https://gitlab.synchro.net/main/sbbs/-/commit/facce791262fb43be1302556
Modified Files:
src/ssh/README.md deucessh-conn.h ssh-conn.c ssh-internal.h src/ssh/test/test_chan.c test_conn.c
Log Message:
DeuceSSH: rx-window enforcement + DSSH_PARAM_ACCEPT_EARLY_DATA
Two related changes that together let DeuceSSH clients tolerate
servers that begin sending CHANNEL_DATA before the terminal-request
response, while otherwise tightening rx-side window handling.
1. Universal rx-window truncation.
handle_channel_data and handle_channel_extended_data now clip the
inbound payload length to the locally-advertised window before
invoking the ZC callback. A peer that ignores the window can no
longer drive the library into unbounded buffering -- bytes past
the window are silently dropped and never reach the bytebuf. The
ZC callback contract is widened (and the typedef comment updated)
to allow len == 0 or len < wire-payload; in-tree consumers
(stream_zc_cb) already handled both safely.
2. Per-channel DSSH_PARAM_ACCEPT_EARLY_DATA opt-in (flag 0x02 + new
dssh_chan_params_set_accept_early_data setter).
Cryptlib-based servers that don't wait for
CRYPT_SESSINFO_SSH_CHANNEL_TYPE to be set before sending (such as
Mystic BBS) emit banner data immediately after CHANNEL_OPEN_
CONFIRMATION, while local_window is still 0. The flag asks the
library to deliver pre-setup data anyway: while
ch->setup_complete is still false, handle_channel_data /
handle_channel_extended_data take a bypass branch that delivers
the full dlen, leaves local_window untouched (no credit returned
to the peer), and skips the ZC WINDOW_ADJUST. Once
send_window_adjust at the end of dssh_chan_open / dssh_chan_zc_
open succeeds, setup_complete latches true and the bypass
disengages permanently.
Type-locked at chan_open entry: the flag is rejected (NULL
return) for DSSH_CHAN_SUBSYSTEM since subsystem channels use a
message queue and have no coherent destination for pre-setup
bytes.
init_channel_buffers is hoisted unconditionally to before
open_session_channel so the bytebufs exist when the first DATA
arrives. Universal rx-truncation makes this a behavioural no-op
for non-flagged channels (early data is clipped to len == 0
before stream_zc_cb runs, so the freshly-allocated bytebuf is
harmless). The flag is the only thing that punches a hole in
that, and only while !setup_complete.
7 new tests:
- params_set_accept_early_data: setter toggles the bit, NULL guard
- rx_truncation/default: closed window drops everything
- rx_truncation/clips_to_window: dlen > local_window clipped to 4
- rx_bypass/pre_setup: flagged + !setup_complete delivers full
payload, local_window untouched
- rx_bypass/disengages_post_setup: flagged + setup_complete drops
again
- early_data/type_lock_subsystem: dssh_chan_open returns NULL for
SUBSYSTEM + ACCEPT_EARLY_DATA
OpenSSL: 3410/3410 pass. Botan: 3411/3411 pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <
noreply@anthropic.com>
---
þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net