Commit d394b602 authored by Thomas Markwalder's avatar Thomas Markwalder

[master] Added DAD error checking on BOUND6 to client scripts

    Merges in rt46805.
parent d638452e
...@@ -87,6 +87,16 @@ ISC DHCP is open source software maintained by Internet Systems ...@@ -87,6 +87,16 @@ ISC DHCP is open source software maintained by Internet Systems
Consortium. This product includes cryptographic software written Consortium. This product includes cryptographic software written
by Eric Young (eay@cryptsoft.com). 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) Changes since 4.4.0b1 (Bug Fixes)
- Added clarifying text to dhcpd.conf.5 explaining the class match expressions - Added clarifying text to dhcpd.conf.5 explaining the class match expressions
......
...@@ -92,6 +92,51 @@ exit_with_hooks() { ...@@ -92,6 +92,51 @@ exit_with_hooks() {
exit $exit_status 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. # Invoke the local dhcp client enter hooks, if they exist.
if [ -f /etc/dhclient-enter-hooks ]; then if [ -f /etc/dhclient-enter-hooks ]; then
exit_status=0 exit_status=0
...@@ -385,7 +430,8 @@ if [ ${reason} = BOUND6 ] ; then ...@@ -385,7 +430,8 @@ if [ ${reason} = BOUND6 ] ; then
exit_with_hooks 2; exit_with_hooks 2;
fi 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. # Check for nameserver options.
make_resolv_conf make_resolv_conf
......
...@@ -177,6 +177,55 @@ exit_with_hooks() { ...@@ -177,6 +177,55 @@ exit_with_hooks() {
exit $exit_status 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. # Invoke the local dhcp client enter hooks, if they exist.
run_hook /etc/dhclient-enter-hooks run_hook /etc/dhclient-enter-hooks
...@@ -401,8 +450,7 @@ case "$reason" in ...@@ -401,8 +450,7 @@ case "$reason" in
BOUND6|RENEW6|REBIND6) BOUND6|RENEW6|REBIND6)
if [ "${new_ip6_address}" ] && [ "${new_ip6_prefixlen}" ]; then if [ "${new_ip6_address}" ] && [ "${new_ip6_prefixlen}" ]; then
# set leased IP # set leased IP
${ip} -6 addr add ${new_ip6_address}/${new_ip6_prefixlen} \ add_ipv6_addr_with_DAD
dev ${interface} scope global
fi fi
# update /etc/resolv.conf # update /etc/resolv.conf
......
...@@ -108,6 +108,51 @@ commit_resolv_conf() { ...@@ -108,6 +108,51 @@ commit_resolv_conf() {
to_commit="done" 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. # Must be used on exit. Invokes the local dhcp client exit hooks, if any.
exit_with_hooks() { exit_with_hooks() {
exit_status=$1 exit_status=$1
...@@ -195,7 +240,8 @@ if [ x$reason = xBOUND6 ]; then ...@@ -195,7 +240,8 @@ if [ x$reason = xBOUND6 ]; then
exit_with_hooks 2; exit_with_hooks 2;
fi 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. # Check for nameserver options.
make_resolv_conf make_resolv_conf
......
...@@ -48,6 +48,51 @@ exit_with_hooks() { ...@@ -48,6 +48,51 @@ exit_with_hooks() {
exit $exit_status 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. # Invoke the local dhcp client enter hooks, if they exist.
if [ -f /etc/dhclient-enter-hooks ]; then if [ -f /etc/dhclient-enter-hooks ]; then
exit_status=0 exit_status=0
...@@ -314,7 +359,8 @@ if [ ${reason} = BOUND6 ] ; then ...@@ -314,7 +359,8 @@ if [ ${reason} = BOUND6 ] ; then
exit_with_hooks 2; exit_with_hooks 2;
fi 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. # Check for nameserver options.
make_resolv_conf make_resolv_conf
......
...@@ -48,6 +48,53 @@ exit_with_hooks() { ...@@ -48,6 +48,53 @@ exit_with_hooks() {
exit $exit_status 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. # Invoke the local dhcp client enter hooks, if they exist.
if [ -f /etc/dhclient-enter-hooks ]; then if [ -f /etc/dhclient-enter-hooks ]; then
exit_status=0 exit_status=0
...@@ -261,13 +308,14 @@ if [ ${reason} = PREINIT6 ] ; then ...@@ -261,13 +308,14 @@ if [ ${reason} = PREINIT6 ] ; then
# We need to give the kernel some time to active interface # We need to give the kernel some time to active interface
interface_up_wait_time=5 interface_up_wait_time=5
for i in $(seq 0 ${interface_up_wait_time}) i=0
do while [ $i -lt ${interface_up_wait_time} ]; do
ifconfig ${interface} | grep inactive >/dev/null 2>&1 ifconfig ${interface} | grep inactive >/dev/null 2>&1
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
break; break;
fi fi
sleep 1 sleep 1
true $(( i++ ))
done done
# Wait for duplicate address detection for this interface if the # Wait for duplicate address detection for this interface if the
...@@ -281,8 +329,8 @@ if [ ${reason} = PREINIT6 ] ; then ...@@ -281,8 +329,8 @@ if [ ${reason} = PREINIT6 ] ; then
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
# Wait for duplicate address detection to complete or for # Wait for duplicate address detection to complete or for
# the timeout specified as --dad-wait-time. # the timeout specified as --dad-wait-time.
for i in $(seq 0 $dad_wait_time) i=0
do while [ $i -lt ${dad_wait_time} ]; do
# We're going to poll for the tentative flag every second. # We're going to poll for the tentative flag every second.
sleep 1 sleep 1
ifconfig ${interface} | grep inet6 | grep tentative \ ifconfig ${interface} | grep inet6 | grep tentative \
...@@ -290,6 +338,7 @@ if [ ${reason} = PREINIT6 ] ; then ...@@ -290,6 +338,7 @@ if [ ${reason} = PREINIT6 ] ; then
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
break; break;
fi fi
true $(( i++ ))
done done
fi fi
fi fi
...@@ -308,7 +357,8 @@ if [ ${reason} = BOUND6 ] ; then ...@@ -308,7 +357,8 @@ if [ ${reason} = BOUND6 ] ; then
exit_with_hooks 2; exit_with_hooks 2;
fi 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. # Check for nameserver options.
make_resolv_conf make_resolv_conf
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment