.
Some checks failed
Test / test (push) Has been cancelled

This commit is contained in:
2026-01-17 10:53:29 +00:00
parent 48d0407c79
commit e462edd99b
11 changed files with 268 additions and 599 deletions

2
apps/cistech-tunnel/build/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
# Large binary files - track tar.gz but not 7z
*.7z

View File

@@ -16,22 +16,23 @@ ENV NOVNC_PORT=6080
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
ENV VIRTUAL_ENV=/opt/venv ENV VIRTUAL_ENV=/opt/venv
ENV PATH=/opt/venv/bin:$PATH ENV PATH=/opt/venv/bin:$PATH
ENV QTWEBENGINE_DISABLE_SANDBOX=1
ENV QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox --disable-gpu"
# Install system dependencies # Install systemd and dependencies
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
openconnect \ systemd \
iproute2 \ systemd-sysv \
dbus \
dbus-x11 \
libgtk-3-0 \
libglib2.0-0 \
libstdc++6 \
iptables \ iptables \
ca-certificates \ libxml2 \
python3 \ network-manager \
python3-pip \ zlib1g \
python3-venv \ policykit-1 \
vpnc-scripts \ xdg-utils \
curl \ libwebkit2gtk-4.0-37 \
wget \
openssh-client \
tigervnc-standalone-server \ tigervnc-standalone-server \
tigervnc-common \ tigervnc-common \
novnc \ novnc \
@@ -40,66 +41,65 @@ RUN apt-get update && apt-get install -y \
xterm \ xterm \
procps \ procps \
net-tools \ net-tools \
curl \
iproute2 \
iputils-ping \
nano \ nano \
x11vnc \ x11vnc \
xvfb \ xvfb \
fluxbox \ fluxbox \
xdotool \
oathtool \ oathtool \
xauth \ openconnect \
python3 \
python3-pip \
python3-venv \
vpnc-scripts \
libasound2 \
libnss3 \ libnss3 \
libatk1.0-0 \ libatk1.0-0 \
libatk-bridge2.0-0 \ libatk-bridge2.0-0 \
libx11-6 \
libx11-xcb1 \
libxcomposite1 \ libxcomposite1 \
libxrandr2 \ libxrandr2 \
libgbm1 \ libgbm1 \
libxdamage1 \ libxdamage1 \
libpango-1.0-0 \ libpango-1.0-0 \
fonts-liberation \ 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 \
sudo \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Install libasound (different package name on different Ubuntu versions) # Remove unnecessary systemd services that cause issues in containers
RUN apt-get update && (apt-get install -y libasound2t64 || apt-get install -y libasound2) && rm -rf /var/lib/apt/lists/* RUN rm -f /lib/systemd/system/multi-user.target.wants/* \
/etc/systemd/system/*.wants/* \
/lib/systemd/system/local-fs.target.wants/* \
/lib/systemd/system/sockets.target.wants/*udev* \
/lib/systemd/system/sockets.target.wants/*initctl* \
/lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* \
/lib/systemd/system/systemd-update-utmp*
# Python venv + openconnect-sso + playwright # Install openconnect-sso with playwright
RUN python3 -m venv "$VIRTUAL_ENV" RUN python3 -m venv "$VIRTUAL_ENV" && \
RUN pip install --no-cache-dir openconnect-sso[full] playwright keyring keyrings.alt && \ pip install --no-cache-dir openconnect-sso[full] playwright keyring keyrings.alt && \
python -m playwright install --with-deps chromium python -m playwright install --with-deps chromium
# Create directories RUN mkdir -p /opt/scripts /shared
RUN mkdir -p /opt/scripts /shared /root/.vnc RUN echo 'IyEvYmluL2Jhc2gKc2V0IC1lCmV4cG9ydCBIT01FPScvcm9vdCcKZXhwb3J0IFVTRVI9J3Jvb3QnCnJtIC1mIC90bXAvLlAxLWxvY2sgL3RtcC8uWDExLXVuaXgvWDEgMj4vZGV2L251bGwgfHwgdHJ1ZQpybSAtcmYgL3RtcC8uWCotbG9jayAvdG1wLy5YMTQtdW5peC8qIDI+L2Rldi9udWxsIHx8IHRydWUKZWNobyAiU3RhcnRpbmcgVGlnZXJWTkMgc2VydmVyIG9uIGRpc3BsYXkgOjEuLi4iCnZuY3NlcnZlciA6MSAtZ2VvbWV0cnkgMTI4MHg4MDAgLWRlcHRoIDI0IC1TZWN1cml0eVR5cGVzIFZuY0F1dGggLWxvY2FsaG9zdCBubwpzbGVlcCAyCmVjaG8gIlN0YXJ0aW5nIG5vVk5DIG9uIHBvcnQgJHtOT1ZOQ19QT1JUOi02MDgwfS4uLiIKd2Vic29ja2lmeSAtLXdlYj0vdXNyL3NoYXJlL25vdm5jLyAke05PVk5DX1BPUlQ6LTYwODB9IGxvY2FsaG9zdDo1OTAxICYKdGFpbCAtZiAvcm9vdC8udm5jLyoubG9nCg==' \
| base64 -d > /opt/scripts/startup-vnc.sh && \
chmod +x /opt/scripts/startup-vnc.sh
# Create VNC startup script (embedded) RUN echo 'W1VuaXRdCkRlc2NyaXB0aW9uPVZOQyBhbmQgbm9WTkMgU2VydmVyCkFmdGVyPW5ldHdvcmsudGFyZ2V0CgpbU2VydmljZV0KVHlwZT1zaW1wbGUKRXhlY1N0YXJ0PS9vcHQvc2NyaXB0cy9zdGFydHVwLXZuYy5zaApSZXN0YXJ0PWFsd2F5cwpSZXN0YXJ0U2VjPTUKRW52aXJvbm1lbnQ9SE9NRT0vcm9vdApFbnZpcm9ubWVudD1VU0VSPXJvb3QKCltJbnN0YWxsXQpXYW50ZWRCeT1tdWx0aS11c2VyLnRhcmdldAo=' \
RUN echo 'IyEvYmluL2Jhc2gKc2V0IC1lCmV4cG9ydCBIT01FPScvcm9vdCcKZXhwb3J0IFVTRVI9J3Jvb3QnCnJtIC1mIC90bXAvLlgxLWxvY2sgL3RtcC8uWDExLXVuaXgvWDEgMj4vZGV2L251bGwgfHwgdHJ1ZQpybSAtcmYgL3RtcC8uWCotbG9jayAvdG1wLy5YMTEtdW5peC8qIDI+L2Rldi9udWxsIHx8IHRydWUKZWNobyAiU3RhcnRpbmcgVGlnZXJWTkMgc2VydmVyIG9uIGRpc3BsYXkgOjEuLi4iCnZuY3NlcnZlciA6MSAtZ2VvbWV0cnkgMTI4MHg4MDAgLWRlcHRoIDI0IC1TZWN1cml0eVR5cGVzIFZuY0F1dGggLWxvY2FsaG9zdCBubwpzbGVlcCAyCmVjaG8gIlN0YXJ0aW5nIG5vVk5DIG9uIHBvcnQgJHtOT1ZOQ19QT1JUOi02MDgwfS4uLiIKd2Vic29ja2lmeSAtLXdlYj0vdXNyL3NoYXJlL25vdm5jLyAke05PVk5DX1BPUlQ6LTYwODB9IGxvY2FsaG9zdDo1OTAxICYKdGFpbCAtZiAvcm9vdC8udm5jLyoubG9nCg==' \ | base64 -d > /lib/systemd/system/vnc.service
| base64 -d > /opt/scripts/startup-vnc.sh && \ RUN chmod 644 /lib/systemd/system/vnc.service && \
chmod +x /opt/scripts/startup-vnc.sh systemctl enable vnc.service
# Copy entrypoint script # Copy entrypoint script
COPY scripts/entrypoint.sh /opt/scripts/ COPY scripts/entrypoint.sh /opt/scripts/
RUN chmod +x /opt/scripts/entrypoint.sh RUN chmod +x /opt/scripts/entrypoint.sh
VOLUME ["/sys/fs/cgroup"]
EXPOSE 5901 6080 EXPOSE 5901 6080
STOPSIGNAL SIGRTMIN+3
CMD ["/opt/scripts/entrypoint.sh"] CMD ["/opt/scripts/entrypoint.sh"]

View File

@@ -0,0 +1,51 @@
# Rego Tunnel - Build Files
This directory contains the Dockerfile and scripts to build the Cisco VPN Docker image.
## Files
- `Dockerfile` - Docker image definition (Ubuntu 22.04 + Cisco Secure Client + noVNC)
- `cisco-secure-client-full.tar.gz` - Pre-extracted Cisco Secure Client 5.1.14.145
- `build.sh` - Build and push script
- `scripts/entrypoint.sh` - Container entrypoint (starts systemd)
## Building
```bash
cd /etc/runtipi/repos/runtipi/apps/rego-tunnel/build
./build.sh
```
This builds and pushes to `git.alexzaw.dev/alexz/cisco-vpn:latest`
To build without pushing:
```bash
docker build -t git.alexzaw.dev/alexz/cisco-vpn:latest .
```
## What's in the image
The Dockerfile creates an image with:
- Ubuntu 22.04 with systemd
- Cisco Secure Client 5.1.14.145 (VPN, DART, Posture modules)
- TigerVNC server + noVNC (web-based VNC)
- Tools: xdotool, oathtool (for TOTP), xclip, openbox
### Systemd services (baked in)
- `vpnagentd.service` - Cisco VPN agent
- `vnc.service` - VNC server + noVNC websockify
### Scripts (baked in via base64 in Dockerfile)
- `/opt/scripts/startup-vnc.sh` - Starts VNC server and noVNC
- `/opt/scripts/entrypoint.sh` - Container entrypoint
## Runtime mounts (from shared/)
When running as rego-tunnel app, these are mounted from `shared/`:
- `/shared/cisco-vpn` - Main VPN automation script
- `/shared/xstartup``/root/.vnc/xstartup` - VNC session startup
## Ports
- `5901` - VNC server
- `6080` - noVNC web interface

View File

@@ -16,7 +16,7 @@ echo ""
echo "Build complete!" echo "Build complete!"
echo "" echo ""
echo "To test locally:" echo "To test locally:"
echo " docker run -d --privileged --cap-add=NET_ADMIN --device=/dev/net/tun -p 5901:5901 -p 6080:6080 -e VNC_PASSWORD=test ${IMAGE_NAME}:${IMAGE_TAG}" echo " docker run -d --privileged --cgroupns=host -v /sys/fs/cgroup:/sys/fs/cgroup:rw --cap-add=NET_ADMIN --device=/dev/net/tun -p 5901:5901 -p 6080:6080 ${IMAGE_NAME}:${IMAGE_TAG}"
echo "" echo ""
echo "Then connect via VNC to localhost:5901 or open noVNC at http://localhost:6080/vnc.html" echo "Then connect via VNC to localhost:5901 or open noVNC at http://localhost:6080/vnc.html"
echo "" echo ""

View File

@@ -1,16 +1,16 @@
#!/bin/bash #!/bin/bash
# Entrypoint: VNC password setup + DNS fix + start VNC # Entrypoint: VNC password setup + DNS fix + systemd
set -euo pipefail set -euo pipefail
# Setup TigerVNC password file from env var # Setup TigerVNC password file from env var (passed by runtipi)
# TigerVNC expects /root/.vnc/passwd when using SecurityTypes=VncAuth.
if [ -n "${VNC_PASSWORD:-}" ]; then if [ -n "${VNC_PASSWORD:-}" ]; then
mkdir -p /root/.vnc mkdir -p /root/.vnc
printf '%s\n%s\n' "$VNC_PASSWORD" "$VNC_PASSWORD" | vncpasswd -f > /root/.vnc/passwd printf '%s\n%s\n' "$VNC_PASSWORD" "$VNC_PASSWORD" | vncpasswd -f > /root/.vnc/passwd
chmod 600 /root/.vnc/passwd chmod 600 /root/.vnc/passwd
fi fi
# DNS fix for containers
cp /etc/resolv.conf /tmp/resolv.conf.bak 2>/dev/null || true cp /etc/resolv.conf /tmp/resolv.conf.bak 2>/dev/null || true
cp /etc/hosts /tmp/hosts.bak 2>/dev/null || true cp /etc/hosts /tmp/hosts.bak 2>/dev/null || true
umount /etc/resolv.conf 2>/dev/null || true umount /etc/resolv.conf 2>/dev/null || true
@@ -18,25 +18,7 @@ umount /etc/hosts 2>/dev/null || true
cat /tmp/resolv.conf.bak > /etc/resolv.conf 2>/dev/null || echo "nameserver 8.8.8.8" > /etc/resolv.conf cat /tmp/resolv.conf.bak > /etc/resolv.conf 2>/dev/null || echo "nameserver 8.8.8.8" > /etc/resolv.conf
cat /tmp/hosts.bak > /etc/hosts 2>/dev/null || echo "127.0.0.1 localhost" > /etc/hosts cat /tmp/hosts.bak > /etc/hosts 2>/dev/null || echo "127.0.0.1 localhost" > /etc/hosts
# Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward echo 1 > /proc/sys/net/ipv4/ip_forward
echo "[entrypoint] IP forwarding enabled" echo "[entrypoint] IP forwarding enabled"
# Clean up stale X locks exec /sbin/init
rm -f /tmp/.X1-lock /tmp/.X11-unix/X1 2>/dev/null || true
# Start VNC server
echo "[entrypoint] Starting TigerVNC server..."
mkdir -p /root/.vnc
vncserver :1 -geometry 1280x800 -depth 24 -SecurityTypes VncAuth -localhost no
# Wait for VNC to start
sleep 2
# Start noVNC websockify
echo "[entrypoint] Starting noVNC on port ${NOVNC_PORT:-6080}..."
websockify --web=/usr/share/novnc/ ${NOVNC_PORT:-6080} localhost:5901 &
# Keep container running
echo "[entrypoint] VNC ready. Tailing logs..."
tail -f /root/.vnc/*.log

View File

@@ -18,6 +18,7 @@
{ "hostPath": "${APP_DATA_DIR}/config", "containerPath": "/config", "readOnly": false }, { "hostPath": "${APP_DATA_DIR}/config", "containerPath": "/config", "readOnly": false },
{ "hostPath": "${APP_DATA_DIR}", "containerPath": "/runtime", "readOnly": false }, { "hostPath": "${APP_DATA_DIR}", "containerPath": "/runtime", "readOnly": false },
{ "hostPath": "/etc/runtipi/repos/runtipi/apps/cistech-tunnel/shared", "containerPath": "/shared", "readOnly": false }, { "hostPath": "/etc/runtipi/repos/runtipi/apps/cistech-tunnel/shared", "containerPath": "/shared", "readOnly": false },
{ "hostPath": "/sys/fs/cgroup", "containerPath": "/sys/fs/cgroup", "readOnly": false },
{ "hostPath": "/etc/runtipi/repos/runtipi/apps/cistech-tunnel/shared/xstartup", "containerPath": "/root/.vnc/xstartup", "readOnly": true } { "hostPath": "/etc/runtipi/repos/runtipi/apps/cistech-tunnel/shared/xstartup", "containerPath": "/root/.vnc/xstartup", "readOnly": true }
], ],
"stopGracePeriod": "30s", "stopGracePeriod": "30s",

View File

@@ -1,22 +1,22 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Host routing script for cistech-tunnel # Host routing script for rego-tunnel
# Routes target subnets through the VPN container # Routes TARGET_IP through the VPN container
# #
set -euo pipefail set -euo pipefail
ACTION="${1:-start}" ACTION="${1:-start}"
# Fixed configuration # Fixed configuration (we assigned these)
CONTAINER_IP="172.30.0.10" CONTAINER_IP="172.31.0.10"
BRIDGE_NAME="br-vpn-static" BRIDGE_NAME="br-rego-vpn"
TARGET_SUBNETS="10.3.1.0/24 10.255.255.0/24" TARGET_IP="${TARGET_IP:-10.35.33.230}"
LAN_SUBNET="192.168.0.0/23" LAN_SUBNET="192.168.0.0/23"
LAN_INTERFACES="eth0 eth1 wlan0" LAN_INTERFACES="eth0 eth1 wlan0"
LOG_FILE="/var/log/cistech-routing.log" LOG_FILE="/var/log/rego-routing.log"
log() { log() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [cistech-routing] $*" local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [rego-routing] $*"
echo "$msg" | tee -a "$LOG_FILE" >&2 echo "$msg" | tee -a "$LOG_FILE" >&2
} }
@@ -25,10 +25,12 @@ get_lan_interface() {
} }
remove_routes() { remove_routes() {
log "Removing stale routes..." log "Removing stale routes for $TARGET_IP..."
for subnet in $TARGET_SUBNETS; do
ip route del "$subnet" 2>/dev/null || true # Remove any existing route to TARGET_IP
done ip route del "$TARGET_IP" 2>/dev/null || true
ip route del "$TARGET_IP/32" 2>/dev/null || true
log "Stale routes removed" log "Stale routes removed"
} }
@@ -39,35 +41,35 @@ apply_routes() {
log "Applying host routing rules..." log "Applying host routing rules..."
log " Container IP: $CONTAINER_IP" log " Container IP: $CONTAINER_IP"
log " Bridge: $BRIDGE_NAME" log " Bridge: $BRIDGE_NAME"
log " Target subnets: $TARGET_SUBNETS" log " Target IP: $TARGET_IP"
log " LAN interface: ${lan_if:-unknown}" log " LAN interface: ${lan_if:-unknown}"
# Enable IP forwarding # Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward echo 1 > /proc/sys/net/ipv4/ip_forward
log "IP forwarding enabled" log "IP forwarding enabled"
# Add routes to target subnets via container # Add route to TARGET_IP via container
for subnet in $TARGET_SUBNETS; do ip route replace "$TARGET_IP/32" via "$CONTAINER_IP" dev "$BRIDGE_NAME"
ip route replace "$subnet" via "$CONTAINER_IP" dev "$BRIDGE_NAME" log "Route added: $TARGET_IP via $CONTAINER_IP dev $BRIDGE_NAME"
log "Route added: $subnet via $CONTAINER_IP dev $BRIDGE_NAME"
done
# Allow forwarding in DOCKER-USER chain for all LAN interfaces # Allow forwarding in DOCKER-USER chain for all LAN interfaces
for lan_if in $LAN_INTERFACES; do for lan_if in $LAN_INTERFACES; do
# Check if interface exists
if ip link show "$lan_if" &>/dev/null; then if ip link show "$lan_if" &>/dev/null; then
# Allow traffic from LAN to container bridge # Allow traffic from LAN to container for TARGET_IP
iptables -C DOCKER-USER -i "$lan_if" -o "$BRIDGE_NAME" -j ACCEPT 2>/dev/null || \ iptables -C DOCKER-USER -i "$lan_if" -o "$BRIDGE_NAME" -d "$TARGET_IP" -j ACCEPT 2>/dev/null || \
iptables -I DOCKER-USER 1 -i "$lan_if" -o "$BRIDGE_NAME" -j ACCEPT iptables -I DOCKER-USER 1 -i "$lan_if" -o "$BRIDGE_NAME" -d "$TARGET_IP" -j ACCEPT
# Allow return traffic # Allow return traffic
iptables -C DOCKER-USER -i "$BRIDGE_NAME" -o "$lan_if" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \ iptables -C DOCKER-USER -i "$BRIDGE_NAME" -o "$lan_if" -s "$TARGET_IP" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
iptables -I DOCKER-USER 1 -i "$BRIDGE_NAME" -o "$lan_if" -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -I DOCKER-USER 1 -i "$BRIDGE_NAME" -o "$lan_if" -s "$TARGET_IP" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
log "DOCKER-USER iptables rules added for $lan_if <-> $BRIDGE_NAME" log "DOCKER-USER iptables rules added for $lan_if <-> $BRIDGE_NAME"
fi fi
done done
# Masquerade traffic from LAN subnet to VPN bridge (using nft) # Masquerade traffic from LAN subnet to VPN bridge (so return traffic routes correctly)
# Use nft since iptables-nft backend doesn't support iptables -t nat commands
if ! nft list chain ip nat POSTROUTING 2>/dev/null | grep -q "saddr $LAN_SUBNET.*oifname.*$BRIDGE_NAME.*masquerade"; then if ! nft list chain ip nat POSTROUTING 2>/dev/null | grep -q "saddr $LAN_SUBNET.*oifname.*$BRIDGE_NAME.*masquerade"; then
nft add rule ip nat POSTROUTING ip saddr "$LAN_SUBNET" oifname "$BRIDGE_NAME" counter masquerade nft add rule ip nat POSTROUTING ip saddr "$LAN_SUBNET" oifname "$BRIDGE_NAME" counter masquerade
log "NAT masquerade rule added for $LAN_SUBNET -> $BRIDGE_NAME" log "NAT masquerade rule added for $LAN_SUBNET -> $BRIDGE_NAME"
@@ -75,21 +77,19 @@ apply_routes() {
log "NAT masquerade rule already exists for $LAN_SUBNET -> $BRIDGE_NAME" log "NAT masquerade rule already exists for $LAN_SUBNET -> $BRIDGE_NAME"
fi fi
log "OK: Host routing applied" log "OK: Host routing applied - $TARGET_IP via $CONTAINER_IP ($BRIDGE_NAME)"
} }
remove_all() { remove_all() {
log "Removing all routing rules..." log "Removing all routing rules..."
# Remove routes # Remove route
for subnet in $TARGET_SUBNETS; do ip route del "$TARGET_IP/32" via "$CONTAINER_IP" dev "$BRIDGE_NAME" 2>/dev/null || true
ip route del "$subnet" via "$CONTAINER_IP" dev "$BRIDGE_NAME" 2>/dev/null || true
done
# Remove iptables rules for all LAN interfaces # Remove iptables rules for all LAN interfaces
for lan_if in $LAN_INTERFACES; do for lan_if in $LAN_INTERFACES; do
iptables -D DOCKER-USER -i "$lan_if" -o "$BRIDGE_NAME" -j ACCEPT 2>/dev/null || true iptables -D DOCKER-USER -i "$lan_if" -o "$BRIDGE_NAME" -d "$TARGET_IP" -j ACCEPT 2>/dev/null || true
iptables -D DOCKER-USER -i "$BRIDGE_NAME" -o "$lan_if" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true iptables -D DOCKER-USER -i "$BRIDGE_NAME" -o "$lan_if" -s "$TARGET_IP" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
done done
# Remove masquerade rule (using nft) # Remove masquerade rule (using nft)

View File

@@ -1,68 +1,55 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Install host-side systemd services for cistech-tunnel # Install host-side systemd services for rego-tunnel
# Run this ONCE on the host after app install # Run this ONCE on the host after installing the app in Runtipi
# #
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
APP_DATA_DIR="/etc/runtipi/app-data/runtipi/cistech-tunnel" APP_DATA_DIR="/etc/runtipi/app-data/runtipi/rego-tunnel"
echo "Installing cistech-tunnel host services..." echo "Installing rego-tunnel host services..."
# Create app-data directory for trigger file # Create the path watcher unit
sudo mkdir -p "$APP_DATA_DIR" cat << 'EOF' | sudo tee /etc/systemd/system/rego-routing-watcher.path
# Create the path unit (watches for trigger file)
sudo tee /etc/systemd/system/cistech-routing-watcher.path > /dev/null << EOF
[Unit] [Unit]
Description=Watch for cistech-tunnel routing trigger Description=Watch for rego-tunnel routing trigger
[Path] [Path]
PathExists=$APP_DATA_DIR/restart-routing PathExists=/etc/runtipi/app-data/runtipi/rego-tunnel/restart-routing
Unit=cistech-routing-watcher.service Unit=rego-routing-watcher.service
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
# Create the service unit (applies routes when triggered) # Create the service unit
sudo tee /etc/systemd/system/cistech-routing-watcher.service > /dev/null << EOF cat << EOF | sudo tee /etc/systemd/system/rego-routing-watcher.service
[Unit] [Unit]
Description=Apply cistech-tunnel routing rules Description=Apply rego-tunnel routing rules
After=docker.service After=docker.service
[Service] [Service]
Type=oneshot Type=oneshot
ExecStart=$SCRIPT_DIR/host-routing.sh restart ExecStart=${SCRIPT_DIR}/host-routing.sh restart
ExecStartPost=/bin/rm -f $APP_DATA_DIR/restart-routing ExecStartPost=/bin/rm -f ${APP_DATA_DIR}/restart-routing
ExecStartPost=/bin/bash -c 'echo "trigger cleared at \$(date)" >> $APP_DATA_DIR/watcher.log' ExecStartPost=/bin/bash -c 'echo "trigger cleared at \$(date)" >> ${APP_DATA_DIR}/watcher.log'
EOF EOF
# Make host-routing.sh executable # Make host-routing.sh executable
chmod +x "$SCRIPT_DIR/host-routing.sh" sudo chmod +x "${SCRIPT_DIR}/host-routing.sh"
# Reload systemd and enable the watcher # Reload systemd and enable the watcher
sudo systemctl daemon-reload sudo systemctl daemon-reload
sudo systemctl enable cistech-routing-watcher.path sudo systemctl enable --now rego-routing-watcher.path
sudo systemctl start cistech-routing-watcher.path
# Disable the old boot-only service if it exists
if systemctl is-enabled cistech-routing.service &>/dev/null; then
echo "Disabling old cistech-routing.service (replaced by watcher)..."
sudo systemctl stop cistech-routing.service 2>/dev/null || true
sudo systemctl disable cistech-routing.service 2>/dev/null || true
fi
# Apply routes now
echo "Applying initial routes..."
sudo "$SCRIPT_DIR/host-routing.sh" start
echo "" echo ""
echo "Done! Watcher installed and routes applied." echo "Done! Services installed:"
echo " - rego-routing-watcher.path (watches for trigger file)"
echo " - rego-routing-watcher.service (applies routing rules)"
echo "" echo ""
echo "To trigger route refresh from container:" echo "To check status:"
echo " touch /runtime/restart-routing" echo " systemctl status rego-routing-watcher.path"
echo "" echo ""
echo "To check watcher status:" echo "To manually trigger routing:"
echo " systemctl status cistech-routing-watcher.path" echo " touch ${APP_DATA_DIR}/restart-routing"

544
apps/cistech-tunnel/shared/openconnect-vpn Normal file → Executable file
View File

@@ -1,33 +1,17 @@
#!/bin/bash #!/bin/bash
# Cistech VPN Connection Script with OpenConnect SSO # Cistech VPN Connection Script with OpenConnect SSO
# Usage: ./openconnect-vpn [-c|--connect] [-d|--disconnect] [-m|--menu] [-r|--routes] [-s|--status] [--help] # Uses config.toml for configuration, openconnect-sso handles auto-connect
# Credentials from environment variables (set by runtipi) # Credentials from environment variables
OC_URL="${OC_URL:-}" OC_URL="${OC_URL:-}"
OC_USER="${OC_USER:-}" OC_USER="${OC_USER:-}"
OC_PASSWORD="${OC_PASSWORD:-}" OC_PASSWORD="${OC_PASSWORD:-}"
OC_TOTP_SECRET="${OC_TOTP_SECRET:-}" OC_TOTP_SECRET="${OC_TOTP_SECRET:-}"
OC_SERVERCERT="${OC_SERVERCERT:-}"
OC_INTERFACE="${OC_INTERFACE:-tun0}" OC_INTERFACE="${OC_INTERFACE:-tun0}"
OC_AUTHGROUP="${OC_AUTHGROUP:-}"
OC_USERAGENT="${OC_USERAGENT:-}"
OC_EXTRA_ARGS="${OC_EXTRA_ARGS:-}"
# Log directory CONFIG_DIR="$HOME/.config/openconnect-sso"
LOG_DIR="/var/log/openconnect-vpn" CONFIG_FILE="$CONFIG_DIR/config.toml"
LOG_RETENTION_DAYS=7
mkdir -p "$LOG_DIR" 2>/dev/null
# Get current log file (changes daily)
get_log_file() {
echo "$LOG_DIR/$(date '+%Y-%m-%d').log"
}
# Cleanup old logs
cleanup_old_logs() {
find "$LOG_DIR" -name "*.log" -type f -mtime +$LOG_RETENTION_DAYS -delete 2>/dev/null
}
# Colors # Colors
RED='\033[0;31m' RED='\033[0;31m'
@@ -37,48 +21,6 @@ CYAN='\033[0;36m'
GRAY='\033[0;90m' GRAY='\033[0;90m'
NC='\033[0m' NC='\033[0m'
# Flags
SKIP_AUTO_LOGIN=false
DO_CONNECT=false
DO_DISCONNECT=false
# Logging function
log() {
local level="$1"
local msg="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local timestamp_short=$(date '+%H:%M:%S')
local log_file=$(get_log_file)
local msg_plain=$(echo -e "$msg" | sed 's/\x1b\[[0-9;]*m//g')
echo "[$timestamp] [$level] $msg_plain" >> "$log_file"
case $level in
INFO) echo -e "${GRAY}[$timestamp_short]${NC} ${GREEN}[INFO]${NC} $msg" ;;
WARN) echo -e "${GRAY}[$timestamp_short]${NC} ${YELLOW}[WARN]${NC} $msg" ;;
ERROR) echo -e "${GRAY}[$timestamp_short]${NC} ${RED}[ERROR]${NC} $msg" ;;
DEBUG) echo -e "${GRAY}[$timestamp_short]${NC} ${CYAN}[DEBUG]${NC} $msg" ;;
CMD) echo -e "${GRAY}[$timestamp_short]${NC} ${GRAY}[CMD]${NC} $msg" ;;
*) echo -e "${GRAY}[$timestamp_short]${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
}
# Print banner
print_banner() { print_banner() {
echo -e "${CYAN}========================================${NC}" echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN} Cistech VPN Connection Script ${NC}" echo -e "${CYAN} Cistech VPN Connection Script ${NC}"
@@ -86,457 +28,165 @@ print_banner() {
echo "" echo ""
} }
# Show help log() {
show_help() { local level="$1"
echo -e "${CYAN}Cistech VPN Connection Script${NC}" local msg="$2"
echo "" local ts=$(date '+%H:%M:%S')
echo "Usage: $0 [OPTIONS]" case $level in
echo "" INFO) echo -e "${GRAY}[$ts]${NC} ${GREEN}[INFO]${NC} $msg" ;;
echo "Options:" WARN) echo -e "${GRAY}[$ts]${NC} ${YELLOW}[WARN]${NC} $msg" ;;
echo " -c, --connect Start VPN connection and exit" ERROR) echo -e "${GRAY}[$ts]${NC} ${RED}[ERROR]${NC} $msg" ;;
echo " -d, --disconnect Disconnect VPN and exit" DEBUG) echo -e "${GRAY}[$ts]${NC} ${CYAN}[DEBUG]${NC} $msg" ;;
echo " -m, --menu Skip auto-connect, show menu directly" *) echo -e "${GRAY}[$ts]${NC} $msg" ;;
echo " -r, --routes Show current routing table and exit" esac
echo " -s, --status Show VPN and network status and exit"
echo " --help Show this help message"
} }
# Auto-fetch server certificate pin
get_server_cert_pin() {
local url="$1"
local host=$(echo "$url" | sed -E 's|https?://([^/:]+).*|\1|')
local port=443
log DEBUG "Fetching certificate pin from $host:$port..."
local pin=$(echo | openssl s_client -connect "$host:$port" -servername "$host" 2>/dev/null | \
openssl x509 -pubkey -noout 2>/dev/null | \
openssl pkey -pubin -outform DER 2>/dev/null | \
openssl dgst -sha256 -binary | \
base64)
if [[ -n "$pin" ]]; then
echo "pin-sha256:$pin"
else
log ERROR "Failed to fetch certificate from $host"
return 1
fi
}
# Get current TOTP
get_totp() { get_totp() {
if [ -n "$OC_TOTP_SECRET" ]; then [ -n "$OC_TOTP_SECRET" ] && oathtool --totp -b "$OC_TOTP_SECRET"
oathtool --totp -b "$OC_TOTP_SECRET"
fi
} }
# Check if VPN is connected
get_vpn_interface() { get_vpn_interface() {
ip link show "$OC_INTERFACE" 2>/dev/null | grep -q "UP" && echo "$OC_INTERFACE" ip link show "$OC_INTERFACE" 2>/dev/null | grep -q "UP" && echo "$OC_INTERFACE"
} }
get_vpn_ip() { get_vpn_ip() {
local iface=$(get_vpn_interface) local iface=$(get_vpn_interface)
if [ -n "$iface" ]; then [ -n "$iface" ] && ip addr show "$iface" 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1
ip addr show "$iface" 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1
fi
} }
get_container_ip() {
ip addr show eth0 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1
}
# Check VPN status
check_vpn_status() { check_vpn_status() {
local vpn_iface=$(get_vpn_interface) local vpn_iface=$(get_vpn_interface)
if [ -n "$vpn_iface" ]; then if [ -n "$vpn_iface" ]; then
local vpn_ip=$(get_vpn_ip) log INFO "VPN: ${GREEN}CONNECTED${NC} ($(get_vpn_ip))"
log INFO "VPN is ${GREEN}CONNECTED${NC}"
log DEBUG " Interface: $vpn_iface"
log DEBUG " VPN IP: $vpn_ip"
return 0 return 0
else else
log WARN "VPN is ${RED}NOT CONNECTED${NC}" log WARN "VPN: ${RED}NOT CONNECTED${NC}"
return 1 return 1
fi fi
} }
# Setup keyring with TOTP secret
setup_keyring() { setup_keyring() {
if [[ -n "$OC_TOTP_SECRET" && -n "$OC_USER" ]]; then if [[ -n "$OC_TOTP_SECRET" && -n "$OC_USER" ]]; then
python3 -c " python3 -c "
import keyring import keyring
keyring.set_password('openconnect-sso', 'totp/$OC_USER', '$OC_TOTP_SECRET'.upper()) keyring.set_password('openconnect-sso', 'totp/$OC_USER', '$OC_TOTP_SECRET'.upper())
print('TOTP secret stored in keyring for $OC_USER') " 2>/dev/null && log INFO "TOTP stored in keyring"
"
fi fi
} }
# Kill openconnect processes setup_config() {
kill_vpn_processes() { mkdir -p "$CONFIG_DIR"
log INFO "Killing VPN processes..."
local killed=0
for pid in $(pgrep -f "openconnect" 2>/dev/null); do # Determine browser display mode
log DEBUG "Killing openconnect (PID $pid)" local browser_mode="hidden"
kill -9 "$pid" 2>/dev/null && ((killed++)) [ -z "$OC_USER" ] && browser_mode="shown"
done
for pid in $(pgrep -f "openconnect-sso" 2>/dev/null); do cat > "$CONFIG_FILE" << EOF
log DEBUG "Killing openconnect-sso (PID $pid)" [openconnect]
kill -9 "$pid" 2>/dev/null && ((killed++)) server = "$OC_URL"
done interface = "$OC_INTERFACE"
if [ $killed -eq 0 ]; then [sso]
log INFO "No VPN processes were running" browser_display_mode = "$browser_mode"
else EOF
log INFO "Killed $killed process(es)"
sleep 1 [ -n "$OC_USER" ] && echo "user = \"$OC_USER\"" >> "$CONFIG_FILE"
fi
log INFO "Config written to $CONFIG_FILE"
} }
# Disconnect VPN
disconnect_vpn() {
log INFO "Disconnecting VPN..."
kill_vpn_processes
if check_vpn_status; then
log WARN "VPN still appears connected"
return 1
fi
log INFO "VPN disconnected"
return 0
}
# Setup IP forwarding
setup_forwarding() { setup_forwarding() {
log INFO "Setting up IP forwarding..." log INFO "Setting up IP forwarding..."
local vpn_iface=$(get_vpn_interface) local vpn_iface=$(get_vpn_interface)
if [ -z "$vpn_iface" ]; then if [ -z "$vpn_iface" ]; then
log ERROR "No VPN interface found! Is VPN connected?" log ERROR "No VPN interface found!"
return 1 return 1
fi fi
sysctl -w net.ipv4.ip_forward=1 >/dev/null
run_cmd "Enabling IP forwarding" sysctl -w net.ipv4.ip_forward=1 iptables -t nat -C POSTROUTING -o "$vpn_iface" -j MASQUERADE 2>/dev/null || \
iptables -t nat -A POSTROUTING -o "$vpn_iface" -j MASQUERADE
# NAT masquerade for traffic going through VPN touch /runtime/restart-routing 2>/dev/null
if ! iptables -t nat -C POSTROUTING -o "$vpn_iface" -j MASQUERADE 2>/dev/null; then
run_cmd "Adding NAT masquerade" iptables -t nat -A POSTROUTING -o "$vpn_iface" -j MASQUERADE
fi
# Trigger host routing service
log INFO "Triggering host routing service..."
touch /runtime/restart-routing
sleep 2
if [ ! -f /runtime/restart-routing ]; then
log INFO "Host routing service restarted"
else
log WARN "Host watcher may not be running"
fi
log INFO "Forwarding configured" log INFO "Forwarding configured"
} }
# Show routing table kill_vpn() {
show_routes() { log INFO "Stopping VPN..."
echo -e "${CYAN}========================================${NC}" pkill -f "openconnect" 2>/dev/null
echo -e "${CYAN} Current Routing Table ${NC}" sleep 1
echo -e "${CYAN}========================================${NC}" }
start_vpn() {
log INFO "Starting OpenConnect SSO..."
setup_keyring
setup_config
log INFO "Credentials:"
echo -e " ${CYAN}URL: $OC_URL${NC}"
echo -e " ${CYAN}User: $OC_USER${NC}"
[ -n "$OC_TOTP_SECRET" ] && echo -e " ${CYAN}TOTP: $(get_totp)${NC}"
echo "" echo ""
echo -e "${GREEN}IPv4 Routes:${NC}"
ip -4 route show | while IFS= read -r line; do # Run openconnect-sso (it handles reconnection)
if echo "$line" | grep -qE "tun[0-9]"; then if [[ -n "$OC_PASSWORD" ]]; then
echo -e " ${YELLOW}$line${NC}" echo "$OC_PASSWORD" | openconnect-sso
else else
echo " $line" echo "" | openconnect-sso
fi
done
echo ""
echo -e "${GREEN}VPN Interface:${NC}"
local vpn_iface=$(get_vpn_interface)
if [ -n "$vpn_iface" ]; then
ip addr show "$vpn_iface" 2>/dev/null | grep -E "inet|link" | while IFS= read -r line; do
echo " $line"
done
else
echo -e " ${RED}No VPN interface found${NC}"
fi fi
} }
# Show network status
show_network_status() {
log INFO "Current network status:"
echo ""
log DEBUG "Network Interfaces:"
ip -4 addr show | grep -E "inet |^[0-9]+:" | while IFS= read -r line; do
echo -e " ${GRAY}|${NC} $line"
done
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
local container_ip=$(get_container_ip)
if [ -n "$container_ip" ]; then
log DEBUG "Container IP: $container_ip"
fi
echo ""
}
# Print TOTP
show_totp() { show_totp() {
if [ -z "$OC_TOTP_SECRET" ]; then [ -z "$OC_TOTP_SECRET" ] && { log ERROR "No TOTP secret"; return 1; }
log ERROR "TOTP secret not configured" log INFO "Live TOTP (Ctrl+C to stop)"
return 1
fi
log INFO "Starting live TOTP display (Ctrl+C to stop)"
echo ""
while true; do while true; do
TOTP=$(get_totp) echo -ne "\r TOTP: ${GREEN}$(get_totp)${NC} (${YELLOW}$((30 - $(date +%s) % 30))s${NC}) "
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 sleep 1
done done
} }
# Start VPN connection
start_vpn() {
local do_auto_login="$1"
log INFO "=== Starting OpenConnect VPN ==="
echo ""
# Kill existing
kill_vpn_processes
# Get server cert if not set
if [[ -z "$OC_SERVERCERT" ]]; then
log INFO "Fetching server certificate..."
OC_SERVERCERT=$(get_server_cert_pin "$OC_URL")
log DEBUG "Server cert: $OC_SERVERCERT"
fi
# Setup keyring for TOTP
setup_keyring
# Build openconnect command
OPENCONNECT_CMD="/usr/sbin/openconnect --protocol=anyconnect --servercert $OC_SERVERCERT --interface $OC_INTERFACE --script /usr/share/vpnc-scripts/vpnc-script"
[[ -n "$OC_AUTHGROUP" ]] && OPENCONNECT_CMD+=" --authgroup $OC_AUTHGROUP"
[[ -n "$OC_USERAGENT" ]] && OPENCONNECT_CMD+=" --useragent $OC_USERAGENT"
[[ -n "$OC_EXTRA_ARGS" ]] && OPENCONNECT_CMD+=" $OC_EXTRA_ARGS"
# Determine SSO args
if [[ -n "$OC_USER" ]]; then
OC_SSO_ARGS="--browser-display-mode hidden -u $OC_USER"
else
OC_SSO_ARGS="--browser-display-mode shown"
fi
# Show credentials
log INFO "Credentials:"
echo -e " ${CYAN}URL: $OC_URL${NC}"
echo -e " ${CYAN}User: $OC_USER${NC}"
if [ -n "$OC_PASSWORD" ]; then
echo -e " ${CYAN}Password: (set)${NC}"
fi
if [ -n "$OC_TOTP_SECRET" ]; then
TOTP=$(get_totp)
echo -e " ${CYAN}TOTP: $TOTP${NC}"
fi
echo ""
log INFO "Launching openconnect-sso..."
# Run openconnect-sso
if [[ -n "$OC_USER" && -n "$OC_PASSWORD" ]]; then
echo "$OC_PASSWORD" | openconnect-sso -s "$OC_URL" $OC_SSO_ARGS -- $OPENCONNECT_CMD &
elif [[ -n "$OC_USER" ]]; then
echo "" | openconnect-sso -s "$OC_URL" $OC_SSO_ARGS -- $OPENCONNECT_CMD &
else
openconnect-sso -s "$OC_URL" $OC_SSO_ARGS -- $OPENCONNECT_CMD &
fi
VPN_PID=$!
# Wait for connection
log INFO "Waiting for VPN connection..."
local wait_count=0
local max_wait=120
while [ -z "$(get_vpn_interface)" ]; do
sleep 2
((wait_count+=2))
if [ $((wait_count % 10)) -eq 0 ]; then
log DEBUG "Still waiting... (${wait_count}s)"
fi
if [ $wait_count -ge $max_wait ]; then
log ERROR "Timeout waiting for VPN after ${max_wait}s"
return 1
fi
# Check if process died
if ! kill -0 $VPN_PID 2>/dev/null; then
log ERROR "openconnect-sso process died"
return 1
fi
done
log INFO "VPN connected!"
local vpn_ip=$(get_vpn_ip)
log DEBUG " Interface: $OC_INTERFACE"
log DEBUG " VPN IP: $vpn_ip"
sleep 3
setup_forwarding
log INFO "VPN setup complete"
return 0
}
# Main menu
main_menu() { main_menu() {
echo -e "${GREEN}Options:${NC}" echo -e "${GREEN}Options:${NC}"
echo -e " ${CYAN}1${NC} - Start VPN connection" echo -e " ${CYAN}1${NC} - Start VPN"
echo -e " ${CYAN}2${NC} - Disconnect VPN" echo -e " ${CYAN}2${NC} - Stop VPN"
echo -e " ${CYAN}3${NC} - Show live TOTP" echo -e " ${CYAN}3${NC} - Show TOTP"
echo -e " ${CYAN}4${NC} - Setup IP forwarding rules" echo -e " ${CYAN}4${NC} - Setup forwarding"
echo -e " ${CYAN}5${NC} - Show network status" echo -e " ${CYAN}5${NC} - Check status"
echo -e " ${CYAN}6${NC} - Show routing table" echo -e " ${CYAN}6${NC} - Show routes"
echo -e " ${CYAN}7${NC} - Kill VPN processes"
echo -e " ${CYAN}q${NC} - Quit" echo -e " ${CYAN}q${NC} - Quit"
echo "" echo ""
} }
# Watchdog
start_watchdog() {
log INFO "Starting VPN watchdog (check every 60s)..."
local check_interval=60
local reconnect_attempts=0
local max_reconnect_attempts=3
while true; do
sleep $check_interval
local vpn_iface=$(get_vpn_interface)
if [ -n "$vpn_iface" ]; then
reconnect_attempts=0
else
((reconnect_attempts++))
log WARN "VPN disconnected! Attempt $reconnect_attempts/$max_reconnect_attempts..."
if [ $reconnect_attempts -le $max_reconnect_attempts ]; then
kill_vpn_processes
sleep 2
start_vpn "true" &
local wait_count=0
while [ -z "$(get_vpn_interface)" ] && [ $wait_count -lt 120 ]; do
sleep 2
((wait_count+=2))
done
if [ -n "$(get_vpn_interface)" ]; then
log INFO "VPN reconnected!"
reconnect_attempts=0
else
log ERROR "Reconnect failed"
fi
else
log ERROR "Max reconnect attempts reached"
sleep 300
reconnect_attempts=0
fi
fi
done
}
# Parse args # Parse args
parse_args() { for arg in "$@"; do
while [[ $# -gt 0 ]]; do case $arg in
case $1 in -m|--menu) SKIP_AUTO=true ;;
-c|--connect) -s|--status) check_vpn_status; exit 0 ;;
DO_CONNECT=true --help) echo "Usage: $0 [-m|--menu] [-s|--status]"; exit 0 ;;
shift
;;
-d|--disconnect)
DO_DISCONNECT=true
shift
;;
-m|--menu)
SKIP_AUTO_LOGIN=true
shift
;;
-r|--routes)
show_routes
exit 0
;;
-s|--status)
print_banner
check_vpn_status
echo ""
show_network_status
exit 0
;;
--help)
show_help
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac esac
done done
}
# Main # Main
parse_args "$@"
cleanup_old_logs
echo "" >> "$(get_log_file)"
log INFO "openconnect-vpn script started"
log DEBUG "OC_URL=$OC_URL"
log DEBUG "OC_USER=$OC_USER"
print_banner print_banner
log INFO "openconnect-vpn started"
if [ "$DO_DISCONNECT" = "true" ]; then if [ "${SKIP_AUTO:-false}" = "true" ]; then
disconnect_vpn
exit $?
fi
if [ "$DO_CONNECT" = "true" ]; then
start_vpn "true"
exit $?
fi
# Check current status or auto-connect
if [ "$SKIP_AUTO_LOGIN" = "true" ]; then
log INFO "Menu mode - skipping auto-connect" log INFO "Menu mode - skipping auto-connect"
elif check_vpn_status; then elif check_vpn_status; then
echo ""
log INFO "VPN already connected. Setting up forwarding..."
setup_forwarding setup_forwarding
else else
echo "" log INFO "Auto-starting VPN..."
log INFO "Auto-starting VPN connection..." start_vpn &
echo "" VPN_PID=$!
if start_vpn "true"; then
# Start watchdog in background # Wait for connection
start_watchdog & for i in {1..60}; do
WATCHDOG_PID=$! sleep 2
log DEBUG "Watchdog started (PID $WATCHDOG_PID)" if [ -n "$(get_vpn_interface)" ]; then
log INFO "VPN connected!"
setup_forwarding
break
fi fi
done
fi fi
# Menu loop # Menu loop
@@ -546,18 +196,14 @@ while true; do
echo -ne "${CYAN}Choice: ${NC}" echo -ne "${CYAN}Choice: ${NC}"
read -r choice read -r choice
echo "" echo ""
[[ -z "${choice// }" ]] && continue [[ -z "${choice// }" ]] && continue
case $choice in case $choice in
1) start_vpn "true" && { start_watchdog & } ;; 1) start_vpn ;;
2) disconnect_vpn ;; 2) kill_vpn ;;
3) show_totp ;; 3) show_totp ;;
4) setup_forwarding ;; 4) setup_forwarding ;;
5) show_network_status ;; 5) check_vpn_status ;;
6) show_routes ;; 6) ip -4 route show ;;
7) kill_vpn_processes ;;
q|Q) log INFO "Goodbye!"; exit 0 ;; q|Q) log INFO "Goodbye!"; exit 0 ;;
*) ;;
esac esac
done done

View File

@@ -1,21 +1,21 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Uninstall host-side systemd services for cistech-tunnel # Uninstall host-side systemd services for rego-tunnel
# #
set -euo pipefail set -euo pipefail
echo "Removing cistech-tunnel host services..." echo "Removing rego-tunnel host services..."
# Stop and disable the watcher # Stop and disable the watcher
sudo systemctl stop cistech-routing-watcher.path 2>/dev/null || true sudo systemctl stop rego-routing-watcher.path 2>/dev/null || true
sudo systemctl disable cistech-routing-watcher.path 2>/dev/null || true sudo systemctl disable rego-routing-watcher.path 2>/dev/null || true
# Remove routing rules # Remove routing rules
/etc/runtipi/repos/runtipi/apps/cistech-tunnel/shared/host-routing.sh stop 2>/dev/null || true /etc/runtipi/repos/runtipi/apps/rego-tunnel/shared/host-routing.sh stop 2>/dev/null || true
# Remove systemd units # Remove systemd units
sudo rm -f /etc/systemd/system/cistech-routing-watcher.path sudo rm -f /etc/systemd/system/rego-routing-watcher.path
sudo rm -f /etc/systemd/system/cistech-routing-watcher.service sudo rm -f /etc/systemd/system/rego-routing-watcher.service
# Reload systemd # Reload systemd
sudo systemctl daemon-reload sudo systemctl daemon-reload

View File

@@ -5,7 +5,7 @@ unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS unset DBUS_SESSION_BUS_ADDRESS
# Import environment variables from container (PID 1) # Import environment variables from container (PID 1)
# VNC doesn't inherit Docker env vars, so we source them here # Systemd services don't inherit Docker env vars, so we source them here
while IFS= read -r -d '' line; do while IFS= read -r -d '' line; do
export "$line" export "$line"
done < /proc/1/environ done < /proc/1/environ
@@ -14,7 +14,7 @@ export XDG_RUNTIME_DIR=/tmp/runtime-root
mkdir -p $XDG_RUNTIME_DIR mkdir -p $XDG_RUNTIME_DIR
chmod 700 $XDG_RUNTIME_DIR chmod 700 $XDG_RUNTIME_DIR
# GPU/WebKit workarounds # GPU/WebKit workarounds for browser
export GDK_BACKEND=x11 export GDK_BACKEND=x11
export WEBKIT_DISABLE_DMABUF_RENDERER=1 export WEBKIT_DISABLE_DMABUF_RENDERER=1