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