Trying to set up Route-Based VPN using StrongSwan, having problems

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?