]>
git.ipfire.org Git - thirdparty/dhcp.git/blob - server/bootp.c
3 BOOTP Protocol support. */
6 * Copyright (c) 2004-2016 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
25 * https://www.isc.org/
33 # define send_packet trace_packet_send
37 struct packet
*packet
;
40 struct host_decl
*hp
= (struct host_decl
*)0;
41 struct host_decl
*host
= (struct host_decl
*)0;
42 struct packet outgoing
;
43 struct dhcp_packet raw
;
44 struct sockaddr_in to
;
47 struct option_state
*options
= (struct option_state
*)0;
48 struct lease
*lease
= (struct lease
*)0;
50 struct data_string d1
;
51 struct option_cache
*oc
;
54 int peer_has_leases
= 0;
56 if (packet
-> raw
-> op
!= BOOTREQUEST
)
59 /* %Audit% This is log output. %2004.06.17,Safe%
60 * If we truncate we hope the user can get a hint from the log.
62 snprintf (msgbuf
, sizeof msgbuf
, "BOOTREQUEST from %s via %s",
63 print_hw_addr (packet
-> raw
-> htype
,
64 packet
-> raw
-> hlen
,
65 packet
-> raw
-> chaddr
),
66 packet
-> raw
-> giaddr
.s_addr
67 ? inet_ntoa (packet
-> raw
-> giaddr
)
68 : packet
-> interface
-> name
);
70 if (!locate_network (packet
)) {
71 log_info ("%s: network unknown", msgbuf
);
75 find_lease (&lease
, packet
, packet
-> shared_network
,
76 0, 0, (struct lease
*)0, MDL
);
78 if (lease
&& lease
->host
)
79 host_reference(&hp
, lease
->host
, MDL
);
81 if (!lease
|| ((lease
->flags
& STATIC_LEASE
) == 0)) {
84 /* We didn't find an applicable fixed-address host
85 declaration. Just in case we may be able to dynamically
86 assign an address, see if there's a host declaration
87 that doesn't have an ip address associated with it. */
90 find_hosts_by_haddr(&hp
, packet
->raw
->htype
,
92 packet
->raw
->hlen
, MDL
);
94 for (h
= hp
; h
; h
= h
-> n_ipaddr
) {
95 if (!h
-> fixed_addr
) {
96 host_reference(&host
, h
, MDL
);
102 host_dereference(&hp
, MDL
);
105 host_reference(&hp
, host
, MDL
);
106 host_dereference(&host
, MDL
);
109 /* Allocate a lease if we have not yet found one. */
111 allocate_lease (&lease
, packet
,
112 packet
-> shared_network
-> pools
,
116 log_info("%s: BOOTP from dynamic client and no "
117 "dynamic leases", msgbuf
);
121 #if defined(FAILOVER_PROTOCOL)
122 if ((lease
->pool
!= NULL
) &&
123 (lease
->pool
->failover_peer
!= NULL
)) {
124 dhcp_failover_state_t
*peer
;
126 peer
= lease
->pool
->failover_peer
;
128 /* If we are in a failover state that bars us from
129 * answering, do not do so.
130 * If we are in a cooperative state, load balance
133 if ((peer
->service_state
== not_responding
) ||
134 (peer
->service_state
== service_startup
)) {
135 log_info("%s: not responding%s",
138 } else if((peer
->service_state
== cooperating
) &&
139 !load_balance_mine(packet
, peer
)) {
140 log_info("%s: load balance to peer %s",
147 ack_lease (packet
, lease
, 0, 0, msgbuf
, 0, hp
);
151 /* Run the executable statements to compute the client and server
153 option_state_allocate (&options
, MDL
);
155 /* Execute the subnet statements. */
156 execute_statements_in_scope (NULL
, packet
, lease
, NULL
,
157 packet
->options
, options
,
158 &lease
->scope
, lease
->subnet
->group
,
161 /* Execute statements from class scopes. */
162 for (i
= packet
-> class_count
; i
> 0; i
--) {
163 execute_statements_in_scope(NULL
, packet
, lease
, NULL
,
164 packet
->options
, options
,
166 packet
->classes
[i
- 1]->group
,
167 lease
->subnet
->group
, NULL
);
170 /* Execute the host statements. */
172 execute_statements_in_scope(NULL
, packet
, lease
, NULL
,
173 packet
->options
, options
,
174 &lease
->scope
, hp
->group
,
175 lease
->subnet
->group
, NULL
);
178 /* Drop the request if it's not allowed for this client. */
179 if ((oc
= lookup_option (&server_universe
, options
, SV_ALLOW_BOOTP
)) &&
180 !evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
182 packet
->options
, options
,
183 &lease
->scope
, oc
, MDL
)) {
185 log_info ("%s: bootp disallowed", msgbuf
);
189 if ((oc
= lookup_option(&server_universe
,
190 options
, SV_ALLOW_BOOTING
)) &&
191 !evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
193 packet
->options
, options
,
194 &lease
->scope
, oc
, MDL
)) {
196 log_info ("%s: booting disallowed", msgbuf
);
200 /* Set up the outgoing packet... */
201 memset (&outgoing
, 0, sizeof outgoing
);
202 memset (&raw
, 0, sizeof raw
);
205 /* If we didn't get a known vendor magic number on the way in,
206 just copy the input options to the output. */
207 i
= SV_ALWAYS_REPLY_RFC1048
;
208 if (!packet
->options_valid
&&
209 !(evaluate_boolean_option_cache(&ignorep
, packet
, lease
, NULL
,
210 packet
->options
, options
,
212 lookup_option (&server_universe
,
213 options
, i
), MDL
))) {
214 if (packet
->packet_length
> DHCP_FIXED_NON_UDP
) {
215 memcpy(outgoing
.raw
->options
, packet
->raw
->options
,
216 packet
->packet_length
- DHCP_FIXED_NON_UDP
);
219 outgoing
.packet_length
=
220 (packet
->packet_length
< BOOTP_MIN_LEN
)
222 : packet
->packet_length
;
225 /* Use the subnet mask from the subnet declaration if no other
226 mask has been provided. */
227 oc
= (struct option_cache
*)0;
229 if (!lookup_option (&dhcp_universe
, options
, i
)) {
230 if (option_cache_allocate (&oc
, MDL
)) {
233 lease
-> subnet
-> netmask
.iabuf
,
234 lease
-> subnet
-> netmask
.len
,
236 option_code_hash_lookup(&oc
->option
,
237 dhcp_universe
.code_hash
,
239 save_option (&dhcp_universe
,
242 option_cache_dereference (&oc
, MDL
);
246 /* If use-host-decl-names is enabled and there is a hostname
247 * defined in the host delcartion, send it back in hostname
249 use_host_decl_name(packet
, lease
, options
);
251 /* Pack the options into the buffer. Unlike DHCP, we
252 can't pack options into the filename and server
255 outgoing
.packet_length
=
256 cons_options (packet
, outgoing
.raw
, lease
,
257 (struct client_state
*)0, 0,
258 packet
-> options
, options
,
260 0, 0, 1, (struct data_string
*)0,
262 if (outgoing
.packet_length
< BOOTP_MIN_LEN
)
263 outgoing
.packet_length
= BOOTP_MIN_LEN
;
266 /* Take the fields that we care about... */
268 raw
.htype
= packet
-> raw
-> htype
;
269 raw
.hlen
= packet
-> raw
-> hlen
;
270 memcpy (raw
.chaddr
, packet
-> raw
-> chaddr
, sizeof raw
.chaddr
);
271 raw
.hops
= packet
-> raw
-> hops
;
272 raw
.xid
= packet
-> raw
-> xid
;
273 raw
.secs
= packet
-> raw
-> secs
;
274 raw
.flags
= packet
-> raw
-> flags
;
275 raw
.ciaddr
= packet
-> raw
-> ciaddr
;
277 /* yiaddr is an ipv4 address, it must be 4 octets. */
278 memcpy (&raw
.yiaddr
, lease
->ip_addr
.iabuf
, 4);
280 /* If we're always supposed to broadcast to this client, set
281 the broadcast bit in the bootp flags field. */
282 if ((oc
= lookup_option (&server_universe
,
283 options
, SV_ALWAYS_BROADCAST
)) &&
284 evaluate_boolean_option_cache (&ignorep
, packet
, lease
,
285 (struct client_state
*)0,
286 packet
-> options
, options
,
287 &lease
-> scope
, oc
, MDL
))
288 raw
.flags
|= htons (BOOTP_BROADCAST
);
290 /* Figure out the address of the next server. */
291 memset (&d1
, 0, sizeof d1
);
292 oc
= lookup_option (&server_universe
, options
, SV_NEXT_SERVER
);
294 evaluate_option_cache (&d1
, packet
, lease
,
295 (struct client_state
*)0,
296 packet
-> options
, options
,
297 &lease
-> scope
, oc
, MDL
)) {
298 /* If there was more than one answer, take the first. */
299 if (d1
.len
>= 4 && d1
.data
)
300 memcpy (&raw
.siaddr
, d1
.data
, 4);
301 data_string_forget (&d1
, MDL
);
303 if ((lease
->subnet
->shared_network
->interface
!= NULL
) &&
304 lease
->subnet
->shared_network
->interface
->address_count
)
306 lease
->subnet
->shared_network
->interface
->addresses
[0];
307 else if (packet
->interface
->address_count
)
308 raw
.siaddr
= packet
->interface
->addresses
[0];
311 raw
.giaddr
= packet
-> raw
-> giaddr
;
313 /* Figure out the filename. */
314 oc
= lookup_option (&server_universe
, options
, SV_FILENAME
);
316 evaluate_option_cache (&d1
, packet
, lease
,
317 (struct client_state
*)0,
318 packet
-> options
, options
,
319 &lease
-> scope
, oc
, MDL
)) {
320 memcpy (raw
.file
, d1
.data
,
321 d1
.len
> sizeof raw
.file
? sizeof raw
.file
: d1
.len
);
322 if (sizeof raw
.file
> d1
.len
)
323 memset (&raw
.file
[d1
.len
],
324 0, (sizeof raw
.file
) - d1
.len
);
325 data_string_forget (&d1
, MDL
);
327 memcpy (raw
.file
, packet
-> raw
-> file
, sizeof raw
.file
);
329 /* Choose a server name as above. */
330 oc
= lookup_option (&server_universe
, options
, SV_SERVER_NAME
);
332 evaluate_option_cache (&d1
, packet
, lease
,
333 (struct client_state
*)0,
334 packet
-> options
, options
,
335 &lease
-> scope
, oc
, MDL
)) {
336 memcpy (raw
.sname
, d1
.data
,
337 d1
.len
> sizeof raw
.sname
? sizeof raw
.sname
: d1
.len
);
338 if (sizeof raw
.sname
> d1
.len
)
339 memset (&raw
.sname
[d1
.len
],
340 0, (sizeof raw
.sname
) - d1
.len
);
341 data_string_forget (&d1
, MDL
);
344 /* Execute the commit statements, if there are any. */
345 execute_statements (NULL
, packet
, lease
, NULL
, packet
->options
,
346 options
, &lease
->scope
, lease
->on_star
.on_commit
,
349 /* We're done with the option state. */
350 option_state_dereference (&options
, MDL
);
352 #if defined(DHCPv6) && defined(DHCP4o6)
353 if (dhcpv4_over_dhcpv6
&& (packet
->dhcp4o6_response
!= NULL
)) {
354 /* Report what we're doing... */
355 log_info("%s", msgbuf
);
356 log_info("DHCP4o6 BOOTREPLY for %s to %s (%s) via %s",
357 piaddr(lease
->ip_addr
),
358 ((hp
!= NULL
) && (hp
->name
!= NULL
)) ?
359 hp
-> name
: "unknown",
360 print_hw_addr (packet
->raw
->htype
,
362 packet
->raw
->chaddr
),
363 piaddr(packet
->client_addr
));
365 /* fill dhcp4o6_response */
366 packet
->dhcp4o6_response
->len
= outgoing
.packet_length
;
367 packet
->dhcp4o6_response
->buffer
= NULL
;
368 if (!buffer_allocate(&packet
->dhcp4o6_response
->buffer
,
369 outgoing
.packet_length
, MDL
)) {
370 log_fatal("No memory to store DHCP4o6 reply.");
372 packet
->dhcp4o6_response
->data
=
373 packet
->dhcp4o6_response
->buffer
->data
;
374 memcpy(packet
->dhcp4o6_response
->buffer
->data
,
375 outgoing
.raw
, outgoing
.packet_length
);
380 /* Set up the hardware destination address... */
381 hto
.hbuf
[0] = packet
-> raw
-> htype
;
382 hto
.hlen
= packet
-> raw
-> hlen
+ 1;
383 memcpy (&hto
.hbuf
[1], packet
-> raw
-> chaddr
, packet
-> raw
-> hlen
);
385 if (packet
->interface
->address_count
) {
386 from
= packet
->interface
->addresses
[0];
388 log_error("%s: Interface %s appears to have no IPv4 "
389 "addresses, and so dhcpd cannot select a source "
390 "address.", msgbuf
, packet
->interface
->name
);
394 /* Report what we're doing... */
395 log_info("%s", msgbuf
);
396 log_info("BOOTREPLY for %s to %s (%s) via %s",
397 piaddr(lease
->ip_addr
),
398 ((hp
!= NULL
) && (hp
->name
!= NULL
)) ? hp
-> name
: "unknown",
399 print_hw_addr (packet
->raw
->htype
,
401 packet
->raw
->chaddr
),
402 packet
->raw
->giaddr
.s_addr
403 ? inet_ntoa (packet
->raw
->giaddr
)
404 : packet
->interface
->name
);
406 /* Set up the parts of the address that are in common. */
407 to
.sin_family
= AF_INET
;
409 to
.sin_len
= sizeof to
;
411 memset (to
.sin_zero
, 0, sizeof to
.sin_zero
);
413 /* If this was gatewayed, send it back to the gateway... */
414 if (raw
.giaddr
.s_addr
) {
415 to
.sin_addr
= raw
.giaddr
;
416 to
.sin_port
= local_port
;
418 if (fallback_interface
) {
419 result
= send_packet (fallback_interface
, NULL
, &raw
,
420 outgoing
.packet_length
, from
,
423 log_error ("%s:%d: Failed to send %d byte long "
424 "packet over %s interface.", MDL
,
425 outgoing
.packet_length
,
426 fallback_interface
->name
);
432 /* If it comes from a client that already knows its address
433 and is not requesting a broadcast response, and we can
434 unicast to a client without using the ARP protocol, sent it
435 directly to that client. */
436 } else if (!(raw
.flags
& htons (BOOTP_BROADCAST
)) &&
437 can_unicast_without_arp (packet
-> interface
)) {
438 to
.sin_addr
= raw
.yiaddr
;
439 to
.sin_port
= remote_port
;
441 /* Otherwise, broadcast it on the local network. */
443 to
.sin_addr
= limited_broadcast
;
444 to
.sin_port
= remote_port
; /* XXX */
448 result
= send_packet(packet
->interface
, packet
, &raw
,
449 outgoing
.packet_length
, from
, &to
, &hto
);
451 log_error ("%s:%d: Failed to send %d byte long packet over %s"
452 " interface.", MDL
, outgoing
.packet_length
,
453 packet
->interface
->name
);
459 option_state_dereference (&options
, MDL
);
461 lease_dereference (&lease
, MDL
);
463 host_dereference (&hp
, MDL
);
465 host_dereference (&host
, MDL
);