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