1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include <bio.h> 5 #include <ndb.h> 6 #include "dat.h" 7 8 /* 9 * ala rfc2131 10 */ 11 12 enum { 13 Maxloglen = 1024, 14 }; 15 16 typedef struct Req Req; 17 struct Req 18 { 19 int fd; /* for reply */ 20 Bootp *bp; 21 Udphdr *up; 22 uchar *e; /* end of received message */ 23 uchar *p; /* options pointer */ 24 uchar *max; /* max end of reply */ 25 26 /* expanded to v6 */ 27 uchar ciaddr[IPaddrlen]; 28 uchar giaddr[IPaddrlen]; 29 30 /* parsed options */ 31 int p9request; /* flag: this is a bootp with plan9 options */ 32 int genrequest; /* flag: this is a bootp with generic options */ 33 int broadcast; /* flag: request was broadcast */ 34 int dhcptype; /* dhcp message type */ 35 int leasetime; /* dhcp lease */ 36 uchar ip[IPaddrlen]; /* requested address */ 37 uchar server[IPaddrlen]; /* server address */ 38 char msg[ERRMAX]; /* error message */ 39 char vci[32]; /* vendor class id */ 40 char *id; /* client id */ 41 uchar requested[32]; /* requested params */ 42 uchar vendorclass[32]; 43 char cputype[32-3]; 44 45 Info gii; /* about target network */ 46 Info ii; /* about target system */ 47 int staticbinding; 48 49 uchar buf[2*1024]; /* message buffer */ 50 }; 51 52 #define TFTP "/lib/tftpd" 53 54 char *blog = "ipboot"; 55 char mysysname[64]; 56 Ipifc *ipifcs; 57 int debug; 58 int nobootp; 59 long now; 60 int slowstat, slowdyn; 61 char net[256]; 62 63 int pptponly; /* only answer request that came from the pptp server */ 64 int mute, mutestat; 65 int minlease = MinLease; 66 int staticlease = StaticLease; 67 68 uvlong start; 69 70 static int v6opts; 71 72 /* option magic */ 73 char plan9opt[4] = { 'p', '9', ' ', ' ' }; 74 char genericopt[4] = { 0x63, 0x82, 0x53, 0x63 }; 75 76 /* well known addresses */ 77 uchar zeros[Maxhwlen]; 78 79 /* option debug buffer */ 80 char optbuf[1024]; 81 char *op; 82 char *oe = optbuf + sizeof(optbuf); 83 84 char *optname[256] = 85 { 86 [OBend] "end", 87 [OBpad] "pad", 88 [OBmask] "mask", 89 [OBtimeoff] "timeoff", 90 [OBrouter] "router", 91 [OBtimeserver] "time", 92 [OBnameserver] "name", 93 [OBdnserver] "dns", 94 [OBlogserver] "log", 95 [OBcookieserver] "cookie", 96 [OBlprserver] "lpr", 97 [OBimpressserver] "impress", 98 [OBrlserver] "rl", 99 [OBhostname] "host", 100 [OBbflen] "bflen", 101 [OBdumpfile] "dumpfile", 102 [OBdomainname] "dom", 103 [OBswapserver] "swap", 104 [OBrootpath] "rootpath", 105 [OBextpath] "extpath", 106 [OBipforward] "ipforward", 107 [OBnonlocal] "nonlocal", 108 [OBpolicyfilter] "policyfilter", 109 [OBmaxdatagram] "maxdatagram", 110 [OBttl] "ttl", 111 [OBpathtimeout] "pathtimeout", 112 [OBpathplateau] "pathplateau", 113 [OBmtu] "mtu", 114 [OBsubnetslocal] "subnetslocal", 115 [OBbaddr] "baddr", 116 [OBdiscovermask] "discovermask", 117 [OBsupplymask] "supplymask", 118 [OBdiscoverrouter] "discoverrouter", 119 [OBrsserver] "rsserver", 120 [OBstaticroutes] "staticroutes", 121 [OBtrailerencap] "trailerencap", 122 [OBarptimeout] "arptimeout", 123 [OBetherencap] "etherencap", 124 [OBtcpttl] "tcpttl", 125 [OBtcpka] "tcpka", 126 [OBtcpkag] "tcpkag", 127 [OBnisdomain] "nisdomain", 128 [OBniserver] "niserver", 129 [OBntpserver] "ntpserver", 130 [OBvendorinfo] "vendorinfo", 131 [OBnetbiosns] "NBns", 132 [OBnetbiosdds] "NBdds", 133 [OBnetbiostype] "NBtype", 134 [OBnetbiosscope] "NBscope", 135 [OBxfontserver] "xfont", 136 [OBxdispmanager] "xdisp", 137 [OBnisplusdomain] "NPdomain", 138 [OBnisplusserver] "NP", 139 [OBhomeagent] "homeagent", 140 [OBsmtpserver] "smtp", 141 [OBpop3server] "pop3", 142 [OBnntpserver] "nntp", 143 [OBwwwserver] "www", 144 [OBfingerserver] "finger", 145 [OBircserver] "ircserver", 146 [OBstserver] "stserver", 147 [OBstdaserver] "stdaserver", 148 149 /* dhcp options */ 150 [ODipaddr] "ip", 151 [ODlease] "leas", 152 [ODoverload] "overload", 153 [ODtype] "typ", 154 [ODserverid] "sid", 155 [ODparams] "params", 156 [ODmessage] "message", 157 [ODmaxmsg] "maxmsg", 158 [ODrenewaltime] "renewaltime", 159 [ODrebindingtime] "rebindingtime", 160 [ODvendorclass] "vendorclass", 161 [ODclientid] "cid", 162 [ODtftpserver] "tftpserver", 163 [ODbootfile] "bf", 164 }; 165 166 void addropt(Req*, int, uchar*); 167 void addrsopt(Req*, int, uchar**, int); 168 void arpenter(uchar*, uchar*); 169 void bootp(Req*); 170 void byteopt(Req*, int, uchar); 171 void dhcp(Req*); 172 void fatal(int, char*, ...); 173 void hexopt(Req*, int, char*); 174 void logdhcp(Req*); 175 void logdhcpout(Req *, char *); 176 void longopt(Req*, int, long); 177 void maskopt(Req*, int, uchar*); 178 void miscoptions(Req*, uchar*); 179 int openlisten(char *net); 180 void p9addrsopt(Req *rp, int t, uchar **ip, int i); 181 void parseoptions(Req*); 182 void proto(Req*, int); 183 void rcvdecline(Req*); 184 void rcvdiscover(Req*); 185 void rcvinform(Req*); 186 void rcvrelease(Req*); 187 void rcvrequest(Req*); 188 int readlast(int, uchar*, int); 189 char* readsysname(void); 190 void remrequested(Req*, int); 191 void sendack(Req*, uchar*, int, int); 192 void sendnak(Req*, char*); 193 void sendoffer(Req*, uchar*, int); 194 void stringopt(Req*, int, char*); 195 void termopt(Req*); 196 int validip(uchar*); 197 void vectoropt(Req*, int, uchar*, int); 198 void warning(int, char*, ...); 199 200 void 201 timestamp(char *tag) 202 { 203 uvlong t; 204 205 t = nsec()/1000; 206 syslog(0, blog, "%s %lludµs", tag, t - start); 207 } 208 209 void 210 usage(void) 211 { 212 fprint(2, "usage: dhcp [-dmnprsSZ] [-f directory] [-M minlease] " 213 "[-x netmtpt] [-Z staticlease] addr n [addr n] ...\n"); 214 exits("usage"); 215 } 216 217 void 218 main(int argc, char **argv) 219 { 220 int i, n, fd; 221 uchar ip[IPaddrlen]; 222 Req r; 223 224 setnetmtpt(net, sizeof net, nil); 225 226 fmtinstall('E', eipfmt); 227 fmtinstall('I', eipfmt); 228 fmtinstall('V', eipfmt); 229 fmtinstall('M', eipfmt); 230 ARGBEGIN { 231 case '6': 232 v6opts = 1; 233 break; 234 case 'd': 235 debug = 1; 236 break; 237 case 'f': 238 ndbfile = EARGF(usage()); 239 break; 240 case 'm': 241 mute = 1; 242 break; 243 case 'M': 244 minlease = atoi(EARGF(usage())); 245 if(minlease <= 0) 246 minlease = MinLease; 247 break; 248 case 'n': 249 nobootp = 1; 250 break; 251 case 'p': 252 pptponly = 1; 253 break; 254 case 'r': 255 mutestat = 1; 256 break; 257 case 's': 258 slowstat = 1; 259 break; 260 case 'S': 261 slowdyn = 1; 262 break; 263 case 'x': 264 setnetmtpt(net, sizeof net, EARGF(usage())); 265 break; 266 case 'Z': 267 staticlease = atoi(EARGF(usage())); 268 if(staticlease <= 0) 269 staticlease = StaticLease; 270 break; 271 default: 272 usage(); 273 break; 274 } ARGEND; 275 276 while(argc > 1){ 277 parseip(ip, argv[0]); 278 if(!validip(ip)) 279 usage(); 280 n = atoi(argv[1]); 281 if(n <= 0) 282 usage(); 283 initbinding(ip, n); 284 argc -= 2; 285 argv += 2; 286 } 287 288 /* for debugging */ 289 for(i = 0; i < 256; i++) 290 if(optname[i] == 0) 291 optname[i] = smprint("%d", i); 292 293 /* what is my name? */ 294 strcpy(mysysname, readsysname()); 295 296 /* put process in background */ 297 if(!debug) 298 switch(rfork(RFNOTEG|RFPROC|RFFDG)) { 299 case -1: 300 fatal(1, "fork"); 301 case 0: 302 break; 303 default: 304 exits(0); 305 } 306 307 if (chdir(TFTP) < 0) 308 warning(1, "can't change directory to %s", TFTP); 309 fd = openlisten(net); 310 311 for(;;){ 312 memset(&r, 0, sizeof(r)); 313 r.fd = fd; 314 n = readlast(r.fd, r.buf, sizeof(r.buf)); 315 if(n < Udphdrsize) 316 fatal(1, "error reading requests"); 317 start = nsec()/1000; 318 op = optbuf; 319 *op = 0; 320 proto(&r, n); 321 if(r.id != nil) 322 free(r.id); 323 } 324 } 325 326 void 327 proto(Req *rp, int n) 328 { 329 uchar relip[IPaddrlen]; 330 char buf[64]; 331 332 now = time(0); 333 334 rp->e = rp->buf + n; 335 rp->bp = (Bootp*)rp->buf; 336 rp->up = (Udphdr*)rp->buf; 337 if (ipcmp(rp->up->laddr, IPv4bcast) == 0){ 338 ipmove(rp->up->laddr, rp->up->ifcaddr); 339 rp->broadcast = 1; 340 } 341 rp->max = rp->buf + Udphdrsize + MINSUPPORTED - IPUDPHDRSIZE; 342 rp->p = rp->bp->optdata; 343 v4tov6(rp->giaddr, rp->bp->giaddr); 344 v4tov6(rp->ciaddr, rp->bp->ciaddr); 345 346 if(pptponly && rp->bp->htype != 0) 347 return; 348 349 ipifcs = readipifc(net, ipifcs, -1); 350 if(validip(rp->giaddr)) 351 ipmove(relip, rp->giaddr); 352 else if(validip(rp->up->raddr)) 353 ipmove(relip, rp->up->raddr); 354 else 355 ipmove(relip, rp->up->laddr); 356 if(rp->e < (uchar*)rp->bp->sname){ 357 warning(0, "packet too short"); 358 return; 359 } 360 if(rp->bp->op != Bootrequest){ 361 warning(0, "not bootrequest"); 362 return; 363 } 364 365 if(rp->e >= rp->bp->optdata){ 366 if(memcmp(rp->bp->optmagic, plan9opt, sizeof(rp->bp->optmagic)) == 0) 367 rp->p9request = 1; 368 if(memcmp(rp->bp->optmagic, genericopt, sizeof(rp->bp->optmagic)) == 0) { 369 rp->genrequest = 1; 370 parseoptions(rp); 371 } 372 } 373 rp->p = rp->bp->optdata; 374 375 /* If no id is specified, make one from the hardware address 376 * of the target. We assume all zeros is not a hardware address 377 * which could be a mistake. 378 */ 379 if(rp->id == nil){ 380 if(rp->bp->hlen > Maxhwlen){ 381 warning(0, "hlen %d", rp->bp->hlen); 382 return; 383 } 384 if(memcmp(zeros, rp->bp->chaddr, rp->bp->hlen) == 0){ 385 warning(0, "no chaddr"); 386 return; 387 } 388 sprint(buf, "hwa%2.2ux_", rp->bp->htype); 389 rp->id = tohex(buf, rp->bp->chaddr, rp->bp->hlen); 390 } 391 392 /* info about gateway */ 393 if(lookupip(relip, &rp->gii, 1) < 0){ 394 warning(0, "lookupip failed"); 395 return; 396 } 397 398 /* info about target system */ 399 if(lookup(rp->bp, &rp->ii, &rp->gii) == 0) 400 if(rp->ii.indb && rp->ii.dhcpgroup[0] == 0) 401 rp->staticbinding = 1; 402 403 if(rp->dhcptype) 404 dhcp(rp); 405 else 406 bootp(rp); 407 timestamp("done"); 408 } 409 410 /* 411 * since we are single-threaded, this causes us to effectively 412 * stop listening for two seconds. 413 */ 414 static void 415 slowdelay(Req *rp) 416 { 417 if(slowstat && rp->staticbinding || slowdyn && !rp->staticbinding) 418 sleep(2000); 419 } 420 421 void 422 dhcp(Req *rp) 423 { 424 logdhcp(rp); 425 426 switch(rp->dhcptype){ 427 case Discover: 428 slowdelay(rp); 429 rcvdiscover(rp); 430 break; 431 case Request: 432 rcvrequest(rp); 433 break; 434 case Decline: 435 rcvdecline(rp); 436 break; 437 case Release: 438 rcvrelease(rp); 439 break; 440 case Inform: 441 rcvinform(rp); 442 break; 443 } 444 } 445 446 void 447 rcvdiscover(Req *rp) 448 { 449 Binding *b, *nb; 450 451 if(rp->staticbinding){ 452 sendoffer(rp, rp->ii.ipaddr, (staticlease > minlease? staticlease: minlease)); 453 return; 454 } 455 456 /* 457 * first look for an outstanding offer 458 */ 459 b = idtooffer(rp->id, &rp->gii); 460 461 /* 462 * rfc2131 says: 463 * If an address is available, the new address 464 * SHOULD be chosen as follows: 465 * 466 * o The client's current address as recorded in the client's current 467 * binding, ELSE 468 * 469 * o The client's previous address as recorded in the client's (now 470 * expired or released) binding, if that address is in the server's 471 * pool of available addresses and not already allocated, ELSE 472 * 473 * o The address requested in the 'Requested IP Address' option, if that 474 * address is valid and not already allocated, ELSE 475 * 476 * o A new address allocated from the server's pool of available 477 * addresses; the address is selected based on the subnet from which 478 * the message was received (if 'giaddr' is 0) or on the address of 479 * the relay agent that forwarded the message ('giaddr' when not 0). 480 */ 481 if(b == nil){ 482 b = idtobinding(rp->id, &rp->gii, 1); 483 if(b && b->boundto && strcmp(b->boundto, rp->id) != 0) 484 if(validip(rp->ip) && samenet(rp->ip, &rp->gii)){ 485 nb = iptobinding(rp->ip, 0); 486 if(nb && nb->lease < now) 487 b = nb; 488 } 489 } 490 if(b == nil){ 491 warning(0, "!Discover(%s via %I): no binding %I", 492 rp->id, rp->gii.ipaddr, rp->ip); 493 return; 494 } 495 mkoffer(b, rp->id, rp->leasetime); 496 sendoffer(rp, b->ip, b->offer); 497 } 498 499 void 500 rcvrequest(Req *rp) 501 { 502 Binding *b; 503 504 if(validip(rp->server)){ 505 /* this is a reply to an offer - SELECTING */ 506 507 /* check for hard assignment */ 508 if(rp->staticbinding){ 509 if(forme(rp->server)) 510 sendack(rp, rp->ii.ipaddr, 511 (staticlease > minlease? staticlease: 512 minlease), 1); 513 else 514 warning(0, "!Request(%s via %I): for server %I not me", 515 rp->id, rp->gii.ipaddr, rp->server); 516 return; 517 } 518 519 b = idtooffer(rp->id, &rp->gii); 520 521 /* if we don't have an offer, nak */ 522 if(b == nil){ 523 warning(0, "!Request(%s via %I): no offer", 524 rp->id, rp->gii.ipaddr); 525 if(forme(rp->server)) 526 sendnak(rp, "no offer for you"); 527 return; 528 } 529 530 /* if not for me, retract offer */ 531 if(!forme(rp->server)){ 532 b->expoffer = 0; 533 warning(0, "!Request(%s via %I): for server %I not me", 534 rp->id, rp->gii.ipaddr, rp->server); 535 return; 536 } 537 538 /* 539 * if the client is confused about what we offered, nak. 540 * client really shouldn't be specifying this when selecting 541 */ 542 if(validip(rp->ip) && ipcmp(rp->ip, b->ip) != 0){ 543 warning(0, "!Request(%s via %I): requests %I, not %I", 544 rp->id, rp->gii.ipaddr, rp->ip, b->ip); 545 sendnak(rp, "bad ip address option"); 546 return; 547 } 548 if(commitbinding(b) < 0){ 549 warning(0, "!Request(%s via %I): can't commit %I", 550 rp->id, rp->gii.ipaddr, b->ip); 551 sendnak(rp, "can't commit binding"); 552 return; 553 } 554 sendack(rp, b->ip, b->offer, 1); 555 } else if(validip(rp->ip)){ 556 /* 557 * checking address/net - INIT-REBOOT 558 * 559 * This is a rebooting client that remembers its old 560 * address. 561 */ 562 /* check for hard assignment */ 563 if(rp->staticbinding){ 564 if(memcmp(rp->ip, rp->ii.ipaddr, IPaddrlen) != 0){ 565 warning(0, "!Request(%s via %I): %I not valid for %E", 566 rp->id, rp->gii.ipaddr, rp->ip, rp->bp->chaddr); 567 sendnak(rp, "not valid"); 568 } 569 sendack(rp, rp->ii.ipaddr, (staticlease > minlease? 570 staticlease: minlease), 1); 571 return; 572 } 573 574 /* make sure the network makes sense */ 575 if(!samenet(rp->ip, &rp->gii)){ 576 warning(0, "!Request(%s via %I): bad forward of %I", 577 rp->id, rp->gii.ipaddr, rp->ip); 578 sendnak(rp, "wrong network"); 579 return; 580 } 581 b = iptobinding(rp->ip, 0); 582 if(b == nil){ 583 warning(0, "!Request(%s via %I): no binding for %I", 584 rp->id, rp->gii.ipaddr, rp->ip); 585 return; 586 } 587 if(memcmp(rp->ip, b->ip, IPaddrlen) != 0 || now > b->lease){ 588 warning(0, "!Request(%s via %I): %I not valid", 589 rp->id, rp->gii.ipaddr, rp->ip); 590 sendnak(rp, "not valid"); 591 return; 592 } 593 b->offer = b->lease - now; 594 sendack(rp, b->ip, b->offer, 1); 595 } else if(validip(rp->ciaddr)){ 596 /* 597 * checking address - RENEWING or REBINDING 598 * 599 * these states are indistinguishable in our action. The only 600 * difference is how close to lease expiration the client is. 601 * If it is really close, it broadcasts the request hoping that 602 * some server will answer. 603 */ 604 605 /* check for hard assignment */ 606 if(rp->staticbinding){ 607 if(ipcmp(rp->ciaddr, rp->ii.ipaddr) != 0){ 608 warning(0, "!Request(%s via %I): %I not valid", 609 rp->id, rp->gii.ipaddr, rp->ciaddr); 610 sendnak(rp, "not valid"); 611 } 612 sendack(rp, rp->ii.ipaddr, (staticlease > minlease? 613 staticlease: minlease), 1); 614 return; 615 } 616 617 /* make sure the network makes sense */ 618 if(!samenet(rp->ciaddr, &rp->gii)){ 619 warning(0, "!Request(%s via %I): bad forward of %I", 620 rp->id, rp->gii.ipaddr, rp->ip); 621 sendnak(rp, "wrong network"); 622 return; 623 } 624 b = iptobinding(rp->ciaddr, 0); 625 if(b == nil){ 626 warning(0, "!Request(%s via %I): no binding for %I", 627 rp->id, rp->gii.ipaddr, rp->ciaddr); 628 return; 629 } 630 if(ipcmp(rp->ciaddr, b->ip) != 0){ 631 warning(0, "!Request(%I via %s): %I not valid", 632 rp->id, rp->gii.ipaddr, rp->ciaddr); 633 sendnak(rp, "invalid ip address"); 634 return; 635 } 636 mkoffer(b, rp->id, rp->leasetime); 637 if(commitbinding(b) < 0){ 638 warning(0, "!Request(%s via %I): can't commit %I", 639 rp->id, rp->gii.ipaddr, b->ip); 640 sendnak(rp, "can't commit binding"); 641 return; 642 } 643 sendack(rp, b->ip, b->offer, 1); 644 } 645 } 646 647 void 648 rcvdecline(Req *rp) 649 { 650 Binding *b; 651 char buf[64]; 652 653 if(rp->staticbinding) 654 return; 655 656 b = idtooffer(rp->id, &rp->gii); 657 if(b == nil){ 658 warning(0, "!Decline(%s via %I): no binding", 659 rp->id, rp->gii.ipaddr); 660 return; 661 } 662 663 /* mark ip address as in use */ 664 snprint(buf, sizeof(buf), "declined by %s", rp->id); 665 mkoffer(b, buf, 0x7fffffff); 666 commitbinding(b); 667 } 668 669 void 670 rcvrelease(Req *rp) 671 { 672 Binding *b; 673 674 if(rp->staticbinding) 675 return; 676 677 b = idtobinding(rp->id, &rp->gii, 0); 678 if(b == nil){ 679 warning(0, "!Release(%s via %I): no binding", 680 rp->id, rp->gii.ipaddr); 681 return; 682 } 683 if(strcmp(rp->id, b->boundto) != 0){ 684 warning(0, "!Release(%s via %I): invalid release of %I", 685 rp->id, rp->gii.ipaddr, rp->ip); 686 return; 687 } 688 warning(0, "Release(%s via %I): releasing %I", b->boundto, rp->gii.ipaddr, b->ip); 689 if(releasebinding(b, rp->id) < 0) 690 warning(0, "release: couldn't release"); 691 } 692 693 void 694 rcvinform(Req *rp) 695 { 696 Binding *b; 697 698 if(rp->staticbinding){ 699 sendack(rp, rp->ii.ipaddr, 0, 0); 700 return; 701 } 702 703 b = iptobinding(rp->ciaddr, 0); 704 if(b == nil){ 705 warning(0, "!Inform(%s via %I): no binding for %I", 706 rp->id, rp->gii.ipaddr, rp->ip); 707 return; 708 } 709 sendack(rp, b->ip, 0, 0); 710 } 711 712 int 713 setsiaddr(uchar *siaddr, uchar *saddr, uchar *laddr) 714 { 715 if(ipcmp(saddr, IPnoaddr) != 0){ 716 v6tov4(siaddr, saddr); 717 return 0; 718 } else { 719 v6tov4(siaddr, laddr); 720 return 1; 721 } 722 } 723 724 int 725 ismuted(Req *rp) 726 { 727 return mute || (mutestat && rp->staticbinding); 728 } 729 730 void 731 sendoffer(Req *rp, uchar *ip, int offer) 732 { 733 int n; 734 ushort flags; 735 Bootp *bp; 736 Udphdr *up; 737 738 bp = rp->bp; 739 up = rp->up; 740 741 /* 742 * set destination 743 */ 744 flags = nhgets(bp->flags); 745 if(validip(rp->giaddr)){ 746 ipmove(up->raddr, rp->giaddr); 747 hnputs(up->rport, 67); 748 } else if(flags & Fbroadcast){ 749 ipmove(up->raddr, IPv4bcast); 750 hnputs(up->rport, 68); 751 } else { 752 ipmove(up->raddr, ip); 753 if(bp->htype == 1) 754 arpenter(up->raddr, bp->chaddr); 755 hnputs(up->rport, 68); 756 } 757 758 /* 759 * fill in standard bootp part 760 */ 761 bp->op = Bootreply; 762 bp->hops = 0; 763 hnputs(bp->secs, 0); 764 memset(bp->ciaddr, 0, sizeof(bp->ciaddr)); 765 v6tov4(bp->giaddr, rp->giaddr); 766 v6tov4(bp->yiaddr, ip); 767 setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr); 768 strncpy(bp->sname, mysysname, sizeof(bp->sname)); 769 strncpy(bp->file, rp->ii.bootf, sizeof(bp->file)); 770 771 /* 772 * set options 773 */ 774 byteopt(rp, ODtype, Offer); 775 longopt(rp, ODlease, offer); 776 addropt(rp, ODserverid, up->laddr); 777 miscoptions(rp, ip); 778 termopt(rp); 779 780 logdhcpout(rp, "Offer"); 781 782 /* 783 * send 784 */ 785 n = rp->p - rp->buf; 786 if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n) 787 warning(0, "offer: write failed: %r"); 788 } 789 790 void 791 sendack(Req *rp, uchar *ip, int offer, int sendlease) 792 { 793 int n; 794 ushort flags; 795 Bootp *bp; 796 Udphdr *up; 797 798 bp = rp->bp; 799 up = rp->up; 800 801 /* 802 * set destination 803 */ 804 flags = nhgets(bp->flags); 805 if(validip(rp->giaddr)){ 806 ipmove(up->raddr, rp->giaddr); 807 hnputs(up->rport, 67); 808 } else if(flags & Fbroadcast){ 809 ipmove(up->raddr, IPv4bcast); 810 hnputs(up->rport, 68); 811 } else { 812 ipmove(up->raddr, ip); 813 if(bp->htype == 1) 814 arpenter(up->raddr, bp->chaddr); 815 hnputs(up->rport, 68); 816 } 817 818 /* 819 * fill in standard bootp part 820 */ 821 bp->op = Bootreply; 822 bp->hops = 0; 823 hnputs(bp->secs, 0); 824 v6tov4(bp->giaddr, rp->giaddr); 825 v6tov4(bp->yiaddr, ip); 826 setsiaddr(bp->siaddr, rp->ii.tftp, up->laddr); 827 strncpy(bp->sname, mysysname, sizeof(bp->sname)); 828 strncpy(bp->file, rp->ii.bootf, sizeof(bp->file)); 829 830 /* 831 * set options 832 */ 833 byteopt(rp, ODtype, Ack); 834 if(sendlease){ 835 longopt(rp, ODlease, offer); 836 } 837 addropt(rp, ODserverid, up->laddr); 838 miscoptions(rp, ip); 839 termopt(rp); 840 841 logdhcpout(rp, "Ack"); 842 843 /* 844 * send 845 */ 846 n = rp->p - rp->buf; 847 if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n) 848 warning(0, "ack: write failed: %r"); 849 } 850 851 void 852 sendnak(Req *rp, char *msg) 853 { 854 int n; 855 Bootp *bp; 856 Udphdr *up; 857 858 bp = rp->bp; 859 up = rp->up; 860 861 /* 862 * set destination (always broadcast) 863 */ 864 if(validip(rp->giaddr)){ 865 ipmove(up->raddr, rp->giaddr); 866 hnputs(up->rport, 67); 867 } else { 868 ipmove(up->raddr, IPv4bcast); 869 hnputs(up->rport, 68); 870 } 871 872 /* 873 * fill in standard bootp part 874 */ 875 bp->op = Bootreply; 876 bp->hops = 0; 877 hnputs(bp->secs, 0); 878 v6tov4(bp->giaddr, rp->giaddr); 879 memset(bp->ciaddr, 0, sizeof(bp->ciaddr)); 880 memset(bp->yiaddr, 0, sizeof(bp->yiaddr)); 881 memset(bp->siaddr, 0, sizeof(bp->siaddr)); 882 883 /* 884 * set options 885 */ 886 byteopt(rp, ODtype, Nak); 887 addropt(rp, ODserverid, up->laddr); 888 if(msg) 889 stringopt(rp, ODmessage, msg); 890 if(strncmp(rp->id, "id", 2) == 0) 891 hexopt(rp, ODclientid, rp->id+2); 892 termopt(rp); 893 894 logdhcpout(rp, "Nak"); 895 896 /* 897 * send nak 898 */ 899 n = rp->p - rp->buf; 900 if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n) 901 warning(0, "nak: write failed: %r"); 902 } 903 904 void 905 bootp(Req *rp) 906 { 907 int n; 908 Bootp *bp; 909 Udphdr *up; 910 ushort flags; 911 Iplifc *lifc; 912 Info *iip; 913 914 warning(0, "bootp %s %I->%I from %s via %I, file %s %s", 915 rp->genrequest? "generic": (rp->p9request? "p9": ""), 916 rp->up->raddr, rp->up->laddr, 917 rp->id, rp->gii.ipaddr, 918 rp->bp->file, rp->broadcast? "broadcast": "unicast"); 919 920 if(nobootp) 921 return; 922 923 bp = rp->bp; 924 up = rp->up; 925 iip = &rp->ii; 926 927 if(rp->staticbinding == 0){ 928 warning(0, "bootp from unknown %s via %I", rp->id, rp->gii.ipaddr); 929 return; 930 } 931 932 /* ignore if not for us */ 933 if(*bp->sname){ 934 if(strcmp(bp->sname, mysysname) != 0){ 935 bp->sname[20] = 0; 936 warning(0, "bootp for server %s", bp->sname); 937 return; 938 } 939 } else 940 slowdelay(rp); 941 942 /* ignore if we don't know what file to load */ 943 if(*bp->file == 0){ 944 if(rp->genrequest && *iip->bootf2) /* if not plan 9 & have alternate file... */ 945 strncpy(bp->file, iip->bootf2, sizeof(bp->file)); 946 else if(*iip->bootf) 947 strncpy(bp->file, iip->bootf, sizeof(bp->file)); 948 else if(*bp->sname) /* if we were asked, respond no matter what */ 949 bp->file[0] = '\0'; 950 else { 951 warning(0, "no bootfile for %I", iip->ipaddr); 952 return; 953 } 954 } 955 956 /* ignore if the file is unreadable */ 957 if((!rp->genrequest) && bp->file[0] && access(bp->file, 4) < 0){ 958 warning(0, "inaccessible bootfile1 %s", bp->file); 959 return; 960 } 961 962 bp->op = Bootreply; 963 v6tov4(bp->yiaddr, iip->ipaddr); 964 if(rp->p9request){ 965 warning(0, "p9bootp: %I", iip->ipaddr); 966 memmove(bp->optmagic, plan9opt, 4); 967 if(iip->gwip == 0) 968 v4tov6(iip->gwip, bp->giaddr); 969 rp->p += sprint((char*)rp->p, "%V %I %I %I", iip->ipmask+IPv4off, iip->fsip, 970 iip->auip, iip->gwip); 971 sprint(optbuf, "%s", (char*)(bp->optmagic)); 972 } else if(rp->genrequest){ 973 warning(0, "genericbootp: %I", iip->ipaddr); 974 memmove(bp->optmagic, genericopt, 4); 975 miscoptions(rp, iip->ipaddr); 976 termopt(rp); 977 } else if(iip->vendor[0] != 0) { 978 warning(0, "bootp vendor field: %s", iip->vendor); 979 memset(rp->p, 0, 128-4); 980 rp->p += sprint((char*)bp->optmagic, "%s", iip->vendor); 981 } else { 982 memset(rp->p, 0, 128-4); 983 rp->p += 128-4; 984 } 985 986 /* 987 * set destination 988 */ 989 flags = nhgets(bp->flags); 990 if(validip(rp->giaddr)){ 991 ipmove(up->raddr, rp->giaddr); 992 hnputs(up->rport, 67); 993 } else if(flags & Fbroadcast){ 994 ipmove(up->raddr, IPv4bcast); 995 hnputs(up->rport, 68); 996 } else { 997 v4tov6(up->raddr, bp->yiaddr); 998 if(bp->htype == 1) 999 arpenter(up->raddr, bp->chaddr); 1000 hnputs(up->rport, 68); 1001 } 1002 1003 /* 1004 * select best local address if destination is directly connected 1005 */ 1006 lifc = findlifc(up->raddr); 1007 if(lifc) 1008 ipmove(up->laddr, lifc->ip); 1009 1010 /* 1011 * our identity 1012 */ 1013 strncpy(bp->sname, mysysname, sizeof(bp->sname)); 1014 1015 /* 1016 * set tftp server 1017 */ 1018 setsiaddr(bp->siaddr, iip->tftp, up->laddr); 1019 if(rp->genrequest && *iip->bootf2) 1020 setsiaddr(bp->siaddr, iip->tftp2, up->laddr); 1021 1022 /* 1023 * RFC 1048 says that we must pad vendor field with 1024 * zeros until we have a 64 byte field. 1025 */ 1026 n = rp->p - rp->bp->optdata; 1027 if(n < 64-4) { 1028 memset(rp->p, 0, (64-4)-n); 1029 rp->p += (64-4)-n; 1030 } 1031 1032 /* 1033 * send 1034 */ 1035 n = rp->p - rp->buf; 1036 if(!ismuted(rp) && write(rp->fd, rp->buf, n) != n) 1037 warning(0, "bootp: write failed: %r"); 1038 1039 warning(0, "bootp via %I: file %s xid(%ux)flag(%ux)ci(%V)gi(%V)yi(%V)si(%V) %s", 1040 up->raddr, bp->file, nhgetl(bp->xid), nhgets(bp->flags), 1041 bp->ciaddr, bp->giaddr, bp->yiaddr, bp->siaddr, 1042 optbuf); 1043 } 1044 1045 void 1046 parseoptions(Req *rp) 1047 { 1048 int n, c, code; 1049 uchar *o, *p; 1050 1051 p = rp->p; 1052 1053 while(p < rp->e){ 1054 code = *p++; 1055 if(code == 255) 1056 break; 1057 if(code == 0) 1058 continue; 1059 1060 /* ignore anything that's too long */ 1061 n = *p++; 1062 o = p; 1063 p += n; 1064 if(p > rp->e) 1065 return; 1066 1067 switch(code){ 1068 case ODipaddr: /* requested ip address */ 1069 if(n == IPv4addrlen) 1070 v4tov6(rp->ip, o); 1071 break; 1072 case ODlease: /* requested lease time */ 1073 rp->leasetime = nhgetl(o); 1074 if(rp->leasetime > MaxLease || rp->leasetime < 0) 1075 rp->leasetime = MaxLease; 1076 break; 1077 case ODtype: 1078 c = *o; 1079 if(c < 10 && c > 0) 1080 rp->dhcptype = c; 1081 break; 1082 case ODserverid: 1083 if(n == IPv4addrlen) 1084 v4tov6(rp->server, o); 1085 break; 1086 case ODmessage: 1087 if(n > sizeof rp->msg-1) 1088 n = sizeof rp->msg-1; 1089 memmove(rp->msg, o, n); 1090 rp->msg[n] = 0; 1091 break; 1092 case ODmaxmsg: 1093 c = nhgets(o); 1094 c -= 28; 1095 c += Udphdrsize; 1096 if(c > 0) 1097 rp->max = rp->buf + c; 1098 break; 1099 case ODclientid: 1100 if(n <= 1) 1101 break; 1102 rp->id = toid( o, n); 1103 break; 1104 case ODparams: 1105 if(n > sizeof(rp->requested)) 1106 n = sizeof(rp->requested); 1107 memmove(rp->requested, o, n); 1108 break; 1109 case ODvendorclass: 1110 if(n >= sizeof(rp->vendorclass)) 1111 n = sizeof(rp->vendorclass)-1; 1112 memmove(rp->vendorclass, o, n); 1113 rp->vendorclass[n] = 0; 1114 if(strncmp((char*)rp->vendorclass, "p9-", 3) == 0) 1115 strcpy(rp->cputype, (char*)rp->vendorclass+3); 1116 break; 1117 case OBend: 1118 return; 1119 } 1120 } 1121 } 1122 1123 void 1124 remrequested(Req *rp, int opt) 1125 { 1126 uchar *p; 1127 1128 p = memchr(rp->requested, opt, sizeof(rp->requested)); 1129 if(p != nil) 1130 *p = OBpad; 1131 } 1132 1133 void 1134 miscoptions(Req *rp, uchar *ip) 1135 { 1136 int i, j, na; 1137 uchar x[2*IPaddrlen], vopts[Maxoptlen]; 1138 uchar *op, *omax; 1139 uchar *addrs[2]; 1140 char *p; 1141 char *attr[100], **a; 1142 Ndbtuple *t; 1143 1144 addrs[0] = x; 1145 addrs[1] = x+IPaddrlen; 1146 1147 /* always supply these */ 1148 maskopt(rp, OBmask, rp->gii.ipmask); 1149 if(validip(rp->gii.gwip)){ 1150 remrequested(rp, OBrouter); 1151 addropt(rp, OBrouter, rp->gii.gwip); 1152 } else if(validip(rp->giaddr)){ 1153 remrequested(rp, OBrouter); 1154 addropt(rp, OBrouter, rp->giaddr); 1155 } 1156 1157 /* 1158 * OBhostname for the HP4000M switches 1159 * (this causes NT to log infinite errors - tough shit) 1160 */ 1161 if(*rp->ii.domain){ 1162 remrequested(rp, OBhostname); 1163 stringopt(rp, OBhostname, rp->ii.domain); 1164 } 1165 if(*rp->ii.rootpath) 1166 stringopt(rp, OBrootpath, rp->ii.rootpath); 1167 1168 /* figure out what we need to lookup */ 1169 na = 0; 1170 a = attr; 1171 if(*rp->ii.domain == 0) 1172 a[na++] = "dom"; 1173 for(i = 0; i < sizeof(rp->requested); i++) 1174 switch(rp->requested[i]){ 1175 case OBrouter: 1176 a[na++] = "@ipgw"; 1177 break; 1178 case OBdnserver: 1179 a[na++] = "@dns"; 1180 break; 1181 case OBnetbiosns: 1182 a[na++] = "@wins"; 1183 break; 1184 case OBsmtpserver: 1185 a[na++] = "@smtp"; 1186 break; 1187 case OBpop3server: 1188 a[na++] = "@pop3"; 1189 break; 1190 case OBwwwserver: 1191 a[na++] = "@www"; 1192 break; 1193 case OBntpserver: 1194 a[na++] = "@ntp"; 1195 break; 1196 case OBtimeserver: 1197 a[na++] = "@time"; 1198 break; 1199 } 1200 if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0 1201 || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){ 1202 a[na++] = "@fs"; 1203 a[na++] = "@auth"; 1204 } 1205 t = lookupinfo(ip, a, na); 1206 1207 /* lookup anything we might be missing */ 1208 if(*rp->ii.domain == 0) 1209 lookupname(rp->ii.domain, t); 1210 1211 /* add any requested ones that we know about */ 1212 for(i = 0; i < sizeof(rp->requested); i++) 1213 switch(rp->requested[i]){ 1214 case OBrouter: 1215 j = lookupserver("ipgw", addrs, t); 1216 addrsopt(rp, OBrouter, addrs, j); 1217 break; 1218 case OBdnserver: 1219 j = lookupserver("dns", addrs, t); 1220 addrsopt(rp, OBdnserver, addrs, j); 1221 break; 1222 case OBhostname: 1223 if(*rp->ii.domain) 1224 stringopt(rp, OBhostname, rp->ii.domain); 1225 break; 1226 case OBdomainname: 1227 p = strchr(rp->ii.domain, '.'); 1228 if(p) 1229 stringopt(rp, OBdomainname, p+1); 1230 break; 1231 case OBnetbiosns: 1232 j = lookupserver("wins", addrs, t); 1233 addrsopt(rp, OBnetbiosns, addrs, j); 1234 break; 1235 case OBnetbiostype: 1236 /* p-node: peer to peer WINS queries */ 1237 byteopt(rp, OBnetbiostype, 0x2); 1238 break; 1239 case OBsmtpserver: 1240 j = lookupserver("smtp", addrs, t); 1241 addrsopt(rp, OBsmtpserver, addrs, j); 1242 break; 1243 case OBpop3server: 1244 j = lookupserver("pop3", addrs, t); 1245 addrsopt(rp, OBpop3server, addrs, j); 1246 break; 1247 case OBwwwserver: 1248 j = lookupserver("www", addrs, t); 1249 addrsopt(rp, OBwwwserver, addrs, j); 1250 break; 1251 case OBntpserver: 1252 j = lookupserver("ntp", addrs, t); 1253 addrsopt(rp, OBntpserver, addrs, j); 1254 break; 1255 case OBtimeserver: 1256 j = lookupserver("time", addrs, t); 1257 addrsopt(rp, OBtimeserver, addrs, j); 1258 break; 1259 case OBttl: 1260 byteopt(rp, OBttl, 255); 1261 break; 1262 } 1263 1264 /* add plan9 specific options */ 1265 if(strncmp((char*)rp->vendorclass, "plan9_", 6) == 0 1266 || strncmp((char*)rp->vendorclass, "p9-", 3) == 0){ 1267 /* point to temporary area */ 1268 op = rp->p; 1269 omax = rp->max; 1270 /* stash encoded options in vopts */ 1271 rp->p = vopts; 1272 rp->max = vopts + sizeof(vopts) - 1; 1273 1274 /* emit old v4 addresses first to make sure that they fit */ 1275 addrsopt(rp, OP9fsv4, addrs, lookupserver("fs", addrs, t)); 1276 addrsopt(rp, OP9authv4, addrs, lookupserver("auth", addrs, t)); 1277 1278 p9addrsopt(rp, OP9fs, addrs, lookupserver("fs", addrs, t)); 1279 p9addrsopt(rp, OP9auth, addrs, lookupserver("auth", addrs, t)); 1280 p9addrsopt(rp, OP9ipaddr, addrs, lookupserver("ip", addrs, t)); 1281 p9addrsopt(rp, OP9ipmask, addrs, lookupserver("ipmask", addrs, t)); 1282 p9addrsopt(rp, OP9ipgw, addrs, lookupserver("ipgw", addrs, t)); 1283 1284 /* point back to packet, encapsulate vopts into packet */ 1285 j = rp->p - vopts; 1286 rp->p = op; 1287 rp->max = omax; 1288 vectoropt(rp, OBvendorinfo, vopts, j); 1289 } 1290 1291 ndbfree(t); 1292 } 1293 1294 int 1295 openlisten(char *net) 1296 { 1297 int fd, cfd; 1298 char data[128], devdir[40]; 1299 1300 sprint(data, "%s/udp!*!bootp", net); 1301 cfd = announce(data, devdir); 1302 if(cfd < 0) 1303 fatal(1, "can't announce"); 1304 if(fprint(cfd, "headers") < 0) 1305 fatal(1, "can't set header mode"); 1306 1307 sprint(data, "%s/data", devdir); 1308 fd = open(data, ORDWR); 1309 if(fd < 0) 1310 fatal(1, "open udp data"); 1311 return fd; 1312 } 1313 1314 void 1315 fatal(int syserr, char *fmt, ...) 1316 { 1317 char buf[Maxloglen]; 1318 va_list arg; 1319 1320 va_start(arg, fmt); 1321 vseprint(buf, buf+sizeof(buf), fmt, arg); 1322 va_end(arg); 1323 if(syserr) 1324 syslog(1, blog, "%s: %r", buf); 1325 else 1326 syslog(1, blog, "%s", buf); 1327 exits(buf); 1328 } 1329 1330 void 1331 warning(int syserr, char *fmt, ...) 1332 { 1333 char buf[Maxloglen]; 1334 va_list arg; 1335 1336 va_start(arg, fmt); 1337 vseprint(buf, buf+sizeof(buf), fmt, arg); 1338 va_end(arg); 1339 if(syserr){ 1340 syslog(0, blog, "%s: %r", buf); 1341 if(debug) 1342 fprint(2, "%s: %r\n", buf); 1343 } else { 1344 syslog(0, blog, "%s", buf); 1345 if(debug) 1346 fprint(2, "%s\n", buf); 1347 } 1348 } 1349 1350 char* 1351 readsysname(void) 1352 { 1353 static char name[128]; 1354 char *p; 1355 int n, fd; 1356 1357 fd = open("/dev/sysname", OREAD); 1358 if(fd >= 0){ 1359 n = read(fd, name, sizeof(name)-1); 1360 close(fd); 1361 if(n > 0){ 1362 name[n] = 0; 1363 return name; 1364 } 1365 } 1366 p = getenv("sysname"); 1367 if(p == nil || *p == 0) 1368 return "unknown"; 1369 return p; 1370 } 1371 1372 extern int 1373 validip(uchar *ip) 1374 { 1375 if(ipcmp(ip, IPnoaddr) == 0) 1376 return 0; 1377 if(ipcmp(ip, v4prefix) == 0) 1378 return 0; 1379 return 1; 1380 } 1381 1382 void 1383 longopt(Req *rp, int t, long v) 1384 { 1385 if(rp->p + 6 > rp->max) 1386 return; 1387 *rp->p++ = t; 1388 *rp->p++ = 4; 1389 hnputl(rp->p, v); 1390 rp->p += 4; 1391 1392 op = seprint(op, oe, "%s(%ld)", optname[t], v); 1393 } 1394 1395 void 1396 addropt(Req *rp, int t, uchar *ip) 1397 { 1398 if(rp->p + 6 > rp->max) 1399 return; 1400 if (!isv4(ip)) { 1401 if (debug) 1402 warning(0, "not a v4 %s server: %I", optname[t], ip); 1403 return; 1404 } 1405 *rp->p++ = t; 1406 *rp->p++ = 4; 1407 memmove(rp->p, ip+IPv4off, 4); 1408 rp->p += 4; 1409 1410 op = seprint(op, oe, "%s(%I)", optname[t], ip); 1411 } 1412 1413 void 1414 maskopt(Req *rp, int t, uchar *ip) 1415 { 1416 if(rp->p + 6 > rp->max) 1417 return; 1418 *rp->p++ = t; 1419 *rp->p++ = 4; 1420 memmove(rp->p, ip+IPv4off, 4); 1421 rp->p += 4; 1422 1423 op = seprint(op, oe, "%s(%M)", optname[t], ip); 1424 } 1425 1426 void 1427 addrsopt(Req *rp, int t, uchar **ip, int i) 1428 { 1429 int v4s, n; 1430 1431 if(i <= 0) 1432 return; 1433 if(rp->p + 2 + 4*i > rp->max) 1434 return; 1435 v4s = 0; 1436 for(n = i; n-- > 0; ) 1437 if (isv4(ip[n])) 1438 v4s++; 1439 if (v4s <= 0) { 1440 if (debug) 1441 warning(0, "no v4 %s servers", optname[t]); 1442 return; 1443 } 1444 *rp->p++ = t; 1445 *rp->p++ = 4*v4s; 1446 op = seprint(op, oe, " %s(", optname[t]); 1447 while(i-- > 0){ 1448 if (!isv4(*ip)) { 1449 op = seprint(op, oe, " skipping %I ", *ip); 1450 continue; 1451 } 1452 v6tov4(rp->p, *ip); 1453 rp->p += 4; 1454 op = seprint(op, oe, "%I", *ip); 1455 ip++; 1456 if(i > 0) 1457 op = seprint(op, oe, " "); 1458 } 1459 op = seprint(op, oe, ")"); 1460 } 1461 1462 void 1463 p9addrsopt(Req *rp, int t, uchar **ip, int i) 1464 { 1465 char *pkt, *payload; 1466 1467 if(i <= 0 || !v6opts) 1468 return; 1469 pkt = (char *)rp->p; 1470 *pkt++ = t; /* option */ 1471 pkt++; /* fill in payload length below */ 1472 payload = pkt; 1473 *pkt++ = i; /* plan 9 address count */ 1474 op = seprint(op, oe, " %s(", optname[t]); 1475 while(i-- > 0){ 1476 pkt = seprint(pkt, (char *)rp->max, "%I", *ip); 1477 if ((uchar *)pkt+1 >= rp->max) { 1478 op = seprint(op, oe, "<out of mem1>)"); 1479 return; 1480 } 1481 pkt++; /* leave NUL as terminator */ 1482 op = seprint(op, oe, "%I", *ip); 1483 ip++; 1484 if(i > 0) 1485 op = seprint(op, oe, " "); 1486 } 1487 if ((uchar *)pkt - rp->p > 0377) { 1488 op = seprint(op, oe, "<out of mem2>)"); 1489 return; 1490 } 1491 op = seprint(op, oe, ")"); 1492 rp->p[1] = pkt - payload; /* payload length */ 1493 rp->p = (uchar *)pkt; 1494 } 1495 1496 void 1497 byteopt(Req *rp, int t, uchar v) 1498 { 1499 if(rp->p + 3 > rp->max) 1500 return; 1501 *rp->p++ = t; 1502 *rp->p++ = 1; 1503 *rp->p++ = v; 1504 1505 op = seprint(op, oe, "%s(%d)", optname[t], v); 1506 } 1507 1508 void 1509 termopt(Req *rp) 1510 { 1511 if(rp->p + 1 > rp->max) 1512 return; 1513 *rp->p++ = OBend; 1514 } 1515 1516 void 1517 stringopt(Req *rp, int t, char *str) 1518 { 1519 int n; 1520 1521 n = strlen(str); 1522 if(n > 255) 1523 n = 255; 1524 if(rp->p+n+2 > rp->max) 1525 return; 1526 *rp->p++ = t; 1527 *rp->p++ = n; 1528 memmove(rp->p, str, n); 1529 rp->p += n; 1530 1531 op = seprint(op, oe, "%s(%s)", optname[t], str); 1532 } 1533 1534 void 1535 vectoropt(Req *rp, int t, uchar *v, int n) 1536 { 1537 int i; 1538 1539 if(n > 255) { 1540 n = 255; 1541 op = seprint(op, oe, "vectoropt len %d > 255 ", n); 1542 } 1543 if(rp->p+n+2 > rp->max) 1544 return; 1545 *rp->p++ = t; 1546 *rp->p++ = n; 1547 memmove(rp->p, v, n); 1548 rp->p += n; 1549 1550 op = seprint(op, oe, "%s(", optname[t]); 1551 if(n > 0) 1552 op = seprint(op, oe, "%ud", v[0]); 1553 for(i = 1; i < n; i++) 1554 op = seprint(op, oe, " %ud", v[i]); 1555 op = seprint(op, oe, ")"); 1556 } 1557 1558 int 1559 fromhex(int x) 1560 { 1561 if(x >= '0' && x <= '9') 1562 return x - '0'; 1563 return x - 'a'; 1564 } 1565 1566 void 1567 hexopt(Req *rp, int t, char *str) 1568 { 1569 int n; 1570 1571 n = strlen(str); 1572 n /= 2; 1573 if(n > 255) 1574 n = 255; 1575 if(rp->p+n+2 > rp->max) 1576 return; 1577 *rp->p++ = t; 1578 *rp->p++ = n; 1579 while(n-- > 0){ 1580 *rp->p++ = (fromhex(str[0])<<4)|fromhex(str[1]); 1581 str += 2; 1582 } 1583 1584 op = seprint(op, oe, "%s(%s)", optname[t], str); 1585 } 1586 1587 void 1588 arpenter(uchar *ip, uchar *ether) 1589 { 1590 int f; 1591 char buf[256]; 1592 1593 sprint(buf, "%s/arp", net); 1594 f = open(buf, OWRITE); 1595 if(f < 0){ 1596 syslog(debug, blog, "open %s: %r", buf); 1597 return; 1598 } 1599 fprint(f, "add ether %I %E", ip, ether); 1600 close(f); 1601 } 1602 1603 char *dhcpmsgname[] = 1604 { 1605 [Discover] "Discover", 1606 [Offer] "Offer", 1607 [Request] "Request", 1608 [Decline] "Decline", 1609 [Ack] "Ack", 1610 [Nak] "Nak", 1611 [Release] "Release", 1612 [Inform] "Inform", 1613 }; 1614 1615 void 1616 logdhcp(Req *rp) 1617 { 1618 char buf[4096]; 1619 char *p, *e; 1620 int i; 1621 1622 p = buf; 1623 e = buf + sizeof(buf); 1624 if(rp->dhcptype > 0 && rp->dhcptype <= Inform) 1625 p = seprint(p, e, "%s(", dhcpmsgname[rp->dhcptype]); 1626 else 1627 p = seprint(p, e, "%d(", rp->dhcptype); 1628 p = seprint(p, e, "%I->%I) xid(%ux)flag(%ux)", rp->up->raddr, rp->up->laddr, 1629 nhgetl(rp->bp->xid), nhgets(rp->bp->flags)); 1630 if(rp->bp->htype == 1) 1631 p = seprint(p, e, "ea(%E)", rp->bp->chaddr); 1632 if(validip(rp->ciaddr)) 1633 p = seprint(p, e, "ci(%I)", rp->ciaddr); 1634 if(validip(rp->giaddr)) 1635 p = seprint(p, e, "gi(%I)", rp->giaddr); 1636 if(validip(rp->ip)) 1637 p = seprint(p, e, "ip(%I)", rp->ip); 1638 if(rp->id != nil) 1639 p = seprint(p, e, "id(%s)", rp->id); 1640 if(rp->leasetime) 1641 p = seprint(p, e, "leas(%d)", rp->leasetime); 1642 if(validip(rp->server)) 1643 p = seprint(p, e, "sid(%I)", rp->server); 1644 p = seprint(p, e, "need("); 1645 for(i = 0; i < sizeof(rp->requested); i++) 1646 if(rp->requested[i] != 0) 1647 p = seprint(p, e, "%s ", optname[rp->requested[i]]); 1648 p = seprint(p, e, ")"); 1649 p = seprint(p, e, " %s", rp->broadcast? "broadcast": "unicast"); 1650 USED(p); 1651 syslog(0, blog, "%s", buf); 1652 } 1653 1654 void 1655 logdhcpout(Req *rp, char *type) 1656 { 1657 syslog(0, blog, "%s(%I-%I)id(%s)ci(%V)gi(%V)yi(%V)si(%V) %s", 1658 type, rp->up->laddr, rp->up->raddr, rp->id, 1659 rp->bp->ciaddr, rp->bp->giaddr, rp->bp->yiaddr, rp->bp->siaddr, optbuf); 1660 } 1661 1662 /* 1663 * if we get behind, it's useless to try answering since the sender 1664 * will probably have retransmitted with a differnt sequence number. 1665 * So dump all but the last message in the queue. 1666 */ 1667 void 1668 ding(void*, char *msg) 1669 { 1670 if(strstr(msg, "alarm")) 1671 noted(NCONT); 1672 else 1673 noted(NDFLT); 1674 } 1675 1676 int 1677 readlast(int fd, uchar *buf, int len) 1678 { 1679 int lastn, n; 1680 1681 notify(ding); 1682 1683 lastn = 0; 1684 for(;;){ 1685 alarm(20); 1686 n = read(fd, buf, len); 1687 alarm(0); 1688 if(n < 0){ 1689 if(lastn > 0) 1690 return lastn; 1691 break; 1692 } 1693 lastn = n; 1694 } 1695 return read(fd, buf, len); 1696 } 1697