Linux XFRM IPsec Site-to-Site Tunnel Configuration - 夜莺博客

Linux XFRM IPsec Site-to-Site Tunnel Configuration

Route-based VPNs have largely replaced policy-based IPsec on Linux because they behave like any other interface: you can put routes on them, run dynamic routing protocols over them, and see their traffic counters. The XFRM interface introduced in kernel 4.19 is the modern way to do this - it replaces the older VTI/VTI6 devices and removes the need to bind a tunnel to a single source address pair. This guide walks through the whole path: creating the interface, wiring strongSwan's swanctl configuration to it, routing the protected subnets, and verifying that traffic is actually hitting the tunnel.

Why Use an XFRM Interface Instead of VTI

VTI devices require you to configure a tunnel source and destination address and only handle one SA pair per device. An XFRM interface uses an interface ID (if_id) instead, so several child SAs can share the same device, including SAs negotiated with multiple remote gateways. That makes XFRM interfaces the right choice for hub-and-spoke or any design where the peer address is not fixed.

Two prerequisites matter. The kernel must be 4.19 or newer, and the iproute2 tools must be version 5.1.0 or newer so that the xfrm link type is understood. If ip link add ... type xfrm fails, the kernel or the tools are too old and you should fall back to VTI.

Step 1: Create the XFRM Interface

Create the device with a link type of xfrm and give it a unique interface ID. Both peers do not need the same ID - the ID is local per gateway and is bound to the child SA through the connection configuration.

ip link add ipsec0 type xfrm if_id 42
ip link set ipsec0 up
ip addr add 10.255.0.1/30 dev ipsec0
ip route add 10.2.0.0/16 dev ipsec0
ip -s link show ipsec0

strongSwan ships a helper binary that does the same thing on systems whose iproute2 build is too old:

/usr/local/libexec/ipsec/xfrmi --name ipsec0 --id 42

Step 2: Bind the Interface ID in swanctl.conf

The connection references the interface with if_id_in and if_id_out. Setting both to the same value binds the CHILD_SA to ipsec0, so decapsulated packets appear on the tunnel interface and route lookup finds the protected prefix through it.

connections {
  net-net {
    version = 2
    local_addrs = 192.0.2.1
    remote_addrs = 192.0.2.2
    local {
      auth = psk
      id = gw-a.example.com
    }
    remote {
      auth = psk
      id = gw-b.example.com
    }
    children {
      net-net {
        local_ts = 10.1.0.0/16
        remote_ts = 10.2.0.0/16
        if_id_in = 42
        if_id_out = 42
        esp_proposals = aes256gcm16-prfsha384-ecp384
        start_action = trap
      }
    }
  }
}

Because the traffic selectors are only used for policy checks and the routes decide forwarding, you can keep local_ts and remote_ts at 0.0.0.0/0 while still sending only the routed prefixes over the tunnel - a common pattern for route-based designs. If you need several remote subnets, add them as extra routes pointing at the same interface instead of enlarging the selectors.

Step 3: Load and Start the Connection

swanctl --load-all
swanctl --initiate --child net-net
swanctl --list-sas

With start_action = trap the kernel installs a trap policy and the first packet for 10.2.0.0/16 triggers negotiation automatically, which is usually friendlier than a static initiate on boot.

Step 4: Verify the Data Path

Three layers need checking: the IKE/CHILD_SA state, the XFRM state and policy tables, and the interface counters.

swanctl --list-sas
ip xfrm state
ip xfrm policy
ip -s link show ipsec0
ping -c 3 -s 1400 10.2.0.1

If ip xfrm state shows no state, IKE did not complete - check swanctl --log or the charon journal for proposal mismatches. If state exists but counters on ipsec0 stay at zero while pings fail, the routing is wrong: traffic is being sent out of the physical interface instead of the tunnel. Confirm with ip route get 10.2.0.1, which should name ipsec0 as the egress device.

MTU and Fragmentation

XFRM interfaces inherit the MTU of the underlying device minus the ESP overhead, but it is safer to set it explicitly on jumbo or overlay paths. A tunnel MTU that is too high causes large packets to disappear while small pings succeed - the classic silent failure. Clamp TCP MSS or lower the interface MTU:

ip link set ipsec0 mtu 1400
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN   -j TCPMSS --clamp-mss-to-pmtu

When to Choose XFRM Over Policy-Based IPsec

Pick XFRM interfaces when you need dynamic routing across the tunnel, multiple SAs on one device, or per-tunnel traffic statistics. Policy-based IPsec still makes sense for one-off host-to-host flows that never change. For a comparison of the two design styles see IPsec VTI vs policy-based VPN and GRE, and if you are building a simpler encrypted overlay without IKE at all, WireGuard site-to-site VPN configuration covers that path.

原文链接:https://docs.strongswan.org/docs/latest/features/routeBasedVpn.html