Files
runtipi/apps/rego-tunnel/shared/cisco-vpn.sh.orig-20251228-143916
alexz f1ba1f050d
Some checks failed
Test / test (push) Has been cancelled
new image structure for cisco-vpn and related scripts
2026-01-04 09:01:52 +00:00

730 lines
21 KiB
Bash

#!/bin/bash
# Dover VPN Connection Script with Semi-Automation
# Usage: ./cisco-vpn.sh [-m|--menu] [-r|--routes] [-h|--hosts] [--help]
#
# Options:
# -m, --menu Skip auto-login, show menu directly
# -r, --routes Show current routing table and exit
# -h, --hosts Show /etc/hosts and exit
# -s, --status Show VPN and network status and exit
# --help Show this help message
#
# 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='Lz@83278327$$@@'
TOTP_SECRET="rzqtqskdwkhz6zyr"
VPN_HOST="vpn-ord1.dovercorp.com"
TARGET_IP="10.35.33.230"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
NC='\033[0m'
# Flags
SKIP_AUTO_LOGIN=false
# 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
}
# Show help
show_help() {
echo -e "${CYAN}Dover VPN Connection Script${NC}"
echo ""
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -m, --menu Skip auto-login, show menu directly"
echo " -r, --routes Show current routing table and exit"
echo " -h, --hosts Show /etc/hosts and exit"
echo " -s, --status Show VPN and network status and exit"
echo " --help Show this help message"
echo ""
echo "Menu Options:"
echo " 1 - Start Cisco AnyConnect (kill existing + launch)"
echo " 2 - Copy credentials to clipboard (one by one)"
echo " 3 - Show live TOTP"
echo " 4 - Setup IP forwarding rules only"
echo " 5 - Test connection to target"
echo " 6 - Show network status"
echo " 7 - Kill all Cisco processes"
echo " 8 - Show routing table"
echo " 9 - Show /etc/hosts"
echo " e - Edit /etc/hosts"
echo " q - Quit"
}
# Show routing table
show_routes() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN} Current Routing Table ${NC}"
echo -e "${CYAN}========================================${NC}"
echo ""
echo -e "${GREEN}IPv4 Routes:${NC}"
ip -4 route show | while IFS= read -r line; do
# Highlight VPN-related routes
if echo "$line" | grep -qE "cscotun|tun[0-9]"; then
echo -e " ${YELLOW}$line${NC}"
elif echo "$line" | grep -qE "10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\."; then
echo -e " ${CYAN}$line${NC}"
else
echo " $line"
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
}
# Show /etc/hosts
show_hosts() {
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN} /etc/hosts ${NC}"
echo -e "${CYAN}========================================${NC}"
echo ""
cat -n /etc/hosts
}
# Edit /etc/hosts
edit_hosts() {
local editor="${EDITOR:-nano}"
if command -v "$editor" &>/dev/null; then
sudo "$editor" /etc/hosts
else
log ERROR "No editor found. Set EDITOR environment variable."
log INFO "Try: sudo nano /etc/hosts"
fi
}
# 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 the bridge network (for container routing)
get_vm_bridge_ip() {
# Get IP from ens3 (main adapter with 100.100.0.x)
ip addr show ens3 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1
}
# Function to get container gateway IP
get_container_gateway() {
# The container bridge is at 100.100.0.1
echo "100.100.0.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_bridge_ip=$(get_vm_bridge_ip)
local container_gw=$(get_container_gateway)
log DEBUG "VPN interface: $vpn_iface"
log DEBUG "VPN IP: $vpn_ip"
log DEBUG "VM bridge IP: $vm_bridge_ip"
log DEBUG "Container gateway: $container_gw"
# Enable IP forwarding
run_cmd "Enabling IP forwarding" sudo sysctl -w net.ipv4.ip_forward=1
# NAT masquerade for traffic from container network (100.100.0.0/24) going through VPN
# This is the ONLY masquerade rule needed - source-based, not destination-based
if ! sudo iptables -t nat -C POSTROUTING -s 100.100.0.0/24 -o "$vpn_iface" -j MASQUERADE 2>/dev/null; then
run_cmd "Adding NAT masquerade for container network -> VPN" sudo iptables -t nat -A POSTROUTING -s 100.100.0.0/24 -o "$vpn_iface" -j MASQUERADE
else
log DEBUG "NAT masquerade for container network 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
# Accept forwarding from container network
if ! sudo iptables -C FORWARD -s 100.100.0.0/24 -j ACCEPT 2>/dev/null; then
run_cmd "Adding forward rule (from container network)" sudo iptables -A FORWARD -s 100.100.0.0/24 -j ACCEPT
else
log DEBUG "Forward rule (from container network) already exists"
fi
if ! sudo iptables -C FORWARD -d 100.100.0.0/24 -j ACCEPT 2>/dev/null; then
run_cmd "Adding forward rule (to container network)" sudo iptables -A FORWARD -d 100.100.0.0/24 -j ACCEPT
else
log DEBUG "Forward rule (to container network) 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
# Also allow container network through ciscovpn chain
if ! sudo iptables -C ciscovpn -s 100.100.0.0/24 -j ACCEPT 2>/dev/null; then
run_cmd "Adding ciscovpn bypass (container network)" sudo iptables -I ciscovpn 3 -s 100.100.0.0/24 -j ACCEPT
fi
else
log DEBUG "ciscovpn chain does not exist (yet)"
fi
log INFO "Forwarding rules configured"
echo ""
log INFO "Container should now be able to reach $TARGET_IP through this VM"
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
# Bridge IP (for container routing)
local vm_bridge_ip=$(get_vm_bridge_ip)
if [ -n "$vm_bridge_ip" ]; then
log DEBUG "VM IP on bridge: $vm_bridge_ip"
fi
# Container gateway
local container_gw=$(get_container_gateway)
log DEBUG "Container gateway: $container_gw"
# Default gateway
echo ""
log DEBUG "Default gateway:"
ip route show default | while IFS= read -r line; do
echo -e " ${GRAY}${NC} $line"
done
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} - Show routing table"
echo -e " ${CYAN}9${NC} - Show /etc/hosts"
echo -e " ${CYAN}e${NC} - Edit /etc/hosts"
echo -e " ${CYAN}q${NC} - Quit"
echo ""
}
# 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
# 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() {
local do_auto_login="$1"
log INFO "=== Starting Cisco AnyConnect VPN ==="
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"
if [ "$do_auto_login" = "true" ]; then
# Run auto-login in background
auto_login &
AUTO_LOGIN_PID=$!
log DEBUG "Auto-login started with PID $AUTO_LOGIN_PID"
else
log INFO "Manual login mode - use keyboard shortcuts or menu option 2 for credentials"
return 0
fi
# 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"
# Wait a bit for routes to stabilize
log DEBUG "Waiting for routes to stabilize..."
sleep 3
# Setup forwarding
setup_forwarding
# Test connection
log INFO "Testing connection to $TARGET_IP..."
if ping -c 2 -W 3 "$TARGET_IP" &>/dev/null; then
log INFO "Connection test: ${GREEN}SUCCESS${NC}"
else
log WARN "Connection test: ${RED}FAILED${NC} (may need manual route on Windows)"
fi
}
# Parse command line arguments
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-m|--menu)
SKIP_AUTO_LOGIN=true
shift
;;
-r|--routes)
show_routes
exit 0
;;
-h|--hosts)
show_hosts
exit 0
;;
-s|--status)
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN} VPN and Network Status ${NC}"
echo -e "${CYAN}========================================${NC}"
echo ""
check_vpn_status
echo ""
show_network_status
exit 0
;;
--help)
show_help
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
done
}
# Main
parse_args "$@"
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN} Dover VPN Connection Script ${NC}"
echo -e "${CYAN}========================================${NC}"
echo ""
log INFO "Script started"
echo ""
# Check current status
if check_vpn_status; then
echo ""
log INFO "VPN already connected. Setting up forwarding..."
setup_forwarding
elif [ "$SKIP_AUTO_LOGIN" = "true" ]; then
echo ""
log INFO "Menu mode - skipping auto-login"
else
echo ""
log INFO "Auto-starting VPN connection..."
echo ""
start_anyconnect "true"
fi
echo ""
main_menu
while true; do
echo -ne "${CYAN}Choice: ${NC}"
read -r choice
case $choice in
1)
echo ""
if [ "$SKIP_AUTO_LOGIN" = "true" ]; then
start_anyconnect "false"
else
start_anyconnect "true"
fi
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 ""
show_routes
echo ""
main_menu
;;
9)
echo ""
show_hosts
echo ""
main_menu
;;
e|E)
echo ""
edit_hosts
echo ""
main_menu
;;
q|Q)
log INFO "Goodbye!"
exit 0
;;
*)
log ERROR "Invalid choice"
;;
esac
done