proxy

command module
v1.0.27 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 23, 2025 License: MIT Imports: 51 Imported by: 0

README

proxy

Go Report Card Pipeline Status CodeQL Dependabot Updates Quality Gate Status REUSE status

Overview

The proxy program acts as a multi‑user terminal server and relay 📡, accepting incoming SSH client connections on the front‑end (listeners 👂) and proxying these connections to one or more TELNET servers on the back‑end (targets 🎯).

This project was originally developed to meet the needs of the BAN.AI Public Access Multics system and the DPS8M Simulator project, but may be useful to anyone who wants to offer SSH access to legacy systems.

Features

  • ✅ SSH ⟷ TELNET gateway
  • ✅ Full IPv6 support
  • ✅ Access control whitelist/blacklist (by IP address or CIDR block)
  • ✅ Independent console and session logging (by date/time and host)
  • ✅ Automatic log‑file compression (using gzip, lzip, xz, or zstandard)
  • ✅ Banners for accepted, denied, and blocked connections (configurable per target)
  • ✅ Session connection monitoring and idle time tracking (with optional timeouts)
  • ✅ Translation of SSH window‑change events to TELNET NAWS messages
  • ✅ Interactive connection management for administrators
  • ✅ User access to TELNET features (e.g., line BREAK, AYT) and statistics
  • ✅ Transparent key remapping mode (translating movement keys to Emacs sequences)
  • ✅ Optional support for management using systemd on Linux (running in a sandbox)
  • ✅ Optional mDNS (Multicast DNS) DNS-SD service advertisements for listeners
  • ✅ Link filtering
  • ✅ Live streaming connection sharing (read‑only)
    • 🤝 Allows users to share their session with one or more viewers

Installation

Binaries
  • We currently publish more than 40 binaries supporting 13 operating systems (IBM AIX, IBM i, Android, Apple macOS, Dragonfly BSD, FreeBSD, illumos, Linux, NetBSD, OpenBSD, Plan 9, Solaris, and Microsoft Windows) on 14 hardware architectures.
Source

A recent version of Go 🐹 is required to build proxy from source code.

  • You can clone the git repository 🌱 and build the source code using make:

    git clone https://gitlab.com/dps8m/proxy.git
    cd proxy
    make
    
    • If you don’t have a (POSIX) make available for some reason, then building with go build is sufficient.

    • The .cross.sh cross‑compilation helper script is provided (which can be called with make cross) that attempts to build proxy binaries for all supported GOOS and GOARCH combinations (except some specific Android builds, which are handled by .cross-android.sh for building the Android binaries that require the Android NDK).

  • You can also install this software using go install 📦:

    go install gitlab.com/dps8m/proxy@latest
    
    • Installations using go install download the required sources, compile, and install the binary to ${GOEXE}/proxy (which will be ${HOME}/go/bin/proxy for most users).

Usage

Invocation
  • The proxy command can be invoked with the following command‑line arguments:
DPS8M Proxy v1.0.27 (2025-Dec-23 g5fdc6b2) [linux/amd64]

