216 lines
7.2 KiB
Markdown
216 lines
7.2 KiB
Markdown
# 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.
|
|
|
|
---
|
|
|
|
## vpn-clip.py — GUI Clipboard Tool
|
|
|
|
PyQt6 tool to manage VPN profiles (password + TOTP) and copy credentials to the
|
|
Wayland clipboard. Useful when `vpn-connect.sh` is not an option (e.g. manual
|
|
OpenVPN clients, other VPN systems).
|
|
|
|
### Prerequisites
|
|
|
|
```bash
|
|
# PyQt6 (usually already present on KDE Plasma)
|
|
sudo pacman -S python-pyqt6
|
|
|
|
# oathtool and wl-clipboard (wl-copy) — already needed by vpn-connect.sh
|
|
sudo pacman -S oath-toolkit wl-clipboard
|
|
|
|
# Required: encrypt/decrypt stored profiles
|
|
sudo pacman -S python-cryptography
|
|
```
|
|
|
|
> **`python-cryptography` is required.** Without it, profiles encrypted on
|
|
> another machine cannot be decrypted. A warning banner is shown in the UI
|
|
> when the package is missing.
|
|
|
|
### Usage
|
|
|
|
```bash
|
|
python3 /path/to/fastvpn/vpn-clip.py
|
|
```
|
|
|
|
- **First run:** no profiles file exists → prompted to set a master password,
|
|
then immediately asked to create the first profile.
|
|
- **Subsequent runs:** enter master password to decrypt and load profiles.
|
|
- Select profile from dropdown.
|
|
- Click **PW+OTP kopieren** to concatenate password + current TOTP and pipe it
|
|
to `wl-copy`. If no OTP secret is set, only the password is copied.
|
|
- The timer label shows seconds remaining in the current 30s TOTP window
|
|
(turns red below 8s — consider waiting for the next window).
|
|
- Click **Profil bearbeiten** to open the profile manager (add / edit / delete).
|
|
|
|
### Profile storage
|
|
|
|
Profiles are stored in `vpn-profiles.enc` next to the script.
|
|
|
|
With `cryptography` installed the file layout is:
|
|
|
|
```
|
|
[2 bytes: salt length] [16 bytes: random salt] [Fernet token]
|
|
```
|
|
|
|
Key derivation: PBKDF2-HMAC-SHA256, 480 000 iterations, 32-byte key.
|
|
|
|
### Installation as desktop app
|
|
|
|
To make `vpn-clip.py` appear in the application launcher and allow pinning to the taskbar:
|
|
|
|
```bash
|
|
# 1. Make executable
|
|
chmod +x /path/to/fastvpn/vpn-clip.py
|
|
|
|
# 2. Create .desktop entry (adjust Exec= path)
|
|
cat > ~/.local/share/applications/vpn-clip.desktop << 'EOF'
|
|
[Desktop Entry]
|
|
Version=1.0
|
|
Type=Application
|
|
Name=VPN Clip
|
|
Comment=VPN password+OTP clipboard tool
|
|
Exec=/path/to/fastvpn/vpn-clip.py
|
|
Icon=network-vpn
|
|
Terminal=false
|
|
Categories=Network;Security;Utility;
|
|
Keywords=vpn;otp;password;clipboard;
|
|
StartupNotify=true
|
|
EOF
|
|
|
|
# 3. Refresh launcher database
|
|
update-desktop-database ~/.local/share/applications/
|
|
```
|
|
|
|
After step 3 the app appears under **Network** / **Utilities** in the start menu.
|
|
Right-click the icon → **Pin to taskbar** (KDE: "Add to panel").
|
|
|
|
To use a custom icon instead of the system `network-vpn` icon, place a PNG at
|
|
`~/.local/share/icons/vpn-clip.png` and set `Icon=vpn-clip` in the `.desktop` file.
|
|
|
|
### Pitfalls (vpn-clip)
|
|
|
|
**`cryptography` not on PATH / wrong Python**
|
|
`pacman -S python-cryptography` installs for the system Python. If you run the
|
|
script with a venv or a different Python binary the package may not be found and
|
|
the fallback kicks in silently — check the warning banner in the UI.
|
|
|
|
**wl-copy requires a running Wayland session**
|
|
Running the script over SSH without a forwarded Wayland socket will make
|
|
`wl-copy` fail. The error is shown in a dialog box.
|
|
|
|
**OTP secret format**
|
|
`oathtool --totp -b` expects a base32-encoded secret (the "seed" shown by most
|
|
authenticator apps as a QR code alternative). Spaces in the secret are fine;
|
|
`oathtool` ignores them.
|
|
|
|
**Password + OTP concatenation**
|
|
The tool concatenates password and OTP with no separator (e.g. `hunter2123456`).
|
|
Sophos and most other SSL VPN gateways expect exactly this format in the
|
|
password field. If your gateway uses a different format, edit `_copy()` in the
|
|
script.
|