You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 lines
7.8 KiB

diff -up dhcp-4.2.4b1/server/dhcpv6.c.UseMulticast dhcp-4.2.4b1/server/dhcpv6.c
--- dhcp-4.2.4b1/server/dhcpv6.c.UseMulticast 2012-04-11 00:14:04.000000000 +0200
+++ dhcp-4.2.4b1/server/dhcpv6.c 2012-04-16 19:21:43.575923732 +0200
@@ -346,6 +346,48 @@ generate_new_server_duid(void) {
}
/*
+ * Is the D6O_UNICAST option defined in dhcpd.conf ?
+ */
+static isc_boolean_t unicast_option_defined;
+
+/*
+ * Did we already search dhcpd.conf for D6O_UNICAST option ?
+ * We need to store it here to not parse dhcpd.conf repeatedly.
+ */
+static isc_boolean_t unicast_option_parsed = ISC_FALSE;
+
+
+/*
+ * Is the D6O_UNICAST option defined in dhcpd.conf ?
+ */
+isc_boolean_t
+is_unicast_option_defined(void) {
+ struct option_state *opt_state;
+ struct option_cache *oc;
+
+ /*
+ * If we are looking for the unicast option for the first time
+ */
+ if (unicast_option_parsed == ISC_FALSE) {
+ unicast_option_parsed = ISC_TRUE;
+ opt_state = NULL;
+ if (!option_state_allocate(&opt_state, MDL)) {
+ log_fatal("No memory for option state.");
+ }
+
+ execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
+ opt_state, &global_scope, root_group, NULL);
+
+ oc = lookup_option(&dhcpv6_universe, opt_state, D6O_UNICAST);
+ unicast_option_defined = (oc != NULL);
+
+ option_state_dereference(&opt_state, MDL);
+ }
+
+ return (unicast_option_defined);
+}
+
+/*
* Get the client identifier from the packet.
*/
isc_result_t
@@ -1404,6 +1446,56 @@ lease_to_client(struct data_string *repl
reply.shared->group);
}
+ /* reject unicast message, unless we set unicast option */
+ if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined())
+ /*
+ * RFC3315 section 18.2.1 (Request):
+ *
+ * When the server receives a Request message via unicast from a client
+ * to which the server has not sent a unicast option, the server
+ * discards the Request message and responds with a Reply message
+ * containing a Status Code option with the value UseMulticast, a Server
+ * Identifier option containing the server's DUID, the Client Identifier
+ * option from the client message, and no other options.
+ *
+ * Section 18.2.3 (Renew):
+ *
+ * When the server receives a Renew message via unicast from a client to
+ * which the server has not sent a unicast option, the server discards
+ * the Renew message and responds with a Reply message containing a
+ * Status Code option with the value UseMulticast, a Server Identifier
+ * option containing the server's DUID, the Client Identifier option
+ * from the client message, and no other options.
+ */
+ {
+ /* Set the UseMulticast status code. */
+ if (!set_status_code(STATUS_UseMulticast,
+ "Unicast not allowed by server.",
+ reply.opt_state)) {
+ log_error("lease_to_client: Unable to set "
+ "UseMulticast status code.");
+ goto exit;
+ }
+
+ /* Rewind the cursor to the start. */
+ reply.cursor = REPLY_OPTIONS_INDEX;
+
+ /*
+ * Produce an reply that includes only:
+ *
+ * Status code.
+ * Server DUID.
+ * Client DUID.
+ */
+ reply.cursor += store_options6((char *)reply.buf.data +
+ reply.cursor,
+ sizeof(reply.buf) -
+ reply.cursor,
+ reply.opt_state, reply.packet,
+ required_opts_NAA,
+ NULL);
+ }
+
/*
* RFC3315 section 17.2.2 (Solicit):
*
@@ -1429,8 +1521,8 @@ lease_to_client(struct data_string *repl
* Sends a Renew/Rebind if the IA is not in the Reply message.
*/
#if defined (RFC3315_PRE_ERRATA_2010_08)
- if (no_resources_avail && (reply.ia_count != 0) &&
- (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
+ else if (no_resources_avail && (reply.ia_count != 0) &&
+ (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
{
/* Set the NoAddrsAvail status code. */
if (!set_status_code(STATUS_NoAddrsAvail,
@@ -1477,6 +1569,7 @@ lease_to_client(struct data_string *repl
* Having stored the client's IA's, store any options that
* will fit in the remaining space.
*/
+ else
reply.cursor += store_options6((char *)reply.buf.data + reply.cursor,
sizeof(reply.buf) - reply.cursor,
reply.opt_state, reply.packet,
@@ -4126,7 +4219,6 @@ dhcpv6_solicit(struct data_string *reply
* Very similar to Solicit handling, except the server DUID is required.
*/
-/* TODO: reject unicast messages, unless we set unicast option */
static void
dhcpv6_request(struct data_string *reply_ret, struct packet *packet) {
struct data_string client_id;
@@ -4456,7 +4548,6 @@ exit:
* except for the error code of when addresses don't match.
*/
-/* TODO: reject unicast messages, unless we set unicast option */
static void
dhcpv6_renew(struct data_string *reply, struct packet *packet) {
struct data_string client_id;
@@ -4700,18 +4791,60 @@ iterate_over_ia_na(struct data_string *r
goto exit;
}
- snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
- if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
- goto exit;
- }
+ /* reject unicast message, unless we set unicast option */
+ if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined()) {
+ /*
+ * RFC3315 section 18.2.6 (Release):
+ *
+ * When the server receives a Release message via unicast from a client
+ * to which the server has not sent a unicast option, the server
+ * discards the Release message and responds with a Reply message
+ * containing a Status Code option with value UseMulticast, a Server
+ * Identifier option containing the server's DUID, the Client Identifier
+ * option from the client message, and no other options.
+ *
+ * Section 18.2.7 (Decline):
+ *
+ * When the server receives a Decline message via unicast from a client
+ * to which the server has not sent a unicast option, the server
+ * discards the Decline message and responds with a Reply message
+ * containing a Status Code option with the value UseMulticast, a Server
+ * Identifier option containing the server's DUID, the Client Identifier
+ * option from the client message, and no other options.
+ */
+ snprintf(status_msg, sizeof(status_msg),
+ "%s received unicast.", packet_type);
+ if (!set_status_code(STATUS_UseMulticast, status_msg, opt_state)) {
+ goto exit;
+ }
- /*
- * Add our options that are not associated with any IA_NA or IA_TA.
- */
- reply_ofs += store_options6(reply_data+reply_ofs,
- sizeof(reply_data)-reply_ofs,
+ /*
+ * Produce an reply that includes only:
+ *
+ * Status code.
+ * Server DUID.
+ * Client DUID.
+ */
+ reply_ofs += store_options6(reply_data+reply_ofs,
+ sizeof(reply_data)-reply_ofs,
opt_state, packet,
- required_opts, NULL);
+ required_opts_NAA, NULL);
+
+ goto return_reply;
+ } else {
+ snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
+ if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
+ goto exit;
+ }
+
+ /*
+ * Add our options that are not associated with any IA_NA or IA_TA.
+ */
+ reply_ofs += store_options6(reply_data+reply_ofs,
+ sizeof(reply_data)-reply_ofs,
+ opt_state, packet,
+ required_opts, NULL);
+ }
/*
* Loop through the IA_NA reported by the client, and deal with
@@ -4849,6 +4982,7 @@ iterate_over_ia_na(struct data_string *r
/*
* Return our reply to the caller.
*/
+return_reply:
reply_ret->len = reply_ofs;
reply_ret->buffer = NULL;
if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
@@ -4894,7 +5028,6 @@ exit:
* we still need to be aware of this possibility.
*/
-/* TODO: reject unicast messages, unless we set unicast option */
/* TODO: IA_TA */
static void
dhcpv6_decline(struct data_string *reply, struct packet *packet) {
@@ -5364,7 +5497,6 @@ exit:
* Release means a client is done with the leases.
*/
-/* TODO: reject unicast messages, unless we set unicast option */
static void
dhcpv6_release(struct data_string *reply, struct packet *packet) {
struct data_string client_id;