Persist rego-tunnel qcow2 under user-config; remove rego-tunnel-linux
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2025-12-28 06:41:10 +00:00
parent c76afb2380
commit a343aecc0d
37 changed files with 8 additions and 82182 deletions

View File

@@ -1,7 +1,6 @@
# Runtipi Development Guidelines # Runtipi Development Guidelines
## App-Specific Context Files ## App-Specific Context Files
- **rego-tunnel-linux**: Read `apps/rego-tunnel-linux/REGO-VPN-CONTEXT.md` for Cisco VPN container details, fixes, and troubleshooting
## Deployment Workflow ## Deployment Workflow

View File

@@ -1,11 +0,0 @@
# Required
OC_URL=https://vpn.rego.net/Employees
OC_SERVERCERT=pin-sha256:HyHob3LiVmIp8ch9AzHJ9jMYqI43tO5N13oWeBLiZ/0=
# Optional
OC_AUTHGROUP=
OC_SSO_ARGS=--browser-display-mode shown
VNC_PASSWORD=vpnSSO12
NOVNC_PORT=6901
PUBLISH_ADDR=0.0.0.0
SSH_KEY_PATH=/home/alexz/.ssh/id_ed25519-lenovo

View File

@@ -1,42 +0,0 @@
# Rego Tunnel
OpenConnect-SSO VPN client running in a container with noVNC for browser-based access.
## Features
- **OpenConnect-SSO**: Cisco AnyConnect VPN with SSO/SAML authentication
- **TOTP Support**: Automatic 2FA via keyring integration
- **Auto-reconnect**: Automatically reconnects on disconnection
- **noVNC**: Browser-based VNC access on port 8806
- **NAT/Masquerade**: Routes traffic through VPN tunnel
- **Cloudflared**: Optional Cloudflare tunnel support
- **SSH Tunnels**: Optional SSH port forwarding
## Runtipi Installation
1. Install from the app store or custom repo
2. Configure the required environment variables
3. Start the app via Runtipi dashboard
## First-time SSO Login
1. Open noVNC at `http://<host>:8806`
2. Enter VNC password
3. Complete SSO login in the browser window
4. VPN will connect and auto-reconnect on disconnect
## Source Files
- `source/Dockerfile`: Container build file
- `source/entrypoint.sh`: Container entrypoint with auto-reconnect
## Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| OC_URL | Yes | VPN server URL |
| OC_SERVERCERT | Yes | Server certificate pin |
| OC_USER | No | Username (enables hidden browser mode) |
| VNC_PASSWORD | Yes | noVNC access password |
| OC_TOTP_SECRET | No | TOTP secret for auto 2FA |
| NOVNC_PORT | No | noVNC port (default: 6901) |

View File

@@ -1,81 +0,0 @@
# Rego VPN Container - Critical Context
## Deployment Workflow (MUST FOLLOW)
```bash
cd /etc/runtipi/repos/runtipi
git add . && git commit -m "message" && git push
sudo runtipi-cli appstore update
sudo runtipi-cli app stop rego-tunnel-linux:runtipi
sudo runtipi-cli app start rego-tunnel-linux:runtipi
```
**NEVER use docker compose directly for runtipi apps**
## Container Details
- **App name**: `rego-tunnel-linux:runtipi`
- **Image**: `rego-vpn:latest`
- **Source dir**: `/etc/runtipi/repos/runtipi/apps/rego-tunnel-linux/source/`
- **Cisco installer**: `cisco-secure-client-linux64-5.1.14.145-core-vpn-webdeploy-k9.sh`
## Key Fixes Applied (in Dockerfile/entrypoint)
1. **Library path**: Dockerfile adds `/opt/cisco/secureclient/lib` to `/etc/ld.so.conf.d/cisco.conf` + runs `ldconfig`
2. **IPC socket cleanup**: entrypoint.sh runs `rm -f /root/.cisco/hostscan/.libcsd.ipc` before vpnagentd
3. **kmod package**: Installed for `lsmod`/`modprobe` needed by load_tun.sh
4. **`.anyconnect_global`**: Baked into `/opt/cisco/secureclient/vpn/`
## vpn-sso.sh (/root/vpn-sso.sh)
- **Email**: c-azaw@regoproducts.com
- **Password**: `Cj@83278327$$@@`
- **TOTP Secret**: rzqtqskdwkhz6zyr
- **VPN Host**: vpn-ord1.dovercorp.com (162.209.24.100)
### Command line flags
- `-m` or `--menu`: Skip auto-login, go directly to menu
### Menu options
- 1: Start Cisco AnyConnect
- 2: Copy credentials to clipboard
- 3: Show live TOTP
- 4: Setup IP forwarding rules (manual)
- 5: Test connection to target
- 6: Show network status
- 7: Kill all Cisco processes
- 8: Restart vpnagentd + test load_tun.sh
- 9: Edit /etc/hosts
- 0: Reset /etc/hosts to default
## VPN Hosts (/etc/hosts entries)
```
162.209.24.100 vpn-ord1.dovercorp.com
13.67.192.27 vpn.dovercorp.com
```
## Known Issues / Status
- VPN connects and gets interface + IP
- "unable to connect to secure gateway" error occurred
- Auto-routing disabled in vpn-sso.sh for isolated testing
- Use menu option 4 to manually setup forwarding after VPN connects
## Troubleshooting Commands
```bash
# Check libraries
sudo docker exec rego-tunnel-linux_runtipi-rego-tunnel-linux-1 ldd /opt/cisco/secureclient/lib/libaccurl.so.4 | grep "not found"
# Check vpnagentd
sudo docker exec rego-tunnel-linux_runtipi-rego-tunnel-linux-1 pgrep vpnagentd
# Check VPN state
sudo docker exec rego-tunnel-linux_runtipi-rego-tunnel-linux-1 /opt/cisco/secureclient/bin/vpn state
# Check tunnel interface
sudo docker exec rego-tunnel-linux_runtipi-rego-tunnel-linux-1 ip link show | grep cscotun
# Check hostscan logs
sudo docker exec rego-tunnel-linux_runtipi-rego-tunnel-linux-1 tail -50 /root/.cisco/hostscan/log/libcsd.log
# Clean IPC socket manually
sudo docker exec rego-tunnel-linux_runtipi-rego-tunnel-linux-1 rm -f /root/.cisco/hostscan/.libcsd.ipc
# Restart vpnagentd
sudo docker exec rego-tunnel-linux_runtipi-rego-tunnel-linux-1 pkill -9 vpnagentd
sudo docker exec rego-tunnel-linux_runtipi-rego-tunnel-linux-1 /opt/cisco/secureclient/bin/vpnagentd
```

