OpenConnect Launch Daemon

Eric Bailey

Written on 17 June, 2019
Tags: , , , ,

What follows is a sparsely documented literate program to manage an OpenConnect VPN connection with launchd on macOS. Many thanks to Ashley Gilman for their blog post, Managing an Openconnect VPN Connection with launchd on OSX, upon which this is based.

OpenConnect Wrapper

Define a function handler to send an INT signal to $PID, then trap TERM signals and call handler instead, which will enable ending an openconnect process gracefully with launchd.

handler() {
    kill -INT "$PID" 2>/dev/null
}

trap handler SIGTERM

Pipe STDIN and pass any given arguments to /usr/local/bin/openconnect, and send to the background.

cat | /usr/local/bin/openconnect "$@" &

Keep the wrapper process alive as long as the openconnect process is, by capturing its PID and wait-ing for it.

PID=$!
wait "$PID"

Password File

Store the password (without a trailing newline) in a file, /etc/openconnect/passwd, owned by root.

Remove read/write access from all but root.

sudo chmod og-rw /etc/openconnect/passwd

Launch Daemon

Set up a launch daemon by creating a property list file, /Library/LaunchDaemons/me.ericb.openconnect.plist.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>me.ericb.openconnect-example</string>

Specify that the password, stored in /etc/openconnect/passwd-example, will be supplied via stdin.

    <key>StandardInPath</key>
    <string>/etc/openconnect/passwd-example</string>

Use the wrapper defined above.

    <key>ProgramArguments</key>
    <array>
      <string>/etc/openconnect-wrapper</string>

Tell openconnect we're supplying the password via stdin.

      <string>--passwd-on-stdin</string>

Set the OpenConnect protocol to AnyConnect.

      <string>--protocol=anyconnect</string>

Set the reconnect timeout to 1800 seconds.

      <string>--reconnect-timeout=1800</string>

Set the username.

      <string>--user=alice</string>

Finally, specify the VPN server hostname.

      <string>vpn.example.com</string>
    </array>

Configure log files for debugging.

    <key>StandardOutPath</key>
    <string>/var/log/me.ericb.openconnectconsole.log</string>
    <key>StandardErrorPath</key>
    <string>/var/log/me.ericb.openconnect/error.log</string>

Close the open XML tags.

  </dict>
</plist>