]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master] Added DAD error checking on BOUND6 to client scripts
authorThomas Markwalder <tmark@isc.org>
Fri, 12 Jan 2018 15:12:41 +0000 (10:12 -0500)
committerThomas Markwalder <tmark@isc.org>
Fri, 12 Jan 2018 15:12:41 +0000 (10:12 -0500)
    Merges in rt46805.

RELNOTES
client/scripts/freebsd
client/scripts/linux
client/scripts/macos
client/scripts/netbsd
client/scripts/openbsd [changed mode: 0644->0755]

index 33e8ee44f02e0364a7dbdf1410f4de1922ce29e5..05d035bfddf53389a06e5e1df1d4fce0e239648b 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -87,6 +87,16 @@ ISC DHCP is open source software maintained by Internet Systems
 Consortium.  This product includes cryptographic software written
 by Eric Young (eay@cryptsoft.com).
 
+                Changes since 4.4.0b1 (New Features)
+
+- Duplicate address detection when binding to a new IPv6 address was added
+  to the following dhclient scripts: linux,freebsd,netbsd,openbsd, and macos.
+  The scripts will check for DAD errors after binding to a new IPv6 address
+  for at most --dad-wait-time seconds.  If a DAD error is detected the script
+  will exit with a value of 3, instructing dhclient to decline the address. If
+  dad-wait-time is zero (the default), DAD error checking is not peformed.
+  [ISC-Bugs 46805]
+
                Changes since 4.4.0b1 (Bug Fixes)
 
 - Added clarifying text to dhcpd.conf.5 explaining the class match expressions
index 8f3e2a23ad761dc66512c837e6ebb29388a1577e..7c073f86e45e0a3644a1be8267c7a95a442a9953 100755 (executable)
@@ -92,6 +92,51 @@ exit_with_hooks() {
   exit $exit_status
 }
 
+# This function was largely borrowed from dhclient-script that
+# ships with Centos, authored by Jiri Popelka and David Cantrell
+# of Redhat. Thanks guys.
+add_ipv6_addr_with_DAD() {
+    ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias
+
+    if [ ${dad_wait_time} -le 0 ]
+    then
+        # if we're not waiting for DAD, assume we're good
+        return 0
+    fi
+
+    # Repeatedly test whether newly added address passed
+    # duplicate address detection (DAD)
+    for i in $(seq 1 ${dad_wait_time}); do
+        sleep 1 # give the DAD some time
+
+        addr=$(ifconfig ${interface} \
+            | grep "${new_ip6_address} prefixlen ${new_ip6_prefixlen}")
+
+        # tentative flag == DAD is still not complete
+        tentative=$(echo "${addr}" | grep tentative)
+        # dadfailed flag == address is already in use somewhere else
+        dadfailed=$(echo "${addr}" | grep duplicated)
+
+        if [ -n "${dadfailed}" ] ; then
+            # dad failed, remove the address
+            ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} -alias
+            exit_with_hooks 3
+        fi
+
+        if [ -z "${tentative}" ] ; then
+            if [ -n "${addr}" ]; then
+                # DAD is over
+                return 0
+            else
+                # address was auto-removed (or not added at all)
+                exit_with_hooks 3
+            fi
+        fi
+    done
+
+    return 0
+}
+
 # Invoke the local dhcp client enter hooks, if they exist.
 if [ -f /etc/dhclient-enter-hooks ]; then
   exit_status=0
@@ -385,7 +430,8 @@ if [ ${reason} = BOUND6 ] ; then
     exit_with_hooks 2;
   fi
 
-  ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias
+  # Add address to interface, check for DAD if dad_wait_time > 0
+  add_ipv6_addr_with_DAD
 
   # Check for nameserver options.
   make_resolv_conf
index 5fb16121f0059fd0ce33142c870ef5566966411a..0c42969744e4fd0ea513f9d5516183cef207c3b4 100755 (executable)
@@ -177,6 +177,55 @@ exit_with_hooks() {
     exit $exit_status
 }
 
