I've been able to successfully set up a policy-based VPN using strongSwan, by following the directions laid out in OpenWrt's IPsec Road-Warrior Configuration guide. Now, I would like to try to see whether I can set up a route-based VPN, as discussed in strongSwan's Route-Based VPN doc. I have also been using this blog post as a reference. So far, I haven't been having very much success.
What I am trying to achieve with this route-based VPN:
- Set up the VPN in a road-warrior configuration.
- Make it so that the IP addresses handed out to road-warrior clients are on a separate subnet from devices on the LAN. By default, OpenWrt assigns the 192.168.1.0/24 subnet to my router's LAN, so I would like the VPN to assign IPs from the 192.168.2.0/24 subnet.
Here is what I have done up to this point, step-by-step.
Set up VTI network interface
According to the Basic Networking doc, additional packages are needed in order to use the VTI interface protocol.
opkg install vti kmod-ip-vti
Then, I added a new interface to /etc/config/network
by following the Tunneling Interface Protocols doc.
config interface 'tun'
option ifname 'vti0'
option proto 'vti'
option ipaddr '192.168.2.1'
option peeraddr '0.0.0.0'
option zone 'vpn'
option ikey 42
option okey 42
After doing an /etc/init.d/network reload
, according to ip link
it looks like two additional links have been added, named ip_vti0@NONE
and vti-tun@NONE
:
ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
4: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
6: ip_vti0@NONE: <NOARP> mtu 1480 qdisc noqueue state DOWN mode DEFAULT group default qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
7: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br-lan state UP mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
8: wlan1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br-lan state UP mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
9: wlan2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br-lan state UP mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
10: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
11: eth0.1@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-lan state UP mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
12: eth0.2@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether xx:xx:xx:xx:xx:bd brd ff:ff:ff:ff:ff:ff
22: vti-tun@NONE: <NOARP,UP,LOWER_UP> mtu 1280 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/ipip 192.168.2.1 brd 0.0.0.0
Also, this is what the output of ifconfig -a
looks like:
ifconfig -a
br-lan Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: <snip> Scope:Global
inet6 addr: <snip> Scope:Global
inet6 addr: <snip> Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
<snip>
eth0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet6 addr: <snip> Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
<snip>
Interrupt:23
eth0.1 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
<snip>
eth0.2 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet add:<public ip> Bcast:<public bcast> Mask:<public netmask>
inet6 addr: <snip> Scope:Global
inet6 addr: <snip> Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
<snip>
eth1 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
BROADCAST MULTICAST MTU:1500 Metric:1
<snip>
Interrupt:24
eth2 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
BROADCAST MULTICAST MTU:1500 Metric:1
<snip>
Interrupt:25
ip_vti0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:1480 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
<snip>
vti-tun Link encap:UNSPEC HWaddr xx-xx-xx-xx-xx-00-00-00-00-00-00-00-00-00-00-00
UP RUNNING NOARP MTU:1280 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:2 dropped:0 overruns:0 carrier:2
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
wlan0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet6 addr: <snip> Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
<snip>
wlan1 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet6 addr: <snip> Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
<snip>
wlan2 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet6 addr: <snip> Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
<snip>
Some things that immediately stood out to me were that the link encapsulation was UNSPEC
(okay, maybe not a big deal, perhaps it's just how the vti
protocol works?), that it was showing up as NOARP
, and that the interface has no inet addr
(Uh-oh. I thought it would have gotten set to 192.168.2.1?). Also, why is the tx queue length showing qlen 1
?
StrongSwan Configuration
/etc/strongswan.conf
# strongswan.conf - strongSwan configuration file
#
# Refer to the strongswan.conf(5) manpage for details
#
# Configuration changes should be made in the included files
charon {
# These two lines added for route-based VPN
install_routes = no
install_virtual_ip = no
load_modular = yes
plugins {
include strongswan.d/charon/*.conf
dhcp {
identity_lease = yes
force_server_address = yes
server = 192.168.2.255
}
}
dns1 = 192.168.2.1
nbns1 = 192.168.2.1
}
include strongswan.d/*.conf
IPsec Configuration
/etc/ipsec.conf
# ipsec.conf - strongSwan IPsec configuration file
# basic configuration
config setup
# strictcrlpolicy=yes
# uniqueids = no
# Add connections here.
# Sample VPN connections
#conn sample-self-signed
<snip>
#conn sample-with-ca-cert
<snip>
conn roadwarrior
keyexchange=ikev2
auto=add
mark_in=42
mark_out=42
left=%any
leftauth=pubkey
leftcert=serverCert.pem
leftid=<dyndns domain>
leftsubnet=0.0.0.0/0,::/0
leftsendcert=always
right=%any
rightauth=pubkey
rightcert=clientCert.pem
rightauth2=eap-mschapv2
rightid=<dyndns domain>
rightsourceip=%dhcp
/etc/ipsec.secrets
# /etc/ipsec.secrets - strongSwan IPsec secrets file
: RSA serverKey.pem
<user name> : EAP <password>
DHCP Configuration
I added a DHCP pool for the tun
interface:
/etc/config/dhcp
config dhcp 'vpn'
option interface 'tun'
option start '100'
option limit '150'
option lease time '12h'
option dhcpv6 'server'
option ra 'server'
Firewall Configuration
Since the firewall config file is pretty long, I only list the rules that I added. The rest of the file remains the same as the default.
/etc/config/firewall
config rule
option name Allow-IPSec-ESP
option src wan
option proto esp
option target ACCEPT
config rule
option name Allow-ISAKMP
option src wan
option dest_port 500
option proto udp
option target ACCEPT
config rule
option name 'IPSec NAT-T'
option src wan
option dest_port 4500
option proto udp
option target ACCEPT
config rule
option name 'Auth Header'
option src wan
option proto ah
option target ACCEPT
config zone
option name vpn
list network 'tun'
option input REJECT
option output ACCEPT
option forward REJECT
config forwarding
option src lan
option dest vpn
config forwarding
option src vpn
option dest lan
config forwarding
option src wan
option dest vpn
config rule
option name Allow-DNS-Queries-VPN
option src vpn
option proto udp
option dest_port 53
option target ACCEPT
config rule
option name Allow-DHCP-Renew-VPN
option src vpn
option proto udp
option dest_port 67-68
option target ACCEPT
option family ipv4
/etc/firewall.user
### Additional rules that are needed for IKEv2/IPsec VPN
iptables -I INPUT -m policy --dir in --pol ipsec --proto esp -j ACCEPT
iptables -I FORWARD -m policy --dir in --pol ipsec --proto esp -j ACCEPT
iptables -I FORWARD -m policy --dir out --pol ipsec --proto esp -j ACCEPT
iptables -I OUTPUT -m policy --dir out --pol ipsec --proto esp -j ACCEPT
Other Configs
If I run the ip route
command, it shows
default via <public gateway> dev eth0.2 proto static src <public ip>
<public subnet> dev eth0.2 proto kernel scope link src <public ip>
<public gateway> dev eth0.2 proto static scope link src <public ip>
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.1
According to both the strongSwan doc and the blog post, I have to add the DHCP pool to the routing table:
ip route add 192.168.2.0/24 dev vti-tun
after which ip route
looks like this:
default via <public gateway> dev eth0.2 proto static src <public ip>
<public subnet> dev eth0.2 proto kernel scope link src <public ip>
<public gateway> dev eth0.2 proto static scope link src <public ip>
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.1
192.168.2.0/24 dev vti-tun scope link
Another indication that something did not seem right with my set-up was by how "incomplete" the new ip route line seemed to be; proto kernel
and, more importantly, src 192.168.2.1
are missing. When I had set up a policy-based VPN, the new routing entry looked "healthy", i.e. it was showing 192.168.2.0/24 dev eth0.3 proto kernel scope link src 192.168.2.1
.
Restart/Start Up Services
/etc/init.d/network reload
killall dnsmasq
/etc/init.d/dnsmasq start
/etc/init.d/firewall restart
logread && logread -f
ipsec start --nofork
When I run ipsec statusall
, it shows
Status of IKE charon daemon (strongSwan 5.5.3, Linux 4.4.153, armv7l):
uptime: 86 seconds, since Jan 31 21:29:31 2019
worker threads: 10 of 16 idle, 6/0/0/0 working, job queue: 0/0/0/0, scheduled: 0
loaded plugins: charon test-vectors ldap pkcs11 aes des blowfish rc2
sha2 sha1 md4 md5 random nonce x509 revocation constraints
pubkey pkcs1 pkcs7 pkcs8 pkcs12 pgp dnskey sshkey pem openssl
gcrypt af-alg fips-prf gmp curve25519 agent xcbc cmac hmac
ctr ccm gcm curl mysql sqlite attr kernel-netlink resolve
socket-default connmark forecast farp stroke smp updown
eap-identity eap-md5 eap-mschapv2 eap-radius eap-tls
xauth-generic xauth-eap dhcp whitelist led duplicheck addrblock unity
Listening IP addresses:
192.168.1.1
<ipv6 addr>
<ipv6 addr>
<public ip>
<ipv6 addr>
Connections:
roadwarrior: %any...%any IKEv2
roadwarrior: local: [<dyndns domain>] uses public key authentication
roadwarrior: cert: "C=US, O=<orgName>, CN=<dyndns domain>"
roadwarrior: remote: [<dyndns domain>] uses public key authentication
roadwarrior: cert: "C=US, O=<orgName>, CN=<dyndns domain>"
roadwarrior: child: 0.0.0.0/0 ::/0 === dynamic TUNNEL
Security Associations (0 up, 0 connecting):
none
As you can see, the daemon is not listening on IP address 192.168.2.1. When I had set up a policy-based VPN, it was showing up in the list. Needless to say, trying to connect to the VPN is not working. Is there something that I am missing from my configurations? Are the instructions I was using as references incomplete?