]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
- The 'hardware [ethernet|etc] ...;' parameter in host records has been
authorDavid Hankins <dhankins@isc.org>
Thu, 19 Nov 2009 23:57:41 +0000 (23:57 +0000)
committerDavid Hankins <dhankins@isc.org>
Thu, 19 Nov 2009 23:57:41 +0000 (23:57 +0000)
  extended to attempt to match DHCPv6 clients by the last octets of a
  DUID-LL or DUID-LLT provided by the client.  [ISC-Bugs #19599]

RELNOTES
doc/examples/dhcpd-dhcpv6.conf
server/confpars.c
server/dhcpv6.c

index fb919172c720d5bbe1e46c0a0f4d960fab03299a..9e9d4388620b788b7289e45d37fee760d56cf6bd 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -91,7 +91,11 @@ work on other platforms. Please report any problems and suggested fixes to
 - Processing the DHCP to DNS server transactions in an asyncrhonous fashion.
   The DHCP server or client can now continue with it's processing while
   awaiting replies from the DNS server.
-  
+
+- The 'hardware [ethernet|etc] ...;' parameter in host records has been
+  extended to attempt to match DHCPv6 clients by the last octets of a
+  DUID-LL or DUID-LLT provided by the client.
+
                        Changes since 4.1.0 (bug fixes)
 
 - Remove infinite loop in token_print_indent_concat().
index f0ca175adc514c328ff9a50ff6e12463dc3d1ca8..59836cf5c54ce3a8448d4aa1e7efb641a44b8912 100644 (file)
@@ -65,6 +65,14 @@ host myclient {
        ##if packet(0,1) = 1 { log(debug,"sol"); }
 }
 
+host otherclient {
+        # This host entry is hopefully matched if the client supplies a DUID-LL
+        # or DUID-LLT containing this MAC address.
+        hardware ethernet 01:00:80:a2:55:67:34;
+
+        fixed-address6 3ffe:501:ffff:100:4321;
+}
+
 # The subnet where the server is attached
 #  (i.e., the server has an address in this subnet)
 subnet6 3ffe:501:ffff:100::/64 {
index 1b3600a8a80fec629b9b4d50ad7c2b05841419df..0e9f2f5688049c2bdd10a2dfcf7b25063a9d744c 100644 (file)
@@ -551,16 +551,6 @@ int parse_statement (cfile, group, type, host_decl, declaration)
 
              case HARDWARE:
                next_token (&val, (unsigned *)0, cfile);
-#ifdef DHCPv6
-               if (local_family == AF_INET6) {
-                       parse_warn(cfile, "You can not use a hardware "
-                                         "parameter for DHCPv6 hosts. "
-                                         "Use the host-identifier parameter "
-                                         "instead.");
-                       skip_to_semi(cfile);
-                       break;
-               }
-#endif /* DHCPv6 */
                memset (&hardware, 0, sizeof hardware);
                if (host_decl && memcmp(&hardware, &(host_decl->interface),
                                        sizeof(hardware)) != 0) {
index 4ced893c07913bc9fc8eb4c2966be011d0d3cbf9..6cca58be18142b08e616319540bf6888ac3727ea 100644 (file)
@@ -140,7 +140,8 @@ static isc_result_t reply_process_send_prefix(struct reply_state *reply,
 static struct iasubopt *prefix_compare(struct reply_state *reply,
                                       struct iasubopt *alpha,
                                       struct iasubopt *beta);
-
+static int find_hosts_by_duid_chaddr(struct host_decl **host,
+                                    const struct data_string *client_id);
 /*
  * This function returns the time since DUID time start for the
  * given time_t value.
@@ -1277,15 +1278,21 @@ lease_to_client(struct data_string *reply_ret,
         * Find a host record that matches from the packet, if any, and is
         * valid for the shared network the client is on.
         */
-       if (find_hosts_by_option(&reply.host, packet, packet->options, MDL)) {
+       if (find_hosts_by_uid(&reply.host, client_id->data, client_id->len,
+                             MDL))
                seek_shared_host(&reply.host, reply.shared);
-       }
 
        if ((reply.host == NULL) &&
-           find_hosts_by_uid(&reply.host, client_id->data, client_id->len,
-                             MDL)) {
+           find_hosts_by_option(&reply.host, packet, packet->options, MDL))
+               seek_shared_host(&reply.host, reply.shared);
+
+       /*
+        * Check for 'hardware' matches last, as some of the synthesis methods
+        * are not considered to be as reliable.
+        */
+       if ((reply.host == NULL) &&
+           find_hosts_by_duid_chaddr(&reply.host, client_id))
                seek_shared_host(&reply.host, reply.shared);
-       }
 
        /* Process the client supplied IA's onto the reply buffer. */
        reply.ia_count = 0;
@@ -4611,6 +4618,10 @@ iterate_over_ia_na(struct data_string *reply_ret,
                if (!find_hosts_by_option(&packet_host, 
                                          packet, packet->options, MDL)) {
                        packet_host = NULL;
+
+                       if (!find_hosts_by_duid_chaddr(&packet_host,
+                                                      client_id))
+                               packet_host = NULL;
                }
        }
 
@@ -4713,7 +4724,8 @@ iterate_over_ia_na(struct data_string *reply_ret,
 
                /* 
                 * Now we need to figure out which host record matches
-                * this IA_NA and IAADDR.
+                * this IA_NA and IAADDR (encapsulated option contents
+                * matching a host record by option).
                 *
                 * XXX: We don't currently track IA_NA separately, but
                 *      we will need to do this!
@@ -5129,6 +5141,10 @@ iterate_over_ia_pd(struct data_string *reply_ret,
                if (!find_hosts_by_option(&packet_host, 
                                          packet, packet->options, MDL)) {
                        packet_host = NULL;
+
+                       if (!find_hosts_by_duid_chaddr(&packet_host,
+                                                      client_id))
+                               packet_host = NULL;
                }
        }
 
@@ -5181,7 +5197,8 @@ iterate_over_ia_pd(struct data_string *reply_ret,
 
                /* 
                 * Now we need to figure out which host record matches
-                * this IA_PD and IAPREFIX.
+                * this IA_PD and IAPREFIX (encapsulated option contents
+                * matching a host record by option).
                 *
                 * XXX: We don't currently track IA_PD separately, but
                 *      we will need to do this!
@@ -5915,5 +5932,78 @@ fixed_matches_shared(struct host_decl *host, struct shared_network *shared) {
        return matched;
 }
 
+/*
+ * find_host_by_duid_chaddr() synthesizes a DHCPv4-like 'hardware'
+ * parameter from a DHCPv6 supplied DUID (client-identifier option),
+ * and may seek to use client or relay supplied hardware addresses.
+ */
+static int
+find_hosts_by_duid_chaddr(struct host_decl **host,
+                         const struct data_string *client_id) {
+       static int once_htype;
+       int htype, hlen;
+       const unsigned char *chaddr;
+
+       /*
+        * The DUID-LL and DUID-LLT must have a 2-byte DUID type and 2-byte
+        * htype.
+        */
+       if (client_id->len < 4)
+               return 0;
+
+       /*
+        * The third and fourth octets of the DUID-LL and DUID-LLT
+        * is the hardware type, but in 16 bits.
+        */
+       htype = getUShort(client_id->data + 2);
+       hlen = 0;
+
+       /* The first two octets of the DUID identify the type. */
+       switch(getUShort(client_id->data)) {
+             case DUID_LLT:
+               if (client_id->len > 8) {
+                       hlen = client_id->len - 8;
+                       chaddr = client_id->data + 8;
+               }
+               break;
+
+             case DUID_LL:
+               /*
+                * Note that client_id->len must be greater than or equal
+                * to four to get to this point in the function.
+                */
+               hlen = client_id->len - 4;
+               chaddr = client_id->data + 4;
+               break;
+
+             default:
+               /* Silence compiler warnings. */
+               chaddr = NULL;
+               break;
+       }
+
+       if (hlen == 0)
+               return 0;
+
+       /*
+        * XXX: DHCPv6 gives a 16-bit field for the htype.  DHCPv4 gives an
+        * 8-bit field.  To change the semantics of the generic 'hardware'
+        * structure, we would have to adjust many DHCPv4 sources (from
+        * interface to DHCPv4 lease code), and we would have to update the
+        * 'hardware' config directive (probably being reverse compatible and
+        * providing a new upgrade/replacement primitive).  This is a little
+        * too much to change for now.  Hopefully we will revisit this before
+        * hardware types exceeding 8 bits are assigned.
+        */
+       if ((htype & 0xFF00) && !once_htype) {
+               once_htype = 1;
+               log_error("Attention: At least one client advertises a "
+                         "hardware type of %d, which exceeds the software "
+                         "limitation of 255.", htype);
+       }
+
+       return find_hosts_by_haddr(host, htype, chaddr, hlen, MDL);
+}
+
 #endif /* DHCPv6 */