]>
git.ipfire.org Git - thirdparty/dhcp.git/blob - server/bootp.c
3 BOOTP Protocol support. */
6 * Copyright (c) 2009,2012-2014 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1995-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
24 * Redwood City, CA 94063
26 * https://www.isc.org/
34 # define send_packet trace_packet_send
38 struct packet
*packet
;
41 struct host_decl
*hp
= (struct host_decl
*)0;
42 struct host_decl
*host
= (struct host_decl
*)0;
43 struct packet outgoing
;
44 struct dhcp_packet raw
;
45 struct sockaddr_in to
;
48 struct option_state
*options
= (struct option_state
*)0;
49 struct lease
*lease
= (struct lease
*)0;
51 struct data_string d1
;
52 struct option_cache
*oc
;
55 int peer_has_leases
= 0;
57 if (packet
-> raw
-> op
!= BOOTREQUEST
)
60 /* %Audit% This is log output. %2004.06.17,Safe%
61 * If we truncate we hope the user can get a hint from the log.
63 snprintf (msgbuf
, sizeof msgbuf
, "BOOTREQUEST from %s via %s",
64 print_hw_addr (packet
-> raw
-> htype
,
65 packet
-> raw
-> hlen
,
66 packet
-> raw
-> chaddr
),
67 packet
-> raw
-> giaddr
.s_addr
68 ? inet_ntoa (packet
-> raw
-> giaddr
)
69 : packet
-> interface
-> name
);
71 if (!locate_network (packet
)) {
72 log_info ("%s: network unknown", msgbuf
);
76 find_lease (&lease
, packet
, packet
-> shared_network
,
77 0, 0, (struct lease
*)0, MDL
);
79 if (lease
&& lease
->host
)
80 host_reference(&hp
, lease
->host
, MDL
);
82 if (!lease
|| ((lease
->flags
& STATIC_LEASE
) == 0)) {
85 /* We didn't find an applicable fixed-address host
86 declaration. Just in case we may be able to dynamically
87 assign an address, see if there's a host declaration
88 that doesn't have an ip address associated with it. */
91 find_hosts_by_haddr(&hp
, packet
->raw
->htype
,
93 packet
->raw
->hlen
, MDL
);
95 for (h
= hp
; h
; h
= h
-> n_ipaddr
) {
96 if (!h
-> fixed_addr
) {
97 host_reference(&host
, h
, MDL
);
103 host_dereference(&hp
, MDL
);
106 host_reference(&hp
, host
, MDL
);
107 host_dereference(&host
, MDL
);
110 /* Allocate a lease if we have not yet found one. */
112 allocate_lease (&lease
, packet
,
113 packet
-> shared_network
-> pools
,
117 log_info("%s: BOOTP from dynamic client and no "
118 "dynamic leases", msgbuf
);
122 #if defined(FAILOVER_PROTOCOL)
123 if ((lease
->pool
!= NULL
) &&
124 (lease
->pool
->failover_peer
!= NULL
)) {
125 dhcp_failover_state_t
*peer
;
127 peer
= lease
->pool
->failover_peer
;
129 /* If we are in a failover state that bars us from
130 * answering, do not do so.
131 * If we are in a cooperative state, load balance
134 if ((peer
->service_state
== not_responding
) ||
135 (peer
->service_state
== service_startup
)) {
136 log_info("%s: not responding%s",
139 } else if((peer
->service_state
== cooperating
) &&
140 !load_balance_mine(packet
, peer
)) {
141 log_info("%s: load balance to peer %s",
148 ack_lease (packet
, lease
, 0, 0, msgbuf
, 0, hp
);
152 /* Run the executable statements to compute the client and server
154 option_state_allocate (&options
, MDL
);
156 /* Execute the subnet statements. */
157 execute_statements_in_scope (NULL
, packet
, lease
, NULL
,
158 packet
->options
, options
,
159 &lease
->scope
, lease
->subnet
->group
,
162 /* Execute statements from class scopes. */
163 for (i
= packet
-> class_count
; i
> 0; i
--) {
164 execute_statements_in_scope(NULL
, packet
, lease
, NULL
,
165 packet
->options
, options
,
167 packet
->classes
[i
- 1]->group
,
168 lease
->subnet
->group
, NULL
);
171 /* Execute the host statements. */
173 execute_statements_in_scope(NULL
, packet
, lease
, NULL
,
174 packet
->options
, options
,
175 &lease
->scope
, hp
->group
,
176 lease
->subnet
->group
, NULL
);
179 /* Drop the request if it's not allowed for this client. */
180 if ((oc
= lookup_option (&server_universe
, options
, SV_ALLOW_BOOTP
)) &&
181 !evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
183 packet
->options
, options
,
184 &lease
->scope
, oc
, MDL
)) {
186 log_info ("%s: bootp disallowed", msgbuf
);
190 if ((oc
= lookup_option(&server_universe
,
191 options
, SV_ALLOW_BOOTING
)) &&
192 !evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
194 packet
->options
, options
,
195 &lease
->scope
, oc
, MDL
)) {
197 log_info ("%s: booting disallowed", msgbuf
);
201 /* Set up the outgoing packet... */
202 memset (&outgoing
, 0, sizeof outgoing
);
203 memset (&raw
, 0, sizeof raw
);
206 /* If we didn't get a known vendor magic number on the way in,
207 just copy the input options to the output. */
208 i
= SV_ALWAYS_REPLY_RFC1048
;
209 if (!packet
->options_valid
&&
210 !(evaluate_boolean_option_cache(&ignorep
, packet
, lease
, NULL
,
211 packet
->options
, options
,
213 lookup_option (&server_universe
,
214 options
, i
), MDL
))) {
215 if (packet
->packet_length
> DHCP_FIXED_NON_UDP
) {
216 memcpy(outgoing
.raw
->options
, packet
->raw
->options
,
217 packet
->packet_length
- DHCP_FIXED_NON_UDP
);
220 outgoing
.packet_length
=
221 (packet
->packet_length
< BOOTP_MIN_LEN
)
223 : packet
->packet_length
;
226 /* Use the subnet mask from the subnet declaration if no other
227 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 /* If use-host-decl-names is enabled and there is a hostname
248 * defined in the host delcartion, send it back in hostname
250 use_host_decl_name(packet
, lease
, options
);
252 /* Pack the options into the buffer. Unlike DHCP, we
253 can't pack options into the filename and server
256 outgoing
.packet_length
=
257 cons_options (packet
, outgoing
.raw
, lease
,
258 (struct client_state
*)0, 0,
259 packet
-> options
, options
,
261 0, 0, 1, (struct data_string
*)0,
263 if (outgoing
.packet_length
< BOOTP_MIN_LEN
)
264 outgoing
.packet_length
= BOOTP_MIN_LEN
;
267 /* Take the fields that we care about... */
269 raw
.htype
= packet
-> raw
-> htype
;
270 raw
.hlen
= packet
-> raw
-> hlen
;
271 memcpy (raw
.chaddr
, packet
-> raw
-> chaddr
, sizeof raw
.chaddr
);
272 raw
.hops
= packet
-> raw
-> hops
;
273 raw
.xid
= packet
-> raw
-> xid
;
274 raw
.secs
= packet
-> raw
-> secs
;
275 raw
.flags
= packet
-> raw
-> flags
;
276 raw
.ciaddr
= packet
-> raw
-> ciaddr
;
278 /* yiaddr is an ipv4 address, it must be 4 octets. */
279 memcpy (&raw
.yiaddr
, lease
->ip_addr
.iabuf
, 4);
281 /* If we're always supposed to broadcast to this client, set
282 the broadcast bit in the bootp flags field. */
283 if ((oc
= lookup_option (&server_universe
,
284 options
, SV_ALWAYS_BROADCAST
)) &&
285 evaluate_boolean_option_cache (&ignorep
, packet
, lease
,
286 (struct client_state
*)0,
287 packet
-> options
, options
,
288 &lease
-> scope
, oc
, MDL
))
289 raw
.flags
|= htons (BOOTP_BROADCAST
);
291 /* Figure out the address of the next server. */
292 memset (&d1
, 0, sizeof d1
);
293 oc
= lookup_option (&server_universe
, options
, SV_NEXT_SERVER
);
295 evaluate_option_cache (&d1
, packet
, lease
,
296 (struct client_state
*)0,
297 packet
-> options
, options
,
298 &lease
-> scope
, oc
, MDL
)) {
299 /* If there was more than one answer, take the first. */
300 if (d1
.len
>= 4 && d1
.data
)
301 memcpy (&raw
.siaddr
, d1
.data
, 4);
302 data_string_forget (&d1
, MDL
);
304 if ((lease
->subnet
->shared_network
->interface
!= NULL
) &&
305 lease
->subnet
->shared_network
->interface
->address_count
)
307 lease
->subnet
->shared_network
->interface
->addresses
[0];
308 else if (packet
->interface
->address_count
)
309 raw
.siaddr
= packet
->interface
->addresses
[0];
312 raw
.giaddr
= packet
-> raw
-> giaddr
;
314 /* Figure out the filename. */
315 oc
= lookup_option (&server_universe
, options
, SV_FILENAME
);
317 evaluate_option_cache (&d1
, packet
, lease
,
318 (struct client_state
*)0,
319 packet
-> options
, options
,
320 &lease
-> scope
, oc
, MDL
)) {
321 memcpy (raw
.file
, d1
.data
,
322 d1
.len
> sizeof raw
.file
? sizeof raw
.file
: d1
.len
);
323 if (sizeof raw
.file
> d1
.len
)
324 memset (&raw
.file
[d1
.len
],
325 0, (sizeof raw
.file
) - d1
.len
);
326 data_string_forget (&d1
, MDL
);
328 memcpy (raw
.file
, packet
-> raw
-> file
, sizeof raw
.file
);
330 /* Choose a server name as above. */
331 oc
= lookup_option (&server_universe
, options
, SV_SERVER_NAME
);
333 evaluate_option_cache (&d1
, packet
, lease
,
334 (struct client_state
*)0,
335 packet
-> options
, options
,
336 &lease
-> scope
, oc
, MDL
)) {
337 memcpy (raw
.sname
, d1
.data
,
338 d1
.len
> sizeof raw
.sname
? sizeof raw
.sname
: d1
.len
);
339 if (sizeof raw
.sname
> d1
.len
)
340 memset (&raw
.sname
[d1
.len
],
341 0, (sizeof raw
.sname
) - d1
.len
);
342 data_string_forget (&d1
, MDL
);
345 /* Execute the commit statements, if there are any. */
346 execute_statements (NULL
, packet
, lease
, NULL
, packet
->options
,
347 options
, &lease
->scope
, lease
->on_star
.on_commit
,
350 /* We're done with the option state. */
351 option_state_dereference (&options
, MDL
);
353 /* Set up the hardware destination address... */
354 hto
.hbuf
[0] = packet
-> raw
-> htype
;
355 hto
.hlen
= packet
-> raw
-> hlen
+ 1;
356 memcpy (&hto
.hbuf
[1], packet
-> raw
-> chaddr
, packet
-> raw
-> hlen
);
358 if (packet
->interface
->address_count
) {
359 from
= packet
->interface
->addresses
[0];
361 log_error("%s: Interface %s appears to have no IPv4 "
362 "addresses, and so dhcpd cannot select a source "
363 "address.", msgbuf
, packet
->interface
->name
);
367 /* Report what we're doing... */
368 log_info("%s", msgbuf
);
369 log_info("BOOTREPLY for %s to %s (%s) via %s",
370 piaddr(lease
->ip_addr
),
371 ((hp
!= NULL
) && (hp
->name
!= NULL
)) ? hp
-> name
: "unknown",
372 print_hw_addr (packet
->raw
->htype
,
374 packet
->raw
->chaddr
),
375 packet
->raw
->giaddr
.s_addr
376 ? inet_ntoa (packet
->raw
->giaddr
)
377 : packet
->interface
->name
);
379 /* Set up the parts of the address that are in common. */
380 to
.sin_family
= AF_INET
;
382 to
.sin_len
= sizeof to
;
384 memset (to
.sin_zero
, 0, sizeof to
.sin_zero
);
386 /* If this was gatewayed, send it back to the gateway... */
387 if (raw
.giaddr
.s_addr
) {
388 to
.sin_addr
= raw
.giaddr
;
389 to
.sin_port
= local_port
;
391 if (fallback_interface
) {
392 result
= send_packet (fallback_interface
, NULL
, &raw
,
393 outgoing
.packet_length
, from
,
396 log_error ("%s:%d: Failed to send %d byte long "
397 "packet over %s interface.", MDL
,
398 outgoing
.packet_length
,
399 fallback_interface
->name
);
405 /* If it comes from a client that already knows its address
406 and is not requesting a broadcast response, and we can
407 unicast to a client without using the ARP protocol, sent it
408 directly to that client. */
409 } else if (!(raw
.flags
& htons (BOOTP_BROADCAST
)) &&
410 can_unicast_without_arp (packet
-> interface
)) {
411 to
.sin_addr
= raw
.yiaddr
;
412 to
.sin_port
= remote_port
;
414 /* Otherwise, broadcast it on the local network. */
416 to
.sin_addr
= limited_broadcast
;
417 to
.sin_port
= remote_port
; /* XXX */
421 result
= send_packet(packet
->interface
, packet
, &raw
,
422 outgoing
.packet_length
, from
, &to
, &hto
);
424 log_error ("%s:%d: Failed to send %d byte long packet over %s"
425 " interface.", MDL
, outgoing
.packet_length
,
426 packet
->interface
->name
);
432 option_state_dereference (&options
, MDL
);
434 lease_dereference (&lease
, MDL
);
436 host_dereference (&hp
, MDL
);
438 host_dereference (&host
, MDL
);