2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-09-01 14:55:30 +00:00

Don't assume routed packets are local; fix up dhcp_nak generation

This commit is contained in:
Ted Lemon
1996-05-23 01:59:38 +00:00
parent 4095edc958
commit 15c00bbad9
2 changed files with 128 additions and 66 deletions

97
dhcp.c
View File

@@ -84,7 +84,7 @@ void dhcp (packet)
void dhcpdiscover (packet) void dhcpdiscover (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet, packet -> shared_network);
struct host_decl *hp; struct host_decl *hp;
note ("DHCPDISCOVER from %s", note ("DHCPDISCOVER from %s",
@@ -92,6 +92,13 @@ void dhcpdiscover (packet)
packet -> raw -> hlen, packet -> raw -> hlen,
packet -> raw -> chaddr)); packet -> raw -> chaddr));
/* Sourceless packets don't make sense here. */
if (!packet -> shared_network) {
note ("Packet from unknown subnet: %s",
inet_ntoa (packet -> raw -> giaddr));
return;
}
/* 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 -> shared_network -> last_lease; lease = packet -> shared_network -> last_lease;
@@ -136,7 +143,7 @@ void dhcpdiscover (packet)
void dhcprequest (packet) void dhcprequest (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease;
struct iaddr cip; struct iaddr cip;
struct subnet *subnet; struct subnet *subnet;
struct lease *ip_lease; struct lease *ip_lease;
@@ -151,21 +158,54 @@ void dhcprequest (packet)
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4); memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
} }
/* Find the lease that matches the address requested by the
client. */
subnet = find_subnet (cip);
lease = find_lease (packet, (subnet
? subnet -> shared_network
: (struct shared_network *)0));
note ("DHCPREQUEST for %s from %s", note ("DHCPREQUEST for %s from %s",
piaddr (cip), 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));
/* If a client on our local network wants to renew a lease on /* If a client on a given network wants to request a lease on
an address off our local network, NAK it. */ an address on a different network, NAK it. If the Requested
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { Address option was used, the protocol says that it must have
subnet = find_grouped_subnet (packet -> shared_network, cip); been broadcast, so we can trust the source network information.
if (!subnet) {
nak_lease (packet, &cip); If ciaddr was specified and Requested Address was not, then
return; we really only know for sure what network a packet came from
if it came through a BOOTP gateway - if it came through an
IP router, we'll just have to assume that it's cool.
This violates the protocol spec in the case that the client
is in the REBINDING state and broadcasts a DHCPREQUEST on
the local wire. We're supposed to check ciaddr for
validity in that case, but if the packet was unicast
through a router from a client in the RENEWING state, it
would look exactly the same to us and it would be very
bad to send a DHCPNAK. I think we just have to live with
this. */
if ((packet -> raw -> ciaddr.s_addr &&
packet -> raw -> giaddr.s_addr) ||
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
/* If we don't know where it came from but we do know
where it claims to have come from, it didn't come
from there. Fry it. */
if (!packet -> shared_network) {
subnet = find_subnet (cip);
if (subnet) {
nak_lease (packet, &cip);
return;
}
} }
} else if (packet -> raw -> ciaddr.s_addr) {
/* If we do know where it came from and we don't know
where it claims to have come from, same deal - fry it. */
subnet = find_grouped_subnet (packet -> shared_network, cip); subnet = find_grouped_subnet (packet -> shared_network, cip);
if (!subnet) { if (!subnet) {
nak_lease (packet, &cip); nak_lease (packet, &cip);
@@ -176,8 +216,7 @@ 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 we own the lease that the client is asking for, /* If we own the lease that the client is asking for,
and it's already been assigned to the client, and it's already been assigned to the client, ack it. */
ack it regardless. */
if ((lease -> uid_len && lease -> uid_len == if ((lease -> uid_len && lease -> uid_len ==
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len && packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len &&
!memcmp (packet -> options !memcmp (packet -> options
@@ -202,23 +241,14 @@ void dhcprequest (packet)
release_lease (lease); release_lease (lease);
return; return;
} }
} else {
return;
} }
return;
/* If we didn't find a lease, don't try to allocate one... */
if (!lease) {
nak_lease (packet, &cip);
return;
}
ack_lease (packet, lease, DHCPACK, 0);
} }
void dhcprelease (packet) void dhcprelease (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet, packet -> shared_network);
note ("DHCPRELEASE of %s from %s", note ("DHCPRELEASE of %s from %s",
inet_ntoa (packet -> raw -> ciaddr), inet_ntoa (packet -> raw -> ciaddr),
@@ -235,7 +265,7 @@ void dhcprelease (packet)
void dhcpdecline (packet) void dhcpdecline (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet, packet -> shared_network);
struct iaddr cip; struct iaddr cip;
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
@@ -748,8 +778,9 @@ void ack_lease (packet, lease, offer, when)
warn ("sendpkt: %m"); warn ("sendpkt: %m");
} }
struct lease *find_lease (packet) struct lease *find_lease (packet, share)
struct packet *packet; struct packet *packet;
struct shared_network *share;
{ {
struct lease *uid_lease, *ip_lease, *hw_lease; struct lease *uid_lease, *ip_lease, *hw_lease;
struct lease *lease = (struct lease *)0; struct lease *lease = (struct lease *)0;
@@ -768,7 +799,7 @@ struct lease *find_lease (packet)
[DHO_DHCP_CLIENT_IDENTIFIER].len); [DHO_DHCP_CLIENT_IDENTIFIER].len);
if (hp) { if (hp) {
host = hp; host = hp;
fixed_lease = mockup_lease (packet, hp); fixed_lease = mockup_lease (packet, share, hp);
} else } else
uid_lease = find_lease_by_uid uid_lease = find_lease_by_uid
(packet -> options (packet -> options
@@ -788,7 +819,7 @@ struct lease *find_lease (packet)
packet -> raw -> hlen); packet -> raw -> hlen);
if (hp) { if (hp) {
host = hp; /* Save it for later. */ host = hp; /* Save it for later. */
fixed_lease = mockup_lease (packet, hp); fixed_lease = mockup_lease (packet, share, hp);
} }
} }
@@ -839,17 +870,17 @@ struct lease *find_lease (packet)
/* Now eliminate leases that are on the wrong network... */ /* Now eliminate leases that are on the wrong network... */
if (ip_lease && if (ip_lease &&
(packet -> shared_network != ip_lease -> shared_network)) { (share != 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 && if (uid_lease &&
(packet -> shared_network != uid_lease -> shared_network)) { (share != 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 && if (hw_lease &&
(packet -> shared_network != hw_lease -> shared_network)) { (share != hw_lease -> shared_network)) {
release_lease (hw_lease); release_lease (hw_lease);
hw_lease = (struct lease *)0; hw_lease = (struct lease *)0;
} }
@@ -912,14 +943,14 @@ struct lease *find_lease (packet)
the specified shared network. If one is found, mock up and return a the specified shared network. If one is found, mock up and return a
lease structure for it; otherwise return the null pointer. */ lease structure for it; otherwise return the null pointer. */
struct lease *mockup_lease (packet, hp) struct lease *mockup_lease (packet, share, hp)
struct packet *packet; struct packet *packet;
struct shared_network *share;
struct host_decl *hp; struct host_decl *hp;
{ {
static struct lease mock; static struct lease mock;
mock.subnet = find_host_for_network (&hp, &mock.ip_addr, mock.subnet = find_host_for_network (&hp, &mock.ip_addr, share);
packet -> shared_network);
if (!mock.subnet) if (!mock.subnet)
return (struct lease *)0; return (struct lease *)0;
mock.next = mock.prev = (struct lease *)0; mock.next = mock.prev = (struct lease *)0;

View File

@@ -84,7 +84,7 @@ void dhcp (packet)
void dhcpdiscover (packet) void dhcpdiscover (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet, packet -> shared_network);
struct host_decl *hp; struct host_decl *hp;
note ("DHCPDISCOVER from %s", note ("DHCPDISCOVER from %s",
@@ -92,6 +92,13 @@ void dhcpdiscover (packet)
packet -> raw -> hlen, packet -> raw -> hlen,
packet -> raw -> chaddr)); packet -> raw -> chaddr));
/* Sourceless packets don't make sense here. */
if (!packet -> shared_network) {
note ("Packet from unknown subnet: %s",
inet_ntoa (packet -> raw -> giaddr));
return;
}
/* 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 -> shared_network -> last_lease; lease = packet -> shared_network -> last_lease;
@@ -136,7 +143,7 @@ void dhcpdiscover (packet)
void dhcprequest (packet) void dhcprequest (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease;
struct iaddr cip; struct iaddr cip;
struct subnet *subnet; struct subnet *subnet;
struct lease *ip_lease; struct lease *ip_lease;
@@ -151,21 +158,54 @@ void dhcprequest (packet)
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4); memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
} }
/* Find the lease that matches the address requested by the
client. */
subnet = find_subnet (cip);
lease = find_lease (packet, (subnet
? subnet -> shared_network
: (struct shared_network *)0));
note ("DHCPREQUEST for %s from %s", note ("DHCPREQUEST for %s from %s",
piaddr (cip), 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));
/* If a client on our local network wants to renew a lease on /* If a client on a given network wants to request a lease on
an address off our local network, NAK it. */ an address on a different network, NAK it. If the Requested
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { Address option was used, the protocol says that it must have
subnet = find_grouped_subnet (packet -> shared_network, cip); been broadcast, so we can trust the source network information.
if (!subnet) {
nak_lease (packet, &cip); If ciaddr was specified and Requested Address was not, then
return; we really only know for sure what network a packet came from
if it came through a BOOTP gateway - if it came through an
IP router, we'll just have to assume that it's cool.
This violates the protocol spec in the case that the client
is in the REBINDING state and broadcasts a DHCPREQUEST on
the local wire. We're supposed to check ciaddr for
validity in that case, but if the packet was unicast
through a router from a client in the RENEWING state, it
would look exactly the same to us and it would be very
bad to send a DHCPNAK. I think we just have to live with
this. */
if ((packet -> raw -> ciaddr.s_addr &&
packet -> raw -> giaddr.s_addr) ||
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
/* If we don't know where it came from but we do know
where it claims to have come from, it didn't come
from there. Fry it. */
if (!packet -> shared_network) {
subnet = find_subnet (cip);
if (subnet) {
nak_lease (packet, &cip);
return;
}
} }
} else if (packet -> raw -> ciaddr.s_addr) {
/* If we do know where it came from and we don't know
where it claims to have come from, same deal - fry it. */
subnet = find_grouped_subnet (packet -> shared_network, cip); subnet = find_grouped_subnet (packet -> shared_network, cip);
if (!subnet) { if (!subnet) {
nak_lease (packet, &cip); nak_lease (packet, &cip);
@@ -176,8 +216,7 @@ 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 we own the lease that the client is asking for, /* If we own the lease that the client is asking for,
and it's already been assigned to the client, and it's already been assigned to the client, ack it. */
ack it regardless. */
if ((lease -> uid_len && lease -> uid_len == if ((lease -> uid_len && lease -> uid_len ==
packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len && packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len &&
!memcmp (packet -> options !memcmp (packet -> options
@@ -202,23 +241,14 @@ void dhcprequest (packet)
release_lease (lease); release_lease (lease);
return; return;
} }
} else {
return;
} }
return;
/* If we didn't find a lease, don't try to allocate one... */
if (!lease) {
nak_lease (packet, &cip);
return;
}
ack_lease (packet, lease, DHCPACK, 0);
} }
void dhcprelease (packet) void dhcprelease (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet, packet -> shared_network);
note ("DHCPRELEASE of %s from %s", note ("DHCPRELEASE of %s from %s",
inet_ntoa (packet -> raw -> ciaddr), inet_ntoa (packet -> raw -> ciaddr),
@@ -235,7 +265,7 @@ void dhcprelease (packet)
void dhcpdecline (packet) void dhcpdecline (packet)
struct packet *packet; struct packet *packet;
{ {
struct lease *lease = find_lease (packet); struct lease *lease = find_lease (packet, packet -> shared_network);
struct iaddr cip; struct iaddr cip;
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) { if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
@@ -748,8 +778,9 @@ void ack_lease (packet, lease, offer, when)
warn ("sendpkt: %m"); warn ("sendpkt: %m");
} }
struct lease *find_lease (packet) struct lease *find_lease (packet, share)
struct packet *packet; struct packet *packet;
struct shared_network *share;
{ {
struct lease *uid_lease, *ip_lease, *hw_lease; struct lease *uid_lease, *ip_lease, *hw_lease;
struct lease *lease = (struct lease *)0; struct lease *lease = (struct lease *)0;
@@ -768,7 +799,7 @@ struct lease *find_lease (packet)
[DHO_DHCP_CLIENT_IDENTIFIER].len); [DHO_DHCP_CLIENT_IDENTIFIER].len);
if (hp) { if (hp) {
host = hp; host = hp;
fixed_lease = mockup_lease (packet, hp); fixed_lease = mockup_lease (packet, share, hp);
} else } else
uid_lease = find_lease_by_uid uid_lease = find_lease_by_uid
(packet -> options (packet -> options
@@ -788,7 +819,7 @@ struct lease *find_lease (packet)
packet -> raw -> hlen); packet -> raw -> hlen);
if (hp) { if (hp) {
host = hp; /* Save it for later. */ host = hp; /* Save it for later. */
fixed_lease = mockup_lease (packet, hp); fixed_lease = mockup_lease (packet, share, hp);
} }
} }
@@ -839,17 +870,17 @@ struct lease *find_lease (packet)
/* Now eliminate leases that are on the wrong network... */ /* Now eliminate leases that are on the wrong network... */
if (ip_lease && if (ip_lease &&
(packet -> shared_network != ip_lease -> shared_network)) { (share != 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 && if (uid_lease &&
(packet -> shared_network != uid_lease -> shared_network)) { (share != 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 && if (hw_lease &&
(packet -> shared_network != hw_lease -> shared_network)) { (share != hw_lease -> shared_network)) {
release_lease (hw_lease); release_lease (hw_lease);
hw_lease = (struct lease *)0; hw_lease = (struct lease *)0;
} }
@@ -912,14 +943,14 @@ struct lease *find_lease (packet)
the specified shared network. If one is found, mock up and return a the specified shared network. If one is found, mock up and return a
lease structure for it; otherwise return the null pointer. */ lease structure for it; otherwise return the null pointer. */
struct lease *mockup_lease (packet, hp) struct lease *mockup_lease (packet, share, hp)
struct packet *packet; struct packet *packet;
struct shared_network *share;
struct host_decl *hp; struct host_decl *hp;
{ {
static struct lease mock; static struct lease mock;
mock.subnet = find_host_for_network (&hp, &mock.ip_addr, mock.subnet = find_host_for_network (&hp, &mock.ip_addr, share);
packet -> shared_network);
if (!mock.subnet) if (!mock.subnet)
return (struct lease *)0; return (struct lease *)0;
mock.next = mock.prev = (struct lease *)0; mock.next = mock.prev = (struct lease *)0;