- 2017/06/16

WHY ??

I need unblocked Internet connection, because in my country Reddit is blocked by all mobile operator and most of Internet provider! Sssstttt… and also, this, this, and of course this.

I am not sysadmin, so basically this article is my note to build my VPN server on Ubuntu 16.04 in chronological order. Please adjust IP Address, Cert CN, Cert O, Cert Name according to your server and your need.

REQUIREMENTS

Install required software packages :

# apt update
# apt upgrade
# apt autoremove
# apt install haveged strongswan strongswan-charon \
libstrongswan-standard-plugins libstrongswan-extra-plugins libcharon-extra-plugins

Make sure haveged service is running :

# systemctl status haveged

It should output something like (green on dot and active (running)) :

● haveged.service - Entropy daemon using the HAVEGE algorithm
   Loaded: loaded (/lib/systemd/system/haveged.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2017-06-15 14:31:51 UTC; 4s ago
     Docs: man:haveged(8)
           http://www.issihosts.com/haveged/
 Main PID: 3410 (haveged)
    Tasks: 1
   Memory: 3.0M
      CPU: 443ms
   CGroup: /system.slice/haveged.service
           └─3410 /usr/sbin/haveged --Foreground --verbose=1 -w 1024

Stop strongswan service before we start setup :

# systemctl stop strongswan

Our working folder is ipsec.d config folder:

# cd /etc/ipsec.d

CA CERTIFICATE

Generate CA certificate private key :

# ipsec pki --gen --type rsa --size 4096 --outform der > private/ca.key.der
# chmod 600 private/ca.key.der

Generate CA certificate :

# ipsec pki --self --ca --lifetime 3650 --in private/ca.key.der \
--type rsa --dn "C=ID, O=SIMUKTINET, CN=SIMUKTI MIAMIVPN CA" \
--outform der > cacerts/ca.crt.der

View generated CA certificate :

# ipsec pki --print --in cacerts/ca.crt.der

It should output something like :

cert:      X509
subject:  "C=ID, O=SIMUKTINET, CN=SIMUKTI MIAMIVPN CA"
issuer:   "C=ID, O=SIMUKTINET, CN=SIMUKTI MIAMIVPN CA"
validity:  not before Jun 15 17:35:14 2017, ok
           not after  Jun 13 17:35:14 2027, ok (expires in 3649 days)
serial:    1c:0f:2c:80:32:e9:dc:0d
flags:     CA CRLSign self-signed 
subjkeyId: 5b:ef:c5:9d:c6:4a:2a:a1:92:fa:e3:61:70:b0:eb:cf:8b:6d:f5:e3
pubkey:    RSA 4096 bits
keyid:     ee:4c:88:ab:77:c5:54:ef:64:83:5c:ae:54:37:99:6f:88:5b:ab:72
subjkey:   5b:ef:c5:9d:c6:4a:2a:a1:92:fa:e3:61:70:b0:eb:cf:8b:6d:f5:e3

HOST CERTIFICATE

Generate host certificate private key:

# ipsec pki --gen --type rsa --size 4096 --outform der > private/host.key.der
# chmod 600 private/host.key.der

Generate host certificate :

# ipsec pki --pub --in private/host.key.der --type rsa | \
ipsec pki --issue --lifetime 1460 --cacert cacerts/ca.crt.der --cakey private/ca.key.der \
--dn "C=ID, O=SIMUKTINET, CN=miami-vpn.simukti.net" \
--san miami-vpn.simukti.net  --san 93.184.216.34  --san @93.184.216.34 \
--flag serverAuth --flag ikeIntermediate --outform der > certs/host.crt.der

View generated host certificate :

# ipsec pki --print --in certs/host.crt.der

It should output something like :

cert:      X509
subject:  "C=ID, O=SIMUKTINET, CN=miami-vpn.simukti.net"
issuer:   "C=ID, O=SIMUKTINET, CN=SIMUKTI MIAMIVPN CA"
validity:  not before Jun 15 17:36:58 2017, ok
           not after  Jun 14 17:36:58 2021, ok (expires in 1459 days)
serial:    5f:ce:f8:a9:16:7f:e1:5b
altNames:  miami-vpn.simukti.net, 93.184.216.34, 93.184.216.34
flags:     serverAuth iKEIntermediate 
authkeyId: 5b:ef:c5:9d:c6:4a:2a:a1:92:fa:e3:61:70:b0:eb:cf:8b:6d:f5:e3
subjkeyId: cb:c5:82:e6:f3:2a:92:ff:f6:c5:82:67:36:bb:74:15:ab:27:ce:aa
pubkey:    RSA 4096 bits
keyid:     79:aa:91:ee:ee:50:46:3d:56:ed:40:da:c5:60:3a:a2:45:58:2d:6e
subjkey:   cb:c5:82:e6:f3:2a:92:ff:f6:c5:82:67:36:bb:74:15:ab:27:ce:aa

USER CERTIFICATE

Generate user certificate private key :

# ipsec pki --gen --type rsa --size 2048 --outform der > private/simukti.key.der
# chmod 600 private/simukti.key.der

Generate user certificate public key :

# ipsec pki --pub --type rsa --in private/simukti.key.der | \
ipsec pki --issue --lifetime 1460 --cacert cacerts/ca.crt.der \
--cakey private/ca.key.der --dn "C=ID, O=SIMUKTINET, [email protected]" \
--san "[email protected]" --san "[email protected]" \
--outform der > certs/simukti.crt.der

View generated user certificate :

# ipsec pki --print --in certs/simukti.crt.der

It should output something like :

cert:      X509
subject:  "C=ID, O=SIMUKTINET, [email protected]"
issuer:   "C=ID, O=SIMUKTINET, CN=SIMUKTI MIAMIVPN CA"
validity:  not before Jun 15 17:39:08 2017, ok
           not after  Jun 14 17:39:08 2021, ok (expires in 1459 days)
serial:    7b:29:ad:a4:b9:5e:3c:27
altNames:  [email protected], [email protected]
flags:     
authkeyId: 5b:ef:c5:9d:c6:4a:2a:a1:92:fa:e3:61:70:b0:eb:cf:8b:6d:f5:e3
subjkeyId: ca:35:f5:54:d7:78:c6:bd:fc:24:ef:2d:31:bd:a5:1d:f9:f1:fc:11
pubkey:    RSA 2048 bits
keyid:     55:a6:44:dd:47:fc:50:cc:8c:cd:e4:ac:b2:e4:15:e9:fd:d8:8b:45
subjkey:   ca:35:f5:54:d7:78:c6:bd:fc:24:ef:2d:31:bd:a5:1d:f9:f1:fc:11

After user certificate created, we should convert required certificates to PEM format, and embed it as one importable PKCS#12 format for client system.

Convert user private key to PEM format :

# openssl rsa -inform DER -in private/simukti.key.der -outform PEM -out private/simukti.key.pem

Convert user certificate to PEM format :

# openssl x509 -inform DER -in certs/simukti.crt.der -outform PEM -out certs/simukti.crt.pem

Convert root certificate to PEM format :

# openssl x509 -inform DER -in cacerts/ca.crt.der -outform PEM -out cacerts/ca.crt.pem

Bundle required certificates as PKCS#12 :

# mkdir p12
# openssl pkcs12 -export -inkey private/simukti.key.pem \
-in certs/simukti.crt.pem -name "SIMUKTI's MIAMI VPN Cert" \
-certfile cacerts/ca.crt.pem -caname "SIMUKTI MIAMIVPN CA" \
-out p12/simukti.miami-vpn.simukti.net.p12

After we hit enter, there is a prompt for export’s password :

Enter Export Password:
Verifying - Enter Export Password:

IPSEC CONFIGURATION

Open ipsec.secrets using nano :

# nano /etc/ipsec.secrets

Fill ipsec.secrets content with something like :

# This file holds shared secrets or RSA private keys for authentication.

# RSA private key for this host, authenticating it to any other host
# which knows the public part.

: RSA /etc/ipsec.d/private/host.key.der

host.key.der is host’s private key from Host Certificate section.

Open ipsec.conf using nano :

# nano /etc/ipsec.conf

Fill ipsec.conf content with :

# ipsec.conf - strongSwan IPsec configuration file

# https://wiki.strongswan.org/projects/strongswan/wiki/ConfigSetupSection
config setup
    # https://wiki.strongswan.org/projects/strongswan/wiki/LoggerConfiguration
    charondebug="ike 0, knl 0, cfg 0, net 0, esp 0, dmn 0, mgr 0, job 0, enc 0, lib 0"

# https://wiki.strongswan.org/projects/strongswan/wiki/ConnSection
conn %default
    keyexchange=ikev2
    ike=aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024!
    esp=aes128gcm16-ecp256,aes256gcm16-ecp384,aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024,aes128gcm16,aes256gcm16,aes128-sha256,aes128-sha1,aes256-sha384,aes256-sha256,aes256-sha1!
    dpdaction=clear
    dpddelay=300s
    authby=pubkey
    rekey=no
    forceencaps=yes
    fragmentation=yes
    mobike=yes
    ikelifetime=6h
    compress=yes

    left=%any
    leftid=miami-vpn.simukti.net
    leftsubnet=0.0.0.0/0
    leftcert=/etc/ipsec.d/certs/host.crt.der
    leftsendcert=always
    leftfirewall=yes

    right=%any
    # you can use subnet /24, your choice
    rightsourceip=10.10.1.0/29
    rightdns=8.8.4.4,8.8.8.8

## ANDROID STRONGSWAN CLIENT (.p12 import)
## OSX IKEv2 (.p12 import)
conn IPSEC-IKEv2
    ## UPDATE 2018-03-25
    rightauth=pubkey
    keyexchange=ikev2
    auto=add

## UPDATE 2018-03-25 (MacOS High Sierra)
## WINDOWS CLIENT
## OSX SIERRA IKEv2 username+password
conn IKEv2-EAP
    also="IPSEC-IKEv2"
    rightauth=eap-mschapv2

Make sure leftid is value from host certificate CN. And now start strongswan service :

UPDATE 2018-03-25 (MacOS High Sierra)

For conn IKEv2-EAP we use username and password because after client upgrade to MacOS High Sierra I cannot use certificate based login.

If those config not working, try to change ike and esp value for MacOS HighSierra client with the following values :

ike=aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024,3des-sha1-modp1024!

esp=aes128gcm16-ecp256,aes256gcm16-ecp384,aes128-sha256-ecp256,aes256-sha384-ecp384,aes128-sha256-modp2048,aes128-sha1-modp2048,aes256-sha384-modp4096,aes256-sha256-modp4096,aes256-sha1-modp4096,aes128-sha256-modp1536,aes128-sha1-modp1536,aes256-sha384-modp2048,aes256-sha256-modp2048,aes256-sha1-modp2048,aes128-sha256-modp1024,aes128-sha1-modp1024,aes256-sha384-modp1536,aes256-sha256-modp1536,aes256-sha1-modp1536,aes256-sha384-modp1024,aes256-sha256-modp1024,aes256-sha1-modp1024,aes128gcm16,aes256gcm16,aes128-sha256,aes128-sha1,aes256-sha384,aes256-sha256,aes256-sha1,3des-sha1!
# nano /etc/ipsec.secrets

Add username and password authentication

# RSA private key for this host, authenticating it to any other host
# which knows the public part.
: RSA /etc/ipsec.d/private/host.key.der

#  UPDATE 2018-03-25
# USERNAME %any% : EAP "PASSWORD"
your_username %any% : EAP "your_password"
# systemctl start strongswan

View status of running strongswan :

# systemctl status strongswan

It should output something like (green on dot and active (running)):

● strongswan.service - strongSwan IPsec services
   Loaded: loaded (/lib/systemd/system/strongswan.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2017-06-15 14:50:34 UTC; 5s ago
  Process: 3528 ExecStopPost=/bin/rm -f /var/run/charon.pid /var/run/starter.charon.pid (code=exited, status=0/SUCCESS)
  Process: 3520 ExecStop=/usr/sbin/ipsec stop (code=exited, status=0/SUCCESS)
  Process: 3538 ExecStart=/usr/sbin/ipsec start (code=exited, status=0/SUCCESS)
  Process: 3535 ExecStartPre=/bin/mkdir -p /var/lock/subsys (code=exited, status=0/SUCCESS)
 Main PID: 3555 (starter)
    Tasks: 18
   Memory: 4.2M
      CPU: 90ms
   CGroup: /system.slice/strongswan.service
           ├─3555 /usr/lib/ipsec/starter --daemon charon
           └─3556 /usr/lib/ipsec/charon --use-syslog --debug-ike 0 --debug-knl 0 --debug-cfg 0 --debug-net 0 --debug-esp 0 --debug-dmn 0 --debug-mgr 0 --debug-job 0 --debug-enc 0 --debug-lib 0

View IPSec status :

# ipsec statusall

It should output something like :

Status of IKE charon daemon (strongSwan 5.3.5, Linux 4.4.0-79-generic, x86_64):
  uptime: 29 seconds, since Jun 15 17:45:46 2017
  malloc: sbrk 2199552, mmap 532480, used 1031312, free 1168240
  worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 0
  loaded plugins: charon test-vectors unbound ldap pkcs11 aes rc2 sha1 sha2 md4 md5 rdrand random nonce x509 revocation constraints acert pubkey pkcs1 pkcs7 pkcs8 pkcs12 pgp dnskey sshkey dnscert ipseckey pem openssl gcrypt af-alg fips-prf gmp agent chapoly xcbc cmac hmac ctr ccm gcm ntru bliss curl soup mysql sqlite attr kernel-netlink resolve socket-default connmark farp stroke updown eap-identity eap-sim eap-sim-pcsc eap-aka eap-aka-3gpp2 eap-simaka-pseudonym eap-simaka-reauth eap-md5 eap-gtc eap-mschapv2 eap-dynamic eap-radius eap-tls eap-ttls eap-peap eap-tnc xauth-generic xauth-eap xauth-pam xauth-noauth tnc-tnccs tnccs-20 tnccs-11 tnccs-dynamic dhcp whitelist lookip error-notify certexpire led radattr addrblock unity
Virtual IP pools (size/online/offline):
  10.10.1.0/29: 6/0/0
Listening IP addresses:
  93.184.216.34
Connections:
 IPSEC-IKEv2:  %any...%any  IKEv2, dpddelay=300s
 IPSEC-IKEv2:   local:  [miami-vpn.simukti.net] uses public key authentication
 IPSEC-IKEv2:    cert:  "C=ID, O=SIMUKTINET, CN=miami-vpn.simukti.net"
 IPSEC-IKEv2:   remote: uses public key authentication
 IPSEC-IKEv2:   child:  0.0.0.0/0 === dynamic TUNNEL, dpdaction=clear
Security Associations (0 up, 0 connecting):
  none

SYSCTL VARIABLES

To allow packet forwarding, we should set sysctl variables.

# nano /etc/sysctl.conf

Add these variables :

# STRONGSWAN
net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.icmp_ignore_bogus_error_responses = 1

View sysctl.conf values, and reload without reboot :

# sysctl -p
# sysctl --system

IPTABLES RULES

Allow system to receive network packets on UDP port 500 (IKE port) and UDP 4500 (NAT Traversal).

First, check our network card config :

# ifconfig

It should output something like :

ens3      Link encap:Ethernet  HWaddr 44:00:00:14:00:ee  
          inet addr:93.184.216.34  Bcast:93.184.216.255  Mask:255.255.254.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:4303 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3003 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:9022990 (9.0 MB)  TX bytes:490839 (490.8 KB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  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)

Note that our primary network card is ens3 (see that inet addr). That IP address (inet addr) must be equivalent with all certificate’s --san values.

Edit rc.local for persistent iptables config after reboot :

# nano /etc/rc.local

Now add postrouting to ens3 ip address and allow input on port 500 and 4500 :

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

iptables -A INPUT -p udp --dport 500 --j ACCEPT
iptables -A INPUT -p udp --dport 4500 --j ACCEPT
iptables -A INPUT -p esp -j ACCEPT
iptables -t nat -A POSTROUTING -j SNAT --to-source 93.184.216.34 -o ens+
for vpn in /proc/sys/net/ipv4/conf/*; do echo 0 > $vpn/accept_redirects; echo 0 > $vpn/send_redirects; done

exit 0

If our network card’s name is something like eth0, change -o ens+ to -o eth+.

Now, run rc.local:

# /etc/rc.local

OSX NATIVE VPN CLIENT SETUP

Copy those PKCS#12 file using scp :

# scp [email protected]:/etc/ipsec.d/p12/simukti.miami-vpn.simukti.net.p12 ~/Downloads/

Open Keychain Access, click on left bottom Category -> Certificates, and drag simukti.miami-vpn.simukti.net.p12 to right window. Enter our export’s password.

Trust all imported certificates :

  • Double click on SIMUKTI MIAMIVPN CA
  • Click Trust and set value of When using this certificate to Always Trust
  • Close those pop-up window
  • Double click on [email protected]
  • Click Trust and set value of When using this certificate to Always Trust
  • Close those pop-up window
  • Expand on [email protected]
  • Double click on SIMUKTI's MIAMI VPN Cert
  • Click tab Access Control and choose Allow all applications to access this item
  • Click Save Changes button on bottom right of pop-up window
  • Close those pop-up window

Now setup native VPN on OSX :

  • Click Apple logo on top left
  • Choose System Preferences
  • Choose Network
  • Click gold lock on bottom left window
  • Click +
  • Choose Interface: VPN
  • Choose VPN Type: IKEv2
  • Service Name: miami-vpn.simukti.net
  • Click Create button

Configure VPN profile miami-vpn.simukti.net :

  • Server address: 93.184.216.34
  • Remote ID: miami-vpn.simukti.net
  • Local ID: [email protected]
  • Click Authentication Settings... button
  • On Authentication Settings pop-window
  • Authentication Settings: None
  • Choose Certificate, and click Select... button
  • Scroll to bottom, and choose [email protected] (SIMUKTI MIAMIVPN CA)
  • Click Continue button
  • Click OK button
  • Make sure to mark Show VPN status in menu bar
  • Click Apply button
  • Click Connect button

In menu bar (top right), we should see timer for connected VPN connection.

We are done connecting OSX to our new IKEv2 VPN server.

UPDATE 2018-03-25 (MacOS High Sierra)

Using username password same with previous IPSec VPN, except for authentication, use Username, and input username and password you’ve defined in /etc/ipsec.secrets.

ANDROID STRONGSWAN CLIENT SETUP

Certificates import :

  • Open/Import simukti.miami-vpn.simukti.net.p12 from our Android (I send that p12 file via Telegram, you can also copy it via usb and open it using your favorite file manager)
  • We will be asked for password (previously set on USER CERTIFICATE section)
  • After we tap OK button, there is a pop-up displaying certificate import confirmation
  • Certificate name must be the same with the one you set on bundling pkcs#12 section (SIMUKTI’s MIAMI VPN Cert)
  • Credential use: VPN and apps
  • Tap OK button

strongSwan setup :

  • Install strongSwan from PlayStore: Click Here
  • My Android version at this time of writing is: 7.1.1
  • My strongSwan version at this time of writing is: 1.8.2
  • Open strongSwan
  • Tap ADD VPN PROFILE
  • Server : 93.184.216.34
  • VPN Type: IKEv2 Certificate
  • Tap Select user certificate
  • Choose the one we’ve just import (SIMUKTI’s MIAMI VPN Cert)
  • Tap Allow
  • CA certificate: mark Select Automatically
  • Profile name: miami-vpn.simukti.net
  • Mark Show advanced settings
  • Scroll down
  • On Split tunneling, mark Block IPv4 traffic not destined for the VPN and Block IPv6 traffic not destined for the VPN
  • Tap Save button (second from top right)

New profile has been added to list of strongSwan VPN profile, tap one of profile to connect to a VPN server.

If we see Status: Connected with green color, we are done connecting Android to our new IKEv2 VPN Server.

Now back to server, if we successfully connect OSX and Android, we should see 2 connections on IPSec status.

# ipsec status

It should output something like:

Security Associations (2 up, 0 connecting):
 IPSEC-IKEv2[7]: ESTABLISHED 11 seconds ago, 93.184.216.34[miami-vpn.simukti.net]...112.215.44.77[C=ID, O=SIMUKTINET, CN=[email protected]]
 IPSEC-IKEv2{5}:  INSTALLED, TUNNEL, reqid 5, ESP in UDP SPIs: cc33bd64_i 1570d7e5_o
 IPSEC-IKEv2{5}:   0.0.0.0/0 === 10.10.1.2/32
 IPSEC-IKEv2[6]: ESTABLISHED 17 seconds ago, 93.184.216.34[miami-vpn.simukti.net]...112.215.44.77[[email protected]]
 IPSEC-IKEv2{4}:  INSTALLED, TUNNEL, reqid 4, ESP in UDP SPIs: c73ec2bf_i 0bd80f1c_o
 IPSEC-IKEv2{4}:   0.0.0.0/0 === 10.10.1.1/32

Congratulation, we just build our very own IPSec-IKEv2 VPN server for OSX and Android client.

This article is mostly taken from Remy van Elst’s blog 1 2. If you think this article is useful, you should thanks to him.