Services don’t bind to an IPv6 address

If you’re using a Linux system to provide IPv6 services, you may notice that some services don’t bind to a specific IPv6 address during system boot. Usually the symptom will be messages in the syslog where the daemons state “bind to port [#] on [IPv6 address] failed: Cannot assign requested address“, and that a simple restart of the service after booting has finished solves the problem.
In my case the issue occured with sshd and sometimes iscsi_trgt on the Debian Wheezy NAS system, which is also the DNS, DHCP, NTP, Kickstart etc server in my lab environment.

The reason is that the IPv6 addresses are not instantly up and usable once the interface is configured. One of the numerous new features of IPv6 are extended states and scopes of interfaces and addresses. Even static global IPv6 addresses go through a “tentative” phase, in which the uniqueness of the address is verified by the host, see RFC 4862. During this phase, which can take some seconds, the address is not finally assigned to an interface and therefore not usable. Daemons trying to bind to that address will fail with the mentioned error message.

The workaround is to pause the startup process until the “tentative” phase has ended. On a Debian system the following script will do the job. Create /etc/network/if-up.d/ipv6-wait and make sure it is executable (chmod 755).

#!/bin/sh
#
# Wait for all global IPv6 addresses to leave the "tentative" state

set -e

# Don't care about the loopback interface
[ "$IFACE" = lo ] && exit 0

# Only run from ifup
[ "$MODE" != start ] && exit 0

# Don't wait forever
COUNTDOWN=30

# Check interface status and wait until its global IPv6 address(es) leaves the "tentative" state
while [ ${COUNTDOWN} -gt 0 -a -n "$(ip -6 addr show dev ${IFACE} scope global tentative)" ]
  do
    # Make some noise
    echo "Waiting for interface ${IFACE} IPv6 address(es) to leave the \"tentative\" state"
    COUNTDOWN=$(($COUNTDOWN - 1))
    sleep 1
  done

# Done
exit 0

From now on the system startup may take a bit longer, but all services will reliably bind to specific global IPv6 addresses. Well, to be perfectly honest I have tested this with static addresses only. Let me know if you observe a different behaviour with DHCPv6 etc.

The script and its location are valid for Debian [Wheezy] – if you use a different Linux distribution you will most likely have to find the right place & filename yourself. Please help others by sharing your findings.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

code