mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-09-01 23:05:29 +00:00
shared net support; static dhcp address assignment; dynamic bootp support
This commit is contained in:
656
dhcp.c
656
dhcp.c
@@ -82,24 +82,49 @@ void dhcpdiscover (packet)
|
|||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
|
struct host_decl *hp;
|
||||||
|
|
||||||
note ("Received DHCPDISCOVER from %s",
|
note ("DHCPDISCOVER from %s",
|
||||||
print_hw_addr (packet -> raw -> htype,
|
print_hw_addr (packet -> raw -> htype,
|
||||||
packet -> raw -> hlen,
|
packet -> raw -> hlen,
|
||||||
packet -> raw -> chaddr));
|
packet -> raw -> chaddr));
|
||||||
|
|
||||||
/* If we didn't find a lease, try to allocate one... */
|
/* If we didn't find a lease, try to allocate one... */
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
lease = packet -> subnet -> last_lease;
|
lease = packet -> shared_network -> last_lease;
|
||||||
|
|
||||||
/* If there are no leases in that subnet that have
|
/* If there are no leases in that subnet that have
|
||||||
expired, we have nothing to offer this client. */
|
expired, we have nothing to offer this client. */
|
||||||
if (lease -> ends >= cur_time) {
|
if (lease -> ends > cur_time) {
|
||||||
note ("no free leases on subnet %s",
|
note ("no free leases on subnet %s",
|
||||||
piaddr (packet -> subnet -> net));
|
packet -> shared_network -> name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lease -> host = (struct host_decl *)0;
|
|
||||||
|
/* Try to find a host_decl that matches the client
|
||||||
|
identifier or hardware address on the packet, and
|
||||||
|
has no fixed IP address. If there is one, hang
|
||||||
|
it off the lease so that its option definitions
|
||||||
|
can be used. */
|
||||||
|
if (((packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len
|
||||||
|
!= 0) &&
|
||||||
|
((hp = find_hosts_by_uid
|
||||||
|
(packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data,
|
||||||
|
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len))
|
||||||
|
!= (struct host_decl *)0)) ||
|
||||||
|
((hp = find_hosts_by_haddr (packet -> raw -> htype,
|
||||||
|
packet -> raw -> chaddr,
|
||||||
|
packet -> raw -> hlen))
|
||||||
|
!= (struct host_decl *)0)) {
|
||||||
|
for (; hp; hp = hp -> n_ipaddr) {
|
||||||
|
if (!hp -> fixed_addr) {
|
||||||
|
lease -> host = hp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lease -> host = (struct host_decl *)0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
|
ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
|
||||||
@@ -110,6 +135,8 @@ void dhcprequest (packet)
|
|||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
struct iaddr cip;
|
struct iaddr cip;
|
||||||
|
struct subnet *subnet;
|
||||||
|
struct lease *ip_lease;
|
||||||
|
|
||||||
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
||||||
cip.len = 4;
|
cip.len = 4;
|
||||||
@@ -121,29 +148,23 @@ void dhcprequest (packet)
|
|||||||
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
|
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
note ("Received DHCPREQUEST from %s for %s",
|
note ("DHCPREQUEST for %s from %s",
|
||||||
print_hw_addr (packet -> raw -> htype,
|
piaddr (cip),
|
||||||
packet -> raw -> hlen,
|
print_hw_addr (packet -> raw -> htype,
|
||||||
packet -> raw -> chaddr),
|
packet -> raw -> hlen,
|
||||||
piaddr (cip));
|
packet -> raw -> chaddr));
|
||||||
|
|
||||||
/* If a client on our local network wants to renew a lease on
|
/* If a client on our local network wants to renew a lease on
|
||||||
an address off our local network, NAK it. */
|
an address off our local network, NAK it. */
|
||||||
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
||||||
if (!addr_eq (packet -> subnet -> net,
|
subnet = find_grouped_subnet (packet -> shared_network, cip);
|
||||||
subnet_number (cip,
|
if (!subnet) {
|
||||||
packet -> subnet -> netmask))) {
|
|
||||||
nak_lease (packet, &cip);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
} else if (packet -> raw -> ciaddr.s_addr) {
|
||||||
|
subnet = find_grouped_subnet (packet -> shared_network, cip);
|
||||||
if (packet -> raw -> ciaddr.s_addr) {
|
if (!subnet) {
|
||||||
cip.len = 4;
|
|
||||||
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
|
|
||||||
if (!addr_eq (packet -> subnet -> net,
|
|
||||||
subnet_number (cip,
|
|
||||||
packet -> subnet -> netmask))) {
|
|
||||||
nak_lease (packet, &cip);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -151,12 +172,29 @@ void dhcprequest (packet)
|
|||||||
|
|
||||||
/* Look for server identifier... */
|
/* Look for server identifier... */
|
||||||
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
|
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
|
||||||
/* If there is one, and it isn't this server, and
|
/* If we own the lease that the client is asking for,
|
||||||
we have a lease for this client, let it go. */
|
and it's already been assigned to the client,
|
||||||
|
ack it regardless. */
|
||||||
|
if ((lease -> uid_len && lease -> uid_len ==
|
||||||
|
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len &&
|
||||||
|
!memcmp (packet -> options
|
||||||
|
[DHO_DHCP_CLIENT_IDENTIFIER].data,
|
||||||
|
lease -> uid, lease -> uid_len)) ||
|
||||||
|
(lease -> hardware_addr.hlen == packet -> raw -> hlen &&
|
||||||
|
lease -> hardware_addr.htype == packet -> raw -> htype &&
|
||||||
|
!memcmp (lease -> hardware_addr.haddr,
|
||||||
|
packet -> raw -> chaddr,
|
||||||
|
packet -> raw -> hlen))) {
|
||||||
|
ack_lease (packet, lease, DHCPACK, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, if we have a lease for this client,
|
||||||
|
release it, and in any case don't reply to the
|
||||||
|
DHCPREQUEST. */
|
||||||
if (memcmp (packet ->
|
if (memcmp (packet ->
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER].data,
|
options [DHO_DHCP_SERVER_IDENTIFIER].data,
|
||||||
packet -> interface -> address.iabuf,
|
server_identifier.iabuf, server_identifier.len)) {
|
||||||
packet -> interface -> address.len)) {
|
|
||||||
if (lease)
|
if (lease)
|
||||||
release_lease (lease);
|
release_lease (lease);
|
||||||
return;
|
return;
|
||||||
@@ -179,11 +217,11 @@ void dhcprelease (packet)
|
|||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
|
|
||||||
note ("Received DHCPRELEASE from %s for %s",
|
note ("DHCPRELEASE of %s from %s",
|
||||||
|
inet_ntoa (packet -> raw -> ciaddr),
|
||||||
print_hw_addr (packet -> raw -> htype,
|
print_hw_addr (packet -> raw -> htype,
|
||||||
packet -> raw -> hlen,
|
packet -> raw -> hlen,
|
||||||
packet -> raw -> chaddr),
|
packet -> raw -> chaddr));
|
||||||
inet_ntoa (packet -> raw -> ciaddr));
|
|
||||||
|
|
||||||
/* If we found a lease, release it. */
|
/* If we found a lease, release it. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
@@ -206,11 +244,11 @@ void dhcpdecline (packet)
|
|||||||
cip.len = 0;
|
cip.len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
note ("Received DHCPDECLINE from %s for %s",
|
note ("DHCPDECLINE on %s from %s",
|
||||||
|
piaddr (cip),
|
||||||
print_hw_addr (packet -> raw -> htype,
|
print_hw_addr (packet -> raw -> htype,
|
||||||
packet -> raw -> hlen,
|
packet -> raw -> hlen,
|
||||||
packet -> raw -> chaddr),
|
packet -> raw -> chaddr));
|
||||||
piaddr (cip));
|
|
||||||
|
|
||||||
/* If we found a lease, mark it as unusable and complain. */
|
/* If we found a lease, mark it as unusable and complain. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
@@ -221,10 +259,7 @@ void dhcpdecline (packet)
|
|||||||
void dhcpinform (packet)
|
void dhcpinform (packet)
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
note ("Received DHCPINFORM from %s for %s",
|
note ("DHCPINFORM from %s",
|
||||||
print_hw_addr (packet -> raw -> htype,
|
|
||||||
packet -> raw -> hlen,
|
|
||||||
packet -> raw -> chaddr),
|
|
||||||
inet_ntoa (packet -> raw -> ciaddr));
|
inet_ntoa (packet -> raw -> ciaddr));
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -274,7 +309,7 @@ void nak_lease (packet, cip)
|
|||||||
cons_options (packet, &outgoing, options, 0);
|
cons_options (packet, &outgoing, options, 0);
|
||||||
|
|
||||||
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
|
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
|
||||||
memcpy (&raw.siaddr, packet -> interface -> address.iabuf, 4);
|
memcpy (&raw.siaddr, server_identifier.iabuf, 4);
|
||||||
raw.giaddr = packet -> raw -> giaddr;
|
raw.giaddr = packet -> raw -> giaddr;
|
||||||
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
||||||
raw.hlen = packet -> raw -> hlen;
|
raw.hlen = packet -> raw -> hlen;
|
||||||
@@ -286,38 +321,12 @@ void nak_lease (packet, cip)
|
|||||||
raw.hops = packet -> raw -> hops;
|
raw.hops = packet -> raw -> hops;
|
||||||
raw.op = BOOTREPLY;
|
raw.op = BOOTREPLY;
|
||||||
|
|
||||||
/* If this was gatewayed, send it back to the gateway.
|
/* Report what we're sending... */
|
||||||
Otherwise, broadcast it on the local network. */
|
note ("DHCPNAK on %s to %s",
|
||||||
if (raw.giaddr.s_addr) {
|
piaddr (*cip),
|
||||||
to.sin_addr = raw.giaddr;
|
print_hw_addr (packet -> raw -> htype,
|
||||||
to.sin_port = server_port;
|
packet -> raw -> hlen,
|
||||||
} else {
|
packet -> raw -> chaddr));
|
||||||
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
|
|
||||||
to.sin_port = packet->client_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
to.sin_family = AF_INET;
|
|
||||||
#ifdef HAVE_SA_LEN
|
|
||||||
to.sin_len = sizeof to;
|
|
||||||
#endif
|
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
|
||||||
|
|
||||||
note ("Sending DHCPNAK to %s at IP address %s",
|
|
||||||
print_hw_addr (packet -> raw -> htype,
|
|
||||||
packet -> raw -> hlen,
|
|
||||||
packet -> raw -> chaddr),
|
|
||||||
inet_ntoa (to.sin_addr), htons (to.sin_port));
|
|
||||||
|
|
||||||
hto.htype = packet -> raw -> htype;
|
|
||||||
hto.hlen = packet -> raw -> hlen;
|
|
||||||
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
result = send_packet (packet -> interface,
|
|
||||||
packet, &raw, outgoing.packet_length,
|
|
||||||
&to, (struct hardware *)0);
|
|
||||||
if (result < 0)
|
|
||||||
warn ("sendpkt: %m");
|
|
||||||
|
|
||||||
#ifdef DEBUG_PACKET
|
#ifdef DEBUG_PACKET
|
||||||
dump_packet (packet);
|
dump_packet (packet);
|
||||||
@@ -325,6 +334,43 @@ void nak_lease (packet, cip)
|
|||||||
dump_packet (&outgoing);
|
dump_packet (&outgoing);
|
||||||
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
hto.htype = packet -> raw -> htype;
|
||||||
|
hto.hlen = packet -> raw -> hlen;
|
||||||
|
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
||||||
|
|
||||||
|
/* Set up the common stuff... */
|
||||||
|
to.sin_family = AF_INET;
|
||||||
|
#ifdef HAVE_SA_LEN
|
||||||
|
to.sin_len = sizeof to;
|
||||||
|
#endif
|
||||||
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
||||||
|
|
||||||
|
/* If this was gatewayed, send it back to the gateway.
|
||||||
|
Otherwise, broadcast it on the local network. */
|
||||||
|
if (raw.giaddr.s_addr) {
|
||||||
|
to.sin_addr = raw.giaddr;
|
||||||
|
to.sin_port = server_port;
|
||||||
|
|
||||||
|
#ifdef USE_FALLBACK
|
||||||
|
result = send_fallback (&fallback_interface,
|
||||||
|
packet, &raw, outgoing.packet_length,
|
||||||
|
raw.siaddr, &to, &hto);
|
||||||
|
if (result < 0)
|
||||||
|
warn ("send_fallback: %m");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
|
||||||
|
to.sin_port = packet->client_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
result = send_packet (packet -> interface,
|
||||||
|
packet, &raw, outgoing.packet_length,
|
||||||
|
raw.siaddr, &to, (struct hardware *)0);
|
||||||
|
if (result < 0)
|
||||||
|
warn ("send_packet: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ack_lease (packet, lease, offer, when)
|
void ack_lease (packet, lease, offer, when)
|
||||||
@@ -353,6 +399,7 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
|
|
||||||
struct class *vendor_class, *user_class;
|
struct class *vendor_class, *user_class;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
char *server_name;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) {
|
if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) {
|
||||||
@@ -377,12 +424,25 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
user_class = (struct class *)0;
|
user_class = (struct class *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user_class && user_class -> filename)
|
/* Choose a filename; first from the host_decl, if any, then from
|
||||||
|
the user class, then from the vendor class. */
|
||||||
|
if (lease -> host -> filename)
|
||||||
|
filename = lease -> host -> filename;
|
||||||
|
else if (user_class && user_class -> filename)
|
||||||
filename = user_class -> filename;
|
filename = user_class -> filename;
|
||||||
else if (vendor_class && vendor_class -> filename)
|
else if (vendor_class && vendor_class -> filename)
|
||||||
filename = vendor_class -> filename;
|
filename = vendor_class -> filename;
|
||||||
else filename = (char *)0;
|
else filename = (char *)0;
|
||||||
|
|
||||||
|
/* Choose a server name as above. */
|
||||||
|
if (lease -> host -> server_name)
|
||||||
|
server_name = lease -> host -> server_name;
|
||||||
|
else if (user_class && user_class -> server_name)
|
||||||
|
server_name = user_class -> server_name;
|
||||||
|
else if (vendor_class && vendor_class -> server_name)
|
||||||
|
server_name = vendor_class -> server_name;
|
||||||
|
else server_name = (char *)0;
|
||||||
|
|
||||||
/* At this point, we have a lease that we can offer the client.
|
/* At this point, we have a lease that we can offer the client.
|
||||||
Now we construct a lease structure that contains what we want,
|
Now we construct a lease structure that contains what we want,
|
||||||
and call supersede_lease to do the right thing with it. */
|
and call supersede_lease to do the right thing with it. */
|
||||||
@@ -396,23 +456,45 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
/* Start now. */
|
/* Start now. */
|
||||||
lt.starts = cur_time;
|
lt.starts = cur_time;
|
||||||
|
|
||||||
/* Figure out how long a lease to assign. */
|
/* Figure out how long a lease to assign. If this is a
|
||||||
if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) {
|
dynamic BOOTP lease, its duration must be infinite. */
|
||||||
lease_time = getULong (packet ->
|
if (offer) {
|
||||||
options [DHO_DHCP_LEASE_TIME].data);
|
if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) {
|
||||||
|
lease_time = getULong
|
||||||
/* Don't let the client ask for a longer lease than
|
(packet -> options [DHO_DHCP_LEASE_TIME].data);
|
||||||
is supported for this subnet. */
|
|
||||||
if (lease_time > packet -> subnet -> max_lease_time)
|
/* Don't let the client ask for a longer lease than
|
||||||
lease_time = packet -> subnet -> max_lease_time;
|
is supported for this subnet or host. */
|
||||||
} else
|
if (lease -> host && lease -> host -> max_lease_time) {
|
||||||
lease_time = packet -> subnet -> default_lease_time;
|
if (lease_time >
|
||||||
|
lease -> host -> max_lease_time)
|
||||||
lt.offered_expiry = cur_time + lease_time;
|
lease_time = (lease -> host ->
|
||||||
if (when)
|
max_lease_time);
|
||||||
lt.ends = when;
|
} else {
|
||||||
else
|
if (lease_time >
|
||||||
lt.ends = lt.offered_expiry;
|
lease -> subnet -> max_lease_time)
|
||||||
|
lease_time = (lease -> subnet ->
|
||||||
|
max_lease_time);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lease -> host
|
||||||
|
&& lease -> host -> default_lease_time)
|
||||||
|
lease_time = (lease -> host ->
|
||||||
|
default_lease_time);
|
||||||
|
else
|
||||||
|
lease_time = (lease -> subnet ->
|
||||||
|
default_lease_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
lt.offered_expiry = cur_time + lease_time;
|
||||||
|
if (when)
|
||||||
|
lt.ends = when;
|
||||||
|
else
|
||||||
|
lt.ends = lt.offered_expiry;
|
||||||
|
} else {
|
||||||
|
lt.offered_expiry = lt.ends = MAX_TIME;
|
||||||
|
lt.flags = BOOTP_LEASE;
|
||||||
|
}
|
||||||
|
|
||||||
lt.timestamp = cur_time;
|
lt.timestamp = cur_time;
|
||||||
|
|
||||||
@@ -432,18 +514,23 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
|
memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
|
||||||
packet -> raw -> hlen);
|
packet -> raw -> hlen);
|
||||||
|
|
||||||
lt.host = lease -> host; /* XXX */
|
lt.host = lease -> host;
|
||||||
lt.contain = lease -> contain;
|
lt.subnet = lease -> subnet;
|
||||||
|
lt.shared_network = lease -> shared_network;
|
||||||
|
|
||||||
/* Record the transaction id... */
|
/* Record the transaction id... */
|
||||||
lt.xid = packet -> raw -> xid;
|
lt.xid = packet -> raw -> xid;
|
||||||
|
|
||||||
|
/* Don't call supersede_lease on a mocked-up lease. */
|
||||||
|
if (lease -> flags & STATIC_LEASE)
|
||||||
|
;
|
||||||
|
else
|
||||||
/* Install the new information about this lease in the database.
|
/* Install the new information about this lease in the database.
|
||||||
If this is a DHCPACK and we can't write the lease, don't
|
If this is a DHCPACK or a dynamic BOOTREPLY and we can't write
|
||||||
ACK it either. */
|
the lease, don't ACK it (or BOOTREPLY it) either. */
|
||||||
if (!(supersede_lease (lease, <, offer == DHCPACK)
|
if (!(supersede_lease (lease, <, !offer || offer == DHCPACK)
|
||||||
|| offer != DHCPACK))
|
|| (offer && offer != DHCPACK)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Send a response to the client... */
|
/* Send a response to the client... */
|
||||||
|
|
||||||
@@ -460,100 +547,135 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
|
|
||||||
/* Copy in the server name if given; otherwise, flag the
|
/* Copy in the server name if given; otherwise, flag the
|
||||||
server_name buffer as available for options. */
|
server_name buffer as available for options. */
|
||||||
bufs |= 2; /* XXX */
|
if (server_name)
|
||||||
|
strncpy (raw.sname, server_name, sizeof raw.sname);
|
||||||
|
else
|
||||||
|
bufs |= 2; /* XXX */
|
||||||
|
|
||||||
memcpy (raw.chaddr, packet -> raw -> chaddr, packet -> raw -> hlen);
|
memcpy (raw.chaddr, packet -> raw -> chaddr, packet -> raw -> hlen);
|
||||||
raw.hlen = packet -> raw -> hlen;
|
raw.hlen = packet -> raw -> hlen;
|
||||||
raw.htype = packet -> raw -> htype;
|
raw.htype = packet -> raw -> htype;
|
||||||
|
|
||||||
/* Start out with the subnet options... */
|
/* Start out with the subnet options... */
|
||||||
memcpy (options, packet -> subnet -> options, sizeof options);
|
memcpy (options, lease -> subnet -> options, sizeof options);
|
||||||
|
|
||||||
/* If we have a vendor class, install those options, superceding
|
/* Vendor and user classes are only supported for DHCP clients. */
|
||||||
any subnet options. */
|
if (offer) {
|
||||||
if (vendor_class) {
|
/* If we have a vendor class, install those options,
|
||||||
|
superseding any subnet options. */
|
||||||
|
if (vendor_class) {
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
if (vendor_class -> options [i])
|
||||||
|
options [i] =
|
||||||
|
vendor_class -> options [i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a user class, install those options,
|
||||||
|
superseding any subnet and vendor class options. */
|
||||||
|
if (user_class) {
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
if (user_class -> options [i])
|
||||||
|
options [i] =
|
||||||
|
user_class -> options [i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a host_decl structure, install the associated
|
||||||
|
options, superseding anything that's in the way. */
|
||||||
|
if (lease -> host) {
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
if (vendor_class -> options [i])
|
if (lease -> host -> options [i])
|
||||||
options [i] = vendor_class -> options [i];
|
options [i] = lease -> host -> options [i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have a user class, install those options, superceding
|
/* Now, if appropriate, put in DHCP-specific options that
|
||||||
any subnet and vendor class options. */
|
override those. */
|
||||||
if (user_class) {
|
if (offer) {
|
||||||
for (i = 0; i < 256; i++)
|
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
|
||||||
if (user_class -> options [i])
|
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
|
||||||
options [i] = user_class -> options [i];
|
options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof offer;
|
||||||
}
|
options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof offer;
|
||||||
|
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
/* Now put in options that override those. */
|
options [DHO_DHCP_SERVER_IDENTIFIER] = &server_id_tree;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
|
value = server_identifier.iabuf;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof offer;
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof offer;
|
len = server_identifier.len;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
|
buf_size = server_identifier.len;
|
||||||
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
|
timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
|
tree = (struct tree *)0;
|
||||||
|
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] = &server_id_tree;
|
/* Sanity check the lease time. */
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> value =
|
if ((lease->offered_expiry - cur_time) < 0)
|
||||||
packet -> interface -> address.iabuf;
|
putULong (lease_time_buf,
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> len =
|
lease -> subnet -> default_lease_time);
|
||||||
packet -> interface -> address.len;
|
else if (lease -> offered_expiry - cur_time >
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> buf_size =
|
lease -> subnet -> max_lease_time)
|
||||||
packet -> interface -> address.len;
|
putULong (lease_time_buf,
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> timeout = 0xFFFFFFFF;
|
lease -> subnet -> max_lease_time);
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> tree = (struct tree *)0;
|
else
|
||||||
|
putULong (lease_time_buf,
|
||||||
|
lease -> offered_expiry - cur_time);
|
||||||
|
|
||||||
/* If we used the vendor class the client specified, we have to
|
|
||||||
return it. */
|
|
||||||
if (vendor_class) {
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] = &vendor_class_tree;
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> value =
|
|
||||||
(unsigned char *)vendor_class -> name;
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> len =
|
|
||||||
strlen (vendor_class -> name);
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> buf_size =
|
|
||||||
strlen (vendor_class -> name);
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> timeout = 0xFFFFFFFF;
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> tree = (struct tree *)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we used the user class the client specified, we have to return
|
|
||||||
it. */
|
|
||||||
if (user_class) {
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] = &user_class_tree;
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> value =
|
|
||||||
(unsigned char *)user_class -> name;
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> len =
|
|
||||||
strlen (user_class -> name);
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> buf_size =
|
|
||||||
strlen (user_class -> name);
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> timeout = 0xFFFFFFFF;
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> tree = (struct tree *)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sanity check the lease time. */
|
|
||||||
if ((lease->offered_expiry - cur_time) < 0)
|
|
||||||
putULong (lease_time_buf,
|
|
||||||
packet -> subnet -> default_lease_time);
|
|
||||||
else if (lease -> offered_expiry - cur_time >
|
|
||||||
packet -> subnet -> max_lease_time)
|
|
||||||
putULong (lease_time_buf, packet -> subnet -> max_lease_time);
|
|
||||||
else
|
|
||||||
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
|
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
|
||||||
|
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] -> len = sizeof lease_time_buf;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] ->
|
||||||
|
buf_size = sizeof lease_time_buf;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] -> timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
|
/* If we used the vendor class the client specified, we
|
||||||
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
|
have to return it. */
|
||||||
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
if (vendor_class) {
|
||||||
options [DHO_DHCP_LEASE_TIME] -> len = sizeof lease_time_buf;
|
options [DHO_DHCP_CLASS_IDENTIFIER] =
|
||||||
options [DHO_DHCP_LEASE_TIME] -> buf_size = sizeof lease_time_buf;
|
&vendor_class_tree;
|
||||||
options [DHO_DHCP_LEASE_TIME] -> timeout = 0xFFFFFFFF;
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
options [DHO_DHCP_LEASE_TIME] -> tree = (struct tree *)0;
|
value = (unsigned char *)vendor_class -> name;
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
|
len = strlen (vendor_class -> name);
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
|
buf_size = strlen (vendor_class -> name);
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
|
timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
|
tree = (struct tree *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we used the user class the client specified, we
|
||||||
|
have to return it. */
|
||||||
|
if (user_class) {
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] = &user_class_tree;
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
value = (unsigned char *)user_class -> name;
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
len = strlen (user_class -> name);
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
buf_size = strlen (user_class -> name);
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
tree = (struct tree *)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cons_options (packet, &outgoing, options, bufs);
|
cons_options (packet, &outgoing, options, bufs);
|
||||||
|
|
||||||
raw.ciaddr = packet -> raw -> ciaddr;
|
raw.ciaddr = packet -> raw -> ciaddr;
|
||||||
memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
|
memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
|
||||||
memcpy (&raw.siaddr, packet -> interface -> address.iabuf, 4);
|
if (lease -> subnet -> interface_address.len)
|
||||||
|
memcpy (&raw.siaddr,
|
||||||
|
lease -> subnet -> interface_address.iabuf, 4);
|
||||||
|
else
|
||||||
|
memcpy (&raw.siaddr, server_identifier.iabuf, 4);
|
||||||
|
|
||||||
raw.giaddr = packet -> raw -> giaddr;
|
raw.giaddr = packet -> raw -> giaddr;
|
||||||
|
|
||||||
raw.xid = packet -> raw -> xid;
|
raw.xid = packet -> raw -> xid;
|
||||||
@@ -562,25 +684,20 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
raw.hops = packet -> raw -> hops;
|
raw.hops = packet -> raw -> hops;
|
||||||
raw.op = BOOTREPLY;
|
raw.op = BOOTREPLY;
|
||||||
|
|
||||||
/* If this was gatewayed, send it back to the gateway... */
|
/* Say what we're doing... */
|
||||||
if (raw.giaddr.s_addr) {
|
note ("%s on %s to %s",
|
||||||
to.sin_addr = raw.giaddr;
|
(offer
|
||||||
to.sin_port = server_port;
|
? (offer == DHCPACK ? "DHCPACK" : "DHCPOFFER")
|
||||||
|
: "BOOTREPLY"),
|
||||||
|
piaddr (lease -> ip_addr),
|
||||||
|
print_hw_addr (packet -> raw -> htype,
|
||||||
|
packet -> raw -> hlen,
|
||||||
|
packet -> raw -> chaddr));
|
||||||
|
|
||||||
/* If it comes from a client who already knows its address,
|
/* Set up the hardware address... */
|
||||||
sent it directly to that client. */
|
hto.htype = packet -> raw -> htype;
|
||||||
} else if (raw.ciaddr.s_addr && offer == DHCPACK) {
|
hto.hlen = packet -> raw -> hlen;
|
||||||
to.sin_addr = packet -> raw -> ciaddr;
|
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
|
||||||
|
|
||||||
/* Otherwise, if we can (we can't), unicast it to the client's
|
|
||||||
hardware address */
|
|
||||||
|
|
||||||
/* Otherwise, broadcast it on the local network. */
|
|
||||||
} else {
|
|
||||||
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
|
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
|
||||||
}
|
|
||||||
|
|
||||||
to.sin_family = AF_INET;
|
to.sin_family = AF_INET;
|
||||||
#ifdef HAVE_SA_LEN
|
#ifdef HAVE_SA_LEN
|
||||||
@@ -588,47 +705,89 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
#endif
|
#endif
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
||||||
|
|
||||||
note ("Sending %s to %s at IP address %s",
|
|
||||||
offer == DHCPACK ? "DHCPACK" : "DHCPOFFER",
|
|
||||||
print_hw_addr (packet -> raw -> htype,
|
|
||||||
packet -> raw -> hlen,
|
|
||||||
packet -> raw -> chaddr),
|
|
||||||
inet_ntoa (to.sin_addr), htons (to.sin_port));
|
|
||||||
|
|
||||||
hto.htype = packet -> raw -> htype;
|
|
||||||
hto.hlen = packet -> raw -> hlen;
|
|
||||||
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
|
||||||
|
|
||||||
result = send_packet (packet -> interface,
|
|
||||||
packet, &raw, outgoing.packet_length,
|
|
||||||
&to, &hto);
|
|
||||||
if (result < 0)
|
|
||||||
warn ("sendpkt: %m");
|
|
||||||
|
|
||||||
#ifdef DEBUG_PACKET
|
#ifdef DEBUG_PACKET
|
||||||
dump_packet (packet);
|
dump_packet (packet);
|
||||||
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
||||||
dump_packet (&outgoing);
|
dump_packet (&outgoing);
|
||||||
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* If this was gatewayed, send it back to the gateway... */
|
||||||
|
if (raw.giaddr.s_addr) {
|
||||||
|
to.sin_addr = raw.giaddr;
|
||||||
|
to.sin_port = server_port;
|
||||||
|
#ifdef USE_FALLBACK
|
||||||
|
result = send_fallback (&fallback_interface,
|
||||||
|
packet, &raw, outgoing.packet_length,
|
||||||
|
raw.siaddr, &to, &hto);
|
||||||
|
if (result < 0)
|
||||||
|
warn ("send_fallback: %m");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If it comes from a client who already knows its address,
|
||||||
|
sent it directly to that client. */
|
||||||
|
} else if (raw.ciaddr.s_addr && offer == DHCPACK) {
|
||||||
|
to.sin_addr = packet -> raw -> ciaddr;
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
|
||||||
|
/* Otherwise, broadcast it on the local network. */
|
||||||
|
} else {
|
||||||
|
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result = send_packet (packet -> interface,
|
||||||
|
packet, &raw, outgoing.packet_length,
|
||||||
|
raw.siaddr, &to, &hto);
|
||||||
|
if (result < 0)
|
||||||
|
warn ("sendpkt: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lease *find_lease (packet)
|
struct lease *find_lease (packet)
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
struct lease *uid_lease, *ip_lease, *hw_lease, *lease;
|
struct lease *uid_lease, *ip_lease, *hw_lease;
|
||||||
|
struct lease *lease = (struct lease *)0;
|
||||||
struct iaddr cip;
|
struct iaddr cip;
|
||||||
|
struct host_decl *hp, *host;
|
||||||
|
struct lease *fixed_lease;
|
||||||
|
|
||||||
/* Try to find a lease that's been assigned to the specified
|
/* Try to find a host or lease that's been assigned to the
|
||||||
unique client identifier. */
|
specified unique client identifier. */
|
||||||
if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len)
|
if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) {
|
||||||
uid_lease =
|
/* First, try to find a fixed host entry for the specified
|
||||||
find_lease_by_uid (packet -> options
|
client identifier... */
|
||||||
[DHO_DHCP_CLIENT_IDENTIFIER].data,
|
hp = find_hosts_by_uid (packet -> options
|
||||||
packet -> options
|
[DHO_DHCP_CLIENT_IDENTIFIER].data,
|
||||||
[DHO_DHCP_CLIENT_IDENTIFIER].len);
|
packet -> options
|
||||||
else
|
[DHO_DHCP_CLIENT_IDENTIFIER].len);
|
||||||
|
if (hp) {
|
||||||
|
host = hp;
|
||||||
|
fixed_lease = mockup_lease (packet, hp);
|
||||||
|
} else
|
||||||
|
uid_lease = find_lease_by_uid
|
||||||
|
(packet -> options
|
||||||
|
[DHO_DHCP_CLIENT_IDENTIFIER].data,
|
||||||
|
packet -> options
|
||||||
|
[DHO_DHCP_CLIENT_IDENTIFIER].len);
|
||||||
|
} else {
|
||||||
uid_lease = (struct lease *)0;
|
uid_lease = (struct lease *)0;
|
||||||
|
fixed_lease = (struct lease *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we didn't find a fixed lease using the uid, try doing
|
||||||
|
it with the hardware address... */
|
||||||
|
if (!fixed_lease) {
|
||||||
|
hp = find_hosts_by_haddr (packet -> raw -> htype,
|
||||||
|
packet -> raw -> chaddr,
|
||||||
|
packet -> raw -> hlen);
|
||||||
|
if (hp) {
|
||||||
|
host = hp; /* Save it for later. */
|
||||||
|
fixed_lease = mockup_lease (packet, hp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to find a lease that's been attached to the client's
|
/* Try to find a lease that's been attached to the client's
|
||||||
hardware address... */
|
hardware address... */
|
||||||
@@ -675,23 +834,38 @@ struct lease *find_lease (packet)
|
|||||||
strcpy (dhcp_message, "requested address on bad subnet");
|
strcpy (dhcp_message, "requested address on bad subnet");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now eliminate leases that are on the wrong subnet... */
|
/* Now eliminate leases that are on the wrong network... */
|
||||||
if (ip_lease && packet -> subnet != ip_lease -> contain) {
|
if (ip_lease &&
|
||||||
|
(packet -> shared_network != ip_lease -> shared_network)) {
|
||||||
release_lease (ip_lease);
|
release_lease (ip_lease);
|
||||||
ip_lease = (struct lease *)0;
|
ip_lease = (struct lease *)0;
|
||||||
}
|
}
|
||||||
if (uid_lease && packet -> subnet != uid_lease -> contain) {
|
if (uid_lease &&
|
||||||
|
(packet -> shared_network != uid_lease -> shared_network)) {
|
||||||
release_lease (uid_lease);
|
release_lease (uid_lease);
|
||||||
uid_lease = (struct lease *)0;
|
uid_lease = (struct lease *)0;
|
||||||
}
|
}
|
||||||
if (hw_lease && packet -> subnet != hw_lease -> contain) {
|
if (hw_lease &&
|
||||||
|
(packet -> shared_network != hw_lease -> shared_network)) {
|
||||||
release_lease (hw_lease);
|
release_lease (hw_lease);
|
||||||
hw_lease = (struct lease *)0;
|
hw_lease = (struct lease *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At this point, if ip_lease is nonzero, we can assign it to
|
/* At this point, if fixed_lease is nonzero, we can assign it to
|
||||||
this client. */
|
this client. */
|
||||||
lease = ip_lease;
|
if (fixed_lease)
|
||||||
|
lease = fixed_lease;
|
||||||
|
|
||||||
|
/* If we got a lease that matched the ip address and don't have
|
||||||
|
a better offer, use that; otherwise, release it. */
|
||||||
|
if (ip_lease) {
|
||||||
|
if (lease) {
|
||||||
|
release_lease (ip_lease);
|
||||||
|
} else {
|
||||||
|
lease = ip_lease;
|
||||||
|
lease -> host = (struct host_decl *)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we got a lease that matched the client identifier, we may want
|
/* If we got a lease that matched the client identifier, we may want
|
||||||
to use it, but if we already have a lease we like, we must free
|
to use it, but if we already have a lease we like, we must free
|
||||||
@@ -699,17 +873,59 @@ struct lease *find_lease (packet)
|
|||||||
if (uid_lease) {
|
if (uid_lease) {
|
||||||
if (lease) {
|
if (lease) {
|
||||||
release_lease (uid_lease);
|
release_lease (uid_lease);
|
||||||
} else
|
} else {
|
||||||
lease = uid_lease;
|
lease = uid_lease;
|
||||||
|
lease -> host = (struct host_decl *)0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The lease that matched the hardware address is treated likewise. */
|
/* The lease that matched the hardware address is treated likewise. */
|
||||||
if (hw_lease) {
|
if (hw_lease) {
|
||||||
if (lease) {
|
if (lease) {
|
||||||
release_lease (hw_lease);
|
release_lease (hw_lease);
|
||||||
} else
|
} else {
|
||||||
lease = hw_lease;
|
lease = hw_lease;
|
||||||
|
lease -> host = (struct host_decl *)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we found a host_decl but no matching address, try to
|
||||||
|
find a host_decl that has no address, and if there is one,
|
||||||
|
hang it off the lease so that we can use the supplied
|
||||||
|
options. */
|
||||||
|
if (lease && host && !lease -> host) {
|
||||||
|
for (; host; host = host -> n_ipaddr) {
|
||||||
|
if (!host -> fixed_addr) {
|
||||||
|
lease -> host = host;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search the provided host_decl structure list for an address that's on
|
||||||
|
the specified shared network. If one is found, mock up and return a
|
||||||
|
lease structure for it; otherwise return the null pointer. */
|
||||||
|
|
||||||
|
struct lease *mockup_lease (packet, hp)
|
||||||
|
struct packet *packet;
|
||||||
|
struct host_decl *hp;
|
||||||
|
{
|
||||||
|
static struct lease mock;
|
||||||
|
|
||||||
|
mock.subnet = find_host_for_network (&hp, &mock.ip_addr,
|
||||||
|
packet -> shared_network);
|
||||||
|
if (!mock.subnet)
|
||||||
|
return (struct lease *)0;
|
||||||
|
mock.next = mock.prev = (struct lease *)0;
|
||||||
|
mock.shared_network = mock.subnet -> shared_network;
|
||||||
|
mock.host = hp;
|
||||||
|
mock.uid_len = 0;
|
||||||
|
mock.hardware_addr.hlen = 0;
|
||||||
|
mock.uid = (unsigned char *)0;
|
||||||
|
mock.starts = mock.timestamp = mock.ends = MIN_TIME;
|
||||||
|
mock.flags = STATIC_LEASE;
|
||||||
|
return &mock;
|
||||||
|
}
|
||||||
|
656
server/dhcp.c
656
server/dhcp.c
@@ -82,24 +82,49 @@ void dhcpdiscover (packet)
|
|||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
|
struct host_decl *hp;
|
||||||
|
|
||||||
note ("Received DHCPDISCOVER from %s",
|
note ("DHCPDISCOVER from %s",
|
||||||
print_hw_addr (packet -> raw -> htype,
|
print_hw_addr (packet -> raw -> htype,
|
||||||
packet -> raw -> hlen,
|
packet -> raw -> hlen,
|
||||||
packet -> raw -> chaddr));
|
packet -> raw -> chaddr));
|
||||||
|
|
||||||
/* If we didn't find a lease, try to allocate one... */
|
/* If we didn't find a lease, try to allocate one... */
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
lease = packet -> subnet -> last_lease;
|
lease = packet -> shared_network -> last_lease;
|
||||||
|
|
||||||
/* If there are no leases in that subnet that have
|
/* If there are no leases in that subnet that have
|
||||||
expired, we have nothing to offer this client. */
|
expired, we have nothing to offer this client. */
|
||||||
if (lease -> ends >= cur_time) {
|
if (lease -> ends > cur_time) {
|
||||||
note ("no free leases on subnet %s",
|
note ("no free leases on subnet %s",
|
||||||
piaddr (packet -> subnet -> net));
|
packet -> shared_network -> name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lease -> host = (struct host_decl *)0;
|
|
||||||
|
/* Try to find a host_decl that matches the client
|
||||||
|
identifier or hardware address on the packet, and
|
||||||
|
has no fixed IP address. If there is one, hang
|
||||||
|
it off the lease so that its option definitions
|
||||||
|
can be used. */
|
||||||
|
if (((packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len
|
||||||
|
!= 0) &&
|
||||||
|
((hp = find_hosts_by_uid
|
||||||
|
(packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data,
|
||||||
|
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len))
|
||||||
|
!= (struct host_decl *)0)) ||
|
||||||
|
((hp = find_hosts_by_haddr (packet -> raw -> htype,
|
||||||
|
packet -> raw -> chaddr,
|
||||||
|
packet -> raw -> hlen))
|
||||||
|
!= (struct host_decl *)0)) {
|
||||||
|
for (; hp; hp = hp -> n_ipaddr) {
|
||||||
|
if (!hp -> fixed_addr) {
|
||||||
|
lease -> host = hp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lease -> host = (struct host_decl *)0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
|
ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
|
||||||
@@ -110,6 +135,8 @@ void dhcprequest (packet)
|
|||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
struct iaddr cip;
|
struct iaddr cip;
|
||||||
|
struct subnet *subnet;
|
||||||
|
struct lease *ip_lease;
|
||||||
|
|
||||||
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
||||||
cip.len = 4;
|
cip.len = 4;
|
||||||
@@ -121,29 +148,23 @@ void dhcprequest (packet)
|
|||||||
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
|
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
note ("Received DHCPREQUEST from %s for %s",
|
note ("DHCPREQUEST for %s from %s",
|
||||||
print_hw_addr (packet -> raw -> htype,
|
piaddr (cip),
|
||||||
packet -> raw -> hlen,
|
print_hw_addr (packet -> raw -> htype,
|
||||||
packet -> raw -> chaddr),
|
packet -> raw -> hlen,
|
||||||
piaddr (cip));
|
packet -> raw -> chaddr));
|
||||||
|
|
||||||
/* If a client on our local network wants to renew a lease on
|
/* If a client on our local network wants to renew a lease on
|
||||||
an address off our local network, NAK it. */
|
an address off our local network, NAK it. */
|
||||||
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
||||||
if (!addr_eq (packet -> subnet -> net,
|
subnet = find_grouped_subnet (packet -> shared_network, cip);
|
||||||
subnet_number (cip,
|
if (!subnet) {
|
||||||
packet -> subnet -> netmask))) {
|
|
||||||
nak_lease (packet, &cip);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
} else if (packet -> raw -> ciaddr.s_addr) {
|
||||||
|
subnet = find_grouped_subnet (packet -> shared_network, cip);
|
||||||
if (packet -> raw -> ciaddr.s_addr) {
|
if (!subnet) {
|
||||||
cip.len = 4;
|
|
||||||
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
|
|
||||||
if (!addr_eq (packet -> subnet -> net,
|
|
||||||
subnet_number (cip,
|
|
||||||
packet -> subnet -> netmask))) {
|
|
||||||
nak_lease (packet, &cip);
|
nak_lease (packet, &cip);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -151,12 +172,29 @@ void dhcprequest (packet)
|
|||||||
|
|
||||||
/* Look for server identifier... */
|
/* Look for server identifier... */
|
||||||
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
|
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
|
||||||
/* If there is one, and it isn't this server, and
|
/* If we own the lease that the client is asking for,
|
||||||
we have a lease for this client, let it go. */
|
and it's already been assigned to the client,
|
||||||
|
ack it regardless. */
|
||||||
|
if ((lease -> uid_len && lease -> uid_len ==
|
||||||
|
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len &&
|
||||||
|
!memcmp (packet -> options
|
||||||
|
[DHO_DHCP_CLIENT_IDENTIFIER].data,
|
||||||
|
lease -> uid, lease -> uid_len)) ||
|
||||||
|
(lease -> hardware_addr.hlen == packet -> raw -> hlen &&
|
||||||
|
lease -> hardware_addr.htype == packet -> raw -> htype &&
|
||||||
|
!memcmp (lease -> hardware_addr.haddr,
|
||||||
|
packet -> raw -> chaddr,
|
||||||
|
packet -> raw -> hlen))) {
|
||||||
|
ack_lease (packet, lease, DHCPACK, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, if we have a lease for this client,
|
||||||
|
release it, and in any case don't reply to the
|
||||||
|
DHCPREQUEST. */
|
||||||
if (memcmp (packet ->
|
if (memcmp (packet ->
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER].data,
|
options [DHO_DHCP_SERVER_IDENTIFIER].data,
|
||||||
packet -> interface -> address.iabuf,
|
server_identifier.iabuf, server_identifier.len)) {
|
||||||
packet -> interface -> address.len)) {
|
|
||||||
if (lease)
|
if (lease)
|
||||||
release_lease (lease);
|
release_lease (lease);
|
||||||
return;
|
return;
|
||||||
@@ -179,11 +217,11 @@ void dhcprelease (packet)
|
|||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
|
|
||||||
note ("Received DHCPRELEASE from %s for %s",
|
note ("DHCPRELEASE of %s from %s",
|
||||||
|
inet_ntoa (packet -> raw -> ciaddr),
|
||||||
print_hw_addr (packet -> raw -> htype,
|
print_hw_addr (packet -> raw -> htype,
|
||||||
packet -> raw -> hlen,
|
packet -> raw -> hlen,
|
||||||
packet -> raw -> chaddr),
|
packet -> raw -> chaddr));
|
||||||
inet_ntoa (packet -> raw -> ciaddr));
|
|
||||||
|
|
||||||
/* If we found a lease, release it. */
|
/* If we found a lease, release it. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
@@ -206,11 +244,11 @@ void dhcpdecline (packet)
|
|||||||
cip.len = 0;
|
cip.len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
note ("Received DHCPDECLINE from %s for %s",
|
note ("DHCPDECLINE on %s from %s",
|
||||||
|
piaddr (cip),
|
||||||
print_hw_addr (packet -> raw -> htype,
|
print_hw_addr (packet -> raw -> htype,
|
||||||
packet -> raw -> hlen,
|
packet -> raw -> hlen,
|
||||||
packet -> raw -> chaddr),
|
packet -> raw -> chaddr));
|
||||||
piaddr (cip));
|
|
||||||
|
|
||||||
/* If we found a lease, mark it as unusable and complain. */
|
/* If we found a lease, mark it as unusable and complain. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
@@ -221,10 +259,7 @@ void dhcpdecline (packet)
|
|||||||
void dhcpinform (packet)
|
void dhcpinform (packet)
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
note ("Received DHCPINFORM from %s for %s",
|
note ("DHCPINFORM from %s",
|
||||||
print_hw_addr (packet -> raw -> htype,
|
|
||||||
packet -> raw -> hlen,
|
|
||||||
packet -> raw -> chaddr),
|
|
||||||
inet_ntoa (packet -> raw -> ciaddr));
|
inet_ntoa (packet -> raw -> ciaddr));
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -274,7 +309,7 @@ void nak_lease (packet, cip)
|
|||||||
cons_options (packet, &outgoing, options, 0);
|
cons_options (packet, &outgoing, options, 0);
|
||||||
|
|
||||||
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
|
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
|
||||||
memcpy (&raw.siaddr, packet -> interface -> address.iabuf, 4);
|
memcpy (&raw.siaddr, server_identifier.iabuf, 4);
|
||||||
raw.giaddr = packet -> raw -> giaddr;
|
raw.giaddr = packet -> raw -> giaddr;
|
||||||
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
||||||
raw.hlen = packet -> raw -> hlen;
|
raw.hlen = packet -> raw -> hlen;
|
||||||
@@ -286,38 +321,12 @@ void nak_lease (packet, cip)
|
|||||||
raw.hops = packet -> raw -> hops;
|
raw.hops = packet -> raw -> hops;
|
||||||
raw.op = BOOTREPLY;
|
raw.op = BOOTREPLY;
|
||||||
|
|
||||||
/* If this was gatewayed, send it back to the gateway.
|
/* Report what we're sending... */
|
||||||
Otherwise, broadcast it on the local network. */
|
note ("DHCPNAK on %s to %s",
|
||||||
if (raw.giaddr.s_addr) {
|
piaddr (*cip),
|
||||||
to.sin_addr = raw.giaddr;
|
print_hw_addr (packet -> raw -> htype,
|
||||||
to.sin_port = server_port;
|
packet -> raw -> hlen,
|
||||||
} else {
|
packet -> raw -> chaddr));
|
||||||
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
|
|
||||||
to.sin_port = packet->client_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
to.sin_family = AF_INET;
|
|
||||||
#ifdef HAVE_SA_LEN
|
|
||||||
to.sin_len = sizeof to;
|
|
||||||
#endif
|
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
|
||||||
|
|
||||||
note ("Sending DHCPNAK to %s at IP address %s",
|
|
||||||
print_hw_addr (packet -> raw -> htype,
|
|
||||||
packet -> raw -> hlen,
|
|
||||||
packet -> raw -> chaddr),
|
|
||||||
inet_ntoa (to.sin_addr), htons (to.sin_port));
|
|
||||||
|
|
||||||
hto.htype = packet -> raw -> htype;
|
|
||||||
hto.hlen = packet -> raw -> hlen;
|
|
||||||
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
result = send_packet (packet -> interface,
|
|
||||||
packet, &raw, outgoing.packet_length,
|
|
||||||
&to, (struct hardware *)0);
|
|
||||||
if (result < 0)
|
|
||||||
warn ("sendpkt: %m");
|
|
||||||
|
|
||||||
#ifdef DEBUG_PACKET
|
#ifdef DEBUG_PACKET
|
||||||
dump_packet (packet);
|
dump_packet (packet);
|
||||||
@@ -325,6 +334,43 @@ void nak_lease (packet, cip)
|
|||||||
dump_packet (&outgoing);
|
dump_packet (&outgoing);
|
||||||
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
hto.htype = packet -> raw -> htype;
|
||||||
|
hto.hlen = packet -> raw -> hlen;
|
||||||
|
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
||||||
|
|
||||||
|
/* Set up the common stuff... */
|
||||||
|
to.sin_family = AF_INET;
|
||||||
|
#ifdef HAVE_SA_LEN
|
||||||
|
to.sin_len = sizeof to;
|
||||||
|
#endif
|
||||||
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
||||||
|
|
||||||
|
/* If this was gatewayed, send it back to the gateway.
|
||||||
|
Otherwise, broadcast it on the local network. */
|
||||||
|
if (raw.giaddr.s_addr) {
|
||||||
|
to.sin_addr = raw.giaddr;
|
||||||
|
to.sin_port = server_port;
|
||||||
|
|
||||||
|
#ifdef USE_FALLBACK
|
||||||
|
result = send_fallback (&fallback_interface,
|
||||||
|
packet, &raw, outgoing.packet_length,
|
||||||
|
raw.siaddr, &to, &hto);
|
||||||
|
if (result < 0)
|
||||||
|
warn ("send_fallback: %m");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
|
||||||
|
to.sin_port = packet->client_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
result = send_packet (packet -> interface,
|
||||||
|
packet, &raw, outgoing.packet_length,
|
||||||
|
raw.siaddr, &to, (struct hardware *)0);
|
||||||
|
if (result < 0)
|
||||||
|
warn ("send_packet: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ack_lease (packet, lease, offer, when)
|
void ack_lease (packet, lease, offer, when)
|
||||||
@@ -353,6 +399,7 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
|
|
||||||
struct class *vendor_class, *user_class;
|
struct class *vendor_class, *user_class;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
char *server_name;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) {
|
if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) {
|
||||||
@@ -377,12 +424,25 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
user_class = (struct class *)0;
|
user_class = (struct class *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user_class && user_class -> filename)
|
/* Choose a filename; first from the host_decl, if any, then from
|
||||||
|
the user class, then from the vendor class. */
|
||||||
|
if (lease -> host -> filename)
|
||||||
|
filename = lease -> host -> filename;
|
||||||
|
else if (user_class && user_class -> filename)
|
||||||
filename = user_class -> filename;
|
filename = user_class -> filename;
|
||||||
else if (vendor_class && vendor_class -> filename)
|
else if (vendor_class && vendor_class -> filename)
|
||||||
filename = vendor_class -> filename;
|
filename = vendor_class -> filename;
|
||||||
else filename = (char *)0;
|
else filename = (char *)0;
|
||||||
|
|
||||||
|
/* Choose a server name as above. */
|
||||||
|
if (lease -> host -> server_name)
|
||||||
|
server_name = lease -> host -> server_name;
|
||||||
|
else if (user_class && user_class -> server_name)
|
||||||
|
server_name = user_class -> server_name;
|
||||||
|
else if (vendor_class && vendor_class -> server_name)
|
||||||
|
server_name = vendor_class -> server_name;
|
||||||
|
else server_name = (char *)0;
|
||||||
|
|
||||||
/* At this point, we have a lease that we can offer the client.
|
/* At this point, we have a lease that we can offer the client.
|
||||||
Now we construct a lease structure that contains what we want,
|
Now we construct a lease structure that contains what we want,
|
||||||
and call supersede_lease to do the right thing with it. */
|
and call supersede_lease to do the right thing with it. */
|
||||||
@@ -396,23 +456,45 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
/* Start now. */
|
/* Start now. */
|
||||||
lt.starts = cur_time;
|
lt.starts = cur_time;
|
||||||
|
|
||||||
/* Figure out how long a lease to assign. */
|
/* Figure out how long a lease to assign. If this is a
|
||||||
if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) {
|
dynamic BOOTP lease, its duration must be infinite. */
|
||||||
lease_time = getULong (packet ->
|
if (offer) {
|
||||||
options [DHO_DHCP_LEASE_TIME].data);
|
if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) {
|
||||||
|
lease_time = getULong
|
||||||
/* Don't let the client ask for a longer lease than
|
(packet -> options [DHO_DHCP_LEASE_TIME].data);
|
||||||
is supported for this subnet. */
|
|
||||||
if (lease_time > packet -> subnet -> max_lease_time)
|
/* Don't let the client ask for a longer lease than
|
||||||
lease_time = packet -> subnet -> max_lease_time;
|
is supported for this subnet or host. */
|
||||||
} else
|
if (lease -> host && lease -> host -> max_lease_time) {
|
||||||
lease_time = packet -> subnet -> default_lease_time;
|
if (lease_time >
|
||||||
|
lease -> host -> max_lease_time)
|
||||||
lt.offered_expiry = cur_time + lease_time;
|
lease_time = (lease -> host ->
|
||||||
if (when)
|
max_lease_time);
|
||||||
lt.ends = when;
|
} else {
|
||||||
else
|
if (lease_time >
|
||||||
lt.ends = lt.offered_expiry;
|
lease -> subnet -> max_lease_time)
|
||||||
|
lease_time = (lease -> subnet ->
|
||||||
|
max_lease_time);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lease -> host
|
||||||
|
&& lease -> host -> default_lease_time)
|
||||||
|
lease_time = (lease -> host ->
|
||||||
|
default_lease_time);
|
||||||
|
else
|
||||||
|
lease_time = (lease -> subnet ->
|
||||||
|
default_lease_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
lt.offered_expiry = cur_time + lease_time;
|
||||||
|
if (when)
|
||||||
|
lt.ends = when;
|
||||||
|
else
|
||||||
|
lt.ends = lt.offered_expiry;
|
||||||
|
} else {
|
||||||
|
lt.offered_expiry = lt.ends = MAX_TIME;
|
||||||
|
lt.flags = BOOTP_LEASE;
|
||||||
|
}
|
||||||
|
|
||||||
lt.timestamp = cur_time;
|
lt.timestamp = cur_time;
|
||||||
|
|
||||||
@@ -432,18 +514,23 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
|
memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
|
||||||
packet -> raw -> hlen);
|
packet -> raw -> hlen);
|
||||||
|
|
||||||
lt.host = lease -> host; /* XXX */
|
lt.host = lease -> host;
|
||||||
lt.contain = lease -> contain;
|
lt.subnet = lease -> subnet;
|
||||||
|
lt.shared_network = lease -> shared_network;
|
||||||
|
|
||||||
/* Record the transaction id... */
|
/* Record the transaction id... */
|
||||||
lt.xid = packet -> raw -> xid;
|
lt.xid = packet -> raw -> xid;
|
||||||
|
|
||||||
|
/* Don't call supersede_lease on a mocked-up lease. */
|
||||||
|
if (lease -> flags & STATIC_LEASE)
|
||||||
|
;
|
||||||
|
else
|
||||||
/* Install the new information about this lease in the database.
|
/* Install the new information about this lease in the database.
|
||||||
If this is a DHCPACK and we can't write the lease, don't
|
If this is a DHCPACK or a dynamic BOOTREPLY and we can't write
|
||||||
ACK it either. */
|
the lease, don't ACK it (or BOOTREPLY it) either. */
|
||||||
if (!(supersede_lease (lease, <, offer == DHCPACK)
|
if (!(supersede_lease (lease, <, !offer || offer == DHCPACK)
|
||||||
|| offer != DHCPACK))
|
|| (offer && offer != DHCPACK)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Send a response to the client... */
|
/* Send a response to the client... */
|
||||||
|
|
||||||
@@ -460,100 +547,135 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
|
|
||||||
/* Copy in the server name if given; otherwise, flag the
|
/* Copy in the server name if given; otherwise, flag the
|
||||||
server_name buffer as available for options. */
|
server_name buffer as available for options. */
|
||||||
bufs |= 2; /* XXX */
|
if (server_name)
|
||||||
|
strncpy (raw.sname, server_name, sizeof raw.sname);
|
||||||
|
else
|
||||||
|
bufs |= 2; /* XXX */
|
||||||
|
|
||||||
memcpy (raw.chaddr, packet -> raw -> chaddr, packet -> raw -> hlen);
|
memcpy (raw.chaddr, packet -> raw -> chaddr, packet -> raw -> hlen);
|
||||||
raw.hlen = packet -> raw -> hlen;
|
raw.hlen = packet -> raw -> hlen;
|
||||||
raw.htype = packet -> raw -> htype;
|
raw.htype = packet -> raw -> htype;
|
||||||
|
|
||||||
/* Start out with the subnet options... */
|
/* Start out with the subnet options... */
|
||||||
memcpy (options, packet -> subnet -> options, sizeof options);
|
memcpy (options, lease -> subnet -> options, sizeof options);
|
||||||
|
|
||||||
/* If we have a vendor class, install those options, superceding
|
/* Vendor and user classes are only supported for DHCP clients. */
|
||||||
any subnet options. */
|
if (offer) {
|
||||||
if (vendor_class) {
|
/* If we have a vendor class, install those options,
|
||||||
|
superseding any subnet options. */
|
||||||
|
if (vendor_class) {
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
if (vendor_class -> options [i])
|
||||||
|
options [i] =
|
||||||
|
vendor_class -> options [i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a user class, install those options,
|
||||||
|
superseding any subnet and vendor class options. */
|
||||||
|
if (user_class) {
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
if (user_class -> options [i])
|
||||||
|
options [i] =
|
||||||
|
user_class -> options [i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a host_decl structure, install the associated
|
||||||
|
options, superseding anything that's in the way. */
|
||||||
|
if (lease -> host) {
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
if (vendor_class -> options [i])
|
if (lease -> host -> options [i])
|
||||||
options [i] = vendor_class -> options [i];
|
options [i] = lease -> host -> options [i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have a user class, install those options, superceding
|
/* Now, if appropriate, put in DHCP-specific options that
|
||||||
any subnet and vendor class options. */
|
override those. */
|
||||||
if (user_class) {
|
if (offer) {
|
||||||
for (i = 0; i < 256; i++)
|
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
|
||||||
if (user_class -> options [i])
|
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
|
||||||
options [i] = user_class -> options [i];
|
options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof offer;
|
||||||
}
|
options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof offer;
|
||||||
|
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
/* Now put in options that override those. */
|
options [DHO_DHCP_SERVER_IDENTIFIER] = &server_id_tree;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
|
value = server_identifier.iabuf;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof offer;
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof offer;
|
len = server_identifier.len;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
|
buf_size = server_identifier.len;
|
||||||
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
|
timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_SERVER_IDENTIFIER] ->
|
||||||
|
tree = (struct tree *)0;
|
||||||
|
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] = &server_id_tree;
|
/* Sanity check the lease time. */
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> value =
|
if ((lease->offered_expiry - cur_time) < 0)
|
||||||
packet -> interface -> address.iabuf;
|
putULong (lease_time_buf,
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> len =
|
lease -> subnet -> default_lease_time);
|
||||||
packet -> interface -> address.len;
|
else if (lease -> offered_expiry - cur_time >
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> buf_size =
|
lease -> subnet -> max_lease_time)
|
||||||
packet -> interface -> address.len;
|
putULong (lease_time_buf,
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> timeout = 0xFFFFFFFF;
|
lease -> subnet -> max_lease_time);
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> tree = (struct tree *)0;
|
else
|
||||||
|
putULong (lease_time_buf,
|
||||||
|
lease -> offered_expiry - cur_time);
|
||||||
|
|
||||||
/* If we used the vendor class the client specified, we have to
|
|
||||||
return it. */
|
|
||||||
if (vendor_class) {
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] = &vendor_class_tree;
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> value =
|
|
||||||
(unsigned char *)vendor_class -> name;
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> len =
|
|
||||||
strlen (vendor_class -> name);
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> buf_size =
|
|
||||||
strlen (vendor_class -> name);
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> timeout = 0xFFFFFFFF;
|
|
||||||
options [DHO_DHCP_CLASS_IDENTIFIER] -> tree = (struct tree *)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we used the user class the client specified, we have to return
|
|
||||||
it. */
|
|
||||||
if (user_class) {
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] = &user_class_tree;
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> value =
|
|
||||||
(unsigned char *)user_class -> name;
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> len =
|
|
||||||
strlen (user_class -> name);
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> buf_size =
|
|
||||||
strlen (user_class -> name);
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> timeout = 0xFFFFFFFF;
|
|
||||||
options [DHO_DHCP_USER_CLASS_ID] -> tree = (struct tree *)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sanity check the lease time. */
|
|
||||||
if ((lease->offered_expiry - cur_time) < 0)
|
|
||||||
putULong (lease_time_buf,
|
|
||||||
packet -> subnet -> default_lease_time);
|
|
||||||
else if (lease -> offered_expiry - cur_time >
|
|
||||||
packet -> subnet -> max_lease_time)
|
|
||||||
putULong (lease_time_buf, packet -> subnet -> max_lease_time);
|
|
||||||
else
|
|
||||||
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
|
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
|
||||||
|
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] -> len = sizeof lease_time_buf;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] ->
|
||||||
|
buf_size = sizeof lease_time_buf;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] -> timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_LEASE_TIME] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
putULong (lease_time_buf, lease -> offered_expiry - cur_time);
|
/* If we used the vendor class the client specified, we
|
||||||
options [DHO_DHCP_LEASE_TIME] = &lease_time_tree;
|
have to return it. */
|
||||||
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
if (vendor_class) {
|
||||||
options [DHO_DHCP_LEASE_TIME] -> len = sizeof lease_time_buf;
|
options [DHO_DHCP_CLASS_IDENTIFIER] =
|
||||||
options [DHO_DHCP_LEASE_TIME] -> buf_size = sizeof lease_time_buf;
|
&vendor_class_tree;
|
||||||
options [DHO_DHCP_LEASE_TIME] -> timeout = 0xFFFFFFFF;
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
options [DHO_DHCP_LEASE_TIME] -> tree = (struct tree *)0;
|
value = (unsigned char *)vendor_class -> name;
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
|
len = strlen (vendor_class -> name);
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
|
buf_size = strlen (vendor_class -> name);
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
|
timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER] ->
|
||||||
|
tree = (struct tree *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we used the user class the client specified, we
|
||||||
|
have to return it. */
|
||||||
|
if (user_class) {
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] = &user_class_tree;
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
value = (unsigned char *)user_class -> name;
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
len = strlen (user_class -> name);
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
buf_size = strlen (user_class -> name);
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID] ->
|
||||||
|
tree = (struct tree *)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cons_options (packet, &outgoing, options, bufs);
|
cons_options (packet, &outgoing, options, bufs);
|
||||||
|
|
||||||
raw.ciaddr = packet -> raw -> ciaddr;
|
raw.ciaddr = packet -> raw -> ciaddr;
|
||||||
memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
|
memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
|
||||||
memcpy (&raw.siaddr, packet -> interface -> address.iabuf, 4);
|
if (lease -> subnet -> interface_address.len)
|
||||||
|
memcpy (&raw.siaddr,
|
||||||
|
lease -> subnet -> interface_address.iabuf, 4);
|
||||||
|
else
|
||||||
|
memcpy (&raw.siaddr, server_identifier.iabuf, 4);
|
||||||
|
|
||||||
raw.giaddr = packet -> raw -> giaddr;
|
raw.giaddr = packet -> raw -> giaddr;
|
||||||
|
|
||||||
raw.xid = packet -> raw -> xid;
|
raw.xid = packet -> raw -> xid;
|
||||||
@@ -562,25 +684,20 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
raw.hops = packet -> raw -> hops;
|
raw.hops = packet -> raw -> hops;
|
||||||
raw.op = BOOTREPLY;
|
raw.op = BOOTREPLY;
|
||||||
|
|
||||||
/* If this was gatewayed, send it back to the gateway... */
|
/* Say what we're doing... */
|
||||||
if (raw.giaddr.s_addr) {
|
note ("%s on %s to %s",
|
||||||
to.sin_addr = raw.giaddr;
|
(offer
|
||||||
to.sin_port = server_port;
|
? (offer == DHCPACK ? "DHCPACK" : "DHCPOFFER")
|
||||||
|
: "BOOTREPLY"),
|
||||||
|
piaddr (lease -> ip_addr),
|
||||||
|
print_hw_addr (packet -> raw -> htype,
|
||||||
|
packet -> raw -> hlen,
|
||||||
|
packet -> raw -> chaddr));
|
||||||
|
|
||||||
/* If it comes from a client who already knows its address,
|
/* Set up the hardware address... */
|
||||||
sent it directly to that client. */
|
hto.htype = packet -> raw -> htype;
|
||||||
} else if (raw.ciaddr.s_addr && offer == DHCPACK) {
|
hto.hlen = packet -> raw -> hlen;
|
||||||
to.sin_addr = packet -> raw -> ciaddr;
|
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
|
||||||
|
|
||||||
/* Otherwise, if we can (we can't), unicast it to the client's
|
|
||||||
hardware address */
|
|
||||||
|
|
||||||
/* Otherwise, broadcast it on the local network. */
|
|
||||||
} else {
|
|
||||||
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
|
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
|
||||||
}
|
|
||||||
|
|
||||||
to.sin_family = AF_INET;
|
to.sin_family = AF_INET;
|
||||||
#ifdef HAVE_SA_LEN
|
#ifdef HAVE_SA_LEN
|
||||||
@@ -588,47 +705,89 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
#endif
|
#endif
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
||||||
|
|
||||||
note ("Sending %s to %s at IP address %s",
|
|
||||||
offer == DHCPACK ? "DHCPACK" : "DHCPOFFER",
|
|
||||||
print_hw_addr (packet -> raw -> htype,
|
|
||||||
packet -> raw -> hlen,
|
|
||||||
packet -> raw -> chaddr),
|
|
||||||
inet_ntoa (to.sin_addr), htons (to.sin_port));
|
|
||||||
|
|
||||||
hto.htype = packet -> raw -> htype;
|
|
||||||
hto.hlen = packet -> raw -> hlen;
|
|
||||||
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
|
||||||
|
|
||||||
result = send_packet (packet -> interface,
|
|
||||||
packet, &raw, outgoing.packet_length,
|
|
||||||
&to, &hto);
|
|
||||||
if (result < 0)
|
|
||||||
warn ("sendpkt: %m");
|
|
||||||
|
|
||||||
#ifdef DEBUG_PACKET
|
#ifdef DEBUG_PACKET
|
||||||
dump_packet (packet);
|
dump_packet (packet);
|
||||||
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
||||||
dump_packet (&outgoing);
|
dump_packet (&outgoing);
|
||||||
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* If this was gatewayed, send it back to the gateway... */
|
||||||
|
if (raw.giaddr.s_addr) {
|
||||||
|
to.sin_addr = raw.giaddr;
|
||||||
|
to.sin_port = server_port;
|
||||||
|
#ifdef USE_FALLBACK
|
||||||
|
result = send_fallback (&fallback_interface,
|
||||||
|
packet, &raw, outgoing.packet_length,
|
||||||
|
raw.siaddr, &to, &hto);
|
||||||
|
if (result < 0)
|
||||||
|
warn ("send_fallback: %m");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If it comes from a client who already knows its address,
|
||||||
|
sent it directly to that client. */
|
||||||
|
} else if (raw.ciaddr.s_addr && offer == DHCPACK) {
|
||||||
|
to.sin_addr = packet -> raw -> ciaddr;
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
|
||||||
|
/* Otherwise, broadcast it on the local network. */
|
||||||
|
} else {
|
||||||
|
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result = send_packet (packet -> interface,
|
||||||
|
packet, &raw, outgoing.packet_length,
|
||||||
|
raw.siaddr, &to, &hto);
|
||||||
|
if (result < 0)
|
||||||
|
warn ("sendpkt: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lease *find_lease (packet)
|
struct lease *find_lease (packet)
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
struct lease *uid_lease, *ip_lease, *hw_lease, *lease;
|
struct lease *uid_lease, *ip_lease, *hw_lease;
|
||||||
|
struct lease *lease = (struct lease *)0;
|
||||||
struct iaddr cip;
|
struct iaddr cip;
|
||||||
|
struct host_decl *hp, *host;
|
||||||
|
struct lease *fixed_lease;
|
||||||
|
|
||||||
/* Try to find a lease that's been assigned to the specified
|
/* Try to find a host or lease that's been assigned to the
|
||||||
unique client identifier. */
|
specified unique client identifier. */
|
||||||
if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len)
|
if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) {
|
||||||
uid_lease =
|
/* First, try to find a fixed host entry for the specified
|
||||||
find_lease_by_uid (packet -> options
|
client identifier... */
|
||||||
[DHO_DHCP_CLIENT_IDENTIFIER].data,
|
hp = find_hosts_by_uid (packet -> options
|
||||||
packet -> options
|
[DHO_DHCP_CLIENT_IDENTIFIER].data,
|
||||||
[DHO_DHCP_CLIENT_IDENTIFIER].len);
|
packet -> options
|
||||||
else
|
[DHO_DHCP_CLIENT_IDENTIFIER].len);
|
||||||
|
if (hp) {
|
||||||
|
host = hp;
|
||||||
|
fixed_lease = mockup_lease (packet, hp);
|
||||||
|
} else
|
||||||
|
uid_lease = find_lease_by_uid
|
||||||
|
(packet -> options
|
||||||
|
[DHO_DHCP_CLIENT_IDENTIFIER].data,
|
||||||
|
packet -> options
|
||||||
|
[DHO_DHCP_CLIENT_IDENTIFIER].len);
|
||||||
|
} else {
|
||||||
uid_lease = (struct lease *)0;
|
uid_lease = (struct lease *)0;
|
||||||
|
fixed_lease = (struct lease *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we didn't find a fixed lease using the uid, try doing
|
||||||
|
it with the hardware address... */
|
||||||
|
if (!fixed_lease) {
|
||||||
|
hp = find_hosts_by_haddr (packet -> raw -> htype,
|
||||||
|
packet -> raw -> chaddr,
|
||||||
|
packet -> raw -> hlen);
|
||||||
|
if (hp) {
|
||||||
|
host = hp; /* Save it for later. */
|
||||||
|
fixed_lease = mockup_lease (packet, hp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to find a lease that's been attached to the client's
|
/* Try to find a lease that's been attached to the client's
|
||||||
hardware address... */
|
hardware address... */
|
||||||
@@ -675,23 +834,38 @@ struct lease *find_lease (packet)
|
|||||||
strcpy (dhcp_message, "requested address on bad subnet");
|
strcpy (dhcp_message, "requested address on bad subnet");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now eliminate leases that are on the wrong subnet... */
|
/* Now eliminate leases that are on the wrong network... */
|
||||||
if (ip_lease && packet -> subnet != ip_lease -> contain) {
|
if (ip_lease &&
|
||||||
|
(packet -> shared_network != ip_lease -> shared_network)) {
|
||||||
release_lease (ip_lease);
|
release_lease (ip_lease);
|
||||||
ip_lease = (struct lease *)0;
|
ip_lease = (struct lease *)0;
|
||||||
}
|
}
|
||||||
if (uid_lease && packet -> subnet != uid_lease -> contain) {
|
if (uid_lease &&
|
||||||
|
(packet -> shared_network != uid_lease -> shared_network)) {
|
||||||
release_lease (uid_lease);
|
release_lease (uid_lease);
|
||||||
uid_lease = (struct lease *)0;
|
uid_lease = (struct lease *)0;
|
||||||
}
|
}
|
||||||
if (hw_lease && packet -> subnet != hw_lease -> contain) {
|
if (hw_lease &&
|
||||||
|
(packet -> shared_network != hw_lease -> shared_network)) {
|
||||||
release_lease (hw_lease);
|
release_lease (hw_lease);
|
||||||
hw_lease = (struct lease *)0;
|
hw_lease = (struct lease *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At this point, if ip_lease is nonzero, we can assign it to
|
/* At this point, if fixed_lease is nonzero, we can assign it to
|
||||||
this client. */
|
this client. */
|
||||||
lease = ip_lease;
|
if (fixed_lease)
|
||||||
|
lease = fixed_lease;
|
||||||
|
|
||||||
|
/* If we got a lease that matched the ip address and don't have
|
||||||
|
a better offer, use that; otherwise, release it. */
|
||||||
|
if (ip_lease) {
|
||||||
|
if (lease) {
|
||||||
|
release_lease (ip_lease);
|
||||||
|
} else {
|
||||||
|
lease = ip_lease;
|
||||||
|
lease -> host = (struct host_decl *)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we got a lease that matched the client identifier, we may want
|
/* If we got a lease that matched the client identifier, we may want
|
||||||
to use it, but if we already have a lease we like, we must free
|
to use it, but if we already have a lease we like, we must free
|
||||||
@@ -699,17 +873,59 @@ struct lease *find_lease (packet)
|
|||||||
if (uid_lease) {
|
if (uid_lease) {
|
||||||
if (lease) {
|
if (lease) {
|
||||||
release_lease (uid_lease);
|
release_lease (uid_lease);
|
||||||
} else
|
} else {
|
||||||
lease = uid_lease;
|
lease = uid_lease;
|
||||||
|
lease -> host = (struct host_decl *)0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The lease that matched the hardware address is treated likewise. */
|
/* The lease that matched the hardware address is treated likewise. */
|
||||||
if (hw_lease) {
|
if (hw_lease) {
|
||||||
if (lease) {
|
if (lease) {
|
||||||
release_lease (hw_lease);
|
release_lease (hw_lease);
|
||||||
} else
|
} else {
|
||||||
lease = hw_lease;
|
lease = hw_lease;
|
||||||
|
lease -> host = (struct host_decl *)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we found a host_decl but no matching address, try to
|
||||||
|
find a host_decl that has no address, and if there is one,
|
||||||
|
hang it off the lease so that we can use the supplied
|
||||||
|
options. */
|
||||||
|
if (lease && host && !lease -> host) {
|
||||||
|
for (; host; host = host -> n_ipaddr) {
|
||||||
|
if (!host -> fixed_addr) {
|
||||||
|
lease -> host = host;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search the provided host_decl structure list for an address that's on
|
||||||
|
the specified shared network. If one is found, mock up and return a
|
||||||
|
lease structure for it; otherwise return the null pointer. */
|
||||||
|
|
||||||
|
struct lease *mockup_lease (packet, hp)
|
||||||
|
struct packet *packet;
|
||||||
|
struct host_decl *hp;
|
||||||
|
{
|
||||||
|
static struct lease mock;
|
||||||
|
|
||||||
|
mock.subnet = find_host_for_network (&hp, &mock.ip_addr,
|
||||||
|
packet -> shared_network);
|
||||||
|
if (!mock.subnet)
|
||||||
|
return (struct lease *)0;
|
||||||
|
mock.next = mock.prev = (struct lease *)0;
|
||||||
|
mock.shared_network = mock.subnet -> shared_network;
|
||||||
|
mock.host = hp;
|
||||||
|
mock.uid_len = 0;
|
||||||
|
mock.hardware_addr.hlen = 0;
|
||||||
|
mock.uid = (unsigned char *)0;
|
||||||
|
mock.starts = mock.timestamp = mock.ends = MIN_TIME;
|
||||||
|
mock.flags = STATIC_LEASE;
|
||||||
|
return &mock;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user