Libreswan Documentation

Logo

Libreswan's Online Documentation

View the Project on GitHub libreswan/libreswan.github.io

Support
FAQ Common Error Messages
History
Implemented Standards
Kernel Support
HOWTO Additional ipsec.conf documentation
AWS Mesh
brendans Road Warrior Setup at Home
Configuration examples
Confuse !?@: github wiki
Enterprise cloud encryption
Entropy matters
EoIP shared ethernet LAN using IPsec
High Availability Fallover VPN in AWS
Host to host VPN
Host to host VPN with PSK
Libreswan as client to a Cisco ASA or VPN3000 server
Microsoft Azure configuration
Migrate from IKEv1 DPD to IKEv2 LIVENESS
Opportunistic IPsec
Opportunistic IPsec using LetsEncrypt
Pluto and DNSSEC
Read status output
Route based VPN
SElinux and Labeled IPsec VPN
Subnet extrusion
Subnet to subnet using NAT
Subnet to subnet VPN
Subnet to subnet VPN with PSK
Unauthenticated Opportunistic IPsec
Using Apache to serve PKCS
Using NSS Hardware Tokens
Using NSS with libreswan
VPN server for remote clients using IKEv2
VPN server for remote clients using IKEv2 split VPN
GSoC 2027 Code Project Ideas DRAFT
Contributor Guidance DRAFT
Completed Projects 2026 RFC 9593 Announcing Supported Authentication Methods in IKEv2
2026 Improve the ACQUIRE to IKE policy lookup
2026 Add HOST TO HOST Support on BSD
2021 RFC 8420 Add EdDSA Signature Authentication Support to IKEv2
2020 Session Resumption
2020 IKEv2 Interop testing with OpenBSD
2020 IKE Intermediate Exchange
2019 Libreswan Opportunistic IPsec using LetsEncrypt
2018 RSA PSS Support in compliance with RFC 7427 and RFC 8247
2018 RFC 7427 Add ECDSA Signature Authentication Support to IKEv2
2018 RFC 5685 Redirect Mechanism
2018 Managing Interface
2017 TCP encapsulation of IKE and IPsec
2017 RFC 7427 Add Signature Authentication Support to IKEv2
2017 Postquantum Preshared Keys
Presentations
IRC
Hacking Documentation
Git, GitHub, and Pull Requests
Merging GitHub Pull Requests
Programming Conventions
Testing Docker
KVM 1. Setup The Host
2. Configure Testing
3. Compile Libreswan
4. Test Libreswan
5. Accessing The Console
6. Maintenance and Internals
Bisecting
Debugging Pluto
Logging In Using SSH
Performance
Running A Custom Kernel
Running A Single Test
Running In The Background
Setup a Web Server
Testing Old Branches
Updating Test Results
Namespace Magic
Namespaces
Topology
Internals 3.14 X509
Benchmarking and Performance testing
Cipher suites and algorithm support
Cloud OE ideas
Compiling with AddressSanitizer
Compliance of RFC 7427 Signature Authentication in IKEv2
Coverity
Cryptographic Acceleration
Developer links strongswan android
Discouraged or forbidden C functions
IKEv2 Child SA
IKEv2 CP and EAP support
Introduction
Libreswan xfrm kernel support
Logging cleanup
New OE
Pluto
Pluto packet processing
Proposed ipsec ca command
Retransmit timings
Road Map
SAref code
Setting up system for debug logging
stf status
Testing 2017 Next Generation
Unbound
Uncrustify
Use Cases and Requirements document for ECC ECDSA support
Use Cases and Requirements document
XFRM Interface Development Notes
XFRM pCPU
XFRM pCPU RSS
Security Crypto boundary and certification
Libreswan and Heartbleed
Libreswan and TunnelCrack
Reporting a Vulnerability
Vulnerabilities
Meetups 2013 Helsinki
2014 San Francisco
2014 Toronto
2018 Toronto
Obsolete HOWTOs IKEv1 XAUTH with FreeOTP and FreeIPA
IKEv1 XAUTH with Google Authenticator One Time Passwords
Route based VPN using VTI
Testing Namespace
VPN server for remote clients using IKEv1 with L2TP
VPN server for remote clients using IKEv1 XAUTH with Certificates
VPN server for remote clients using IKEv1 XAUTH with PSK

