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
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)
67 #define borderchar(c) (alphachar(c) || digitchar(c))
68 #define middlechar(c) (borderchar(c) || hyphenchar(c))
69 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
71 unsigned long debug_trace_level
= 0; /* DEBUG_ULTRA */
73 char *path_dhclient_conf
= _PATH_DHCLIENT_CONF
;
74 char *path_dhclient_db
= NULL
;
80 struct iaddr iaddr_broadcast
= { 4, { 255, 255, 255, 255 } };
81 struct in_addr inaddr_any
;
82 struct sockaddr_in sockaddr_broadcast
;
85 * ASSERT_STATE() does nothing now; it used to be
86 * assert (state_is == state_shouldbe).
88 #define ASSERT_STATE(state_is, state_shouldbe) {}
90 #define TIME_MAX 2147483647
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
);
105 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
109 static WCHAR ServiceName
[] = L
"DHCP";
111 SERVICE_STATUS_HANDLE ServiceStatusHandle
= 0;
112 SERVICE_STATUS ServiceStatus
;
115 /* XXX Implement me */
116 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
) {
122 UpdateServiceStatus(DWORD dwState
)
124 ServiceStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
125 ServiceStatus
.dwCurrentState
= dwState
;
127 ServiceStatus
.dwControlsAccepted
= 0;
129 ServiceStatus
.dwWin32ExitCode
= 0;
130 ServiceStatus
.dwServiceSpecificExitCode
= 0;
131 ServiceStatus
.dwCheckPoint
= 0;
133 if (dwState
== SERVICE_START_PENDING
||
134 dwState
== SERVICE_STOP_PENDING
||
135 dwState
== SERVICE_PAUSE_PENDING
||
136 dwState
== SERVICE_CONTINUE_PENDING
)
137 ServiceStatus
.dwWaitHint
= 10000;
139 ServiceStatus
.dwWaitHint
= 0;
141 SetServiceStatus(ServiceStatusHandle
,
147 ServiceControlHandler(DWORD dwControl
,
154 case SERVICE_CONTROL_STOP
:
155 UpdateServiceStatus(SERVICE_STOP_PENDING
);
156 UpdateServiceStatus(SERVICE_STOPPED
);
157 return ERROR_SUCCESS
;
159 case SERVICE_CONTROL_PAUSE
:
160 UpdateServiceStatus(SERVICE_PAUSED
);
161 return ERROR_SUCCESS
;
163 case SERVICE_CONTROL_CONTINUE
:
164 UpdateServiceStatus(SERVICE_START_PENDING
);
165 UpdateServiceStatus(SERVICE_RUNNING
);
166 return ERROR_SUCCESS
;
168 case SERVICE_CONTROL_INTERROGATE
:
169 SetServiceStatus(ServiceStatusHandle
,
171 return ERROR_SUCCESS
;
173 case SERVICE_CONTROL_SHUTDOWN
:
174 UpdateServiceStatus(SERVICE_STOP_PENDING
);
175 UpdateServiceStatus(SERVICE_STOPPED
);
176 return ERROR_SUCCESS
;
179 return ERROR_CALL_NOT_IMPLEMENTED
;
185 ServiceMain(DWORD argc
, LPWSTR
*argv
)
187 ServiceStatusHandle
= RegisterServiceCtrlHandlerExW(ServiceName
,
188 ServiceControlHandler
,
190 if (!ServiceStatusHandle
)
192 DbgPrint("DHCPCSVC: Unable to register service control handler (%lx)\n", GetLastError());
196 UpdateServiceStatus(SERVICE_START_PENDING
);
203 memset(&sockaddr_broadcast
, 0, sizeof(sockaddr_broadcast
));
204 sockaddr_broadcast
.sin_family
= AF_INET
;
205 sockaddr_broadcast
.sin_port
= htons(REMOTE_PORT
);
206 sockaddr_broadcast
.sin_addr
.s_addr
= INADDR_BROADCAST
;
207 inaddr_any
.s_addr
= INADDR_ANY
;
208 bootp_packet_handler
= do_packet
;
210 if (PipeInit() == INVALID_HANDLE_VALUE
)
212 DbgPrint("DHCPCSVC: PipeInit() failed!\n");
215 UpdateServiceStatus(SERVICE_STOPPED
);
218 DH_DbgPrint(MID_TRACE
,("DHCP Service Started\n"));
220 UpdateServiceStatus(SERVICE_RUNNING
);
222 DH_DbgPrint(MID_TRACE
,("Going into dispatch()\n"));
224 DbgPrint("DHCPCSVC: DHCP service is starting up\n");
228 DbgPrint("DHCPCSVC: DHCP service is shutting down\n");
232 /* FIXME: Close pipe and kill pipe thread */
234 UpdateServiceStatus(SERVICE_STOPPED
);
240 * Each routine is called from the dhclient_state_machine() in one of
242 * -> entering INIT state
243 * -> recvpacket_flag == 0: timeout in this state
244 * -> otherwise: received a packet in this state
246 * Return conditions as handled by dhclient_state_machine():
247 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
248 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
249 * Returns 0: finish the nap which was interrupted for no good reason.
251 * Several per-interface variables are used to keep track of the process:
252 * active_lease: the lease that is being used on the interface
253 * (null pointer if not configured yet).
254 * offered_leases: leases corresponding to DHCPOFFER messages that have
255 * been sent to us by DHCP servers.
256 * acked_leases: leases corresponding to DHCPACK messages that have been
257 * sent to us by DHCP servers.
258 * sendpacket: DHCP packet we're trying to send.
259 * destination: IP address to send sendpacket to
260 * In addition, there are several relevant per-lease variables.
261 * T1_expiry, T2_expiry, lease_expiry: lease milestones
262 * In the active lease, these control the process of renewing the lease;
263 * In leases on the acked_leases list, this simply determines when we
264 * can no longer legitimately use the lease.
268 state_reboot(void *ipp
)
270 struct interface_info
*ip
= ipp
;
271 ULONG foo
= (ULONG
) GetTickCount();
273 /* If we don't remember an active lease, go straight to INIT. */
274 if (!ip
->client
->active
|| ip
->client
->active
->is_bootp
) {
279 /* We are in the rebooting state. */
280 ip
->client
->state
= S_REBOOTING
;
282 /* make_request doesn't initialize xid because it normally comes
283 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
284 so pick an xid now. */
285 ip
->client
->xid
= RtlRandom(&foo
);
287 /* Make a DHCPREQUEST packet, and set appropriate per-interface
289 make_request(ip
, ip
->client
->active
);
290 ip
->client
->destination
= iaddr_broadcast
;
291 time(&ip
->client
->first_sending
);
292 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
294 /* Zap the medium list... */
295 ip
->client
->medium
= NULL
;
297 /* Send out the first DHCPREQUEST packet. */
302 * Called when a lease has completely expired and we've
303 * been unable to renew it.
306 state_init(void *ipp
)
308 struct interface_info
*ip
= ipp
;
310 ASSERT_STATE(state
, S_INIT
);
312 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
314 make_discover(ip
, ip
->client
->active
);
315 ip
->client
->xid
= ip
->client
->packet
.xid
;
316 ip
->client
->destination
= iaddr_broadcast
;
317 ip
->client
->state
= S_SELECTING
;
318 time(&ip
->client
->first_sending
);
319 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
321 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
327 * state_selecting is called when one or more DHCPOFFER packets
328 * have been received and a configurable period of time has passed.
331 state_selecting(void *ipp
)
333 struct interface_info
*ip
= ipp
;
334 struct client_lease
*lp
, *next
, *picked
;
337 ASSERT_STATE(state
, S_SELECTING
);
341 /* Cancel state_selecting and send_discover timeouts, since either
342 one could have got us here. */
343 cancel_timeout(state_selecting
, ip
);
344 cancel_timeout(send_discover
, ip
);
346 /* We have received one or more DHCPOFFER packets. Currently,
347 the only criterion by which we judge leases is whether or
348 not we get a response when we arp for them. */
350 for (lp
= ip
->client
->offered_leases
; lp
; lp
= next
) {
353 /* Check to see if we got an ARPREPLY for the address
354 in this particular lease. */
356 if( !check_arp(ip
,lp
) ) goto freeit
;
361 free_client_lease(lp
);
364 ip
->client
->offered_leases
= NULL
;
366 /* If we just tossed all the leases we were offered, go back
369 ip
->client
->state
= S_INIT
;
374 /* If it was a BOOTREPLY, we can just take the address right now. */
375 if (!picked
->options
[DHO_DHCP_MESSAGE_TYPE
].len
) {
376 ip
->client
->new = picked
;
378 /* Make up some lease expiry times
379 XXX these should be configurable. */
380 ip
->client
->new->expiry
= cur_time
+ 12000;
381 ip
->client
->new->renewal
+= cur_time
+ 8000;
382 ip
->client
->new->rebind
+= cur_time
+ 10000;
384 ip
->client
->state
= S_REQUESTING
;
386 /* Bind to the address we received. */
391 /* Go to the REQUESTING state. */
392 ip
->client
->destination
= iaddr_broadcast
;
393 ip
->client
->state
= S_REQUESTING
;
394 ip
->client
->first_sending
= cur_time
;
395 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
397 /* Make a DHCPREQUEST packet from the lease we picked. */
398 make_request(ip
, picked
);
399 ip
->client
->xid
= ip
->client
->packet
.xid
;
401 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
402 free_client_lease(picked
);
404 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
408 /* state_requesting is called when we receive a DHCPACK message after
409 having sent out one or more DHCPREQUEST packets. */
412 dhcpack(struct packet
*packet
)
414 struct interface_info
*ip
= packet
->interface
;
415 struct client_lease
*lease
;
420 /* If we're not receptive to an offer right now, or if the offer
421 has an unrecognizable transaction id, then just drop it. */
422 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
423 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
424 (memcmp(packet
->interface
->hw_address
.haddr
,
425 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
428 if (ip
->client
->state
!= S_REBOOTING
&&
429 ip
->client
->state
!= S_REQUESTING
&&
430 ip
->client
->state
!= S_RENEWING
&&
431 ip
->client
->state
!= S_REBINDING
)
434 note("DHCPACK from %s", piaddr(packet
->client_addr
));
436 lease
= packet_to_lease(packet
);
438 note("packet_to_lease failed.");
442 ip
->client
->new = lease
;
444 /* Stop resending DHCPREQUEST. */
445 cancel_timeout(send_request
, ip
);
447 /* Figure out the lease time. */
448 if (ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
)
449 ip
->client
->new->expiry
= getULong(
450 ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
);
452 ip
->client
->new->expiry
= DHCP_DEFAULT_LEASE_TIME
;
453 /* A number that looks negative here is really just very large,
454 because the lease expiry offset is unsigned. */
455 if (ip
->client
->new->expiry
< 0)
456 ip
->client
->new->expiry
= TIME_MAX
;
457 /* XXX should be fixed by resetting the client state */
458 if (ip
->client
->new->expiry
< 60)
459 ip
->client
->new->expiry
= 60;
461 /* Take the server-provided renewal time if there is one;
462 otherwise figure it out according to the spec. */
463 if (ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].len
)
464 ip
->client
->new->renewal
= getULong(
465 ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].data
);
467 ip
->client
->new->renewal
= ip
->client
->new->expiry
/ 2;
469 /* Same deal with the rebind time. */
470 if (ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].len
)
471 ip
->client
->new->rebind
= getULong(
472 ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].data
);
474 ip
->client
->new->rebind
= ip
->client
->new->renewal
+
475 ip
->client
->new->renewal
/ 2 + ip
->client
->new->renewal
/ 4;
478 ip
->client
->new->obtained
= cur_time
;
480 ip
->client
->new->expiry
+= cur_time
;
481 /* Lease lengths can never be negative. */
482 if (ip
->client
->new->expiry
< cur_time
)
483 ip
->client
->new->expiry
= TIME_MAX
;
484 ip
->client
->new->renewal
+= cur_time
;
485 if (ip
->client
->new->renewal
< cur_time
)
486 ip
->client
->new->renewal
= TIME_MAX
;
487 ip
->client
->new->rebind
+= cur_time
;
488 if (ip
->client
->new->rebind
< cur_time
)
489 ip
->client
->new->rebind
= TIME_MAX
;
494 void set_name_servers( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
495 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
498 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
499 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &RegKey
) != ERROR_SUCCESS
)
503 if( new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
) {
505 struct iaddr nameserver
;
508 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
/ sizeof(ULONG
);
510 nsbuf
= malloc( addrs
* sizeof(IP_ADDRESS_STRING
) );
514 for( i
= 0; i
< addrs
; i
++ ) {
515 nameserver
.len
= sizeof(ULONG
);
516 memcpy( nameserver
.iabuf
,
517 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].data
+
518 (i
* sizeof(ULONG
)), sizeof(ULONG
) );
519 strcat( nsbuf
, piaddr(nameserver
) );
520 if( i
!= addrs
-1 ) strcat( nsbuf
, "," );
523 DH_DbgPrint(MID_TRACE
,("Setting DhcpNameserver: %s\n", nsbuf
));
525 RegSetValueExA( RegKey
, "DhcpNameServer", 0, REG_SZ
,
526 (LPBYTE
)nsbuf
, strlen(nsbuf
) + 1 );
531 RegDeleteValueW( RegKey
, L
"DhcpNameServer" );
534 RegCloseKey( RegKey
);
538 void setup_adapter( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
539 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
540 struct iaddr netmask
;
545 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
546 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &hkey
) != ERROR_SUCCESS
)
550 if( Adapter
->NteContext
)
552 DeleteIPAddress( Adapter
->NteContext
);
553 Adapter
->NteContext
= 0;
556 /* Set up our default router if we got one from the DHCP server */
557 if( new_lease
->options
[DHO_SUBNET_MASK
].len
) {
560 memcpy( netmask
.iabuf
,
561 new_lease
->options
[DHO_SUBNET_MASK
].data
,
562 new_lease
->options
[DHO_SUBNET_MASK
].len
);
563 Status
= AddIPAddress
564 ( *((ULONG
*)new_lease
->address
.iabuf
),
565 *((ULONG
*)netmask
.iabuf
),
566 Adapter
->IfMib
.dwIndex
,
567 &Adapter
->NteContext
,
568 &Adapter
->NteInstance
);
570 RegSetValueExA(hkey
, "DhcpIPAddress", 0, REG_SZ
, (LPBYTE
)piaddr(new_lease
->address
), strlen(piaddr(new_lease
->address
))+1);
572 for(i
= 0; i
< new_lease
->options
[DHO_SUBNET_MASK
].len
; i
++)
574 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_SUBNET_MASK
].data
[i
]);
575 if (i
+ 1 < new_lease
->options
[DHO_SUBNET_MASK
].len
)
578 RegSetValueExA(hkey
, "DhcpSubnetMask", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
580 RegSetValueExA(hkey
, "EnableDHCP", 0, REG_DWORD
, (LPBYTE
)&dwEnableDHCP
, sizeof(DWORD
));
583 if( !NT_SUCCESS(Status
) )
584 warning("AddIPAddress: %lx\n", Status
);
587 if( new_lease
->options
[DHO_ROUTERS
].len
) {
590 Adapter
->RouterMib
.dwForwardDest
= 0; /* Default route */
591 Adapter
->RouterMib
.dwForwardMask
= 0;
592 Adapter
->RouterMib
.dwForwardMetric1
= 1;
593 Adapter
->RouterMib
.dwForwardIfIndex
= Adapter
->IfMib
.dwIndex
;
595 if( Adapter
->RouterMib
.dwForwardNextHop
) {
596 /* If we set a default route before, delete it before continuing */
597 DeleteIpForwardEntry( &Adapter
->RouterMib
);
600 Adapter
->RouterMib
.dwForwardNextHop
=
601 *((ULONG
*)new_lease
->options
[DHO_ROUTERS
].data
);
603 Status
= CreateIpForwardEntry( &Adapter
->RouterMib
);
605 if( !NT_SUCCESS(Status
) )
606 warning("CreateIpForwardEntry: %lx\n", Status
);
610 for(i
= 0; i
< new_lease
->options
[DHO_ROUTERS
].len
; i
++)
612 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_ROUTERS
].data
[i
]);
613 if (i
+ 1 < new_lease
->options
[DHO_ROUTERS
].len
)
616 RegSetValueExA(hkey
, "DhcpDefaultGateway", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
626 bind_lease(struct interface_info
*ip
)
628 PDHCP_ADAPTER Adapter
;
629 struct client_lease
*new_lease
= ip
->client
->new;
634 /* Remember the medium. */
635 ip
->client
->new->medium
= ip
->client
->medium
;
636 ip
->client
->active
= ip
->client
->new;
637 ip
->client
->new = NULL
;
639 /* Set up a timeout to start the renewal process. */
640 /* Timeout of zero means no timeout (some implementations seem to use
643 if( ip
->client
->active
->renewal
- cur_time
)
644 add_timeout(ip
->client
->active
->renewal
, state_bound
, ip
);
646 note("bound to %s -- renewal in %ld seconds.",
647 piaddr(ip
->client
->active
->address
),
648 (long int)(ip
->client
->active
->renewal
- cur_time
));
650 ip
->client
->state
= S_BOUND
;
652 Adapter
= AdapterFindInfo( ip
);
654 if( Adapter
) setup_adapter( Adapter
, new_lease
);
656 warning("Could not find adapter for info %p\n", ip
);
659 set_name_servers( Adapter
, new_lease
);
663 * state_bound is called when we've successfully bound to a particular
664 * lease, but the renewal time on that lease has expired. We are
665 * expected to unicast a DHCPREQUEST to the server that gave us our
669 state_bound(void *ipp
)
671 struct interface_info
*ip
= ipp
;
673 ASSERT_STATE(state
, S_BOUND
);
675 /* T1 has expired. */
676 make_request(ip
, ip
->client
->active
);
677 ip
->client
->xid
= ip
->client
->packet
.xid
;
679 if (ip
->client
->active
->options
[DHO_DHCP_SERVER_IDENTIFIER
].len
== 4) {
680 memcpy(ip
->client
->destination
.iabuf
, ip
->client
->active
->
681 options
[DHO_DHCP_SERVER_IDENTIFIER
].data
, 4);
682 ip
->client
->destination
.len
= 4;
684 ip
->client
->destination
= iaddr_broadcast
;
686 time(&ip
->client
->first_sending
);
687 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
688 ip
->client
->state
= S_RENEWING
;
690 /* Send the first packet immediately. */
695 bootp(struct packet
*packet
)
697 struct iaddrlist
*ap
;
699 if (packet
->raw
->op
!= BOOTREPLY
)
702 /* If there's a reject list, make sure this packet's sender isn't
704 for (ap
= packet
->interface
->client
->config
->reject_list
;
706 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
707 note("BOOTREPLY from %s rejected.", piaddr(ap
->addr
));
715 dhcp(struct packet
*packet
)
717 struct iaddrlist
*ap
;
718 void (*handler
)(struct packet
*);
721 switch (packet
->packet_type
) {
738 /* If there's a reject list, make sure this packet's sender isn't
740 for (ap
= packet
->interface
->client
->config
->reject_list
;
742 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
743 note("%s from %s rejected.", type
, piaddr(ap
->addr
));
751 dhcpoffer(struct packet
*packet
)
753 struct interface_info
*ip
= packet
->interface
;
754 struct client_lease
*lease
, *lp
;
756 int arp_timeout_needed
= 0, stop_selecting
;
757 char *name
= packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
?
758 "DHCPOFFER" : "BOOTREPLY";
763 /* If we're not receptive to an offer right now, or if the offer
764 has an unrecognizable transaction id, then just drop it. */
765 if (ip
->client
->state
!= S_SELECTING
||
766 packet
->interface
->client
->xid
!= packet
->raw
->xid
||
767 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
768 (memcmp(packet
->interface
->hw_address
.haddr
,
769 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
772 note("%s from %s", name
, piaddr(packet
->client_addr
));
775 /* If this lease doesn't supply the minimum required parameters,
777 for (i
= 0; ip
->client
->config
->required_options
[i
]; i
++) {
778 if (!packet
->options
[ip
->client
->config
->
779 required_options
[i
]].len
) {
780 note("%s isn't satisfactory.", name
);
785 /* If we've already seen this lease, don't record it again. */
786 for (lease
= ip
->client
->offered_leases
;
787 lease
; lease
= lease
->next
) {
788 if (lease
->address
.len
== sizeof(packet
->raw
->yiaddr
) &&
789 !memcmp(lease
->address
.iabuf
,
790 &packet
->raw
->yiaddr
, lease
->address
.len
)) {
791 debug("%s already seen.", name
);
796 lease
= packet_to_lease(packet
);
798 note("packet_to_lease failed.");
802 /* If this lease was acquired through a BOOTREPLY, record that
804 if (!packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
)
807 /* Record the medium under which this lease was offered. */
808 lease
->medium
= ip
->client
->medium
;
810 /* Send out an ARP Request for the offered IP address. */
811 if( !check_arp( ip
, lease
) ) {
812 note("Arp check failed\n");
816 /* Figure out when we're supposed to stop selecting. */
818 ip
->client
->first_sending
+ ip
->client
->config
->select_interval
;
820 /* If this is the lease we asked for, put it at the head of the
821 list, and don't mess with the arp request timeout. */
822 if (lease
->address
.len
== ip
->client
->requested_address
.len
&&
823 !memcmp(lease
->address
.iabuf
,
824 ip
->client
->requested_address
.iabuf
,
825 ip
->client
->requested_address
.len
)) {
826 lease
->next
= ip
->client
->offered_leases
;
827 ip
->client
->offered_leases
= lease
;
829 /* If we already have an offer, and arping for this
830 offer would take us past the selection timeout,
831 then don't extend the timeout - just hope for the
833 if (ip
->client
->offered_leases
&&
834 (cur_time
+ arp_timeout_needed
) > stop_selecting
)
835 arp_timeout_needed
= 0;
837 /* Put the lease at the end of the list. */
839 if (!ip
->client
->offered_leases
)
840 ip
->client
->offered_leases
= lease
;
842 for (lp
= ip
->client
->offered_leases
; lp
->next
;
849 /* If we're supposed to stop selecting before we've had time
850 to wait for the ARPREPLY, add some delay to wait for
852 if (stop_selecting
- cur_time
< arp_timeout_needed
)
853 stop_selecting
= cur_time
+ arp_timeout_needed
;
855 /* If the selecting interval has expired, go immediately to
856 state_selecting(). Otherwise, time out into
857 state_selecting at the select interval. */
858 if (stop_selecting
<= 0)
861 add_timeout(stop_selecting
, state_selecting
, ip
);
862 cancel_timeout(send_discover
, ip
);
866 /* Allocate a client_lease structure and initialize it from the parameters
867 in the specified packet. */
869 struct client_lease
*
870 packet_to_lease(struct packet
*packet
)
872 struct client_lease
*lease
;
875 lease
= malloc(sizeof(struct client_lease
));
878 warning("dhcpoffer: no memory to record lease.");
882 memset(lease
, 0, sizeof(*lease
));
884 /* Copy the lease options. */
885 for (i
= 0; i
< 256; i
++) {
886 if (packet
->options
[i
].len
) {
887 lease
->options
[i
].data
=
888 malloc(packet
->options
[i
].len
+ 1);
889 if (!lease
->options
[i
].data
) {
890 warning("dhcpoffer: no memory for option %d", i
);
891 free_client_lease(lease
);
894 memcpy(lease
->options
[i
].data
,
895 packet
->options
[i
].data
,
896 packet
->options
[i
].len
);
897 lease
->options
[i
].len
=
898 packet
->options
[i
].len
;
899 lease
->options
[i
].data
[lease
->options
[i
].len
] =
902 if (!check_option(lease
,i
)) {
903 /* ignore a bogus lease offer */
904 warning("Invalid lease option - ignoring offer");
905 free_client_lease(lease
);
911 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
912 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
, lease
->address
.len
);
914 lease
->serveraddress
.len
= sizeof(packet
->raw
->siaddr
);
915 memcpy(lease
->serveraddress
.iabuf
, &packet
->raw
->siaddr
, lease
->address
.len
);
918 /* If the server name was filled out, copy it. */
919 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
920 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 2)) &&
921 packet
->raw
->sname
[0]) {
922 lease
->server_name
= malloc(DHCP_SNAME_LEN
+ 1);
923 if (!lease
->server_name
) {
924 warning("dhcpoffer: no memory for server name.");
925 free_client_lease(lease
);
928 memcpy(lease
->server_name
, packet
->raw
->sname
, DHCP_SNAME_LEN
);
929 lease
->server_name
[DHCP_SNAME_LEN
]='\0';
930 if (!res_hnok(lease
->server_name
) ) {
931 warning("Bogus server name %s", lease
->server_name
);
932 free_client_lease(lease
);
938 /* Ditto for the filename. */
939 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
940 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 1)) &&
941 packet
->raw
->file
[0]) {
942 /* Don't count on the NUL terminator. */
943 lease
->filename
= malloc(DHCP_FILE_LEN
+ 1);
944 if (!lease
->filename
) {
945 warning("dhcpoffer: no memory for filename.");
946 free_client_lease(lease
);
949 memcpy(lease
->filename
, packet
->raw
->file
, DHCP_FILE_LEN
);
950 lease
->filename
[DHCP_FILE_LEN
]='\0';
956 dhcpnak(struct packet
*packet
)
958 struct interface_info
*ip
= packet
->interface
;
960 /* If we're not receptive to an offer right now, or if the offer
961 has an unrecognizable transaction id, then just drop it. */
962 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
963 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
964 (memcmp(packet
->interface
->hw_address
.haddr
,
965 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
968 if (ip
->client
->state
!= S_REBOOTING
&&
969 ip
->client
->state
!= S_REQUESTING
&&
970 ip
->client
->state
!= S_RENEWING
&&
971 ip
->client
->state
!= S_REBINDING
)
974 note("DHCPNAK from %s", piaddr(packet
->client_addr
));
976 if (!ip
->client
->active
) {
977 note("DHCPNAK with no active lease.\n");
981 free_client_lease(ip
->client
->active
);
982 ip
->client
->active
= NULL
;
984 /* Stop sending DHCPREQUEST packets... */
985 cancel_timeout(send_request
, ip
);
987 ip
->client
->state
= S_INIT
;
991 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
992 one after the right interval has expired. If we don't get an offer by
993 the time we reach the panic interval, call the panic function. */
996 send_discover(void *ipp
)
998 struct interface_info
*ip
= ipp
;
999 int interval
, increase
= 1;
1002 DH_DbgPrint(MID_TRACE
,("Doing discover on interface %p\n",ip
));
1006 /* Figure out how long it's been since we started transmitting. */
1007 interval
= cur_time
- ip
->client
->first_sending
;
1009 /* If we're past the panic timeout, call the script and tell it
1010 we haven't found anything for this interface yet. */
1011 if (interval
> ip
->client
->config
->timeout
) {
1013 ip
->client
->first_sending
= cur_time
;
1016 /* If we're selecting media, try the whole list before doing
1017 the exponential backoff, but if we've already received an
1018 offer, stop looping, because we obviously have it right. */
1019 if (!ip
->client
->offered_leases
&&
1020 ip
->client
->config
->media
) {
1023 if (ip
->client
->medium
) {
1024 ip
->client
->medium
= ip
->client
->medium
->next
;
1027 if (!ip
->client
->medium
) {
1029 error("No valid media types for %s!", ip
->name
);
1030 ip
->client
->medium
= ip
->client
->config
->media
;
1034 note("Trying medium \"%s\" %d", ip
->client
->medium
->string
,
1036 /* XXX Support other media types eventually */
1040 * If we're supposed to increase the interval, do so. If it's
1041 * currently zero (i.e., we haven't sent any packets yet), set
1042 * it to one; otherwise, add to it a random number between zero
1043 * and two times itself. On average, this means that it will
1044 * double with every transmission.
1047 if (!ip
->client
->interval
)
1048 ip
->client
->interval
=
1049 ip
->client
->config
->initial_interval
;
1051 ip
->client
->interval
+= (rand() >> 2) %
1052 (2 * ip
->client
->interval
);
1055 /* Don't backoff past cutoff. */
1056 if (ip
->client
->interval
>
1057 ip
->client
->config
->backoff_cutoff
)
1058 ip
->client
->interval
=
1059 ((ip
->client
->config
->backoff_cutoff
/ 2)
1061 ip
->client
->config
->backoff_cutoff
));
1062 } else if (!ip
->client
->interval
)
1063 ip
->client
->interval
=
1064 ip
->client
->config
->initial_interval
;
1066 /* If the backoff would take us to the panic timeout, just use that
1068 if (cur_time
+ ip
->client
->interval
>
1069 ip
->client
->first_sending
+ ip
->client
->config
->timeout
)
1070 ip
->client
->interval
=
1071 (ip
->client
->first_sending
+
1072 ip
->client
->config
->timeout
) - cur_time
+ 1;
1074 /* Record the number of seconds since we started sending. */
1075 if (interval
< 65536)
1076 ip
->client
->packet
.secs
= htons(interval
);
1078 ip
->client
->packet
.secs
= htons(65535);
1079 ip
->client
->secs
= ip
->client
->packet
.secs
;
1081 note("DHCPDISCOVER on %s to %s port %d interval %ld",
1082 ip
->name
, inet_ntoa(sockaddr_broadcast
.sin_addr
),
1083 ntohs(sockaddr_broadcast
.sin_port
), (long int)ip
->client
->interval
);
1085 /* Send out a packet. */
1086 (void)send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1087 inaddr_any
, &sockaddr_broadcast
, NULL
);
1089 DH_DbgPrint(MID_TRACE
,("discover timeout: now %x -> then %x\n",
1090 cur_time
, cur_time
+ ip
->client
->interval
));
1092 add_timeout(cur_time
+ ip
->client
->interval
, send_discover
, ip
);
1096 * state_panic gets called if we haven't received any offers in a preset
1097 * amount of time. When this happens, we try to use existing leases
1098 * that haven't yet expired, and failing that, we call the client script
1099 * and hope it can do something.
1102 state_panic(void *ipp
)
1104 struct interface_info
*ip
= ipp
;
1105 PDHCP_ADAPTER Adapter
= AdapterFindInfo(ip
);
1107 note("No DHCPOFFERS received.");
1109 if (!Adapter
->NteContext
)
1111 /* Generate an automatic private address */
1112 DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n");
1114 /* FIXME: The address generation code sucks */
1115 AddIPAddress(htonl(0xA9FE0000 | (rand() % 0xFFFF)), //169.254.X.X
1116 htonl(0xFFFF0000), //255.255.0.0
1117 Adapter
->IfMib
.dwIndex
,
1118 &Adapter
->NteContext
,
1119 &Adapter
->NteInstance
);
1124 send_request(void *ipp
)
1126 struct interface_info
*ip
= ipp
;
1127 struct sockaddr_in destination
;
1128 struct in_addr from
;
1134 /* Figure out how long it's been since we started transmitting. */
1135 interval
= cur_time
- ip
->client
->first_sending
;
1137 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1138 past the reboot timeout, go to INIT and see if we can
1139 DISCOVER an address... */
1140 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1141 means either that we're on a network with no DHCP server,
1142 or that our server is down. In the latter case, assuming
1143 that there is a backup DHCP server, DHCPDISCOVER will get
1144 us a new address, but we could also have successfully
1145 reused our old address. In the former case, we're hosed
1146 anyway. This is not a win-prone situation. */
1147 if ((ip
->client
->state
== S_REBOOTING
||
1148 ip
->client
->state
== S_REQUESTING
) &&
1149 interval
> ip
->client
->config
->reboot_timeout
) {
1150 ip
->client
->state
= S_INIT
;
1151 cancel_timeout(send_request
, ip
);
1156 /* If we're in the reboot state, make sure the media is set up
1158 if (ip
->client
->state
== S_REBOOTING
&&
1159 !ip
->client
->medium
&&
1160 ip
->client
->active
->medium
) {
1161 /* If the medium we chose won't fly, go to INIT state. */
1162 /* XXX Nothing for now */
1164 /* Record the medium. */
1165 ip
->client
->medium
= ip
->client
->active
->medium
;
1168 /* If the lease has expired, relinquish the address and go back
1169 to the INIT state. */
1170 if (ip
->client
->state
!= S_REQUESTING
&&
1171 cur_time
> ip
->client
->active
->expiry
) {
1172 PDHCP_ADAPTER Adapter
= AdapterFindInfo( ip
);
1173 /* Run the client script with the new parameters. */
1174 /* No script actions necessary in the expiry case */
1175 /* Now do a preinit on the interface so that we can
1176 discover a new address. */
1180 DeleteIPAddress( Adapter
->NteContext
);
1181 Adapter
->NteContext
= 0;
1184 ip
->client
->state
= S_INIT
;
1189 /* Do the exponential backoff... */
1190 if (!ip
->client
->interval
)
1191 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
1193 ip
->client
->interval
+= ((rand() >> 2) %
1194 (2 * ip
->client
->interval
));
1196 /* Don't backoff past cutoff. */
1197 if (ip
->client
->interval
>
1198 ip
->client
->config
->backoff_cutoff
)
1199 ip
->client
->interval
=
1200 ((ip
->client
->config
->backoff_cutoff
/ 2) +
1201 ((rand() >> 2) % ip
->client
->interval
));
1203 /* If the backoff would take us to the expiry time, just set the
1204 timeout to the expiry time. */
1205 if (ip
->client
->state
!= S_REQUESTING
&&
1206 cur_time
+ ip
->client
->interval
>
1207 ip
->client
->active
->expiry
)
1208 ip
->client
->interval
=
1209 ip
->client
->active
->expiry
- cur_time
+ 1;
1211 /* If the lease T2 time has elapsed, or if we're not yet bound,
1212 broadcast the DHCPREQUEST rather than unicasting. */
1213 memset(&destination
, 0, sizeof(destination
));
1214 if (ip
->client
->state
== S_REQUESTING
||
1215 ip
->client
->state
== S_REBOOTING
||
1216 cur_time
> ip
->client
->active
->rebind
)
1217 destination
.sin_addr
.s_addr
= INADDR_BROADCAST
;
1219 memcpy(&destination
.sin_addr
.s_addr
,
1220 ip
->client
->destination
.iabuf
,
1221 sizeof(destination
.sin_addr
.s_addr
));
1222 destination
.sin_port
= htons(REMOTE_PORT
);
1223 destination
.sin_family
= AF_INET
;
1224 // destination.sin_len = sizeof(destination);
1226 if (ip
->client
->state
!= S_REQUESTING
)
1227 memcpy(&from
, ip
->client
->active
->address
.iabuf
,
1230 from
.s_addr
= INADDR_ANY
;
1232 /* Record the number of seconds since we started sending. */
1233 if (ip
->client
->state
== S_REQUESTING
)
1234 ip
->client
->packet
.secs
= ip
->client
->secs
;
1236 if (interval
< 65536)
1237 ip
->client
->packet
.secs
= htons(interval
);
1239 ip
->client
->packet
.secs
= htons(65535);
1242 note("DHCPREQUEST on %s to %s port %d", ip
->name
,
1243 inet_ntoa(destination
.sin_addr
), ntohs(destination
.sin_port
));
1245 /* Send out a packet. */
1246 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1247 from
, &destination
, NULL
);
1249 add_timeout(cur_time
+ ip
->client
->interval
, send_request
, ip
);
1253 send_decline(void *ipp
)
1255 struct interface_info
*ip
= ipp
;
1257 note("DHCPDECLINE on %s to %s port %d", ip
->name
,
1258 inet_ntoa(sockaddr_broadcast
.sin_addr
),
1259 ntohs(sockaddr_broadcast
.sin_port
));
1261 /* Send out a packet. */
1262 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1263 inaddr_any
, &sockaddr_broadcast
, NULL
);
1267 make_discover(struct interface_info
*ip
, struct client_lease
*lease
)
1269 unsigned char discover
= DHCPDISCOVER
;
1270 struct tree_cache
*options
[256];
1271 struct tree_cache option_elements
[256];
1273 ULONG foo
= (ULONG
) GetTickCount();
1275 memset(option_elements
, 0, sizeof(option_elements
));
1276 memset(options
, 0, sizeof(options
));
1277 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1279 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1280 i
= DHO_DHCP_MESSAGE_TYPE
;
1281 options
[i
] = &option_elements
[i
];
1282 options
[i
]->value
= &discover
;
1283 options
[i
]->len
= sizeof(discover
);
1284 options
[i
]->buf_size
= sizeof(discover
);
1285 options
[i
]->timeout
= 0xFFFFFFFF;
1287 /* Request the options we want */
1288 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1289 options
[i
] = &option_elements
[i
];
1290 options
[i
]->value
= ip
->client
->config
->requested_options
;
1291 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1292 options
[i
]->buf_size
=
1293 ip
->client
->config
->requested_option_count
;
1294 options
[i
]->timeout
= 0xFFFFFFFF;
1296 /* If we had an address, try to get it again. */
1298 ip
->client
->requested_address
= lease
->address
;
1299 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1300 options
[i
] = &option_elements
[i
];
1301 options
[i
]->value
= lease
->address
.iabuf
;
1302 options
[i
]->len
= lease
->address
.len
;
1303 options
[i
]->buf_size
= lease
->address
.len
;
1304 options
[i
]->timeout
= 0xFFFFFFFF;
1306 ip
->client
->requested_address
.len
= 0;
1308 /* Send any options requested in the config file. */
1309 for (i
= 0; i
< 256; i
++)
1311 ip
->client
->config
->send_options
[i
].data
) {
1312 options
[i
] = &option_elements
[i
];
1314 ip
->client
->config
->send_options
[i
].data
;
1316 ip
->client
->config
->send_options
[i
].len
;
1317 options
[i
]->buf_size
=
1318 ip
->client
->config
->send_options
[i
].len
;
1319 options
[i
]->timeout
= 0xFFFFFFFF;
1322 /* Set up the option buffer... */
1323 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1324 options
, 0, 0, 0, NULL
, 0);
1325 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1326 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1328 ip
->client
->packet
.op
= BOOTREQUEST
;
1329 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1330 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1331 ip
->client
->packet
.hops
= 0;
1332 ip
->client
->packet
.xid
= RtlRandom(&foo
);
1333 ip
->client
->packet
.secs
= 0; /* filled in by send_discover. */
1334 ip
->client
->packet
.flags
= 0;
1336 memset(&(ip
->client
->packet
.ciaddr
),
1337 0, sizeof(ip
->client
->packet
.ciaddr
));
1338 memset(&(ip
->client
->packet
.yiaddr
),
1339 0, sizeof(ip
->client
->packet
.yiaddr
));
1340 memset(&(ip
->client
->packet
.siaddr
),
1341 0, sizeof(ip
->client
->packet
.siaddr
));
1342 memset(&(ip
->client
->packet
.giaddr
),
1343 0, sizeof(ip
->client
->packet
.giaddr
));
1344 memcpy(ip
->client
->packet
.chaddr
,
1345 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1350 make_request(struct interface_info
*ip
, struct client_lease
* lease
)
1352 unsigned char request
= DHCPREQUEST
;
1353 struct tree_cache
*options
[256];
1354 struct tree_cache option_elements
[256];
1357 memset(options
, 0, sizeof(options
));
1358 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1360 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1361 i
= DHO_DHCP_MESSAGE_TYPE
;
1362 options
[i
] = &option_elements
[i
];
1363 options
[i
]->value
= &request
;
1364 options
[i
]->len
= sizeof(request
);
1365 options
[i
]->buf_size
= sizeof(request
);
1366 options
[i
]->timeout
= 0xFFFFFFFF;
1368 /* Request the options we want */
1369 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1370 options
[i
] = &option_elements
[i
];
1371 options
[i
]->value
= ip
->client
->config
->requested_options
;
1372 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1373 options
[i
]->buf_size
=
1374 ip
->client
->config
->requested_option_count
;
1375 options
[i
]->timeout
= 0xFFFFFFFF;
1377 /* If we are requesting an address that hasn't yet been assigned
1378 to us, use the DHCP Requested Address option. */
1379 if (ip
->client
->state
== S_REQUESTING
) {
1380 /* Send back the server identifier... */
1381 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1382 options
[i
] = &option_elements
[i
];
1383 options
[i
]->value
= lease
->options
[i
].data
;
1384 options
[i
]->len
= lease
->options
[i
].len
;
1385 options
[i
]->buf_size
= lease
->options
[i
].len
;
1386 options
[i
]->timeout
= 0xFFFFFFFF;
1388 if (ip
->client
->state
== S_REQUESTING
||
1389 ip
->client
->state
== S_REBOOTING
) {
1390 ip
->client
->requested_address
= lease
->address
;
1391 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1392 options
[i
] = &option_elements
[i
];
1393 options
[i
]->value
= lease
->address
.iabuf
;
1394 options
[i
]->len
= lease
->address
.len
;
1395 options
[i
]->buf_size
= lease
->address
.len
;
1396 options
[i
]->timeout
= 0xFFFFFFFF;
1398 ip
->client
->requested_address
.len
= 0;
1400 /* Send any options requested in the config file. */
1401 for (i
= 0; i
< 256; i
++)
1403 ip
->client
->config
->send_options
[i
].data
) {
1404 options
[i
] = &option_elements
[i
];
1406 ip
->client
->config
->send_options
[i
].data
;
1408 ip
->client
->config
->send_options
[i
].len
;
1409 options
[i
]->buf_size
=
1410 ip
->client
->config
->send_options
[i
].len
;
1411 options
[i
]->timeout
= 0xFFFFFFFF;
1414 /* Set up the option buffer... */
1415 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1416 options
, 0, 0, 0, NULL
, 0);
1417 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1418 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1420 ip
->client
->packet
.op
= BOOTREQUEST
;
1421 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1422 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1423 ip
->client
->packet
.hops
= 0;
1424 ip
->client
->packet
.xid
= ip
->client
->xid
;
1425 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1427 /* If we own the address we're requesting, put it in ciaddr;
1428 otherwise set ciaddr to zero. */
1429 if (ip
->client
->state
== S_BOUND
||
1430 ip
->client
->state
== S_RENEWING
||
1431 ip
->client
->state
== S_REBINDING
) {
1432 memcpy(&ip
->client
->packet
.ciaddr
,
1433 lease
->address
.iabuf
, lease
->address
.len
);
1434 ip
->client
->packet
.flags
= 0;
1436 memset(&ip
->client
->packet
.ciaddr
, 0,
1437 sizeof(ip
->client
->packet
.ciaddr
));
1438 ip
->client
->packet
.flags
= 0;
1441 memset(&ip
->client
->packet
.yiaddr
, 0,
1442 sizeof(ip
->client
->packet
.yiaddr
));
1443 memset(&ip
->client
->packet
.siaddr
, 0,
1444 sizeof(ip
->client
->packet
.siaddr
));
1445 memset(&ip
->client
->packet
.giaddr
, 0,
1446 sizeof(ip
->client
->packet
.giaddr
));
1447 memcpy(ip
->client
->packet
.chaddr
,
1448 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1452 make_decline(struct interface_info
*ip
, struct client_lease
*lease
)
1454 struct tree_cache
*options
[256], message_type_tree
;
1455 struct tree_cache requested_address_tree
;
1456 struct tree_cache server_id_tree
, client_id_tree
;
1457 unsigned char decline
= DHCPDECLINE
;
1460 memset(options
, 0, sizeof(options
));
1461 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1463 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1464 i
= DHO_DHCP_MESSAGE_TYPE
;
1465 options
[i
] = &message_type_tree
;
1466 options
[i
]->value
= &decline
;
1467 options
[i
]->len
= sizeof(decline
);
1468 options
[i
]->buf_size
= sizeof(decline
);
1469 options
[i
]->timeout
= 0xFFFFFFFF;
1471 /* Send back the server identifier... */
1472 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1473 options
[i
] = &server_id_tree
;
1474 options
[i
]->value
= lease
->options
[i
].data
;
1475 options
[i
]->len
= lease
->options
[i
].len
;
1476 options
[i
]->buf_size
= lease
->options
[i
].len
;
1477 options
[i
]->timeout
= 0xFFFFFFFF;
1479 /* Send back the address we're declining. */
1480 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1481 options
[i
] = &requested_address_tree
;
1482 options
[i
]->value
= lease
->address
.iabuf
;
1483 options
[i
]->len
= lease
->address
.len
;
1484 options
[i
]->buf_size
= lease
->address
.len
;
1485 options
[i
]->timeout
= 0xFFFFFFFF;
1487 /* Send the uid if the user supplied one. */
1488 i
= DHO_DHCP_CLIENT_IDENTIFIER
;
1489 if (ip
->client
->config
->send_options
[i
].len
) {
1490 options
[i
] = &client_id_tree
;
1491 options
[i
]->value
= ip
->client
->config
->send_options
[i
].data
;
1492 options
[i
]->len
= ip
->client
->config
->send_options
[i
].len
;
1493 options
[i
]->buf_size
= ip
->client
->config
->send_options
[i
].len
;
1494 options
[i
]->timeout
= 0xFFFFFFFF;
1498 /* Set up the option buffer... */
1499 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1500 options
, 0, 0, 0, NULL
, 0);
1501 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1502 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1504 ip
->client
->packet
.op
= BOOTREQUEST
;
1505 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1506 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1507 ip
->client
->packet
.hops
= 0;
1508 ip
->client
->packet
.xid
= ip
->client
->xid
;
1509 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1510 ip
->client
->packet
.flags
= 0;
1512 /* ciaddr must always be zero. */
1513 memset(&ip
->client
->packet
.ciaddr
, 0,
1514 sizeof(ip
->client
->packet
.ciaddr
));
1515 memset(&ip
->client
->packet
.yiaddr
, 0,
1516 sizeof(ip
->client
->packet
.yiaddr
));
1517 memset(&ip
->client
->packet
.siaddr
, 0,
1518 sizeof(ip
->client
->packet
.siaddr
));
1519 memset(&ip
->client
->packet
.giaddr
, 0,
1520 sizeof(ip
->client
->packet
.giaddr
));
1521 memcpy(ip
->client
->packet
.chaddr
,
1522 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1526 free_client_lease(struct client_lease
*lease
)
1530 if (lease
->server_name
)
1531 free(lease
->server_name
);
1532 if (lease
->filename
)
1533 free(lease
->filename
);
1534 for (i
= 0; i
< 256; i
++) {
1535 if (lease
->options
[i
].len
)
1536 free(lease
->options
[i
].data
);
1544 rewrite_client_leases(struct interface_info
*ifi
)
1546 struct client_lease
*lp
;
1549 leaseFile
= fopen(path_dhclient_db
, "w");
1551 error("can't create %s", path_dhclient_db
);
1557 for (lp
= ifi
->client
->leases
; lp
; lp
= lp
->next
)
1558 write_client_lease(ifi
, lp
, 1);
1559 if (ifi
->client
->active
)
1560 write_client_lease(ifi
, ifi
->client
->active
, 1);
1566 write_client_lease(struct interface_info
*ip
, struct client_lease
*lease
,
1569 static int leases_written
;
1574 if (leases_written
++ > 20) {
1575 rewrite_client_leases(ip
);
1580 /* If the lease came from the config file, we don't need to stash
1581 a copy in the lease database. */
1582 if (lease
->is_static
)
1585 if (!leaseFile
) { /* XXX */
1586 leaseFile
= fopen(path_dhclient_db
, "w");
1588 error("can't create %s", path_dhclient_db
);
1593 fprintf(leaseFile
, "lease {\n");
1594 if (lease
->is_bootp
)
1595 fprintf(leaseFile
, " bootp;\n");
1596 fprintf(leaseFile
, " interface \"%s\";\n", ip
->name
);
1597 fprintf(leaseFile
, " fixed-address %s;\n", piaddr(lease
->address
));
1598 if (lease
->filename
)
1599 fprintf(leaseFile
, " filename \"%s\";\n", lease
->filename
);
1600 if (lease
->server_name
)
1601 fprintf(leaseFile
, " server-name \"%s\";\n",
1602 lease
->server_name
);
1604 fprintf(leaseFile
, " medium \"%s\";\n", lease
->medium
->string
);
1605 for (i
= 0; i
< 256; i
++)
1606 if (lease
->options
[i
].len
)
1607 fprintf(leaseFile
, " option %s %s;\n",
1608 dhcp_options
[i
].name
,
1609 pretty_print_option(i
, lease
->options
[i
].data
,
1610 lease
->options
[i
].len
, 1, 1));
1612 t
= gmtime(&lease
->renewal
);
1614 fprintf(leaseFile
, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1615 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1616 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1617 t
= gmtime(&lease
->rebind
);
1619 fprintf(leaseFile
, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1620 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1621 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1622 t
= gmtime(&lease
->expiry
);
1624 fprintf(leaseFile
, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1625 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1626 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1627 fprintf(leaseFile
, "}\n");
1632 priv_script_init(struct interface_info
*ip
, char *reason
, char *medium
)
1635 // XXX Do we need to do anything?
1640 priv_script_write_params(struct interface_info
*ip
, char *prefix
, struct client_lease
*lease
)
1642 u_int8_t dbuf
[1500];
1646 script_set_env(ip
->client
, prefix
, "ip_address",
1647 piaddr(lease
->address
));
1650 if (lease
->options
[DHO_SUBNET_MASK
].len
&&
1651 (lease
->options
[DHO_SUBNET_MASK
].len
<
1652 sizeof(lease
->address
.iabuf
))) {
1653 struct iaddr netmask
, subnet
, broadcast
;
1655 memcpy(netmask
.iabuf
, lease
->options
[DHO_SUBNET_MASK
].data
,
1656 lease
->options
[DHO_SUBNET_MASK
].len
);
1657 netmask
.len
= lease
->options
[DHO_SUBNET_MASK
].len
;
1659 subnet
= subnet_number(lease
->address
, netmask
);
1662 script_set_env(ip
->client
, prefix
, "network_number",
1665 if (!lease
->options
[DHO_BROADCAST_ADDRESS
].len
) {
1666 broadcast
= broadcast_addr(subnet
, netmask
);
1669 script_set_env(ip
->client
, prefix
,
1670 "broadcast_address",
1680 if (lease
->filename
)
1681 script_set_env(ip
->client
, prefix
, "filename", lease
->filename
);
1682 if (lease
->server_name
)
1683 script_set_env(ip
->client
, prefix
, "server_name",
1684 lease
->server_name
);
1687 for (i
= 0; i
< 256; i
++) {
1688 u_int8_t
*dp
= NULL
;
1690 if (ip
->client
->config
->defaults
[i
].len
) {
1691 if (lease
->options
[i
].len
) {
1693 ip
->client
->config
->default_actions
[i
]) {
1694 case ACTION_DEFAULT
:
1695 dp
= lease
->options
[i
].data
;
1696 len
= lease
->options
[i
].len
;
1698 case ACTION_SUPERSEDE
:
1701 config
->defaults
[i
].data
;
1703 config
->defaults
[i
].len
;
1705 case ACTION_PREPEND
:
1707 config
->defaults
[i
].len
+
1708 lease
->options
[i
].len
;
1709 if (len
>= sizeof(dbuf
)) {
1710 warning("no space to %s %s",
1712 dhcp_options
[i
].name
);
1718 config
->defaults
[i
].data
,
1720 config
->defaults
[i
].len
);
1721 memcpy(dp
+ ip
->client
->
1722 config
->defaults
[i
].len
,
1723 lease
->options
[i
].data
,
1724 lease
->options
[i
].len
);
1729 config
->defaults
[i
].len
+
1730 lease
->options
[i
].len
+ 1;
1731 if (len
> sizeof(dbuf
)) {
1732 warning("no space to %s %s",
1734 dhcp_options
[i
].name
);
1739 lease
->options
[i
].data
,
1740 lease
->options
[i
].len
);
1741 memcpy(dp
+ lease
->options
[i
].len
,
1743 config
->defaults
[i
].data
,
1745 config
->defaults
[i
].len
);
1750 config
->defaults
[i
].data
;
1752 config
->defaults
[i
].len
;
1754 } else if (lease
->options
[i
].len
) {
1755 len
= lease
->options
[i
].len
;
1756 dp
= lease
->options
[i
].data
;
1764 if (dhcp_option_ev_name(name
, sizeof(name
),
1766 script_set_env(ip
->client
, prefix
, name
,
1767 pretty_print_option(i
, dp
, len
, 0, 0));
1772 snprintf(tbuf
, sizeof(tbuf
), "%d", (int)lease
->expiry
);
1773 script_set_env(ip
->client
, prefix
, "expiry", tbuf
);
1778 dhcp_option_ev_name(char *buf
, size_t buflen
, struct dhcp_option
*option
)
1782 for (i
= 0; option
->name
[i
]; i
++) {
1783 if (i
+ 1 == buflen
)
1785 if (option
->name
[i
] == '-')
1788 buf
[i
] = option
->name
[i
];
1799 static int state
= 0;
1801 if (no_daemon
|| state
)
1806 /* Stop logging to stderr... */
1809 if (daemon(1, 0) == -1)
1812 /* we are chrooted, daemon(3) fails to open /dev/null */
1814 dup2(nullfd
, STDIN_FILENO
);
1815 dup2(nullfd
, STDOUT_FILENO
);
1816 dup2(nullfd
, STDERR_FILENO
);
1824 check_option(struct client_lease
*l
, int option
)
1829 /* we use this, since this is what gets passed to dhclient-script */
1831 opbuf
= pretty_print_option(option
, l
->options
[option
].data
,
1832 l
->options
[option
].len
, 0, 0);
1834 sbuf
= option_as_string(option
, l
->options
[option
].data
,
1835 l
->options
[option
].len
);
1838 case DHO_SUBNET_MASK
:
1839 case DHO_TIME_SERVERS
:
1840 case DHO_NAME_SERVERS
:
1842 case DHO_DOMAIN_NAME_SERVERS
:
1843 case DHO_LOG_SERVERS
:
1844 case DHO_COOKIE_SERVERS
:
1845 case DHO_LPR_SERVERS
:
1846 case DHO_IMPRESS_SERVERS
:
1847 case DHO_RESOURCE_LOCATION_SERVERS
:
1848 case DHO_SWAP_SERVER
:
1849 case DHO_BROADCAST_ADDRESS
:
1850 case DHO_NIS_SERVERS
:
1851 case DHO_NTP_SERVERS
:
1852 case DHO_NETBIOS_NAME_SERVERS
:
1853 case DHO_NETBIOS_DD_SERVER
:
1854 case DHO_FONT_SERVERS
:
1855 case DHO_DHCP_SERVER_IDENTIFIER
:
1856 if (!ipv4addrs(opbuf
)) {
1857 warning("Invalid IP address in option(%d): %s", option
, opbuf
);
1862 case DHO_DOMAIN_NAME
:
1863 case DHO_NIS_DOMAIN
:
1864 if (!res_hnok(sbuf
))
1865 warning("Bogus Host Name option %d: %s (%s)", option
,
1869 case DHO_TIME_OFFSET
:
1871 case DHO_MERIT_DUMP
:
1873 case DHO_EXTENSIONS_PATH
:
1874 case DHO_IP_FORWARDING
:
1875 case DHO_NON_LOCAL_SOURCE_ROUTING
:
1876 case DHO_POLICY_FILTER
:
1877 case DHO_MAX_DGRAM_REASSEMBLY
:
1878 case DHO_DEFAULT_IP_TTL
:
1879 case DHO_PATH_MTU_AGING_TIMEOUT
:
1880 case DHO_PATH_MTU_PLATEAU_TABLE
:
1881 case DHO_INTERFACE_MTU
:
1882 case DHO_ALL_SUBNETS_LOCAL
:
1883 case DHO_PERFORM_MASK_DISCOVERY
:
1884 case DHO_MASK_SUPPLIER
:
1885 case DHO_ROUTER_DISCOVERY
:
1886 case DHO_ROUTER_SOLICITATION_ADDRESS
:
1887 case DHO_STATIC_ROUTES
:
1888 case DHO_TRAILER_ENCAPSULATION
:
1889 case DHO_ARP_CACHE_TIMEOUT
:
1890 case DHO_IEEE802_3_ENCAPSULATION
:
1891 case DHO_DEFAULT_TCP_TTL
:
1892 case DHO_TCP_KEEPALIVE_INTERVAL
:
1893 case DHO_TCP_KEEPALIVE_GARBAGE
:
1894 case DHO_VENDOR_ENCAPSULATED_OPTIONS
:
1895 case DHO_NETBIOS_NODE_TYPE
:
1896 case DHO_NETBIOS_SCOPE
:
1897 case DHO_X_DISPLAY_MANAGER
:
1898 case DHO_DHCP_REQUESTED_ADDRESS
:
1899 case DHO_DHCP_LEASE_TIME
:
1900 case DHO_DHCP_OPTION_OVERLOAD
:
1901 case DHO_DHCP_MESSAGE_TYPE
:
1902 case DHO_DHCP_PARAMETER_REQUEST_LIST
:
1903 case DHO_DHCP_MESSAGE
:
1904 case DHO_DHCP_MAX_MESSAGE_SIZE
:
1905 case DHO_DHCP_RENEWAL_TIME
:
1906 case DHO_DHCP_REBINDING_TIME
:
1907 case DHO_DHCP_CLASS_IDENTIFIER
:
1908 case DHO_DHCP_CLIENT_IDENTIFIER
:
1909 case DHO_DHCP_USER_CLASS_ID
:
1913 warning("unknown dhcp option value 0x%x", option
);
1914 return (unknown_ok
);
1919 res_hnok(const char *dn
)
1921 int pch
= PERIOD
, ch
= *dn
++;
1923 while (ch
!= '\0') {
1926 if (periodchar(ch
)) {
1928 } else if (periodchar(pch
)) {
1929 if (!borderchar(ch
))
1931 } else if (periodchar(nch
) || nch
== '\0') {
1932 if (!borderchar(ch
))
1935 if (!middlechar(ch
))
1943 /* Does buf consist only of dotted decimal ipv4 addrs?
1944 * return how many if so,
1945 * otherwise, return 0
1948 ipv4addrs(char * buf
)
1954 note("Input: %s", buf
);
1957 tmp
= strtok(buf
, " ");
1958 note("got %s", tmp
);
1959 if( tmp
&& inet_aton(tmp
, &jnk
) ) i
++;
1968 option_as_string(unsigned int code
, unsigned char *data
, int len
)
1970 static char optbuf
[32768]; /* XXX */
1972 int opleft
= sizeof(optbuf
);
1973 unsigned char *dp
= data
;
1976 error("option_as_string: bad code %d", code
);
1978 for (; dp
< data
+ len
; dp
++) {
1979 if (!isascii(*dp
) || !isprint(*dp
)) {
1980 if (dp
+ 1 != data
+ len
|| *dp
!= 0) {
1981 _snprintf(op
, opleft
, "\\%03o", *dp
);
1985 } else if (*dp
== '"' || *dp
== '\'' || *dp
== '$' ||
1986 *dp
== '`' || *dp
== '\\') {
2000 warning("dhcp option too large");