View File

@@ -1,38 +0,0 @@
{
"name": "Rego Tunnel Linux",
"id": "rego-tunnel-linux",
"available": true,
"short_desc": "Cisco Secure Client VPN with noVNC.",
"author": "alexz",
"port": 8806,
"categories": [
"utilities",
"network"
],
"description": "Cisco Secure Client VPN running in a container with noVNC for GUI access.",
"tipi_version": 1,
"version": "latest",
"source": "local",
"exposable": true,
"dynamic_config": true,
"no_gui": false,
"form_fields": [
{
"label": "VNC Password",
"type": "password",
"env_variable": "VNC_PASSWORD",
"required": true,
"default": "Az@83278327$$@@"
},
{
"label": "APP Port",
"type": "number",
"env_variable": "NOVNC_PORT",
"required": true,
"default": 8806
}
],
"supported_architectures": [
"amd64"
]
}

View File

@@ -1,56 +0,0 @@
{
"schemaVersion": 2,
"services": [
{
"name": "rego-tunnel-linux",
"image": "rego-vpn:latest",
"environment": [
{
"key": "VNC_PASSWORD",
"value": "${VNC_PASSWORD}"
},
{
"key": "NOVNC_PORT",
"value": "${NOVNC_PORT}"
}
],
"internalPort": 8806,
"volumes": [
{
"hostPath": "${APP_DATA_DIR}/data",
"containerPath": "/data",
"readOnly": false,
"shared": false,
"private": false
},
{
"hostPath": "/etc/runtipi/repos/runtipi/apps/rego-tunnel-linux/source",
"containerPath": "/config",
"readOnly": true,
"shared": false,
"private": false
},
{
"hostPath": "/sys/fs/cgroup",
"containerPath": "/sys/fs/cgroup",
"readOnly": false,
"shared": false,
"private": false
}
],
"devices": [
"/dev/net/tun:/dev/net/tun"
],
"privileged": true,
"capAdd": [
"NET_ADMIN"
],
"isMain": true,
"extraLabels": {
"generated": true,
"runtipi.managed": true,
"runtipi.appurn": "rego-tunnel-linux:runtipi"
}
}
]
}

View File

@@ -1,50 +0,0 @@
services:
rego-tunnel-linux:
image: rego-vpn:latest
restart: unless-stopped
networks:
rego-tunnel-linux_runtipi_network:
gw_priority: 0
tipi_main_network:
gw_priority: 1
environment:
VNC_PASSWORD: ${VNC_PASSWORD}
NOVNC_PORT: ${NOVNC_PORT}
ports:
- ${NOVNC_PORT}:8806
volumes:
- ${APP_DATA_DIR}/data:/data
- /etc/runtipi/repos/runtipi/apps/rego-tunnel-linux/source:/config:ro
- /sys/fs/cgroup:/sys/fs/cgroup:rw
labels:
generated: true
traefik.enable: true
traefik.docker.network: runtipi_tipi_main_network
traefik.http.middlewares.rego-tunnel-linux-runtipi-web-redirect.redirectscheme.scheme: https
traefik.http.services.rego-tunnel-linux-runtipi.loadbalancer.server.port: "8806"
traefik.http.routers.rego-tunnel-linux-runtipi-insecure.rule: Host(`${APP_DOMAIN}`)
traefik.http.routers.rego-tunnel-linux-runtipi-insecure.entrypoints: web
traefik.http.routers.rego-tunnel-linux-runtipi-insecure.service: rego-tunnel-linux-runtipi
traefik.http.routers.rego-tunnel-linux-runtipi-insecure.middlewares: rego-tunnel-linux-runtipi-web-redirect
traefik.http.routers.rego-tunnel-linux-runtipi.rule: Host(`${APP_DOMAIN}`)
traefik.http.routers.rego-tunnel-linux-runtipi.entrypoints: websecure
traefik.http.routers.rego-tunnel-linux-runtipi.service: rego-tunnel-linux-runtipi
traefik.http.routers.rego-tunnel-linux-runtipi.tls.certresolver: myresolver
runtipi.managed: true
runtipi.appurn: rego-tunnel-linux:runtipi
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
privileged: true
networks:
tipi_main_network:
name: runtipi_tipi_main_network
external: true
rego-tunnel-linux_runtipi_network:
name: rego-tunnel-linux_runtipi_network
external: false
ipam:
config:
- subnet: 10.128.23.0/24

