summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Markwalder <tmark@isc.org>2018-01-12 10:12:41 -0500
committerThomas Markwalder <tmark@isc.org>2018-01-12 10:12:41 -0500
commitd394b602d43f24cd96fff3fbfb0c7b386b352cca (patch)
tree14a33169b67a6ac01e4c6d251a3702489ec899e0
parentd638452ea1a83e12f61e64fe39838a74e453f40a (diff)
downloadisc-dhcp-d394b602d43f24cd96fff3fbfb0c7b386b352cca.tar.gz
[master] Added DAD error checking on BOUND6 to client scripts
Merges in rt46805.
-rw-r--r--RELNOTES10
-rwxr-xr-xclient/scripts/freebsd48
-rwxr-xr-xclient/scripts/linux52
-rwxr-xr-xclient/scripts/macos48
-rwxr-xr-xclient/scripts/netbsd48
-rwxr-xr-x[-rw-r--r--]client/scripts/openbsd60
6 files changed, 256 insertions, 10 deletions
diff --git a/RELNOTES b/RELNOTES
index 33e8ee44..05d035bf 100644
--- 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
diff --git a/client/scripts/freebsd b/client/scripts/freebsd
index 8f3e2a23..7c073f86 100755
--- a/client/scripts/freebsd
+++ b/client/scripts/freebsd
@@ -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
diff --git a/client/scripts/linux b/client/scripts/linux
index 5fb16121..0c429697 100755
--- a/client/scripts/linux
+++ b/client/scripts/linux
@@ -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
diff --git a/client/scripts/macos b/client/scripts/macos
index a896b1e9..0164b1f0 100755
--- a/client/scripts/macos
+++ b/client/scripts/macos
@@ -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
diff --git a/client/scripts/netbsd b/client/scripts/netbsd
index 07383b78..fa086376 100755
--- a/client/scripts/netbsd
+++ b/client/scripts/netbsd
@@ -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
diff --git a/client/scripts/openbsd b/client/scripts/openbsd
index e7f4746f..afb79241 100644..100755
--- a/client/scripts/openbsd
+++ b/client/scripts/openbsd
@@ -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