Source address selection depending on destination
Carmen Sandiego on Tuesday, 29 November 2011 03:12:56
Hi!
I have a rather complex setup in order to access certain destinations from different source addresses. This is necessary because several services (i.e. Google, YouTube, etc.) have their disadvantages if accessed with an address located in Germany. On the other hand I don't want to route my entire traffic via my VPN gateway in the US because of performance issues. In the old IPv4-world the solution was rather simple: NAT! A method I'm not willing to implement in IPv6.
As a result my router advertises two different prefixes to my LAN. Even the routing works fine - connections originating from an address belonging to the prefix in the US are routed though the VPN, others find their way to the internet directly (well, via the sixxs-tunnel).
Linux clients send their traffic to the correct router address, but they allways use the same source address. Let me (try to) explain. My radvd.conf looks like this:
interface six0
{
AdvSendAdvert on;
MinRtrAdvInterval 10;
MaxRtrAdvInterval 60;
AdvManagedFlag on;
AdvDefaultLifetime 3600;
AdvDefaultPreference medium;
AdvOtherConfigFlag on;
prefix 2001:aaaa::/64 {
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr on;
AdvValidLifetime 259200;
AdvPreferredLifetime 86400;
};
RDNSS 2001:aaaa::5 {
};
};
interface six1
{
AdvSendAdvert on;
MinRtrAdvInterval 10;
MaxRtrAdvInterval 60;
AdvManagedFlag on;
AdvDefaultLifetime 0;
AdvDefaultPreference low;
prefix 2001:bbbb:0:aa01::/64 {
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr on;
AdvValidLifetime 259200;
AdvPreferredLifetime 86400;
};
# VPN subnet
route 2001:bbbb::/48 {
AdvRoutePreference high;
AdvRouteLifetime 3600;
};
# Google
route 2607:F8B0::/32 {
AdvRoutePreference high;
AdvRouteLifetime 3600;
};
};
This advertises (or at least I intended to) a default gateway on six0 with medium preference accessible from 2001:aaaa::/64. Additionally it advertises a gateway to 2001:bbbb::/48 and 2607:F8B0::/32 with high preference on six1 accessible from 2001:bbbb:0:aa01::/64. The idea is that a client which is about to make a connection to 2001:bbbb::/48 or 2607:F8B0::/32 uses a source address with a prefix 2001:bbbb:0:aa01::/64 and sends the packet to six1. If the destination is anything else the client should use a 2001:aaaa::/64 address and send the packet to six0.
Linux clients honor the route preferences and send the data towards the correct router address but they use the wrong source address. In fact the go right through all eight rules of RFC 3484 and use the last address added to the interface.
Is this by design, a bug in the Linux IPv6 stack or did I do something wrong? If it helps I have the following entries in the clients /etc/sysctl.conf:
# Privacy Extensions
net.ipv6.conf.default.use_tempaddr = 2
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.eth0.use_tempaddr = 2
net.ipv6.conf.wlan0.use_tempaddr = 2
# Route Advertisement options
net.ipv6.conf.default.accept_ra_rt_info_max_plen = 128
net.ipv6.conf.all.accept_ra_rt_info_max_plen = 128
net.ipv6.conf.eth0.accept_ra_rt_info_max_plen = 128
net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen = 128
net.ipv6.conf.default.accept_ra_rtr_pref = 1
net.ipv6.conf.all.accept_ra_rtr_pref = 1
net.ipv6.conf.eth0.accept_ra_rtr_pref = 1
net.ipv6.conf.wlan0.accept_ra_rtr_pref = 1
BTW: A Windows 7 client acts exactly as I intended...
Fabian
Source address selection depending on destination
Jeroen Massar on Tuesday, 29 November 2011 09:53:58
You will want to check on the client Linux host:
ip -6 ro get 2001:db8::1
and do that for all the prefixes. That will tell you what the details for that route are, eg:
2001:db8::1 from :: via fe80::1 dev eth0 src 2001:db8::2 metric 0 cache
Do note that any kind of source address routing will always mess up somewhere, it is amazing that it works for Windows 7.
Source address selection depending on destination
Carmen Sandiego on Tuesday, 29 November 2011 17:54:01
Well, as I expected the output looks this way with the following affiliations:
six0 link local address on router: fe80::a:b:c:0
six1 link local address on router: fe80::a:b:c:1
wlan0 global address in 2001:aaaa::/64 prefix on client: 2001:aaaa::1234
wlan0 global address in 2001:bbbb::/64 prefix on client: 2001:bbbb::1234
(I used 2001:bbbb:0:aa01::/64 in my first post but this looks more clearly.)
# ip -6 ro get 2001:db8::1
2001:db8::1 from :: via fe80::a:b:c:0 dev wlan0 src 2001:aaaa::1234 metric 0
cache
# ip -6 ro get 2607:f8b0::/32
2607:f8b0:: from :: via fe80::a:b:c:1 dev wlan0 src 2001:aaaa::1234 metric 0
cache
I can change the behavior if I set the routes manually.
# ip -6 ro delete 2607:f8b0::/32 via fe80::a:b:c:1 dev wlan0
# ip -6 ro add 2607:f8b0::/32 via fe80::a:b:c:1 dev wlan0 src 2001:bbbb::1234
# ip -6 ro get 2001:db8::1
2001:db8::1 from :: via fe80::a:b:c:0 dev wlan0 src 2001:aaaa::1234 metric 0
cache
# ip -6 ro get 2607:f8b0::/32
2607:f8b0:: from :: via fe80::a:b:c:2 dev wlan0 src 2001:bbbb::1234 metric 0
cache
Of course it is a little more typing if 2001:bbbb::1234 is added last to the interface...
Now I'm looking for a solution that does this automaticly. I don't want to maintain all my 'special' routes on all clients. I mean, what's the point to put prefixes in route advertisements if they are only used as an decorative object to the interface? Or am I completly mistaken and it was never intended to assign addresses with different prefixes t
o one interface?
I also was suprised that this works for Windows 7. But now I think it's time to do amazing stuff with Linux! ;)
Source address selection depending on destination
Jeroen Massar on Tuesday, 29 November 2011 17:57:53 Now I'm looking for a solution that does this automaticly
Check first that you are running the newest kernel (3.1.x series) as they might have support for this.
Otherwise, you'll need to add kernel support for those special messages as that is where Linux handles this, unlike various other OSs which handle rtsol in userspace.
Source address selection depending on destination
Carmen Sandiego on Tuesday, 29 November 2011 18:11:32
I'm using a vanilla kernel 3.1.1 and have everything activated that looks like IPv6... Do you have anything special in mind?
~# uname -a
Linux grumman 3.1.1 #1 SMP PREEMPT Sun Nov 20 10:03:00 CET 2011 x86_64 GNU/Linux
~# zgrep -iE "ipv6|ip6" /proc/config.gz
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_SIT=y
CONFIG_IPV6_SIT_6RD=y
CONFIG_IPV6_NDISC_NODETYPE=y
CONFIG_IPV6_TUNNEL=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
CONFIG_IPV6_PIMSM_V2=y
# IPv6: Netfilter Configuration
CONFIG_NF_DEFRAG_IPV6=y
CONFIG_NF_CONNTRACK_IPV6=y
CONFIG_IP6_NF_QUEUE=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_MATCH_AH=y
CONFIG_IP6_NF_MATCH_EUI64=y
CONFIG_IP6_NF_MATCH_FRAG=y
CONFIG_IP6_NF_MATCH_OPTS=y
CONFIG_IP6_NF_MATCH_HL=y
CONFIG_IP6_NF_MATCH_IPV6HEADER=y
CONFIG_IP6_NF_MATCH_MH=y
CONFIG_IP6_NF_MATCH_RT=y
CONFIG_IP6_NF_TARGET_HL=y
CONFIG_IP6_NF_TARGET_LOG=y
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IP6_NF_MANGLE=y
CONFIG_IP6_NF_RAW=y
CONFIG_IP6_NF_SECURITY=y
CONFIG_BRIDGE_EBT_IP6=m
CONFIG_SLIP_MODE_SLIP6=y
Source address selection depending on destination
Jeroen Massar on Tuesday, 29 November 2011 18:17:20
If you already got the latest 3.1 then well, not much newer stuff there then.
And it seems to have been in there for a while already:
CONFIG_IPV6_ROUTER_PREF=y
Is the one that you would need, possibly it is broken.
"IPv6: Router Preference (RFC 4191) support"
found in Linux kernels: 2.6.172.6.39, 3.03.1, 3.2-rc+HEAD
Thus you got a long road of debugging left....
Source address selection depending on destination
Carmen Sandiego on Saturday, 17 December 2011 01:10:17
Just an update in case anyone else has this scenario... Here is my workaround:
I added the route 2001:aaaa::/48 to six0 in my radvd.conf. With these routes configured automaticly now, I am able to group my prefixes so I can use labels for source address selection. For this purpose I wrote a small shell script and put it into /etc/NetworkManager/dispatcher.d/.
#!/bin/bash
IFACE=$1;
ACTION=$2; # <up|down>
LABEL=100;
IFS="
";
case $ACTION in
up)
sleep 1;
ip addrlabel delete prefix ::/0 label 1;
for ROUTER in `ip -6 route show dev $IFACE |grep via |awk '{print $3}' |sort |uniq`; do
for PREFIX in `ip -6 route show dev $IFACE |grep $ROUTER |awk '{print $1}' |sed "s|default|::/0|"`; do
ip addrlabel add prefix $PREFIX label $LABEL;
done;
LABEL=$[$LABEL + 1];
done;
;;
down)
for i in `ip addrlabel show |grep "label 1[0-9][0-9]"`; do
PREFIX=$(echo $i |awk '{print $2}');
LABEL=$(echo $i |awk '{print $4}');
ip addrlabel delete prefix $PREFIX label $LABEL;
done;
ip addrlabel add prefix ::/0 label 1;
;;
*)
echo "Usage: $0 INTERFACE <up|down>";
exit 1;
;;
esac;
exit 0;
Again, this is just a workaround that works for me. It will not work in a setup with multiple routers for the same prefix, at least!
If there is a solution do distribute labels 'the right way' with route advertisement or DHCPv6, I'm all ears. After all RFC 4191 states in it's introduction that 'it is not recommended that routers "dump out" their entire routing tables to hosts.' But that is exactly what is going to happen when there are more services I would like to access with an US IPv6 address in the future. I think of imdb.com, hulu.com and several TV stations. For those I route about 100 IPv4 networks through my VPN at the moment...
Posting is only allowed when you are logged in. |