1 /* 2 * ipconfig - configure parameters of an ip stack 3 */ 4 #include <u.h> 5 #include <libc.h> 6 #include <ip.h> 7 #include <bio.h> 8 #include <ndb.h> 9 #include "../dhcp.h" 10 #include "ipconfig.h" 11 12 #define DEBUG if(debug)warning 13 14 /* possible verbs */ 15 enum 16 { 17 /* commands */ 18 Vadd, 19 Vremove, 20 Vunbind, 21 Vaddpref6, 22 Vra6, 23 /* media */ 24 Vether, 25 Vgbe, 26 Vppp, 27 Vloopback, 28 Vtorus, 29 Vtree, 30 }; 31 32 enum 33 { 34 Taddr, 35 Taddrs, 36 Tstr, 37 Tbyte, 38 Tulong, 39 Tvec, 40 }; 41 42 typedef struct Option Option; 43 struct Option 44 { 45 char *name; 46 int type; 47 }; 48 49 /* 50 * I was too lazy to look up the types for each of these 51 * options. If someone feels like it, please mail me a 52 * corrected array -- presotto 53 */ 54 Option option[256] = 55 { 56 [OBmask] { "ipmask", Taddr }, 57 [OBtimeoff] { "timeoff", Tulong }, 58 [OBrouter] { "ipgw", Taddrs }, 59 [OBtimeserver] { "time", Taddrs }, 60 [OBnameserver] { "name", Taddrs }, 61 [OBdnserver] { "dns", Taddrs }, 62 [OBlogserver] { "log", Taddrs }, 63 [OBcookieserver] { "cookie", Taddrs }, 64 [OBlprserver] { "lpr", Taddrs }, 65 [OBimpressserver] { "impress", Taddrs }, 66 [OBrlserver] { "rl", Taddrs }, 67 [OBhostname] { "sys", Tstr }, 68 [OBbflen] { "bflen", Tulong }, 69 [OBdumpfile] { "dumpfile", Tstr }, 70 [OBdomainname] { "dom", Tstr }, 71 [OBswapserver] { "swap", Taddrs }, 72 [OBrootpath] { "rootpath", Tstr }, 73 [OBextpath] { "extpath", Tstr }, 74 [OBipforward] { "ipforward", Taddrs }, 75 [OBnonlocal] { "nonlocal", Taddrs }, 76 [OBpolicyfilter] { "policyfilter", Taddrs }, 77 [OBmaxdatagram] { "maxdatagram", Tulong }, 78 [OBttl] { "ttl", Tulong }, 79 [OBpathtimeout] { "pathtimeout", Taddrs }, 80 [OBpathplateau] { "pathplateau", Taddrs }, 81 [OBmtu] { "mtu", Tulong }, 82 [OBsubnetslocal] { "subnetslocal", Taddrs }, 83 [OBbaddr] { "baddr", Taddrs }, 84 [OBdiscovermask] { "discovermask", Taddrs }, 85 [OBsupplymask] { "supplymask", Taddrs }, 86 [OBdiscoverrouter] { "discoverrouter", Taddrs }, 87 [OBrsserver] { "rs", Taddrs }, 88 [OBstaticroutes] { "staticroutes", Taddrs }, 89 [OBtrailerencap] { "trailerencap", Taddrs }, 90 [OBarptimeout] { "arptimeout", Tulong }, 91 [OBetherencap] { "etherencap", Taddrs }, 92 [OBtcpttl] { "tcpttl", Tulong }, 93 [OBtcpka] { "tcpka", Tulong }, 94 [OBtcpkag] { "tcpkag", Tulong }, 95 [OBnisdomain] { "nisdomain", Tstr }, 96 [OBniserver] { "ni", Taddrs }, 97 [OBntpserver] { "ntp", Taddrs }, 98 [OBnetbiosns] { "netbiosns", Taddrs }, 99 [OBnetbiosdds] { "netbiosdds", Taddrs }, 100 [OBnetbiostype] { "netbiostype", Taddrs }, 101 [OBnetbiosscope] { "netbiosscope", Taddrs }, 102 [OBxfontserver] { "xfont", Taddrs }, 103 [OBxdispmanager] { "xdispmanager", Taddrs }, 104 [OBnisplusdomain] { "nisplusdomain", Tstr }, 105 [OBnisplusserver] { "nisplus", Taddrs }, 106 [OBhomeagent] { "homeagent", Taddrs }, 107 [OBsmtpserver] { "smtp", Taddrs }, 108 [OBpop3server] { "pop3", Taddrs }, 109 [OBnntpserver] { "nntp", Taddrs }, 110 [OBwwwserver] { "www", Taddrs }, 111 [OBfingerserver] { "finger", Taddrs }, 112 [OBircserver] { "irc", Taddrs }, 113 [OBstserver] { "st", Taddrs }, 114 [OBstdaserver] { "stdar", Taddrs }, 115 116 [ODipaddr] { "ipaddr", Taddr }, 117 [ODlease] { "lease", Tulong }, 118 [ODoverload] { "overload", Taddr }, 119 [ODtype] { "type", Tbyte }, 120 [ODserverid] { "serverid", Taddr }, 121 [ODparams] { "params", Tvec }, 122 [ODmessage] { "message", Tstr }, 123 [ODmaxmsg] { "maxmsg", Tulong }, 124 [ODrenewaltime] { "renewaltime", Tulong }, 125 [ODrebindingtime] { "rebindingtime", Tulong }, 126 [ODvendorclass] { "vendorclass", Tvec }, 127 [ODclientid] { "clientid", Tvec }, 128 [ODtftpserver] { "tftp", Taddr }, 129 [ODbootfile] { "bootfile", Tstr }, 130 }; 131 132 uchar defrequested[] = { 133 OBmask, OBrouter, OBdnserver, OBhostname, OBdomainname, OBntpserver, 134 }; 135 136 uchar requested[256]; 137 int nrequested; 138 139 int Oflag; 140 int beprimary = -1; 141 Conf conf; 142 int debug; 143 int dodhcp; 144 int dolog; 145 int dondbconfig = 0; 146 int dupl_disc = 1; /* flag: V6 duplicate neighbor discovery */ 147 Ctl *firstctl, **ctll; 148 Ipifc *ifc; 149 int ipv6auto = 0; 150 int myifc = -1; 151 char *ndboptions; 152 int nip; 153 int noconfig; 154 int nodhcpwatch; 155 char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 }; 156 int plan9 = 1; 157 int sendhostname; 158 159 static char logfile[] = "ipconfig"; 160 161 char *verbs[] = { 162 [Vadd] "add", 163 [Vremove] "remove", 164 [Vunbind] "unbind", 165 [Vether] "ether", 166 [Vgbe] "gbe", 167 [Vppp] "ppp", 168 [Vloopback] "loopback", 169 [Vaddpref6] "add6", 170 [Vra6] "ra6", 171 [Vtorus] "torus", 172 [Vtree] "tree", 173 }; 174 175 void adddefroute(char*, uchar*); 176 int addoption(char*); 177 void binddevice(void); 178 void bootprequest(void); 179 void controldevice(void); 180 void dhcpquery(int, int); 181 void dhcprecv(void); 182 void dhcpsend(int); 183 int dhcptimer(void); 184 void dhcpwatch(int); 185 void doadd(int); 186 void doremove(void); 187 void dounbind(void); 188 int getndb(void); 189 void getoptions(uchar*); 190 int ip4cfg(void); 191 int ip6cfg(int a); 192 void lookforip(char*); 193 void mkclientid(void); 194 void ndbconfig(void); 195 int nipifcs(char*); 196 int openlisten(void); 197 uchar* optaddaddr(uchar*, int, uchar*); 198 uchar* optaddbyte(uchar*, int, int); 199 uchar* optaddstr(uchar*, int, char*); 200 uchar* optadd(uchar*, int, void*, int); 201 uchar* optaddulong(uchar*, int, ulong); 202 uchar* optaddvec(uchar*, int, uchar*, int); 203 int optgetaddrs(uchar*, int, uchar*, int); 204 int optgetp9addrs(uchar*, int, uchar*, int); 205 int optgetaddr(uchar*, int, uchar*); 206 int optgetbyte(uchar*, int); 207 int optgetstr(uchar*, int, char*, int); 208 uchar* optget(uchar*, int, int*); 209 ulong optgetulong(uchar*, int); 210 int optgetvec(uchar*, int, uchar*, int); 211 char* optgetx(uchar*, uchar); 212 Bootp* parsebootp(uchar*, int); 213 int parseoptions(uchar *p, int n); 214 int parseverb(char*); 215 void pppbinddev(void); 216 void putndb(void); 217 void tweakservers(void); 218 void usage(void); 219 int validip(uchar*); 220 void writendb(char*, int, int); 221 222 void 223 usage(void) 224 { 225 fprint(2, "usage: %s [-6dDGnNOpPruX][-b baud][-c ctl]* [-g gw]" 226 "[-h host][-m mtu]\n" 227 "\t[-x mtpt][-o dhcpopt] type dev [verb] [laddr [mask " 228 "[raddr [fs [auth]]]]]\n", argv0); 229 exits("usage"); 230 } 231 232 void 233 warning(char *fmt, ...) 234 { 235 char buf[1024]; 236 va_list arg; 237 238 va_start(arg, fmt); 239 vseprint(buf, buf + sizeof buf, fmt, arg); 240 va_end(arg); 241 if (dolog) 242 syslog(0, logfile, "%s", buf); 243 else 244 fprint(2, "%s: %s\n", argv0, buf); 245 } 246 247 static void 248 parsenorm(int argc, char **argv) 249 { 250 switch(argc){ 251 case 5: 252 if (parseip(conf.auth, argv[4]) == -1) 253 usage(); 254 /* fall through */ 255 case 4: 256 if (parseip(conf.fs, argv[3]) == -1) 257 usage(); 258 /* fall through */ 259 case 3: 260 if (parseip(conf.raddr, argv[2]) == -1) 261 usage(); 262 /* fall through */ 263 case 2: 264 /* 265 * can't test for parseipmask()==-1 cuz 255.255.255.255 266 * looks like that. 267 */ 268 if (strcmp(argv[1], "0") != 0) 269 parseipmask(conf.mask, argv[1]); 270 /* fall through */ 271 case 1: 272 if (parseip(conf.laddr, argv[0]) == -1) 273 usage(); 274 /* fall through */ 275 case 0: 276 break; 277 default: 278 usage(); 279 } 280 } 281 282 static void 283 parse6pref(int argc, char **argv) 284 { 285 switch(argc){ 286 case 6: 287 conf.preflt = strtoul(argv[5], 0, 10); 288 /* fall through */ 289 case 5: 290 conf.validlt = strtoul(argv[4], 0, 10); 291 /* fall through */ 292 case 4: 293 conf.autoflag = (atoi(argv[3]) != 0); 294 /* fall through */ 295 case 3: 296 conf.onlink = (atoi(argv[2]) != 0); 297 /* fall through */ 298 case 2: 299 conf.prefixlen = atoi(argv[1]); 300 /* fall through */ 301 case 1: 302 parseip(conf.v6pref, argv[0]); 303 break; 304 } 305 DEBUG("parse6pref: pref %I len %d", conf.v6pref, conf.prefixlen); 306 } 307 308 /* parse router advertisement (keyword, value) pairs */ 309 static void 310 parse6ra(int argc, char **argv) 311 { 312 int i, argsleft; 313 char *kw, *val; 314 315 if (argc % 2 != 0) 316 usage(); 317 318 i = 0; 319 for (argsleft = argc; argsleft > 1; argsleft -= 2) { 320 kw = argv[i]; 321 val = argv[i+1]; 322 if (strcmp(kw, "recvra") == 0) 323 conf.recvra = (atoi(val) != 0); 324 else if (strcmp(kw, "sendra") == 0) 325 conf.sendra = (atoi(val) != 0); 326 else if (strcmp(kw, "mflag") == 0) 327 conf.mflag = (atoi(val) != 0); 328 else if (strcmp(kw, "oflag") == 0) 329 conf.oflag = (atoi(val) != 0); 330 else if (strcmp(kw, "maxraint") == 0) 331 conf.maxraint = atoi(val); 332 else if (strcmp(kw, "minraint") == 0) 333 conf.minraint = atoi(val); 334 else if (strcmp(kw, "linkmtu") == 0) 335 conf.linkmtu = atoi(val); 336 else if (strcmp(kw, "reachtime") == 0) 337 conf.reachtime = atoi(val); 338 else if (strcmp(kw, "rxmitra") == 0) 339 conf.rxmitra = atoi(val); 340 else if (strcmp(kw, "ttl") == 0) 341 conf.ttl = atoi(val); 342 else if (strcmp(kw, "routerlt") == 0) 343 conf.routerlt = atoi(val); 344 else { 345 warning("bad ra6 keyword %s", kw); 346 usage(); 347 } 348 i += 2; 349 } 350 351 /* consistency check */ 352 if (conf.maxraint < conf.minraint) 353 sysfatal("maxraint %d < minraint %d", 354 conf.maxraint, conf.minraint); 355 } 356 357 static void 358 init(void) 359 { 360 srand(truerand()); 361 fmtinstall('E', eipfmt); 362 fmtinstall('I', eipfmt); 363 fmtinstall('M', eipfmt); 364 fmtinstall('V', eipfmt); 365 nsec(); /* make sure time file is open before forking */ 366 367 setnetmtpt(conf.mpoint, sizeof conf.mpoint, nil); 368 conf.cputype = getenv("cputype"); 369 if(conf.cputype == nil) 370 conf.cputype = "386"; 371 372 ctll = &firstctl; 373 v6paraminit(&conf); 374 375 /* init set of requested dhcp parameters with the default */ 376 nrequested = sizeof defrequested; 377 memcpy(requested, defrequested, nrequested); 378 } 379 380 static int 381 parseargs(int argc, char **argv) 382 { 383 char *p; 384 int action, verb; 385 386 /* default to any host name we already have */ 387 if(*conf.hostname == 0){ 388 p = getenv("sysname"); 389 if(p == nil || *p == 0) 390 p = sysname(); 391 if(p != nil) 392 strncpy(conf.hostname, p, sizeof conf.hostname-1); 393 } 394 395 /* defaults */ 396 conf.type = "ether"; 397 conf.dev = "/net/ether0"; 398 action = Vadd; 399 400 /* get optional medium and device */ 401 if (argc > 0){ 402 verb = parseverb(*argv); 403 switch(verb){ 404 case Vether: 405 case Vgbe: 406 case Vppp: 407 case Vloopback: 408 case Vtorus: 409 case Vtree: 410 conf.type = *argv++; 411 argc--; 412 if(argc > 0){ 413 conf.dev = *argv++; 414 argc--; 415 } else if(verb == Vppp) 416 conf.dev = "/dev/eia0"; 417 break; 418 } 419 } 420 421 /* get optional verb */ 422 if (argc > 0){ 423 verb = parseverb(*argv); 424 switch(verb){ 425 case Vether: 426 case Vgbe: 427 case Vppp: 428 case Vloopback: 429 case Vtorus: 430 case Vtree: 431 sysfatal("medium %s already specified", conf.type); 432 case Vadd: 433 case Vremove: 434 case Vunbind: 435 case Vaddpref6: 436 case Vra6: 437 argv++; 438 argc--; 439 action = verb; 440 break; 441 } 442 } 443 444 /* get verb-dependent arguments */ 445 switch (action) { 446 case Vadd: 447 case Vremove: 448 case Vunbind: 449 parsenorm(argc, argv); 450 break; 451 case Vaddpref6: 452 parse6pref(argc, argv); 453 break; 454 case Vra6: 455 parse6ra(argc, argv); 456 break; 457 } 458 return action; 459 } 460 461 void 462 main(int argc, char **argv) 463 { 464 int retry, action; 465 Ctl *cp; 466 467 init(); 468 retry = 0; 469 ARGBEGIN { 470 case '6': /* IPv6 auto config */ 471 ipv6auto = 1; 472 break; 473 case 'b': 474 conf.baud = EARGF(usage()); 475 break; 476 case 'c': 477 cp = malloc(sizeof *cp); 478 if(cp == nil) 479 sysfatal("%r"); 480 *ctll = cp; 481 ctll = &cp->next; 482 cp->next = nil; 483 cp->ctl = EARGF(usage()); 484 break; 485 case 'd': 486 dodhcp = 1; 487 break; 488 case 'D': 489 debug = 1; 490 break; 491 case 'g': 492 if (parseip(conf.gaddr, EARGF(usage())) == -1) 493 usage(); 494 break; 495 case 'G': 496 plan9 = 0; 497 break; 498 case 'h': 499 snprint(conf.hostname, sizeof conf.hostname, "%s", 500 EARGF(usage())); 501 sendhostname = 1; 502 break; 503 case 'm': 504 conf.mtu = atoi(EARGF(usage())); 505 break; 506 case 'n': 507 noconfig = 1; 508 break; 509 case 'N': 510 dondbconfig = 1; 511 break; 512 case 'o': 513 if(addoption(EARGF(usage())) < 0) 514 usage(); 515 break; 516 case 'O': 517 Oflag = 1; 518 break; 519 case 'p': 520 beprimary = 1; 521 break; 522 case 'P': 523 beprimary = 0; 524 break; 525 case 'r': 526 retry = 1; 527 break; 528 case 'u': /* IPv6: duplicate neighbour disc. off */ 529 dupl_disc = 0; 530 break; 531 case 'x': 532 setnetmtpt(conf.mpoint, sizeof conf.mpoint, EARGF(usage())); 533 break; 534 case 'X': 535 nodhcpwatch = 1; 536 break; 537 default: 538 usage(); 539 } ARGEND; 540 argv0 = "ipconfig"; /* boot invokes us as tcp? */ 541 542 action = parseargs(argc, argv); 543 switch(action){ 544 case Vadd: 545 doadd(retry); 546 break; 547 case Vremove: 548 doremove(); 549 break; 550 case Vunbind: 551 dounbind(); 552 break; 553 case Vaddpref6: 554 case Vra6: 555 doipv6(action); 556 break; 557 } 558 exits(0); 559 } 560 561 int 562 havendb(char *net) 563 { 564 Dir *d; 565 char buf[128]; 566 567 snprint(buf, sizeof buf, "%s/ndb", net); 568 if((d = dirstat(buf)) == nil) 569 return 0; 570 if(d->length == 0){ 571 free(d); 572 return 0; 573 } 574 free(d); 575 return 1; 576 } 577 578 void 579 doadd(int retry) 580 { 581 int tries, ppp; 582 583 ppp = strcmp(conf.type, "ppp") == 0; 584 585 /* get number of preexisting interfaces */ 586 nip = nipifcs(conf.mpoint); 587 if(beprimary == -1 && (nip == 0 || !havendb(conf.mpoint))) 588 beprimary = 1; 589 590 /* get ipifc into name space and condition device for ip */ 591 if(!noconfig){ 592 lookforip(conf.mpoint); 593 controldevice(); 594 binddevice(); 595 } 596 597 if (ipv6auto && !ppp) { 598 if (ip6cfg(ipv6auto) < 0) 599 sysfatal("can't automatically start IPv6 on %s", 600 conf.dev); 601 // return; 602 } else if (validip(conf.laddr) && !isv4(conf.laddr)) { 603 if (ip6cfg(0) < 0) 604 sysfatal("can't start IPv6 on %s, address %I", 605 conf.dev, conf.laddr); 606 // return; 607 } 608 609 if(!validip(conf.laddr) && !ppp) 610 if(dondbconfig) 611 ndbconfig(); 612 else 613 dodhcp = 1; 614 615 /* run dhcp if we need something */ 616 if(dodhcp){ 617 mkclientid(); 618 for(tries = 0; tries < 6; tries++){ 619 dhcpquery(!noconfig, Sselecting); 620 if(conf.state == Sbound) 621 break; 622 sleep(1000); 623 } 624 } 625 626 if(!validip(conf.laddr)) 627 if(retry && dodhcp && !noconfig){ 628 warning("couldn't determine ip address, retrying"); 629 dhcpwatch(1); 630 return; 631 } else 632 sysfatal("no success with DHCP"); 633 634 if(!noconfig) 635 if(ip4cfg() < 0) 636 sysfatal("can't start ip"); 637 else if(dodhcp && conf.lease != Lforever) 638 dhcpwatch(0); 639 640 /* leave everything we've learned somewhere other procs can find it */ 641 if(beprimary == 1){ 642 putndb(); 643 tweakservers(); 644 } 645 } 646 647 void 648 doremove(void) 649 { 650 char file[128]; 651 int cfd; 652 Ipifc *nifc; 653 Iplifc *lifc; 654 655 if(!validip(conf.laddr)) 656 sysfatal("remove requires an address"); 657 ifc = readipifc(conf.mpoint, ifc, -1); 658 for(nifc = ifc; nifc != nil; nifc = nifc->next){ 659 if(strcmp(nifc->dev, conf.dev) != 0) 660 continue; 661 for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next){ 662 if(ipcmp(conf.laddr, lifc->ip) != 0) 663 continue; 664 if (validip(conf.mask) && 665 ipcmp(conf.mask, lifc->mask) != 0) 666 continue; 667 if (validip(conf.raddr) && 668 ipcmp(conf.raddr, lifc->net) != 0) 669 continue; 670 671 snprint(file, sizeof file, "%s/ipifc/%d/ctl", 672 conf.mpoint, nifc->index); 673 cfd = open(file, ORDWR); 674 if(cfd < 0){ 675 warning("can't open %s: %r", conf.mpoint); 676 continue; 677 } 678 if(fprint(cfd, "remove %I %M", lifc->ip, lifc->mask) < 0) 679 warning("can't remove %I %M from %s: %r", 680 lifc->ip, lifc->mask, file); 681 } 682 } 683 } 684 685 void 686 dounbind(void) 687 { 688 Ipifc *nifc; 689 char file[128]; 690 int cfd; 691 692 ifc = readipifc(conf.mpoint, ifc, -1); 693 for(nifc = ifc; nifc != nil; nifc = nifc->next){ 694 if(strcmp(nifc->dev, conf.dev) == 0){ 695 snprint(file, sizeof file, "%s/ipifc/%d/ctl", 696 conf.mpoint, nifc->index); 697 cfd = open(file, ORDWR); 698 if(cfd < 0){ 699 warning("can't open %s: %r", conf.mpoint); 700 break; 701 } 702 if(fprint(cfd, "unbind") < 0) 703 warning("can't unbind from %s: %r", file); 704 break; 705 } 706 } 707 } 708 709 /* set the default route */ 710 void 711 adddefroute(char *mpoint, uchar *gaddr) 712 { 713 char buf[256]; 714 int cfd; 715 716 sprint(buf, "%s/iproute", mpoint); 717 cfd = open(buf, ORDWR); 718 if(cfd < 0) 719 return; 720 if(isv4(gaddr)) 721 fprint(cfd, "add 0 0 %I", gaddr); 722 else 723 fprint(cfd, "add :: /0 %I", gaddr); 724 close(cfd); 725 } 726 727 /* create a client id */ 728 void 729 mkclientid(void) 730 { 731 if(strcmp(conf.type, "ether") == 0 || strcmp(conf.type, "gbe") == 0) 732 if(myetheraddr(conf.hwa, conf.dev) == 0){ 733 conf.hwalen = 6; 734 conf.hwatype = 1; 735 conf.cid[0] = conf.hwatype; 736 memmove(&conf.cid[1], conf.hwa, conf.hwalen); 737 conf.cidlen = conf.hwalen+1; 738 } else { 739 conf.hwatype = -1; 740 snprint((char*)conf.cid, sizeof conf.cid, 741 "plan9_%ld.%d", lrand(), getpid()); 742 conf.cidlen = strlen((char*)conf.cid); 743 } 744 } 745 746 /* bind ip into the namespace */ 747 void 748 lookforip(char *net) 749 { 750 char proto[64]; 751 752 snprint(proto, sizeof proto, "%s/ipifc", net); 753 if(access(proto, 0) == 0) 754 return; 755 sysfatal("no ip stack bound onto %s", net); 756 } 757 758 /* send some ctls to a device */ 759 void 760 controldevice(void) 761 { 762 char ctlfile[256]; 763 int fd; 764 Ctl *cp; 765 766 if (firstctl == nil || 767 strcmp(conf.type, "ether") != 0 && strcmp(conf.type, "gbe") != 0) 768 return; 769 770 snprint(ctlfile, sizeof ctlfile, "%s/clone", conf.dev); 771 fd = open(ctlfile, ORDWR); 772 if(fd < 0) 773 sysfatal("can't open %s", ctlfile); 774 775 for(cp = firstctl; cp != nil; cp = cp->next){ 776 if(write(fd, cp->ctl, strlen(cp->ctl)) < 0) 777 sysfatal("ctl message %s: %r", cp->ctl); 778 seek(fd, 0, 0); 779 } 780 // close(fd); /* or does it need to be left hanging? */ 781 } 782 783 /* bind an ip stack to a device, leave the control channel open */ 784 void 785 binddevice(void) 786 { 787 char buf[256]; 788 789 if(strcmp(conf.type, "ppp") == 0) 790 pppbinddev(); 791 else if(myifc < 0){ 792 /* get a new ip interface */ 793 snprint(buf, sizeof buf, "%s/ipifc/clone", conf.mpoint); 794 conf.cfd = open(buf, ORDWR); 795 if(conf.cfd < 0) 796 sysfatal("opening %s/ipifc/clone: %r", conf.mpoint); 797 798 /* specify medium as ethernet, bind the interface to it */ 799 if(fprint(conf.cfd, "bind %s %s", conf.type, conf.dev) < 0) 800 sysfatal("%s: bind %s %s: %r", buf, conf.type, conf.dev); 801 } else { 802 /* open the old interface */ 803 snprint(buf, sizeof buf, "%s/ipifc/%d/ctl", conf.mpoint, myifc); 804 conf.cfd = open(buf, ORDWR); 805 if(conf.cfd < 0) 806 sysfatal("open %s: %r", buf); 807 } 808 809 } 810 811 /* add a logical interface to the ip stack */ 812 int 813 ip4cfg(void) 814 { 815 char buf[256]; 816 int n; 817 818 if(!validip(conf.laddr)) 819 return -1; 820 821 n = sprint(buf, "add"); 822 n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr); 823 824 if(!validip(conf.mask)) 825 ipmove(conf.mask, defmask(conf.laddr)); 826 n += snprint(buf+n, sizeof buf-n, " %I", conf.mask); 827 828 if(validip(conf.raddr)){ 829 n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr); 830 if(conf.mtu != 0) 831 n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu); 832 } 833 834 if(write(conf.cfd, buf, n) < 0){ 835 warning("write(%s): %r", buf); 836 return -1; 837 } 838 839 if(beprimary==1 && validip(conf.gaddr)) 840 adddefroute(conf.mpoint, conf.gaddr); 841 842 return 0; 843 } 844 845 /* remove a logical interface to the ip stack */ 846 void 847 ipunconfig(void) 848 { 849 char buf[256]; 850 int n; 851 852 if(!validip(conf.laddr)) 853 return; 854 DEBUG("couldn't renew IP lease, releasing %I", conf.laddr); 855 n = sprint(buf, "remove"); 856 n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr); 857 858 if(!validip(conf.mask)) 859 ipmove(conf.mask, defmask(conf.laddr)); 860 n += snprint(buf+n, sizeof buf-n, " %I", conf.mask); 861 862 write(conf.cfd, buf, n); 863 864 ipmove(conf.laddr, IPnoaddr); 865 ipmove(conf.raddr, IPnoaddr); 866 ipmove(conf.mask, IPnoaddr); 867 868 /* forget configuration info */ 869 if(beprimary==1) 870 writendb("", 0, 0); 871 } 872 873 void 874 ding(void*, char *msg) 875 { 876 if(strstr(msg, "alarm")) 877 noted(NCONT); 878 noted(NDFLT); 879 } 880 881 void 882 dhcpquery(int needconfig, int startstate) 883 { 884 if(needconfig) 885 fprint(conf.cfd, "add %I %I", IPnoaddr, IPnoaddr); 886 887 conf.fd = openlisten(); 888 if(conf.fd < 0){ 889 conf.state = Sinit; 890 return; 891 } 892 notify(ding); 893 894 /* try dhcp for 10 seconds */ 895 conf.xid = lrand(); 896 conf.starttime = time(0); 897 conf.state = startstate; 898 switch(startstate){ 899 case Sselecting: 900 conf.offered = 0; 901 dhcpsend(Discover); 902 break; 903 case Srenewing: 904 dhcpsend(Request); 905 break; 906 default: 907 sysfatal("internal error 0"); 908 } 909 conf.resend = 0; 910 conf.timeout = time(0) + 4; 911 912 while(conf.state != Sbound){ 913 dhcprecv(); 914 if(dhcptimer() < 0) 915 break; 916 if(time(0) - conf.starttime > 10) 917 break; 918 } 919 close(conf.fd); 920 921 if(needconfig) 922 fprint(conf.cfd, "remove %I %I", IPnoaddr, IPnoaddr); 923 924 } 925 926 enum { 927 /* 928 * was an hour, needs to be less for the ARM/GS1 until the timer 929 * code has been cleaned up (pb). 930 */ 931 Maxsleep = 450, 932 }; 933 934 void 935 dhcpwatch(int needconfig) 936 { 937 int secs, s; 938 ulong t; 939 940 if(nodhcpwatch) 941 return; 942 943 switch(rfork(RFPROC|RFFDG|RFNOWAIT|RFNOTEG)){ 944 default: 945 return; 946 case 0: 947 break; 948 } 949 950 dolog = 1; /* log, don't print */ 951 procsetname("dhcpwatch"); 952 /* keep trying to renew the lease */ 953 for(;;){ 954 if(conf.lease == 0) 955 secs = 5; 956 else 957 secs = conf.lease >> 1; 958 959 /* avoid overflows */ 960 for(s = secs; s > 0; s -= t){ 961 if(s > Maxsleep) 962 t = Maxsleep; 963 else 964 t = s; 965 sleep(t*1000); 966 } 967 968 if(conf.lease > 0){ 969 /* 970 * during boot, the starttime can be bogus so avoid 971 * spurious ipinconfig's 972 */ 973 t = time(0) - conf.starttime; 974 if(t > (3*secs)/2) 975 t = secs; 976 if(t >= conf.lease){ 977 conf.lease = 0; 978 if(!noconfig){ 979 ipunconfig(); 980 needconfig = 1; 981 } 982 } else 983 conf.lease -= t; 984 } 985 dhcpquery(needconfig, needconfig? Sselecting: Srenewing); 986 987 if(needconfig && conf.state == Sbound){ 988 if(ip4cfg() < 0) 989 sysfatal("can't start ip: %r"); 990 needconfig = 0; 991 /* 992 * leave everything we've learned somewhere that 993 * other procs can find it. 994 */ 995 if(beprimary==1){ 996 putndb(); 997 tweakservers(); 998 } 999 } 1000 } 1001 } 1002 1003 int 1004 dhcptimer(void) 1005 { 1006 ulong now; 1007 1008 now = time(0); 1009 if(now < conf.timeout) 1010 return 0; 1011 1012 switch(conf.state) { 1013 default: 1014 sysfatal("dhcptimer: unknown state %d", conf.state); 1015 case Sinit: 1016 case Sbound: 1017 break; 1018 case Sselecting: 1019 case Srequesting: 1020 case Srebinding: 1021 dhcpsend(conf.state == Sselecting? Discover: Request); 1022 conf.timeout = now + 4; 1023 if(++conf.resend > 5) { 1024 conf.state = Sinit; 1025 return -1; 1026 } 1027 break; 1028 case Srenewing: 1029 dhcpsend(Request); 1030 conf.timeout = now + 1; 1031 if(++conf.resend > 3) { 1032 conf.state = Srebinding; 1033 conf.resend = 0; 1034 } 1035 break; 1036 } 1037 return 0; 1038 } 1039 1040 void 1041 dhcpsend(int type) 1042 { 1043 Bootp bp; 1044 uchar *p; 1045 int n; 1046 uchar vendor[64]; 1047 Udphdr *up = (Udphdr*)bp.udphdr; 1048 1049 memset(&bp, 0, sizeof bp); 1050 1051 hnputs(up->rport, 67); 1052 bp.op = Bootrequest; 1053 hnputl(bp.xid, conf.xid); 1054 hnputs(bp.secs, time(0)-conf.starttime); 1055 hnputs(bp.flags, 0); 1056 memmove(bp.optmagic, optmagic, 4); 1057 if(conf.hwatype >= 0 && conf.hwalen < sizeof bp.chaddr){ 1058 memmove(bp.chaddr, conf.hwa, conf.hwalen); 1059 bp.hlen = conf.hwalen; 1060 bp.htype = conf.hwatype; 1061 } 1062 p = bp.optdata; 1063 p = optaddbyte(p, ODtype, type); 1064 p = optadd(p, ODclientid, conf.cid, conf.cidlen); 1065 switch(type) { 1066 default: 1067 sysfatal("dhcpsend: unknown message type: %d", type); 1068 case Discover: 1069 ipmove(up->raddr, IPv4bcast); /* broadcast */ 1070 if(*conf.hostname && sendhostname) 1071 p = optaddstr(p, OBhostname, conf.hostname); 1072 if(plan9){ 1073 n = snprint((char*)vendor, sizeof vendor, 1074 "plan9_%s", conf.cputype); 1075 p = optaddvec(p, ODvendorclass, vendor, n); 1076 } 1077 p = optaddvec(p, ODparams, requested, nrequested); 1078 if(validip(conf.laddr)) 1079 p = optaddaddr(p, ODipaddr, conf.laddr); 1080 break; 1081 case Request: 1082 switch(conf.state){ 1083 case Srenewing: 1084 ipmove(up->raddr, conf.server); 1085 v6tov4(bp.ciaddr, conf.laddr); 1086 break; 1087 case Srebinding: 1088 ipmove(up->raddr, IPv4bcast); /* broadcast */ 1089 v6tov4(bp.ciaddr, conf.laddr); 1090 break; 1091 case Srequesting: 1092 ipmove(up->raddr, IPv4bcast); /* broadcast */ 1093 p = optaddaddr(p, ODipaddr, conf.laddr); 1094 p = optaddaddr(p, ODserverid, conf.server); 1095 break; 1096 } 1097 p = optaddulong(p, ODlease, conf.offered); 1098 if(plan9){ 1099 n = snprint((char*)vendor, sizeof vendor, 1100 "plan9_%s", conf.cputype); 1101 p = optaddvec(p, ODvendorclass, vendor, n); 1102 } 1103 p = optaddvec(p, ODparams, requested, nrequested); 1104 if(*conf.hostname && sendhostname) 1105 p = optaddstr(p, OBhostname, conf.hostname); 1106 break; 1107 case Release: 1108 ipmove(up->raddr, conf.server); 1109 v6tov4(bp.ciaddr, conf.laddr); 1110 p = optaddaddr(p, ODipaddr, conf.laddr); 1111 p = optaddaddr(p, ODserverid, conf.server); 1112 break; 1113 } 1114 1115 *p++ = OBend; 1116 1117 n = p - (uchar*)&bp; 1118 USED(n); 1119 1120 /* 1121 * We use a maximum size DHCP packet to survive the 1122 * All_Aboard NAT package from Internet Share. It 1123 * always replies to DHCP requests with a packet of the 1124 * same size, so if the request is too short the reply 1125 * is truncated. 1126 */ 1127 if(write(conf.fd, &bp, sizeof bp) != sizeof bp) 1128 warning("dhcpsend: write failed: %r"); 1129 } 1130 1131 void 1132 dhcprecv(void) 1133 { 1134 int i, n, type; 1135 ulong lease; 1136 char err[ERRMAX]; 1137 uchar buf[8000], vopts[256], taddr[IPaddrlen]; 1138 Bootp *bp; 1139 1140 alarm(1000); 1141 n = read(conf.fd, buf, sizeof buf); 1142 alarm(0); 1143 1144 if(n < 0){ 1145 errstr(err, sizeof err); 1146 if(strstr(err, "interrupt") == nil) 1147 warning("dhcprecv: bad read: %s", err); 1148 else 1149 DEBUG("dhcprecv: read timed out"); 1150 return; 1151 } 1152 1153 bp = parsebootp(buf, n); 1154 if(bp == 0) { 1155 DEBUG("parsebootp failed: dropping packet"); 1156 return; 1157 } 1158 1159 type = optgetbyte(bp->optdata, ODtype); 1160 switch(type) { 1161 default: 1162 warning("dhcprecv: unknown type: %d", type); 1163 break; 1164 case Offer: 1165 DEBUG("got offer from %V ", bp->siaddr); 1166 if(conf.state != Sselecting){ 1167 // DEBUG(""); 1168 break; 1169 } 1170 lease = optgetulong(bp->optdata, ODlease); 1171 if(lease == 0){ 1172 /* 1173 * The All_Aboard NAT package from Internet Share 1174 * doesn't give a lease time, so we have to assume one. 1175 */ 1176 warning("Offer with %lud lease, using %d", lease, MinLease); 1177 lease = MinLease; 1178 } 1179 DEBUG("lease=%lud ", lease); 1180 if(!optgetaddr(bp->optdata, ODserverid, conf.server)) { 1181 warning("Offer from server with invalid serverid"); 1182 break; 1183 } 1184 1185 v4tov6(conf.laddr, bp->yiaddr); 1186 memmove(conf.sname, bp->sname, sizeof conf.sname); 1187 conf.sname[sizeof conf.sname-1] = 0; 1188 DEBUG("server=%I sname=%s", conf.server, conf.sname); 1189 conf.offered = lease; 1190 conf.state = Srequesting; 1191 dhcpsend(Request); 1192 conf.resend = 0; 1193 conf.timeout = time(0) + 4; 1194 break; 1195 case Ack: 1196 DEBUG("got ack from %V ", bp->siaddr); 1197 if (conf.state != Srequesting && conf.state != Srenewing && 1198 conf.state != Srebinding) 1199 break; 1200 1201 /* ignore a bad lease */ 1202 lease = optgetulong(bp->optdata, ODlease); 1203 if(lease == 0){ 1204 /* 1205 * The All_Aboard NAT package from Internet Share 1206 * doesn't give a lease time, so we have to assume one. 1207 */ 1208 warning("Ack with %lud lease, using %d", lease, MinLease); 1209 lease = MinLease; 1210 } 1211 DEBUG("lease=%lud ", lease); 1212 1213 /* address and mask */ 1214 if(!validip(conf.laddr) || !Oflag) 1215 v4tov6(conf.laddr, bp->yiaddr); 1216 if(!validip(conf.mask) || !Oflag){ 1217 if(!optgetaddr(bp->optdata, OBmask, conf.mask)) 1218 ipmove(conf.mask, IPnoaddr); 1219 } 1220 DEBUG("ipaddr=%I ipmask=%M ", conf.laddr, conf.mask); 1221 1222 /* 1223 * get a router address either from the router option 1224 * or from the router that forwarded the dhcp packet 1225 */ 1226 if(validip(conf.gaddr) && Oflag) { 1227 DEBUG("ipgw=%I ", conf.gaddr); 1228 } else if(optgetaddr(bp->optdata, OBrouter, conf.gaddr)){ 1229 DEBUG("ipgw=%I ", conf.gaddr); 1230 } else if(memcmp(bp->giaddr, IPnoaddr+IPv4off, IPv4addrlen)!=0){ 1231 v4tov6(conf.gaddr, bp->giaddr); 1232 DEBUG("giaddr=%I ", conf.gaddr); 1233 } 1234 1235 /* get dns servers */ 1236 memset(conf.dns, 0, sizeof conf.dns); 1237 n = optgetaddrs(bp->optdata, OBdnserver, conf.dns, 1238 sizeof conf.dns/IPaddrlen); 1239 for(i = 0; i < n; i++) 1240 DEBUG("dns=%I ", conf.dns + i*IPaddrlen); 1241 1242 /* get ntp servers */ 1243 memset(conf.ntp, 0, sizeof conf.ntp); 1244 n = optgetaddrs(bp->optdata, OBntpserver, conf.ntp, 1245 sizeof conf.ntp/IPaddrlen); 1246 for(i = 0; i < n; i++) 1247 DEBUG("ntp=%I ", conf.ntp + i*IPaddrlen); 1248 1249 /* get names */ 1250 optgetstr(bp->optdata, OBhostname, 1251 conf.hostname, sizeof conf.hostname); 1252 optgetstr(bp->optdata, OBdomainname, 1253 conf.domainname, sizeof conf.domainname); 1254 1255 /* get anything else we asked for */ 1256 getoptions(bp->optdata); 1257 1258 /* get plan9-specific options */ 1259 n = optgetvec(bp->optdata, OBvendorinfo, vopts, sizeof vopts-1); 1260 if(n > 0 && parseoptions(vopts, n) == 0){ 1261 if(validip(conf.fs) && Oflag) 1262 n = 1; 1263 else { 1264 n = optgetp9addrs(vopts, OP9fs, conf.fs, 2); 1265 if (n == 0) 1266 n = optgetaddrs(vopts, OP9fsv4, 1267 conf.fs, 2); 1268 } 1269 for(i = 0; i < n; i++) 1270 DEBUG("fs=%I ", conf.fs + i*IPaddrlen); 1271 1272 if(validip(conf.auth) && Oflag) 1273 n = 1; 1274 else { 1275 n = optgetp9addrs(vopts, OP9auth, conf.auth, 2); 1276 if (n == 0) 1277 n = optgetaddrs(vopts, OP9authv4, 1278 conf.auth, 2); 1279 } 1280 for(i = 0; i < n; i++) 1281 DEBUG("auth=%I ", conf.auth + i*IPaddrlen); 1282 1283 n = optgetp9addrs(vopts, OP9ipaddr, taddr, 1); 1284 if (n > 0) 1285 memmove(conf.laddr, taddr, IPaddrlen); 1286 n = optgetp9addrs(vopts, OP9ipmask, taddr, 1); 1287 if (n > 0) 1288 memmove(conf.mask, taddr, IPaddrlen); 1289 n = optgetp9addrs(vopts, OP9ipgw, taddr, 1); 1290 if (n > 0) 1291 memmove(conf.gaddr, taddr, IPaddrlen); 1292 DEBUG("new ipaddr=%I new ipmask=%M new ipgw=%I", 1293 conf.laddr, conf.mask, conf.gaddr); 1294 } 1295 conf.lease = lease; 1296 conf.state = Sbound; 1297 DEBUG("server=%I sname=%s", conf.server, conf.sname); 1298 break; 1299 case Nak: 1300 conf.state = Sinit; 1301 warning("recved dhcpnak on %s", conf.mpoint); 1302 break; 1303 } 1304 } 1305 1306 /* return pseudo-random integer in range low...(hi-1) */ 1307 ulong 1308 randint(ulong low, ulong hi) 1309 { 1310 if (hi < low) 1311 return low; 1312 return low + nrand(hi - low); 1313 } 1314 1315 long 1316 jitter(void) /* compute small pseudo-random delay in ms */ 1317 { 1318 return randint(0, 10*1000); 1319 } 1320 1321 int 1322 openlisten(void) 1323 { 1324 int n, fd, cfd; 1325 char data[128], devdir[40]; 1326 1327 if (validip(conf.laddr) && 1328 (conf.state == Srenewing || conf.state == Srebinding)) 1329 sprint(data, "%s/udp!%I!68", conf.mpoint, conf.laddr); 1330 else 1331 sprint(data, "%s/udp!*!68", conf.mpoint); 1332 for (n = 0; (cfd = announce(data, devdir)) < 0; n++) { 1333 if(!noconfig) 1334 sysfatal("can't announce for dhcp: %r"); 1335 1336 /* might be another client - wait and try again */ 1337 warning("can't announce %s: %r", data); 1338 sleep(jitter()); 1339 if(n > 10) 1340 return -1; 1341 } 1342 1343 if(fprint(cfd, "headers") < 0) 1344 sysfatal("can't set header mode: %r"); 1345 1346 sprint(data, "%s/data", devdir); 1347 fd = open(data, ORDWR); 1348 if(fd < 0) 1349 sysfatal("open %s: %r", data); 1350 close(cfd); 1351 return fd; 1352 } 1353 1354 uchar* 1355 optadd(uchar *p, int op, void *d, int n) 1356 { 1357 p[0] = op; 1358 p[1] = n; 1359 memmove(p+2, d, n); 1360 return p+n+2; 1361 } 1362 1363 uchar* 1364 optaddbyte(uchar *p, int op, int b) 1365 { 1366 p[0] = op; 1367 p[1] = 1; 1368 p[2] = b; 1369 return p+3; 1370 } 1371 1372 uchar* 1373 optaddulong(uchar *p, int op, ulong x) 1374 { 1375 p[0] = op; 1376 p[1] = 4; 1377 hnputl(p+2, x); 1378 return p+6; 1379 } 1380 1381 uchar * 1382 optaddaddr(uchar *p, int op, uchar *ip) 1383 { 1384 p[0] = op; 1385 p[1] = 4; 1386 v6tov4(p+2, ip); 1387 return p+6; 1388 } 1389 1390 /* add dhcp option op with value v of length n to dhcp option array p */ 1391 uchar * 1392 optaddvec(uchar *p, int op, uchar *v, int n) 1393 { 1394 p[0] = op; 1395 p[1] = n; 1396 memmove(p+2, v, n); 1397 return p+2+n; 1398 } 1399 1400 uchar * 1401 optaddstr(uchar *p, int op, char *v) 1402 { 1403 int n; 1404 1405 n = strlen(v)+1; /* microsoft leaves on the NUL, so we do too */ 1406 p[0] = op; 1407 p[1] = n; 1408 memmove(p+2, v, n); 1409 return p+2+n; 1410 } 1411 1412 /* 1413 * parse p, looking for option `op'. if non-nil, np points to minimum length. 1414 * return nil if option is too small, else ptr to opt, and 1415 * store actual length via np if non-nil. 1416 */ 1417 uchar* 1418 optget(uchar *p, int op, int *np) 1419 { 1420 int len, code; 1421 1422 while ((code = *p++) != OBend) { 1423 if(code == OBpad) 1424 continue; 1425 len = *p++; 1426 if(code != op) { 1427 p += len; 1428 continue; 1429 } 1430 if(np != nil){ 1431 if(*np > len) { 1432 return 0; 1433 } 1434 *np = len; 1435 } 1436 return p; 1437 } 1438 return 0; 1439 } 1440 1441 int 1442 optgetbyte(uchar *p, int op) 1443 { 1444 int len; 1445 1446 len = 1; 1447 p = optget(p, op, &len); 1448 if(p == nil) 1449 return 0; 1450 return *p; 1451 } 1452 1453 ulong 1454 optgetulong(uchar *p, int op) 1455 { 1456 int len; 1457 1458 len = 4; 1459 p = optget(p, op, &len); 1460 if(p == nil) 1461 return 0; 1462 return nhgetl(p); 1463 } 1464 1465 int 1466 optgetaddr(uchar *p, int op, uchar *ip) 1467 { 1468 int len; 1469 1470 len = 4; 1471 p = optget(p, op, &len); 1472 if(p == nil) 1473 return 0; 1474 v4tov6(ip, p); 1475 return 1; 1476 } 1477 1478 /* expect at most n addresses; ip[] only has room for that many */ 1479 int 1480 optgetaddrs(uchar *p, int op, uchar *ip, int n) 1481 { 1482 int len, i; 1483 1484 len = 4; 1485 p = optget(p, op, &len); 1486 if(p == nil) 1487 return 0; 1488 len /= IPv4addrlen; 1489 if(len > n) 1490 len = n; 1491 for(i = 0; i < len; i++) 1492 v4tov6(&ip[i*IPaddrlen], &p[i*IPv4addrlen]); 1493 return i; 1494 } 1495 1496 /* expect at most n addresses; ip[] only has room for that many */ 1497 int 1498 optgetp9addrs(uchar *ap, int op, uchar *ip, int n) 1499 { 1500 int len, i, slen, addrs; 1501 char *p; 1502 1503 len = 1; /* minimum bytes needed */ 1504 p = (char *)optget(ap, op, &len); 1505 if(p == nil) 1506 return 0; 1507 addrs = *p++; /* first byte is address count */ 1508 for (i = 0; i < n && i < addrs && len > 0; i++) { 1509 slen = strlen(p) + 1; 1510 parseip(&ip[i*IPaddrlen], p); 1511 DEBUG("got plan 9 option %d addr %I (%s)", 1512 op, &ip[i*IPaddrlen], p); 1513 p += slen; 1514 len -= slen; 1515 } 1516 return addrs; 1517 } 1518 1519 int 1520 optgetvec(uchar *p, int op, uchar *v, int n) 1521 { 1522 int len; 1523 1524 len = 1; 1525 p = optget(p, op, &len); 1526 if(p == nil) 1527 return 0; 1528 if(len > n) 1529 len = n; 1530 memmove(v, p, len); 1531 return len; 1532 } 1533 1534 int 1535 optgetstr(uchar *p, int op, char *s, int n) 1536 { 1537 int len; 1538 1539 len = 1; 1540 p = optget(p, op, &len); 1541 if(p == nil) 1542 return 0; 1543 if(len >= n) 1544 len = n-1; 1545 memmove(s, p, len); 1546 s[len] = 0; 1547 return len; 1548 } 1549 1550 /* 1551 * sanity check options area 1552 * - options don't overflow packet 1553 * - options end with an OBend 1554 */ 1555 int 1556 parseoptions(uchar *p, int n) 1557 { 1558 int code, len, nin = n; 1559 1560 while (n > 0) { 1561 code = *p++; 1562 n--; 1563 if(code == OBend) 1564 return 0; 1565 if(code == OBpad) 1566 continue; 1567 if(n == 0) { 1568 warning("parseoptions: bad option: 0x%ux: truncated: " 1569 "opt length = %d", code, nin); 1570 return -1; 1571 } 1572 1573 len = *p++; 1574 n--; 1575 DEBUG("parseoptions: %s(%d) len %d, bytes left %d", 1576 option[code].name, code, len, n); 1577 if(len > n) { 1578 warning("parseoptions: bad option: 0x%ux: %d > %d: " 1579 "opt length = %d", code, len, n, nin); 1580 return -1; 1581 } 1582 p += len; 1583 n -= len; 1584 } 1585 1586 /* make sure packet ends with an OBend after all the optget code */ 1587 *p = OBend; 1588 return 0; 1589 } 1590 1591 /* 1592 * sanity check received packet: 1593 * - magic is dhcp magic 1594 * - options don't overflow packet 1595 */ 1596 Bootp * 1597 parsebootp(uchar *p, int n) 1598 { 1599 Bootp *bp; 1600 1601 bp = (Bootp*)p; 1602 if(n < bp->optmagic - p) { 1603 warning("parsebootp: short bootp packet"); 1604 return nil; 1605 } 1606 1607 if(conf.xid != nhgetl(bp->xid)) 1608 return nil; 1609 1610 if(bp->op != Bootreply) { 1611 warning("parsebootp: bad op %d", bp->op); 1612 return nil; 1613 } 1614 1615 n -= bp->optmagic - p; 1616 p = bp->optmagic; 1617 1618 if(n < 4) { 1619 warning("parsebootp: no option data"); 1620 return nil; 1621 } 1622 if(memcmp(optmagic, p, 4) != 0) { 1623 warning("parsebootp: bad opt magic %ux %ux %ux %ux", 1624 p[0], p[1], p[2], p[3]); 1625 return nil; 1626 } 1627 p += 4; 1628 n -= 4; 1629 DEBUG("parsebootp: new packet"); 1630 if(parseoptions(p, n) < 0) 1631 return nil; 1632 return bp; 1633 } 1634 1635 /* write out an ndb entry */ 1636 void 1637 writendb(char *s, int n, int append) 1638 { 1639 char file[64]; 1640 int fd; 1641 1642 snprint(file, sizeof file, "%s/ndb", conf.mpoint); 1643 if(append){ 1644 fd = open(file, OWRITE); 1645 seek(fd, 0, 2); 1646 } else 1647 fd = open(file, OWRITE|OTRUNC); 1648 write(fd, s, n); 1649 close(fd); 1650 } 1651 1652 /* put server addresses into the ndb entry */ 1653 char* 1654 putaddrs(char *p, char *e, char *attr, uchar *a, int len) 1655 { 1656 int i; 1657 1658 for(i = 0; i < len && validip(a); i += IPaddrlen, a += IPaddrlen) 1659 p = seprint(p, e, "%s=%I\n", attr, a); 1660 return p; 1661 } 1662 1663 /* make an ndb entry and put it into /net/ndb for the servers to see */ 1664 void 1665 putndb(void) 1666 { 1667 int append; 1668 char buf[1024]; 1669 char *p, *e, *np; 1670 1671 p = buf; 1672 e = buf + sizeof buf; 1673 if(getndb() == 0) 1674 append = 1; 1675 else { 1676 append = 0; 1677 p = seprint(p, e, "ip=%I ipmask=%M ipgw=%I\n", 1678 conf.laddr, conf.mask, conf.gaddr); 1679 } 1680 if(np = strchr(conf.hostname, '.')){ 1681 if(*conf.domainname == 0) 1682 strcpy(conf.domainname, np+1); 1683 *np = 0; 1684 } 1685 if(*conf.hostname) 1686 p = seprint(p, e, "\tsys=%s\n", conf.hostname); 1687 if(*conf.domainname) 1688 p = seprint(p, e, "\tdom=%s.%s\n", 1689 conf.hostname, conf.domainname); 1690 if(validip(conf.fs)) 1691 p = putaddrs(p, e, "\tfs", conf.fs, sizeof conf.fs); 1692 if(validip(conf.auth)) 1693 p = putaddrs(p, e, "\tauth", conf.auth, sizeof conf.auth); 1694 if(validip(conf.dns)) 1695 p = putaddrs(p, e, "\tdns", conf.dns, sizeof conf.dns); 1696 if(validip(conf.ntp)) 1697 p = putaddrs(p, e, "\tntp", conf.ntp, sizeof conf.ntp); 1698 if(ndboptions) 1699 p = seprint(p, e, "%s\n", ndboptions); 1700 if(p > buf) 1701 writendb(buf, p-buf, append); 1702 } 1703 1704 /* get an ndb entry someone else wrote */ 1705 int 1706 getndb(void) 1707 { 1708 char buf[1024]; 1709 int fd, n; 1710 char *p; 1711 1712 snprint(buf, sizeof buf, "%s/ndb", conf.mpoint); 1713 fd = open(buf, OREAD); 1714 n = read(fd, buf, sizeof buf-1); 1715 close(fd); 1716 if(n <= 0) 1717 return -1; 1718 buf[n] = 0; 1719 p = strstr(buf, "ip="); 1720 if(p == nil) 1721 return -1; 1722 parseip(conf.laddr, p+3); 1723 return 0; 1724 } 1725 1726 /* tell a server to refresh */ 1727 void 1728 tweakserver(char *server) 1729 { 1730 int fd; 1731 char file[64]; 1732 1733 snprint(file, sizeof file, "%s/%s", conf.mpoint, server); 1734 fd = open(file, ORDWR); 1735 if(fd < 0) 1736 return; 1737 fprint(fd, "refresh"); 1738 close(fd); 1739 } 1740 1741 /* tell all servers to refresh their information */ 1742 void 1743 tweakservers(void) 1744 { 1745 tweakserver("dns"); 1746 tweakserver("cs"); 1747 } 1748 1749 /* return number of networks */ 1750 int 1751 nipifcs(char *net) 1752 { 1753 int n; 1754 Ipifc *nifc; 1755 Iplifc *lifc; 1756 1757 n = 0; 1758 ifc = readipifc(net, ifc, -1); 1759 for(nifc = ifc; nifc != nil; nifc = nifc->next){ 1760 /* 1761 * ignore loopback devices when trying to 1762 * figure out if we're the primary interface. 1763 */ 1764 if(strcmp(nifc->dev, "/dev/null") != 0) 1765 for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next) 1766 if(validip(lifc->ip)){ 1767 n++; 1768 break; 1769 } 1770 if(strcmp(nifc->dev, conf.dev) == 0) 1771 myifc = nifc->index; 1772 } 1773 return n; 1774 } 1775 1776 /* return true if this is a valid v4 address */ 1777 int 1778 validip(uchar *addr) 1779 { 1780 return ipcmp(addr, IPnoaddr) != 0 && ipcmp(addr, v4prefix) != 0; 1781 } 1782 1783 /* look for an action */ 1784 int 1785 parseverb(char *name) 1786 { 1787 int i; 1788 1789 for(i = 0; i < nelem(verbs); i++) 1790 if(verbs[i] != nil && strcmp(name, verbs[i]) == 0) 1791 return i; 1792 return -1; 1793 } 1794 1795 /* get everything out of ndb */ 1796 void 1797 ndbconfig(void) 1798 { 1799 int nattr, nauth = 0, ndns = 0, nfs = 0; 1800 char etheraddr[32]; 1801 char *attrs[10]; 1802 Ndb *db; 1803 Ndbtuple *t, *nt; 1804 1805 db = ndbopen(0); 1806 if(db == nil) 1807 sysfatal("can't open ndb: %r"); 1808 if (strcmp(conf.type, "ether") != 0 && strcmp(conf.type, "gbe") != 0 || 1809 myetheraddr(conf.hwa, conf.dev) != 0) 1810 sysfatal("can't read hardware address"); 1811 sprint(etheraddr, "%E", conf.hwa); 1812 nattr = 0; 1813 attrs[nattr++] = "ip"; 1814 attrs[nattr++] = "ipmask"; 1815 attrs[nattr++] = "ipgw"; 1816 /* the @ triggers resolution to an IP address; see ndb(2) */ 1817 attrs[nattr++] = "@dns"; 1818 attrs[nattr++] = "@ntp"; 1819 attrs[nattr++] = "@fs"; 1820 attrs[nattr++] = "@auth"; 1821 attrs[nattr] = nil; 1822 t = ndbipinfo(db, "ether", etheraddr, attrs, nattr); 1823 for(nt = t; nt != nil; nt = nt->entry) 1824 if(strcmp(nt->attr, "ip") == 0) 1825 parseip(conf.laddr, nt->val); 1826 else if(strcmp(nt->attr, "ipmask") == 0) 1827 parseipmask(conf.mask, nt->val); 1828 else if(strcmp(nt->attr, "ipgw") == 0) 1829 parseip(conf.gaddr, nt->val); 1830 else if(ndns < 2 && strcmp(nt->attr, "dns") == 0) 1831 parseip(conf.dns+IPaddrlen*ndns, nt->val); 1832 else if(strcmp(nt->attr, "ntp") == 0) 1833 parseip(conf.ntp, nt->val); 1834 else if(nfs < 2 && strcmp(nt->attr, "fs") == 0) 1835 parseip(conf.fs+IPaddrlen*nfs, nt->val); 1836 else if(nauth < 2 && strcmp(nt->attr, "auth") == 0) 1837 parseip(conf.auth+IPaddrlen*nauth, nt->val); 1838 ndbfree(t); 1839 if(!validip(conf.laddr)) 1840 sysfatal("address not found in ndb"); 1841 } 1842 1843 int 1844 addoption(char *opt) 1845 { 1846 int i; 1847 Option *o; 1848 1849 if(opt == nil) 1850 return -1; 1851 for(o = option; o < &option[nelem(option)]; o++) 1852 if(o->name && strcmp(opt, o->name) == 0){ 1853 i = o - option; 1854 if(memchr(requested, i, nrequested) == 0 && 1855 nrequested < nelem(requested)) 1856 requested[nrequested++] = i; 1857 return 0; 1858 } 1859 return -1; 1860 } 1861 1862 char* 1863 optgetx(uchar *p, uchar opt) 1864 { 1865 int i, n; 1866 ulong x; 1867 char *s, *ns; 1868 char str[256]; 1869 uchar ip[IPaddrlen], ips[16*IPaddrlen], vec[256]; 1870 Option *o; 1871 1872 o = &option[opt]; 1873 if(o->name == nil) 1874 return nil; 1875 1876 s = nil; 1877 switch(o->type){ 1878 case Taddr: 1879 if(optgetaddr(p, opt, ip)) 1880 s = smprint("%s=%I", o->name, ip); 1881 break; 1882 case Taddrs: 1883 n = optgetaddrs(p, opt, ips, 16); 1884 if(n > 0) 1885 s = smprint("%s=%I", o->name, ips); 1886 for(i = 1; i < n; i++){ 1887 ns = smprint("%s %s=%I", s, o->name, &ips[i*IPaddrlen]); 1888 free(s); 1889 s = ns; 1890 } 1891 break; 1892 case Tulong: 1893 x = optgetulong(p, opt); 1894 if(x != 0) 1895 s = smprint("%s=%lud", o->name, x); 1896 break; 1897 case Tbyte: 1898 x = optgetbyte(p, opt); 1899 if(x != 0) 1900 s = smprint("%s=%lud", o->name, x); 1901 break; 1902 case Tstr: 1903 if(optgetstr(p, opt, str, sizeof str)) 1904 s = smprint("%s=%s", o->name, str); 1905 break; 1906 case Tvec: 1907 n = optgetvec(p, opt, vec, sizeof vec); 1908 if(n > 0) 1909 /* what's %H? it's not installed */ 1910 s = smprint("%s=%.*H", o->name, n, vec); 1911 break; 1912 } 1913 return s; 1914 } 1915 1916 void 1917 getoptions(uchar *p) 1918 { 1919 int i; 1920 char *s, *t; 1921 1922 for(i = nelem(defrequested); i < nrequested; i++){ 1923 s = optgetx(p, requested[i]); 1924 if(s != nil) 1925 DEBUG("%s ", s); 1926 if(ndboptions == nil) 1927 ndboptions = smprint("\t%s", s); 1928 else{ 1929 t = ndboptions; 1930 ndboptions = smprint("\t%s%s", s, ndboptions); 1931 free(t); 1932 } 1933 free(s); 1934 } 1935 } 1936