1 diff -up dhcp-4.2.0/server/dhcpv6.c.UseMulticast dhcp-4.2.0/server/dhcpv6.c
2 --- dhcp-4.2.0/server/dhcpv6.c.UseMulticast 2010-06-01 19:30:00.000000000 +0200
3 +++ dhcp-4.2.0/server/dhcpv6.c 2010-07-21 16:17:30.000000000 +0200
4 @@ -346,6 +346,48 @@ generate_new_server_duid(void) {
8 + * Is the D6O_UNICAST option defined in dhcpd.conf ?
10 +static isc_boolean_t unicast_option_defined;
13 + * Did we already search dhcpd.conf for D6O_UNICAST option ?
14 + * We need to store it here to not parse dhcpd.conf repeatedly.
16 +static isc_boolean_t unicast_option_parsed = ISC_FALSE;
20 + * Is the D6O_UNICAST option defined in dhcpd.conf ?
23 +is_unicast_option_defined(void) {
24 + struct option_state *opt_state;
25 + struct option_cache *oc;
28 + * If we are looking for the unicast option for the first time
30 + if (unicast_option_parsed == ISC_FALSE) {
31 + unicast_option_parsed = ISC_TRUE;
33 + if (!option_state_allocate(&opt_state, MDL)) {
34 + log_fatal("No memory for option state.");
37 + execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
38 + opt_state, &global_scope, root_group, NULL);
40 + oc = lookup_option(&dhcpv6_universe, opt_state, D6O_UNICAST);
41 + unicast_option_defined = (oc != NULL);
43 + option_state_dereference(&opt_state, MDL);
46 + return (unicast_option_defined);
50 * Get the client identifier from the packet.
53 @@ -1405,6 +1447,56 @@ lease_to_client(struct data_string *repl
57 + /* reject unicast message, unless we set unicast option */
58 + if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined())
60 + * RFC3315 section 18.2.1 (Request):
62 + * When the server receives a Request message via unicast from a client
63 + * to which the server has not sent a unicast option, the server
64 + * discards the Request message and responds with a Reply message
65 + * containing a Status Code option with the value UseMulticast, a Server
66 + * Identifier option containing the server's DUID, the Client Identifier
67 + * option from the client message, and no other options.
69 + * Section 18.2.3 (Renew):
71 + * When the server receives a Renew message via unicast from a client to
72 + * which the server has not sent a unicast option, the server discards
73 + * the Renew message and responds with a Reply message containing a
74 + * Status Code option with the value UseMulticast, a Server Identifier
75 + * option containing the server's DUID, the Client Identifier option
76 + * from the client message, and no other options.
79 + /* Set the UseMulticast status code. */
80 + if (!set_status_code(STATUS_UseMulticast,
81 + "Unicast not allowed by server.",
83 + log_error("lease_to_client: Unable to set "
84 + "UseMulticast status code.");
88 + /* Rewind the cursor to the start. */
89 + reply.cursor = REPLY_OPTIONS_INDEX;
92 + * Produce an reply that includes only:
98 + reply.cursor += store_options6((char *)reply.buf.data +
100 + sizeof(reply.buf) -
102 + reply.opt_state, reply.packet,
105 + } else if (no_resources_avail && (reply.ia_count != 0) &&
106 + (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
108 * RFC3315 section 17.2.2 (Solicit):
110 @@ -1429,8 +1521,6 @@ lease_to_client(struct data_string *repl
112 * Sends a Renew/Rebind if the IA is not in the Reply message.
114 - if (no_resources_avail && (reply.ia_count != 0) &&
115 - (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
117 /* Set the NoAddrsAvail status code. */
118 if (!set_status_code(STATUS_NoAddrsAvail,
119 @@ -4128,7 +4218,6 @@ dhcpv6_solicit(struct data_string *reply
120 * Very similar to Solicit handling, except the server DUID is required.
123 -/* TODO: reject unicast messages, unless we set unicast option */
125 dhcpv6_request(struct data_string *reply_ret, struct packet *packet) {
126 struct data_string client_id;
127 @@ -4443,7 +4532,6 @@ exit:
128 * except for the error code of when addresses don't match.
131 -/* TODO: reject unicast messages, unless we set unicast option */
133 dhcpv6_renew(struct data_string *reply, struct packet *packet) {
134 struct data_string client_id;
135 @@ -4688,18 +4776,60 @@ iterate_over_ia_na(struct data_string *r
139 - snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
140 - if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
143 + /* reject unicast message, unless we set unicast option */
144 + if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined()) {
146 + * RFC3315 section 18.2.6 (Release):
148 + * When the server receives a Release message via unicast from a client
149 + * to which the server has not sent a unicast option, the server
150 + * discards the Release message and responds with a Reply message
151 + * containing a Status Code option with value UseMulticast, a Server
152 + * Identifier option containing the server's DUID, the Client Identifier
153 + * option from the client message, and no other options.
155 + * Section 18.2.7 (Decline):
157 + * When the server receives a Decline message via unicast from a client
158 + * to which the server has not sent a unicast option, the server
159 + * discards the Decline message and responds with a Reply message
160 + * containing a Status Code option with the value UseMulticast, a Server
161 + * Identifier option containing the server's DUID, the Client Identifier
162 + * option from the client message, and no other options.
164 + snprintf(status_msg, sizeof(status_msg),
165 + "%s received unicast.", packet_type);
166 + if (!set_status_code(STATUS_UseMulticast, status_msg, opt_state)) {
171 - * Add our options that are not associated with any IA_NA or IA_TA.
173 - reply_ofs += store_options6(reply_data+reply_ofs,
174 - sizeof(reply_data)-reply_ofs,
176 + * Produce an reply that includes only:
182 + reply_ofs += store_options6(reply_data+reply_ofs,
183 + sizeof(reply_data)-reply_ofs,
185 - required_opts, NULL);
186 + required_opts_NAA, NULL);
190 + snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
191 + if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
196 + * Add our options that are not associated with any IA_NA or IA_TA.
198 + reply_ofs += store_options6(reply_data+reply_ofs,
199 + sizeof(reply_data)-reply_ofs,
201 + required_opts, NULL);
205 * Loop through the IA_NA reported by the client, and deal with
206 @@ -4838,6 +4968,7 @@ iterate_over_ia_na(struct data_string *r
208 * Return our reply to the caller.
211 reply_ret->len = reply_ofs;
212 reply_ret->buffer = NULL;
213 if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
214 @@ -4883,7 +5014,6 @@ exit:
215 * we still need to be aware of this possibility.
218 -/* TODO: reject unicast messages, unless we set unicast option */
221 dhcpv6_decline(struct data_string *reply, struct packet *packet) {
222 @@ -5355,7 +5485,6 @@ exit:
223 * Release means a client is done with the leases.
226 -/* TODO: reject unicast messages, unless we set unicast option */
228 dhcpv6_release(struct data_string *reply, struct packet *packet) {
229 struct data_string client_id;