1995-11-29 07:40:04 +00:00
|
|
|
/* bootp.c
|
|
|
|
|
|
|
|
BOOTP Protocol support. */
|
|
|
|
|
|
|
|
/*
|
1998-06-25 03:41:03 +00:00
|
|
|
* Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
|
1996-02-07 22:43:54 +00:00
|
|
|
* All rights reserved.
|
1995-11-29 07:40:04 +00:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of The Internet Software Consortium nor the names
|
|
|
|
* of its contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
|
|
|
|
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* This software has been written for the Internet Software Consortium
|
|
|
|
* by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
|
|
|
|
* Enterprises. To learn more about the Internet Software Consortium,
|
|
|
|
* see ``http://www.vix.com/isc''. To learn more about Vixie
|
|
|
|
* Enterprises, see ``http://www.vix.com''.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
static char copyright[] =
|
1998-11-09 02:47:29 +00:00
|
|
|
"$Id: bootp.c,v 1.34 1998/11/09 02:45:59 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
|
1995-11-29 07:40:04 +00:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
#include "dhcpd.h"
|
|
|
|
|
|
|
|
void bootp (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
|
|
|
int result;
|
1996-05-22 09:29:56 +00:00
|
|
|
struct host_decl *hp;
|
1996-05-22 07:14:13 +00:00
|
|
|
struct host_decl *host = (struct host_decl *)0;
|
1996-03-06 10:38:04 +00:00
|
|
|
struct packet outgoing;
|
|
|
|
struct dhcp_packet raw;
|
1995-11-29 07:40:04 +00:00
|
|
|
struct sockaddr_in to;
|
1996-08-27 09:33:41 +00:00
|
|
|
struct in_addr from;
|
1996-05-12 23:55:27 +00:00
|
|
|
struct hardware hto;
|
1998-06-25 03:41:03 +00:00
|
|
|
struct option_state options;
|
1996-05-22 07:14:13 +00:00
|
|
|
struct subnet *subnet;
|
|
|
|
struct lease *lease;
|
|
|
|
struct iaddr ip_address;
|
1996-03-06 10:38:04 +00:00
|
|
|
int i;
|
1998-06-25 03:41:03 +00:00
|
|
|
struct data_string d1;
|
1998-11-05 18:54:55 +00:00
|
|
|
struct option_cache *oc;
|
1995-11-29 07:40:04 +00:00
|
|
|
|
1997-05-09 08:20:12 +00:00
|
|
|
if (packet -> raw -> op != BOOTREQUEST)
|
|
|
|
return;
|
|
|
|
|
1996-06-01 00:02:36 +00:00
|
|
|
note ("BOOTREQUEST from %s via %s",
|
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr),
|
|
|
|
packet -> raw -> giaddr.s_addr
|
|
|
|
? inet_ntoa (packet -> raw -> giaddr)
|
|
|
|
: packet -> interface -> name);
|
|
|
|
|
|
|
|
|
1996-05-22 07:14:13 +00:00
|
|
|
|
1996-08-27 09:33:41 +00:00
|
|
|
if (!locate_network (packet))
|
|
|
|
return;
|
1996-05-22 09:29:56 +00:00
|
|
|
|
|
|
|
hp = find_hosts_by_haddr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> chaddr,
|
|
|
|
packet -> raw -> hlen);
|
|
|
|
|
1997-06-08 04:10:54 +00:00
|
|
|
lease = find_lease (packet, packet -> shared_network, 0);
|
1996-05-22 07:14:13 +00:00
|
|
|
|
|
|
|
/* Find an IP address in the host_decl that matches the
|
|
|
|
specified network. */
|
1996-08-27 09:33:41 +00:00
|
|
|
if (hp)
|
1996-05-22 07:14:13 +00:00
|
|
|
subnet = find_host_for_network (&hp, &ip_address,
|
|
|
|
packet -> shared_network);
|
|
|
|
else
|
|
|
|
subnet = (struct subnet *)0;
|
|
|
|
|
|
|
|
if (!subnet) {
|
|
|
|
/* We didn't find an applicable host declaration.
|
|
|
|
Just in case we may be able to dynamically assign
|
|
|
|
an address, see if there's a host declaration
|
|
|
|
that doesn't have an ip address associated with it. */
|
|
|
|
if (hp) {
|
|
|
|
for (; hp; hp = hp -> n_ipaddr) {
|
|
|
|
if (!hp -> fixed_addr) {
|
|
|
|
host = hp;
|
1996-12-31 02:00:33 +00:00
|
|
|
break;
|
1996-05-22 07:14:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-11-09 02:47:29 +00:00
|
|
|
/* If a lease has already been assigned to this client,
|
|
|
|
use it. */
|
1996-05-22 07:14:13 +00:00
|
|
|
if (lease) {
|
1998-11-09 02:47:29 +00:00
|
|
|
ack_lease (packet, lease, 0, 0);
|
|
|
|
return;
|
1996-05-22 07:14:13 +00:00
|
|
|
}
|
|
|
|
|
1998-11-09 02:47:29 +00:00
|
|
|
/* Otherwise, try to allocate one. */
|
|
|
|
lease = allocate_lease (packet,
|
|
|
|
packet -> shared_network -> pools, 0);
|
|
|
|
if (lease) {
|
|
|
|
lease -> host = host;
|
|
|
|
ack_lease (packet, lease, 0, 0);
|
|
|
|
return;
|
1996-05-22 07:14:13 +00:00
|
|
|
}
|
1998-11-09 02:47:29 +00:00
|
|
|
note ("No available leases for BOOTP client %s",
|
1998-06-25 03:41:03 +00:00
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr));
|
1998-11-09 02:47:29 +00:00
|
|
|
return;
|
1995-11-29 07:40:04 +00:00
|
|
|
}
|
1996-03-06 10:38:04 +00:00
|
|
|
|
1998-06-25 03:41:03 +00:00
|
|
|
/* Run the executable statements to compute the client and server
|
|
|
|
options. */
|
|
|
|
|
|
|
|
memset (&options, 0, sizeof options);
|
|
|
|
|
|
|
|
/* Execute the subnet statements. */
|
|
|
|
execute_statements_in_scope (packet, &options,
|
|
|
|
lease -> subnet -> group,
|
|
|
|
(struct group *)0);
|
|
|
|
|
|
|
|
/* Execute the host statements. */
|
|
|
|
execute_statements_in_scope (packet, &options, hp -> group,
|
|
|
|
lease -> subnet -> group);
|
|
|
|
|
|
|
|
/* Drop the request if it's not allowed for this client. */
|
1998-11-05 18:54:55 +00:00
|
|
|
if (evaluate_boolean_option_cache (packet, &options,
|
|
|
|
lookup_option (options.dhcp_hash,
|
|
|
|
SV_ALLOW_BOOTP))) {
|
|
|
|
note ("Ignoring BOOTP client %s",
|
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr));
|
|
|
|
return;
|
1998-06-25 03:41:03 +00:00
|
|
|
}
|
|
|
|
|
1998-11-05 18:54:55 +00:00
|
|
|
if (evaluate_boolean_option_cache (packet, &options,
|
|
|
|
lookup_option (options.dhcp_hash,
|
|
|
|
SV_ALLOW_BOOTP))) {
|
|
|
|
note ("Declining to boot client %s",
|
|
|
|
lease -> host -> name
|
|
|
|
? lease -> host -> name
|
|
|
|
: print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr));
|
|
|
|
return;
|
1997-02-22 08:36:36 +00:00
|
|
|
}
|
1998-06-25 03:41:03 +00:00
|
|
|
|
1996-03-06 10:38:04 +00:00
|
|
|
/* Set up the outgoing packet... */
|
|
|
|
memset (&outgoing, 0, sizeof outgoing);
|
|
|
|
memset (&raw, 0, sizeof raw);
|
|
|
|
outgoing.raw = &raw;
|
|
|
|
|
1998-02-06 01:05:39 +00:00
|
|
|
/* If we didn't get a known vendor magic number on the way in,
|
|
|
|
just copy the input options to the output. */
|
|
|
|
if (!packet -> options_valid) {
|
|
|
|
memcpy (outgoing.raw -> options,
|
|
|
|
packet -> raw -> options, DHCP_OPTION_LEN);
|
|
|
|
outgoing.packet_length = BOOTP_MIN_LEN;
|
|
|
|
} else {
|
|
|
|
/* Pack the options into the buffer. Unlike DHCP, we
|
|
|
|
can't pack options into the filename and server
|
|
|
|
name buffers. */
|
1996-03-06 10:38:04 +00:00
|
|
|
|
1998-02-06 01:05:39 +00:00
|
|
|
outgoing.packet_length =
|
1998-11-06 00:15:51 +00:00
|
|
|
cons_options (packet, outgoing.raw, 0,
|
|
|
|
&options, (struct agent_options *)0,
|
|
|
|
0, 0, 1);
|
1998-02-06 01:05:39 +00:00
|
|
|
if (outgoing.packet_length < BOOTP_MIN_LEN)
|
|
|
|
outgoing.packet_length = BOOTP_MIN_LEN;
|
|
|
|
}
|
1996-03-06 10:38:04 +00:00
|
|
|
|
1995-11-29 07:40:04 +00:00
|
|
|
/* Take the fields that we care about... */
|
1996-03-06 10:38:04 +00:00
|
|
|
raw.op = BOOTREPLY;
|
|
|
|
raw.htype = packet -> raw -> htype;
|
|
|
|
raw.hlen = packet -> raw -> hlen;
|
1998-02-06 01:05:39 +00:00
|
|
|
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
1996-03-06 10:38:04 +00:00
|
|
|
raw.hops = packet -> raw -> hops;
|
|
|
|
raw.xid = packet -> raw -> xid;
|
|
|
|
raw.secs = packet -> raw -> secs;
|
|
|
|
raw.flags = 0;
|
|
|
|
raw.ciaddr = packet -> raw -> ciaddr;
|
1996-05-22 07:14:13 +00:00
|
|
|
memcpy (&raw.yiaddr, ip_address.iabuf, sizeof raw.yiaddr);
|
|
|
|
|
1996-08-27 09:33:41 +00:00
|
|
|
/* Figure out the address of the next server. */
|
1998-06-25 03:41:03 +00:00
|
|
|
raw.siaddr = lease -> shared_network -> interface -> primary_address;
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = lookup_option (options.dhcp_hash, SV_NEXT_SERVER);
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache (&d1, packet, &options, oc)) {
|
1998-06-25 03:41:03 +00:00
|
|
|
/* If there was more than one answer, take the first. */
|
|
|
|
if (d1.len >= 4 && d1.data)
|
|
|
|
memcpy (&raw.siaddr, d1.data, 4);
|
1998-11-05 18:54:55 +00:00
|
|
|
data_string_forget (&d1, "bootrequest");
|
1998-06-25 03:41:03 +00:00
|
|
|
}
|
1996-05-22 07:14:13 +00:00
|
|
|
|
1996-03-06 10:38:04 +00:00
|
|
|
raw.giaddr = packet -> raw -> giaddr;
|
1998-06-25 03:41:03 +00:00
|
|
|
|
|
|
|
/* Figure out the filename. */
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = lookup_option (options.dhcp_hash, SV_FILENAME);
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache (&d1, packet, &options, oc)) {
|
1998-06-25 03:41:03 +00:00
|
|
|
memcpy (raw.file, d1.data,
|
|
|
|
d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
|
|
|
|
if (sizeof raw.file > d1.len)
|
|
|
|
memset (&raw.file [d1.len],
|
|
|
|
0, (sizeof raw.file) - d1.len);
|
1998-11-05 18:54:55 +00:00
|
|
|
data_string_forget (&d1, "bootrequest");
|
1995-11-29 07:40:04 +00:00
|
|
|
}
|
1998-06-25 03:41:03 +00:00
|
|
|
|
|
|
|
/* Choose a server name as above. */
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = lookup_option (options.dhcp_hash, SV_SERVER_NAME);
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache (&d1, packet, &options, oc)) {
|
1998-06-25 03:41:03 +00:00
|
|
|
memcpy (raw.sname, d1.data,
|
|
|
|
d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
|
|
|
|
if (sizeof raw.sname > d1.len)
|
|
|
|
memset (&raw.sname [d1.len],
|
|
|
|
0, (sizeof raw.sname) - d1.len);
|
1998-11-05 18:54:55 +00:00
|
|
|
data_string_forget (&d1, "bootrequest");
|
1995-11-29 07:40:04 +00:00
|
|
|
}
|
|
|
|
|
1996-05-22 07:14:13 +00:00
|
|
|
/* Set up the hardware destination address... */
|
|
|
|
hto.htype = packet -> raw -> htype;
|
|
|
|
hto.hlen = packet -> raw -> hlen;
|
|
|
|
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
|
|
|
|
1997-02-22 08:36:36 +00:00
|
|
|
from = packet -> interface -> primary_address;
|
1996-08-27 09:33:41 +00:00
|
|
|
|
1996-05-22 07:14:13 +00:00
|
|
|
/* Report what we're doing... */
|
1996-06-12 23:53:10 +00:00
|
|
|
note ("BOOTREPLY for %s to %s (%s) via %s",
|
|
|
|
piaddr (ip_address), hp -> name,
|
1996-05-22 07:14:13 +00:00
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
1996-06-01 00:02:36 +00:00
|
|
|
packet -> raw -> chaddr),
|
|
|
|
packet -> raw -> giaddr.s_addr
|
|
|
|
? inet_ntoa (packet -> raw -> giaddr)
|
|
|
|
: packet -> interface -> name);
|
1996-05-22 07:14:13 +00:00
|
|
|
|
|
|
|
/* Set up the parts of the address that are in common. */
|
|
|
|
to.sin_family = AF_INET;
|
|
|
|
#ifdef HAVE_SA_LEN
|
|
|
|
to.sin_len = sizeof to;
|
|
|
|
#endif
|
|
|
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
|
|
|
|
1996-03-06 10:38:04 +00:00
|
|
|
/* If this was gatewayed, send it back to the gateway... */
|
|
|
|
if (raw.giaddr.s_addr) {
|
|
|
|
to.sin_addr = raw.giaddr;
|
1997-02-19 10:50:40 +00:00
|
|
|
to.sin_port = local_port;
|
1996-05-22 07:14:13 +00:00
|
|
|
|
|
|
|
#ifdef USE_FALLBACK
|
|
|
|
result = send_fallback (&fallback_interface,
|
1996-05-22 09:29:56 +00:00
|
|
|
(struct packet *)0,
|
|
|
|
&raw, outgoing.packet_length,
|
1996-08-27 09:33:41 +00:00
|
|
|
from, &to, &hto);
|
1996-05-22 07:14:13 +00:00
|
|
|
if (result < 0)
|
|
|
|
warn ("send_fallback: %m");
|
|
|
|
return;
|
|
|
|
#endif
|
1996-03-06 10:38:04 +00:00
|
|
|
/* Otherwise, broadcast it on the local network. */
|
|
|
|
} else {
|
1995-11-29 07:40:04 +00:00
|
|
|
to.sin_addr.s_addr = INADDR_BROADCAST;
|
1997-02-19 10:50:40 +00:00
|
|
|
to.sin_port = remote_port; /* XXX */
|
1996-03-06 10:38:04 +00:00
|
|
|
}
|
1995-11-29 07:40:04 +00:00
|
|
|
|
|
|
|
errno = 0;
|
1996-05-12 23:55:27 +00:00
|
|
|
result = send_packet (packet -> interface,
|
1996-05-22 07:14:13 +00:00
|
|
|
packet, &raw, outgoing.packet_length,
|
1996-08-27 09:33:41 +00:00
|
|
|
from, &to, &hto);
|
1995-11-29 07:40:04 +00:00
|
|
|
if (result < 0)
|
1996-05-12 23:55:27 +00:00
|
|
|
warn ("send_packet: %m");
|
1995-11-29 07:40:04 +00:00
|
|
|
}
|