183 lines
6.2 KiB
Markdown
183 lines
6.2 KiB
Markdown
# SecLink Proxy -- Linux Serial Bridge
|
|
|
|
Linux-hosted proxy that bridges an 86Box emulated serial port to a
|
|
remote telnet BBS. Part of the DVX GUI project.
|
|
|
|
The 86Box side communicates using the SecLink protocol (HDLC packet
|
|
framing, CRC-16, DH key exchange, XTEA-CTR encryption). The BBS side
|
|
is plain telnet over TCP. All crypto is transparent to the BBS -- it
|
|
sees a normal telnet client.
|
|
|
|
|
|
## Architecture
|
|
|
|
```
|
|
86Box (DOS terminal) Remote BBS
|
|
| |
|
|
emulated modem telnet
|
|
| |
|
|
TCP:2323 TCP:23
|
|
| |
|
|
+--- secproxy ----------------------------------+
|
|
secLink <-> plaintext
|
|
(encrypted, reliable)
|
|
```
|
|
|
|
The proxy accepts a single TCP connection from 86Box, performs the
|
|
SecLink handshake (Diffie-Hellman 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 with IAC negotiation handling.
|
|
|
|
|
|
## Usage
|
|
|
|
```
|
|
secproxy [listen_port] [bbs_host] [bbs_port]
|
|
```
|
|
|
|
| Argument | Default | Description |
|
|
|---------------|--------------|---------------------------------|
|
|
| `listen_port` | 2323 | TCP port for 86Box connection |
|
|
| `bbs_host` | 10.1.0.244 | BBS hostname or IP |
|
|
| `bbs_port` | 2023 | BBS TCP port |
|
|
|
|
Examples:
|
|
|
|
```
|
|
secproxy # all defaults
|
|
secproxy 5000 # listen on port 5000
|
|
secproxy 2323 bbs.example.com 23 # different BBS
|
|
secproxy --help # show usage
|
|
```
|
|
|
|
|
|
## Startup Sequence
|
|
|
|
1. Listen on the configured TCP port.
|
|
2. Wait for 86Box to connect (polls with Ctrl+C support).
|
|
3. Map the TCP socket to COM0 via the socket shim.
|
|
4. Seed the RNG from `/dev/urandom`.
|
|
5. Open SecLink and perform the DH handshake (blocks until the DOS
|
|
side completes its handshake).
|
|
6. Wait for the terminal to send ENTER (so the user can confirm the
|
|
connection is working before BBS output starts).
|
|
7. Connect to the remote BBS.
|
|
8. 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, then the telnet
|
|
filter strips IAC sequences, then `secLinkSend()` encrypts and sends
|
|
to 86Box via the socket shim. If the send window is full, the loop
|
|
retries with ACK processing until the data goes through.
|
|
- **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.
|
|
|
|
|
|
## Telnet Negotiation
|
|
|
|
The proxy handles RFC 854 telnet IAC sequences from the BBS so they
|
|
do not corrupt the terminal display. A state machine parser strips
|
|
IAC sequences from the data stream, persisting state across TCP
|
|
segment boundaries.
|
|
|
|
Accepted options:
|
|
|
|
- ECHO (option 1) -- server echoes characters
|
|
- SGA (option 3) -- suppress go-ahead for character-at-a-time mode
|
|
- TTYPE (option 24) -- terminal type negotiation
|
|
- NAWS (option 31) -- window size negotiation
|
|
|
|
All other options are refused. Subnegotiations (SB...SE) are consumed
|
|
silently.
|
|
|
|
|
|
## 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 functions backed by TCP sockets instead of UART
|
|
hardware:
|
|
|
|
| rs232 function | Socket shim behavior |
|
|
|----------------|-----------------------------------------------|
|
|
| `rs232Open()` | Validates socket assigned; ignores serial params |
|
|
| `rs232Close()` | Marks port closed (socket lifecycle is caller's) |
|
|
| `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. Up to 4 ports are supported.
|
|
|
|
The Makefile uses `-include sockShim.h` when compiling the packet and
|
|
secLink layers, which defines `RS232_H` to prevent the real `rs232.h`
|
|
from being included.
|
|
|
|
|
|
## DJGPP Stubs
|
|
|
|
DOS-specific headers required by the security library are replaced by
|
|
minimal stubs in `stubs/`:
|
|
|
|
| Stub | Replaces DJGPP header | Contents |
|
|
|-------------------|------------------------|-------------------|
|
|
| `stubs/pc.h` | `<pc.h>` | No-op definitions |
|
|
| `stubs/go32.h` | `<go32.h>` | No-op definitions |
|
|
| `stubs/sys/farptr.h` | `<sys/farptr.h>` | No-op definitions |
|
|
|
|
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.
|
|
|
|
|
|
## 86Box Configuration
|
|
|
|
Configure the 86Box serial port to connect to the proxy:
|
|
|
|
1. In 86Box settings, set a COM port to TCP client mode pointing at
|
|
the proxy's listen port (default 2323).
|
|
2. Enable "No telnet negotiation" to send raw bytes.
|
|
3. The DOS terminal application running inside 86Box uses SecLink
|
|
over this serial port.
|
|
|
|
|
|
## 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 beyond the project's own packet, security, and secLink
|
|
source files, which are compiled directly from their source directories.
|
|
|
|
|
|
## Files
|
|
|
|
```
|
|
proxy/
|
|
proxy.c main proxy program
|
|
sockShim.h rs232-compatible socket API (header)
|
|
sockShim.c socket shim implementation
|
|
Makefile Linux native 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>
|
|
```
|