Skip to content
nxctfPublic

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

pnetctl — PNETLab Console Manager

License: MIT Python: 3.11+

pnetctl is a fast, keyboard-first terminal console manager for Cisco routers, switches, and other virtual lab nodes running inside PNETLab (or EVE-NG).

Instead of manually SSHing into your PNETLab host, running ps -ef | grep ... to discover ports, and repeatedly typing telnet localhost 30043, pnetctl automates the entire workflow directly from your Windows Terminal or PowerShell.


Table of Contents


Overview

In typical PNETLab environments, virtual lab devices (Cisco IOL/IOSv/IOSvL2/Dynamips/QEMU) expose local Telnet consoles bound to 127.0.0.1 on random or dynamic TCP ports (e.g., 30043, 30044).

pnetctl provides:

  1. Zero Port Forwarding: Connects securely over SSH. Device Telnet sessions stay strictly on the remote server's 127.0.0.1.
  2. Automatic Node Discovery: Interrogates running PNETLab processes dynamically over SSH.
  3. Interactive Terminal UI: Powered by Textual with instant search, filtering, and status badges.
  4. ANSI/VT100 Console Emulation: Powered by pyte supporting full Cisco editing shortcuts (Tab, Ctrl+C, Ctrl+Z, Ctrl+Shift+6).
  5. Multi-Session Keep-Alive: Detach back to the node selector without terminating active router console sessions.

How It Works (Direct Telnet + SSH Discovery)

┌─────────────────────────────────────────────────────────────┐
│                      Windows Host                           │
│                                                             │
│       pnetctl (Desktop GUI & Direct Telnet Client)          │
└──────────────┬──────────────────────────────┬───────────────┘
               │                              │
  [1] SSH Port 22 (Fast Discovery)            │ [2] Direct TCP Telnet Socket
      Runs `ps -ef | grep ...`                │     (1ms Handshake, Zero Lag!)
      Discovers active ports:                 │     Connects directly to:
        SW-LAN   -> Port 30043                │       192.168.2.20:30043
        R-GW-LAN -> Port 30044                │       192.168.2.20:30044
        R1       -> Port 30046                │       ...
               ▼                              ▼
┌─────────────────────────────────────────────────────────────┐
│                  PNETLab Linux Server                       │
│                                                             │
│   Virtual Lab Nodes (QEMU / IOL / Dynamips)                 │
│   Telnet consoles listening on TCP ports 30043, 30044, etc. │
└─────────────────────────────────────────────────────────────┘

Key Advantages:

  1. ⚡ Ultra-Low Latency (Zero Lag): As soon as ports are discovered, console tabs connect directly via raw TCP socket. Typing feels instantaneous.
  2. 🛡️ Automatic SSH Fallback: If device ports are firewalled or bound strictly to 127.0.0.1, pnetctl seamlessly falls back to an SSH tunnel PTY channel.
  3. 🚀 1-Click PuTTY / Windows Terminal: Opens external PuTTY directly via -telnet <host> <port> in milliseconds.

System Requirements

  • Local Machine: Windows 10/11 (PowerShell 7 / Windows Terminal recommended). Also works on Linux/macOS.
  • Python: Python 3.11, 3.12, or 3.13+.
  • Remote Server: Linux-based PNETLab or EVE-NG server with SSH access and telnet client installed.

Installation

Option A: Global CLI with pipx (Recommended for Windows)

If you use Scoop:

scoop install python pipx
pipx ensurepath

Install pnetctl directly:

pipx install .

Or from a git repository:

pipx install git+https://github.com/nxctf/pnetctl.git

Now pnetctl is available everywhere in your terminal:

pnetctl --version

Option B: From Source in Virtual Environment

# Clone the repository
git clone https://github.com/nxctf/pnetctl.git
cd pnetctl

# Create and activate virtual environment
python -m venv .venv
.venv\Scripts\Activate.ps1

# Install in editable mode with development tools
pip install -e ".[dev]"

# Run (launches Desktop GUI by default!)
pnetctl

Option C: Scoop Distribution

A Scoop manifest template is provided in packaging/scoop/pnetctl.json.