View File

@@ -1,20 +0,0 @@
# Dockerized OpenConnect-SSO with noVNC and Cloudflared
## Setup
1) Copy `.env.example` to `.env` and fill values (URLs, servercert pins, VNC passwords, cloudflared tokens).
2) First-time SSO: leave `OC_SSO_ARGS_*=--browser-display-mode visible`.
3) Build and start:
docker compose build
docker compose up -d vpn_a
# Open http://localhost:6901, complete SSO.
# After success, attach app containers or start cloudflared_a.
4) Optional: switch to headless after first login:
Set `OC_SSO_ARGS_*=--browser-display-mode hidden` (or `headless`) and restart the vpn service.
## Notes
- Each VPN runs in its own net namespace; routes from one cannot affect the other or the host.
- DNS from the VPN applies within its container namespace and attached services only.
- Persisted state lives in the named volumes mounted at `/root` (Playwright cache, configs).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 609 KiB

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<AnyConnectPreferences>
<DefaultUser></DefaultUser>
<DefaultSecondUser></DefaultSecondUser>
<ClientCertificateThumbprint></ClientCertificateThumbprint>
<MultipleClientCertificateThumbprints></MultipleClientCertificateThumbprints>
<ServerCertificateThumbprint></ServerCertificateThumbprint>
<DefaultHostName>vpn-ord1.dovercorp.com</DefaultHostName>
<DefaultHostAddress>162.209.24.100:443</DefaultHostAddress>
<DefaultGroup></DefaultGroup>
<ProxyHost></ProxyHost>
<ProxyPort></ProxyPort>
<SDITokenType>none</SDITokenType>
<ControllablePreferences>
<AutoConnectOnStart>true</AutoConnectOnStart>
<LocalLanAccess>true</LocalLanAccess></ControllablePreferences>
</AnyConnectPreferences>

View File

