Multiple IPSec VPN tunnels with FreeBSD ======================================= Introduction ------------ The FreeBSD handbook describes an IPSec VPN tunnel between 2 FreeBSD hosts (see https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ipsec.html) But it is also possible to have multiple, 2 or more, IPSec VPN tunnels created and running on a FreeBSD host. How to implement and configure this is described below. The requirement --------------- The requirements is to have 3 locations (A, B and C) connected with IPSec VPN tunnels using FreeBSD (11.3-RELEASE). Each location has 1 IPSec VPN host running FreeBSD (VPN host A, B and C). VPN host A has 2 IPSec VPN tunnels: 1 to location B (VPN host B) and 1 to location C (VPN host C). Diagram ------- Location B Location C Network B Network C |-----------| |-----------| | | | | ----- VPN host B ----- VPN host C | | | | | | | | ----- ----- \ / - Internet - \ / - - \ / Location A ----- VPN host A | | | | ----- | | |-----------| Network A1 | | ----- Firewall A | | | | ----- | |-----------| Network A2 The starting points ------------------- - We have 3 locations: location A, B and C - Each location has a VPN host (VPN host A, VPN host B and VPN host C) - All 3 VPN hosts A, B and C run FreeBSD (11.3-RELEASE) - The internet facing interfaces of the VPN hosts are em0 - The internal facing interfaces of the VPN hosts are em1 - All VPN hosts are directly connected to the internet with their em0 interfaces and have a public IP address - The public IP address of VPN host A (interface em0) is: 1.2.3.4 - The public IP address of VPN host B (interface em0) is: 9.8.7.6 - The public IP address of VPN host C (interface em0) is: 11.12.13.14 - VPN host A has 2 site to site VPN connections: 1 to VPN host B (location B) and 1 to VPN host C (location C) - VPN host A uses alias IP addresses on its internal interface to route traffic through the VPN tunnels B and C - VPN hosts B and C do NOT use alias IP addresses, but uses the IP address if its internal interface (em1) to route traffic through the VPN tunnel (to site A) - Site A has 2 internal networks called network A1 and network A2. The networks A1 and A2 are separated by a firewall Firewall A - Site B has 1 internal network called network B - Site C has 1 internal network called network C - Both networks A1 and A2 can route to networks B and C, through the site to site VPN tunnels - Network A1 is subnet 192.168.9.0/24 - Network A2 is subnet 192.168.1.0/24 - Network B is subnet 10.1.1.0/24 - Network C is subnet 172.16.1.0/24 - The internal interfaces of the VPN hosts (interface em1) have an IP address of .1 - Firewall A has IP address .254 in network A1 - Firewall A has IP address .1 in network A2 - Only static routing is used - It is assumed that pf is running on all 3 VPN hosts - Firewall A is also running FreeBSD (11.3-RELEASE) configured as a gateway with pf enabled - All commands are done with the root account (with /bin/csh as shell) The implementation steps ------------------------ Step 1: On all 3 VPN hosts - install the ipsec-tools package: # pkg update & pkg upgrade # pkg install ipsec-tools Step 2: On all 3 VPN hosts - enable the gateway functionality: # sysrc gateway_enable="YES" Step 3: On all 3 VPN hosts - enable ipsec and racoon in rc.conf: # sysrc ipsec_enable="YES" # sysrc ipsec_program="/usr/local/sbin/setkey" # sysrc ipsec_file="/usr/local/etc/racoon/setkey.conf" # sysrc racoon_enable="YES" Step 4: On VPN host A Create alias IP addresses on internal interface em1 # sysrc ifconfig_em1_alias0="inet 192.168.9.2 netmask 255.255.255.255" # sysrc ifconfig_em1_alias1="inet 192.168.9.3 netmask 255.255.255.255" Create gif0 and gif1 interfaces and setup the tunnels # sysrc cloned_interfaces="gif0 gif1" # sysrc ifconfig_gif0="192.168.9.2 10.1.1.1 netmask 255.255.255.0 tunnel 1.2.3.4 9.8.7.6" # sysrc ifconfig_gif1="192.168.9.3 172.16.1.1 netmask 255.255.255.0 tunnel 1.2.3.4 11.12.13.14" Create static routes to Network B and Network C # sysrc static_routes+="networkb" # sysrc route_networkb="10.1.1.0/24 192.168.9.2" # sysrc static_routes+="networkc" # sysrc route_networkc="172.16.1.0/24 192.168.9.3" Step 5: On VPN host B: Create gif0 interface and setup the tunnel to VPN host A (site A) # sysrc ifconfig_gif0="10.1.1.1 192.168.9.2 netmask 255.255.255.0 tunnel 9.8.7.6 1.2.3.4" Create the static routes to networks A1 and A2 (site A) # sysrc static_routes+="networka1 networka2" # sysrc route_networka1="192.168.9.0/24 10.1.1.1" # sysrc route_networka2="192.168.1.0/24 10.1.1.1" Step 6: On VPN host C: Create gif0 interface and setup the tunnel to VPN host A (site A) # sysrc ifconfig_gif0="172.16.1.1 192.168.9.3 netmask 255.255.255.0 tunnel 11.12.13.14 1.2.3.4" Create the static routes to networks A1 and A2 (site A) # sysrc static_routes+="networka1 networka2" # sysrc route_networka1="192.168.9.0/24 172.16.1.1" # sysrc route_networka2="192.168.1.0/24 172.16.1.1" Step 7: On Firewall A: Create the static routes to network B and C # sysrc static_routes+="networkb networkc" # sysrc route_networkb="10.1.1.0/24 192.168.9.2" # sysrc route_networkc="172.16.1.0/24 192.168.9.3" Step 8: On VPN host A: Create the configuration files for racoon # cat << EOF >> /usr/local/etc/racoon/psk.txt 9.8.7.6 HardToGuessPreSharedKeyAToB 11.12.13.14 HardToGuessPreSharedKeyAToC EOF # cat << EOF >> /usr/local/etc/racoon/racoon.conf path pre_shared_key "/usr/local/etc/racoon/psk.txt"; log info; padding { maximum_length 20; randomize off; strict_check off; exclusive_tail off; } timer { counter 5; interval 20 sec; persend 1; phase1 30 sec; phase2 15 sec; } listen { isakmp 1.2.3.4 [500]; adminsock "/var/db/racoon/racoon.sock"; } remote 9.8.7.6 [500] { exchange_mode main, aggressive; my_identifier address 1.2.3.4; peers_identifier address 9.8.7.6; passive off; proposal_check obey; nat_traversal off; generate_policy off; proposal { authentication_method pre_shared_key; encryption_algorithm aes 256; hash_algorithm sha256; dh_group 2; lifetime time 28800 secs; } } remote 11.12.13.14 [500] { exchange_mode main, aggressive; my_identifier address 1.2.3.4; peers_identifier address 11.12.13.14; passive off; proposal_check obey; nat_traversal off; generate_policy off; proposal { authentication_method pre_shared_key; encryption_algorithm aes 256; hash_algorithm sha256; dh_group 2; lifetime time 28800 secs; } } sainfo (address 192.168.9.0/24 any address 10.1.1.0/24 any) { encryption_algorithm aes 256, aes 192, aes 128; authentication_algorithm hmac_sha256; lifetime time 3600 sec; compression_algorithm deflate; } sainfo (address 192.168.1.0/24 any address 10.1.1.0/24 any) { encryption_algorithm aes 256, aes 192, aes 128; authentication_algorithm hmac_sha256; lifetime time 3600 sec; compression_algorithm deflate; } sainfo (address 192.168.9.0/24 any address 172.16.1.0/24 any) { encryption_algorithm aes 256, aes 192, aes 128; authentication_algorithm hmac_sha256; lifetime time 3600 sec; compression_algorithm deflate; } sainfo (address 192.168.1.0/24 any address 172.16.1.0/24 any) { encryption_algorithm aes 256, aes 192, aes 128; authentication_algorithm hmac_sha256; lifetime time 3600 sec; compression_algorithm deflate; } EOF # cat << EOF >> /usr/local/etc/racoon/setkey.conf flush; spdflush; spdadd -4 192.168.9.0/24 10.1.1.0/24 any -P out ipsec esp/tunnel/1.2.3.4-9.8.7.6/unique; spdadd -4 10.1.1.0/24 192.168.9.0/24 any -P in ipsec esp/tunnel/9.8.7.6-1.2.3.4/unique; spdadd -4 192.168.1.0/24 10.1.1.0/24 any -P out ipsec esp/tunnel/1.2.3.4-9.8.7.6/unique; spdadd -4 10.1.1.0/24 192.168.1.0/24 any -P in ipsec esp/tunnel/9.8.7.6-1.2.3.4/unique; spdadd -4 192.168.9.0/24 172.16.1.0/24 any -P out ipsec esp/tunnel/1.2.3.4-11.12.13.14/unique; spdadd -4 172.16.1.0/24 192.168.9.0/24 any -P in ipsec esp/tunnel/11.12.13.14-1.2.3.4/unique; spdadd -4 192.168.1.0/24 172.16.1.0/24 any -P out ipsec esp/tunnel/1.2.3.4-11.12.13.14/unique; spdadd -4 172.16.1.0/24 192.168.1.0/24 any -P in ipsec esp/tunnel/11.12.13.14-80.127.154.213/unique; EOF Step 9: On VPN host B: # cat << EOF >> /usr/local/etc/racoon/psk.txt 1.2.3.4 HardToGuessPreSharedKeyAToB EOF # cat << EOF >> /usr/local/etc/racoon/racoon.conf path pre_shared_key "/usr/local/etc/racoon/psk.txt"; log info; padding { maximum_length 20; randomize off; strict_check off; exclusive_tail off; } timer { counter 5; interval 20 sec; persend 1; phase1 30 sec; phase2 15 sec; } listen { isakmp 9.8.7.6 [500]; adminsock "/var/db/racoon/racoon.sock"; } remote 1.2.3.4 [500] { exchange_mode main, aggressive; my_identifier address 9.8.7.6; peers_identifier address 1.2.3.4; passive off; proposal_check obey; nat_traversal off; generate_policy off; proposal { authentication_method pre_shared_key; encryption_algorithm aes 256; hash_algorithm sha256; dh_group 2; lifetime time 28800 secs; } } sainfo (address 10.1.1.0/24 any address 192.168.9.0/24 any) { encryption_algorithm aes 256, aes 192, aes 128; authentication_algorithm hmac_sha256; lifetime time 3600 sec; compression_algorithm deflate; } sainfo (address 10.1.1.0/24 any address 192.168.1.0/24 any) { encryption_algorithm aes 256, aes 192, aes 128; authentication_algorithm hmac_sha256; lifetime time 3600 sec; compression_algorithm deflate; } EOF # cat << EOF >> /usr/local/etc/racoon/setkey.conf flush; spdflush; spdadd -4 10.1.1.0/24 192.168.9.0/24 any -P out ipsec esp/tunnel/9.8.7.6-1.2.3.4/unique; spdadd -4 192.168.9.0/24 10.1.1.0/24 any -P in ipsec esp/tunnel/1.2.3.4-9.8.7.6/unique; spdadd -4 10.1.1.0/24 192.168.1.0/24 any -P out ipsec esp/tunnel/9.8.7.6-1.2.3.4/unique; spdadd -4 192.168.1.0/24 10.1.1.0/24 any -P in ipsec esp/tunnel/1.2.3.4-9.8.7.6/unique; EOF Step 10: On VPN host C: # cat << EOF >> /usr/local/etc/racoon/psk.txt 1.2.3.4 HardToGuessPreSharedKeyAToC EOF # cat << EOF >> /usr/local/etc/racoon/racoon.conf path pre_shared_key "/usr/local/etc/racoon/psk.txt"; log info; padding { maximum_length 20; randomize off; strict_check off; exclusive_tail off; } timer { counter 5; interval 20 sec; persend 1; phase1 30 sec; phase2 15 sec; } listen { isakmp 11.12.13.14 [500]; adminsock "/var/db/racoon/racoon.sock"; } remote 1.2.3.4 [500] { exchange_mode main, aggressive; my_identifier address 11.12.13.14; peers_identifier address 1.2.3.4; passive off; proposal_check obey; nat_traversal off; generate_policy off; proposal { authentication_method pre_shared_key; encryption_algorithm aes 256; hash_algorithm sha256; dh_group 2; lifetime time 28800 secs; } } sainfo (address 172.16.1.0/24 any address 192.168.9.0/24 any) { encryption_algorithm aes 256, aes 192, aes 128; authentication_algorithm hmac_sha256; lifetime time 3600 sec; compression_algorithm deflate; } sainfo (address 172.16.1.0/24 any address 192.168.1.0/24 any) { encryption_algorithm aes 256, aes 192, aes 128; authentication_algorithm hmac_sha256; lifetime time 3600 sec; compression_algorithm deflate; } EOF # cat << EOF >> /usr/local/etc/racoon/setkey.conf flush; spdflush; spdadd -4 172.16.1.0/24 192.168.9.0/24 any -P out ipsec esp/tunnel/11.12.13.14-1.2.3.4/unique; spdadd -4 192.168.9.0/24 172.16.1.0/24 any -P in ipsec esp/tunnel/1.2.3.4-11.12.13.14/unique; spdadd -4 172.16.1.0/24 192.168.1.0/24 any -P out ipsec esp/tunnel/11.12.13.14-1.2.3.4/unique; spdadd -4 192.168.1.0/24 172.16.1.0/24 any -P in ipsec esp/tunnel/1.2.3.4-11.12.13.14/unique; EOF Step 12: On all 3 VPN hosts: Make sure you allow the IPSec traffic in pf: pass in quick proto esp from any to any pass in quick proto ah from any to any pass in quick proto ipencap from any to any pass in quick proto udp from any port = 500 to any port = 500 pass in quick on gif0 from any to any pass out quick proto esp from any to any pass out quick proto ah from any to any pass out quick proto ipencap from any to any pass out quick proto udp from any port = 500 to any port = 500 pass out quick on gif0 from any to any And to allow ICMP ping traffic: On VPN host A: pass in log quick on em1 inet proto icmp from { 192.168.9.0/24 , 192.168.1.0/24 } to { 10.1.1.0/24, 172.16.1.0/24 } icmp-type echoreq keep state On VPN host B: pass in log quick on em1 inet proto icmp from { 10.1.1.0/24 } to { 192.168.9.0/24 , 192.168.1.0/24 } icmp-type echoreq keep state On VPN host C: pass in log quick on em1 inet proto icmp from { 172.16.1.0/24 } to { 192.168.9.0/24 , 192.168.1.0/24 } icmp-type echoreq keep state Please add more rules to allow other traffic through the IPSec VPN tunnels Step 13: If all done right then the relevant items of the /etc/rc.conf files of the VPN hosts are: VPN host A: ifconfig_em0="inet 1.2.3.4 netmask 255.255.255.0" ifconfig_em1="inet 192.168.9.1 netmask 255.255.255.0" ifconfig_em1_alias0="inet 192.168.9.2 netmask 255.255.255.255" ifconfig_em1_alias1="inet 192.168.9.3 netmask 255.255.255.255" cloned_interfaces="gif0 gif1" ifconfig_gif0="192.168.9.2 10.1.1.1 netmask 255.255.255.0 tunnel 1.2.3.4 9.8.7.6" ifconfig_gif1="192.168.9.3 172.16.1.1 netmask 255.255.255.0 tunnel 1.2.3.4 11.12.13.14" static_routes="networkb networkc" route_networkb="10.1.1.0/24 192.168.9.2" route_networkc="172.16.1.0/24 192.168.9.3" gateway_enable="YES" pf_enable="YES" pf_rules="/etc/pf.conf" pf_flags="" pflog_enable="YES" pflog_logfile="/var/log/pf.log" pflog_flags="" ipsec_enable="YES" ipsec_program="/usr/local/sbin/setkey" ipsec_file="/usr/local/etc/racoon/setkey.conf" racoon_enable="YES" VPN host B: ifconfig_em0="inet 9.8.7.6 netmask 255.255.255.0" ifconfig_em1="inet 10.1.1.1 netmask 255.255.255.0" cloned_interfaces="gif0" ifconfig_gif0="10.1.1.1 192.168.9.2 netmask 255.255.255.0 tunnel 9.8.7.6 1.2.3.4" static_routes="networka1 networka2" route_networka1="192.168.9.0/24 10.1.1.1" route_networka2="192.168.1.0/24 10.1.1.1" gateway_enable="YES" pf_enable="YES" pf_rules="/etc/pf.conf" pf_flags="" pflog_enable="YES" pflog_logfile="/var/log/pf.log" pflog_flags="" ipsec_enable="YES" ipsec_program="/usr/local/sbin/setkey" ipsec_file="/usr/local/etc/racoon/setkey.conf" racoon_enable="YES" VPN host C: ifconfig_em0="inet 11.12.13.14 netmask 255.255.255.0" ifconfig_em1="inet 172.16.1.1 netmask 255.255.255.0" cloned_interfaces="gif0" ifconfig_gif0="172.16.1.1 192.168.9.3 netmask 255.255.255.0 tunnel 11.12.13.14 1.2.3.4" static_routes="networka1 networka2" route_networka1="192.168.9.0/24 172.16.1.1" route_networka2="192.168.1.0/24 172.16.1.1" gateway_enable="YES" pf_enable="YES" pf_rules="/etc/pf.conf" pf_flags="" pflog_enable="YES" pflog_logfile="/var/log/pf.log" pflog_flags="" ipsec_enable="YES" ipsec_program="/usr/local/sbin/setkey" ipsec_file="/usr/local/etc/racoon/setkey.conf" racoon_enable="YES" Step 14: On all 3 VPN hosts: # shutdown -r now Now you can check if your IPSec VPN tunnels are actually up: On VPN host A: # racoonctl show-sa isakmp Destination Cookies Created 9.8.7.6.500 58b278b5c6fbeeeb:1287d273aa783893 2019-11-18 09:01:55 11.12.13.14.500 07169fd9cdb41b1f:5112f93f33d5aa40 2019-11-18 07:21:55 On VPN host B: # racoonctl show-sa isakmp Destination Cookies Created 1.2.3.4.500 58b278b5c6fbeeeb:1287d273aa783893 2019-11-18 09:01:55 On VPN host C: Destination Cookies Created 1.1.1.1.500 07169fd9cdb41b1f:5112f93f33d5aa40 2019-11-18 07:21:55 Other resources: ---------------- - https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ipsec.html - https://virtualisationworks.wordpress.com/2017/02/10/virtual-private-network-with-freebsd-part-1/ - https://forums.freebsd.org/threads/setting-up-multiple-tunnels-in-rc-conf.14270/