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