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
41void 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