@@ -1,78 +0,0 @@
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
ENV container=docker
# Install systemd and required packages
RUN apt-get update && apt-get install -y \
systemd systemd-sysv dbus dbus-x11 \
iproute2 iptables ca-certificates kmod \
curl wget openssh-client \
x11vnc xvfb fluxbox novnc websockify xterm nano oathtool \
xauth libnss3 libatk1.0-0 libatk-bridge2.0-0 \
libx11-6 libx11-xcb1 libxcomposite1 libxrandr2 libgbm1 libxdamage1 \
libpango-1.0-0 fonts-liberation \
libegl1 libgl1 libopengl0 libdbus-1-3 libglib2.0-0 \
libxkbcommon0 libxkbcommon-x11-0 \
libxcb1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render0 libxcb-render-util0 libxcb-shm0 libxcb-xfixes0 libxcb-xinerama0 libxcb-randr0 libxcb-glx0 \
xdotool xclip \
libwebkit2gtk-4.1-0 libgtk-3-0 libxml2 libxss1 libcairo2 libgdk-pixbuf2.0-0 \
sudo && rm -rf /var/lib/apt/lists/*
RUN apt-get update && (apt-get install -y libasound2t64 || apt-get install -y libasound2) && rm -rf /var/lib/apt/lists/*
# Configure systemd for container use
RUN cd /lib/systemd/system/sysinit.target.wants/ && \
ls | grep -v systemd-tmpfiles-setup | xargs rm -f && \
rm -f /lib/systemd/system/multi-user.target.wants/* && \
rm -f /etc/systemd/system/*.wants/* && \
rm -f /lib/systemd/system/local-fs.target.wants/* && \
rm -f /lib/systemd/system/sockets.target.wants/*udev* && \
rm -f /lib/systemd/system/sockets.target.wants/*initctl* && \
rm -f /lib/systemd/system/basic.target.wants/* && \
rm -f /lib/systemd/system/anaconda.target.wants/* && \
rm -f /lib/systemd/system/plymouth* && \
rm -f /lib/systemd/system/systemd-update-utmp*
# Pre-create directories needed by Cisco installer
RUN mkdir -p /usr/share/desktop-directories
# Install Cisco Secure Client 5.1.14.145
COPY cisco-secure-client-linux64-5.1.14.145-core-vpn-webdeploy-k9.sh /tmp/cisco-install.sh
RUN chmod +x /tmp/cisco-install.sh && \
/tmp/cisco-install.sh && \
rm /tmp/cisco-install.sh && \
echo "/opt/cisco/secureclient/lib" > /etc/ld.so.conf.d/cisco.conf && \
ldconfig
# Copy user data (hostscan, etc)
COPY cisco-userdata.tar.gz /tmp/
RUN tar -xzf /tmp/cisco-userdata.tar.gz -C /root && \
rm /tmp/cisco-userdata.tar.gz
COPY vpn-sso.sh /root/vpn-sso.sh
RUN chmod +x /root/vpn-sso.sh
# Copy AnyConnect preferences
COPY .anyconnect_global /opt/cisco/secureclient/vpn/.anyconnect_global
# Copy entrypoint script
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Copy systemd services
COPY rego-vpn.service /etc/systemd/system/rego-vpn.service
COPY cisco-vpnagentd.service /etc/systemd/system/cisco-vpnagentd.service
# Enable services
RUN systemctl enable rego-vpn.service && \
systemctl enable cisco-vpnagentd.service
# Create cgroup directory for systemd
RUN mkdir -p /sys/fs/cgroup
VOLUME [ "/sys/fs/cgroup" ]
EXPOSE 8806
# Use systemd as init
STOPSIGNAL SIGRTMIN+3
CMD ["/sbin/init"]

File diff suppressed because one or more lines are too long

View File

@@ -1,17 +0,0 @@
[Unit]
Description=Cisco Secure Client VPN Agent
After=dbus.service
Wants=dbus.service
[Service]
Type=forking
ExecStartPre=/opt/cisco/secureclient/bin/load_tun.sh
ExecStartPre=-/bin/rm -f /root/.cisco/hostscan/.libcsd.ipc
ExecStartPre=-/bin/rm -f /run/vpnagentd.pid
ExecStartPre=-/bin/rm -f /run/scan.pid
ExecStart=/opt/cisco/secureclient/bin/vpnagentd
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target

View File

@@ -1,71 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
NOVNC_PORT="${NOVNC_PORT:-8806}"
VNC_PASSWORD="${VNC_PASSWORD:-vpnpass}"
DISPLAY_ADDR="${DISPLAY:-:1}"
pids=()
setup_hosts() {
# Add VPN hosts entries (Docker manages /etc/hosts, so add at runtime)
grep -q "vpn-ord1.dovercorp.com" /etc/hosts || echo "162.209.24.100 vpn-ord1.dovercorp.com" >> /etc/hosts
grep -q "vpn.dovercorp.com" /etc/hosts || echo "13.67.192.27 vpn.dovercorp.com" >> /etc/hosts
}
start_dbus() {
# Start dbus for Cisco Secure Client
mkdir -p /run/dbus
rm -f /run/dbus/pid
dbus-daemon --system --fork 2>/dev/null || true
}
start_gui() {
mkdir -p /root/.vnc
x11vnc -storepasswd "$VNC_PASSWORD" /root/.vnc/pass >/dev/null 2>&1 || true
rm -f /tmp/.X1-lock /tmp/.X11-unix/X1 2>/dev/null || true
Xvfb "$DISPLAY_ADDR" -screen 0 ${XVFB_WxHxD:-1280x800x24} +extension RANDR &
pids+=($!)
sleep 0.5
export DISPLAY="$DISPLAY_ADDR"
fluxbox >/tmp/fluxbox.log 2>&1 &
pids+=($!)
x11vnc -display "$DISPLAY_ADDR" -rfbauth /root/.vnc/pass -forever -shared -rfbport 5900 -quiet &
pids+=($!)
websockify --web=/usr/share/novnc/ 0.0.0.0:"$NOVNC_PORT" localhost:5900 >/tmp/websockify.log 2>&1 &
pids+=($!)
}
# vpnagentd is now started by systemd (cisco-vpnagentd.service)
setup_tun() {
mkdir -p /dev/net
if [ ! -c /dev/net/tun ]; then
mknod /dev/net/tun c 10 200
chmod 600 /dev/net/tun
fi
}
setup_nat() {
sysctl -w net.ipv4.ip_forward=1 >/dev/null 2>&1 || true
}
start_terminal() {
sleep 1
xterm -fa 'Monospace' -fs 11 -bg black -fg white -geometry 120x35+50+50 \
-T "Rego VPN" -e bash &
pids+=($!)
}
trap 'kill 0' INT TERM
echo "Starting Rego VPN container..."
setup_hosts
setup_tun
setup_nat
start_dbus
start_gui
start_terminal
echo "All services started. noVNC available on port $NOVNC_PORT"
wait

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +0,0 @@
[Unit]
Description=Rego VPN GUI Services
After=network.target dbus.service
Wants=dbus.service
[Service]
Type=simple
ExecStart=/entrypoint.sh
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

View File

@@ -1,614 +0,0 @@
#!/bin/bash
# Dover VPN Connection Script with Semi-Automation
# Keyboard shortcuts (global, work anywhere):
# Ctrl+1 - Type email
# Ctrl+2 - Type password
# Ctrl+3 - Type TOTP code
# Ctrl+4 - Type email + Tab + password (combo)
# Ctrl+5 - Full sequence: email + Tab + password + Tab + TOTP + Enter
EMAIL="c-azaw@regoproducts.com"
PASSWORD='Cj@83278327$$@@'
TOTP_SECRET="rzqtqskdwkhz6zyr"
VPN_HOST="vpn-ord1.dovercorp.com"
TARGET_IP="10.35.33.230"
# Parse command line arguments
SKIP_AUTO_LOGIN=false
while [[ $# -gt 0 ]]; do
case $1 in
-m|--menu)
SKIP_AUTO_LOGIN=true
shift
;;
*)
shift
;;
esac
done
# Default /etc/hosts content
DEFAULT_HOSTS='127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
162.209.24.100 vpn-ord1.dovercorp.com
13.67.192.27 vpn.dovercorp.com'
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
NC='\033[0m'
# Logging function with timestamp
log() {
local level="$1"
local msg="$2"
local timestamp=$(date '+%H:%M:%S')
case $level in
INFO) echo -e "${GRAY}[$timestamp]${NC} ${GREEN}[INFO]${NC} $msg" ;;
WARN) echo -e "${GRAY}[$timestamp]${NC} ${YELLOW}[WARN]${NC} $msg" ;;
ERROR) echo -e "${GRAY}[$timestamp]${NC} ${RED}[ERROR]${NC} $msg" ;;
DEBUG) echo -e "${GRAY}[$timestamp]${NC} ${CYAN}[DEBUG]${NC} $msg" ;;
CMD) echo -e "${GRAY}[$timestamp]${NC} ${GRAY}[CMD]${NC} $msg" ;;
*) echo -e "${GRAY}[$timestamp]${NC} $msg" ;;
esac
}
# Run command with logging
run_cmd() {
local desc="$1"
shift
log CMD "$desc: $*"
output=$("$@" 2>&1)
local rc=$?
if [ -n "$output" ]; then
echo "$output" | while IFS= read -r line; do
echo -e " ${GRAY}${NC} $line"
done
fi
return $rc
}
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN} Dover VPN Connection Script ${NC}"
echo -e "${CYAN}========================================${NC}"
echo ""
# Function to get current TOTP
get_totp() {
oathtool --totp -b "$TOTP_SECRET"
}
# Function to detect VPN tunnel interface dynamically
get_vpn_interface() {
# Look for cscotun* or tun* interfaces that are UP
local iface=$(ip link show | grep -oP '(cscotun\d+|tun\d+)(?=:.*UP)' | head -1)
if [ -z "$iface" ]; then
# Fallback: any cscotun interface
iface=$(ip link show | grep -oP 'cscotun\d+' | head -1)
fi
echo "$iface"
}
# Function to get VM's IP on host-only network (for Windows routing)
get_vm_hostonly_ip() {
# Get IP from ens38 (host-only adapter) - could be any 192.168.x.x
ip addr show ens38 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1
}
# Function to get VPN tunnel IP
get_vpn_ip() {
local iface=$(get_vpn_interface)
if [ -n "$iface" ]; then
ip addr show "$iface" 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1
fi
}
# Start xbindkeys for keyboard macros
start_xbindkeys() {
log INFO "Starting keyboard macro listener (xbindkeys)..."
# Kill any existing xbindkeys
pkill xbindkeys 2>/dev/null
sleep 0.5
# Start xbindkeys
xbindkeys -f ~/.xbindkeysrc 2>/dev/null &
XBINDKEYS_PID=$!
if pgrep xbindkeys >/dev/null; then
log DEBUG "xbindkeys started (PID: $(pgrep xbindkeys))"
log INFO "Keyboard shortcuts active: Ctrl+1=email, Ctrl+2=pass, Ctrl+3=TOTP, Ctrl+4=combo, Ctrl+5=all"
else
log WARN "Failed to start xbindkeys"
fi
}
# Stop xbindkeys
stop_xbindkeys() {
if pgrep xbindkeys >/dev/null; then
log INFO "Stopping keyboard macro listener..."
pkill xbindkeys 2>/dev/null
log DEBUG "xbindkeys stopped"
fi
}
# Kill all Cisco-related processes
kill_cisco_processes() {
log INFO "Killing all Cisco-related processes..."
local killed=0
local my_pid=$$
local my_ppid=$(ps -o ppid= -p $$ | tr -d ' ')
# Kill vpnui specifically (not just any process with "vpn" in name)
for pid in $(pgrep -x "vpnui" 2>/dev/null); do
if [ "$pid" != "$my_pid" ] && [ "$pid" != "$my_ppid" ]; then
log DEBUG "Killing vpnui (PID $pid)"
sudo kill -9 "$pid" 2>/dev/null && ((killed++))
fi
done
# Note: Don't kill vpnagentd - we need it running
# Kill Cisco-specific processes by exact path
for proc in cstub cscan acwebsecagent vpndownloader; do
for pid in $(pgrep -x "$proc" 2>/dev/null); do
log DEBUG "Killing $proc (PID $pid)"
sudo kill -9 "$pid" 2>/dev/null && ((killed++))
done
done
# Kill openconnect (exact match)
for pid in $(pgrep -x "openconnect" 2>/dev/null); do
log DEBUG "Killing openconnect (PID $pid)"
sudo kill -9 "$pid" 2>/dev/null && ((killed++))
done
if [ $killed -eq 0 ]; then
log INFO "No Cisco processes were running"
else
log INFO "Killed $killed process(es)"
sleep 1
fi
}
# Function to setup iptables rules for forwarding
setup_forwarding() {
log INFO "Setting up IP forwarding rules for $TARGET_IP..."
local vpn_iface=$(get_vpn_interface)
if [ -z "$vpn_iface" ]; then
log ERROR "No VPN interface found! Is VPN connected?"
return 1
fi
local vpn_ip=$(get_vpn_ip)
local vm_ip=$(get_vm_hostonly_ip)
log DEBUG "VPN interface: $vpn_iface"
log DEBUG "VPN IP: $vpn_ip"
log DEBUG "VM host-only IP: $vm_ip"
# Enable IP forwarding
run_cmd "Enabling IP forwarding" sudo sysctl -w net.ipv4.ip_forward=1
# NAT masquerade
if ! sudo iptables -t nat -C POSTROUTING -d "$TARGET_IP" -j MASQUERADE 2>/dev/null; then
run_cmd "Adding NAT masquerade rule" sudo iptables -t nat -A POSTROUTING -d "$TARGET_IP" -j MASQUERADE
else
log DEBUG "NAT masquerade rule already exists"
fi
# Forward rules
if ! sudo iptables -C FORWARD -d "$TARGET_IP" -j ACCEPT 2>/dev/null; then
run_cmd "Adding forward rule (to target)" sudo iptables -A FORWARD -d "$TARGET_IP" -j ACCEPT
else
log DEBUG "Forward rule (to target) already exists"
fi
if ! sudo iptables -C FORWARD -s "$TARGET_IP" -j ACCEPT 2>/dev/null; then
run_cmd "Adding forward rule (from target)" sudo iptables -A FORWARD -s "$TARGET_IP" -j ACCEPT
else
log DEBUG "Forward rule (from target) already exists"
fi
# Cisco VPN chain bypass (insert at top if chain exists)
if sudo iptables -L ciscovpn -n &>/dev/null; then
if ! sudo iptables -C ciscovpn -o "$vpn_iface" -d "$TARGET_IP" -j ACCEPT 2>/dev/null; then
run_cmd "Adding ciscovpn bypass (outbound)" sudo iptables -I ciscovpn 1 -o "$vpn_iface" -d "$TARGET_IP" -j ACCEPT
else
log DEBUG "Ciscovpn bypass (outbound) already exists"
fi
if ! sudo iptables -C ciscovpn -i "$vpn_iface" -s "$TARGET_IP" -j ACCEPT 2>/dev/null; then
run_cmd "Adding ciscovpn bypass (inbound)" sudo iptables -I ciscovpn 2 -i "$vpn_iface" -s "$TARGET_IP" -j ACCEPT
else
log DEBUG "Ciscovpn bypass (inbound) already exists"
fi
else
log DEBUG "ciscovpn chain does not exist (yet)"
fi
log INFO "Forwarding rules configured"
echo ""
log INFO "Windows route command (run as Admin):"
echo -e " ${CYAN}route add $TARGET_IP mask 255.255.255.255 $vm_ip${NC}"
echo ""
}
# Copy credentials to clipboard as alternative
copy_to_clipboard() {
log INFO "Starting clipboard credential rotation..."
echo ""
log INFO "Copying EMAIL to clipboard"
echo "$EMAIL" | xclip -selection clipboard
echo -e " ${CYAN}Email ready: $EMAIL${NC}"
echo -e " Paste now (Ctrl+V), then press ${GREEN}Enter${NC} here for password..."
read -r
log INFO "Copying PASSWORD to clipboard"
echo "$PASSWORD" | xclip -selection clipboard
echo -e " ${CYAN}Password ready${NC}"
echo -e " Paste now (Ctrl+V), then press ${GREEN}Enter${NC} here for TOTP..."
read -r
TOTP=$(get_totp)
log INFO "Copying TOTP to clipboard"
echo "$TOTP" | xclip -selection clipboard
echo -e " ${CYAN}TOTP ready: $TOTP${NC}"
echo -e " Paste now (Ctrl+V)"
}
# Print current TOTP with countdown
show_totp() {
log INFO "Starting live TOTP display (Ctrl+C to stop)"
echo ""
while true; do
TOTP=$(get_totp)
SECONDS_LEFT=$((30 - ($(date +%s) % 30)))
echo -ne "\r ${CYAN}Current TOTP:${NC} ${GREEN}$TOTP${NC} (expires in ${YELLOW}${SECONDS_LEFT}s${NC}) "
sleep 1
done
}
# Show network status
show_network_status() {
log INFO "Current network status:"
# VM IPs
echo ""
log DEBUG "VM Network Interfaces:"
ip -4 addr show | grep -E "inet |^[0-9]+:" | while IFS= read -r line; do
echo -e " ${GRAY}${NC} $line"
done
# VPN status
echo ""
local vpn_iface=$(get_vpn_interface)
if [ -n "$vpn_iface" ]; then
local vpn_ip=$(get_vpn_ip)
log INFO "VPN Status: ${GREEN}CONNECTED${NC}"
log DEBUG " Interface: $vpn_iface"
log DEBUG " VPN IP: $vpn_ip"
else
log WARN "VPN Status: ${RED}NOT CONNECTED${NC}"
fi
# Host-only IP for Windows
local vm_ip=$(get_vm_hostonly_ip)
if [ -n "$vm_ip" ]; then
log DEBUG "Host-only IP (for Windows): $vm_ip"
fi
echo ""
}
# Main menu
main_menu() {
echo -e "${GREEN}Options:${NC}"
echo -e " ${CYAN}1${NC} - Start Cisco AnyConnect (kill existing + launch)"
echo -e " ${CYAN}2${NC} - Copy credentials to clipboard (one by one)"
echo -e " ${CYAN}3${NC} - Show live TOTP"
echo -e " ${CYAN}4${NC} - Setup IP forwarding rules only"
echo -e " ${CYAN}5${NC} - Test connection to $TARGET_IP"
echo -e " ${CYAN}6${NC} - Show network status"
echo -e " ${CYAN}7${NC} - Kill all Cisco processes"
echo -e " ${CYAN}8${NC} - Restart vpnagentd + test load_tun.sh"
echo -e " ${CYAN}9${NC} - Edit /etc/hosts"
echo -e " ${CYAN}0${NC} - Reset /etc/hosts to default"
echo -e " ${CYAN}q${NC} - Quit"
echo ""
}
# Restart vpnagentd and test load_tun
restart_vpnagentd() {
log INFO "Testing load_tun.sh..."
/opt/cisco/secureclient/bin/load_tun.sh
if [ $? -eq 0 ]; then
log INFO "load_tun.sh: ${GREEN}OK${NC}"
else
log WARN "load_tun.sh: ${YELLOW}WARNING${NC}"
fi
log INFO "Restarting vpnagentd..."
sudo pkill -9 vpnagentd 2>/dev/null
sleep 1
# Clean up stale IPC socket
rm -f /root/.cisco/hostscan/.libcsd.ipc 2>/dev/null
sudo /opt/cisco/secureclient/bin/vpnagentd &
sleep 2
if pgrep -x vpnagentd >/dev/null; then
log INFO "vpnagentd: ${GREEN}RUNNING${NC}"
else
log ERROR "vpnagentd: ${RED}FAILED TO START${NC}"
fi
}
# Edit /etc/hosts
edit_hosts() {
log INFO "Opening /etc/hosts in nano..."
sudo nano /etc/hosts
}
# Reset /etc/hosts to default
reset_hosts() {
log INFO "Resetting /etc/hosts to default..."
echo "$DEFAULT_HOSTS" | sudo tee /etc/hosts > /dev/null
log INFO "/etc/hosts reset complete"
log DEBUG "Current contents:"
cat /etc/hosts | while IFS= read -r line; do
echo -e " ${GRAY}${NC} $line"
done
}
# Check if VPN is already connected
check_vpn_status() {
local vpn_iface=$(get_vpn_interface)
if [ -n "$vpn_iface" ]; then
local vpn_ip=$(get_vpn_ip)
log INFO "VPN is ${GREEN}CONNECTED${NC}"
log DEBUG " Interface: $vpn_iface"
log DEBUG " VPN IP: $vpn_ip"
return 0
else
log WARN "VPN is ${RED}NOT CONNECTED${NC}"
return 1
fi
}
# Focus on Cisco AnyConnect window
focus_vpn_window() {
local win_id=$(xdotool search --name "Cisco" 2>/dev/null | head -1)
if [ -n "$win_id" ]; then
xdotool windowactivate --sync "$win_id" 2>/dev/null
sleep 0.3
return 0
fi
return 1
}
# Auto-login sequence using xdotool (no auto-focus, types to active window)
auto_login() {
log INFO "Starting automated login sequence..."
# Wait for UI to fully load
log DEBUG "Waiting 5s for UI to load..."
sleep 5
# Press Enter to initiate connection
log DEBUG "Pressing Enter to start connection..."
xdotool key Return
sleep 5
# Press Enter again (Connect button)
log DEBUG "Pressing Enter for Connect..."
xdotool key Return
# Wait for SSO browser to open
log DEBUG "Waiting for SSO browser to open..."
sleep 7
# Type email
log DEBUG "Typing email..."
xdotool type --delay 50 "$EMAIL"
xdotool key Return
sleep 5
# Type password
log DEBUG "Typing password..."
xdotool type --delay 50 "$PASSWORD"
xdotool key Return
sleep 5
# Type TOTP
log DEBUG "Typing TOTP..."
local totp=$(oathtool --totp -b "$TOTP_SECRET")
log DEBUG "TOTP: $totp"
xdotool type --delay 50 "$totp"
xdotool key Return
sleep 5
# Extra enters for any confirmation dialogs
log DEBUG "Sending confirmation enters..."
xdotool key Return
sleep 2
xdotool key Return
sleep 5
xdotool key Return
log INFO "Auto-login sequence completed"
}
# Start Cisco AnyConnect with logging
start_anyconnect() {
log INFO "=== Starting Cisco AnyConnect VPN (FULLY AUTOMATED) ==="
echo ""
# Kill existing processes first
kill_cisco_processes
# Start vpnagentd if not running
if ! pgrep -x vpnagentd >/dev/null; then
log INFO "Starting vpnagentd..."
sudo /opt/cisco/secureclient/bin/vpnagentd &
log DEBUG "Waiting for vpnagentd to initialize..."
sleep 5
fi
# Show credentials
log INFO "Credentials for SSO login:"
echo -e " ${CYAN}Email: $EMAIL${NC}"
echo -e " ${CYAN}Password: $PASSWORD${NC}"
TOTP=$(get_totp)
echo -e " ${CYAN}TOTP: $TOTP${NC}"
echo ""
# Start AnyConnect with GPU/WebKit workarounds
log INFO "Launching Cisco AnyConnect UI..."
export GDK_BACKEND=x11
export WEBKIT_DISABLE_DMABUF_RENDERER=1
/opt/cisco/secureclient/bin/vpnui &
VPNUI_PID=$!
log DEBUG "vpnui started with PID $VPNUI_PID"
# Run auto-login in background
auto_login &
AUTO_LOGIN_PID=$!
log DEBUG "Auto-login started with PID $AUTO_LOGIN_PID"
# Wait for VPN to connect
log INFO "Waiting for VPN connection..."
local wait_count=0
local max_wait=300 # 5 minutes
while [ -z "$(get_vpn_interface)" ]; do
sleep 2
((wait_count+=2))
if [ $((wait_count % 10)) -eq 0 ]; then
log DEBUG "Still waiting for VPN... (${wait_count}s)"
fi
if [ $wait_count -ge $max_wait ]; then
log ERROR "Timeout waiting for VPN connection after ${max_wait}s"
stop_xbindkeys
return 1
fi
done
log INFO "VPN connected!"
local vpn_iface=$(get_vpn_interface)
local vpn_ip=$(get_vpn_ip)
log DEBUG " Interface: $vpn_iface"
log DEBUG " VPN IP: $vpn_ip"
# Skip auto-routing - use menu option 4 to setup forwarding manually
log INFO "VPN ready. Use menu option 4 to setup forwarding if needed."
}
# Main
log INFO "Script started"
echo ""
# Check current status and auto-start unless --menu flag
if [ "$SKIP_AUTO_LOGIN" = true ]; then
log INFO "Menu mode - skipping auto-login"
elif check_vpn_status; then
echo ""
log INFO "VPN already connected. Use menu option 4 to setup forwarding if needed."
else
echo ""
log INFO "Auto-starting VPN connection..."
echo ""
start_anyconnect
fi
echo ""
main_menu
while true; do
echo -ne "${CYAN}Choice: ${NC}"
read -r choice
case $choice in
1)
echo ""
start_anyconnect
echo ""
main_menu
;;
2)
echo ""
copy_to_clipboard
echo ""
main_menu
;;
3)
echo ""
show_totp
echo ""
main_menu
;;
4)
echo ""
setup_forwarding
echo ""
main_menu
;;
5)
echo ""
log INFO "Testing connection to $TARGET_IP..."
if ping -c 3 "$TARGET_IP"; then
log INFO "Connection test: ${GREEN}SUCCESS${NC}"
else
log ERROR "Connection test: ${RED}FAILED${NC}"
fi
echo ""
main_menu
;;
6)
echo ""
show_network_status
main_menu
;;
7)
echo ""
kill_cisco_processes
echo ""
main_menu
;;
8)
echo ""
restart_vpnagentd
echo ""
main_menu
;;
9)
echo ""
edit_hosts
echo ""
main_menu
;;
0)
echo ""
reset_hosts
echo ""
main_menu
;;
q|Q)
log INFO "Goodbye!"
exit 0
;;
*)
log ERROR "Invalid choice"
;;
esac
done

View File

@@ -2,7 +2,7 @@ FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y qemu-system-x86 qemu-utils novnc websockify openssh-server supervisor iproute2 bridge-utils iptables nano net-tools && rm -rf /var/lib/apt/lists/* RUN apt-get update && apt-get install -y qemu-system-x86 qemu-utils novnc websockify openssh-server supervisor iproute2 bridge-utils iptables nano net-tools p7zip-full && rm -rf /var/lib/apt/lists/*
# Setup SSH # Setup SSH
RUN mkdir /var/run/sshd && echo 'root:vmpassword' | chpasswd && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config RUN mkdir /var/run/sshd && echo 'root:vmpassword' | chpasswd && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

View File

@@ -2,9 +2,9 @@
"services": [ "services": [
{ {
"name": "rego-tunnel", "name": "rego-tunnel",
"image": "git.alexzaw.dev/alexz/linux-vm:latest", "image": "linux-vm:latest",
"isMain": true, "isMain": true,
"internalPort": 6080, "internalPort": 8006,
"environment": [ "environment": [
{ {
"key": "VM_RAM", "key": "VM_RAM",
@@ -17,11 +17,11 @@
], ],
"volumes": [ "volumes": [
{ {
"hostPath": "${APP_DATA_DIR}/data/storage/linux-vm.qcow2", "hostPath": "/etc/runtipi/user-config/runtipi/rego-tunnel/storage/linux-vm.qcow2",
"containerPath": "/vm/linux-vm.qcow2" "containerPath": "/vm/linux-vm.qcow2"
}, },
{ {
"hostPath": "${APP_DATA_DIR}/data/shared", "hostPath": "/etc/runtipi/user-config/runtipi/rego-tunnel/shared",
"containerPath": "/shared" "containerPath": "/shared"
} }
], ],

View File

@@ -1,7 +1,7 @@
services: services:
rego-tunnel: rego-tunnel:
container_name: rego-tunnel container_name: rego-tunnel
image: localhost:8108/alexz/linux-vm:latest image: linux-vm:latest
restart: unless-stopped restart: unless-stopped
privileged: true privileged: true
devices: devices:
@@ -16,8 +16,8 @@ services:
- VM_RAM=${WINDOWS_RAM_GB}G - VM_RAM=${WINDOWS_RAM_GB}G
- VM_CPUS=${WINDOWS_CPU_CORES} - VM_CPUS=${WINDOWS_CPU_CORES}
volumes: volumes:
- ${APP_DATA_DIR}/data/storage/linux-vm.qcow2:/vm/linux-vm.qcow2 - /etc/runtipi/user-config/runtipi/rego-tunnel/storage/linux-vm.qcow2:/vm/linux-vm.qcow2
- ${APP_DATA_DIR}/data/shared:/shared - /etc/runtipi/user-config/runtipi/rego-tunnel/shared:/shared
networks: networks:
- tipi_main_network - tipi_main_network
sysctls: sysctls: