1 /* $OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $ */ 2 3 /* 4 * Copyright 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 1995, 1996, 1997, 1998, 1999 6 * The Internet Software Consortium. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of The Internet Software Consortium nor the names 18 * of its contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 22 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * This software has been written for the Internet Software Consortium 36 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 37 * Enterprises. To learn more about the Internet Software Consortium, 38 * see ``http://www.vix.com/isc''. To learn more about Vixie 39 * Enterprises, see ``http://www.vix.com''. 40 * 41 * This client was substantially modified and enhanced by Elliot Poger 42 * for use on Linux while he was working on the MosquitoNet project at 43 * Stanford. 44 * 45 * The current version owes much to Elliot's Linux enhancements, but 46 * was substantially reorganized and partially rewritten by Ted Lemon 47 * so as to use the same networking framework that the Internet Software 48 * Consortium DHCP server uses. Much system-specific configuration code 49 * was moved into a shell script so that as support for more operating 50 * systems is added, it will not be necessary to port and maintain 51 * system-specific configuration code to these operating systems - instead, 52 * the shell script can invoke the native tools to accomplish the same 53 * purpose. 54 */ 55 56 #include <rosdhcp.h> 57 58 #define PERIOD 0x2e 59 #define hyphenchar(c) ((c) == 0x2d) 60 #define bslashchar(c) ((c) == 0x5c) 61 #define periodchar(c) ((c) == PERIOD) 62 #define asterchar(c) ((c) == 0x2a) 63 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \ 64 ((c) >= 0x61 && (c) <= 0x7a)) 65 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) 66 67 #define borderchar(c) (alphachar(c) || digitchar(c)) 68 #define middlechar(c) (borderchar(c) || hyphenchar(c)) 69 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f) 70 71 unsigned long debug_trace_level = 0; /* DEBUG_ULTRA */ 72 73 char *path_dhclient_conf = _PATH_DHCLIENT_CONF; 74 char *path_dhclient_db = NULL; 75 76 int log_perror = 1; 77 int privfd; 78 //int nullfd = -1; 79 80 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; 81 struct in_addr inaddr_any; 82 struct sockaddr_in sockaddr_broadcast; 83 84 /* 85 * ASSERT_STATE() does nothing now; it used to be 86 * assert (state_is == state_shouldbe). 87 */ 88 #define ASSERT_STATE(state_is, state_shouldbe) {} 89 90 #define TIME_MAX 2147483647 91 92 int log_priority; 93 int no_daemon; 94 int unknown_ok = 1; 95 int routefd; 96 97 void usage(void); 98 int check_option(struct client_lease *l, int option); 99 int ipv4addrs(char * buf); 100 int res_hnok(const char *dn); 101 char *option_as_string(unsigned int code, unsigned char *data, int len); 102 int fork_privchld(int, int); 103 int check_arp( struct interface_info *ip, struct client_lease *lp ); 104 105 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 106 107 time_t scripttime; 108 109 110 int 111 init_client(void) 112 { 113 ApiInit(); 114 AdapterInit(); 115 116 tzset(); 117 118 memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast)); 119 sockaddr_broadcast.sin_family = AF_INET; 120 sockaddr_broadcast.sin_port = htons(REMOTE_PORT); 121 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; 122 inaddr_any.s_addr = INADDR_ANY; 123 bootp_packet_handler = do_packet; 124 125 return 1; // TRUE 126 } 127 128 void 129 stop_client(void) 130 { 131 // AdapterStop(); 132 // ApiFree(); 133 /* FIXME: Close pipe and kill pipe thread */ 134 } 135 136 /* XXX Implement me */ 137 int check_arp( struct interface_info *ip, struct client_lease *lp ) { 138 return 1; 139 } 140 141 /* 142 * Individual States: 143 * 144 * Each routine is called from the dhclient_state_machine() in one of 145 * these conditions: 146 * -> entering INIT state 147 * -> recvpacket_flag == 0: timeout in this state 148 * -> otherwise: received a packet in this state 149 * 150 * Return conditions as handled by dhclient_state_machine(): 151 * Returns 1, sendpacket_flag = 1: send packet, reset timer. 152 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). 153 * Returns 0: finish the nap which was interrupted for no good reason. 154 * 155 * Several per-interface variables are used to keep track of the process: 156 * active_lease: the lease that is being used on the interface 157 * (null pointer if not configured yet). 158 * offered_leases: leases corresponding to DHCPOFFER messages that have 159 * been sent to us by DHCP servers. 160 * acked_leases: leases corresponding to DHCPACK messages that have been 161 * sent to us by DHCP servers. 162 * sendpacket: DHCP packet we're trying to send. 163 * destination: IP address to send sendpacket to 164 * In addition, there are several relevant per-lease variables. 165 * T1_expiry, T2_expiry, lease_expiry: lease milestones 166 * In the active lease, these control the process of renewing the lease; 167 * In leases on the acked_leases list, this simply determines when we 168 * can no longer legitimately use the lease. 169 */ 170 171 void 172 state_reboot(void *ipp) 173 { 174 struct interface_info *ip = ipp; 175 ULONG foo = (ULONG) GetTickCount(); 176 177 /* If we don't remember an active lease, go straight to INIT. */ 178 if (!ip->client->active || ip->client->active->is_bootp) { 179 state_init(ip); 180 return; 181 } 182 183 /* We are in the rebooting state. */ 184 ip->client->state = S_REBOOTING; 185 186 /* make_request doesn't initialize xid because it normally comes 187 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, 188 so pick an xid now. */ 189 ip->client->xid = RtlRandom(&foo); 190 191 /* Make a DHCPREQUEST packet, and set appropriate per-interface 192 flags. */ 193 make_request(ip, ip->client->active); 194 ip->client->destination = iaddr_broadcast; 195 time(&ip->client->first_sending); 196 ip->client->interval = ip->client->config->initial_interval; 197 198 /* Zap the medium list... */ 199 ip->client->medium = NULL; 200 201 /* Send out the first DHCPREQUEST packet. */ 202 send_request(ip); 203 } 204 205 /* 206 * Called when a lease has completely expired and we've 207 * been unable to renew it. 208 */ 209 void 210 state_init(void *ipp) 211 { 212 struct interface_info *ip = ipp; 213 214 ASSERT_STATE(state, S_INIT); 215 216 /* Make a DHCPDISCOVER packet, and set appropriate per-interface 217 flags. */ 218 make_discover(ip, ip->client->active); 219 ip->client->xid = ip->client->packet.xid; 220 ip->client->destination = iaddr_broadcast; 221 ip->client->state = S_SELECTING; 222 time(&ip->client->first_sending); 223 ip->client->interval = ip->client->config->initial_interval; 224 225 /* Add an immediate timeout to cause the first DHCPDISCOVER packet 226 to go out. */ 227 send_discover(ip); 228 } 229 230 /* 231 * state_selecting is called when one or more DHCPOFFER packets 232 * have been received and a configurable period of time has passed. 233 */ 234 void 235 state_selecting(void *ipp) 236 { 237 struct interface_info *ip = ipp; 238 struct client_lease *lp, *next, *picked; 239 time_t cur_time; 240 241 ASSERT_STATE(state, S_SELECTING); 242 243 time(&cur_time); 244 245 /* Cancel state_selecting and send_discover timeouts, since either 246 one could have got us here. */ 247 cancel_timeout(state_selecting, ip); 248 cancel_timeout(send_discover, ip); 249 250 /* We have received one or more DHCPOFFER packets. Currently, 251 the only criterion by which we judge leases is whether or 252 not we get a response when we arp for them. */ 253 picked = NULL; 254 for (lp = ip->client->offered_leases; lp; lp = next) { 255 next = lp->next; 256 257 /* Check to see if we got an ARPREPLY for the address 258 in this particular lease. */ 259 if (!picked) { 260 if( !check_arp(ip,lp) ) goto freeit; 261 picked = lp; 262 picked->next = NULL; 263 } else { 264 freeit: 265 free_client_lease(lp); 266 } 267 } 268 ip->client->offered_leases = NULL; 269 270 /* If we just tossed all the leases we were offered, go back 271 to square one. */ 272 if (!picked) { 273 ip->client->state = S_INIT; 274 state_init(ip); 275 return; 276 } 277 278 /* If it was a BOOTREPLY, we can just take the address right now. */ 279 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) { 280 ip->client->new = picked; 281 282 /* Make up some lease expiry times 283 XXX these should be configurable. */ 284 ip->client->new->expiry = cur_time + 12000; 285 ip->client->new->renewal += cur_time + 8000; 286 ip->client->new->rebind += cur_time + 10000; 287 288 ip->client->state = S_REQUESTING; 289 290 /* Bind to the address we received. */ 291 bind_lease(ip); 292 return; 293 } 294 295 /* Go to the REQUESTING state. */ 296 ip->client->destination = iaddr_broadcast; 297 ip->client->state = S_REQUESTING; 298 ip->client->first_sending = cur_time; 299 ip->client->interval = ip->client->config->initial_interval; 300 301 /* Make a DHCPREQUEST packet from the lease we picked. */ 302 make_request(ip, picked); 303 ip->client->xid = ip->client->packet.xid; 304 305 /* Toss the lease we picked - we'll get it back in a DHCPACK. */ 306 free_client_lease(picked); 307 308 /* Add an immediate timeout to send the first DHCPREQUEST packet. */ 309 send_request(ip); 310 } 311 312 /* state_requesting is called when we receive a DHCPACK message after 313 having sent out one or more DHCPREQUEST packets. */ 314 315 void 316 dhcpack(struct packet *packet) 317 { 318 struct interface_info *ip = packet->interface; 319 struct client_lease *lease; 320 time_t cur_time; 321 322 time(&cur_time); 323 324 /* If we're not receptive to an offer right now, or if the offer 325 has an unrecognizable transaction id, then just drop it. */ 326 if (packet->interface->client->xid != packet->raw->xid || 327 (packet->interface->hw_address.hlen != packet->raw->hlen) || 328 (memcmp(packet->interface->hw_address.haddr, 329 packet->raw->chaddr, packet->raw->hlen))) 330 return; 331 332 if (ip->client->state != S_REBOOTING && 333 ip->client->state != S_REQUESTING && 334 ip->client->state != S_RENEWING && 335 ip->client->state != S_REBINDING) 336 return; 337 338 note("DHCPACK from %s", piaddr(packet->client_addr)); 339 340 lease = packet_to_lease(packet); 341 if (!lease) { 342 note("packet_to_lease failed."); 343 return; 344 } 345 346 ip->client->new = lease; 347 348 /* Stop resending DHCPREQUEST. */ 349 cancel_timeout(send_request, ip); 350 351 /* Figure out the lease time. */ 352 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data) 353 ip->client->new->expiry = getULong( 354 ip->client->new->options[DHO_DHCP_LEASE_TIME].data); 355 else 356 ip->client->new->expiry = DHCP_DEFAULT_LEASE_TIME; 357 /* A number that looks negative here is really just very large, 358 because the lease expiry offset is unsigned. */ 359 if (ip->client->new->expiry < 0) 360 ip->client->new->expiry = TIME_MAX; 361 /* XXX should be fixed by resetting the client state */ 362 if (ip->client->new->expiry < 60) 363 ip->client->new->expiry = 60; 364 365 /* Take the server-provided renewal time if there is one; 366 otherwise figure it out according to the spec. */ 367 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len) 368 ip->client->new->renewal = getULong( 369 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data); 370 else 371 ip->client->new->renewal = ip->client->new->expiry / 2; 372 373 /* Same deal with the rebind time. */ 374 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len) 375 ip->client->new->rebind = getULong( 376 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data); 377 else 378 ip->client->new->rebind = ip->client->new->renewal + 379 ip->client->new->renewal / 2 + ip->client->new->renewal / 4; 380 381 #ifdef __REACTOS__ 382 ip->client->new->obtained = cur_time; 383 #endif 384 ip->client->new->expiry += cur_time; 385 /* Lease lengths can never be negative. */ 386 if (ip->client->new->expiry < cur_time) 387 ip->client->new->expiry = TIME_MAX; 388 ip->client->new->renewal += cur_time; 389 if (ip->client->new->renewal < cur_time) 390 ip->client->new->renewal = TIME_MAX; 391 ip->client->new->rebind += cur_time; 392 if (ip->client->new->rebind < cur_time) 393 ip->client->new->rebind = TIME_MAX; 394 395 bind_lease(ip); 396 } 397 398 void set_name_servers( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) { 399 CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; 400 HKEY RegKey; 401 402 strcat(Buffer, Adapter->DhclientInfo.name); 403 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &RegKey ) != ERROR_SUCCESS) 404 return; 405 406 407 if( new_lease->options[DHO_DOMAIN_NAME_SERVERS].len ) { 408 409 struct iaddr nameserver; 410 char *nsbuf; 411 int i, addrs = 412 new_lease->options[DHO_DOMAIN_NAME_SERVERS].len / sizeof(ULONG); 413 414 nsbuf = malloc( addrs * sizeof(IP_ADDRESS_STRING) ); 415 416 if( nsbuf) { 417 nsbuf[0] = 0; 418 for( i = 0; i < addrs; i++ ) { 419 nameserver.len = sizeof(ULONG); 420 memcpy( nameserver.iabuf, 421 new_lease->options[DHO_DOMAIN_NAME_SERVERS].data + 422 (i * sizeof(ULONG)), sizeof(ULONG) ); 423 strcat( nsbuf, piaddr(nameserver) ); 424 if( i != addrs-1 ) strcat( nsbuf, "," ); 425 } 426 427 DH_DbgPrint(MID_TRACE,("Setting DhcpNameserver: %s\n", nsbuf)); 428 429 RegSetValueExA( RegKey, "DhcpNameServer", 0, REG_SZ, 430 (LPBYTE)nsbuf, strlen(nsbuf) + 1 ); 431 free( nsbuf ); 432 } 433 434 } else { 435 RegDeleteValueW( RegKey, L"DhcpNameServer" ); 436 } 437 438 RegCloseKey( RegKey ); 439 440 } 441 442 void 443 set_domain(PDHCP_ADAPTER Adapter, 444 struct client_lease *new_lease) 445 { 446 CHAR Buffer1[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; 447 CHAR Buffer2[MAX_PATH] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"; 448 HKEY RegKey1, RegKey2; 449 450 strcat(Buffer1, Adapter->DhclientInfo.name); 451 452 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer1, 0, KEY_WRITE, &RegKey1 ) != ERROR_SUCCESS) 453 { 454 return; 455 } 456 457 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer2, 0, KEY_WRITE, &RegKey2 ) != ERROR_SUCCESS) 458 { 459 RegCloseKey(RegKey1); 460 return; 461 } 462 463 if (new_lease->options[DHO_DOMAIN_NAME].len) 464 { 465 DH_DbgPrint(MID_TRACE, ("Setting DhcpDomain: %s\n", new_lease->options[DHO_DOMAIN_NAME].data)); 466 467 RegSetValueExA(RegKey1, 468 "DhcpDomain", 469 0, 470 REG_SZ, 471 (LPBYTE)new_lease->options[DHO_DOMAIN_NAME].data, 472 new_lease->options[DHO_DOMAIN_NAME].len); 473 474 RegSetValueExA(RegKey2, 475 "DhcpDomain", 476 0, 477 REG_SZ, 478 (LPBYTE)new_lease->options[DHO_DOMAIN_NAME].data, 479 new_lease->options[DHO_DOMAIN_NAME].len); 480 } 481 else 482 { 483 RegDeleteValueW(RegKey1, L"DhcpDomain"); 484 RegDeleteValueW(RegKey2, L"DhcpDomain"); 485 } 486 487 RegCloseKey(RegKey1); 488 RegCloseKey(RegKey2); 489 490 } 491 492 void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) { 493 CHAR Buffer[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"; 494 struct iaddr netmask; 495 HKEY hkey; 496 int i; 497 DWORD dwEnableDHCP; 498 499 strcat(Buffer, Adapter->DhclientInfo.name); 500 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, Buffer, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS) 501 hkey = NULL; 502 503 504 if( Adapter->NteContext ) 505 { 506 DeleteIPAddress( Adapter->NteContext ); 507 Adapter->NteContext = 0; 508 } 509 510 /* Set up our default router if we got one from the DHCP server */ 511 if( new_lease->options[DHO_SUBNET_MASK].len ) { 512 NTSTATUS Status; 513 514 memcpy( netmask.iabuf, 515 new_lease->options[DHO_SUBNET_MASK].data, 516 new_lease->options[DHO_SUBNET_MASK].len ); 517 Status = AddIPAddress 518 ( *((ULONG*)new_lease->address.iabuf), 519 *((ULONG*)netmask.iabuf), 520 Adapter->IfMib.dwIndex, 521 &Adapter->NteContext, 522 &Adapter->NteInstance ); 523 if (hkey) { 524 RegSetValueExA(hkey, "DhcpIPAddress", 0, REG_SZ, (LPBYTE)piaddr(new_lease->address), strlen(piaddr(new_lease->address))+1); 525 Buffer[0] = '\0'; 526 for(i = 0; i < new_lease->options[DHO_SUBNET_MASK].len; i++) 527 { 528 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_SUBNET_MASK].data[i]); 529 if (i + 1 < new_lease->options[DHO_SUBNET_MASK].len) 530 strcat(Buffer, "."); 531 } 532 RegSetValueExA(hkey, "DhcpSubnetMask", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1); 533 dwEnableDHCP = 1; 534 RegSetValueExA(hkey, "EnableDHCP", 0, REG_DWORD, (LPBYTE)&dwEnableDHCP, sizeof(DWORD)); 535 } 536 537 if( !NT_SUCCESS(Status) ) 538 warning("AddIPAddress: %lx\n", Status); 539 } 540 541 if( new_lease->options[DHO_ROUTERS].len ) { 542 NTSTATUS Status; 543 544 Adapter->RouterMib.dwForwardDest = 0; /* Default route */ 545 Adapter->RouterMib.dwForwardMask = 0; 546 Adapter->RouterMib.dwForwardMetric1 = 1; 547 Adapter->RouterMib.dwForwardIfIndex = Adapter->IfMib.dwIndex; 548 549 if( Adapter->RouterMib.dwForwardNextHop ) { 550 /* If we set a default route before, delete it before continuing */ 551 DeleteIpForwardEntry( &Adapter->RouterMib ); 552 } 553 554 Adapter->RouterMib.dwForwardNextHop = 555 *((ULONG*)new_lease->options[DHO_ROUTERS].data); 556 557 Status = CreateIpForwardEntry( &Adapter->RouterMib ); 558 559 if( !NT_SUCCESS(Status) ) 560 warning("CreateIpForwardEntry: %lx\n", Status); 561 562 if (hkey) { 563 Buffer[0] = '\0'; 564 for(i = 0; i < new_lease->options[DHO_ROUTERS].len; i++) 565 { 566 sprintf(&Buffer[strlen(Buffer)], "%u", new_lease->options[DHO_ROUTERS].data[i]); 567 if (i + 1 < new_lease->options[DHO_ROUTERS].len) 568 strcat(Buffer, "."); 569 } 570 RegSetValueExA(hkey, "DhcpDefaultGateway", 0, REG_SZ, (LPBYTE)Buffer, strlen(Buffer)+1); 571 } 572 } 573 574 if (hkey) 575 RegCloseKey(hkey); 576 } 577 578 579 void 580 bind_lease(struct interface_info *ip) 581 { 582 PDHCP_ADAPTER Adapter; 583 struct client_lease *new_lease = ip->client->new; 584 time_t cur_time; 585 586 time(&cur_time); 587 588 /* Remember the medium. */ 589 ip->client->new->medium = ip->client->medium; 590 591 /* Replace the old active lease with the new one. */ 592 if (ip->client->active) 593 free_client_lease(ip->client->active); 594 ip->client->active = ip->client->new; 595 ip->client->new = NULL; 596 597 /* Set up a timeout to start the renewal process. */ 598 /* Timeout of zero means no timeout (some implementations seem to use 599 * one day). 600 */ 601 if( ip->client->active->renewal - cur_time ) 602 add_timeout(ip->client->active->renewal, state_bound, ip); 603 604 note("bound to %s -- renewal in %ld seconds.", 605 piaddr(ip->client->active->address), 606 (long int)(ip->client->active->renewal - cur_time)); 607 608 ip->client->state = S_BOUND; 609 610 Adapter = AdapterFindInfo( ip ); 611 612 if( Adapter ) setup_adapter( Adapter, new_lease ); 613 else { 614 warning("Could not find adapter for info %p\n", ip); 615 return; 616 } 617 set_name_servers( Adapter, new_lease ); 618 set_domain( Adapter, new_lease ); 619 } 620 621 /* 622 * state_bound is called when we've successfully bound to a particular 623 * lease, but the renewal time on that lease has expired. We are 624 * expected to unicast a DHCPREQUEST to the server that gave us our 625 * original lease. 626 */ 627 void 628 state_bound(void *ipp) 629 { 630 struct interface_info *ip = ipp; 631 632 ASSERT_STATE(state, S_BOUND); 633 634 /* T1 has expired. */ 635 make_request(ip, ip->client->active); 636 ip->client->xid = ip->client->packet.xid; 637 638 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) { 639 memcpy(ip->client->destination.iabuf, ip->client->active-> 640 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4); 641 ip->client->destination.len = 4; 642 } else 643 ip->client->destination = iaddr_broadcast; 644 645 time(&ip->client->first_sending); 646 ip->client->interval = ip->client->config->initial_interval; 647 ip->client->state = S_RENEWING; 648 649 /* Send the first packet immediately. */ 650 send_request(ip); 651 } 652 653 void 654 bootp(struct packet *packet) 655 { 656 struct iaddrlist *ap; 657 658 if (packet->raw->op != BOOTREPLY) 659 return; 660 661 /* If there's a reject list, make sure this packet's sender isn't 662 on it. */ 663 for (ap = packet->interface->client->config->reject_list; 664 ap; ap = ap->next) { 665 if (addr_eq(packet->client_addr, ap->addr)) { 666 note("BOOTREPLY from %s rejected.", piaddr(ap->addr)); 667 return; 668 } 669 } 670 dhcpoffer(packet); 671 } 672 673 void 674 dhcp(struct packet *packet) 675 { 676 struct iaddrlist *ap; 677 void (*handler)(struct packet *); 678 char *type; 679 680 switch (packet->packet_type) { 681 case DHCPOFFER: 682 handler = dhcpoffer; 683 type = "DHCPOFFER"; 684 break; 685 case DHCPNAK: 686 handler = dhcpnak; 687 type = "DHCPNACK"; 688 break; 689 case DHCPACK: 690 handler = dhcpack; 691 type = "DHCPACK"; 692 break; 693 default: 694 return; 695 } 696 697 /* If there's a reject list, make sure this packet's sender isn't 698 on it. */ 699 for (ap = packet->interface->client->config->reject_list; 700 ap; ap = ap->next) { 701 if (addr_eq(packet->client_addr, ap->addr)) { 702 note("%s from %s rejected.", type, piaddr(ap->addr)); 703 return; 704 } 705 } 706 (*handler)(packet); 707 } 708 709 void 710 dhcpoffer(struct packet *packet) 711 { 712 struct interface_info *ip = packet->interface; 713 struct client_lease *lease, *lp; 714 int i; 715 int arp_timeout_needed = 0, stop_selecting; 716 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ? 717 "DHCPOFFER" : "BOOTREPLY"; 718 time_t cur_time; 719 720 time(&cur_time); 721 722 /* If we're not receptive to an offer right now, or if the offer 723 has an unrecognizable transaction id, then just drop it. */ 724 if (ip->client->state != S_SELECTING || 725 packet->interface->client->xid != packet->raw->xid || 726 (packet->interface->hw_address.hlen != packet->raw->hlen) || 727 (memcmp(packet->interface->hw_address.haddr, 728 packet->raw->chaddr, packet->raw->hlen))) 729 return; 730 731 note("%s from %s", name, piaddr(packet->client_addr)); 732 733 734 /* If this lease doesn't supply the minimum required parameters, 735 blow it off. */ 736 for (i = 0; ip->client->config->required_options[i]; i++) { 737 if (!packet->options[ip->client->config-> 738 required_options[i]].len) { 739 note("%s isn't satisfactory.", name); 740 return; 741 } 742 } 743 744 /* If we've already seen this lease, don't record it again. */ 745 for (lease = ip->client->offered_leases; 746 lease; lease = lease->next) { 747 if (lease->address.len == sizeof(packet->raw->yiaddr) && 748 !memcmp(lease->address.iabuf, 749 &packet->raw->yiaddr, lease->address.len)) { 750 debug("%s already seen.", name); 751 return; 752 } 753 } 754 755 lease = packet_to_lease(packet); 756 if (!lease) { 757 note("packet_to_lease failed."); 758 return; 759 } 760 761 /* If this lease was acquired through a BOOTREPLY, record that 762 fact. */ 763 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len) 764 lease->is_bootp = 1; 765 766 /* Record the medium under which this lease was offered. */ 767 lease->medium = ip->client->medium; 768 769 /* Send out an ARP Request for the offered IP address. */ 770 if( !check_arp( ip, lease ) ) { 771 note("Arp check failed\n"); 772 return; 773 } 774 775 /* Figure out when we're supposed to stop selecting. */ 776 stop_selecting = 777 ip->client->first_sending + ip->client->config->select_interval; 778 779 /* If this is the lease we asked for, put it at the head of the 780 list, and don't mess with the arp request timeout. */ 781 if (lease->address.len == ip->client->requested_address.len && 782 !memcmp(lease->address.iabuf, 783 ip->client->requested_address.iabuf, 784 ip->client->requested_address.len)) { 785 lease->next = ip->client->offered_leases; 786 ip->client->offered_leases = lease; 787 } else { 788 /* If we already have an offer, and arping for this 789 offer would take us past the selection timeout, 790 then don't extend the timeout - just hope for the 791 best. */ 792 if (ip->client->offered_leases && 793 (cur_time + arp_timeout_needed) > stop_selecting) 794 arp_timeout_needed = 0; 795 796 /* Put the lease at the end of the list. */ 797 lease->next = NULL; 798 if (!ip->client->offered_leases) 799 ip->client->offered_leases = lease; 800 else { 801 for (lp = ip->client->offered_leases; lp->next; 802 lp = lp->next) 803 ; /* nothing */ 804 lp->next = lease; 805 } 806 } 807 808 /* If we're supposed to stop selecting before we've had time 809 to wait for the ARPREPLY, add some delay to wait for 810 the ARPREPLY. */ 811 if (stop_selecting - cur_time < arp_timeout_needed) 812 stop_selecting = cur_time + arp_timeout_needed; 813 814 /* If the selecting interval has expired, go immediately to 815 state_selecting(). Otherwise, time out into 816 state_selecting at the select interval. */ 817 if (stop_selecting <= 0) 818 state_selecting(ip); 819 else { 820 add_timeout(stop_selecting, state_selecting, ip); 821 cancel_timeout(send_discover, ip); 822 } 823 } 824 825 /* Allocate a client_lease structure and initialize it from the parameters 826 in the specified packet. */ 827 828 struct client_lease * 829 packet_to_lease(struct packet *packet) 830 { 831 struct client_lease *lease; 832 int i; 833 834 lease = malloc(sizeof(struct client_lease)); 835 836 if (!lease) { 837 warning("dhcpoffer: no memory to record lease."); 838 return (NULL); 839 } 840 841 memset(lease, 0, sizeof(*lease)); 842 843 /* Copy the lease options. */ 844 for (i = 0; i < 256; i++) { 845 if (packet->options[i].len) { 846 lease->options[i].data = 847 malloc(packet->options[i].len + 1); 848 if (!lease->options[i].data) { 849 warning("dhcpoffer: no memory for option %d", i); 850 free_client_lease(lease); 851 return (NULL); 852 } else { 853 memcpy(lease->options[i].data, 854 packet->options[i].data, 855 packet->options[i].len); 856 lease->options[i].len = 857 packet->options[i].len; 858 lease->options[i].data[lease->options[i].len] = 859 0; 860 } 861 if (!check_option(lease,i)) { 862 /* ignore a bogus lease offer */ 863 warning("Invalid lease option - ignoring offer"); 864 free_client_lease(lease); 865 return (NULL); 866 } 867 } 868 } 869 870 lease->address.len = sizeof(packet->raw->yiaddr); 871 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len); 872 #ifdef __REACTOS__ 873 lease->serveraddress.len = sizeof(packet->raw->siaddr); 874 memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->address.len); 875 #endif 876 877 /* If the server name was filled out, copy it. */ 878 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || 879 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) && 880 packet->raw->sname[0]) { 881 lease->server_name = malloc(DHCP_SNAME_LEN + 1); 882 if (!lease->server_name) { 883 warning("dhcpoffer: no memory for server name."); 884 free_client_lease(lease); 885 return (NULL); 886 } 887 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN); 888 lease->server_name[DHCP_SNAME_LEN]='\0'; 889 if (!res_hnok(lease->server_name) ) { 890 warning("Bogus server name %s", lease->server_name ); 891 free_client_lease(lease); 892 return (NULL); 893 } 894 895 } 896 897 /* Ditto for the filename. */ 898 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || 899 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) && 900 packet->raw->file[0]) { 901 /* Don't count on the NUL terminator. */ 902 lease->filename = malloc(DHCP_FILE_LEN + 1); 903 if (!lease->filename) { 904 warning("dhcpoffer: no memory for filename."); 905 free_client_lease(lease); 906 return (NULL); 907 } 908 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN); 909 lease->filename[DHCP_FILE_LEN]='\0'; 910 } 911 return lease; 912 } 913 914 void 915 dhcpnak(struct packet *packet) 916 { 917 struct interface_info *ip = packet->interface; 918 919 /* If we're not receptive to an offer right now, or if the offer 920 has an unrecognizable transaction id, then just drop it. */ 921 if (packet->interface->client->xid != packet->raw->xid || 922 (packet->interface->hw_address.hlen != packet->raw->hlen) || 923 (memcmp(packet->interface->hw_address.haddr, 924 packet->raw->chaddr, packet->raw->hlen))) 925 return; 926 927 if (ip->client->state != S_REBOOTING && 928 ip->client->state != S_REQUESTING && 929 ip->client->state != S_RENEWING && 930 ip->client->state != S_REBINDING) 931 return; 932 933 note("DHCPNAK from %s", piaddr(packet->client_addr)); 934 935 if (!ip->client->active) { 936 note("DHCPNAK with no active lease.\n"); 937 return; 938 } 939 940 free_client_lease(ip->client->active); 941 ip->client->active = NULL; 942 943 /* Stop sending DHCPREQUEST packets... */ 944 cancel_timeout(send_request, ip); 945 946 ip->client->state = S_INIT; 947 state_init(ip); 948 } 949 950 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another 951 one after the right interval has expired. If we don't get an offer by 952 the time we reach the panic interval, call the panic function. */ 953 954 void 955 send_discover(void *ipp) 956 { 957 struct interface_info *ip = ipp; 958 int interval, increase = 1; 959 time_t cur_time; 960 961 DH_DbgPrint(MID_TRACE,("Doing discover on interface %p\n",ip)); 962 963 time(&cur_time); 964 965 /* Figure out how long it's been since we started transmitting. */ 966 interval = cur_time - ip->client->first_sending; 967 968 /* If we're past the panic timeout, call the script and tell it 969 we haven't found anything for this interface yet. */ 970 if (interval > ip->client->config->timeout) { 971 state_panic(ip); 972 ip->client->first_sending = cur_time; 973 } 974 975 /* If we're selecting media, try the whole list before doing 976 the exponential backoff, but if we've already received an 977 offer, stop looping, because we obviously have it right. */ 978 if (!ip->client->offered_leases && 979 ip->client->config->media) { 980 int fail = 0; 981 982 if (ip->client->medium) { 983 ip->client->medium = ip->client->medium->next; 984 increase = 0; 985 } 986 if (!ip->client->medium) { 987 if (fail) 988 error("No valid media types for %s!", ip->name); 989 ip->client->medium = ip->client->config->media; 990 increase = 1; 991 } 992 993 note("Trying medium \"%s\" %d", ip->client->medium->string, 994 increase); 995 /* XXX Support other media types eventually */ 996 } 997 998 /* 999 * If we're supposed to increase the interval, do so. If it's 1000 * currently zero (i.e., we haven't sent any packets yet), set 1001 * it to one; otherwise, add to it a random number between zero 1002 * and two times itself. On average, this means that it will 1003 * double with every transmission. 1004 */ 1005 if (increase) { 1006 if (!ip->client->interval) 1007 ip->client->interval = 1008 ip->client->config->initial_interval; 1009 else { 1010 ip->client->interval += (rand() >> 2) % 1011 (2 * ip->client->interval); 1012 } 1013 1014 /* Don't backoff past cutoff. */ 1015 if (ip->client->interval > 1016 ip->client->config->backoff_cutoff) 1017 ip->client->interval = 1018 ((ip->client->config->backoff_cutoff / 2) 1019 + ((rand() >> 2) % 1020 ip->client->config->backoff_cutoff)); 1021 } else if (!ip->client->interval) 1022 ip->client->interval = 1023 ip->client->config->initial_interval; 1024 1025 /* If the backoff would take us to the panic timeout, just use that 1026 as the interval. */ 1027 if (cur_time + ip->client->interval > 1028 ip->client->first_sending + ip->client->config->timeout) 1029 ip->client->interval = 1030 (ip->client->first_sending + 1031 ip->client->config->timeout) - cur_time + 1; 1032 1033 /* Record the number of seconds since we started sending. */ 1034 if (interval < 65536) 1035 ip->client->packet.secs = htons(interval); 1036 else 1037 ip->client->packet.secs = htons(65535); 1038 ip->client->secs = ip->client->packet.secs; 1039 1040 note("DHCPDISCOVER on %s to %s port %d interval %ld", 1041 ip->name, inet_ntoa(sockaddr_broadcast.sin_addr), 1042 ntohs(sockaddr_broadcast.sin_port), (long int)ip->client->interval); 1043 1044 /* Send out a packet. */ 1045 (void)send_packet(ip, &ip->client->packet, ip->client->packet_length, 1046 inaddr_any, &sockaddr_broadcast, NULL); 1047 1048 DH_DbgPrint(MID_TRACE,("discover timeout: now %x -> then %x\n", 1049 cur_time, cur_time + ip->client->interval)); 1050 1051 add_timeout(cur_time + ip->client->interval, send_discover, ip); 1052 } 1053 1054 /* 1055 * state_panic gets called if we haven't received any offers in a preset 1056 * amount of time. When this happens, we try to use existing leases 1057 * that haven't yet expired, and failing that, we call the client script 1058 * and hope it can do something. 1059 */ 1060 void 1061 state_panic(void *ipp) 1062 { 1063 struct interface_info *ip = ipp; 1064 uint16_t address_low; 1065 int i; 1066 IPAddr IpAddress; 1067 ULONG Buffer[20]; 1068 ULONG BufferSize; 1069 DWORD ret; 1070 PDHCP_ADAPTER Adapter = AdapterFindInfo(ip); 1071 1072 note("No DHCPOFFERS received."); 1073 1074 if (!Adapter->NteContext) 1075 { 1076 /* Generate an automatic private address */ 1077 DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n"); 1078 1079 /* FIXME: The address generation code sucks */ 1080 srand(0); 1081 1082 for (;;) 1083 { 1084 address_low = rand(); 1085 for (i = 0; i < ip->hw_address.hlen; i++) 1086 address_low += ip->hw_address.haddr[i]; 1087 1088 IpAddress = htonl(0xA9FE0000 | address_low); // 169.254.X.X 1089 1090 /* Send an ARP request to check if the IP address is already in use */ 1091 BufferSize = sizeof(Buffer); 1092 ret = SendARP(IpAddress, 1093 IpAddress, 1094 Buffer, 1095 &BufferSize); 1096 DH_DbgPrint(MID_TRACE,("DHCPCSVC: SendARP returned %lu\n", ret)); 1097 if (ret != 0) 1098 { 1099 /* The IP address is not in use */ 1100 DH_DbgPrint(MID_TRACE,("DHCPCSVC: Using automatic private address\n")); 1101 AddIPAddress(IpAddress, 1102 htonl(0xFFFF0000), // 255.255.0.0 1103 Adapter->IfMib.dwIndex, 1104 &Adapter->NteContext, 1105 &Adapter->NteInstance); 1106 return; 1107 } 1108 } 1109 } 1110 } 1111 1112 void 1113 send_request(void *ipp) 1114 { 1115 struct interface_info *ip = ipp; 1116 struct sockaddr_in destination; 1117 struct in_addr from; 1118 int interval; 1119 time_t cur_time; 1120 1121 time(&cur_time); 1122 1123 /* Figure out how long it's been since we started transmitting. */ 1124 interval = cur_time - ip->client->first_sending; 1125 1126 /* If we're in the INIT-REBOOT or REQUESTING state and we're 1127 past the reboot timeout, go to INIT and see if we can 1128 DISCOVER an address... */ 1129 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it 1130 means either that we're on a network with no DHCP server, 1131 or that our server is down. In the latter case, assuming 1132 that there is a backup DHCP server, DHCPDISCOVER will get 1133 us a new address, but we could also have successfully 1134 reused our old address. In the former case, we're hosed 1135 anyway. This is not a win-prone situation. */ 1136 if ((ip->client->state == S_REBOOTING || 1137 ip->client->state == S_REQUESTING) && 1138 interval > ip->client->config->reboot_timeout) { 1139 ip->client->state = S_INIT; 1140 cancel_timeout(send_request, ip); 1141 state_init(ip); 1142 return; 1143 } 1144 1145 /* If we're in the reboot state, make sure the media is set up 1146 correctly. */ 1147 if (ip->client->state == S_REBOOTING && 1148 !ip->client->medium && 1149 ip->client->active->medium ) { 1150 /* If the medium we chose won't fly, go to INIT state. */ 1151 /* XXX Nothing for now */ 1152 1153 /* Record the medium. */ 1154 ip->client->medium = ip->client->active->medium; 1155 } 1156 1157 /* If the lease has expired, relinquish the address and go back 1158 to the INIT state. */ 1159 if (ip->client->state != S_REQUESTING && 1160 cur_time > ip->client->active->expiry) { 1161 PDHCP_ADAPTER Adapter = AdapterFindInfo( ip ); 1162 /* Run the client script with the new parameters. */ 1163 /* No script actions necessary in the expiry case */ 1164 /* Now do a preinit on the interface so that we can 1165 discover a new address. */ 1166 1167 if( Adapter ) 1168 { 1169 DeleteIPAddress( Adapter->NteContext ); 1170 Adapter->NteContext = 0; 1171 } 1172 1173 ip->client->state = S_INIT; 1174 state_init(ip); 1175 return; 1176 } 1177 1178 /* Do the exponential backoff... */ 1179 if (!ip->client->interval) 1180 ip->client->interval = ip->client->config->initial_interval; 1181 else 1182 ip->client->interval += ((rand() >> 2) % 1183 (2 * ip->client->interval)); 1184 1185 /* Don't backoff past cutoff. */ 1186 if (ip->client->interval > 1187 ip->client->config->backoff_cutoff) 1188 ip->client->interval = 1189 ((ip->client->config->backoff_cutoff / 2) + 1190 ((rand() >> 2) % ip->client->interval)); 1191 1192 /* If the backoff would take us to the expiry time, just set the 1193 timeout to the expiry time. */ 1194 if (ip->client->state != S_REQUESTING && 1195 cur_time + ip->client->interval > 1196 ip->client->active->expiry) 1197 ip->client->interval = 1198 ip->client->active->expiry - cur_time + 1; 1199 1200 /* If the lease T2 time has elapsed, or if we're not yet bound, 1201 broadcast the DHCPREQUEST rather than unicasting. */ 1202 memset(&destination, 0, sizeof(destination)); 1203 if (ip->client->state == S_REQUESTING || 1204 ip->client->state == S_REBOOTING || 1205 cur_time > ip->client->active->rebind) 1206 destination.sin_addr.s_addr = INADDR_BROADCAST; 1207 else 1208 memcpy(&destination.sin_addr.s_addr, 1209 ip->client->destination.iabuf, 1210 sizeof(destination.sin_addr.s_addr)); 1211 destination.sin_port = htons(REMOTE_PORT); 1212 destination.sin_family = AF_INET; 1213 // destination.sin_len = sizeof(destination); 1214 1215 if (ip->client->state != S_REQUESTING) 1216 memcpy(&from, ip->client->active->address.iabuf, 1217 sizeof(from)); 1218 else 1219 from.s_addr = INADDR_ANY; 1220 1221 /* Record the number of seconds since we started sending. */ 1222 if (ip->client->state == S_REQUESTING) 1223 ip->client->packet.secs = ip->client->secs; 1224 else { 1225 if (interval < 65536) 1226 ip->client->packet.secs = htons(interval); 1227 else 1228 ip->client->packet.secs = htons(65535); 1229 } 1230 1231 note("DHCPREQUEST on %s to %s port %d", ip->name, 1232 inet_ntoa(destination.sin_addr), ntohs(destination.sin_port)); 1233 1234 /* Send out a packet. */ 1235 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, 1236 from, &destination, NULL); 1237 1238 add_timeout(cur_time + ip->client->interval, send_request, ip); 1239 } 1240 1241 void 1242 send_decline(void *ipp) 1243 { 1244 struct interface_info *ip = ipp; 1245 1246 note("DHCPDECLINE on %s to %s port %d", ip->name, 1247 inet_ntoa(sockaddr_broadcast.sin_addr), 1248 ntohs(sockaddr_broadcast.sin_port)); 1249 1250 /* Send out a packet. */ 1251 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, 1252 inaddr_any, &sockaddr_broadcast, NULL); 1253 } 1254 1255 void 1256 make_discover(struct interface_info *ip, struct client_lease *lease) 1257 { 1258 unsigned char discover = DHCPDISCOVER; 1259 struct tree_cache *options[256]; 1260 struct tree_cache option_elements[256]; 1261 int i; 1262 ULONG foo = (ULONG) GetTickCount(); 1263 1264 memset(option_elements, 0, sizeof(option_elements)); 1265 memset(options, 0, sizeof(options)); 1266 memset(&ip->client->packet, 0, sizeof(ip->client->packet)); 1267 1268 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ 1269 i = DHO_DHCP_MESSAGE_TYPE; 1270 options[i] = &option_elements[i]; 1271 options[i]->value = &discover; 1272 options[i]->len = sizeof(discover); 1273 options[i]->buf_size = sizeof(discover); 1274 options[i]->timeout = 0xFFFFFFFF; 1275 1276 /* Request the options we want */ 1277 i = DHO_DHCP_PARAMETER_REQUEST_LIST; 1278 options[i] = &option_elements[i]; 1279 options[i]->value = ip->client->config->requested_options; 1280 options[i]->len = ip->client->config->requested_option_count; 1281 options[i]->buf_size = 1282 ip->client->config->requested_option_count; 1283 options[i]->timeout = 0xFFFFFFFF; 1284 1285 /* If we had an address, try to get it again. */ 1286 if (lease) { 1287 ip->client->requested_address = lease->address; 1288 i = DHO_DHCP_REQUESTED_ADDRESS; 1289 options[i] = &option_elements[i]; 1290 options[i]->value = lease->address.iabuf; 1291 options[i]->len = lease->address.len; 1292 options[i]->buf_size = lease->address.len; 1293 options[i]->timeout = 0xFFFFFFFF; 1294 } else 1295 ip->client->requested_address.len = 0; 1296 1297 /* Send any options requested in the config file. */ 1298 for (i = 0; i < 256; i++) 1299 if (!options[i] && 1300 ip->client->config->send_options[i].data) { 1301 options[i] = &option_elements[i]; 1302 options[i]->value = 1303 ip->client->config->send_options[i].data; 1304 options[i]->len = 1305 ip->client->config->send_options[i].len; 1306 options[i]->buf_size = 1307 ip->client->config->send_options[i].len; 1308 options[i]->timeout = 0xFFFFFFFF; 1309 } 1310 1311 /* Set up the option buffer... */ 1312 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, 1313 options); 1314 if (ip->client->packet_length < BOOTP_MIN_LEN) 1315 ip->client->packet_length = BOOTP_MIN_LEN; 1316 1317 ip->client->packet.op = BOOTREQUEST; 1318 ip->client->packet.htype = ip->hw_address.htype; 1319 ip->client->packet.hlen = ip->hw_address.hlen; 1320 ip->client->packet.hops = 0; 1321 ip->client->packet.xid = RtlRandom(&foo); 1322 ip->client->packet.secs = 0; /* filled in by send_discover. */ 1323 ip->client->packet.flags = 0; 1324 1325 memset(&(ip->client->packet.ciaddr), 1326 0, sizeof(ip->client->packet.ciaddr)); 1327 memset(&(ip->client->packet.yiaddr), 1328 0, sizeof(ip->client->packet.yiaddr)); 1329 memset(&(ip->client->packet.siaddr), 1330 0, sizeof(ip->client->packet.siaddr)); 1331 memset(&(ip->client->packet.giaddr), 1332 0, sizeof(ip->client->packet.giaddr)); 1333 memcpy(ip->client->packet.chaddr, 1334 ip->hw_address.haddr, ip->hw_address.hlen); 1335 } 1336 1337 1338 void 1339 make_request(struct interface_info *ip, struct client_lease * lease) 1340 { 1341 unsigned char request = DHCPREQUEST; 1342 struct tree_cache *options[256]; 1343 struct tree_cache option_elements[256]; 1344 int i; 1345 1346 memset(options, 0, sizeof(options)); 1347 memset(&ip->client->packet, 0, sizeof(ip->client->packet)); 1348 1349 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ 1350 i = DHO_DHCP_MESSAGE_TYPE; 1351 options[i] = &option_elements[i]; 1352 options[i]->value = &request; 1353 options[i]->len = sizeof(request); 1354 options[i]->buf_size = sizeof(request); 1355 options[i]->timeout = 0xFFFFFFFF; 1356 1357 /* Request the options we want */ 1358 i = DHO_DHCP_PARAMETER_REQUEST_LIST; 1359 options[i] = &option_elements[i]; 1360 options[i]->value = ip->client->config->requested_options; 1361 options[i]->len = ip->client->config->requested_option_count; 1362 options[i]->buf_size = 1363 ip->client->config->requested_option_count; 1364 options[i]->timeout = 0xFFFFFFFF; 1365 1366 /* If we are requesting an address that hasn't yet been assigned 1367 to us, use the DHCP Requested Address option. */ 1368 if (ip->client->state == S_REQUESTING) { 1369 /* Send back the server identifier... */ 1370 i = DHO_DHCP_SERVER_IDENTIFIER; 1371 options[i] = &option_elements[i]; 1372 options[i]->value = lease->options[i].data; 1373 options[i]->len = lease->options[i].len; 1374 options[i]->buf_size = lease->options[i].len; 1375 options[i]->timeout = 0xFFFFFFFF; 1376 } 1377 if (ip->client->state == S_REQUESTING || 1378 ip->client->state == S_REBOOTING) { 1379 ip->client->requested_address = lease->address; 1380 i = DHO_DHCP_REQUESTED_ADDRESS; 1381 options[i] = &option_elements[i]; 1382 options[i]->value = lease->address.iabuf; 1383 options[i]->len = lease->address.len; 1384 options[i]->buf_size = lease->address.len; 1385 options[i]->timeout = 0xFFFFFFFF; 1386 } else 1387 ip->client->requested_address.len = 0; 1388 1389 /* Send any options requested in the config file. */ 1390 for (i = 0; i < 256; i++) 1391 if (!options[i] && 1392 ip->client->config->send_options[i].data) { 1393 options[i] = &option_elements[i]; 1394 options[i]->value = 1395 ip->client->config->send_options[i].data; 1396 options[i]->len = 1397 ip->client->config->send_options[i].len; 1398 options[i]->buf_size = 1399 ip->client->config->send_options[i].len; 1400 options[i]->timeout = 0xFFFFFFFF; 1401 } 1402 1403 /* Set up the option buffer... */ 1404 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, 1405 options); 1406 if (ip->client->packet_length < BOOTP_MIN_LEN) 1407 ip->client->packet_length = BOOTP_MIN_LEN; 1408 1409 ip->client->packet.op = BOOTREQUEST; 1410 ip->client->packet.htype = ip->hw_address.htype; 1411 ip->client->packet.hlen = ip->hw_address.hlen; 1412 ip->client->packet.hops = 0; 1413 ip->client->packet.xid = ip->client->xid; 1414 ip->client->packet.secs = 0; /* Filled in by send_request. */ 1415 1416 /* If we own the address we're requesting, put it in ciaddr; 1417 otherwise set ciaddr to zero. */ 1418 if (ip->client->state == S_BOUND || 1419 ip->client->state == S_RENEWING || 1420 ip->client->state == S_REBINDING) { 1421 memcpy(&ip->client->packet.ciaddr, 1422 lease->address.iabuf, lease->address.len); 1423 ip->client->packet.flags = 0; 1424 } else { 1425 memset(&ip->client->packet.ciaddr, 0, 1426 sizeof(ip->client->packet.ciaddr)); 1427 ip->client->packet.flags = 0; 1428 } 1429 1430 memset(&ip->client->packet.yiaddr, 0, 1431 sizeof(ip->client->packet.yiaddr)); 1432 memset(&ip->client->packet.siaddr, 0, 1433 sizeof(ip->client->packet.siaddr)); 1434 memset(&ip->client->packet.giaddr, 0, 1435 sizeof(ip->client->packet.giaddr)); 1436 memcpy(ip->client->packet.chaddr, 1437 ip->hw_address.haddr, ip->hw_address.hlen); 1438 } 1439 1440 void 1441 make_decline(struct interface_info *ip, struct client_lease *lease) 1442 { 1443 struct tree_cache *options[256], message_type_tree; 1444 struct tree_cache requested_address_tree; 1445 struct tree_cache server_id_tree, client_id_tree; 1446 unsigned char decline = DHCPDECLINE; 1447 int i; 1448 1449 memset(options, 0, sizeof(options)); 1450 memset(&ip->client->packet, 0, sizeof(ip->client->packet)); 1451 1452 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ 1453 i = DHO_DHCP_MESSAGE_TYPE; 1454 options[i] = &message_type_tree; 1455 options[i]->value = &decline; 1456 options[i]->len = sizeof(decline); 1457 options[i]->buf_size = sizeof(decline); 1458 options[i]->timeout = 0xFFFFFFFF; 1459 1460 /* Send back the server identifier... */ 1461 i = DHO_DHCP_SERVER_IDENTIFIER; 1462 options[i] = &server_id_tree; 1463 options[i]->value = lease->options[i].data; 1464 options[i]->len = lease->options[i].len; 1465 options[i]->buf_size = lease->options[i].len; 1466 options[i]->timeout = 0xFFFFFFFF; 1467 1468 /* Send back the address we're declining. */ 1469 i = DHO_DHCP_REQUESTED_ADDRESS; 1470 options[i] = &requested_address_tree; 1471 options[i]->value = lease->address.iabuf; 1472 options[i]->len = lease->address.len; 1473 options[i]->buf_size = lease->address.len; 1474 options[i]->timeout = 0xFFFFFFFF; 1475 1476 /* Send the uid if the user supplied one. */ 1477 i = DHO_DHCP_CLIENT_IDENTIFIER; 1478 if (ip->client->config->send_options[i].len) { 1479 options[i] = &client_id_tree; 1480 options[i]->value = ip->client->config->send_options[i].data; 1481 options[i]->len = ip->client->config->send_options[i].len; 1482 options[i]->buf_size = ip->client->config->send_options[i].len; 1483 options[i]->timeout = 0xFFFFFFFF; 1484 } 1485 1486 1487 /* Set up the option buffer... */ 1488 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, 1489 options); 1490 if (ip->client->packet_length < BOOTP_MIN_LEN) 1491 ip->client->packet_length = BOOTP_MIN_LEN; 1492 1493 ip->client->packet.op = BOOTREQUEST; 1494 ip->client->packet.htype = ip->hw_address.htype; 1495 ip->client->packet.hlen = ip->hw_address.hlen; 1496 ip->client->packet.hops = 0; 1497 ip->client->packet.xid = ip->client->xid; 1498 ip->client->packet.secs = 0; /* Filled in by send_request. */ 1499 ip->client->packet.flags = 0; 1500 1501 /* ciaddr must always be zero. */ 1502 memset(&ip->client->packet.ciaddr, 0, 1503 sizeof(ip->client->packet.ciaddr)); 1504 memset(&ip->client->packet.yiaddr, 0, 1505 sizeof(ip->client->packet.yiaddr)); 1506 memset(&ip->client->packet.siaddr, 0, 1507 sizeof(ip->client->packet.siaddr)); 1508 memset(&ip->client->packet.giaddr, 0, 1509 sizeof(ip->client->packet.giaddr)); 1510 memcpy(ip->client->packet.chaddr, 1511 ip->hw_address.haddr, ip->hw_address.hlen); 1512 } 1513 1514 void 1515 free_client_lease(struct client_lease *lease) 1516 { 1517 int i; 1518 1519 if (lease->server_name) 1520 free(lease->server_name); 1521 if (lease->filename) 1522 free(lease->filename); 1523 for (i = 0; i < 256; i++) { 1524 if (lease->options[i].len) 1525 free(lease->options[i].data); 1526 } 1527 free(lease); 1528 } 1529 1530 FILE *leaseFile; 1531 1532 void 1533 rewrite_client_leases(struct interface_info *ifi) 1534 { 1535 struct client_lease *lp; 1536 1537 if (!leaseFile) { 1538 leaseFile = fopen(path_dhclient_db, "w"); 1539 if (!leaseFile) 1540 error("can't create %s", path_dhclient_db); 1541 } else { 1542 fflush(leaseFile); 1543 rewind(leaseFile); 1544 } 1545 1546 for (lp = ifi->client->leases; lp; lp = lp->next) 1547 write_client_lease(ifi, lp, 1); 1548 if (ifi->client->active) 1549 write_client_lease(ifi, ifi->client->active, 1); 1550 1551 fflush(leaseFile); 1552 } 1553 1554 void 1555 write_client_lease(struct interface_info *ip, struct client_lease *lease, 1556 int rewrite) 1557 { 1558 static int leases_written; 1559 struct tm *t; 1560 int i; 1561 1562 if (!rewrite) { 1563 if (leases_written++ > 20) { 1564 rewrite_client_leases(ip); 1565 leases_written = 0; 1566 } 1567 } 1568 1569 /* If the lease came from the config file, we don't need to stash 1570 a copy in the lease database. */ 1571 if (lease->is_static) 1572 return; 1573 1574 if (!leaseFile) { /* XXX */ 1575 leaseFile = fopen(path_dhclient_db, "w"); 1576 if (!leaseFile) { 1577 error("can't create %s", path_dhclient_db); 1578 return; 1579 } 1580 } 1581 1582 fprintf(leaseFile, "lease {\n"); 1583 if (lease->is_bootp) 1584 fprintf(leaseFile, " bootp;\n"); 1585 fprintf(leaseFile, " interface \"%s\";\n", ip->name); 1586 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address)); 1587 if (lease->filename) 1588 fprintf(leaseFile, " filename \"%s\";\n", lease->filename); 1589 if (lease->server_name) 1590 fprintf(leaseFile, " server-name \"%s\";\n", 1591 lease->server_name); 1592 if (lease->medium) 1593 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string); 1594 for (i = 0; i < 256; i++) 1595 if (lease->options[i].len) 1596 fprintf(leaseFile, " option %s %s;\n", 1597 dhcp_options[i].name, 1598 pretty_print_option(i, lease->options[i].data, 1599 lease->options[i].len, 1, 1)); 1600 1601 t = gmtime(&lease->renewal); 1602 if (t) 1603 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n", 1604 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1605 t->tm_hour, t->tm_min, t->tm_sec); 1606 t = gmtime(&lease->rebind); 1607 if (t) 1608 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n", 1609 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1610 t->tm_hour, t->tm_min, t->tm_sec); 1611 t = gmtime(&lease->expiry); 1612 if (t) 1613 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n", 1614 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1615 t->tm_hour, t->tm_min, t->tm_sec); 1616 fprintf(leaseFile, "}\n"); 1617 fflush(leaseFile); 1618 } 1619 1620 void 1621 priv_script_init(struct interface_info *ip, char *reason, char *medium) 1622 { 1623 if (ip) { 1624 // XXX Do we need to do anything? 1625 } 1626 } 1627 1628 void 1629 priv_script_write_params(struct interface_info *ip, char *prefix, struct client_lease *lease) 1630 { 1631 u_int8_t dbuf[1500]; 1632 int i, len = 0; 1633 1634 #if 0 1635 script_set_env(ip->client, prefix, "ip_address", 1636 piaddr(lease->address)); 1637 #endif 1638 1639 if (lease->options[DHO_SUBNET_MASK].len && 1640 (lease->options[DHO_SUBNET_MASK].len < 1641 sizeof(lease->address.iabuf))) { 1642 struct iaddr netmask, subnet, broadcast; 1643 1644 memcpy(netmask.iabuf, lease->options[DHO_SUBNET_MASK].data, 1645 lease->options[DHO_SUBNET_MASK].len); 1646 netmask.len = lease->options[DHO_SUBNET_MASK].len; 1647 1648 subnet = subnet_number(lease->address, netmask); 1649 if (subnet.len) { 1650 #if 0 1651 script_set_env(ip->client, prefix, "network_number", 1652 piaddr(subnet)); 1653 #endif 1654 if (!lease->options[DHO_BROADCAST_ADDRESS].len) { 1655 broadcast = broadcast_addr(subnet, netmask); 1656 if (broadcast.len) 1657 #if 0 1658 script_set_env(ip->client, prefix, 1659 "broadcast_address", 1660 piaddr(broadcast)); 1661 #else 1662 ; 1663 #endif 1664 } 1665 } 1666 } 1667 1668 #if 0 1669 if (lease->filename) 1670 script_set_env(ip->client, prefix, "filename", lease->filename); 1671 if (lease->server_name) 1672 script_set_env(ip->client, prefix, "server_name", 1673 lease->server_name); 1674 #endif 1675 1676 for (i = 0; i < 256; i++) { 1677 u_int8_t *dp = NULL; 1678 1679 if (ip->client->config->defaults[i].len) { 1680 if (lease->options[i].len) { 1681 switch ( 1682 ip->client->config->default_actions[i]) { 1683 case ACTION_DEFAULT: 1684 dp = lease->options[i].data; 1685 len = lease->options[i].len; 1686 break; 1687 case ACTION_SUPERSEDE: 1688 supersede: 1689 dp = ip->client-> 1690 config->defaults[i].data; 1691 len = ip->client-> 1692 config->defaults[i].len; 1693 break; 1694 case ACTION_PREPEND: 1695 len = ip->client-> 1696 config->defaults[i].len + 1697 lease->options[i].len; 1698 if (len >= sizeof(dbuf)) { 1699 warning("no space to %s %s", 1700 "prepend option", 1701 dhcp_options[i].name); 1702 goto supersede; 1703 } 1704 dp = dbuf; 1705 memcpy(dp, 1706 ip->client-> 1707 config->defaults[i].data, 1708 ip->client-> 1709 config->defaults[i].len); 1710 memcpy(dp + ip->client-> 1711 config->defaults[i].len, 1712 lease->options[i].data, 1713 lease->options[i].len); 1714 dp[len] = '\0'; 1715 break; 1716 case ACTION_APPEND: 1717 len = ip->client-> 1718 config->defaults[i].len + 1719 lease->options[i].len + 1; 1720 if (len > sizeof(dbuf)) { 1721 warning("no space to %s %s", 1722 "append option", 1723 dhcp_options[i].name); 1724 goto supersede; 1725 } 1726 dp = dbuf; 1727 memcpy(dp, 1728 lease->options[i].data, 1729 lease->options[i].len); 1730 memcpy(dp + lease->options[i].len, 1731 ip->client-> 1732 config->defaults[i].data, 1733 ip->client-> 1734 config->defaults[i].len); 1735 dp[len-1] = '\0'; 1736 } 1737 } else { 1738 dp = ip->client-> 1739 config->defaults[i].data; 1740 len = ip->client-> 1741 config->defaults[i].len; 1742 } 1743 } else if (lease->options[i].len) { 1744 len = lease->options[i].len; 1745 dp = lease->options[i].data; 1746 } else { 1747 len = 0; 1748 } 1749 #if 0 1750 if (len) { 1751 char name[256]; 1752 1753 if (dhcp_option_ev_name(name, sizeof(name), 1754 &dhcp_options[i])) 1755 script_set_env(ip->client, prefix, name, 1756 pretty_print_option(i, dp, len, 0, 0)); 1757 } 1758 #endif 1759 } 1760 #if 0 1761 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry); 1762 script_set_env(ip->client, prefix, "expiry", tbuf); 1763 #endif 1764 } 1765 1766 int 1767 dhcp_option_ev_name(char *buf, size_t buflen, struct dhcp_option *option) 1768 { 1769 int i; 1770 1771 for (i = 0; option->name[i]; i++) { 1772 if (i + 1 == buflen) 1773 return 0; 1774 if (option->name[i] == '-') 1775 buf[i] = '_'; 1776 else 1777 buf[i] = option->name[i]; 1778 } 1779 1780 buf[i] = 0; 1781 return 1; 1782 } 1783 1784 #if 0 1785 void 1786 go_daemon(void) 1787 { 1788 static int state = 0; 1789 1790 if (no_daemon || state) 1791 return; 1792 1793 state = 1; 1794 1795 /* Stop logging to stderr... */ 1796 log_perror = 0; 1797 1798 if (daemon(1, 0) == -1) 1799 error("daemon"); 1800 1801 /* we are chrooted, daemon(3) fails to open /dev/null */ 1802 if (nullfd != -1) { 1803 dup2(nullfd, STDIN_FILENO); 1804 dup2(nullfd, STDOUT_FILENO); 1805 dup2(nullfd, STDERR_FILENO); 1806 close(nullfd); 1807 nullfd = -1; 1808 } 1809 } 1810 #endif 1811 1812 int 1813 check_option(struct client_lease *l, int option) 1814 { 1815 char *opbuf; 1816 char *sbuf; 1817 1818 /* we use this, since this is what gets passed to dhclient-script */ 1819 1820 opbuf = pretty_print_option(option, l->options[option].data, 1821 l->options[option].len, 0, 0); 1822 1823 sbuf = option_as_string(option, l->options[option].data, 1824 l->options[option].len); 1825 1826 switch (option) { 1827 case DHO_SUBNET_MASK: 1828 case DHO_TIME_SERVERS: 1829 case DHO_NAME_SERVERS: 1830 case DHO_ROUTERS: 1831 case DHO_DOMAIN_NAME_SERVERS: 1832 case DHO_LOG_SERVERS: 1833 case DHO_COOKIE_SERVERS: 1834 case DHO_LPR_SERVERS: 1835 case DHO_IMPRESS_SERVERS: 1836 case DHO_RESOURCE_LOCATION_SERVERS: 1837 case DHO_SWAP_SERVER: 1838 case DHO_BROADCAST_ADDRESS: 1839 case DHO_NIS_SERVERS: 1840 case DHO_NTP_SERVERS: 1841 case DHO_NETBIOS_NAME_SERVERS: 1842 case DHO_NETBIOS_DD_SERVER: 1843 case DHO_FONT_SERVERS: 1844 case DHO_DHCP_SERVER_IDENTIFIER: 1845 if (!ipv4addrs(opbuf)) { 1846 warning("Invalid IP address in option(%d): %s", option, opbuf); 1847 return (0); 1848 } 1849 return (1) ; 1850 case DHO_HOST_NAME: 1851 case DHO_DOMAIN_NAME: 1852 case DHO_NIS_DOMAIN: 1853 if (!res_hnok(sbuf)) 1854 warning("Bogus Host Name option %d: %s (%s)", option, 1855 sbuf, opbuf); 1856 return (1); 1857 case DHO_PAD: 1858 case DHO_TIME_OFFSET: 1859 case DHO_BOOT_SIZE: 1860 case DHO_MERIT_DUMP: 1861 case DHO_ROOT_PATH: 1862 case DHO_EXTENSIONS_PATH: 1863 case DHO_IP_FORWARDING: 1864 case DHO_NON_LOCAL_SOURCE_ROUTING: 1865 case DHO_POLICY_FILTER: 1866 case DHO_MAX_DGRAM_REASSEMBLY: 1867 case DHO_DEFAULT_IP_TTL: 1868 case DHO_PATH_MTU_AGING_TIMEOUT: 1869 case DHO_PATH_MTU_PLATEAU_TABLE: 1870 case DHO_INTERFACE_MTU: 1871 case DHO_ALL_SUBNETS_LOCAL: 1872 case DHO_PERFORM_MASK_DISCOVERY: 1873 case DHO_MASK_SUPPLIER: 1874 case DHO_ROUTER_DISCOVERY: 1875 case DHO_ROUTER_SOLICITATION_ADDRESS: 1876 case DHO_STATIC_ROUTES: 1877 case DHO_TRAILER_ENCAPSULATION: 1878 case DHO_ARP_CACHE_TIMEOUT: 1879 case DHO_IEEE802_3_ENCAPSULATION: 1880 case DHO_DEFAULT_TCP_TTL: 1881 case DHO_TCP_KEEPALIVE_INTERVAL: 1882 case DHO_TCP_KEEPALIVE_GARBAGE: 1883 case DHO_VENDOR_ENCAPSULATED_OPTIONS: 1884 case DHO_NETBIOS_NODE_TYPE: 1885 case DHO_NETBIOS_SCOPE: 1886 case DHO_X_DISPLAY_MANAGER: 1887 case DHO_DHCP_REQUESTED_ADDRESS: 1888 case DHO_DHCP_LEASE_TIME: 1889 case DHO_DHCP_OPTION_OVERLOAD: 1890 case DHO_DHCP_MESSAGE_TYPE: 1891 case DHO_DHCP_PARAMETER_REQUEST_LIST: 1892 case DHO_DHCP_MESSAGE: 1893 case DHO_DHCP_MAX_MESSAGE_SIZE: 1894 case DHO_DHCP_RENEWAL_TIME: 1895 case DHO_DHCP_REBINDING_TIME: 1896 case DHO_DHCP_CLASS_IDENTIFIER: 1897 case DHO_DHCP_CLIENT_IDENTIFIER: 1898 case DHO_DHCP_USER_CLASS_ID: 1899 case DHO_END: 1900 return (1); 1901 default: 1902 warning("unknown dhcp option value 0x%x", option); 1903 return (unknown_ok); 1904 } 1905 } 1906 1907 int 1908 res_hnok(const char *dn) 1909 { 1910 int pch = PERIOD, ch = *dn++; 1911 1912 while (ch != '\0') { 1913 int nch = *dn++; 1914 1915 if (periodchar(ch)) { 1916 ; 1917 } else if (periodchar(pch)) { 1918 if (!borderchar(ch)) 1919 return (0); 1920 } else if (periodchar(nch) || nch == '\0') { 1921 if (!borderchar(ch)) 1922 return (0); 1923 } else { 1924 if (!middlechar(ch)) 1925 return (0); 1926 } 1927 pch = ch, ch = nch; 1928 } 1929 return (1); 1930 } 1931 1932 /* Does buf consist only of dotted decimal ipv4 addrs? 1933 * return how many if so, 1934 * otherwise, return 0 1935 */ 1936 int 1937 ipv4addrs(char * buf) 1938 { 1939 char *tmp; 1940 struct in_addr jnk; 1941 int i = 0; 1942 1943 note("Input: %s", buf); 1944 1945 do { 1946 tmp = strtok(buf, " "); 1947 note("got %s", tmp); 1948 if( tmp && inet_aton(tmp, &jnk) ) i++; 1949 buf = NULL; 1950 } while( tmp ); 1951 1952 return (i); 1953 } 1954 1955 1956 char * 1957 option_as_string(unsigned int code, unsigned char *data, int len) 1958 { 1959 static char optbuf[32768]; /* XXX */ 1960 char *op = optbuf; 1961 int opleft = sizeof(optbuf); 1962 unsigned char *dp = data; 1963 1964 if (code > 255) 1965 error("option_as_string: bad code %d", code); 1966 1967 for (; dp < data + len; dp++) { 1968 if (!isascii(*dp) || !isprint(*dp)) { 1969 if (dp + 1 != data + len || *dp != 0) { 1970 _snprintf(op, opleft, "\\%03o", *dp); 1971 op += 4; 1972 opleft -= 4; 1973 } 1974 } else if (*dp == '"' || *dp == '\'' || *dp == '$' || 1975 *dp == '`' || *dp == '\\') { 1976 *op++ = '\\'; 1977 *op++ = *dp; 1978 opleft -= 2; 1979 } else { 1980 *op++ = *dp; 1981 opleft--; 1982 } 1983 } 1984 if (opleft < 1) 1985 goto toobig; 1986 *op = 0; 1987 return optbuf; 1988 toobig: 1989 warning("dhcp option too large"); 1990 return "<error>"; 1991 } 1992 1993