summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Markwalder <tmark@isc.org>2017-04-26 14:09:31 -0400
committerThomas Markwalder <tmark@isc.org>2017-04-26 14:09:31 -0400
commit417b7b4a6dfd593a71851f4ff8807089d28d3820 (patch)
tree52eadc9d9c4c012b4db6ad50595172f7ecf6f5a6
parent48ffe4b8d366792e6fbc0eaa7a8dc5be5c469213 (diff)
downloadisc-dhcp-417b7b4a6dfd593a71851f4ff8807089d28d3820.tar.gz
[master] Server now supports EUI-64 based address allocation scheme
Merged rt43927.
-rw-r--r--RELNOTES7
-rw-r--r--common/inet.c18
-rw-r--r--includes/dhcp6.h3
-rw-r--r--includes/dhcpd.h20
-rw-r--r--includes/site.h7
-rw-r--r--server/confpars.c13
-rw-r--r--server/dhcpd.conf.5143
-rw-r--r--server/dhcpv6.c63
-rw-r--r--server/mdb6.c243
-rw-r--r--server/stables.c3
10 files changed, 470 insertions, 50 deletions
diff --git a/RELNOTES b/RELNOTES
index 873b3661..b0101882 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -153,6 +153,13 @@ by Eric Young (eay@cryptsoft.com).
supplying the patch.
[ISC-Bugs #29108]
+- IPv6 operation now supports an EUI-64 based address allocation which will
+ calculate addresses for clients with EUI-64 DUIDs based on those DUIDs when
+ enabled by setting use-eui-64 true. The parameter may defined down to the
+ pool scope. Note this feature must be compiled in by defining EUI_64 in
+ includes/site.h. This flag is undefined by default.
+ [ISC-Bugs #43927]
+
Changes since 4.3.0 (bug fixes)
- Tidy up several small tickets.
diff --git a/common/inet.c b/common/inet.c
index 2e3449cc..9b545b3a 100644
--- a/common/inet.c
+++ b/common/inet.c
@@ -4,7 +4,7 @@
way... */
/*
- * Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-2003 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
@@ -646,3 +646,19 @@ validate_port_pair(char *port) {
return htons((u_int16_t)local_port);
}
+
+#ifdef DHCPv6
+/* Print a v6 address from an in6_addr struct */
+const char *
+pin6_addr(const struct in6_addr *src){
+
+ if (!src) {
+ return ("<null>");
+ }
+
+ struct iaddr addr;
+ addr.len = 16;
+ memcpy(addr.iabuf, src->s6_addr, 16);
+ return (piaddr(addr));
+}
+#endif
diff --git a/includes/dhcp6.h b/includes/dhcp6.h
index bf8205c3..617af2d8 100644
--- a/includes/dhcp6.h
+++ b/includes/dhcp6.h
@@ -277,3 +277,6 @@ struct dhcpv4_over_dhcpv6_packet {
#define IRT_DEFAULT 86400
#define IRT_MINIMUM 600
+#define EUI_64_ID_LEN 12 /* 2 for duid-type, 2 for hardware type, 8 for ID */
+#define IAID_LEN 4
+
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index ef42f21d..5a3888d5 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -3,7 +3,7 @@
Definitions for dhcpd... */
/*
- * Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-2003 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
@@ -799,6 +799,9 @@ struct lease_state {
#define SV_PREFIX_LEN_MODE 87
#define SV_DHCPV6_SET_TEE_TIMES 88
#define SV_ABANDON_LEASE_TIME 89
+#ifdef EUI_64
+#define SV_USE_EUI_64 90
+#endif
#if !defined (DEFAULT_PING_TIMEOUT)
# define DEFAULT_PING_TIMEOUT 1
@@ -1717,6 +1720,9 @@ struct ipv6_pond {
int logged; /* already logged a message */
isc_uint64_t low_threshold; /* low threshold to restart logging */
int jumbo_range;
+#ifdef EUI_64
+ int use_eui_64; /* use EUI-64 address assignment when true */
+#endif
};
/*
@@ -2900,6 +2906,9 @@ char *piaddrmask(struct iaddr *, struct iaddr *);
char *piaddrcidr(const struct iaddr *, unsigned int);
u_int16_t validate_port(char *);
u_int16_t validate_port_pair(char *);
+#if defined(DHCPv6)
+const char *pin6_addr (const struct in6_addr*);
+#endif
/* dhclient.c */
extern int nowait;
@@ -3748,6 +3757,15 @@ isc_result_t create_lease6(struct ipv6_pool *pool,
unsigned int *attempts,
const struct data_string *uid,
time_t soft_lifetime_end_time);
+#ifdef EUI_64
+int valid_eui_64_duid(const struct data_string* uid, int duid_beg);
+int valid_for_eui_64_pool(struct ipv6_pool*, struct data_string* uid,
+ int duid_beg, struct in6_addr* ia_addr);
+isc_result_t create_lease6_eui_64(struct ipv6_pool *pool,
+ struct iasubopt **addr,
+ const struct data_string *iaid_uid,
+ time_t soft_lifetime_end_time);
+#endif
isc_result_t add_lease6(struct ipv6_pool *pool,
struct iasubopt *lease,
time_t valid_lifetime_end_time);
diff --git a/includes/site.h b/includes/site.h
index 1f4407f4..d4140d91 100644
--- a/includes/site.h
+++ b/includes/site.h
@@ -318,6 +318,13 @@
allow at one time. A value of 0 means there is no limit.*/
#define MAX_FD_VALUE 200
+/* Enable EUI-64 Address assignment policy. Instructs the server
+ * to use EUI-64 addressing instead of dynamic address allocation
+ * for IA_NA pools, if the parameter use-eui-64 is true for the
+ * pool. Can be at all scopes down to the pool level. Not
+ * supported by the configure script. */
+/* #define EUI_64 */
+
/* Include definitions for various options. In general these
should be left as is, but if you have already defined one
of these and prefer your definition you can comment the
diff --git a/server/confpars.c b/server/confpars.c
index 126b3d6b..d2714516 100644
--- a/server/confpars.c
+++ b/server/confpars.c
@@ -3,7 +3,7 @@
Parser for dhcpd config file... */
/*
- * Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-2003 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
@@ -5101,6 +5101,17 @@ parse_ia_na_declaration(struct parse *cfile) {
iasubopt_dereference(&iaaddr, MDL);
continue;
}
+#ifdef EUI_64
+ if ((pool->ipv6_pond->use_eui_64) &&
+ (!valid_for_eui_64_pool(pool, &ia->iaid_duid, IAID_LEN,
+ &iaaddr->addr))) {
+ log_error("Non EUI-64 lease in EUI-64 pool: %s"
+ " discarding it",
+ pin6_addr(&iaaddr->addr));
+ iasubopt_dereference(&iaaddr, MDL);
+ continue;
+ }
+#endif
/* remove old information */
if (cleanup_lease6(ia_na_active, pool,
diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5
index 97531835..ba9e4277 100644
--- a/server/dhcpd.conf.5
+++ b/server/dhcpd.conf.5
@@ -1,6 +1,6 @@
.\" dhcpd.conf.5
.\"
-.\" Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
.\" Copyright (c) 1996-2003 by Internet Software Consortium
.\"
.\" Permission to use, copy, modify, and distribute this software for any
@@ -344,7 +344,7 @@ which case the server will send a DHCPNAK even though it doesn't know
about the address.
.PP
There may be a host declaration matching the client's identification.
-If that host declaration contains a fixed-address declaration that
+If that host declaration contains a fixed-address declaration that
lists an IP address that is valid for the network segment to which the
client is connected. In this case, the DHCP server will never do
dynamic address allocation. In this case, the client is \fIrequired\fR
@@ -557,7 +557,7 @@ include "/etc/dhcpd.master";
.PP
The statements in the peer declaration are as follows:
.PP
-The
+The
.I primary
and
.I secondary
@@ -570,7 +570,7 @@ This determines whether the server is primary or secondary, as
described earlier under DHCP FAILOVER.
.RE
.PP
-The
+The
.I address
statement
.RS 0.25i
@@ -583,7 +583,7 @@ value to use for the DHCP Failover Protocol server identifier. Because this
value is used as an identifier, it may not be omitted.
.RE
.PP
-The
+The
.I peer address
statement
.RS 0.25i
@@ -595,7 +595,7 @@ which the server should connect to reach its failover peer for failover
messages.
.RE
.PP
-The
+The
.I port
statement
.RS 0.25i
@@ -608,7 +608,7 @@ may be omitted, in which case the IANA assigned port number 647 will be
used by default.
.RE
.PP
-The
+The
.I peer port
statement
.RS 0.25i
@@ -652,7 +652,7 @@ to say what a good value for this is, but 10 seems to work. This
parameter must be specified.
.RE
.PP
-The
+The
.I mclt
statement
.RS 0.25i
@@ -671,7 +671,7 @@ probably reasonable, but again bear in mind that we have no real
operational experience with this.
.RE
.PP
-The
+The
.I split
statement
.RS 0.25i
@@ -693,7 +693,7 @@ a value of 0 makes the secondary responsible for all clients and a value
of 256 makes the primary responsible for all clients.
.RE
.PP
-The
+The
.I hba
statement
.RS 0.25i
@@ -711,7 +711,7 @@ for such fine-grained control, however. An example hba statement:
.fi
.PP
This is equivalent to a \fBsplit 128;\fR statement, and identical. The
-following two examples are also equivalent to a \fBsplit\fR of 128, but
+following two examples are also equivalent to a \fBsplit\fR of 128, but
are not identical:
.PP
.nf
@@ -733,7 +733,7 @@ cases, the fine-grained control that \fBhba\fR offers isn't necessary, and
\fBsplit\fR should be used.
.RE
.PP
-The
+The
.I load balance max seconds
statement
.RS 0.25i
@@ -1178,7 +1178,7 @@ the FQDN Option, that implies to the client that it should perform its
own updates if it chooses to do so. With \fIdeny client-updates;\fR, a
response is sent which indicates the client may not perform updates.
.PP
-Both the standard and interim options also include a method to
+Both the standard and interim options also include a method to
allow more than one DHCP server to update the DNS database without
accidentally deleting A records that shouldn\'t be deleted nor failing
to add A records that should be added. For the standard option the
@@ -1298,7 +1298,7 @@ Note that the zone declarations have to correspond to authority
records in your name server - in the above example, there must be an
SOA record for "example.org." and for "17.10.10.in-addr.arpa.". For
example, if there were a subdomain "foo.example.org" with no separate
-SOA, you could not write a zone declaration for "foo.example.org."
+SOA, you could not write a zone declaration for "foo.example.org."
Also keep in mind that zone names in your DHCP configuration should end in a
"."; this is the preferred syntax. If you do not end your zone name in a
".", the DHCP server will figure it out. Also note that in the DHCP
@@ -1382,7 +1382,7 @@ The \fIinclude\fR statement is used to read in a named file, and process
the contents of that file as though it were entered in place of the
include statement.
.PP
-.B The
+.B The
.I shared-network
.B statement
.PP
@@ -1412,7 +1412,7 @@ shared network. The name may have the syntax of a valid domain name
(although it will never be used as such), or it may be any arbitrary
name, enclosed in quotes.
.PP
-.B The
+.B The
.I subnet
.B statement
.PP
@@ -1433,7 +1433,7 @@ declaration.
The
.I subnet-number
should be an IP address or domain name which resolves to the subnet
-number of the subnet being described. The
+number of the subnet being described. The
.I netmask
should be an IP address or domain name which resolves to the subnet mask
of the subnet being described. The subnet number, together with the
@@ -1446,7 +1446,7 @@ subnet-mask option statement be used in each subnet declaration to set
the desired subnet mask, since any subnet-mask option statement will
override the subnet mask declared in the subnet statement.
.PP
-.B The
+.B The
.I subnet6
.B statement
.PP
@@ -1461,7 +1461,7 @@ The \fIsubnet6\fR statement is used to provide dhcpd with enough
information to tell whether or not an IPv6 address is on that subnet6.
It may also be used to provide subnet-specific parameters and to
specify what addresses may be dynamically allocated to clients booting
-on that subnet.
+on that subnet.
.PP
The
.I subnet6-number
@@ -1497,8 +1497,8 @@ single address, \fIhigh-address\fR can be omitted.
.PP
For any IPv6 subnet6 on which addresses will be assigned dynamically, there
must be at least one \fIrange6\fR statement. The \fIrange6\fR statement
-can either be the lowest and highest IPv6 addresses in a \fIrange6\fR, or
-use CIDR notation, specified as ip6-address/bits. All IP addresses
+can either be the lowest and highest IPv6 addresses in a \fIrange6\fR, or
+use CIDR notation, specified as ip6-address/bits. All IP addresses
in the \fIrange6\fR should be in the subnet6 in which the
\fIrange6\fR statement is declared.
.PP
@@ -1507,7 +1507,7 @@ for temporary (RFC 4941) addresses. A new address per prefix in the shared
network is computed at each request with an IA_TA option. Release and Confirm
ignores temporary addresses.
.PP
-Any IPv6 addresses given to hosts with \fIfixed-address6\fR are excluded
+Any IPv6 addresses given to hosts with \fIfixed-address6\fR are excluded
from the \fIrange6\fR, as are IPv6 addresses on the server itself.
.PP
.PP
@@ -1561,7 +1561,7 @@ address. For multiple addresses specify multiple
statements.
.PP
If client-specific boot parameters must change based on the network
-to which the client is attached, then multiple
+to which the client is attached, then multiple
.B host
declarations should be used. The
.B host
@@ -1792,8 +1792,8 @@ the documentation under the heading THE DNS UPDATE SCHEME for details.
.PP
The \fBleasequery\fR flag tells the DHCP server whether or not to
answer DHCPLEASEQUERY packets. The answer to a DHCPLEASEQUERY packet
-includes information about a specific lease, such as when it was
-issued and when it will expire. By default, the server will not
+includes information about a specific lease, such as when it was
+issued and when it will expire. By default, the server will not
respond to these packets.
.SH ALLOW AND DENY WITHIN POOL DECLARATIONS
.PP
@@ -2098,7 +2098,7 @@ to use different DNS update styles for different clients. The default
is \fBnone\fR.
.RE
.PP
-.B The
+.B The
.I ddns-updates
.B statement
.RS 0.25i
@@ -2162,8 +2162,8 @@ in order to minimize problems with existing configuration files we have
left it disabled by default.
.RE
.PP
-The
-.I dhcp-cache-threshold
+The
+.I dhcp-cache-threshold
statement
.RS 0.25i
.PP
@@ -2399,7 +2399,7 @@ done for all addresses in the current scope. By default, or if
\fIflag\fR is false, no lookups are done.
.RE
.PP
-The
+The
.I hardware
statement
.RS 0.25i
@@ -2426,7 +2426,7 @@ separated by colons. The \fIhardware\fR statement may also be used
for DHCP clients.
.RE
.PP
-The
+The
.I host-identifier option
statement
.RS 0.25i
@@ -2441,9 +2441,9 @@ This identifies a DHCPv6 client in a
.I host
statement.
.I option-name
-is any option, and
+is any option, and
.I option-data
-is the value for the option that the client will send. The
+is the value for the option that the client will send. The
.I option-data
must be a constant value. In the v6relopts case the additional number
is the relay to examine for the specified option name and value. The
@@ -2453,7 +2453,7 @@ are larger than the maximum number of relays (currently 32) indicate the
relay closest to the server independent of number.
.RE
.PP
-The
+The
.I ignore-client-uids
statement
.RS 0.25i
@@ -2463,7 +2463,7 @@ statement
If the \fIignore-client-uids\fR statement is present and has a value of
\fItrue\fR or \fIon\fR, the UID for clients will not be recorded.
If this statement is not present or has a value of \fIfalse\fR or
-\fIoff\fR, then client UIDs will be recorded.
+\fIoff\fR, then client UIDs will be recorded.
.RE
.PP
The
@@ -2645,7 +2645,7 @@ possible.
.PP
The
.I log-threshold-high
-and
+and
.I log-threshold-low
statements
.RS 0.25i
@@ -2704,7 +2704,7 @@ statement
.I Time
should be the minimum length in seconds that will be assigned to a
lease.
-The default is the minimum of 300 seconds or
+The default is the minimum of 300 seconds or
\fBmax-lease-time\fR.
.RE
.PP
@@ -2941,7 +2941,7 @@ subnet 3000::/64 {
pool6 {
:
}
- # pool C
+ # pool C
pool6 {
:
}
@@ -3205,6 +3205,71 @@ in use. Also, the server must attempt the update each time the
client renews its lease, which could have a significant performance
impact in environments that place heavy demands on the DHCP server.
.RE
+
+
+.PP
+The
+.I use-eui-64
+statement
+.RS 0.25i
+.PP
+.B use-eui-64 \fIflag\fB;\fR
+.PP
+
+(Support for this must be enabled at compile time, see EUI_64 in
+ includes/site.h)
+
+The \fIuse-eui-64\fR flag, if enabled, instructs the server to construct an
+address using the client's EUI-64 DUID (Type 3, HW Type EUI-64), rather than
+creating an address using the dynamic algorithm. This means that a given DUID
+will always generate the same address for a given pool and further that the
+address is guaranteed to be unique to that DUID. The IPv6 address will be
+calculated from the EUI-64 link layer address, conforming to RFC 2373, unless
+there is a host declaration for the client-id.
+
+The range6 statement for EUI-64 must define full /64 bit ranges. Invalid ranges
+will be flagged during configuration parsing as errors. See the following
+example:
+
+ subnet6 fc00:e4::/64 {
+ use-eui-64 true;
+ range6 fc00:e4::/64;
+ }
+
+The statement may be specified down to the pool level, allowing a mixture of
+dynamic and EUI-64 based pools.
+
+During lease file parsing, any leases which map to an EUI-64 pool, that have a
+non-EUI-64 DUID or for which the lease address is not the EUI-64 address for
+that DUID in that pool, will be discarded.
+
+If a host declaration exists for the DUID, the server grants the address
+(fixed-prefix6, fixed-address6) according to the host declaration, regardless
+of the DUID type of the client (even for EUI-64 DUIDs).
+
+If a client request's an EUI-64 lease for a given network, and the resultant
+address conflicts with a fixed address reservation, the server will send the
+client a "no addresses available" response.
+
+Any client with a non-conforming DUID (not type 3 or not hw type EUI-64) that
+is not linked to a host declaration, which requests an address from an EUI-64
+enabled pool will be ignored and the event will be logged.
+
+Pools that are configured for EUI-64 will be skipped for dynamic allocation.
+If there are no pools in the shared network from which to allocate, the client
+will get back a no addresses available status.
+
+On an EUI-64 enabled pool, any client with a DUID 3, HW Type EUI-64, requesting
+a solicit/renew and including IA_NA that do not match the EUI-64 policy, they
+will be treated as though they are "outside" the subnet for a given client
+message:
+
+ Solicit - Server will advertise with EUI-64 ia suboption, but with rapid
+ commit off
+ Request - Server will send "an address not on link status", and no ia
+ suboption Renew/Rebind - Server will send the requested address ia
+ suboption with lifetimes of 0, plus an EUI-64 ia
+.RE
.PP
The
.I use-host-decl-names
@@ -3285,7 +3350,7 @@ the \fIVENDOR ENCAPSULATED OPTIONS\fR section.
.SH SETTING PARAMETER VALUES USING EXPRESSIONS
Sometimes it's helpful to be able to set the value of a DHCP server
parameter based on some value that the client has sent. To do this,
-you can use expression evaluation. The
+you can use expression evaluation. The
.B dhcp-eval(5)
manual page describes how to write expressions. To assign the result
of an evaluation to an option, define the option as follows:
@@ -3305,7 +3370,7 @@ For example:
It's often useful to allocate a single address to a single client, in
approximate perpetuity. Host statements with \fBfixed-address\fR clauses
exist to a certain extent to serve this purpose, but because host statements
-are intended to approximate \'static configuration\', they suffer from not
+are intended to approximate \'static configuration\', they suffer from not
being referenced in a littany of other Server Services, such as dynamic DNS,
failover, \'on events\' and so forth.
.PP
diff --git a/server/dhcpv6.c b/server/dhcpv6.c
index 18d8bb88..d18758ba 100644
--- a/server/dhcpv6.c
+++ b/server/dhcpv6.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2016 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2006-2017 by Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -1248,7 +1248,6 @@ try_client_v6_address(struct iasubopt **addr,
return result;
}
-
/*!
*
* \brief Get an IPv6 address for the client.
@@ -1330,14 +1329,37 @@ pick_v6_address(struct reply_state *reply)
(!permitted(reply->packet, pond->permit_list))))
continue;
+#ifdef EUI_64
+ /* If pond is EUI-64 but client duid isn't a valid EUI-64
+ * id, then skip this pond */
+ if (pond->use_eui_64 &&
+ !valid_eui_64_duid(&reply->ia->iaid_duid, IAID_LEN)) {
+ continue;
+ }
+#endif
+
start_pool = pond->last_ipv6_pool;
i = start_pool;
do {
p = pond->ipv6_pools[i];
if (p->pool_type == D6O_IA_NA) {
- result = create_lease6(p, addr, &attempts,
- &reply->ia->iaid_duid,
- cur_time + 120);
+#ifdef EUI_64
+ if (pond->use_eui_64) {
+ result =
+ create_lease6_eui_64(p, addr,
+ &reply->ia->iaid_duid,
+ cur_time + 120);
+ }
+ else
+#endif
+ {
+ result =
+ create_lease6(p, addr, &attempts,
+ &reply->ia->iaid_duid,
+ cur_time + 120);
+
+ }
+
if (result == ISC_R_SUCCESS) {
/*
* Record the pool used (or next one if
@@ -2368,6 +2390,9 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
struct option_cache *oc;
struct data_string iaaddr, data;
isc_result_t status = ISC_R_SUCCESS;
+#ifdef EUI_64
+ int invalid_for_eui_64 = 0;
+#endif
/* Initializes values that will be cleaned up. */
memset(&iaaddr, 0, sizeof(iaaddr));
@@ -2429,8 +2454,31 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
break;
}
+#ifdef EUI_64
+ if (subnet) {
+ /* If the requested address falls into an EUI-64 pool, then
+ * we need to verify if it has EUI-64 duid AND the requested
+ * address is correct for that duid. If not we treat it just
+ * like an not-on-link request. */
+ struct ipv6_pool* pool = NULL;
+ struct in6_addr* addr = (struct in6_addr*)(iaaddr.data);
+ if ((find_ipv6_pool(&pool, D6O_IA_NA, addr) == ISC_R_SUCCESS)
+ && (pool->ipv6_pond->use_eui_64) &&
+ (!valid_for_eui_64_pool(pool, &reply->client_id, 0, addr))) {
+ log_debug ("Requested address: %s,"
+ " not valid for EUI-64 pool",
+ pin6_addr(addr));
+ invalid_for_eui_64 = 1;
+ }
+ }
+#endif
+
/* Address not found on shared network. */
+#ifdef EUI_64
+ if ((subnet == NULL) || invalid_for_eui_64) {
+#else
if (subnet == NULL) {
+#endif
/* Ignore this address on 'soft' bindings. */
if (reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) {
/* disable rapid commit */
@@ -2497,6 +2545,7 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
goto send_addr;
}
+
/* Verify the address belongs to the client. */
if (!address_is_owned(reply, &tmp_addr)) {
/*
@@ -3199,7 +3248,9 @@ find_client_temporaries(struct reply_state *reply) {
* Get an address in this temporary pool.
*/
status = create_lease6(p, &reply->lease, &attempts,
- &reply->client_id, cur_time + 120);
+ &reply->client_id,
+ cur_time + 120);
+
if (status != ISC_R_SUCCESS) {
log_debug("Unable to get a temporary address.");
goto cleanup;
diff --git a/server/mdb6.c b/server/mdb6.c
index 984988ad..6da59ac3 100644
--- a/server/mdb6.c
+++ b/server/mdb6.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2016 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2007-2017 by Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -851,6 +851,80 @@ build_address6(struct in6_addr *addr,
str[8] &= ~0x02;
}
+#ifdef EUI_64
+int
+valid_eui_64_duid(const struct data_string* uid, int offset) {
+ if (uid->len == (offset + EUI_64_ID_LEN)) {
+ const unsigned char* duid = uid->data + offset;
+ return (((duid[0] == 0x00 && duid[1] == 0x03) &&
+ (duid[2] == 0x00 && duid[3] == 0x1b)));
+ }
+
+ return(0);
+}
+
+
+/*
+ * Create an EUI-64 address
+ */
+static isc_result_t
+build_address6_eui_64(struct in6_addr *addr,
+ const struct in6_addr *net_start_addr, int net_bits,
+ const struct data_string *iaid_duid, int duid_beg) {
+
+ if (net_bits != 64) {
+ log_error("build_address_eui_64: network is not 64 bits");
+ return (ISC_R_FAILURE);
+ }
+
+ if (valid_eui_64_duid(iaid_duid, duid_beg)) {
+ const unsigned char *duid = iaid_duid->data + duid_beg;
+
+ /* copy network prefix to the high 64 bits */
+ memcpy(addr->s6_addr, net_start_addr->s6_addr, 8);
+
+ /* copy Link-layer address to low 64 bits */
+ memcpy(addr->s6_addr + 8, duid + 4, 8);
+
+ /* RFC-3315 Any address assigned by a server that is based
+ * on an EUI-64 identifier MUST include an interface identifier
+ * with the "u" (universal/local) and "g" (individual/group)
+ * bits of the interface identifier set appropriately, as
+ * indicated in section 2.5.1 of RFC 2373 [5]. */
+ addr->s6_addr[8] |= 0x02;
+ return (ISC_R_SUCCESS);
+ }
+
+ log_error("build_address_eui_64: iaid_duid not a valid EUI-64: %s",
+ print_hex_1(iaid_duid->len, iaid_duid->data, 60));
+ return (ISC_R_FAILURE);
+}
+
+int
+valid_for_eui_64_pool(struct ipv6_pool* pool, struct data_string* uid,
+ int duid_beg, struct in6_addr* ia_addr) {
+ struct in6_addr test_addr;
+ /* If it's not an EUI-64 pool bail */
+ if (!pool->ipv6_pond->use_eui_64) {
+ return (0);
+ }
+
+ if (!valid_eui_64_duid(uid, duid_beg)) {
+ /* Dynamic lease in a now eui_64 pond, toss it*/
+ return (0);
+ }
+
+ /* Call build_address6_eui_64() and compare it's result to
+ * this lease and see if they match. */
+ memset (&test_addr, 0, sizeof(test_addr));
+ build_address6_eui_64(&test_addr, &pool->start_addr, pool->bits,
+ uid, duid_beg);
+
+ return (!memcmp(ia_addr, &test_addr, sizeof(test_addr)));
+}
+#endif
+
+
/*
* Create a temporary address by a variant of RFC 4941 algo.
* Note: this should not be used for prefixes shorter than 64 bits.
@@ -1079,6 +1153,107 @@ create_lease6(struct ipv6_pool *pool, struct iasubopt **addr,
return result;
}
+#ifdef EUI_64
+/*!
+ * \brief Assign an EUI-64 address from a pool for a given iaid-duid
+ *
+ * \param pool - pool from which the address is assigned
+ * \param iaddr - pointer to the iasubopt to contain the assigned address is
+ * \param uid - data_string containing the iaid-duid tuple
+ * \param soft_lifetime_end_time - lifetime of the lease for a solicit?
+ *
+ * \return status indicating success or nature of the failure
+*/
+isc_result_t
+create_lease6_eui_64(struct ipv6_pool *pool, struct iasubopt **addr,
+ const struct data_string *uid,
+ time_t soft_lifetime_end_time) {
+ struct in6_addr tmp;
+ struct iasubopt *test_iaaddr;
+ struct iasubopt *iaaddr;
+ isc_result_t result;
+ static isc_boolean_t init_resiid = ISC_FALSE;
+
+ /* Fill the reserved IIDs. */
+ if (!init_resiid) {
+ memset(&rtany, 0, 16);
+ memset(&resany, 0, 8);
+ resany.s6_addr[8] = 0xfd;
+ memset(&resany.s6_addr[9], 0xff, 6);
+ init_resiid = ISC_TRUE;
+ }
+
+ /* Pool must be IA_NA */
+ if (pool->pool_type != D6O_IA_NA) {
+ log_error("create_lease6_eui_64: pool type is not IA_NA.");
+ return (DHCP_R_INVALIDARG);
+ }
+
+ /* Attempt to build the address */
+ if (build_address6_eui_64 (&tmp, &pool->start_addr, pool->bits,
+ uid, IAID_LEN) != ISC_R_SUCCESS) {
+ log_error("create_lease6_eui_64: build_address6_eui_64 failed");
+ return (ISC_R_FAILURE);
+ }
+
+ /* Avoid reserved interface IDs. (cf. RFC 5453) */
+ if ((memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) ||
+ ((memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) &&
+ ((tmp.s6_addr[15] & 0x80) == 0x80))) {
+ log_error("create_lease6_eui_64: "
+ "address conflicts with reserved IID");
+ return (ISC_R_FAILURE);
+ }
+
+ /* If this address is not in use, we're happy with it */
+ test_iaaddr = NULL;
+ if (iasubopt_hash_lookup(&test_iaaddr, pool->leases,
+ &tmp, sizeof(tmp), MDL) != 0) {
+
+ /* See if it's ours. Static leases won't have an ia */
+ int ours = 0;
+ if (!test_iaaddr->ia) {
+ log_error("create_lease6_eui_64: "
+ "address %s is assigned to static lease",
+ pin6_addr(&test_iaaddr->addr));
+ } else {
+ /* Not sure if this can actually happen */
+ struct data_string* found = &test_iaaddr->ia->iaid_duid;
+ ours = ((found->len == uid->len) &&
+ (!memcmp(found->data, uid->data, uid->len)));
+ log_error("create_lease6_eui_64: "
+ "address %s belongs to %s",
+ pin6_addr(&test_iaaddr->addr),
+ print_hex_1(found->len, found->data, 60));
+ }
+
+ iasubopt_dereference(&test_iaaddr, MDL);
+ if (!ours) {
+ /* Cant' use it */
+ return (ISC_R_FAILURE);
+ }
+ }
+
+ /* We're happy with the address, create an IAADDR to hold it. */
+ iaaddr = NULL;
+ result = iasubopt_allocate(&iaaddr, MDL);
+ if (result != ISC_R_SUCCESS) {
+ log_error("create_lease6_eui_64: could not allocate iasubop");
+ return result;
+ }
+ iaaddr->plen = 0;
+ memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr));
+
+ /* Add the lease to the pool and the reply */
+ result = add_lease6(pool, iaaddr, soft_lifetime_end_time);
+ if (result == ISC_R_SUCCESS) {
+ iasubopt_reference(addr, iaaddr, MDL);
+ }
+
+ iasubopt_dereference(&iaaddr, MDL);
+ return result;
+}
+#endif
/*!
*
@@ -2494,6 +2669,56 @@ ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) {
return ISC_R_SUCCESS;
}
+#ifdef EUI_64
+/*
+ * Enables/disables EUI-64 address assignment for a pond
+ *
+ * Excecutes statements down to the pond's scope and sets the pond's
+ * use_eui_64 flag accordingly. In addition it iterates over the
+ * pond's pools ensuring they are all /64. Anything else is deemed
+ * invalid for EUI-64. It returns the number of invalid pools
+ * detected. This is done post-parsing as use-eui-64 can be set
+ * down to the pool scope and we can't reliably do it until the
+ * entire configuration has been parsed.
+ */
+int
+set_eui_64(struct ipv6_pond *pond) {
+ int invalid_cnt = 0;
+ struct option_state* options = NULL;
+ struct option_cache *oc = NULL;
+ option_state_allocate(&options, MDL);
+ execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL, options,
+ &global_scope, pond->group, NULL, NULL);
+
+ pond->use_eui_64 =
+ ((oc = lookup_option(&server_universe, options, SV_USE_EUI_64))
+ &&
+ (evaluate_boolean_option_cache (NULL, NULL, NULL, NULL,
+ options, NULL, &global_scope,
+ oc, MDL)));
+ if (pond->use_eui_64) {
+ // Check all pools are valid
+ int i = 0;
+ struct ipv6_pool* p;
+ while((p = pond->ipv6_pools[i++]) != NULL) {
+ if (p->bits != 64) {
+ log_error("Pool %s/%d cannot use EUI-64,"
+ " prefix must 64",
+ pin6_addr(&p->start_addr), p->bits);
+ invalid_cnt++;
+ } else {
+ log_debug("Pool: %s/%d - will use EUI-64",
+ pin6_addr(&p->start_addr), p->bits);
+ }
+ }
+ }
+
+ /* Don't need the options anymore. */
+ option_state_dereference(&options, MDL);
+ return (invalid_cnt);
+}
+#endif
+
/*
* Emits a log for each pond that has been flagged as being a "jumbo range"
* A pond is considered a "jumbo range" when the total number of elements
@@ -2510,11 +2735,18 @@ void
report_jumbo_ranges() {
struct shared_network* s;
char log_buf[1084];
+#ifdef EUI_64
+ int invalid_cnt = 0;
+#endif
/* Loop thru all the networks looking for jumbo range ponds */
for (s = shared_networks; s; s = s -> next) {
struct ipv6_pond* pond = s->ipv6_pond;
while (pond) {
+#ifdef EUI_64
+ /* while we're here, set the pond's use_eui_64 flag */
+ invalid_cnt += set_eui_64(pond);
+#endif
/* if its a jumbo and has pools(sanity check) */
if (pond->jumbo_range == 1 && (pond->ipv6_pools)) {
struct ipv6_pool* pool;
@@ -2557,7 +2789,15 @@ report_jumbo_ranges() {
}
pond = pond->next;
}
+
+ }
+
+#ifdef EUI_64
+ if (invalid_cnt) {
+ log_fatal ("%d pool(s) are invalid for EUI-64 use",
+ invalid_cnt);
}
+#endif
}
@@ -2776,5 +3016,4 @@ find_hosts6(struct host_decl** host, struct packet* packet,
|| find_hosts_by_duid_chaddr(host, client_id));
}
-
/* unittest moved to server/tests/mdb6_unittest.c */
diff --git a/server/stables.c b/server/stables.c
index 445ef0fd..156e1fe6 100644
--- a/server/stables.c
+++ b/server/stables.c
@@ -277,6 +277,9 @@ static struct option server_options[] = {
{ "prefix-length-mode", "Nprefix_length_modes.", &server_universe, SV_PREFIX_LEN_MODE, 1 },
{ "dhcpv6-set-tee-times", "f", &server_universe, SV_DHCPV6_SET_TEE_TIMES, 1 },
{ "abandon-lease-time", "T", &server_universe, SV_ABANDON_LEASE_TIME, 1 },
+#ifdef EUI_64
+ { "use-eui-64", "f", &server_universe, SV_USE_EUI_64, 1 },
+#endif
{ NULL, NULL, NULL, 0, 0 }
};