| .. | ||
| stubs | ||
| Makefile | ||
| proxy.c | ||
| README.md | ||
| sockShim.c | ||
| sockShim.h | ||
SecLink Proxy
Linux-hosted proxy that bridges an 86Box emulated serial port to a remote telnet BBS. The 86Box side communicates using the secLink protocol (packet framing, DH key exchange, XTEA encryption). The BBS side is plain telnet over TCP.
Architecture
86Box (DOS terminal) Remote BBS
| |
emulated modem telnet:23
| |
TCP:2323 TCP:23
| |
+--- secproxy ----------------------------------+
secLink ←→ plaintext
(encrypted, reliable)
The proxy accepts a single TCP connection from 86Box, performs the secLink handshake (DH key exchange), then connects to the BBS. All traffic between 86Box and the proxy is encrypted via XTEA-CTR on channel 0. Traffic between the proxy and the BBS is unencrypted telnet.
Usage
secproxy [listen_port] [bbs_host] [bbs_port]
| Argument | Default | Description |
|---|---|---|
listen_port |
2323 | TCP port for 86Box connection |
bbs_host |
bbs.duensing.digital | BBS hostname |
bbs_port |
23 | BBS TCP port |
secproxy # all defaults
secproxy 5000 # listen on port 5000
secproxy 2323 bbs.example.com 23 # different BBS
secproxy --help # show usage
Startup Sequence
- Listen on the configured TCP port
- Wait for 86Box to connect (blocks on accept)
- Connect to the remote BBS
- Seed the RNG from
/dev/urandom - Open secLink and perform the DH handshake (blocks until the DOS side completes its handshake)
- Enter the proxy loop
Proxy Loop
The main loop uses poll() with a 10ms timeout to multiplex between
the two TCP connections:
- 86Box → BBS:
secLinkPoll()reads from the 86Box socket via the socket shim, decrypts incoming packets, and the receive callback writes plaintext to the BBS socket. - BBS → 86Box:
read()from the BBS socket, thensecLinkSend()encrypts and sends to 86Box via the socket shim. - Maintenance:
secLinkPoll()also handles packet-layer retransmit timers on every iteration.
The proxy exits cleanly on Ctrl+C (SIGINT), SIGTERM, or when either side disconnects.
86Box Configuration
Configure the 86Box serial port to use a telnet connection:
- In 86Box settings, set a COM port to "TCP (server)" or "TCP (client)" mode pointing at the proxy's listen port
- Enable "No telnet negotiation" to send raw bytes
- The DOS terminal application running inside 86Box uses secLink over this serial port
Socket Shim
The proxy reuses the same packet, security, and secLink source code
as the DOS build. A socket shim (sockShim.h/sockShim.c) provides
rs232-compatible rs232Read()/rs232Write() functions backed by TCP
sockets instead of UART hardware:
| rs232 function | Socket shim behavior |
|---|---|
rs232Open() |
No-op (socket already connected) |
rs232Close() |
Marks port closed (socket managed by caller) |
rs232Read() |
Non-blocking recv() with MSG_DONTWAIT |
rs232Write() |
Blocking send() loop with MSG_NOSIGNAL |
The shim maps COM port indices (0-3) to socket file descriptors via
sockShimSetFd(), which must be called before opening the secLink
layer.
DOS-specific headers (<pc.h>, <go32.h>, <sys/farptr.h>) are
replaced by minimal stubs in stubs/ that provide no-op
implementations. The security library's hardware entropy function
returns zeros on Linux, which is harmless since the proxy seeds the
RNG from /dev/urandom before the handshake.
Building
make # builds ../bin/secproxy
make clean # removes objects and binary
Objects are placed in ../obj/proxy/, the binary in ../bin/.
Requires only a standard Linux C toolchain (gcc, libc). No external dependencies.
Files
proxy/
proxy.c main proxy program
sockShim.h rs232-compatible socket API (header)
sockShim.c socket shim implementation
Makefile Linux build
stubs/
pc.h stub for DJGPP <pc.h>
go32.h stub for DJGPP <go32.h>
sys/
farptr.h stub for DJGPP <sys/farptr.h>