Kill-switch for strongSwan IKEv2 with iptables

Hello.

How do I add iptables that block Internet Service Provider traffic and only allow IPSEC traffic?

I only found these rules in the forum:

iptables -I INPUT -m policy --dir in --pol ipsec --proto esp -j ACCEPT 
iptables -I FORWARD -m policy --dir in --pol ipsec --proto esp -j ACCEPT
iptables -I FORWARD -m policy --dir out --pol ipsec --proto esp -j ACCEPT
iptables -I OUTPUT -m policy --dir out --pol ipsec --proto esp -j ACCEPT
iptables -t nat -I POSTROUTING -m policy --pol ipsec --dir out -j ACCEPT

I do not know much about iptables, but the following iptables have no effect.
/etc/firewall.user:

	#Flush tables
	iptables -F
	iptables -F INPUT
	iptables -F OUTPUT
	iptables -F FORWARD
	iptables -F -t nat
	iptables -X
	
	#Set Default Policys
	iptables -P INPUT DROP
	iptables -P OUTPUT DROP
	iptables -P FORWARD DROP

	#Allow DNS lokal
	iptables -A INPUT -p udp --sport 53 -j ACCEPT
	iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

	#Allow DNS
	iptables -A FORWARD -p udp --destination-port 53 -j ACCEPT
	iptables -A FORWARD -p udp --source-port 53 -j ACCEPT

	#VPN-Configuration
	iptables -A FORWARD -p 50 -j ACCEPT
	iptables -A FORWARD -p 51 -j ACCEPT
	iptables -A FORWARD -p udp --dport 500 -j ACCEPT
	iptables -A FORWARD -p udp --sport 500 -j ACCEPT
	iptables -A FORWARD -p udp --dport 4500 -j ACCEPT
	iptables -A FORWARD -p udp --sport 4500 -j ACCEPT
	iptables -t nat -A PREROUTING -i br-lan -p udp --dport 50 -j DNAT --to 192.168.1.1 :50
	iptables -t nat -A PREROUTING -i br-lan -p udp --dport 51 -j DNAT --to 192.168.1.1:51
	iptables -t nat -A PREROUTING -i br-lan -p udp --dport 53 -j DNAT --to 192.168.1.1:53
	iptables -t nat -A PREROUTING -i br-lan -p udp --dport 500 -j DNAT --to 192.168.1.1:500
	iptables -t nat -A PREROUTING -i br-lan -p udp --dport 4500 -j DNAT --to 192.168.1.1:4500

	#Activate routing
	iptables -t nat -I POSTROUTING -m policy --pol ipsec --dir out -j ACCEPT

What is missing or what is wrong?

Personally I would use openwrt's firewall, and configure the general settings to input reject, output reject and forward reject, and then remove the default lan to wan forwarding. Then add traffic rules for ESP and isakmp (udp port 500).

In /etc/firewall.user I use the following rules for my IPsec VPN. Replace dmz with wan if you connect to an external party service.

# Don't SNAT to IPsec VPN
iptables -t nat -A postrouting_wan_rule -m policy --dir out --pol ipsec -j ACCEPT

# IPsec VPNs are in the DMZ zone
iptables -A forwarding_rule -m policy --dir in --pol ipsec -m conntrack --ctstate NEW -j zone_dmz_forward
ip6tables -A forwarding_rule -m policy --dir in --pol ipsec -m conntrack --ctstate NEW -j zone_dmz_forward

# Input from IPsec VPN
#iptables -A input_wan_rule -m policy --dir in --pol ipsec -m conntrack --ctstate NEW -j ACCEPT
#ip6tables -A input_wan_rule -m policy --dir in --pol ipsec -m conntrack --ctstate NEW -j ACCEPT

@mikma

Thank you very much for the description, but I am doing something wrong.

Here is my configuration:

/etc/config/firewall:

.
.
.

config rule
	option name 'Allow-ESP-input'
	option src 'wan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-IKE-input'
	option src 'wan'
	option dest_port '500 4500'
	option proto 'udp'
	option target 'ACCEPT'

/etc/firewall.user:

.
.
.

# Don't SNAT to IPsec VPN
iptables -t nat -A postrouting_wan_rule -m policy --dir out --pol ipsec -j ACCEPT

# IPsec VPNs are in the WAN zone
iptables -A forwarding_rule -m policy --dir in --pol ipsec -m conntrack --ctstate NEW -j zone_wan_forward
ip6tables -A forwarding_rule -m policy --dir in --pol ipsec -m conntrack --ctstate NEW -j zone_wan_forward

# Input from IPsec VPN
#iptables -A input_wan_rule -m policy --dir in --pol ipsec -m conntrack --ctstate NEW -j ACCEPT
#ip6tables -A input_wan_rule -m policy --dir in --pol ipsec -m conntrack --ctstate NEW -j ACCEPT

You should set output=reject also in the wan zone, and add rules for the traffic you want to allow, i.e. ESP, IKE, and also DHCP if you have a dynamic IPv4 address on wan.

Strange. If I remove the default lan to wan forwarding rule, then I won't be able to use ipsec to access the internet anymore.
If I set output=reject also in the wan zone, then the ipsec connection is no longer established.

You mean these rules?

/etc/config/firewall:

config rule
	option name 'Allow-ESP-input'
	option src 'wan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-IKE-input'
	option src 'wan'
	option dest_port '500 4500'
	option proto 'udp'
	option target 'ACCEPT'

