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 char *path_dhclient_conf
= _PATH_DHCLIENT_CONF
;
77 char *path_dhclient_db
= NULL
;
83 struct iaddr iaddr_broadcast
= { 4, { 255, 255, 255, 255 } };
84 struct in_addr inaddr_any
;
85 struct sockaddr_in sockaddr_broadcast
;
88 * ASSERT_STATE() does nothing now; it used to be
89 * assert (state_is == state_shouldbe).
91 #define ASSERT_STATE(state_is, state_shouldbe) {}
93 #define TIME_MAX 2147483647
101 int check_option(struct client_lease
*l
, int option
);
102 int ipv4addrs(char * buf
);
103 int res_hnok(const char *dn
);
104 char *option_as_string(unsigned int code
, unsigned char *data
, int len
);
105 int fork_privchld(int, int);
106 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
);
108 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
112 /* XXX Implement me */
113 int check_arp( struct interface_info
*ip
, struct client_lease
*lp
) {
118 DispatchMain(DWORD argc
, LPTSTR
*argv
)
123 static SERVICE_TABLE_ENTRY ServiceTable
[2] =
125 {TEXT("DHCP"), DispatchMain
},
130 main(int argc
, char *argv
[])
138 memset(&sockaddr_broadcast
, 0, sizeof(sockaddr_broadcast
));
139 sockaddr_broadcast
.sin_family
= AF_INET
;
140 sockaddr_broadcast
.sin_port
= htons(REMOTE_PORT
);
141 sockaddr_broadcast
.sin_addr
.s_addr
= INADDR_BROADCAST
;
142 inaddr_any
.s_addr
= INADDR_ANY
;
144 DH_DbgPrint(MID_TRACE
,("DHCP Service Started\n"));
146 bootp_packet_handler
= do_packet
;
148 DH_DbgPrint(MID_TRACE
,("Going into dispatch()\n"));
150 StartServiceCtrlDispatcher(ServiceTable
);
159 // extern char *__progname;
161 // fprintf(stderr, "usage: %s [-dqu] ", __progname);
162 fprintf(stderr
, "usage: dhclient [-dqu] ");
163 fprintf(stderr
, "[-c conffile] [-l leasefile] interface\n");
170 * Each routine is called from the dhclient_state_machine() in one of
172 * -> entering INIT state
173 * -> recvpacket_flag == 0: timeout in this state
174 * -> otherwise: received a packet in this state
176 * Return conditions as handled by dhclient_state_machine():
177 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
178 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
179 * Returns 0: finish the nap which was interrupted for no good reason.
181 * Several per-interface variables are used to keep track of the process:
182 * active_lease: the lease that is being used on the interface
183 * (null pointer if not configured yet).
184 * offered_leases: leases corresponding to DHCPOFFER messages that have
185 * been sent to us by DHCP servers.
186 * acked_leases: leases corresponding to DHCPACK messages that have been
187 * sent to us by DHCP servers.
188 * sendpacket: DHCP packet we're trying to send.
189 * destination: IP address to send sendpacket to
190 * In addition, there are several relevant per-lease variables.
191 * T1_expiry, T2_expiry, lease_expiry: lease milestones
192 * In the active lease, these control the process of renewing the lease;
193 * In leases on the acked_leases list, this simply determines when we
194 * can no longer legitimately use the lease.
198 state_reboot(void *ipp
)
200 struct interface_info
*ip
= ipp
;
201 ULONG foo
= (ULONG
) GetTickCount();
203 /* If we don't remember an active lease, go straight to INIT. */
204 if (!ip
->client
->active
|| ip
->client
->active
->is_bootp
) {
209 /* We are in the rebooting state. */
210 ip
->client
->state
= S_REBOOTING
;
212 /* make_request doesn't initialize xid because it normally comes
213 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
214 so pick an xid now. */
215 ip
->client
->xid
= RtlRandom(&foo
);
217 /* Make a DHCPREQUEST packet, and set appropriate per-interface
219 make_request(ip
, ip
->client
->active
);
220 ip
->client
->destination
= iaddr_broadcast
;
221 time(&ip
->client
->first_sending
);
222 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
224 /* Zap the medium list... */
225 ip
->client
->medium
= NULL
;
227 /* Send out the first DHCPREQUEST packet. */
232 * Called when a lease has completely expired and we've
233 * been unable to renew it.
236 state_init(void *ipp
)
238 struct interface_info
*ip
= ipp
;
240 ASSERT_STATE(state
, S_INIT
);
242 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
244 make_discover(ip
, ip
->client
->active
);
245 ip
->client
->xid
= ip
->client
->packet
.xid
;
246 ip
->client
->destination
= iaddr_broadcast
;
247 ip
->client
->state
= S_SELECTING
;
248 time(&ip
->client
->first_sending
);
249 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
251 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
257 * state_selecting is called when one or more DHCPOFFER packets
258 * have been received and a configurable period of time has passed.
261 state_selecting(void *ipp
)
263 struct interface_info
*ip
= ipp
;
264 struct client_lease
*lp
, *next
, *picked
;
267 ASSERT_STATE(state
, S_SELECTING
);
271 /* Cancel state_selecting and send_discover timeouts, since either
272 one could have got us here. */
273 cancel_timeout(state_selecting
, ip
);
274 cancel_timeout(send_discover
, ip
);
276 /* We have received one or more DHCPOFFER packets. Currently,
277 the only criterion by which we judge leases is whether or
278 not we get a response when we arp for them. */
280 for (lp
= ip
->client
->offered_leases
; lp
; lp
= next
) {
283 /* Check to see if we got an ARPREPLY for the address
284 in this particular lease. */
286 if( !check_arp(ip
,lp
) ) goto freeit
;
291 free_client_lease(lp
);
294 ip
->client
->offered_leases
= NULL
;
296 /* If we just tossed all the leases we were offered, go back
299 ip
->client
->state
= S_INIT
;
304 /* If it was a BOOTREPLY, we can just take the address right now. */
305 if (!picked
->options
[DHO_DHCP_MESSAGE_TYPE
].len
) {
306 ip
->client
->new = picked
;
308 /* Make up some lease expiry times
309 XXX these should be configurable. */
310 ip
->client
->new->expiry
= cur_time
+ 12000;
311 ip
->client
->new->renewal
+= cur_time
+ 8000;
312 ip
->client
->new->rebind
+= cur_time
+ 10000;
314 ip
->client
->state
= S_REQUESTING
;
316 /* Bind to the address we received. */
321 /* Go to the REQUESTING state. */
322 ip
->client
->destination
= iaddr_broadcast
;
323 ip
->client
->state
= S_REQUESTING
;
324 ip
->client
->first_sending
= cur_time
;
325 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
327 /* Make a DHCPREQUEST packet from the lease we picked. */
328 make_request(ip
, picked
);
329 ip
->client
->xid
= ip
->client
->packet
.xid
;
331 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
332 free_client_lease(picked
);
334 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
338 /* state_requesting is called when we receive a DHCPACK message after
339 having sent out one or more DHCPREQUEST packets. */
342 dhcpack(struct packet
*packet
)
344 struct interface_info
*ip
= packet
->interface
;
345 struct client_lease
*lease
;
350 /* If we're not receptive to an offer right now, or if the offer
351 has an unrecognizable transaction id, then just drop it. */
352 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
353 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
354 (memcmp(packet
->interface
->hw_address
.haddr
,
355 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
358 if (ip
->client
->state
!= S_REBOOTING
&&
359 ip
->client
->state
!= S_REQUESTING
&&
360 ip
->client
->state
!= S_RENEWING
&&
361 ip
->client
->state
!= S_REBINDING
)
364 note("DHCPACK from %s", piaddr(packet
->client_addr
));
366 lease
= packet_to_lease(packet
);
368 note("packet_to_lease failed.");
372 ip
->client
->new = lease
;
374 /* Stop resending DHCPREQUEST. */
375 cancel_timeout(send_request
, ip
);
377 /* Figure out the lease time. */
378 if (ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
)
379 ip
->client
->new->expiry
= getULong(
380 ip
->client
->new->options
[DHO_DHCP_LEASE_TIME
].data
);
382 ip
->client
->new->expiry
= DHCP_DEFAULT_LEASE_TIME
;
383 /* A number that looks negative here is really just very large,
384 because the lease expiry offset is unsigned. */
385 if (ip
->client
->new->expiry
< 0)
386 ip
->client
->new->expiry
= TIME_MAX
;
387 /* XXX should be fixed by resetting the client state */
388 if (ip
->client
->new->expiry
< 60)
389 ip
->client
->new->expiry
= 60;
391 /* Take the server-provided renewal time if there is one;
392 otherwise figure it out according to the spec. */
393 if (ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].len
)
394 ip
->client
->new->renewal
= getULong(
395 ip
->client
->new->options
[DHO_DHCP_RENEWAL_TIME
].data
);
397 ip
->client
->new->renewal
= ip
->client
->new->expiry
/ 2;
399 /* Same deal with the rebind time. */
400 if (ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].len
)
401 ip
->client
->new->rebind
= getULong(
402 ip
->client
->new->options
[DHO_DHCP_REBINDING_TIME
].data
);
404 ip
->client
->new->rebind
= ip
->client
->new->renewal
+
405 ip
->client
->new->renewal
/ 2 + ip
->client
->new->renewal
/ 4;
408 ip
->client
->new->obtained
= cur_time
;
410 ip
->client
->new->expiry
+= cur_time
;
411 /* Lease lengths can never be negative. */
412 if (ip
->client
->new->expiry
< cur_time
)
413 ip
->client
->new->expiry
= TIME_MAX
;
414 ip
->client
->new->renewal
+= cur_time
;
415 if (ip
->client
->new->renewal
< cur_time
)
416 ip
->client
->new->renewal
= TIME_MAX
;
417 ip
->client
->new->rebind
+= cur_time
;
418 if (ip
->client
->new->rebind
< cur_time
)
419 ip
->client
->new->rebind
= TIME_MAX
;
424 void set_name_servers( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
425 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
428 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
429 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &RegKey
) != ERROR_SUCCESS
)
433 if( new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
) {
435 struct iaddr nameserver
;
438 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].len
/ sizeof(ULONG
);
440 nsbuf
= malloc( addrs
* sizeof(IP_ADDRESS_STRING
) );
444 for( i
= 0; i
< addrs
; i
++ ) {
445 nameserver
.len
= sizeof(ULONG
);
446 memcpy( nameserver
.iabuf
,
447 new_lease
->options
[DHO_DOMAIN_NAME_SERVERS
].data
+
448 (i
* sizeof(ULONG
)), sizeof(ULONG
) );
449 strcat( nsbuf
, piaddr(nameserver
) );
450 if( i
!= addrs
-1 ) strcat( nsbuf
, "," );
453 DH_DbgPrint(MID_TRACE
,("Setting DhcpNameserver: %s\n", nsbuf
));
455 RegSetValueExA( RegKey
, "DhcpNameServer", 0, REG_SZ
,
456 (LPBYTE
)nsbuf
, strlen(nsbuf
) + 1 );
461 RegDeleteValueW( RegKey
, L
"DhcpNameServer" );
464 RegCloseKey( RegKey
);
468 void setup_adapter( PDHCP_ADAPTER Adapter
, struct client_lease
*new_lease
) {
469 CHAR Buffer
[200] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
470 struct iaddr netmask
;
475 strcat(Buffer
, Adapter
->DhclientInfo
.name
);
476 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, Buffer
, 0, KEY_WRITE
, &hkey
) != ERROR_SUCCESS
)
480 if( Adapter
->NteContext
)
481 DeleteIPAddress( Adapter
->NteContext
);
483 /* Set up our default router if we got one from the DHCP server */
484 if( new_lease
->options
[DHO_SUBNET_MASK
].len
) {
487 memcpy( netmask
.iabuf
,
488 new_lease
->options
[DHO_SUBNET_MASK
].data
,
489 new_lease
->options
[DHO_SUBNET_MASK
].len
);
490 Status
= AddIPAddress
491 ( *((ULONG
*)new_lease
->address
.iabuf
),
492 *((ULONG
*)netmask
.iabuf
),
493 Adapter
->IfMib
.dwIndex
,
494 &Adapter
->NteContext
,
495 &Adapter
->NteInstance
);
497 RegSetValueExA(hkey
, "DhcpIPAddress", 0, REG_SZ
, (LPBYTE
)piaddr(new_lease
->address
), strlen(piaddr(new_lease
->address
))+1);
499 for(i
= 0; i
< new_lease
->options
[DHO_SUBNET_MASK
].len
; i
++)
501 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_SUBNET_MASK
].data
[i
]);
502 if (i
+ 1 < new_lease
->options
[DHO_SUBNET_MASK
].len
)
505 RegSetValueExA(hkey
, "DhcpSubnetMask", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
506 RegSetValueExA(hkey
, "IPAddress", 0, REG_SZ
, (LPBYTE
)"0.0.0.0", 8);
507 RegSetValueExA(hkey
, "SubnetMask", 0, REG_SZ
, (LPBYTE
)"0.0.0.0", 8);
509 RegSetValueExA(hkey
, "EnableDHCP", 0, REG_DWORD
, (LPBYTE
)&dwEnableDHCP
, sizeof(DWORD
));
512 if( !NT_SUCCESS(Status
) )
513 warning("AddIPAddress: %lx\n", Status
);
516 if( new_lease
->options
[DHO_ROUTERS
].len
) {
519 Adapter
->RouterMib
.dwForwardDest
= 0; /* Default route */
520 Adapter
->RouterMib
.dwForwardMask
= 0;
521 Adapter
->RouterMib
.dwForwardMetric1
= 1;
523 if( Adapter
->RouterMib
.dwForwardNextHop
) {
524 /* If we set a default route before, delete it before continuing */
525 DeleteIpForwardEntry( &Adapter
->RouterMib
);
528 Adapter
->RouterMib
.dwForwardNextHop
=
529 *((ULONG
*)new_lease
->options
[DHO_ROUTERS
].data
);
531 Status
= CreateIpForwardEntry( &Adapter
->RouterMib
);
533 if( !NT_SUCCESS(Status
) )
534 warning("CreateIpForwardEntry: %lx\n", Status
);
538 for(i
= 0; i
< new_lease
->options
[DHO_ROUTERS
].len
; i
++)
540 sprintf(&Buffer
[strlen(Buffer
)], "%u", new_lease
->options
[DHO_ROUTERS
].data
[i
]);
541 if (i
+ 1 < new_lease
->options
[DHO_ROUTERS
].len
)
544 RegSetValueExA(hkey
, "DhcpDefaultGateway", 0, REG_SZ
, (LPBYTE
)Buffer
, strlen(Buffer
)+1);
545 RegSetValueExA(hkey
, "DefaultGateway", 0, REG_SZ
, (LPBYTE
)"0.0.0.0", 8);
555 bind_lease(struct interface_info
*ip
)
557 PDHCP_ADAPTER Adapter
;
558 struct client_lease
*new_lease
= ip
->client
->new;
563 /* Remember the medium. */
564 ip
->client
->new->medium
= ip
->client
->medium
;
565 ip
->client
->active
= ip
->client
->new;
566 ip
->client
->new = NULL
;
568 /* Set up a timeout to start the renewal process. */
569 /* Timeout of zero means no timeout (some implementations seem to use
572 if( ip
->client
->active
->renewal
- cur_time
)
573 add_timeout(ip
->client
->active
->renewal
, state_bound
, ip
);
575 note("bound to %s -- renewal in %ld seconds.",
576 piaddr(ip
->client
->active
->address
),
577 (long int)(ip
->client
->active
->renewal
- cur_time
));
579 ip
->client
->state
= S_BOUND
;
581 Adapter
= AdapterFindInfo( ip
);
583 if( Adapter
) setup_adapter( Adapter
, new_lease
);
585 warning("Could not find adapter for info %p\n", ip
);
588 set_name_servers( Adapter
, new_lease
);
592 * state_bound is called when we've successfully bound to a particular
593 * lease, but the renewal time on that lease has expired. We are
594 * expected to unicast a DHCPREQUEST to the server that gave us our
598 state_bound(void *ipp
)
600 struct interface_info
*ip
= ipp
;
602 ASSERT_STATE(state
, S_BOUND
);
604 /* T1 has expired. */
605 make_request(ip
, ip
->client
->active
);
606 ip
->client
->xid
= ip
->client
->packet
.xid
;
608 if (ip
->client
->active
->options
[DHO_DHCP_SERVER_IDENTIFIER
].len
== 4) {
609 memcpy(ip
->client
->destination
.iabuf
, ip
->client
->active
->
610 options
[DHO_DHCP_SERVER_IDENTIFIER
].data
, 4);
611 ip
->client
->destination
.len
= 4;
613 ip
->client
->destination
= iaddr_broadcast
;
615 time(&ip
->client
->first_sending
);
616 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
617 ip
->client
->state
= S_RENEWING
;
619 /* Send the first packet immediately. */
624 bootp(struct packet
*packet
)
626 struct iaddrlist
*ap
;
628 if (packet
->raw
->op
!= BOOTREPLY
)
631 /* If there's a reject list, make sure this packet's sender isn't
633 for (ap
= packet
->interface
->client
->config
->reject_list
;
635 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
636 note("BOOTREPLY from %s rejected.", piaddr(ap
->addr
));
644 dhcp(struct packet
*packet
)
646 struct iaddrlist
*ap
;
647 void (*handler
)(struct packet
*);
650 switch (packet
->packet_type
) {
667 /* If there's a reject list, make sure this packet's sender isn't
669 for (ap
= packet
->interface
->client
->config
->reject_list
;
671 if (addr_eq(packet
->client_addr
, ap
->addr
)) {
672 note("%s from %s rejected.", type
, piaddr(ap
->addr
));
680 dhcpoffer(struct packet
*packet
)
682 struct interface_info
*ip
= packet
->interface
;
683 struct client_lease
*lease
, *lp
;
685 int arp_timeout_needed
= 0, stop_selecting
;
686 char *name
= packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
?
687 "DHCPOFFER" : "BOOTREPLY";
692 /* If we're not receptive to an offer right now, or if the offer
693 has an unrecognizable transaction id, then just drop it. */
694 if (ip
->client
->state
!= S_SELECTING
||
695 packet
->interface
->client
->xid
!= packet
->raw
->xid
||
696 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
697 (memcmp(packet
->interface
->hw_address
.haddr
,
698 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
701 note("%s from %s", name
, piaddr(packet
->client_addr
));
704 /* If this lease doesn't supply the minimum required parameters,
706 for (i
= 0; ip
->client
->config
->required_options
[i
]; i
++) {
707 if (!packet
->options
[ip
->client
->config
->
708 required_options
[i
]].len
) {
709 note("%s isn't satisfactory.", name
);
714 /* If we've already seen this lease, don't record it again. */
715 for (lease
= ip
->client
->offered_leases
;
716 lease
; lease
= lease
->next
) {
717 if (lease
->address
.len
== sizeof(packet
->raw
->yiaddr
) &&
718 !memcmp(lease
->address
.iabuf
,
719 &packet
->raw
->yiaddr
, lease
->address
.len
)) {
720 debug("%s already seen.", name
);
725 lease
= packet_to_lease(packet
);
727 note("packet_to_lease failed.");
731 /* If this lease was acquired through a BOOTREPLY, record that
733 if (!packet
->options
[DHO_DHCP_MESSAGE_TYPE
].len
)
736 /* Record the medium under which this lease was offered. */
737 lease
->medium
= ip
->client
->medium
;
739 /* Send out an ARP Request for the offered IP address. */
740 if( !check_arp( ip
, lease
) ) {
741 note("Arp check failed\n");
745 /* Figure out when we're supposed to stop selecting. */
747 ip
->client
->first_sending
+ ip
->client
->config
->select_interval
;
749 /* If this is the lease we asked for, put it at the head of the
750 list, and don't mess with the arp request timeout. */
751 if (lease
->address
.len
== ip
->client
->requested_address
.len
&&
752 !memcmp(lease
->address
.iabuf
,
753 ip
->client
->requested_address
.iabuf
,
754 ip
->client
->requested_address
.len
)) {
755 lease
->next
= ip
->client
->offered_leases
;
756 ip
->client
->offered_leases
= lease
;
758 /* If we already have an offer, and arping for this
759 offer would take us past the selection timeout,
760 then don't extend the timeout - just hope for the
762 if (ip
->client
->offered_leases
&&
763 (cur_time
+ arp_timeout_needed
) > stop_selecting
)
764 arp_timeout_needed
= 0;
766 /* Put the lease at the end of the list. */
768 if (!ip
->client
->offered_leases
)
769 ip
->client
->offered_leases
= lease
;
771 for (lp
= ip
->client
->offered_leases
; lp
->next
;
778 /* If we're supposed to stop selecting before we've had time
779 to wait for the ARPREPLY, add some delay to wait for
781 if (stop_selecting
- cur_time
< arp_timeout_needed
)
782 stop_selecting
= cur_time
+ arp_timeout_needed
;
784 /* If the selecting interval has expired, go immediately to
785 state_selecting(). Otherwise, time out into
786 state_selecting at the select interval. */
787 if (stop_selecting
<= 0)
790 add_timeout(stop_selecting
, state_selecting
, ip
);
791 cancel_timeout(send_discover
, ip
);
795 /* Allocate a client_lease structure and initialize it from the parameters
796 in the specified packet. */
798 struct client_lease
*
799 packet_to_lease(struct packet
*packet
)
801 struct client_lease
*lease
;
804 lease
= malloc(sizeof(struct client_lease
));
807 warning("dhcpoffer: no memory to record lease.");
811 memset(lease
, 0, sizeof(*lease
));
813 /* Copy the lease options. */
814 for (i
= 0; i
< 256; i
++) {
815 if (packet
->options
[i
].len
) {
816 lease
->options
[i
].data
=
817 malloc(packet
->options
[i
].len
+ 1);
818 if (!lease
->options
[i
].data
) {
819 warning("dhcpoffer: no memory for option %d", i
);
820 free_client_lease(lease
);
823 memcpy(lease
->options
[i
].data
,
824 packet
->options
[i
].data
,
825 packet
->options
[i
].len
);
826 lease
->options
[i
].len
=
827 packet
->options
[i
].len
;
828 lease
->options
[i
].data
[lease
->options
[i
].len
] =
831 if (!check_option(lease
,i
)) {
832 /* ignore a bogus lease offer */
833 warning("Invalid lease option - ignoring offer");
834 free_client_lease(lease
);
840 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
841 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
, lease
->address
.len
);
843 lease
->serveraddress
.len
= sizeof(packet
->raw
->siaddr
);
844 memcpy(lease
->serveraddress
.iabuf
, &packet
->raw
->siaddr
, lease
->address
.len
);
847 /* If the server name was filled out, copy it. */
848 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
849 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 2)) &&
850 packet
->raw
->sname
[0]) {
851 lease
->server_name
= malloc(DHCP_SNAME_LEN
+ 1);
852 if (!lease
->server_name
) {
853 warning("dhcpoffer: no memory for server name.");
854 free_client_lease(lease
);
857 memcpy(lease
->server_name
, packet
->raw
->sname
, DHCP_SNAME_LEN
);
858 lease
->server_name
[DHCP_SNAME_LEN
]='\0';
859 if (!res_hnok(lease
->server_name
) ) {
860 warning("Bogus server name %s", lease
->server_name
);
861 free_client_lease(lease
);
867 /* Ditto for the filename. */
868 if ((!packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].len
||
869 !(packet
->options
[DHO_DHCP_OPTION_OVERLOAD
].data
[0] & 1)) &&
870 packet
->raw
->file
[0]) {
871 /* Don't count on the NUL terminator. */
872 lease
->filename
= malloc(DHCP_FILE_LEN
+ 1);
873 if (!lease
->filename
) {
874 warning("dhcpoffer: no memory for filename.");
875 free_client_lease(lease
);
878 memcpy(lease
->filename
, packet
->raw
->file
, DHCP_FILE_LEN
);
879 lease
->filename
[DHCP_FILE_LEN
]='\0';
885 dhcpnak(struct packet
*packet
)
887 struct interface_info
*ip
= packet
->interface
;
889 /* If we're not receptive to an offer right now, or if the offer
890 has an unrecognizable transaction id, then just drop it. */
891 if (packet
->interface
->client
->xid
!= packet
->raw
->xid
||
892 (packet
->interface
->hw_address
.hlen
!= packet
->raw
->hlen
) ||
893 (memcmp(packet
->interface
->hw_address
.haddr
,
894 packet
->raw
->chaddr
, packet
->raw
->hlen
)))
897 if (ip
->client
->state
!= S_REBOOTING
&&
898 ip
->client
->state
!= S_REQUESTING
&&
899 ip
->client
->state
!= S_RENEWING
&&
900 ip
->client
->state
!= S_REBINDING
)
903 note("DHCPNAK from %s", piaddr(packet
->client_addr
));
905 if (!ip
->client
->active
) {
906 note("DHCPNAK with no active lease.\n");
910 free_client_lease(ip
->client
->active
);
911 ip
->client
->active
= NULL
;
913 /* Stop sending DHCPREQUEST packets... */
914 cancel_timeout(send_request
, ip
);
916 ip
->client
->state
= S_INIT
;
920 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
921 one after the right interval has expired. If we don't get an offer by
922 the time we reach the panic interval, call the panic function. */
925 send_discover(void *ipp
)
927 struct interface_info
*ip
= ipp
;
928 int interval
, increase
= 1;
931 DH_DbgPrint(MID_TRACE
,("Doing discover on interface %p\n",ip
));
935 /* Figure out how long it's been since we started transmitting. */
936 interval
= cur_time
- ip
->client
->first_sending
;
938 /* If we're past the panic timeout, call the script and tell it
939 we haven't found anything for this interface yet. */
940 if (interval
> ip
->client
->config
->timeout
) {
945 /* If we're selecting media, try the whole list before doing
946 the exponential backoff, but if we've already received an
947 offer, stop looping, because we obviously have it right. */
948 if (!ip
->client
->offered_leases
&&
949 ip
->client
->config
->media
) {
952 if (ip
->client
->medium
) {
953 ip
->client
->medium
= ip
->client
->medium
->next
;
956 if (!ip
->client
->medium
) {
958 error("No valid media types for %s!", ip
->name
);
959 ip
->client
->medium
= ip
->client
->config
->media
;
963 note("Trying medium \"%s\" %d", ip
->client
->medium
->string
,
965 /* XXX Support other media types eventually */
969 * If we're supposed to increase the interval, do so. If it's
970 * currently zero (i.e., we haven't sent any packets yet), set
971 * it to one; otherwise, add to it a random number between zero
972 * and two times itself. On average, this means that it will
973 * double with every transmission.
976 if (!ip
->client
->interval
)
977 ip
->client
->interval
=
978 ip
->client
->config
->initial_interval
;
980 ip
->client
->interval
+= (rand() >> 2) %
981 (2 * ip
->client
->interval
);
984 /* Don't backoff past cutoff. */
985 if (ip
->client
->interval
>
986 ip
->client
->config
->backoff_cutoff
)
987 ip
->client
->interval
=
988 ((ip
->client
->config
->backoff_cutoff
/ 2)
990 ip
->client
->config
->backoff_cutoff
));
991 } else if (!ip
->client
->interval
)
992 ip
->client
->interval
=
993 ip
->client
->config
->initial_interval
;
995 /* If the backoff would take us to the panic timeout, just use that
997 if (cur_time
+ ip
->client
->interval
>
998 ip
->client
->first_sending
+ ip
->client
->config
->timeout
)
999 ip
->client
->interval
=
1000 (ip
->client
->first_sending
+
1001 ip
->client
->config
->timeout
) - cur_time
+ 1;
1003 /* Record the number of seconds since we started sending. */
1004 if (interval
< 65536)
1005 ip
->client
->packet
.secs
= htons(interval
);
1007 ip
->client
->packet
.secs
= htons(65535);
1008 ip
->client
->secs
= ip
->client
->packet
.secs
;
1010 note("DHCPDISCOVER on %s to %s port %d interval %ld",
1011 ip
->name
, inet_ntoa(sockaddr_broadcast
.sin_addr
),
1012 ntohs(sockaddr_broadcast
.sin_port
), (long int)ip
->client
->interval
);
1014 /* Send out a packet. */
1015 (void)send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1016 inaddr_any
, &sockaddr_broadcast
, NULL
);
1018 DH_DbgPrint(MID_TRACE
,("discover timeout: now %x -> then %x\n",
1019 cur_time
, cur_time
+ ip
->client
->interval
));
1021 add_timeout(cur_time
+ ip
->client
->interval
, send_discover
, ip
);
1025 * state_panic gets called if we haven't received any offers in a preset
1026 * amount of time. When this happens, we try to use existing leases
1027 * that haven't yet expired, and failing that, we call the client script
1028 * and hope it can do something.
1031 state_panic(void *ipp
)
1033 struct interface_info
*ip
= ipp
;
1034 struct client_lease
*loop
= ip
->client
->active
;
1035 struct client_lease
*lp
;
1038 note("No DHCPOFFERS received.");
1042 /* We may not have an active lease, but we may have some
1043 predefined leases that we can try. */
1044 if (!ip
->client
->active
&& ip
->client
->leases
)
1047 /* Run through the list of leases and see if one can be used. */
1048 while (ip
->client
->active
) {
1049 if (ip
->client
->active
->expiry
> cur_time
) {
1050 note("Trying recorded lease %s",
1051 piaddr(ip
->client
->active
->address
));
1052 /* Run the client script with the existing
1054 script_init("TIMEOUT",
1055 ip
->client
->active
->medium
);
1056 script_write_params("new_", ip
->client
->active
);
1057 if (ip
->client
->alias
)
1058 script_write_params("alias_",
1061 /* If the old lease is still good and doesn't
1062 yet need renewal, go into BOUND state and
1063 timeout at the renewal time. */
1065 ip
->client
->active
->renewal
) {
1066 ip
->client
->state
= S_BOUND
;
1067 note("bound: renewal in %ld seconds.",
1068 (long int)(ip
->client
->active
->renewal
-
1071 ip
->client
->active
->renewal
,
1074 ip
->client
->state
= S_BOUND
;
1075 note("bound: immediate renewal.");
1081 /* If there are no other leases, give up. */
1082 if (!ip
->client
->leases
) {
1083 ip
->client
->leases
= ip
->client
->active
;
1084 ip
->client
->active
= NULL
;
1089 /* Otherwise, put the active lease at the end of the
1090 lease list, and try another lease.. */
1091 for (lp
= ip
->client
->leases
; lp
->next
; lp
= lp
->next
)
1093 lp
->next
= ip
->client
->active
;
1095 lp
->next
->next
= NULL
;
1096 ip
->client
->active
= ip
->client
->leases
;
1097 ip
->client
->leases
= ip
->client
->leases
->next
;
1099 /* If we already tried this lease, we've exhausted the
1100 set of leases, so we might as well give up for
1102 if (ip
->client
->active
== loop
)
1105 loop
= ip
->client
->active
;
1108 /* No leases were available, or what was available didn't work, so
1109 tell the shell script that we failed to allocate an address,
1110 and try again later. */
1111 note("No working leases in persistent database - sleeping.\n");
1112 ip
->client
->state
= S_INIT
;
1113 add_timeout(cur_time
+ ip
->client
->config
->retry_interval
, state_init
,
1115 /* XXX Take any failure actions necessary */
1119 send_request(void *ipp
)
1121 struct interface_info
*ip
= ipp
;
1122 struct sockaddr_in destination
;
1123 struct in_addr from
;
1129 /* Figure out how long it's been since we started transmitting. */
1130 interval
= cur_time
- ip
->client
->first_sending
;
1132 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1133 past the reboot timeout, go to INIT and see if we can
1134 DISCOVER an address... */
1135 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1136 means either that we're on a network with no DHCP server,
1137 or that our server is down. In the latter case, assuming
1138 that there is a backup DHCP server, DHCPDISCOVER will get
1139 us a new address, but we could also have successfully
1140 reused our old address. In the former case, we're hosed
1141 anyway. This is not a win-prone situation. */
1142 if ((ip
->client
->state
== S_REBOOTING
||
1143 ip
->client
->state
== S_REQUESTING
) &&
1144 interval
> ip
->client
->config
->reboot_timeout
) {
1145 ip
->client
->state
= S_INIT
;
1146 cancel_timeout(send_request
, ip
);
1151 /* If we're in the reboot state, make sure the media is set up
1153 if (ip
->client
->state
== S_REBOOTING
&&
1154 !ip
->client
->medium
&&
1155 ip
->client
->active
->medium
) {
1156 script_init("MEDIUM", ip
->client
->active
->medium
);
1158 /* If the medium we chose won't fly, go to INIT state. */
1159 /* XXX Nothing for now */
1161 /* Record the medium. */
1162 ip
->client
->medium
= ip
->client
->active
->medium
;
1165 /* If the lease has expired, relinquish the address and go back
1166 to the INIT state. */
1167 if (ip
->client
->state
!= S_REQUESTING
&&
1168 cur_time
> ip
->client
->active
->expiry
) {
1169 PDHCP_ADAPTER Adapter
= AdapterFindInfo( ip
);
1170 /* Run the client script with the new parameters. */
1171 /* No script actions necessary in the expiry case */
1172 /* Now do a preinit on the interface so that we can
1173 discover a new address. */
1176 DeleteIPAddress( Adapter
->NteContext
);
1178 ip
->client
->state
= S_INIT
;
1183 /* Do the exponential backoff... */
1184 if (!ip
->client
->interval
)
1185 ip
->client
->interval
= ip
->client
->config
->initial_interval
;
1187 ip
->client
->interval
+= ((rand() >> 2) %
1188 (2 * ip
->client
->interval
));
1190 /* Don't backoff past cutoff. */
1191 if (ip
->client
->interval
>
1192 ip
->client
->config
->backoff_cutoff
)
1193 ip
->client
->interval
=
1194 ((ip
->client
->config
->backoff_cutoff
/ 2) +
1195 ((rand() >> 2) % ip
->client
->interval
));
1197 /* If the backoff would take us to the expiry time, just set the
1198 timeout to the expiry time. */
1199 if (ip
->client
->state
!= S_REQUESTING
&&
1200 cur_time
+ ip
->client
->interval
>
1201 ip
->client
->active
->expiry
)
1202 ip
->client
->interval
=
1203 ip
->client
->active
->expiry
- cur_time
+ 1;
1205 /* If the lease T2 time has elapsed, or if we're not yet bound,
1206 broadcast the DHCPREQUEST rather than unicasting. */
1207 memset(&destination
, 0, sizeof(destination
));
1208 if (ip
->client
->state
== S_REQUESTING
||
1209 ip
->client
->state
== S_REBOOTING
||
1210 cur_time
> ip
->client
->active
->rebind
)
1211 destination
.sin_addr
.s_addr
= INADDR_BROADCAST
;
1213 memcpy(&destination
.sin_addr
.s_addr
,
1214 ip
->client
->destination
.iabuf
,
1215 sizeof(destination
.sin_addr
.s_addr
));
1216 destination
.sin_port
= htons(REMOTE_PORT
);
1217 destination
.sin_family
= AF_INET
;
1218 // destination.sin_len = sizeof(destination);
1220 if (ip
->client
->state
!= S_REQUESTING
)
1221 memcpy(&from
, ip
->client
->active
->address
.iabuf
,
1224 from
.s_addr
= INADDR_ANY
;
1226 /* Record the number of seconds since we started sending. */
1227 if (ip
->client
->state
== S_REQUESTING
)
1228 ip
->client
->packet
.secs
= ip
->client
->secs
;
1230 if (interval
< 65536)
1231 ip
->client
->packet
.secs
= htons(interval
);
1233 ip
->client
->packet
.secs
= htons(65535);
1236 note("DHCPREQUEST on %s to %s port %d", ip
->name
,
1237 inet_ntoa(destination
.sin_addr
), ntohs(destination
.sin_port
));
1239 /* Send out a packet. */
1240 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1241 from
, &destination
, NULL
);
1243 add_timeout(cur_time
+ ip
->client
->interval
, send_request
, ip
);
1247 send_decline(void *ipp
)
1249 struct interface_info
*ip
= ipp
;
1251 note("DHCPDECLINE on %s to %s port %d", ip
->name
,
1252 inet_ntoa(sockaddr_broadcast
.sin_addr
),
1253 ntohs(sockaddr_broadcast
.sin_port
));
1255 /* Send out a packet. */
1256 (void) send_packet(ip
, &ip
->client
->packet
, ip
->client
->packet_length
,
1257 inaddr_any
, &sockaddr_broadcast
, NULL
);
1261 make_discover(struct interface_info
*ip
, struct client_lease
*lease
)
1263 unsigned char discover
= DHCPDISCOVER
;
1264 struct tree_cache
*options
[256];
1265 struct tree_cache option_elements
[256];
1267 ULONG foo
= (ULONG
) GetTickCount();
1269 memset(option_elements
, 0, sizeof(option_elements
));
1270 memset(options
, 0, sizeof(options
));
1271 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1273 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1274 i
= DHO_DHCP_MESSAGE_TYPE
;
1275 options
[i
] = &option_elements
[i
];
1276 options
[i
]->value
= &discover
;
1277 options
[i
]->len
= sizeof(discover
);
1278 options
[i
]->buf_size
= sizeof(discover
);
1279 options
[i
]->timeout
= 0xFFFFFFFF;
1281 /* Request the options we want */
1282 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1283 options
[i
] = &option_elements
[i
];
1284 options
[i
]->value
= ip
->client
->config
->requested_options
;
1285 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1286 options
[i
]->buf_size
=
1287 ip
->client
->config
->requested_option_count
;
1288 options
[i
]->timeout
= 0xFFFFFFFF;
1290 /* If we had an address, try to get it again. */
1292 ip
->client
->requested_address
= lease
->address
;
1293 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1294 options
[i
] = &option_elements
[i
];
1295 options
[i
]->value
= lease
->address
.iabuf
;
1296 options
[i
]->len
= lease
->address
.len
;
1297 options
[i
]->buf_size
= lease
->address
.len
;
1298 options
[i
]->timeout
= 0xFFFFFFFF;
1300 ip
->client
->requested_address
.len
= 0;
1302 /* Send any options requested in the config file. */
1303 for (i
= 0; i
< 256; i
++)
1305 ip
->client
->config
->send_options
[i
].data
) {
1306 options
[i
] = &option_elements
[i
];
1308 ip
->client
->config
->send_options
[i
].data
;
1310 ip
->client
->config
->send_options
[i
].len
;
1311 options
[i
]->buf_size
=
1312 ip
->client
->config
->send_options
[i
].len
;
1313 options
[i
]->timeout
= 0xFFFFFFFF;
1316 /* Set up the option buffer... */
1317 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1318 options
, 0, 0, 0, NULL
, 0);
1319 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1320 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1322 ip
->client
->packet
.op
= BOOTREQUEST
;
1323 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1324 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1325 ip
->client
->packet
.hops
= 0;
1326 ip
->client
->packet
.xid
= RtlRandom(&foo
);
1327 ip
->client
->packet
.secs
= 0; /* filled in by send_discover. */
1328 ip
->client
->packet
.flags
= 0;
1330 memset(&(ip
->client
->packet
.ciaddr
),
1331 0, sizeof(ip
->client
->packet
.ciaddr
));
1332 memset(&(ip
->client
->packet
.yiaddr
),
1333 0, sizeof(ip
->client
->packet
.yiaddr
));
1334 memset(&(ip
->client
->packet
.siaddr
),
1335 0, sizeof(ip
->client
->packet
.siaddr
));
1336 memset(&(ip
->client
->packet
.giaddr
),
1337 0, sizeof(ip
->client
->packet
.giaddr
));
1338 memcpy(ip
->client
->packet
.chaddr
,
1339 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1344 make_request(struct interface_info
*ip
, struct client_lease
* lease
)
1346 unsigned char request
= DHCPREQUEST
;
1347 struct tree_cache
*options
[256];
1348 struct tree_cache option_elements
[256];
1351 memset(options
, 0, sizeof(options
));
1352 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1354 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1355 i
= DHO_DHCP_MESSAGE_TYPE
;
1356 options
[i
] = &option_elements
[i
];
1357 options
[i
]->value
= &request
;
1358 options
[i
]->len
= sizeof(request
);
1359 options
[i
]->buf_size
= sizeof(request
);
1360 options
[i
]->timeout
= 0xFFFFFFFF;
1362 /* Request the options we want */
1363 i
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
1364 options
[i
] = &option_elements
[i
];
1365 options
[i
]->value
= ip
->client
->config
->requested_options
;
1366 options
[i
]->len
= ip
->client
->config
->requested_option_count
;
1367 options
[i
]->buf_size
=
1368 ip
->client
->config
->requested_option_count
;
1369 options
[i
]->timeout
= 0xFFFFFFFF;
1371 /* If we are requesting an address that hasn't yet been assigned
1372 to us, use the DHCP Requested Address option. */
1373 if (ip
->client
->state
== S_REQUESTING
) {
1374 /* Send back the server identifier... */
1375 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1376 options
[i
] = &option_elements
[i
];
1377 options
[i
]->value
= lease
->options
[i
].data
;
1378 options
[i
]->len
= lease
->options
[i
].len
;
1379 options
[i
]->buf_size
= lease
->options
[i
].len
;
1380 options
[i
]->timeout
= 0xFFFFFFFF;
1382 if (ip
->client
->state
== S_REQUESTING
||
1383 ip
->client
->state
== S_REBOOTING
) {
1384 ip
->client
->requested_address
= lease
->address
;
1385 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1386 options
[i
] = &option_elements
[i
];
1387 options
[i
]->value
= lease
->address
.iabuf
;
1388 options
[i
]->len
= lease
->address
.len
;
1389 options
[i
]->buf_size
= lease
->address
.len
;
1390 options
[i
]->timeout
= 0xFFFFFFFF;
1392 ip
->client
->requested_address
.len
= 0;
1394 /* Send any options requested in the config file. */
1395 for (i
= 0; i
< 256; i
++)
1397 ip
->client
->config
->send_options
[i
].data
) {
1398 options
[i
] = &option_elements
[i
];
1400 ip
->client
->config
->send_options
[i
].data
;
1402 ip
->client
->config
->send_options
[i
].len
;
1403 options
[i
]->buf_size
=
1404 ip
->client
->config
->send_options
[i
].len
;
1405 options
[i
]->timeout
= 0xFFFFFFFF;
1408 /* Set up the option buffer... */
1409 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1410 options
, 0, 0, 0, NULL
, 0);
1411 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1412 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1414 ip
->client
->packet
.op
= BOOTREQUEST
;
1415 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1416 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1417 ip
->client
->packet
.hops
= 0;
1418 ip
->client
->packet
.xid
= ip
->client
->xid
;
1419 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1421 /* If we own the address we're requesting, put it in ciaddr;
1422 otherwise set ciaddr to zero. */
1423 if (ip
->client
->state
== S_BOUND
||
1424 ip
->client
->state
== S_RENEWING
||
1425 ip
->client
->state
== S_REBINDING
) {
1426 memcpy(&ip
->client
->packet
.ciaddr
,
1427 lease
->address
.iabuf
, lease
->address
.len
);
1428 ip
->client
->packet
.flags
= 0;
1430 memset(&ip
->client
->packet
.ciaddr
, 0,
1431 sizeof(ip
->client
->packet
.ciaddr
));
1432 ip
->client
->packet
.flags
= 0;
1435 memset(&ip
->client
->packet
.yiaddr
, 0,
1436 sizeof(ip
->client
->packet
.yiaddr
));
1437 memset(&ip
->client
->packet
.siaddr
, 0,
1438 sizeof(ip
->client
->packet
.siaddr
));
1439 memset(&ip
->client
->packet
.giaddr
, 0,
1440 sizeof(ip
->client
->packet
.giaddr
));
1441 memcpy(ip
->client
->packet
.chaddr
,
1442 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1446 make_decline(struct interface_info
*ip
, struct client_lease
*lease
)
1448 struct tree_cache
*options
[256], message_type_tree
;
1449 struct tree_cache requested_address_tree
;
1450 struct tree_cache server_id_tree
, client_id_tree
;
1451 unsigned char decline
= DHCPDECLINE
;
1454 memset(options
, 0, sizeof(options
));
1455 memset(&ip
->client
->packet
, 0, sizeof(ip
->client
->packet
));
1457 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1458 i
= DHO_DHCP_MESSAGE_TYPE
;
1459 options
[i
] = &message_type_tree
;
1460 options
[i
]->value
= &decline
;
1461 options
[i
]->len
= sizeof(decline
);
1462 options
[i
]->buf_size
= sizeof(decline
);
1463 options
[i
]->timeout
= 0xFFFFFFFF;
1465 /* Send back the server identifier... */
1466 i
= DHO_DHCP_SERVER_IDENTIFIER
;
1467 options
[i
] = &server_id_tree
;
1468 options
[i
]->value
= lease
->options
[i
].data
;
1469 options
[i
]->len
= lease
->options
[i
].len
;
1470 options
[i
]->buf_size
= lease
->options
[i
].len
;
1471 options
[i
]->timeout
= 0xFFFFFFFF;
1473 /* Send back the address we're declining. */
1474 i
= DHO_DHCP_REQUESTED_ADDRESS
;
1475 options
[i
] = &requested_address_tree
;
1476 options
[i
]->value
= lease
->address
.iabuf
;
1477 options
[i
]->len
= lease
->address
.len
;
1478 options
[i
]->buf_size
= lease
->address
.len
;
1479 options
[i
]->timeout
= 0xFFFFFFFF;
1481 /* Send the uid if the user supplied one. */
1482 i
= DHO_DHCP_CLIENT_IDENTIFIER
;
1483 if (ip
->client
->config
->send_options
[i
].len
) {
1484 options
[i
] = &client_id_tree
;
1485 options
[i
]->value
= ip
->client
->config
->send_options
[i
].data
;
1486 options
[i
]->len
= ip
->client
->config
->send_options
[i
].len
;
1487 options
[i
]->buf_size
= ip
->client
->config
->send_options
[i
].len
;
1488 options
[i
]->timeout
= 0xFFFFFFFF;
1492 /* Set up the option buffer... */
1493 ip
->client
->packet_length
= cons_options(NULL
, &ip
->client
->packet
, 0,
1494 options
, 0, 0, 0, NULL
, 0);
1495 if (ip
->client
->packet_length
< BOOTP_MIN_LEN
)
1496 ip
->client
->packet_length
= BOOTP_MIN_LEN
;
1498 ip
->client
->packet
.op
= BOOTREQUEST
;
1499 ip
->client
->packet
.htype
= ip
->hw_address
.htype
;
1500 ip
->client
->packet
.hlen
= ip
->hw_address
.hlen
;
1501 ip
->client
->packet
.hops
= 0;
1502 ip
->client
->packet
.xid
= ip
->client
->xid
;
1503 ip
->client
->packet
.secs
= 0; /* Filled in by send_request. */
1504 ip
->client
->packet
.flags
= 0;
1506 /* ciaddr must always be zero. */
1507 memset(&ip
->client
->packet
.ciaddr
, 0,
1508 sizeof(ip
->client
->packet
.ciaddr
));
1509 memset(&ip
->client
->packet
.yiaddr
, 0,
1510 sizeof(ip
->client
->packet
.yiaddr
));
1511 memset(&ip
->client
->packet
.siaddr
, 0,
1512 sizeof(ip
->client
->packet
.siaddr
));
1513 memset(&ip
->client
->packet
.giaddr
, 0,
1514 sizeof(ip
->client
->packet
.giaddr
));
1515 memcpy(ip
->client
->packet
.chaddr
,
1516 ip
->hw_address
.haddr
, ip
->hw_address
.hlen
);
1520 free_client_lease(struct client_lease
*lease
)
1524 if (lease
->server_name
)
1525 free(lease
->server_name
);
1526 if (lease
->filename
)
1527 free(lease
->filename
);
1528 for (i
= 0; i
< 256; i
++) {
1529 if (lease
->options
[i
].len
)
1530 free(lease
->options
[i
].data
);
1538 rewrite_client_leases(struct interface_info
*ifi
)
1540 struct client_lease
*lp
;
1543 leaseFile
= fopen(path_dhclient_db
, "w");
1545 error("can't create %s", path_dhclient_db
);
1551 for (lp
= ifi
->client
->leases
; lp
; lp
= lp
->next
)
1552 write_client_lease(ifi
, lp
, 1);
1553 if (ifi
->client
->active
)
1554 write_client_lease(ifi
, ifi
->client
->active
, 1);
1560 write_client_lease(struct interface_info
*ip
, struct client_lease
*lease
,
1563 static int leases_written
;
1568 if (leases_written
++ > 20) {
1569 rewrite_client_leases(ip
);
1574 /* If the lease came from the config file, we don't need to stash
1575 a copy in the lease database. */
1576 if (lease
->is_static
)
1579 if (!leaseFile
) { /* XXX */
1580 leaseFile
= fopen(path_dhclient_db
, "w");
1582 error("can't create %s", path_dhclient_db
);
1587 fprintf(leaseFile
, "lease {\n");
1588 if (lease
->is_bootp
)
1589 fprintf(leaseFile
, " bootp;\n");
1590 fprintf(leaseFile
, " interface \"%s\";\n", ip
->name
);
1591 fprintf(leaseFile
, " fixed-address %s;\n", piaddr(lease
->address
));
1592 if (lease
->filename
)
1593 fprintf(leaseFile
, " filename \"%s\";\n", lease
->filename
);
1594 if (lease
->server_name
)
1595 fprintf(leaseFile
, " server-name \"%s\";\n",
1596 lease
->server_name
);
1598 fprintf(leaseFile
, " medium \"%s\";\n", lease
->medium
->string
);
1599 for (i
= 0; i
< 256; i
++)
1600 if (lease
->options
[i
].len
)
1601 fprintf(leaseFile
, " option %s %s;\n",
1602 dhcp_options
[i
].name
,
1603 pretty_print_option(i
, lease
->options
[i
].data
,
1604 lease
->options
[i
].len
, 1, 1));
1606 t
= gmtime(&lease
->renewal
);
1608 fprintf(leaseFile
, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1609 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1610 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1611 t
= gmtime(&lease
->rebind
);
1613 fprintf(leaseFile
, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1614 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1615 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1616 t
= gmtime(&lease
->expiry
);
1618 fprintf(leaseFile
, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1619 t
->tm_wday
, t
->tm_year
+ 1900, t
->tm_mon
+ 1, t
->tm_mday
,
1620 t
->tm_hour
, t
->tm_min
, t
->tm_sec
);
1621 fprintf(leaseFile
, "}\n");
1626 script_init(char *reason
, struct string_list
*medium
)
1628 size_t len
, mediumlen
= 0;
1629 struct imsg_hdr hdr
;
1633 if (medium
!= NULL
&& medium
->string
!= NULL
)
1634 mediumlen
= strlen(medium
->string
);
1636 hdr
.code
= IMSG_SCRIPT_INIT
;
1637 hdr
.len
= sizeof(struct imsg_hdr
) +
1638 sizeof(size_t) + mediumlen
+
1639 sizeof(size_t) + strlen(reason
);
1641 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1645 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1646 errs
+= buf_add(buf
, &mediumlen
, sizeof(mediumlen
));
1648 errs
+= buf_add(buf
, medium
->string
, mediumlen
);
1649 len
= strlen(reason
);
1650 errs
+= buf_add(buf
, &len
, sizeof(len
));
1651 errs
+= buf_add(buf
, reason
, len
);
1654 error("buf_add: %d", WSAGetLastError());
1656 if (buf_close(privfd
, buf
) == -1)
1657 error("buf_close: %d", WSAGetLastError());
1661 priv_script_init(struct interface_info
*ip
, char *reason
, char *medium
)
1664 // XXX Do we need to do anything?
1669 priv_script_write_params(struct interface_info
*ip
, char *prefix
, struct client_lease
*lease
)
1671 u_int8_t dbuf
[1500];
1675 script_set_env(ip
->client
, prefix
, "ip_address",
1676 piaddr(lease
->address
));
1679 if (lease
->options
[DHO_SUBNET_MASK
].len
&&
1680 (lease
->options
[DHO_SUBNET_MASK
].len
<
1681 sizeof(lease
->address
.iabuf
))) {
1682 struct iaddr netmask
, subnet
, broadcast
;
1684 memcpy(netmask
.iabuf
, lease
->options
[DHO_SUBNET_MASK
].data
,
1685 lease
->options
[DHO_SUBNET_MASK
].len
);
1686 netmask
.len
= lease
->options
[DHO_SUBNET_MASK
].len
;
1688 subnet
= subnet_number(lease
->address
, netmask
);
1691 script_set_env(ip
->client
, prefix
, "network_number",
1694 if (!lease
->options
[DHO_BROADCAST_ADDRESS
].len
) {
1695 broadcast
= broadcast_addr(subnet
, netmask
);
1698 script_set_env(ip
->client
, prefix
,
1699 "broadcast_address",
1709 if (lease
->filename
)
1710 script_set_env(ip
->client
, prefix
, "filename", lease
->filename
);
1711 if (lease
->server_name
)
1712 script_set_env(ip
->client
, prefix
, "server_name",
1713 lease
->server_name
);
1716 for (i
= 0; i
< 256; i
++) {
1717 u_int8_t
*dp
= NULL
;
1719 if (ip
->client
->config
->defaults
[i
].len
) {
1720 if (lease
->options
[i
].len
) {
1722 ip
->client
->config
->default_actions
[i
]) {
1723 case ACTION_DEFAULT
:
1724 dp
= lease
->options
[i
].data
;
1725 len
= lease
->options
[i
].len
;
1727 case ACTION_SUPERSEDE
:
1730 config
->defaults
[i
].data
;
1732 config
->defaults
[i
].len
;
1734 case ACTION_PREPEND
:
1736 config
->defaults
[i
].len
+
1737 lease
->options
[i
].len
;
1738 if (len
>= sizeof(dbuf
)) {
1739 warning("no space to %s %s",
1741 dhcp_options
[i
].name
);
1747 config
->defaults
[i
].data
,
1749 config
->defaults
[i
].len
);
1750 memcpy(dp
+ ip
->client
->
1751 config
->defaults
[i
].len
,
1752 lease
->options
[i
].data
,
1753 lease
->options
[i
].len
);
1758 config
->defaults
[i
].len
+
1759 lease
->options
[i
].len
+ 1;
1760 if (len
> sizeof(dbuf
)) {
1761 warning("no space to %s %s",
1763 dhcp_options
[i
].name
);
1768 lease
->options
[i
].data
,
1769 lease
->options
[i
].len
);
1770 memcpy(dp
+ lease
->options
[i
].len
,
1772 config
->defaults
[i
].data
,
1774 config
->defaults
[i
].len
);
1779 config
->defaults
[i
].data
;
1781 config
->defaults
[i
].len
;
1783 } else if (lease
->options
[i
].len
) {
1784 len
= lease
->options
[i
].len
;
1785 dp
= lease
->options
[i
].data
;
1793 if (dhcp_option_ev_name(name
, sizeof(name
),
1795 script_set_env(ip
->client
, prefix
, name
,
1796 pretty_print_option(i
, dp
, len
, 0, 0));
1801 snprintf(tbuf
, sizeof(tbuf
), "%d", (int)lease
->expiry
);
1802 script_set_env(ip
->client
, prefix
, "expiry", tbuf
);
1807 script_write_params(char *prefix
, struct client_lease
*lease
)
1809 size_t fn_len
= 0, sn_len
= 0, pr_len
= 0;
1810 struct imsg_hdr hdr
;
1814 if (lease
->filename
!= NULL
)
1815 fn_len
= strlen(lease
->filename
);
1816 if (lease
->server_name
!= NULL
)
1817 sn_len
= strlen(lease
->server_name
);
1819 pr_len
= strlen(prefix
);
1821 hdr
.code
= IMSG_SCRIPT_WRITE_PARAMS
;
1822 hdr
.len
= sizeof(hdr
) + sizeof(struct client_lease
) +
1823 sizeof(size_t) + fn_len
+ sizeof(size_t) + sn_len
+
1824 sizeof(size_t) + pr_len
;
1826 for (i
= 0; i
< 256; i
++)
1827 hdr
.len
+= sizeof(int) + lease
->options
[i
].len
;
1829 scripttime
= time(NULL
);
1831 if ((buf
= buf_open(hdr
.len
)) == NULL
)
1835 errs
+= buf_add(buf
, &hdr
, sizeof(hdr
));
1836 errs
+= buf_add(buf
, lease
, sizeof(struct client_lease
));
1837 errs
+= buf_add(buf
, &fn_len
, sizeof(fn_len
));
1838 errs
+= buf_add(buf
, lease
->filename
, fn_len
);
1839 errs
+= buf_add(buf
, &sn_len
, sizeof(sn_len
));
1840 errs
+= buf_add(buf
, lease
->server_name
, sn_len
);
1841 errs
+= buf_add(buf
, &pr_len
, sizeof(pr_len
));
1842 errs
+= buf_add(buf
, prefix
, pr_len
);
1844 for (i
= 0; i
< 256; i
++) {
1845 errs
+= buf_add(buf
, &lease
->options
[i
].len
,
1846 sizeof(lease
->options
[i
].len
));
1847 errs
+= buf_add(buf
, lease
->options
[i
].data
,
1848 lease
->options
[i
].len
);
1852 error("buf_add: %d", WSAGetLastError());
1854 if (buf_close(privfd
, buf
) == -1)
1855 error("buf_close: %d", WSAGetLastError());
1859 dhcp_option_ev_name(char *buf
, size_t buflen
, struct dhcp_option
*option
)
1863 for (i
= 0; option
->name
[i
]; i
++) {
1864 if (i
+ 1 == buflen
)
1866 if (option
->name
[i
] == '-')
1869 buf
[i
] = option
->name
[i
];
1880 static int state
= 0;
1882 if (no_daemon
|| state
)
1887 /* Stop logging to stderr... */
1890 if (daemon(1, 0) == -1)
1893 /* we are chrooted, daemon(3) fails to open /dev/null */
1895 dup2(nullfd
, STDIN_FILENO
);
1896 dup2(nullfd
, STDOUT_FILENO
);
1897 dup2(nullfd
, STDERR_FILENO
);
1905 check_option(struct client_lease
*l
, int option
)
1910 /* we use this, since this is what gets passed to dhclient-script */
1912 opbuf
= pretty_print_option(option
, l
->options
[option
].data
,
1913 l
->options
[option
].len
, 0, 0);
1915 sbuf
= option_as_string(option
, l
->options
[option
].data
,
1916 l
->options
[option
].len
);
1919 case DHO_SUBNET_MASK
:
1920 case DHO_TIME_SERVERS
:
1921 case DHO_NAME_SERVERS
:
1923 case DHO_DOMAIN_NAME_SERVERS
:
1924 case DHO_LOG_SERVERS
:
1925 case DHO_COOKIE_SERVERS
:
1926 case DHO_LPR_SERVERS
:
1927 case DHO_IMPRESS_SERVERS
:
1928 case DHO_RESOURCE_LOCATION_SERVERS
:
1929 case DHO_SWAP_SERVER
:
1930 case DHO_BROADCAST_ADDRESS
:
1931 case DHO_NIS_SERVERS
:
1932 case DHO_NTP_SERVERS
:
1933 case DHO_NETBIOS_NAME_SERVERS
:
1934 case DHO_NETBIOS_DD_SERVER
:
1935 case DHO_FONT_SERVERS
:
1936 case DHO_DHCP_SERVER_IDENTIFIER
:
1937 if (!ipv4addrs(opbuf
)) {
1938 warning("Invalid IP address in option(%d): %s", option
, opbuf
);
1943 case DHO_DOMAIN_NAME
:
1944 case DHO_NIS_DOMAIN
:
1945 if (!res_hnok(sbuf
))
1946 warning("Bogus Host Name option %d: %s (%s)", option
,
1950 case DHO_TIME_OFFSET
:
1952 case DHO_MERIT_DUMP
:
1954 case DHO_EXTENSIONS_PATH
:
1955 case DHO_IP_FORWARDING
:
1956 case DHO_NON_LOCAL_SOURCE_ROUTING
:
1957 case DHO_POLICY_FILTER
:
1958 case DHO_MAX_DGRAM_REASSEMBLY
:
1959 case DHO_DEFAULT_IP_TTL
:
1960 case DHO_PATH_MTU_AGING_TIMEOUT
:
1961 case DHO_PATH_MTU_PLATEAU_TABLE
:
1962 case DHO_INTERFACE_MTU
:
1963 case DHO_ALL_SUBNETS_LOCAL
:
1964 case DHO_PERFORM_MASK_DISCOVERY
:
1965 case DHO_MASK_SUPPLIER
:
1966 case DHO_ROUTER_DISCOVERY
:
1967 case DHO_ROUTER_SOLICITATION_ADDRESS
:
1968 case DHO_STATIC_ROUTES
:
1969 case DHO_TRAILER_ENCAPSULATION
:
1970 case DHO_ARP_CACHE_TIMEOUT
:
1971 case DHO_IEEE802_3_ENCAPSULATION
:
1972 case DHO_DEFAULT_TCP_TTL
:
1973 case DHO_TCP_KEEPALIVE_INTERVAL
:
1974 case DHO_TCP_KEEPALIVE_GARBAGE
:
1975 case DHO_VENDOR_ENCAPSULATED_OPTIONS
:
1976 case DHO_NETBIOS_NODE_TYPE
:
1977 case DHO_NETBIOS_SCOPE
:
1978 case DHO_X_DISPLAY_MANAGER
:
1979 case DHO_DHCP_REQUESTED_ADDRESS
:
1980 case DHO_DHCP_LEASE_TIME
:
1981 case DHO_DHCP_OPTION_OVERLOAD
:
1982 case DHO_DHCP_MESSAGE_TYPE
:
1983 case DHO_DHCP_PARAMETER_REQUEST_LIST
:
1984 case DHO_DHCP_MESSAGE
:
1985 case DHO_DHCP_MAX_MESSAGE_SIZE
:
1986 case DHO_DHCP_RENEWAL_TIME
:
1987 case DHO_DHCP_REBINDING_TIME
:
1988 case DHO_DHCP_CLASS_IDENTIFIER
:
1989 case DHO_DHCP_CLIENT_IDENTIFIER
:
1990 case DHO_DHCP_USER_CLASS_ID
:
1994 warning("unknown dhcp option value 0x%x", option
);
1995 return (unknown_ok
);
2000 res_hnok(const char *dn
)
2002 int pch
= PERIOD
, ch
= *dn
++;
2004 while (ch
!= '\0') {
2007 if (periodchar(ch
)) {
2009 } else if (periodchar(pch
)) {
2010 if (!borderchar(ch
))
2012 } else if (periodchar(nch
) || nch
== '\0') {
2013 if (!borderchar(ch
))
2016 if (!middlechar(ch
))
2024 /* Does buf consist only of dotted decimal ipv4 addrs?
2025 * return how many if so,
2026 * otherwise, return 0
2029 ipv4addrs(char * buf
)
2035 note("Input: %s", buf
);
2038 tmp
= strtok(buf
, " ");
2039 note("got %s", tmp
);
2040 if( tmp
&& inet_aton(tmp
, &jnk
) ) i
++;
2049 option_as_string(unsigned int code
, unsigned char *data
, int len
)
2051 static char optbuf
[32768]; /* XXX */
2053 int opleft
= sizeof(optbuf
);
2054 unsigned char *dp
= data
;
2057 error("option_as_string: bad code %d", code
);
2059 for (; dp
< data
+ len
; dp
++) {
2060 if (!isascii(*dp
) || !isprint(*dp
)) {
2061 if (dp
+ 1 != data
+ len
|| *dp
!= 0) {
2062 _snprintf(op
, opleft
, "\\%03o", *dp
);
2066 } else if (*dp
== '"' || *dp
== '\'' || *dp
== '$' ||
2067 *dp
== '`' || *dp
== '\\') {
2081 warning("dhcp option too large");