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))
118 memset(&sockaddr_broadcast
, 0, sizeof(sockaddr_broadcast
));
119 sockaddr_broadcast
.sin_family
= AF_INET
;
120 sockaddr_broadcast
.sin_port
= htons(REMOTE_PORT
);
121 sockaddr_broadcast
.sin_addr
.s_addr
= INADDR_BROADCAST
;
122 inaddr_any
.s_addr
= INADDR_ANY
;
123 bootp_packet_handler
= do_packet
;
125 if (PipeInit() == INVALID_HANDLE_VALUE
)
127 DbgPrint("DHCPCSVC: PipeInit() failed!\n");
141 /* FIXME: Close pipe and kill pipe thread */
144 /* XXX Implement me */
145 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
) {
152 * Each routine is called from the dhclient_state_machine() in one of
154 * -> entering INIT state
155 * -> recvpacket_flag == 0: timeout in this state
156 * -> otherwise: received a packet in this state
158 * Return conditions as handled by dhclient_state_machine():
159 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
160 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
161 * Returns 0: finish the nap which was interrupted for no good reason.
163 * Several per-interface variables are used to keep track of the process:
164 * active_lease: the lease that is being used on the interface
165 * (null pointer if not configured yet).
166 * offered_leases: leases corresponding to DHCPOFFER messages that have
167 * been sent to us by DHCP servers.
168 * acked_leases: leases corresponding to DHCPACK messages that have been
169 * sent to us by DHCP servers.
170 * sendpacket: DHCP packet we're trying to send.
171 * destination: IP address to send sendpacket to
172 * In addition, there are several relevant per-lease variables.
173 * T1_expiry, T2_expiry, lease_expiry: lease milestones
174 * In the active lease, these control the process of renewing the lease;
175 * In leases on the acked_leases list, this simply determines when we
176 * can no longer legitimately use the lease.
180 state_reboot(void *ipp
)
182 struct interface_info
*ip
= ipp
;
183 ULONG foo
= (ULONG
) GetTickCount();
185 /* If we don't remember an active lease, go straight to INIT. */
186 if (!ip
->client
->active
|| ip
->client
->active
->is_bootp
) {
191 /* We are in the rebooting state. */
192 ip
->client
->state
= S_REBOOTING
;
194 /* make_request doesn't initialize xid because it normally comes
195 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
196 so pick an xid now. */
197 ip
->client
->xid
= RtlRandom(&foo
);
199 /* Make a DHCPREQUEST packet, and set appropriate per-interface
201 make_request(ip
, ip
->client
->active
);
202 ip
->client
->destination
= iaddr_broadcast
;
203 time(&ip
->client
->first_sending
);
204 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
206 /* Zap the medium list... */
207 ip
->client
->medium
= NULL
;
209 /* Send out the first DHCPREQUEST packet. */
214 * Called when a lease has completely expired and we've
215 * been unable to renew it.
218 state_init(void *ipp
)
220 struct interface_info
*ip
= ipp
;
222 ASSERT_STATE(state
, S_INIT
);
224 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
226 make_discover(ip
, ip
->client
->active
);
227 ip
->client
->xid
= ip
->client
->packet
.xid
;
228 ip
->client
->destination
= iaddr_broadcast
;
229 ip
->client
->state
= S_SELECTING
;
230 time(&ip
->client
->first_sending
);
231 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
233 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
239 * state_selecting is called when one or more DHCPOFFER packets
240 * have been received and a configurable period of time has passed.
243 state_selecting(void *ipp
)
245 struct interface_info
*ip
= ipp
;
246 struct client_lease
*lp
, *next
, *picked
;
249 ASSERT_STATE(state
, S_SELECTING
);
253 /* Cancel state_selecting and send_discover timeouts, since either
254 one could have got us here. */
255 cancel_timeout(state_selecting
, ip
);
256 cancel_timeout(send_discover
, ip
);
258 /* We have received one or more DHCPOFFER packets. Currently,
259 the only criterion by which we judge leases is whether or
260 not we get a response when we arp for them. */
262 for (lp
= ip
->client
->offered_leases
; lp
; lp
= next
) {
265 /* Check to see if we got an ARPREPLY for the address
266 in this particular lease. */
268 if( !check_arp(ip
,lp
) ) goto freeit
;
273 free_client_lease(lp
);
276 ip
->client
->offered_leases
= NULL
;
278 /* If we just tossed all the leases we were offered, go back
281 ip
->client
->state
= S_INIT
;
286 /* If it was a BOOTREPLY, we can just take the address right now. */
287 if (!picked
->options
[DHO_DHCP_MESSAGE_TYPE
].len
) {
288 ip
->client
->new = picked
;
290 /* Make up some lease expiry times
291 XXX these should be configurable. */
292 ip
->client
->new->expiry
= cur_time
+ 12000;
293 ip
->client
->new->renewal
+= cur_time
+ 8000;
294 ip
->client
->new->rebind
+= cur_time
+ 10000;
296 ip
->client
->state
= S_REQUESTING
;
298 /* Bind to the address we received. */
303 /* Go to the REQUESTING state. */
304 ip
->client
->destination
= iaddr_broadcast
;
305 ip
->client
->state
= S_REQUESTING
;
306 ip
->client
->first_sending
= cur_time
;
307 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
309 /* Make a DHCPREQUEST packet from the lease we picked. */
310 make_request(ip
, picked
);
311 ip
->client
->xid
= ip
->client
->packet
.xid
;
313 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
314 free_client_lease(picked
);
316 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
320 /* state_requesting is called when we receive a DHCPACK message after
321 having sent out one or more DHCPREQUEST packets. */
324 dhcpack(struct packet
*packet
)
326 struct interface_info
*ip
= packet
->interface
;
327 struct client_lease
*lease
;
332 /* If we're not receptive to an offer right now, or if the offer
333 has an unrecognizable transaction id, then just drop it. */
334 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
335 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
336 (memcmp(packet
->interface
->hw_address
.haddr
,
337 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
340 if (ip
->client
->state
!= S_REBOOTING
&&
341 ip
->client
->state
!= S_REQUESTING
&&
342 ip
->client
->state
!= S_RENEWING
&&
343 ip
->client
->state
!= S_REBINDING
)
346 note("DHCPACK from %s", piaddr(packet
->client_addr
));
348 lease
= packet_to_lease(packet
);
350 note("packet_to_lease failed.");
354 ip
->client
->new = lease
;
356 /* Stop resending DHCPREQUEST. */
357 cancel_timeout(send_request
, ip
);
359 /* Figure out the lease time. */
360 if (ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
)
361 ip
->client
->new->expiry
= getULong(
362 ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
);
364 ip
->client
->new->expiry
= DHCP_DEFAULT_LEASE_TIME
;
365 /* A number that looks negative here is really just very large,
366 because the lease expiry offset is unsigned. */
367 if (ip
->client
->new->expiry
< 0)
368 ip
->client
->new->expiry
= TIME_MAX
;
369 /* XXX should be fixed by resetting the client state */
370 if (ip
->client
->new->expiry
< 60)
371 ip
->client
->new->expiry
= 60;
373 /* Take the server-provided renewal time if there is one;
374 otherwise figure it out according to the spec. */
375 if (ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].len
)
376 ip
->client
->new->renewal
= getULong(
377 ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].data
);
379 ip
->client
->new->renewal
= ip
->client
->new->expiry
/ 2;
381 /* Same deal with the rebind time. */
382 if (ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].len
)
383 ip
->client
->new->rebind
= getULong(
384 ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].data
);
386 ip
->client
->new->rebind
= ip
->client
->new->renewal
+
387 ip
->client
->new->renewal
/ 2 + ip
->client
->new->renewal
/ 4;
390 ip
->client
->new->obtained
= cur_time
;
392 ip
->client
->new->expiry
+= cur_time
;
393 /* Lease lengths can never be negative. */
394 if (ip
->client
->new->expiry
< cur_time
)
395 ip
->client
->new->expiry
= TIME_MAX
;
396 ip
->client
->new->renewal
+= cur_time
;
397 if (ip
->client
->new->renewal
< cur_time
)
398 ip
->client
->new->renewal
= TIME_MAX
;
399 ip
->client
->new->rebind
+= cur_time
;
400 if (ip
->client
->new->rebind
< cur_time
)
401 ip
->client
->new->rebind
= TIME_MAX
;
406 void set_name_servers( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
407 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
410 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
411 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &RegKey
) != ERROR_SUCCESS
)
415 if( new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
) {
417 struct iaddr nameserver
;
420 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
/ sizeof(ULONG
);
422 nsbuf
= malloc( addrs
* sizeof(IP_ADDRESS_STRING
) );
426 for( i
= 0; i
< addrs
; i
++ ) {
427 nameserver
.len
= sizeof(ULONG
);
428 memcpy( nameserver
.iabuf
,
429 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].data
+
430 (i
* sizeof(ULONG
)), sizeof(ULONG
) );
431 strcat( nsbuf
, piaddr(nameserver
) );
432 if( i
!= addrs
-1 ) strcat( nsbuf
, "," );
435 DH_DbgPrint(MID_TRACE
,("Setting DhcpNameserver: %s\n", nsbuf
));
437 RegSetValueExA( RegKey
, "DhcpNameServer", 0, REG_SZ
,
438 (LPBYTE
)nsbuf
, strlen(nsbuf
) + 1 );
443 RegDeleteValueW( RegKey
, L
"DhcpNameServer" );
446 RegCloseKey( RegKey
);
451 set_domain(PDHCP_ADAPTER Adapter
,
452 struct client_lease
*new_lease
)
454 CHAR Buffer1
[MAX_PATH
] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
455 CHAR Buffer2
[MAX_PATH
] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
456 HKEY RegKey1
, RegKey2
;
458 strcat(Buffer1
, Adapter
->DhclientInfo
.name
);
460 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer1
, 0, KEY_WRITE
, &RegKey1
) != ERROR_SUCCESS
)
465 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer2
, 0, KEY_WRITE
, &RegKey2
) != ERROR_SUCCESS
)
467 RegCloseKey(RegKey1
);
471 if (new_lease
->options
[DHO_DOMAIN_NAME
].len
)
473 DH_DbgPrint(MID_TRACE
, ("Setting DhcpDomain: %s\n", new_lease
->options
[DHO_DOMAIN_NAME
].data
));
475 RegSetValueExA(RegKey1
,
479 (LPBYTE
)new_lease
->options
[DHO_DOMAIN_NAME
].data
,
480 new_lease
->options
[DHO_DOMAIN_NAME
].len
);
482 RegSetValueExA(RegKey2
,
486 (LPBYTE
)new_lease
->options
[DHO_DOMAIN_NAME
].data
,
487 new_lease
->options
[DHO_DOMAIN_NAME
].len
);
491 RegDeleteValueW(RegKey1
, L
"DhcpDomain");
492 RegDeleteValueW(RegKey2
, L
"DhcpDomain");
495 RegCloseKey(RegKey1
);
496 RegCloseKey(RegKey2
);
500 void setup_adapter( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
501 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
502 struct iaddr netmask
;
507 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
508 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &hkey
) != ERROR_SUCCESS
)
512 if( Adapter
->NteContext
)
514 DeleteIPAddress( Adapter
->NteContext
);
515 Adapter
->NteContext
= 0;
518 /* Set up our default router if we got one from the DHCP server */
519 if( new_lease
->options
[DHO_SUBNET_MASK
].len
) {
522 memcpy( netmask
.iabuf
,
523 new_lease
->options
[DHO_SUBNET_MASK
].data
,
524 new_lease
->options
[DHO_SUBNET_MASK
].len
);
525 Status
= AddIPAddress
526 ( *((ULONG
*)new_lease
->address
.iabuf
),
527 *((ULONG
*)netmask
.iabuf
),
528 Adapter
->IfMib
.dwIndex
,
529 &Adapter
->NteContext
,
530 &Adapter
->NteInstance
);
532 RegSetValueExA(hkey
, "DhcpIPAddress", 0, REG_SZ
, (LPBYTE
)piaddr(new_lease
->address
), strlen(piaddr(new_lease
->address
))+1);
534 for(i
= 0; i
< new_lease
->options
[DHO_SUBNET_MASK
].len
; i
++)
536 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_SUBNET_MASK
].data
[i
]);
537 if (i
+ 1 < new_lease
->options
[DHO_SUBNET_MASK
].len
)
540 RegSetValueExA(hkey
, "DhcpSubnetMask", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
542 RegSetValueExA(hkey
, "EnableDHCP", 0, REG_DWORD
, (LPBYTE
)&dwEnableDHCP
, sizeof(DWORD
));
545 if( !NT_SUCCESS(Status
) )
546 warning("AddIPAddress: %lx\n", Status
);
549 if( new_lease
->options
[DHO_ROUTERS
].len
) {
552 Adapter
->RouterMib
.dwForwardDest
= 0; /* Default route */
553 Adapter
->RouterMib
.dwForwardMask
= 0;
554 Adapter
->RouterMib
.dwForwardMetric1
= 1;
555 Adapter
->RouterMib
.dwForwardIfIndex
= Adapter
->IfMib
.dwIndex
;
557 if( Adapter
->RouterMib
.dwForwardNextHop
) {
558 /* If we set a default route before, delete it before continuing */
559 DeleteIpForwardEntry( &Adapter
->RouterMib
);
562 Adapter
->RouterMib
.dwForwardNextHop
=
563 *((ULONG
*)new_lease
->options
[DHO_ROUTERS
].data
);
565 Status
= CreateIpForwardEntry( &Adapter
->RouterMib
);
567 if( !NT_SUCCESS(Status
) )
568 warning("CreateIpForwardEntry: %lx\n", Status
);
572 for(i
= 0; i
< new_lease
->options
[DHO_ROUTERS
].len
; i
++)
574 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_ROUTERS
].data
[i
]);
575 if (i
+ 1 < new_lease
->options
[DHO_ROUTERS
].len
)
578 RegSetValueExA(hkey
, "DhcpDefaultGateway", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
588 bind_lease(struct interface_info
*ip
)
590 PDHCP_ADAPTER Adapter
;
591 struct client_lease
*new_lease
= ip
->client
->new;
596 /* Remember the medium. */
597 ip
->client
->new->medium
= ip
->client
->medium
;
598 ip
->client
->active
= ip
->client
->new;
599 ip
->client
->new = NULL
;
601 /* Set up a timeout to start the renewal process. */
602 /* Timeout of zero means no timeout (some implementations seem to use
605 if( ip
->client
->active
->renewal
- cur_time
)
606 add_timeout(ip
->client
->active
->renewal
, state_bound
, ip
);
608 note("bound to %s -- renewal in %ld seconds.",
609 piaddr(ip
->client
->active
->address
),
610 (long int)(ip
->client
->active
->renewal
- cur_time
));
612 ip
->client
->state
= S_BOUND
;
614 Adapter
= AdapterFindInfo( ip
);
616 if( Adapter
) setup_adapter( Adapter
, new_lease
);
618 warning("Could not find adapter for info %p\n", ip
);
621 set_name_servers( Adapter
, new_lease
);
622 set_domain( Adapter
, new_lease
);
626 * state_bound is called when we've successfully bound to a particular
627 * lease, but the renewal time on that lease has expired. We are
628 * expected to unicast a DHCPREQUEST to the server that gave us our
632 state_bound(void *ipp
)
634 struct interface_info
*ip
= ipp
;
636 ASSERT_STATE(state
, S_BOUND
);
638 /* T1 has expired. */
639 make_request(ip
, ip
->client
->active
);
640 ip
->client
->xid
= ip
->client
->packet
.xid
;
642 if (ip
->client
->active
->options
[DHO_DHCP_SERVER_IDENTIFIER
].len
== 4) {
643 memcpy(ip
->client
->destination
.iabuf
, ip
->client
->active
->
644 options
[DHO_DHCP_SERVER_IDENTIFIER
].data
, 4);
645 ip
->client
->destination
.len
= 4;
647 ip
->client
->destination
= iaddr_broadcast
;
649 time(&ip
->client
->first_sending
);
650 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
651 ip
->client
->state
= S_RENEWING
;
653 /* Send the first packet immediately. */
658 bootp(struct packet
*packet
)
660 struct iaddrlist
*ap
;
662 if (packet
->raw
->op
!= BOOTREPLY
)
665 /* If there's a reject list, make sure this packet's sender isn't
667 for (ap
= packet
->interface
->client
->config
->reject_list
;
669 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
670 note("BOOTREPLY from %s rejected.", piaddr(ap
->addr
));
678 dhcp(struct packet
*packet
)
680 struct iaddrlist
*ap
;
681 void (*handler
)(struct packet
*);
684 switch (packet
->packet_type
) {
701 /* If there's a reject list, make sure this packet's sender isn't
703 for (ap
= packet
->interface
->client
->config
->reject_list
;
705 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
706 note("%s from %s rejected.", type
, piaddr(ap
->addr
));
714 dhcpoffer(struct packet
*packet
)
716 struct interface_info
*ip
= packet
->interface
;
717 struct client_lease
*lease
, *lp
;
719 int arp_timeout_needed
= 0, stop_selecting
;
720 char *name
= packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
?
721 "DHCPOFFER" : "BOOTREPLY";
726 /* If we're not receptive to an offer right now, or if the offer
727 has an unrecognizable transaction id, then just drop it. */
728 if (ip
->client
->state
!= S_SELECTING
||
729 packet
->interface
->client
->xid
!= packet
->raw
->xid
||
730 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
731 (memcmp(packet
->interface
->hw_address
.haddr
,
732 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
735 note("%s from %s", name
, piaddr(packet
->client_addr
));
738 /* If this lease doesn't supply the minimum required parameters,
740 for (i
= 0; ip
->client
->config
->required_options
[i
]; i
++) {
741 if (!packet
->options
[ip
->client
->config
->
742 required_options
[i
]].len
) {
743 note("%s isn't satisfactory.", name
);
748 /* If we've already seen this lease, don't record it again. */
749 for (lease
= ip
->client
->offered_leases
;
750 lease
; lease
= lease
->next
) {
751 if (lease
->address
.len
== sizeof(packet
->raw
->yiaddr
) &&
752 !memcmp(lease
->address
.iabuf
,
753 &packet
->raw
->yiaddr
, lease
->address
.len
)) {
754 debug("%s already seen.", name
);
759 lease
= packet_to_lease(packet
);
761 note("packet_to_lease failed.");
765 /* If this lease was acquired through a BOOTREPLY, record that
767 if (!packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
)
770 /* Record the medium under which this lease was offered. */
771 lease
->medium
= ip
->client
->medium
;
773 /* Send out an ARP Request for the offered IP address. */
774 if( !check_arp( ip
, lease
) ) {
775 note("Arp check failed\n");
779 /* Figure out when we're supposed to stop selecting. */
781 ip
->client
->first_sending
+ ip
->client
->config
->select_interval
;
783 /* If this is the lease we asked for, put it at the head of the
784 list, and don't mess with the arp request timeout. */
785 if (lease
->address
.len
== ip
->client
->requested_address
.len
&&
786 !memcmp(lease
->address
.iabuf
,
787 ip
->client
->requested_address
.iabuf
,
788 ip
->client
->requested_address
.len
)) {
789 lease
->next
= ip
->client
->offered_leases
;
790 ip
->client
->offered_leases
= lease
;
792 /* If we already have an offer, and arping for this
793 offer would take us past the selection timeout,
794 then don't extend the timeout - just hope for the
796 if (ip
->client
->offered_leases
&&
797 (cur_time
+ arp_timeout_needed
) > stop_selecting
)
798 arp_timeout_needed
= 0;
800 /* Put the lease at the end of the list. */
802 if (!ip
->client
->offered_leases
)
803 ip
->client
->offered_leases
= lease
;
805 for (lp
= ip
->client
->offered_leases
; lp
->next
;
812 /* If we're supposed to stop selecting before we've had time
813 to wait for the ARPREPLY, add some delay to wait for
815 if (stop_selecting
- cur_time
< arp_timeout_needed
)
816 stop_selecting
= cur_time
+ arp_timeout_needed
;
818 /* If the selecting interval has expired, go immediately to
819 state_selecting(). Otherwise, time out into
820 state_selecting at the select interval. */
821 if (stop_selecting
<= 0)
824 add_timeout(stop_selecting
, state_selecting
, ip
);
825 cancel_timeout(send_discover
, ip
);
829 /* Allocate a client_lease structure and initialize it from the parameters
830 in the specified packet. */
832 struct client_lease
*
833 packet_to_lease(struct packet
*packet
)
835 struct client_lease
*lease
;
838 lease
= malloc(sizeof(struct client_lease
));
841 warning("dhcpoffer: no memory to record lease.");
845 memset(lease
, 0, sizeof(*lease
));
847 /* Copy the lease options. */
848 for (i
= 0; i
< 256; i
++) {
849 if (packet
->options
[i
].len
) {
850 lease
->options
[i
].data
=
851 malloc(packet
->options
[i
].len
+ 1);
852 if (!lease
->options
[i
].data
) {
853 warning("dhcpoffer: no memory for option %d", i
);
854 free_client_lease(lease
);
857 memcpy(lease
->options
[i
].data
,
858 packet
->options
[i
].data
,
859 packet
->options
[i
].len
);
860 lease
->options
[i
].len
=
861 packet
->options
[i
].len
;
862 lease
->options
[i
].data
[lease
->options
[i
].len
] =
865 if (!check_option(lease
,i
)) {
866 /* ignore a bogus lease offer */
867 warning("Invalid lease option - ignoring offer");
868 free_client_lease(lease
);
874 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
875 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
, lease
->address
.len
);
877 lease
->serveraddress
.len
= sizeof(packet
->raw
->siaddr
);
878 memcpy(lease
->serveraddress
.iabuf
, &packet
->raw
->siaddr
, lease
->address
.len
);
881 /* If the server name was filled out, copy it. */
882 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
883 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 2)) &&
884 packet
->raw
->sname
[0]) {
885 lease
->server_name
= malloc(DHCP_SNAME_LEN
+ 1);
886 if (!lease
->server_name
) {
887 warning("dhcpoffer: no memory for server name.");
888 free_client_lease(lease
);
891 memcpy(lease
->server_name
, packet
->raw
->sname
, DHCP_SNAME_LEN
);
892 lease
->server_name
[DHCP_SNAME_LEN
]='\0';
893 if (!res_hnok(lease
->server_name
) ) {
894 warning("Bogus server name %s", lease
->server_name
);
895 free_client_lease(lease
);
901 /* Ditto for the filename. */
902 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
903 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 1)) &&
904 packet
->raw
->file
[0]) {
905 /* Don't count on the NUL terminator. */
906 lease
->filename
= malloc(DHCP_FILE_LEN
+ 1);
907 if (!lease
->filename
) {
908 warning("dhcpoffer: no memory for filename.");
909 free_client_lease(lease
);
912 memcpy(lease
->filename
, packet
->raw
->file
, DHCP_FILE_LEN
);
913 lease
->filename
[DHCP_FILE_LEN
]='\0';
919 dhcpnak(struct packet
*packet
)
921 struct interface_info
*ip
= packet
->interface
;
923 /* If we're not receptive to an offer right now, or if the offer
924 has an unrecognizable transaction id, then just drop it. */
925 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
926 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
927 (memcmp(packet
->interface
->hw_address
.haddr
,
928 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
931 if (ip
->client
->state
!= S_REBOOTING
&&
932 ip
->client
->state
!= S_REQUESTING
&&
933 ip
->client
->state
!= S_RENEWING
&&
934 ip
->client
->state
!= S_REBINDING
)
937 note("DHCPNAK from %s", piaddr(packet
->client_addr
));
939 if (!ip
->client
->active
) {
940 note("DHCPNAK with no active lease.\n");
944 free_client_lease(ip
->client
->active
);
945 ip
->client
->active
= NULL
;
947 /* Stop sending DHCPREQUEST packets... */
948 cancel_timeout(send_request
, ip
);
950 ip
->client
->state
= S_INIT
;
954 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
955 one after the right interval has expired. If we don't get an offer by
956 the time we reach the panic interval, call the panic function. */
959 send_discover(void *ipp
)
961 struct interface_info
*ip
= ipp
;
962 int interval
, increase
= 1;
965 DH_DbgPrint(MID_TRACE
,("Doing discover on interface %p\n",ip
));
969 /* Figure out how long it's been since we started transmitting. */
970 interval
= cur_time
- ip
->client
->first_sending
;
972 /* If we're past the panic timeout, call the script and tell it
973 we haven't found anything for this interface yet. */
974 if (interval
> ip
->client
->config
->timeout
) {
976 ip
->client
->first_sending
= cur_time
;
979 /* If we're selecting media, try the whole list before doing
980 the exponential backoff, but if we've already received an
981 offer, stop looping, because we obviously have it right. */
982 if (!ip
->client
->offered_leases
&&
983 ip
->client
->config
->media
) {
986 if (ip
->client
->medium
) {
987 ip
->client
->medium
= ip
->client
->medium
->next
;
990 if (!ip
->client
->medium
) {
992 error("No valid media types for %s!", ip
->name
);
993 ip
->client
->medium
= ip
->client
->config
->media
;
997 note("Trying medium \"%s\" %d", ip
->client
->medium
->string
,
999 /* XXX Support other media types eventually */
1003 * If we're supposed to increase the interval, do so. If it's
1004 * currently zero (i.e., we haven't sent any packets yet), set
1005 * it to one; otherwise, add to it a random number between zero
1006 * and two times itself. On average, this means that it will
1007 * double with every transmission.
1010 if (!ip
->client
->interval
)
1011 ip
->client
->interval
=
1012 ip
->client
->config
->initial_interval
;
1014 ip
->client
->interval
+= (rand() >> 2) %
1015 (2 * ip
->client
->interval
);
1018 /* Don't backoff past cutoff. */
1019 if (ip
->client
->interval
>
1020 ip
->client
->config
->backoff_cutoff
)
1021 ip
->client
->interval
=
1022 ((ip
->client
->config
->backoff_cutoff
/ 2)
1024 ip
->client
->config
->backoff_cutoff
));
1025 } else if (!ip
->client
->interval
)
1026 ip
->client
->interval
=
1027 ip
->client
->config
->initial_interval
;
1029 /* If the backoff would take us to the panic timeout, just use that
1031 if (cur_time
+ ip
->client
->interval
>
1032 ip
->client
->first_sending
+ ip
->client
->config
->timeout
)
1033 ip
->client
->interval
=
1034 (ip
->client
->first_sending
+
1035 ip
->client
->config
->timeout
) - cur_time
+ 1;
1037 /* Record the number of seconds since we started sending. */
1038 if (interval
< 65536)
1039 ip
->client
->packet
.secs
= htons(interval
);
1041 ip
->client
->packet
.secs
= htons(65535);
1042 ip
->client
->secs
= ip
->client
->packet
.secs
;
1044 note("DHCPDISCOVER on %s to %s port %d interval %ld",
1045 ip
->name
, inet_ntoa(sockaddr_broadcast
.sin_addr
),
1046 ntohs(sockaddr_broadcast
.sin_port
), (long int)ip
->client
->interval
);
1048 /* Send out a packet. */
1049 (void)send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1050 inaddr_any
, &sockaddr_broadcast
, NULL
);
1052 DH_DbgPrint(MID_TRACE
,("discover timeout: now %x -> then %x\n",
1053 cur_time
, cur_time
+ ip
->client
->interval
));
1055 add_timeout(cur_time
+ ip
->client
->interval
, send_discover
, ip
);
1059 * state_panic gets called if we haven't received any offers in a preset
1060 * amount of time. When this happens, we try to use existing leases
1061 * that haven't yet expired, and failing that, we call the client script
1062 * and hope it can do something.
1065 state_panic(void *ipp
)
1067 struct interface_info
*ip
= ipp
;
1068 PDHCP_ADAPTER Adapter
= AdapterFindInfo(ip
);
1070 note("No DHCPOFFERS received.");
1072 if (!Adapter
->NteContext
)
1074 /* Generate an automatic private address */
1075 DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n");
1077 /* FIXME: The address generation code sucks */
1078 AddIPAddress(htonl(0xA9FE0000 | (rand() % 0xFFFF)), //169.254.X.X
1079 htonl(0xFFFF0000), //255.255.0.0
1080 Adapter
->IfMib
.dwIndex
,
1081 &Adapter
->NteContext
,
1082 &Adapter
->NteInstance
);
1087 send_request(void *ipp
)
1089 struct interface_info
*ip
= ipp
;
1090 struct sockaddr_in destination
;
1091 struct in_addr from
;
1097 /* Figure out how long it's been since we started transmitting. */
1098 interval
= cur_time
- ip
->client
->first_sending
;
1100 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1101 past the reboot timeout, go to INIT and see if we can
1102 DISCOVER an address... */
1103 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1104 means either that we're on a network with no DHCP server,
1105 or that our server is down. In the latter case, assuming
1106 that there is a backup DHCP server, DHCPDISCOVER will get
1107 us a new address, but we could also have successfully
1108 reused our old address. In the former case, we're hosed
1109 anyway. This is not a win-prone situation. */
1110 if ((ip
->client
->state
== S_REBOOTING
||
1111 ip
->client
->state
== S_REQUESTING
) &&
1112 interval
> ip
->client
->config
->reboot_timeout
) {
1113 ip
->client
->state
= S_INIT
;
1114 cancel_timeout(send_request
, ip
);
1119 /* If we're in the reboot state, make sure the media is set up
1121 if (ip
->client
->state
== S_REBOOTING
&&
1122 !ip
->client
->medium
&&
1123 ip
->client
->active
->medium
) {
1124 /* If the medium we chose won't fly, go to INIT state. */
1125 /* XXX Nothing for now */
1127 /* Record the medium. */
1128 ip
->client
->medium
= ip
->client
->active
->medium
;
1131 /* If the lease has expired, relinquish the address and go back
1132 to the INIT state. */
1133 if (ip
->client
->state
!= S_REQUESTING
&&
1134 cur_time
> ip
->client
->active
->expiry
) {
1135 PDHCP_ADAPTER Adapter
= AdapterFindInfo( ip
);
1136 /* Run the client script with the new parameters. */
1137 /* No script actions necessary in the expiry case */
1138 /* Now do a preinit on the interface so that we can
1139 discover a new address. */
1143 DeleteIPAddress( Adapter
->NteContext
);
1144 Adapter
->NteContext
= 0;
1147 ip
->client
->state
= S_INIT
;
1152 /* Do the exponential backoff... */
1153 if (!ip
->client
->interval
)
1154 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
1156 ip
->client
->interval
+= ((rand() >> 2) %
1157 (2 * ip
->client
->interval
));
1159 /* Don't backoff past cutoff. */
1160 if (ip
->client
->interval
>
1161 ip
->client
->config
->backoff_cutoff
)
1162 ip
->client
->interval
=
1163 ((ip
->client
->config
->backoff_cutoff
/ 2) +
1164 ((rand() >> 2) % ip
->client
->interval
));
1166 /* If the backoff would take us to the expiry time, just set the
1167 timeout to the expiry time. */
1168 if (ip
->client
->state
!= S_REQUESTING
&&
1169 cur_time
+ ip
->client
->interval
>
1170 ip
->client
->active
->expiry
)
1171 ip
->client
->interval
=
1172 ip
->client
->active
->expiry
- cur_time
+ 1;
1174 /* If the lease T2 time has elapsed, or if we're not yet bound,
1175 broadcast the DHCPREQUEST rather than unicasting. */
1176 memset(&destination
, 0, sizeof(destination
));
1177 if (ip
->client
->state
== S_REQUESTING
||
1178 ip
->client
->state
== S_REBOOTING
||
1179 cur_time
> ip
->client
->active
->rebind
)
1180 destination
.sin_addr
.s_addr
= INADDR_BROADCAST
;
1182 memcpy(&destination
.sin_addr
.s_addr
,
1183 ip
->client
->destination
.iabuf
,
1184 sizeof(destination
.sin_addr
.s_addr
));
1185 destination
.sin_port
= htons(REMOTE_PORT
);
1186 destination
.sin_family
= AF_INET
;
1187 // destination.sin_len = sizeof(destination);
1189 if (ip
->client
->state
!= S_REQUESTING
)
1190 memcpy(&from
, ip
->client
->active
->address
.iabuf
,
1193 from
.s_addr
= INADDR_ANY
;
1195 /* Record the number of seconds since we started sending. */
1196 if (ip
->client
->state
== S_REQUESTING
)
1197 ip
->client
->packet
.secs
= ip
->client
->secs
;
1199 if (interval
< 65536)
1200 ip
->client
->packet
.secs
= htons(interval
);
1202 ip
->client
->packet
.secs
= htons(65535);
1205 note("DHCPREQUEST on %s to %s port %d", ip
->name
,
1206 inet_ntoa(destination
.sin_addr
), ntohs(destination
.sin_port
));
1208 /* Send out a packet. */
1209 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1210 from
, &destination
, NULL
);
1212 add_timeout(cur_time
+ ip
->client
->interval
, send_request
, ip
);
1216 send_decline(void *ipp
)
1218 struct interface_info
*ip
= ipp
;
1220 note("DHCPDECLINE on %s to %s port %d", ip
->name
,
1221 inet_ntoa(sockaddr_broadcast
.sin_addr
),
1222 ntohs(sockaddr_broadcast
.sin_port
));
1224 /* Send out a packet. */
1225 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1226 inaddr_any
, &sockaddr_broadcast
, NULL
);
1230 make_discover(struct interface_info
*ip
, struct client_lease
*lease
)
1232 unsigned char discover
= DHCPDISCOVER
;
1233 struct tree_cache
*options
[256];
1234 struct tree_cache option_elements
[256];
1236 ULONG foo
= (ULONG
) GetTickCount();
1238 memset(option_elements
, 0, sizeof(option_elements
));
1239 memset(options
, 0, sizeof(options
));
1240 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1242 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1243 i
= DHO_DHCP_MESSAGE_TYPE
;
1244 options
[i
] = &option_elements
[i
];
1245 options
[i
]->value
= &discover
;
1246 options
[i
]->len
= sizeof(discover
);
1247 options
[i
]->buf_size
= sizeof(discover
);
1248 options
[i
]->timeout
= 0xFFFFFFFF;
1250 /* Request the options we want */
1251 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1252 options
[i
] = &option_elements
[i
];
1253 options
[i
]->value
= ip
->client
->config
->requested_options
;
1254 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1255 options
[i
]->buf_size
=
1256 ip
->client
->config
->requested_option_count
;
1257 options
[i
]->timeout
= 0xFFFFFFFF;
1259 /* If we had an address, try to get it again. */
1261 ip
->client
->requested_address
= lease
->address
;
1262 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1263 options
[i
] = &option_elements
[i
];
1264 options
[i
]->value
= lease
->address
.iabuf
;
1265 options
[i
]->len
= lease
->address
.len
;
1266 options
[i
]->buf_size
= lease
->address
.len
;
1267 options
[i
]->timeout
= 0xFFFFFFFF;
1269 ip
->client
->requested_address
.len
= 0;
1271 /* Send any options requested in the config file. */
1272 for (i
= 0; i
< 256; i
++)
1274 ip
->client
->config
->send_options
[i
].data
) {
1275 options
[i
] = &option_elements
[i
];
1277 ip
->client
->config
->send_options
[i
].data
;
1279 ip
->client
->config
->send_options
[i
].len
;
1280 options
[i
]->buf_size
=
1281 ip
->client
->config
->send_options
[i
].len
;
1282 options
[i
]->timeout
= 0xFFFFFFFF;
1285 /* Set up the option buffer... */
1286 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1287 options
, 0, 0, 0, NULL
, 0);
1288 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1289 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1291 ip
->client
->packet
.op
= BOOTREQUEST
;
1292 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1293 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1294 ip
->client
->packet
.hops
= 0;
1295 ip
->client
->packet
.xid
= RtlRandom(&foo
);
1296 ip
->client
->packet
.secs
= 0; /* filled in by send_discover. */
1297 ip
->client
->packet
.flags
= 0;
1299 memset(&(ip
->client
->packet
.ciaddr
),
1300 0, sizeof(ip
->client
->packet
.ciaddr
));
1301 memset(&(ip
->client
->packet
.yiaddr
),
1302 0, sizeof(ip
->client
->packet
.yiaddr
));
1303 memset(&(ip
->client
->packet
.siaddr
),
1304 0, sizeof(ip
->client
->packet
.siaddr
));
1305 memset(&(ip
->client
->packet
.giaddr
),
1306 0, sizeof(ip
->client
->packet
.giaddr
));
1307 memcpy(ip
->client
->packet
.chaddr
,
1308 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1313 make_request(struct interface_info
*ip
, struct client_lease
* lease
)
1315 unsigned char request
= DHCPREQUEST
;
1316 struct tree_cache
*options
[256];
1317 struct tree_cache option_elements
[256];
1320 memset(options
, 0, sizeof(options
));
1321 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1323 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1324 i
= DHO_DHCP_MESSAGE_TYPE
;
1325 options
[i
] = &option_elements
[i
];
1326 options
[i
]->value
= &request
;
1327 options
[i
]->len
= sizeof(request
);
1328 options
[i
]->buf_size
= sizeof(request
);
1329 options
[i
]->timeout
= 0xFFFFFFFF;
1331 /* Request the options we want */
1332 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1333 options
[i
] = &option_elements
[i
];
1334 options
[i
]->value
= ip
->client
->config
->requested_options
;
1335 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1336 options
[i
]->buf_size
=
1337 ip
->client
->config
->requested_option_count
;
1338 options
[i
]->timeout
= 0xFFFFFFFF;
1340 /* If we are requesting an address that hasn't yet been assigned
1341 to us, use the DHCP Requested Address option. */
1342 if (ip
->client
->state
== S_REQUESTING
) {
1343 /* Send back the server identifier... */
1344 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1345 options
[i
] = &option_elements
[i
];
1346 options
[i
]->value
= lease
->options
[i
].data
;
1347 options
[i
]->len
= lease
->options
[i
].len
;
1348 options
[i
]->buf_size
= lease
->options
[i
].len
;
1349 options
[i
]->timeout
= 0xFFFFFFFF;
1351 if (ip
->client
->state
== S_REQUESTING
||
1352 ip
->client
->state
== S_REBOOTING
) {
1353 ip
->client
->requested_address
= lease
->address
;
1354 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1355 options
[i
] = &option_elements
[i
];
1356 options
[i
]->value
= lease
->address
.iabuf
;
1357 options
[i
]->len
= lease
->address
.len
;
1358 options
[i
]->buf_size
= lease
->address
.len
;
1359 options
[i
]->timeout
= 0xFFFFFFFF;
1361 ip
->client
->requested_address
.len
= 0;
1363 /* Send any options requested in the config file. */
1364 for (i
= 0; i
< 256; i
++)
1366 ip
->client
->config
->send_options
[i
].data
) {
1367 options
[i
] = &option_elements
[i
];
1369 ip
->client
->config
->send_options
[i
].data
;
1371 ip
->client
->config
->send_options
[i
].len
;
1372 options
[i
]->buf_size
=
1373 ip
->client
->config
->send_options
[i
].len
;
1374 options
[i
]->timeout
= 0xFFFFFFFF;
1377 /* Set up the option buffer... */
1378 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1379 options
, 0, 0, 0, NULL
, 0);
1380 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1381 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1383 ip
->client
->packet
.op
= BOOTREQUEST
;
1384 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1385 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1386 ip
->client
->packet
.hops
= 0;
1387 ip
->client
->packet
.xid
= ip
->client
->xid
;
1388 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1390 /* If we own the address we're requesting, put it in ciaddr;
1391 otherwise set ciaddr to zero. */
1392 if (ip
->client
->state
== S_BOUND
||
1393 ip
->client
->state
== S_RENEWING
||
1394 ip
->client
->state
== S_REBINDING
) {
1395 memcpy(&ip
->client
->packet
.ciaddr
,
1396 lease
->address
.iabuf
, lease
->address
.len
);
1397 ip
->client
->packet
.flags
= 0;
1399 memset(&ip
->client
->packet
.ciaddr
, 0,
1400 sizeof(ip
->client
->packet
.ciaddr
));
1401 ip
->client
->packet
.flags
= 0;
1404 memset(&ip
->client
->packet
.yiaddr
, 0,
1405 sizeof(ip
->client
->packet
.yiaddr
));
1406 memset(&ip
->client
->packet
.siaddr
, 0,
1407 sizeof(ip
->client
->packet
.siaddr
));
1408 memset(&ip
->client
->packet
.giaddr
, 0,
1409 sizeof(ip
->client
->packet
.giaddr
));
1410 memcpy(ip
->client
->packet
.chaddr
,
1411 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1415 make_decline(struct interface_info
*ip
, struct client_lease
*lease
)
1417 struct tree_cache
*options
[256], message_type_tree
;
1418 struct tree_cache requested_address_tree
;
1419 struct tree_cache server_id_tree
, client_id_tree
;
1420 unsigned char decline
= DHCPDECLINE
;
1423 memset(options
, 0, sizeof(options
));
1424 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1426 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1427 i
= DHO_DHCP_MESSAGE_TYPE
;
1428 options
[i
] = &message_type_tree
;
1429 options
[i
]->value
= &decline
;
1430 options
[i
]->len
= sizeof(decline
);
1431 options
[i
]->buf_size
= sizeof(decline
);
1432 options
[i
]->timeout
= 0xFFFFFFFF;
1434 /* Send back the server identifier... */
1435 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1436 options
[i
] = &server_id_tree
;
1437 options
[i
]->value
= lease
->options
[i
].data
;
1438 options
[i
]->len
= lease
->options
[i
].len
;
1439 options
[i
]->buf_size
= lease
->options
[i
].len
;
1440 options
[i
]->timeout
= 0xFFFFFFFF;
1442 /* Send back the address we're declining. */
1443 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1444 options
[i
] = &requested_address_tree
;
1445 options
[i
]->value
= lease
->address
.iabuf
;
1446 options
[i
]->len
= lease
->address
.len
;
1447 options
[i
]->buf_size
= lease
->address
.len
;
1448 options
[i
]->timeout
= 0xFFFFFFFF;
1450 /* Send the uid if the user supplied one. */
1451 i
= DHO_DHCP_CLIENT_IDENTIFIER
;
1452 if (ip
->client
->config
->send_options
[i
].len
) {
1453 options
[i
] = &client_id_tree
;
1454 options
[i
]->value
= ip
->client
->config
->send_options
[i
].data
;
1455 options
[i
]->len
= ip
->client
->config
->send_options
[i
].len
;
1456 options
[i
]->buf_size
= ip
->client
->config
->send_options
[i
].len
;
1457 options
[i
]->timeout
= 0xFFFFFFFF;
1461 /* Set up the option buffer... */
1462 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1463 options
, 0, 0, 0, NULL
, 0);
1464 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1465 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1467 ip
->client
->packet
.op
= BOOTREQUEST
;
1468 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1469 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1470 ip
->client
->packet
.hops
= 0;
1471 ip
->client
->packet
.xid
= ip
->client
->xid
;
1472 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1473 ip
->client
->packet
.flags
= 0;
1475 /* ciaddr must always be zero. */
1476 memset(&ip
->client
->packet
.ciaddr
, 0,
1477 sizeof(ip
->client
->packet
.ciaddr
));
1478 memset(&ip
->client
->packet
.yiaddr
, 0,
1479 sizeof(ip
->client
->packet
.yiaddr
));
1480 memset(&ip
->client
->packet
.siaddr
, 0,
1481 sizeof(ip
->client
->packet
.siaddr
));
1482 memset(&ip
->client
->packet
.giaddr
, 0,
1483 sizeof(ip
->client
->packet
.giaddr
));
1484 memcpy(ip
->client
->packet
.chaddr
,
1485 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1489 free_client_lease(struct client_lease
*lease
)
1493 if (lease
->server_name
)
1494 free(lease
->server_name
);
1495 if (lease
->filename
)
1496 free(lease
->filename
);
1497 for (i
= 0; i
< 256; i
++) {
1498 if (lease
->options
[i
].len
)
1499 free(lease
->options
[i
].data
);
1507 rewrite_client_leases(struct interface_info
*ifi
)
1509 struct client_lease
*lp
;
1512 leaseFile
= fopen(path_dhclient_db
, "w");
1514 error("can't create %s", path_dhclient_db
);
1520 for (lp
= ifi
->client
->leases
; lp
; lp
= lp
->next
)
1521 write_client_lease(ifi
, lp
, 1);
1522 if (ifi
->client
->active
)
1523 write_client_lease(ifi
, ifi
->client
->active
, 1);
1529 write_client_lease(struct interface_info
*ip
, struct client_lease
*lease
,
1532 static int leases_written
;
1537 if (leases_written
++ > 20) {
1538 rewrite_client_leases(ip
);
1543 /* If the lease came from the config file, we don't need to stash
1544 a copy in the lease database. */
1545 if (lease
->is_static
)
1548 if (!leaseFile
) { /* XXX */
1549 leaseFile
= fopen(path_dhclient_db
, "w");
1551 error("can't create %s", path_dhclient_db
);
1556 fprintf(leaseFile
, "lease {\n");
1557 if (lease
->is_bootp
)
1558 fprintf(leaseFile
, " bootp;\n");
1559 fprintf(leaseFile
, " interface \"%s\";\n", ip
->name
);
1560 fprintf(leaseFile
, " fixed-address %s;\n", piaddr(lease
->address
));
1561 if (lease
->filename
)
1562 fprintf(leaseFile
, " filename \"%s\";\n", lease
->filename
);
1563 if (lease
->server_name
)
1564 fprintf(leaseFile
, " server-name \"%s\";\n",
1565 lease
->server_name
);
1567 fprintf(leaseFile
, " medium \"%s\";\n", lease
->medium
->string
);
1568 for (i
= 0; i
< 256; i
++)
1569 if (lease
->options
[i
].len
)
1570 fprintf(leaseFile
, " option %s %s;\n",
1571 dhcp_options
[i
].name
,
1572 pretty_print_option(i
, lease
->options
[i
].data
,
1573 lease
->options
[i
].len
, 1, 1));
1575 t
= gmtime(&lease
->renewal
);
1577 fprintf(leaseFile
, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1578 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1579 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1580 t
= gmtime(&lease
->rebind
);
1582 fprintf(leaseFile
, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1583 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1584 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1585 t
= gmtime(&lease
->expiry
);
1587 fprintf(leaseFile
, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1588 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1589 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1590 fprintf(leaseFile
, "}\n");
1595 priv_script_init(struct interface_info
*ip
, char *reason
, char *medium
)
1598 // XXX Do we need to do anything?
1603 priv_script_write_params(struct interface_info
*ip
, char *prefix
, struct client_lease
*lease
)
1605 u_int8_t dbuf
[1500];
1609 script_set_env(ip
->client
, prefix
, "ip_address",
1610 piaddr(lease
->address
));
1613 if (lease
->options
[DHO_SUBNET_MASK
].len
&&
1614 (lease
->options
[DHO_SUBNET_MASK
].len
<
1615 sizeof(lease
->address
.iabuf
))) {
1616 struct iaddr netmask
, subnet
, broadcast
;
1618 memcpy(netmask
.iabuf
, lease
->options
[DHO_SUBNET_MASK
].data
,
1619 lease
->options
[DHO_SUBNET_MASK
].len
);
1620 netmask
.len
= lease
->options
[DHO_SUBNET_MASK
].len
;
1622 subnet
= subnet_number(lease
->address
, netmask
);
1625 script_set_env(ip
->client
, prefix
, "network_number",
1628 if (!lease
->options
[DHO_BROADCAST_ADDRESS
].len
) {
1629 broadcast
= broadcast_addr(subnet
, netmask
);
1632 script_set_env(ip
->client
, prefix
,
1633 "broadcast_address",
1643 if (lease
->filename
)
1644 script_set_env(ip
->client
, prefix
, "filename", lease
->filename
);
1645 if (lease
->server_name
)
1646 script_set_env(ip
->client
, prefix
, "server_name",
1647 lease
->server_name
);
1650 for (i
= 0; i
< 256; i
++) {
1651 u_int8_t
*dp
= NULL
;
1653 if (ip
->client
->config
->defaults
[i
].len
) {
1654 if (lease
->options
[i
].len
) {
1656 ip
->client
->config
->default_actions
[i
]) {
1657 case ACTION_DEFAULT
:
1658 dp
= lease
->options
[i
].data
;
1659 len
= lease
->options
[i
].len
;
1661 case ACTION_SUPERSEDE
:
1664 config
->defaults
[i
].data
;
1666 config
->defaults
[i
].len
;
1668 case ACTION_PREPEND
:
1670 config
->defaults
[i
].len
+
1671 lease
->options
[i
].len
;
1672 if (len
>= sizeof(dbuf
)) {
1673 warning("no space to %s %s",
1675 dhcp_options
[i
].name
);
1681 config
->defaults
[i
].data
,
1683 config
->defaults
[i
].len
);
1684 memcpy(dp
+ ip
->client
->
1685 config
->defaults
[i
].len
,
1686 lease
->options
[i
].data
,
1687 lease
->options
[i
].len
);
1692 config
->defaults
[i
].len
+
1693 lease
->options
[i
].len
+ 1;
1694 if (len
> sizeof(dbuf
)) {
1695 warning("no space to %s %s",
1697 dhcp_options
[i
].name
);
1702 lease
->options
[i
].data
,
1703 lease
->options
[i
].len
);
1704 memcpy(dp
+ lease
->options
[i
].len
,
1706 config
->defaults
[i
].data
,
1708 config
->defaults
[i
].len
);
1713 config
->defaults
[i
].data
;
1715 config
->defaults
[i
].len
;
1717 } else if (lease
->options
[i
].len
) {
1718 len
= lease
->options
[i
].len
;
1719 dp
= lease
->options
[i
].data
;
1727 if (dhcp_option_ev_name(name
, sizeof(name
),
1729 script_set_env(ip
->client
, prefix
, name
,
1730 pretty_print_option(i
, dp
, len
, 0, 0));
1735 snprintf(tbuf
, sizeof(tbuf
), "%d", (int)lease
->expiry
);
1736 script_set_env(ip
->client
, prefix
, "expiry", tbuf
);
1741 dhcp_option_ev_name(char *buf
, size_t buflen
, struct dhcp_option
*option
)
1745 for (i
= 0; option
->name
[i
]; i
++) {
1746 if (i
+ 1 == buflen
)
1748 if (option
->name
[i
] == '-')
1751 buf
[i
] = option
->name
[i
];
1762 static int state
= 0;
1764 if (no_daemon
|| state
)
1769 /* Stop logging to stderr... */
1772 if (daemon(1, 0) == -1)
1775 /* we are chrooted, daemon(3) fails to open /dev/null */
1777 dup2(nullfd
, STDIN_FILENO
);
1778 dup2(nullfd
, STDOUT_FILENO
);
1779 dup2(nullfd
, STDERR_FILENO
);
1787 check_option(struct client_lease
*l
, int option
)
1792 /* we use this, since this is what gets passed to dhclient-script */
1794 opbuf
= pretty_print_option(option
, l
->options
[option
].data
,
1795 l
->options
[option
].len
, 0, 0);
1797 sbuf
= option_as_string(option
, l
->options
[option
].data
,
1798 l
->options
[option
].len
);
1801 case DHO_SUBNET_MASK
:
1802 case DHO_TIME_SERVERS
:
1803 case DHO_NAME_SERVERS
:
1805 case DHO_DOMAIN_NAME_SERVERS
:
1806 case DHO_LOG_SERVERS
:
1807 case DHO_COOKIE_SERVERS
:
1808 case DHO_LPR_SERVERS
:
1809 case DHO_IMPRESS_SERVERS
:
1810 case DHO_RESOURCE_LOCATION_SERVERS
:
1811 case DHO_SWAP_SERVER
:
1812 case DHO_BROADCAST_ADDRESS
:
1813 case DHO_NIS_SERVERS
:
1814 case DHO_NTP_SERVERS
:
1815 case DHO_NETBIOS_NAME_SERVERS
:
1816 case DHO_NETBIOS_DD_SERVER
:
1817 case DHO_FONT_SERVERS
:
1818 case DHO_DHCP_SERVER_IDENTIFIER
:
1819 if (!ipv4addrs(opbuf
)) {
1820 warning("Invalid IP address in option(%d): %s", option
, opbuf
);
1825 case DHO_DOMAIN_NAME
:
1826 case DHO_NIS_DOMAIN
:
1827 if (!res_hnok(sbuf
))
1828 warning("Bogus Host Name option %d: %s (%s)", option
,
1832 case DHO_TIME_OFFSET
:
1834 case DHO_MERIT_DUMP
:
1836 case DHO_EXTENSIONS_PATH
:
1837 case DHO_IP_FORWARDING
:
1838 case DHO_NON_LOCAL_SOURCE_ROUTING
:
1839 case DHO_POLICY_FILTER
:
1840 case DHO_MAX_DGRAM_REASSEMBLY
:
1841 case DHO_DEFAULT_IP_TTL
:
1842 case DHO_PATH_MTU_AGING_TIMEOUT
:
1843 case DHO_PATH_MTU_PLATEAU_TABLE
:
1844 case DHO_INTERFACE_MTU
:
1845 case DHO_ALL_SUBNETS_LOCAL
:
1846 case DHO_PERFORM_MASK_DISCOVERY
:
1847 case DHO_MASK_SUPPLIER
:
1848 case DHO_ROUTER_DISCOVERY
:
1849 case DHO_ROUTER_SOLICITATION_ADDRESS
:
1850 case DHO_STATIC_ROUTES
:
1851 case DHO_TRAILER_ENCAPSULATION
:
1852 case DHO_ARP_CACHE_TIMEOUT
:
1853 case DHO_IEEE802_3_ENCAPSULATION
:
1854 case DHO_DEFAULT_TCP_TTL
:
1855 case DHO_TCP_KEEPALIVE_INTERVAL
:
1856 case DHO_TCP_KEEPALIVE_GARBAGE
:
1857 case DHO_VENDOR_ENCAPSULATED_OPTIONS
:
1858 case DHO_NETBIOS_NODE_TYPE
:
1859 case DHO_NETBIOS_SCOPE
:
1860 case DHO_X_DISPLAY_MANAGER
:
1861 case DHO_DHCP_REQUESTED_ADDRESS
:
1862 case DHO_DHCP_LEASE_TIME
:
1863 case DHO_DHCP_OPTION_OVERLOAD
:
1864 case DHO_DHCP_MESSAGE_TYPE
:
1865 case DHO_DHCP_PARAMETER_REQUEST_LIST
:
1866 case DHO_DHCP_MESSAGE
:
1867 case DHO_DHCP_MAX_MESSAGE_SIZE
:
1868 case DHO_DHCP_RENEWAL_TIME
:
1869 case DHO_DHCP_REBINDING_TIME
:
1870 case DHO_DHCP_CLASS_IDENTIFIER
:
1871 case DHO_DHCP_CLIENT_IDENTIFIER
:
1872 case DHO_DHCP_USER_CLASS_ID
:
1876 warning("unknown dhcp option value 0x%x", option
);
1877 return (unknown_ok
);
1882 res_hnok(const char *dn
)
1884 int pch
= PERIOD
, ch
= *dn
++;
1886 while (ch
!= '\0') {
1889 if (periodchar(ch
)) {
1891 } else if (periodchar(pch
)) {
1892 if (!borderchar(ch
))
1894 } else if (periodchar(nch
) || nch
== '\0') {
1895 if (!borderchar(ch
))
1898 if (!middlechar(ch
))
1906 /* Does buf consist only of dotted decimal ipv4 addrs?
1907 * return how many if so,
1908 * otherwise, return 0
1911 ipv4addrs(char * buf
)
1917 note("Input: %s", buf
);
1920 tmp
= strtok(buf
, " ");
1921 note("got %s", tmp
);
1922 if( tmp
&& inet_aton(tmp
, &jnk
) ) i
++;
1931 option_as_string(unsigned int code
, unsigned char *data
, int len
)
1933 static char optbuf
[32768]; /* XXX */
1935 int opleft
= sizeof(optbuf
);
1936 unsigned char *dp
= data
;
1939 error("option_as_string: bad code %d", code
);
1941 for (; dp
< data
+ len
; dp
++) {
1942 if (!isascii(*dp
) || !isprint(*dp
)) {
1943 if (dp
+ 1 != data
+ len
|| *dp
!= 0) {
1944 _snprintf(op
, opleft
, "\\%03o", *dp
);
1948 } else if (*dp
== '"' || *dp
== '\'' || *dp
== '$' ||
1949 *dp
== '`' || *dp
== '\\') {
1963 warning("dhcp option too large");