by Brendan Kearney

i finally have a working config that i am content with. i have been trying to get a road warrior setup working in my home network and had to work through the expected “growing pains” to achieve what success i have. i wanted to share some insights, configs and questions and ask for feedback. so, please enjoy my long winded diatribe. :D

first, i’ll go into the network and server side of things.

on my firewall, which is iptables (i have not migrated to nftables yet), i have a NAT rule (specifically, an inbound DNAT rule) and an access rule. with iptables, NAT acts on a packet before the access policy, so you have to DNAT the packet and then allow access to the NAT’d destination. my NAT rule, in plain speak is:

Original Source = Any;
Original Destination = My Router/Firewall/Gateway External IP;
Original Service = IKE (UDP/500), IPSec-NAT-T (UDP/4500), ESP (proto 50);
Translated Source = Original/Unmodified;
Translated Destination = 192.168.152.254;
Translated Service = Original/Unmodified;
Inbound Interface = Auto/Any;
Outbound Interface = Auto/Any

i do not set an inbound interface intentionally, as this allows me to establish an IPSec connection from behind my firewall, on my local network, which is really helpful when setting things up and testing through initial configs. with NAT set, my access rule is, again in plain speak:

Source = Any;
Destination = 192.168.152.254;
Service = IKE (UDP/500), IPSec-NAT-T (UDP/4500), ESP (proto 50);
Interface = Any;
Direction = Inbound;
Action = Accept;
Time = Any;
Log = Enabled

note again that in the access rule, any interface is allowed so that i can be on my internal network and still establish an IPSec tunnel. all i have to do is point at the external FQDN or IP and the NAT and Access Rule will handle the rest. also, the ports and protocols include both IKE and IKE NAT Traversal, so that all bases are covered.

i run BGP on my home network, and the 192.168.152.0/24 network does not exist on the wire. my VPN server advertises/injects a route pointing any traffic to that /24 via the servers “in-band” interface. my router has this route listed:

192.168.152.0/24 nhid 141 via 192.168.88.5 dev vlan88 proto bgp src
192.168.248.254 metric 20

i may look to revise my routing scheme a bit, as i am running an eBGP setup now, with my router in a separate AS than my servers. i am told that an iBGP setup will make things easier, but for now this is working. I wont dive too deep into the routing pieces, but will share if interest exists. in the case of IPSec, the routing i have in place would help me and my one user (myself) if i were to go multi-site and wanted failover between sites. otherwise, this is all a learning environment.

as you may have guessed, i do some crazy stuff with routing. LibreSWAN does not listen on a physical interface. in the days of yore, one could stack virtual IPs on the loopback interface, but with systemd-networkd which does not manage the loopback interface (lo), i dont know if it has the same effect. i have not tested, but using the “Kind=dummy” type of interface closely resembles the setup and seems to have the benefit i am looking for. i do this because of the improvement i saw with BIND/named when i switched to Anycast. there was a perceptible improvement in DNS response time. the switch to Anycast took my BIND/named listener off the physical interface and put it on an IP that was stacked on the loopback. in the old network-scripts package days, i had an interface “lo:1” with the IP of the Anycast address. now i have an interface called “named” with the “Kind” set to “dummy”. it seems to work the same way and still performs with the same perceptible improvements. now, with LibreSWAN i have an interface “ipsec” set with “Kind=dummy” and the listener is not on the wire.

i believe the improvement i see to be because there is less “context switching” and “stops along the way” when getting from the wire to the listener. because i am (trying to) ride the loopback, there is a higher MTU, faster path, fewer drivers, and a memory space in kernel that the listener is listening on. seriously, things seem faster. of course i have not measured any of this, so feel free to refute my claims. that said, i do have a very well performing network with lots of services trucking right along. also, i have quite a few sysctl.conf tweaks for my servers and assorted linux machines acting as load balancers, firewalls, routers, gateways, etc. if any interest exists, i can share those tweaks.