Usage for /home/jhj/dps8m-proxy/proxy:

  --allow-root                  Allow running as root (UID 0)
  --cert-dir <string>           Directory containing SSH host certificates
                                    (default: current working directory)
  --cert-perm <octal>           Permissions (octal) for new certificate files
                                    [e.g., "600", "644"] (default 600)
  --cert-rsa-bits <uint>        RSA key size in bits for new certificates
                                    ["1024" to "4096"] (default 2048)
  --cert-ecdsa-bits <uint>      ECDSA key size in bits for new certificates
                                    ["256", "384", "521"] (default 256)
  --ssh-addr <string>           SSH listener address(es)
                                    [e.g., ":2222", "[::1]:8000"]
                                    (multiple allowed) (default ":2222")
  --ssh-delay <float>           Delay for incoming SSH connections
                                    ["0.0" to "30.0" seconds] (no default)
  --no-banner                   Disable SSH connection banner
  --telnet-host <string>        Default TELNET target [host:port]
                                    (default "127.0.0.1:6180")
  --alt-host <string>           Alternate TELNET target(s) [sshuser@host:port]
                                    (multiple allowed)
  --debug-telnet                Debug TELNET option negotiation
  --debug-server <string>       Enable HTTP debug server listening address
                                    [e.g., ":6060", "[::1]:6060"]
  --no-sanitize                 Disable ASCII sanitization of error messages
                                    (allowing non-ASCII error reports via SSH)
  --gops                        Enable the "gops" diagnostic agent
                                    (see https://github.com/google/gops)
  --mdns                        Enable mDNS (Multicast DNS) advertisements
                                    (i.e., Bonjour, Avahi announcements)
  --keymap                      Enable Emacs keymapping mode by default
  --log-dir <string>            Base directory for logs (default "log")
  --no-log                      Disable all session logging
                                    (for console logging see "--console-log")
  --no-console                  Disable the interactive admin console
  --console-log <string>        Enable console logging ["quiet", "noquiet"]
                                    (disabled by default)
  --compress-algo <string>      Compression algorithm for log files
                                    ["gzip", "lzip", "xz", "zstd"]
                                    (default "gzip")
  --compress-level <string>     Compression level for gzip, lzip, and zstd
                                    algorithms ["fast", "normal", "high"]
                                    (default "normal")
  --no-compress                 Disable session and/or console log compression
  --log-perm <octal>            Permissions (octal) for new log files
                                    [e.g., "600", "644"] (default 600)
  --log-dir-perm <octal>        Permissions (octal) for new log directories
                                    [e.g., "755", "750"] (default 750)
  --db-file <string>            Path to persistent statistics storage database
                                    (disabled by default)
  --db-time <uint>              Elapsed seconds between database updates
                                    [0 disables periodic writes] (default 30)
  --db-perm <octal>             Permissions (octal) for new database files
                                    [e.g., "600", "644"] (default 600)
  --db-loglevel <string>        Database engine (BBoltDB) logging output level
                                    [level: "0" - "6", or "none" - "debug"]
                                    (default "error")
  --idle-max <uint>             Maximum connection idle time allowed [seconds]
  --time-max <uint>             Maximum connection link time allowed [seconds]
  --blacklist <string>          Enable blacklist [filename] (no default)
  --whitelist <string>          Enable whitelist [filename] (no default)
  --utc                         Use UTC (Coordinated Universal Time) for time
                                    display and timestamping in log files
  --license                     Show license terms and conditions
  --version                     Show version information
  --help                        Show this help and usage information

proxy home page (bug reports): <https://gitlab.com/dps8m/proxy/>

Most of these command‑line arguments are straightforward with usage that should be obvious, and those that require demystification are, hopefully, documented here:

  • Logging of sessions is enabled by default. Logging of console messages is disabled by default.

    • Console logging, if enabled, supports two modes: quiet and noquiet. In quiet mode, all non‑fatal messages are logged only to the log file, where in noquiet mode, messages are logged to both the console and the log file.

    • By default, the local time zone is used for time display and writing log files. Users can specify the ‑‑utc option to use UTC (Coordinated Universal Time) instead. Additionally, on Unix-like systems, the TZ environment variable is respected.

    • If the proxy fails to create log directories or files, a warning will be displayed on the console and the session and/or console logging feature may be (but is not guaranteed to be) disabled. In a future version, this behavior may be configurable (e.g., to allow either immediately or gracefully exiting on logging failures).

  • Enabling the database (with the ‑‑db-file option) persists to disk the connection statistics (viewable with the s admin console command) so the stats are not lost when restarting the proxy. It is customary to use a name ending with the extension db (e.g., proxy.db).

  • The default TELNET target for --telnet-host is specified as a host:port or path (for connecting to a UNIX domain socket). Valid examples include hostname:23, 1.2.3.4:2323, [2607:f8b0:4008:805::2000]:23, ./socket, and /path/socket.

  • All incoming SSH users are connected to the default TELNET target, unless their supplied SSH username matches an alternate target enabled with the ‑‑alt‑host flag. The alt‑host syntax is sshuser@host:port or sshuser@path, where sshuser is the SSH username, and the host:port (or path, an absolute or relative path to a UNIX domain socket) is the TELNET target.

  • All users connecting with SSH are shown a banner which includes details such as the date and time of the session, their IP address, and possibly a resolved host name. This can be disabled with ‑‑no‑banner.

  • The ‑‑no‑banner command disables only those lines described above. It does not disable the file‑based banner content. These are the three primary text files which can be displayed to connecting SSH users:

    File Purpose
    block.txt Displayed before disconnecting connections matching the blacklist
    deny.txt Displayed when denying target sessions (e.g., during graceful shutdown)
    issue.txt Displayed to users before their actual session with the target begins
    • When multiple targets are defined using the ‑‑alt‑host functionality, the system will display a file that matches ‑NAME before the .txt extension. For example, if you have defined a target as oldunix@10.0.5.9:3333 the proxy will look for block‑oldunix.txt, deny‑oldunix.txt, and issue‑oldunix.txt files to serve to the connected user, before beginning their session with the target (via TELNET to 10.0.5.9:3333). If any of the target‑specific text files do not exist, then the standard files will be served.
    • To disable the file‑based banner for specific targets only, you can create empty files using the naming scheme described above. You can also remove all of these files if you don’t want to use this functionality.
  • You need to start proxy using the ‑‑whitelist and/or ‑‑blacklist argument to enable the access control functionality. If only the whitelist is enabled, then all connections will be denied by default. Note that if only the blacklist is enabled, it will be impossible to exempt individual IP addresses within a range that has been blocked. It is recommended that you enable both lists when using the access control features.

    • The format of the whitelist and blacklist is an IPv4 or IPv6 address (e.g., 23.215.0.138, 2600:1406:bc00:53::b81e:94ce), or a CIDR block (e.g., 123.45.0.0/17 which covers 123.45.0.0 to 123.45.127.255, or 2600:1408:ec00:36::/64 covering 2600:1408:ec00:36:0000:0000:0000:0000 to 2600:1408:ec00:36:ffff:ffff:ffff:ffff).

    • The whitelist always takes precedence over the blacklist. If an address is allowed due to a whitelist match that would have otherwise been blocked by the blacklist, it is tagged as EXEMPTED in the logs.

  • The ‑‑version command shows detailed version information, which includes the versions of any embedded dependencies as well as the name and version of the Go toolchain used to build the software:

DPS8M Proxy v1.0.27 (2025-Dec-23 g5fdc6b2) [linux/amd64]

+===========================+==================================+
| Component                 | Version                          |
+===========================+==================================+
| dps8m/proxy               | v1.0.27                          |
| arl/statsviz              | v0.8.0                           |
| google/gops               | v0.3.29* (2025-May-14, ga2d8f77) |
| gorilla/websocket         | v1.5.3                           |
| hashicorp/mdns            | v1.0.6                           |
| klauspost/compress        | v1.18.2                          |
| miekg/dns                 | v1.1.69                          |
| sorairolake/lzip-go       | v0.3.8                           |
| spf13/pflag               | v1.0.11* (2025-Oct-07, g6fcfbc9) |
| ulikunitz/xz              | v0.5.15                          |
| go.etcd.io/bbolt          | v1.4.3                           |
| golang.org/x/crypto       | v0.46.0                          |
| golang.org/x/net          | v0.48.0                          |
| golang.org/x/sys          | v0.39.0                          |
| golang.org/x/term         | v0.38.0                          |
| kernel.org/.../libcap/cap | v1.2.77                          |
| kernel.org/.../libcap/psx | v1.2.77                          |
| Go compiler (gc)          | v1.25.5                          |
+===========================+==================================+
  • If you need to see additional details about the proxy binary, you can run go version ‑m proxy.
Port binding
  • If you want to listen on the regular SSH port of 22 (without running as root, which is strongly discouraged), on Linux systems you can use setcap to allow the proxy to bind to privileged ports:

    sudo setcap 'cap_net_bind_service=+ep' "/path/to/proxy"
    
  • If this is necessary (i.e., a non‑root user on Linux is attempting to bind an SSH listener to a privileged port and the CAP_NET_BIND_SERVICE capability is not currently effective), the software should provide a warning message with the above instructions.

  • Note that some Android distributions restrict usage of ports below 8000.

Admin interaction
  • The running proxy can be controlled interactively with the following admin console commands:
    • ? — Show help text
    • c — Show proxy configuration
    • v — Show version details
    • s — Show connection statistics
    • l — List active connections
    • k — Kill a connection
    • d — Deny new connections
    • r — Reload access control lists
    • q — Graceful shutdown
    • Q — Immediate shutdown (also via ^C)

Most of these admin console commands are straightforward and should be self‑explanatory, although there are a few options that merit further clarification:

  • When the Graceful shutdown mode is active, all new connections are denied (and are served an appropriate deny.txt banner). Once all clients have disconnected, the proxy software will exit. Note that new monitoring sessions can still connect to observe active users, as these sessions are automatically closed when their observation target disconnects.

  • When the Deny new connections mode is active, all new connections are denied (and are served an appropriate deny.txt banner). In addition, all logging of new connection attempts, including any denied and/or rejected connections, is suppressed. This can be useful when the logs or admin console are overwhelmed with activity (such as during bot attacks, busy periods, or when troubleshooting). Activating this mode can help reduce console noise, making it easier to perform admin actions such as viewing the configuration, or listing and killing active connections.

  • The k command, which kills a connection, takes either a Session ID as an argument (shown when listing active connections with the l command) or *, which kills all active connections.

If it is detected that you have a UTF-8 capable terminal, then some console output will be augmented with icons or emoji glyphs (and in a future version, UTF-8 box drawing symbols may be used for drawing tables).

Signals
  • The proxy also acts on the following signals (on systems where signals are supported):

    Signal Action
    SIGINT Enables the Immediate shutdown mode
    SIGQUIT Enables the Immediate shutdown mode
    SIGUSR1 Enables the Graceful shutdown mode
    SIGUSR2 Enables the Deny new connections mode
    SIGHUP Reloads access control lists (‑‑whitelist, ‑‑blacklist)
    SIGDANGER Attempts to immediately free as much memory as possible (AIX‑only)
Management with systemd

If you’re running the proxy on a Linux system, you can use systemd to manage the service (while maintaining access to the interactive admin console).

  • The systemd integration requires systemd version 247 or later (Nov. 2020), and a recent version of tmux.

  • With minor changes 🔧 to the unit file, this setup can also work with systemd as old as version 229 (Feb. 2016).
  • See the detailed instructions in the systemd/dps8m‑proxy.service file for full installation instructions.
User interaction

Users connected via SSH can send ^] (i.e., Control + ]) during their session to access the following following TELNET control features:

  • ] — sends a literal Control‑] to the target TELNET host

  • 0 — sends a literal NUL to the target TELNET host

  • A — sends an IAC AYT (Are You There?) to the target TELNET host

  • B — sends an IAC BREAK signal to the target TELNET host

  • I — sends an IAC INTERRUPT signal to the target TELNET host

  • K — toggles the transparent key remapping mode, which translates modern xterm/VT320 movement key inputs to Emacs sequences:

    Input Output
    Control + Up Escape, [
    Control + Down Escape, ]
    Control + Right Escape, f
    Control + Left Escape, b
    Home Control + A
    Delete Control + D
    End Control + E
    Up Escape + v
    Down Control + V
    Up Control + P
    Down Control + N
    Right Control + F
    Left Control + B
  • N — sends an IAC NOP (No Operation) to the target TELNET host

  • S — displays the status of the session, sharing information, and some statistics:

    >> LNK ‑ The username '_gRSyWHxPcMp2MWvtmWWF' can be used to share this session.
    >> SSH ‑ in:   58 B,   out: 4.82 KiB, in rate:   4 B/s, out rate: 381 B/s
    >> NVT ‑ in: 4.82 KiB, out:   57 B,   in rate: 381 B/s, out rate:   4 B/s
    >> LNK ‑ link time: 13s (Emacs keymap enabled)
    
  • X — disconnects from the target TELNET host (and ends the SSH session)

