3 * RS means Router Solicitation
4 * RA means Router Advertisement
16 #pragma varargck argpos ralog 1
18 #define RALOG "v6routeradv"
20 #define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1])
21 #define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \
22 ((uchar*)x)[2]<< 8 | ((uchar*)x)[3])
28 typedef struct Hdr Hdr;
29 struct Hdr /* ICMP v4 & v6 header */
33 uchar cksum[2]; /* Checksum */
37 char *icmpmsg6[Maxtype6+1] =
39 [EchoReply] "EchoReply",
40 [UnreachableV6] "UnreachableV6",
41 [PacketTooBigV6] "PacketTooBigV6",
42 [TimeExceedV6] "TimeExceedV6",
43 [Redirect] "Redirect",
44 [EchoRequest] "EchoRequest",
45 [TimeExceed] "TimeExceed",
46 [InParmProblem] "InParmProblem",
47 [Timestamp] "Timestamp",
48 [TimestampReply] "TimestampReply",
49 [InfoRequest] "InfoRequest",
50 [InfoReply] "InfoReply",
51 [AddrMaskRequest] "AddrMaskRequest",
52 [AddrMaskReply] "AddrMaskReply",
53 [EchoRequestV6] "EchoRequestV6",
54 [EchoReplyV6] "EchoReplyV6",
55 [RouterSolicit] "RouterSolicit",
56 [RouterAdvert] "RouterAdvert",
57 [NbrSolicit] "NbrSolicit",
58 [NbrAdvert] "NbrAdvert",
59 [RedirectV6] "RedirectV6",
62 static char *icmp6opts[] =
65 [V6nd_srclladdr] "srcll_addr",
66 [V6nd_targlladdr] "targll_addr",
67 [V6nd_pfxinfo] "prefix",
68 [V6nd_redirhdr] "redirect",
71 [V6nd_srcaddrs] "src_addrs",
78 uchar v6allroutersL[IPaddrlen] = {
85 uchar v6allnodesL[IPaddrlen] = {
92 uchar v6Unspecified[IPaddrlen] = {
99 uchar v6loopback[IPaddrlen] = {
106 uchar v6glunicast[IPaddrlen] = {
113 uchar v6linklocal[IPaddrlen] = {
120 uchar v6solpfx[IPaddrlen] = {
124 /* last 3 bytes filled with low-order bytes of addr being solicited */
128 uchar v6defmask[IPaddrlen] = {
129 0xff, 0xff, 0xff, 0xff,
130 0xff, 0xff, 0xff, 0xff,
145 ralog(char *fmt, ...)
151 vseprint(msg, msg+sizeof msg, fmt, arg);
153 syslog(debug, RALOG, msg);
157 ea2lla(uchar *lla, uchar *ea)
159 assert(IPaddrlen == 16);
160 memset(lla, 0, IPaddrlen);
163 lla[8] = ea[0] ^ 0x2;
174 ipv62smcast(uchar *smcast, uchar *a)
176 assert(IPaddrlen == 16);
177 memset(smcast, 0, IPaddrlen);
188 v6paraminit(Conf *cf)
190 cf->sendra = cf->recvra = 0;
193 cf->maxraint = Maxv6initraintvl;
194 cf->minraint = Maxv6initraintvl / 4;
196 cf->reachtime = V6reachabletime;
197 cf->rxmitra = V6retranstimer;
205 cf->validlt = cf->preflt = ~0L;
209 optname(unsigned opt)
213 if(opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) {
214 snprint(buf, sizeof buf, "unknown option %d", opt);
217 return icmp6opts[opt];
221 opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
223 int otype, osz, pktlen;
225 char *p = sps, *e = spe;
228 for (pktlen = pe - ps; pktlen > 0; pktlen -= osz) {
234 return seprint(p, e, " option=%s ", optname(otype));
236 case V6nd_targlladdr:
237 if(pktlen < osz || osz != 8)
238 return seprint(p, e, " option=%s bad size=%d",
239 optname(otype), osz);
240 p = seprint(p, e, " option=%s maddr=%E", optname(otype),
244 if(pktlen < osz || osz != 32)
245 return seprint(p, e, " option=%s: bad size=%d",
246 optname(otype), osz);
248 p = seprint(p, e, " option=%s pref=%I preflen=%3.3d"
249 " lflag=%1.1d aflag=%1.1d unused1=%1.1d"
250 " validlt=%ud preflt=%ud unused2=%1.1d",
251 optname(otype), a+16, (int)(*(a+2)),
252 (*(a+3) & (1 << 7)) != 0,
253 (*(a+3) & (1 << 6)) != 0,
255 NetL(a+4), NetL(a+8), NetL(a+12)!=0);
264 catch(void *a, char *msg)
267 if(strstr(msg, "alarm"))
274 dialicmpv6(uchar *ip, int port)
276 char addr[128], local[128];
279 snprint(addr, sizeof(addr), "%s/icmpv6!%I!%d!r", conf.mpoint, ip, port);
280 snprint(local, sizeof(local), "%I!%d", conf.laddr, port);
281 if((fd = dial(addr, local, nil, &cfd)) < 0)
282 sysfatal("dialicmp6: %r");
283 fprint(cfd, "headers");
284 fprint(cfd, "ignoreadvice");
286 fprint(cfd, "addmulti %I", conf.laddr);
292 arpenter(uchar *ip, uchar *mac)
299 snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
300 if((fd = open(buf, OWRITE)) < 0){
301 warning("couldn't open %s: %r", buf);
304 n = snprint(buf, sizeof buf, "add %s %I %E %I\n", conf.type, ip, mac, conf.laddr);
305 if(write(fd, buf, n) != n) {
306 warning("arpenter: %s: %r", buf);
317 char buf[256], *f[5], *p;
318 uchar addr[IPaddrlen];
322 snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
323 bp = Bopen(buf, OREAD);
325 warning("couldn't open %s: %r", buf);
329 while((p = Brdline(bp, '\n')) != nil){
330 p[Blinelen(bp)-1] = 0;
331 if(tokenize(p, f, nelem(f)) < 3)
333 if(parseip(addr, f[2]) != -1)
335 if(ipcmp(addr, ip) == 0){
349 for(len=0; len < 128; len += 8){
354 while(len < 128 && (*mask & (0x80 >> (len & 7))) != 0)
360 genipmkask(uchar *mask, int len)
362 memset(mask, 0, IPaddrlen);
367 for(; len >= 8; len -= 8)
370 *mask = ~((1<<(8-len))-1);
373 /* add ipv6 addr to an interface */
380 if(!validip(conf.laddr) || isv4(conf.laddr))
383 tentative = dupl_disc;
387 n = sprint(buf, "try");
389 n = sprint(buf, "add");
391 n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
392 if(!validip(conf.mask))
393 ipmove(conf.mask, v6defmask);
394 n += snprint(buf+n, sizeof buf-n, " %M", conf.mask);
395 if(validip(conf.raddr)){
396 n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
398 n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
401 if(write(conf.cfd, buf, n) < 0){
402 warning("write(%s): %r", buf);
407 if(validip(conf.gaddr) && !isv4(conf.gaddr))
408 adddefroute(conf.gaddr, conf.laddr, conf.laddr, conf.mask);
414 if(arpcheck(conf.laddr) <= 0) {
419 warning("found dup entry in arp cache");
425 recvra6on(Ipifc *ifc)
429 else if(ifc->sendra6 > 0)
431 else if(ifc->recvra6 > 0)
438 findllip(uchar *ip, Ipifc *ifc)
442 for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
443 if(ISIPV6LINKLOCAL(lifc->ip)){
444 ipmove(ip, lifc->ip);
448 ipmove(ip, v6Unspecified);
453 sendrs(int fd, uchar *dst)
460 memset(buf, 0, sizeof buf);
462 rs = (Routersol *)buf;
464 ipmove(rs->dst, dst);
465 ipmove(rs->src, conf.laddr);
469 llao = (Lladdropt *)&buf[pktlen];
470 llao->type = V6nd_srclladdr;
471 llao->len = (2+7+conf.hwalen)/8;
472 memmove(llao->lladdr, conf.hwa, conf.hwalen);
473 pktlen += 8 * llao->len;
476 if(write(fd, rs, pktlen) != pktlen)
477 ralog("sendrs: write failed, pkt size %d", pktlen);
479 ralog("sendrs: sent solicitation to %I from %I on %s",
480 rs->dst, rs->src, conf.dev);
484 * a router receiving a router adv from another
485 * router calls this; it is basically supposed to
486 * log the information in the ra and raise a flag
487 * if any parameter value is different from its configured values.
489 * doing nothing for now since I don't know where to log this yet.
492 recvrarouter(uchar buf[], int pktlen)
497 /* host receiving a router advertisement calls this */
500 ewrite(int fd, char *str)
508 if(write(fd, str, n) != n)
509 ralog("write(%s) failed: %r", str);
513 issuebasera6(Conf *cf)
517 cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d "
518 "ttl %d routerlt %d",
519 cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra,
520 cf->ttl, cf->routerlt);
521 ewrite(cf->cfd, cfg);
530 cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d "
532 cf->sendra, cf->recvra, cf->maxraint, cf->minraint,
534 ewrite(cf->cfd, cfg);
543 cfg = smprint("add6 %I %d %d %d %lud %lud", cf->v6pref, cf->prefixlen,
544 cf->onlink, cf->autoflag, cf->validlt, cf->preflt);
545 ewrite(cf->cfd, cfg);
552 static uchar tab[SHA1dlen*100], *w;
553 uchar hash[SHA1dlen], *r;
555 sha1((uchar*)cf, sizeof(*cf), hash, nil);
556 if(w == nil || w == &tab[sizeof(tab)])
558 for(r = tab; r < w; r += SHA1dlen)
559 if(memcmp(r, hash, SHA1dlen) == 0)
561 memmove(w, hash, SHA1dlen);
567 recvrahost(uchar buf[], int pktlen)
569 int m, n, optype, needrefresh;
570 uchar src[IPaddrlen];
577 ra = (Routeradv*)buf;
581 if(!ISIPV6LINKLOCAL(ra->src))
585 conf.mflag = (MFMASK & ra->mor);
586 conf.oflag = (OCMASK & ra->mor);
587 conf.routerlt = nhgets(ra->routerlt);
588 conf.reachtime = nhgetl(ra->rchbltime);
589 conf.rxmitra = nhgetl(ra->rxmtimer);
593 while(pktlen - m >= 8) {
602 llao = (Lladdropt *)&buf[n];
603 if(llao->len == 1 && conf.hwalen == 6)
604 arpenter(ra->src, llao->lladdr);
607 mtuo = (Mtuopt*)&buf[n];
608 conf.linkmtu = nhgetl(mtuo->mtu);
611 prfo = (Prefixopt*)&buf[n];
615 conf.prefixlen = prfo->plen & 127;
616 genipmkask(conf.mask, conf.prefixlen);
617 maskip(prfo->pref, conf.mask, conf.v6pref);
618 conf.onlink = ((prfo->lar & OLMASK) != 0);
619 conf.autoflag = ((prfo->lar & AFMASK) != 0);
620 conf.validlt = nhgetl(prfo->validlt);
621 conf.preflt = nhgetl(prfo->preflt);
624 if(conf.routerlt == 0)
625 ipmove(conf.gaddr, IPnoaddr);
626 else if((prfo->lar & RFMASK) != 0)
627 ipmove(conf.gaddr, prfo->pref);
629 ipmove(conf.gaddr, ra->src);
631 /* report prefix only once */
635 if(conf.prefixlen == 0
636 || !validip(conf.v6pref)
638 || ipcmp(conf.v6pref, v6loopback) == 0
639 || ISIPV6MCAST(conf.v6pref)
640 || ISIPV6LINKLOCAL(conf.v6pref)){
641 ralog("igoring bogus prefix from %I on %s; pfx %I %M",
642 ra->src, conf.dev, conf.v6pref, conf.mask);
646 ralog("got initial RA from %I on %s; pfx %I %M",
647 ra->src, conf.dev, conf.v6pref, conf.mask);
649 if(validip(conf.gaddr)){
650 memmove(src, conf.v6pref, 8);
651 memmove(src+8, conf.laddr+8, 8);
652 adddefroute(conf.gaddr, conf.laddr, src, conf.mask);
664 * daemon to receive router advertisements from routers
669 int fd, n, sendrscnt, recvracnt, sleepfor;
673 ifc = readipifc(conf.mpoint, nil, myifc);
675 sysfatal("can't read ipifc: %r");
677 if(!findllip(conf.laddr, ifc))
678 sysfatal("no link local address");
680 fd = dialicmpv6(v6allnodesL, ICMP6_RA);
682 sysfatal("can't open icmp_ra connection: %r");
685 sendrscnt = Maxv6rss;
688 switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
690 sysfatal("can't fork: %r");
698 procsetname("recvra6 on %s %I", conf.dev, conf.laddr);
699 ralog("recvra6 on %s", conf.dev);
700 sleepfor = Minv6interradelay;
703 n = read(fd, buf, sizeof buf);
706 /* wait for alarm to expire */
707 if(sendrscnt < 0 && sleepfor > 100)
710 ifc = readipifc(conf.mpoint, ifc, myifc);
712 ralog("recvra6: can't read router params on %s, quitting on %s",
713 conf.mpoint, conf.dev);
720 if(recvra6on(ifc) == IsHostRecv)
721 sendrs(fd, v6allroutersL);
722 sleepfor = V6rsintvl + nrand(100);
727 ralog("recvra6: no router advs after %d sols on %s",
733 /* got at least initial ra; no whining */
737 if(++recvracnt >= Maxv6initras){
739 sleepfor = Maxv6radelay;
742 switch (recvra6on(ifc)) {
744 recvrarouter(buf, n);
750 ralog("recvra6: recvra off, quitting on %s", conf.dev);
757 * return -1 -- error, reading/writing some file,
758 * 0 -- no arp table updates
759 * 1 -- successful arp table update
762 recvrs(uchar *buf, int pktlen, uchar *sol)
768 n = sizeof *rs + sizeof *llao;
769 rs = (Routersol *)buf;
773 llao = (Lladdropt *)&buf[sizeof *rs];
774 if(llao->type != V6nd_srclladdr || llao->len != 1 || conf.hwalen != 6)
779 || ipcmp(rs->src, v6loopback) == 0
780 || ISIPV6MCAST(rs->src))
783 if((n = arpenter(rs->src, llao->lladdr)) <= 0)
786 ipmove(sol, rs->src);
791 sendra(int fd, uchar *dst, int rlt, Ipifc *ifc)
800 memset(buf, 0, sizeof buf);
802 ra = (Routeradv *)buf;
803 ipmove(ra->dst, dst);
804 ipmove(ra->src, conf.laddr);
812 hnputs(ra->routerlt, conf.routerlt);
814 hnputs(ra->routerlt, 0);
815 hnputl(ra->rchbltime, conf.reachtime);
816 hnputl(ra->rxmtimer, conf.rxmitra);
820 * include link layer address (mac address for now) in
821 * link layer address option
824 llao = (Lladdropt *)&buf[pktlen];
825 llao->type = V6nd_srclladdr;
826 llao->len = (2+7+conf.hwalen)/8;
827 memmove(llao->lladdr, conf.hwa, conf.hwalen);
828 pktlen += 8 * llao->len;
831 /* include all global unicast prefixes on interface in prefix options */
832 for (lifc = (ifc != nil? ifc->lifc: nil); lifc != nil; lifc = lifc->next) {
833 if(pktlen > sizeof buf - 4*8)
835 if(!validip(lifc->ip)
837 || ipcmp(lifc->ip, v6loopback) == 0
838 || ISIPV6MCAST(lifc->ip)
839 || ISIPV6LINKLOCAL(lifc->ip))
841 prfo = (Prefixopt *)&buf[pktlen];
842 prfo->type = V6nd_pfxinfo;
844 prfo->plen = masklen(lifc->mask) & 127;
847 ipmove(prfo->pref, lifc->net);
848 prfo->lar = AFMASK|OLMASK;
849 hnputl(prfo->validlt, lifc->validlt);
850 hnputl(prfo->preflt, lifc->preflt);
851 pktlen += 8 * prfo->len;
854 write(fd, buf, pktlen);
858 * daemon to send router advertisements to hosts
863 int fd, n, sleepfor, nquitmsgs;
864 uchar buf[4096], dst[IPaddrlen];
867 ifc = readipifc(conf.mpoint, nil, myifc);
869 sysfatal("can't read ipifc: %r");
871 if(!findllip(conf.laddr, ifc))
872 sysfatal("no link local address");
874 fd = dialicmpv6(v6allroutersL, ICMP6_RS);
876 sysfatal("can't open icmp_rs connection: %r");
879 nquitmsgs = Maxv6finalras;
881 switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
883 sysfatal("can't fork: %r");
891 procsetname("sendra6 on %s %I", conf.dev, conf.laddr);
892 ralog("sendra6 on %s", conf.dev);
893 sleepfor = 100 + jitter();
896 n = read(fd, buf, sizeof buf);
899 if(n > 0 && recvrs(buf, n, dst) > 0)
900 sendra(fd, dst, 1, ifc);
902 /* wait for alarm to expire */
905 sleepfor = Minv6interradelay;
907 ifc = readipifc(conf.mpoint, ifc, myifc);
909 ralog("sendra6: can't read router params on %s, quitting on %s",
910 conf.mpoint, conf.dev);
913 if(ifc->sendra6 <= 0){
916 sendra(fd, v6allnodesL, 0, ifc);
919 ralog("sendra6: sendra off, quitting on %s", conf.dev);
923 sendra(fd, v6allnodesL, 1, ifc);
924 sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint);
931 static char routeon[] = "iprouting 1";
938 if(conf.sendra > 0) {
939 if(write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
940 warning("write (iprouting 1) failed: %r");
952 fprint(conf.rfd, "tag ra6");
956 sysfatal("unknown IPv6 verb");