Jump to content

# OpenConnect

From ArchWiki

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.

Note NetworkManager-openconnect does not handle every VPN scenario yet, so in some cases you might have to use plain OpenConnect as described above.

#### 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.

#### Issues caused by AnyConnectLocalPolicy.xml

    Automatic profile updates are disabled and the local VPN profile does not match the secure gateway VPN profile.

Is caused by `/opt/cisco/anyconnect/AnyConnectLocalPolicy.xml`. To fix it edit the file and set

    <BypassDownloader>false</BypassDownloader>

#### Issues caused by IPv6

In some cases, Cisco AnyConnect fails to establish a VPN connection due to conflicts with IPv6.

    AnyConnect was not able to establish a connection to the specified secure gateway.

Can be temporary fixed by disabling ipv6:

    # sysctl -w net.ipv6.conf.all.disable_ipv6=1

Category:

- Virtual Private Network

OpenConnect
Add topic