210 lines
5.2 KiB
Bash
Executable File
210 lines
5.2 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Cistech VPN Connection Script with OpenConnect SSO
|
|
# Uses config.toml for configuration, openconnect-sso handles auto-connect
|
|
|
|
# Credentials from environment variables
|
|
OC_URL="${OC_URL:-}"
|
|
OC_USER="${OC_USER:-}"
|
|
OC_PASSWORD="${OC_PASSWORD:-}"
|
|
OC_TOTP_SECRET="${OC_TOTP_SECRET:-}"
|
|
OC_INTERFACE="${OC_INTERFACE:-tun0}"
|
|
|
|
CONFIG_DIR="$HOME/.config/openconnect-sso"
|
|
CONFIG_FILE="$CONFIG_DIR/config.toml"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
GRAY='\033[0;90m'
|
|
NC='\033[0m'
|
|
|
|
print_banner() {
|
|
echo -e "${CYAN}========================================${NC}"
|
|
echo -e "${CYAN} Cistech VPN Connection Script ${NC}"
|
|
echo -e "${CYAN}========================================${NC}"
|
|
echo ""
|
|
}
|
|
|
|
log() {
|
|
local level="$1"
|
|
local msg="$2"
|
|
local ts=$(date '+%H:%M:%S')
|
|
case $level in
|
|
INFO) echo -e "${GRAY}[$ts]${NC} ${GREEN}[INFO]${NC} $msg" ;;
|
|
WARN) echo -e "${GRAY}[$ts]${NC} ${YELLOW}[WARN]${NC} $msg" ;;
|
|
ERROR) echo -e "${GRAY}[$ts]${NC} ${RED}[ERROR]${NC} $msg" ;;
|
|
DEBUG) echo -e "${GRAY}[$ts]${NC} ${CYAN}[DEBUG]${NC} $msg" ;;
|
|
*) echo -e "${GRAY}[$ts]${NC} $msg" ;;
|
|
esac
|
|
}
|
|
|
|
get_totp() {
|
|
[ -n "$OC_TOTP_SECRET" ] && oathtool --totp -b "$OC_TOTP_SECRET"
|
|
}
|
|
|
|
get_vpn_interface() {
|
|
ip link show "$OC_INTERFACE" 2>/dev/null | grep -q "UP" && echo "$OC_INTERFACE"
|
|
}
|
|
|
|
get_vpn_ip() {
|
|
local iface=$(get_vpn_interface)
|
|
[ -n "$iface" ] && ip addr show "$iface" 2>/dev/null | grep -oP 'inet \K[\d.]+' | head -1
|
|
}
|
|
|
|
check_vpn_status() {
|
|
local vpn_iface=$(get_vpn_interface)
|
|
if [ -n "$vpn_iface" ]; then
|
|
log INFO "VPN: ${GREEN}CONNECTED${NC} ($(get_vpn_ip))"
|
|
return 0
|
|
else
|
|
log WARN "VPN: ${RED}NOT CONNECTED${NC}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
setup_keyring() {
|
|
if [[ -n "$OC_TOTP_SECRET" && -n "$OC_USER" ]]; then
|
|
python3 -c "
|
|
import keyring
|
|
keyring.set_password('openconnect-sso', 'totp/$OC_USER', '$OC_TOTP_SECRET'.upper())
|
|
" 2>/dev/null && log INFO "TOTP stored in keyring"
|
|
fi
|
|
}
|
|
|
|
setup_config() {
|
|
mkdir -p "$CONFIG_DIR"
|
|
|
|
# Determine browser display mode
|
|
local browser_mode="hidden"
|
|
[ -z "$OC_USER" ] && browser_mode="shown"
|
|
|
|
cat > "$CONFIG_FILE" << EOF
|
|
[openconnect]
|
|
server = "$OC_URL"
|
|
interface = "$OC_INTERFACE"
|
|
|
|
[sso]
|
|
browser_display_mode = "$browser_mode"
|
|
EOF
|
|
|
|
[ -n "$OC_USER" ] && echo "user = \"$OC_USER\"" >> "$CONFIG_FILE"
|
|
|
|
log INFO "Config written to $CONFIG_FILE"
|
|
}
|
|
|
|
setup_forwarding() {
|
|
log INFO "Setting up IP forwarding..."
|
|
local vpn_iface=$(get_vpn_interface)
|
|
if [ -z "$vpn_iface" ]; then
|
|
log ERROR "No VPN interface found!"
|
|
return 1
|
|
fi
|
|
sysctl -w net.ipv4.ip_forward=1 >/dev/null
|
|
iptables -t nat -C POSTROUTING -o "$vpn_iface" -j MASQUERADE 2>/dev/null || \
|
|
iptables -t nat -A POSTROUTING -o "$vpn_iface" -j MASQUERADE
|
|
touch /runtime/restart-routing 2>/dev/null
|
|
log INFO "Forwarding configured"
|
|
}
|
|
|
|
kill_vpn() {
|
|
log INFO "Stopping VPN..."
|
|
pkill -f "openconnect" 2>/dev/null
|
|
sleep 1
|
|
}
|
|
|
|
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 ""
|
|
|
|
# Run openconnect-sso (it handles reconnection)
|
|
if [[ -n "$OC_PASSWORD" ]]; then
|
|
echo "$OC_PASSWORD" | openconnect-sso
|
|
else
|
|
echo "" | openconnect-sso
|
|
fi
|
|
}
|
|
|
|
show_totp() {
|
|
[ -z "$OC_TOTP_SECRET" ] && { log ERROR "No TOTP secret"; return 1; }
|
|
log INFO "Live TOTP (Ctrl+C to stop)"
|
|
while true; do
|
|
echo -ne "\r TOTP: ${GREEN}$(get_totp)${NC} (${YELLOW}$((30 - $(date +%s) % 30))s${NC}) "
|
|
sleep 1
|
|
done
|
|
}
|
|
|
|
main_menu() {
|
|
echo -e "${GREEN}Options:${NC}"
|
|
echo -e " ${CYAN}1${NC} - Start VPN"
|
|
echo -e " ${CYAN}2${NC} - Stop VPN"
|
|
echo -e " ${CYAN}3${NC} - Show TOTP"
|
|
echo -e " ${CYAN}4${NC} - Setup forwarding"
|
|
echo -e " ${CYAN}5${NC} - Check status"
|
|
echo -e " ${CYAN}6${NC} - Show routes"
|
|
echo -e " ${CYAN}q${NC} - Quit"
|
|
echo ""
|
|
}
|
|
|
|
# Parse args
|
|
for arg in "$@"; do
|
|
case $arg in
|
|
-m|--menu) SKIP_AUTO=true ;;
|
|
-s|--status) check_vpn_status; exit 0 ;;
|
|
--help) echo "Usage: $0 [-m|--menu] [-s|--status]"; exit 0 ;;
|
|
esac
|
|
done
|
|
|
|
# Main
|
|
print_banner
|
|
log INFO "openconnect-vpn started"
|
|
|
|
if [ "${SKIP_AUTO:-false}" = "true" ]; then
|
|
log INFO "Menu mode - skipping auto-connect"
|
|
elif check_vpn_status; then
|
|
setup_forwarding
|
|
else
|
|
log INFO "Auto-starting VPN..."
|
|
start_vpn &
|
|
VPN_PID=$!
|
|
|
|
# Wait for connection
|
|
for i in {1..60}; do
|
|
sleep 2
|
|
if [ -n "$(get_vpn_interface)" ]; then
|
|
log INFO "VPN connected!"
|
|
setup_forwarding
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Menu loop
|
|
while true; do
|
|
echo ""
|
|
main_menu
|
|
echo -ne "${CYAN}Choice: ${NC}"
|
|
read -r choice
|
|
echo ""
|
|
[[ -z "${choice// }" ]] && continue
|
|
case $choice in
|
|
1) start_vpn ;;
|
|
2) kill_vpn ;;
|
|
3) show_totp ;;
|
|
4) setup_forwarding ;;
|
|
5) check_vpn_status ;;
|
|
6) ip -4 route show ;;
|
|
q|Q) log INFO "Goodbye!"; exit 0 ;;
|
|
esac
|
|
done
|