1 /*
2 * ipconfig for IPv6
3 * RS means Router Solicitation
4 * RA means Router Advertisement
5 */
6
7 #include <u.h>
8 #include <libc.h>
9 #include <bio.h>
10 #include <ip.h>
11 #include "ipconfig.h"
12 #include "../icmp.h"
13
14 #pragma varargck argpos ralog 1
15
16 #define RALOG "v6routeradv"
17
18 #define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1])
19 #define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \
20 ((uchar*)x)[2]<< 8 | ((uchar*)x)[3])
21
22 enum {
23 ICMP6LEN= 4,
24 };
25
26 typedef struct Hdr Hdr;
27 struct Hdr /* ICMP v4 & v6 header */
28 {
29 uchar type;
30 uchar code;
31 uchar cksum[2]; /* Checksum */
32 uchar data[];
33 };
34
35 char *icmpmsg6[Maxtype6+1] =
36 {
37 [EchoReply] "EchoReply",
38 [UnreachableV6] "UnreachableV6",
39 [PacketTooBigV6] "PacketTooBigV6",
40 [TimeExceedV6] "TimeExceedV6",
41 [Redirect] "Redirect",
42 [EchoRequest] "EchoRequest",
43 [TimeExceed] "TimeExceed",
44 [InParmProblem] "InParmProblem",
45 [Timestamp] "Timestamp",
46 [TimestampReply] "TimestampReply",
47 [InfoRequest] "InfoRequest",
48 [InfoReply] "InfoReply",
49 [AddrMaskRequest] "AddrMaskRequest",
50 [AddrMaskReply] "AddrMaskReply",
51 [EchoRequestV6] "EchoRequestV6",
52 [EchoReplyV6] "EchoReplyV6",
53 [RouterSolicit] "RouterSolicit",
54 [RouterAdvert] "RouterAdvert",
55 [NbrSolicit] "NbrSolicit",
56 [NbrAdvert] "NbrAdvert",
57 [RedirectV6] "RedirectV6",
58 };
59
60 static char *icmp6opts[] =
61 {
62 [0] "unknown option",
63 [V6nd_srclladdr] "srcll_addr",
64 [V6nd_targlladdr] "targll_addr",
65 [V6nd_pfxinfo] "prefix",
66 [V6nd_redirhdr] "redirect",
67 [V6nd_mtu] "mtu",
68 [V6nd_home] "home",
69 [V6nd_srcaddrs] "src_addrs",
70 [V6nd_ip] "ip",
71 [V6nd_rdns] "rdns",
72 [V6nd_9fs] "9fs",
73 [V6nd_9auth] "9auth",
74 };
75
76 uchar v6allroutersL[IPaddrlen] = {
77 0xff, 0x02, 0, 0,
78 0, 0, 0, 0,
79 0, 0, 0, 0,
80 0, 0, 0, 0x02
81 };
82
83 uchar v6allnodesL[IPaddrlen] = {
84 0xff, 0x02, 0, 0,
85 0, 0, 0, 0,
86 0, 0, 0, 0,
87 0, 0, 0, 0x01
88 };
89
90 uchar v6Unspecified[IPaddrlen] = {
91 0, 0, 0, 0,
92 0, 0, 0, 0,
93 0, 0, 0, 0,
94 0, 0, 0, 0
95 };
96
97 uchar v6loopback[IPaddrlen] = {
98 0, 0, 0, 0,
99 0, 0, 0, 0,
100 0, 0, 0, 0,
101 0, 0, 0, 1
102 };
103
104 uchar v6glunicast[IPaddrlen] = {
105 0x08, 0, 0, 0,
106 0, 0, 0, 0,
107 0, 0, 0, 0,
108 0, 0, 0, 0
109 };
110
111 uchar v6linklocal[IPaddrlen] = {
112 0xfe, 0x80, 0, 0,
113 0, 0, 0, 0,
114 0, 0, 0, 0,
115 0, 0, 0, 0
116 };
117
118 uchar v6solpfx[IPaddrlen] = {
119 0xff, 0x02, 0, 0,
120 0, 0, 0, 0,
121 0, 0, 0, 1,
122 /* last 3 bytes filled with low-order bytes of addr being solicited */
123 0xff, 0, 0, 0,
124 };
125
126 uchar v6defmask[IPaddrlen] = {
127 0xff, 0xff, 0xff, 0xff,
128 0xff, 0xff, 0xff, 0xff,
129 0, 0, 0, 0,
130 0, 0, 0, 0
131 };
132
133 enum
134 {
135 Vadd,
136 Vremove,
137 Vunbind,
138 Vaddpref6,
139 Vra6,
140 };
141
142 static void
ralog(char * fmt,...)143 ralog(char *fmt, ...)
144 {
145 char msg[512];
146 va_list arg;
147
148 va_start(arg, fmt);
149 vseprint(msg, msg+sizeof msg, fmt, arg);
150 va_end(arg);
151 syslog(debug, RALOG, msg);
152 }
153
154 extern void
ea2lla(uchar * lla,uchar * ea)155 ea2lla(uchar *lla, uchar *ea)
156 {
157 assert(IPaddrlen == 16);
158 memset(lla, 0, IPaddrlen);
159 lla[0] = 0xFE;
160 lla[1] = 0x80;
161 lla[8] = ea[0] | 0x2;
162 lla[9] = ea[1];
163 lla[10] = ea[2];
164 lla[11] = 0xFF;
165 lla[12] = 0xFE;
166 lla[13] = ea[3];
167 lla[14] = ea[4];
168 lla[15] = ea[5];
169 }
170
171 extern void
ipv62smcast(uchar * smcast,uchar * a)172 ipv62smcast(uchar *smcast, uchar *a)
173 {
174 assert(IPaddrlen == 16);
175 memset(smcast, 0, IPaddrlen);
176 smcast[0] = 0xFF;
177 smcast[1] = 0x02;
178 smcast[11] = 0x1;
179 smcast[12] = 0xFF;
180 smcast[13] = a[13];
181 smcast[14] = a[14];
182 smcast[15] = a[15];
183 }
184
185 void
v6paraminit(Conf * cf)186 v6paraminit(Conf *cf)
187 {
188 cf->sendra = cf->recvra = 0;
189 cf->mflag = 0;
190 cf->oflag = 0;
191 cf->maxraint = Maxv6initraintvl;
192 cf->minraint = Maxv6initraintvl / 4;
193 cf->linkmtu = 1500;
194 cf->reachtime = V6reachabletime;
195 cf->rxmitra = V6retranstimer;
196 cf->ttl = MAXTTL;
197
198 cf->routerlt = 0;
199
200 cf->prefixlen = 64;
201 cf->onlink = 0;
202 cf->autoflag = 0;
203 cf->validlt = cf->preflt = ~0L;
204 }
205
206 static char *
optname(unsigned opt)207 optname(unsigned opt)
208 {
209 static char buf[32];
210
211 if (opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) {
212 snprint(buf, sizeof buf, "unknown option %d", opt);
213 return buf;
214 } else
215 return icmp6opts[opt];
216 }
217
218 static char*
opt_seprint(uchar * ps,uchar * pe,char * sps,char * spe)219 opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
220 {
221 int otype, osz, pktsz;
222 uchar *a;
223 char *p = sps, *e = spe;
224
225 a = ps;
226 for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) {
227 otype = a[0];
228 osz = a[1] * 8;
229
230 switch (otype) {
231 default:
232 return seprint(p, e, " option=%s ", optname(otype));
233 case V6nd_srclladdr:
234 case V6nd_targlladdr:
235 if (pktsz < osz || osz != 8)
236 return seprint(p, e, " option=%s bad size=%d",
237 optname(otype), osz);
238 p = seprint(p, e, " option=%s maddr=%E", optname(otype),
239 a+2);
240 break;
241 case V6nd_pfxinfo:
242 if (pktsz < osz || osz != 32)
243 return seprint(p, e, " option=%s: bad size=%d",
244 optname(otype), osz);
245
246 p = seprint(p, e, " option=%s pref=%I preflen=%3.3d"
247 " lflag=%1.1d aflag=%1.1d unused1=%1.1d"
248 " validlt=%ud preflt=%ud unused2=%1.1d",
249 optname(otype), a+16, (int)(*(a+2)),
250 (*(a+3) & (1 << 7)) != 0,
251 (*(a+3) & (1 << 6)) != 0,
252 (*(a+3) & 63) != 0,
253 NetL(a+4), NetL(a+8), NetL(a+12)!=0);
254 break;
255 }
256 a += osz;
257 }
258 return p;
259 }
260
261 static void
pkt2str(uchar * ps,uchar * pe,char * sps,char * spe)262 pkt2str(uchar *ps, uchar *pe, char *sps, char *spe)
263 {
264 int pktlen;
265 char *tn, *p, *e;
266 uchar *a;
267 Hdr *h;
268
269 h = (Hdr*)ps;
270 a = ps + 4;
271 p = sps;
272 e = spe;
273
274 pktlen = pe - ps;
275 if(pktlen < ICMP6LEN) {
276 seprint(sps, spe, "short pkt");
277 return;
278 }
279
280 tn = icmpmsg6[h->type];
281 if(tn == nil)
282 p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
283 h->code, (ushort)NetS(h->cksum));
284 else
285 p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
286 h->code, (ushort)NetS(h->cksum));
287
288 switch(h->type){
289 case RouterSolicit:
290 ps += 8;
291 p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
292 opt_seprint(ps, pe, p, e);
293 break;
294 case RouterAdvert:
295 ps += 16;
296 p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d"
297 " unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d",
298 a[0],
299 (*(a+1) & (1 << 7)) != 0,
300 (*(a+1) & (1 << 6)) != 0,
301 (*(a+1) & 63) != 0,
302 NetS(a+2), NetL(a+4), NetL(a+8));
303 opt_seprint(ps, pe, p, e);
304 break;
305 default:
306 seprint(p, e, " unexpected icmp6 pkt type");
307 break;
308 }
309 }
310
311 static void
catch(void * a,char * msg)312 catch(void *a, char *msg)
313 {
314 USED(a);
315 if(strstr(msg, "alarm"))
316 noted(NCONT);
317 else
318 noted(NDFLT);
319 }
320
321 /*
322 * based on libthread's threadsetname, but drags in less library code.
323 * actually just sets the arguments displayed.
324 */
325 void
procsetname(char * fmt,...)326 procsetname(char *fmt, ...)
327 {
328 int fd;
329 char *cmdname;
330 char buf[128];
331 va_list arg;
332
333 va_start(arg, fmt);
334 cmdname = vsmprint(fmt, arg);
335 va_end(arg);
336 if (cmdname == nil)
337 return;
338 snprint(buf, sizeof buf, "#p/%d/args", getpid());
339 if((fd = open(buf, OWRITE)) >= 0){
340 write(fd, cmdname, strlen(cmdname)+1);
341 close(fd);
342 }
343 free(cmdname);
344 }
345
346 int
dialicmp(uchar * dst,int dport,int * ctlfd)347 dialicmp(uchar *dst, int dport, int *ctlfd)
348 {
349 int fd, cfd, n, m;
350 char cmsg[100], name[128], connind[40];
351 char hdrs[] = "headers";
352
353 snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint);
354 cfd = open(name, ORDWR);
355 if(cfd < 0)
356 sysfatal("dialicmp: can't open %s: %r", name);
357
358 n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport);
359 m = write(cfd, cmsg, n);
360 if (m < n)
361 sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name);
362
363 seek(cfd, 0, 0);
364 n = read(cfd, connind, sizeof connind);
365 if (n < 0)
366 connind[0] = 0;
367 else if (n < sizeof connind)
368 connind[n] = 0;
369 else
370 connind[sizeof connind - 1] = 0;
371
372 snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind);
373 fd = open(name, ORDWR);
374 if(fd < 0)
375 sysfatal("dialicmp: can't open %s: %r", name);
376
377 n = sizeof hdrs - 1;
378 if(write(cfd, hdrs, n) < n)
379 sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name);
380 *ctlfd = cfd;
381 return fd;
382 }
383
384 /* add ipv6 addr to an interface */
385 int
ip6cfg(int autoconf)386 ip6cfg(int autoconf)
387 {
388 int dupfound = 0, n, nf;
389 char *p, *fields[4];
390 char buf[256];
391 uchar ethaddr[6];
392 Biobuf *bp;
393
394 if (autoconf) { /* create link-local addr */
395 if (myetheraddr(ethaddr, conf.dev) < 0)
396 sysfatal("myetheraddr w/ %s failed: %r", conf.dev);
397 ea2lla(conf.laddr, ethaddr);
398 }
399
400 if (dupl_disc)
401 n = sprint(buf, "try");
402 else
403 n = sprint(buf, "add");
404
405 n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
406 if(!validip(conf.mask))
407 ipmove(conf.mask, v6defmask);
408 n += snprint(buf+n, sizeof buf-n, " %M", conf.mask);
409 if(validip(conf.raddr)){
410 n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
411 if(conf.mtu != 0)
412 n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
413 }
414
415 if(write(conf.cfd, buf, n) < 0){
416 warning("write(%s): %r", buf);
417 return -1;
418 }
419
420 if (!dupl_disc)
421 return 0;
422
423 sleep(3000);
424
425 /* read arp table, look for addr duplication */
426 snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
427 bp = Bopen(buf, OREAD);
428 if (bp == 0) {
429 warning("couldn't open %s: %r", buf);
430 return -1;
431 }
432
433 snprint(buf, sizeof buf, "%I", conf.laddr);
434 while(p = Brdline(bp, '\n')){
435 p[Blinelen(bp)-1] = 0;
436 nf = tokenize(p, fields, nelem(fields));
437 if(nf >= 4 && cistrcmp(fields[2], buf) == 0) {
438 warning("found dup entry in arp cache");
439 dupfound = 1;
440 break;
441 }
442 }
443 Bterm(bp);
444
445 if (dupfound)
446 doremove();
447 else {
448 n = sprint(buf, "add %I %M", conf.laddr, conf.mask);
449 if(validip(conf.raddr)){
450 n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
451 if(conf.mtu != 0)
452 n += snprint(buf+n, sizeof buf-n, " %d",
453 conf.mtu);
454 }
455 write(conf.cfd, buf, n);
456 }
457 return 0;
458 }
459
460 static int
recvra6on(char * net,int conn)461 recvra6on(char *net, int conn)
462 {
463 Ipifc* ifc;
464
465 ifc = readipifc(net, nil, conn);
466 if (ifc == nil)
467 return 0;
468 else if (ifc->sendra6 > 0)
469 return IsRouter;
470 else if (ifc->recvra6 > 0)
471 return IsHostRecv;
472 else
473 return IsHostNoRecv;
474 }
475
476 /* send icmpv6 router solicitation to multicast address for all routers */
477 static void
sendrs(int fd)478 sendrs(int fd)
479 {
480 Routersol *rs;
481 uchar buff[sizeof *rs];
482
483 memset(buff, 0, sizeof buff);
484 rs = (Routersol *)buff;
485 memmove(rs->dst, v6allroutersL, IPaddrlen);
486 memmove(rs->src, v6Unspecified, IPaddrlen);
487 rs->type = ICMP6_RS;
488
489 if(write(fd, rs, sizeof buff) < sizeof buff)
490 ralog("sendrs: write failed, pkt size %d", sizeof buff);
491 else
492 ralog("sendrs: sent solicitation to %I from %I on %s",
493 rs->dst, rs->src, conf.dev);
494 }
495
496 /*
497 * a router receiving a router adv from another
498 * router calls this; it is basically supposed to
499 * log the information in the ra and raise a flag
500 * if any parameter value is different from its configured values.
501 *
502 * doing nothing for now since I don't know where to log this yet.
503 */
504 static void
recvrarouter(uchar buf[],int pktlen)505 recvrarouter(uchar buf[], int pktlen)
506 {
507 USED(buf, pktlen);
508 ralog("i am a router and got a router advert");
509 }
510
511 /* host receiving a router advertisement calls this */
512
513 static void
ewrite(int fd,char * str)514 ewrite(int fd, char *str)
515 {
516 int n;
517
518 n = strlen(str);
519 if (write(fd, str, n) != n)
520 ralog("write(%s) failed: %r", str);
521 }
522
523 static void
issuebasera6(Conf * cf)524 issuebasera6(Conf *cf)
525 {
526 char *cfg;
527
528 cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d "
529 "ttl %d routerlt %d",
530 cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra,
531 cf->ttl, cf->routerlt);
532 ewrite(cf->cfd, cfg);
533 free(cfg);
534 }
535
536 static void
issuerara6(Conf * cf)537 issuerara6(Conf *cf)
538 {
539 char *cfg;
540
541 cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d "
542 "linkmtu %d",
543 cf->sendra, cf->recvra, cf->maxraint, cf->minraint,
544 cf->linkmtu);
545 ewrite(cf->cfd, cfg);
546 free(cfg);
547 }
548
549 static void
issueadd6(Conf * cf)550 issueadd6(Conf *cf)
551 {
552 char *cfg;
553
554 cfg = smprint("add6 %I %d %d %d %lud %lud", cf->v6pref, cf->prefixlen,
555 cf->onlink, cf->autoflag, cf->validlt, cf->preflt);
556 ewrite(cf->cfd, cfg);
557 free(cfg);
558 }
559
560 static void
recvrahost(uchar buf[],int pktlen)561 recvrahost(uchar buf[], int pktlen)
562 {
563 int arpfd, m, n;
564 char abuf[100];
565 uchar optype;
566 Lladdropt *llao;
567 Mtuopt *mtuo;
568 Prefixopt *prfo;
569 Routeradv *ra;
570 static int first = 1;
571
572 ra = (Routeradv*)buf;
573 // memmove(conf.v6gaddr, ra->src, IPaddrlen);
574 conf.ttl = ra->cttl;
575 conf.mflag = (MFMASK & ra->mor);
576 conf.oflag = (OCMASK & ra->mor);
577 conf.routerlt = nhgets(ra->routerlt);
578 conf.reachtime = nhgetl(ra->rchbltime);
579 conf.rxmitra = nhgetl(ra->rxmtimer);
580
581 // issueadd6(&conf); /* for conf.v6gaddr? */
582 if (fprint(conf.cfd, "ra6 recvra 1") < 0)
583 ralog("write(ra6 recvra 1) failed: %r");
584 issuebasera6(&conf);
585
586 m = sizeof *ra;
587 while (pktlen - m > 0) {
588 optype = buf[m];
589 switch (optype) {
590 case V6nd_srclladdr:
591 llao = (Lladdropt *)&buf[m];
592 m += 8 * buf[m+1];
593 if (llao->len != 1) {
594 ralog("recvrahost: illegal len (%d) for source "
595 "link layer address option", llao->len);
596 return;
597 }
598 if (!ISIPV6LINKLOCAL(ra->src)) {
599 ralog("recvrahost: non-link-local src addr for "
600 "router adv %I", ra->src);
601 return;
602 }
603
604 snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
605 arpfd = open(abuf, OWRITE);
606 if (arpfd < 0) {
607 ralog("recvrahost: couldn't open %s to write: %r",
608 abuf);
609 return;
610 }
611
612 n = snprint(abuf, sizeof abuf, "add ether %I %E",
613 ra->src, llao->lladdr);
614 if (write(arpfd, abuf, n) < n)
615 ralog("recvrahost: couldn't write to %s/arp",
616 conf.mpoint);
617 close(arpfd);
618 break;
619 case V6nd_targlladdr:
620 case V6nd_redirhdr:
621 m += 8 * buf[m+1];
622 ralog("ignoring unexpected option type `%s' in Routeradv",
623 optname(optype));
624 break;
625 case V6nd_mtu:
626 mtuo = (Mtuopt*)&buf[m];
627 m += 8 * mtuo->len;
628 conf.linkmtu = nhgetl(mtuo->mtu);
629 break;
630 case V6nd_pfxinfo:
631 prfo = (Prefixopt*)&buf[m];
632 m += 8 * prfo->len;
633 if (prfo->len != 4) {
634 ralog("illegal len (%d) for prefix option",
635 prfo->len);
636 return;
637 }
638 memmove(conf.v6pref, prfo->pref, IPaddrlen);
639 conf.prefixlen = prfo->plen;
640 conf.onlink = ((prfo->lar & OLMASK) != 0);
641 conf.autoflag = ((prfo->lar & AFMASK) != 0);
642 conf.validlt = nhgetl(prfo->validlt);
643 conf.preflt = nhgetl(prfo->preflt);
644 issueadd6(&conf);
645 if (first) {
646 first = 0;
647 ralog("got initial RA from %I on %s; pfx %I",
648 ra->src, conf.dev, prfo->pref);
649 }
650 break;
651 default:
652 if (debug)
653 ralog("ignoring optype %d in Routeradv from %I",
654 optype, ra->src);
655 /* fall through */
656 case V6nd_srcaddrs:
657 /* netsbd sends this, so quietly ignore it for now */
658 m += 8 * buf[m+1];
659 break;
660 }
661 }
662 }
663
664 /*
665 * daemon to receive router advertisements from routers
666 */
667 void
recvra6(void)668 recvra6(void)
669 {
670 int fd, cfd, n, sendrscnt, sleepfor;
671 uchar buf[4096];
672
673 /* TODO: why not v6allroutersL? */
674 fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
675 if (fd < 0)
676 sysfatal("can't open icmp_ra connection: %r");
677
678 notify(catch);
679 sendrscnt = Maxv6rss;
680
681 switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
682 case -1:
683 sysfatal("can't fork: %r");
684 default:
685 return;
686 case 0:
687 break;
688 }
689
690 procsetname("recvra6 on %s", conf.dev);
691 ralog("recvra6 on %s", conf.dev);
692 sleepfor = jitter();
693 for (;;) {
694 /*
695 * We only get 3 (Maxv6rss) tries, so make sure we
696 * wait long enough to be certain that at least one RA
697 * will be transmitted.
698 */
699 if (sleepfor < 7000)
700 sleepfor = 7000;
701 alarm(sleepfor);
702 n = read(fd, buf, sizeof buf);
703 alarm(0);
704 if (n <= 0) {
705 if (sendrscnt > 0) {
706 sendrscnt--;
707 if (recvra6on(conf.mpoint, myifc) == IsHostRecv)
708 sendrs(fd);
709 sleepfor = V6rsintvl + nrand(100);
710 }
711 if (sendrscnt == 0) {
712 sendrscnt--;
713 sleepfor = 0;
714 ralog("recvra6: no router advs after %d sols on %s",
715 Maxv6rss, conf.dev);
716 }
717 continue;
718 }
719
720 sleepfor = 0;
721 sendrscnt = -1; /* got at least initial ra; no whining */
722 switch (recvra6on(conf.mpoint, myifc)) {
723 case IsRouter:
724 recvrarouter(buf, n);
725 break;
726 case IsHostRecv:
727 recvrahost(buf, n);
728 break;
729 case IsHostNoRecv:
730 ralog("recvra6: recvra off, quitting on %s", conf.dev);
731 close(fd);
732 exits(0);
733 default:
734 ralog("recvra6: unable to read router status on %s",
735 conf.dev);
736 break;
737 }
738 }
739 }
740
741 /*
742 * return -1 -- error, reading/writing some file,
743 * 0 -- no arp table updates
744 * 1 -- successful arp table update
745 */
746 int
recvrs(uchar * buf,int pktlen,uchar * sol)747 recvrs(uchar *buf, int pktlen, uchar *sol)
748 {
749 int n, optsz, arpfd;
750 char abuf[256];
751 Routersol *rs;
752 Lladdropt *llao;
753
754 rs = (Routersol *)buf;
755 n = sizeof *rs;
756 optsz = pktlen - n;
757 pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
758
759 if (optsz != sizeof *llao)
760 return 0;
761 if (buf[n] != V6nd_srclladdr || 8*buf[n+1] != sizeof *llao) {
762 ralog("rs opt err %s", abuf);
763 return -1;
764 }
765
766 ralog("rs recv %s", abuf);
767
768 if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
769 return 0;
770
771 snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
772 arpfd = open(abuf, OWRITE);
773 if (arpfd < 0) {
774 ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
775 return -1;
776 }
777
778 llao = (Lladdropt *)buf[n];
779 n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
780 if (write(arpfd, abuf, n) < n) {
781 ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
782 close(arpfd);
783 return -1;
784 }
785
786 memmove(sol, rs->src, IPaddrlen);
787 close(arpfd);
788 return 1;
789 }
790
791 void
sendra(int fd,uchar * dst,int rlt)792 sendra(int fd, uchar *dst, int rlt)
793 {
794 int pktsz, preflen;
795 char abuf[1024], tmp[40];
796 uchar buf[1024], macaddr[6], src[IPaddrlen];
797 Ipifc *ifc = nil;
798 Iplifc *lifc, *nlifc;
799 Lladdropt *llao;
800 Prefixopt *prfo;
801 Routeradv *ra;
802
803 memset(buf, 0, sizeof buf);
804 ra = (Routeradv *)buf;
805
806 myetheraddr(macaddr, conf.dev);
807 ea2lla(src, macaddr);
808 memmove(ra->src, src, IPaddrlen);
809 memmove(ra->dst, dst, IPaddrlen);
810 ra->type = ICMP6_RA;
811 ra->cttl = conf.ttl;
812
813 if (conf.mflag > 0)
814 ra->mor |= MFMASK;
815 if (conf.oflag > 0)
816 ra->mor |= OCMASK;
817 if (rlt > 0)
818 hnputs(ra->routerlt, conf.routerlt);
819 else
820 hnputs(ra->routerlt, 0);
821 hnputl(ra->rchbltime, conf.reachtime);
822 hnputl(ra->rxmtimer, conf.rxmitra);
823
824 pktsz = sizeof *ra;
825
826 /* include all global unicast prefixes on interface in prefix options */
827 ifc = readipifc(conf.mpoint, ifc, myifc);
828 for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
829 nlifc = lifc->next;
830 prfo = (Prefixopt *)(buf + pktsz);
831 /* global unicast address? */
832 if (!ISIPV6LINKLOCAL(lifc->ip) && !ISIPV6MCAST(lifc->ip) &&
833 memcmp(lifc->ip, IPnoaddr, IPaddrlen) != 0 &&
834 memcmp(lifc->ip, v6loopback, IPaddrlen) != 0 &&
835 !isv4(lifc->ip)) {
836 memmove(prfo->pref, lifc->net, IPaddrlen);
837
838 /* hack to find prefix length */
839 snprint(tmp, sizeof tmp, "%M", lifc->mask);
840 preflen = atoi(&tmp[1]);
841 prfo->plen = preflen & 0xff;
842 if (prfo->plen == 0)
843 continue;
844
845 prfo->type = V6nd_pfxinfo;
846 prfo->len = 4;
847 prfo->lar = AFMASK;
848 hnputl(prfo->validlt, lifc->validlt);
849 hnputl(prfo->preflt, lifc->preflt);
850 pktsz += sizeof *prfo;
851 }
852 }
853 /*
854 * include link layer address (mac address for now) in
855 * link layer address option
856 */
857 llao = (Lladdropt *)(buf + pktsz);
858 llao->type = V6nd_srclladdr;
859 llao->len = 1;
860 memmove(llao->lladdr, macaddr, sizeof macaddr);
861 pktsz += sizeof *llao;
862
863 pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
864 if(write(fd, buf, pktsz) < pktsz)
865 ralog("sendra fail %s: %r", abuf);
866 else if (debug)
867 ralog("sendra succ %s", abuf);
868 }
869
870 /*
871 * daemon to send router advertisements to hosts
872 */
873 void
sendra6(void)874 sendra6(void)
875 {
876 int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
877 long lastra, now;
878 uchar buf[4096], dst[IPaddrlen];
879 Ipifc *ifc = nil;
880
881 fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
882 if (fd < 0)
883 sysfatal("can't open icmp_rs connection: %r");
884
885 notify(catch);
886 sendracnt = Maxv6initras;
887 nquitmsgs = Maxv6finalras;
888
889 switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
890 case -1:
891 sysfatal("can't fork: %r");
892 default:
893 return;
894 case 0:
895 break;
896 }
897
898 procsetname("sendra6 on %s", conf.dev);
899 ralog("sendra6 on %s", conf.dev);
900 sleepfor = jitter();
901 for (;;) {
902 lastra = time(0);
903 if (sleepfor < 0)
904 sleepfor = 0;
905 alarm(sleepfor);
906 n = read(fd, buf, sizeof buf);
907 alarm(0);
908
909 ifc = readipifc(conf.mpoint, ifc, myifc);
910 if (ifc == nil) {
911 ralog("sendra6: can't read router params on %s",
912 conf.mpoint);
913 continue;
914 }
915
916 if (ifc->sendra6 <= 0)
917 if (nquitmsgs > 0) {
918 sendra(fd, v6allnodesL, 0);
919 nquitmsgs--;
920 sleepfor = Minv6interradelay + jitter();
921 continue;
922 } else {
923 ralog("sendra6: sendra off, quitting on %s",
924 conf.dev);
925 exits(0);
926 }
927
928 nquitmsgs = Maxv6finalras;
929
930 if (n <= 0) { /* no RS */
931 if (sendracnt > 0)
932 sendracnt--;
933 } else { /* respond to RS */
934 dstknown = recvrs(buf, n, dst);
935 now = time(0);
936
937 if (now - lastra < Minv6interradelay) {
938 /* too close, skip */
939 sleepfor = lastra + Minv6interradelay +
940 jitter() - now;
941 continue;
942 }
943 sleep(jitter());
944 }
945 sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint);
946 if (dstknown > 0)
947 sendra(fd, dst, 1);
948 else
949 sendra(fd, v6allnodesL, 1);
950 }
951 }
952
953 void
startra6(void)954 startra6(void)
955 {
956 static char routeon[] = "iprouting 1";
957
958 if (conf.recvra > 0)
959 recvra6();
960
961 if (conf.sendra > 0) {
962 if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
963 warning("write (iprouting 1) failed: %r");
964 return;
965 }
966 sendra6();
967 if (conf.recvra <= 0)
968 recvra6();
969 }
970 }
971
972 void
doipv6(int what)973 doipv6(int what)
974 {
975 nip = nipifcs(conf.mpoint);
976 if(!noconfig){
977 lookforip(conf.mpoint);
978 controldevice();
979 binddevice();
980 }
981
982 switch (what) {
983 default:
984 sysfatal("unknown IPv6 verb");
985 case Vaddpref6:
986 issueadd6(&conf);
987 break;
988 case Vra6:
989 issuebasera6(&conf);
990 issuerara6(&conf);
991 dolog = 1;
992 startra6();
993 break;
994 }
995 }
996