This commit is contained in:
2025-12-28 13:09:48 +00:00
parent 68a9af9331
commit f9c17c644a
12 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
# 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"

View File

@@ -0,0 +1,45 @@
# 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

View File

@@ -0,0 +1,34 @@
# 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

View File

@@ -0,0 +1,188 @@
# 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$@@`

View File

@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBh1EJ8NFn3hUUMe+lJSJl14bt8Xjh+NT5g0YnfKVitQwAAAJhfESWEXxEl
hAAAAAtzc2gtZWQyNTUxOQAAACBh1EJ8NFn3hUUMe+lJSJl14bt8Xjh+NT5g0YnfKVitQw
AAAEDgYZN7HwPbKY++p612bnhGC10P3GUHQdJlprPEFbODgWHUQnw0WfeFRQx76UlImXXh
u3xeOH41PmDRid8pWK1DAAAAEWFsZXh6QEFaYXdQQy1QMTZTAQIDBA==
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1,35 @@
@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

View File

@@ -0,0 +1,69 @@
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}`);
});

View File

@@ -0,0 +1,117 @@
#!/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

View File

@@ -0,0 +1,441 @@
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);
});

View File

@@ -0,0 +1,4 @@
@echo off
cd /d C:\Users\%USERNAME%\vpn_scripts\
node vpn-login.js
pause