initial commit

This commit is contained in:
d-chrka 2026-03-15 21:14:29 +01:00
commit d3bf08c523
3 changed files with 188 additions and 0 deletions

107
README.md Normal file
View File

@ -0,0 +1,107 @@
# fastvpn — Automated Sophos SSL VPN Connect
Fully automated connect to Sophos SSL VPN with TOTP (no dialog, no manual input).
## How it works
Sophos SSL VPN uses OpenVPN with certificate + username/password+OTP authentication.
NetworkManager's normal flow requires an interactive KDE dialog which cannot be automated
reliably on Wayland. Instead, `vpn-connect.sh` starts `openvpn` directly with a Unix
management socket and feeds credentials programmatically via `socat`.
## Prerequisites
### Packages
```bash
sudo pacman -S openvpn oathtool socat libsecret
```
### Sudo rule (no password prompt for openvpn)
```bash
sudo bash -c 'echo "YOUR_USER ALL=(ALL) NOPASSWD: /usr/bin/openvpn" > /etc/sudoers.d/vpn-openvpn && chmod 440 /etc/sudoers.d/vpn-openvpn'
```
### Store credentials in keyring (once)
```bash
# VPN password
secret-tool store --label="Sophos VPN password" service sslvpn user YOUR_USER
# TOTP secret (base32 seed from your authenticator app)
secret-tool store --label="Sophos VPN TOTP" service sslvpn-totp user YOUR_USER
```
### Required files
- OpenVPN config: `~/Downloads/sslvpn-fixed.ovpn` (exported from Sophos user portal)
- Client certificate + key in NetworkManager certificate store:
`/home/chk/.local/share/networkmanagement/certificates/nm-openvpn/`
- `sslvpn-fixed-cert.pem`
- `sslvpn-fixed-key.pem`
> The `.ovpn` file has empty `<cert>` and `<key>` blocks — NM stores them separately.
> The scripts reference the NM certificate path directly.
## Usage
```bash
# Connect
~/bin/vpn-connect.sh
# Disconnect
~/bin/vpn-disconnect.sh
# Check log
sudo cat /tmp/vpn-sophos.log
```
## Configuration
Edit the variables at the top of `vpn-connect.sh`:
| Variable | Description |
|----------|-------------|
| `VPN_USER` | VPN username |
| `OVPN` | Path to .ovpn config file |
| `DNS_SERVER` | VPN DNS server IP |
| `DNS_SEARCH` | Space-separated search domains |
| `CERT_DIR` | Directory containing cert/key PEM files |
## Pitfalls & lessons learned
### `#` in password breaks openvpn management interface
The openvpn management protocol interprets `#` as a comment character.
Passwords containing `#` must be wrapped in double quotes:
```
password "Auth" "mypassword#123456"
```
Without quotes, everything after `#` is silently ignored → `AUTH_FAILED`.
### ydotool / wtype don't work on KDE Wayland
- `ydotool` sends US keycodes — `y`↔`z` swap, `#` becomes `$` on DE layout
- `wtype` requires `zwp_virtual_keyboard` protocol — not supported by KDE Plasma
- `xdotool` works via XWayland but the KDE auth dialog runs natively on Wayland
### NM passwd-file is ignored with challenge-response-flags=2
Sophos VPN profiles exported from the user portal set `challenge-response-flags=2`
in the NetworkManager connection. With this flag, NM ignores `--passwd-file` and
waits for its interactive secret agent (KDE dialog). Removing the flag causes
connection timeouts. The only reliable automation path is bypassing NM entirely.
### OTP timing
The script waits for a fresh 30s TOTP window (>20s remaining) before generating
the OTP to avoid expiry during the TLS handshake.
### DNS requires routing domains (`~` prefix)
`resolvectl domain tun0 krah-gruppe.de` sets a search domain but does NOT route
DNS queries for that domain to tun0. The `~` prefix is required:
```
resolvectl domain tun0 ~krah-gruppe.de ~internal.lan ...
```
### VPN network icon does not show connected state
Since openvpn is started directly (not via NM), the NetworkManager applet in the
system tray does not reflect the VPN state. Functionally everything works.
To check: `ip link show tun0` or `sudo cat /tmp/vpn-sophos.log`.
### Account lockout
Sophos locks the account after several failed AUTH attempts. Wait ~5 minutes
before retrying after multiple failures.

