Project

General

Profile

Issue #2472

ikev2 tunnel narrowing for netflix subnets

Added by Joe Lippa almost 8 years ago. Updated almost 8 years ago.

Status:
Closed
Priority:
Normal
Category:
configuration
Affected version:
5.6.1
Resolution:
No change required

Description

I have a large list of netflix ip subnets that I'd like to exclude from my tunnel. I know this type of configuration is possible as described in split tunneling but unfortunately I can't get my head around how to calculate the narrowing subnets. If I understand correctly, I believe I need leftsubnet list of subnets at the VPN server side where it will contain all subnets that are to be tunneled excluding the large list of netflix ip subnets that I have.

If correct, this means I really need the opposite of the large list of netflix ip subnets. Is there a reasonably easy way to calculate this?

History

#1 Updated by Tobias Brunner almost 8 years ago

  • Status changed from New to Feedback

Why not use passthrough policies instead (see e.g. UsableExamples)?

Is there a reasonably easy way to calculate this?

If you really want to do this, a Python script (using ipaddress.ip_network) should do the job reasonably well.

#2 Updated by Joe Lippa almost 8 years ago

Thanks Tobias I think you're right to suggest that using multiple passthrough policies is the way to go here.

There are a couple of hundred separate subnets for both Netflix and AWS that I'll have to exclude from the tunnel so I think that will mean the same number of separate passthrough policies. Even so if this is the case, I think this is going to be more readable than a big list of narrowing subnets.

As long as there is no performance penalty for configuring this many passthrough policies I think it will be perfectly fine.

Taking 1 given subnet as an example: 108.175.32.0/20, I assume something like this should work:

conn passthrough_base
    left=127.0.0.1
    right=127.0.0.1    
    type=passthrough
    auto=route

conn passthrough_1
    also=passthrough_base
    leftsubnet=108.175.32.0/20
    rightsubnet=108.175.32.0/20

#3 Updated by Tobias Brunner almost 8 years ago

There are a couple of hundred separate subnets for both Netflix and AWS that I'll have to exclude from the tunnel so I think that will mean the same number of separate passthrough policies. Even so if this is the case, I think this is going to be more readable than a big list of narrowing subnets.

You can just set a list of the excluded IPs/subnets in rightsubnet (comma-separated).

As long as there is no performance penalty for configuring this many passthrough policies I think it will be perfectly fine.

There is (you have to try how noticeable it really is), as policies are stored in a list (sorted by priority) in the kernel, unless, you configure charon.plugins.kernel-netlink.spdh_thresh in strongswan.conf, which enables hashing parts of the addresses/selectors to lookup policies (only works on newer kernels and with newer strongSwan releases).

Taking 1 given subnet as an example: 108.175.32.0/20, I assume something like this should work:

Set leftsubnet to your actual local subnet (or just 0.0.0.0/0), and as mentioned above you can set rightsubnet to a list of subnets.

#4 Updated by Joe Lippa almost 8 years ago

I think there's something not quite working as expected.

As a test I added the IP addresses for api.ipify.org to a test passthrough connection to test that curl api.ipify.org would return my local LAN public IP address and not the public IP of my remote VPN server.

Unfortunately it didn't seem to work because I see the IP of my remote VPN server returned from curl api.ipify.org which would seem to indicate the request to api.ipify.org is still going down the tunnel regardless of my configured passthrough connection.

Here's my ipsec.conf and ipsec statusall output:

# ipsec.conf - strongSwan IPsec configuration file

# basic configuration

config setup
    # strictcrlpolicy=yes
    # uniqueids=never

conn base
    fragmentation=yes

    closeaction=restart
    dpdaction=restart
    # dpddelay=35s
    keyingtries=%forever

    keyexchange=ikev2    
    ike=aes128gcm16-prfsha512-ecp256,aes128-sha2_512-prfsha512-ecp256,aes128-sha2_384-prfsha384-ecp256!
    esp=aes128gcm16-ecp256,aes128-sha2_512-prfsha512-ecp256!

    auto=start

conn vpn
    also=base

    right=46.101.30.31
    rightid=46.101.30.31
    rightsubnet=0.0.0.0/0
    rightauth=pubkey    

    leftsourceip=%config     
    leftauth=pubkey
    leftcert=joe.crt    
    left=%defaultroute
    leftsubnet=%dynamic,192.168.0.1/24
    leftupdown=/usr/lib/ipsec/strongswan-updown