+# This function was largely borrowed from dhclient-script that
+# ships with Centos, authored by Jiri Popelka and David Cantrell
+# of Redhat. Thanks guys.
+add_ipv6_addr_with_DAD() {
+    ${ip} -6 addr replace ${new_ip6_address}/${new_ip6_prefixlen} \
+    dev ${interface} scope global valid_lft ${new_max_life} \
+        preferred_lft ${new_preferred_life}
+
+    if [ ${dad_wait_time} -le 0 ]
+    then
+        # if we're not waiting for DAD, assume we're good
+        return 0
+    fi
+
+    # Repeatedly test whether newly added address passed
+    # duplicate address detection (DAD)
+    for i in $(seq 1 ${dad_wait_time}); do
+        sleep 1 # give the DAD some time
+
+        addr=$(${ip} -6 addr show dev ${interface} \
+            | grep ${new_ip6_address}/${new_ip6_prefixlen})
+
+        # tentative flag == DAD is still not complete
+        tentative=$(echo "${addr}" | grep tentative)
+        # dadfailed flag == address is already in use somewhere else
+        dadfailed=$(echo "${addr}" | grep dadfailed)
+
+        if [ -n "${dadfailed}" ] ; then
+            # address was added with valid_lft/preferred_lft 'forever',
+            # remove it
+            ${ip} -6 addr del ${new_ip6_address}/${new_ip6_prefixlen} \
+                dev ${interface}
+
+            exit_with_hooks 3
+        fi
+
+        if [ -z "${tentative}" ] ; then
+            if [ -n "${addr}" ]; then
+                # DAD is over
+                    return 0
+            else
+                # address was auto-removed (or not added at all)
+                exit_with_hooks 3
+            fi
+        fi
+    done
+
+    return 0
+}
 
 # Invoke the local dhcp client enter hooks, if they exist.
 run_hook /etc/dhclient-enter-hooks
@@ -401,8 +450,7 @@ case "$reason" in
     BOUND6|RENEW6|REBIND6)
         if [ "${new_ip6_address}" ] && [ "${new_ip6_prefixlen}" ]; then
             # set leased IP
-            ${ip} -6 addr add ${new_ip6_address}/${new_ip6_prefixlen} \
-                dev ${interface} scope global
+            add_ipv6_addr_with_DAD
         fi
 
         # update /etc/resolv.conf
index a896b1e9a288e4145379c3b60449e45fc6c2def9..0164b1f0b3747e618c2679043c09d22fa1b16295 100755 (executable)
@@ -108,6 +108,51 @@ commit_resolv_conf() {
   to_commit="done"
 }
 
+# This function was largely borrowed from dhclient-script that
+# ships with Centos, authored by Jiri Popelka and David Cantrell
+# of Redhat. Thanks guys.
+add_ipv6_addr_with_DAD() {
+    ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias
+
+    if [ ${dad_wait_time} -le 0 ]
+    then
+        # if we're not waiting for DAD, assume we're good
+        return 0
+    fi
+
+    # Repeatedly test whether newly added address passed
+    # duplicate address detection (DAD)
+    for i in $(seq 1 ${dad_wait_time}); do
+        sleep 1 # give the DAD some time
+
+        addr=$(ifconfig ${interface} \
+            | grep "${new_ip6_address} prefixlen ${new_ip6_prefixlen}")
+
+        # tentative flag == DAD is still not complete
+        tentative=$(echo "${addr}" | grep tentative)
+        # dadfailed flag == address is already in use somewhere else
+        dadfailed=$(echo "${addr}" | grep duplicated)
+
+        if [ -n "${dadfailed}" ] ; then
+            # dad failed, remove the address
+            ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} -alias
+            exit_with_hooks 3
+        fi
+
+        if [ -z "${tentative}" ] ; then
+            if [ -n "${addr}" ]; then
+                # DAD is over
+                return 0
+            else
+                # address was auto-removed (or not added at all)
+                exit_with_hooks 3
+            fi
+        fi
+    done
+
+    return 0
+}
+
 # Must be used on exit.   Invokes the local dhcp client exit hooks, if any.
 exit_with_hooks() {
   exit_status=$1
@@ -195,7 +240,8 @@ if [ x$reason = xBOUND6 ]; then
     exit_with_hooks 2;
   fi
 
-  ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias
+  # Add address to interface, check for DAD if dad_wait_time > 0
+  add_ipv6_addr_with_DAD
 
   # Check for nameserver options.
   make_resolv_conf
index 07383b784745e7a54ac251c602a1af97982a92c0..fa086376a40607da06ca5b32028fc0b65761545e 100755 (executable)
@@ -48,6 +48,51 @@ exit_with_hooks() {
   exit $exit_status
 }
 
+# This function was largely borrowed from dhclient-script that
+# ships with Centos, authored by Jiri Popelka and David Cantrell
+# of Redhat. Thanks guys.
+add_ipv6_addr_with_DAD() {
+    ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias
+
+    if [ ${dad_wait_time} -le 0 ]
+    then
+        # if we're not waiting for DAD, assume we're good
+        return 0
+    fi
+
+    # Repeatedly test whether newly added address passed
+    # duplicate address detection (DAD)
+    for i in $(seq 1 ${dad_wait_time}); do
+        sleep 1 # give the DAD some time
+
+        addr=$(ifconfig ${interface} \
+            | grep "${new_ip6_address} prefixlen ${new_ip6_prefixlen}")
+
+        # tentative flag == DAD is still not complete
+        tentative=$(echo "${addr}" | grep tentative)
+        # dadfailed flag == address is already in use somewhere else
+        dadfailed=$(echo "${addr}" | grep duplicated)
+
+        if [ -n "${dadfailed}" ] ; then
+            # dad failed, remove the address
+            ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} -alias
+            exit_with_hooks 3
+        fi
+
+        if [ -z "${tentative}" ] ; then
+            if [ -n "${addr}" ]; then
+                # DAD is over
+                return 0
+            else
+                # address was auto-removed (or not added at all)
+                exit_with_hooks 3
+            fi
+        fi
+    done
+
+    return 0
+}
+
 # Invoke the local dhcp client enter hooks, if they exist.
 if [ -f /etc/dhclient-enter-hooks ]; then
   exit_status=0
