xref: /minix3/external/bsd/dhcp/dist/server/bootp.c (revision d56f51ea7d8b9045e5c8e2028422523d3f9a5840)
1 /*	$NetBSD: bootp.c,v 1.1.1.3 2014/07/12 11:58:04 spz Exp $	*/
2 /* bootp.c
3 
4    BOOTP Protocol support. */
5 
6 /*
7  * Copyright (c) 2009,2012-2014 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1995-2003 by Internet Software Consortium
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
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  *   950 Charter Street
25  *   Redwood City, CA 94063
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: bootp.c,v 1.1.1.3 2014/07/12 11:58:04 spz 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 
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 					    (struct client_state *)0,
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 					    (struct client_state *)0,
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 	if (!packet -> options_valid &&
213 	    !(evaluate_boolean_option_cache
214 	      (&ignorep, packet, lease, (struct client_state *)0,
215 	       packet -> options, options, &lease -> scope,
216 	       lookup_option (&server_universe, options,
217 			      SV_ALWAYS_REPLY_RFC1048), MDL))) {
218 		memcpy (outgoing.raw -> options,
219 			packet -> raw -> options, DHCP_MAX_OPTION_LEN);
220 		outgoing.packet_length = BOOTP_MIN_LEN;
221 	} else {
222 
223 		/* Use the subnet mask from the subnet declaration if no other
224 		   mask has been provided. */
225 
226 		oc = (struct option_cache *)0;
227 		i = DHO_SUBNET_MASK;
228 		if (!lookup_option (&dhcp_universe, options, i)) {
229 			if (option_cache_allocate (&oc, MDL)) {
230 				if (make_const_data
231 				    (&oc -> expression,
232 				     lease -> subnet -> netmask.iabuf,
233 				     lease -> subnet -> netmask.len,
234 				     0, 0, MDL)) {
235 					option_code_hash_lookup(&oc->option,
236 							dhcp_universe.code_hash,
237 								&i, 0, MDL);
238 					save_option (&dhcp_universe,
239 						     options, oc);
240 				}
241 				option_cache_dereference (&oc, MDL);
242 			}
243 		}
244 
245 		/* Pack the options into the buffer.  Unlike DHCP, we
246 		   can't pack options into the filename and server
247 		   name buffers. */
248 
249 		outgoing.packet_length =
250 			cons_options (packet, outgoing.raw, lease,
251 				      (struct client_state *)0, 0,
252 				      packet -> options, options,
253 				      &lease -> scope,
254 				      0, 0, 1, (struct data_string *)0,
255 				      (const char *)0);
256 		if (outgoing.packet_length < BOOTP_MIN_LEN)
257 			outgoing.packet_length = BOOTP_MIN_LEN;
258 	}
259 
260 	/* Take the fields that we care about... */
261 	raw.op = BOOTREPLY;
262 	raw.htype = packet -> raw -> htype;
263 	raw.hlen = packet -> raw -> hlen;
264 	memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
265 	raw.hops = packet -> raw -> hops;
266 	raw.xid = packet -> raw -> xid;
267 	raw.secs = packet -> raw -> secs;
268 	raw.flags = packet -> raw -> flags;
269 	raw.ciaddr = packet -> raw -> ciaddr;
270 
271 	/* yiaddr is an ipv4 address, it must be 4 octets. */
272 	memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
273 
274 	/* If we're always supposed to broadcast to this client, set
275 	   the broadcast bit in the bootp flags field. */
276 	if ((oc = lookup_option (&server_universe,
277 				options, SV_ALWAYS_BROADCAST)) &&
278 	    evaluate_boolean_option_cache (&ignorep, packet, lease,
279 					   (struct client_state *)0,
280 					   packet -> options, options,
281 					   &lease -> scope, oc, MDL))
282 		raw.flags |= htons (BOOTP_BROADCAST);
283 
284 	/* Figure out the address of the next server. */
285 	memset (&d1, 0, sizeof d1);
286 	oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
287 	if (oc &&
288 	    evaluate_option_cache (&d1, packet, lease,
289 				   (struct client_state *)0,
290 				   packet -> options, options,
291 				   &lease -> scope, oc, MDL)) {
292 		/* If there was more than one answer, take the first. */
293 		if (d1.len >= 4 && d1.data)
294 			memcpy (&raw.siaddr, d1.data, 4);
295 		data_string_forget (&d1, MDL);
296 	} else {
297 		if ((lease->subnet->shared_network->interface != NULL) &&
298 		    lease->subnet->shared_network->interface->address_count)
299 		    raw.siaddr =
300 			lease->subnet->shared_network->interface->addresses[0];
301 		else if (packet->interface->address_count)
302 			raw.siaddr = packet->interface->addresses[0];
303 	}
304 
305 	raw.giaddr = packet -> raw -> giaddr;
306 
307 	/* Figure out the filename. */
308 	oc = lookup_option (&server_universe, options, SV_FILENAME);
309 	if (oc &&
310 	    evaluate_option_cache (&d1, packet, lease,
311 				   (struct client_state *)0,
312 				   packet -> options, options,
313 				   &lease -> scope, oc, MDL)) {
314 		memcpy (raw.file, d1.data,
315 			d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
316 		if (sizeof raw.file > d1.len)
317 			memset (&raw.file [d1.len],
318 				0, (sizeof raw.file) - d1.len);
319 		data_string_forget (&d1, MDL);
320 	} else
321 		memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
322 
323 	/* Choose a server name as above. */
324 	oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
325 	if (oc &&
326 	    evaluate_option_cache (&d1, packet, lease,
327 				   (struct client_state *)0,
328 				   packet -> options, options,
329 				   &lease -> scope, oc, MDL)) {
330 		memcpy (raw.sname, d1.data,
331 			d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
332 		if (sizeof raw.sname > d1.len)
333 			memset (&raw.sname [d1.len],
334 				0, (sizeof raw.sname) - d1.len);
335 		data_string_forget (&d1, MDL);
336 	}
337 
338 	/* Execute the commit statements, if there are any. */
339 	execute_statements (NULL, packet, lease, NULL, packet->options,
340 			    options, &lease->scope, lease->on_star.on_commit,
341 			    NULL);
342 
343 	/* We're done with the option state. */
344 	option_state_dereference (&options, MDL);
345 
346 	/* Set up the hardware destination address... */
347 	hto.hbuf [0] = packet -> raw -> htype;
348 	hto.hlen = packet -> raw -> hlen + 1;
349 	memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
350 
351 	if (packet->interface->address_count) {
352 		from = packet->interface->addresses[0];
353 	} else {
354 		log_error("%s: Interface %s appears to have no IPv4 "
355 			  "addresses, and so dhcpd cannot select a source "
356 			  "address.", msgbuf, packet->interface->name);
357 		goto out;
358 	}
359 
360 	/* Report what we're doing... */
361 	log_info("%s", msgbuf);
362 	log_info("BOOTREPLY for %s to %s (%s) via %s",
363 		 piaddr(lease->ip_addr),
364 		 ((hp != NULL) && (hp->name != NULL)) ? hp -> name : "unknown",
365 		 print_hw_addr (packet->raw->htype,
366 				packet->raw->hlen,
367 				packet->raw->chaddr),
368 		 packet->raw->giaddr.s_addr
369 		 ? inet_ntoa (packet->raw->giaddr)
370 		 : packet->interface->name);
371 
372 	/* Set up the parts of the address that are in common. */
373 	to.sin_family = AF_INET;
374 #ifdef HAVE_SA_LEN
375 	to.sin_len = sizeof to;
376 #endif
377 	memset (to.sin_zero, 0, sizeof to.sin_zero);
378 
379 	/* If this was gatewayed, send it back to the gateway... */
380 	if (raw.giaddr.s_addr) {
381 		to.sin_addr = raw.giaddr;
382 		to.sin_port = local_port;
383 
384 		if (fallback_interface) {
385 			result = send_packet (fallback_interface, NULL, &raw,
386 					      outgoing.packet_length, from,
387 					      &to, &hto);
388 			if (result < 0) {
389 				log_error ("%s:%d: Failed to send %d byte long "
390 					   "packet over %s interface.", MDL,
391 					   outgoing.packet_length,
392 					   fallback_interface->name);
393 			}
394 
395 			goto out;
396 		}
397 
398 	/* If it comes from a client that already knows its address
399 	   and is not requesting a broadcast response, and we can
400 	   unicast to a client without using the ARP protocol, sent it
401 	   directly to that client. */
402 	} else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
403 		   can_unicast_without_arp (packet -> interface)) {
404 		to.sin_addr = raw.yiaddr;
405 		to.sin_port = remote_port;
406 
407 	/* Otherwise, broadcast it on the local network. */
408 	} else {
409 		to.sin_addr = limited_broadcast;
410 		to.sin_port = remote_port; /* XXX */
411 	}
412 
413 	errno = 0;
414 	result = send_packet(packet->interface, packet, &raw,
415 			     outgoing.packet_length, from, &to, &hto);
416 	if (result < 0) {
417 		log_error ("%s:%d: Failed to send %d byte long packet over %s"
418 			   " interface.", MDL, outgoing.packet_length,
419 			   packet->interface->name);
420 	}
421 
422       out:
423 
424 	if (options)
425 		option_state_dereference (&options, MDL);
426 	if (lease)
427 		lease_dereference (&lease, MDL);
428 	if (hp)
429 		host_dereference (&hp, MDL);
430 	if (host)
431 		host_dereference (&host, MDL);
432 }
433