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