3 BOOTP Protocol support. */
6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
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.
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.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
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''.
36 static char copyright
[] =
37 "$Id: bootp.c,v 1.77 2007/05/08 23:05:21 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
43 # define send_packet trace_packet_send
47 struct packet
*packet
;
50 struct host_decl
*hp
= (struct host_decl
*)0;
51 struct host_decl
*host
= (struct host_decl
*)0;
52 struct packet outgoing
;
53 struct dhcp_packet raw
;
54 struct sockaddr_in to
;
57 struct option_state
*options
= (struct option_state
*)0;
58 struct lease
*lease
= (struct lease
*)0;
60 struct data_string d1
;
61 struct option_cache
*oc
;
64 int peer_has_leases
= 0;
66 if (packet
-> raw
-> op
!= BOOTREQUEST
)
69 /* %Audit% This is log output. %2004.06.17,Safe%
70 * If we truncate we hope the user can get a hint from the log.
72 snprintf (msgbuf
, sizeof msgbuf
, "BOOTREQUEST from %s via %s",
73 print_hw_addr (packet
-> raw
-> htype
,
74 packet
-> raw
-> hlen
,
75 packet
-> raw
-> chaddr
),
76 packet
-> raw
-> giaddr
.s_addr
77 ? inet_ntoa (packet
-> raw
-> giaddr
)
78 : packet
-> interface
-> name
);
80 if (!locate_network (packet
)) {
81 log_info ("%s: network unknown", msgbuf
);
85 find_lease (&lease
, packet
, packet
-> shared_network
,
86 0, 0, (struct lease
*)0, MDL
);
88 if (lease
&& lease
->host
)
89 host_reference(&hp
, lease
->host
, MDL
);
91 if (!lease
|| ((lease
->flags
& STATIC_LEASE
) == 0)) {
93 /* We didn't find an applicable fixed-address host
94 declaration. Just in case we may be able to dynamically
95 assign an address, see if there's a host declaration
96 that doesn't have an ip address associated with it. */
99 find_hosts_by_haddr(&hp
, packet
->raw
->htype
,
101 packet
->raw
->hlen
, MDL
);
103 for (h
= hp
; h
; h
= h
-> n_ipaddr
) {
104 if (!h
-> fixed_addr
) {
105 host_reference(&host
, h
, MDL
);
111 host_dereference(&hp
, MDL
);
114 host_reference(&hp
, host
, MDL
);
115 host_dereference(&host
, MDL
);
118 /* Allocate a lease if we have not yet found one. */
120 allocate_lease (&lease
, packet
,
121 packet
-> shared_network
-> pools
,
125 ack_lease (packet
, lease
, 0, 0, msgbuf
, 0, hp
);
127 log_info ("%s: BOOTP from dynamic client and no "
128 "dynamic leases", msgbuf
);
133 /* Run the executable statements to compute the client and server
135 option_state_allocate (&options
, MDL
);
137 /* Execute the subnet statements. */
138 execute_statements_in_scope ((struct binding_value
**)0,
139 packet
, lease
, (struct client_state
*)0,
140 packet
-> options
, options
,
141 &lease
-> scope
, lease
-> subnet
-> group
,
144 /* Execute statements from class scopes. */
145 for (i
= packet
-> class_count
; i
> 0; i
--) {
146 execute_statements_in_scope
147 ((struct binding_value
**)0,
148 packet
, lease
, (struct client_state
*)0,
149 packet
-> options
, options
,
150 &lease
-> scope
, packet
-> classes
[i
- 1] -> group
,
151 lease
-> subnet
-> group
);
154 /* Execute the host statements. */
155 execute_statements_in_scope ((struct binding_value
**)0,
156 packet
, lease
, (struct client_state
*)0,
157 packet
-> options
, options
,
159 hp
-> group
, lease
-> subnet
-> group
);
161 /* Drop the request if it's not allowed for this client. */
162 if ((oc
= lookup_option (&server_universe
, options
, SV_ALLOW_BOOTP
)) &&
163 !evaluate_boolean_option_cache (&ignorep
, packet
, lease
,
164 (struct client_state
*)0,
165 packet
-> options
, options
,
166 &lease
-> scope
, oc
, MDL
)) {
168 log_info ("%s: bootp disallowed", msgbuf
);
172 if ((oc
= lookup_option (&server_universe
,
173 options
, SV_ALLOW_BOOTING
)) &&
174 !evaluate_boolean_option_cache (&ignorep
, packet
, lease
,
175 (struct client_state
*)0,
176 packet
-> options
, options
,
177 &lease
-> scope
, oc
, MDL
)) {
179 log_info ("%s: booting disallowed", msgbuf
);
183 /* Set up the outgoing packet... */
184 memset (&outgoing
, 0, sizeof outgoing
);
185 memset (&raw
, 0, sizeof raw
);
188 /* If we didn't get a known vendor magic number on the way in,
189 just copy the input options to the output. */
190 if (!packet
-> options_valid
&&
191 !(evaluate_boolean_option_cache
192 (&ignorep
, packet
, lease
, (struct client_state
*)0,
193 packet
-> options
, options
, &lease
-> scope
,
194 lookup_option (&server_universe
, options
,
195 SV_ALWAYS_REPLY_RFC1048
), MDL
))) {
196 memcpy (outgoing
.raw
-> options
,
197 packet
-> raw
-> options
, DHCP_OPTION_LEN
);
198 outgoing
.packet_length
= BOOTP_MIN_LEN
;
201 /* Use the subnet mask from the subnet declaration if no other
202 mask has been provided. */
204 oc
= (struct option_cache
*)0;
206 if (!lookup_option (&dhcp_universe
, options
, i
)) {
207 if (option_cache_allocate (&oc
, MDL
)) {
210 lease
-> subnet
-> netmask
.iabuf
,
211 lease
-> subnet
-> netmask
.len
,
213 option_code_hash_lookup(&oc
->option
,
214 dhcp_universe
.code_hash
,
216 save_option (&dhcp_universe
,
219 option_cache_dereference (&oc
, MDL
);
223 /* Pack the options into the buffer. Unlike DHCP, we
224 can't pack options into the filename and server
227 outgoing
.packet_length
=
228 cons_options (packet
, outgoing
.raw
, lease
,
229 (struct client_state
*)0, 0,
230 packet
-> options
, options
,
232 0, 0, 1, (struct data_string
*)0,
234 if (outgoing
.packet_length
< BOOTP_MIN_LEN
)
235 outgoing
.packet_length
= BOOTP_MIN_LEN
;
238 /* Take the fields that we care about... */
240 raw
.htype
= packet
-> raw
-> htype
;
241 raw
.hlen
= packet
-> raw
-> hlen
;
242 memcpy (raw
.chaddr
, packet
-> raw
-> chaddr
, sizeof raw
.chaddr
);
243 raw
.hops
= packet
-> raw
-> hops
;
244 raw
.xid
= packet
-> raw
-> xid
;
245 raw
.secs
= packet
-> raw
-> secs
;
246 raw
.flags
= packet
-> raw
-> flags
;
247 raw
.ciaddr
= packet
-> raw
-> ciaddr
;
249 /* yiaddr is an ipv4 address, it must be 4 octets. */
250 memcpy (&raw
.yiaddr
, lease
->ip_addr
.iabuf
, 4);
252 /* If we're always supposed to broadcast to this client, set
253 the broadcast bit in the bootp flags field. */
254 if ((oc
= lookup_option (&server_universe
,
255 options
, SV_ALWAYS_BROADCAST
)) &&
256 evaluate_boolean_option_cache (&ignorep
, packet
, lease
,
257 (struct client_state
*)0,
258 packet
-> options
, options
,
259 &lease
-> scope
, oc
, MDL
))
260 raw
.flags
|= htons (BOOTP_BROADCAST
);
262 /* Figure out the address of the next server. */
263 memset (&d1
, 0, sizeof d1
);
264 oc
= lookup_option (&server_universe
, options
, SV_NEXT_SERVER
);
266 evaluate_option_cache (&d1
, packet
, lease
,
267 (struct client_state
*)0,
268 packet
-> options
, options
,
269 &lease
-> scope
, oc
, MDL
)) {
270 /* If there was more than one answer, take the first. */
271 if (d1
.len
>= 4 && d1
.data
)
272 memcpy (&raw
.siaddr
, d1
.data
, 4);
273 data_string_forget (&d1
, MDL
);
275 if ((lease
->subnet
->shared_network
->interface
!= NULL
) &&
276 lease
->subnet
->shared_network
->interface
->address_count
)
278 lease
->subnet
->shared_network
->interface
->addresses
[0];
279 else if (packet
->interface
->address_count
)
280 raw
.siaddr
= packet
->interface
->addresses
[0];
283 raw
.giaddr
= packet
-> raw
-> giaddr
;
285 /* Figure out the filename. */
286 oc
= lookup_option (&server_universe
, options
, SV_FILENAME
);
288 evaluate_option_cache (&d1
, packet
, lease
,
289 (struct client_state
*)0,
290 packet
-> options
, options
,
291 &lease
-> scope
, oc
, MDL
)) {
292 memcpy (raw
.file
, d1
.data
,
293 d1
.len
> sizeof raw
.file
? sizeof raw
.file
: d1
.len
);
294 if (sizeof raw
.file
> d1
.len
)
295 memset (&raw
.file
[d1
.len
],
296 0, (sizeof raw
.file
) - d1
.len
);
297 data_string_forget (&d1
, MDL
);
299 memcpy (raw
.file
, packet
-> raw
-> file
, sizeof raw
.file
);
301 /* Choose a server name as above. */
302 oc
= lookup_option (&server_universe
, options
, SV_SERVER_NAME
);
304 evaluate_option_cache (&d1
, packet
, lease
,
305 (struct client_state
*)0,
306 packet
-> options
, options
,
307 &lease
-> scope
, oc
, MDL
)) {
308 memcpy (raw
.sname
, d1
.data
,
309 d1
.len
> sizeof raw
.sname
? sizeof raw
.sname
: d1
.len
);
310 if (sizeof raw
.sname
> d1
.len
)
311 memset (&raw
.sname
[d1
.len
],
312 0, (sizeof raw
.sname
) - d1
.len
);
313 data_string_forget (&d1
, MDL
);
316 /* Execute the commit statements, if there are any. */
317 execute_statements ((struct binding_value
**)0,
318 packet
, lease
, (struct client_state
*)0,
320 options
, &lease
-> scope
, lease
-> on_commit
);
322 /* We're done with the option state. */
323 option_state_dereference (&options
, MDL
);
325 /* Set up the hardware destination address... */
326 hto
.hbuf
[0] = packet
-> raw
-> htype
;
327 hto
.hlen
= packet
-> raw
-> hlen
+ 1;
328 memcpy (&hto
.hbuf
[1], packet
-> raw
-> chaddr
, packet
-> raw
-> hlen
);
330 if (packet
->interface
->address_count
)
331 from
= packet
->interface
->addresses
[0];
333 /* Report what we're doing... */
334 log_info ("%s", msgbuf
);
335 log_info ("BOOTREPLY for %s to %s (%s) via %s",
336 piaddr (lease
->ip_addr
), hp
-> name
,
337 print_hw_addr (packet
-> raw
-> htype
,
338 packet
-> raw
-> hlen
,
339 packet
-> raw
-> chaddr
),
340 packet
-> raw
-> giaddr
.s_addr
341 ? inet_ntoa (packet
-> raw
-> giaddr
)
342 : packet
-> interface
-> name
);
344 /* Set up the parts of the address that are in common. */
345 to
.sin_family
= AF_INET
;
347 to
.sin_len
= sizeof to
;
349 memset (to
.sin_zero
, 0, sizeof to
.sin_zero
);
351 /* If this was gatewayed, send it back to the gateway... */
352 if (raw
.giaddr
.s_addr
) {
353 to
.sin_addr
= raw
.giaddr
;
354 to
.sin_port
= local_port
;
356 if (fallback_interface
) {
357 result
= send_packet (fallback_interface
,
359 &raw
, outgoing
.packet_length
,
364 /* If it comes from a client that already knows its address
365 and is not requesting a broadcast response, and we can
366 unicast to a client without using the ARP protocol, sent it
367 directly to that client. */
368 } else if (!(raw
.flags
& htons (BOOTP_BROADCAST
)) &&
369 can_unicast_without_arp (packet
-> interface
)) {
370 to
.sin_addr
= raw
.yiaddr
;
371 to
.sin_port
= remote_port
;
373 /* Otherwise, broadcast it on the local network. */
375 to
.sin_addr
= limited_broadcast
;
376 to
.sin_port
= remote_port
; /* XXX */
380 result
= send_packet (packet
-> interface
,
381 packet
, &raw
, outgoing
.packet_length
,
385 option_state_dereference (&options
, MDL
);
387 lease_dereference (&lease
, MDL
);
389 host_dereference (&hp
, MDL
);
391 host_dereference (&host
, MDL
);