summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hankins <dhankins@isc.org>2009-11-19 23:57:41 +0000
committerDavid Hankins <dhankins@isc.org>2009-11-19 23:57:41 +0000
commitc900c5b249bfcb93a5dc8d463caeb78256574779 (patch)
tree868993e0bb8631f9b81de83b983bd8f34c320998
parent8fa0112dd11ee301046b42fe463074b067e61a35 (diff)
downloadisc-dhcp-c900c5b249bfcb93a5dc8d463caeb78256574779.tar.gz
- 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. [ISC-Bugs #19599]
-rw-r--r--RELNOTES6
-rw-r--r--doc/examples/dhcpd-dhcpv6.conf8
-rw-r--r--server/confpars.c10
-rw-r--r--server/dhcpv6.c106
4 files changed, 111 insertions, 19 deletions
diff --git a/RELNOTES b/RELNOTES
index fb919172..9e9d4388 100644
--- 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().
diff --git a/doc/examples/dhcpd-dhcpv6.conf b/doc/examples/dhcpd-dhcpv6.conf
index f0ca175a..59836cf5 100644
--- a/doc/examples/dhcpd-dhcpv6.conf
+++ b/doc/examples/dhcpd-dhcpv6.conf
@@ -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 {
diff --git a/server/confpars.c b/server/confpars.c
index 1b3600a8..0e9f2f56 100644
--- a/server/confpars.c
+++ b/server/confpars.c
@@ -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) {
diff --git a/server/dhcpv6.c b/server/dhcpv6.c
index 4ced893c..6cca58be 100644
--- a/server/dhcpv6.c
+++ b/server/dhcpv6.c
@@ -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 */