]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/bootp.c
[master] Added null check to eliminate call to dfree in lc_delete_all
[thirdparty/dhcp.git] / server / bootp.c
1 /* bootp.c
2
3 BOOTP Protocol support. */
4
5 /*
6 * Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
8 *
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.
12 *
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.
20 *
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * https://www.isc.org/
26 *
27 */
28
29 #include "dhcpd.h"
30 #include <errno.h>
31
32 #if defined (TRACING)
33 # define send_packet trace_packet_send
34 #endif
35
36 void bootp (packet)
37 struct packet *packet;
38 {
39 int result;
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;
45 struct in_addr from;
46 struct hardware hto;
47 struct option_state *options = (struct option_state *)0;
48 struct lease *lease = (struct lease *)0;
49 unsigned i;
50 struct data_string d1;
51 struct option_cache *oc;
52 char msgbuf [1024];
53 int ignorep;
54 int peer_has_leases = 0;
55
56 if (packet -> raw -> op != BOOTREQUEST)
57 return;
58
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.
61 */
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);
69
70 if (!locate_network (packet)) {
71 log_info ("%s: network unknown", msgbuf);
72 return;
73 }
74
75 find_lease (&lease, packet, packet -> shared_network,
76 0, 0, (struct lease *)0, MDL);
77
78 if (lease && lease->host)
79 host_reference(&hp, lease->host, MDL);
80
81 if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
82 struct host_decl *h;
83
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. */
88
89 if (!hp)
90 find_hosts_by_haddr(&hp, packet->raw->htype,
91 packet->raw->chaddr,
92 packet->raw->hlen, MDL);
93
94 for (h = hp; h; h = h -> n_ipaddr) {
95 if (!h -> fixed_addr) {
96 host_reference(&host, h, MDL);
97 break;
98 }
99 }
100
101 if (hp)
102 host_dereference(&hp, MDL);
103
104 if (host) {
105 host_reference(&hp, host, MDL);
106 host_dereference(&host, MDL);
107 }
108
109 /* Allocate a lease if we have not yet found one. */
110 if (!lease)
111 allocate_lease (&lease, packet,
112 packet -> shared_network -> pools,
113 &peer_has_leases);
114
115 if (lease == NULL) {
116 log_info("%s: BOOTP from dynamic client and no "
117 "dynamic leases", msgbuf);
118 goto out;
119 }
120
121 #if defined(FAILOVER_PROTOCOL)
122 if ((lease->pool != NULL) &&
123 (lease->pool->failover_peer != NULL)) {
124 dhcp_failover_state_t *peer;
125
126 peer = lease->pool->failover_peer;
127
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
131 * (all) responses.
132 */
133 if ((peer->service_state == not_responding) ||
134 (peer->service_state == service_startup)) {
135 log_info("%s: not responding%s",
136 msgbuf, peer->nrr);
137 goto out;
138 } else if((peer->service_state == cooperating) &&
139 !load_balance_mine(packet, peer)) {
140 log_info("%s: load balance to peer %s",
141 msgbuf, peer->name);
142 goto out;
143 }
144 }
145 #endif
146
147 ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
148 goto out;
149 }
150
151 /* Run the executable statements to compute the client and server
152 options. */
153 option_state_allocate (&options, MDL);
154
155 /* Execute the subnet statements. */
156 execute_statements_in_scope (NULL, packet, lease, NULL,
157 packet->options, options,
158 &lease->scope, lease->subnet->group,
159 NULL, NULL);
160
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,
165 &lease->scope,
166 packet->classes[i - 1]->group,
167 lease->subnet->group, NULL);
168 }
169
170 /* Execute the host statements. */
171 if (hp != NULL) {
172 execute_statements_in_scope(NULL, packet, lease, NULL,
173 packet->options, options,
174 &lease->scope, hp->group,
175 lease->subnet->group, NULL);
176 }
177
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,
181 NULL,
182 packet->options, options,
183 &lease->scope, oc, MDL)) {
184 if (!ignorep)
185 log_info ("%s: bootp disallowed", msgbuf);
186 goto out;
187 }
188
189 if ((oc = lookup_option(&server_universe,
190 options, SV_ALLOW_BOOTING)) &&
191 !evaluate_boolean_option_cache(&ignorep, packet, lease,
192 NULL,
193 packet->options, options,
194 &lease->scope, oc, MDL)) {
195 if (!ignorep)
196 log_info ("%s: booting disallowed", msgbuf);
197 goto out;
198 }
199
200 /* Set up the outgoing packet... */
201 memset (&outgoing, 0, sizeof outgoing);
202 memset (&raw, 0, sizeof raw);
203 outgoing.raw = &raw;
204
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,
211 &lease->scope,
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);
217 }
218
219 outgoing.packet_length =
220 (packet->packet_length < BOOTP_MIN_LEN)
221 ? BOOTP_MIN_LEN
222 : packet->packet_length;
223 } else {
224
225 /* Use the subnet mask from the subnet declaration if no other
226 mask has been provided. */
227 oc = (struct option_cache *)0;
228 i = DHO_SUBNET_MASK;
229 if (!lookup_option (&dhcp_universe, options, i)) {
230 if (option_cache_allocate (&oc, MDL)) {
231 if (make_const_data
232 (&oc -> expression,
233 lease -> subnet -> netmask.iabuf,
234 lease -> subnet -> netmask.len,
235 0, 0, MDL)) {
236 option_code_hash_lookup(&oc->option,
237 dhcp_universe.code_hash,
238 &i, 0, MDL);
239 save_option (&dhcp_universe,
240 options, oc);
241 }
242 option_cache_dereference (&oc, MDL);
243 }
244 }
245
246 /* If use-host-decl-names is enabled and there is a hostname
247 * defined in the host delcartion, send it back in hostname
248 * option */
249 use_host_decl_name(packet, lease, options);
250
251 /* Pack the options into the buffer. Unlike DHCP, we
252 can't pack options into the filename and server
253 name buffers. */
254
255 outgoing.packet_length =
256 cons_options (packet, outgoing.raw, lease,
257 (struct client_state *)0, 0,
258 packet -> options, options,
259 &lease -> scope,
260 0, 0, 1, (struct data_string *)0,
261 (const char *)0);
262 if (outgoing.packet_length < BOOTP_MIN_LEN)
263 outgoing.packet_length = BOOTP_MIN_LEN;
264 }
265
266 /* Take the fields that we care about... */
267 raw.op = BOOTREPLY;
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;
276
277 /* yiaddr is an ipv4 address, it must be 4 octets. */
278 memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
279
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);
289
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);
293 if (oc &&
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);
302 } else {
303 if ((lease->subnet->shared_network->interface != NULL) &&
304 lease->subnet->shared_network->interface->address_count)
305 raw.siaddr =
306 lease->subnet->shared_network->interface->addresses[0];
307 else if (packet->interface->address_count)
308 raw.siaddr = packet->interface->addresses[0];
309 }
310
311 raw.giaddr = packet -> raw -> giaddr;
312
313 /* Figure out the filename. */
314 oc = lookup_option (&server_universe, options, SV_FILENAME);
315 if (oc &&
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);
326 } else
327 memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
328
329 /* Choose a server name as above. */
330 oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
331 if (oc &&
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);
342 }
343
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,
347 NULL);
348
349 /* We're done with the option state. */
350 option_state_dereference (&options, MDL);
351
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,
361 packet->raw->hlen,
362 packet->raw->chaddr),
363 piaddr(packet->client_addr));
364
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.");
371 }
372 packet->dhcp4o6_response->data =
373 packet->dhcp4o6_response->buffer->data;
374 memcpy(packet->dhcp4o6_response->buffer->data,
375 outgoing.raw, outgoing.packet_length);
376 goto out;
377 }
378 #endif
379
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);
384
385 if (packet->interface->address_count) {
386 from = packet->interface->addresses[0];
387 } else {
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);
391 goto out;
392 }
393
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,
400 packet->raw->hlen,
401 packet->raw->chaddr),
402 packet->raw->giaddr.s_addr
403 ? inet_ntoa (packet->raw->giaddr)
404 : packet->interface->name);
405
406 /* Set up the parts of the address that are in common. */
407 to.sin_family = AF_INET;
408 #ifdef HAVE_SA_LEN
409 to.sin_len = sizeof to;
410 #endif
411 memset (to.sin_zero, 0, sizeof to.sin_zero);
412
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;
417
418 if (fallback_interface) {
419 result = send_packet (fallback_interface, NULL, &raw,
420 outgoing.packet_length, from,
421 &to, &hto);
422 if (result < 0) {
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);
427 }
428
429 goto out;
430 }
431
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;
440
441 /* Otherwise, broadcast it on the local network. */
442 } else {
443 to.sin_addr = limited_broadcast;
444 to.sin_port = remote_port; /* XXX */
445 }
446
447 errno = 0;
448 result = send_packet(packet->interface, packet, &raw,
449 outgoing.packet_length, from, &to, &hto);
450 if (result < 0) {
451 log_error ("%s:%d: Failed to send %d byte long packet over %s"
452 " interface.", MDL, outgoing.packet_length,
453 packet->interface->name);
454 }
455
456 out:
457
458 if (options)
459 option_state_dereference (&options, MDL);
460 if (lease)
461 lease_dereference (&lease, MDL);
462 if (hp)
463 host_dereference (&hp, MDL);
464 if (host)
465 host_dereference (&host, MDL);
466 }