For team or bucket distribution:

  1. Tag a release on GitHub (e.g. v0.1.0).
  2. Generate SHA256 checksum of the release ZIP.
  3. Add the manifest to your custom Scoop bucket:
    scoop bucket add mybucket https://github.com/your-org/scoop-bucket
    scoop install pnetctl

Configuration

Config File Location

On Windows, the default configuration file is stored at:

%APPDATA%\pnetctl\config.toml

(e.g., C:\Users\<username>\AppData\Roaming\pnetctl\config.toml).

On Linux/macOS:

~/.config/pnetctl/config.toml

You can override the path using the --config flag or the PNETCTL_CONFIG environment variable:

$env:PNETCTL_CONFIG = "D:\labs\my-pnetlab-config.toml"

Interactive Setup Wizard

Run:

pnetctl setup

The wizard will guide you through:

  • Remote server hostname or IP.
  • SSH port (default 22).
  • Username (default root).
  • Authentication method (Key, Agent, or Password).
  • Private key location.

Configuration Schema

See config.example.toml for reference:

[connection]
host = "192.168.1.100"
port = 22
username = "root"
auth_method = "key"
private_key = "~/.ssh/id_ed25519"
timeout = 10.0
strict_host_key_check = true

[discovery]
refresh_interval = 10
command_timeout = 10.0

[terminal]
term_type = "xterm-256color"
scrollback = 5000
keep_sessions = true
detach_key = "ctrl+b"

SSH Authentication & Host Key Security

  • SSH Keys (Recommended): Supports Ed25519, RSA, and ECDSA keys. Expands ~ and environment variables.
  • SSH Agent: Leverages Windows OpenSSH Agent or Pageant.
  • Passwords: Never stored in plaintext in config.toml. Prompted securely without echo at runtime.
  • Host Key Verification: Rejects unknown or modified server host keys by default. Prompts interactively to verify and add new host keys into your ~/.ssh/known_hosts file.

Usage & Commands

Desktop GUI — MobaXterm Edition (Default)

Running pnetctl without arguments launches the modern tabbed desktop GUI with mouse navigation, mousewheel scrolling, in-app configuration & password setup, and quick action buttons:

pnetctl                        # Launch Desktop GUI (reads saved config or prompts setup dialog)
pnetctl 192.168.2.20           # Launch GUI directly targeting server IP
pnetctl root@192.168.2.20:22   # Launch GUI with full target [user@]host[:port]
pnetctl nodes                  # Fast CLI: List discovered active router/switch nodes & ports
pnetctl nodes 192.168.2.20     # Fast CLI: Scan nodes directly from target server
pnetctl tui                    # Launch terminal Textual TUI interface
pnetctl doctor                 # Inspect health & connectivity
pnetctl -v                     # Display version

100% In-GUI Setup & Password Management

No need to touch the terminal for configuration:

  1. When you run pnetctl for the first time (or click ⚙️ Edit Connection / Password in the sidebar), a configuration dialog appears.
  2. Enter your PNETLab Server IP, SSH Port, Username, and SSH Password (with show/hide 👁 toggle).
  3. Check 💾 Save these settings to config.toml and click ⚡ Save & Connect!
  4. Discovered routers & switches appear immediately in the left sidebar table. Double-click any node to open an ultra-fast Direct Telnet console tab.

Diagnostics (pnetctl doctor)

Check your Python environment, configuration file, SSH reachability, and remote server dependencies:

pnetctl doctor

Output:

+-----------------------------------------------------------------------------+
| pnetctl Diagnostic Doctor                                                   |
+-----------------------------------------------------------------------------+
| Check              | Result | Details                                       |
| Python Version     | PASS   | 3.13.0 (>= 3.11 required)                     |
| Config File        | PASS   | Valid: C:\Users\user\AppData\Roaming\...      |
| Private Key        | PASS   | Exists: C:\Users\user\.ssh\id_ed25519         |
| Known Hosts        | PASS   | C:\Users\user\.ssh\known_hosts                |
| SSH Reachability   | PASS   | Connected to 192.168.1.100:22                 |
| Remote Telnet Tool | PASS   | Found at /usr/bin/telnet                      |
| Discovery Command  | PASS   | Executed successfully (found 7 active node(s))|
+-----------------------------------------------------------------------------+

