#!/bin/bash # # Cisco VPN Automation Script (runs inside container) # Usage: vpn-connect.sh [-c|--connect] [-d|--disconnect] [-s|--status] [-m|--manual] [--help] # # Options: # -c, --connect Auto-connect to VPN (default if no option) # -d, --disconnect Disconnect VPN # -s, --status Show VPN status # -m, --manual Start UI without auto-login # --help Show this help message # # Load config from environment or config file CONFIG_FILE="${VPN_CONFIG_FILE:-/config/vpn.conf}" if [ -f "$CONFIG_FILE" ]; then source "$CONFIG_FILE" fi # These can be set via environment variables or config file EMAIL="${VPN_EMAIL:-}" PASSWORD="${VPN_PASSWORD:-}" TOTP_SECRET="${VPN_TOTP_SECRET:-}" VPN_HOST="${VPN_HOST:-}" # 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 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" ;; *) echo -e "${GRAY}[$timestamp]${NC} $msg" ;; esac } # Function to get current TOTP get_totp() { if [ -n "$TOTP_SECRET" ]; then oathtool --totp -b "$TOTP_SECRET" else log WARN "TOTP_SECRET not set" echo "" fi } # Detect VPN tunnel interface get_vpn_interface() { ip link show | grep -oP '(cscotun\d+|tun\d+)(?=:.*UP)' | head -1 } # Get VPN 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 } # Check VPN status 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 } # Kill Cisco processes kill_cisco_processes() { local kill_agentd="${1:-false}" log INFO "Stopping Cisco processes..." local killed=0 local my_pid=$$ # Kill vpnui for pid in $(pgrep -x "vpnui" 2>/dev/null); do if [ "$pid" != "$my_pid" ]; then log DEBUG "Killing vpnui (PID $pid)" kill -9 "$pid" 2>/dev/null && ((killed++)) fi done # Optionally kill vpnagentd if [ "$kill_agentd" = "true" ]; then systemctl stop vpnagentd.service 2>/dev/null || true log DEBUG "Stopped vpnagentd service" fi if [ $killed -eq 0 ]; then log INFO "No Cisco UI processes were running" else log INFO "Stopped $killed process(es)" sleep 1 fi } # Disconnect VPN disconnect_vpn() { log INFO "Disconnecting Cisco AnyConnect..." # Try clean disconnect via CLI if [ -x /opt/cisco/secureclient/bin/vpn ]; then echo "disconnect" | /opt/cisco/secureclient/bin/vpn -s 2>/dev/null || true fi # Kill UI processes kill_cisco_processes "false" sleep 2 if check_vpn_status; then log WARN "VPN still appears connected" return 1 fi log INFO "VPN disconnected" return 0 } # Auto-login using xdotool auto_login() { log INFO "Starting automated login sequence..." # Check credentials if [ -z "$EMAIL" ] || [ -z "$PASSWORD" ]; then log ERROR "EMAIL and PASSWORD must be set for auto-login" return 1 fi # 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..." DISPLAY=:1 xdotool key Return sleep 5 # Type email log DEBUG "Typing email..." DISPLAY=:1 xdotool type --delay 50 "$EMAIL" DISPLAY=:1 xdotool key Return sleep 5 # Type password log DEBUG "Typing password..." DISPLAY=:1 xdotool type --delay 50 "$PASSWORD" DISPLAY=:1 xdotool key Return sleep 5 # Type TOTP if configured if [ -n "$TOTP_SECRET" ]; then log DEBUG "Typing TOTP..." local totp=$(oathtool --totp -b "$TOTP_SECRET") log DEBUG "TOTP: $totp" DISPLAY=:1 xdotool type --delay 50 "$totp" DISPLAY=:1 xdotool key Return sleep 5 fi # Extra enters for confirmation dialogs log DEBUG "Sending confirmation enters..." DISPLAY=:1 xdotool key Return sleep 2 DISPLAY=:1 xdotool key Return sleep 5 DISPLAY=:1 xdotool key Return log INFO "Auto-login sequence completed" } # Start VPN UI start_vpn_ui() { local do_auto_login="$1" log INFO "=== Starting Cisco Secure Client ===" echo "" # Kill existing UI processes kill_cisco_processes "false" # Ensure vpnagentd is running if ! pgrep -x vpnagentd >/dev/null; then log INFO "Starting vpnagentd..." systemctl start vpnagentd.service log DEBUG "Waiting for vpnagentd to initialize..." sleep 5 fi # Show credentials if configured if [ -n "$EMAIL" ]; then log INFO "Credentials configured:" echo -e " ${CYAN}Email: $EMAIL${NC}" echo -e " ${CYAN}Password: ****${NC}" if [ -n "$TOTP_SECRET" ]; then local totp=$(get_totp) echo -e " ${CYAN}TOTP: $totp${NC}" fi echo "" fi # Start VPN UI log INFO "Launching Cisco Secure Client UI..." export DISPLAY=:1 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 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" 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" # Monitor and auto-reconnect log INFO "Monitoring VPN connection (will auto-reconnect if disconnected)..." while true; do sleep 30 if [ -z "$(get_vpn_interface)" ]; then log WARN "VPN disconnected! Reconnecting in 5 seconds..." sleep 5 start_vpn_ui "$do_auto_login" return $? fi done else log INFO "Manual mode - use the noVNC GUI to log in" log INFO "VPN host: ${VPN_HOST:-not configured}" return 0 fi } # Show help show_help() { echo -e "${CYAN}Cisco VPN Automation Script${NC}" echo "" echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " -c, --connect Auto-connect to VPN (default if no option)" echo " -d, --disconnect Disconnect VPN" echo " -s, --status Show VPN status" echo " -m, --manual Start UI without auto-login" echo " --help Show this help message" echo "" echo "Configuration (via environment or /config/vpn.conf):" echo " VPN_EMAIL Email for SSO login" echo " VPN_PASSWORD Password for SSO login" echo " VPN_TOTP_SECRET TOTP secret for 2FA" echo " VPN_HOST VPN server hostname" } # Parse arguments ACTION="connect" while [[ $# -gt 0 ]]; do case $1 in -c|--connect) ACTION="connect" shift ;; -d|--disconnect) ACTION="disconnect" shift ;; -s|--status) ACTION="status" shift ;; -m|--manual) ACTION="manual" shift ;; --help) show_help exit 0 ;; *) echo "Unknown option: $1" show_help exit 1 ;; esac done # Execute action case $ACTION in connect) if [ -z "$EMAIL" ] || [ -z "$PASSWORD" ]; then log ERROR "VPN_EMAIL and VPN_PASSWORD must be set for auto-connect" log INFO "Use -m/--manual for manual login, or set credentials in /config/vpn.conf" exit 1 fi start_vpn_ui "true" ;; disconnect) disconnect_vpn ;; status) check_vpn_status ;; manual) start_vpn_ui "false" ;; esac