I don’t yet have IPv6 native at home. Perhaps Verizon FiOS will provide it soon. In the meantime, I make use of Hurricane Electric, which seems to be everyone’s go-to ISP for tunnels.
This post isn’t about creating an IPv6 tunnel. It’s about making sure that tunnel is rebuilt after you have an IP address change. At home, my Verizon FiOS connection has a dynamic IP address. It changes from time to time, and without warning. This happened a few days ago, overnight.
HE support
The HE FAQ show what to do if your IPv4 endpoint address is dynamic. When I wrote this, the FAQ pointed you at this HE Forum post.
DHCP hooks
It was this post on FreeBSD Forums which pointed me towards using /etc/dhclient-exit-hooks, which contains this:
$ cat /etc/dhclient-exit-hooks #!/bin/sh logger -t dyndns /etc/dhclient-exit-hooks has been invoked logger -t dyndns "'$reason' '$interface' '$medium' '$new_ip_address' '$old_ip_address'" if [ "${old_ip_address}" = "" ] then if [ -e /var/tmp/currentIP ] then old_ip_address=`/bin/cat /var/tmp/currentIP` fi fi if [ "$new_ip_address" = "" ] ; then new_ip_address=`/sbin/ifconfig fxp0 | /usr/bin/sed -n '/.inet /{s///;s/ .*//;p;}'` logger -t dyndns "new IP from ifconfig is ${new_ip_address}" else logger -t dyndns "new IP from dhclient is ${new_ip_address}" fi if [ "${new_ip_address}" = "" -o "${new_ip_address}" = "${old_ip_address}" ] ; then echo "nochg ${old_ip_address}" logger -t dyndns "Ooops, IP has not actually changed from ${old_ip_address}" else /usr/local/bin/curl -v --netrc "https://ipv4.tunnelbroker.net/nic/update?hostname=XXXXX" ifconfig gif0 down ifconfig gif0 delete route delete -inet6 default -interface gif0 ifconfig gif0 tunnel ${new_ip_address} 209.51.161.14 ifconfig gif0 inet6 2001:470:1f06:9ea::2 2001:470:1f06:9ea::1 prefixlen 128 route -n add -inet6 default 2001:470:1f06:9ea::1 ifconfig gif0 up echo "${new_ip_address}" > /var/tmp/currentIP logger -t dyndns "updated from ${old_ip_address} to ${new_ip_address}" fi logger -t dyndns "all done here"
You will see a curl above. That call will use the contents of /root/.netrc, which contains:
machine ipv4.tunnelbroker.net login MYLOGIN password MYPASSWORD
That curl request contains a hostname paramter. This is your tunnel id, which you can get from https://www.tunnelbroker.net/. Login, and click on the tunnel in question. Under Tunnel Details, you will see Tunnel ID:. That is the value you want.
So what happens here?
This is what happens when you manually invoke that curl command. I did this back in October, when I started writing this post.
# /usr/local/bin/curl -v --netrc "https://ipv4.tunnelbroker.net/nic/update?hostname=MYTUNNELID" * Adding handle: conn: 0x801c62600 * Adding handle: send: 0 * Adding handle: recv: 0 * Curl_addHandleToPipeline: length: 1 * - Conn 0 (0x801c62600) send_pipe: 1, recv_pipe: 0 * About to connect() to ipv4.tunnelbroker.net port 443 (#0) * Trying 64.62.200.2... * Connected to ipv4.tunnelbroker.net (64.62.200.2) port 443 (#0) * successfully set certificate verify locations: * CAfile: /usr/local/share/certs/ca-root-nss.crt CApath: none * SSLv3, TLS handshake, Client hello (1): * SSLv3, TLS handshake, Server hello (2): * SSLv3, TLS handshake, CERT (11): * SSLv3, TLS handshake, Server key exchange (12): * SSLv3, TLS handshake, Server finished (14): * SSLv3, TLS handshake, Client key exchange (16): * SSLv3, TLS change cipher, Client hello (1): * SSLv3, TLS handshake, Finished (20): * SSLv3, TLS change cipher, Client hello (1): * SSLv3, TLS handshake, Finished (20): * SSL connection using DHE-RSA-AES256-SHA * Server certificate: * subject: O=tunnelbroker.net; OU=Domain Control Validated; CN=tunnelbroker.net * start date: 2011-11-05 00:44:14 GMT * expire date: 2016-11-04 21:10:42 GMT * subjectAltName: ipv4.tunnelbroker.net matched * issuer: C=US; ST=Arizona; L=Scottsdale; O=Starfield Technologies, Inc.; OU=http://certificates.starfieldtech.com/repository; CN=Starfield Secure Certification Authority; serialNumber=10688435 * SSL certificate verify ok. * Server auth using Basic with user 'xxxxxxx' > GET /nic/update?hostname=xxxxxx HTTP/1.1 > Authorization: Basic ZHZsOnByb2ZsZXg= > User-Agent: curl/7.31.0 > Host: ipv4.tunnelbroker.net > Accept: */* > * HTTP 1.0, assume close after body < HTTP/1.0 200 ok < Date: Wed, 02 Oct 2013 11:48:03 GMT < Server: Apache/2.2.8 (Ubuntu) DAV/2 SVN/1.4.6 PHP/5.2.4-2ubuntu5.17 with Suhosin-Patch mod_ssl/2.2.8 OpenSSL/0.9.8g < X-Powered-By: PHP/5.2.4-2ubuntu5.17 < Set-Cookie: referer=Direct+Access < Content-Length: 20 < Connection: close < Content-Type: text/html; charset=utf-8 < good 98.111.147.220 * Closing connection 0 * SSLv3, TLS alert, Client hello (1): #
After that, to recontruct the tunnel, you need this:
ifconfig gif0 down ifconfig gif0 delete route delete -inet6 default -interface gif0 ifconfig gif0 tunnel 98.111.147.220 209.51.161.14 ifconfig gif0 inet6 2001:470:1f06:9ea::2 2001:470:1f06:9ea::1 prefixlen 128 route -n add -inet6 default 2001:470:1f06:9ea::1 ifconfig gif0 up
… where 98.111.147.220 was my new IP address.
All that should happen within the dhclient-exit-hooks script. Or so I thought…
What happened next?
After setting this up, I waited for an IP address change. It took a few months, but it happened a few days ago. Here is what I found in /var/log/messages:
Jan 8 05:14:39 bast ntpd[1808]: sendto(204.2.134.163) (fd=26): No route to host Jan 8 05:14:40 bast ntpd[1808]: sendto(2001:470:8:104::2) (fd=30): No route to host Jan 8 05:14:43 bast dyndns: /etc/dhclient-exit-hooks has been invoked Jan 8 05:14:43 bast dyndns: 'ARPSEND' 'fxp0' '' '' '' Jan 8 05:14:43 bast dyndns: new IP from ifconfig is 71.185.48.53 Jan 8 05:14:43 bast dyndns: Ooops, IP has not actually changed from 71.185.48.53 Jan 8 05:14:43 bast dyndns: all done here Jan 8 05:14:45 bast dyndns: /etc/dhclient-exit-hooks has been invoked Jan 8 05:14:45 bast dyndns: 'ARPCHECK' 'fxp0' '' '' '' Jan 8 05:14:45 bast dyndns: new IP from ifconfig is 71.185.48.53 Jan 8 05:14:45 bast dyndns: Ooops, IP has not actually changed from 71.185.48.53 Jan 8 05:14:45 bast dyndns: all done here Jan 8 05:14:46 bast dhclient: New IP Address (fxp0): 108.36.196.71 Jan 8 05:14:46 bast dhclient: New Subnet Mask (fxp0): 255.255.255.0 Jan 8 05:14:46 bast dhclient: New Broadcast Address (fxp0): 108.36.196.255 Jan 8 05:14:46 bast dhclient: New Routers (fxp0): 108.36.196.1 Jan 8 05:14:46 bast dyndns: /etc/dhclient-exit-hooks has been invoked Jan 8 05:14:46 bast dyndns: 'BOUND' 'fxp0' '' '108.36.196.71' '' Jan 8 05:14:46 bast dyndns: new IP from dhclient is 108.36.196.71 Jan 8 05:14:46 bast dyndns: updated from 71.185.48.53 to 108.36.196.71 Jan 8 05:14:46 bast dyndns: all done here
You can see that at 05:14:46, the IP address was finally BOUND, and that’s when the BIG part of the script is invoked.
But wait, there’s more
Sadly, I had removed curl from my system a few days before this occurred. I have reinstalled it, and now I’m waiting for the next IP address change.
Oh, wait, this won’t work for booting. When you boot, your IP address changes. So this entry in /etc/rc.conf will not work. It needs to be scripted…
That’s because /etc/rc.conf won’t know what address to use….