Remove unused shared scripts and vpn_scripts-not-used folder
Some checks failed
Test / test (push) Has been cancelled
Some checks failed
Test / test (push) Has been cancelled
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,56 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Rego Tunnel Init Script
|
||||
# Combines:
|
||||
# 1. DNS unmount fix (from cisco-vpn) - allows VPN to modify /etc/resolv.conf and /etc/hosts
|
||||
# 2. Basic network setup (IP forwarding)
|
||||
# 3. Starts systemd
|
||||
|
||||
set -e
|
||||
|
||||
echo "[init-rego] Starting Rego Tunnel initialization..."
|
||||
|
||||
# ============================================
|
||||
# 1. Fix Docker's read-only bind mounts
|
||||
# ============================================
|
||||
echo "[init-rego] Fixing DNS bind mounts..."
|
||||
|
||||
# Backup current DNS config
|
||||
cp /etc/resolv.conf /tmp/resolv.conf.bak 2>/dev/null || true
|
||||
cp /etc/hosts /tmp/hosts.bak 2>/dev/null || true
|
||||
|
||||
# Unmount Docker's bind mounts (required for VPN to modify DNS)
|
||||
umount /etc/resolv.conf 2>/dev/null || true
|
||||
umount /etc/hosts 2>/dev/null || true
|
||||
|
||||
# Restore DNS config as regular writable files
|
||||
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
|
||||
|
||||
echo "[init-rego] DNS files are now writable"
|
||||
|
||||
# ============================================
|
||||
# 2. Network Setup
|
||||
# ============================================
|
||||
echo "[init-rego] Setting up network..."
|
||||
|
||||
# Enable IP forwarding
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
echo "[init-rego] IP forwarding enabled"
|
||||
|
||||
# Note: NAT/forwarding rules for VPN traffic are set up by the cisco-vpn script
|
||||
# AFTER the VPN connects (it needs to know the VPN interface name)
|
||||
|
||||
# ============================================
|
||||
# 3. Make shared scripts executable
|
||||
# ============================================
|
||||
if [ -d /shared ]; then
|
||||
chmod +x /shared/*.sh 2>/dev/null || true
|
||||
chmod +x /shared/cisco-vpn 2>/dev/null || true
|
||||
echo "[init-rego] Shared scripts made executable"
|
||||
fi
|
||||
|
||||
# ============================================
|
||||
# 4. Start systemd
|
||||
# ============================================
|
||||
echo "[init-rego] Starting systemd..."
|
||||
exec /sbin/init
|
||||
@@ -1,149 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Setup TAP/Bridge networking for QEMU VM
|
||||
# Defaults:
|
||||
# BRIDGE_NAME=br-rego-vpn
|
||||
# TAP_NAME=tap0
|
||||
# BRIDGE_CIDR=100.100.0.1/24
|
||||
# VM_NET_IP=100.100.0.2
|
||||
# VM_SUBNET=100.100.0.0/24
|
||||
|
||||
set -e
|
||||
|
||||
BRIDGE_NAME="${BRIDGE_NAME:-br-rego-vpn}"
|
||||
TAP_NAME="${TAP_NAME:-tap0}"
|
||||
BRIDGE_CIDR="${BRIDGE_CIDR:-100.100.0.1}"
|
||||
VM_NET_IP="${VM_NET_IP:-100.100.0.2}"
|
||||
VM_SUBNET="${VM_SUBNET:-100.100.0.0}"
|
||||
TARGET_IP="${TARGET_IP:-10.35.33.230}"
|
||||
|
||||
# Optional second bridge/tap for a second VM NIC (pure L2 with the container).
|
||||
# This is opt-in: set BRIDGE2_NAME and TAP2_NAME (and optionally BRIDGE2_CIDR).
|
||||
BRIDGE2_NAME="${BRIDGE2_NAME:-}"
|
||||
TAP2_NAME="${TAP2_NAME:-}"
|
||||
BRIDGE2_CIDR="${BRIDGE2_CIDR:-}"
|
||||
BRIDGE2_UPLINK_IF="${BRIDGE2_UPLINK_IF:-}"
|
||||
|
||||
if [[ "$BRIDGE_CIDR" != */* ]]; then
|
||||
BRIDGE_CIDR="$BRIDGE_CIDR/24"
|
||||
fi
|
||||
|
||||
if [[ "$VM_SUBNET" != */* ]]; then
|
||||
VM_SUBNET="$VM_SUBNET/24"
|
||||
fi
|
||||
|
||||
# Pick the outbound interface based on the container's default route.
|
||||
# (In Docker, this is not always eth1 when multiple networks are attached.)
|
||||
WAN_IF="$(ip route show default 0.0.0.0/0 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev"){print $(i+1); exit}}')"
|
||||
if [ -z "${WAN_IF}" ]; then
|
||||
WAN_IF="eth1"
|
||||
fi
|
||||
|
||||
# Ensure bridge exists
|
||||
if ! ip link show "$BRIDGE_NAME" &>/dev/null; then
|
||||
ip link add "$BRIDGE_NAME" type bridge
|
||||
fi
|
||||
|
||||
# Ensure bridge has address and is up
|
||||
ip addr show dev "$BRIDGE_NAME" | grep -qF "$BRIDGE_CIDR" || ip addr add "$BRIDGE_CIDR" dev "$BRIDGE_NAME" 2>/dev/null || true
|
||||
ip link set "$BRIDGE_NAME" up
|
||||
|
||||
# Ensure TAP exists
|
||||
if ! ip link show "$TAP_NAME" &>/dev/null; then
|
||||
ip tuntap add "$TAP_NAME" mode tap
|
||||
fi
|
||||
|
||||
# Ensure TAP is attached and up
|
||||
ip link set "$TAP_NAME" master "$BRIDGE_NAME" 2>/dev/null || true
|
||||
ip link set "$TAP_NAME" up
|
||||
|
||||
# Optional second bridge/tap (no NAT rules are applied here)
|
||||
if [ -n "$BRIDGE2_NAME" ] || [ -n "$TAP2_NAME" ]; then
|
||||
if [ -z "$BRIDGE2_NAME" ] || [ -z "$TAP2_NAME" ]; then
|
||||
echo "[rego-tunnel] WARN: BRIDGE2_NAME and TAP2_NAME must both be set to enable the second bridge"
|
||||
else
|
||||
# Optionally bridge an existing container uplink into BRIDGE2 (e.g. eth0/eth1)
|
||||
# so the VM NIC shares the same L2 network as that uplink.
|
||||
if [ -n "$BRIDGE2_UPLINK_IF" ]; then
|
||||
if ! ip link show "$BRIDGE2_UPLINK_IF" &>/dev/null; then
|
||||
echo "[rego-tunnel] WARN: BRIDGE2_UPLINK_IF=$BRIDGE2_UPLINK_IF not found; skipping uplink bridging"
|
||||
BRIDGE2_UPLINK_IF=""
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! ip link show "$BRIDGE2_NAME" &>/dev/null; then
|
||||
ip link add "$BRIDGE2_NAME" type bridge
|
||||
fi
|
||||
ip link set "$BRIDGE2_NAME" up
|
||||
|
||||
# If an uplink interface is provided, move its IPv4 address to the bridge.
|
||||
# This keeps the container reachable on that network while allowing the VM
|
||||
# to participate in the same L2 broadcast domain.
|
||||
if [ -n "$BRIDGE2_UPLINK_IF" ]; then
|
||||
UPLINK_CIDR="$(ip -o -4 addr show dev "$BRIDGE2_UPLINK_IF" 2>/dev/null | awk '{print $4}' | head -n1)"
|
||||
UPLINK_DEFAULT_GW="$(ip route show default dev "$BRIDGE2_UPLINK_IF" 2>/dev/null | awk '{print $3}' | head -n1)"
|
||||
UPLINK_DEFAULT_METRIC="$(ip route show default dev "$BRIDGE2_UPLINK_IF" 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="metric"){print $(i+1); exit}}')"
|
||||
if [ -z "$BRIDGE2_CIDR" ] && [ -n "$UPLINK_CIDR" ]; then
|
||||
BRIDGE2_CIDR="$UPLINK_CIDR"
|
||||
fi
|
||||
if [ -n "$BRIDGE2_CIDR" ]; then
|
||||
if [[ "$BRIDGE2_CIDR" != */* ]]; then
|
||||
BRIDGE2_CIDR="$BRIDGE2_CIDR/24"
|
||||
fi
|
||||
ip addr show dev "$BRIDGE2_NAME" | grep -qF "$BRIDGE2_CIDR" || ip addr add "$BRIDGE2_CIDR" dev "$BRIDGE2_NAME" 2>/dev/null || true
|
||||
fi
|
||||
# Remove IP from uplink and enslave it into the bridge
|
||||
ip addr flush dev "$BRIDGE2_UPLINK_IF" 2>/dev/null || true
|
||||
ip link set "$BRIDGE2_UPLINK_IF" master "$BRIDGE2_NAME" 2>/dev/null || true
|
||||
ip link set "$BRIDGE2_UPLINK_IF" up 2>/dev/null || true
|
||||
|
||||
# If the uplink carried the container default route, it may have been removed
|
||||
# by the address flush. Restore it on the bridge.
|
||||
if [ -n "$UPLINK_DEFAULT_GW" ]; then
|
||||
if ip route show default 2>/dev/null | grep -q '^default '; then
|
||||
ip route replace default via "$UPLINK_DEFAULT_GW" dev "$BRIDGE2_NAME" ${UPLINK_DEFAULT_METRIC:+metric "$UPLINK_DEFAULT_METRIC"} 2>/dev/null || true
|
||||
else
|
||||
ip route add default via "$UPLINK_DEFAULT_GW" dev "$BRIDGE2_NAME" ${UPLINK_DEFAULT_METRIC:+metric "$UPLINK_DEFAULT_METRIC"} 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! ip link show "$TAP2_NAME" &>/dev/null; then
|
||||
ip tuntap add "$TAP2_NAME" mode tap
|
||||
fi
|
||||
ip link set "$TAP2_NAME" master "$BRIDGE2_NAME" 2>/dev/null || true
|
||||
ip link set "$TAP2_NAME" up
|
||||
echo "[rego-tunnel] Second bridge enabled: $BRIDGE2_NAME (tap $TAP2_NAME)${BRIDGE2_UPLINK_IF:+ uplink $BRIDGE2_UPLINK_IF}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Enable IP forwarding
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
|
||||
# Setup NAT/masquerade for outbound traffic from VM
|
||||
iptables -t nat -C POSTROUTING -s "$VM_SUBNET" -o "$WAN_IF" -j MASQUERADE 2>/dev/null || \
|
||||
iptables -t nat -A POSTROUTING -s "$VM_SUBNET" -o "$WAN_IF" -j MASQUERADE
|
||||
|
||||
# Ensure forwarding between the VM bridge and outbound interface
|
||||
iptables -C FORWARD -i "$BRIDGE_NAME" -o "$WAN_IF" -j ACCEPT 2>/dev/null || \
|
||||
iptables -A FORWARD -i "$BRIDGE_NAME" -o "$WAN_IF" -j ACCEPT
|
||||
iptables -C FORWARD -i "$WAN_IF" -o "$BRIDGE_NAME" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
|
||||
iptables -A FORWARD -i "$WAN_IF" -o "$BRIDGE_NAME" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
|
||||
# Forward traffic destined for VPN networks to VM (TARGET_IP defaults to IBM i)
|
||||
# The VM will route this through its VPN tunnel
|
||||
iptables -C FORWARD -d "$TARGET_IP" -j ACCEPT 2>/dev/null || iptables -A FORWARD -d "$TARGET_IP" -j ACCEPT
|
||||
iptables -C FORWARD -s "$TARGET_IP" -j ACCEPT 2>/dev/null || iptables -A FORWARD -s "$TARGET_IP" -j ACCEPT
|
||||
|
||||
# Route to TARGET_IP through VM
|
||||
ip route add "$TARGET_IP" via "$VM_NET_IP" 2>/dev/null || true
|
||||
|
||||
echo "Network setup complete"
|
||||
echo "Bridge: $BRIDGE_NAME = $BRIDGE_CIDR"
|
||||
echo "TAP: $TAP_NAME attached to $BRIDGE_NAME"
|
||||
echo "Route: $TARGET_IP via $VM_NET_IP (VM)"
|
||||
echo "Outbound interface: ${WAN_IF}"
|
||||
|
||||
if [ -n "$BRIDGE2_NAME" ] && [ -n "$TAP2_NAME" ]; then
|
||||
echo "Bridge2: $BRIDGE2_NAME${BRIDGE2_CIDR:+ = $BRIDGE2_CIDR}"
|
||||
echo "TAP2: $TAP2_NAME attached to $BRIDGE2_NAME"
|
||||
fi
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
BRIDGE_NAME="${BRIDGE_NAME:-br-rego-vpn}"
|
||||
BRIDGE_CIDR="${BRIDGE_CIDR:-100.100.0.1}"
|
||||
VM_NET_IP="${VM_NET_IP:-100.100.0.2}"
|
||||
VM_MAC="${VM_MAC:-52:54:00:12:34:56}"
|
||||
|
||||
LEASE_TIME="${LEASE_TIME:-12h}"
|
||||
DNS_SERVERS="${DNS_SERVERS:-1.1.1.1,8.8.8.8}"
|
||||
|
||||
if [[ "$BRIDGE_CIDR" != */* ]]; then
|
||||
BRIDGE_CIDR="$BRIDGE_CIDR/24"
|
||||
fi
|
||||
|
||||
GATEWAY_IP="${BRIDGE_CIDR%%/*}"
|
||||
|
||||
mkdir -p /etc/dnsmasq.d
|
||||
|
||||
cat > /etc/dnsmasq.d/rego.conf <<EOF
|
||||
interface=${BRIDGE_NAME}
|
||||
bind-interfaces
|
||||
except-interface=lo
|
||||
|
||||
dhcp-authoritative
|
||||
log-dhcp
|
||||
|
||||
dhcp-range=${VM_NET_IP},${VM_NET_IP},${LEASE_TIME}
|
||||
dhcp-option=option:router,${GATEWAY_IP}
|
||||
dhcp-option=option:dns-server,${DNS_SERVERS}
|
||||
|
||||
# Static lease for the VM
|
||||
# (VM must use DHCP for this to take effect)
|
||||
dhcp-host=${VM_MAC},${VM_NET_IP}
|
||||
EOF
|
||||
|
||||
echo "[rego-tunnel] dnsmasq on ${BRIDGE_NAME} gateway=${GATEWAY_IP} lease ${VM_MAC} -> ${VM_NET_IP}"
|
||||
exec dnsmasq --no-daemon --conf-file=/etc/dnsmasq.d/rego.conf
|
||||
@@ -1,116 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# If provided, extract ssh.zip to /root/.ssh (not baked into the image)
|
||||
SSH_ZIP_PATH="/shared/ssh.zip"
|
||||
SSH_ZIP_DEST="/root/.ssh"
|
||||
|
||||
if [ -f "$SSH_ZIP_PATH" ]; then
|
||||
mkdir -p "$SSH_ZIP_DEST"
|
||||
chmod 700 "$SSH_ZIP_DEST"
|
||||
|
||||
echo "[rego-tunnel] Extracting $SSH_ZIP_PATH -> $SSH_ZIP_DEST"
|
||||
# Exclude editor swap/backup files; overwrite existing.
|
||||
7z x -y -aoa -o"$SSH_ZIP_DEST" "$SSH_ZIP_PATH" \
|
||||
-x!*.swp -x!*.swo -x!*.swx -x!*~ -x!.DS_Store >/dev/null
|
||||
|
||||
find "$SSH_ZIP_DEST" -type d -exec chmod 700 {} \;
|
||||
find "$SSH_ZIP_DEST" -type f -exec chmod 600 {} \;
|
||||
else
|
||||
echo "[rego-tunnel] No $SSH_ZIP_PATH found; skipping SSH zip extraction"
|
||||
fi
|
||||
|
||||
# Wait for network setup
|
||||
sleep 2
|
||||
|
||||
TAP_NAME="${TAP_NAME:-tap0}"
|
||||
|
||||
# Optional: provide a dedicated 9p export for host app-data (bind-mounted into the container at /shared/app-data)
|
||||
TSCLIENT_PATH="/hostshare"
|
||||
TSCLIENT_TAG="${TSCLIENT_TAG:-TSCLIENT}"
|
||||
SHARED_TAG="${SHARED_TAG:-shared}"
|
||||
|
||||
# Ensure the VM auto-mounts the 9p shares without manual steps.
|
||||
# This edits the QCOW2 from the outside (idempotent) before QEMU boots.
|
||||
AUTO_MOUNT_9P="${AUTO_MOUNT_9P:-1}"
|
||||
if [ "$AUTO_MOUNT_9P" = "1" ]; then
|
||||
QCOW2_PATH="/vm/linux-vm.qcow2"
|
||||
NBD_DEV="${NBD_DEV:-/dev/nbd0}"
|
||||
VMROOT_MNT="/mnt/vmroot"
|
||||
|
||||
if [ -e "$QCOW2_PATH" ] && [ -e "$NBD_DEV" ]; then
|
||||
echo "[rego-tunnel] Ensuring guest fstab mounts 9p tags ($SHARED_TAG, $TSCLIENT_TAG)"
|
||||
modprobe nbd max_part=16 >/dev/null 2>&1 || true
|
||||
qemu-nbd --disconnect "$NBD_DEV" >/dev/null 2>&1 || true
|
||||
qemu-nbd --connect "$NBD_DEV" "$QCOW2_PATH"
|
||||
sleep 1
|
||||
|
||||
# In containers, the kernel may create sysfs partition entries but not
|
||||
# auto-create the corresponding /dev/nbd0p* nodes. Create them if missing.
|
||||
base_dev="$(basename "$NBD_DEV")"
|
||||
for sysfs_dev in /sys/class/block/${base_dev}p*; do
|
||||
[ -e "$sysfs_dev" ] || continue
|
||||
part_name="$(basename "$sysfs_dev")"
|
||||
devnode="/dev/$part_name"
|
||||
[ -e "$devnode" ] && continue
|
||||
if [ -r "$sysfs_dev/dev" ]; then
|
||||
IFS=: read -r major minor < "$sysfs_dev/dev" || true
|
||||
if [ -n "${major:-}" ] && [ -n "${minor:-}" ]; then
|
||||
mknod "$devnode" b "$major" "$minor" 2>/dev/null || true
|
||||
chmod 660 "$devnode" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
mkdir -p "$VMROOT_MNT"
|
||||
ROOT_PART=""
|
||||
for part in "${NBD_DEV}"p*; do
|
||||
[ -e "$part" ] || continue
|
||||
# Try mount and detect a Linux root by presence of /etc/fstab and /etc/os-release
|
||||
if mount "$part" "$VMROOT_MNT" >/dev/null 2>&1; then
|
||||
if [ -d "$VMROOT_MNT/etc" ] && { [ -f "$VMROOT_MNT/etc/os-release" ] || [ -f "$VMROOT_MNT/usr/lib/os-release" ] || [ -f "$VMROOT_MNT/usr/share/os-release" ]; }; then
|
||||
ROOT_PART="$part"
|
||||
break
|
||||
fi
|
||||
umount "$VMROOT_MNT" >/dev/null 2>&1 || true
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$ROOT_PART" ]; then
|
||||
# already mounted from loop above
|
||||
mkdir -p "$VMROOT_MNT/shared" "$VMROOT_MNT/hostshare"
|
||||
|
||||
FSTAB="$VMROOT_MNT/etc/fstab"
|
||||
# Add entries only if missing
|
||||
grep -qE "^[[:space:]]*${SHARED_TAG}[[:space:]]+" "$FSTAB" || echo "${SHARED_TAG} /shared 9p trans=virtio,version=9p2000.L,msize=262144,_netdev,nofail,x-systemd.automount 0 0" >> "$FSTAB"
|
||||
grep -qE "^[[:space:]]*${TSCLIENT_TAG}[[:space:]]+" "$FSTAB" || echo "${TSCLIENT_TAG} /hostshare 9p trans=virtio,version=9p2000.L,msize=262144,_netdev,nofail,x-systemd.automount 0 0" >> "$FSTAB"
|
||||
|
||||
umount "$VMROOT_MNT" >/dev/null 2>&1 || true
|
||||
else
|
||||
echo "[rego-tunnel] WARN: could not locate guest root partition; skipping auto-mount setup"
|
||||
lsblk -fp "$NBD_DEV" 2>/dev/null || true
|
||||
blkid "$NBD_DEV"* 2>/dev/null || true
|
||||
fi
|
||||
|
||||
qemu-nbd --disconnect "$NBD_DEV" >/dev/null 2>&1 || true
|
||||
else
|
||||
echo "[rego-tunnel] WARN: missing $QCOW2_PATH or $NBD_DEV; skipping auto-mount setup"
|
||||
fi
|
||||
fi
|
||||
|
||||
exec qemu-system-x86_64 \
|
||||
-enable-kvm \
|
||||
-cpu host \
|
||||
-m ${VM_RAM:-8G} \
|
||||
-smp ${VM_CPUS:-4} \
|
||||
-hda /vm/linux-vm.qcow2 \
|
||||
-fsdev local,id=fsdev0,path=/shared,security_model=none,multidevs=remap \
|
||||
-device virtio-9p-pci,fsdev=fsdev0,mount_tag="$SHARED_TAG" \
|
||||
-fsdev local,id=fsdev1,path="$TSCLIENT_PATH",security_model=none,multidevs=remap \
|
||||
-device virtio-9p-pci,fsdev=fsdev1,mount_tag="$TSCLIENT_TAG" \
|
||||
-netdev tap,id=net0,ifname="$TAP_NAME",script=no,downscript=no \
|
||||
-device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:56 \
|
||||
-vnc :0 \
|
||||
-vga virtio \
|
||||
-usb \
|
||||
-device usb-tablet
|
||||
@@ -1,46 +0,0 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
logfile=/var/log/supervisord.log
|
||||
|
||||
[program:network-setup]
|
||||
command=/usr/local/bin/setup-network.sh
|
||||
autostart=true
|
||||
autorestart=false
|
||||
startsecs=0
|
||||
priority=1
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:dnsmasq]
|
||||
command=/usr/local/bin/start-dnsmasq.sh
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=5
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:sshd]
|
||||
command=/usr/sbin/sshd -D
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=10
|
||||
|
||||
[program:qemu]
|
||||
command=/usr/local/bin/start-vm.sh
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=20
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:novnc]
|
||||
command=/usr/bin/websockify --web /usr/share/novnc 8006 localhost:5900
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=30
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/bin/bash
|
||||
# VNC xstartup - launches terminal with cisco-vpn script
|
||||
# This runs inside the VNC session
|
||||
|
||||
unset SESSION_MANAGER
|
||||
unset DBUS_SESSION_BUS_ADDRESS
|
||||
|
||||
export XDG_RUNTIME_DIR=/tmp/runtime-root
|
||||
mkdir -p $XDG_RUNTIME_DIR
|
||||
chmod 700 $XDG_RUNTIME_DIR
|
||||
|
||||
# GPU/WebKit workarounds for Cisco UI
|
||||
export GDK_BACKEND=x11
|
||||
export WEBKIT_DISABLE_DMABUF_RENDERER=1
|
||||
|
||||
# Start dbus session
|
||||
[ -x /usr/bin/dbus-launch ] && eval $(dbus-launch --sh-syntax --exit-with-session)
|
||||
|
||||
# Start window manager
|
||||
openbox &
|
||||
sleep 2
|
||||
|
||||
# Make sure the script is executable
|
||||
chmod +x /shared/cisco-vpn 2>/dev/null || true
|
||||
|
||||
# Start xterm with the cisco-vpn script
|
||||
# The script handles everything: vpnagentd, vpnui, auto-login, forwarding
|
||||
xterm -fa 'Monospace' -fs 11 -bg black -fg white -geometry 130x45+10+10 \
|
||||
-title "Rego VPN Terminal" \
|
||||
-e "bash -c '/shared/cisco-vpn; exec bash'" &
|
||||
|
||||
wait
|
||||
@@ -1,31 +0,0 @@
|
||||
# Install Node.js on Windows
|
||||
# Run as Administrator in PowerShell
|
||||
|
||||
$Username = if ($env:REGO_USER) { $env:REGO_USER } else { $env:USERNAME }
|
||||
$nodeVersion = "22.9.0"
|
||||
$nodeUrl = "https://nodejs.org/dist/v$nodeVersion/node-v$nodeVersion-x64.msi"
|
||||
$installerPath = "$env:TEMP\node-installer.msi"
|
||||
|
||||
Write-Host "Downloading Node.js v$nodeVersion..." -ForegroundColor Cyan
|
||||
Invoke-WebRequest -Uri $nodeUrl -OutFile $installerPath
|
||||
|
||||
Write-Host "Installing Node.js..." -ForegroundColor Cyan
|
||||
Start-Process msiexec.exe -Wait -ArgumentList "/i `"$installerPath`" /quiet /norestart"
|
||||
|
||||
# Refresh PATH
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
||||
|
||||
Write-Host "Verifying installation..." -ForegroundColor Cyan
|
||||
node --version
|
||||
npm --version
|
||||
|
||||
Write-Host "Node.js installed successfully!" -ForegroundColor Green
|
||||
|
||||
# Cleanup
|
||||
Remove-Item $installerPath -Force
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Next steps:" -ForegroundColor Yellow
|
||||
Write-Host "1. Copy vpn-login.js, socks5.js, vpn.bat to C:\Users\$Username\vpn_scripts\"
|
||||
Write-Host "2. Open CMD in C:\Users\$Username\vpn_scripts\ and run: npm install ws otplib"
|
||||
Write-Host "3. Add vpn.bat shortcut to shell:startup folder"
|
||||
@@ -1,45 +0,0 @@
|
||||
# Setup OpenSSH Server and Auto-Login
|
||||
# Run as Administrator in PowerShell
|
||||
|
||||
$Username = if ($env:REGO_USER) { $env:REGO_USER } else { $env:USERNAME }
|
||||
$Password = if ($env:REGO_PASS) { $env:REGO_PASS } else { "admin" }
|
||||
|
||||
Write-Host "=== Setting up OpenSSH Server ===" -ForegroundColor Cyan
|
||||
Write-Host "Using username: $Username" -ForegroundColor Yellow
|
||||
|
||||
# Install OpenSSH Server
|
||||
$sshCapability = Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Server*'
|
||||
if ($sshCapability.State -ne 'Installed') {
|
||||
Write-Host "Installing OpenSSH Server..." -ForegroundColor Yellow
|
||||
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
|
||||
} else {
|
||||
Write-Host "OpenSSH Server already installed" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Start and enable SSH service
|
||||
Write-Host "Starting SSH service..." -ForegroundColor Yellow
|
||||
Start-Service sshd
|
||||
Set-Service -Name sshd -StartupType 'Automatic'
|
||||
|
||||
# Configure firewall
|
||||
$fwRule = Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue
|
||||
if (-not $fwRule) {
|
||||
Write-Host "Adding firewall rule..." -ForegroundColor Yellow
|
||||
New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
|
||||
}
|
||||
|
||||
Write-Host "OpenSSH Server configured!" -ForegroundColor Green
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=== Setting up Auto-Login ===" -ForegroundColor Cyan
|
||||
|
||||
$RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
|
||||
Set-ItemProperty -Path $RegPath -Name "AutoAdminLogon" -Value "1"
|
||||
Set-ItemProperty -Path $RegPath -Name "DefaultUserName" -Value $Username
|
||||
Set-ItemProperty -Path $RegPath -Name "DefaultPassword" -Value $Password
|
||||
Remove-ItemProperty -Path $RegPath -Name "DefaultDomainName" -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "Auto-login configured for '$Username'!" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "Setup complete! SSH is now available and auto-login is enabled." -ForegroundColor Green
|
||||
Write-Host "Reboot to test auto-login." -ForegroundColor Yellow
|
||||
@@ -1,34 +0,0 @@
|
||||
# Setup SSH Keys
|
||||
# Run as Administrator in PowerShell
|
||||
|
||||
$Username = if ($env:REGO_USER) { $env:REGO_USER } else { $env:USERNAME }
|
||||
$PublicKey = if ($env:REGO_SSH_PUBKEY) { $env:REGO_SSH_PUBKEY } else { "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGHUQnw0WfeFRQx76UlImXXhu3xeOH41PmDRid8pWK1D default-key" }
|
||||
|
||||
Write-Host "=== Setting up SSH Keys ===" -ForegroundColor Cyan
|
||||
Write-Host "Using username: $Username" -ForegroundColor Yellow
|
||||
|
||||
# User authorized_keys
|
||||
$userSshDir = "C:\Users\$Username\.ssh"
|
||||
$userAuthKeys = "$userSshDir\authorized_keys"
|
||||
|
||||
Write-Host "Creating user .ssh directory..." -ForegroundColor Yellow
|
||||
New-Item -ItemType Directory -Path $userSshDir -Force | Out-Null
|
||||
|
||||
Write-Host "Adding key to user authorized_keys..." -ForegroundColor Yellow
|
||||
Add-Content -Path $userAuthKeys -Value $PublicKey -Force
|
||||
|
||||
# Fix permissions for user file
|
||||
icacls $userAuthKeys /inheritance:r /grant "${Username}:F" /grant "SYSTEM:F"
|
||||
|
||||
# Administrator authorized_keys (for admin users)
|
||||
$adminAuthKeys = "C:\ProgramData\ssh\administrators_authorized_keys"
|
||||
|
||||
Write-Host "Adding key to administrators_authorized_keys..." -ForegroundColor Yellow
|
||||
Add-Content -Path $adminAuthKeys -Value $PublicKey -Force
|
||||
|
||||
# Fix permissions for admin file (required by OpenSSH)
|
||||
icacls $adminAuthKeys /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "SSH keys configured!" -ForegroundColor Green
|
||||
Write-Host "You can now SSH in with the configured key." -ForegroundColor Yellow
|
||||
@@ -1,188 +0,0 @@
|
||||
# Rego VPN Automation - Technical Setup Guide
|
||||
|
||||
## Overview
|
||||
|
||||
Cisco Secure Client VPN running in Windows VM (dockurr/windows) inside Docker container, with SOCKS5 proxy for transparent routing to IBM i systems.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Clients → Host (iptables/redsocks) → Container (socat) → Windows VM (SOCKS5) → VPN → 10.35.33.x
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### 1. Windows VM (inside container)
|
||||
- **Container**: `rego-tunnel_runtipi-rego-tunnel-1`
|
||||
- **Windows VM IP**: `172.30.0.16` or `172.30.0.17` (internal to container)
|
||||
- **VPN**: Cisco Secure Client with SAML auth (email + password + TOTP)
|
||||
- **Files on Windows** (`C:\Users\alexz\vpn_scripts`):
|
||||
- `vpn.bat` - Startup batch file
|
||||
- `vpn-login.js` - Node.js script that automates SAML login via Chrome DevTools Protocol
|
||||
- `socks5.js` - Simple SOCKS5 proxy server
|
||||
- `node_modules/` - ws, otplib packages
|
||||
|
||||
### 2. Container
|
||||
- **External IPs**: `10.128.16.2` or similar
|
||||
- **Internal bridge**: `172.30.0.1/24` (Windows VM at .16 or .17)
|
||||
- **socat**: Forwards port 1080 from container to Windows VM SOCKS5
|
||||
- **start.sh**: Mounted at `/run/start.sh` - sets up iptables DNAT rules
|
||||
|
||||
### 3. Host
|
||||
- **redsocks**: Transparent SOCKS5 redirector (optional)
|
||||
- **iptables**: Redirects traffic to VPN network through container
|
||||
|
||||
## VPN Credentials
|
||||
|
||||
Located in `vpn-login.js`:
|
||||
```javascript
|
||||
const CONFIG = {
|
||||
email: "c-azaw@regoproducts.com",
|
||||
password: "Fuckyou4suhail",
|
||||
totpSecret: "RZQTQSKDWKHZ6ZYR",
|
||||
devtoolsPort: 9222,
|
||||
vpnTestIp: "10.35.33.230"
|
||||
};
|
||||
```
|
||||
|
||||
## Windows Setup Steps
|
||||
|
||||
### 1. Install Node.js
|
||||
Run PowerShell as Administrator:
|
||||
```powershell
|
||||
# Option A: Run the install script
|
||||
.\install-nodejs.ps1
|
||||
|
||||
# Option B: Manual download from https://nodejs.org/
|
||||
```
|
||||
|
||||
### 2. Install Cisco Secure Client
|
||||
- Download from company VPN portal or Cisco
|
||||
- Install with default options
|
||||
- Path: `C:\Program Files (x86)\Cisco\Cisco Secure Client\`
|
||||
|
||||
### 3. Setup VPN Scripts
|
||||
```cmd
|
||||
mkdir C:\Users\alexz\vpn_scripts
|
||||
copy \\TSCLIENT\shared\vpn-scripts\*.js C:\Users\alexz\vpn_scripts\
|
||||
copy \\TSCLIENT\shared\vpn-scripts\vpn.bat C:\Users\alexz\vpn_scripts\
|
||||
|
||||
cd C:\Users\alexz\vpn_scripts
|
||||
npm install ws otplib
|
||||
```
|
||||
|
||||
### 4. Add to Windows Startup
|
||||
```cmd
|
||||
# Create shortcut to vpn.bat in:
|
||||
shell:startup
|
||||
# Or: C:\Users\alexz\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
|
||||
```
|
||||
|
||||
### 5. Enable Remote Debugging for Cisco UI
|
||||
The vpn-login.js script sets this environment variable before launching Cisco:
|
||||
```
|
||||
WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=9222 --remote-debugging-address=0.0.0.0 --remote-allow-origins=*
|
||||
```
|
||||
|
||||
## Container Configuration
|
||||
|
||||
### docker-compose.yml (user-config)
|
||||
```yaml
|
||||
services:
|
||||
rego-tunnel:
|
||||
environment:
|
||||
USER: alexz
|
||||
PASS: Az@83278327$$@@
|
||||
VERSION: win10
|
||||
entrypoint: ["/bin/bash", "-c", "source /run/start.sh; exec /usr/bin/tini -s /run/entry.sh"]
|
||||
```
|
||||
|
||||
### start.sh (Container Startup Script)
|
||||
Located at: `/etc/runtipi/user-config/runtipi/rego-tunnel/scripts/start.sh`
|
||||
|
||||
Sets up:
|
||||
- iptables MASQUERADE for docker bridge
|
||||
- Route to IBM i network via Windows VM
|
||||
- DNAT rules for port forwarding (SSH, IBM i ports)
|
||||
|
||||
## Key Ports
|
||||
|
||||
| Port | Service |
|
||||
|------|---------|
|
||||
| 22 | SSH |
|
||||
| 23 | Telnet (IBM i) |
|
||||
| 446, 448, 449 | IBM i services |
|
||||
| 1080 | SOCKS5 proxy |
|
||||
| 8006 | noVNC web console |
|
||||
| 8470-8476 | IBM i data ports |
|
||||
| 9222 | Chrome DevTools (for automation) |
|
||||
|
||||
## Manual Commands
|
||||
|
||||
### Start VPN from host:
|
||||
```bash
|
||||
docker exec rego-tunnel_runtipi-rego-tunnel-1 ssh docker@172.30.0.16 'C:\Users\alexz\vpn_scripts\vpn.bat'
|
||||
```
|
||||
|
||||
### Start socat in container:
|
||||
```bash
|
||||
docker exec -d rego-tunnel_runtipi-rego-tunnel-1 socat TCP-LISTEN:1080,fork,reuseaddr TCP:172.30.0.16:1080
|
||||
```
|
||||
|
||||
### Test SOCKS5 connectivity:
|
||||
```bash
|
||||
nc -zv 10.128.16.2 1080
|
||||
```
|
||||
|
||||
### Check VPN status in Windows:
|
||||
```cmd
|
||||
ipconfig | findstr 10\.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### VPN not connecting
|
||||
1. Check time sync: `w32tm /resync /force`
|
||||
2. Verify Cisco agent: `net start "Cisco Secure Client Agent"`
|
||||
3. Check DevTools: `http://172.30.0.16:9222/json`
|
||||
|
||||
### SOCKS5 not working
|
||||
1. Verify VPN connected first (ping 10.35.33.230)
|
||||
2. Check socks5.js running: `tasklist | findstr node`
|
||||
3. Test locally: `nc -zv 127.0.0.1 1080`
|
||||
|
||||
### Container issues
|
||||
1. Check logs: `docker logs rego-tunnel_runtipi-rego-tunnel-1`
|
||||
2. Verify start.sh: `docker exec rego-tunnel_runtipi-rego-tunnel-1 cat /run/start.sh`
|
||||
3. Check Windows VM IP: `docker exec rego-tunnel_runtipi-rego-tunnel-1 cat /run/qemu.pid`
|
||||
|
||||
## File Locations
|
||||
|
||||
### Host
|
||||
- `/etc/runtipi/user-config/runtipi/rego-tunnel/docker-compose.yml` - User overrides
|
||||
- `/etc/runtipi/user-config/runtipi/rego-tunnel/scripts/start.sh` - Container startup
|
||||
- `/etc/runtipi/repos/runtipi/apps/rego-tunnel/docker-compose.yml` - Base config
|
||||
- `/etc/runtipi/app-data/runtipi/rego-tunnel/data/storage/` - Windows disk image
|
||||
- `/etc/runtipi/app-data/runtipi/rego-tunnel/data/shared/` - Shared folder with Windows
|
||||
|
||||
### Windows VM
|
||||
- `C:\Users\alexz\vpn_scripts\vpn-login.js` - Main automation script
|
||||
- `C:\Users\alexz\vpn_scripts\socks5.js` - SOCKS5 proxy
|
||||
- `C:\Users\alexz\vpn_scripts\vpn.bat` - Startup batch file
|
||||
- `C:\Program Files (x86)\Cisco\Cisco Secure Client\` - Cisco installation
|
||||
|
||||
## Watchdog Mode
|
||||
|
||||
The vpn-login.js script includes a watchdog that:
|
||||
- Monitors VPN connectivity every 2 minutes
|
||||
- Auto-reconnects after 2 consecutive failures
|
||||
- Restarts SOCKS5 proxy after reconnection
|
||||
- Logs memory usage every hour
|
||||
|
||||
## Notes
|
||||
|
||||
- Windows VM takes ~2-3 minutes to boot
|
||||
- VPN login takes ~30 seconds
|
||||
- TOTP requires accurate system time (script syncs automatically)
|
||||
- The container uses VERSION=win10 for dockurr/windows compatibility
|
||||
- noVNC password: `Az@83278327$@@`
|
||||
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACBh1EJ8NFn3hUUMe+lJSJl14bt8Xjh+NT5g0YnfKVitQwAAAJhfESWEXxEl
|
||||
hAAAAAtzc2gtZWQyNTUxOQAAACBh1EJ8NFn3hUUMe+lJSJl14bt8Xjh+NT5g0YnfKVitQw
|
||||
AAAEDgYZN7HwPbKY++p612bnhGC10P3GUHQdJlprPEFbODgWHUQnw0WfeFRQx76UlImXXh
|
||||
u3xeOH41PmDRid8pWK1DAAAAEWFsZXh6QEFaYXdQQy1QMTZTAQIDBA==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
@@ -1,35 +0,0 @@
|
||||
@echo off
|
||||
echo === Rego VPN Windows Setup ===
|
||||
echo.
|
||||
|
||||
echo [1/7] Installing Node.js...
|
||||
powershell -ExecutionPolicy Bypass -File "%~dp001_install-nodejs.ps1"
|
||||
|
||||
echo [2/7] Setting up OpenSSH and Auto-Login...
|
||||
powershell -ExecutionPolicy Bypass -File "%~dp002_setup-autologin-sshd.ps1"
|
||||
|
||||
echo [3/7] Configuring SSH Keys...
|
||||
powershell -ExecutionPolicy Bypass -File "%~dp003_setup-ssh-keys.ps1"
|
||||
|
||||
echo [4/7] Creating vpn_scripts folder...
|
||||
mkdir "C:\Users\%USERNAME%\vpn_scripts" 2>nul
|
||||
|
||||
echo [5/7] Copying runtime scripts...
|
||||
copy "%~dp0vpn-login.js" "C:\Users\%USERNAME%\vpn_scripts\"
|
||||
copy "%~dp0socks5.js" "C:\Users\%USERNAME%\vpn_scripts\"
|
||||
copy "%~dp0vpn.bat" "C:\Users\%USERNAME%\vpn_scripts\"
|
||||
|
||||
echo [6/7] Installing npm dependencies...
|
||||
cd /d "C:\Users\%USERNAME%\vpn_scripts"
|
||||
call npm install ws otplib
|
||||
|
||||
echo [7/7] Adding to startup (Run as Admin)...
|
||||
copy "%~dp0vpn-startup.lnk" "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\vpn.lnk"
|
||||
|
||||
echo.
|
||||
echo === Setup Complete ===
|
||||
echo.
|
||||
echo Manual step remaining:
|
||||
echo - Install Anyconnect (run anyconnect-win-*.exe from this folder)
|
||||
echo.
|
||||
pause
|
||||
@@ -1,69 +0,0 @@
|
||||
const net = require('net');
|
||||
|
||||
const PORT = 1080;
|
||||
const HOST = '0.0.0.0';
|
||||
|
||||
const server = net.createServer((client) => {
|
||||
client.once('data', (data) => {
|
||||
// SOCKS5 handshake
|
||||
if (data[0] !== 0x05) {
|
||||
client.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// No auth required
|
||||
client.write(Buffer.from([0x05, 0x00]));
|
||||
|
||||
client.once('data', (data) => {
|
||||
if (data[0] !== 0x05 || data[1] !== 0x01) {
|
||||
client.write(Buffer.from([0x05, 0x07, 0x00, 0x01, 0, 0, 0, 0, 0, 0]));
|
||||
client.end();
|
||||
return;
|
||||
}
|
||||
|
||||
let host, port;
|
||||
const atyp = data[3];
|
||||
|
||||
if (atyp === 0x01) {
|
||||
// IPv4
|
||||
host = `${data[4]}.${data[5]}.${data[6]}.${data[7]}`;
|
||||
port = data.readUInt16BE(8);
|
||||
} else if (atyp === 0x03) {
|
||||
// Domain
|
||||
const len = data[4];
|
||||
host = data.slice(5, 5 + len).toString();
|
||||
port = data.readUInt16BE(5 + len);
|
||||
} else if (atyp === 0x04) {
|
||||
// IPv6
|
||||
host = '';
|
||||
for (let i = 0; i < 16; i += 2) {
|
||||
host += data.slice(4 + i, 6 + i).toString('hex');
|
||||
if (i < 14) host += ':';
|
||||
}
|
||||
port = data.readUInt16BE(20);
|
||||
} else {
|
||||
client.write(Buffer.from([0x05, 0x08, 0x00, 0x01, 0, 0, 0, 0, 0, 0]));
|
||||
client.end();
|
||||
return;
|
||||
}
|
||||
|
||||
const remote = net.createConnection(port, host, () => {
|
||||
const response = Buffer.from([0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0]);
|
||||
client.write(response);
|
||||
client.pipe(remote);
|
||||
remote.pipe(client);
|
||||
});
|
||||
|
||||
remote.on('error', () => {
|
||||
client.write(Buffer.from([0x05, 0x05, 0x00, 0x01, 0, 0, 0, 0, 0, 0]));
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
client.on('error', () => {});
|
||||
});
|
||||
|
||||
server.listen(PORT, HOST, () => {
|
||||
console.log(`SOCKS5 proxy running on ${HOST}:${PORT}`);
|
||||
});
|
||||
@@ -1,117 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Startup hook - runs after container starts
|
||||
# Dynamically detects Windows VM IP and sets up networking
|
||||
|
||||
# Install required packages (not persistent across restarts)
|
||||
echo "[rego-tunnel] Installing required packages..."
|
||||
apt-get update -qq && apt-get install -y -qq socat openssh-client netcat-openbsd >/dev/null 2>&1 || true
|
||||
|
||||
# Setup SSH key for accessing Windows VM
|
||||
echo "[rego-tunnel] Setting up SSH key..."
|
||||
mkdir -p /root/.ssh
|
||||
cp /vpn_scripts/id_ed25519-lenovo /root/.ssh/ 2>/dev/null || true
|
||||
chmod 600 /root/.ssh/id_ed25519-lenovo 2>/dev/null || true
|
||||
|
||||
get_windows_ip() {
|
||||
# Use VM_NET_IP env var if set, otherwise detect from DHCP leases
|
||||
if [[ -n "${VM_NET_IP:-}" ]]; then
|
||||
echo "$VM_NET_IP"
|
||||
return
|
||||
fi
|
||||
awk '/Windows/ {print $3}' /var/lib/misc/dnsmasq.leases 2>/dev/null | head -1
|
||||
}
|
||||
|
||||
get_container_ip() {
|
||||
# Get container's external IP (172.31.0.10) - exclude docker bridge gateway (.1)
|
||||
ip -4 addr 2>/dev/null | grep -oE '172\.31\.0\.[0-9]+' | grep -v '\.1$' | head -1
|
||||
}
|
||||
|
||||
(
|
||||
# Wait for Windows VM to boot and get IP
|
||||
echo "[rego-tunnel] Waiting for Windows VM..."
|
||||
WINDOWS_IP=""
|
||||
for i in {1..120}; do
|
||||
WINDOWS_IP=$(get_windows_ip)
|
||||
if [[ -n "$WINDOWS_IP" ]]; then
|
||||
echo "[rego-tunnel] Windows VM IP: $WINDOWS_IP"
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [[ -z "$WINDOWS_IP" ]]; then
|
||||
echo "[rego-tunnel] ERROR: Could not detect Windows VM IP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Wait for SSH to be available on Windows
|
||||
echo "[rego-tunnel] Waiting for SSH on Windows..."
|
||||
for i in {1..60}; do
|
||||
if nc -z "$WINDOWS_IP" 22 2>/dev/null; then
|
||||
echo "[rego-tunnel] SSH is available"
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
CONTAINER_IP=$(get_container_ip)
|
||||
echo "[rego-tunnel] Container IP: $CONTAINER_IP"
|
||||
|
||||
# Add MASQUERADE for docker bridge
|
||||
iptables -t nat -C POSTROUTING -o docker -j MASQUERADE 2>/dev/null || \
|
||||
iptables -t nat -A POSTROUTING -o docker -j MASQUERADE
|
||||
|
||||
# Allow forwarding to Windows VM
|
||||
iptables -C FORWARD -d "$WINDOWS_IP" -j ACCEPT 2>/dev/null || \
|
||||
iptables -A FORWARD -d "$WINDOWS_IP" -j ACCEPT
|
||||
|
||||
# Forward port 2222 to VM's SSH (2222) for VM access
|
||||
pkill -f "socat.*:2222" 2>/dev/null || true
|
||||
socat TCP-LISTEN:2222,fork,reuseaddr TCP:"$WINDOWS_IP":2222 &
|
||||
echo "[rego-tunnel] SSH to VM available on port 2222"
|
||||
|
||||
# Add DNAT rules for port forwarding
|
||||
add_dnat() {
|
||||
local port=$1
|
||||
iptables -t nat -C PREROUTING -d "$CONTAINER_IP" -p tcp --dport "$port" -j DNAT --to-destination "$WINDOWS_IP:$port" 2>/dev/null || \
|
||||
iptables -t nat -A PREROUTING -d "$CONTAINER_IP" -p tcp --dport "$port" -j DNAT --to-destination "$WINDOWS_IP:$port"
|
||||
}
|
||||
|
||||
# IBM i standard ports (via VM portproxy)
|
||||
add_dnat 22
|
||||
add_dnat 23
|
||||
add_dnat 446
|
||||
add_dnat 448
|
||||
add_dnat 449
|
||||
|
||||
# IBM i data ports
|
||||
for port in $(seq 8470 8476); do add_dnat $port; done
|
||||
|
||||
# Additional port ranges
|
||||
for port in $(seq 2000 2020); do add_dnat $port; done
|
||||
for port in $(seq 3000 3020); do add_dnat $port; done
|
||||
for port in $(seq 10000 10020); do add_dnat $port; done
|
||||
for port in $(seq 36000 36010); do add_dnat $port; done
|
||||
|
||||
echo "[rego-tunnel] iptables DNAT rules configured"
|
||||
echo "[rego-tunnel] Port forwarding ready via $CONTAINER_IP"
|
||||
|
||||
# Set VNC password if VNC_PASSWORD env var is set
|
||||
if [[ -n "${VNC_PASSWORD:-}" ]]; then
|
||||
echo "[rego-tunnel] Setting VNC password..."
|
||||
for i in {1..30}; do
|
||||
if nc -z localhost 7100 2>/dev/null; then
|
||||
sleep 2
|
||||
echo "set_password vnc ${VNC_PASSWORD}" | nc -q1 localhost 7100 >/dev/null 2>&1 && \
|
||||
echo "[rego-tunnel] VNC password set successfully" || \
|
||||
echo "[rego-tunnel] Failed to set VNC password"
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
fi
|
||||
) &
|
||||
|
||||
return 0
|
||||
@@ -1,441 +0,0 @@
|
||||
const WebSocket = require("ws");
|
||||
const { authenticator } = require("otplib");
|
||||
const { execSync, spawn } = require("child_process");
|
||||
|
||||
const CONFIG = {
|
||||
email: "c-azaw@regoproducts.com",
|
||||
password: "Fuckyou4suhail",
|
||||
totpSecret: "RZQTQSKDWKHZ6ZYR",
|
||||
devtoolsPort: 9222,
|
||||
vpnTestIp: "10.35.33.230"
|
||||
};
|
||||
|
||||
let ws;
|
||||
let msgId = 1;
|
||||
|
||||
function log(msg) {
|
||||
console.log("[" + new Date().toLocaleTimeString() + "] " + msg);
|
||||
}
|
||||
|
||||
function run(cmd) {
|
||||
try { execSync(cmd, { stdio: "ignore", timeout: 10000 }); } catch (e) {}
|
||||
}
|
||||
|
||||
function runOutput(cmd) {
|
||||
try {
|
||||
return execSync(cmd, { encoding: "utf8", timeout: 10000 });
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
async function getPages() {
|
||||
const res = await fetch("http://localhost:" + CONFIG.devtoolsPort + "/json");
|
||||
return res.json();
|
||||
}
|
||||
|
||||
function send(method, params = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = msgId++;
|
||||
const timeout = setTimeout(() => reject(new Error("Timeout: " + method)), 15000);
|
||||
const handler = (data) => {
|
||||
const msg = JSON.parse(data);
|
||||
if (msg.id === id) {
|
||||
clearTimeout(timeout);
|
||||
ws.off("message", handler);
|
||||
resolve(msg.result);
|
||||
}
|
||||
};
|
||||
ws.on("message", handler);
|
||||
ws.send(JSON.stringify({ id, method, params }));
|
||||
});
|
||||
}
|
||||
|
||||
async function waitForSelector(selector, timeout = 30000) {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < timeout) {
|
||||
try {
|
||||
const result = await send("Runtime.evaluate", {
|
||||
expression: "document.querySelector('" + selector + "') !== null",
|
||||
returnByValue: true
|
||||
});
|
||||
if (result.result.value === true) return true;
|
||||
} catch (e) {}
|
||||
await sleep(500);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function typeText(selector, text) {
|
||||
await send("Runtime.evaluate", {
|
||||
expression: "var el = document.querySelector('" + selector + "'); el.focus(); el.value = '';"
|
||||
});
|
||||
await sleep(100);
|
||||
for (const char of text) {
|
||||
await send("Input.dispatchKeyEvent", { type: "char", text: char });
|
||||
await sleep(30);
|
||||
}
|
||||
}
|
||||
|
||||
async function click(selector) {
|
||||
await send("Runtime.evaluate", {
|
||||
expression: "document.querySelector('" + selector + "').click()"
|
||||
});
|
||||
}
|
||||
|
||||
async function clickSubmit() {
|
||||
const methods = [
|
||||
"document.querySelector('#submitButton') && document.querySelector('#submitButton').click()",
|
||||
"typeof Login !== 'undefined' && Login.submitLoginRequest && Login.submitLoginRequest()",
|
||||
"document.querySelector('input[type=\"submit\"]') && document.querySelector('input[type=\"submit\"]').click()",
|
||||
"document.querySelector('button[type=\"submit\"]') && document.querySelector('button[type=\"submit\"]').click()",
|
||||
"document.querySelector('#idSIButton9') && document.querySelector('#idSIButton9').click()"
|
||||
];
|
||||
for (const expr of methods) {
|
||||
try { await send("Runtime.evaluate", { expression: expr }); } catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
async function sleep(ms) {
|
||||
return new Promise(r => setTimeout(r, ms));
|
||||
}
|
||||
|
||||
async function waitForDevtools(maxWait = 120000) {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < maxWait) {
|
||||
try {
|
||||
const pages = await getPages();
|
||||
const page = pages.find(p => p.type === "page");
|
||||
if (page) return page;
|
||||
} catch (e) {}
|
||||
log("Waiting for WebView...");
|
||||
await sleep(2000);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// VPN adapter check skipped - IP range is unpredictable
|
||||
// We rely solely on connectivity test to target IP
|
||||
|
||||
// Test connectivity via ping (check for actual reply, not TTL expired)
|
||||
function testVpnConnectivity(ip) {
|
||||
try {
|
||||
const output = execSync(`ping -n 1 -w 3000 ${ip}`, { encoding: "utf8", timeout: 5000 });
|
||||
// Must have "Reply from <ip>" - not "TTL expired" or "Request timed out"
|
||||
return output.includes(`Reply from ${ip}`);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify VPN is connected with retries (connectivity test only)
|
||||
async function verifyVpnConnection(maxRetries = 10, retryDelay = 5000) {
|
||||
log("--- VPN VERIFICATION ---");
|
||||
|
||||
for (let i = 1; i <= maxRetries; i++) {
|
||||
log(`Attempt ${i}/${maxRetries}: Pinging ${CONFIG.vpnTestIp}...`);
|
||||
const connected = testVpnConnectivity(CONFIG.vpnTestIp);
|
||||
|
||||
if (connected) {
|
||||
log("VPN connectivity confirmed!");
|
||||
return true;
|
||||
}
|
||||
|
||||
log("Not reachable yet, waiting...");
|
||||
if (i < maxRetries) {
|
||||
await sleep(retryDelay);
|
||||
}
|
||||
}
|
||||
|
||||
log("VPN verification failed after " + maxRetries + " attempts");
|
||||
return false;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log("");
|
||||
console.log("========================================");
|
||||
console.log(" CISCO VPN AUTO-LOGIN");
|
||||
console.log("========================================");
|
||||
console.log("");
|
||||
|
||||
// Sync time first (TOTP requires accurate time)
|
||||
log("Syncing system time...");
|
||||
run("sc config w32time start= auto");
|
||||
run("net start w32time");
|
||||
run("w32tm /config /manualpeerlist:pool.ntp.org /syncfromflags:manual /update");
|
||||
run("w32tm /resync /force");
|
||||
await sleep(2000);
|
||||
|
||||
// Kill everything
|
||||
log("Killing Cisco processes...");
|
||||
run("taskkill /F /IM csc_ui.exe");
|
||||
run("taskkill /F /IM vpnui.exe");
|
||||
run("taskkill /F /IM vpnagent.exe");
|
||||
run('net stop csc_vpnagent');
|
||||
await sleep(2000);
|
||||
|
||||
// Start agent
|
||||
log("Starting Cisco agent...");
|
||||
run('net start csc_vpnagent');
|
||||
await sleep(3000);
|
||||
|
||||
// Start UI
|
||||
log("Starting Cisco UI...");
|
||||
process.env.WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS = "--remote-debugging-port=9222 --remote-debugging-address=0.0.0.0 --remote-allow-origins=*";
|
||||
spawn("C:\\Program Files (x86)\\Cisco\\Cisco Secure Client\\UI\\csc_ui.exe", [], {
|
||||
detached: true,
|
||||
stdio: "ignore"
|
||||
}).unref();
|
||||
|
||||
await sleep(5000);
|
||||
|
||||
// Wait for WebView
|
||||
const page = await waitForDevtools();
|
||||
if (!page) {
|
||||
log("ERROR: WebView not found - rebooting...");
|
||||
run("shutdown /r /t 1");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
log("WebView: " + page.title);
|
||||
ws = new WebSocket(page.webSocketDebuggerUrl);
|
||||
await new Promise((resolve, reject) => {
|
||||
ws.on("open", resolve);
|
||||
ws.on("error", reject);
|
||||
});
|
||||
|
||||
await send("DOM.enable");
|
||||
await send("Runtime.enable");
|
||||
await send("Input.enable");
|
||||
log("Connected to DevTools");
|
||||
|
||||
const url = page.url || "";
|
||||
const isADFS = url.includes("adfs");
|
||||
log("Login type: " + (isADFS ? "ADFS" : "Microsoft"));
|
||||
|
||||
if (isADFS) {
|
||||
log("--- ADFS LOGIN ---");
|
||||
if (!await waitForSelector("#passwordInput", 15000)) {
|
||||
log("Password field not found");
|
||||
process.exit(1);
|
||||
}
|
||||
log("Entering password...");
|
||||
await typeText("#passwordInput", CONFIG.password);
|
||||
await sleep(500);
|
||||
log("Clicking Sign In...");
|
||||
await clickSubmit();
|
||||
await sleep(3000);
|
||||
} else {
|
||||
log("--- EMAIL ---");
|
||||
if (await waitForSelector('input[type="email"]', 5000)) {
|
||||
log("Entering email...");
|
||||
await typeText('input[type="email"]', CONFIG.email);
|
||||
await sleep(500);
|
||||
log("Clicking Next...");
|
||||
await clickSubmit();
|
||||
await sleep(3000);
|
||||
}
|
||||
|
||||
log("--- PASSWORD ---");
|
||||
if (!await waitForSelector('input[type="password"]', 15000)) {
|
||||
log("Password field not found");
|
||||
process.exit(1);
|
||||
}
|
||||
log("Entering password...");
|
||||
await typeText('input[type="password"]', CONFIG.password);
|
||||
await sleep(500);
|
||||
log("Clicking Sign In...");
|
||||
await clickSubmit();
|
||||
await sleep(3000);
|
||||
}
|
||||
|
||||
// TOTP
|
||||
log("--- TOTP ---");
|
||||
if (await waitForSelector('input[name="otc"]', 15000)) {
|
||||
await sleep(500);
|
||||
const totp = authenticator.generate(CONFIG.totpSecret);
|
||||
log("TOTP: " + totp);
|
||||
await typeText('input[name="otc"]', totp);
|
||||
await sleep(500);
|
||||
log("Submitting...");
|
||||
await clickSubmit();
|
||||
await sleep(3000);
|
||||
} else {
|
||||
log("No TOTP field");
|
||||
}
|
||||
|
||||
// Stay signed in
|
||||
log("--- STAY SIGNED IN ---");
|
||||
if (await waitForSelector("#idBtn_Back", 5000)) {
|
||||
log("Clicking No...");
|
||||
await click("#idBtn_Back");
|
||||
}
|
||||
|
||||
await sleep(2000);
|
||||
ws.close();
|
||||
|
||||
// Verify VPN connection
|
||||
const vpnConnected = await verifyVpnConnection();
|
||||
|
||||
if (!vpnConnected) {
|
||||
log("ERROR: VPN connection could not be verified");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("========================================");
|
||||
console.log(" VPN CONNECTED!");
|
||||
console.log(" Entering watchdog mode...");
|
||||
console.log("========================================");
|
||||
console.log("");
|
||||
|
||||
// Enter watchdog mode - monitor and reconnect if needed
|
||||
await watchdogLoop();
|
||||
}
|
||||
|
||||
async function watchdogLoop() {
|
||||
const checkInterval = 2 * 60 * 1000; // 2 minutes
|
||||
let consecutiveFailures = 0;
|
||||
let checkCount = 0;
|
||||
|
||||
log("Watchdog: Monitoring every 2 minutes...");
|
||||
|
||||
while (true) {
|
||||
await sleep(checkInterval);
|
||||
checkCount++;
|
||||
|
||||
// Force garbage collection every 10 checks (~20 min)
|
||||
if (checkCount % 10 === 0 && global.gc) {
|
||||
global.gc();
|
||||
}
|
||||
|
||||
// Log memory every 30 checks (~1 hour)
|
||||
if (checkCount % 30 === 0) {
|
||||
const mem = Math.round(process.memoryUsage().heapUsed / 1024 / 1024);
|
||||
log(`Watchdog: Memory ${mem}MB, checks ${checkCount}`);
|
||||
}
|
||||
|
||||
const connected = testVpnConnectivity(CONFIG.vpnTestIp);
|
||||
|
||||
if (connected) {
|
||||
if (consecutiveFailures > 0) {
|
||||
log("Watchdog: Connection restored");
|
||||
}
|
||||
consecutiveFailures = 0;
|
||||
} else {
|
||||
consecutiveFailures++;
|
||||
log(`Watchdog: Connection FAILED (${consecutiveFailures})`);
|
||||
|
||||
if (consecutiveFailures >= 2) {
|
||||
log("Watchdog: Reconnecting...");
|
||||
await reconnectVpn();
|
||||
consecutiveFailures = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function reconnectVpn() {
|
||||
// Sync time first (TOTP requires accurate time)
|
||||
log("Syncing system time...");
|
||||
run("sc config w32time start= auto");
|
||||
run("net start w32time");
|
||||
run("w32tm /resync /force");
|
||||
await sleep(1000);
|
||||
|
||||
// Kill and restart VPN
|
||||
log("Killing Cisco processes...");
|
||||
run("taskkill /F /IM csc_ui.exe");
|
||||
run("taskkill /F /IM vpnui.exe");
|
||||
run("taskkill /F /IM vpnagent.exe");
|
||||
run('net stop "Cisco Secure Client Agent"');
|
||||
await sleep(2000);
|
||||
|
||||
log("Starting Cisco agent...");
|
||||
run('net start "Cisco Secure Client Agent"');
|
||||
await sleep(3000);
|
||||
|
||||
log("Starting Cisco UI...");
|
||||
spawn("C:\\Program Files (x86)\\Cisco\\Cisco Secure Client\\UI\\csc_ui.exe", [], {
|
||||
detached: true,
|
||||
stdio: "ignore"
|
||||
}).unref();
|
||||
|
||||
await sleep(5000);
|
||||
|
||||
const page = await waitForDevtools();
|
||||
if (!page) {
|
||||
log("ERROR: WebView not found - rebooting...");
|
||||
run("shutdown /r /t 1");
|
||||
return false;
|
||||
}
|
||||
|
||||
ws = new WebSocket(page.webSocketDebuggerUrl);
|
||||
await new Promise((resolve, reject) => {
|
||||
ws.on("open", resolve);
|
||||
ws.on("error", reject);
|
||||
});
|
||||
|
||||
await send("DOM.enable");
|
||||
await send("Runtime.enable");
|
||||
await send("Input.enable");
|
||||
|
||||
const url = page.url || "";
|
||||
const isADFS = url.includes("adfs");
|
||||
|
||||
if (isADFS) {
|
||||
if (await waitForSelector("#passwordInput", 15000)) {
|
||||
await typeText("#passwordInput", CONFIG.password);
|
||||
await sleep(500);
|
||||
await clickSubmit();
|
||||
await sleep(3000);
|
||||
}
|
||||
} else {
|
||||
if (await waitForSelector('input[type="email"]', 5000)) {
|
||||
await typeText('input[type="email"]', CONFIG.email);
|
||||
await sleep(500);
|
||||
await clickSubmit();
|
||||
await sleep(3000);
|
||||
}
|
||||
if (await waitForSelector('input[type="password"]', 15000)) {
|
||||
await typeText('input[type="password"]', CONFIG.password);
|
||||
await sleep(500);
|
||||
await clickSubmit();
|
||||
await sleep(3000);
|
||||
}
|
||||
}
|
||||
|
||||
// TOTP
|
||||
if (await waitForSelector('input[name="otc"]', 15000)) {
|
||||
await sleep(500);
|
||||
const totp = authenticator.generate(CONFIG.totpSecret);
|
||||
log("TOTP: " + totp);
|
||||
await typeText('input[name="otc"]', totp);
|
||||
await sleep(500);
|
||||
await clickSubmit();
|
||||
await sleep(3000);
|
||||
}
|
||||
|
||||
// Stay signed in - No
|
||||
if (await waitForSelector("#idBtn_Back", 5000)) {
|
||||
await click("#idBtn_Back");
|
||||
}
|
||||
|
||||
await sleep(2000);
|
||||
ws.close();
|
||||
|
||||
// Verify reconnection
|
||||
const verified = await verifyVpnConnection();
|
||||
if (verified) {
|
||||
log("Reconnection successful!");
|
||||
return true;
|
||||
}
|
||||
|
||||
log("Reconnection failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
log("ERROR: " + err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Binary file not shown.
@@ -1,4 +0,0 @@
|
||||
@echo off
|
||||
cd /d C:\Users\%USERNAME%\vpn_scripts\
|
||||
node vpn-login.js
|
||||
pause
|
||||
Reference in New Issue
Block a user