]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
The DHCP server now responds to DHCPLEASEQUERY messages from agents using
authorTomek Mrugalski <tomek@isc.org>
Fri, 22 Apr 2011 13:30:14 +0000 (13:30 +0000)
committerTomek Mrugalski <tomek@isc.org>
Fri, 22 Apr 2011 13:30:14 +0000 (13:30 +0000)
IP addresses not covered by a subnet in configuration. The server also
returns vendor-class-id option, if client sent it. [ISC-Bugs #21094]

RELNOTES
server/dhcp.c
server/dhcpd.leases.5
server/dhcpleasequery.c

index 2e395a535fcd8525fa504aae83731db98d8128cb..779510c8e27b3525055e5ffe1761475cc3049a86 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -97,7 +97,13 @@ work on other platforms. Please report any problems and suggested fixes to
 - If a 'next-server' parameter is configured in a dynamic host record via
   OMAPI as a domain name, the syntax written to disk is now correctly parsed
   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.1rc1
 
index f398bfc2cd6875de86248510fa305fa0c94b6b09..cce0951f3a75c7b64dd0aed49f9ef439c7ab38b1 100644 (file)
@@ -2329,6 +2329,20 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
                option_chain_head_reference (&lt -> agent_options,
                                             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
         * cache them for renewal in case the relay agent can't supply them
         * when the client unicasts.  The options may be from an addressed
index ad8a22a0f63d3a3615a053e149d0884a3d4c2d82..f567bc60fa4c4c7dabd02906aef163b4d65de27d 100644 (file)
@@ -28,7 +28,7 @@
 .\" see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
 .\" ``http://www.nominum.com''.
 .\"
-.\" $Id: dhcpd.leases.5,v 1.14.24.1 2009/11/20 01:49:03 sar Exp $
+.\" $Id: dhcpd.leases.5,v 1.14.24.2 2011/04/22 13:30:14 tomasz Exp $
 .\"
 .TH dhcpd.leases 5
 .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
 \fIddns-fwd-name\fR or the \fIddns-client-fqdn\fR.
 .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 }
 The \fBon\fI statement records a list of statements to execute if a
 certain event occurs.   The possible events that can occur for an
index ab937d06102071b533c64f7a4e24ea01f678fd20..9daff89493fa81d3b9ce262e71b6b91c93ed1cc6 100644 (file)
@@ -17,9 +17,6 @@
 #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
  *       options it would for a DHCREQUEST message, if no Parameter
  *       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;
        const char *dhcp_msg_type_name;
        struct subnet *subnet;
+       struct group *relay_group;
        struct option_state *options;
        struct option_cache *oc;
        int allow_leasequery;
@@ -180,23 +178,26 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
        }
 
        /* 
-        * Set up our options, scope, and, um... stuff.
-        * This is basically copied from dhcpinform() in dhcp.c.
+        * Initially we use the 'giaddr' subnet options scope to determine if
+        * 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);
        memcpy(gip.iabuf, &packet->raw->giaddr, sizeof(packet->raw->giaddr));
 
        subnet = NULL;
        find_subnet(&subnet, gip, MDL);
-       if (subnet == NULL) {
-               log_info("%s: unknown subnet for address %s", 
-                        msgbuf, piaddr(gip));
-               return;
-       }
+       if (subnet != NULL)
+               relay_group = subnet->group;
+       else
+               relay_group = root_group;
+
+       subnet_dereference(&subnet, MDL);
 
        options = NULL;
        if (!option_state_allocate(&options, MDL)) {
-               subnet_dereference(&subnet, MDL);
                log_error("No memory for option state.");
                log_info("%s: out of memory, no reply sent", msgbuf);
                return;
@@ -209,8 +210,9 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
                                    packet->options,
                                    options,
                                    &global_scope,
-                                   subnet->group,
+                                   relay_group,
                                    NULL);
+
        for (i=packet->class_count-1; i>=0; i--) {
                execute_statements_in_scope(NULL,
                                            packet,
@@ -220,11 +222,9 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
                                            options,
                                            &global_scope,
                                            packet->classes[i]->group,
-                                           subnet->group);
+                                           relay_group);
        }
 
-       subnet_dereference(&subnet, MDL);
-
        /* 
         * Because LEASEQUERY has some privacy concerns, default to deny.
         */
@@ -245,7 +245,7 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
                option_state_dereference(&options, MDL);
                return;
        }
-           
+
 
        /* 
         * Copy out the client IP address.
@@ -385,6 +385,30 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
 
        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.
@@ -430,7 +454,11 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
                        (lease_duration / 8);
 
                if (time_renewal > cur_time) {
-                       time_renewal = htonl(time_renewal - cur_time);
+                       if (time_renewal < cur_time)
+                               time_renewal = 0;
+                       else
+                               time_renewal = htonl(time_renewal - cur_time);
+
                        if (!add_option(options, 
                                        DHO_DHCP_RENEWAL_TIME,
                                        &time_renewal, 
@@ -445,6 +473,7 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
 
                if (time_rebinding > cur_time) {
                        time_rebinding = htonl(time_rebinding - cur_time);
+
                        if (!add_option(options, 
                                        DHO_DHCP_REBINDING_TIME,
                                        &time_rebinding, 
@@ -458,6 +487,14 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
                }
 
                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);
                        if (!add_option(options, 
                                        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.
+                *
+                * 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) {