VPN: Virtual Private Network
Strongswan: IPsec-based VPN
IKEv2: VPN encryption protocol
MS-CHAPv2 (MSCHAPv2): authentication protocol
VPNs can be used for various reasons: the need to securely connect to a company's local network resources; the need to bypass geolocation restrictions; to route our internet traffic through a secured gateway. Whatever the reason, we have to be able to spawn a tunnel for that (connection to a VPN provider/server).
How do we connect to these VPN providers using Ubuntu Linux
With OpenVPN everything is damn simple, install the OpenVPN NetworkManager plugin (sudo apt install network-manager-openvpn
) then import an OpenVPN connection by double click on a .ovpn file (provided by the VPN provider). With Strongswan VPNs (configured with IKEv2 encryption and MSCHAPv2 authentication) things gets a little bit complicated ...
First time when I was dealing with an IPsec-based tunnel, I thought, "Well, I'm pretty sure there is a NetworkManager plugin that I can use for that". And I was right, except that ... it didn't work, always authentication failure notices. Ok then, I'm still on Linux, sure there is a way to connect to the VPN using CLI, and I was right again, it worked this time, except ... the CLI solution doesn't provide Gnome visual feedbacks. So I wrote a small shell script, added it to the Argos Gnome Extension, and here we are, we can connect/disconnect/see the status of our CLI based IKEv2 IPsec-VPN connection, using the Gnome interface.
... meanwhile, I didn't forget that there is a Network Manager extension that should work, and thanks to Tobias from Strongswan, who was kind enough to provide me direct assistance, I've managed to connect to my VPNs using the NetworkManager interface. But again, found that using the NM interface, there is no way to use the connection only for resources on its network. Then I came with the final hybrid solution, the Gnome extension able to connect/disconnect/show status from both CLI and NM, and below are the steps and the necessary code to accomplish that.
Step 1: compile strongswan from source
wget https://download.strongswan.org/strongswan-5.9.3.tar.bz2 tar -xf strongswan-5.9.3.tar.bz2 cd strongswan-5.9.3 ./configure --sysconfdir=/etc --prefix=/usr --libexecdir=/usr/lib \ --enable-aesni --enable-acert --disable-aes --disable-des --disable-md5 --disable-sha1 --disable-sha2 \ --disable-fips-prf --disable-gmp --enable-openssl --enable-nm --enable-agent \ --disable-eap-gtc --disable-eap-md5 --disable-eap-peap --enable-eap-mschapv2 --enable-eap-identity make sudo make install
5.9.3
with one up to date at the time; remove the --enable-aesni
flag if your CPU or kernel doesn't support AES-NIStep 2: compile strongswan network-manager plugin from source
wget https://download.strongswan.org/NetworkManager/NetworkManager-strongswan-1.5.2.tar.bz2 tar -xf NetworkManager-strongswan-1.5.2.tar.bz2 ./configure --sysconfdir=/etc --prefix=/usr --libexecdir=/usr/lib --without-libnm-glib make sudo make install
Step 3: disable peap, md5, and gtc plugins for charon-nm (strongswan network-manager plugin)
Edit /etc/strongswan.confsudo nano /etc/strongswan.conf
charon { load_modular = yes plugins { include strongswan.d/charon/*.conf } } charon-nm { plugins { eap-peap { load = no } eap-md5 { load = no } eap-gtc { load = no } } } include strongswan.d/*.conf
At this step we shall be able to create (and connect to) IKEv2 MS-CHAPv2 IPsec-based VPNs using NetworkManager.
hide.me IKE IPsec connection using NetworkManager |
|
*pem from https://hide.me/downloads/hide.me.pem |
[UPDATE] Using a VPN connection only for resources on its network
The default "Use this connection only for resources on its network" checkbox (within the NM VPN setting IPv4 panel) does nothing. That's why I've initially written the extra steps 4-6 tutorial, but recently discovered the "dispatcher" options of the NetworkManager and decided to give it a try, and it works.
How to make it work: just install ipcalc sudo apt install ipcalc
and add the following code snippet to the /etc/NetworkManager/dispatcher.d/01-ifupdown
dispatcher script
# VPN: use this connection only for resources on its network if [ "$2" = "vpn-up" ]; then CONN_INTERNAL_ONLY=$(grep 'never-default' $CONNECTION_FILENAME) if [ -n "$CONN_INTERNAL_ONLY" ]; then VPN_IP4_ADDRESS=$(echo $VPN_IP4_ADDRESS_0 | sed -n 's/\([0-9\.]*\).*/\1/p') VPN_IP4_NETWORK=$(ipcalc $VPN_IP4_ADDRESS | grep Network | awk '{print $2}') ip rule add not from all to $VPN_IP4_NETWORK table main priority 219 fi fi if [ "$2" = "vpn-down" ]; then ip rule del pref 219 fi
Step 4-CLI: copy VPN server or CA provided certificate to /etc/ssl/certs
sudo cp /path/to/vpn-server.pem /etc/ssl/certs/ sudo rm -r /etc/ipsec.d/cacerts/ sudo ln -s /etc/ssl/certs /etc/ipsec.d/cacerts
Step 5-CLI: declare your VPN connections on /etc/ipsec.conf
Edit ipsec.confsudo nano /etc/ipsec.conf
conn road-warrior-base keyexchange=ike fragmentation=yes dpdaction=clear dpdtimeout=90s dpddelay=30s conn contoso.localnet #adjust this to better reflect the VPN connection name also=road-warrior-base eap_identity=catalin #adjust this as required leftauth=eap-mschapv2 left=%defaultroute leftsourceip=%config right=vpn.contoso.net #adjust this as required rightsubnet=10.10.1.0/24 #adjust this as required (only trafic to 10.10.1.0/24 network is routed via this tunnel) type=tunnel auto=add conn hide.me #this is a real VPN provider that works on both CLI and NM also=road-warrior-base eap_identity=b247 #adjust this as required leftauth=eap-mschapv2 left=%defaultroute leftsourceip=%config right=free-nl.hide.me #for a free hide.me VPN account rightauth=pubkey rightsubnet=0.0.0.0/0 #all trafic is routed via this tunnel rightid="C=MY, L=Labuan, O=eVenture Limited, CN=*.hide.me" type=tunnel auto=add
Step 6-CLI: declare your EAP passwords on /etc/ipsec.secrets
Edit ipsec.secretssudo nano /etc/ipsec.secrets
contosousername : EAP "the password for contoso.localnet" hidemeusername : EAP "the password for hide.me"
sudo ipsec restart
and try to connect to any of ipsec.conf declared VPNs, using CLI (sudo ipsec up contoso.localnet
, sudo ipsec up hide.me
).The Gnome Extension
First we will need to install the argos gnome extension (https://extensions.gnome.org/extension/1176/argos/), using either Firefox or Chromium/Chrome, then we have to patch it for Gnome 3.36+ compatibility
git clone --single-branch --branch gnome-3.36 https://github.com/rammie/argos.git && cp -r argos/argos@pew.worldwidemann.com /home/$USER/.local/share/gnome-shell/extensions/
Create vpn.5s.sh nano /home/$USER/.config/argos/vpn.5s.sh
#!/usr/bin/env bash STARTER_VPNS=( $(cat /etc/ipsec.conf | grep conn | awk '{print $2}') ) # get a list of starter vpns BLACKLISTED_STARTER_VPNS=( "road-warrior-base" ) # blacklist (remove from the menu) NM_VPNS=( $(nmcli con show | grep vpn | awk '{print $1}') ) # get a list of NM vpns for i in "${BLACKLISTED_STARTER_VPNS[@]}"; do STARTER_VPNS=(${STARTER_VPNS[@]//*$i*}) done VPN_IP=$(ip r show table 220 | grep 'src' | awk '{print $9}') # get VPN IP from routing table NM_VPN_NAME=$(nmcli con show --active | grep -i vpn | awk '{print $1}') # get VPN conn name from nmcli STARTER_VPN_ACTIVE=$(cat /tmp/savpn.tmp) # use a temporary file to store active vpn from starter VPN_ICON="network-vpn" if [[ $NM_VPN_NAME ]]; then VPN_INFO="$NM_VPN_NAME $VPN_IP | iconName=$VPN_ICON" else VPN_INFO="$STARTER_VPN_ACTIVE $VPN_IP | iconName=$VPN_ICON" fi echo ${VPN_INFO} echo "---" for i in "${STARTER_VPNS[@]}" do if [[ $STARTER_VPN_ACTIVE == $i ]]; then action="cat /dev/null > /tmp/savpn.tmp && pkexec ipsec down $i" icon=network-wired else if [[ -z $STARTER_VPN_ACTIVE ]]; then action="echo $i > /tmp/savpn.tmp && pkexec ipsec up $i" else action= fi icon= fi echo "$i | iconName=$icon bash='$action' terminal=false refresh=true" done for i in "${NM_VPNS[@]}" do if [[ $NM_VPN_NAME == $i ]]; then action="nmcli con down $i" icon=network-wired else if [[ $NM_VPN_NAME ]]; then action="nmcli con down $NM_VPN_NAME && nmcli con up $i" else action="nmcli con up $i" fi icon= fi echo "$i | iconName=$icon bash='$action' terminal=false refresh=true" done
The Gnome VPN extension |
|
It wasn't easy to achieve this functionality, but I need it (mainly because of the "work from home" - COVID-19 prevention strategies). It works as expected, I'm using this extension to connect/disconnect/see the connection status for both NM managed VPNs (charon-nm) and the charon managed ones (CLI).
Thank You for reading this article.