anywho, with my routing (FRR) handling the path to the listener, LibreSWAN listens on a “virtual” IP. in /etc/ipsec.conf, i set the listener to 192.168.152.254 (i route on the high side). i also set “ikev1-policy” to “drop”. the packaging for Fedora, which is my distro of choice, sets “include” to “/etc/ipsec.d/*.conf” so i can add my configs separately.

in /etc/ipsec.d/, i have my rac.conf and rac.secrets files, with “rac” being short for Remote Access Connection. i have tried to keep my configs concise with comments separating different sections or stanzas, to keep thing legible. i dont know if blank lines are acceptable between lines within a “conn” definition, so i have avoided them. otherwise, things are pretty straight forward. my rac.conf file:

# Remote Access Connection
conn rac
     # Local Definitions
     left=ipsec.bpk2.com
     leftsubnet=0.0.0.0/0
     # Remote Definitions
     right=%any
     rightaddresspool=192.168.152.50-192.168.152.99
     # Configuration Parameters
     auto=add
     authby=secret
     ikelifetime=24h
     salifetime=1h
     ikev2=insist
     rekey=yes
     fragmentation=yes
     mobike=yes
     # Dead Peer Detection
     dpddelay=30
     dpdaction=clear
     # Push Configs to Remote
     modecfgdns=192.168.248.254
     modecfgdomains=bpk2.com

conn x1titanium
     also=rac
     rightid=@x1titanium.bpk2.com

conn netbook
     also=rac
     rightid=@netbook.bpk2.com

conn s24ultra
     also=rac
     rightid=@s24ultra.bpk2.com

in the rac definition i set all my base configs that all subordinate connections inherit. then i set a specific conn for each device, so that i can use separate pre-shared keys (PSKs) per device. i dont want to have a single PSK for all devices, in case of compromise. each “per device” conn includes the base settings via the “also” directive, and then specifies the “rightid” which is matched in the rac.secrets file.

there is a nuance i came across is in dealing with the value of the “left” directive. as an aside, i adhere to the “left is local, right is remote” mantra and my configs reflect this. i believe this nuance is due to the fact that i NAT the traffic, and the different names of the external vs. internal IPs requires these config directives be different. on the server side, “left” is set to the FQDN of the listener. on the client side, “right” is set to the external name/IP on my ISP connection, and “rightid” is set to the internal IP of the listener. the “rightid” is set to the IP and not the FQDN because DNS resolution of the internal name will not work until the tunnel is up, so i have to use the IP. i might be able to use a string with “@” preceding the value to avoid a DNS lookup or other matching mechanism, but that is an option left to the reader.

also to note, with the “leftsubnet=0.0.0.0/0” directive, i backhaul all traffic. i do not “split-tunnel”. specifying something like 192.168.0.0/16 would setup split tunneling, so that anything not in that range would not be routed via the VPN tunnel. the use of “narrowing=yes” may also be needed or useful when doing split tunneling. i have not dug into split tunneling or narrowing, so i can only claim ignorance on the topics.

in the rac.secrets file, i have a line for each of the device specific “conn” definitions. again blank lines may be a no-no, so i avoid them here as well. the formula for the entries in the secrets file is pretty simple and described in the man file. my rac.secrets file:

# generate PSKs using 'openssl rand -hex 32' or 'openssl rand -hex 64'
ipsec.bpk2.com @x1titanium.bpk2.com : PSK "SomeSecret12345"
ipsec.bpk2.com @netbook.bpk2.com : PSK "SomeSecret67890"
ipsec.bpk2.com @s24ultra.bpk2.com : PSK "SomeOtherSecret123"

the first value is the FQDN, matching the server’s “left” setting. the second value is a string, as designated by the “@” preceding it, and matches the “rightid” of the device specific “conn”. then a colon. then the PSK designator and string, with the actual PSK string encapsulated in double-quotes. i leave a comment at the beginning of the secrets file to help me remember how to create high quality PSKs. i have even taken creating PSKs to another level with a simple script…

#!/bin/bash

if [ -z $1 ]
then
     echo "You must supply an identifier, typically a FQDN..."
     exit
fi

server="ipsec.bpk2.com"
fqdn=$1
bits=32
PSK=$(openssl rand -hex $bits)
outFile="rac.secrets"

echo "$server @${fqdn} : PSK \"${PSK}\"" >> $outFile

name the script what you want. adjust the variables to your environment. call it with one parameter, which is the string you match on in the device specific “conn” definition and bob’s your uncle. hit your running instance with a “ispec auto –rereadall” and everything should be running on the servers side.

one final note on the server side of things. i dont know if i need to set this or not, but i do anyway and it does not break things. i am not sure if the applicability of this setting is due to the IPSec listener being on a machine separate from my router/gateway or not, but having set it does not seem to affect the functionality. in /etc/sysctl.conf i have the following configured:

# Enable proxy arp?
net.ipv4.conf.all.proxy_arp = 1
net.ipv4.conf.default.proxy_arp = 1
net.ipv4.conf.enp1s0.proxy_arp = 1

i am handing out internal, LAN side IPs and this is supposed to facilitate that. because i set the “all” setting, i dont think i need to specify any other interfaces. the in-band interface is specifically set, but my virtual is not. in my quest to find what setting i needed to specify, i found this and set it. i was hoping this would allow me to have my DHCP instance give out IPs to the IPSec clients, but i dont think DHCP is a supported capability. questions about DHCP capability later…

now, on to the client side of things.

the client config is pretty straight forward, and i dont have crazy routing going on there. there are a couple important details to pay attention to, and i will explain those in detail. the client side rac.conf file:

# Remote Access Connection
conn rac
     # Local Definitions
     left=%defaultroute
     leftid=@x1titanium.bpk2.com
     leftsubnet=0.0.0.0/0
     leftmodecfgclient=yes
     # Remote Definitions
     right=my.dyndns.name
     rightid=192.168.152.254
     rightsubnet=0.0.0.0/0
     # Configuration Parameters
     auto=add
     authby=secret
     ikev2=insist
     ikelifetime=24h
     salifetime=1h
     rekey=yes
     fragmentation=yes
     pfs=yes
     mobike=yes
     # Dead Peer Detection
     dpddelay=30
     dpdaction=clear
     retransmit-timeout=120

adhering to the “left = local, right = remote” mantra, “left” is set to the special setting of “%defaultroute” which auto populates a couple of unspecified parameters. it makes things easy. ‘nuff said. the “leftid” is specified to match the secrets file PSK on both sides of the tunnel. “leftsubnet” is set to everything, to backhaul all traffic and not perform split-tunneling.

the “right” directive is set to the external dynamic DNS name for my ISP connection. the “rightid” is set to the internal IP of the LibreSWAN listener. the “right” and “rightid” settings are critical because i am running a NAT Traversal scenario, and the box running with a routable IP (i.e. not an RFC 1918 IP) is not the same box as the one running the VPN listener. “rightid” has to be set to the IP and not the internally resolvable FQDN, as DNS resolution of that name cannot be performed until the tunnel is up. therefore, it is set to the IP. “rightsubnet” is also set to everything, for backhauling of all traffic.

i have chosen the other config parameters based on the “best practices” i have found across the internet, trying to provide a secure and robust tunnel that affords the best available security and reliability. granted, certificates would be an improvement above PSKs, but i dont have PKI infrastructure to mint certs and automate their renewal and deployment. otherwise, no IKE v1, relatively short IKE and SA lifetimes, PFS enabled (which does not always work when setting up connections between differing VPN vendors), and MobIKE because road warriors might change interfaces and IPs based on connection and availability. adjust seasonings to taste…

as for the secrets file, there is one entry and it follows the same format as the server side, but the first two values are reversed. the client side rac.secrets file:

@x1titanium.bpk2.com ipsec.bpk2.com : PSK "SomeSecret12345"

note that the second value is the FQDN of the NAT’d, internal (RFC 1918) IP for the LibreSWAN listener. i expected this to have to be an IP, but it works as a FQDN, so i leave it as is. that could vary from implementation to implementation, or OS to OS, so be wary and test. YMMV.