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 DispatchMain(DWORD argc
, LPTSTR
*argv
)
128 static SERVICE_TABLE_ENTRY ServiceTable
[2] =
130 {TEXT("DHCP"), DispatchMain
},
135 main(int argc
, char *argv
[])
145 memset(&sockaddr_broadcast
, 0, sizeof(sockaddr_broadcast
));
146 sockaddr_broadcast
.sin_family
= AF_INET
;
147 sockaddr_broadcast
.sin_port
= htons(REMOTE_PORT
);
148 sockaddr_broadcast
.sin_addr
.s_addr
= INADDR_BROADCAST
;
149 inaddr_any
.s_addr
= INADDR_ANY
;
151 DH_DbgPrint(MID_TRACE
,("DHCP Service Started\n"));
155 if (!interface_link_status(ifi
->name
)) {
156 DH_DbgPrint(MID_TRACE
,("%s: no link ", ifi
->name
));
158 while (!interface_link_status(ifi
->name
)) {
159 DH_DbgPrint(MID_TRACE
,("."));
161 DH_DbgPrint(MID_TRACE
,("Giving up for now on adapter [%s]\n", ifi
->name
));
165 DH_DbgPrint(MID_TRACE
,("Got link on [%s]\n", ifi
->name
));
168 DH_DbgPrint(MID_TRACE
,("Discover Interfaces\n"));
170 /* If no adapters were found, just idle for now ... If any show up,
171 * then we'll start it later */
173 /* set up the interface */
174 discover_interfaces(ifi
);
178 ("Setting init state and restarting interface %p\n",ifi
));
181 bootp_packet_handler
= do_packet
;
183 DH_DbgPrint(MID_TRACE
,("Going into dispatch()\n"));
185 StartServiceCtrlDispatcher(ServiceTable
);
194 // extern char *__progname;
196 // fprintf(stderr, "usage: %s [-dqu] ", __progname);
197 fprintf(stderr
, "usage: dhclient [-dqu] ");
198 fprintf(stderr
, "[-c conffile] [-l leasefile] interface\n");
205 * Each routine is called from the dhclient_state_machine() in one of
207 * -> entering INIT state
208 * -> recvpacket_flag == 0: timeout in this state
209 * -> otherwise: received a packet in this state
211 * Return conditions as handled by dhclient_state_machine():
212 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
213 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
214 * Returns 0: finish the nap which was interrupted for no good reason.
216 * Several per-interface variables are used to keep track of the process:
217 * active_lease: the lease that is being used on the interface
218 * (null pointer if not configured yet).
219 * offered_leases: leases corresponding to DHCPOFFER messages that have
220 * been sent to us by DHCP servers.
221 * acked_leases: leases corresponding to DHCPACK messages that have been
222 * sent to us by DHCP servers.
223 * sendpacket: DHCP packet we're trying to send.
224 * destination: IP address to send sendpacket to
225 * In addition, there are several relevant per-lease variables.
226 * T1_expiry, T2_expiry, lease_expiry: lease milestones
227 * In the active lease, these control the process of renewing the lease;
228 * In leases on the acked_leases list, this simply determines when we
229 * can no longer legitimately use the lease.
233 state_reboot(void *ipp
)
235 struct interface_info
*ip
= ipp
;
236 ULONG foo
= (ULONG
) GetTickCount();
238 /* If we don't remember an active lease, go straight to INIT. */
239 if (!ip
->client
->active
|| ip
->client
->active
->is_bootp
) {
244 /* We are in the rebooting state. */
245 ip
->client
->state
= S_REBOOTING
;
247 /* make_request doesn't initialize xid because it normally comes
248 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
249 so pick an xid now. */
250 ip
->client
->xid
= RtlRandom(&foo
);
252 /* Make a DHCPREQUEST packet, and set appropriate per-interface
254 make_request(ip
, ip
->client
->active
);
255 ip
->client
->destination
= iaddr_broadcast
;
256 ip
->client
->first_sending
= cur_time
;
257 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
259 /* Zap the medium list... */
260 ip
->client
->medium
= NULL
;
262 /* Send out the first DHCPREQUEST packet. */
267 * Called when a lease has completely expired and we've
268 * been unable to renew it.
271 state_init(void *ipp
)
273 struct interface_info
*ip
= ipp
;
275 ASSERT_STATE(state
, S_INIT
);
277 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
279 make_discover(ip
, ip
->client
->active
);
280 ip
->client
->xid
= ip
->client
->packet
.xid
;
281 ip
->client
->destination
= iaddr_broadcast
;
282 ip
->client
->state
= S_SELECTING
;
283 ip
->client
->first_sending
= cur_time
;
284 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
286 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
292 * state_selecting is called when one or more DHCPOFFER packets
293 * have been received and a configurable period of time has passed.
296 state_selecting(void *ipp
)
298 struct interface_info
*ip
= ipp
;
299 struct client_lease
*lp
, *next
, *picked
;
301 ASSERT_STATE(state
, S_SELECTING
);
303 /* Cancel state_selecting and send_discover timeouts, since either
304 one could have got us here. */
305 cancel_timeout(state_selecting
, ip
);
306 cancel_timeout(send_discover
, ip
);
308 /* We have received one or more DHCPOFFER packets. Currently,
309 the only criterion by which we judge leases is whether or
310 not we get a response when we arp for them. */
312 for (lp
= ip
->client
->offered_leases
; lp
; lp
= next
) {
315 /* Check to see if we got an ARPREPLY for the address
316 in this particular lease. */
318 if( !check_arp(ip
,lp
) ) goto freeit
;
323 free_client_lease(lp
);
326 ip
->client
->offered_leases
= NULL
;
328 /* If we just tossed all the leases we were offered, go back
331 ip
->client
->state
= S_INIT
;
336 /* If it was a BOOTREPLY, we can just take the address right now. */
337 if (!picked
->options
[DHO_DHCP_MESSAGE_TYPE
].len
) {
338 ip
->client
->new = picked
;
340 /* Make up some lease expiry times
341 XXX these should be configurable. */
342 ip
->client
->new->expiry
= cur_time
+ 12000;
343 ip
->client
->new->renewal
+= cur_time
+ 8000;
344 ip
->client
->new->rebind
+= cur_time
+ 10000;
346 ip
->client
->state
= S_REQUESTING
;
348 /* Bind to the address we received. */
353 /* Go to the REQUESTING state. */
354 ip
->client
->destination
= iaddr_broadcast
;
355 ip
->client
->state
= S_REQUESTING
;
356 ip
->client
->first_sending
= cur_time
;
357 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
359 /* Make a DHCPREQUEST packet from the lease we picked. */
360 make_request(ip
, picked
);
361 ip
->client
->xid
= ip
->client
->packet
.xid
;
363 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
364 free_client_lease(picked
);
366 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
370 /* state_requesting is called when we receive a DHCPACK message after
371 having sent out one or more DHCPREQUEST packets. */
374 dhcpack(struct packet
*packet
)
376 struct interface_info
*ip
= packet
->interface
;
377 struct client_lease
*lease
;
379 /* If we're not receptive to an offer right now, or if the offer
380 has an unrecognizable transaction id, then just drop it. */
381 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
382 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
383 (memcmp(packet
->interface
->hw_address
.haddr
,
384 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
387 if (ip
->client
->state
!= S_REBOOTING
&&
388 ip
->client
->state
!= S_REQUESTING
&&
389 ip
->client
->state
!= S_RENEWING
&&
390 ip
->client
->state
!= S_REBINDING
)
393 note("DHCPACK from %s", piaddr(packet
->client_addr
));
395 lease
= packet_to_lease(packet
);
397 note("packet_to_lease failed.");
401 ip
->client
->new = lease
;
403 /* Stop resending DHCPREQUEST. */
404 cancel_timeout(send_request
, ip
);
406 /* Figure out the lease time. */
407 if (ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
)
408 ip
->client
->new->expiry
= getULong(
409 ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
);
411 ip
->client
->new->expiry
= default_lease_time
;
412 /* A number that looks negative here is really just very large,
413 because the lease expiry offset is unsigned. */
414 if (ip
->client
->new->expiry
< 0)
415 ip
->client
->new->expiry
= TIME_MAX
;
416 /* XXX should be fixed by resetting the client state */
417 if (ip
->client
->new->expiry
< 60)
418 ip
->client
->new->expiry
= 60;
420 /* Take the server-provided renewal time if there is one;
421 otherwise figure it out according to the spec. */
422 if (ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].len
)
423 ip
->client
->new->renewal
= getULong(
424 ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].data
);
426 ip
->client
->new->renewal
= ip
->client
->new->expiry
/ 2;
428 /* Same deal with the rebind time. */
429 if (ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].len
)
430 ip
->client
->new->rebind
= getULong(
431 ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].data
);
433 ip
->client
->new->rebind
= ip
->client
->new->renewal
+
434 ip
->client
->new->renewal
/ 2 + ip
->client
->new->renewal
/ 4;
437 ip
->client
->new->obtained
= cur_time
;
439 ip
->client
->new->expiry
+= cur_time
;
440 /* Lease lengths can never be negative. */
441 if (ip
->client
->new->expiry
< cur_time
)
442 ip
->client
->new->expiry
= TIME_MAX
;
443 ip
->client
->new->renewal
+= cur_time
;
444 if (ip
->client
->new->renewal
< cur_time
)
445 ip
->client
->new->renewal
= TIME_MAX
;
446 ip
->client
->new->rebind
+= cur_time
;
447 if (ip
->client
->new->rebind
< cur_time
)
448 ip
->client
->new->rebind
= TIME_MAX
;
453 void set_name_servers( struct client_lease
*new_lease
) {
454 if( new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
) {
456 struct iaddr nameserver
;
459 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
/ sizeof(ULONG
);
461 /* XXX I'm setting addrs to 1 until we are ready up the chain */
463 nsbuf
= malloc( addrs
* sizeof(IP_ADDRESS_STRING
) );
466 if( nsbuf
&& !RegOpenKeyEx
467 ( HKEY_LOCAL_MACHINE
,
468 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
469 0, KEY_WRITE
, &RegKey
) ) {
470 for( i
= 0; i
< addrs
; i
++ ) {
471 nameserver
.len
= sizeof(ULONG
);
472 memcpy( nameserver
.iabuf
,
473 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].data
+
474 (i
* sizeof(ULONG
)), sizeof(ULONG
) );
475 strcat( nsbuf
, piaddr(nameserver
) );
476 if( i
!= addrs
-1 ) strcat( nsbuf
, "," );
479 DH_DbgPrint(MID_TRACE
,("Setting DhcpNameserver: %s\n", nsbuf
));
481 RegSetValueEx( RegKey
, "DhcpNameServer", 0, REG_SZ
,
482 (LPBYTE
)nsbuf
, strlen(nsbuf
) + 1);
484 // free(NULL) is defined to be OK too
489 void setup_adapter( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
490 struct iaddr netmask
;
492 if( Adapter
->NteContext
)
493 DeleteIPAddress( Adapter
->NteContext
);
495 /* Set up our default router if we got one from the DHCP server */
496 if( new_lease
->options
[DHO_SUBNET_MASK
].len
) {
499 memcpy( netmask
.iabuf
,
500 new_lease
->options
[DHO_SUBNET_MASK
].data
,
501 new_lease
->options
[DHO_SUBNET_MASK
].len
);
503 Status
= AddIPAddress
504 ( *((ULONG
*)new_lease
->address
.iabuf
),
505 *((ULONG
*)netmask
.iabuf
),
506 Adapter
->IfMib
.dwIndex
,
507 &Adapter
->NteContext
,
508 &Adapter
->NteInstance
);
510 if( !NT_SUCCESS(Status
) )
511 warning("AddIPAddress: %lx\n", Status
);
514 if( new_lease
->options
[DHO_ROUTERS
].len
) {
515 MIB_IPFORWARDROW RouterMib
;
518 RouterMib
.dwForwardDest
= 0; /* Default route */
519 RouterMib
.dwForwardMask
= 0;
520 RouterMib
.dwForwardMetric1
= 1;
522 if( old_default_route
) {
523 /* If we set a default route before, delete it before continuing */
524 RouterMib
.dwForwardDest
= old_default_route
;
525 DeleteIpForwardEntry( &RouterMib
);
528 RouterMib
.dwForwardNextHop
=
529 *((ULONG
*)new_lease
->options
[DHO_ROUTERS
].data
);
531 Status
= CreateIpForwardEntry( &RouterMib
);
533 if( !NT_SUCCESS(Status
) )
534 warning("CreateIpForwardEntry: %lx\n", Status
);
536 old_default_route
= RouterMib
.dwForwardNextHop
;
542 bind_lease(struct interface_info
*ip
)
544 PDHCP_ADAPTER Adapter
;
545 struct client_lease
*new_lease
= ip
->client
->new;
547 /* Remember the medium. */
548 ip
->client
->new->medium
= ip
->client
->medium
;
549 ip
->client
->active
= ip
->client
->new;
550 ip
->client
->new = NULL
;
552 /* Set up a timeout to start the renewal process. */
553 /* Timeout of zero means no timeout (some implementations seem to use
556 if( ip
->client
->active
->renewal
- cur_time
)
557 add_timeout(ip
->client
->active
->renewal
, state_bound
, ip
);
559 note("bound to %s -- renewal in %ld seconds.",
560 piaddr(ip
->client
->active
->address
),
561 ip
->client
->active
->renewal
- cur_time
);
563 ip
->client
->state
= S_BOUND
;
565 Adapter
= AdapterFindInfo( ip
);
567 if( Adapter
) setup_adapter( Adapter
, new_lease
);
568 else warning("Could not find adapter for info %p\n", ip
);
570 set_name_servers( new_lease
);
572 reinitialize_interfaces();
576 * state_bound is called when we've successfully bound to a particular
577 * lease, but the renewal time on that lease has expired. We are
578 * expected to unicast a DHCPREQUEST to the server that gave us our
582 state_bound(void *ipp
)
584 struct interface_info
*ip
= ipp
;
586 ASSERT_STATE(state
, S_BOUND
);
588 /* T1 has expired. */
589 make_request(ip
, ip
->client
->active
);
590 ip
->client
->xid
= ip
->client
->packet
.xid
;
592 if (ip
->client
->active
->options
[DHO_DHCP_SERVER_IDENTIFIER
].len
== 4) {
593 memcpy(ip
->client
->destination
.iabuf
, ip
->client
->active
->
594 options
[DHO_DHCP_SERVER_IDENTIFIER
].data
, 4);
595 ip
->client
->destination
.len
= 4;
597 ip
->client
->destination
= iaddr_broadcast
;
599 ip
->client
->first_sending
= cur_time
;
600 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
601 ip
->client
->state
= S_RENEWING
;
603 /* Send the first packet immediately. */
608 bootp(struct packet
*packet
)
610 struct iaddrlist
*ap
;
612 if (packet
->raw
->op
!= BOOTREPLY
)
615 /* If there's a reject list, make sure this packet's sender isn't
617 for (ap
= packet
->interface
->client
->config
->reject_list
;
619 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
620 note("BOOTREPLY from %s rejected.", piaddr(ap
->addr
));
628 dhcp(struct packet
*packet
)
630 struct iaddrlist
*ap
;
631 void (*handler
)(struct packet
*);
634 switch (packet
->packet_type
) {
651 /* If there's a reject list, make sure this packet's sender isn't
653 for (ap
= packet
->interface
->client
->config
->reject_list
;
655 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
656 note("%s from %s rejected.", type
, piaddr(ap
->addr
));
664 dhcpoffer(struct packet
*packet
)
666 struct interface_info
*ip
= packet
->interface
;
667 struct client_lease
*lease
, *lp
;
669 int arp_timeout_needed
= 0, stop_selecting
;
670 char *name
= packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
?
671 "DHCPOFFER" : "BOOTREPLY";
673 /* If we're not receptive to an offer right now, or if the offer
674 has an unrecognizable transaction id, then just drop it. */
675 if (ip
->client
->state
!= S_SELECTING
||
676 packet
->interface
->client
->xid
!= packet
->raw
->xid
||
677 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
678 (memcmp(packet
->interface
->hw_address
.haddr
,
679 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
682 note("%s from %s", name
, piaddr(packet
->client_addr
));
685 /* If this lease doesn't supply the minimum required parameters,
687 for (i
= 0; ip
->client
->config
->required_options
[i
]; i
++) {
688 if (!packet
->options
[ip
->client
->config
->
689 required_options
[i
]].len
) {
690 note("%s isn't satisfactory.", name
);
695 /* If we've already seen this lease, don't record it again. */
696 for (lease
= ip
->client
->offered_leases
;
697 lease
; lease
= lease
->next
) {
698 if (lease
->address
.len
== sizeof(packet
->raw
->yiaddr
) &&
699 !memcmp(lease
->address
.iabuf
,
700 &packet
->raw
->yiaddr
, lease
->address
.len
)) {
701 debug("%s already seen.", name
);
706 lease
= packet_to_lease(packet
);
708 note("packet_to_lease failed.");
712 /* If this lease was acquired through a BOOTREPLY, record that
714 if (!packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
)
717 /* Record the medium under which this lease was offered. */
718 lease
->medium
= ip
->client
->medium
;
720 /* Send out an ARP Request for the offered IP address. */
721 if( !check_arp( ip
, lease
) ) {
722 note("Arp check failed\n");
726 /* Figure out when we're supposed to stop selecting. */
728 ip
->client
->first_sending
+ ip
->client
->config
->select_interval
;
730 /* If this is the lease we asked for, put it at the head of the
731 list, and don't mess with the arp request timeout. */
732 if (lease
->address
.len
== ip
->client
->requested_address
.len
&&
733 !memcmp(lease
->address
.iabuf
,
734 ip
->client
->requested_address
.iabuf
,
735 ip
->client
->requested_address
.len
)) {
736 lease
->next
= ip
->client
->offered_leases
;
737 ip
->client
->offered_leases
= lease
;
739 /* If we already have an offer, and arping for this
740 offer would take us past the selection timeout,
741 then don't extend the timeout - just hope for the
743 if (ip
->client
->offered_leases
&&
744 (cur_time
+ arp_timeout_needed
) > stop_selecting
)
745 arp_timeout_needed
= 0;
747 /* Put the lease at the end of the list. */
749 if (!ip
->client
->offered_leases
)
750 ip
->client
->offered_leases
= lease
;
752 for (lp
= ip
->client
->offered_leases
; lp
->next
;
759 /* If we're supposed to stop selecting before we've had time
760 to wait for the ARPREPLY, add some delay to wait for
762 if (stop_selecting
- cur_time
< arp_timeout_needed
)
763 stop_selecting
= cur_time
+ arp_timeout_needed
;
765 /* If the selecting interval has expired, go immediately to
766 state_selecting(). Otherwise, time out into
767 state_selecting at the select interval. */
768 if (stop_selecting
<= 0)
771 add_timeout(stop_selecting
, state_selecting
, ip
);
772 cancel_timeout(send_discover
, ip
);
776 /* Allocate a client_lease structure and initialize it from the parameters
777 in the specified packet. */
779 struct client_lease
*
780 packet_to_lease(struct packet
*packet
)
782 struct client_lease
*lease
;
785 lease
= malloc(sizeof(struct client_lease
));
788 warning("dhcpoffer: no memory to record lease.");
792 memset(lease
, 0, sizeof(*lease
));
794 /* Copy the lease options. */
795 for (i
= 0; i
< 256; i
++) {
796 if (packet
->options
[i
].len
) {
797 lease
->options
[i
].data
=
798 malloc(packet
->options
[i
].len
+ 1);
799 if (!lease
->options
[i
].data
) {
800 warning("dhcpoffer: no memory for option %d", i
);
801 free_client_lease(lease
);
804 memcpy(lease
->options
[i
].data
,
805 packet
->options
[i
].data
,
806 packet
->options
[i
].len
);
807 lease
->options
[i
].len
=
808 packet
->options
[i
].len
;
809 lease
->options
[i
].data
[lease
->options
[i
].len
] =
812 if (!check_option(lease
,i
)) {
813 /* ignore a bogus lease offer */
814 warning("Invalid lease option - ignoring offer");
815 free_client_lease(lease
);
821 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
822 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
, lease
->address
.len
);
824 lease
->serveraddress
.len
= sizeof(packet
->raw
->siaddr
);
825 memcpy(lease
->serveraddress
.iabuf
, &packet
->raw
->siaddr
, lease
->address
.len
);
828 /* If the server name was filled out, copy it. */
829 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
830 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 2)) &&
831 packet
->raw
->sname
[0]) {
832 lease
->server_name
= malloc(DHCP_SNAME_LEN
+ 1);
833 if (!lease
->server_name
) {
834 warning("dhcpoffer: no memory for server name.");
835 free_client_lease(lease
);
838 memcpy(lease
->server_name
, packet
->raw
->sname
, DHCP_SNAME_LEN
);
839 lease
->server_name
[DHCP_SNAME_LEN
]='\0';
840 if (!res_hnok(lease
->server_name
) ) {
841 warning("Bogus server name %s", lease
->server_name
);
842 free_client_lease(lease
);
848 /* Ditto for the filename. */
849 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
850 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 1)) &&
851 packet
->raw
->file
[0]) {
852 /* Don't count on the NUL terminator. */
853 lease
->filename
= malloc(DHCP_FILE_LEN
+ 1);
854 if (!lease
->filename
) {
855 warning("dhcpoffer: no memory for filename.");
856 free_client_lease(lease
);
859 memcpy(lease
->filename
, packet
->raw
->file
, DHCP_FILE_LEN
);
860 lease
->filename
[DHCP_FILE_LEN
]='\0';
866 dhcpnak(struct packet
*packet
)
868 struct interface_info
*ip
= packet
->interface
;
870 /* If we're not receptive to an offer right now, or if the offer
871 has an unrecognizable transaction id, then just drop it. */
872 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
873 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
874 (memcmp(packet
->interface
->hw_address
.haddr
,
875 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
878 if (ip
->client
->state
!= S_REBOOTING
&&
879 ip
->client
->state
!= S_REQUESTING
&&
880 ip
->client
->state
!= S_RENEWING
&&
881 ip
->client
->state
!= S_REBINDING
)
884 note("DHCPNAK from %s", piaddr(packet
->client_addr
));
886 if (!ip
->client
->active
) {
887 note("DHCPNAK with no active lease.\n");
891 free_client_lease(ip
->client
->active
);
892 ip
->client
->active
= NULL
;
894 /* Stop sending DHCPREQUEST packets... */
895 cancel_timeout(send_request
, ip
);
897 ip
->client
->state
= S_INIT
;
901 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
902 one after the right interval has expired. If we don't get an offer by
903 the time we reach the panic interval, call the panic function. */
906 send_discover(void *ipp
)
908 struct interface_info
*ip
= ipp
;
909 int interval
, increase
= 1;
911 DH_DbgPrint(MID_TRACE
,("Doing discover on interface %p\n",ip
));
913 /* Figure out how long it's been since we started transmitting. */
914 interval
= cur_time
- ip
->client
->first_sending
;
916 /* If we're past the panic timeout, call the script and tell it
917 we haven't found anything for this interface yet. */
918 if (interval
> ip
->client
->config
->timeout
) {
923 /* If we're selecting media, try the whole list before doing
924 the exponential backoff, but if we've already received an
925 offer, stop looping, because we obviously have it right. */
926 if (!ip
->client
->offered_leases
&&
927 ip
->client
->config
->media
) {
930 if (ip
->client
->medium
) {
931 ip
->client
->medium
= ip
->client
->medium
->next
;
934 if (!ip
->client
->medium
) {
936 error("No valid media types for %s!", ip
->name
);
937 ip
->client
->medium
= ip
->client
->config
->media
;
941 note("Trying medium \"%s\" %d", ip
->client
->medium
->string
,
943 /* XXX Support other media types eventually */
947 * If we're supposed to increase the interval, do so. If it's
948 * currently zero (i.e., we haven't sent any packets yet), set
949 * it to one; otherwise, add to it a random number between zero
950 * and two times itself. On average, this means that it will
951 * double with every transmission.
954 if (!ip
->client
->interval
)
955 ip
->client
->interval
=
956 ip
->client
->config
->initial_interval
;
958 ip
->client
->interval
+= (rand() >> 2) %
959 (2 * ip
->client
->interval
);
962 /* Don't backoff past cutoff. */
963 if (ip
->client
->interval
>
964 ip
->client
->config
->backoff_cutoff
)
965 ip
->client
->interval
=
966 ((ip
->client
->config
->backoff_cutoff
/ 2)
968 ip
->client
->config
->backoff_cutoff
));
969 } else if (!ip
->client
->interval
)
970 ip
->client
->interval
=
971 ip
->client
->config
->initial_interval
;
973 /* If the backoff would take us to the panic timeout, just use that
975 if (cur_time
+ ip
->client
->interval
>
976 ip
->client
->first_sending
+ ip
->client
->config
->timeout
)
977 ip
->client
->interval
=
978 (ip
->client
->first_sending
+
979 ip
->client
->config
->timeout
) - cur_time
+ 1;
981 /* Record the number of seconds since we started sending. */
982 if (interval
< 65536)
983 ip
->client
->packet
.secs
= htons(interval
);
985 ip
->client
->packet
.secs
= htons(65535);
986 ip
->client
->secs
= ip
->client
->packet
.secs
;
988 note("DHCPDISCOVER on %s to %s port %d interval %ld",
989 ip
->name
, inet_ntoa(sockaddr_broadcast
.sin_addr
),
990 ntohs(sockaddr_broadcast
.sin_port
), ip
->client
->interval
);
992 /* Send out a packet. */
993 (void)send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
994 inaddr_any
, &sockaddr_broadcast
, NULL
);
996 DH_DbgPrint(MID_TRACE
,("discover timeout: now %x -> then %x\n",
997 cur_time
, cur_time
+ ip
->client
->interval
));
999 add_timeout(cur_time
+ ip
->client
->interval
, send_discover
, ip
);
1003 * state_panic gets called if we haven't received any offers in a preset
1004 * amount of time. When this happens, we try to use existing leases
1005 * that haven't yet expired, and failing that, we call the client script
1006 * and hope it can do something.
1009 state_panic(void *ipp
)
1011 struct interface_info
*ip
= ipp
;
1012 struct client_lease
*loop
= ip
->client
->active
;
1013 struct client_lease
*lp
;
1015 note("No DHCPOFFERS received.");
1017 /* We may not have an active lease, but we may have some
1018 predefined leases that we can try. */
1019 if (!ip
->client
->active
&& ip
->client
->leases
)
1022 /* Run through the list of leases and see if one can be used. */
1023 while (ip
->client
->active
) {
1024 if (ip
->client
->active
->expiry
> cur_time
) {
1025 note("Trying recorded lease %s",
1026 piaddr(ip
->client
->active
->address
));
1027 /* Run the client script with the existing
1029 script_init("TIMEOUT",
1030 ip
->client
->active
->medium
);
1031 script_write_params("new_", ip
->client
->active
);
1032 if (ip
->client
->alias
)
1033 script_write_params("alias_",
1036 /* If the old lease is still good and doesn't
1037 yet need renewal, go into BOUND state and
1038 timeout at the renewal time. */
1040 ip
->client
->active
->renewal
) {
1041 ip
->client
->state
= S_BOUND
;
1042 note("bound: renewal in %ld seconds.",
1043 ip
->client
->active
->renewal
-
1046 ip
->client
->active
->renewal
,
1049 ip
->client
->state
= S_BOUND
;
1050 note("bound: immediate renewal.");
1053 reinitialize_interfaces();
1057 /* If there are no other leases, give up. */
1058 if (!ip
->client
->leases
) {
1059 ip
->client
->leases
= ip
->client
->active
;
1060 ip
->client
->active
= NULL
;
1065 /* Otherwise, put the active lease at the end of the
1066 lease list, and try another lease.. */
1067 for (lp
= ip
->client
->leases
; lp
->next
; lp
= lp
->next
)
1069 lp
->next
= ip
->client
->active
;
1071 lp
->next
->next
= NULL
;
1072 ip
->client
->active
= ip
->client
->leases
;
1073 ip
->client
->leases
= ip
->client
->leases
->next
;
1075 /* If we already tried this lease, we've exhausted the
1076 set of leases, so we might as well give up for
1078 if (ip
->client
->active
== loop
)
1081 loop
= ip
->client
->active
;
1084 /* No leases were available, or what was available didn't work, so
1085 tell the shell script that we failed to allocate an address,
1086 and try again later. */
1087 note("No working leases in persistent database - sleeping.\n");
1088 ip
->client
->state
= S_INIT
;
1089 add_timeout(cur_time
+ ip
->client
->config
->retry_interval
, state_init
,
1091 /* XXX Take any failure actions necessary */
1095 send_request(void *ipp
)
1097 struct interface_info
*ip
= ipp
;
1098 struct sockaddr_in destination
;
1099 struct in_addr from
;
1102 /* Figure out how long it's been since we started transmitting. */
1103 interval
= cur_time
- ip
->client
->first_sending
;
1105 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1106 past the reboot timeout, go to INIT and see if we can
1107 DISCOVER an address... */
1108 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1109 means either that we're on a network with no DHCP server,
1110 or that our server is down. In the latter case, assuming
1111 that there is a backup DHCP server, DHCPDISCOVER will get
1112 us a new address, but we could also have successfully
1113 reused our old address. In the former case, we're hosed
1114 anyway. This is not a win-prone situation. */
1115 if ((ip
->client
->state
== S_REBOOTING
||
1116 ip
->client
->state
== S_REQUESTING
) &&
1117 interval
> ip
->client
->config
->reboot_timeout
) {
1118 ip
->client
->state
= S_INIT
;
1119 cancel_timeout(send_request
, ip
);
1124 /* If we're in the reboot state, make sure the media is set up
1126 if (ip
->client
->state
== S_REBOOTING
&&
1127 !ip
->client
->medium
&&
1128 ip
->client
->active
->medium
) {
1129 script_init("MEDIUM", ip
->client
->active
->medium
);
1131 /* If the medium we chose won't fly, go to INIT state. */
1132 /* XXX Nothing for now */
1134 /* Record the medium. */
1135 ip
->client
->medium
= ip
->client
->active
->medium
;
1138 /* If the lease has expired, relinquish the address and go back
1139 to the INIT state. */
1140 if (ip
->client
->state
!= S_REQUESTING
&&
1141 cur_time
> ip
->client
->active
->expiry
) {
1142 PDHCP_ADAPTER Adapter
= AdapterFindInfo( ip
);
1143 /* Run the client script with the new parameters. */
1144 /* No script actions necessary in the expiry case */
1145 /* Now do a preinit on the interface so that we can
1146 discover a new address. */
1149 DeleteIPAddress( Adapter
->NteContext
);
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(void)
1513 struct client_lease
*lp
;
1516 leaseFile
= fopen(path_dhclient_db
, "w");
1518 error("can't create %s: %m", 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();
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: %m", path_dhclient_db
);
1558 fprintf(leaseFile
, "lease {\n");
1559 if (lease
->is_bootp
)
1560 fprintf(leaseFile
, " bootp;\n");
1561 fprintf(leaseFile
, " interface \"%s\";\n", ip
->name
);
1562 fprintf(leaseFile
, " fixed-address %s;\n", piaddr(lease
->address
));
1563 if (lease
->filename
)
1564 fprintf(leaseFile
, " filename \"%s\";\n", lease
->filename
);
1565 if (lease
->server_name
)
1566 fprintf(leaseFile
, " server-name \"%s\";\n",
1567 lease
->server_name
);
1569 fprintf(leaseFile
, " medium \"%s\";\n", lease
->medium
->string
);
1570 for (i
= 0; i
< 256; i
++)
1571 if (lease
->options
[i
].len
)
1572 fprintf(leaseFile
, " option %s %s;\n",
1573 dhcp_options
[i
].name
,
1574 pretty_print_option(i
, lease
->options
[i
].data
,
1575 lease
->options
[i
].len
, 1, 1));
1577 t
= gmtime(&lease
->renewal
);
1578 fprintf(leaseFile
, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1579 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1580 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1581 t
= gmtime(&lease
->rebind
);
1582 fprintf(leaseFile
, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1583 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1584 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1585 t
= gmtime(&lease
->expiry
);
1586 fprintf(leaseFile
, " expire %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 fprintf(leaseFile
, "}\n");
1594 script_init(char *reason
, struct string_list
*medium
)
1596 size_t len
, mediumlen
= 0;
1597 struct imsg_hdr hdr
;
1601 if (medium
!= NULL
&& medium
->string
!= NULL
)
1602 mediumlen
= strlen(medium
->string
);
1604 hdr
.code
= IMSG_SCRIPT_INIT
;
1605 hdr
.len
= sizeof(struct imsg_hdr
) +
1606 sizeof(size_t) + mediumlen
+
1607 sizeof(size_t) + strlen(reason
);
1609 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1610 error("buf_open: %m");
1613 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1614 errs
+= buf_add(buf
, &mediumlen
, sizeof(mediumlen
));
1616 errs
+= buf_add(buf
, medium
->string
, mediumlen
);
1617 len
= strlen(reason
);
1618 errs
+= buf_add(buf
, &len
, sizeof(len
));
1619 errs
+= buf_add(buf
, reason
, len
);
1622 error("buf_add: %m");
1624 if (buf_close(privfd
, buf
) == -1)
1625 error("buf_close: %m");
1629 priv_script_init(char *reason
, char *medium
)
1631 struct interface_info
*ip
= ifi
;
1634 // XXX Do we need to do anything?
1639 priv_script_write_params(char *prefix
, struct client_lease
*lease
)
1641 struct interface_info
*ip
= ifi
;
1642 u_int8_t dbuf
[1500];
1646 script_set_env(ip
->client
, prefix
, "ip_address",
1647 piaddr(lease
->address
));
1650 if (lease
->options
[DHO_SUBNET_MASK
].len
&&
1651 (lease
->options
[DHO_SUBNET_MASK
].len
<
1652 sizeof(lease
->address
.iabuf
))) {
1653 struct iaddr netmask
, subnet
, broadcast
;
1655 memcpy(netmask
.iabuf
, lease
->options
[DHO_SUBNET_MASK
].data
,
1656 lease
->options
[DHO_SUBNET_MASK
].len
);
1657 netmask
.len
= lease
->options
[DHO_SUBNET_MASK
].len
;
1659 subnet
= subnet_number(lease
->address
, netmask
);
1662 script_set_env(ip
->client
, prefix
, "network_number",
1665 if (!lease
->options
[DHO_BROADCAST_ADDRESS
].len
) {
1666 broadcast
= broadcast_addr(subnet
, netmask
);
1669 script_set_env(ip
->client
, prefix
,
1670 "broadcast_address",
1680 if (lease
->filename
)
1681 script_set_env(ip
->client
, prefix
, "filename", lease
->filename
);
1682 if (lease
->server_name
)
1683 script_set_env(ip
->client
, prefix
, "server_name",
1684 lease
->server_name
);
1687 for (i
= 0; i
< 256; i
++) {
1688 u_int8_t
*dp
= NULL
;
1690 if (ip
->client
->config
->defaults
[i
].len
) {
1691 if (lease
->options
[i
].len
) {
1693 ip
->client
->config
->default_actions
[i
]) {
1694 case ACTION_DEFAULT
:
1695 dp
= lease
->options
[i
].data
;
1696 len
= lease
->options
[i
].len
;
1698 case ACTION_SUPERSEDE
:
1701 config
->defaults
[i
].data
;
1703 config
->defaults
[i
].len
;
1705 case ACTION_PREPEND
:
1707 config
->defaults
[i
].len
+
1708 lease
->options
[i
].len
;
1709 if (len
>= sizeof(dbuf
)) {
1710 warning("no space to %s %s",
1712 dhcp_options
[i
].name
);
1718 config
->defaults
[i
].data
,
1720 config
->defaults
[i
].len
);
1721 memcpy(dp
+ ip
->client
->
1722 config
->defaults
[i
].len
,
1723 lease
->options
[i
].data
,
1724 lease
->options
[i
].len
);
1729 config
->defaults
[i
].len
+
1730 lease
->options
[i
].len
;
1731 if (len
> sizeof(dbuf
)) {
1732 warning("no space to %s %s",
1734 dhcp_options
[i
].name
);
1739 lease
->options
[i
].data
,
1740 lease
->options
[i
].len
);
1741 memcpy(dp
+ lease
->options
[i
].len
,
1743 config
->defaults
[i
].data
,
1745 config
->defaults
[i
].len
);
1750 config
->defaults
[i
].data
;
1752 config
->defaults
[i
].len
;
1754 } else if (lease
->options
[i
].len
) {
1755 len
= lease
->options
[i
].len
;
1756 dp
= lease
->options
[i
].data
;
1764 if (dhcp_option_ev_name(name
, sizeof(name
),
1766 script_set_env(ip
->client
, prefix
, name
,
1767 pretty_print_option(i
, dp
, len
, 0, 0));
1772 snprintf(tbuf
, sizeof(tbuf
), "%d", (int)lease
->expiry
);
1773 script_set_env(ip
->client
, prefix
, "expiry", tbuf
);
1778 script_write_params(char *prefix
, struct client_lease
*lease
)
1780 size_t fn_len
= 0, sn_len
= 0, pr_len
= 0;
1781 struct imsg_hdr hdr
;
1785 if (lease
->filename
!= NULL
)
1786 fn_len
= strlen(lease
->filename
);
1787 if (lease
->server_name
!= NULL
)
1788 sn_len
= strlen(lease
->server_name
);
1790 pr_len
= strlen(prefix
);
1792 hdr
.code
= IMSG_SCRIPT_WRITE_PARAMS
;
1793 hdr
.len
= sizeof(hdr
) + sizeof(struct client_lease
) +
1794 sizeof(size_t) + fn_len
+ sizeof(size_t) + sn_len
+
1795 sizeof(size_t) + pr_len
;
1797 for (i
= 0; i
< 256; i
++)
1798 hdr
.len
+= sizeof(int) + lease
->options
[i
].len
;
1800 scripttime
= time(NULL
);
1802 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1803 error("buf_open: %m");
1806 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1807 errs
+= buf_add(buf
, lease
, sizeof(struct client_lease
));
1808 errs
+= buf_add(buf
, &fn_len
, sizeof(fn_len
));
1809 errs
+= buf_add(buf
, lease
->filename
, fn_len
);
1810 errs
+= buf_add(buf
, &sn_len
, sizeof(sn_len
));
1811 errs
+= buf_add(buf
, lease
->server_name
, sn_len
);
1812 errs
+= buf_add(buf
, &pr_len
, sizeof(pr_len
));
1813 errs
+= buf_add(buf
, prefix
, pr_len
);
1815 for (i
= 0; i
< 256; i
++) {
1816 errs
+= buf_add(buf
, &lease
->options
[i
].len
,
1817 sizeof(lease
->options
[i
].len
));
1818 errs
+= buf_add(buf
, lease
->options
[i
].data
,
1819 lease
->options
[i
].len
);
1823 error("buf_add: %m");
1825 if (buf_close(privfd
, buf
) == -1)
1826 error("buf_close: %m");
1830 dhcp_option_ev_name(char *buf
, size_t buflen
, struct dhcp_option
*option
)
1834 for (i
= 0; option
->name
[i
]; i
++) {
1835 if (i
+ 1 == buflen
)
1837 if (option
->name
[i
] == '-')
1840 buf
[i
] = option
->name
[i
];
1851 static int state
= 0;
1853 if (no_daemon
|| state
)
1858 /* Stop logging to stderr... */
1861 if (daemon(1, 0) == -1)
1864 /* we are chrooted, daemon(3) fails to open /dev/null */
1866 dup2(nullfd
, STDIN_FILENO
);
1867 dup2(nullfd
, STDOUT_FILENO
);
1868 dup2(nullfd
, STDERR_FILENO
);
1876 check_option(struct client_lease
*l
, int option
)
1881 /* we use this, since this is what gets passed to dhclient-script */
1883 opbuf
= pretty_print_option(option
, l
->options
[option
].data
,
1884 l
->options
[option
].len
, 0, 0);
1886 sbuf
= option_as_string(option
, l
->options
[option
].data
,
1887 l
->options
[option
].len
);
1890 case DHO_SUBNET_MASK
:
1891 case DHO_TIME_SERVERS
:
1892 case DHO_NAME_SERVERS
:
1894 case DHO_DOMAIN_NAME_SERVERS
:
1895 case DHO_LOG_SERVERS
:
1896 case DHO_COOKIE_SERVERS
:
1897 case DHO_LPR_SERVERS
:
1898 case DHO_IMPRESS_SERVERS
:
1899 case DHO_RESOURCE_LOCATION_SERVERS
:
1900 case DHO_SWAP_SERVER
:
1901 case DHO_BROADCAST_ADDRESS
:
1902 case DHO_NIS_SERVERS
:
1903 case DHO_NTP_SERVERS
:
1904 case DHO_NETBIOS_NAME_SERVERS
:
1905 case DHO_NETBIOS_DD_SERVER
:
1906 case DHO_FONT_SERVERS
:
1907 case DHO_DHCP_SERVER_IDENTIFIER
:
1908 if (!ipv4addrs(opbuf
)) {
1909 warning("Invalid IP address in option(%d): %s", option
, opbuf
);
1914 case DHO_DOMAIN_NAME
:
1915 case DHO_NIS_DOMAIN
:
1916 if (!res_hnok(sbuf
)) {
1917 warning("Bogus Host Name option %d: %s (%s)", option
,
1923 case DHO_TIME_OFFSET
:
1925 case DHO_MERIT_DUMP
:
1927 case DHO_EXTENSIONS_PATH
:
1928 case DHO_IP_FORWARDING
:
1929 case DHO_NON_LOCAL_SOURCE_ROUTING
:
1930 case DHO_POLICY_FILTER
:
1931 case DHO_MAX_DGRAM_REASSEMBLY
:
1932 case DHO_DEFAULT_IP_TTL
:
1933 case DHO_PATH_MTU_AGING_TIMEOUT
:
1934 case DHO_PATH_MTU_PLATEAU_TABLE
:
1935 case DHO_INTERFACE_MTU
:
1936 case DHO_ALL_SUBNETS_LOCAL
:
1937 case DHO_PERFORM_MASK_DISCOVERY
:
1938 case DHO_MASK_SUPPLIER
:
1939 case DHO_ROUTER_DISCOVERY
:
1940 case DHO_ROUTER_SOLICITATION_ADDRESS
:
1941 case DHO_STATIC_ROUTES
:
1942 case DHO_TRAILER_ENCAPSULATION
:
1943 case DHO_ARP_CACHE_TIMEOUT
:
1944 case DHO_IEEE802_3_ENCAPSULATION
:
1945 case DHO_DEFAULT_TCP_TTL
:
1946 case DHO_TCP_KEEPALIVE_INTERVAL
:
1947 case DHO_TCP_KEEPALIVE_GARBAGE
:
1948 case DHO_VENDOR_ENCAPSULATED_OPTIONS
:
1949 case DHO_NETBIOS_NODE_TYPE
:
1950 case DHO_NETBIOS_SCOPE
:
1951 case DHO_X_DISPLAY_MANAGER
:
1952 case DHO_DHCP_REQUESTED_ADDRESS
:
1953 case DHO_DHCP_LEASE_TIME
:
1954 case DHO_DHCP_OPTION_OVERLOAD
:
1955 case DHO_DHCP_MESSAGE_TYPE
:
1956 case DHO_DHCP_PARAMETER_REQUEST_LIST
:
1957 case DHO_DHCP_MESSAGE
:
1958 case DHO_DHCP_MAX_MESSAGE_SIZE
:
1959 case DHO_DHCP_RENEWAL_TIME
:
1960 case DHO_DHCP_REBINDING_TIME
:
1961 case DHO_DHCP_CLASS_IDENTIFIER
:
1962 case DHO_DHCP_CLIENT_IDENTIFIER
:
1963 case DHO_DHCP_USER_CLASS_ID
:
1967 warning("unknown dhcp option value 0x%x", option
);
1968 return (unknown_ok
);
1973 res_hnok(const char *dn
)
1975 int pch
= PERIOD
, ch
= *dn
++;
1977 while (ch
!= '\0') {
1980 if (periodchar(ch
)) {
1982 } else if (periodchar(pch
)) {
1983 if (!borderchar(ch
))
1985 } else if (periodchar(nch
) || nch
== '\0') {
1986 if (!borderchar(ch
))
1989 if (!middlechar(ch
))
1997 /* Does buf consist only of dotted decimal ipv4 addrs?
1998 * return how many if so,
1999 * otherwise, return 0
2002 ipv4addrs(char * buf
)
2008 note("Input: %s", buf
);
2011 tmp
= strtok(buf
, " ");
2012 note("got %s", tmp
);
2013 if( tmp
&& inet_aton(tmp
, &jnk
) ) i
++;
2022 option_as_string(unsigned int code
, unsigned char *data
, int len
)
2024 static char optbuf
[32768]; /* XXX */
2026 int opleft
= sizeof(optbuf
);
2027 unsigned char *dp
= data
;
2030 error("option_as_string: bad code %d", code
);
2032 for (; dp
< data
+ len
; dp
++) {
2033 if (!isascii(*dp
) || !isprint(*dp
)) {
2034 if (dp
+ 1 != data
+ len
|| *dp
!= 0) {
2035 _snprintf(op
, opleft
, "\\%03o", *dp
);
2039 } else if (*dp
== '"' || *dp
== '\'' || *dp
== '$' ||
2040 *dp
== '`' || *dp
== '\\') {
2054 warning("dhcp option too large");
2060 fork_privchld(int fd
, int fd2
)
2062 struct pollfd pfd
[1];
2067 error("cannot fork");
2074 setproctitle("%s [priv]", ifi
->name
);
2076 dup2(nullfd
, STDIN_FILENO
);
2077 dup2(nullfd
, STDOUT_FILENO
);
2078 dup2(nullfd
, STDERR_FILENO
);
2084 pfd
[0].events
= POLLIN
;
2085 if ((nfds
= poll(pfd
, 1, INFTIM
)) == -1)
2087 error("poll error");
2089 if (nfds
== 0 || !(pfd
[0].revents
& POLLIN
))