Connection sharing
  • The user can share 🤝 the username presented above with others, allowing the session to be viewed live 👀 (read‑only) by one or more viewers:

    $ ssh _gRSyWHxPcMp2MWvtmWWF@proxybox
    
    CONNECTION from remote.com [18.17.16.15] started at 2025/07/15 08:22:55.
    This is a READ‑ONLY shared monitoring session.
    Send Control‑] to disconnect.
    

Compressed logs

  • By default, all session log files are compressed 🗜️ automatically when the session terminates, and console log files are compressed when the log rolls over (i.e., when starting a new day).

  • When reviewing logs, administrators often need to search through all the past data, including through the compressed files. We recommend using ripgrep (with the ‑z option) for this task.

Using OpenSSH host keys

If you have existing OpenSSH Ed25519, RSA, or ECDSA host keys that you want to use with the proxy, you’ll first need to convert those keys to standard PEM format.

🚨 NB: These instructions do not include any specific details for safe handling of key file permissions—we assume you are root and that you know what you’re doing!

  1. Make a copy of the key files you wish to convert. Be aware that these copies will be overwritten in the conversion process:

    cp /etc/ssh/ssh_host_ed25519_key ssh_host_ed25519_key.tmp
    cp /etc/ssh/ssh_host_rsa_key ssh_host_rsa_key.tmp
    cp /etc/ssh/ssh_host_ecdsa_key ssh_host_ecdsa_key.tmp
    
  2. Convert the keys (using ssh‑keygen) and rename them appropriately:

    ssh-keygen -p -m PEM -N '' -P '' -f ssh_host_ed25519_key.tmp
    mv ssh_host_ed25519_key.tmp ssh_host_ed25519_key.pem
    
    ssh-keygen -p -m PEM -N '' -P '' -f ssh_host_rsa_key.tmp
    mv ssh_host_rsa_key.tmp ssh_host_rsa_key.pem
    
    ssh-keygen -p -m PEM -N '' -P '' -f ssh_host_ecdsa_key.tmp
    mv ssh_host_ecdsa_key.tmp ssh_host_ecdsa_key.pem
    

