3 BOOTP Protocol support. */
6 * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
39 # define send_packet trace_packet_send
43 struct packet
*packet
;
46 struct host_decl
*hp
= (struct host_decl
*)0;
47 struct host_decl
*host
= (struct host_decl
*)0;
48 struct packet outgoing
;
49 struct dhcp_packet raw
;
50 struct sockaddr_in to
;
53 struct option_state
*options
= (struct option_state
*)0;
54 struct lease
*lease
= (struct lease
*)0;
56 struct data_string d1
;
57 struct option_cache
*oc
;
60 int peer_has_leases
= 0;
62 if (packet
-> raw
-> op
!= BOOTREQUEST
)
65 /* %Audit% This is log output. %2004.06.17,Safe%
66 * If we truncate we hope the user can get a hint from the log.
68 snprintf (msgbuf
, sizeof msgbuf
, "BOOTREQUEST from %s via %s",
69 print_hw_addr (packet
-> raw
-> htype
,
70 packet
-> raw
-> hlen
,
71 packet
-> raw
-> chaddr
),
72 packet
-> raw
-> giaddr
.s_addr
73 ? inet_ntoa (packet
-> raw
-> giaddr
)
74 : packet
-> interface
-> name
);
76 if (!locate_network (packet
)) {
77 log_info ("%s: network unknown", msgbuf
);
81 find_lease (&lease
, packet
, packet
-> shared_network
,
82 0, 0, (struct lease
*)0, MDL
);
84 if (lease
&& lease
->host
)
85 host_reference(&hp
, lease
->host
, MDL
);
87 if (!lease
|| ((lease
->flags
& STATIC_LEASE
) == 0)) {
90 /* We didn't find an applicable fixed-address host
91 declaration. Just in case we may be able to dynamically
92 assign an address, see if there's a host declaration
93 that doesn't have an ip address associated with it. */
96 find_hosts_by_haddr(&hp
, packet
->raw
->htype
,
98 packet
->raw
->hlen
, MDL
);
100 for (h
= hp
; h
; h
= h
-> n_ipaddr
) {
101 if (!h
-> fixed_addr
) {
102 host_reference(&host
, h
, MDL
);
108 host_dereference(&hp
, MDL
);
111 host_reference(&hp
, host
, MDL
);
112 host_dereference(&host
, MDL
);
115 /* Allocate a lease if we have not yet found one. */
117 allocate_lease (&lease
, packet
,
118 packet
-> shared_network
-> pools
,
122 log_info("%s: BOOTP from dynamic client and no "
123 "dynamic leases", msgbuf
);
127 #if defined(FAILOVER_PROTOCOL)
128 if ((lease
->pool
!= NULL
) &&
129 (lease
->pool
->failover_peer
!= NULL
)) {
130 dhcp_failover_state_t
*peer
;
132 peer
= lease
->pool
->failover_peer
;
134 /* If we are in a failover state that bars us from
135 * answering, do not do so.
136 * If we are in a cooperative state, load balance
139 if ((peer
->service_state
== not_responding
) ||
140 (peer
->service_state
== service_startup
)) {
141 log_info("%s: not responding%s",
144 } else if((peer
->service_state
== cooperating
) &&
145 !load_balance_mine(packet
, peer
)) {
146 log_info("%s: load balance to peer %s",
153 ack_lease (packet
, lease
, 0, 0, msgbuf
, 0, hp
);
157 /* Run the executable statements to compute the client and server
159 option_state_allocate (&options
, MDL
);
161 /* Execute the subnet statements. */
162 execute_statements_in_scope ((struct binding_value
**)0,
163 packet
, lease
, (struct client_state
*)0,
164 packet
-> options
, options
,
165 &lease
-> scope
, lease
-> subnet
-> group
,
168 /* Execute statements from class scopes. */
169 for (i
= packet
-> class_count
; i
> 0; i
--) {
170 execute_statements_in_scope
171 ((struct binding_value
**)0,
172 packet
, lease
, (struct client_state
*)0,
173 packet
-> options
, options
,
174 &lease
-> scope
, packet
-> classes
[i
- 1] -> group
,
175 lease
-> subnet
-> group
);
178 /* Execute the host statements. */
179 execute_statements_in_scope ((struct binding_value
**)0,
180 packet
, lease
, (struct client_state
*)0,
181 packet
-> options
, options
,
183 hp
-> group
, lease
-> subnet
-> group
);
185 /* Drop the request if it's not allowed for this client. */
186 if ((oc
= lookup_option (&server_universe
, options
, SV_ALLOW_BOOTP
)) &&
187 !evaluate_boolean_option_cache (&ignorep
, packet
, lease
,
188 (struct client_state
*)0,
189 packet
-> options
, options
,
190 &lease
-> scope
, oc
, MDL
)) {
192 log_info ("%s: bootp disallowed", msgbuf
);
196 if ((oc
= lookup_option (&server_universe
,
197 options
, SV_ALLOW_BOOTING
)) &&
198 !evaluate_boolean_option_cache (&ignorep
, packet
, lease
,
199 (struct client_state
*)0,
200 packet
-> options
, options
,
201 &lease
-> scope
, oc
, MDL
)) {
203 log_info ("%s: booting disallowed", msgbuf
);
207 /* Set up the outgoing packet... */
208 memset (&outgoing
, 0, sizeof outgoing
);
209 memset (&raw
, 0, sizeof raw
);
212 /* If we didn't get a known vendor magic number on the way in,
213 just copy the input options to the output. */
214 if (!packet
-> options_valid
&&
215 !(evaluate_boolean_option_cache
216 (&ignorep
, packet
, lease
, (struct client_state
*)0,
217 packet
-> options
, options
, &lease
-> scope
,
218 lookup_option (&server_universe
, options
,
219 SV_ALWAYS_REPLY_RFC1048
), MDL
))) {
220 memcpy (outgoing
.raw
-> options
,
221 packet
-> raw
-> options
, DHCP_MAX_OPTION_LEN
);
222 outgoing
.packet_length
= BOOTP_MIN_LEN
;
225 /* Use the subnet mask from the subnet declaration if no other
226 mask has been provided. */
228 oc
= (struct option_cache
*)0;
230 if (!lookup_option (&dhcp_universe
, options
, i
)) {
231 if (option_cache_allocate (&oc
, MDL
)) {
234 lease
-> subnet
-> netmask
.iabuf
,
235 lease
-> subnet
-> netmask
.len
,
237 option_code_hash_lookup(&oc
->option
,
238 dhcp_universe
.code_hash
,
240 save_option (&dhcp_universe
,
243 option_cache_dereference (&oc
, MDL
);
247 /* Pack the options into the buffer. Unlike DHCP, we
248 can't pack options into the filename and server
251 outgoing
.packet_length
=
252 cons_options (packet
, outgoing
.raw
, lease
,
253 (struct client_state
*)0, 0,
254 packet
-> options
, options
,
256 0, 0, 1, (struct data_string
*)0,
258 if (outgoing
.packet_length
< BOOTP_MIN_LEN
)
259 outgoing
.packet_length
= BOOTP_MIN_LEN
;
262 /* Take the fields that we care about... */
264 raw
.htype
= packet
-> raw
-> htype
;
265 raw
.hlen
= packet
-> raw
-> hlen
;
266 memcpy (raw
.chaddr
, packet
-> raw
-> chaddr
, sizeof raw
.chaddr
);
267 raw
.hops
= packet
-> raw
-> hops
;
268 raw
.xid
= packet
-> raw
-> xid
;
269 raw
.secs
= packet
-> raw
-> secs
;
270 raw
.flags
= packet
-> raw
-> flags
;
271 raw
.ciaddr
= packet
-> raw
-> ciaddr
;
273 /* yiaddr is an ipv4 address, it must be 4 octets. */
274 memcpy (&raw
.yiaddr
, lease
->ip_addr
.iabuf
, 4);
276 /* If we're always supposed to broadcast to this client, set
277 the broadcast bit in the bootp flags field. */
278 if ((oc
= lookup_option (&server_universe
,
279 options
, SV_ALWAYS_BROADCAST
)) &&
280 evaluate_boolean_option_cache (&ignorep
, packet
, lease
,
281 (struct client_state
*)0,
282 packet
-> options
, options
,
283 &lease
-> scope
, oc
, MDL
))
284 raw
.flags
|= htons (BOOTP_BROADCAST
);
286 /* Figure out the address of the next server. */
287 memset (&d1
, 0, sizeof d1
);
288 oc
= lookup_option (&server_universe
, options
, SV_NEXT_SERVER
);
290 evaluate_option_cache (&d1
, packet
, lease
,
291 (struct client_state
*)0,
292 packet
-> options
, options
,
293 &lease
-> scope
, oc
, MDL
)) {
294 /* If there was more than one answer, take the first. */
295 if (d1
.len
>= 4 && d1
.data
)
296 memcpy (&raw
.siaddr
, d1
.data
, 4);
297 data_string_forget (&d1
, MDL
);
299 if ((lease
->subnet
->shared_network
->interface
!= NULL
) &&
300 lease
->subnet
->shared_network
->interface
->address_count
)
302 lease
->subnet
->shared_network
->interface
->addresses
[0];
303 else if (packet
->interface
->address_count
)
304 raw
.siaddr
= packet
->interface
->addresses
[0];
307 raw
.giaddr
= packet
-> raw
-> giaddr
;
309 /* Figure out the filename. */
310 oc
= lookup_option (&server_universe
, options
, SV_FILENAME
);
312 evaluate_option_cache (&d1
, packet
, lease
,
313 (struct client_state
*)0,
314 packet
-> options
, options
,
315 &lease
-> scope
, oc
, MDL
)) {
316 memcpy (raw
.file
, d1
.data
,
317 d1
.len
> sizeof raw
.file
? sizeof raw
.file
: d1
.len
);
318 if (sizeof raw
.file
> d1
.len
)
319 memset (&raw
.file
[d1
.len
],
320 0, (sizeof raw
.file
) - d1
.len
);
321 data_string_forget (&d1
, MDL
);
323 memcpy (raw
.file
, packet
-> raw
-> file
, sizeof raw
.file
);
325 /* Choose a server name as above. */
326 oc
= lookup_option (&server_universe
, options
, SV_SERVER_NAME
);
328 evaluate_option_cache (&d1
, packet
, lease
,
329 (struct client_state
*)0,
330 packet
-> options
, options
,
331 &lease
-> scope
, oc
, MDL
)) {
332 memcpy (raw
.sname
, d1
.data
,
333 d1
.len
> sizeof raw
.sname
? sizeof raw
.sname
: d1
.len
);
334 if (sizeof raw
.sname
> d1
.len
)
335 memset (&raw
.sname
[d1
.len
],
336 0, (sizeof raw
.sname
) - d1
.len
);
337 data_string_forget (&d1
, MDL
);
340 /* Execute the commit statements, if there are any. */
341 execute_statements ((struct binding_value
**)0,
342 packet
, lease
, (struct client_state
*)0,
344 options
, &lease
-> scope
, lease
-> on_commit
);
346 /* We're done with the option state. */
347 option_state_dereference (&options
, MDL
);
349 /* Set up the hardware destination address... */
350 hto
.hbuf
[0] = packet
-> raw
-> htype
;
351 hto
.hlen
= packet
-> raw
-> hlen
+ 1;
352 memcpy (&hto
.hbuf
[1], packet
-> raw
-> chaddr
, packet
-> raw
-> hlen
);
354 if (packet
->interface
->address_count
) {
355 from
= packet
->interface
->addresses
[0];
357 log_error("%s: Interface %s appears to have no IPv4 "
358 "addresses, and so dhcpd cannot select a source "
359 "address.", msgbuf
, packet
->interface
->name
);
363 /* Report what we're doing... */
364 log_info ("%s", msgbuf
);
365 log_info ("BOOTREPLY for %s to %s (%s) via %s",
366 piaddr (lease
->ip_addr
), hp
-> name
,
367 print_hw_addr (packet
-> raw
-> htype
,
368 packet
-> raw
-> hlen
,
369 packet
-> raw
-> chaddr
),
370 packet
-> raw
-> giaddr
.s_addr
371 ? inet_ntoa (packet
-> raw
-> giaddr
)
372 : packet
-> interface
-> name
);
374 /* Set up the parts of the address that are in common. */
375 to
.sin_family
= AF_INET
;
377 to
.sin_len
= sizeof to
;
379 memset (to
.sin_zero
, 0, sizeof to
.sin_zero
);
381 /* If this was gatewayed, send it back to the gateway... */
382 if (raw
.giaddr
.s_addr
) {
383 to
.sin_addr
= raw
.giaddr
;
384 to
.sin_port
= local_port
;
386 if (fallback_interface
) {
387 result
= send_packet (fallback_interface
,
389 &raw
, outgoing
.packet_length
,
394 /* If it comes from a client that already knows its address
395 and is not requesting a broadcast response, and we can
396 unicast to a client without using the ARP protocol, sent it
397 directly to that client. */
398 } else if (!(raw
.flags
& htons (BOOTP_BROADCAST
)) &&
399 can_unicast_without_arp (packet
-> interface
)) {
400 to
.sin_addr
= raw
.yiaddr
;
401 to
.sin_port
= remote_port
;
403 /* Otherwise, broadcast it on the local network. */
405 to
.sin_addr
= limited_broadcast
;
406 to
.sin_port
= remote_port
; /* XXX */
410 result
= send_packet (packet
-> interface
,
411 packet
, &raw
, outgoing
.packet_length
,
415 option_state_dereference (&options
, MDL
);
417 lease_dereference (&lease
, MDL
);
419 host_dereference (&hp
, MDL
);
421 host_dereference (&host
, MDL
);