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;
389 char *p;
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 if(cistrstr(p, buf) != 0) {
437 warning("found dup entry in arp cache");
438 dupfound = 1;
439 break;
440 }
441 }
442 Bterm(bp);
443
444 if (dupfound)
445 doremove();
446 else {
447 n = sprint(buf, "add %I %M", conf.laddr, conf.mask);
448 if(validip(conf.raddr)){
449 n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
450 if(conf.mtu != 0)
451 n += snprint(buf+n, sizeof buf-n, " %d",
452 conf.mtu);
453 }
454 write(conf.cfd, buf, n);
455 }
456 return 0;
457 }
458
459 static int
recvra6on(char * net,int conn)460 recvra6on(char *net, int conn)
461 {
462 Ipifc* ifc;
463
464 ifc = readipifc(net, nil, conn);
465 if (ifc == nil)
466 return 0;
467 else if (ifc->sendra6 > 0)
468 return IsRouter;
469 else if (ifc->recvra6 > 0)
470 return IsHostRecv;
471 else
472 return IsHostNoRecv;
473 }
474
475 /* send icmpv6 router solicitation to multicast address for all routers */
476 static void
sendrs(int fd)477 sendrs(int fd)
478 {
479 Routersol *rs;
480 uchar buff[sizeof *rs];
481
482 memset(buff, 0, sizeof buff);
483 rs = (Routersol *)buff;
484 memmove(rs->dst, v6allroutersL, IPaddrlen);
485 memmove(rs->src, v6Unspecified, IPaddrlen);
486 rs->type = ICMP6_RS;
487
488 if(write(fd, rs, sizeof buff) < sizeof buff)
489 ralog("sendrs: write failed, pkt size %d", sizeof buff);
490 else
491 ralog("sendrs: sent solicitation to %I from %I on %s",
492 rs->dst, rs->src, conf.dev);
493 }
494
495 /*
496 * a router receiving a router adv from another
497 * router calls this; it is basically supposed to
498 * log the information in the ra and raise a flag
499 * if any parameter value is different from its configured values.
500 *
501 * doing nothing for now since I don't know where to log this yet.
502 */
503 static void
recvrarouter(uchar buf[],int pktlen)504 recvrarouter(uchar buf[], int pktlen)
505 {
506 USED(buf, pktlen);
507 ralog("i am a router and got a router advert");
508 }
509
510 /* host receiving a router advertisement calls this */
511
512 static void
ewrite(int fd,char * str)513 ewrite(int fd, char *str)
514 {
515 int n;
516
517 n = strlen(str);
518 if (write(fd, str, n) != n)
519 ralog("write(%s) failed: %r", str);
520 }
521
522 static void
issuebasera6(Conf * cf)523 issuebasera6(Conf *cf)
524 {
525 char *cfg;
526
527 cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d "
528 "ttl %d routerlt %d",
529 cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra,
530 cf->ttl, cf->routerlt);
531 ewrite(cf->cfd, cfg);
532 free(cfg);
533 }
534
535 static void
issuerara6(Conf * cf)536 issuerara6(Conf *cf)
537 {
538 char *cfg;
539
540 cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d "
541 "linkmtu %d",
542 cf->sendra, cf->recvra, cf->maxraint, cf->minraint,
543 cf->linkmtu);
544 ewrite(cf->cfd, cfg);
545 free(cfg);
546 }
547
548 static void
issueadd6(Conf * cf)549 issueadd6(Conf *cf)
550 {
551 char *cfg;
552
553 cfg = smprint("add6 %I %d %d %d %lud %lud", cf->v6pref, cf->prefixlen,
554 cf->onlink, cf->autoflag, cf->validlt, cf->preflt);
555 ewrite(cf->cfd, cfg);
556 free(cfg);
557 }
558
559 static void
recvrahost(uchar buf[],int pktlen)560 recvrahost(uchar buf[], int pktlen)
561 {
562 int arpfd, m, n;
563 char abuf[100];
564 uchar optype;
565 Lladdropt *llao;
566 Mtuopt *mtuo;
567 Prefixopt *prfo;
568 Routeradv *ra;
569 static int first = 1;
570
571 ra = (Routeradv*)buf;
572 // memmove(conf.v6gaddr, ra->src, IPaddrlen);
573 conf.ttl = ra->cttl;
574 conf.mflag = (MFMASK & ra->mor);
575 conf.oflag = (OCMASK & ra->mor);
576 conf.routerlt = nhgets(ra->routerlt);
577 conf.reachtime = nhgetl(ra->rchbltime);
578 conf.rxmitra = nhgetl(ra->rxmtimer);
579
580 // issueadd6(&conf); /* for conf.v6gaddr? */
581 if (fprint(conf.cfd, "ra6 recvra 1") < 0)
582 ralog("write(ra6 recvra 1) failed: %r");
583 issuebasera6(&conf);
584
585 m = sizeof *ra;
586 while (pktlen - m > 0) {
587 optype = buf[m];
588 switch (optype) {
589 case V6nd_srclladdr:
590 llao = (Lladdropt *)&buf[m];
591 m += 8 * buf[m+1];
592 if (llao->len != 1) {
593 ralog("recvrahost: illegal len (%d) for source "
594 "link layer address option", llao->len);
595 return;
596 }
597 if (!ISIPV6LINKLOCAL(ra->src)) {
598 ralog("recvrahost: non-link-local src addr for "
599 "router adv %I", ra->src);
600 return;
601 }
602
603 snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
604 arpfd = open(abuf, OWRITE);
605 if (arpfd < 0) {
606 ralog("recvrahost: couldn't open %s to write: %r",
607 abuf);
608 return;
609 }
610
611 n = snprint(abuf, sizeof abuf, "add ether %I %E",
612 ra->src, llao->lladdr);
613 if (write(arpfd, abuf, n) < n)
614 ralog("recvrahost: couldn't write to %s/arp",
615 conf.mpoint);
616 close(arpfd);
617 break;
618 case V6nd_targlladdr:
619 case V6nd_redirhdr:
620 m += 8 * buf[m+1];
621 ralog("ignoring unexpected option type `%s' in Routeradv",
622 optname(optype));
623 break;
624 case V6nd_mtu:
625 mtuo = (Mtuopt*)&buf[m];
626 m += 8 * mtuo->len;
627 conf.linkmtu = nhgetl(mtuo->mtu);
628 break;
629 case V6nd_pfxinfo:
630 prfo = (Prefixopt*)&buf[m];
631 m += 8 * prfo->len;
632 if (prfo->len != 4) {
633 ralog("illegal len (%d) for prefix option",
634 prfo->len);
635 return;
636 }
637 memmove(conf.v6pref, prfo->pref, IPaddrlen);
638 conf.prefixlen = prfo->plen;
639 conf.onlink = ((prfo->lar & OLMASK) != 0);
640 conf.autoflag = ((prfo->lar & AFMASK) != 0);
641 conf.validlt = nhgetl(prfo->validlt);
642 conf.preflt = nhgetl(prfo->preflt);
643 issueadd6(&conf);
644 if (first) {
645 first = 0;
646 ralog("got initial RA from %I on %s; pfx %I",
647 ra->src, conf.dev, prfo->pref);
648 }
649 break;
650 default:
651 if (debug)
652 ralog("ignoring optype %d in Routeradv from %I",
653 optype, ra->src);
654 /* fall through */
655 case V6nd_srcaddrs:
656 /* netsbd sends this, so quietly ignore it for now */
657 m += 8 * buf[m+1];
658 break;
659 }
660 }
661 }
662
663 /*
664 * daemon to receive router advertisements from routers
665 */
666 void
recvra6(void)667 recvra6(void)
668 {
669 int fd, cfd, n, sendrscnt, sleepfor;
670 uchar buf[4096];
671
672 /* TODO: why not v6allroutersL? */
673 fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
674 if (fd < 0)
675 sysfatal("can't open icmp_ra connection: %r");
676
677 notify(catch);
678 sendrscnt = Maxv6rss;
679
680 switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
681 case -1:
682 sysfatal("can't fork: %r");
683 default:
684 return;
685 case 0:
686 break;
687 }
688
689 procsetname("recvra6 on %s", conf.dev);
690 ralog("recvra6 on %s", conf.dev);
691 sleepfor = jitter();
692 for (;;) {
693 /*
694 * We only get 3 (Maxv6rss) tries, so make sure we
695 * wait long enough to be certain that at least one RA
696 * will be transmitted.
697 */
698 if (sleepfor < 7000)
699 sleepfor = 7000;
700 alarm(sleepfor);
701 n = read(fd, buf, sizeof buf);
702 alarm(0);
703 if (n <= 0) {
704 if (sendrscnt > 0) {
705 sendrscnt--;
706 if (recvra6on(conf.mpoint, myifc) == IsHostRecv)
707 sendrs(fd);
708 sleepfor = V6rsintvl + nrand(100);
709 }
710 if (sendrscnt == 0) {
711 sendrscnt--;
712 sleepfor = 0;
713 ralog("recvra6: no router advs after %d sols on %s",
714 Maxv6rss, conf.dev);
715 }
716 continue;
717 }
718
719 sleepfor = 0;
720 sendrscnt = -1; /* got at least initial ra; no whining */
721 switch (recvra6on(conf.mpoint, myifc)) {
722 case IsRouter:
723 recvrarouter(buf, n);
724 break;
725 case IsHostRecv:
726 recvrahost(buf, n);
727 break;
728 case IsHostNoRecv:
729 ralog("recvra6: recvra off, quitting on %s", conf.dev);
730 close(fd);
731 exits(0);
732 default:
733 ralog("recvra6: unable to read router status on %s",
734 conf.dev);
735 break;
736 }
737 }
738 }
739
740 /*
741 * return -1 -- error, reading/writing some file,
742 * 0 -- no arp table updates
743 * 1 -- successful arp table update
744 */
745 int
recvrs(uchar * buf,int pktlen,uchar * sol)746 recvrs(uchar *buf, int pktlen, uchar *sol)
747 {
748 int n, optsz, arpfd;
749 char abuf[256];
750 Routersol *rs;
751 Lladdropt *llao;
752
753 rs = (Routersol *)buf;
754 n = sizeof *rs;
755 optsz = pktlen - n;
756 pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
757
758 if (optsz != sizeof *llao)
759 return 0;
760 if (buf[n] != V6nd_srclladdr || 8*buf[n+1] != sizeof *llao) {
761 ralog("rs opt err %s", abuf);
762 return -1;
763 }
764
765 ralog("rs recv %s", abuf);
766
767 if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
768 return 0;
769
770 snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
771 arpfd = open(abuf, OWRITE);
772 if (arpfd < 0) {
773 ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
774 return -1;
775 }
776
777 llao = (Lladdropt *)buf[n];
778 n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
779 if (write(arpfd, abuf, n) < n) {
780 ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
781 close(arpfd);
782 return -1;
783 }
784
785 memmove(sol, rs->src, IPaddrlen);
786 close(arpfd);
787 return 1;
788 }
789
790 void
sendra(int fd,uchar * dst,int rlt)791 sendra(int fd, uchar *dst, int rlt)
792 {
793 int pktsz, preflen;
794 char abuf[1024], tmp[40];
795 uchar buf[1024], macaddr[6], src[IPaddrlen];
796 Ipifc *ifc = nil;
797 Iplifc *lifc, *nlifc;
798 Lladdropt *llao;
799 Prefixopt *prfo;
800 Routeradv *ra;
801
802 memset(buf, 0, sizeof buf);
803 ra = (Routeradv *)buf;
804
805 myetheraddr(macaddr, conf.dev);
806 ea2lla(src, macaddr);
807 memmove(ra->src, src, IPaddrlen);
808 memmove(ra->dst, dst, IPaddrlen);
809 ra->type = ICMP6_RA;
810 ra->cttl = conf.ttl;
811
812 if (conf.mflag > 0)
813 ra->mor |= MFMASK;
814 if (conf.oflag > 0)
815 ra->mor |= OCMASK;
816 if (rlt > 0)
817 hnputs(ra->routerlt, conf.routerlt);
818 else
819 hnputs(ra->routerlt, 0);
820 hnputl(ra->rchbltime, conf.reachtime);
821 hnputl(ra->rxmtimer, conf.rxmitra);
822
823 pktsz = sizeof *ra;
824
825 /* include all global unicast prefixes on interface in prefix options */
826 ifc = readipifc(conf.mpoint, ifc, myifc);
827 for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
828 nlifc = lifc->next;
829 prfo = (Prefixopt *)(buf + pktsz);
830 /* global unicast address? */
831 if (!ISIPV6LINKLOCAL(lifc->ip) && !ISIPV6MCAST(lifc->ip) &&
832 memcmp(lifc->ip, IPnoaddr, IPaddrlen) != 0 &&
833 memcmp(lifc->ip, v6loopback, IPaddrlen) != 0 &&
834 !isv4(lifc->ip)) {
835 memmove(prfo->pref, lifc->net, IPaddrlen);
836
837 /* hack to find prefix length */
838 snprint(tmp, sizeof tmp, "%M", lifc->mask);
839 preflen = atoi(&tmp[1]);
840 prfo->plen = preflen & 0xff;
841 if (prfo->plen == 0)
842 continue;
843
844 prfo->type = V6nd_pfxinfo;
845 prfo->len = 4;
846 prfo->lar = AFMASK;
847 hnputl(prfo->validlt, lifc->validlt);
848 hnputl(prfo->preflt, lifc->preflt);
849 pktsz += sizeof *prfo;
850 }
851 }
852 /*
853 * include link layer address (mac address for now) in
854 * link layer address option
855 */
856 llao = (Lladdropt *)(buf + pktsz);
857 llao->type = V6nd_srclladdr;
858 llao->len = 1;
859 memmove(llao->lladdr, macaddr, sizeof macaddr);
860 pktsz += sizeof *llao;
861
862 pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
863 if(write(fd, buf, pktsz) < pktsz)
864 ralog("sendra fail %s: %r", abuf);
865 else if (debug)
866 ralog("sendra succ %s", abuf);
867 }
868
869 /*
870 * daemon to send router advertisements to hosts
871 */
872 void
sendra6(void)873 sendra6(void)
874 {
875 int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
876 long lastra, now;
877 uchar buf[4096], dst[IPaddrlen];
878 Ipifc *ifc = nil;
879
880 fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
881 if (fd < 0)
882 sysfatal("can't open icmp_rs connection: %r");
883
884 notify(catch);
885 sendracnt = Maxv6initras;
886 nquitmsgs = Maxv6finalras;
887
888 switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
889 case -1:
890 sysfatal("can't fork: %r");
891 default:
892 return;
893 case 0:
894 break;
895 }
896
897 procsetname("sendra6 on %s", conf.dev);
898 ralog("sendra6 on %s", conf.dev);
899 sleepfor = jitter();
900 for (;;) {
901 lastra = time(0);
902 if (sleepfor < 0)
903 sleepfor = 0;
904 alarm(sleepfor);
905 n = read(fd, buf, sizeof buf);
906 alarm(0);
907
908 ifc = readipifc(conf.mpoint, ifc, myifc);
909 if (ifc == nil) {
910 ralog("sendra6: can't read router params on %s",
911 conf.mpoint);
912 continue;
913 }
914
915 if (ifc->sendra6 <= 0)
916 if (nquitmsgs > 0) {
917 sendra(fd, v6allnodesL, 0);
918 nquitmsgs--;
919 sleepfor = Minv6interradelay + jitter();
920 continue;
921 } else {
922 ralog("sendra6: sendra off, quitting on %s",
923 conf.dev);
924 exits(0);
925 }
926
927 nquitmsgs = Maxv6finalras;
928
929 if (n <= 0) { /* no RS */
930 if (sendracnt > 0)
931 sendracnt--;
932 } else { /* respond to RS */
933 dstknown = recvrs(buf, n, dst);
934 now = time(0);
935
936 if (now - lastra < Minv6interradelay) {
937 /* too close, skip */
938 sleepfor = lastra + Minv6interradelay +
939 jitter() - now;
940 continue;
941 }
942 sleep(jitter());
943 }
944 sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint);
945 if (dstknown > 0)
946 sendra(fd, dst, 1);
947 else
948 sendra(fd, v6allnodesL, 1);
949 }
950 }
951
952 void
startra6(void)953 startra6(void)
954 {
955 static char routeon[] = "iprouting 1";
956
957 if (conf.recvra > 0)
958 recvra6();
959
960 if (conf.sendra > 0) {
961 if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
962 warning("write (iprouting 1) failed: %r");
963 return;
964 }
965 sendra6();
966 if (conf.recvra <= 0)
967 recvra6();
968 }
969 }
970
971 void
doipv6(int what)972 doipv6(int what)
973 {
974 nip = nipifcs(conf.mpoint);
975 if(!noconfig){
976 lookforip(conf.mpoint);
977 controldevice();
978 binddevice();
979 }
980
981 switch (what) {
982 default:
983 sysfatal("unknown IPv6 verb");
984 case Vaddpref6:
985 issueadd6(&conf);
986 break;
987 case Vra6:
988 issuebasera6(&conf);
989 issuerara6(&conf);
990 dolog = 1;
991 startra6();
992 break;
993 }
994 }
995