mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-30 13:57:50 +00:00
Rearrange debugging dumps; disable them; add support for dhcp message; DHCPDECLINE now abandons the address that was declined, rather than releasing it for future use; DHCPINFORM function added but not implemented; NAK lease renewals on wrong network even if server id isn't ours; use DHCPACK, not DHCPOFFER, when acking a least; zap ciaddr on NAK; copy chaddr on NAK; make relay agent broadcast NAK; send relay response to server port; vendor class support
This commit is contained in:
225
dhcp.c
225
dhcp.c
@@ -1,9 +1,10 @@
|
|||||||
/* dhcp.c
|
/* dhcp.c
|
||||||
|
|
||||||
DHCP Protocol support. */
|
DHCP Protocol engine. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1995 The Internet Software Consortium. All rights reserved.
|
* Copyright (c) 1995, 1996 The Internet Software Consortium.
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -46,11 +47,11 @@ static char copyright[] =
|
|||||||
|
|
||||||
#include "dhcpd.h"
|
#include "dhcpd.h"
|
||||||
|
|
||||||
|
static char dhcp_message [256];
|
||||||
|
|
||||||
void dhcp (packet)
|
void dhcp (packet)
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
dump_packet (packet);
|
|
||||||
|
|
||||||
switch (packet -> packet_type) {
|
switch (packet -> packet_type) {
|
||||||
case DHCPDISCOVER:
|
case DHCPDISCOVER:
|
||||||
dhcpdiscover (packet);
|
dhcpdiscover (packet);
|
||||||
@@ -60,11 +61,18 @@ void dhcp (packet)
|
|||||||
dhcprequest (packet);
|
dhcprequest (packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DHCPDECLINE:
|
|
||||||
case DHCPRELEASE:
|
case DHCPRELEASE:
|
||||||
dhcprelease (packet);
|
dhcprelease (packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DHCPDECLINE:
|
||||||
|
dhcpdecline (packet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DHCPINFORM:
|
||||||
|
dhcpinform (packet);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -96,6 +104,33 @@ void dhcprequest (packet)
|
|||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
|
struct iaddr cip;
|
||||||
|
|
||||||
|
/* If a client on our local network wants to renew a lease on
|
||||||
|
an address off our local network, NAK it. */
|
||||||
|
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
||||||
|
cip.len = 4;
|
||||||
|
memcpy (cip.iabuf,
|
||||||
|
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
|
||||||
|
4);
|
||||||
|
if (!addr_eq (packet -> subnet -> net,
|
||||||
|
subnet_number (cip,
|
||||||
|
packet -> subnet -> netmask))) {
|
||||||
|
nak_lease (packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet -> raw -> ciaddr.s_addr) {
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Look for server identifier... */
|
/* Look for server identifier... */
|
||||||
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
|
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
|
||||||
@@ -109,17 +144,16 @@ void dhcprequest (packet)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* If no server identifier, drop it on the floor -
|
|
||||||
it's a protocol violation. */
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* If we didn't find a lease, try to allocate one... */
|
|
||||||
|
/* If we didn't find a lease, don't try to allocate one... */
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
nak_lease (packet);
|
nak_lease (packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
|
ack_lease (packet, lease, DHCPACK, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dhcprelease (packet)
|
void dhcprelease (packet)
|
||||||
@@ -127,12 +161,28 @@ void dhcprelease (packet)
|
|||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
|
|
||||||
/* If we didn't find a lease, try to allocate one... */
|
/* If we found a lease, release it. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
release_lease (lease);
|
release_lease (lease);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dhcpdecline (packet)
|
||||||
|
struct packet *packet;
|
||||||
|
{
|
||||||
|
struct lease *lease = find_lease (packet);
|
||||||
|
|
||||||
|
/* If we found a lease, mark it as unusable and complain. */
|
||||||
|
if (lease) {
|
||||||
|
abandon_lease (lease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dhcpinform (packet)
|
||||||
|
struct packet *packet;
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void nak_lease (packet)
|
void nak_lease (packet)
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
@@ -144,6 +194,7 @@ void nak_lease (packet)
|
|||||||
|
|
||||||
struct tree_cache *options [256];
|
struct tree_cache *options [256];
|
||||||
struct tree_cache dhcpnak_tree;
|
struct tree_cache dhcpnak_tree;
|
||||||
|
struct tree_cache dhcpmsg_tree;
|
||||||
|
|
||||||
memset (options, 0, sizeof options);
|
memset (options, 0, sizeof options);
|
||||||
memset (&outgoing, 0, sizeof outgoing);
|
memset (&outgoing, 0, sizeof outgoing);
|
||||||
@@ -158,28 +209,45 @@ void nak_lease (packet)
|
|||||||
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
|
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
|
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
|
/* Set DHCP_MESSAGE to whatever the message is */
|
||||||
|
options [DHO_DHCP_MESSAGE] = &dhcpmsg_tree;
|
||||||
|
options [DHO_DHCP_MESSAGE] -> value = dhcp_message;
|
||||||
|
options [DHO_DHCP_MESSAGE] -> len = strlen (dhcp_message);
|
||||||
|
options [DHO_DHCP_MESSAGE] -> buf_size = strlen (dhcp_message);
|
||||||
|
options [DHO_DHCP_MESSAGE] -> timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_MESSAGE] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
|
/* Do not use the client's requested parameter list. */
|
||||||
|
packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].len = 0;
|
||||||
|
packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].data =
|
||||||
|
(unsigned char *)0;
|
||||||
|
|
||||||
/* Set up the option buffer... */
|
/* Set up the option buffer... */
|
||||||
cons_options (packet, &outgoing, options, 0);
|
cons_options (packet, &outgoing, options, 0);
|
||||||
|
|
||||||
raw.ciaddr = packet -> raw -> ciaddr;
|
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
|
||||||
memcpy (&raw.siaddr, siaddr.iabuf, 4);
|
memcpy (&raw.siaddr, siaddr.iabuf, 4);
|
||||||
raw.giaddr = packet -> raw -> giaddr;
|
raw.giaddr = packet -> raw -> giaddr;
|
||||||
|
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
||||||
|
raw.hlen = packet -> raw -> hlen;
|
||||||
|
raw.htype = packet -> raw -> htype;
|
||||||
|
|
||||||
raw.xid = packet -> raw -> xid;
|
raw.xid = packet -> raw -> xid;
|
||||||
raw.secs = packet -> raw -> secs;
|
raw.secs = packet -> raw -> secs;
|
||||||
raw.flags = packet -> raw -> flags;
|
raw.flags = packet -> raw -> flags | htons (BOOTP_BROADCAST);
|
||||||
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... */
|
/* If this was gatewayed, send it back to the gateway.
|
||||||
if (raw.giaddr.s_addr)
|
Otherwise, broadcast it on the local network. */
|
||||||
|
if (raw.giaddr.s_addr) {
|
||||||
to.sin_addr = raw.giaddr;
|
to.sin_addr = raw.giaddr;
|
||||||
/* Otherwise, broadcast it on the local network. */
|
to.sin_port = server_port;
|
||||||
else
|
} else {
|
||||||
/* inet_aton ("204.254.239.2", &to.sin_addr); /* XXX bcst bug */
|
|
||||||
to.sin_addr.s_addr = INADDR_BROADCAST;
|
to.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
}
|
||||||
|
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
|
||||||
to.sin_family = AF_INET;
|
to.sin_family = AF_INET;
|
||||||
to.sin_len = sizeof to;
|
to.sin_len = sizeof to;
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
||||||
@@ -193,6 +261,12 @@ void nak_lease (packet)
|
|||||||
if (result < 0)
|
if (result < 0)
|
||||||
warn ("sendto: %m");
|
warn ("sendto: %m");
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
dump_packet (packet);
|
||||||
|
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
||||||
|
dump_packet (&outgoing);
|
||||||
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ack_lease (packet, lease, offer, when)
|
void ack_lease (packet, lease, offer, when)
|
||||||
@@ -215,6 +289,40 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
unsigned char lease_time_buf [4];
|
unsigned char lease_time_buf [4];
|
||||||
struct tree_cache lease_time_tree;
|
struct tree_cache lease_time_tree;
|
||||||
struct tree_cache server_id_tree;
|
struct tree_cache server_id_tree;
|
||||||
|
struct tree_cache vendor_class_tree;
|
||||||
|
struct tree_cache user_class_tree;
|
||||||
|
|
||||||
|
struct class *vendor_class, *user_class;
|
||||||
|
char *filename;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) {
|
||||||
|
vendor_class =
|
||||||
|
find_class (0,
|
||||||
|
packet ->
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER].data,
|
||||||
|
packet ->
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER].len);
|
||||||
|
} else {
|
||||||
|
vendor_class = (struct class *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet -> options [DHO_DHCP_USER_CLASS_ID].len) {
|
||||||
|
user_class =
|
||||||
|
find_class (0,
|
||||||
|
packet ->
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID].data,
|
||||||
|
packet ->
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID].len);
|
||||||
|
} else {
|
||||||
|
user_class = (struct class *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_class && user_class -> filename)
|
||||||
|
filename = user_class -> filename;
|
||||||
|
else if (vendor_class && vendor_class -> filename)
|
||||||
|
filename = vendor_class -> filename;
|
||||||
|
else filename = (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,
|
||||||
@@ -282,7 +390,10 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
|
|
||||||
/* Copy in the filename if given; otherwise, flag the filename
|
/* Copy in the filename if given; otherwise, flag the filename
|
||||||
buffer as available for options. */
|
buffer as available for options. */
|
||||||
bufs |= 1; /* XXX */
|
if (filename)
|
||||||
|
strncpy (raw.file, filename, sizeof raw.file);
|
||||||
|
else
|
||||||
|
bufs |= 1;
|
||||||
|
|
||||||
/* 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. */
|
||||||
@@ -295,6 +406,22 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
/* Start out with the subnet options... */
|
/* Start out with the subnet options... */
|
||||||
memcpy (options, packet -> subnet -> options, sizeof options);
|
memcpy (options, packet -> subnet -> options, sizeof options);
|
||||||
|
|
||||||
|
/* If we have a vendor class, install those options, superceding
|
||||||
|
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, superceding
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
/* Now put in options that override those. */
|
/* Now put in options that override those. */
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
|
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
|
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
|
||||||
@@ -310,6 +437,34 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> timeout = 0xFFFFFFFF;
|
options [DHO_DHCP_SERVER_IDENTIFIER] -> timeout = 0xFFFFFFFF;
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> tree = (struct tree *)0;
|
options [DHO_DHCP_SERVER_IDENTIFIER] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
|
/* 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 =
|
||||||
|
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 =
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
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] = &lease_time_tree;
|
||||||
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
||||||
@@ -325,8 +480,6 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
memcpy (&raw.siaddr, siaddr.iabuf, 4);
|
memcpy (&raw.siaddr, siaddr.iabuf, 4);
|
||||||
raw.giaddr = packet -> raw -> giaddr;
|
raw.giaddr = packet -> raw -> giaddr;
|
||||||
|
|
||||||
dump_packet (&outgoing);
|
|
||||||
|
|
||||||
raw.xid = packet -> raw -> xid;
|
raw.xid = packet -> raw -> xid;
|
||||||
raw.secs = packet -> raw -> secs;
|
raw.secs = packet -> raw -> secs;
|
||||||
raw.flags = packet -> raw -> flags;
|
raw.flags = packet -> raw -> flags;
|
||||||
@@ -334,18 +487,24 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
raw.op = BOOTREPLY;
|
raw.op = BOOTREPLY;
|
||||||
|
|
||||||
/* If this was gatewayed, send it back to the gateway... */
|
/* If this was gatewayed, send it back to the gateway... */
|
||||||
if (raw.giaddr.s_addr)
|
if (raw.giaddr.s_addr) {
|
||||||
to.sin_addr = raw.giaddr;
|
to.sin_addr = raw.giaddr;
|
||||||
|
to.sin_port = server_port;
|
||||||
|
|
||||||
/* If it comes from a client who already knows its address,
|
/* If it comes from a client who already knows its address,
|
||||||
sent it directly to that client. */
|
sent it directly to that client. */
|
||||||
else if (raw.ciaddr.s_addr && offer == DHCPACK)
|
} else if (raw.ciaddr.s_addr && offer == DHCPACK) {
|
||||||
to.sin_addr = packet -> raw -> ciaddr;
|
to.sin_addr = packet -> raw -> ciaddr;
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
|
||||||
/* Otherwise, if we can (we can't), unicast it to the client's
|
/* Otherwise, if we can (we can't), unicast it to the client's
|
||||||
hardware address */
|
hardware address */
|
||||||
|
|
||||||
/* Otherwise, broadcast it on the local network. */
|
/* Otherwise, broadcast it on the local network. */
|
||||||
else
|
} else {
|
||||||
/* inet_aton ("204.254.239.255", &to.sin_addr); /* XXX bcst bug */
|
|
||||||
to.sin_addr.s_addr = INADDR_BROADCAST;
|
to.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
}
|
||||||
|
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
to.sin_family = AF_INET;
|
to.sin_family = AF_INET;
|
||||||
@@ -360,6 +519,13 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
0, (struct sockaddr *)&to, sizeof to);
|
0, (struct sockaddr *)&to, sizeof to);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
warn ("sendto: %m");
|
warn ("sendto: %m");
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
dump_packet (packet);
|
||||||
|
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
||||||
|
dump_packet (&outgoing);
|
||||||
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lease *find_lease (packet)
|
struct lease *find_lease (packet)
|
||||||
@@ -415,6 +581,15 @@ struct lease *find_lease (packet)
|
|||||||
ip_lease -> ends >= cur_time)
|
ip_lease -> ends >= cur_time)
|
||||||
ip_lease = (struct lease *)0;
|
ip_lease = (struct lease *)0;
|
||||||
|
|
||||||
|
/* If we've already eliminated the lease, it wasn't there to
|
||||||
|
begin with. If we have come up with a matching lease,
|
||||||
|
set the message to bad network in case we have to throw it out. */
|
||||||
|
if (!ip_lease && !hw_lease && !uid_lease) {
|
||||||
|
strcpy (dhcp_message, "requested address not available");
|
||||||
|
} else {
|
||||||
|
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 subnet... */
|
||||||
if (ip_lease && packet -> subnet != ip_lease -> contain) {
|
if (ip_lease && packet -> subnet != ip_lease -> contain) {
|
||||||
release_lease (ip_lease);
|
release_lease (ip_lease);
|
||||||
|
225
server/dhcp.c
225
server/dhcp.c
@@ -1,9 +1,10 @@
|
|||||||
/* dhcp.c
|
/* dhcp.c
|
||||||
|
|
||||||
DHCP Protocol support. */
|
DHCP Protocol engine. */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1995 The Internet Software Consortium. All rights reserved.
|
* Copyright (c) 1995, 1996 The Internet Software Consortium.
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@@ -46,11 +47,11 @@ static char copyright[] =
|
|||||||
|
|
||||||
#include "dhcpd.h"
|
#include "dhcpd.h"
|
||||||
|
|
||||||
|
static char dhcp_message [256];
|
||||||
|
|
||||||
void dhcp (packet)
|
void dhcp (packet)
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
dump_packet (packet);
|
|
||||||
|
|
||||||
switch (packet -> packet_type) {
|
switch (packet -> packet_type) {
|
||||||
case DHCPDISCOVER:
|
case DHCPDISCOVER:
|
||||||
dhcpdiscover (packet);
|
dhcpdiscover (packet);
|
||||||
@@ -60,11 +61,18 @@ void dhcp (packet)
|
|||||||
dhcprequest (packet);
|
dhcprequest (packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DHCPDECLINE:
|
|
||||||
case DHCPRELEASE:
|
case DHCPRELEASE:
|
||||||
dhcprelease (packet);
|
dhcprelease (packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DHCPDECLINE:
|
||||||
|
dhcpdecline (packet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DHCPINFORM:
|
||||||
|
dhcpinform (packet);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -96,6 +104,33 @@ void dhcprequest (packet)
|
|||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
|
struct iaddr cip;
|
||||||
|
|
||||||
|
/* If a client on our local network wants to renew a lease on
|
||||||
|
an address off our local network, NAK it. */
|
||||||
|
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
|
||||||
|
cip.len = 4;
|
||||||
|
memcpy (cip.iabuf,
|
||||||
|
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
|
||||||
|
4);
|
||||||
|
if (!addr_eq (packet -> subnet -> net,
|
||||||
|
subnet_number (cip,
|
||||||
|
packet -> subnet -> netmask))) {
|
||||||
|
nak_lease (packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet -> raw -> ciaddr.s_addr) {
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Look for server identifier... */
|
/* Look for server identifier... */
|
||||||
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
|
if (packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len) {
|
||||||
@@ -109,17 +144,16 @@ void dhcprequest (packet)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* If no server identifier, drop it on the floor -
|
|
||||||
it's a protocol violation. */
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* If we didn't find a lease, try to allocate one... */
|
|
||||||
|
/* If we didn't find a lease, don't try to allocate one... */
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
nak_lease (packet);
|
nak_lease (packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
|
ack_lease (packet, lease, DHCPACK, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dhcprelease (packet)
|
void dhcprelease (packet)
|
||||||
@@ -127,12 +161,28 @@ void dhcprelease (packet)
|
|||||||
{
|
{
|
||||||
struct lease *lease = find_lease (packet);
|
struct lease *lease = find_lease (packet);
|
||||||
|
|
||||||
/* If we didn't find a lease, try to allocate one... */
|
/* If we found a lease, release it. */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
release_lease (lease);
|
release_lease (lease);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dhcpdecline (packet)
|
||||||
|
struct packet *packet;
|
||||||
|
{
|
||||||
|
struct lease *lease = find_lease (packet);
|
||||||
|
|
||||||
|
/* If we found a lease, mark it as unusable and complain. */
|
||||||
|
if (lease) {
|
||||||
|
abandon_lease (lease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dhcpinform (packet)
|
||||||
|
struct packet *packet;
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void nak_lease (packet)
|
void nak_lease (packet)
|
||||||
struct packet *packet;
|
struct packet *packet;
|
||||||
{
|
{
|
||||||
@@ -144,6 +194,7 @@ void nak_lease (packet)
|
|||||||
|
|
||||||
struct tree_cache *options [256];
|
struct tree_cache *options [256];
|
||||||
struct tree_cache dhcpnak_tree;
|
struct tree_cache dhcpnak_tree;
|
||||||
|
struct tree_cache dhcpmsg_tree;
|
||||||
|
|
||||||
memset (options, 0, sizeof options);
|
memset (options, 0, sizeof options);
|
||||||
memset (&outgoing, 0, sizeof outgoing);
|
memset (&outgoing, 0, sizeof outgoing);
|
||||||
@@ -158,28 +209,45 @@ void nak_lease (packet)
|
|||||||
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
|
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
|
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
|
/* Set DHCP_MESSAGE to whatever the message is */
|
||||||
|
options [DHO_DHCP_MESSAGE] = &dhcpmsg_tree;
|
||||||
|
options [DHO_DHCP_MESSAGE] -> value = dhcp_message;
|
||||||
|
options [DHO_DHCP_MESSAGE] -> len = strlen (dhcp_message);
|
||||||
|
options [DHO_DHCP_MESSAGE] -> buf_size = strlen (dhcp_message);
|
||||||
|
options [DHO_DHCP_MESSAGE] -> timeout = 0xFFFFFFFF;
|
||||||
|
options [DHO_DHCP_MESSAGE] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
|
/* Do not use the client's requested parameter list. */
|
||||||
|
packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].len = 0;
|
||||||
|
packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].data =
|
||||||
|
(unsigned char *)0;
|
||||||
|
|
||||||
/* Set up the option buffer... */
|
/* Set up the option buffer... */
|
||||||
cons_options (packet, &outgoing, options, 0);
|
cons_options (packet, &outgoing, options, 0);
|
||||||
|
|
||||||
raw.ciaddr = packet -> raw -> ciaddr;
|
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
|
||||||
memcpy (&raw.siaddr, siaddr.iabuf, 4);
|
memcpy (&raw.siaddr, siaddr.iabuf, 4);
|
||||||
raw.giaddr = packet -> raw -> giaddr;
|
raw.giaddr = packet -> raw -> giaddr;
|
||||||
|
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
||||||
|
raw.hlen = packet -> raw -> hlen;
|
||||||
|
raw.htype = packet -> raw -> htype;
|
||||||
|
|
||||||
raw.xid = packet -> raw -> xid;
|
raw.xid = packet -> raw -> xid;
|
||||||
raw.secs = packet -> raw -> secs;
|
raw.secs = packet -> raw -> secs;
|
||||||
raw.flags = packet -> raw -> flags;
|
raw.flags = packet -> raw -> flags | htons (BOOTP_BROADCAST);
|
||||||
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... */
|
/* If this was gatewayed, send it back to the gateway.
|
||||||
if (raw.giaddr.s_addr)
|
Otherwise, broadcast it on the local network. */
|
||||||
|
if (raw.giaddr.s_addr) {
|
||||||
to.sin_addr = raw.giaddr;
|
to.sin_addr = raw.giaddr;
|
||||||
/* Otherwise, broadcast it on the local network. */
|
to.sin_port = server_port;
|
||||||
else
|
} else {
|
||||||
/* inet_aton ("204.254.239.2", &to.sin_addr); /* XXX bcst bug */
|
|
||||||
to.sin_addr.s_addr = INADDR_BROADCAST;
|
to.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
}
|
||||||
|
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
|
||||||
to.sin_family = AF_INET;
|
to.sin_family = AF_INET;
|
||||||
to.sin_len = sizeof to;
|
to.sin_len = sizeof to;
|
||||||
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
||||||
@@ -193,6 +261,12 @@ void nak_lease (packet)
|
|||||||
if (result < 0)
|
if (result < 0)
|
||||||
warn ("sendto: %m");
|
warn ("sendto: %m");
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
dump_packet (packet);
|
||||||
|
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
||||||
|
dump_packet (&outgoing);
|
||||||
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ack_lease (packet, lease, offer, when)
|
void ack_lease (packet, lease, offer, when)
|
||||||
@@ -215,6 +289,40 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
unsigned char lease_time_buf [4];
|
unsigned char lease_time_buf [4];
|
||||||
struct tree_cache lease_time_tree;
|
struct tree_cache lease_time_tree;
|
||||||
struct tree_cache server_id_tree;
|
struct tree_cache server_id_tree;
|
||||||
|
struct tree_cache vendor_class_tree;
|
||||||
|
struct tree_cache user_class_tree;
|
||||||
|
|
||||||
|
struct class *vendor_class, *user_class;
|
||||||
|
char *filename;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) {
|
||||||
|
vendor_class =
|
||||||
|
find_class (0,
|
||||||
|
packet ->
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER].data,
|
||||||
|
packet ->
|
||||||
|
options [DHO_DHCP_CLASS_IDENTIFIER].len);
|
||||||
|
} else {
|
||||||
|
vendor_class = (struct class *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet -> options [DHO_DHCP_USER_CLASS_ID].len) {
|
||||||
|
user_class =
|
||||||
|
find_class (0,
|
||||||
|
packet ->
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID].data,
|
||||||
|
packet ->
|
||||||
|
options [DHO_DHCP_USER_CLASS_ID].len);
|
||||||
|
} else {
|
||||||
|
user_class = (struct class *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_class && user_class -> filename)
|
||||||
|
filename = user_class -> filename;
|
||||||
|
else if (vendor_class && vendor_class -> filename)
|
||||||
|
filename = vendor_class -> filename;
|
||||||
|
else filename = (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,
|
||||||
@@ -282,7 +390,10 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
|
|
||||||
/* Copy in the filename if given; otherwise, flag the filename
|
/* Copy in the filename if given; otherwise, flag the filename
|
||||||
buffer as available for options. */
|
buffer as available for options. */
|
||||||
bufs |= 1; /* XXX */
|
if (filename)
|
||||||
|
strncpy (raw.file, filename, sizeof raw.file);
|
||||||
|
else
|
||||||
|
bufs |= 1;
|
||||||
|
|
||||||
/* 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. */
|
||||||
@@ -295,6 +406,22 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
/* Start out with the subnet options... */
|
/* Start out with the subnet options... */
|
||||||
memcpy (options, packet -> subnet -> options, sizeof options);
|
memcpy (options, packet -> subnet -> options, sizeof options);
|
||||||
|
|
||||||
|
/* If we have a vendor class, install those options, superceding
|
||||||
|
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, superceding
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
/* Now put in options that override those. */
|
/* Now put in options that override those. */
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
|
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpoffer_tree;
|
||||||
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
|
options [DHO_DHCP_MESSAGE_TYPE] -> value = &offer;
|
||||||
@@ -310,6 +437,34 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> timeout = 0xFFFFFFFF;
|
options [DHO_DHCP_SERVER_IDENTIFIER] -> timeout = 0xFFFFFFFF;
|
||||||
options [DHO_DHCP_SERVER_IDENTIFIER] -> tree = (struct tree *)0;
|
options [DHO_DHCP_SERVER_IDENTIFIER] -> tree = (struct tree *)0;
|
||||||
|
|
||||||
|
/* 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 =
|
||||||
|
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 =
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
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] = &lease_time_tree;
|
||||||
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
options [DHO_DHCP_LEASE_TIME] -> value = lease_time_buf;
|
||||||
@@ -325,8 +480,6 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
memcpy (&raw.siaddr, siaddr.iabuf, 4);
|
memcpy (&raw.siaddr, siaddr.iabuf, 4);
|
||||||
raw.giaddr = packet -> raw -> giaddr;
|
raw.giaddr = packet -> raw -> giaddr;
|
||||||
|
|
||||||
dump_packet (&outgoing);
|
|
||||||
|
|
||||||
raw.xid = packet -> raw -> xid;
|
raw.xid = packet -> raw -> xid;
|
||||||
raw.secs = packet -> raw -> secs;
|
raw.secs = packet -> raw -> secs;
|
||||||
raw.flags = packet -> raw -> flags;
|
raw.flags = packet -> raw -> flags;
|
||||||
@@ -334,18 +487,24 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
raw.op = BOOTREPLY;
|
raw.op = BOOTREPLY;
|
||||||
|
|
||||||
/* If this was gatewayed, send it back to the gateway... */
|
/* If this was gatewayed, send it back to the gateway... */
|
||||||
if (raw.giaddr.s_addr)
|
if (raw.giaddr.s_addr) {
|
||||||
to.sin_addr = raw.giaddr;
|
to.sin_addr = raw.giaddr;
|
||||||
|
to.sin_port = server_port;
|
||||||
|
|
||||||
/* If it comes from a client who already knows its address,
|
/* If it comes from a client who already knows its address,
|
||||||
sent it directly to that client. */
|
sent it directly to that client. */
|
||||||
else if (raw.ciaddr.s_addr && offer == DHCPACK)
|
} else if (raw.ciaddr.s_addr && offer == DHCPACK) {
|
||||||
to.sin_addr = packet -> raw -> ciaddr;
|
to.sin_addr = packet -> raw -> ciaddr;
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
|
||||||
/* Otherwise, if we can (we can't), unicast it to the client's
|
/* Otherwise, if we can (we can't), unicast it to the client's
|
||||||
hardware address */
|
hardware address */
|
||||||
|
|
||||||
/* Otherwise, broadcast it on the local network. */
|
/* Otherwise, broadcast it on the local network. */
|
||||||
else
|
} else {
|
||||||
/* inet_aton ("204.254.239.255", &to.sin_addr); /* XXX bcst bug */
|
|
||||||
to.sin_addr.s_addr = INADDR_BROADCAST;
|
to.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
|
}
|
||||||
|
|
||||||
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
to.sin_port = htons (ntohs (server_port) + 1); /* XXX */
|
||||||
to.sin_family = AF_INET;
|
to.sin_family = AF_INET;
|
||||||
@@ -360,6 +519,13 @@ void ack_lease (packet, lease, offer, when)
|
|||||||
0, (struct sockaddr *)&to, sizeof to);
|
0, (struct sockaddr *)&to, sizeof to);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
warn ("sendto: %m");
|
warn ("sendto: %m");
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
dump_packet (packet);
|
||||||
|
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
||||||
|
dump_packet (&outgoing);
|
||||||
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lease *find_lease (packet)
|
struct lease *find_lease (packet)
|
||||||
@@ -415,6 +581,15 @@ struct lease *find_lease (packet)
|
|||||||
ip_lease -> ends >= cur_time)
|
ip_lease -> ends >= cur_time)
|
||||||
ip_lease = (struct lease *)0;
|
ip_lease = (struct lease *)0;
|
||||||
|
|
||||||
|
/* If we've already eliminated the lease, it wasn't there to
|
||||||
|
begin with. If we have come up with a matching lease,
|
||||||
|
set the message to bad network in case we have to throw it out. */
|
||||||
|
if (!ip_lease && !hw_lease && !uid_lease) {
|
||||||
|
strcpy (dhcp_message, "requested address not available");
|
||||||
|
} else {
|
||||||
|
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 subnet... */
|
||||||
if (ip_lease && packet -> subnet != ip_lease -> contain) {
|
if (ip_lease && packet -> subnet != ip_lease -> contain) {
|
||||||
release_lease (ip_lease);
|
release_lease (ip_lease);
|
||||||
|
Reference in New Issue
Block a user