History

This is a from‑scratch re‑implementation (in Go 🐹) of an older legacy program of the same name.

The original software used a multi‑process architecture and consisted of nearly 15,000 lines of haphazardly constructed code: ≅14,000 lines of mostly C‑Kermit 🐸 (yes, the programming language) and ksh93 🐚 (along with some C 💻, Python 🐍, and Perl 🐪) which was difficult to maintain, configure, and securely install.

This new implementation uses many lightweight Goroutines 🚀 instead of spawning multiple processes, resulting in significantly improved performance and reduced system overhead.

Code statistics

The new proxy program is considerably simpler than its legacy predecessor (code statistics 📈 provided by scc):

Language Files Lines Blank Comment Code Complexity Bytes Uloc
Go 20 8844 1941 582 6321 1550 212365 3847
Shell 4 436 99 112 225 34 12876 207
Makefile 1 537 83 92 362 154 18514 324
Markdown 1 583 109 0 474 0 27472 459
Systemd 1 209 35 107 67 0 7595 135
YAML 1 84 6 10 68 0 3961 75
Total 28 10693 2273 903 7517 1738 282783 5029

Future plans

  • Some features of the legacy software are still missing in this implementation and may be added in future updates. These features include text CAPTCHAs, load‑balancing, fail‑over, flow control, SSH targets, and TELNET listeners.
  • When users access an SSH listener, the connecting client may supply a password or present public keys for authentication. These authentication attempts are currently logged, but are not otherwise used by the proxy. A future update may allow for passwords and public keys to be used for pre‑authentication or to influence target routing.

  • While TELNET protocol support will improve in the future, there are no plans to support the linemode, environment, authentication, or encryption features at this time.
    • If you need these features, you should look into C‑Kermit or Kermit 95.
    • Although directly executing programs isn’t something on the roadmap, it’s not difficult to use socat creatively to connect C‑Kermit to the proxy using a UNIX domain socket (i.e., socat UNIX‑LISTEN:socket,fork,reuseaddr EXEC:kermit,pty,setsid,echo=0,rawer,opost=1,icrnl=1,onlcr,cread).
    • ⚠️ Be aware that doing this securely—safe for public usage—is more involved than one might imagine. Safely configuring the proxy for this type of operation is possible, but beyond the scope of this documentation.