conn lan_base
    also=base

    left=46.101.30.31
    leftid=46.101.30.31
    leftsubnet=0.0.0.0/0
    leftauth=pubkey

    rightauth=pubkey
    rightcert=joe.crt
    rightsubnet=%dynamic,192.168.0.1/24

conn my_laptop
    also=lan_base
    rightsourceip=192.168.0.11
    rightid=192.168.0.11

conn my_phone
    also=lan_base
    rightsourceip=192.168.0.12
    rightid=192.168.0.12

conn sony_bravia_tv
    also=lan_base
    rightsourceip=192.168.0.15
    rightid=192.168.0.15

# VPN passthrough / tunnel bypass rules
conn passthrough_base
    left=127.0.0.1
    right=127.0.0.1
    leftsubnet=192.168.0.1/24
    authby=never
    type=passthrough
    auto=route

# exclude all LAN IPs from the tunnel
conn lan_traffic_passthrough
    also=passthrough_base    
    rightsubnet=192.168.0.1/24

# exclude ipify subnets from the tunnel
conn ipify_passthrough
    also=passthrough_base
    rightsubnet=174.129.241.106/32,23.23.170.235/32,184.73.220.206/32
root@nanopineo2:~/strongswan-5.6.1# ipsec statusall
Status of IKE charon daemon (strongSwan 5.6.1, Linux 4.11.1-sun50iw2, aarch64):
  uptime: 10 minutes, since Nov 28 23:58:50 2017
  malloc: sbrk 2555904, mmap 0, used 463696, free 2092208
  worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 4
  loaded plugins: charon aes des rc2 sha2 sha1 md5 random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pkcs8 pkcs12 pgp dnskey sshkey pem openssl fips-prf curve25519 agent xcbc cmac hmac attr kernel-netlink resolve socket-default stroke vici updown eap-identity eap-md5 eap-gtc eap-mschapv2 xauth-generic counters
Virtual IP pools (size/online/offline):
  192.168.0.11: 1/0/0
  192.168.0.12: 1/0/0
  192.168.0.15: 1/0/0
Listening IP addresses:
  192.168.0.10
Connections:
        base:  %any...%any  IKEv2, dpddelay=30s
        base:   local:  uses public key authentication
        base:   remote: uses public key authentication
        base:   child:  dynamic === dynamic TUNNEL, dpdaction=restart
         vpn:  %any...46.101.30.31  IKEv2, dpddelay=30s
         vpn:   local:  [CN=joe] uses public key authentication
         vpn:    cert:  "CN=joe" 
         vpn:   remote: [46.101.30.31] uses public key authentication
         vpn:   child:  dynamic 192.168.0.0/24 === 0.0.0.0/0 TUNNEL, dpdaction=restart
    lan_base:  46.101.30.31...%any  IKEv2, dpddelay=30s
    lan_base:   local:  [46.101.30.31] uses public key authentication
    lan_base:   remote: [CN=joe] uses public key authentication
    lan_base:    cert:  "CN=joe" 
    lan_base:   child:  0.0.0.0/0 === dynamic 192.168.0.0/24 TUNNEL, dpdaction=restart
   my_laptop:  46.101.30.31...%any  IKEv2, dpddelay=30s
   my_laptop:   local:  [46.101.30.31] uses public key authentication
   my_laptop:   remote: [CN=joe] uses public key authentication
   my_laptop:    cert:  "CN=joe" 
   my_laptop:   child:  0.0.0.0/0 === dynamic 192.168.0.0/24 TUNNEL, dpdaction=restart
    my_phone:  46.101.30.31...%any  IKEv2, dpddelay=30s
    my_phone:   local:  [46.101.30.31] uses public key authentication
    my_phone:   remote: [CN=joe] uses public key authentication
    my_phone:    cert:  "CN=joe" 
    my_phone:   child:  0.0.0.0/0 === dynamic 192.168.0.0/24 TUNNEL, dpdaction=restart
