3
BOOTP Protocol support. */
6
* Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium.
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of The Internet Software Consortium nor the names
19
* of its contributors may be used to endorse or promote products derived
20
* from this software without specific prior written permission.
22
* THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
* DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
* This software has been written for the Internet Software Consortium
37
* by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38
* Enterprises. To learn more about the Internet Software Consortium,
39
* see ``http://www.vix.com/isc''. To learn more about Vixie
40
* Enterprises, see ``http://www.vix.com''.
44
static char copyright[] =
45
"$Id: bootp.c,v 1.28.2.9 1999/10/19 17:32:49 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
51
struct packet *packet;
55
struct host_decl *host = (struct host_decl *)0;
56
struct packet outgoing;
57
struct dhcp_packet raw;
58
struct sockaddr_in to;
61
struct tree_cache *options [256];
62
struct subnet *subnet;
64
struct iaddr ip_address;
67
if (packet -> raw -> op != BOOTREQUEST)
70
note ("BOOTREQUEST from %s via %s%s",
71
print_hw_addr (packet -> raw -> htype,
72
packet -> raw -> hlen,
73
packet -> raw -> chaddr),
74
packet -> raw -> giaddr.s_addr
75
? inet_ntoa (packet -> raw -> giaddr)
76
: packet -> interface -> name,
77
packet -> options_valid ? "" : " (non-rfc1048)");
81
if (!locate_network (packet))
84
hp = find_hosts_by_haddr (packet -> raw -> htype,
85
packet -> raw -> chaddr,
86
packet -> raw -> hlen);
88
lease = find_lease (packet, packet -> shared_network, 0);
90
/* Find an IP address in the host_decl that matches the
93
subnet = find_host_for_network (&hp, &ip_address,
94
packet -> shared_network);
96
subnet = (struct subnet *)0;
99
/* We didn't find an applicable host declaration.
100
Just in case we may be able to dynamically assign
101
an address, see if there's a host declaration
102
that doesn't have an ip address associated with it. */
104
for (; hp; hp = hp -> n_ipaddr) {
105
if (!hp -> fixed_addr) {
112
if (host && (!host -> group -> allow_booting)) {
113
note ("Ignoring excluded BOOTP client %s",
116
: print_hw_addr (packet -> raw -> htype,
117
packet -> raw -> hlen,
118
packet -> raw -> chaddr));
122
if (host && (!host -> group -> allow_bootp)) {
123
note ("Ignoring BOOTP request from client %s",
126
: print_hw_addr (packet -> raw -> htype,
127
packet -> raw -> hlen,
128
packet -> raw -> chaddr));
132
/* If we've been told not to boot unknown clients,
133
and we didn't find any host record for this client,
135
if (!host && !(packet -> shared_network ->
136
group -> boot_unknown_clients)) {
137
note ("Ignoring unknown BOOTP client %s via %s",
138
print_hw_addr (packet -> raw -> htype,
139
packet -> raw -> hlen,
140
packet -> raw -> chaddr),
141
packet -> raw -> giaddr.s_addr
142
? inet_ntoa (packet -> raw -> giaddr)
143
: packet -> interface -> name);
147
/* If we've been told not to boot with bootp on this
148
network, ignore it. */
150
!(packet -> shared_network -> group -> allow_bootp)) {
151
note ("Ignoring BOOTP request from client %s via %s",
152
print_hw_addr (packet -> raw -> htype,
153
packet -> raw -> hlen,
154
packet -> raw -> chaddr),
155
packet -> raw -> giaddr.s_addr
156
? inet_ntoa (packet -> raw -> giaddr)
157
: packet -> interface -> name);
161
/* If the packet is from a host we don't know and there
162
are no dynamic bootp addresses on the network it came
163
in on, drop it on the floor. */
164
if (!(packet -> shared_network -> group -> dynamic_bootp)) {
166
note ("No applicable record for BOOTP host %s via %s",
167
print_hw_addr (packet -> raw -> htype,
168
packet -> raw -> hlen,
169
packet -> raw -> chaddr),
170
packet -> raw -> giaddr.s_addr
171
? inet_ntoa (packet -> raw -> giaddr)
172
: packet -> interface -> name);
176
/* If a lease has already been assigned to this client
177
and it's still okay to use dynamic bootp on
178
that lease, reassign it. */
180
/* If this lease can be used for dynamic bootp,
182
if ((lease -> flags & DYNAMIC_BOOTP_OK)) {
184
/* If it's not a DYNAMIC_BOOTP lease,
185
release it before reassigning it
186
so that we don't get a lease
188
if (!(lease -> flags & BOOTP_LEASE))
189
release_lease (lease);
191
lease -> host = host;
192
ack_lease (packet, lease, 0, 0);
196
/* If dynamic BOOTP is no longer allowed for
197
this lease, set it free. */
198
release_lease (lease);
201
/* If there are dynamic bootp addresses that might be
202
available, try to snag one. */
203
for (lease = packet -> shared_network -> last_lease;
204
lease && lease -> ends <= cur_time;
205
lease = lease -> prev) {
206
if ((lease -> flags & DYNAMIC_BOOTP_OK)) {
207
lease -> host = host;
208
ack_lease (packet, lease, 0, 0);
215
/* Make sure we're allowed to boot this client. */
216
if (hp && (!hp -> group -> allow_booting)) {
217
note ("Ignoring excluded BOOTP client %s",
222
/* Make sure we're allowed to boot this client with bootp. */
223
if (hp && (!hp -> group -> allow_bootp)) {
224
note ("Ignoring BOOTP request from client %s",
229
/* Set up the outgoing packet... */
230
memset (&outgoing, 0, sizeof outgoing);
231
memset (&raw, 0, sizeof raw);
234
/* If we didn't get a known vendor magic number on the way in,
235
just copy the input options to the output. */
236
if (!packet -> options_valid &&
237
!subnet -> group -> always_reply_rfc1048 &&
238
(!hp || !hp -> group -> always_reply_rfc1048)) {
239
memcpy (outgoing.raw -> options,
240
packet -> raw -> options, DHCP_OPTION_LEN);
241
outgoing.packet_length = BOOTP_MIN_LEN;
243
struct tree_cache netmask_tree; /* -- RBF */
245
/* Come up with a list of options that we want to send
246
to this client. Start with the per-subnet options,
247
and then override those with client-specific
250
memcpy (options, subnet -> group -> options, sizeof options);
252
for (i = 0; i < 256; i++) {
253
if (hp -> group -> options [i])
254
options [i] = hp -> group -> options [i];
257
/* Use the subnet mask from the subnet declaration if no other
258
mask has been provided. */
259
if (!options [DHO_SUBNET_MASK]) {
260
options [DHO_SUBNET_MASK] = &netmask_tree;
261
netmask_tree.flags = TC_TEMPORARY;
262
netmask_tree.value = lease -> subnet -> netmask.iabuf;
263
netmask_tree.len = lease -> subnet -> netmask.len;
264
netmask_tree.buf_size = lease -> subnet -> netmask.len;
265
netmask_tree.timeout = 0xFFFFFFFF;
266
netmask_tree.tree = (struct tree *)0;
269
/* Pack the options into the buffer. Unlike DHCP, we
270
can't pack options into the filename and server
273
outgoing.packet_length =
274
cons_options (packet, outgoing.raw,
275
0, options, 0, 0, 1, (u_int8_t *)0, 0);
276
if (outgoing.packet_length < BOOTP_MIN_LEN)
277
outgoing.packet_length = BOOTP_MIN_LEN;
280
/* Take the fields that we care about... */
282
raw.htype = packet -> raw -> htype;
283
raw.hlen = packet -> raw -> hlen;
284
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
285
raw.hops = packet -> raw -> hops;
286
raw.xid = packet -> raw -> xid;
287
raw.secs = packet -> raw -> secs;
288
raw.flags = packet -> raw -> flags;
289
raw.ciaddr = packet -> raw -> ciaddr;
290
memcpy (&raw.yiaddr, ip_address.iabuf, sizeof raw.yiaddr);
292
/* Figure out the address of the next server. */
293
if (hp && hp -> group -> next_server.len)
294
memcpy (&raw.siaddr, hp -> group -> next_server.iabuf, 4);
295
else if (subnet -> group -> next_server.len)
296
memcpy (&raw.siaddr, subnet -> group -> next_server.iabuf, 4);
297
else if (subnet -> interface_address.len)
298
memcpy (&raw.siaddr, subnet -> interface_address.iabuf, 4);
300
raw.siaddr = packet -> interface -> primary_address;
302
raw.giaddr = packet -> raw -> giaddr;
303
if (hp -> group -> server_name)
304
strncpy (raw.sname, hp -> group -> server_name,
306
else if (subnet -> group -> server_name)
307
strncpy (raw.sname, subnet -> group -> server_name,
310
if (hp -> group -> filename)
311
strncpy (raw.file, hp -> group -> filename,
313
else if (subnet -> group -> filename)
314
strncpy (raw.file, subnet -> group -> filename,
317
memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
319
/* Set up the hardware destination address... */
320
hto.htype = packet -> raw -> htype;
321
hto.hlen = packet -> raw -> hlen;
322
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
324
from = packet -> interface -> primary_address;
326
/* Report what we're doing... */
327
note ("BOOTREPLY for %s to %s (%s) via %s",
328
piaddr (ip_address), hp -> name,
329
print_hw_addr (packet -> raw -> htype,
330
packet -> raw -> hlen,
331
packet -> raw -> chaddr),
332
packet -> raw -> giaddr.s_addr
333
? inet_ntoa (packet -> raw -> giaddr)
334
: packet -> interface -> name);
336
/* Set up the parts of the address that are in common. */
337
to.sin_family = AF_INET;
339
to.sin_len = sizeof to;
341
memset (to.sin_zero, 0, sizeof to.sin_zero);
343
/* If this was gatewayed, send it back to the gateway... */
344
if (raw.giaddr.s_addr) {
345
to.sin_addr = raw.giaddr;
346
to.sin_port = local_port;
348
if (fallback_interface) {
349
result = send_packet (fallback_interface,
351
&raw, outgoing.packet_length,
356
/* If it comes from a client that already knows its address
357
and is not requesting a broadcast response, and we can
358
unicast to a client without using the ARP protocol, sent it
359
directly to that client. */
360
} else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
361
can_unicast_without_arp ()) {
362
to.sin_addr = raw.yiaddr;
363
to.sin_port = remote_port;
365
/* Otherwise, broadcast it on the local network. */
367
to.sin_addr.s_addr = INADDR_BROADCAST;
368
to.sin_port = remote_port; /* XXX */
372
result = send_packet (packet -> interface,
373
packet, &raw, outgoing.packet_length,