I have a Ubuntu 24.04.1 LTS server, running Strongswan.
I have since learned that it's using nftables and not iptables for its firewall.
In setting up the VPN, I am able to connect with the client, but I'm not able to access hosts on the internet by ip address, or resolve names.
I think I'm missing some of the forwarding rules, but I'm not sure how to translate/apply them in a nft format.
What rule(s) do I need to apply to have IPV4 and IPV6 work for the clients?
The below config started out from a wireguard guide and I modified it to include other services I have on the machine. I found some references from openwrt and strongswan and tried to translate that, but I think I have not met the mark yet. I appreciate any advice.
Thank you.
I added these in an attempt to pass the ipsec traffic
chain prerouting
meta ipsec exists ip saddr $IKE_NETS counter accept
chain inbound_world
meta l4proto ah accept
meta l4proto esp accept
/etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
define DEV_WG = wg0
define DEV_OVPN = tun0
define DEV_VPN = { $DEV_WG, $DEV_OVPN }
define DEV_WORLD = eth0
define IP_OVPN = 10.8.0.0/24
define IP_WORLD_V4 = public_v4_ip
define IP_WORLD_V6 = public_v6_ip
define PORT_IKE = { 500, 4500 }
define PORT_WG = 51820
define PORT_OVPN = 1194
define PORT_VPN = { $PORT_IKE, $PORT_WG, $PORT_OVPN }
define DEV_LOCAL_NETS = { $DEV_VPN }
define DEV_OUT_NETS = { $DEV_WORLD }
#define IKE_NETS = { 172.16.252.0/24, fd5a:4c1f:8d73:f583::/64 } <- did not like the Ipv6 address
define IKE_NETS = { 172.16.252.0/24 }
# `inet` applies to both IPv4 and IPv6.
table inet global {
map port_forwards_tcp_ipv4 {
type ipv4_addr . inet_service : ipv4_addr . inet_service
# lets forward port for our torrent. Our 12345 to 12345 on 172.16.0.2
elements = { $IP_WORLD_V4 . 12345 : 172.16.0.2 . 12345 }
}
map port_forwards_tcp_ipv6 {
type ipv6_addr . inet_service : ipv6_addr . inet_service
# lets forward port for our torrent. Our 12345 to 12345 on fdf5:6028:947d:1234::2
elements = { $IP_WORLD_V6 . 12345 : [fdf5:6028:947d:1234::2] . 12345}
}
map port_forwards_udp_ipv4 {
type ipv4_addr . inet_service : ipv4_addr . inet_service
# lets forward port for our torrent. Our 12345 to 12345 on 172.16.0.2
elements = { $IP_WORLD_V4 . 12345 : 172.16.0.2 . 12345 }
}
map port_forwards_udp_ipv6 {
type ipv6_addr . inet_service : ipv6_addr . inet_service
# lets forward port for our torrent. Our 12345 to 12345 on fdf5:6028:947d:1234::2
elements = { $IP_WORLD_V6 . 12345 : [fdf5:6028:947d:1234::2] . 12345}
}
chain inbound_world {
# accepting ping (icmp-echo-request) for diagnostic purposes.
# However, it also lets probes discover this host is alive.
# This sample accepts them within a certain rate limit:
#
# icmp type echo-request limit rate 5/second accept
# Allow IPv6 configuration packets
icmpv6 type {nd-neighbor-solicit,nd-neighbor-advert,nd-router-solicit,
nd-router-advert,mld-listener-query,destination-unreachable,
packet-too-big,time-exceeded,parameter-problem} accept
# allow SSH
tcp dport { 22 } accept
# http, https
tcp dport 80 accept
tcp dport 443 accept
# smtp, submission, smtps
tcp dport 25 accept
tcp dport 587 accept
tcp dport 465 accept
# pop3, pop3s
tcp dport 110 accept
tcp dport 995 accept
# imap, imaps
tcp dport 143 accept
tcp dport 993 accept
# allow VPN connection
udp dport { $PORT_VPN } accept
meta l4proto ah accept
meta l4proto esp accept
}
chain inbound_vpn {
# accepting ping (icmp-echo-request) for diagnostic purposes.
icmp type echo-request limit rate 5/second accept
# Allow IPv6 configuration packets
icmpv6 type {nd-neighbor-solicit,nd-neighbor-advert,nd-router-solicit,
nd-router-advert,mld-listener-query,destination-unreachable,
packet-too-big,time-exceeded,parameter-problem} accept
# allow DNS and SSH from the private network
tcp dport { 22, 53 } accept
udp dport { 53 } accept
}
chain inbound {
# drop all traffic by default
type filter hook input priority filter; policy drop;
# Allow traffic from established and related packets, drop invalid
ct state vmap { established : accept, related : accept, invalid : drop }
# Allow dnat (port forwarding)
ct status dnat accept
# allow loopback traffic, anything else jump to chain for further evaluation
iifname vmap { lo : accept, $DEV_WORLD : jump inbound_world, $DEV_VPN : jump inbound_vpn}
# the rest is dropped by the above policy
}
chain forward {
type filter hook forward priority filter; policy drop;
# Allow traffic from established and related packets, drop invalid
ct state vmap { established : accept, related : accept, invalid : drop }
# Allow port forwarding
ct status dnat accept
# connections from the internal nets to the out nets are allowed
iifname $DEV_LOCAL_NETS oifname $DEV_OUT_NETS accept
# the rest is dropped by the above policy
meta ipsec exists ip saddr $IKE_NETS counter accept
}
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
dnat ip addr . port to ip daddr . tcp dport map @port_forwards_tcp_ipv4
dnat ip6 addr . port to ip6 daddr . tcp dport map @port_forwards_tcp_ipv6
dnat ip addr . port to ip daddr . udp dport map @port_forwards_udp_ipv4
dnat ip6 addr . port to ip6 daddr . udp dport map @port_forwards_udp_ipv6
meta ipsec exists ip saddr $IKE_NETS counter accept
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
# Hide IPs from local nets to the internet.
# We are using SNAT because we have static IP and it wil work faster than MASQUERADE
iifname $DEV_LOCAL_NETS oifname $DEV_WORLD snat ip to $IP_WORLD_V4
iifname $DEV_LOCAL_NETS oifname $DEV_WORLD snat ip6 to $IP_WORLD_V6
}
}
Strongswan pools:
pools {
primary-pool-ipv4 {
addrs = 172.16.252.0/24
dns = 172.16.252.1, 8.8.8.8, 9.9.9.9
split_exclude = 172.16.0.0/12
}
primary-pool-ipv6 {
addrs = fd5a:4c1f:8d73:f583::/64
dns = 2620:fe::fe, 2620:fe::9
}
Working implementation on my server for IPSEC and other VPNS.