Development

Required
  • For proxy development, along with the most recent version of Go, you’ll also need to have a standard POSIX.1 shell environment (at a minimum sh, make, diff, grep, awk, & sed), and reuse, staticcheck, gopls, revive, errcheck, gofumpt, govulncheck, NilAway, scc, scspell, codespell, and Perl.
  • If you plan to make any changes to the Makefile (or .cross.sh and other scripts), you’ll need to have the ShellCheck and shfmt linters available.
  • Additionally, all modifications to the Makefile and .cross.sh and other scripts must be tested against pdpmake (with PDPMAKE_POSIXLY_CORRECT set) and yash to ensure POSIX conformance.
  • The Makefile provides a lint convenience target to help you run all this. You can also examine our .gitlab-ci.yml file. There is also a convenience script, .lintsetup.sh, to help install the Go-based linters, and the Python-based linters can be installed via pip (i.e., pip install --upgrade scspell3k codespell reuse).
  • Source code tags are generated using gogtags and gotags (or universal-ctags) if installed.
  • While not absolutely required, it’s a good idea to have the latest golangci-lint (v2) installed. We ship a config file file for it, and try to make sure that all the tests pass when using the most recently released version.
  • It’s also recommended to (manually) use hunspell for spell checking—in addition to using codespell and scspell.

Security

Licenses

Documentation

Overview

DPS8M Proxy

DPS8M Proxy

DPS8M Proxy

DPS8M Proxy

DPS8M Proxy

DPS8M Proxy

DPS8M Proxy

DPS8M Proxy

DPS8M Proxy

DPS8M Proxy