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
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 (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