sony_bravia_tv:  46.101.30.31...%any  IKEv2, dpddelay=30s
sony_bravia_tv:   local:  [46.101.30.31] uses public key authentication
sony_bravia_tv:   remote: [CN=joe] uses public key authentication
sony_bravia_tv:    cert:  "CN=joe" 
sony_bravia_tv:   child:  0.0.0.0/0 === dynamic 192.168.0.0/24 TUNNEL, dpdaction=restart
passthrough_base:  127.0.0.1...127.0.0.1  IKEv1/2
passthrough_base:   local:  [127.0.0.1] uses public key authentication
passthrough_base:   remote: [127.0.0.1] uses public key authentication
passthrough_base:   child:  dynamic === 192.168.0.0/24 PASS
lan_traffic_passthrough:   child:  192.168.0.0/24 === 192.168.0.0/24 PASS
ipify_passthrough:   child:  174.129.241.106/32 23.23.170.235/32 184.73.220.206/32 === 192.168.0.0/24 PASS
Shunted Connections:
passthrough_base:  dynamic === 192.168.0.0/24 PASS
lan_traffic_passthrough:  192.168.0.0/24 === 192.168.0.0/24 PASS
ipify_passthrough:  174.129.241.106/32 23.23.170.235/32 184.73.220.206/32 === 192.168.0.0/24 PASS
Security Associations (1 up, 0 connecting):
         vpn[2]: ESTABLISHED 10 minutes ago, 192.168.0.10[CN=joe]...46.101.30.31[46.101.30.31]
         vpn[2]: IKEv2 SPIs: 9dc40f7c15b43f2e_i* ef44c3bfe2308aab_r, public key reauthentication in 2 hours
         vpn[2]: IKE proposal: AES_GCM_16_128/PRF_HMAC_SHA2_512/ECP_256
         vpn{1}:  INSTALLED, TUNNEL, reqid 1, ESP in UDP SPIs: cfcc58cf_i c78c7398_o
         vpn{1}:  AES_GCM_16_128, 7431042 bytes_i (8183 pkts, 2s ago), 560903 bytes_o (5604 pkts, 2s ago), rekeying in 31 minutes
         vpn{1}:   10.19.48.2/32 === 0.0.0.0/0

#5 Updated by Tobias Brunner almost 8 years ago

These passthrough policies are reversed (there is a log message on level 2 in cfg that shows when/why, basically the reason is right=127.0.0.1, which is a local address). You might want to disable charon.plugins.stroke.allow_swap or switch to swanctl.conf.

#6 Updated by Joe Lippa almost 8 years ago

Thanks Tobias, clearly I wasn't 100% on the "l"eft ("l"ocal) / "r"ight("r"emote) convention in strongswan. I have rearranged my configuration so it's more clear that left is local and right is remote now.

Although I have for the moment decided to leave charon.plugins.stroke.allow_swap in it's default state (yes, allow_swap), my log appears to confirm that no left/right swap is occurring because there's no mention of either "left is other host, swapping ends" or "left nor right host is our side, assuming left=local" in my log which is running at level 2.

So it would appear that my test ipify passthrough just isn't working here in 5.6.1. Either that or my configuration has confused strongswan so it doesn't work.

I'd like to try and stay with using ipsec.conf if at all possible. It seems like what I'm trying to do should be possible: configure a passthrough for LAN traffic and also configure a passthrough for public subnets.

#7 Updated by Tobias Brunner almost 8 years ago

So it would appear that my test ipify passthrough just isn't working here in 5.6.1. Either that or my configuration has confused strongswan so it doesn't work.

Just look at the output of ipsec statusall or ip xfrm policy. If it still looks like the output you posted above the local and remote traffic selectors are clearly reversed (those on the left of === are local, those on the right remote). If you don't see a log message your logging configuration might be incorrect. Instead of disabling allow_swap (why are you reluctant to change it?) you can also remove right=127.0.0.1 (so it defaults to 0.0.0.0), left=127.0.0.1 should probably be enough to avoid that the connection is used for incoming packets.

#8 Updated by Joe Lippa almost 8 years ago

I believe I'm getting closer to understanding what's going on now (even though it's still not working :))

I can see that strongswan is doing it's best to enable the passthrough to work by adding the required routes to table 220:

root@nanopineo2:~# ip route show table 220
default via 192.168.0.1 dev eth0  proto static  src 192.168.0.10 
23.23.170.235 via 192.168.0.1 dev eth0  proto static  src 192.168.0.10 
174.129.241.106 via 192.168.0.1 dev eth0  proto static  src 192.168.0.10 
184.73.220.206 via 192.168.0.1 dev eth0  proto static  src 192.168.0.10 
192.168.0.0/24 dev eth0  proto static  src 192.168.0.10

..however I believe it's my custom updown script up-client section which is 'overriding' these routes, resulting in traffic being pushed down the tunnel regardless due to my SNAT rule:

up-client:)
    # custom iptables nat rule insert for LAN clients    
    iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT
    iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j SNAT --to-source $PLUTO_MY_SOURCEIP   

    # custom iptables MSS adjust rule insert for LAN clients
    iptables -t mangle -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1280

    if [ $VPN_LOGGING ]
    then
      echo "iptables up-client rules done" 

      logger -t $TAG -p $FAC_PRIO \
      "+ $PLUTO_PEER_ID $PLUTO_PEER -- $PLUTO_ME" + "iptables up-client rules done" 

    fi

    ;;

