1 /* $NetBSD: bootp.c,v 1.3 2022/04/03 01:10:59 christos Exp $ */
2
3 /* bootp.c
4
5 BOOTP Protocol support. */
6
7 /*
8 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1995-2003 by Internet Software Consortium
10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Internet Systems Consortium, Inc.
24 * PO Box 360
25 * Newmarket, NH 03857 USA
26 * <info@isc.org>
27 * https://www.isc.org/
28 *
29 */
30
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: bootp.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
33
34 #include "dhcpd.h"
35 #include <errno.h>
36
37 #if defined (TRACING)
38 # define send_packet trace_packet_send
39 #endif
40
bootp(packet)41 void bootp (packet)
42 struct packet *packet;
43 {
44 int result;
45 struct host_decl *hp = (struct host_decl *)0;
46 struct host_decl *host = (struct host_decl *)0;
47 struct packet outgoing;
48 struct dhcp_packet raw;
49 struct sockaddr_in to;
50 struct in_addr from;
51 struct hardware hto;
52 struct option_state *options = (struct option_state *)0;
53 struct lease *lease = (struct lease *)0;
54 unsigned i;
55 struct data_string d1;
56 struct option_cache *oc;
57 char msgbuf [1024];
58 int ignorep;
59 int peer_has_leases = 0;
60
61 if (packet -> raw -> op != BOOTREQUEST)
62 return;
63
64 /* %Audit% This is log output. %2004.06.17,Safe%
65 * If we truncate we hope the user can get a hint from the log.
66 */
67 snprintf (msgbuf, sizeof msgbuf, "BOOTREQUEST from %s via %s",
68 print_hw_addr (packet -> raw -> htype,
69 packet -> raw -> hlen,
70 packet -> raw -> chaddr),
71 packet -> raw -> giaddr.s_addr
72 ? inet_ntoa (packet -> raw -> giaddr)
73 : packet -> interface -> name);
74
75 if (!locate_network (packet)) {
76 log_info ("%s: network unknown", msgbuf);
77 return;
78 }
79
80 find_lease (&lease, packet, packet -> shared_network,
81 0, 0, (struct lease *)0, MDL);
82
83 if (lease && lease->host)
84 host_reference(&hp, lease->host, MDL);
85
86 if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
87 struct host_decl *h;
88
89 /* We didn't find an applicable fixed-address host
90 declaration. Just in case we may be able to dynamically
91 assign an address, see if there's a host declaration
92 that doesn't have an ip address associated with it. */
93
94 if (!hp)
95 find_hosts_by_haddr(&hp, packet->raw->htype,
96 packet->raw->chaddr,
97 packet->raw->hlen, MDL);
98
99 for (h = hp; h; h = h -> n_ipaddr) {
100 if (!h -> fixed_addr) {
101 host_reference(&host, h, MDL);
102 break;
103 }
104 }
105
106 if (hp)
107 host_dereference(&hp, MDL);
108
109 if (host) {
110 host_reference(&hp, host, MDL);
111 host_dereference(&host, MDL);
112 }
113
114 /* Allocate a lease if we have not yet found one. */
115 if (!lease)
116 allocate_lease (&lease, packet,
117 packet -> shared_network -> pools,
118 &peer_has_leases);
119
120 if (lease == NULL) {
121 log_info("%s: BOOTP from dynamic client and no "
122 "dynamic leases", msgbuf);
123 goto out;
124 }
125
126 #if defined(FAILOVER_PROTOCOL)
127 if ((lease->pool != NULL) &&
128 (lease->pool->failover_peer != NULL)) {
129 dhcp_failover_state_t *peer;
130
131 peer = lease->pool->failover_peer;
132
133 /* If we are in a failover state that bars us from
134 * answering, do not do so.
135 * If we are in a cooperative state, load balance
136 * (all) responses.
137 */
138 if ((peer->service_state == not_responding) ||
139 (peer->service_state == service_startup)) {
140 log_info("%s: not responding%s",
141 msgbuf, peer->nrr);
142 goto out;
143 } else if((peer->service_state == cooperating) &&
144 !load_balance_mine(packet, peer)) {
145 log_info("%s: load balance to peer %s",
146 msgbuf, peer->name);
147 goto out;
148 }
149 }
150 #endif
151
152 ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
153 goto out;
154 }
155
156 /* Run the executable statements to compute the client and server
157 options. */
158 option_state_allocate (&options, MDL);
159
160 /* Execute the subnet statements. */
161 execute_statements_in_scope (NULL, packet, lease, NULL,
162 packet->options, options,
163 &lease->scope, lease->subnet->group,
164 NULL, NULL);
165
166 /* Execute statements from class scopes. */
167 for (i = packet -> class_count; i > 0; i--) {
168 execute_statements_in_scope(NULL, packet, lease, NULL,
169 packet->options, options,
170 &lease->scope,
171 packet->classes[i - 1]->group,
172 lease->subnet->group, NULL);
173 }
174
175 /* Execute the host statements. */
176 if (hp != NULL) {
177 execute_statements_in_scope(NULL, packet, lease, NULL,
178 packet->options, options,
179 &lease->scope, hp->group,
180 lease->subnet->group, NULL);
181 }
182
183 /* Drop the request if it's not allowed for this client. */
184 if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
185 !evaluate_boolean_option_cache(&ignorep, packet, lease,
186 NULL,
187 packet->options, options,
188 &lease->scope, oc, MDL)) {
189 if (!ignorep)
190 log_info ("%s: bootp disallowed", msgbuf);
191 goto out;
192 }
193
194 if ((oc = lookup_option(&server_universe,
195 options, SV_ALLOW_BOOTING)) &&
196 !evaluate_boolean_option_cache(&ignorep, packet, lease,
197 NULL,
198 packet->options, options,
199 &lease->scope, oc, MDL)) {
200 if (!ignorep)
201 log_info ("%s: booting disallowed", msgbuf);
202 goto out;
203 }
204
205 /* Set up the outgoing packet... */
206 memset (&outgoing, 0, sizeof outgoing);
207 memset (&raw, 0, sizeof raw);
208 outgoing.raw = &raw;
209
210 /* If we didn't get a known vendor magic number on the way in,
211 just copy the input options to the output. */
212 i = SV_ALWAYS_REPLY_RFC1048;
213 if (!packet->options_valid &&
214 !(evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
215 packet->options, options,
216 &lease->scope,
217 lookup_option (&server_universe,
218 options, i), MDL))) {
219 if (packet->packet_length > DHCP_FIXED_NON_UDP) {
220 memcpy(outgoing.raw->options, packet->raw->options,
221 packet->packet_length - DHCP_FIXED_NON_UDP);
222 }
223
224 outgoing.packet_length =
225 (packet->packet_length < BOOTP_MIN_LEN)
226 ? BOOTP_MIN_LEN
227 : packet->packet_length;
228 } else {
229
230 /* Use the subnet mask from the subnet declaration if no other
231 mask has been provided. */
232 oc = (struct option_cache *)0;
233 i = DHO_SUBNET_MASK;
234 if (!lookup_option (&dhcp_universe, options, i)) {
235 if (option_cache_allocate (&oc, MDL)) {
236 if (make_const_data
237 (&oc -> expression,
238 lease -> subnet -> netmask.iabuf,
239 lease -> subnet -> netmask.len,
240 0, 0, MDL)) {
241 option_code_hash_lookup(&oc->option,
242 dhcp_universe.code_hash,
243 &i, 0, MDL);
244 save_option (&dhcp_universe,
245 options, oc);
246 }
247 option_cache_dereference (&oc, MDL);
248 }
249 }
250
251 /* If use-host-decl-names is enabled and there is a hostname
252 * defined in the host delcartion, send it back in hostname
253 * option */
254 use_host_decl_name(packet, lease, options);
255
256 /* Pack the options into the buffer. Unlike DHCP, we
257 can't pack options into the filename and server
258 name buffers. */
259
260 outgoing.packet_length =
261 cons_options (packet, outgoing.raw, lease,
262 (struct client_state *)0, 0,
263 packet -> options, options,
264 &lease -> scope,
265 0, 0, 1, (struct data_string *)0,
266 (const char *)0);
267 if (outgoing.packet_length < BOOTP_MIN_LEN)
268 outgoing.packet_length = BOOTP_MIN_LEN;
269 }
270
271 /* Take the fields that we care about... */
272 raw.op = BOOTREPLY;
273 raw.htype = packet -> raw -> htype;
274 raw.hlen = packet -> raw -> hlen;
275 memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
276 raw.hops = packet -> raw -> hops;
277 raw.xid = packet -> raw -> xid;
278 raw.secs = packet -> raw -> secs;
279 raw.flags = packet -> raw -> flags;
280 raw.ciaddr = packet -> raw -> ciaddr;
281
282 /* yiaddr is an ipv4 address, it must be 4 octets. */
283 memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
284
285 /* If we're always supposed to broadcast to this client, set
286 the broadcast bit in the bootp flags field. */
287 if ((oc = lookup_option (&server_universe,
288 options, SV_ALWAYS_BROADCAST)) &&
289 evaluate_boolean_option_cache (&ignorep, packet, lease,
290 (struct client_state *)0,
291 packet -> options, options,
292 &lease -> scope, oc, MDL))
293 raw.flags |= htons (BOOTP_BROADCAST);
294
295 /* Figure out the address of the next server. */
296 memset (&d1, 0, sizeof d1);
297 oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
298 if (oc &&
299 evaluate_option_cache (&d1, packet, lease,
300 (struct client_state *)0,
301 packet -> options, options,
302 &lease -> scope, oc, MDL)) {
303 /* If there was more than one answer, take the first. */
304 if (d1.len >= 4 && d1.data)
305 memcpy (&raw.siaddr, d1.data, 4);
306 data_string_forget (&d1, MDL);
307 } else {
308 if ((lease->subnet->shared_network->interface != NULL) &&
309 lease->subnet->shared_network->interface->address_count)
310 raw.siaddr =
311 lease->subnet->shared_network->interface->addresses[0];
312 else if (packet->interface->address_count)
313 raw.siaddr = packet->interface->addresses[0];
314 }
315
316 raw.giaddr = packet -> raw -> giaddr;
317
318 /* Figure out the filename. */
319 oc = lookup_option (&server_universe, options, SV_FILENAME);
320 if (oc &&
321 evaluate_option_cache (&d1, packet, lease,
322 (struct client_state *)0,
323 packet -> options, options,
324 &lease -> scope, oc, MDL)) {
325 memcpy (raw.file, d1.data,
326 d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
327 if (sizeof raw.file > d1.len)
328 memset (&raw.file [d1.len],
329 0, (sizeof raw.file) - d1.len);
330 data_string_forget (&d1, MDL);
331 } else
332 memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
333
334 /* Choose a server name as above. */
335 oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
336 if (oc &&
337 evaluate_option_cache (&d1, packet, lease,
338 (struct client_state *)0,
339 packet -> options, options,
340 &lease -> scope, oc, MDL)) {
341 memcpy (raw.sname, d1.data,
342 d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
343 if (sizeof raw.sname > d1.len)
344 memset (&raw.sname [d1.len],
345 0, (sizeof raw.sname) - d1.len);
346 data_string_forget (&d1, MDL);
347 }
348
349 /* Execute the commit statements, if there are any. */
350 execute_statements (NULL, packet, lease, NULL, packet->options,
351 options, &lease->scope, lease->on_star.on_commit,
352 NULL);
353
354 /* We're done with the option state. */
355 option_state_dereference (&options, MDL);
356
357 #if defined(DHCPv6) && defined(DHCP4o6)
358 if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
359 /* Report what we're doing... */
360 log_info("%s", msgbuf);
361 log_info("DHCP4o6 BOOTREPLY for %s to %s (%s) via %s",
362 piaddr(lease->ip_addr),
363 ((hp != NULL) && (hp->name != NULL)) ?
364 hp -> name : "unknown",
365 print_hw_addr (packet->raw->htype,
366 packet->raw->hlen,
367 packet->raw->chaddr),
368 piaddr(packet->client_addr));
369
370 /* fill dhcp4o6_response */
371 packet->dhcp4o6_response->len = outgoing.packet_length;
372 packet->dhcp4o6_response->buffer = NULL;
373 if (!buffer_allocate(&packet->dhcp4o6_response->buffer,
374 outgoing.packet_length, MDL)) {
375 log_fatal("No memory to store DHCP4o6 reply.");
376 }
377 packet->dhcp4o6_response->data =
378 packet->dhcp4o6_response->buffer->data;
379 memcpy(packet->dhcp4o6_response->buffer->data,
380 outgoing.raw, outgoing.packet_length);
381 goto out;
382 }
383 #endif
384
385 /* Set up the hardware destination address... */
386 hto.hbuf [0] = packet -> raw -> htype;
387 hto.hlen = packet -> raw -> hlen + 1;
388 memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
389
390 if (packet->interface->address_count) {
391 from = packet->interface->addresses[0];
392 } else {
393 log_error("%s: Interface %s appears to have no IPv4 "
394 "addresses, and so dhcpd cannot select a source "
395 "address.", msgbuf, packet->interface->name);
396 goto out;
397 }
398
399 /* Report what we're doing... */
400 log_info("%s", msgbuf);
401 log_info("BOOTREPLY for %s to %s (%s) via %s",
402 piaddr(lease->ip_addr),
403 ((hp != NULL) && (hp->name != NULL)) ? hp -> name : "unknown",
404 print_hw_addr (packet->raw->htype,
405 packet->raw->hlen,
406 packet->raw->chaddr),
407 packet->raw->giaddr.s_addr
408 ? inet_ntoa (packet->raw->giaddr)
409 : packet->interface->name);
410
411 /* Set up the parts of the address that are in common. */
412 to.sin_family = AF_INET;
413 #ifdef HAVE_SA_LEN
414 to.sin_len = sizeof to;
415 #endif
416 memset (to.sin_zero, 0, sizeof to.sin_zero);
417
418 /* If this was gatewayed, send it back to the gateway... */
419 if (raw.giaddr.s_addr) {
420 to.sin_addr = raw.giaddr;
421 to.sin_port = local_port;
422
423 if (fallback_interface) {
424 result = send_packet (fallback_interface, NULL, &raw,
425 outgoing.packet_length, from,
426 &to, &hto);
427 if (result < 0) {
428 log_error ("%s:%d: Failed to send %d byte long "
429 "packet over %s interface.", MDL,
430 outgoing.packet_length,
431 fallback_interface->name);
432 }
433
434 goto out;
435 }
436
437 /* If it comes from a client that already knows its address
438 and is not requesting a broadcast response, and we can
439 unicast to a client without using the ARP protocol, sent it
440 directly to that client. */
441 } else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
442 can_unicast_without_arp (packet -> interface)) {
443 to.sin_addr = raw.yiaddr;
444 to.sin_port = remote_port;
445
446 /* Otherwise, broadcast it on the local network. */
447 } else {
448 to.sin_addr = limited_broadcast;
449 to.sin_port = remote_port; /* XXX */
450 }
451
452 errno = 0;
453 result = send_packet(packet->interface, packet, &raw,
454 outgoing.packet_length, from, &to, &hto);
455 if (result < 0) {
456 log_error ("%s:%d: Failed to send %d byte long packet over %s"
457 " interface.", MDL, outgoing.packet_length,
458 packet->interface->name);
459 }
460
461 out:
462
463 if (options)
464 option_state_dereference (&options, MDL);
465 if (lease)
466 lease_dereference (&lease, MDL);
467 if (hp)
468 host_dereference (&hp, MDL);
469 if (host)
470 host_dereference (&host, MDL);
471 }
472