Set Up IKEv2 VPN for iOS and macOS With Local DNS Cache and Dnscrypt

Since IKEv2 VPN supports MOBIKE and is natively supported by iOS 9, OS X 10.11 and newer, it’s a good choice for iOS and macOS. In my setup, I use Debian Stretch, unbound for DNS cache and dnscrypt-proxy for dnscrypt protocol.

Set up DNS service

Set up a network interface for DNS listening

An network interface file with name 10-loopback-services.cfg should be added to folder /etc/network/interfaces.d with the following content.

auto lo:100
iface lo:100 inet static

Then we need to restart networking service.

$ sudo service networking restart

Set up dnscrypt-proxy

Install dnscrypt-proxy

$ wget
$ tar zxf dnscrypt-proxy-x86_64-linux-musl.tar.gz
$ cd dnscrypt-proxy-x86_64-linux-musl
$ sudo sh

Now we need to replace the dnscrypt-proxy configuration, which located in /opt/dnscrypt-proxy/x86_64-linux-musl/etc/dnscrypt-proxy.conf, with the following content.

ResolverName cisco
Daemonize no
PidFile /var/run/
LocalCache off
EphemeralKeys off
BlockIPv6 no

Set up auto start script

A auto start script with name dnscrypt-proxy.service should be add to folder /etc/systemd/system with the following content.

Description=DNSCrypt client proxy

ExecStart=/opt/dnscrypt-proxy/x86_64-linux-musl/bin/dnscrypt-proxy /opt/dnscrypt-proxy/x86_64-linux-musl/etc/dnscrypt-proxy.conf


Then start dnscrypt-proxy service.

$ sudo systemctl start dnscrypt-proxy.service
$ sudo systemctl enable dnscrypt-proxy.service

Set up unbound

$ sudo apt-get install unbound -y
$ sudo wget ftp://FTP.INTERNIC.NET/domain/named.cache -O /etc/unbound/root.hints

Then the following content should be added to /etc/unbound/unbound.conf.

    num-threads: 2

    so-rcvbuf: 4m
    so-sndbuf: 4m
    so-reuseport: yes
    msg-cache-size: 64m
    rrset-cache-size: 128m
    cache-max-ttl: 3600
    outgoing-num-tcp: 256
    incoming-num-tcp: 1024

    do-ip4: yes
    do-ip6: yes
    do-udp: yes
    do-tcp: yes
    tcp-upstream: no
    access-control: allow
    access-control: allow
    access-control: allow
    root-hints: "/etc/unbound/root.hints"
    hide-identity: yes
    hide-version: yes

    harden-glue: yes
    module-config: "iterator"
    unwanted-reply-threshold: 10000000
    do-not-query-localhost: no
    prefetch: yes
    minimal-responses: yes
    name: "."

Then restart unbound service.

$ sudo service unbound restart

Set up IKEv2 VPN

Set up strongswan

Since strongswan in Debian Stretch is not the latest version, we compile from source.

$ sudo apt-get install -y --no-install-recommends build-essential libgmp-dev libssl-dev
$ wget
$ tar zxf strongswan-5.5.3.tar.gz
$ cd strongswan-5.5.3
$ ./configure --prefix=/usr --sysconfdir=/etc \
--enable-aes \
--enable-gcm \
--enable-hmac \
--enable-kernel-netlink \
--enable-nonce \
--enable-openssl \
--enable-pem \
--enable-pgp \
--enable-pkcs12 \
--enable-pkcs7 \
--enable-pkcs8 \
--enable-pubkey \
--enable-random \
--enable-revocation \
--enable-sha2 \
--enable-socket-default \
--enable-stroke \
$ make
$ sudo make install

Create certificates

Create CA

$ ipsec pki --gen --type ecdsa --size 384 --outform pem > ca-key.pem
$ ipsec pki --self --ca --lifetime 3650 --in ca-key.pem --type ecdsa --dn "C=NL, O=Example Company, CN=strongSwan Root CA" --outform pem > ca-cert.pem

Create server certificate

Repacle <server ip> with your current server ip address.

$ ipsec pki --gen --type ecdsa --size 384 --outform pem > server-key.pem
$ ipsec pki --pub --in server-key.pem --type ecdsa | ipsec pki --issue --lifetime 730 --cacert ca-cert.pem --cakey ca-key.pem --dn "C=NL, O=Example Company, CN=<server ip>" --san <server ip> --san @<server ip> --flag serverAuth --outform pem > server-cert.pem

Create client certificate

$ ipsec pki --gen --type ecdsa --size 384 --outform pem > client-key.pem
$ ipsec pki --pub --in client-key.pem --type ecdsa | ipsec pki --issue --lifetime 730 --cacert ca-cert.pem --cakey ca-key.pem --dn "C=NL, O=Example Company, CN=client" --san "client" --flag clientAuth --outform pem > client-cert.pem

Then copy certificates to necessary folders.

$ sudo cp server-key.pem /etc/ipsec.d/private
$ sudo cp server-cert.pem /etc/ipsec.d/certs
$ sudo cp ca-cert.pem /etc/ipsec.d/cacerts

Configure IPsec

Replace /etc/ipsec.conf with following content, do replace <server ip> with your server ip address.

config setup
    uniqueids=never # allow multiple connections per user
    charondebug="ike 2, knl 2, cfg 2, net 2, esp 2, dmn 2,  mgr 2"

conn %default


    leftid=<server ip>


conn ikev2-pubkey

Add the following line to file /etc/ipsec.secrets

: ECDSA server-key.pem

Then start IKEv2 VPN service.

$ sudo ipsec start

Configure iptables

$ iptables -A INPUT -p udp --dport 500 --j ACCEPT
$ iptables -A INPUT -p udp --dport 4500 --j ACCEPT
$ iptables -A INPUT -p ipencap -m policy --dir in --pol ipsec --proto esp -j ACCEPT
$ iptables -t nat -A POSTROUTING -s -m policy --pol none --dir out -j MASQUERADE
$ iptables -A FORWARD -m conntrack --ctstate NEW -s -m policy --pol ipsec --dir in -j ACCEPT

Set up mobileconfig for iOS and macOS

Since we cannot configure details like cipher in iOS and macOS GUI, we have to use mobileconfig. I use Apple Configurator 2 on macOS. You can just change certificate’s file extension to crt for use with Apple Configurator 2. We use AES-256-GCM for encryption algorithm, SHA2-512 for Integrity Algorithm and 20 for Diffie-Hellman Group. Or a mobileconfig template at Strongswan website can be used for modification.

comments powered by Disqus