78
vpn-connect.sh Executable file
View File

@ -0,0 +1,78 @@
#!/usr/bin/env bash
# Connect to Sophos SSL VPN via openvpn management interface (same as NM)
set -euo pipefail
VPN_USER="d-chrka"
OVPN="/home/d-chrka@internal.lan/Downloads/sslvpn-fixed.ovpn"
LOGFILE="/tmp/vpn-sophos.log"
MGMT_SOCK="/tmp/vpn-mgmt-$$.sock"
DNS_SERVER="172.21.20.201"
DNS_SEARCH="krah-gruppe.de internal.lan krah.intranet.de hirsau.seuffer resistec.pri krahicenet.local"
CERT_DIR="/home/chk/.local/share/networkmanagement/certificates/nm-openvpn"
PW=$(secret-tool lookup service sslvpn user "$VPN_USER")
OTP_SECRET=$(secret-tool lookup service sslvpn-totp user "$VPN_USER")
# Wait for fresh OTP window (>20s remaining)
while true; do
REMAINING=$(( 30 - ($(date +%s) % 30) ))
[ "$REMAINING" -gt 20 ] && break
echo "Waiting for fresh OTP window (${REMAINING}s remaining)..."
sleep $(( REMAINING + 1 ))
done
OTP=$(oathtool --totp -b "$OTP_SECRET")
echo "OTP generated, $(( 30 - ($(date +%s) % 30) ))s valid"
# Up-script: configure DNS once tun is up
UPSCRIPT=$(mktemp /dev/shm/vpn-up-XXXXXX)
cat > "$UPSCRIPT" << EOF
#!/bin/bash
DEV="\$1"
resolvectl dns "\$DEV" $DNS_SERVER
resolvectl domain "\$DEV" ~krah-gruppe.de ~internal.lan ~krah.intranet.de ~hirsau.seuffer ~resistec.pri ~krahicenet.local
resolvectl default-route "\$DEV" no
echo "DNS configured on \$DEV" >> "$LOGFILE"
EOF
chmod +x "$UPSCRIPT"
echo "Connecting..."
sudo openvpn \
--config "$OVPN" \
--remote rcdro1.krah-gruppe.de 8443 udp \
--cert "$CERT_DIR/sslvpn-fixed-cert.pem" \
--key "$CERT_DIR/sslvpn-fixed-key.pem" \
--auth-nocache \
--management "$MGMT_SOCK" unix \
--management-query-passwords \
--auth-retry interact \
--script-security 2 \
--up "$UPSCRIPT" \
--daemon vpn-sophos \
--log "$LOGFILE"
# Feed credentials via management interface
sleep 1
(
printf 'username "Auth" %s\n' "$VPN_USER"
sleep 0.2
printf 'password "Auth" "%s%s"\n' "$PW" "$OTP"
sleep 2
) | socat - UNIX-CONNECT:"$MGMT_SOCK" 2>/dev/null || true
# Wait for tun interface
echo -n "Waiting for tunnel"
for i in $(seq 1 30); do
if ip link show tun0 &>/dev/null; then
echo " connected."
echo "Disconnect: ~/bin/vpn-disconnect.sh"
rm -f "$UPSCRIPT"
exit 0
fi
echo -n "."
sleep 1
done
rm -f "$UPSCRIPT" "$MGMT_SOCK"
echo " failed. Log: sudo cat $LOGFILE"
exit 1

3
vpn-disconnect.sh Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
# Disconnect Sophos SSL VPN
sudo pkill -f "vpn-sophos" 2>/dev/null && echo "VPN disconnected." || echo "VPN was not running."