2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-29 13:28:14 +00:00

The DHCP server now responds to DHCPLEASEQUERY messages from agents using

IP addresses not covered by a subnet in configuration. Server also returns
vendor-class-id option, if client sent it. [ISC-Bugs #21094]
This commit is contained in:
Tomek Mrugalski 2011-04-22 13:21:35 +00:00
parent 023fbaa03e
commit 656b1ecebe
4 changed files with 110 additions and 18 deletions

View File

@ -99,6 +99,13 @@ work on other platforms. Please report any problems and suggested fixes to
OMAPI as a domain name, the syntax written to disk is now correctly parsed OMAPI as a domain name, the syntax written to disk is now correctly parsed
upon restart. [ISC-Bugs #22266] upon restart. [ISC-Bugs #22266]
- The DHCP server now responds to DHCPLEASEQUERY messages from agents using
IP addresses not covered by a subnet in configuration. Whether or not to
respond to such an agent is still governed by the 'allow leasequery;'
configuration parameter, in the case of an agent not covered by a configured
subnet the root configuration area is examined. Server now also returns
vendor-class-id option, if client sent it. [ISC-Bugs #21094]
Changes since 4.2.0 Changes since 4.2.0
- Documentation cleanup covering multiple tickets - Documentation cleanup covering multiple tickets

View File

@ -2329,6 +2329,20 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
option_chain_head_reference (&lt -> agent_options, option_chain_head_reference (&lt -> agent_options,
lease -> agent_options, MDL); lease -> agent_options, MDL);
/* Save the vendor-class-identifier for DHCPLEASEQUERY. */
oc = lookup_option(&dhcp_universe, packet->options,
DHO_VENDOR_CLASS_IDENTIFIER);
if (oc != NULL &&
evaluate_option_cache(&d1, packet, NULL, NULL, packet->options,
NULL, &lease->scope, oc, MDL)) {
if (d1.len != 0) {
bind_ds_value(&lease->scope, "vendor-class-identifier",
&d1);
}
data_string_forget(&d1, MDL);
}
/* If we got relay agent information options from the packet, then /* If we got relay agent information options from the packet, then
* cache them for renewal in case the relay agent can't supply them * cache them for renewal in case the relay agent can't supply them
* when the client unicasts. The options may be from an addressed * when the client unicasts. The options may be from an addressed

View File

@ -28,7 +28,7 @@
.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see
.\" ``http://www.nominum.com''. .\" ``http://www.nominum.com''.
.\" .\"
.\" $Id: dhcpd.leases.5,v 1.15 2009/11/24 02:06:57 sar Exp $ .\" $Id: dhcpd.leases.5,v 1.16 2011/04/22 13:21:35 tomasz Exp $
.\" .\"
.TH dhcpd.leases 5 .TH dhcpd.leases 5
.SH NAME .SH NAME
@ -241,6 +241,11 @@ variable will record the name that the DHCP server used for the PTR
record. The name to which the PTR record points will be either the record. The name to which the PTR record points will be either the
\fIddns-fwd-name\fR or the \fIddns-client-fqdn\fR. \fIddns-fwd-name\fR or the \fIddns-client-fqdn\fR.
.PP .PP
.B The \fIvendor-class-identifier\fB variable
.PP
The server retains the client-supplied Vendor Class Identifier option
for informational purposes, and to render them in DHCPLEASEQUERY responses.
.PP
.B on \fIevents\fB { \fIstatements...\fB } .B on \fIevents\fB { \fIstatements...\fB }
The \fBon\fI statement records a list of statements to execute if a The \fBon\fI statement records a list of statements to execute if a
certain event occurs. The possible events that can occur for an certain event occurs. The possible events that can occur for an

View File

@ -17,9 +17,6 @@
#include "dhcpd.h" #include "dhcpd.h"
/* /*
* TODO: RFC4388 specifies that the server SHOULD store the
* vendor-class-id.
*
* TODO: RFC4388 specifies that the server SHOULD return the same * TODO: RFC4388 specifies that the server SHOULD return the same
* options it would for a DHCREQUEST message, if no Parameter * options it would for a DHCREQUEST message, if no Parameter
* Request List option (option 55) is passed. We do not do that. * Request List option (option 55) is passed. We do not do that.
@ -145,6 +142,7 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
unsigned char dhcpMsgType; unsigned char dhcpMsgType;
const char *dhcp_msg_type_name; const char *dhcp_msg_type_name;
struct subnet *subnet; struct subnet *subnet;
struct group *relay_group;
struct option_state *options; struct option_state *options;
struct option_cache *oc; struct option_cache *oc;
int allow_leasequery; int allow_leasequery;
@ -180,23 +178,26 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
} }
/* /*
* Set up our options, scope, and, um... stuff. * Initially we use the 'giaddr' subnet options scope to determine if
* This is basically copied from dhcpinform() in dhcp.c. * the giaddr-identified relay agent is permitted to perform a
* leasequery. The subnet is not required, and may be omitted, in
* which case we are essentially interrogating the root options class
* to find a globally permit.
*/ */
gip.len = sizeof(packet->raw->giaddr); gip.len = sizeof(packet->raw->giaddr);
memcpy(gip.iabuf, &packet->raw->giaddr, sizeof(packet->raw->giaddr)); memcpy(gip.iabuf, &packet->raw->giaddr, sizeof(packet->raw->giaddr));
subnet = NULL; subnet = NULL;
find_subnet(&subnet, gip, MDL); find_subnet(&subnet, gip, MDL);
if (subnet == NULL) { if (subnet != NULL)
log_info("%s: unknown subnet for address %s", relay_group = subnet->group;
msgbuf, piaddr(gip)); else
return; relay_group = root_group;
}
subnet_dereference(&subnet, MDL);
options = NULL; options = NULL;
if (!option_state_allocate(&options, MDL)) { if (!option_state_allocate(&options, MDL)) {
subnet_dereference(&subnet, MDL);
log_error("No memory for option state."); log_error("No memory for option state.");
log_info("%s: out of memory, no reply sent", msgbuf); log_info("%s: out of memory, no reply sent", msgbuf);
return; return;
@ -209,8 +210,9 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
packet->options, packet->options,
options, options,
&global_scope, &global_scope,
subnet->group, relay_group,
NULL); NULL);
for (i=packet->class_count-1; i>=0; i--) { for (i=packet->class_count-1; i>=0; i--) {
execute_statements_in_scope(NULL, execute_statements_in_scope(NULL,
packet, packet,
@ -220,11 +222,9 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
options, options,
&global_scope, &global_scope,
packet->classes[i]->group, packet->classes[i]->group,
subnet->group); relay_group);
} }
subnet_dereference(&subnet, MDL);
/* /*
* Because LEASEQUERY has some privacy concerns, default to deny. * Because LEASEQUERY has some privacy concerns, default to deny.
*/ */
@ -385,6 +385,30 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
if (dhcpMsgType == DHCPLEASEACTIVE) if (dhcpMsgType == DHCPLEASEACTIVE)
{ {
/*
* RFC 4388 uses the PRL to request options for the agent to
* receive that are "about" the client. It is confusing
* because in some cases it wants to know what was sent to
* the client (lease times, adjusted), and in others it wants
* to know information the client sent. You're supposed to
* know this on a case-by-case basis.
*
* "Name servers", "domain name", and the like from the relay
* agent's scope seems less than useful. Our options are to
* restart the option cache from the lease's best point of view
* (execute statements from the lease pool's group), or to
* simply restart the option cache from empty.
*
* I think restarting the option cache from empty best
* approaches RFC 4388's intent; specific options are included.
*/
option_state_dereference(&options, MDL);
if (!option_state_allocate(&options, MDL)) {
log_error("%s: out of memory, no reply sent", msgbuf);
lease_dereference(&lease, MDL);
return;
}
/* /*
* Set the hardware address fields. * Set the hardware address fields.
@ -430,7 +454,11 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
(lease_duration / 8); (lease_duration / 8);
if (time_renewal > cur_time) { if (time_renewal > cur_time) {
if (time_renewal < cur_time)
time_renewal = 0;
else
time_renewal = htonl(time_renewal - cur_time); time_renewal = htonl(time_renewal - cur_time);
if (!add_option(options, if (!add_option(options,
DHO_DHCP_RENEWAL_TIME, DHO_DHCP_RENEWAL_TIME,
&time_renewal, &time_renewal,
@ -445,6 +473,7 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
if (time_rebinding > cur_time) { if (time_rebinding > cur_time) {
time_rebinding = htonl(time_rebinding - cur_time); time_rebinding = htonl(time_rebinding - cur_time);
if (!add_option(options, if (!add_option(options,
DHO_DHCP_REBINDING_TIME, DHO_DHCP_REBINDING_TIME,
&time_rebinding, &time_rebinding,
@ -458,6 +487,14 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
} }
if (lease->ends > cur_time) { if (lease->ends > cur_time) {
if (time_expiry < cur_time) {
log_error("Impossible condition at %s:%d.",
MDL);
option_state_dereference(&options, MDL);
lease_dereference(&lease, MDL);
return;
}
time_expiry = htonl(lease->ends - cur_time); time_expiry = htonl(lease->ends - cur_time);
if (!add_option(options, if (!add_option(options,
DHO_DHCP_LEASE_TIME, DHO_DHCP_LEASE_TIME,
@ -471,9 +508,38 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
} }
} }
/* Supply the Vendor-Class-Identifier. */
if (lease->scope != NULL) {
struct data_string vendor_class;
memset(&vendor_class, 0, sizeof(vendor_class));
if (find_bound_string(&vendor_class, lease->scope,
"vendor-class-identifier")) {
if (!add_option(options,
DHO_VENDOR_CLASS_IDENTIFIER,
(void *)vendor_class.data,
vendor_class.len)) {
option_state_dereference(&options,
MDL);
lease_dereference(&lease, MDL);
log_error("%s: error adding vendor "
"class identifier, no reply "
"sent", msgbuf);
data_string_forget(&vendor_class, MDL);
return;
}
data_string_forget(&vendor_class, MDL);
}
}
/* /*
* Set the relay agent info. * Set the relay agent info.
*
* Note that because agent info is appended without regard
* to the PRL in cons_options(), this will be sent as the
* last option in the packet whether it is listed on PRL or
* not.
*/ */
if (lease->agent_options != NULL) { if (lease->agent_options != NULL) {