Putting the problem with the passthrough to one side for the moment, under normal circumstances my SNAT rule here works because I generally do want all traffic pushed down the tunnel. However I'm now trying to implement an exemption for some subnets.

Perhaps what I need to do here is take control of the passthrough subnets within my updown script and somehow add a PREROUTING exit rule to prevent the POSTROUTING SNAT rule for the target passthrough subnets.

Clearly I'm no expert with this stuff and any help / advice is very much appreciated. I can't help but think this is much harder than it should be and perhaps I'm doing everything completely wrong.

#9 Updated by Joe Lippa almost 8 years ago

It appears that I'm on the right lines because introducing these new -j RETURN exit rules into the POSTROUTING chain is making the passthrough work as it should:

up-client:)
# custom iptables nat rule insert for LAN clients    
  iptables -t nat -A POSTROUTING -d 174.129.241.106/32 -j RETURN
  iptables -t nat -A POSTROUTING -d 23.23.170.235/32 -j RETURN
  iptables -t nat -A POSTROUTING -d 184.73.220.206/32 -j RETURN

  iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT        
  iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j SNAT --to-source $PLUTO_MY_SOURCEIP   

  # custom iptables MSS adjust rule insert for LAN clients
  iptables -t mangle -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1280

  if [ $VPN_LOGGING ]
  then
    echo "iptables up-client rules done" 

    logger -t $TAG -p $FAC_PRIO \
    "+ $PLUTO_PEER_ID $PLUTO_PEER -- $PLUTO_ME" + "iptables up-client rules done" 
  fi

  ;;

If this is the solution I probably just need a better way of managing the list of exemption subnets now.

#10 Updated by Tobias Brunner almost 8 years ago

If this is the solution I probably just need a better way of managing the list of exemption subnets now.

You might only need these rules to avoid that packets to certain locations are tunneled (the outbound IPsec policy will only match if the source address matches the virtual IP, which will not be the case if the NAT rule is not applied). So passthrough policies might not be necessary (for local traffic generated on the server itself that could be different if the route installed in table 220 forces the virtual IP as source address, in the output above there is no such route, though). You can also combine multiple subnets in a single rule (just comma-separate them: -d 174.129.241.106/32,23.23.170.235/32,...).

#11 Updated by Joe Lippa almost 8 years ago

Thanks Tobias, I have success.

You were right there's no need for a passthrough policy here, with my setup at least, and a POSTROUTING exit rule alone is enough to prevent traffic being routed down the tunnel. Thank you for all your help.

For the record I boiled it down to look like the following using ipset (http://ipset.netfilter.org/ipset.man.html) where my subnet exemption rows are contained within the strongswan_updown_exemption_subnets.txt file:

up-client:)
  # custom iptables nat rule insert for LAN clients

  ipset -L tunnel_exemptions >/dev/null 2>&1
  if [ $? -ne 0 ]; then
    ipset create tunnel_exemptions hash:ip
    for subnet in $(cat /usr/lib/ipsec/strongswan_updown_exemption_subnets.txt); do 
      ipset add tunnel_exemptions $subnet;
    done
  fi

  iptables -t nat -A POSTROUTING -m set --match-set tunnel_exemptions dst -j RETURN

  iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT        
  iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j SNAT --to-source $PLUTO_MY_SOURCEIP   

  # custom iptables MSS adjust rule insert for LAN clients
  iptables -t mangle -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1280

  if [ $VPN_LOGGING ]
  then
    echo "iptables up-client rules done" 

    logger -t $TAG -p $FAC_PRIO \
    "+ $PLUTO_PEER_ID $PLUTO_PEER -- $PLUTO_ME" + "iptables up-client rules done" 
  fi

  ;;

#12 Updated by Tobias Brunner almost 8 years ago

  • Category set to configuration
  • Status changed from Feedback to Closed
  • Assignee set to Tobias Brunner
  • Resolution set to No change required

OK, great!