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
;
599 /* Replace the old active lease with the new one. */
600 if (ip
->client
->active
)
601 free_client_lease(ip
->client
->active
);
602 ip
->client
->active
= ip
->client
->new;
603 ip
->client
->new = NULL
;
605 /* Set up a timeout to start the renewal process. */
606 /* Timeout of zero means no timeout (some implementations seem to use
609 if( ip
->client
->active
->renewal
- cur_time
)
610 add_timeout(ip
->client
->active
->renewal
, state_bound
, ip
);
612 note("bound to %s -- renewal in %ld seconds.",
613 piaddr(ip
->client
->active
->address
),
614 (long int)(ip
->client
->active
->renewal
- cur_time
));
616 ip
->client
->state
= S_BOUND
;
618 Adapter
= AdapterFindInfo( ip
);
620 if( Adapter
) setup_adapter( Adapter
, new_lease
);
622 warning("Could not find adapter for info %p\n", ip
);
625 set_name_servers( Adapter
, new_lease
);
626 set_domain( Adapter
, new_lease
);
630 * state_bound is called when we've successfully bound to a particular
631 * lease, but the renewal time on that lease has expired. We are
632 * expected to unicast a DHCPREQUEST to the server that gave us our
636 state_bound(void *ipp
)
638 struct interface_info
*ip
= ipp
;
640 ASSERT_STATE(state
, S_BOUND
);
642 /* T1 has expired. */
643 make_request(ip
, ip
->client
->active
);
644 ip
->client
->xid
= ip
->client
->packet
.xid
;
646 if (ip
->client
->active
->options
[DHO_DHCP_SERVER_IDENTIFIER
].len
== 4) {
647 memcpy(ip
->client
->destination
.iabuf
, ip
->client
->active
->
648 options
[DHO_DHCP_SERVER_IDENTIFIER
].data
, 4);
649 ip
->client
->destination
.len
= 4;
651 ip
->client
->destination
= iaddr_broadcast
;
653 time(&ip
->client
->first_sending
);
654 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
655 ip
->client
->state
= S_RENEWING
;
657 /* Send the first packet immediately. */
662 bootp(struct packet
*packet
)
664 struct iaddrlist
*ap
;
666 if (packet
->raw
->op
!= BOOTREPLY
)
669 /* If there's a reject list, make sure this packet's sender isn't
671 for (ap
= packet
->interface
->client
->config
->reject_list
;
673 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
674 note("BOOTREPLY from %s rejected.", piaddr(ap
->addr
));
682 dhcp(struct packet
*packet
)
684 struct iaddrlist
*ap
;
685 void (*handler
)(struct packet
*);
688 switch (packet
->packet_type
) {
705 /* If there's a reject list, make sure this packet's sender isn't
707 for (ap
= packet
->interface
->client
->config
->reject_list
;
709 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
710 note("%s from %s rejected.", type
, piaddr(ap
->addr
));
718 dhcpoffer(struct packet
*packet
)
720 struct interface_info
*ip
= packet
->interface
;
721 struct client_lease
*lease
, *lp
;
723 int arp_timeout_needed
= 0, stop_selecting
;
724 char *name
= packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
?
725 "DHCPOFFER" : "BOOTREPLY";
730 /* If we're not receptive to an offer right now, or if the offer
731 has an unrecognizable transaction id, then just drop it. */
732 if (ip
->client
->state
!= S_SELECTING
||
733 packet
->interface
->client
->xid
!= packet
->raw
->xid
||
734 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
735 (memcmp(packet
->interface
->hw_address
.haddr
,
736 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
739 note("%s from %s", name
, piaddr(packet
->client_addr
));
742 /* If this lease doesn't supply the minimum required parameters,
744 for (i
= 0; ip
->client
->config
->required_options
[i
]; i
++) {
745 if (!packet
->options
[ip
->client
->config
->
746 required_options
[i
]].len
) {
747 note("%s isn't satisfactory.", name
);
752 /* If we've already seen this lease, don't record it again. */
753 for (lease
= ip
->client
->offered_leases
;
754 lease
; lease
= lease
->next
) {
755 if (lease
->address
.len
== sizeof(packet
->raw
->yiaddr
) &&
756 !memcmp(lease
->address
.iabuf
,
757 &packet
->raw
->yiaddr
, lease
->address
.len
)) {
758 debug("%s already seen.", name
);
763 lease
= packet_to_lease(packet
);
765 note("packet_to_lease failed.");
769 /* If this lease was acquired through a BOOTREPLY, record that
771 if (!packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
)
774 /* Record the medium under which this lease was offered. */
775 lease
->medium
= ip
->client
->medium
;
777 /* Send out an ARP Request for the offered IP address. */
778 if( !check_arp( ip
, lease
) ) {
779 note("Arp check failed\n");
783 /* Figure out when we're supposed to stop selecting. */
785 ip
->client
->first_sending
+ ip
->client
->config
->select_interval
;
787 /* If this is the lease we asked for, put it at the head of the
788 list, and don't mess with the arp request timeout. */
789 if (lease
->address
.len
== ip
->client
->requested_address
.len
&&
790 !memcmp(lease
->address
.iabuf
,
791 ip
->client
->requested_address
.iabuf
,
792 ip
->client
->requested_address
.len
)) {
793 lease
->next
= ip
->client
->offered_leases
;
794 ip
->client
->offered_leases
= lease
;
796 /* If we already have an offer, and arping for this
797 offer would take us past the selection timeout,
798 then don't extend the timeout - just hope for the
800 if (ip
->client
->offered_leases
&&
801 (cur_time
+ arp_timeout_needed
) > stop_selecting
)
802 arp_timeout_needed
= 0;
804 /* Put the lease at the end of the list. */
806 if (!ip
->client
->offered_leases
)
807 ip
->client
->offered_leases
= lease
;
809 for (lp
= ip
->client
->offered_leases
; lp
->next
;
816 /* If we're supposed to stop selecting before we've had time
817 to wait for the ARPREPLY, add some delay to wait for
819 if (stop_selecting
- cur_time
< arp_timeout_needed
)
820 stop_selecting
= cur_time
+ arp_timeout_needed
;
822 /* If the selecting interval has expired, go immediately to
823 state_selecting(). Otherwise, time out into
824 state_selecting at the select interval. */
825 if (stop_selecting
<= 0)
828 add_timeout(stop_selecting
, state_selecting
, ip
);
829 cancel_timeout(send_discover
, ip
);
833 /* Allocate a client_lease structure and initialize it from the parameters
834 in the specified packet. */
836 struct client_lease
*
837 packet_to_lease(struct packet
*packet
)
839 struct client_lease
*lease
;
842 lease
= malloc(sizeof(struct client_lease
));
845 warning("dhcpoffer: no memory to record lease.");
849 memset(lease
, 0, sizeof(*lease
));
851 /* Copy the lease options. */
852 for (i
= 0; i
< 256; i
++) {
853 if (packet
->options
[i
].len
) {
854 lease
->options
[i
].data
=
855 malloc(packet
->options
[i
].len
+ 1);
856 if (!lease
->options
[i
].data
) {
857 warning("dhcpoffer: no memory for option %d", i
);
858 free_client_lease(lease
);
861 memcpy(lease
->options
[i
].data
,
862 packet
->options
[i
].data
,
863 packet
->options
[i
].len
);
864 lease
->options
[i
].len
=
865 packet
->options
[i
].len
;
866 lease
->options
[i
].data
[lease
->options
[i
].len
] =
869 if (!check_option(lease
,i
)) {
870 /* ignore a bogus lease offer */
871 warning("Invalid lease option - ignoring offer");
872 free_client_lease(lease
);
878 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
879 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
, lease
->address
.len
);
881 lease
->serveraddress
.len
= sizeof(packet
->raw
->siaddr
);
882 memcpy(lease
->serveraddress
.iabuf
, &packet
->raw
->siaddr
, lease
->address
.len
);
885 /* If the server name was filled out, copy it. */
886 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
887 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 2)) &&
888 packet
->raw
->sname
[0]) {
889 lease
->server_name
= malloc(DHCP_SNAME_LEN
+ 1);
890 if (!lease
->server_name
) {
891 warning("dhcpoffer: no memory for server name.");
892 free_client_lease(lease
);
895 memcpy(lease
->server_name
, packet
->raw
->sname
, DHCP_SNAME_LEN
);
896 lease
->server_name
[DHCP_SNAME_LEN
]='\0';
897 if (!res_hnok(lease
->server_name
) ) {
898 warning("Bogus server name %s", lease
->server_name
);
899 free_client_lease(lease
);
905 /* Ditto for the filename. */
906 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
907 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 1)) &&
908 packet
->raw
->file
[0]) {
909 /* Don't count on the NUL terminator. */
910 lease
->filename
= malloc(DHCP_FILE_LEN
+ 1);
911 if (!lease
->filename
) {
912 warning("dhcpoffer: no memory for filename.");
913 free_client_lease(lease
);
916 memcpy(lease
->filename
, packet
->raw
->file
, DHCP_FILE_LEN
);
917 lease
->filename
[DHCP_FILE_LEN
]='\0';
923 dhcpnak(struct packet
*packet
)
925 struct interface_info
*ip
= packet
->interface
;
927 /* If we're not receptive to an offer right now, or if the offer
928 has an unrecognizable transaction id, then just drop it. */
929 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
930 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
931 (memcmp(packet
->interface
->hw_address
.haddr
,
932 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
935 if (ip
->client
->state
!= S_REBOOTING
&&
936 ip
->client
->state
!= S_REQUESTING
&&
937 ip
->client
->state
!= S_RENEWING
&&
938 ip
->client
->state
!= S_REBINDING
)
941 note("DHCPNAK from %s", piaddr(packet
->client_addr
));
943 if (!ip
->client
->active
) {
944 note("DHCPNAK with no active lease.\n");
948 free_client_lease(ip
->client
->active
);
949 ip
->client
->active
= NULL
;
951 /* Stop sending DHCPREQUEST packets... */
952 cancel_timeout(send_request
, ip
);
954 ip
->client
->state
= S_INIT
;
958 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
959 one after the right interval has expired. If we don't get an offer by
960 the time we reach the panic interval, call the panic function. */
963 send_discover(void *ipp
)
965 struct interface_info
*ip
= ipp
;
966 int interval
, increase
= 1;
969 DH_DbgPrint(MID_TRACE
,("Doing discover on interface %p\n",ip
));
973 /* Figure out how long it's been since we started transmitting. */
974 interval
= cur_time
- ip
->client
->first_sending
;
976 /* If we're past the panic timeout, call the script and tell it
977 we haven't found anything for this interface yet. */
978 if (interval
> ip
->client
->config
->timeout
) {
980 ip
->client
->first_sending
= cur_time
;
983 /* If we're selecting media, try the whole list before doing
984 the exponential backoff, but if we've already received an
985 offer, stop looping, because we obviously have it right. */
986 if (!ip
->client
->offered_leases
&&
987 ip
->client
->config
->media
) {
990 if (ip
->client
->medium
) {
991 ip
->client
->medium
= ip
->client
->medium
->next
;
994 if (!ip
->client
->medium
) {
996 error("No valid media types for %s!", ip
->name
);
997 ip
->client
->medium
= ip
->client
->config
->media
;
1001 note("Trying medium \"%s\" %d", ip
->client
->medium
->string
,
1003 /* XXX Support other media types eventually */
1007 * If we're supposed to increase the interval, do so. If it's
1008 * currently zero (i.e., we haven't sent any packets yet), set
1009 * it to one; otherwise, add to it a random number between zero
1010 * and two times itself. On average, this means that it will
1011 * double with every transmission.
1014 if (!ip
->client
->interval
)
1015 ip
->client
->interval
=
1016 ip
->client
->config
->initial_interval
;
1018 ip
->client
->interval
+= (rand() >> 2) %
1019 (2 * ip
->client
->interval
);
1022 /* Don't backoff past cutoff. */
1023 if (ip
->client
->interval
>
1024 ip
->client
->config
->backoff_cutoff
)
1025 ip
->client
->interval
=
1026 ((ip
->client
->config
->backoff_cutoff
/ 2)
1028 ip
->client
->config
->backoff_cutoff
));
1029 } else if (!ip
->client
->interval
)
1030 ip
->client
->interval
=
1031 ip
->client
->config
->initial_interval
;
1033 /* If the backoff would take us to the panic timeout, just use that
1035 if (cur_time
+ ip
->client
->interval
>
1036 ip
->client
->first_sending
+ ip
->client
->config
->timeout
)
1037 ip
->client
->interval
=
1038 (ip
->client
->first_sending
+
1039 ip
->client
->config
->timeout
) - cur_time
+ 1;
1041 /* Record the number of seconds since we started sending. */
1042 if (interval
< 65536)
1043 ip
->client
->packet
.secs
= htons(interval
);
1045 ip
->client
->packet
.secs
= htons(65535);
1046 ip
->client
->secs
= ip
->client
->packet
.secs
;
1048 note("DHCPDISCOVER on %s to %s port %d interval %ld",
1049 ip
->name
, inet_ntoa(sockaddr_broadcast
.sin_addr
),
1050 ntohs(sockaddr_broadcast
.sin_port
), (long int)ip
->client
->interval
);
1052 /* Send out a packet. */
1053 (void)send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1054 inaddr_any
, &sockaddr_broadcast
, NULL
);
1056 DH_DbgPrint(MID_TRACE
,("discover timeout: now %x -> then %x\n",
1057 cur_time
, cur_time
+ ip
->client
->interval
));
1059 add_timeout(cur_time
+ ip
->client
->interval
, send_discover
, ip
);
1063 * state_panic gets called if we haven't received any offers in a preset
1064 * amount of time. When this happens, we try to use existing leases
1065 * that haven't yet expired, and failing that, we call the client script
1066 * and hope it can do something.
1069 state_panic(void *ipp
)
1071 struct interface_info
*ip
= ipp
;
1072 PDHCP_ADAPTER Adapter
= AdapterFindInfo(ip
);
1074 note("No DHCPOFFERS received.");
1076 if (!Adapter
->NteContext
)
1078 /* Generate an automatic private address */
1079 DbgPrint("DHCPCSVC: Failed to receive a response from a DHCP server. An automatic private address will be assigned.\n");
1081 /* FIXME: The address generation code sucks */
1082 AddIPAddress(htonl(0xA9FE0000 | (rand() % 0xFFFF)), //169.254.X.X
1083 htonl(0xFFFF0000), //255.255.0.0
1084 Adapter
->IfMib
.dwIndex
,
1085 &Adapter
->NteContext
,
1086 &Adapter
->NteInstance
);
1091 send_request(void *ipp
)
1093 struct interface_info
*ip
= ipp
;
1094 struct sockaddr_in destination
;
1095 struct in_addr from
;
1101 /* Figure out how long it's been since we started transmitting. */
1102 interval
= cur_time
- ip
->client
->first_sending
;
1104 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1105 past the reboot timeout, go to INIT and see if we can
1106 DISCOVER an address... */
1107 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1108 means either that we're on a network with no DHCP server,
1109 or that our server is down. In the latter case, assuming
1110 that there is a backup DHCP server, DHCPDISCOVER will get
1111 us a new address, but we could also have successfully
1112 reused our old address. In the former case, we're hosed
1113 anyway. This is not a win-prone situation. */
1114 if ((ip
->client
->state
== S_REBOOTING
||
1115 ip
->client
->state
== S_REQUESTING
) &&
1116 interval
> ip
->client
->config
->reboot_timeout
) {
1117 ip
->client
->state
= S_INIT
;
1118 cancel_timeout(send_request
, ip
);
1123 /* If we're in the reboot state, make sure the media is set up
1125 if (ip
->client
->state
== S_REBOOTING
&&
1126 !ip
->client
->medium
&&
1127 ip
->client
->active
->medium
) {
1128 /* If the medium we chose won't fly, go to INIT state. */
1129 /* XXX Nothing for now */
1131 /* Record the medium. */
1132 ip
->client
->medium
= ip
->client
->active
->medium
;
1135 /* If the lease has expired, relinquish the address and go back
1136 to the INIT state. */
1137 if (ip
->client
->state
!= S_REQUESTING
&&
1138 cur_time
> ip
->client
->active
->expiry
) {
1139 PDHCP_ADAPTER Adapter
= AdapterFindInfo( ip
);
1140 /* Run the client script with the new parameters. */
1141 /* No script actions necessary in the expiry case */
1142 /* Now do a preinit on the interface so that we can
1143 discover a new address. */
1147 DeleteIPAddress( Adapter
->NteContext
);
1148 Adapter
->NteContext
= 0;
1151 ip
->client
->state
= S_INIT
;
1156 /* Do the exponential backoff... */
1157 if (!ip
->client
->interval
)
1158 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
1160 ip
->client
->interval
+= ((rand() >> 2) %
1161 (2 * ip
->client
->interval
));
1163 /* Don't backoff past cutoff. */
1164 if (ip
->client
->interval
>
1165 ip
->client
->config
->backoff_cutoff
)
1166 ip
->client
->interval
=
1167 ((ip
->client
->config
->backoff_cutoff
/ 2) +
1168 ((rand() >> 2) % ip
->client
->interval
));
1170 /* If the backoff would take us to the expiry time, just set the
1171 timeout to the expiry time. */
1172 if (ip
->client
->state
!= S_REQUESTING
&&
1173 cur_time
+ ip
->client
->interval
>
1174 ip
->client
->active
->expiry
)
1175 ip
->client
->interval
=
1176 ip
->client
->active
->expiry
- cur_time
+ 1;
1178 /* If the lease T2 time has elapsed, or if we're not yet bound,
1179 broadcast the DHCPREQUEST rather than unicasting. */
1180 memset(&destination
, 0, sizeof(destination
));
1181 if (ip
->client
->state
== S_REQUESTING
||
1182 ip
->client
->state
== S_REBOOTING
||
1183 cur_time
> ip
->client
->active
->rebind
)
1184 destination
.sin_addr
.s_addr
= INADDR_BROADCAST
;
1186 memcpy(&destination
.sin_addr
.s_addr
,
1187 ip
->client
->destination
.iabuf
,
1188 sizeof(destination
.sin_addr
.s_addr
));
1189 destination
.sin_port
= htons(REMOTE_PORT
);
1190 destination
.sin_family
= AF_INET
;
1191 // destination.sin_len = sizeof(destination);
1193 if (ip
->client
->state
!= S_REQUESTING
)
1194 memcpy(&from
, ip
->client
->active
->address
.iabuf
,
1197 from
.s_addr
= INADDR_ANY
;
1199 /* Record the number of seconds since we started sending. */
1200 if (ip
->client
->state
== S_REQUESTING
)
1201 ip
->client
->packet
.secs
= ip
->client
->secs
;
1203 if (interval
< 65536)
1204 ip
->client
->packet
.secs
= htons(interval
);
1206 ip
->client
->packet
.secs
= htons(65535);
1209 note("DHCPREQUEST on %s to %s port %d", ip
->name
,
1210 inet_ntoa(destination
.sin_addr
), ntohs(destination
.sin_port
));
1212 /* Send out a packet. */
1213 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1214 from
, &destination
, NULL
);
1216 add_timeout(cur_time
+ ip
->client
->interval
, send_request
, ip
);
1220 send_decline(void *ipp
)
1222 struct interface_info
*ip
= ipp
;
1224 note("DHCPDECLINE on %s to %s port %d", ip
->name
,
1225 inet_ntoa(sockaddr_broadcast
.sin_addr
),
1226 ntohs(sockaddr_broadcast
.sin_port
));
1228 /* Send out a packet. */
1229 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1230 inaddr_any
, &sockaddr_broadcast
, NULL
);
1234 make_discover(struct interface_info
*ip
, struct client_lease
*lease
)
1236 unsigned char discover
= DHCPDISCOVER
;
1237 struct tree_cache
*options
[256];
1238 struct tree_cache option_elements
[256];
1240 ULONG foo
= (ULONG
) GetTickCount();
1242 memset(option_elements
, 0, sizeof(option_elements
));
1243 memset(options
, 0, sizeof(options
));
1244 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1246 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1247 i
= DHO_DHCP_MESSAGE_TYPE
;
1248 options
[i
] = &option_elements
[i
];
1249 options
[i
]->value
= &discover
;
1250 options
[i
]->len
= sizeof(discover
);
1251 options
[i
]->buf_size
= sizeof(discover
);
1252 options
[i
]->timeout
= 0xFFFFFFFF;
1254 /* Request the options we want */
1255 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1256 options
[i
] = &option_elements
[i
];
1257 options
[i
]->value
= ip
->client
->config
->requested_options
;
1258 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1259 options
[i
]->buf_size
=
1260 ip
->client
->config
->requested_option_count
;
1261 options
[i
]->timeout
= 0xFFFFFFFF;
1263 /* If we had an address, try to get it again. */
1265 ip
->client
->requested_address
= lease
->address
;
1266 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1267 options
[i
] = &option_elements
[i
];
1268 options
[i
]->value
= lease
->address
.iabuf
;
1269 options
[i
]->len
= lease
->address
.len
;
1270 options
[i
]->buf_size
= lease
->address
.len
;
1271 options
[i
]->timeout
= 0xFFFFFFFF;
1273 ip
->client
->requested_address
.len
= 0;
1275 /* Send any options requested in the config file. */
1276 for (i
= 0; i
< 256; i
++)
1278 ip
->client
->config
->send_options
[i
].data
) {
1279 options
[i
] = &option_elements
[i
];
1281 ip
->client
->config
->send_options
[i
].data
;
1283 ip
->client
->config
->send_options
[i
].len
;
1284 options
[i
]->buf_size
=
1285 ip
->client
->config
->send_options
[i
].len
;
1286 options
[i
]->timeout
= 0xFFFFFFFF;
1289 /* Set up the option buffer... */
1290 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1291 options
, 0, 0, 0, NULL
, 0);
1292 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1293 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1295 ip
->client
->packet
.op
= BOOTREQUEST
;
1296 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1297 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1298 ip
->client
->packet
.hops
= 0;
1299 ip
->client
->packet
.xid
= RtlRandom(&foo
);
1300 ip
->client
->packet
.secs
= 0; /* filled in by send_discover. */
1301 ip
->client
->packet
.flags
= 0;
1303 memset(&(ip
->client
->packet
.ciaddr
),
1304 0, sizeof(ip
->client
->packet
.ciaddr
));
1305 memset(&(ip
->client
->packet
.yiaddr
),
1306 0, sizeof(ip
->client
->packet
.yiaddr
));
1307 memset(&(ip
->client
->packet
.siaddr
),
1308 0, sizeof(ip
->client
->packet
.siaddr
));
1309 memset(&(ip
->client
->packet
.giaddr
),
1310 0, sizeof(ip
->client
->packet
.giaddr
));
1311 memcpy(ip
->client
->packet
.chaddr
,
1312 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1317 make_request(struct interface_info
*ip
, struct client_lease
* lease
)
1319 unsigned char request
= DHCPREQUEST
;
1320 struct tree_cache
*options
[256];
1321 struct tree_cache option_elements
[256];
1324 memset(options
, 0, sizeof(options
));
1325 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1327 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1328 i
= DHO_DHCP_MESSAGE_TYPE
;
1329 options
[i
] = &option_elements
[i
];
1330 options
[i
]->value
= &request
;
1331 options
[i
]->len
= sizeof(request
);
1332 options
[i
]->buf_size
= sizeof(request
);
1333 options
[i
]->timeout
= 0xFFFFFFFF;
1335 /* Request the options we want */
1336 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1337 options
[i
] = &option_elements
[i
];
1338 options
[i
]->value
= ip
->client
->config
->requested_options
;
1339 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1340 options
[i
]->buf_size
=
1341 ip
->client
->config
->requested_option_count
;
1342 options
[i
]->timeout
= 0xFFFFFFFF;
1344 /* If we are requesting an address that hasn't yet been assigned
1345 to us, use the DHCP Requested Address option. */
1346 if (ip
->client
->state
== S_REQUESTING
) {
1347 /* Send back the server identifier... */
1348 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1349 options
[i
] = &option_elements
[i
];
1350 options
[i
]->value
= lease
->options
[i
].data
;
1351 options
[i
]->len
= lease
->options
[i
].len
;
1352 options
[i
]->buf_size
= lease
->options
[i
].len
;
1353 options
[i
]->timeout
= 0xFFFFFFFF;
1355 if (ip
->client
->state
== S_REQUESTING
||
1356 ip
->client
->state
== S_REBOOTING
) {
1357 ip
->client
->requested_address
= lease
->address
;
1358 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1359 options
[i
] = &option_elements
[i
];
1360 options
[i
]->value
= lease
->address
.iabuf
;
1361 options
[i
]->len
= lease
->address
.len
;
1362 options
[i
]->buf_size
= lease
->address
.len
;
1363 options
[i
]->timeout
= 0xFFFFFFFF;
1365 ip
->client
->requested_address
.len
= 0;
1367 /* Send any options requested in the config file. */
1368 for (i
= 0; i
< 256; i
++)
1370 ip
->client
->config
->send_options
[i
].data
) {
1371 options
[i
] = &option_elements
[i
];
1373 ip
->client
->config
->send_options
[i
].data
;
1375 ip
->client
->config
->send_options
[i
].len
;
1376 options
[i
]->buf_size
=
1377 ip
->client
->config
->send_options
[i
].len
;
1378 options
[i
]->timeout
= 0xFFFFFFFF;
1381 /* Set up the option buffer... */
1382 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1383 options
, 0, 0, 0, NULL
, 0);
1384 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1385 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1387 ip
->client
->packet
.op
= BOOTREQUEST
;
1388 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1389 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1390 ip
->client
->packet
.hops
= 0;
1391 ip
->client
->packet
.xid
= ip
->client
->xid
;
1392 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1394 /* If we own the address we're requesting, put it in ciaddr;
1395 otherwise set ciaddr to zero. */
1396 if (ip
->client
->state
== S_BOUND
||
1397 ip
->client
->state
== S_RENEWING
||
1398 ip
->client
->state
== S_REBINDING
) {
1399 memcpy(&ip
->client
->packet
.ciaddr
,
1400 lease
->address
.iabuf
, lease
->address
.len
);
1401 ip
->client
->packet
.flags
= 0;
1403 memset(&ip
->client
->packet
.ciaddr
, 0,
1404 sizeof(ip
->client
->packet
.ciaddr
));
1405 ip
->client
->packet
.flags
= 0;
1408 memset(&ip
->client
->packet
.yiaddr
, 0,
1409 sizeof(ip
->client
->packet
.yiaddr
));
1410 memset(&ip
->client
->packet
.siaddr
, 0,
1411 sizeof(ip
->client
->packet
.siaddr
));
1412 memset(&ip
->client
->packet
.giaddr
, 0,
1413 sizeof(ip
->client
->packet
.giaddr
));
1414 memcpy(ip
->client
->packet
.chaddr
,
1415 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1419 make_decline(struct interface_info
*ip
, struct client_lease
*lease
)
1421 struct tree_cache
*options
[256], message_type_tree
;
1422 struct tree_cache requested_address_tree
;
1423 struct tree_cache server_id_tree
, client_id_tree
;
1424 unsigned char decline
= DHCPDECLINE
;
1427 memset(options
, 0, sizeof(options
));
1428 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1430 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1431 i
= DHO_DHCP_MESSAGE_TYPE
;
1432 options
[i
] = &message_type_tree
;
1433 options
[i
]->value
= &decline
;
1434 options
[i
]->len
= sizeof(decline
);
1435 options
[i
]->buf_size
= sizeof(decline
);
1436 options
[i
]->timeout
= 0xFFFFFFFF;
1438 /* Send back the server identifier... */
1439 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1440 options
[i
] = &server_id_tree
;
1441 options
[i
]->value
= lease
->options
[i
].data
;
1442 options
[i
]->len
= lease
->options
[i
].len
;
1443 options
[i
]->buf_size
= lease
->options
[i
].len
;
1444 options
[i
]->timeout
= 0xFFFFFFFF;
1446 /* Send back the address we're declining. */
1447 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1448 options
[i
] = &requested_address_tree
;
1449 options
[i
]->value
= lease
->address
.iabuf
;
1450 options
[i
]->len
= lease
->address
.len
;
1451 options
[i
]->buf_size
= lease
->address
.len
;
1452 options
[i
]->timeout
= 0xFFFFFFFF;
1454 /* Send the uid if the user supplied one. */
1455 i
= DHO_DHCP_CLIENT_IDENTIFIER
;
1456 if (ip
->client
->config
->send_options
[i
].len
) {
1457 options
[i
] = &client_id_tree
;
1458 options
[i
]->value
= ip
->client
->config
->send_options
[i
].data
;
1459 options
[i
]->len
= ip
->client
->config
->send_options
[i
].len
;
1460 options
[i
]->buf_size
= ip
->client
->config
->send_options
[i
].len
;
1461 options
[i
]->timeout
= 0xFFFFFFFF;
1465 /* Set up the option buffer... */
1466 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1467 options
, 0, 0, 0, NULL
, 0);
1468 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1469 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1471 ip
->client
->packet
.op
= BOOTREQUEST
;
1472 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1473 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1474 ip
->client
->packet
.hops
= 0;
1475 ip
->client
->packet
.xid
= ip
->client
->xid
;
1476 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1477 ip
->client
->packet
.flags
= 0;
1479 /* ciaddr must always be zero. */
1480 memset(&ip
->client
->packet
.ciaddr
, 0,
1481 sizeof(ip
->client
->packet
.ciaddr
));
1482 memset(&ip
->client
->packet
.yiaddr
, 0,
1483 sizeof(ip
->client
->packet
.yiaddr
));
1484 memset(&ip
->client
->packet
.siaddr
, 0,
1485 sizeof(ip
->client
->packet
.siaddr
));
1486 memset(&ip
->client
->packet
.giaddr
, 0,
1487 sizeof(ip
->client
->packet
.giaddr
));
1488 memcpy(ip
->client
->packet
.chaddr
,
1489 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1493 free_client_lease(struct client_lease
*lease
)
1497 if (lease
->server_name
)
1498 free(lease
->server_name
);
1499 if (lease
->filename
)
1500 free(lease
->filename
);
1501 for (i
= 0; i
< 256; i
++) {
1502 if (lease
->options
[i
].len
)
1503 free(lease
->options
[i
].data
);
1511 rewrite_client_leases(struct interface_info
*ifi
)
1513 struct client_lease
*lp
;
1516 leaseFile
= fopen(path_dhclient_db
, "w");
1518 error("can't create %s", path_dhclient_db
);
1524 for (lp
= ifi
->client
->leases
; lp
; lp
= lp
->next
)
1525 write_client_lease(ifi
, lp
, 1);
1526 if (ifi
->client
->active
)
1527 write_client_lease(ifi
, ifi
->client
->active
, 1);
1533 write_client_lease(struct interface_info
*ip
, struct client_lease
*lease
,
1536 static int leases_written
;
1541 if (leases_written
++ > 20) {
1542 rewrite_client_leases(ip
);
1547 /* If the lease came from the config file, we don't need to stash
1548 a copy in the lease database. */
1549 if (lease
->is_static
)
1552 if (!leaseFile
) { /* XXX */
1553 leaseFile
= fopen(path_dhclient_db
, "w");
1555 error("can't create %s", path_dhclient_db
);
1560 fprintf(leaseFile
, "lease {\n");
1561 if (lease
->is_bootp
)
1562 fprintf(leaseFile
, " bootp;\n");
1563 fprintf(leaseFile
, " interface \"%s\";\n", ip
->name
);
1564 fprintf(leaseFile
, " fixed-address %s;\n", piaddr(lease
->address
));
1565 if (lease
->filename
)
1566 fprintf(leaseFile
, " filename \"%s\";\n", lease
->filename
);
1567 if (lease
->server_name
)
1568 fprintf(leaseFile
, " server-name \"%s\";\n",
1569 lease
->server_name
);
1571 fprintf(leaseFile
, " medium \"%s\";\n", lease
->medium
->string
);
1572 for (i
= 0; i
< 256; i
++)
1573 if (lease
->options
[i
].len
)
1574 fprintf(leaseFile
, " option %s %s;\n",
1575 dhcp_options
[i
].name
,
1576 pretty_print_option(i
, lease
->options
[i
].data
,
1577 lease
->options
[i
].len
, 1, 1));
1579 t
= gmtime(&lease
->renewal
);
1581 fprintf(leaseFile
, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1582 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1583 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1584 t
= gmtime(&lease
->rebind
);
1586 fprintf(leaseFile
, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1587 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1588 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1589 t
= gmtime(&lease
->expiry
);
1591 fprintf(leaseFile
, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1592 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1593 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1594 fprintf(leaseFile
, "}\n");
1599 priv_script_init(struct interface_info
*ip
, char *reason
, char *medium
)
1602 // XXX Do we need to do anything?
1607 priv_script_write_params(struct interface_info
*ip
, char *prefix
, struct client_lease
*lease
)
1609 u_int8_t dbuf
[1500];
1613 script_set_env(ip
->client
, prefix
, "ip_address",
1614 piaddr(lease
->address
));
1617 if (lease
->options
[DHO_SUBNET_MASK
].len
&&
1618 (lease
->options
[DHO_SUBNET_MASK
].len
<
1619 sizeof(lease
->address
.iabuf
))) {
1620 struct iaddr netmask
, subnet
, broadcast
;
1622 memcpy(netmask
.iabuf
, lease
->options
[DHO_SUBNET_MASK
].data
,
1623 lease
->options
[DHO_SUBNET_MASK
].len
);
1624 netmask
.len
= lease
->options
[DHO_SUBNET_MASK
].len
;
1626 subnet
= subnet_number(lease
->address
, netmask
);
1629 script_set_env(ip
->client
, prefix
, "network_number",
1632 if (!lease
->options
[DHO_BROADCAST_ADDRESS
].len
) {
1633 broadcast
= broadcast_addr(subnet
, netmask
);
1636 script_set_env(ip
->client
, prefix
,
1637 "broadcast_address",
1647 if (lease
->filename
)
1648 script_set_env(ip
->client
, prefix
, "filename", lease
->filename
);
1649 if (lease
->server_name
)
1650 script_set_env(ip
->client
, prefix
, "server_name",
1651 lease
->server_name
);
1654 for (i
= 0; i
< 256; i
++) {
1655 u_int8_t
*dp
= NULL
;
1657 if (ip
->client
->config
->defaults
[i
].len
) {
1658 if (lease
->options
[i
].len
) {
1660 ip
->client
->config
->default_actions
[i
]) {
1661 case ACTION_DEFAULT
:
1662 dp
= lease
->options
[i
].data
;
1663 len
= lease
->options
[i
].len
;
1665 case ACTION_SUPERSEDE
:
1668 config
->defaults
[i
].data
;
1670 config
->defaults
[i
].len
;
1672 case ACTION_PREPEND
:
1674 config
->defaults
[i
].len
+
1675 lease
->options
[i
].len
;
1676 if (len
>= sizeof(dbuf
)) {
1677 warning("no space to %s %s",
1679 dhcp_options
[i
].name
);
1685 config
->defaults
[i
].data
,
1687 config
->defaults
[i
].len
);
1688 memcpy(dp
+ ip
->client
->
1689 config
->defaults
[i
].len
,
1690 lease
->options
[i
].data
,
1691 lease
->options
[i
].len
);
1696 config
->defaults
[i
].len
+
1697 lease
->options
[i
].len
+ 1;
1698 if (len
> sizeof(dbuf
)) {
1699 warning("no space to %s %s",
1701 dhcp_options
[i
].name
);
1706 lease
->options
[i
].data
,
1707 lease
->options
[i
].len
);
1708 memcpy(dp
+ lease
->options
[i
].len
,
1710 config
->defaults
[i
].data
,
1712 config
->defaults
[i
].len
);
1717 config
->defaults
[i
].data
;
1719 config
->defaults
[i
].len
;
1721 } else if (lease
->options
[i
].len
) {
1722 len
= lease
->options
[i
].len
;
1723 dp
= lease
->options
[i
].data
;
1731 if (dhcp_option_ev_name(name
, sizeof(name
),
1733 script_set_env(ip
->client
, prefix
, name
,
1734 pretty_print_option(i
, dp
, len
, 0, 0));
1739 snprintf(tbuf
, sizeof(tbuf
), "%d", (int)lease
->expiry
);
1740 script_set_env(ip
->client
, prefix
, "expiry", tbuf
);
1745 dhcp_option_ev_name(char *buf
, size_t buflen
, struct dhcp_option
*option
)
1749 for (i
= 0; option
->name
[i
]; i
++) {
1750 if (i
+ 1 == buflen
)
1752 if (option
->name
[i
] == '-')
1755 buf
[i
] = option
->name
[i
];
1766 static int state
= 0;
1768 if (no_daemon
|| state
)
1773 /* Stop logging to stderr... */
1776 if (daemon(1, 0) == -1)
1779 /* we are chrooted, daemon(3) fails to open /dev/null */
1781 dup2(nullfd
, STDIN_FILENO
);
1782 dup2(nullfd
, STDOUT_FILENO
);
1783 dup2(nullfd
, STDERR_FILENO
);
1791 check_option(struct client_lease
*l
, int option
)
1796 /* we use this, since this is what gets passed to dhclient-script */
1798 opbuf
= pretty_print_option(option
, l
->options
[option
].data
,
1799 l
->options
[option
].len
, 0, 0);
1801 sbuf
= option_as_string(option
, l
->options
[option
].data
,
1802 l
->options
[option
].len
);
1805 case DHO_SUBNET_MASK
:
1806 case DHO_TIME_SERVERS
:
1807 case DHO_NAME_SERVERS
:
1809 case DHO_DOMAIN_NAME_SERVERS
:
1810 case DHO_LOG_SERVERS
:
1811 case DHO_COOKIE_SERVERS
:
1812 case DHO_LPR_SERVERS
:
1813 case DHO_IMPRESS_SERVERS
:
1814 case DHO_RESOURCE_LOCATION_SERVERS
:
1815 case DHO_SWAP_SERVER
:
1816 case DHO_BROADCAST_ADDRESS
:
1817 case DHO_NIS_SERVERS
:
1818 case DHO_NTP_SERVERS
:
1819 case DHO_NETBIOS_NAME_SERVERS
:
1820 case DHO_NETBIOS_DD_SERVER
:
1821 case DHO_FONT_SERVERS
:
1822 case DHO_DHCP_SERVER_IDENTIFIER
:
1823 if (!ipv4addrs(opbuf
)) {
1824 warning("Invalid IP address in option(%d): %s", option
, opbuf
);
1829 case DHO_DOMAIN_NAME
:
1830 case DHO_NIS_DOMAIN
:
1831 if (!res_hnok(sbuf
))
1832 warning("Bogus Host Name option %d: %s (%s)", option
,
1836 case DHO_TIME_OFFSET
:
1838 case DHO_MERIT_DUMP
:
1840 case DHO_EXTENSIONS_PATH
:
1841 case DHO_IP_FORWARDING
:
1842 case DHO_NON_LOCAL_SOURCE_ROUTING
:
1843 case DHO_POLICY_FILTER
:
1844 case DHO_MAX_DGRAM_REASSEMBLY
:
1845 case DHO_DEFAULT_IP_TTL
:
1846 case DHO_PATH_MTU_AGING_TIMEOUT
:
1847 case DHO_PATH_MTU_PLATEAU_TABLE
:
1848 case DHO_INTERFACE_MTU
:
1849 case DHO_ALL_SUBNETS_LOCAL
:
1850 case DHO_PERFORM_MASK_DISCOVERY
:
1851 case DHO_MASK_SUPPLIER
:
1852 case DHO_ROUTER_DISCOVERY
:
1853 case DHO_ROUTER_SOLICITATION_ADDRESS
:
1854 case DHO_STATIC_ROUTES
:
1855 case DHO_TRAILER_ENCAPSULATION
:
1856 case DHO_ARP_CACHE_TIMEOUT
:
1857 case DHO_IEEE802_3_ENCAPSULATION
:
1858 case DHO_DEFAULT_TCP_TTL
:
1859 case DHO_TCP_KEEPALIVE_INTERVAL
:
1860 case DHO_TCP_KEEPALIVE_GARBAGE
:
1861 case DHO_VENDOR_ENCAPSULATED_OPTIONS
:
1862 case DHO_NETBIOS_NODE_TYPE
:
1863 case DHO_NETBIOS_SCOPE
:
1864 case DHO_X_DISPLAY_MANAGER
:
1865 case DHO_DHCP_REQUESTED_ADDRESS
:
1866 case DHO_DHCP_LEASE_TIME
:
1867 case DHO_DHCP_OPTION_OVERLOAD
:
1868 case DHO_DHCP_MESSAGE_TYPE
:
1869 case DHO_DHCP_PARAMETER_REQUEST_LIST
:
1870 case DHO_DHCP_MESSAGE
:
1871 case DHO_DHCP_MAX_MESSAGE_SIZE
:
1872 case DHO_DHCP_RENEWAL_TIME
:
1873 case DHO_DHCP_REBINDING_TIME
:
1874 case DHO_DHCP_CLASS_IDENTIFIER
:
1875 case DHO_DHCP_CLIENT_IDENTIFIER
:
1876 case DHO_DHCP_USER_CLASS_ID
:
1880 warning("unknown dhcp option value 0x%x", option
);
1881 return (unknown_ok
);
1886 res_hnok(const char *dn
)
1888 int pch
= PERIOD
, ch
= *dn
++;
1890 while (ch
!= '\0') {
1893 if (periodchar(ch
)) {
1895 } else if (periodchar(pch
)) {
1896 if (!borderchar(ch
))
1898 } else if (periodchar(nch
) || nch
== '\0') {
1899 if (!borderchar(ch
))
1902 if (!middlechar(ch
))
1910 /* Does buf consist only of dotted decimal ipv4 addrs?
1911 * return how many if so,
1912 * otherwise, return 0
1915 ipv4addrs(char * buf
)
1921 note("Input: %s", buf
);
1924 tmp
= strtok(buf
, " ");
1925 note("got %s", tmp
);
1926 if( tmp
&& inet_aton(tmp
, &jnk
) ) i
++;
1935 option_as_string(unsigned int code
, unsigned char *data
, int len
)
1937 static char optbuf
[32768]; /* XXX */
1939 int opleft
= sizeof(optbuf
);
1940 unsigned char *dp
= data
;
1943 error("option_as_string: bad code %d", code
);
1945 for (; dp
< data
+ len
; dp
++) {
1946 if (!isascii(*dp
) || !isprint(*dp
)) {
1947 if (dp
+ 1 != data
+ len
|| *dp
!= 0) {
1948 _snprintf(op
, opleft
, "\\%03o", *dp
);
1952 } else if (*dp
== '"' || *dp
== '\'' || *dp
== '$' ||
1953 *dp
== '`' || *dp
== '\\') {
1967 warning("dhcp option too large");