Quick Nodes Listing (pnetctl nodes)

Print all discovered nodes in a table and exit:

pnetctl nodes

Connection Test (pnetctl connect)

Test your SSH connection credentials:

pnetctl connect

Keyboard Shortcuts

Main Menu

Key Action
Up / Down Navigate through discovered nodes
Enter or C Connect to selected node console
/ Focus search / filter input
R Refresh discovery over SSH
D Close active session for selected node
? Show interactive help modal
Q Safely disconnect and quit

Inside Console View

Key Action Notes
F10 or Ctrl+B Detach to main node menu Session remains alive in background
F12 Close console channel Closes remote Telnet process
Ctrl+Shift+6 Cisco Abort (^^) Cancels ping / traceroute
Ctrl+C Interrupt signal Forwarded to Cisco CLI
Ctrl+Z Exit configuration mode Forwarded to Cisco CLI
Tab Command completion Forwarded to Cisco CLI
Up / Down CLI history navigation Forwarded to Cisco CLI

Session Management & Detach

pnetctl supports seamless multi-session multiplexing over a single persistent SSH connection:

  1. Reattach: If you detach from SW-LAN (via F10 or Ctrl+B) and connect to R1, SW-LAN stays running in the background. Selecting SW-LAN again restores your exact console state immediately.
  2. Close vs Detach:
    • Detaching (F10 / Ctrl+B) leaves the Telnet connection active on the server.
    • Closing (F12 in console, or D in main menu) closes the remote channel cleanly.
  3. Graceful Exit: Quitting the application (Q) terminates all active channels and closes the SSH transport cleanly.

Concrete Lab Example

Consider the following running PNETLab processes:

SW-LAN      30043
R-GW-LAN    30044
SW-TRANSIT  30045
R1          30046
R2          30047
R-ISPB      30049
R-GW-SRV    30050

(Note: These ports are dynamically assigned by PNETLab and discovered automatically at runtime).

  1. When you run pnetctl, all 7 nodes appear in the table.
  2. Typing / then GW filters the view instantly to R-GW-LAN (30044) and R-GW-SRV (30050).
  3. Press Enter on SW-LAN: pnetctl executes telnet 127.0.0.1 30043 over an interactive PTY channel on the PNETLab server.
  4. You configure VLANs in SW-LAN, press F10 to detach, select R-GW-LAN (30044), and test default gateway routing.
  5. If a ping gets stuck on a Cisco router, press Ctrl+Shift+6 to abort it instantly.

Troubleshooting

1. "Configuration file not found"

Run pnetctl setup to generate an initial configuration file, or copy config.example.toml to %APPDATA%\pnetctl\config.toml.

2. "Host key verification mismatch"

Your PNETLab server may have been reinstalled or changed IP address. Check your ~/.ssh/known_hosts file or run pnetctl connect to accept the new fingerprint.

3. "No active console nodes found"

Ensure your lab nodes are powered on inside the PNETLab web interface. Check running processes on the server using pnetctl doctor.

4. Special Characters / Keybindings in Windows Terminal

Windows Terminal handles VT sequences natively. Ensure you use Windows Terminal rather than legacy cmd.exe for optimal ANSI escape code rendering.


Security Considerations

  • No Remote Port Exposure: Telnet is unencrypted by nature. pnetctl accesses 127.0.0.1 strictly over an encrypted SSH channel; no Telnet ports (30000+) are ever opened to the public network.
  • Port Validation: All discovered ports are strictly validated as integers (1–65535) before building the telnet 127.0.0.1 <PORT> command.
  • Credential Safety: No passwords are saved in plain text.

Limitations

  1. Application Lifetime: Sessions kept alive in the background remain alive while pnetctl is running. Closing pnetctl terminates active Telnet channels.
  2. Telnet Binary Requirement: PNETLab Linux host must have the telnet client package installed (default on all PNETLab releases).

Development & Automated Testing

Run the automated test suite:

pytest -v

All 41 unit and UI tests run in isolation with mocked SSH transports and test fixtures.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages