]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/bootp.c
- Reworked cons_options() and store_options() to fix a buffer
[thirdparty/dhcp.git] / server / bootp.c
1 /* bootp.c
2
3 BOOTP Protocol support. */
4
5 /*
6 * Copyright (c) 2004,2005,2007 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 * http://www.isc.org/
26 *
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
33 */
34
35 #include "dhcpd.h"
36 #include <errno.h>
37
38 #if defined (TRACING)
39 # define send_packet trace_packet_send
40 #endif
41
42 void bootp (packet)
43 struct packet *packet;
44 {
45 int result;
46 struct host_decl *hp = (struct host_decl *)0;
47 struct host_decl *host = (struct host_decl *)0;
48 struct packet outgoing;
49 struct dhcp_packet raw;
50 struct sockaddr_in to;
51 struct in_addr from;
52 struct hardware hto;
53 struct option_state *options = (struct option_state *)0;
54 struct lease *lease = (struct lease *)0;
55 unsigned i;
56 struct data_string d1;
57 struct option_cache *oc;
58 char msgbuf [1024];
59 int ignorep;
60 int peer_has_leases = 0;
61
62 if (packet -> raw -> op != BOOTREQUEST)
63 return;
64
65 /* %Audit% This is log output. %2004.06.17,Safe%
66 * If we truncate we hope the user can get a hint from the log.
67 */
68 snprintf (msgbuf, sizeof msgbuf, "BOOTREQUEST from %s via %s",
69 print_hw_addr (packet -> raw -> htype,
70 packet -> raw -> hlen,
71 packet -> raw -> chaddr),
72 packet -> raw -> giaddr.s_addr
73 ? inet_ntoa (packet -> raw -> giaddr)
74 : packet -> interface -> name);
75
76 if (!locate_network (packet)) {
77 log_info ("%s: network unknown", msgbuf);
78 return;
79 }
80
81 find_lease (&lease, packet, packet -> shared_network,
82 0, 0, (struct lease *)0, MDL);
83
84 if (lease && lease->host)
85 host_reference(&hp, lease->host, MDL);
86
87 if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
88 struct host_decl *h;
89
90 /* We didn't find an applicable fixed-address host
91 declaration. Just in case we may be able to dynamically
92 assign an address, see if there's a host declaration
93 that doesn't have an ip address associated with it. */
94
95 if (!hp)
96 find_hosts_by_haddr(&hp, packet->raw->htype,
97 packet->raw->chaddr,
98 packet->raw->hlen, MDL);
99
100 for (h = hp; h; h = h -> n_ipaddr) {
101 if (!h -> fixed_addr) {
102 host_reference(&host, h, MDL);
103 break;
104 }
105 }
106
107 if (hp)
108 host_dereference(&hp, MDL);
109
110 if (host) {
111 host_reference(&hp, host, MDL);
112 host_dereference(&host, MDL);
113 }
114
115 /* Allocate a lease if we have not yet found one. */
116 if (!lease)
117 allocate_lease (&lease, packet,
118 packet -> shared_network -> pools,
119 &peer_has_leases);
120
121 if (lease == NULL) {
122 log_info("%s: BOOTP from dynamic client and no "
123 "dynamic leases", msgbuf);
124 goto out;
125 }
126
127 #if defined(FAILOVER_PROTOCOL)
128 if ((lease->pool != NULL) &&
129 (lease->pool->failover_peer != NULL)) {
130 dhcp_failover_state_t *peer;
131
132 peer = lease->pool->failover_peer;
133
134 /* If we are in a failover state that bars us from
135 * answering, do not do so.
136 * If we are in a cooperative state, load balance
137 * (all) responses.
138 */
139 if ((peer->service_state == not_responding) ||
140 (peer->service_state == service_startup)) {
141 log_info("%s: not responding%s",
142 msgbuf, peer->nrr);
143 goto out;
144 } else if((peer->service_state == cooperating) &&
145 !load_balance_mine(packet, peer)) {
146 log_info("%s: load balance to peer %s",
147 msgbuf, peer->name);
148 goto out;
149 }
150 }
151 #endif
152
153 ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
154 goto out;
155 }
156
157 /* Run the executable statements to compute the client and server
158 options. */
159 option_state_allocate (&options, MDL);
160
161 /* Execute the subnet statements. */
162 execute_statements_in_scope ((struct binding_value **)0,
163 packet, lease, (struct client_state *)0,
164 packet -> options, options,
165 &lease -> scope, lease -> subnet -> group,
166 (struct group *)0);
167
168 /* Execute statements from class scopes. */
169 for (i = packet -> class_count; i > 0; i--) {
170 execute_statements_in_scope
171 ((struct binding_value **)0,
172 packet, lease, (struct client_state *)0,
173 packet -> options, options,
174 &lease -> scope, packet -> classes [i - 1] -> group,
175 lease -> subnet -> group);
176 }
177
178 /* Execute the host statements. */
179 execute_statements_in_scope ((struct binding_value **)0,
180 packet, lease, (struct client_state *)0,
181 packet -> options, options,
182 &lease -> scope,
183 hp -> group, lease -> subnet -> group);
184
185 /* Drop the request if it's not allowed for this client. */
186 if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
187 !evaluate_boolean_option_cache (&ignorep, packet, lease,
188 (struct client_state *)0,
189 packet -> options, options,
190 &lease -> scope, oc, MDL)) {
191 if (!ignorep)
192 log_info ("%s: bootp disallowed", msgbuf);
193 goto out;
194 }
195
196 if ((oc = lookup_option (&server_universe,
197 options, SV_ALLOW_BOOTING)) &&
198 !evaluate_boolean_option_cache (&ignorep, packet, lease,
199 (struct client_state *)0,
200 packet -> options, options,
201 &lease -> scope, oc, MDL)) {
202 if (!ignorep)
203 log_info ("%s: booting disallowed", msgbuf);
204 goto out;
205 }
206
207 /* Set up the outgoing packet... */
208 memset (&outgoing, 0, sizeof outgoing);
209 memset (&raw, 0, sizeof raw);
210 outgoing.raw = &raw;
211
212 /* If we didn't get a known vendor magic number on the way in,
213 just copy the input options to the output. */
214 if (!packet -> options_valid &&
215 !(evaluate_boolean_option_cache
216 (&ignorep, packet, lease, (struct client_state *)0,
217 packet -> options, options, &lease -> scope,
218 lookup_option (&server_universe, options,
219 SV_ALWAYS_REPLY_RFC1048), MDL))) {
220 memcpy (outgoing.raw -> options,
221 packet -> raw -> options, DHCP_MAX_OPTION_LEN);
222 outgoing.packet_length = BOOTP_MIN_LEN;
223 } else {
224
225 /* Use the subnet mask from the subnet declaration if no other
226 mask has been provided. */
227
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 /* Pack the options into the buffer. Unlike DHCP, we
248 can't pack options into the filename and server
249 name buffers. */
250
251 outgoing.packet_length =
252 cons_options (packet, outgoing.raw, lease,
253 (struct client_state *)0, 0,
254 packet -> options, options,
255 &lease -> scope,
256 0, 0, 1, (struct data_string *)0,
257 (const char *)0);
258 if (outgoing.packet_length < BOOTP_MIN_LEN)
259 outgoing.packet_length = BOOTP_MIN_LEN;
260 }
261
262 /* Take the fields that we care about... */
263 raw.op = BOOTREPLY;
264 raw.htype = packet -> raw -> htype;
265 raw.hlen = packet -> raw -> hlen;
266 memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
267 raw.hops = packet -> raw -> hops;
268 raw.xid = packet -> raw -> xid;
269 raw.secs = packet -> raw -> secs;
270 raw.flags = packet -> raw -> flags;
271 raw.ciaddr = packet -> raw -> ciaddr;
272
273 /* yiaddr is an ipv4 address, it must be 4 octets. */
274 memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
275
276 /* If we're always supposed to broadcast to this client, set
277 the broadcast bit in the bootp flags field. */
278 if ((oc = lookup_option (&server_universe,
279 options, SV_ALWAYS_BROADCAST)) &&
280 evaluate_boolean_option_cache (&ignorep, packet, lease,
281 (struct client_state *)0,
282 packet -> options, options,
283 &lease -> scope, oc, MDL))
284 raw.flags |= htons (BOOTP_BROADCAST);
285
286 /* Figure out the address of the next server. */
287 memset (&d1, 0, sizeof d1);
288 oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
289 if (oc &&
290 evaluate_option_cache (&d1, packet, lease,
291 (struct client_state *)0,
292 packet -> options, options,
293 &lease -> scope, oc, MDL)) {
294 /* If there was more than one answer, take the first. */
295 if (d1.len >= 4 && d1.data)
296 memcpy (&raw.siaddr, d1.data, 4);
297 data_string_forget (&d1, MDL);
298 } else {
299 if ((lease->subnet->shared_network->interface != NULL) &&
300 lease->subnet->shared_network->interface->address_count)
301 raw.siaddr =
302 lease->subnet->shared_network->interface->addresses[0];
303 else if (packet->interface->address_count)
304 raw.siaddr = packet->interface->addresses[0];
305 }
306
307 raw.giaddr = packet -> raw -> giaddr;
308
309 /* Figure out the filename. */
310 oc = lookup_option (&server_universe, options, SV_FILENAME);
311 if (oc &&
312 evaluate_option_cache (&d1, packet, lease,
313 (struct client_state *)0,
314 packet -> options, options,
315 &lease -> scope, oc, MDL)) {
316 memcpy (raw.file, d1.data,
317 d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
318 if (sizeof raw.file > d1.len)
319 memset (&raw.file [d1.len],
320 0, (sizeof raw.file) - d1.len);
321 data_string_forget (&d1, MDL);
322 } else
323 memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
324
325 /* Choose a server name as above. */
326 oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
327 if (oc &&
328 evaluate_option_cache (&d1, packet, lease,
329 (struct client_state *)0,
330 packet -> options, options,
331 &lease -> scope, oc, MDL)) {
332 memcpy (raw.sname, d1.data,
333 d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
334 if (sizeof raw.sname > d1.len)
335 memset (&raw.sname [d1.len],
336 0, (sizeof raw.sname) - d1.len);
337 data_string_forget (&d1, MDL);
338 }
339
340 /* Execute the commit statements, if there are any. */
341 execute_statements ((struct binding_value **)0,
342 packet, lease, (struct client_state *)0,
343 packet -> options,
344 options, &lease -> scope, lease -> on_commit);
345
346 /* We're done with the option state. */
347 option_state_dereference (&options, MDL);
348
349 /* Set up the hardware destination address... */
350 hto.hbuf [0] = packet -> raw -> htype;
351 hto.hlen = packet -> raw -> hlen + 1;
352 memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
353
354 if (packet->interface->address_count)
355 from = packet->interface->addresses[0];
356
357 /* Report what we're doing... */
358 log_info ("%s", msgbuf);
359 log_info ("BOOTREPLY for %s to %s (%s) via %s",
360 piaddr (lease->ip_addr), hp -> name,
361 print_hw_addr (packet -> raw -> htype,
362 packet -> raw -> hlen,
363 packet -> raw -> chaddr),
364 packet -> raw -> giaddr.s_addr
365 ? inet_ntoa (packet -> raw -> giaddr)
366 : packet -> interface -> name);
367
368 /* Set up the parts of the address that are in common. */
369 to.sin_family = AF_INET;
370 #ifdef HAVE_SA_LEN
371 to.sin_len = sizeof to;
372 #endif
373 memset (to.sin_zero, 0, sizeof to.sin_zero);
374
375 /* If this was gatewayed, send it back to the gateway... */
376 if (raw.giaddr.s_addr) {
377 to.sin_addr = raw.giaddr;
378 to.sin_port = local_port;
379
380 if (fallback_interface) {
381 result = send_packet (fallback_interface,
382 (struct packet *)0,
383 &raw, outgoing.packet_length,
384 from, &to, &hto);
385 goto out;
386 }
387
388 /* If it comes from a client that already knows its address
389 and is not requesting a broadcast response, and we can
390 unicast to a client without using the ARP protocol, sent it
391 directly to that client. */
392 } else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
393 can_unicast_without_arp (packet -> interface)) {
394 to.sin_addr = raw.yiaddr;
395 to.sin_port = remote_port;
396
397 /* Otherwise, broadcast it on the local network. */
398 } else {
399 to.sin_addr = limited_broadcast;
400 to.sin_port = remote_port; /* XXX */
401 }
402
403 errno = 0;
404 result = send_packet (packet -> interface,
405 packet, &raw, outgoing.packet_length,
406 from, &to, &hto);
407 out:
408 if (options)
409 option_state_dereference (&options, MDL);
410 if (lease)
411 lease_dereference (&lease, MDL);
412 if (hp)
413 host_dereference (&hp, MDL);
414 if (host)
415 host_dereference (&host, MDL);
416 }