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