If you read the doco (like “man gai.conf
“) you would be forgiven for thinking that the contents of /etc/gai.conf
controlled source and destination address selection in IPv6. You would be wrong.
It does control destination address selection; it is completely ignored for source address selection. Disclaimer: I’m talking here about Ubuntu, but I suspect all Debian derivatives and probably all Linuxes have the same issue.
/etc/gai.conf
contains three types of information: A label table, a precedence table, and an IPv4 scopes table. The label information is needed by source address selection; all three types of information are needed by destination address selection.
For destination address selection, /etc/gai.conf
works as advertised. If you make a change to /etc/gai.conf
, the new information will be used immediately by all new processes. Running processes will need to be restarted before they “see” the change. You can put “reload yes
” in the file to cause even running processes to react immediately to changes, but this will cause all processes to check the last-modified timestamp on /etc/gai.conf
(and, worst-case, re-read it) every time they do a DNS lookup, which is probably a bad idea. The comments in /etc/gai.conf
suggest you should not do that.
However, for source address selection, /etc/gai.conf
is ignored. So we have to find another way to get the label information used.
The obvious way is simply to use the ip
program to insert it as needed:
ip addrlabel add prefix 2001:db8:0:100::/64 label 25
But you would need to do this at startup, for a bunch of prefixes, and where would the information be stored?
I like the idea of all address selection information being in one place. Since destination address selection is already controlled via /etc/gai.conf
, and the label table used should really be the same for destination and source address selection, it makes sense to use the /etc/gai.conf
file to control source address selection as its designers apparently intended. Therefore we will, in the immortal words of Jean Luc Picard, “make it so” with an appropriate script.
As long as /etc/gai.conf
exists, and as long as there is at least one line beginning with “label
“, the script below will replace all existing source address selection information with the information out of /etc/gai.conf
. This is also the behaviour described in /etc/gai.conf
and its man page.
There is no easy way to implement the automatic “reload” facility. For destination address selection, there is an easy and natural per-process synchronisation via the getaddrinfo()
calls each process makes. For source address selection, there is no natural synchronisation point. A reload has to first remove all destination address selection information, then replace it, and the replacement is not atomic. If this were to happen just as some process was trying to make a network connection, the results might be less than optimal.
This script is therefore best run at startup, along with other network related startup scripts. However, it can also be run manually whenever needed. The script must be run as root.
Save the script as /etc/init.d/ipv6_sas
. Set up SysV startup links to start it in runlevels 2, 3, 4 and 5, and stop it in runlevels 0, 1 and 6. Alternatively, add a suitable conf file in /etc/init
(see below) and let Upstart do the work.
#!/bin/sh GAICONF=/etc/gai.conf PREFIX=$1 LABEL=$2 # This case statement allows this script to be used as a SysV # startup script. Delete it if you will only be running the # script manually or via Upstart. case "$1" in start) $0 exit $? ;; restart|reload|force-reload) $0 exit $? ;; stop) # No-op exit 0 ;; esac if [ -z $PREFIX ] ; then if [ -r $GAICONF ] ; then # Is there at least one "label" line? grep "^\s*label" /etc/gai.conf > /dev/null RETCODE=$? if [ $RETCODE = 0 ] ; then echo "flushing existing source address selection info..." ip addrlabel flush echo "adding source address selection info from $GAICONF..." grep "^\s*label" /etc/gai.conf | cut -d\ -f2- | xargs -n2 $0 echo "...done." else echo "$GAICONF contains no \"label\" lines. No changes made." fi else echo "$GAICONF not found or not readable. No changes made." fi exit 0 else echo "\tadding prefix $PREFIX with label $LABEL" ip addrlabel add prefix $PREFIX label $LABEL fi
To run this script via Upstart, put these lines in a file called /etc/init/ipv6_sas.conf
:
description "Read IPv6 source address selection rules" author "Karl Auer <kauer@biplane.com.au>" start on (net-device-up and local-filesystems and runlevel [2345]) stop on runlevel [016] respawn env HOME=/ umask 007 exec /etc/init.d/ipv6_sas
[This article was copied from my personal blog, where it was originally posted on July 25, 2012]