I have a StrongSwan IPSec remote access server running on RHEL and a client all on the same local network. I have a Samba server running on the same RHEL host that I want to be available through the VPN but not outside the tunnel. I can get the IPSec tunnel up successfully (had to make a MacOS profile with Apple Configurator2 enabling Perfect Forward Security in order to have a ciphersuite match) but I can't get traffic to route within the server properly. I did a packet capture and I could see the inbound ESP and decrypted ICMP packets from a ping from the client but the server couldn't reply back. I've spent several weekends trying to find out which iptables rules I need to get connectivity up but I think I'm missing some sort of understanding. I've been able to set up OpenVPN and WireGuard VPNs no problem with the tun interfaces but IPSec per my understanding is decrypted by policy in the kernel so I'm not familiar with how that would affect routing.
I've based my setup off the official StrongSwan example docs for remote access, used this swanctl config doc, read forum posts and translated the older format to the newer one with this - as well as read about forwarding and route-based VPNs - but I think I'm just missing the high-level understanding about how the traffic routes within the VPN server.
Logical Network Diagram
Logical Network Diagram
swanctl.conf (with commented other things I've tried)
connections {
ikev2-vpn {
fragmentation=yes
rekey_time=0s
#mobike = no
version=2
proposals=aes256gcm16-prfsha384-ecp384
remote_addrs=%any
local_addrs=192.168.1.15
#vips=10.0.3.1
#remote_addrs=192.168.1.23
#pools=10.0.3.0/24
#encap=yes
#dpd_delay=300s
pools=pool1,pool2
#if_id_in=6
#if_id_out=6
children {
ikev2-vpn {
#start_action=none
esp_proposals=aes256gcm16-prfsha384-ecp384
#local_ts=10.0.3.1/32
local_ts=10.0.1.0/24
remote_ts=10.0.2.0/24
#remote_ts=10.0.3.10-10.0.3.200
#dpd_action=clear
updown=/usr/libexec/strongswan/_updown iptables
}
}
local {
auth=ecdsa-384-sha384
certs = /etc/strongswan/ipsec.d/certs/server.crt
id = 192.168.1.15
}
remote {
auth=ecdsa-384-sha384
id = %any
}
}
}
pools {
pool1 {
#addrs=10.0.3.0/24
addrs=10.0.1.0/24
}
pool2 {
#addrs=10.0.3.10-10.0.3.200
addrs=10.0.2.0/24
}
}
secrets {
ecdsa-server {
file=/etc/strongswan/ipsec.d/private/server.key
}
ecdsa-client {
file=/etc/strongswan/ipsec.d/private/client.key
}
}
authorities {
certauthority {
cacert = /etc/strongswan/ipsec.d/cacerts/ca.crt
}
}
swanctl --list-sas
ikev2-vpn: #2, ESTABLISHED, IKEv2, c98d6dc49ca0acd4_i 85342c9a0809e294_r*
local '192.168.1.15' @ 192.168.1.15[4500]
remote 'client2.vpn' @ 192.168.1.23[4500] [10.0.1.1]
AES_GCM_16-256/PRF_HMAC_SHA2_384/ECP_384
established 53s ago
ikev2-vpn: #4, reqid 1, INSTALLED, TUNNEL, ESP:AES_GCM_16-256
installed 53s ago, rekeying in 3247s, expires in 3907s
in c334ea0b, 0 bytes, 0 packets
out 021348d4, 0 bytes, 0 packets
local 10.0.1.0/24
remote 10.0.2.0/24
swanctl --list-conns
ikev2-vpn: IKEv2, no reauthentication, no rekeying
local: 192.168.1.15
remote: %any
local public key authentication:
id: 192.168.1.15
certs: [CERT_DN]
remote public key authentication:
id: %any
ikev2-vpn: TUNNEL, rekeying every 3600s
local: 10.0.1.0/24
remote: 10.0.2.0/24
ip -s xfrm state
src 192.168.1.15 dst 192.168.1.23
proto esp spi 0x021348d4(34818260) reqid 1(0x00000001) mode tunnel
replay-window 0 seq 0x00000000 flag af-unspec (0x00100000)
aead rfc4106(gcm(aes)) [KEY] (288 bits) 128
anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000
lifetime config:
limit: soft (INF)(bytes), hard (INF)(bytes)
limit: soft (INF)(packets), hard (INF)(packets)
expire add: soft 3418(sec), hard 3960(sec)
expire use: soft 0(sec), hard 0(sec)
lifetime current:
0(bytes), 0(packets)
add [TIME] use -
stats:
replay-window 0 replay 0 failed 0
src 192.168.1.23 dst 192.168.1.15
proto esp spi 0xc334ea0b(3275024907) reqid 1(0x00000001) mode tunnel
replay-window 32 seq 0x00000000 flag af-unspec (0x00100000)
aead rfc4106(gcm(aes)) [KEY] (288 bits) 128
anti-replay context: seq 0xc, oseq 0x0, bitmap 0x00000fff
lifetime config:
limit: soft (INF)(bytes), hard (INF)(bytes)
limit: soft (INF)(packets), hard (INF)(packets)
expire add: soft 3300(sec), hard 3960(sec)
expire use: soft 0(sec), hard 0(sec)
lifetime current:
1008(bytes), 12(packets)
add [TIME] use [TIME]
stats:
replay-window 0 replay 0 failed 0
ip xfrm policy show
src 10.0.1.0/24 dst 10.0.2.0/24
dir out priority 375423 ptype main
tmpl src 192.168.1.15 dst 192.168.1.23
proto esp spi 0x021348d4 reqid 1 mode tunnel
src 10.0.2.0/24 dst 10.0.1.0/24
dir fwd priority 375423 ptype main
tmpl src 192.168.1.23 dst 192.168.1.15
proto esp reqid 1 mode tunnel
src 10.0.2.0/24 dst 10.0.1.0/24
dir in priority 375423 ptype main
tmpl src 192.168.1.23 dst 192.168.1.15
proto esp reqid 1 mode tunnel
src 0.0.0.0/0 dst 0.0.0.0/0
socket in priority 0 ptype main
src 0.0.0.0/0 dst 0.0.0.0/0
socket out priority 0 ptype main
src 0.0.0.0/0 dst 0.0.0.0/0
socket in priority 0 ptype main
src 0.0.0.0/0 dst 0.0.0.0/0
socket out priority 0 ptype main
src ::/0 dst ::/0
socket in priority 0 ptype main
src ::/0 dst ::/0
socket out priority 0 ptype main
src ::/0 dst ::/0
socket in priority 0 ptype main
src ::/0 dst ::/0
socket out priority 0 ptype main
iptables-save
# Generated by iptables-save v1.8.4
*security
:INPUT ACCEPT [22858074:106762962340]
:FORWARD ACCEPT [7:588]
:OUTPUT ACCEPT [13832427:3964756363]
COMMIT
# Generated by iptables-save v1.8.4
*raw
:PREROUTING ACCEPT [22858911:106763119967]
:OUTPUT ACCEPT [13832428:3964756655]
COMMIT
# Generated by iptables-save v1.8.4
*mangle
:PREROUTING ACCEPT [22858911:106763119967]
:INPUT ACCEPT [22858308:106763007491]
:FORWARD ACCEPT [7:588]
:OUTPUT ACCEPT [13832428:3964756655]
:POSTROUTING ACCEPT [13833383:3964877586]
:LIBVIRT_PRT - [0:0]
-A POSTROUTING -j LIBVIRT_PRT
-A LIBVIRT_PRT -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
COMMIT
# Generated by iptables-save v1.8.4
*nat
:PREROUTING ACCEPT [186346:34394324]
:INPUT ACCEPT [185651:34259782]
:POSTROUTING ACCEPT [16086:1727773]
:OUTPUT ACCEPT [16085:1727689]
:LIBVIRT_PRT - [0:0]
-A POSTROUTING -j LIBVIRT_PRT
-A POSTROUTING -s 172.16.0.0/24 -o enp0s31f6 -j MASQUERADE
-A LIBVIRT_PRT -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN
-A LIBVIRT_PRT -s 192.168.122.0/24 -d 255.255.255.255/32 -j RETURN
-A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
-A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
-A LIBVIRT_PRT -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
COMMIT
# Generated by iptables-save
*filter
:INPUT ACCEPT [22831621:106727043679]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [13832420:3964757167]
:LIBVIRT_INP - [0:0]
:LIBVIRT_OUT - [0:0]
:LIBVIRT_FWO - [0:0]
:LIBVIRT_FWI - [0:0]
:LIBVIRT_FWX - [0:0]
-A FORWARD -s 10.0.2.0/24 -d 10.0.1.0/24 -i enp0s31f6 -m policy --dir in --pol ipsec --reqid 1 --proto esp -j ACCEPT
-A FORWARD -s 10.0.1.0/24 -d 10.0.2.0/24 -o enp0s31f6 -m policy --dir out --pol ipsec --reqid 1 --proto esp -j ACCEPT
-A LIBVIRT_INP -i virbr0 -p udp -m udp --dport 53 -j ACCEPT
-A LIBVIRT_INP -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT
-A LIBVIRT_INP -i virbr0 -p udp -m udp --dport 67 -j ACCEPT
-A LIBVIRT_INP -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT
-A LIBVIRT_OUT -o virbr0 -p udp -m udp --dport 53 -j ACCEPT
-A LIBVIRT_OUT -o virbr0 -p tcp -m tcp --dport 53 -j ACCEPT
-A LIBVIRT_OUT -o virbr0 -p udp -m udp --dport 68 -j ACCEPT
-A LIBVIRT_OUT -o virbr0 -p tcp -m tcp --dport 68 -j ACCEPT
-A LIBVIRT_FWO -s 192.168.122.0/24 -i virbr0 -j ACCEPT
-A LIBVIRT_FWO -i virbr0 -j REJECT --reject-with icmp-port-unreachable
-A LIBVIRT_FWI -d 192.168.122.0/24 -o virbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A LIBVIRT_FWI -o virbr0 -j REJECT --reject-with icmp-port-unreachable
-A LIBVIRT_FWX -i virbr0 -o virbr0 -j ACCEPT
COMMIT