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