1 /* $OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $ */
4 * Copyright 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 1995, 1996, 1997, 1998, 1999
6 * The Internet Software Consortium. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
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''.
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
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
60 #define hyphenchar(c) ((c) == 0x2d)
61 #define bslashchar(c) ((c) == 0x5c)
62 #define periodchar(c) ((c) == PERIOD)
63 #define asterchar(c) ((c) == 0x2a)
64 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
65 ((c) >= 0x61 && (c) <= 0x7a))
66 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
68 #define borderchar(c) (alphachar(c) || digitchar(c))
69 #define middlechar(c) (borderchar(c) || hyphenchar(c))
70 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
72 unsigned long debug_trace_level
= 0; /* DEBUG_ULTRA */
74 char *path_dhclient_conf
= _PATH_DHCLIENT_CONF
;
75 char *path_dhclient_db
= NULL
;
81 struct iaddr iaddr_broadcast
= { 4, { 255, 255, 255, 255 } };
82 struct in_addr inaddr_any
;
83 struct sockaddr_in sockaddr_broadcast
;
86 * ASSERT_STATE() does nothing now; it used to be
87 * assert (state_is == state_shouldbe).
89 #define ASSERT_STATE(state_is, state_shouldbe) {}
91 #define TIME_MAX 2147483647
99 int check_option(struct client_lease
*l
, int option
);
100 int ipv4addrs(char * buf
);
101 int res_hnok(const char *dn
);
102 char *option_as_string(unsigned int code
, unsigned char *data
, int len
);
103 int fork_privchld(int, int);
104 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
);
106 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
110 static WCHAR ServiceName
[] = L
"DHCP";
112 SERVICE_STATUS_HANDLE ServiceStatusHandle
= 0;
113 SERVICE_STATUS ServiceStatus
;
116 /* XXX Implement me */
117 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
) {
123 UpdateServiceStatus(DWORD dwState
)
125 ServiceStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
126 ServiceStatus
.dwCurrentState
= dwState
;
128 ServiceStatus
.dwControlsAccepted
= 0;
130 ServiceStatus
.dwWin32ExitCode
= 0;
131 ServiceStatus
.dwServiceSpecificExitCode
= 0;
132 ServiceStatus
.dwCheckPoint
= 0;
134 if (dwState
== SERVICE_START_PENDING
||
135 dwState
== SERVICE_STOP_PENDING
||
136 dwState
== SERVICE_PAUSE_PENDING
||
137 dwState
== SERVICE_CONTINUE_PENDING
)
138 ServiceStatus
.dwWaitHint
= 10000;
140 ServiceStatus
.dwWaitHint
= 0;
142 SetServiceStatus(ServiceStatusHandle
,
148 ServiceControlHandler(DWORD dwControl
,
155 case SERVICE_CONTROL_STOP
:
156 UpdateServiceStatus(SERVICE_STOP_PENDING
);
157 UpdateServiceStatus(SERVICE_STOPPED
);
158 return ERROR_SUCCESS
;
160 case SERVICE_CONTROL_PAUSE
:
161 UpdateServiceStatus(SERVICE_PAUSED
);
162 return ERROR_SUCCESS
;
164 case SERVICE_CONTROL_CONTINUE
:
165 UpdateServiceStatus(SERVICE_START_PENDING
);
166 UpdateServiceStatus(SERVICE_RUNNING
);
167 return ERROR_SUCCESS
;
169 case SERVICE_CONTROL_INTERROGATE
:
170 SetServiceStatus(ServiceStatusHandle
,
172 return ERROR_SUCCESS
;
174 case SERVICE_CONTROL_SHUTDOWN
:
175 UpdateServiceStatus(SERVICE_STOP_PENDING
);
176 UpdateServiceStatus(SERVICE_STOPPED
);
177 return ERROR_SUCCESS
;
180 return ERROR_CALL_NOT_IMPLEMENTED
;
186 ServiceMain(DWORD argc
, LPWSTR
*argv
)
188 ServiceStatusHandle
= RegisterServiceCtrlHandlerExW(ServiceName
,
189 ServiceControlHandler
,
191 if (!ServiceStatusHandle
)
193 DbgPrint("DHCPCSVC: Unable to register service control handler (%x)\n", GetLastError
);
197 UpdateServiceStatus(SERVICE_START_PENDING
);
204 memset(&sockaddr_broadcast
, 0, sizeof(sockaddr_broadcast
));
205 sockaddr_broadcast
.sin_family
= AF_INET
;
206 sockaddr_broadcast
.sin_port
= htons(REMOTE_PORT
);
207 sockaddr_broadcast
.sin_addr
.s_addr
= INADDR_BROADCAST
;
208 inaddr_any
.s_addr
= INADDR_ANY
;
209 bootp_packet_handler
= do_packet
;
211 if (PipeInit() == INVALID_HANDLE_VALUE
)
213 DbgPrint("DHCPCSVC: PipeInit() failed!\n");
216 UpdateServiceStatus(SERVICE_STOPPED
);
219 DH_DbgPrint(MID_TRACE
,("DHCP Service Started\n"));
221 UpdateServiceStatus(SERVICE_RUNNING
);
223 DH_DbgPrint(MID_TRACE
,("Going into dispatch()\n"));
225 DbgPrint("DHCPCSVC: DHCP service is starting up\n");
229 DbgPrint("DHCPCSVC: DHCP service is shutting down\n");
233 /* FIXME: Close pipe and kill pipe thread */
235 UpdateServiceStatus(SERVICE_STOPPED
);
241 * Each routine is called from the dhclient_state_machine() in one of
243 * -> entering INIT state
244 * -> recvpacket_flag == 0: timeout in this state
245 * -> otherwise: received a packet in this state
247 * Return conditions as handled by dhclient_state_machine():
248 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
249 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
250 * Returns 0: finish the nap which was interrupted for no good reason.
252 * Several per-interface variables are used to keep track of the process:
253 * active_lease: the lease that is being used on the interface
254 * (null pointer if not configured yet).
255 * offered_leases: leases corresponding to DHCPOFFER messages that have
256 * been sent to us by DHCP servers.
257 * acked_leases: leases corresponding to DHCPACK messages that have been
258 * sent to us by DHCP servers.
259 * sendpacket: DHCP packet we're trying to send.
260 * destination: IP address to send sendpacket to
261 * In addition, there are several relevant per-lease variables.
262 * T1_expiry, T2_expiry, lease_expiry: lease milestones
263 * In the active lease, these control the process of renewing the lease;
264 * In leases on the acked_leases list, this simply determines when we
265 * can no longer legitimately use the lease.
269 state_reboot(void *ipp
)
271 struct interface_info
*ip
= ipp
;
272 ULONG foo
= (ULONG
) GetTickCount();
274 /* If we don't remember an active lease, go straight to INIT. */
275 if (!ip
->client
->active
|| ip
->client
->active
->is_bootp
) {
280 /* We are in the rebooting state. */
281 ip
->client
->state
= S_REBOOTING
;
283 /* make_request doesn't initialize xid because it normally comes
284 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
285 so pick an xid now. */
286 ip
->client
->xid
= RtlRandom(&foo
);
288 /* Make a DHCPREQUEST packet, and set appropriate per-interface
290 make_request(ip
, ip
->client
->active
);
291 ip
->client
->destination
= iaddr_broadcast
;
292 time(&ip
->client
->first_sending
);
293 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
295 /* Zap the medium list... */
296 ip
->client
->medium
= NULL
;
298 /* Send out the first DHCPREQUEST packet. */
303 * Called when a lease has completely expired and we've
304 * been unable to renew it.
307 state_init(void *ipp
)
309 struct interface_info
*ip
= ipp
;
311 ASSERT_STATE(state
, S_INIT
);
313 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
315 make_discover(ip
, ip
->client
->active
);
316 ip
->client
->xid
= ip
->client
->packet
.xid
;
317 ip
->client
->destination
= iaddr_broadcast
;
318 ip
->client
->state
= S_SELECTING
;
319 time(&ip
->client
->first_sending
);
320 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
322 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
328 * state_selecting is called when one or more DHCPOFFER packets
329 * have been received and a configurable period of time has passed.
332 state_selecting(void *ipp
)
334 struct interface_info
*ip
= ipp
;
335 struct client_lease
*lp
, *next
, *picked
;
338 ASSERT_STATE(state
, S_SELECTING
);
342 /* Cancel state_selecting and send_discover timeouts, since either
343 one could have got us here. */
344 cancel_timeout(state_selecting
, ip
);
345 cancel_timeout(send_discover
, ip
);
347 /* We have received one or more DHCPOFFER packets. Currently,
348 the only criterion by which we judge leases is whether or
349 not we get a response when we arp for them. */
351 for (lp
= ip
->client
->offered_leases
; lp
; lp
= next
) {
354 /* Check to see if we got an ARPREPLY for the address
355 in this particular lease. */
357 if( !check_arp(ip
,lp
) ) goto freeit
;
362 free_client_lease(lp
);
365 ip
->client
->offered_leases
= NULL
;
367 /* If we just tossed all the leases we were offered, go back
370 ip
->client
->state
= S_INIT
;
375 /* If it was a BOOTREPLY, we can just take the address right now. */
376 if (!picked
->options
[DHO_DHCP_MESSAGE_TYPE
].len
) {
377 ip
->client
->new = picked
;
379 /* Make up some lease expiry times
380 XXX these should be configurable. */
381 ip
->client
->new->expiry
= cur_time
+ 12000;
382 ip
->client
->new->renewal
+= cur_time
+ 8000;
383 ip
->client
->new->rebind
+= cur_time
+ 10000;
385 ip
->client
->state
= S_REQUESTING
;
387 /* Bind to the address we received. */
392 /* Go to the REQUESTING state. */
393 ip
->client
->destination
= iaddr_broadcast
;
394 ip
->client
->state
= S_REQUESTING
;
395 ip
->client
->first_sending
= cur_time
;
396 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
398 /* Make a DHCPREQUEST packet from the lease we picked. */
399 make_request(ip
, picked
);
400 ip
->client
->xid
= ip
->client
->packet
.xid
;
402 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
403 free_client_lease(picked
);
405 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
409 /* state_requesting is called when we receive a DHCPACK message after
410 having sent out one or more DHCPREQUEST packets. */
413 dhcpack(struct packet
*packet
)
415 struct interface_info
*ip
= packet
->interface
;
416 struct client_lease
*lease
;
421 /* If we're not receptive to an offer right now, or if the offer
422 has an unrecognizable transaction id, then just drop it. */
423 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
424 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
425 (memcmp(packet
->interface
->hw_address
.haddr
,
426 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
429 if (ip
->client
->state
!= S_REBOOTING
&&
430 ip
->client
->state
!= S_REQUESTING
&&
431 ip
->client
->state
!= S_RENEWING
&&
432 ip
->client
->state
!= S_REBINDING
)
435 note("DHCPACK from %s", piaddr(packet
->client_addr
));
437 lease
= packet_to_lease(packet
);
439 note("packet_to_lease failed.");
443 ip
->client
->new = lease
;
445 /* Stop resending DHCPREQUEST. */
446 cancel_timeout(send_request
, ip
);
448 /* Figure out the lease time. */
449 if (ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
)
450 ip
->client
->new->expiry
= getULong(
451 ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
);
453 ip
->client
->new->expiry
= DHCP_DEFAULT_LEASE_TIME
;
454 /* A number that looks negative here is really just very large,
455 because the lease expiry offset is unsigned. */
456 if (ip
->client
->new->expiry
< 0)
457 ip
->client
->new->expiry
= TIME_MAX
;
458 /* XXX should be fixed by resetting the client state */
459 if (ip
->client
->new->expiry
< 60)
460 ip
->client
->new->expiry
= 60;
462 /* Take the server-provided renewal time if there is one;
463 otherwise figure it out according to the spec. */
464 if (ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].len
)
465 ip
->client
->new->renewal
= getULong(
466 ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].data
);
468 ip
->client
->new->renewal
= ip
->client
->new->expiry
/ 2;
470 /* Same deal with the rebind time. */
471 if (ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].len
)
472 ip
->client
->new->rebind
= getULong(
473 ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].data
);
475 ip
->client
->new->rebind
= ip
->client
->new->renewal
+
476 ip
->client
->new->renewal
/ 2 + ip
->client
->new->renewal
/ 4;
479 ip
->client
->new->obtained
= cur_time
;
481 ip
->client
->new->expiry
+= cur_time
;
482 /* Lease lengths can never be negative. */
483 if (ip
->client
->new->expiry
< cur_time
)
484 ip
->client
->new->expiry
= TIME_MAX
;
485 ip
->client
->new->renewal
+= cur_time
;
486 if (ip
->client
->new->renewal
< cur_time
)
487 ip
->client
->new->renewal
= TIME_MAX
;
488 ip
->client
->new->rebind
+= cur_time
;
489 if (ip
->client
->new->rebind
< cur_time
)
490 ip
->client
->new->rebind
= TIME_MAX
;
495 void set_name_servers( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
496 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
499 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
500 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &RegKey
) != ERROR_SUCCESS
)
504 if( new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
) {
506 struct iaddr nameserver
;
509 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
/ sizeof(ULONG
);
511 nsbuf
= malloc( addrs
* sizeof(IP_ADDRESS_STRING
) );
515 for( i
= 0; i
< addrs
; i
++ ) {
516 nameserver
.len
= sizeof(ULONG
);
517 memcpy( nameserver
.iabuf
,
518 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].data
+
519 (i
* sizeof(ULONG
)), sizeof(ULONG
) );
520 strcat( nsbuf
, piaddr(nameserver
) );
521 if( i
!= addrs
-1 ) strcat( nsbuf
, "," );
524 DH_DbgPrint(MID_TRACE
,("Setting DhcpNameserver: %s\n", nsbuf
));
526 RegSetValueExA( RegKey
, "DhcpNameServer", 0, REG_SZ
,
527 (LPBYTE
)nsbuf
, strlen(nsbuf
) + 1 );
532 RegDeleteValueW( RegKey
, L
"DhcpNameServer" );
535 RegCloseKey( RegKey
);
539 void setup_adapter( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
540 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
541 struct iaddr netmask
;
546 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
547 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &hkey
) != ERROR_SUCCESS
)
551 if( Adapter
->NteContext
)
552 DeleteIPAddress( Adapter
->NteContext
);
554 /* Set up our default router if we got one from the DHCP server */
555 if( new_lease
->options
[DHO_SUBNET_MASK
].len
) {
558 memcpy( netmask
.iabuf
,
559 new_lease
->options
[DHO_SUBNET_MASK
].data
,
560 new_lease
->options
[DHO_SUBNET_MASK
].len
);
561 Status
= AddIPAddress
562 ( *((ULONG
*)new_lease
->address
.iabuf
),
563 *((ULONG
*)netmask
.iabuf
),
564 Adapter
->IfMib
.dwIndex
,
565 &Adapter
->NteContext
,
566 &Adapter
->NteInstance
);
568 RegSetValueExA(hkey
, "DhcpIPAddress", 0, REG_SZ
, (LPBYTE
)piaddr(new_lease
->address
), strlen(piaddr(new_lease
->address
))+1);
570 for(i
= 0; i
< new_lease
->options
[DHO_SUBNET_MASK
].len
; i
++)
572 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_SUBNET_MASK
].data
[i
]);
573 if (i
+ 1 < new_lease
->options
[DHO_SUBNET_MASK
].len
)
576 RegSetValueExA(hkey
, "DhcpSubnetMask", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
578 RegSetValueExA(hkey
, "EnableDHCP", 0, REG_DWORD
, (LPBYTE
)&dwEnableDHCP
, sizeof(DWORD
));
581 if( !NT_SUCCESS(Status
) )
582 warning("AddIPAddress: %lx\n", Status
);
585 if( new_lease
->options
[DHO_ROUTERS
].len
) {
588 Adapter
->RouterMib
.dwForwardDest
= 0; /* Default route */
589 Adapter
->RouterMib
.dwForwardMask
= 0;
590 Adapter
->RouterMib
.dwForwardMetric1
= 1;
591 Adapter
->RouterMib
.dwForwardIfIndex
= Adapter
->IfMib
.dwIndex
;
593 if( Adapter
->RouterMib
.dwForwardNextHop
) {
594 /* If we set a default route before, delete it before continuing */
595 DeleteIpForwardEntry( &Adapter
->RouterMib
);
598 Adapter
->RouterMib
.dwForwardNextHop
=
599 *((ULONG
*)new_lease
->options
[DHO_ROUTERS
].data
);
601 Status
= CreateIpForwardEntry( &Adapter
->RouterMib
);
603 if( !NT_SUCCESS(Status
) )
604 warning("CreateIpForwardEntry: %lx\n", Status
);
608 for(i
= 0; i
< new_lease
->options
[DHO_ROUTERS
].len
; i
++)
610 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_ROUTERS
].data
[i
]);
611 if (i
+ 1 < new_lease
->options
[DHO_ROUTERS
].len
)
614 RegSetValueExA(hkey
, "DhcpDefaultGateway", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
624 bind_lease(struct interface_info
*ip
)
626 PDHCP_ADAPTER Adapter
;
627 struct client_lease
*new_lease
= ip
->client
->new;
632 /* Remember the medium. */
633 ip
->client
->new->medium
= ip
->client
->medium
;
634 ip
->client
->active
= ip
->client
->new;
635 ip
->client
->new = NULL
;
637 /* Set up a timeout to start the renewal process. */
638 /* Timeout of zero means no timeout (some implementations seem to use
641 if( ip
->client
->active
->renewal
- cur_time
)
642 add_timeout(ip
->client
->active
->renewal
, state_bound
, ip
);
644 note("bound to %s -- renewal in %ld seconds.",
645 piaddr(ip
->client
->active
->address
),
646 (long int)(ip
->client
->active
->renewal
- cur_time
));
648 ip
->client
->state
= S_BOUND
;
650 Adapter
= AdapterFindInfo( ip
);
652 if( Adapter
) setup_adapter( Adapter
, new_lease
);
654 warning("Could not find adapter for info %p\n", ip
);
657 set_name_servers( Adapter
, new_lease
);
661 * state_bound is called when we've successfully bound to a particular
662 * lease, but the renewal time on that lease has expired. We are
663 * expected to unicast a DHCPREQUEST to the server that gave us our
667 state_bound(void *ipp
)
669 struct interface_info
*ip
= ipp
;
671 ASSERT_STATE(state
, S_BOUND
);
673 /* T1 has expired. */
674 make_request(ip
, ip
->client
->active
);
675 ip
->client
->xid
= ip
->client
->packet
.xid
;
677 if (ip
->client
->active
->options
[DHO_DHCP_SERVER_IDENTIFIER
].len
== 4) {
678 memcpy(ip
->client
->destination
.iabuf
, ip
->client
->active
->
679 options
[DHO_DHCP_SERVER_IDENTIFIER
].data
, 4);
680 ip
->client
->destination
.len
= 4;
682 ip
->client
->destination
= iaddr_broadcast
;
684 time(&ip
->client
->first_sending
);
685 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
686 ip
->client
->state
= S_RENEWING
;
688 /* Send the first packet immediately. */
693 bootp(struct packet
*packet
)
695 struct iaddrlist
*ap
;
697 if (packet
->raw
->op
!= BOOTREPLY
)
700 /* If there's a reject list, make sure this packet's sender isn't
702 for (ap
= packet
->interface
->client
->config
->reject_list
;
704 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
705 note("BOOTREPLY from %s rejected.", piaddr(ap
->addr
));
713 dhcp(struct packet
*packet
)
715 struct iaddrlist
*ap
;
716 void (*handler
)(struct packet
*);
719 switch (packet
->packet_type
) {
736 /* If there's a reject list, make sure this packet's sender isn't
738 for (ap
= packet
->interface
->client
->config
->reject_list
;
740 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
741 note("%s from %s rejected.", type
, piaddr(ap
->addr
));
749 dhcpoffer(struct packet
*packet
)
751 struct interface_info
*ip
= packet
->interface
;
752 struct client_lease
*lease
, *lp
;
754 int arp_timeout_needed
= 0, stop_selecting
;
755 char *name
= packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
?
756 "DHCPOFFER" : "BOOTREPLY";
761 /* If we're not receptive to an offer right now, or if the offer
762 has an unrecognizable transaction id, then just drop it. */
763 if (ip
->client
->state
!= S_SELECTING
||
764 packet
->interface
->client
->xid
!= packet
->raw
->xid
||
765 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
766 (memcmp(packet
->interface
->hw_address
.haddr
,
767 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
770 note("%s from %s", name
, piaddr(packet
->client_addr
));
773 /* If this lease doesn't supply the minimum required parameters,
775 for (i
= 0; ip
->client
->config
->required_options
[i
]; i
++) {
776 if (!packet
->options
[ip
->client
->config
->
777 required_options
[i
]].len
) {
778 note("%s isn't satisfactory.", name
);
783 /* If we've already seen this lease, don't record it again. */
784 for (lease
= ip
->client
->offered_leases
;
785 lease
; lease
= lease
->next
) {
786 if (lease
->address
.len
== sizeof(packet
->raw
->yiaddr
) &&
787 !memcmp(lease
->address
.iabuf
,
788 &packet
->raw
->yiaddr
, lease
->address
.len
)) {
789 debug("%s already seen.", name
);
794 lease
= packet_to_lease(packet
);
796 note("packet_to_lease failed.");
800 /* If this lease was acquired through a BOOTREPLY, record that
802 if (!packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
)
805 /* Record the medium under which this lease was offered. */
806 lease
->medium
= ip
->client
->medium
;
808 /* Send out an ARP Request for the offered IP address. */
809 if( !check_arp( ip
, lease
) ) {
810 note("Arp check failed\n");
814 /* Figure out when we're supposed to stop selecting. */
816 ip
->client
->first_sending
+ ip
->client
->config
->select_interval
;
818 /* If this is the lease we asked for, put it at the head of the
819 list, and don't mess with the arp request timeout. */
820 if (lease
->address
.len
== ip
->client
->requested_address
.len
&&
821 !memcmp(lease
->address
.iabuf
,
822 ip
->client
->requested_address
.iabuf
,
823 ip
->client
->requested_address
.len
)) {
824 lease
->next
= ip
->client
->offered_leases
;
825 ip
->client
->offered_leases
= lease
;
827 /* If we already have an offer, and arping for this
828 offer would take us past the selection timeout,
829 then don't extend the timeout - just hope for the
831 if (ip
->client
->offered_leases
&&
832 (cur_time
+ arp_timeout_needed
) > stop_selecting
)
833 arp_timeout_needed
= 0;
835 /* Put the lease at the end of the list. */
837 if (!ip
->client
->offered_leases
)
838 ip
->client
->offered_leases
= lease
;
840 for (lp
= ip
->client
->offered_leases
; lp
->next
;
847 /* If we're supposed to stop selecting before we've had time
848 to wait for the ARPREPLY, add some delay to wait for
850 if (stop_selecting
- cur_time
< arp_timeout_needed
)
851 stop_selecting
= cur_time
+ arp_timeout_needed
;
853 /* If the selecting interval has expired, go immediately to
854 state_selecting(). Otherwise, time out into
855 state_selecting at the select interval. */
856 if (stop_selecting
<= 0)
859 add_timeout(stop_selecting
, state_selecting
, ip
);
860 cancel_timeout(send_discover
, ip
);
864 /* Allocate a client_lease structure and initialize it from the parameters
865 in the specified packet. */
867 struct client_lease
*
868 packet_to_lease(struct packet
*packet
)
870 struct client_lease
*lease
;
873 lease
= malloc(sizeof(struct client_lease
));
876 warning("dhcpoffer: no memory to record lease.");
880 memset(lease
, 0, sizeof(*lease
));
882 /* Copy the lease options. */
883 for (i
= 0; i
< 256; i
++) {
884 if (packet
->options
[i
].len
) {
885 lease
->options
[i
].data
=
886 malloc(packet
->options
[i
].len
+ 1);
887 if (!lease
->options
[i
].data
) {
888 warning("dhcpoffer: no memory for option %d", i
);
889 free_client_lease(lease
);
892 memcpy(lease
->options
[i
].data
,
893 packet
->options
[i
].data
,
894 packet
->options
[i
].len
);
895 lease
->options
[i
].len
=
896 packet
->options
[i
].len
;
897 lease
->options
[i
].data
[lease
->options
[i
].len
] =
900 if (!check_option(lease
,i
)) {
901 /* ignore a bogus lease offer */
902 warning("Invalid lease option - ignoring offer");
903 free_client_lease(lease
);
909 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
910 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
, lease
->address
.len
);
912 lease
->serveraddress
.len
= sizeof(packet
->raw
->siaddr
);
913 memcpy(lease
->serveraddress
.iabuf
, &packet
->raw
->siaddr
, lease
->address
.len
);
916 /* If the server name was filled out, copy it. */
917 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
918 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 2)) &&
919 packet
->raw
->sname
[0]) {
920 lease
->server_name
= malloc(DHCP_SNAME_LEN
+ 1);
921 if (!lease
->server_name
) {
922 warning("dhcpoffer: no memory for server name.");
923 free_client_lease(lease
);
926 memcpy(lease
->server_name
, packet
->raw
->sname
, DHCP_SNAME_LEN
);
927 lease
->server_name
[DHCP_SNAME_LEN
]='\0';
928 if (!res_hnok(lease
->server_name
) ) {
929 warning("Bogus server name %s", lease
->server_name
);
930 free_client_lease(lease
);
936 /* Ditto for the filename. */
937 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
938 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 1)) &&
939 packet
->raw
->file
[0]) {
940 /* Don't count on the NUL terminator. */
941 lease
->filename
= malloc(DHCP_FILE_LEN
+ 1);
942 if (!lease
->filename
) {
943 warning("dhcpoffer: no memory for filename.");
944 free_client_lease(lease
);
947 memcpy(lease
->filename
, packet
->raw
->file
, DHCP_FILE_LEN
);
948 lease
->filename
[DHCP_FILE_LEN
]='\0';
954 dhcpnak(struct packet
*packet
)
956 struct interface_info
*ip
= packet
->interface
;
958 /* If we're not receptive to an offer right now, or if the offer
959 has an unrecognizable transaction id, then just drop it. */
960 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
961 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
962 (memcmp(packet
->interface
->hw_address
.haddr
,
963 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
966 if (ip
->client
->state
!= S_REBOOTING
&&
967 ip
->client
->state
!= S_REQUESTING
&&
968 ip
->client
->state
!= S_RENEWING
&&
969 ip
->client
->state
!= S_REBINDING
)
972 note("DHCPNAK from %s", piaddr(packet
->client_addr
));
974 if (!ip
->client
->active
) {
975 note("DHCPNAK with no active lease.\n");
979 free_client_lease(ip
->client
->active
);
980 ip
->client
->active
= NULL
;
982 /* Stop sending DHCPREQUEST packets... */
983 cancel_timeout(send_request
, ip
);
985 ip
->client
->state
= S_INIT
;
989 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
990 one after the right interval has expired. If we don't get an offer by
991 the time we reach the panic interval, call the panic function. */
994 send_discover(void *ipp
)
996 struct interface_info
*ip
= ipp
;
997 int interval
, increase
= 1;
1000 DH_DbgPrint(MID_TRACE
,("Doing discover on interface %p\n",ip
));
1004 /* Figure out how long it's been since we started transmitting. */
1005 interval
= cur_time
- ip
->client
->first_sending
;
1007 /* If we're past the panic timeout, call the script and tell it
1008 we haven't found anything for this interface yet. */
1009 if (interval
> ip
->client
->config
->timeout
) {
1014 /* If we're selecting media, try the whole list before doing
1015 the exponential backoff, but if we've already received an
1016 offer, stop looping, because we obviously have it right. */
1017 if (!ip
->client
->offered_leases
&&
1018 ip
->client
->config
->media
) {
1021 if (ip
->client
->medium
) {
1022 ip
->client
->medium
= ip
->client
->medium
->next
;
1025 if (!ip
->client
->medium
) {
1027 error("No valid media types for %s!", ip
->name
);
1028 ip
->client
->medium
= ip
->client
->config
->media
;
1032 note("Trying medium \"%s\" %d", ip
->client
->medium
->string
,
1034 /* XXX Support other media types eventually */
1038 * If we're supposed to increase the interval, do so. If it's
1039 * currently zero (i.e., we haven't sent any packets yet), set
1040 * it to one; otherwise, add to it a random number between zero
1041 * and two times itself. On average, this means that it will
1042 * double with every transmission.
1045 if (!ip
->client
->interval
)
1046 ip
->client
->interval
=
1047 ip
->client
->config
->initial_interval
;
1049 ip
->client
->interval
+= (rand() >> 2) %
1050 (2 * ip
->client
->interval
);
1053 /* Don't backoff past cutoff. */
1054 if (ip
->client
->interval
>
1055 ip
->client
->config
->backoff_cutoff
)
1056 ip
->client
->interval
=
1057 ((ip
->client
->config
->backoff_cutoff
/ 2)
1059 ip
->client
->config
->backoff_cutoff
));
1060 } else if (!ip
->client
->interval
)
1061 ip
->client
->interval
=
1062 ip
->client
->config
->initial_interval
;
1064 /* If the backoff would take us to the panic timeout, just use that
1066 if (cur_time
+ ip
->client
->interval
>
1067 ip
->client
->first_sending
+ ip
->client
->config
->timeout
)
1068 ip
->client
->interval
=
1069 (ip
->client
->first_sending
+
1070 ip
->client
->config
->timeout
) - cur_time
+ 1;
1072 /* Record the number of seconds since we started sending. */
1073 if (interval
< 65536)
1074 ip
->client
->packet
.secs
= htons(interval
);
1076 ip
->client
->packet
.secs
= htons(65535);
1077 ip
->client
->secs
= ip
->client
->packet
.secs
;
1079 note("DHCPDISCOVER on %s to %s port %d interval %ld",
1080 ip
->name
, inet_ntoa(sockaddr_broadcast
.sin_addr
),
1081 ntohs(sockaddr_broadcast
.sin_port
), (long int)ip
->client
->interval
);
1083 /* Send out a packet. */
1084 (void)send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1085 inaddr_any
, &sockaddr_broadcast
, NULL
);
1087 DH_DbgPrint(MID_TRACE
,("discover timeout: now %x -> then %x\n",
1088 cur_time
, cur_time
+ ip
->client
->interval
));
1090 add_timeout(cur_time
+ ip
->client
->interval
, send_discover
, ip
);
1094 * state_panic gets called if we haven't received any offers in a preset
1095 * amount of time. When this happens, we try to use existing leases
1096 * that haven't yet expired, and failing that, we call the client script
1097 * and hope it can do something.
1100 state_panic(void *ipp
)
1102 struct interface_info
*ip
= ipp
;
1103 PDHCP_ADAPTER Adapter
= AdapterFindInfo(ip
);
1108 note("No DHCPOFFERS received.");
1110 note("No working leases in persistent database - sleeping.\n");
1111 ip
->client
->state
= S_INIT
;
1112 add_timeout(cur_time
+ ip
->client
->config
->retry_interval
, state_init
,
1115 if (!Adapter
->NteContext
)
1117 /* Generate an automatic private address */
1118 DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n");
1120 /* FIXME: The address generation code sucks */
1121 AddIPAddress(htonl(0xA9FE0000 | (rand() % 0xFFFF)), //169.254.X.X
1122 htonl(0xFFFF0000), //255.255.0.0
1123 Adapter
->IfMib
.dwIndex
,
1124 &Adapter
->NteContext
,
1125 &Adapter
->NteInstance
);
1130 send_request(void *ipp
)
1132 struct interface_info
*ip
= ipp
;
1133 struct sockaddr_in destination
;
1134 struct in_addr from
;
1140 /* Figure out how long it's been since we started transmitting. */
1141 interval
= cur_time
- ip
->client
->first_sending
;
1143 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1144 past the reboot timeout, go to INIT and see if we can
1145 DISCOVER an address... */
1146 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1147 means either that we're on a network with no DHCP server,
1148 or that our server is down. In the latter case, assuming
1149 that there is a backup DHCP server, DHCPDISCOVER will get
1150 us a new address, but we could also have successfully
1151 reused our old address. In the former case, we're hosed
1152 anyway. This is not a win-prone situation. */
1153 if ((ip
->client
->state
== S_REBOOTING
||
1154 ip
->client
->state
== S_REQUESTING
) &&
1155 interval
> ip
->client
->config
->reboot_timeout
) {
1156 ip
->client
->state
= S_INIT
;
1157 cancel_timeout(send_request
, ip
);
1162 /* If we're in the reboot state, make sure the media is set up
1164 if (ip
->client
->state
== S_REBOOTING
&&
1165 !ip
->client
->medium
&&
1166 ip
->client
->active
->medium
) {
1167 /* If the medium we chose won't fly, go to INIT state. */
1168 /* XXX Nothing for now */
1170 /* Record the medium. */
1171 ip
->client
->medium
= ip
->client
->active
->medium
;
1174 /* If the lease has expired, relinquish the address and go back
1175 to the INIT state. */
1176 if (ip
->client
->state
!= S_REQUESTING
&&
1177 cur_time
> ip
->client
->active
->expiry
) {
1178 PDHCP_ADAPTER Adapter
= AdapterFindInfo( ip
);
1179 /* Run the client script with the new parameters. */
1180 /* No script actions necessary in the expiry case */
1181 /* Now do a preinit on the interface so that we can
1182 discover a new address. */
1185 DeleteIPAddress( Adapter
->NteContext
);
1187 ip
->client
->state
= S_INIT
;
1192 /* Do the exponential backoff... */
1193 if (!ip
->client
->interval
)
1194 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
1196 ip
->client
->interval
+= ((rand() >> 2) %
1197 (2 * ip
->client
->interval
));
1199 /* Don't backoff past cutoff. */
1200 if (ip
->client
->interval
>
1201 ip
->client
->config
->backoff_cutoff
)
1202 ip
->client
->interval
=
1203 ((ip
->client
->config
->backoff_cutoff
/ 2) +
1204 ((rand() >> 2) % ip
->client
->interval
));
1206 /* If the backoff would take us to the expiry time, just set the
1207 timeout to the expiry time. */
1208 if (ip
->client
->state
!= S_REQUESTING
&&
1209 cur_time
+ ip
->client
->interval
>
1210 ip
->client
->active
->expiry
)
1211 ip
->client
->interval
=
1212 ip
->client
->active
->expiry
- cur_time
+ 1;
1214 /* If the lease T2 time has elapsed, or if we're not yet bound,
1215 broadcast the DHCPREQUEST rather than unicasting. */
1216 memset(&destination
, 0, sizeof(destination
));
1217 if (ip
->client
->state
== S_REQUESTING
||
1218 ip
->client
->state
== S_REBOOTING
||
1219 cur_time
> ip
->client
->active
->rebind
)
1220 destination
.sin_addr
.s_addr
= INADDR_BROADCAST
;
1222 memcpy(&destination
.sin_addr
.s_addr
,
1223 ip
->client
->destination
.iabuf
,
1224 sizeof(destination
.sin_addr
.s_addr
));
1225 destination
.sin_port
= htons(REMOTE_PORT
);
1226 destination
.sin_family
= AF_INET
;
1227 // destination.sin_len = sizeof(destination);
1229 if (ip
->client
->state
!= S_REQUESTING
)
1230 memcpy(&from
, ip
->client
->active
->address
.iabuf
,
1233 from
.s_addr
= INADDR_ANY
;
1235 /* Record the number of seconds since we started sending. */
1236 if (ip
->client
->state
== S_REQUESTING
)
1237 ip
->client
->packet
.secs
= ip
->client
->secs
;
1239 if (interval
< 65536)
1240 ip
->client
->packet
.secs
= htons(interval
);
1242 ip
->client
->packet
.secs
= htons(65535);
1245 note("DHCPREQUEST on %s to %s port %d", ip
->name
,
1246 inet_ntoa(destination
.sin_addr
), ntohs(destination
.sin_port
));
1248 /* Send out a packet. */
1249 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1250 from
, &destination
, NULL
);
1252 add_timeout(cur_time
+ ip
->client
->interval
, send_request
, ip
);
1256 send_decline(void *ipp
)
1258 struct interface_info
*ip
= ipp
;
1260 note("DHCPDECLINE on %s to %s port %d", ip
->name
,
1261 inet_ntoa(sockaddr_broadcast
.sin_addr
),
1262 ntohs(sockaddr_broadcast
.sin_port
));
1264 /* Send out a packet. */
1265 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1266 inaddr_any
, &sockaddr_broadcast
, NULL
);
1270 make_discover(struct interface_info
*ip
, struct client_lease
*lease
)
1272 unsigned char discover
= DHCPDISCOVER
;
1273 struct tree_cache
*options
[256];
1274 struct tree_cache option_elements
[256];
1276 ULONG foo
= (ULONG
) GetTickCount();
1278 memset(option_elements
, 0, sizeof(option_elements
));
1279 memset(options
, 0, sizeof(options
));
1280 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1282 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1283 i
= DHO_DHCP_MESSAGE_TYPE
;
1284 options
[i
] = &option_elements
[i
];
1285 options
[i
]->value
= &discover
;
1286 options
[i
]->len
= sizeof(discover
);
1287 options
[i
]->buf_size
= sizeof(discover
);
1288 options
[i
]->timeout
= 0xFFFFFFFF;
1290 /* Request the options we want */
1291 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1292 options
[i
] = &option_elements
[i
];
1293 options
[i
]->value
= ip
->client
->config
->requested_options
;
1294 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1295 options
[i
]->buf_size
=
1296 ip
->client
->config
->requested_option_count
;
1297 options
[i
]->timeout
= 0xFFFFFFFF;
1299 /* If we had an address, try to get it again. */
1301 ip
->client
->requested_address
= lease
->address
;
1302 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1303 options
[i
] = &option_elements
[i
];
1304 options
[i
]->value
= lease
->address
.iabuf
;
1305 options
[i
]->len
= lease
->address
.len
;
1306 options
[i
]->buf_size
= lease
->address
.len
;
1307 options
[i
]->timeout
= 0xFFFFFFFF;
1309 ip
->client
->requested_address
.len
= 0;
1311 /* Send any options requested in the config file. */
1312 for (i
= 0; i
< 256; i
++)
1314 ip
->client
->config
->send_options
[i
].data
) {
1315 options
[i
] = &option_elements
[i
];
1317 ip
->client
->config
->send_options
[i
].data
;
1319 ip
->client
->config
->send_options
[i
].len
;
1320 options
[i
]->buf_size
=
1321 ip
->client
->config
->send_options
[i
].len
;
1322 options
[i
]->timeout
= 0xFFFFFFFF;
1325 /* Set up the option buffer... */
1326 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1327 options
, 0, 0, 0, NULL
, 0);
1328 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1329 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1331 ip
->client
->packet
.op
= BOOTREQUEST
;
1332 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1333 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1334 ip
->client
->packet
.hops
= 0;
1335 ip
->client
->packet
.xid
= RtlRandom(&foo
);
1336 ip
->client
->packet
.secs
= 0; /* filled in by send_discover. */
1337 ip
->client
->packet
.flags
= 0;
1339 memset(&(ip
->client
->packet
.ciaddr
),
1340 0, sizeof(ip
->client
->packet
.ciaddr
));
1341 memset(&(ip
->client
->packet
.yiaddr
),
1342 0, sizeof(ip
->client
->packet
.yiaddr
));
1343 memset(&(ip
->client
->packet
.siaddr
),
1344 0, sizeof(ip
->client
->packet
.siaddr
));
1345 memset(&(ip
->client
->packet
.giaddr
),
1346 0, sizeof(ip
->client
->packet
.giaddr
));
1347 memcpy(ip
->client
->packet
.chaddr
,
1348 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1353 make_request(struct interface_info
*ip
, struct client_lease
* lease
)
1355 unsigned char request
= DHCPREQUEST
;
1356 struct tree_cache
*options
[256];
1357 struct tree_cache option_elements
[256];
1360 memset(options
, 0, sizeof(options
));
1361 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1363 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1364 i
= DHO_DHCP_MESSAGE_TYPE
;
1365 options
[i
] = &option_elements
[i
];
1366 options
[i
]->value
= &request
;
1367 options
[i
]->len
= sizeof(request
);
1368 options
[i
]->buf_size
= sizeof(request
);
1369 options
[i
]->timeout
= 0xFFFFFFFF;
1371 /* Request the options we want */
1372 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1373 options
[i
] = &option_elements
[i
];
1374 options
[i
]->value
= ip
->client
->config
->requested_options
;
1375 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1376 options
[i
]->buf_size
=
1377 ip
->client
->config
->requested_option_count
;
1378 options
[i
]->timeout
= 0xFFFFFFFF;
1380 /* If we are requesting an address that hasn't yet been assigned
1381 to us, use the DHCP Requested Address option. */
1382 if (ip
->client
->state
== S_REQUESTING
) {
1383 /* Send back the server identifier... */
1384 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1385 options
[i
] = &option_elements
[i
];
1386 options
[i
]->value
= lease
->options
[i
].data
;
1387 options
[i
]->len
= lease
->options
[i
].len
;
1388 options
[i
]->buf_size
= lease
->options
[i
].len
;
1389 options
[i
]->timeout
= 0xFFFFFFFF;
1391 if (ip
->client
->state
== S_REQUESTING
||
1392 ip
->client
->state
== S_REBOOTING
) {
1393 ip
->client
->requested_address
= lease
->address
;
1394 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1395 options
[i
] = &option_elements
[i
];
1396 options
[i
]->value
= lease
->address
.iabuf
;
1397 options
[i
]->len
= lease
->address
.len
;
1398 options
[i
]->buf_size
= lease
->address
.len
;
1399 options
[i
]->timeout
= 0xFFFFFFFF;
1401 ip
->client
->requested_address
.len
= 0;
1403 /* Send any options requested in the config file. */
1404 for (i
= 0; i
< 256; i
++)
1406 ip
->client
->config
->send_options
[i
].data
) {
1407 options
[i
] = &option_elements
[i
];
1409 ip
->client
->config
->send_options
[i
].data
;
1411 ip
->client
->config
->send_options
[i
].len
;
1412 options
[i
]->buf_size
=
1413 ip
->client
->config
->send_options
[i
].len
;
1414 options
[i
]->timeout
= 0xFFFFFFFF;
1417 /* Set up the option buffer... */
1418 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1419 options
, 0, 0, 0, NULL
, 0);
1420 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1421 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1423 ip
->client
->packet
.op
= BOOTREQUEST
;
1424 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1425 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1426 ip
->client
->packet
.hops
= 0;
1427 ip
->client
->packet
.xid
= ip
->client
->xid
;
1428 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1430 /* If we own the address we're requesting, put it in ciaddr;
1431 otherwise set ciaddr to zero. */
1432 if (ip
->client
->state
== S_BOUND
||
1433 ip
->client
->state
== S_RENEWING
||
1434 ip
->client
->state
== S_REBINDING
) {
1435 memcpy(&ip
->client
->packet
.ciaddr
,
1436 lease
->address
.iabuf
, lease
->address
.len
);
1437 ip
->client
->packet
.flags
= 0;
1439 memset(&ip
->client
->packet
.ciaddr
, 0,
1440 sizeof(ip
->client
->packet
.ciaddr
));
1441 ip
->client
->packet
.flags
= 0;
1444 memset(&ip
->client
->packet
.yiaddr
, 0,
1445 sizeof(ip
->client
->packet
.yiaddr
));
1446 memset(&ip
->client
->packet
.siaddr
, 0,
1447 sizeof(ip
->client
->packet
.siaddr
));
1448 memset(&ip
->client
->packet
.giaddr
, 0,
1449 sizeof(ip
->client
->packet
.giaddr
));
1450 memcpy(ip
->client
->packet
.chaddr
,
1451 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1455 make_decline(struct interface_info
*ip
, struct client_lease
*lease
)
1457 struct tree_cache
*options
[256], message_type_tree
;
1458 struct tree_cache requested_address_tree
;
1459 struct tree_cache server_id_tree
, client_id_tree
;
1460 unsigned char decline
= DHCPDECLINE
;
1463 memset(options
, 0, sizeof(options
));
1464 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1466 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1467 i
= DHO_DHCP_MESSAGE_TYPE
;
1468 options
[i
] = &message_type_tree
;
1469 options
[i
]->value
= &decline
;
1470 options
[i
]->len
= sizeof(decline
);
1471 options
[i
]->buf_size
= sizeof(decline
);
1472 options
[i
]->timeout
= 0xFFFFFFFF;
1474 /* Send back the server identifier... */
1475 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1476 options
[i
] = &server_id_tree
;
1477 options
[i
]->value
= lease
->options
[i
].data
;
1478 options
[i
]->len
= lease
->options
[i
].len
;
1479 options
[i
]->buf_size
= lease
->options
[i
].len
;
1480 options
[i
]->timeout
= 0xFFFFFFFF;
1482 /* Send back the address we're declining. */
1483 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1484 options
[i
] = &requested_address_tree
;
1485 options
[i
]->value
= lease
->address
.iabuf
;
1486 options
[i
]->len
= lease
->address
.len
;
1487 options
[i
]->buf_size
= lease
->address
.len
;
1488 options
[i
]->timeout
= 0xFFFFFFFF;
1490 /* Send the uid if the user supplied one. */
1491 i
= DHO_DHCP_CLIENT_IDENTIFIER
;
1492 if (ip
->client
->config
->send_options
[i
].len
) {
1493 options
[i
] = &client_id_tree
;
1494 options
[i
]->value
= ip
->client
->config
->send_options
[i
].data
;
1495 options
[i
]->len
= ip
->client
->config
->send_options
[i
].len
;
1496 options
[i
]->buf_size
= ip
->client
->config
->send_options
[i
].len
;
1497 options
[i
]->timeout
= 0xFFFFFFFF;
1501 /* Set up the option buffer... */
1502 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1503 options
, 0, 0, 0, NULL
, 0);
1504 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1505 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1507 ip
->client
->packet
.op
= BOOTREQUEST
;
1508 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1509 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1510 ip
->client
->packet
.hops
= 0;
1511 ip
->client
->packet
.xid
= ip
->client
->xid
;
1512 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1513 ip
->client
->packet
.flags
= 0;
1515 /* ciaddr must always be zero. */
1516 memset(&ip
->client
->packet
.ciaddr
, 0,
1517 sizeof(ip
->client
->packet
.ciaddr
));
1518 memset(&ip
->client
->packet
.yiaddr
, 0,
1519 sizeof(ip
->client
->packet
.yiaddr
));
1520 memset(&ip
->client
->packet
.siaddr
, 0,
1521 sizeof(ip
->client
->packet
.siaddr
));
1522 memset(&ip
->client
->packet
.giaddr
, 0,
1523 sizeof(ip
->client
->packet
.giaddr
));
1524 memcpy(ip
->client
->packet
.chaddr
,
1525 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1529 free_client_lease(struct client_lease
*lease
)
1533 if (lease
->server_name
)
1534 free(lease
->server_name
);
1535 if (lease
->filename
)
1536 free(lease
->filename
);
1537 for (i
= 0; i
< 256; i
++) {
1538 if (lease
->options
[i
].len
)
1539 free(lease
->options
[i
].data
);
1547 rewrite_client_leases(struct interface_info
*ifi
)
1549 struct client_lease
*lp
;
1552 leaseFile
= fopen(path_dhclient_db
, "w");
1554 error("can't create %s", path_dhclient_db
);
1560 for (lp
= ifi
->client
->leases
; lp
; lp
= lp
->next
)
1561 write_client_lease(ifi
, lp
, 1);
1562 if (ifi
->client
->active
)
1563 write_client_lease(ifi
, ifi
->client
->active
, 1);
1569 write_client_lease(struct interface_info
*ip
, struct client_lease
*lease
,
1572 static int leases_written
;
1577 if (leases_written
++ > 20) {
1578 rewrite_client_leases(ip
);
1583 /* If the lease came from the config file, we don't need to stash
1584 a copy in the lease database. */
1585 if (lease
->is_static
)
1588 if (!leaseFile
) { /* XXX */
1589 leaseFile
= fopen(path_dhclient_db
, "w");
1591 error("can't create %s", path_dhclient_db
);
1596 fprintf(leaseFile
, "lease {\n");
1597 if (lease
->is_bootp
)
1598 fprintf(leaseFile
, " bootp;\n");
1599 fprintf(leaseFile
, " interface \"%s\";\n", ip
->name
);
1600 fprintf(leaseFile
, " fixed-address %s;\n", piaddr(lease
->address
));
1601 if (lease
->filename
)
1602 fprintf(leaseFile
, " filename \"%s\";\n", lease
->filename
);
1603 if (lease
->server_name
)
1604 fprintf(leaseFile
, " server-name \"%s\";\n",
1605 lease
->server_name
);
1607 fprintf(leaseFile
, " medium \"%s\";\n", lease
->medium
->string
);
1608 for (i
= 0; i
< 256; i
++)
1609 if (lease
->options
[i
].len
)
1610 fprintf(leaseFile
, " option %s %s;\n",
1611 dhcp_options
[i
].name
,
1612 pretty_print_option(i
, lease
->options
[i
].data
,
1613 lease
->options
[i
].len
, 1, 1));
1615 t
= gmtime(&lease
->renewal
);
1617 fprintf(leaseFile
, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1618 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1619 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1620 t
= gmtime(&lease
->rebind
);
1622 fprintf(leaseFile
, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1623 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1624 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1625 t
= gmtime(&lease
->expiry
);
1627 fprintf(leaseFile
, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1628 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1629 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1630 fprintf(leaseFile
, "}\n");
1635 priv_script_init(struct interface_info
*ip
, char *reason
, char *medium
)
1638 // XXX Do we need to do anything?
1643 priv_script_write_params(struct interface_info
*ip
, char *prefix
, struct client_lease
*lease
)
1645 u_int8_t dbuf
[1500];
1649 script_set_env(ip
->client
, prefix
, "ip_address",
1650 piaddr(lease
->address
));
1653 if (lease
->options
[DHO_SUBNET_MASK
].len
&&
1654 (lease
->options
[DHO_SUBNET_MASK
].len
<
1655 sizeof(lease
->address
.iabuf
))) {
1656 struct iaddr netmask
, subnet
, broadcast
;
1658 memcpy(netmask
.iabuf
, lease
->options
[DHO_SUBNET_MASK
].data
,
1659 lease
->options
[DHO_SUBNET_MASK
].len
);
1660 netmask
.len
= lease
->options
[DHO_SUBNET_MASK
].len
;
1662 subnet
= subnet_number(lease
->address
, netmask
);
1665 script_set_env(ip
->client
, prefix
, "network_number",
1668 if (!lease
->options
[DHO_BROADCAST_ADDRESS
].len
) {
1669 broadcast
= broadcast_addr(subnet
, netmask
);
1672 script_set_env(ip
->client
, prefix
,
1673 "broadcast_address",
1683 if (lease
->filename
)
1684 script_set_env(ip
->client
, prefix
, "filename", lease
->filename
);
1685 if (lease
->server_name
)
1686 script_set_env(ip
->client
, prefix
, "server_name",
1687 lease
->server_name
);
1690 for (i
= 0; i
< 256; i
++) {
1691 u_int8_t
*dp
= NULL
;
1693 if (ip
->client
->config
->defaults
[i
].len
) {
1694 if (lease
->options
[i
].len
) {
1696 ip
->client
->config
->default_actions
[i
]) {
1697 case ACTION_DEFAULT
:
1698 dp
= lease
->options
[i
].data
;
1699 len
= lease
->options
[i
].len
;
1701 case ACTION_SUPERSEDE
:
1704 config
->defaults
[i
].data
;
1706 config
->defaults
[i
].len
;
1708 case ACTION_PREPEND
:
1710 config
->defaults
[i
].len
+
1711 lease
->options
[i
].len
;
1712 if (len
>= sizeof(dbuf
)) {
1713 warning("no space to %s %s",
1715 dhcp_options
[i
].name
);
1721 config
->defaults
[i
].data
,
1723 config
->defaults
[i
].len
);
1724 memcpy(dp
+ ip
->client
->
1725 config
->defaults
[i
].len
,
1726 lease
->options
[i
].data
,
1727 lease
->options
[i
].len
);
1732 config
->defaults
[i
].len
+
1733 lease
->options
[i
].len
+ 1;
1734 if (len
> sizeof(dbuf
)) {
1735 warning("no space to %s %s",
1737 dhcp_options
[i
].name
);
1742 lease
->options
[i
].data
,
1743 lease
->options
[i
].len
);
1744 memcpy(dp
+ lease
->options
[i
].len
,
1746 config
->defaults
[i
].data
,
1748 config
->defaults
[i
].len
);
1753 config
->defaults
[i
].data
;
1755 config
->defaults
[i
].len
;
1757 } else if (lease
->options
[i
].len
) {
1758 len
= lease
->options
[i
].len
;
1759 dp
= lease
->options
[i
].data
;
1767 if (dhcp_option_ev_name(name
, sizeof(name
),
1769 script_set_env(ip
->client
, prefix
, name
,
1770 pretty_print_option(i
, dp
, len
, 0, 0));
1775 snprintf(tbuf
, sizeof(tbuf
), "%d", (int)lease
->expiry
);
1776 script_set_env(ip
->client
, prefix
, "expiry", tbuf
);
1781 dhcp_option_ev_name(char *buf
, size_t buflen
, struct dhcp_option
*option
)
1785 for (i
= 0; option
->name
[i
]; i
++) {
1786 if (i
+ 1 == buflen
)
1788 if (option
->name
[i
] == '-')
1791 buf
[i
] = option
->name
[i
];
1802 static int state
= 0;
1804 if (no_daemon
|| state
)
1809 /* Stop logging to stderr... */
1812 if (daemon(1, 0) == -1)
1815 /* we are chrooted, daemon(3) fails to open /dev/null */
1817 dup2(nullfd
, STDIN_FILENO
);
1818 dup2(nullfd
, STDOUT_FILENO
);
1819 dup2(nullfd
, STDERR_FILENO
);
1827 check_option(struct client_lease
*l
, int option
)
1832 /* we use this, since this is what gets passed to dhclient-script */
1834 opbuf
= pretty_print_option(option
, l
->options
[option
].data
,
1835 l
->options
[option
].len
, 0, 0);
1837 sbuf
= option_as_string(option
, l
->options
[option
].data
,
1838 l
->options
[option
].len
);
1841 case DHO_SUBNET_MASK
:
1842 case DHO_TIME_SERVERS
:
1843 case DHO_NAME_SERVERS
:
1845 case DHO_DOMAIN_NAME_SERVERS
:
1846 case DHO_LOG_SERVERS
:
1847 case DHO_COOKIE_SERVERS
:
1848 case DHO_LPR_SERVERS
:
1849 case DHO_IMPRESS_SERVERS
:
1850 case DHO_RESOURCE_LOCATION_SERVERS
:
1851 case DHO_SWAP_SERVER
:
1852 case DHO_BROADCAST_ADDRESS
:
1853 case DHO_NIS_SERVERS
:
1854 case DHO_NTP_SERVERS
:
1855 case DHO_NETBIOS_NAME_SERVERS
:
1856 case DHO_NETBIOS_DD_SERVER
:
1857 case DHO_FONT_SERVERS
:
1858 case DHO_DHCP_SERVER_IDENTIFIER
:
1859 if (!ipv4addrs(opbuf
)) {
1860 warning("Invalid IP address in option(%d): %s", option
, opbuf
);
1865 case DHO_DOMAIN_NAME
:
1866 case DHO_NIS_DOMAIN
:
1867 if (!res_hnok(sbuf
))
1868 warning("Bogus Host Name option %d: %s (%s)", option
,
1872 case DHO_TIME_OFFSET
:
1874 case DHO_MERIT_DUMP
:
1876 case DHO_EXTENSIONS_PATH
:
1877 case DHO_IP_FORWARDING
:
1878 case DHO_NON_LOCAL_SOURCE_ROUTING
:
1879 case DHO_POLICY_FILTER
:
1880 case DHO_MAX_DGRAM_REASSEMBLY
:
1881 case DHO_DEFAULT_IP_TTL
:
1882 case DHO_PATH_MTU_AGING_TIMEOUT
:
1883 case DHO_PATH_MTU_PLATEAU_TABLE
:
1884 case DHO_INTERFACE_MTU
:
1885 case DHO_ALL_SUBNETS_LOCAL
:
1886 case DHO_PERFORM_MASK_DISCOVERY
:
1887 case DHO_MASK_SUPPLIER
:
1888 case DHO_ROUTER_DISCOVERY
:
1889 case DHO_ROUTER_SOLICITATION_ADDRESS
:
1890 case DHO_STATIC_ROUTES
:
1891 case DHO_TRAILER_ENCAPSULATION
:
1892 case DHO_ARP_CACHE_TIMEOUT
:
1893 case DHO_IEEE802_3_ENCAPSULATION
:
1894 case DHO_DEFAULT_TCP_TTL
:
1895 case DHO_TCP_KEEPALIVE_INTERVAL
:
1896 case DHO_TCP_KEEPALIVE_GARBAGE
:
1897 case DHO_VENDOR_ENCAPSULATED_OPTIONS
:
1898 case DHO_NETBIOS_NODE_TYPE
:
1899 case DHO_NETBIOS_SCOPE
:
1900 case DHO_X_DISPLAY_MANAGER
:
1901 case DHO_DHCP_REQUESTED_ADDRESS
:
1902 case DHO_DHCP_LEASE_TIME
:
1903 case DHO_DHCP_OPTION_OVERLOAD
:
1904 case DHO_DHCP_MESSAGE_TYPE
:
1905 case DHO_DHCP_PARAMETER_REQUEST_LIST
:
1906 case DHO_DHCP_MESSAGE
:
1907 case DHO_DHCP_MAX_MESSAGE_SIZE
:
1908 case DHO_DHCP_RENEWAL_TIME
:
1909 case DHO_DHCP_REBINDING_TIME
:
1910 case DHO_DHCP_CLASS_IDENTIFIER
:
1911 case DHO_DHCP_CLIENT_IDENTIFIER
:
1912 case DHO_DHCP_USER_CLASS_ID
:
1916 warning("unknown dhcp option value 0x%x", option
);
1917 return (unknown_ok
);
1922 res_hnok(const char *dn
)
1924 int pch
= PERIOD
, ch
= *dn
++;
1926 while (ch
!= '\0') {
1929 if (periodchar(ch
)) {
1931 } else if (periodchar(pch
)) {
1932 if (!borderchar(ch
))
1934 } else if (periodchar(nch
) || nch
== '\0') {
1935 if (!borderchar(ch
))
1938 if (!middlechar(ch
))
1946 /* Does buf consist only of dotted decimal ipv4 addrs?
1947 * return how many if so,
1948 * otherwise, return 0
1951 ipv4addrs(char * buf
)
1957 note("Input: %s", buf
);
1960 tmp
= strtok(buf
, " ");
1961 note("got %s", tmp
);
1962 if( tmp
&& inet_aton(tmp
, &jnk
) ) i
++;
1971 option_as_string(unsigned int code
, unsigned char *data
, int len
)
1973 static char optbuf
[32768]; /* XXX */
1975 int opleft
= sizeof(optbuf
);
1976 unsigned char *dp
= data
;
1979 error("option_as_string: bad code %d", code
);
1981 for (; dp
< data
+ len
; dp
++) {
1982 if (!isascii(*dp
) || !isprint(*dp
)) {
1983 if (dp
+ 1 != data
+ len
|| *dp
!= 0) {
1984 _snprintf(op
, opleft
, "\\%03o", *dp
);
1988 } else if (*dp
== '"' || *dp
== '\'' || *dp
== '$' ||
1989 *dp
== '`' || *dp
== '\\') {
2003 warning("dhcp option too large");