@@ -314,7 +359,8 @@ if [ ${reason} = BOUND6 ] ; then
     exit_with_hooks 2;
   fi
 
-  ifconfig ${interface} inet6 alias ${new_ip6_address}/${new_ip6_prefixlen}
+  # Add address to interface, check for DAD if dad_wait_time > 0
+  add_ipv6_addr_with_DAD
 
   # Check for nameserver options.
   make_resolv_conf
old mode 100644 (file)
new mode 100755 (executable)
index e7f4746..afb7924
@@ -48,6 +48,53 @@ exit_with_hooks() {
   exit $exit_status
 }
 
+# This function was largely borrowed from dhclient-script that
+# ships with Centos, authored by Jiri Popelka and David Cantrell
+# of Redhat. Thanks guys.
+add_ipv6_addr_with_DAD() {
+    ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias
+
+    if [ ${dad_wait_time} -le 0 ]
+    then
+        # if we're not waiting for DAD, assume we're good
+        return 0
+    fi
+
+    # Repeatedly test whether newly added address passed
+    # duplicate address detection (DAD)
+    i=0
+    while [ $i -lt ${dad_wait_time} ]; do
+        sleep 1 # give the DAD some time
+
+        addr=$(ifconfig ${interface} \
+            | grep "${new_ip6_address} prefixlen ${new_ip6_prefixlen}")
+
+        # tentative flag == DAD is still not complete
+        tentative=$(echo "${addr}" | grep tentative)
+        # dadfailed flag == address is already in use somewhere else
+        dadfailed=$(echo "${addr}" | grep duplicated)
+
+        if [ -n "${dadfailed}" ] ; then
+            # dad failed, remove the address
+            ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} -alias
+            exit_with_hooks 3
+        fi
+
+        if [ -z "${tentative}" ] ; then
+            if [ -n "${addr}" ]; then
+                # DAD is over
+                return 0
+            else
+                # address was auto-removed (or not added at all)
+                exit_with_hooks 3
+            fi
+        fi
+        true $(( i++ ))
+    done
+
+    return 0
+}
+
 # Invoke the local dhcp client enter hooks, if they exist.
 if [ -f /etc/dhclient-enter-hooks ]; then
   exit_status=0
@@ -261,13 +308,14 @@ if [ ${reason} = PREINIT6 ] ; then
 
   # We need to give the kernel some time to active interface
   interface_up_wait_time=5
-  for i in $(seq 0 ${interface_up_wait_time})
-  do
+  i=0
+  while [ $i -lt ${interface_up_wait_time} ]; do
       ifconfig ${interface} | grep inactive >/dev/null 2>&1
       if [ $? -ne 0 ]; then
           break;
       fi
       sleep 1
+      true $(( i++ ))
   done
 
   # Wait for duplicate address detection for this interface if the
@@ -281,8 +329,8 @@ if [ ${reason} = PREINIT6 ] ; then
       if [ $? -eq 0 ]; then
           # Wait for duplicate address detection to complete or for
           # the timeout specified as --dad-wait-time.
-          for i in $(seq 0 $dad_wait_time)
-          do
+          i=0
+          while [ $i -lt ${dad_wait_time} ]; do
               # We're going to poll for the tentative flag every second.
               sleep 1
               ifconfig ${interface} | grep inet6 | grep tentative \
@@ -290,6 +338,7 @@ if [ ${reason} = PREINIT6 ] ; then
               if [ $? -ne 0 ]; then
                   break;
               fi
+          true $(( i++ ))
           done
       fi
   fi
@@ -308,7 +357,8 @@ if [ ${reason} = BOUND6 ] ; then
     exit_with_hooks 2;
   fi
 
-  ifconfig ${interface} inet6 alias ${new_ip6_address}/${new_ip6_prefixlen}
+  # Add address to interface, check for DAD if dad_wait_time > 0
+  add_ipv6_addr_with_DAD
 
   # Check for nameserver options.
   make_resolv_conf