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
62 #define hyphenchar(c) ((c) == 0x2d)
63 #define bslashchar(c) ((c) == 0x5c)
64 #define periodchar(c) ((c) == PERIOD)
65 #define asterchar(c) ((c) == 0x2a)
66 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
67 ((c) >= 0x61 && (c) <= 0x7a))
68 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
70 #define borderchar(c) (alphachar(c) || digitchar(c))
71 #define middlechar(c) (borderchar(c) || hyphenchar(c))
72 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
74 unsigned long debug_trace_level
= 0; /* DEBUG_ULTRA */
76 time_t default_lease_time
= 43200; /* 12 hours... */
78 char *path_dhclient_conf
= _PATH_DHCLIENT_CONF
;
79 char *path_dhclient_db
= NULL
;
85 struct iaddr iaddr_broadcast
= { 4, { 255, 255, 255, 255 } };
86 struct in_addr inaddr_any
;
87 struct sockaddr_in sockaddr_broadcast
;
88 unsigned long old_default_route
= 0;
91 * ASSERT_STATE() does nothing now; it used to be
92 * assert (state_is == state_shouldbe).
94 #define ASSERT_STATE(state_is, state_shouldbe) {}
96 #define TIME_MAX 2147483647
103 struct interface_info
*ifi
= NULL
;
106 int check_option(struct client_lease
*l
, int option
);
107 int ipv4addrs(char * buf
);
108 int res_hnok(const char *dn
);
109 char *option_as_string(unsigned int code
, unsigned char *data
, int len
);
110 int fork_privchld(int, int);
111 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
);
113 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
117 /* XXX Implement me */
118 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
) {
123 main(int argc
, char *argv
[])
133 memset(&sockaddr_broadcast
, 0, sizeof(sockaddr_broadcast
));
134 sockaddr_broadcast
.sin_family
= AF_INET
;
135 sockaddr_broadcast
.sin_port
= htons(REMOTE_PORT
);
136 sockaddr_broadcast
.sin_addr
.s_addr
= INADDR_BROADCAST
;
137 inaddr_any
.s_addr
= INADDR_ANY
;
139 DH_DbgPrint(MID_TRACE
,("DHCP Service Started\n"));
143 if (!interface_link_status(ifi
->name
)) {
144 DH_DbgPrint(MID_TRACE
,("%s: no link ", ifi
->name
));
146 while (!interface_link_status(ifi
->name
)) {
147 DH_DbgPrint(MID_TRACE
,("."));
149 DH_DbgPrint(MID_TRACE
,("Giving up for now on adapter [%s]\n", ifi
->name
));
153 DH_DbgPrint(MID_TRACE
,("Got link on [%s]\n", ifi
->name
));
156 DH_DbgPrint(MID_TRACE
,("Discover Interfaces\n"));
158 /* If no adapters were found, just idle for now ... If any show up,
159 * then we'll start it later */
161 /* set up the interface */
162 discover_interfaces(ifi
);
166 ("Setting init state and restarting interface %p\n",ifi
));
169 bootp_packet_handler
= do_packet
;
171 DH_DbgPrint(MID_TRACE
,("Going into dispatch()\n"));
182 // extern char *__progname;
184 // fprintf(stderr, "usage: %s [-dqu] ", __progname);
185 fprintf(stderr
, "usage: dhclient [-dqu] ");
186 fprintf(stderr
, "[-c conffile] [-l leasefile] interface\n");
193 * Each routine is called from the dhclient_state_machine() in one of
195 * -> entering INIT state
196 * -> recvpacket_flag == 0: timeout in this state
197 * -> otherwise: received a packet in this state
199 * Return conditions as handled by dhclient_state_machine():
200 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
201 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
202 * Returns 0: finish the nap which was interrupted for no good reason.
204 * Several per-interface variables are used to keep track of the process:
205 * active_lease: the lease that is being used on the interface
206 * (null pointer if not configured yet).
207 * offered_leases: leases corresponding to DHCPOFFER messages that have
208 * been sent to us by DHCP servers.
209 * acked_leases: leases corresponding to DHCPACK messages that have been
210 * sent to us by DHCP servers.
211 * sendpacket: DHCP packet we're trying to send.
212 * destination: IP address to send sendpacket to
213 * In addition, there are several relevant per-lease variables.
214 * T1_expiry, T2_expiry, lease_expiry: lease milestones
215 * In the active lease, these control the process of renewing the lease;
216 * In leases on the acked_leases list, this simply determines when we
217 * can no longer legitimately use the lease.
221 state_reboot(void *ipp
)
223 struct interface_info
*ip
= ipp
;
225 /* If we don't remember an active lease, go straight to INIT. */
226 if (!ip
->client
->active
|| ip
->client
->active
->is_bootp
) {
231 /* We are in the rebooting state. */
232 ip
->client
->state
= S_REBOOTING
;
234 /* make_request doesn't initialize xid because it normally comes
235 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
236 so pick an xid now. */
237 ip
->client
->xid
= rand();
239 /* Make a DHCPREQUEST packet, and set appropriate per-interface
241 make_request(ip
, ip
->client
->active
);
242 ip
->client
->destination
= iaddr_broadcast
;
243 ip
->client
->first_sending
= cur_time
;
244 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
246 /* Zap the medium list... */
247 ip
->client
->medium
= NULL
;
249 /* Send out the first DHCPREQUEST packet. */
254 * Called when a lease has completely expired and we've
255 * been unable to renew it.
258 state_init(void *ipp
)
260 struct interface_info
*ip
= ipp
;
262 ASSERT_STATE(state
, S_INIT
);
264 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
266 make_discover(ip
, ip
->client
->active
);
267 ip
->client
->xid
= ip
->client
->packet
.xid
;
268 ip
->client
->destination
= iaddr_broadcast
;
269 ip
->client
->state
= S_SELECTING
;
270 ip
->client
->first_sending
= cur_time
;
271 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
273 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
279 * state_selecting is called when one or more DHCPOFFER packets
280 * have been received and a configurable period of time has passed.
283 state_selecting(void *ipp
)
285 struct interface_info
*ip
= ipp
;
286 struct client_lease
*lp
, *next
, *picked
;
288 ASSERT_STATE(state
, S_SELECTING
);
290 /* Cancel state_selecting and send_discover timeouts, since either
291 one could have got us here. */
292 cancel_timeout(state_selecting
, ip
);
293 cancel_timeout(send_discover
, ip
);
295 /* We have received one or more DHCPOFFER packets. Currently,
296 the only criterion by which we judge leases is whether or
297 not we get a response when we arp for them. */
299 for (lp
= ip
->client
->offered_leases
; lp
; lp
= next
) {
302 /* Check to see if we got an ARPREPLY for the address
303 in this particular lease. */
305 if( !check_arp(ip
,lp
) ) goto freeit
;
310 free_client_lease(lp
);
313 ip
->client
->offered_leases
= NULL
;
315 /* If we just tossed all the leases we were offered, go back
318 ip
->client
->state
= S_INIT
;
323 /* If it was a BOOTREPLY, we can just take the address right now. */
324 if (!picked
->options
[DHO_DHCP_MESSAGE_TYPE
].len
) {
325 ip
->client
->new = picked
;
327 /* Make up some lease expiry times
328 XXX these should be configurable. */
329 ip
->client
->new->expiry
= cur_time
+ 12000;
330 ip
->client
->new->renewal
+= cur_time
+ 8000;
331 ip
->client
->new->rebind
+= cur_time
+ 10000;
333 ip
->client
->state
= S_REQUESTING
;
335 /* Bind to the address we received. */
340 /* Go to the REQUESTING state. */
341 ip
->client
->destination
= iaddr_broadcast
;
342 ip
->client
->state
= S_REQUESTING
;
343 ip
->client
->first_sending
= cur_time
;
344 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
346 /* Make a DHCPREQUEST packet from the lease we picked. */
347 make_request(ip
, picked
);
348 ip
->client
->xid
= ip
->client
->packet
.xid
;
350 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
351 free_client_lease(picked
);
353 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
357 /* state_requesting is called when we receive a DHCPACK message after
358 having sent out one or more DHCPREQUEST packets. */
361 dhcpack(struct packet
*packet
)
363 struct interface_info
*ip
= packet
->interface
;
364 struct client_lease
*lease
;
366 /* If we're not receptive to an offer right now, or if the offer
367 has an unrecognizable transaction id, then just drop it. */
368 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
369 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
370 (memcmp(packet
->interface
->hw_address
.haddr
,
371 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
374 if (ip
->client
->state
!= S_REBOOTING
&&
375 ip
->client
->state
!= S_REQUESTING
&&
376 ip
->client
->state
!= S_RENEWING
&&
377 ip
->client
->state
!= S_REBINDING
)
380 note("DHCPACK from %s", piaddr(packet
->client_addr
));
382 lease
= packet_to_lease(packet
);
384 note("packet_to_lease failed.");
388 ip
->client
->new = lease
;
390 /* Stop resending DHCPREQUEST. */
391 cancel_timeout(send_request
, ip
);
393 /* Figure out the lease time. */
394 if (ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
)
395 ip
->client
->new->expiry
= getULong(
396 ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
);
398 ip
->client
->new->expiry
= default_lease_time
;
399 /* A number that looks negative here is really just very large,
400 because the lease expiry offset is unsigned. */
401 if (ip
->client
->new->expiry
< 0)
402 ip
->client
->new->expiry
= TIME_MAX
;
403 /* XXX should be fixed by resetting the client state */
404 if (ip
->client
->new->expiry
< 60)
405 ip
->client
->new->expiry
= 60;
407 /* Take the server-provided renewal time if there is one;
408 otherwise figure it out according to the spec. */
409 if (ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].len
)
410 ip
->client
->new->renewal
= getULong(
411 ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].data
);
413 ip
->client
->new->renewal
= ip
->client
->new->expiry
/ 2;
415 /* Same deal with the rebind time. */
416 if (ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].len
)
417 ip
->client
->new->rebind
= getULong(
418 ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].data
);
420 ip
->client
->new->rebind
= ip
->client
->new->renewal
+
421 ip
->client
->new->renewal
/ 2 + ip
->client
->new->renewal
/ 4;
423 ip
->client
->new->expiry
+= cur_time
;
424 /* Lease lengths can never be negative. */
425 if (ip
->client
->new->expiry
< cur_time
)
426 ip
->client
->new->expiry
= TIME_MAX
;
427 ip
->client
->new->renewal
+= cur_time
;
428 if (ip
->client
->new->renewal
< cur_time
)
429 ip
->client
->new->renewal
= TIME_MAX
;
430 ip
->client
->new->rebind
+= cur_time
;
431 if (ip
->client
->new->rebind
< cur_time
)
432 ip
->client
->new->rebind
= TIME_MAX
;
437 void set_name_servers( struct client_lease
*new_lease
) {
438 if( new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
) {
440 struct iaddr nameserver
;
443 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
/ sizeof(ULONG
);
445 /* XXX I'm setting addrs to 1 until we are ready up the chain */
447 nsbuf
= malloc( addrs
* sizeof(IP_ADDRESS_STRING
) );
450 if( nsbuf
&& !RegOpenKeyEx
451 ( HKEY_LOCAL_MACHINE
,
452 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
453 0, KEY_WRITE
, &RegKey
) ) {
454 for( i
= 0; i
< addrs
; i
++ ) {
455 nameserver
.len
= sizeof(ULONG
);
456 memcpy( nameserver
.iabuf
,
457 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].data
+
458 (i
* sizeof(ULONG
)), sizeof(ULONG
) );
459 strcat( nsbuf
, piaddr(nameserver
) );
460 if( i
!= addrs
-1 ) strcat( nsbuf
, "," );
463 DH_DbgPrint(MID_TRACE
,("Setting Nameservers: %s\n", nsbuf
));
465 /* XXX Fixme: I think this may be wrong and that we might have
466 * a problem somewhere else (in iphlpapi for example).
468 * Recheck the +1 below.
470 RegSetValueEx( RegKey
, "NameServer", 0, REG_SZ
,
471 (LPBYTE
)nsbuf
, strlen(nsbuf
) + 1 );
478 void setup_adapter( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
479 struct iaddr netmask
;
481 if( Adapter
->NteContext
)
482 DeleteIPAddress( Adapter
->NteContext
);
484 /* Set up our default router if we got one from the DHCP server */
485 if( new_lease
->options
[DHO_SUBNET_MASK
].len
) {
488 memcpy( netmask
.iabuf
,
489 new_lease
->options
[DHO_SUBNET_MASK
].data
,
490 new_lease
->options
[DHO_SUBNET_MASK
].len
);
492 Status
= AddIPAddress
493 ( *((ULONG
*)new_lease
->address
.iabuf
),
494 *((ULONG
*)netmask
.iabuf
),
495 Adapter
->IfMib
.dwIndex
,
496 &Adapter
->NteContext
,
497 &Adapter
->NteInstance
);
499 if( !NT_SUCCESS(Status
) )
500 warning("AddIPAddress: %lx\n", Status
);
503 if( new_lease
->options
[DHO_ROUTERS
].len
) {
504 MIB_IPFORWARDROW RouterMib
;
507 RouterMib
.dwForwardDest
= 0; /* Default route */
508 RouterMib
.dwForwardMask
= 0;
509 RouterMib
.dwForwardMetric1
= 1;
511 if( old_default_route
) {
512 /* If we set a default route before, delete it before continuing */
513 RouterMib
.dwForwardDest
= old_default_route
;
514 DeleteIpForwardEntry( &RouterMib
);
517 RouterMib
.dwForwardNextHop
=
518 *((ULONG
*)new_lease
->options
[DHO_ROUTERS
].data
);
520 Status
= CreateIpForwardEntry( &RouterMib
);
522 if( !NT_SUCCESS(Status
) )
523 warning("CreateIpForwardEntry: %lx\n", Status
);
525 old_default_route
= RouterMib
.dwForwardNextHop
;
531 bind_lease(struct interface_info
*ip
)
533 PDHCP_ADAPTER Adapter
;
534 struct client_lease
*new_lease
= ip
->client
->new;
536 /* Remember the medium. */
537 ip
->client
->new->medium
= ip
->client
->medium
;
538 ip
->client
->active
= ip
->client
->new;
539 ip
->client
->new = NULL
;
541 /* Set up a timeout to start the renewal process. */
542 /* Timeout of zero means no timeout (some implementations seem to use
545 if( ip
->client
->active
->renewal
- cur_time
)
546 add_timeout(ip
->client
->active
->renewal
, state_bound
, ip
);
548 note("bound to %s -- renewal in %ld seconds.",
549 piaddr(ip
->client
->active
->address
),
550 ip
->client
->active
->renewal
- cur_time
);
552 ip
->client
->state
= S_BOUND
;
554 Adapter
= AdapterFindInfo( ip
);
556 if( Adapter
) setup_adapter( Adapter
, new_lease
);
557 else warning("Could not find adapter for info %p\n", ip
);
559 set_name_servers( new_lease
);
561 reinitialize_interfaces();
565 * state_bound is called when we've successfully bound to a particular
566 * lease, but the renewal time on that lease has expired. We are
567 * expected to unicast a DHCPREQUEST to the server that gave us our
571 state_bound(void *ipp
)
573 struct interface_info
*ip
= ipp
;
575 ASSERT_STATE(state
, S_BOUND
);
577 /* T1 has expired. */
578 make_request(ip
, ip
->client
->active
);
579 ip
->client
->xid
= ip
->client
->packet
.xid
;
581 if (ip
->client
->active
->options
[DHO_DHCP_SERVER_IDENTIFIER
].len
== 4) {
582 memcpy(ip
->client
->destination
.iabuf
, ip
->client
->active
->
583 options
[DHO_DHCP_SERVER_IDENTIFIER
].data
, 4);
584 ip
->client
->destination
.len
= 4;
586 ip
->client
->destination
= iaddr_broadcast
;
588 ip
->client
->first_sending
= cur_time
;
589 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
590 ip
->client
->state
= S_RENEWING
;
592 /* Send the first packet immediately. */
597 bootp(struct packet
*packet
)
599 struct iaddrlist
*ap
;
601 if (packet
->raw
->op
!= BOOTREPLY
)
604 /* If there's a reject list, make sure this packet's sender isn't
606 for (ap
= packet
->interface
->client
->config
->reject_list
;
608 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
609 note("BOOTREPLY from %s rejected.", piaddr(ap
->addr
));
617 dhcp(struct packet
*packet
)
619 struct iaddrlist
*ap
;
620 void (*handler
)(struct packet
*);
623 switch (packet
->packet_type
) {
640 /* If there's a reject list, make sure this packet's sender isn't
642 for (ap
= packet
->interface
->client
->config
->reject_list
;
644 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
645 note("%s from %s rejected.", type
, piaddr(ap
->addr
));
653 dhcpoffer(struct packet
*packet
)
655 struct interface_info
*ip
= packet
->interface
;
656 struct client_lease
*lease
, *lp
;
658 int arp_timeout_needed
= 0, stop_selecting
;
659 char *name
= packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
?
660 "DHCPOFFER" : "BOOTREPLY";
662 /* If we're not receptive to an offer right now, or if the offer
663 has an unrecognizable transaction id, then just drop it. */
664 if (ip
->client
->state
!= S_SELECTING
||
665 packet
->interface
->client
->xid
!= packet
->raw
->xid
||
666 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
667 (memcmp(packet
->interface
->hw_address
.haddr
,
668 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
671 note("%s from %s", name
, piaddr(packet
->client_addr
));
674 /* If this lease doesn't supply the minimum required parameters,
676 for (i
= 0; ip
->client
->config
->required_options
[i
]; i
++) {
677 if (!packet
->options
[ip
->client
->config
->
678 required_options
[i
]].len
) {
679 note("%s isn't satisfactory.", name
);
684 /* If we've already seen this lease, don't record it again. */
685 for (lease
= ip
->client
->offered_leases
;
686 lease
; lease
= lease
->next
) {
687 if (lease
->address
.len
== sizeof(packet
->raw
->yiaddr
) &&
688 !memcmp(lease
->address
.iabuf
,
689 &packet
->raw
->yiaddr
, lease
->address
.len
)) {
690 debug("%s already seen.", name
);
695 lease
= packet_to_lease(packet
);
697 note("packet_to_lease failed.");
701 /* If this lease was acquired through a BOOTREPLY, record that
703 if (!packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
)
706 /* Record the medium under which this lease was offered. */
707 lease
->medium
= ip
->client
->medium
;
709 /* Send out an ARP Request for the offered IP address. */
710 if( !check_arp( ip
, lease
) ) {
711 note("Arp check failed\n");
715 /* Figure out when we're supposed to stop selecting. */
717 ip
->client
->first_sending
+ ip
->client
->config
->select_interval
;
719 /* If this is the lease we asked for, put it at the head of the
720 list, and don't mess with the arp request timeout. */
721 if (lease
->address
.len
== ip
->client
->requested_address
.len
&&
722 !memcmp(lease
->address
.iabuf
,
723 ip
->client
->requested_address
.iabuf
,
724 ip
->client
->requested_address
.len
)) {
725 lease
->next
= ip
->client
->offered_leases
;
726 ip
->client
->offered_leases
= lease
;
728 /* If we already have an offer, and arping for this
729 offer would take us past the selection timeout,
730 then don't extend the timeout - just hope for the
732 if (ip
->client
->offered_leases
&&
733 (cur_time
+ arp_timeout_needed
) > stop_selecting
)
734 arp_timeout_needed
= 0;
736 /* Put the lease at the end of the list. */
738 if (!ip
->client
->offered_leases
)
739 ip
->client
->offered_leases
= lease
;
741 for (lp
= ip
->client
->offered_leases
; lp
->next
;
748 /* If we're supposed to stop selecting before we've had time
749 to wait for the ARPREPLY, add some delay to wait for
751 if (stop_selecting
- cur_time
< arp_timeout_needed
)
752 stop_selecting
= cur_time
+ arp_timeout_needed
;
754 /* If the selecting interval has expired, go immediately to
755 state_selecting(). Otherwise, time out into
756 state_selecting at the select interval. */
757 if (stop_selecting
<= 0)
760 add_timeout(stop_selecting
, state_selecting
, ip
);
761 cancel_timeout(send_discover
, ip
);
765 /* Allocate a client_lease structure and initialize it from the parameters
766 in the specified packet. */
768 struct client_lease
*
769 packet_to_lease(struct packet
*packet
)
771 struct client_lease
*lease
;
774 lease
= malloc(sizeof(struct client_lease
));
777 warning("dhcpoffer: no memory to record lease.");
781 memset(lease
, 0, sizeof(*lease
));
783 /* Copy the lease options. */
784 for (i
= 0; i
< 256; i
++) {
785 if (packet
->options
[i
].len
) {
786 lease
->options
[i
].data
=
787 malloc(packet
->options
[i
].len
+ 1);
788 if (!lease
->options
[i
].data
) {
789 warning("dhcpoffer: no memory for option %d", i
);
790 free_client_lease(lease
);
793 memcpy(lease
->options
[i
].data
,
794 packet
->options
[i
].data
,
795 packet
->options
[i
].len
);
796 lease
->options
[i
].len
=
797 packet
->options
[i
].len
;
798 lease
->options
[i
].data
[lease
->options
[i
].len
] =
801 if (!check_option(lease
,i
)) {
802 /* ignore a bogus lease offer */
803 warning("Invalid lease option - ignoring offer");
804 free_client_lease(lease
);
810 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
811 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
, lease
->address
.len
);
813 /* If the server name was filled out, copy it. */
814 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
815 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 2)) &&
816 packet
->raw
->sname
[0]) {
817 lease
->server_name
= malloc(DHCP_SNAME_LEN
+ 1);
818 if (!lease
->server_name
) {
819 warning("dhcpoffer: no memory for server name.");
820 free_client_lease(lease
);
823 memcpy(lease
->server_name
, packet
->raw
->sname
, DHCP_SNAME_LEN
);
824 lease
->server_name
[DHCP_SNAME_LEN
]='\0';
825 if (!res_hnok(lease
->server_name
) ) {
826 warning("Bogus server name %s", lease
->server_name
);
827 free_client_lease(lease
);
833 /* Ditto for the filename. */
834 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
835 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 1)) &&
836 packet
->raw
->file
[0]) {
837 /* Don't count on the NUL terminator. */
838 lease
->filename
= malloc(DHCP_FILE_LEN
+ 1);
839 if (!lease
->filename
) {
840 warning("dhcpoffer: no memory for filename.");
841 free_client_lease(lease
);
844 memcpy(lease
->filename
, packet
->raw
->file
, DHCP_FILE_LEN
);
845 lease
->filename
[DHCP_FILE_LEN
]='\0';
851 dhcpnak(struct packet
*packet
)
853 struct interface_info
*ip
= packet
->interface
;
855 /* If we're not receptive to an offer right now, or if the offer
856 has an unrecognizable transaction id, then just drop it. */
857 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
858 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
859 (memcmp(packet
->interface
->hw_address
.haddr
,
860 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
863 if (ip
->client
->state
!= S_REBOOTING
&&
864 ip
->client
->state
!= S_REQUESTING
&&
865 ip
->client
->state
!= S_RENEWING
&&
866 ip
->client
->state
!= S_REBINDING
)
869 note("DHCPNAK from %s", piaddr(packet
->client_addr
));
871 if (!ip
->client
->active
) {
872 note("DHCPNAK with no active lease.\n");
876 free_client_lease(ip
->client
->active
);
877 ip
->client
->active
= NULL
;
879 /* Stop sending DHCPREQUEST packets... */
880 cancel_timeout(send_request
, ip
);
882 ip
->client
->state
= S_INIT
;
886 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
887 one after the right interval has expired. If we don't get an offer by
888 the time we reach the panic interval, call the panic function. */
891 send_discover(void *ipp
)
893 struct interface_info
*ip
= ipp
;
894 int interval
, increase
= 1;
896 DH_DbgPrint(MID_TRACE
,("Doing discover on interface %p\n",ip
));
898 /* Figure out how long it's been since we started transmitting. */
899 interval
= cur_time
- ip
->client
->first_sending
;
901 /* If we're past the panic timeout, call the script and tell it
902 we haven't found anything for this interface yet. */
903 if (interval
> ip
->client
->config
->timeout
) {
908 /* If we're selecting media, try the whole list before doing
909 the exponential backoff, but if we've already received an
910 offer, stop looping, because we obviously have it right. */
911 if (!ip
->client
->offered_leases
&&
912 ip
->client
->config
->media
) {
915 if (ip
->client
->medium
) {
916 ip
->client
->medium
= ip
->client
->medium
->next
;
919 if (!ip
->client
->medium
) {
921 error("No valid media types for %s!", ip
->name
);
922 ip
->client
->medium
= ip
->client
->config
->media
;
926 note("Trying medium \"%s\" %d", ip
->client
->medium
->string
,
928 /* XXX Support other media types eventually */
932 * If we're supposed to increase the interval, do so. If it's
933 * currently zero (i.e., we haven't sent any packets yet), set
934 * it to one; otherwise, add to it a random number between zero
935 * and two times itself. On average, this means that it will
936 * double with every transmission.
939 if (!ip
->client
->interval
)
940 ip
->client
->interval
=
941 ip
->client
->config
->initial_interval
;
943 ip
->client
->interval
+= (rand() >> 2) %
944 (2 * ip
->client
->interval
);
947 /* Don't backoff past cutoff. */
948 if (ip
->client
->interval
>
949 ip
->client
->config
->backoff_cutoff
)
950 ip
->client
->interval
=
951 ((ip
->client
->config
->backoff_cutoff
/ 2)
953 ip
->client
->config
->backoff_cutoff
));
954 } else if (!ip
->client
->interval
)
955 ip
->client
->interval
=
956 ip
->client
->config
->initial_interval
;
958 /* If the backoff would take us to the panic timeout, just use that
960 if (cur_time
+ ip
->client
->interval
>
961 ip
->client
->first_sending
+ ip
->client
->config
->timeout
)
962 ip
->client
->interval
=
963 (ip
->client
->first_sending
+
964 ip
->client
->config
->timeout
) - cur_time
+ 1;
966 /* Record the number of seconds since we started sending. */
967 if (interval
< 65536)
968 ip
->client
->packet
.secs
= htons(interval
);
970 ip
->client
->packet
.secs
= htons(65535);
971 ip
->client
->secs
= ip
->client
->packet
.secs
;
973 note("DHCPDISCOVER on %s to %s port %d interval %ld",
974 ip
->name
, inet_ntoa(sockaddr_broadcast
.sin_addr
),
975 ntohs(sockaddr_broadcast
.sin_port
), ip
->client
->interval
);
977 /* Send out a packet. */
978 (void)send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
979 inaddr_any
, &sockaddr_broadcast
, NULL
);
981 DH_DbgPrint(MID_TRACE
,("discover timeout: now %x -> then %x\n",
982 cur_time
, cur_time
+ ip
->client
->interval
));
984 add_timeout(cur_time
+ ip
->client
->interval
, send_discover
, ip
);
988 * state_panic gets called if we haven't received any offers in a preset
989 * amount of time. When this happens, we try to use existing leases
990 * that haven't yet expired, and failing that, we call the client script
991 * and hope it can do something.
994 state_panic(void *ipp
)
996 struct interface_info
*ip
= ipp
;
997 struct client_lease
*loop
= ip
->client
->active
;
998 struct client_lease
*lp
;
1000 note("No DHCPOFFERS received.");
1002 /* We may not have an active lease, but we may have some
1003 predefined leases that we can try. */
1004 if (!ip
->client
->active
&& ip
->client
->leases
)
1007 /* Run through the list of leases and see if one can be used. */
1008 while (ip
->client
->active
) {
1009 if (ip
->client
->active
->expiry
> cur_time
) {
1010 note("Trying recorded lease %s",
1011 piaddr(ip
->client
->active
->address
));
1012 /* Run the client script with the existing
1014 script_init("TIMEOUT",
1015 ip
->client
->active
->medium
);
1016 script_write_params("new_", ip
->client
->active
);
1017 if (ip
->client
->alias
)
1018 script_write_params("alias_",
1021 /* If the old lease is still good and doesn't
1022 yet need renewal, go into BOUND state and
1023 timeout at the renewal time. */
1025 ip
->client
->active
->renewal
) {
1026 ip
->client
->state
= S_BOUND
;
1027 note("bound: renewal in %ld seconds.",
1028 ip
->client
->active
->renewal
-
1031 ip
->client
->active
->renewal
,
1034 ip
->client
->state
= S_BOUND
;
1035 note("bound: immediate renewal.");
1038 reinitialize_interfaces();
1042 /* If there are no other leases, give up. */
1043 if (!ip
->client
->leases
) {
1044 ip
->client
->leases
= ip
->client
->active
;
1045 ip
->client
->active
= NULL
;
1050 /* Otherwise, put the active lease at the end of the
1051 lease list, and try another lease.. */
1052 for (lp
= ip
->client
->leases
; lp
->next
; lp
= lp
->next
)
1054 lp
->next
= ip
->client
->active
;
1056 lp
->next
->next
= NULL
;
1057 ip
->client
->active
= ip
->client
->leases
;
1058 ip
->client
->leases
= ip
->client
->leases
->next
;
1060 /* If we already tried this lease, we've exhausted the
1061 set of leases, so we might as well give up for
1063 if (ip
->client
->active
== loop
)
1066 loop
= ip
->client
->active
;
1069 /* No leases were available, or what was available didn't work, so
1070 tell the shell script that we failed to allocate an address,
1071 and try again later. */
1072 note("No working leases in persistent database - sleeping.\n");
1073 ip
->client
->state
= S_INIT
;
1074 add_timeout(cur_time
+ ip
->client
->config
->retry_interval
, state_init
,
1076 /* XXX Take any failure actions necessary */
1080 send_request(void *ipp
)
1082 struct interface_info
*ip
= ipp
;
1083 struct sockaddr_in destination
;
1084 struct in_addr from
;
1087 /* Figure out how long it's been since we started transmitting. */
1088 interval
= cur_time
- ip
->client
->first_sending
;
1090 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1091 past the reboot timeout, go to INIT and see if we can
1092 DISCOVER an address... */
1093 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1094 means either that we're on a network with no DHCP server,
1095 or that our server is down. In the latter case, assuming
1096 that there is a backup DHCP server, DHCPDISCOVER will get
1097 us a new address, but we could also have successfully
1098 reused our old address. In the former case, we're hosed
1099 anyway. This is not a win-prone situation. */
1100 if ((ip
->client
->state
== S_REBOOTING
||
1101 ip
->client
->state
== S_REQUESTING
) &&
1102 interval
> ip
->client
->config
->reboot_timeout
) {
1103 ip
->client
->state
= S_INIT
;
1104 cancel_timeout(send_request
, ip
);
1109 /* If we're in the reboot state, make sure the media is set up
1111 if (ip
->client
->state
== S_REBOOTING
&&
1112 !ip
->client
->medium
&&
1113 ip
->client
->active
->medium
) {
1114 script_init("MEDIUM", ip
->client
->active
->medium
);
1116 /* If the medium we chose won't fly, go to INIT state. */
1117 /* XXX Nothing for now */
1119 /* Record the medium. */
1120 ip
->client
->medium
= ip
->client
->active
->medium
;
1123 /* If the lease has expired, relinquish the address and go back
1124 to the INIT state. */
1125 if (ip
->client
->state
!= S_REQUESTING
&&
1126 cur_time
> ip
->client
->active
->expiry
) {
1127 PDHCP_ADAPTER Adapter
= AdapterFindInfo( ip
);
1128 /* Run the client script with the new parameters. */
1129 /* No script actions necessary in the expiry case */
1130 /* Now do a preinit on the interface so that we can
1131 discover a new address. */
1134 DeleteIPAddress( Adapter
->NteContext
);
1136 ip
->client
->state
= S_INIT
;
1141 /* Do the exponential backoff... */
1142 if (!ip
->client
->interval
)
1143 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
1145 ip
->client
->interval
+= ((rand() >> 2) %
1146 (2 * ip
->client
->interval
));
1148 /* Don't backoff past cutoff. */
1149 if (ip
->client
->interval
>
1150 ip
->client
->config
->backoff_cutoff
)
1151 ip
->client
->interval
=
1152 ((ip
->client
->config
->backoff_cutoff
/ 2) +
1153 ((rand() >> 2) % ip
->client
->interval
));
1155 /* If the backoff would take us to the expiry time, just set the
1156 timeout to the expiry time. */
1157 if (ip
->client
->state
!= S_REQUESTING
&&
1158 cur_time
+ ip
->client
->interval
>
1159 ip
->client
->active
->expiry
)
1160 ip
->client
->interval
=
1161 ip
->client
->active
->expiry
- cur_time
+ 1;
1163 /* If the lease T2 time has elapsed, or if we're not yet bound,
1164 broadcast the DHCPREQUEST rather than unicasting. */
1165 memset(&destination
, 0, sizeof(destination
));
1166 if (ip
->client
->state
== S_REQUESTING
||
1167 ip
->client
->state
== S_REBOOTING
||
1168 cur_time
> ip
->client
->active
->rebind
)
1169 destination
.sin_addr
.s_addr
= INADDR_BROADCAST
;
1171 memcpy(&destination
.sin_addr
.s_addr
,
1172 ip
->client
->destination
.iabuf
,
1173 sizeof(destination
.sin_addr
.s_addr
));
1174 destination
.sin_port
= htons(REMOTE_PORT
);
1175 destination
.sin_family
= AF_INET
;
1176 // destination.sin_len = sizeof(destination);
1178 if (ip
->client
->state
!= S_REQUESTING
)
1179 memcpy(&from
, ip
->client
->active
->address
.iabuf
,
1182 from
.s_addr
= INADDR_ANY
;
1184 /* Record the number of seconds since we started sending. */
1185 if (ip
->client
->state
== S_REQUESTING
)
1186 ip
->client
->packet
.secs
= ip
->client
->secs
;
1188 if (interval
< 65536)
1189 ip
->client
->packet
.secs
= htons(interval
);
1191 ip
->client
->packet
.secs
= htons(65535);
1194 note("DHCPREQUEST on %s to %s port %d", ip
->name
,
1195 inet_ntoa(destination
.sin_addr
), ntohs(destination
.sin_port
));
1197 /* Send out a packet. */
1198 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1199 from
, &destination
, NULL
);
1201 add_timeout(cur_time
+ ip
->client
->interval
, send_request
, ip
);
1205 send_decline(void *ipp
)
1207 struct interface_info
*ip
= ipp
;
1209 note("DHCPDECLINE on %s to %s port %d", ip
->name
,
1210 inet_ntoa(sockaddr_broadcast
.sin_addr
),
1211 ntohs(sockaddr_broadcast
.sin_port
));
1213 /* Send out a packet. */
1214 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1215 inaddr_any
, &sockaddr_broadcast
, NULL
);
1219 make_discover(struct interface_info
*ip
, struct client_lease
*lease
)
1221 unsigned char discover
= DHCPDISCOVER
;
1222 struct tree_cache
*options
[256];
1223 struct tree_cache option_elements
[256];
1226 memset(option_elements
, 0, sizeof(option_elements
));
1227 memset(options
, 0, sizeof(options
));
1228 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1230 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1231 i
= DHO_DHCP_MESSAGE_TYPE
;
1232 options
[i
] = &option_elements
[i
];
1233 options
[i
]->value
= &discover
;
1234 options
[i
]->len
= sizeof(discover
);
1235 options
[i
]->buf_size
= sizeof(discover
);
1236 options
[i
]->timeout
= 0xFFFFFFFF;
1238 /* Request the options we want */
1239 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1240 options
[i
] = &option_elements
[i
];
1241 options
[i
]->value
= ip
->client
->config
->requested_options
;
1242 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1243 options
[i
]->buf_size
=
1244 ip
->client
->config
->requested_option_count
;
1245 options
[i
]->timeout
= 0xFFFFFFFF;
1247 /* If we had an address, try to get it again. */
1249 ip
->client
->requested_address
= lease
->address
;
1250 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1251 options
[i
] = &option_elements
[i
];
1252 options
[i
]->value
= lease
->address
.iabuf
;
1253 options
[i
]->len
= lease
->address
.len
;
1254 options
[i
]->buf_size
= lease
->address
.len
;
1255 options
[i
]->timeout
= 0xFFFFFFFF;
1257 ip
->client
->requested_address
.len
= 0;
1259 /* Send any options requested in the config file. */
1260 for (i
= 0; i
< 256; i
++)
1262 ip
->client
->config
->send_options
[i
].data
) {
1263 options
[i
] = &option_elements
[i
];
1265 ip
->client
->config
->send_options
[i
].data
;
1267 ip
->client
->config
->send_options
[i
].len
;
1268 options
[i
]->buf_size
=
1269 ip
->client
->config
->send_options
[i
].len
;
1270 options
[i
]->timeout
= 0xFFFFFFFF;
1273 /* Set up the option buffer... */
1274 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1275 options
, 0, 0, 0, NULL
, 0);
1276 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1277 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1279 ip
->client
->packet
.op
= BOOTREQUEST
;
1280 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1281 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1282 ip
->client
->packet
.hops
= 0;
1283 ip
->client
->packet
.xid
= rand();
1284 ip
->client
->packet
.secs
= 0; /* filled in by send_discover. */
1285 ip
->client
->packet
.flags
= 0;
1287 memset(&(ip
->client
->packet
.ciaddr
),
1288 0, sizeof(ip
->client
->packet
.ciaddr
));
1289 memset(&(ip
->client
->packet
.yiaddr
),
1290 0, sizeof(ip
->client
->packet
.yiaddr
));
1291 memset(&(ip
->client
->packet
.siaddr
),
1292 0, sizeof(ip
->client
->packet
.siaddr
));
1293 memset(&(ip
->client
->packet
.giaddr
),
1294 0, sizeof(ip
->client
->packet
.giaddr
));
1295 memcpy(ip
->client
->packet
.chaddr
,
1296 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1301 make_request(struct interface_info
*ip
, struct client_lease
* lease
)
1303 unsigned char request
= DHCPREQUEST
;
1304 struct tree_cache
*options
[256];
1305 struct tree_cache option_elements
[256];
1308 memset(options
, 0, sizeof(options
));
1309 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1311 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1312 i
= DHO_DHCP_MESSAGE_TYPE
;
1313 options
[i
] = &option_elements
[i
];
1314 options
[i
]->value
= &request
;
1315 options
[i
]->len
= sizeof(request
);
1316 options
[i
]->buf_size
= sizeof(request
);
1317 options
[i
]->timeout
= 0xFFFFFFFF;
1319 /* Request the options we want */
1320 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1321 options
[i
] = &option_elements
[i
];
1322 options
[i
]->value
= ip
->client
->config
->requested_options
;
1323 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1324 options
[i
]->buf_size
=
1325 ip
->client
->config
->requested_option_count
;
1326 options
[i
]->timeout
= 0xFFFFFFFF;
1328 /* If we are requesting an address that hasn't yet been assigned
1329 to us, use the DHCP Requested Address option. */
1330 if (ip
->client
->state
== S_REQUESTING
) {
1331 /* Send back the server identifier... */
1332 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1333 options
[i
] = &option_elements
[i
];
1334 options
[i
]->value
= lease
->options
[i
].data
;
1335 options
[i
]->len
= lease
->options
[i
].len
;
1336 options
[i
]->buf_size
= lease
->options
[i
].len
;
1337 options
[i
]->timeout
= 0xFFFFFFFF;
1339 if (ip
->client
->state
== S_REQUESTING
||
1340 ip
->client
->state
== S_REBOOTING
) {
1341 ip
->client
->requested_address
= lease
->address
;
1342 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1343 options
[i
] = &option_elements
[i
];
1344 options
[i
]->value
= lease
->address
.iabuf
;
1345 options
[i
]->len
= lease
->address
.len
;
1346 options
[i
]->buf_size
= lease
->address
.len
;
1347 options
[i
]->timeout
= 0xFFFFFFFF;
1349 ip
->client
->requested_address
.len
= 0;
1351 /* Send any options requested in the config file. */
1352 for (i
= 0; i
< 256; i
++)
1354 ip
->client
->config
->send_options
[i
].data
) {
1355 options
[i
] = &option_elements
[i
];
1357 ip
->client
->config
->send_options
[i
].data
;
1359 ip
->client
->config
->send_options
[i
].len
;
1360 options
[i
]->buf_size
=
1361 ip
->client
->config
->send_options
[i
].len
;
1362 options
[i
]->timeout
= 0xFFFFFFFF;
1365 /* Set up the option buffer... */
1366 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1367 options
, 0, 0, 0, NULL
, 0);
1368 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1369 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1371 ip
->client
->packet
.op
= BOOTREQUEST
;
1372 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1373 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1374 ip
->client
->packet
.hops
= 0;
1375 ip
->client
->packet
.xid
= ip
->client
->xid
;
1376 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1378 /* If we own the address we're requesting, put it in ciaddr;
1379 otherwise set ciaddr to zero. */
1380 if (ip
->client
->state
== S_BOUND
||
1381 ip
->client
->state
== S_RENEWING
||
1382 ip
->client
->state
== S_REBINDING
) {
1383 memcpy(&ip
->client
->packet
.ciaddr
,
1384 lease
->address
.iabuf
, lease
->address
.len
);
1385 ip
->client
->packet
.flags
= 0;
1387 memset(&ip
->client
->packet
.ciaddr
, 0,
1388 sizeof(ip
->client
->packet
.ciaddr
));
1389 ip
->client
->packet
.flags
= 0;
1392 memset(&ip
->client
->packet
.yiaddr
, 0,
1393 sizeof(ip
->client
->packet
.yiaddr
));
1394 memset(&ip
->client
->packet
.siaddr
, 0,
1395 sizeof(ip
->client
->packet
.siaddr
));
1396 memset(&ip
->client
->packet
.giaddr
, 0,
1397 sizeof(ip
->client
->packet
.giaddr
));
1398 memcpy(ip
->client
->packet
.chaddr
,
1399 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1403 make_decline(struct interface_info
*ip
, struct client_lease
*lease
)
1405 struct tree_cache
*options
[256], message_type_tree
;
1406 struct tree_cache requested_address_tree
;
1407 struct tree_cache server_id_tree
, client_id_tree
;
1408 unsigned char decline
= DHCPDECLINE
;
1411 memset(options
, 0, sizeof(options
));
1412 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1414 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1415 i
= DHO_DHCP_MESSAGE_TYPE
;
1416 options
[i
] = &message_type_tree
;
1417 options
[i
]->value
= &decline
;
1418 options
[i
]->len
= sizeof(decline
);
1419 options
[i
]->buf_size
= sizeof(decline
);
1420 options
[i
]->timeout
= 0xFFFFFFFF;
1422 /* Send back the server identifier... */
1423 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1424 options
[i
] = &server_id_tree
;
1425 options
[i
]->value
= lease
->options
[i
].data
;
1426 options
[i
]->len
= lease
->options
[i
].len
;
1427 options
[i
]->buf_size
= lease
->options
[i
].len
;
1428 options
[i
]->timeout
= 0xFFFFFFFF;
1430 /* Send back the address we're declining. */
1431 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1432 options
[i
] = &requested_address_tree
;
1433 options
[i
]->value
= lease
->address
.iabuf
;
1434 options
[i
]->len
= lease
->address
.len
;
1435 options
[i
]->buf_size
= lease
->address
.len
;
1436 options
[i
]->timeout
= 0xFFFFFFFF;
1438 /* Send the uid if the user supplied one. */
1439 i
= DHO_DHCP_CLIENT_IDENTIFIER
;
1440 if (ip
->client
->config
->send_options
[i
].len
) {
1441 options
[i
] = &client_id_tree
;
1442 options
[i
]->value
= ip
->client
->config
->send_options
[i
].data
;
1443 options
[i
]->len
= ip
->client
->config
->send_options
[i
].len
;
1444 options
[i
]->buf_size
= ip
->client
->config
->send_options
[i
].len
;
1445 options
[i
]->timeout
= 0xFFFFFFFF;
1449 /* Set up the option buffer... */
1450 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1451 options
, 0, 0, 0, NULL
, 0);
1452 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1453 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1455 ip
->client
->packet
.op
= BOOTREQUEST
;
1456 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1457 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1458 ip
->client
->packet
.hops
= 0;
1459 ip
->client
->packet
.xid
= ip
->client
->xid
;
1460 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1461 ip
->client
->packet
.flags
= 0;
1463 /* ciaddr must always be zero. */
1464 memset(&ip
->client
->packet
.ciaddr
, 0,
1465 sizeof(ip
->client
->packet
.ciaddr
));
1466 memset(&ip
->client
->packet
.yiaddr
, 0,
1467 sizeof(ip
->client
->packet
.yiaddr
));
1468 memset(&ip
->client
->packet
.siaddr
, 0,
1469 sizeof(ip
->client
->packet
.siaddr
));
1470 memset(&ip
->client
->packet
.giaddr
, 0,
1471 sizeof(ip
->client
->packet
.giaddr
));
1472 memcpy(ip
->client
->packet
.chaddr
,
1473 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1477 free_client_lease(struct client_lease
*lease
)
1481 if (lease
->server_name
)
1482 free(lease
->server_name
);
1483 if (lease
->filename
)
1484 free(lease
->filename
);
1485 for (i
= 0; i
< 256; i
++) {
1486 if (lease
->options
[i
].len
)
1487 free(lease
->options
[i
].data
);
1495 rewrite_client_leases(void)
1497 struct client_lease
*lp
;
1500 leaseFile
= fopen(path_dhclient_db
, "w");
1502 error("can't create %s: %m", path_dhclient_db
);
1508 for (lp
= ifi
->client
->leases
; lp
; lp
= lp
->next
)
1509 write_client_lease(ifi
, lp
, 1);
1510 if (ifi
->client
->active
)
1511 write_client_lease(ifi
, ifi
->client
->active
, 1);
1517 write_client_lease(struct interface_info
*ip
, struct client_lease
*lease
,
1520 static int leases_written
;
1525 if (leases_written
++ > 20) {
1526 rewrite_client_leases();
1531 /* If the lease came from the config file, we don't need to stash
1532 a copy in the lease database. */
1533 if (lease
->is_static
)
1536 if (!leaseFile
) { /* XXX */
1537 leaseFile
= fopen(path_dhclient_db
, "w");
1539 error("can't create %s: %m", path_dhclient_db
);
1542 fprintf(leaseFile
, "lease {\n");
1543 if (lease
->is_bootp
)
1544 fprintf(leaseFile
, " bootp;\n");
1545 fprintf(leaseFile
, " interface \"%s\";\n", ip
->name
);
1546 fprintf(leaseFile
, " fixed-address %s;\n", piaddr(lease
->address
));
1547 if (lease
->filename
)
1548 fprintf(leaseFile
, " filename \"%s\";\n", lease
->filename
);
1549 if (lease
->server_name
)
1550 fprintf(leaseFile
, " server-name \"%s\";\n",
1551 lease
->server_name
);
1553 fprintf(leaseFile
, " medium \"%s\";\n", lease
->medium
->string
);
1554 for (i
= 0; i
< 256; i
++)
1555 if (lease
->options
[i
].len
)
1556 fprintf(leaseFile
, " option %s %s;\n",
1557 dhcp_options
[i
].name
,
1558 pretty_print_option(i
, lease
->options
[i
].data
,
1559 lease
->options
[i
].len
, 1, 1));
1561 t
= gmtime(&lease
->renewal
);
1562 fprintf(leaseFile
, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1563 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1564 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1565 t
= gmtime(&lease
->rebind
);
1566 fprintf(leaseFile
, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1567 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1568 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1569 t
= gmtime(&lease
->expiry
);
1570 fprintf(leaseFile
, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1571 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1572 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1573 fprintf(leaseFile
, "}\n");
1578 script_init(char *reason
, struct string_list
*medium
)
1580 size_t len
, mediumlen
= 0;
1581 struct imsg_hdr hdr
;
1585 if (medium
!= NULL
&& medium
->string
!= NULL
)
1586 mediumlen
= strlen(medium
->string
);
1588 hdr
.code
= IMSG_SCRIPT_INIT
;
1589 hdr
.len
= sizeof(struct imsg_hdr
) +
1590 sizeof(size_t) + mediumlen
+
1591 sizeof(size_t) + strlen(reason
);
1593 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1594 error("buf_open: %m");
1597 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1598 errs
+= buf_add(buf
, &mediumlen
, sizeof(mediumlen
));
1600 errs
+= buf_add(buf
, medium
->string
, mediumlen
);
1601 len
= strlen(reason
);
1602 errs
+= buf_add(buf
, &len
, sizeof(len
));
1603 errs
+= buf_add(buf
, reason
, len
);
1606 error("buf_add: %m");
1608 if (buf_close(privfd
, buf
) == -1)
1609 error("buf_close: %m");
1613 priv_script_init(char *reason
, char *medium
)
1615 struct interface_info
*ip
= ifi
;
1618 // XXX Do we need to do anything?
1623 priv_script_write_params(char *prefix
, struct client_lease
*lease
)
1625 struct interface_info
*ip
= ifi
;
1626 u_int8_t dbuf
[1500];
1630 script_set_env(ip
->client
, prefix
, "ip_address",
1631 piaddr(lease
->address
));
1634 if (lease
->options
[DHO_SUBNET_MASK
].len
&&
1635 (lease
->options
[DHO_SUBNET_MASK
].len
<
1636 sizeof(lease
->address
.iabuf
))) {
1637 struct iaddr netmask
, subnet
, broadcast
;
1639 memcpy(netmask
.iabuf
, lease
->options
[DHO_SUBNET_MASK
].data
,
1640 lease
->options
[DHO_SUBNET_MASK
].len
);
1641 netmask
.len
= lease
->options
[DHO_SUBNET_MASK
].len
;
1643 subnet
= subnet_number(lease
->address
, netmask
);
1646 script_set_env(ip
->client
, prefix
, "network_number",
1649 if (!lease
->options
[DHO_BROADCAST_ADDRESS
].len
) {
1650 broadcast
= broadcast_addr(subnet
, netmask
);
1653 script_set_env(ip
->client
, prefix
,
1654 "broadcast_address",
1664 if (lease
->filename
)
1665 script_set_env(ip
->client
, prefix
, "filename", lease
->filename
);
1666 if (lease
->server_name
)
1667 script_set_env(ip
->client
, prefix
, "server_name",
1668 lease
->server_name
);
1671 for (i
= 0; i
< 256; i
++) {
1672 u_int8_t
*dp
= NULL
;
1674 if (ip
->client
->config
->defaults
[i
].len
) {
1675 if (lease
->options
[i
].len
) {
1677 ip
->client
->config
->default_actions
[i
]) {
1678 case ACTION_DEFAULT
:
1679 dp
= lease
->options
[i
].data
;
1680 len
= lease
->options
[i
].len
;
1682 case ACTION_SUPERSEDE
:
1685 config
->defaults
[i
].data
;
1687 config
->defaults
[i
].len
;
1689 case ACTION_PREPEND
:
1691 config
->defaults
[i
].len
+
1692 lease
->options
[i
].len
;
1693 if (len
> sizeof(dbuf
)) {
1694 warning("no space to %s %s",
1696 dhcp_options
[i
].name
);
1702 config
->defaults
[i
].data
,
1704 config
->defaults
[i
].len
);
1705 memcpy(dp
+ ip
->client
->
1706 config
->defaults
[i
].len
,
1707 lease
->options
[i
].data
,
1708 lease
->options
[i
].len
);
1713 config
->defaults
[i
].len
+
1714 lease
->options
[i
].len
;
1715 if (len
> sizeof(dbuf
)) {
1716 warning("no space to %s %s",
1718 dhcp_options
[i
].name
);
1723 lease
->options
[i
].data
,
1724 lease
->options
[i
].len
);
1725 memcpy(dp
+ lease
->options
[i
].len
,
1727 config
->defaults
[i
].data
,
1729 config
->defaults
[i
].len
);
1734 config
->defaults
[i
].data
;
1736 config
->defaults
[i
].len
;
1738 } else if (lease
->options
[i
].len
) {
1739 len
= lease
->options
[i
].len
;
1740 dp
= lease
->options
[i
].data
;
1748 if (dhcp_option_ev_name(name
, sizeof(name
),
1750 script_set_env(ip
->client
, prefix
, name
,
1751 pretty_print_option(i
, dp
, len
, 0, 0));
1756 snprintf(tbuf
, sizeof(tbuf
), "%d", (int)lease
->expiry
);
1757 script_set_env(ip
->client
, prefix
, "expiry", tbuf
);
1762 script_write_params(char *prefix
, struct client_lease
*lease
)
1764 size_t fn_len
= 0, sn_len
= 0, pr_len
= 0;
1765 struct imsg_hdr hdr
;
1769 if (lease
->filename
!= NULL
)
1770 fn_len
= strlen(lease
->filename
);
1771 if (lease
->server_name
!= NULL
)
1772 sn_len
= strlen(lease
->server_name
);
1774 pr_len
= strlen(prefix
);
1776 hdr
.code
= IMSG_SCRIPT_WRITE_PARAMS
;
1777 hdr
.len
= sizeof(hdr
) + sizeof(struct client_lease
) +
1778 sizeof(size_t) + fn_len
+ sizeof(size_t) + sn_len
+
1779 sizeof(size_t) + pr_len
;
1781 for (i
= 0; i
< 256; i
++)
1782 hdr
.len
+= sizeof(int) + lease
->options
[i
].len
;
1784 scripttime
= time(NULL
);
1786 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1787 error("buf_open: %m");
1790 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1791 errs
+= buf_add(buf
, lease
, sizeof(struct client_lease
));
1792 errs
+= buf_add(buf
, &fn_len
, sizeof(fn_len
));
1793 errs
+= buf_add(buf
, lease
->filename
, fn_len
);
1794 errs
+= buf_add(buf
, &sn_len
, sizeof(sn_len
));
1795 errs
+= buf_add(buf
, lease
->server_name
, sn_len
);
1796 errs
+= buf_add(buf
, &pr_len
, sizeof(pr_len
));
1797 errs
+= buf_add(buf
, prefix
, pr_len
);
1799 for (i
= 0; i
< 256; i
++) {
1800 errs
+= buf_add(buf
, &lease
->options
[i
].len
,
1801 sizeof(lease
->options
[i
].len
));
1802 errs
+= buf_add(buf
, lease
->options
[i
].data
,
1803 lease
->options
[i
].len
);
1807 error("buf_add: %m");
1809 if (buf_close(privfd
, buf
) == -1)
1810 error("buf_close: %m");
1814 dhcp_option_ev_name(char *buf
, size_t buflen
, struct dhcp_option
*option
)
1818 for (i
= 0; option
->name
[i
]; i
++) {
1819 if (i
+ 1 == buflen
)
1821 if (option
->name
[i
] == '-')
1824 buf
[i
] = option
->name
[i
];
1835 static int state
= 0;
1837 if (no_daemon
|| state
)
1842 /* Stop logging to stderr... */
1845 if (daemon(1, 0) == -1)
1848 /* we are chrooted, daemon(3) fails to open /dev/null */
1850 dup2(nullfd
, STDIN_FILENO
);
1851 dup2(nullfd
, STDOUT_FILENO
);
1852 dup2(nullfd
, STDERR_FILENO
);
1860 check_option(struct client_lease
*l
, int option
)
1865 /* we use this, since this is what gets passed to dhclient-script */
1867 opbuf
= pretty_print_option(option
, l
->options
[option
].data
,
1868 l
->options
[option
].len
, 0, 0);
1870 sbuf
= option_as_string(option
, l
->options
[option
].data
,
1871 l
->options
[option
].len
);
1874 case DHO_SUBNET_MASK
:
1875 case DHO_TIME_SERVERS
:
1876 case DHO_NAME_SERVERS
:
1878 case DHO_DOMAIN_NAME_SERVERS
:
1879 case DHO_LOG_SERVERS
:
1880 case DHO_COOKIE_SERVERS
:
1881 case DHO_LPR_SERVERS
:
1882 case DHO_IMPRESS_SERVERS
:
1883 case DHO_RESOURCE_LOCATION_SERVERS
:
1884 case DHO_SWAP_SERVER
:
1885 case DHO_BROADCAST_ADDRESS
:
1886 case DHO_NIS_SERVERS
:
1887 case DHO_NTP_SERVERS
:
1888 case DHO_NETBIOS_NAME_SERVERS
:
1889 case DHO_NETBIOS_DD_SERVER
:
1890 case DHO_FONT_SERVERS
:
1891 case DHO_DHCP_SERVER_IDENTIFIER
:
1892 if (!ipv4addrs(opbuf
)) {
1893 warning("Invalid IP address in option(%d): %s", option
, opbuf
);
1898 case DHO_DOMAIN_NAME
:
1899 case DHO_NIS_DOMAIN
:
1900 if (!res_hnok(sbuf
)) {
1901 warning("Bogus Host Name option %d: %s (%s)", option
,
1907 case DHO_TIME_OFFSET
:
1909 case DHO_MERIT_DUMP
:
1911 case DHO_EXTENSIONS_PATH
:
1912 case DHO_IP_FORWARDING
:
1913 case DHO_NON_LOCAL_SOURCE_ROUTING
:
1914 case DHO_POLICY_FILTER
:
1915 case DHO_MAX_DGRAM_REASSEMBLY
:
1916 case DHO_DEFAULT_IP_TTL
:
1917 case DHO_PATH_MTU_AGING_TIMEOUT
:
1918 case DHO_PATH_MTU_PLATEAU_TABLE
:
1919 case DHO_INTERFACE_MTU
:
1920 case DHO_ALL_SUBNETS_LOCAL
:
1921 case DHO_PERFORM_MASK_DISCOVERY
:
1922 case DHO_MASK_SUPPLIER
:
1923 case DHO_ROUTER_DISCOVERY
:
1924 case DHO_ROUTER_SOLICITATION_ADDRESS
:
1925 case DHO_STATIC_ROUTES
:
1926 case DHO_TRAILER_ENCAPSULATION
:
1927 case DHO_ARP_CACHE_TIMEOUT
:
1928 case DHO_IEEE802_3_ENCAPSULATION
:
1929 case DHO_DEFAULT_TCP_TTL
:
1930 case DHO_TCP_KEEPALIVE_INTERVAL
:
1931 case DHO_TCP_KEEPALIVE_GARBAGE
:
1932 case DHO_VENDOR_ENCAPSULATED_OPTIONS
:
1933 case DHO_NETBIOS_NODE_TYPE
:
1934 case DHO_NETBIOS_SCOPE
:
1935 case DHO_X_DISPLAY_MANAGER
:
1936 case DHO_DHCP_REQUESTED_ADDRESS
:
1937 case DHO_DHCP_LEASE_TIME
:
1938 case DHO_DHCP_OPTION_OVERLOAD
:
1939 case DHO_DHCP_MESSAGE_TYPE
:
1940 case DHO_DHCP_PARAMETER_REQUEST_LIST
:
1941 case DHO_DHCP_MESSAGE
:
1942 case DHO_DHCP_MAX_MESSAGE_SIZE
:
1943 case DHO_DHCP_RENEWAL_TIME
:
1944 case DHO_DHCP_REBINDING_TIME
:
1945 case DHO_DHCP_CLASS_IDENTIFIER
:
1946 case DHO_DHCP_CLIENT_IDENTIFIER
:
1947 case DHO_DHCP_USER_CLASS_ID
:
1951 warning("unknown dhcp option value 0x%x", option
);
1952 return (unknown_ok
);
1957 res_hnok(const char *dn
)
1959 int pch
= PERIOD
, ch
= *dn
++;
1961 while (ch
!= '\0') {
1964 if (periodchar(ch
)) {
1966 } else if (periodchar(pch
)) {
1967 if (!borderchar(ch
))
1969 } else if (periodchar(nch
) || nch
== '\0') {
1970 if (!borderchar(ch
))
1973 if (!middlechar(ch
))
1981 /* Does buf consist only of dotted decimal ipv4 addrs?
1982 * return how many if so,
1983 * otherwise, return 0
1986 ipv4addrs(char * buf
)
1992 note("Input: %s\n", buf
);
1995 tmp
= strtok(buf
, " ");
1996 note("got %s\n", tmp
);
1997 if( tmp
&& inet_aton(tmp
, &jnk
) ) i
++;
2006 option_as_string(unsigned int code
, unsigned char *data
, int len
)
2008 static char optbuf
[32768]; /* XXX */
2010 int opleft
= sizeof(optbuf
);
2011 unsigned char *dp
= data
;
2014 error("option_as_string: bad code %d", code
);
2016 for (; dp
< data
+ len
; dp
++) {
2017 if (!isascii(*dp
) || !isprint(*dp
)) {
2018 if (dp
+ 1 != data
+ len
|| *dp
!= 0) {
2019 snprintf(op
, opleft
, "\\%03o", *dp
);
2023 } else if (*dp
== '"' || *dp
== '\'' || *dp
== '$' ||
2024 *dp
== '`' || *dp
== '\\') {
2038 warning("dhcp option too large");
2044 fork_privchld(int fd
, int fd2
)
2046 struct pollfd pfd
[1];
2051 error("cannot fork");
2058 setproctitle("%s [priv]", ifi
->name
);
2060 dup2(nullfd
, STDIN_FILENO
);
2061 dup2(nullfd
, STDOUT_FILENO
);
2062 dup2(nullfd
, STDERR_FILENO
);
2068 pfd
[0].events
= POLLIN
;
2069 if ((nfds
= poll(pfd
, 1, INFTIM
)) == -1)
2071 error("poll error");
2073 if (nfds
== 0 || !(pfd
[0].revents
& POLLIN
))