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 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 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 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 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 * 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* 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 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 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 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 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 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 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 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 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 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 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 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 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 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 ralog("ignoring optype %d in Routeradv from %I", 652 optype, ra->src); 653 /* fall through */ 654 case V6nd_srcaddrs: 655 /* netsbd sends this, so quietly ignore it for now */ 656 m += 8 * buf[m+1]; 657 break; 658 } 659 } 660 } 661 662 /* 663 * daemon to receive router advertisements from routers 664 */ 665 void 666 recvra6(void) 667 { 668 int fd, cfd, n, sendrscnt, sleepfor; 669 uchar buf[4096]; 670 671 /* TODO: why not v6allroutersL? */ 672 fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd); 673 if (fd < 0) 674 sysfatal("can't open icmp_ra connection: %r"); 675 676 notify(catch); 677 sendrscnt = Maxv6rss; 678 679 switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){ 680 case -1: 681 sysfatal("can't fork: %r"); 682 default: 683 return; 684 case 0: 685 break; 686 } 687 688 procsetname("recvra6 on %s", conf.dev); 689 ralog("recvra6 on %s", conf.dev); 690 sleepfor = jitter(); 691 for (;;) { 692 /* 693 * We only get 3 (Maxv6rss) tries, so make sure we 694 * wait long enough to be certain that at least one RA 695 * will be transmitted. 696 */ 697 if (sleepfor < 7000) 698 sleepfor = 7000; 699 alarm(sleepfor); 700 n = read(fd, buf, sizeof buf); 701 alarm(0); 702 if (n <= 0) { 703 if (sendrscnt > 0) { 704 sendrscnt--; 705 if (recvra6on(conf.mpoint, myifc) == IsHostRecv) 706 sendrs(fd); 707 sleepfor = V6rsintvl + nrand(100); 708 } 709 if (sendrscnt == 0) { 710 sendrscnt--; 711 sleepfor = 0; 712 ralog("recvra6: no router advs after %d sols on %s", 713 Maxv6rss, conf.dev); 714 } 715 continue; 716 } 717 718 sleepfor = 0; 719 sendrscnt = -1; /* got at least initial ra; no whining */ 720 switch (recvra6on(conf.mpoint, myifc)) { 721 case IsRouter: 722 recvrarouter(buf, n); 723 break; 724 case IsHostRecv: 725 recvrahost(buf, n); 726 break; 727 case IsHostNoRecv: 728 ralog("recvra6: recvra off, quitting on %s", conf.dev); 729 close(fd); 730 exits(0); 731 default: 732 ralog("recvra6: unable to read router status on %s", 733 conf.dev); 734 break; 735 } 736 } 737 } 738 739 /* 740 * return -1 -- error, reading/writing some file, 741 * 0 -- no arp table updates 742 * 1 -- successful arp table update 743 */ 744 int 745 recvrs(uchar *buf, int pktlen, uchar *sol) 746 { 747 int n, optsz, arpfd; 748 char abuf[256]; 749 Routersol *rs; 750 Lladdropt *llao; 751 752 rs = (Routersol *)buf; 753 n = sizeof *rs; 754 optsz = pktlen - n; 755 pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf)); 756 757 if (optsz != sizeof *llao) 758 return 0; 759 if (buf[n] != V6nd_srclladdr || 8*buf[n+1] != sizeof *llao) { 760 ralog("rs opt err %s", abuf); 761 return -1; 762 } 763 764 ralog("rs recv %s", abuf); 765 766 if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0) 767 return 0; 768 769 snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint); 770 arpfd = open(abuf, OWRITE); 771 if (arpfd < 0) { 772 ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint); 773 return -1; 774 } 775 776 llao = (Lladdropt *)buf[n]; 777 n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr); 778 if (write(arpfd, abuf, n) < n) { 779 ralog("recvrs: can't write to %s/arp: %r", conf.mpoint); 780 close(arpfd); 781 return -1; 782 } 783 784 memmove(sol, rs->src, IPaddrlen); 785 close(arpfd); 786 return 1; 787 } 788 789 void 790 sendra(int fd, uchar *dst, int rlt) 791 { 792 int pktsz, preflen; 793 char abuf[1024], tmp[40]; 794 uchar buf[1024], macaddr[6], src[IPaddrlen]; 795 Ipifc *ifc = nil; 796 Iplifc *lifc, *nlifc; 797 Lladdropt *llao; 798 Prefixopt *prfo; 799 Routeradv *ra; 800 801 memset(buf, 0, sizeof buf); 802 ra = (Routeradv *)buf; 803 804 myetheraddr(macaddr, conf.dev); 805 ea2lla(src, macaddr); 806 memmove(ra->src, src, IPaddrlen); 807 memmove(ra->dst, dst, IPaddrlen); 808 ra->type = ICMP6_RA; 809 ra->cttl = conf.ttl; 810 811 if (conf.mflag > 0) 812 ra->mor |= MFMASK; 813 if (conf.oflag > 0) 814 ra->mor |= OCMASK; 815 if (rlt > 0) 816 hnputs(ra->routerlt, conf.routerlt); 817 else 818 hnputs(ra->routerlt, 0); 819 hnputl(ra->rchbltime, conf.reachtime); 820 hnputl(ra->rxmtimer, conf.rxmitra); 821 822 pktsz = sizeof *ra; 823 824 /* include all global unicast prefixes on interface in prefix options */ 825 ifc = readipifc(conf.mpoint, ifc, myifc); 826 for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) { 827 nlifc = lifc->next; 828 prfo = (Prefixopt *)(buf + pktsz); 829 /* global unicast address? */ 830 if (!ISIPV6LINKLOCAL(lifc->ip) && !ISIPV6MCAST(lifc->ip) && 831 memcmp(lifc->ip, IPnoaddr, IPaddrlen) != 0 && 832 memcmp(lifc->ip, v6loopback, IPaddrlen) != 0 && 833 !isv4(lifc->ip)) { 834 memmove(prfo->pref, lifc->net, IPaddrlen); 835 836 /* hack to find prefix length */ 837 snprint(tmp, sizeof tmp, "%M", lifc->mask); 838 preflen = atoi(&tmp[1]); 839 prfo->plen = preflen & 0xff; 840 if (prfo->plen == 0) 841 continue; 842 843 prfo->type = V6nd_pfxinfo; 844 prfo->len = 4; 845 prfo->lar = AFMASK; 846 hnputl(prfo->validlt, lifc->validlt); 847 hnputl(prfo->preflt, lifc->preflt); 848 pktsz += sizeof *prfo; 849 } 850 } 851 /* 852 * include link layer address (mac address for now) in 853 * link layer address option 854 */ 855 llao = (Lladdropt *)(buf + pktsz); 856 llao->type = V6nd_srclladdr; 857 llao->len = 1; 858 memmove(llao->lladdr, macaddr, sizeof macaddr); 859 pktsz += sizeof *llao; 860 861 pkt2str(buf+40, buf+pktsz, abuf, abuf+1024); 862 if(write(fd, buf, pktsz) < pktsz) 863 ralog("sendra fail %s: %r", abuf); 864 else if (debug) 865 ralog("sendra succ %s", abuf); 866 } 867 868 /* 869 * daemon to send router advertisements to hosts 870 */ 871 void 872 sendra6(void) 873 { 874 int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs; 875 long lastra, now; 876 uchar buf[4096], dst[IPaddrlen]; 877 Ipifc *ifc = nil; 878 879 fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd); 880 if (fd < 0) 881 sysfatal("can't open icmp_rs connection: %r"); 882 883 notify(catch); 884 sendracnt = Maxv6initras; 885 nquitmsgs = Maxv6finalras; 886 887 switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){ 888 case -1: 889 sysfatal("can't fork: %r"); 890 default: 891 return; 892 case 0: 893 break; 894 } 895 896 procsetname("sendra6 on %s", conf.dev); 897 ralog("sendra6 on %s", conf.dev); 898 sleepfor = jitter(); 899 for (;;) { 900 lastra = time(0); 901 if (sleepfor < 0) 902 sleepfor = 0; 903 alarm(sleepfor); 904 n = read(fd, buf, sizeof buf); 905 alarm(0); 906 907 ifc = readipifc(conf.mpoint, ifc, myifc); 908 if (ifc == nil) { 909 ralog("sendra6: can't read router params on %s", 910 conf.mpoint); 911 continue; 912 } 913 914 if (ifc->sendra6 <= 0) 915 if (nquitmsgs > 0) { 916 sendra(fd, v6allnodesL, 0); 917 nquitmsgs--; 918 sleepfor = Minv6interradelay + jitter(); 919 continue; 920 } else { 921 ralog("sendra6: sendra off, quitting on %s", 922 conf.dev); 923 exits(0); 924 } 925 926 nquitmsgs = Maxv6finalras; 927 928 if (n <= 0) { /* no RS */ 929 if (sendracnt > 0) 930 sendracnt--; 931 } else { /* respond to RS */ 932 dstknown = recvrs(buf, n, dst); 933 now = time(0); 934 935 if (now - lastra < Minv6interradelay) { 936 /* too close, skip */ 937 sleepfor = lastra + Minv6interradelay + 938 jitter() - now; 939 continue; 940 } 941 sleep(jitter()); 942 } 943 sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint); 944 if (dstknown > 0) 945 sendra(fd, dst, 1); 946 else 947 sendra(fd, v6allnodesL, 1); 948 } 949 } 950 951 void 952 startra6(void) 953 { 954 static char routeon[] = "iprouting 1"; 955 956 if (conf.recvra > 0) 957 recvra6(); 958 959 if (conf.sendra > 0) { 960 if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) { 961 warning("write (iprouting 1) failed: %r"); 962 return; 963 } 964 sendra6(); 965 if (conf.recvra <= 0) 966 recvra6(); 967 } 968 } 969 970 void 971 doipv6(int what) 972 { 973 nip = nipifcs(conf.mpoint); 974 if(!noconfig){ 975 lookforip(conf.mpoint); 976 controldevice(); 977 binddevice(); 978 } 979 980 switch (what) { 981 default: 982 sysfatal("unknown IPv6 verb"); 983 case Vaddpref6: 984 issueadd6(&conf); 985 break; 986 case Vra6: 987 issuebasera6(&conf); 988 issuerara6(&conf); 989 dolog = 1; 990 startra6(); 991 break; 992 } 993 } 994