| diff -up dhcp-4.2.4b1/server/dhcpv6.c.UseMulticast dhcp-4.2.4b1/server/dhcpv6.c |
| |
| |
| @@ -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; |