From 21b8c45264838e9e4a5959d2d902288b22806bde Mon Sep 17 00:00:00 2001 From: Jiří Popelka Date: Mar 24 2010 11:06:45 +0000 Subject: - In dhclient-script check whether bound address passed duplicate address detection (DAD) (#559147) - If the bound address failed DAD (is found to be in use on the link), the dhcpv6 client sends a Decline message to the server as described in section 18.1.7 of RFC-3315 (#559147) --- diff --git a/dhclient-script b/dhclient-script index 73d49ee..fbc734a 100755 --- a/dhclient-script +++ b/dhclient-script @@ -417,6 +417,29 @@ dh6config() { ip -6 addr add ${new_ip6_address}/${new_ip6_prefixlen} \ dev ${interface} scope global + + # repeatedly test whether newly added address passed + # duplicate address detection (DAD) + for i in $(seq 5); do + sleep 1 # give the DAD some time + + # tentative flag = DAD is still not complete or failed + duplicate=$(ip -6 addr show dev ${interface} tentative \ + | grep ${new_ip6_address}/${new_ip6_prefixlen}) + + # if there's no tentative flag, address passed DAD + if [ -z "${duplicate}" ]; then + break + fi + done + + # if there's still tentative flag = address didn't pass DAD = + # = it's duplicate = remove it + if [ -n "${duplicate}" ]; then + ip -6 addr del ${new_ip6_address}/${new_ip6_prefixlen} dev ${interface} + exit_with_hooks 3 + fi + make_resolv_conf ;; diff --git a/dhcp-4.1.1-sendDecline.patch b/dhcp-4.1.1-sendDecline.patch new file mode 100644 index 0000000..7188a19 --- /dev/null +++ b/dhcp-4.1.1-sendDecline.patch @@ -0,0 +1,216 @@ +diff -up dhcp-4.1.1/client/dhc6.c.sendDecline dhcp-4.1.1/client/dhc6.c +--- dhcp-4.1.1/client/dhc6.c.sendDecline 2009-07-25 00:04:51.000000000 +0200 ++++ dhcp-4.1.1/client/dhc6.c 2010-03-24 10:41:31.000000000 +0100 +@@ -95,6 +95,8 @@ void do_select6(void *input); + void do_refresh6(void *input); + static void do_release6(void *input); + static void start_bound(struct client_state *client); ++static void start_decline6(struct client_state *client); ++static void do_decline6(void *input); + static void start_informed(struct client_state *client); + void informed_handler(struct packet *packet, struct client_state *client); + void bound_handler(struct packet *packet, struct client_state *client); +@@ -2137,6 +2139,7 @@ start_release6(struct client_state *clie + cancel_timeout(do_select6, client); + cancel_timeout(do_refresh6, client); + cancel_timeout(do_release6, client); ++ cancel_timeout(do_decline6, client); + client->state = S_STOPPED; + + /* +@@ -2787,6 +2790,7 @@ dhc6_check_reply(struct client_state *cl + break; + + case S_STOPPED: ++ case S_DECLINED: + action = dhc6_stop_action; + break; + +@@ -2888,6 +2892,7 @@ dhc6_check_reply(struct client_state *cl + break; + + case S_STOPPED: ++ case S_DECLINED: + /* Nothing critical to do at this stage. */ + break; + +@@ -3930,17 +3935,23 @@ reply_handler(struct packet *packet, str + cancel_timeout(do_select6, client); + cancel_timeout(do_refresh6, client); + cancel_timeout(do_release6, client); ++ cancel_timeout(do_decline6, client); + + /* If this is in response to a Release/Decline, clean up and return. */ +- if (client->state == S_STOPPED) { +- if (client->active_lease == NULL) +- return; ++ if ((client->state == S_STOPPED) || ++ (client->state == S_DECLINED)) { ++ ++ if (client->active_lease != NULL) { ++ dhc6_lease_destroy(&client->active_lease, MDL); ++ client->active_lease = NULL; ++ /* We should never wait for nothing!? */ ++ if (stopping_finished()) ++ exit(0); ++ } ++ ++ if (client->state == S_DECLINED) ++ start_init6(client); + +- dhc6_lease_destroy(&client->active_lease, MDL); +- client->active_lease = NULL; +- /* We should never wait for nothing!? */ +- if (stopping_finished()) +- exit(0); + return; + } + +@@ -4463,7 +4474,11 @@ start_bound(struct client_state *client) + oldia, oldaddr); + dhc6_marshall_values("new_", client, lease, ia, addr); + +- script_go(client); ++ // when script returns 3, DAD failed ++ if (script_go(client) == 3) { ++ start_decline6(client); ++ return; ++ } + } + + /* XXX: maybe we should loop on the old values instead? */ +@@ -4509,6 +4524,134 @@ start_bound(struct client_state *client) + dhc6_check_times(client); + } + ++/* ++ * Decline addresses. ++ */ ++void ++start_decline6(struct client_state *client) ++{ ++ /* Cancel any pending transmissions */ ++ cancel_timeout(do_confirm6, client); ++ cancel_timeout(do_select6, client); ++ cancel_timeout(do_refresh6, client); ++ cancel_timeout(do_release6, client); ++ cancel_timeout(do_decline6, client); ++ client->state = S_DECLINED; ++ ++ if (client->active_lease == NULL) ++ return; ++ ++ /* Set timers per RFC3315 section 18.1.7. */ ++ client->IRT = DEC_TIMEOUT * 100; ++ client->MRT = 0; ++ client->MRC = DEC_MAX_RC; ++ client->MRD = 0; ++ ++ dhc6_retrans_init(client); ++ client->v6_handler = reply_handler; ++ ++ client->refresh_type = DHCPV6_DECLINE; ++ do_decline6(client); ++} ++ ++/* ++ * do_decline6() creates a Decline packet and transmits it. ++ */ ++static void ++do_decline6(void *input) ++{ ++ struct client_state *client; ++ struct data_string ds; ++ int send_ret; ++ struct timeval elapsed, tv; ++ ++ client = input; ++ ++ if ((client->active_lease == NULL) || !active_prefix(client)) ++ return; ++ ++ if ((client->MRC != 0) && (client->txcount > client->MRC)) { ++ log_info("Max retransmission count exceeded."); ++ goto decline_done; ++ } ++ ++ /* ++ * Start_time starts at the first transmission. ++ */ ++ if (client->txcount == 0) { ++ client->start_time.tv_sec = cur_tv.tv_sec; ++ client->start_time.tv_usec = cur_tv.tv_usec; ++ } ++ ++ memset(&ds, 0, sizeof(ds)); ++ if (!buffer_allocate(&ds.buffer, 4, MDL)) { ++ log_error("Unable to allocate memory for Decline."); ++ goto decline_done; ++ } ++ ++ ds.data = ds.buffer->data; ++ ds.len = 4; ++ ds.buffer->data[0] = DHCPV6_DECLINE; ++ memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3); ++ ++ log_debug("XMT: Forming Decline."); ++ make_client6_options(client, &client->sent_options, ++ client->active_lease, DHCPV6_DECLINE); ++ dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL, ++ client->sent_options, &global_scope, ++ &dhcpv6_universe); ++ ++ /* Append IA's (but don't release temporary addresses). */ ++ if (wanted_ia_na && ++ dhc6_add_ia_na(client, &ds, client->active_lease, ++ DHCPV6_DECLINE) != ISC_R_SUCCESS) { ++ data_string_forget(&ds, MDL); ++ goto decline_done; ++ } ++ if (wanted_ia_pd && ++ dhc6_add_ia_pd(client, &ds, client->active_lease, ++ DHCPV6_DECLINE) != ISC_R_SUCCESS) { ++ data_string_forget(&ds, MDL); ++ goto decline_done; ++ } ++ ++ /* Transmit and wait. */ ++ log_info("XMT: Decline on %s, interval %ld0ms.", ++ client->name ? client->name : client->interface->name, ++ (long int)client->RT); ++ ++ send_ret = send_packet6(client->interface, ds.data, ds.len, ++ &DHCPv6DestAddr); ++ if (send_ret != ds.len) { ++ log_error("dhc6: sendpacket6() sent %d of %d bytes", ++ send_ret, ds.len); ++ } ++ ++ data_string_forget(&ds, MDL); ++ ++ /* Wait RT */ ++ tv.tv_sec = cur_tv.tv_sec + client->RT / 100; ++ tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000; ++ if (tv.tv_usec >= 1000000) { ++ tv.tv_sec += 1; ++ tv.tv_usec -= 1000000; ++ } ++ add_timeout(&tv, do_decline6, client, NULL, NULL); ++ dhc6_retrans_advance(client); ++ return; ++ ++decline_done: ++ if (client->active_lease != NULL) { ++ dhc6_lease_destroy(&client->active_lease, MDL); ++ client->active_lease = NULL; ++ /* We should never wait for nothing!? */ ++ if (stopping_finished()) ++ exit(0); ++ } ++ start_init6(client); ++ return; ++} ++ + /* While bound, ignore packets. In the future we'll want to answer + * Reconfigure-Request messages and the like. + */ diff --git a/dhcp.spec b/dhcp.spec index 639a110..40d18d4 100644 --- a/dhcp.spec +++ b/dhcp.spec @@ -13,7 +13,7 @@ Summary: Dynamic host configuration protocol software Name: dhcp Version: %{basever} -Release: 14%{?dist} +Release: 15%{?dist} # NEVER CHANGE THE EPOCH on this package. The previous maintainer (prior to # dcantrell maintaining the package) made incorrect use of the epoch and # that's why it is at 12 now. It should have never been used, but it was. @@ -55,6 +55,7 @@ Patch19: %{name}-4.1.1-64_bit_lease_parse.patch Patch20: %{name}-4.1.1-capability.patch Patch21: %{name}-4.1.1-logpid.patch Patch22: %{name}-4.1.1-UseMulticast.patch +Patch23: %{name}-4.1.1-sendDecline.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: autoconf @@ -213,6 +214,11 @@ libdhcpctl and libomapi static libraries are also included in this package. # with UseMulticast Status Code option (#573090) %patch22 -p1 -b .UseMulticast +# If any of the bound addresses are found to be in use on the link, +# the dhcpv6 client sends a Decline message to the server +# as described in section 18.1.7 of RFC-3315 (#559147) +%patch23 -p1 -b .sendDecline + # Copy in documentation and example scripts for LDAP patch to dhcpd %{__install} -p -m 0755 ldap-for-dhcp-%{ldappatchver}/dhcpd-conf-to-ldap contrib/ @@ -495,6 +501,13 @@ fi %attr(0644,root,root) %{_mandir}/man3/omapi.3.gz %changelog +* Wed Mar 24 2010 Jiri Popelka - 12:4.1.1-15 +- In dhclient-script check whether bound address + passed duplicate address detection (DAD) (#559147) +- If the bound address failed DAD (is found to be in use on the link), + the dhcpv6 client sends a Decline message to the server + as described in section 18.1.7 of RFC-3315 (#559147) + * Fri Mar 19 2010 Jiri Popelka - 12:4.1.1-14 - Fix UseMulticast.patch to not repeatedly parse dhcpd.conf for unicast option - Fix dhclient-script to set interface MTU only when it's greater than 576 (#574629)