How do I do that for DHCP?

You probably should use a separate zone for the traffic sent via vpn, for example called the vpn zone. (I call it dmz since it's my own private vpn server.)

1 Like

@mikma

I tried adding "IpsecFW" firewall rule:

/etc/config/firewall:

config zone                   
        option name 'IpsecFW'   
        option input 'ACCEPT' 
        option output 'ACCEPT'
        option forward 'ACCEPT'
        option subnet '192.168.1.0/24'

config forwarding
	option dest 'IpsecFW'
	option src 'lan'

But it doesn't work.

I tried subnet 0.0.0.0/0. It worked with ipsec IP and with WAN IP. Maybe 192.168.1.0/24 is wrong subnet?

Ipsec has no interface. How do you bind ipsec with the firewall?

As an alternative, use a XFRM interface (I have not tried this).

Hello mpa.

I have already tried your instructions in the thread "IPsec site-to-site tunnel".
Without success. Something is wrong or missing in my configuration.

Here is my last IKEv2 configuration.

I am trying to add an xfrm interface via this instruction too:

ip link add <name> type xfrm dev <underlying interface> if_id <interface ID>
ip link set <name> up

For example, if I use this command:

ip link add ipsec0 type xfrm dev lo if_id 1

Then I get as output:

RTNETLINK answers: Not supported

Does anyone have an idea how the error message can be solved?

I have tried another method.

/etc/config/network:

config interface 'ipsec'
	option proto 'xfrm'
        option mtu '1300'
	option tunlink 'lan'
	option zone 'IpsecFW'
        option ifid '1'

Output of LuCI:

Unsupported protocol type

Are these incorrect settings or is xfrm not supported?

The documentation says:

if_id set in ipsec sa policy

Where do I find the correct ifid or is it freely selectable?

As I understand it, a matching if_id must be set in the SA configuration.
Some documentation which might be helpful:

Apparently, if_id is not supported in ipsec.conf, but only in swanctl.conf.
If you are still using starter, you have to replace it with swanctl to enable configuration of if_id.

I have read following from your links @mpa.

To add a basic XFRM virtual interface, I need iproute2 with xfrm interface support.
(Link)

Is iproute2 in openwrt somewhere?

Support for XFRM interfaces (available since Linux 4.19) has been added, which are intended to replace VTI devices (they are similar but offer several advantages, for instance, they are not bound to an address or address family).
(Link)

Highlights In OpenWrt 18.06.0
Updated Linux kernel:
Kernel 4.9.111 for ar7, ar71xx, arc770, at91, brcm2708, brcm63xx, ixp4xx, lantiq, layerscape, mpc85xx, orion, rb532 and uml
Kernel 4.14.52 for apm821xx, archs38, armvirt, ath25, bcm53xx, brcm47xx, cns3xxx, gemini, imx6, ipq40xx, ipq806x, kirkwood, malta, mediatek, mvebu, mxs, octeon, octeontx, omap, oxnas, pistachio, ramips, sunxi and x86
(Link)

I have OpenWRT 18.06.05 bcm53xx.
Linux kernel: 4.14.151

So I'll have to wait until kernel 4.19 or buy a new router with "ar7, ar71xx, arc770, at91, brcm2708, brcm63xx, ixp4xx, lantiq, layerscape, mpc85xx, orion, rb532 and uml".

Is that correct or do I have any alternatives?

Yes, in package ip-full.
I have not checked whether support for XFRM interfaces has been integrated yet.

  • look again at the policy-based solution without a virtual interface
  • use protocol VTI (I have not tried this)
  • set up an x86 VM with OpenWrt
1 Like

When I try the configuration in "etc/config/network" with protocol Virtual Tunnel Interface (VTI), then it doesn't work like with protocol xfrm.
As output I get "Unsupported protocol type".

I have tried command lines following these instructions.

+/etc/ipsec.conf:

        mark_in=2
        mark_out=2

+/etc/strongswan.conf:

        install_routes=no
        install_virtual_ip=no

+/etc/config/network:

config interface 'ipsec'
	option ifname 'ipsec0'
	option proto 'none'

+Terminal:

ip tunnel add ipsec0 local 192.168.1.1 remote 37.48.94.1 mode vti key 2
sysctl -w net.ipv4.conf.ipsec0.disable_policy=1
ip link set ipsec0 up
ip route add 10.0.0.0/24 dev ipsec0
ifconfig ipsec0 192.168.1.1 netmask 255.255.255.0 broadcast 192.168.1.255

As you can see, I receive packets on the interface "ipsec", but no packets are transmitted.
So there is something missing in the configuration?

How important is this part of this instruction?:

ip rule add from 192.168.3.0/24 table 1000
ip route add 0.0.0.0/0 dev vti0 table 1000
ip route show table 1000

iptables -A PREROUTING -p udp -s 192.168.3.0 --dport 53 -j DNAT --to 10.0.0.4
iptables -A PREROUTING -p tcp -s 192.168.3.0 --dport 53 -j DNAT --to 10.0.0.4

@mpa

I have heard that it is possible to configure a kill switch with ipsec drop policies (similar to passthrough policies).

Do you know anything about this?

StrongSwan IPsec/IKEv2 runs well on OpenWrt.

How can I block all ports via LuCI and allow only specific ports (like 53, 500, 4500)?

This would not be a real kill switch, but better than nothing.