strongSwan IKEv2 Site-to-Site VPN with swanctl - 夜莺博客

strongSwan IKEv2 Site-to-Site VPN with swanctl

strongSwan is the reference open-source IPsec implementation and the usual answer when a Linux host must terminate an IKEv2 tunnel. Modern deployments use swanctl and the vici interface rather than the deprecated ipsec command and ipsec.conf. This article builds a site-to-site tunnel between two gateways, then covers the verification and debugging sequence that turns a silent tunnel into a diagnosable one.

File layout

/etc/swanctl/x509ca/strongswanCert.pem   # CA certificate
/etc/swanctl/x509/moonCert.pem           # gateway certificate
/etc/swanctl/private/moonKey.pem         # private key
/etc/swanctl/swanctl.conf                # connections and child SAs

The certificate must carry the identity you use as the peer ID (typically the FQDN in the CN or a SAN), because identity matching is what fails when everything else looks correct.

The connection on gateway "moon" (10.1.0.0/16 behind 192.168.0.1)

connections {
  net-net {
    remote_addrs = 192.168.0.2
    local {
      auth = pubkey
      certs = moonCert.pem
    }
    remote {
      auth = pubkey
      id = "C=CH, O=strongSwan, CN=sun.strongswan.org"
    }
    children {
      net-net {
        local_ts  = 10.1.0.0/16
        remote_ts = 10.2.0.0/16
        start_action = trap
      }
    }
  }
}

The mirror configuration on "sun" swaps the addresses, certificate and traffic selectors. start_action = trap installs a trap policy: the tunnel is negotiated automatically when the first packet for the remote subnet appears, which avoids a permanently idle SA while still re-establishing on demand. Use start for always-on tunnels and none when the tunnel should only come up on explicit command.

Loading and verifying

# swanctl --load-creds
# swanctl --load-conns
# swanctl --list-conns
# swanctl --list-sas
# swanctl --list-pols

--list-sas is the state that matters. A healthy output shows the IKE SA in ESTABLISHED with the negotiated proposals and rekey timer, and a child SA in INSTALLED with byte counters that increment. Counters that stay at zero mean the tunnel exists but is not carrying traffic - usually a routing or firewall problem, not an IPsec problem.

Making the traffic path work

# sysctl -w net.ipv4.ip_forward=1
# firewall: allow IKE and ESP
udp dport {500, 4500} accept
esp accept
# allow the encrypted traffic between the two subnets
ip saddr 10.1.0.0/16 ip daddr 10.2.0.0/16 accept

Three things break a correctly negotiated tunnel: IP forwarding disabled on the gateway, the firewall dropping ESP or UDP 500/4500, or a policy rule dropping the plaintext between the subnets. Keep the IPsec policy rules and the tunnel's traffic selectors aligned - a traffic selector narrower than what the routing table sends into the tunnel produces "no matching policy" style drops.

Debugging sequence

  • Nothing negotiates: check reachability of UDP 500/4500 between the public addresses, then journalctl -u strongswan for proposal mismatches. A "no proposal chosen" message means the IKE or ESP proposal sets do not overlap.
  • IKE SA up, child SA failing: traffic selector mismatch - compare local_ts/remote_ts on both ends.
  • Authentication failure: identity mismatch, expired certificate, or a clock problem (certificate validity is checked against local time).
  • Tunnel up, no data: route the remote subnet through the tunnel (ip route add 10.2.0.0/16 dev ... or an xfrm interface for route-based designs), and verify counters again.
  • Large transfers stall: MTU and fragmentation. Lowering the interface MTU to account for the ESP overhead, or enabling MSS clamping, fixes the classic "ping works, scp hangs" symptom.
  • Raise logging with swanctl --log or the charon log settings, and lower it again afterwards - debug-level logging on a busy gateway is expensive.

Related: WireGuard MTU and handshake troubleshooting, nf_conntrack table tuning, and nftables migration from iptables.

原文链接:https://docs.strongswan.org/docs/latest/config/quickstart.html