OpenConnect
OpenConnect is free open-source software for client-to-site VPNs. It allows you to connect to various commercial so-called SSL VPN servers/gateways/concentrators, namely:
- Cisco AnyConnect anyconnect
- Palo Alto Networks (PAN) GlobalProtect gp
- Junos/Ivanti Pulse Secure pulse, see also Pulse Connect Secure
- Juniper Network Connect nc
- Fortinet fortinet
- F5 f5
- Array Networks array
Installation
For integration with NetworkManager which you probably use if you have a desktop environment like GNOME or KDE, install the networkmanager-openconnect package. It will pull in the openconnect package as a dependency. If you do not need the integration, install only the openconnect package.
Some VPNs are set up for split routing and therefore split DNS. To cater for that and in general, it's recommended to use systemd-resolved and the resolv.conf stub mode. To verify that this is the case, run resolvectl
and look for the line "resolv.conf mode: stub" in the Global section. Understanding the full output can be very useful so it's probably a good idea to study it. When connected to a VPN, the output will look roughly like this:
$ resolvectl
Global Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported resolv.conf mode: stub Link 2 (enp1s0) Current Scopes: DNS Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported Current DNS Server: 192.168.0.1 DNS Servers: 192.168.0.1 DNS Domain: ~home.box Link 3 (tun0) Current Scopes: DNS Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported Current DNS Server: 10.10.10.10 DNS Servers: 10.10.10.10 DNS Domain: ~example.org ~int.example.net
Usage
Plain OpenConnect
OpenConnect has many options, see openconnect(8). In the simplest case, you are using a Cisco AnyConnect VPN, thus you only have to provide the address, then enter your username and password when prompted:
$ sudo openconnect vpnserviceaddr
If you use a VPN type other than Cisco AnyConnect, add the "--protocol" option specifying either nc, gp, pulse, f5, fortinet, or array:
$ sudo openconnect --protocol=vpntype vpnserviceaddr
The username can be provided too:
$ sudo openconnect --protocol=vpntype -u user vpnserviceaddr
Some VPNs offer different authentication groups for different access configurations like for example for a full tunnel or split tunnel connection. To show the different offered auth-groups and to get more information about the service in general, use:
$ sudo openconnect --protocol=vpntype --authenticate vpnserviceaddr
Some VPNs require gathering information about your computer when connecting. In that case the "--csd-wrapper" option can help. Scripts to use and adapt can be found under "/usr/lib/openconnect/".
$ sudo openconnect --protocol=vpntype --csd-wrapper=script vpnserviceaddr
Some VPNs delegate authentication to an identity provider (IdP) like Google, Microsoft AzureActiveDirectory, or Okta. This scenario is often called single sign-on (SSO) and usually employs the SAML 2.0 standard or the OIDC standard. It goes like this: In a browser or webview, you open the VPN's SSO address which redirects to the IdP which sends you back to the VPN page where you end up with a cookie. The cookie must be passed to openconnect using the option "-C,--cookie" or "--cookie-on-stdin". To copy the cookie from your browser, use its developer tools.
$ sudo openconnect --protocol=vpntype --cookie-on-stdin vpnserviceaddr
For Fortinet SSO VPNs, you can use openfortivpn-webview-qtAUR to fetch the cookie instead of fiddling with your browser's developer tools:
$ sudo openconnect --protocol=fortinet -C "$(openfortivpn-webview vpnserviceaddr)" vpnserviceaddr
OpenConnect passes a couple of environment variables to a script in order to configure IP routing and DNS routing. By default that's "/etc/vpnc/vpnc-script". It supports a few environment variables that you can set if needed, e.g. "CISCO_SPLIT_DNS" to add additional DNS domains to the network interface besides the ones pushed by the VPN:
$ sudo CISCO_SPLIT_DNS=~internal.example.com,~10.in-addr.arpa openconnect --protocol=vpntype vpnserviceaddr
You can use your own script instead of the default one using the option "-s,--script":
$ sudo openconnect --protocol=vpntype -s script vpnserviceaddr
You can also team up OpenConnect with a proxy like ocproxy-gitAUR in order to do SSH-style port-forwarding. E.g. a connection to localhost:13389 using rdesktop gets forwarded through the VPN to the RDS service rds.int.example.net:3389 if you run:
$ openconnect --protocol=vpntype --script-tun -s "ocproxy -L 13389:rds.int.example.net:3389" vpnserviceaddr $ rdesktop localhost:13389
With NetworkManager
NetworkManager can be controlled via command line interface nmcli
, via terminal user interface nmtui
, and via many desktop environments, thanks to its D-Bus API. For NetworkManager a VPN is just another connection of type "vpn". To create one based on OpenConnect named "MyOrgVPN" with the CLI, run:
$ nmcli connection add \ connection.id MyOrgVPN \ connection.type vpn \ vpn.service-type openconnect \ vpn.data cookie-flags=2,gateway=vpnserviceaddr,protocol=vpntype vpn.secrets gateway=vpnserviceaddr,gwcert=
Activating the connection using nmcli connection up MyOrgVPN
(i.e. without --ask
) or GNOME's menu in the top right corner or GNOME settings a.k.a control center works in most cases as one would expect: a window opens and asks for a username, password, and possibly 2FA/MFA; even SSO scenarios often work if the VPN type is anyconnect or gp. For other desktop environments you might have to install network-manager-applet, nm-connection-editor, or some other package in order to control NetworkManager connections.
Activating the connection using nmcli --ask connection up MyOrgVPN
or nmtui
or nmtui connect MyOrgVPN
does not work the way one would expect though: instead of getting asked for a username, etc., one gets asked for "Cookie (vpn.secrets.cookie)". To provide it, you can use a Bash script like this one:
~/vpn-up.bash
#!/usr/bin/bash connection_name=$(nmcli -t -g type,name connection \ | grep -Po '^vpn:\K.*' \ | sed 's/\\:/:/g' | fzf ) eval "$(nmcli -t -g vpn.data connection show "$connection_name" \ | grep -Po '(^|[ ,])(protocol|gateway)\ =\ [^,]*' \ | sed 's/ //g')" eval "$(openconnect --authenticate --protocol="$protocol" "$gateway")" nmcli connection up "$connection_name" \ passwd-file <(echo "vpn.secrets.cookie:$COOKIE")
To deactivate the connection, use nmcli connection down MyOrgVPN
or nmtui
or GNOME's menu in the top right corner or GNOME settings a.k.a control center.
Single Sign-On (SSO) with WebAuth and Anyconnect
networkmanager-openconnect supports Single Sign-On (SSO) with WebAuth for Cisco Anyconnect. To use WebAuth:
- Do not forget to install optional dependencies for networkmanager-openconnect like webkit2gtk-*
- Add something like "AnyConnect Linux_64 4.10.07061" to "User Agent" field on the VPN tab for this connection
Activate the connection. It should bring you a window with a browser for WebAuth to complete. If it succeeded the networkmanager-openconnect will launch openconnect and pass the "webvpn" cookie for it to connect.
With netctl
A simple tuntap
netctl.profile(5) can be used to integrate OpenConnect in the normal netctl workflow. For example:
/etc/netctl/vpn
Description='VPN' Interface=vpn Connection=tuntap Mode=tun #User=root #Group=root BindsToInterfaces=(enp0s25 wlp2s0) IP=no PIDFILE=/run/openconnect_${Interface}.pid SERVER=vpn.example.net AUTHGROUP='<AUTHGROUP>' LOCAL_USERNAME=<USERNAME> REMOTE_USERNAME=<VPN_USERNAME> # Assuming the use of pass(1): PASSWORD_CMD="su ${LOCAL_USERNAME} -c \"pass ${REMOTE_USERNAME} | head -n 1\"" ExecUpPost="${PASSWORD_CMD} | /usr/bin/openconnect --background --pid-file=${PIDFILE} --interface='${Interface}' --authgroup='${AUTHGROUP}' --user='${REMOTE_USERNAME}' --passwd-on-stdin ${SERVER}" ExecDownPre="kill -INT $(cat ${PIDFILE}) ; resolvconf -d ${Interface} ; ip link delete ${Interface}"
This allows execution like:
$ netctl start vpn $ netctl restart vpn $ netctl stop vpn
Note that this relies on LOCAL_USERNAME
having a gpg-agent running, with the passphrase for the PGP key already cached.
If pass's interactive query is wanted, use the following line for PASSWORD_CMD
:
DISPLAY=":0" PASSWORD_CMD="su ${LOCAL_USERNAME} -c \"DISPLAY=${DISPLAY} pass ${REMOTE_USERNAME} | head -n 1\""
Adjust the DISPLAY
variable as necessary.
Troubleshooting
Cisco AnyConnect
For Cisco AnyConnect VPNs, if you try to use 2FA/MFA but it is not prompting you for the passcode, you need to set the useragent to AnyConnect ...
. This is an issue with Cisco, here is the relevant issue in the OpenConnect project.