Roadwarrior IPsec on VMM
This guide is designed to help you simulate a roadwarrior configuration with VMM using the IPsec roadwarrior guide. If you lack real hardware to test with, you can simulate the setup inside vmm.
This guide assumes you have read the IPsec roadwarrior guide. It only covers those parts that are specific to the setup on VMM.
192.0.2.1 (NAT) 198.51.100.1 198.51.0.1 init <---------------> resp <------> Internet 10.0.5.0/24 10.0.5.1
Configuring the host
First, we set up the host's interfaces:
host# cat /etc/hostname.vport11 inet 198.51.0.1 0xffffff00 !route add -inet 198.51.100.1 -cloning -link -iface vport11 !route add -inet 198.51.100/24 198.51.100.1 !route add -inet 192.0.2.1 -cloning -link -iface vport11 !route add -inet 192.0.2/24 192.0.2.1 up host# cat /etc/hostname.veb11 add vport11 up
Next we configure vm.conf:
socket owner :vmdusers switch "switch11" { locked lladdr interface veb11 } bsdiso="/home/iso/install75.iso" vm "init" { owner $USER memory 1G cdrom $bsdiso disk /home/$USER/init.qcow2 format qcow2 interface tap11 { locked lladdr e8:8b:11:11:11:11 switch "switch11" } } vm "resp" { owner $USER memory 1G cdrom $bsdiso disk /home/$USER/resp.qcow2 format qcow2 interface tap22 { locked lladdr e8:8b:22:22:22:22 switch "switch11" } }
We need to add a firewall rule similar to this one on the host:
match out on egress from !(egress:network) to any nat-to (egress:0)
Make sure to create each of the qcow2 images and install OpenBSD.
Then inside the virtual machines, we configure the interfaces:
init# cat /etc/hostname.vio0 inet 192.0.2.1 0xffffff00 !route add -inet 198.51.0.1 -cloning -link -iface vio0 !route add -inet 198.51.0/24 198.51.0.1 !route add -inet default 198.51.0.1 init# cat /etc/hostname.lo1 up resp# cat /etc/hostname.vio0 inet 198.51.100.1 0xffffff00 !route add -inet 198.51.0.1 -cloning -link -iface vio0 !route add -inet 198.51.0/24 198.51.0.1 !route add -inet default 198.51.0.1 resp# cat /etc/hostname.vether0 inet 10.0.5.1 0xffffff00
We now configure iked(8) as mentioned in the IPsec roadwarrior guide.
Exchange public keys. First, copy the public key from resp
to init
:
init$ ssh 198.51.100.1 'doas cat /etc/iked/local.pub' | doas tee /etc/iked/pubkeys/fqdn/resp.example.com
Replace resp.example.com
with resp's fully qualified domain name.
Next, copy the public key from init
to resp
:
init$ cat /etc/iked/local.pub | ssh 198.51.100.1 'doas tee /etc/iked/pubkeys/fqdn/in it.example.com'
Configure iked.conf(5) for both
resp
and init
:
init# cat /etc/iked.conf gateway = "198.51.100.1" srcname = "init.example.com" destname = "resp.example.com" pool = "10.0.5.0/24" dns = "198.51.100.1" ikev2 $destname active esp \ from dynamic to any \ peer $gateway \ srcid $srcname dstid $destname \ request address any \ iface lo1 resp# cat /etc/iked.conf gateway = "198.51.100.1" hostname = "resp.example.com" pool = "10.0.5.0/24" dns = "198.51.100.1" ikev2 $hostname passive esp \ from any to dynamic \ local $gateway peer any \ srcid $hostname \ config address $pool \ config name-server $dns \ tag "ROADW"
Tighten permissions for iked(8):
init# chmod 0600 /etc/iked.conf resp# chmod 0600 /etc/iked.conf
Appropriate sysctls should be enabled on resp
:
resp# cat /etc/sysctl.conf net.inet.ip.forwarding=1 net.inet6.ip6.forwarding=1 net.inet.ipcomp.enable=1 net.inet.esp.enable=1 net.inet.ah.enable=1 resp# sysctl net.inet.ip.forwarding=1 resp# sysctl net.inet6.ip6.forwarding=1 resp# sysctl net.inet.ipcomp.enable=1 resp# sysctl net.inet.esp.enable=1 resp# sysctl net.inet.ah.enable=1
Adjust /etc/pf.conf? for resp
:
resp="198.51.100.1" ext_if="vio0" pass in on $ext_if proto udp to $resp port {isakmp, ipsec-nat-t} tag IKED pass in on $ext_if proto esp to $resp tag IKED pass on enc0 inet tagged ROADW match out on $ext_if inet tagged ROADW nat-to $ext_if match in quick on enc0 inet proto { tcp, udp } to port 53 rdr-to 127.0.0.1 port 53
Reload packet filter:
resp# pfctl -f /etc/pf.conf
Start iked:
init# rcctl enable iked init# rcctl start iked iked(ok) resp# rcctl enable iked resp# rcctl start iked iked(ok)
Confirm IPsec flows with ipsecctl and verify security associations with ikectl:
init# ipsecctl -sa FLOWS: flow esp in from 0.0.0.0/0 to 10.0.5.117 peer 198.51.100.1 srcid FQDN/init.example.com dstid FQDN/resp.example.com type require flow esp out from 10.0.5.117 to 0.0.0.0/0 peer 198.51.100.1 srcid FQDN/init.example.com dstid FQDN/resp.example.com type require SAD: esp tunnel from 198.51.100.1 to 192.0.2.1 spi 0x24ce827e enc aes-128-gcm esp tunnel from 192.0.2.1 to 198.51.100.1 spi 0x7c42210d enc aes-128-gcm resp# ikectl show sa iked_sas: 0xceb3d56a780 rspi 0x964bd34b809388a9 ispi 0x9b48ee25a0b56672 198.51.100.1:500->192.0.2.1:500<FQDN/init.example.com>[10.0.5.117] ESTABLISHED r udpecap nexti 0x0 pol 0xcebae8df000 sa_childsas: 0xceb3d55e780 ESP 0x7c42210d in 192.0.2.1:500 -> 198.51.100.1:500 (LA) B=0x0 P=0xceb3d556c00 @0xceb3d56a780 sa_childsas: 0xceb3d556c00 ESP 0x24ce827e out 198.51.100.1:500 -> 192.0.2.1:500 (L) B=0x0 P=0xceb3d55e780 @0xceb3d56a780 sa_flows: 0xceb3d571400 ESP out 0.0.0.0/0 -> 10.0.5.117/32 [0]@-1 (L) @0xceb3d56a780 sa_flows: 0xceb3d57c800 ESP in 10.0.5.117/32 -> 0.0.0.0/0 [0]@-1 (L) @0xceb3d56a780 iked_activesas: 0xceb3d556c00 ESP 0x24ce827e out 198.51.100.1:500 -> 192.0.2.1:500 (L) B=0x0 P=0xceb3d55e780 @0xceb3d56a780 iked_activesas: 0xceb3d55e780 ESP 0x7c42210d in 192.0.2.1:500 -> 198.51.100.1:500 (LA) B=0x0 P=0xceb3d556c00 @0xceb3d56a780 iked_flows: 0xceb3d57c800 ESP in 10.0.5.117/32 -> 0.0.0.0/0 [0]@-1 (L) @0xceb3d56a780 iked_flows: 0xceb3d571400 ESP out 0.0.0.0/0 -> 10.0.5.117/32 [0]@-1 (L) @0xceb3d56a780 iked_dstid_sas: 0xceb3d56a780 rspi 0x964bd34b809388a9 ispi 0x9b48ee25a0b56672 198.51.100.1:500->192.0.2.1:500<FQDN/init.example.com>[10.0.5.117] ESTABLISHED r udpecap nexti 0x0 pol 0xcebae8df000
Testing
From init
, ping resp
to confirm:
init# ping 10.0.5.1 PING 10.0.5.1 (10.0.5.1): 56 data bytes 64 bytes from 10.0.5.1: icmp_seq=0 ttl=255 time=0.695 ms 64 bytes from 10.0.5.1: icmp_seq=1 ttl=255 time=0.793 ms resp# tcpdump -ne -i enc0 tcpdump: listening on enc0, link-type ENC 01:43:23.420194 (authentic,confidential): SPI 0x2b3e01ae: 10.0.5.117 > 10.0.5.1: icmp: echo request (encap) 01:43:23.420216 (authentic,confidential): SPI 0x41576324: 10.0.5.1 > 10.0.5.117: icm p: echo reply (encap) 01:43:24.420194 (authentic,confidential): SPI 0x2b3e01ae: 10.0.5.117 > 10.0.5.1: icm p: echo request (encap) 01:43:24.420214 (authentic,confidential): SPI 0x41576324: 10.0.5.1 > 10.0.5.117: icm p: echo reply (encap)
From init
, ping an external IP address and confirm that all packets pass through
resp
'senc0
interface:
init# ping 1.1.1.1 PING 1.1.1.1 (1.1.1.1): 56 data bytes 64 bytes from 1.1.1.1: icmp_seq=0 ttl=52 time=8.297 ms 64 bytes from 1.1.1.1: icmp_seq=1 ttl=52 time=8.191 ms resp# tcpdump -ne -i enc0 tcpdump: listening on enc0, link-type ENC 01:44:24.830185 (authentic,confidential): SPI 0x2b3e01ae: 10.0.5.117 > 1.1.1.1: icmp : echo request (encap) 01:44:24.837528 (authentic,confidential): SPI 0x41576324: 1.1.1.1 > 10.0.5.117: icmp : echo reply (encap) 01:44:25.830193 (authentic,confidential): SPI 0x2b3e01ae: 10.0.5.117 > 1.1.1.1: icmp : echo request (encap) 01:44:25.837375 (authentic,confidential): SPI 0x41576324: 1.1.1.1 > 10.0.5.117: icmp : echo reply (encap)
Configuring DNS
Change the following values in resp
's /var/unbound/etc/unbound.conf
:
outgoing-interface: 198.51.100.1 access-control: 10.0.0.0/8 allow
Make sure to enable and start unbound:
resp# rcctl enable unbound resp# rcctl start unbound
You may want to configure domain blacklists to block unwanted traffic.
If init
is running OpenBSD, you can verify if DNS lookup is working properly:
init# host ircnow.org ircnow.org has address 198.251.82.194 ircnow.org has IPv6 address 2605:6404:2d3:: ircnow.org mail is handled by 10 mail.ircnow.org. resp# tcpdump -ne -i enc0 tcpdump: listening on enc0, link-type ENC 01:25:54.119770 (authentic,confidential): SPI 0xb5cda039: 10.0.5.117.33324 > 8.8.8.8 .53: 63988+ A? ircnow.org.(28) (encap) 01:25:54.119882 (authentic,confidential): SPI 0x6f31fa50: 8.8.8.8.53 > 10.0.5.117.33 324: 63988 1/0/0 A 198.251.82.194(44) (encap) 01:25:55.139849 (authentic,confidential): SPI 0xb5cda039: 10.0.5.117.37113 > 8.8.8.8 .53: 10591+ AAAA? ircnow.org.(28) (encap) 01:25:55.139942 (authentic,confidential): SPI 0x6f31fa50: 8.8.8.8.53 > 10.0.5.117.37 113: 10591 1/0/0 AAAA 2605:6404:2d3::(56) (encap) 01:25:56.159754 (authentic,confidential): SPI 0xb5cda039: 10.0.5.117.1698 > 8.8.8.8. 53: 43204+ MX? ircnow.org.(28) (encap) 01:25:56.159846 (authentic,confidential): SPI 0x6f31fa50: 8.8.8.8.53 > 10.0.5.117.16 98: 43204 1/0/0 MX mail.ircnow.org. 10(49) (encap)
IPsec Statistics
init# netstat -s -p esp esp: 144 input ESP packets 150 output ESP packets 0 packets from unsupported protocol families .... 0 raw ESP packets for encapsulating TDB received 19976 input bytes 20406 output bytes init# netstat -s -p ah ah: 0 input AH packets 0 output AH packets 0 packets from unsupported protocol families ... 0 output packets could not be sent 0 input bytes 0 output bytes
As expected, there are no AH packets being sent because the IPsec flows are configured to use ESP for confidentiality. For more information, see ipsec(4).