SNAT confusion
I have recently setup a SixXS IPv6 tunnel as my ISP only provides IPv4 currently.
Having a static IP address I have opted for a static tunnel to be configured - this works great until my Internet connection gets interrupted. The tunnel then disappears for an indeterminate period of time, eventually coming up sometimes many hours later.
I wasn't entirely sure if there was any "initiation" that needed to be done to get a tunnel to wake up, but some investigation showed that a tunnel is dumb - the packets just flow to the parent address, there is no establishing of a connection or such (like you would with a SSL VPN tunnel or similar).
So the question I was presented with was why were my dumb packets not getting to the other end of the tunnel?
After some time filtering out the chaff from tcpdump I could see that my packets were leaving my network with the incorrect IP4 address. How does this happen? For most people, it won't, but I have multiple IP4 addresses (might be worth something one day, right?) and my tunnel is configured against a non-default one or, a virtual interface on my router.
Whilst I had already setup a DNAT (aka forwarding) for the inbound tunnel data, I hadn't setup an outgoing SNAT rule. This meant that when data came in from my PoP (tunnel provider) it would setup ok - but if I tried to send data out first then it would attempt to setup a connection from the default address on the router. iptables (the Linux firewall) doesn't allow you to bind to virtual/alias interfaces (e.g. eth0:1), so instead you just have to hard-code the external address you want to use (PITA):
iptables -t nat -I POSTROUTING -o eth0 -p 41 -j SNAT --to-source XXX.XXX.XXX.XXX
Where the X's is the external IP address you wish to use (and replace eth0 with your external interface device).
Alas, whilst this command was the correct one, alone it did not work for me. Thanks to some help from #ipv6 on Freenode I discovered that the outgoing connection was already getting established before I could type in my new SNAT command. As such all outgoing data for this was on the default address. This is because the NAT table is only used initially on NEW connections, everything else follows the established configuration. To view this, you can search for "unknown" in your connection tracking file:
grep "unknown" /proc/self/net/ip_conntrack
This lists your current NATs. In my case I found that for protocol 41 (IPv6 tunnels) there was already one established on the default address.
By adding in the new SNAT rule into my firewall startup script, the command was in place before any such connections could be established and everything suddenly started to work.