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