[strongSwan] Using xfrm marks to select right tunnels based on uid

Noel Kuntze noel.kuntze+strongswan-users-ml at thermi.consulting
Wed Nov 29 19:41:19 CET 2017


Hi,

> I have set charon.install_routes = 0 to avoid installing default route to route table 220, so I can actually setup the second tunnel.

Set it to "no".

> So it seems that the kernel's source address selection does not work correctly in my case. I am able to workaround my troubles by specifying SNAT rules like:
> [...]
> This got me thinking that the source ip selection probably happens sooner than marking the packets.

It is exactly like that. Take a look at the flow graph for netfilter[1].

> So I tried  to insert my marking rules based on uid to OUTPUT chain of raw table. When I did this, it did not help and moreover, even the case with manual selection of source ip in curl stopped working.

I never used the uid PBR selector, so I can't tell you if some parts of it are broken - or not. Keep it simple and/or test other kernels. Maybe you need to disable the return path filter (rp_filter setting for the interface, all or default).

You could work around the problem by putting the processes in cgroups, setting the mark in the application's socket (maybe using some LD_PRELOAD hack) or something else.
If you use cgroups, you again need marking rules.

Kind regards

Noel

[1] inai.de/images/nf-packet-flow.png


On 28.11.2017 07:55, Jiri Horky wrote:
> Hi list,
>
> I am wondering if it is possible to create ~1000 of tunnels from a single linux machine for testing purposes and route the traffic based on UID of the processes. I was trying to do PoC with just two tunnels  using the following setup:
>
> strongswan-5.5.3, kernel 4.12.5-gentoo
>
> hotgeorge horky # cat /etc/ipsec.conf
> conn node13
>   auto=add
>   type=tunnel
>   keyexchange=ikev2
>   ike=aes256-sha1-modp1024!
>   esp=aes256-sha1-noesn!
>   left=%defaultroute
>   leftid="SomeID"
>   leftsourceip=%config4
>   right=node13
>   rightid=myrightid
>   rightsubnet=0.0.0.0/0 <http://0.0.0.0/0>
>   authby=psk
>   mark_out=13
>   leftupdown=/usr/bin/sudo -E /etc/ipsec_mark_updown
>
> conn node14
>   auto=add
>   type=tunnel
>   keyexchange=ikev2
>   ike=aes256-sha1-modp1024!
>   esp=aes256-sha1-noesn!
>   left=%defaultroute
>   leftid="SomeID"
>   leftsourceip=%config4
>   right=node14
>   rightid=myrightid
>   rightsubnet=0.0.0.0/0 <http://0.0.0.0/0>
>   authby=psk
>   mark_out=14
>   leftupdown=/usr/bin/sudo -E /etc/ipsec_mark_updown
>
> I have set charon.install_routes = 0 to avoid installing default route to route table 220, so I can actually setup the second tunnel.
>
> I use following static iptables rules to mark the traffic based on UID:
> iptables -t mangle -A OUTPUT -m owner --uid 1013 -j MARK --set-xmark 0xd/0xffffffff
> iptables -t mangle -A OUTPUT -m owner --uid 1014 -j MARK --set-xmark 0xe/0xffffffff
>
> The interesting content of /etc/ipsec_mark_updown script is the following:
> MY_DEFAULT_GW=10.7.65.1
> case $PLUTO_CONNECTION in
>   *node13*)
>   MARK=13
> ;;
>   *node14*)
>   MARK=14
> ;;
> esac
>
> ROUTE_TABLE=$((1000+MARK))
>
> case $PLUTO_VERB in
>   up-client)
> ip route flush table $ROUTE_TABLE
> ip rule del fwmark $MARK table $ROUTE_TABLE 2>/dev/null
> ip rule add priority 10 fwmark $MARK table $ROUTE_TABLE
> ip route add default via $MY_DEFAULT_GW proto static src $PLUTO_MY_SOURCEIP table $ROUTE_TABLE
>         ;;
>
> Now, if I fire up the two tunnels:
> ipsec up node13
> ipsec up node14
>
> I have the following routing rules:
> hotgeorge horky # ip rule list
> 0:from all lookup local 
> 10:from all fwmark 0xd lookup 1013 
> 10:from all fwmark 0xe lookup 1014 
> 220:from all lookup 220 
> 32766:from all lookup main 
> 32767:from all lookup default 
>
> And following routing table:
> hotgeorge horky # ip route list table 1013
> default via 10.7.65.1 dev wlo1  proto static  src 100.111.0.91 
> hotgeorge horky # ip route list table 1014
> default via 10.7.65.1 dev wlo1  proto static  src 100.111.0.167 
> hotgeorge horky # ip route list table 220
>
> Where table 220 is empty.
>
> The trouble is the if I execute curl under user test_1013 (with uid 1013), it times out on sending a DNS query:
> su test_1013 -c "curl http://ip-info.ff.avast.com/v1/info"
>
> When I manually specify the source address, it works:
>
> su test_1013 -c "curl http://ipv4bot.whatismyipaddress.com --interface 100.111.0.91 --dns-ipv4-addr 100.111.0.91"; echo
> 77.234.40.153
>
> su test_1014 -c "curl http://ipv4bot.whatismyipaddress.com --interface 100.111.0.167 --dns-ipv4-addr 100.111.0.167"; echo
> 77.234.40.182
>
> So it seems that the kernel's source address selection does not work correctly in my case. I am able to workaround my troubles by specifying SNAT rules like:
>
> iptables -t nat -A POSTROUTING -m mark --mark $MARK ! -s $PLUTO_MY_SOURCEIP -j SNAT --to-source $PLUTO_MY_SOURCEIP
>
> But I would like to avoid doing that.
>
> Could you please enlighten me what I am doing wrong? It seems that if I let strongwan install the routes to the table 220 (without any restrictions to marks), the source address is selected correctly. This got me thinking that the source ip selection probably happens sooner than marking the packets. So I tried  to insert my marking rules based on uid to OUTPUT chain of raw table. When I did this, it did not help and moreover, even the case with manual selection of source ip in curl stopped working.
>
> I would be grateful for any tips.
>
> Note: I know that using network namespaces could sound like a better idea than this. Unfortunatelly, even the newest kernel contain some race conditions when destroying namespaces rapidly preventing us to use this way.
>
> Thanks
> Jiri Horky

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.strongswan.org/pipermail/users/attachments/20171129/89326f1c/attachment.sig>


More information about the Users mailing list