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$ Copyright (c) 2004 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
,
214 dhcp_universe
.options
[i
];
215 save_option (&dhcp_universe
,
218 option_cache_dereference (&oc
, MDL
);
222 /* Pack the options into the buffer. Unlike DHCP, we
223 can't pack options into the filename and server
226 outgoing
.packet_length
=
227 cons_options (packet
, outgoing
.raw
, lease
,
228 (struct client_state
*)0, 0,
229 packet
-> options
, options
,
231 0, 0, 1, (struct data_string
*)0,
233 if (outgoing
.packet_length
< BOOTP_MIN_LEN
)
234 outgoing
.packet_length
= BOOTP_MIN_LEN
;
237 /* Take the fields that we care about... */
239 raw
.htype
= packet
-> raw
-> htype
;
240 raw
.hlen
= packet
-> raw
-> hlen
;
241 memcpy (raw
.chaddr
, packet
-> raw
-> chaddr
, sizeof raw
.chaddr
);
242 raw
.hops
= packet
-> raw
-> hops
;
243 raw
.xid
= packet
-> raw
-> xid
;
244 raw
.secs
= packet
-> raw
-> secs
;
245 raw
.flags
= packet
-> raw
-> flags
;
246 raw
.ciaddr
= packet
-> raw
-> ciaddr
;
248 /* yiaddr is an ipv4 address, it must be 4 octets. */
249 memcpy (&raw
.yiaddr
, lease
->ip_addr
.iabuf
, 4);
251 /* If we're always supposed to broadcast to this client, set
252 the broadcast bit in the bootp flags field. */
253 if ((oc
= lookup_option (&server_universe
,
254 options
, SV_ALWAYS_BROADCAST
)) &&
255 evaluate_boolean_option_cache (&ignorep
, packet
, lease
,
256 (struct client_state
*)0,
257 packet
-> options
, options
,
258 &lease
-> scope
, oc
, MDL
))
259 raw
.flags
|= htons (BOOTP_BROADCAST
);
261 /* Figure out the address of the next server. */
262 memset (&d1
, 0, sizeof d1
);
263 oc
= lookup_option (&server_universe
, options
, SV_NEXT_SERVER
);
265 evaluate_option_cache (&d1
, packet
, lease
,
266 (struct client_state
*)0,
267 packet
-> options
, options
,
268 &lease
-> scope
, oc
, MDL
)) {
269 /* If there was more than one answer, take the first. */
270 if (d1
.len
>= 4 && d1
.data
)
271 memcpy (&raw
.siaddr
, d1
.data
, 4);
272 data_string_forget (&d1
, MDL
);
274 if (lease
-> subnet
-> shared_network
-> interface
)
275 raw
.siaddr
= (lease
-> subnet
-> shared_network
->
276 interface
-> primary_address
);
278 raw
.siaddr
= packet
-> interface
-> primary_address
;
281 raw
.giaddr
= packet
-> raw
-> giaddr
;
283 /* Figure out the filename. */
284 oc
= lookup_option (&server_universe
, options
, SV_FILENAME
);
286 evaluate_option_cache (&d1
, packet
, lease
,
287 (struct client_state
*)0,
288 packet
-> options
, options
,
289 &lease
-> scope
, oc
, MDL
)) {
290 memcpy (raw
.file
, d1
.data
,
291 d1
.len
> sizeof raw
.file
? sizeof raw
.file
: d1
.len
);
292 if (sizeof raw
.file
> d1
.len
)
293 memset (&raw
.file
[d1
.len
],
294 0, (sizeof raw
.file
) - d1
.len
);
295 data_string_forget (&d1
, MDL
);
297 memcpy (raw
.file
, packet
-> raw
-> file
, sizeof raw
.file
);
299 /* Choose a server name as above. */
300 oc
= lookup_option (&server_universe
, options
, SV_SERVER_NAME
);
302 evaluate_option_cache (&d1
, packet
, lease
,
303 (struct client_state
*)0,
304 packet
-> options
, options
,
305 &lease
-> scope
, oc
, MDL
)) {
306 memcpy (raw
.sname
, d1
.data
,
307 d1
.len
> sizeof raw
.sname
? sizeof raw
.sname
: d1
.len
);
308 if (sizeof raw
.sname
> d1
.len
)
309 memset (&raw
.sname
[d1
.len
],
310 0, (sizeof raw
.sname
) - d1
.len
);
311 data_string_forget (&d1
, MDL
);
314 /* Execute the commit statements, if there are any. */
315 execute_statements ((struct binding_value
**)0,
316 packet
, lease
, (struct client_state
*)0,
318 options
, &lease
-> scope
, lease
-> on_commit
);
320 /* We're done with the option state. */
321 option_state_dereference (&options
, MDL
);
323 /* Set up the hardware destination address... */
324 hto
.hbuf
[0] = packet
-> raw
-> htype
;
325 hto
.hlen
= packet
-> raw
-> hlen
+ 1;
326 memcpy (&hto
.hbuf
[1], packet
-> raw
-> chaddr
, packet
-> raw
-> hlen
);
328 from
= packet
-> interface
-> primary_address
;
330 /* Report what we're doing... */
331 log_info ("%s", msgbuf
);
332 log_info ("BOOTREPLY for %s to %s (%s) via %s",
333 piaddr (lease
->ip_addr
), hp
-> name
,
334 print_hw_addr (packet
-> raw
-> htype
,
335 packet
-> raw
-> hlen
,
336 packet
-> raw
-> chaddr
),
337 packet
-> raw
-> giaddr
.s_addr
338 ? inet_ntoa (packet
-> raw
-> giaddr
)
339 : packet
-> interface
-> name
);
341 /* Set up the parts of the address that are in common. */
342 to
.sin_family
= AF_INET
;
344 to
.sin_len
= sizeof to
;
346 memset (to
.sin_zero
, 0, sizeof to
.sin_zero
);
348 /* If this was gatewayed, send it back to the gateway... */
349 if (raw
.giaddr
.s_addr
) {
350 to
.sin_addr
= raw
.giaddr
;
351 to
.sin_port
= local_port
;
353 if (fallback_interface
) {
354 result
= send_packet (fallback_interface
,
356 &raw
, outgoing
.packet_length
,
361 /* If it comes from a client that already knows its address
362 and is not requesting a broadcast response, and we can
363 unicast to a client without using the ARP protocol, sent it
364 directly to that client. */
365 } else if (!(raw
.flags
& htons (BOOTP_BROADCAST
)) &&
366 can_unicast_without_arp (packet
-> interface
)) {
367 to
.sin_addr
= raw
.yiaddr
;
368 to
.sin_port
= remote_port
;
370 /* Otherwise, broadcast it on the local network. */
372 to
.sin_addr
= limited_broadcast
;
373 to
.sin_port
= remote_port
; /* XXX */
377 result
= send_packet (packet
-> interface
,
378 packet
, &raw
, outgoing
.packet_length
,
382 option_state_dereference (&options
, MDL
);
384 lease_dereference (&lease
, MDL
);
386 host_dereference (&hp
, MDL
);
388 host_dereference (&host
, MDL
);