ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
connection.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file connection.h
6 * @brief RFC 4254 connection protocol: channel multiplexing, windows, and port forwarding.
7 */
8
9#ifndef PROTOCORE_CONNECTION_CONNECTION_H
10#define PROTOCORE_CONNECTION_CONNECTION_H
11
13
15
16// ---------------------------------------------------------------------------
17// RFC 4254 sec 5.2 - the window pair
18// ---------------------------------------------------------------------------
19
20/** @brief One channel's flow-control state (RFC 4254 sec 5.2). */
21typedef struct
22{
23 uint32_t local_window; ///< Bytes the peer may still send us before we WINDOW_ADJUST.
24 uint32_t local_max; ///< The window we advertised, and replenish back up to.
25 uint32_t peer_window; ///< Bytes we may still send the peer.
26 uint32_t peer_max_pkt; ///< Peer's maximum packet size; caps a single send independently of the window.
27} SshFlow;
28
29/**
30 * @brief Start a channel's windows: ours at @p local_window, the peer's at what it advertised.
31 *
32 * The local window is a parameter rather than a baked-in constant because the server and the
33 * client advertise different sizes, and the value we replenish to must be the value we told the
34 * peer about. Passing it here keeps the two from drifting apart.
35 *
36 * @param local_window what we advertise in CHANNEL_OPEN / CONFIRMATION; also the replenish target.
37 * @param peer_window the peer's initial window from CHANNEL_OPEN / CONFIRMATION.
38 * @param peer_max_pkt the peer's maximum packet size from the same message.
39 */
40
41/**
42 * @brief Account @p n inbound bytes against our window.
43 *
44 * @return false if @p n exceeds what we advertised - the peer overran the window (RFC 4254 sec 5.2)
45 * and the caller must fail the channel. The window is left untouched on failure.
46 */
47
48/**
49 * @brief Decide whether a WINDOW_ADJUST is due, and for how much. Does not mutate.
50 *
51 * Replenishes once the window has drained past half, which keeps a bulk transfer from stalling
52 * without emitting an adjust per packet.
53 *
54 * Pair it with protocore_ssh_flow_local_credit() only after the adjust has actually gone out. Deciding and
55 * crediting are separate because on some paths the send can fail, and crediting first would leave us
56 * believing we advertised bytes the peer never heard about - the peer then stops at its smaller
57 * window while we wait for data, and the transfer deadlocks.
58 *
59 * @return true if a WINDOW_ADJUST is due; @p *add receives the delta to advertise.
60 */
61
62/** @brief Credit our window by @p add, once that WINDOW_ADJUST has actually been sent. */
63
64/** @brief True if @p len bytes fit both the peer's remaining window and its maximum packet size. */
65
66/**
67 * @brief Clamp a would-be send to what the peer currently permits.
68 *
69 * A producer that pulls from a local source sizes its read to this, so it never reads bytes it
70 * cannot legally forward. Returns 0 when the window is closed, which the caller treats as
71 * "stop pumping until a WINDOW_ADJUST arrives".
72 *
73 * @return min(@p want, peer window, peer maximum packet size).
74 */
75
76/** @brief Account @p n outbound bytes against the peer's window (call only after send_allows()). */
77
78/**
79 * @brief Credit the peer's window from an inbound WINDOW_ADJUST.
80 *
81 * Saturates at UINT32_MAX rather than wrapping: a peer advertising a total past 2^32 is out of spec,
82 * and wrapping would hand us a tiny window and stall the transfer.
83 */
84
85// ---------------------------------------------------------------------------
86// Channel signaling (RFC 4254 sec 5)
87//
88// Every channel-related message is a transition on the window state above: OPEN / OPEN_CONFIRMATION
89// establish it (they carry the initial window and maximum packet size), WINDOW_ADJUST increments it,
90// DATA consumes it, EOF / CLOSE terminate it. Because the transitions and the state are the same
91// concern, they live together - the RFC's rule that no data may be sent until the window allows it is
92// only enforceable where the window is.
93//
94// These take the flow plus the ids the wire carries, never a channel struct: resolving a recipient
95// channel number to a channel is multiplexing, and that stays in ssh_channel.
96// ---------------------------------------------------------------------------
97
98// The connection protocol's message numbers (RFC 4250 §4.1.1: 80 to 89 generic, 90 to 127 channel
99// related). They sit with the builders below, which are what write them onto the wire.
100
101/** @brief CHANNEL_OPEN_FAILURE. @p reason: 1 admin-prohibited, 2 connect-failed, 3 unknown-type, 4 resource. */
102int32_t protocore_ssh_sig_build_open_failure(uint8_t *out, size_t cap, uint32_t peer_id, uint32_t reason,
103 size_t *out_len);
104
105/** @brief CHANNEL_OPEN_CONFIRMATION, advertising our current window and maximum packet size. */
106int32_t protocore_ssh_sig_build_open_confirm(const SshFlow *f, uint32_t peer_id, uint32_t local_id, uint8_t *out,
107 size_t cap, size_t *out_len);
108
109/**
110 * @brief CHANNEL_DATA carrying @p len bytes, and account them against the peer's window.
111 *
112 * Refuses when the send would exceed the peer's window or its maximum packet size, so the RFC 4254
113 * sec 5.2 limit cannot be violated by any caller - the check and the debit are one step here.
114 */
115int32_t protocore_ssh_sig_build_data(SshFlow *f, uint32_t peer_id, const uint8_t *data, size_t len, uint8_t *out,
116 size_t cap, size_t *out_len);
117
118/** @brief CHANNEL_WINDOW_ADJUST granting @p add more bytes. Credit the window only once this is sent. */
119int32_t protocore_ssh_sig_build_window_adjust(uint32_t peer_id, uint32_t add, uint8_t *out, size_t cap,
120 size_t *out_len);
121
122/** @brief CHANNEL_EOF, as one 5-byte message. */
123int32_t protocore_ssh_sig_build_eof(uint32_t peer_id, uint8_t *out, size_t cap, size_t *out_len);
124
125/** @brief CHANNEL_CLOSE, as one 5-byte message. */
126int32_t protocore_ssh_sig_build_close(uint32_t peer_id, uint8_t *out, size_t cap, size_t *out_len);
127
128// ---------------------------------------------------------------------------
129// RFC 4254 sec 5 - channel multiplexing
130// ---------------------------------------------------------------------------
131
132/** @brief Channel type (RFC 4254). */
134{
135 SSH_CHAN_SESSION = 0, ///< "session" - shell / exec / data
136 SSH_CHAN_DIRECT_TCPIP = 1, ///< "direct-tcpip" - client-initiated TCP forward (ssh -L)
137 SSH_CHAN_FORWARDED_TCPIP = 2 ///< "forwarded-tcpip" - server-initiated TCP forward (ssh -R)
139
140/**
141 * @brief What a session channel's sec 6 request bound to it, if anything.
142 *
143 * These are not channel types: sec 5.1 names the type on the wire, and a file-transfer service is
144 * a sec 6.5 "subsystem" or `exec` request arriving later on a channel already open as "session".
145 * The type says how the channel was opened; this says what its data means.
146 */
148{
149 SSH_CHAN_SERVICE_NONE = 0, ///< shell / exec output, handed to the channel-data callback
150 SSH_CHAN_SERVICE_SFTP = 1, ///< subsystem "sftp" (PROTOCORE_ENABLE_SSH_SFTP)
151 SSH_CHAN_SERVICE_SCP = 2 ///< exec "scp ..." (PROTOCORE_ENABLE_SSH_SCP)
153
154/** @brief Per-connection channel state. */
155typedef struct
156{
157 proto_bool open; ///< True once the channel is confirmed open both ways.
158 proto_bool pending; ///< True for a server-initiated channel we opened, awaiting the client's confirmation.
159 SshChanType type; ///< session, direct-tcpip, or forwarded-tcpip.
160 SshChanService service; ///< What a sec 6 request bound over a session channel, if anything.
161 uint32_t local_id; ///< Our channel id (== slot index).
162 uint32_t peer_id; ///< Client's channel id.
163 SshFlow flow; ///< RFC 4254 sec 5.2 window pair (owner: ssh_flow_control.*).
164 proto_bool eof_sent; ///< We sent CHANNEL_EOF (RFC 4254 sec 5.3).
165 proto_bool relay_eof; ///< The peer sent CHANNEL_EOF.
166 // sec 5.3: "The channel is considered closed for a party when it has both sent and received
167 // SSH_MSG_CHANNEL_CLOSE, and the party may then reuse the channel number." One latch each, so
168 // the number is not handed out again while the peer's CLOSE is still in flight.
169 proto_bool close_sent; ///< We sent CHANNEL_CLOSE.
170 proto_bool close_received; ///< The peer sent CHANNEL_CLOSE.
171 // sec 6.2: a terminal allocated for this session, and the dimensions sec 6.7 updates. The
172 // dimensions are "only informational", so they are carried, not acted on, by this layer.
173 proto_bool pty; ///< A "pty-req" was accepted on this channel.
174 uint32_t width_chars; ///< terminal width, characters
175 uint32_t height_rows; ///< terminal height, rows
176 uint32_t width_px; ///< terminal width, pixels
177 uint32_t height_px; ///< terminal height, pixels
178} SshChannel;
179
180/** @brief Channel pool: PROTOCORE_SSH_MAX_CHANNELS channels per SSH connection (BSS).
181 * Owned by this layer; src/ code routes through the functions below, never the
182 * array (tests inspect it white-box). Index: [connection slot][channel slot]. */
184
185/** @brief Application callback for inbound channel data (raw bytes), tagged with
186 * the channel id it arrived on. */
187typedef void (*SshChannelDataCb)(uint8_t slot, uint32_t channel, const uint8_t *data, size_t len);
188/** @brief Install the inbound-data callback (session channels). */
189
190/**
191 * @brief "direct-tcpip" forward request: a client asked the server to open a TCP
192 * connection to @p host : @p port (ssh -L). The forwarding owner (which
193 * does the actual TCP I/O - this codec does not) decides whether to allow
194 * it; @p host is not NUL-terminated (@p host_len bytes).
195 * @return 0 to accept (the channel is opened and confirmed), < 0 to refuse
196 * (CHANNEL_OPEN_FAILURE, administratively prohibited / connect failed).
197 *
198 * If no callback is installed, all forward requests are refused - so forwarding is
199 * opt-in (no open relay by default).
200 */
201typedef int (*SshForwardOpenCb)(uint8_t slot, uint32_t channel, const char *host, size_t host_len, uint16_t port);
202/** @brief Inbound data on a direct-tcpip channel (the owner writes it to the
203 * forwarded TCP socket). Kept separate from the session data callback. */
204typedef void (*SshForwardDataCb)(uint8_t slot, uint32_t channel, const uint8_t *data, size_t len);
205/** @brief Install the direct-tcpip forward open-policy callback (opt-in). */
206
207/** @brief Install the direct-tcpip forward inbound-data callback. */
208
209/**
210 * @brief "tcpip-forward" remote-forward request (ssh -R): the client asks the server
211 * to listen on @p bind_addr : @p bind_port and open a channel back for each
212 * accepted connection (RFC 4254 §7.1). @p bind_addr is @p addr_len bytes (not
213 * NUL-terminated). The forwarding owner (which allocates the real listener -
214 * this codec does no I/O) decides.
215 * @return the bound port on success (echo @p bind_port, or the port the owner picked
216 * when @p bind_port == 0), or < 0 to refuse. If no callback is installed every
217 * request is refused, so remote forwarding is opt-in (no listener is opened).
218 */
219typedef int (*SshRemoteForwardOpenCb)(uint8_t slot, const char *bind_addr, size_t addr_len, uint16_t bind_port);
220/** @brief "cancel-tcpip-forward" request (RFC 4254 §7.1): drop a remote forward.
221 * @return 0 if a matching forward was cancelled, < 0 if none / unsupported. */
222typedef int (*SshRemoteForwardCancelCb)(uint8_t slot, const char *bind_addr, size_t addr_len, uint16_t bind_port);
223/** @brief Install the remote-forward (ssh -R) open-policy callback (opt-in). */
224
225/** @brief Install the remote-forward (ssh -R) cancel callback (opt-in). */
226
227/**
228 * @brief Result of the client's reply to a server-initiated forwarded-tcpip channel:
229 * @p ok = true on CHANNEL_OPEN_CONFIRMATION (the bridge may start), false on
230 * CHANNEL_OPEN_FAILURE (the owner tears the bridge down). @p channel is the
231 * local id returned by protocore_ssh_channel_open_forwarded().
232 */
233typedef void (*SshForwardConfirmCb)(uint8_t slot, uint32_t channel, proto_bool ok);
234/** @brief Install the forwarded-tcpip open-confirmation callback (opt-in, ssh -R). */
235
236/** @brief A `subsystem "sftp"` request was accepted on @p channel; the binding starts an SFTP session. */
237typedef void (*SshSftpOpenCb)(uint8_t slot, uint32_t channel);
238/** @brief Inbound bytes on an SFTP channel (the raw SSH_FXP_* stream) - kept out of the session data cb. */
239typedef void (*SshSftpDataCb)(uint8_t slot, uint32_t channel, const uint8_t *data, size_t len);
240
241#if PROTOCORE_ENABLE_SSH_SFTP
242/** @brief The registered sftp-open callback, or null; fired when sec 6.5 names the subsystem. */
243SshSftpOpenCb protocore_ssh_channel_sftp_open_cb(void);
244#endif
245
246/** @brief An `exec "scp …"` request was accepted on @p channel (@p cmd is @p cmd_len bytes, not NUL-terminated). */
247typedef void (*SshScpOpenCb)(uint8_t slot, uint32_t channel, const char *cmd, size_t cmd_len);
248/** @brief Inbound bytes on an SCP channel (the RCP protocol stream). */
249typedef void (*SshScpDataCb)(uint8_t slot, uint32_t channel, const uint8_t *data, size_t len);
250
251#if PROTOCORE_ENABLE_SSH_SCP
252/** @brief The registered scp-open callback, or null; fired when sec 6.5 names an scp command. */
253SshScpOpenCb protocore_ssh_channel_scp_open_cb(void);
254#endif
255
256/**
257 * @brief Open a server-initiated "forwarded-tcpip" channel (RFC 4254 §7.2, ssh -R).
258 *
259 * Allocates a local channel on connection @p i (state = pending, awaiting the
260 * client's confirmation) and builds the SSH_MSG_CHANNEL_OPEN in @p out.
261 * @p conn_addr / @p conn_port are the forward's bound address/port (the "address
262 * that was connected"); @p orig_addr / @p orig_port are the peer that connected.
263 *
264 * @return the local channel id (>= 0) on success, or -1 (pool full, or @p out too
265 * small). On success the caller emits @p out and, on the eventual confirm,
266 * bridges bytes on the returned channel.
267 */
268
269/**
270 * @brief Handle SSH_MSG_CHANNEL_OPEN_CONFIRMATION for a channel we opened (ssh -R).
271 *
272 * Matches the pending channel by our recipient id, records the peer's channel id /
273 * window / max-packet, and marks it open. Fires the confirm callback (@p ok = true).
274 * @return 0 on success, -1 if malformed or no matching pending channel.
275 */
276
277/**
278 * @brief Handle SSH_MSG_CHANNEL_OPEN_FAILURE for a channel we opened (ssh -R).
279 *
280 * Frees the pending channel and fires the confirm callback (@p ok = false).
281 * @return 0 on success, -1 if malformed or no matching pending channel.
282 */
283
284/**
285 * @brief Handle SSH_MSG_GLOBAL_REQUEST (RFC 4254 §4).
286 *
287 * Parses the request name and want_reply flag. "tcpip-forward" /
288 * "cancel-tcpip-forward" are routed to the remote-forward seam above (accepted only
289 * when a callback is installed); a "tcpip-forward" that bound port 0 gets its
290 * allocated port echoed in the reply (RFC 4254 §7.1). Any other request name is
291 * unrecognized: per §4 it is answered with SSH_MSG_REQUEST_FAILURE when want_reply is
292 * set, and silently ignored otherwise (never SSH_MSG_UNIMPLEMENTED - GLOBAL_REQUEST is
293 * a known message type; only the request name is unknown).
294 *
295 * @return 0 on success (a reply is in @p out with *@p out_len bytes, or *@p out_len is
296 * 0 when no reply is due), -1 if the message is malformed.
297 */
298
299/**
300 * @brief Bind a sec 6.5 file-transfer service to an open channel.
301 *
302 * The channel was opened as "session" (sec 5.1); the request that names the service arrives later,
303 * and this records which one so inbound CHANNEL_DATA routes to its binding rather than to the
304 * channel-data callback. This layer owns the channel record, so the request handler above it asks
305 * rather than writes.
306 *
307 * @return 0 on success, -1 when the channel is closed or unknown.
308 */
309
310/** @brief Reset channel state for slot @p i. */
311
312/** @brief The open channel @p id on connection @p i, or null. Local id == slot index. */
313
314/**
315 * @brief First free channel slot on connection @p i, or -1 if the pool is full. A pending
316 * (opened-but-unconfirmed) channel is in use just like an open one.
317 */
318
319/**
320 * @brief Handle SSH_MSG_CHANNEL_OPEN and emit CHANNEL_OPEN_CONFIRMATION.
321 *
322 * Accepts a "session" channel; any other type yields CHANNEL_OPEN_FAILURE.
323 * @return 0 if a response was produced, -1 if malformed.
324 */
325
326// RFC 4250 sec 4.9.3 lists pty-req, env, shell, exec and subsystem under "Connection Protocol
327// Channel Request Names", so what each carries after want_reply is this layer's to check. Both
328// answer one question: are the fields the section names present and whole.
329
330/** @brief Read @p n consecutive strings from @p off: true when every one is present and whole. */
331
332/** @brief RFC 4254 sec 6.2: string TERM, four uint32 dimensions, string encoded terminal modes. */
333
334// ---------------------------------------------------------------------------
335// RFC 4254 sec 6.2 / sec 6.7 / sec 8 - the pseudo-terminal a session channel carries
336// ---------------------------------------------------------------------------
337
338/**
339 * @brief The terminal a "pty-req" asked for, as sec 6.2 orders its fields.
340 *
341 * "Zero dimension parameters MUST be ignored. The character/row dimensions override the pixel
342 * dimensions (when nonzero)." Both pairs are kept as they arrived; a consumer applies that rule.
343 */
344typedef struct
345{
346 char term[PROTOCORE_SSH_PTY_TERM_MAX]; ///< TERM value, null-terminated, truncated to fit.
347 uint32_t width_chars; ///< terminal width, characters
348 uint32_t height_rows; ///< terminal height, rows
349 uint32_t width_px; ///< terminal width, pixels
350 uint32_t height_px; ///< terminal height, pixels
351 const uint8_t *modes; ///< encoded terminal modes, pointing into the request
352 uint32_t modes_len; ///< length of modes
354
355/**
356 * @brief Walk an encoded terminal-mode stream (RFC 4254 sec 8) and report whether it is well formed.
357 *
358 * "Opcodes 1 to 159 have a single uint32 argument. Opcodes 160 to 255 are not yet defined, and cause
359 * parsing to stop... The stream is terminated by opcode TTY_OP_END (0x00)." Only a truncated
360 * argument makes a stream malformed. A stream that runs out before its terminator is accepted for
361 * what it did carry, and an empty one is well formed: it sets no modes.
362 *
363 * @param modes Encoded stream.
364 * @param len Bytes in @p modes.
365 * @param consumed Set to the bytes parsed before TTY_OP_END or an undefined opcode. May be null.
366 */
367
368/**
369 * @brief Parse a "pty-req" body (sec 6.2) starting at @p off.
370 * @return true when every field is present and whole and the mode stream parses.
371 */
372
373/**
374 * @brief Parse a "window-change" body (sec 6.7): four uint32 dimensions, no reply.
375 * @return true when all four are present.
376 */
377
378/** @brief An accepted "pty-req" on channel @p channel. Return false to refuse the terminal. */
379typedef proto_bool (*SshPtyReqCb)(uint8_t i, uint32_t channel, const SshPtyRequest *pty);
380
381/** @brief A "window-change" (sec 6.7) on a channel that already has a terminal. */
382typedef void (*SshWindowChangeCb)(uint8_t i, uint32_t channel, uint32_t width_chars, uint32_t height_rows,
383 uint32_t width_px, uint32_t height_px);
384
385/** @brief Install the sec 6.2 handler. Without one a "pty-req" is refused: no terminal exists. */
386
387/** @brief Install the sec 6.7 handler. */
388
389/** @brief The terminal dimensions channel @p channel carries, or false when it has no pty. */
390
391// ---------------------------------------------------------------------------
392// RFC 4254 sec 6.10 - returning exit status
393// ---------------------------------------------------------------------------
394
395/**
396 * @brief Send "exit-status" for a command that has terminated (RFC 4254 sec 6.10).
397 *
398 * "When the command running at the other end terminates, the following message can be sent to
399 * return the exit status of the command. Returning the status is RECOMMENDED. No acknowledgement is
400 * sent for this message. The channel needs to be closed with SSH_MSG_CHANNEL_CLOSE after this
401 * message." want_reply is FALSE, as the section fixes it.
402 *
403 * @return 0 on success, -1 when the channel is closed or the stream is gone.
404 */
405
406/**
407 * @brief Send "exit-signal" for a command killed by a signal (RFC 4254 sec 6.10).
408 *
409 * @param signal_name Signal name without the "SIG" prefix, as sec 6.10 lists them.
410 * @param core_dumped Whether the command dumped core.
411 * @param err_msg Error message in UTF-8; may be null for an empty one.
412 * @return 0 on success, -1 when the channel is closed, the stream is gone, or the names do not fit.
413 */
414
415#if PROTOCORE_ENABLE_SSH_SFTP || PROTOCORE_ENABLE_SSH_SCP
416/**
417 * @brief Tag @p c and fire the open callback when a sec 6.5 request names a file-transfer service.
418 *
419 * Declared here and implemented above, in the layer that owns those services. RFC 4251 sec 1 puts
420 * the connection protocol beneath them, so this layer reaches up through a hook it declares rather
421 * than including a header from the layer above. @p off points at the request-specific argument and
422 * may be advanced; *@p accept is raised for a subsystem the base set does not already admit.
423 */
424#endif
425
426/**
427 * @brief Handle SSH_MSG_CHANNEL_REQUEST.
428 *
429 * "shell", "exec", "pty-req", and "env" are accepted; anything else is refused - except that when
430 * PROTOCORE_ENABLE_SSH_SFTP is set a `subsystem "sftp"` is accepted (the channel binds SSH_CHAN_SERVICE_SFTP and the
431 * sftp-open callback fires), and when PROTOCORE_ENABLE_SSH_SCP is set an `exec "scp …"` is additionally tagged
432 * SSH_CHAN_SERVICE_SCP (the scp-open callback fires with the command). When want_reply is set, CHANNEL_SUCCESS /
433 * CHANNEL_FAILURE is written to @p out and *@p out_len > 0; otherwise *@p out_len is 0.
434 * @return 0 on success, -1 if malformed.
435 */
436
437/**
438 * @brief Handle SSH_MSG_CHANNEL_DATA: bounds-check, update the window, and
439 * invoke the data callback. If the local window is exhausted a
440 * CHANNEL_WINDOW_ADJUST is written to @p out (*@p out_len > 0).
441 * @return 0 on success, -1 if malformed or channel not open.
442 */
443
444/**
445 * @brief Handle SSH_MSG_CHANNEL_EXTENDED_DATA (RFC 4254 §5.2): bounds-check, update
446 * the window, and discard the payload. The data_type_code selects a stream
447 * this end does not surface, so the bytes are accounted for and dropped. If
448 * the local window is exhausted a CHANNEL_WINDOW_ADJUST is written to @p out
449 * (*@p out_len > 0).
450 * @return 0 on success, -1 if malformed or channel not open.
451 */
452
453/**
454 * @brief Build an SSH_MSG_CHANNEL_DATA message carrying @p data to the client on
455 * channel @p channel (a local channel id from a prior open).
456 * @return 0 on success, -1 if the channel is closed/unknown, the peer window is
457 * too small, or @p out is too small.
458 */
459
460/**
461 * @brief Handle SSH_MSG_CHANNEL_WINDOW_ADJUST (grows the peer window).
462 * @return 0 on success, -1 if malformed.
463 */
464
465/**
466 * @brief Build SSH_MSG_CHANNEL_EOF for channel @p channel and latch that we sent it.
467 * The channel stays open (RFC 4254 sec 5.3).
468 * @return 0 on success, -1 if the channel is closed/unknown or @p out is too small.
469 */
470
471/**
472 * @brief Build SSH_MSG_CHANNEL_CLOSE for channel @p channel and mark it closed.
473 * @return 0 on success, -1 if the channel is closed/unknown or @p out is too small.
474 */
475
476/** @brief Bytes in SSH_MSG_CHANNEL_EOF: the message number and the recipient channel. */
477#define SSH_CHANNEL_EOF_LEN 5u
478
479/** @brief Bytes in SSH_MSG_CHANNEL_CLOSE: the message number and the recipient channel. */
480#define SSH_CHANNEL_CLOSE_LEN 5u
481
482/**
483 * @brief Build SSH_MSG_CHANNEL_DATA for @p channel and put it on the slot's stream (sec 5.2).
484 * @return the bytes accepted from @p data, -1 when the stream is gone or the build failed.
485 */
486
487/**
488 * @brief Build SSH_MSG_CHANNEL_EOF for @p channel and put it on the slot's stream (sec 5.3).
489 * @return 0 on success, -1 otherwise.
490 */
491
492/**
493 * @brief Build SSH_MSG_CHANNEL_CLOSE for @p channel and put it on the slot's stream (sec 5.3).
494 * @return 0 on success, -1 otherwise.
495 */
496
497/**
498 * @brief Open a "forwarded-tcpip" channel to the peer and put it on the slot's stream (sec 7.2).
499 * @return the local channel number on success, -1 when the pool is full or the stream is gone.
500 */
501
502/**
503 * @brief Handle an inbound SSH_MSG_CHANNEL_EOF: mark the peer done sending on the
504 * recipient channel. Sends nothing and leaves the channel open, so the other
505 * direction keeps carrying data (RFC 4254 sec 5.3).
506 * @return 0 on success, -1 if malformed or the channel is unknown.
507 */
508
509/**
510 * @brief Handle an inbound SSH_MSG_CHANNEL_CLOSE: route to the recipient channel,
511 * reply with EOF + CLOSE, and mark it closed.
512 * @return 0 if a response was produced, -1 if malformed or the channel is unknown.
513 */
514
515// ---------------------------------------------------------------------------
516// RFC 4254 sec 7 - TCP/IP port forwarding
517// ---------------------------------------------------------------------------
518
519/**
520 * @brief Allow/deny policy for a forward target. Return true to permit the connect.
521 *
522 * @p host is NUL-terminated. If no policy is installed every post-authentication
523 * forward is permitted (an open proxy for authenticated users) - install one to
524 * the reachable host:port set.
525 */
526typedef proto_bool (*SshForwardPolicyCb)(const char *host, uint16_t port);
527
528#if PROTOCORE_SSH_PORT_FORWARD
529
530/** @brief Install the forward-target policy (optional; default permits all). */
531
532/**
533 * @brief Enable direct-tcpip forwarding: install the channel forward callbacks.
534 *
535 * Call once after protocore_ssh_conn_setup(). Until then (or if PROTOCORE_SSH_PORT_FORWARD is 0)
536 * the channel codec refuses every direct-tcpip open, so there is no open relay.
537 */
538
539/**
540 * @brief Pump every forward on SSH connection @p ssh_slot: move buffered target
541 * bytes to the client (bounded by the channel's peer window) and propagate
542 * a close from either side. Called from the SSH connection poll each loop.
543 */
544
545/**
546 * @brief RFC 4254 sec 7.2: the sec 7.1 binding that owns @p listener_idx.
547 *
548 * A connection accepted on a forwarded listener is answered with a "forwarded-tcpip" CHANNEL_OPEN
549 * carrying "the address that was connected" and "port that was connected", which are the ones the
550 * binding requested. False when no active binding owns the listener.
551 */
552
553/** @brief Tear down all forwards on @p ssh_slot (its SSH connection is closing). */
554
555#endif // PROTOCORE_SSH_PORT_FORWARD
556
557/** @brief Dispatch messages 80 to 127 (RFC 4254). */
558
559/** @brief RFC 4254 sec 5.2 window: what a flow-control call reads and writes. */
560typedef struct
561{
562 SshFlow *f; ///< the window a call acts on
563 uint32_t local_window; ///< our initial window
564 uint32_t peer_window; ///< the peer's
565 uint32_t peer_max_pkt; ///< the largest packet it will take
566 uint32_t n; ///< bytes a take accounts for
567 uint32_t add; ///< in: credit to add; out: what a replenish owes
568 uint32_t want; ///< bytes a send would like to put out
569 size_t len; ///< the length a send test measures
571
572/** @brief RFC 4254 sec 5 channels: what a channel call acts on. */
573typedef struct
574{
575 uint8_t slot; ///< the SSH slot
576 uint32_t channel; ///< the channel number on it
577 uint32_t id; ///< the channel a lookup names
578 SshChanService service; ///< the service a bind attaches
579 const uint8_t *payload; ///< the message body
580 size_t len; ///< how many bytes it has
581 const uint8_t *data; ///< payload bytes a send carries
582 uint8_t *out; ///< where a reply is written
583 size_t out_len; ///< what was written
584 size_t cap; ///< how much room it has
585 uint32_t exit_status; ///< sec 6.10 exit-status
586 const char *signal_name; ///< sec 6.10 exit-signal
587 proto_bool core_dumped; ///< whether it dumped core
588 const char *err_msg; ///< the message that accompanies it
589 const uint8_t *rtype; ///< sec 5.4 request type
590 uint32_t rtype_len; ///< its length
592
593/** @brief RFC 4254 sec 6.2 pty-req and sec 6.7 window-change: what a terminal call parses. */
594typedef struct
595{
596 const uint8_t *p; ///< the request bytes
597 size_t len; ///< how many
598 size_t off; ///< where the fields start
599 uint8_t n; ///< strings a presence check counts
600 const uint8_t *modes; ///< the encoded terminal modes
601 uint32_t modes_len; ///< their length
602 uint32_t consumed; ///< what a mode walk consumed
603 SshPtyRequest *req; ///< where a parse lands
604 uint32_t width_chars; ///< the reported terminal width
605 uint32_t height_rows; ///< its height
606 uint32_t width_px; ///< the same in pixels
607 uint32_t height_px; ///<
608} SshPtyArgs;
609
610/** @brief RFC 4254 sec 7 TCP/IP forwarding: what a forwarding call names. */
611typedef struct
612{
613 uint8_t slot; ///< the SSH slot a forward belongs to
614 const char *conn_addr; ///< the address connected to
615 uint16_t conn_port; ///< its port
616 const char *orig_addr; ///< where the connection came from
617 uint16_t orig_port; ///< its port
618 uint8_t listener_idx; ///< the listener row a binding lookup names
619 uint8_t out_slot; ///< the slot that binding belongs to
620 uint16_t bind_port; ///< the port it bound
621 const char *bind_addr; ///< the address it bound
622} SshFwdArgs;
623
624/**
625 * @brief The SSH connection protocol (RFC 4254): channels, their windows, and what runs on them.
626 *
627 * A caller fills the group its call belongs to, invokes the call through ::SshConnection, and reads
628 * the outcome off the same handle. The groups are separate because a window has nothing to do with
629 * a forwarding binding, and neither has anything to do with a pty request.
630 *
631 * @var SshConnectionNs::flow sec 5.2 window arguments
632 * @var SshConnectionNs::chan sec 5 channel arguments
633 * @var SshConnectionNs::pty sec 6.2 / 6.7 terminal arguments
634 * @var SshConnectionNs::fwd sec 7 forwarding arguments
635 * @var SshConnectionNs::msg_type the message a dispatch routes
636 * @var SshConnectionNs::ok a call's true/false outcome
637 * @var SshConnectionNs::i32 a call's signed outcome
638 * @var SshConnectionNs::u32 a call's 32-bit outcome
639 * @var SshConnectionNs::found the channel a lookup reports, or NULL
640 */
672
673/** @brief The operands and the outcome. */
675
676/** @brief The entries. */
677typedef struct
678{
679 void (*const flow_init)(uint8_t *work);
680 void (*const flow_recv_take)(uint8_t *work);
681 void (*const flow_replenish_due)(uint8_t *work);
682 void (*const flow_local_credit)(uint8_t *work);
683 void (*const flow_send_allows)(uint8_t *work);
684 void (*const flow_send_cap)(uint8_t *work);
685 void (*const flow_send_take)(uint8_t *work);
686 void (*const flow_peer_add)(uint8_t *work);
687 void (*const channel_init)(uint8_t *work);
688 void (*const chan_alloc)(uint8_t *work);
689 void (*const chan_by_id)(uint8_t *work);
690 void (*const channel_bind_service)(uint8_t *work);
691 void (*const channel_handle_open)(uint8_t *work);
692 void (*const channel_handle_open_confirm)(uint8_t *work);
693 void (*const channel_handle_open_failure)(uint8_t *work);
694 void (*const channel_handle_request)(uint8_t *work);
695 void (*const channel_handle_data)(uint8_t *work);
696 void (*const channel_handle_extended_data)(uint8_t *work);
697 void (*const channel_handle_window_adjust)(uint8_t *work);
698 void (*const channel_handle_eof)(uint8_t *work);
699 void (*const channel_handle_close)(uint8_t *work);
700 void (*const channel_build_data)(uint8_t *work);
701 void (*const channel_build_eof)(uint8_t *work);
702 void (*const channel_build_close)(uint8_t *work);
703 void (*const channel_send_data)(uint8_t *work);
704 void (*const channel_send_eof)(uint8_t *work);
705 void (*const channel_send_close)(uint8_t *work);
706 void (*const channel_send_exit_status)(uint8_t *work);
707 void (*const channel_send_exit_signal)(uint8_t *work);
708 void (*const channel_open_forwarded)(uint8_t *work);
709 void (*const channel_send_open_forwarded)(uint8_t *work);
710 void (*const channel_pty)(uint8_t *work);
711 void (*const req_strings_present)(uint8_t *work);
712 void (*const pty_req_fields_present)(uint8_t *work);
713 void (*const pty_modes_valid)(uint8_t *work);
714 void (*const pty_req_parse)(uint8_t *work);
715 void (*const window_change_parse)(uint8_t *work);
716 void (*const forward_begin)(uint8_t *work);
717 void (*const forward_pump)(uint8_t *work);
718 void (*const forward_binding)(uint8_t *work);
719 void (*const forward_reset)(uint8_t *work);
720 void (*const global_request_handle)(uint8_t *work);
721 void (*const dispatch)(uint8_t *work);
722 void (*const set_data_cb)(uint8_t *work);
723 void (*const set_pty_req_cb)(uint8_t *work);
724 void (*const set_window_change_cb)(uint8_t *work);
725 void (*const set_forward_open_cb)(uint8_t *work);
726 void (*const set_forward_data_cb)(uint8_t *work);
727 void (*const set_forward_confirm_cb)(uint8_t *work);
728 void (*const set_forward_policy_cb)(uint8_t *work);
729 void (*const set_rforward_open_cb)(uint8_t *work);
730 void (*const set_rforward_cancel_cb)(uint8_t *work);
731 void (*const set_sftp_open_cb)(uint8_t *work);
732 void (*const set_sftp_data_cb)(uint8_t *work);
733 void (*const set_scp_open_cb)(uint8_t *work);
734 void (*const set_scp_data_cb)(uint8_t *work);
736
737// What the table binds, defined once in the .c and taking one parameter each: everything
738// else an entry needs is an operand in SshConnectionV or a region of the borrow at a fixed offset.
795
796// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
797// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
798// `SshConnection.flow_init(work)` resolves to a named function and becomes a DIRECT call. An extern table
799// leaves the call indirect and the symbol live at every level, -O2 -flto included.
800static const SshConnectionNs SshConnection __attribute__((unused)) = {
812 .channel_bind_service = protocore_ssh_connection_channel_bind_service,
814 .channel_handle_open_confirm = protocore_ssh_connection_channel_handle_open_confirm,
815 .channel_handle_open_failure = protocore_ssh_connection_channel_handle_open_failure,
816 .channel_handle_request = protocore_ssh_connection_channel_handle_request,
818 .channel_handle_extended_data = protocore_ssh_connection_channel_handle_extended_data,
819 .channel_handle_window_adjust = protocore_ssh_connection_channel_handle_window_adjust,
821 .channel_handle_close = protocore_ssh_connection_channel_handle_close,
828 .channel_send_exit_status = protocore_ssh_connection_channel_send_exit_status,
829 .channel_send_exit_signal = protocore_ssh_connection_channel_send_exit_signal,
830 .channel_open_forwarded = protocore_ssh_connection_channel_open_forwarded,
831 .channel_send_open_forwarded = protocore_ssh_connection_channel_send_open_forwarded,
834 .pty_req_fields_present = protocore_ssh_connection_pty_req_fields_present,
842 .global_request_handle = protocore_ssh_connection_global_request_handle,
846 .set_window_change_cb = protocore_ssh_connection_set_window_change_cb,
849 .set_forward_confirm_cb = protocore_ssh_connection_set_forward_confirm_cb,
850 .set_forward_policy_cb = protocore_ssh_connection_set_forward_policy_cb,
851 .set_rforward_open_cb = protocore_ssh_connection_set_rforward_open_cb,
852 .set_rforward_cancel_cb = protocore_ssh_connection_set_rforward_cancel_cb,
857};
858
859/**
860 * @brief The PROTOCORE_SSH_CONNECTION_BORROW bytes this module's state lives in.
861 *
862 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
863 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
864 * walks, so the state lasts the life of the program.
865 *
866 * @return the span.
867 */
869
871
872#endif // PROTOCORE_CONNECTION_CONNECTION_H
#define MAX_SSH_CONNS
Maximum simultaneous SSH connections.
#define PROTOCORE_SSH_PTY_TERM_MAX
Max stored TERM value from a pty-req (RFC 4254 sec 6.2).
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
void protocore_ssh_connection_set_sftp_open_cb(uint8_t *work)
int(* SshForwardOpenCb)(uint8_t slot, uint32_t channel, const char *host, size_t host_len, uint16_t port)
Install the inbound-data callback (session channels).
Definition connection.h:201
SshChannel ssh_chan[MAX_SSH_CONNS][PROTOCORE_SSH_MAX_CHANNELS]
Channel pool: PROTOCORE_SSH_MAX_CHANNELS channels per SSH connection (BSS). Owned by this layer; src/...
void protocore_ssh_connection_flow_recv_take(uint8_t *work)
void protocore_ssh_connection_channel_handle_close(uint8_t *work)
void protocore_ssh_connection_set_scp_data_cb(uint8_t *work)
void protocore_ssh_connection_set_window_change_cb(uint8_t *work)
void protocore_ssh_connection_channel_handle_open(uint8_t *work)
void protocore_ssh_connection_forward_binding(uint8_t *work)
proto_bool(* SshForwardPolicyCb)(const char *host, uint16_t port)
Build SSH_MSG_CHANNEL_DATA for channel and put it on the slot's stream (sec 5.2).
Definition connection.h:526
void protocore_ssh_connection_channel_handle_extended_data(uint8_t *work)
void protocore_ssh_connection_channel_send_exit_signal(uint8_t *work)
void protocore_ssh_connection_forward_pump(uint8_t *work)
void protocore_ssh_connection_set_rforward_open_cb(uint8_t *work)
void(* SshChannelDataCb)(uint8_t slot, uint32_t channel, const uint8_t *data, size_t len)
Application callback for inbound channel data (raw bytes), tagged with the channel id it arrived on.
Definition connection.h:187
void protocore_ssh_connection_set_data_cb(uint8_t *work)
proto_bool(* SshPtyReqCb)(uint8_t i, uint32_t channel, const SshPtyRequest *pty)
Walk an encoded terminal-mode stream (RFC 4254 sec 8) and report whether it is well formed.
Definition connection.h:379
void protocore_ssh_connection_channel_handle_request(uint8_t *work)
void protocore_ssh_connection_flow_peer_add(uint8_t *work)
int32_t protocore_ssh_sig_build_eof(uint32_t peer_id, uint8_t *out, size_t cap, size_t *out_len)
CHANNEL_EOF, as one 5-byte message.
void protocore_ssh_connection_set_forward_open_cb(uint8_t *work)
void protocore_ssh_connection_channel_open_forwarded(uint8_t *work)
void(* SshForwardConfirmCb)(uint8_t slot, uint32_t channel, proto_bool ok)
Install the remote-forward (ssh -R) open-policy callback (opt-in).
Definition connection.h:233
void protocore_ssh_connection_flow_local_credit(uint8_t *work)
void protocore_ssh_connection_channel_build_eof(uint8_t *work)
void protocore_ssh_connection_flow_send_cap(uint8_t *work)
void protocore_ssh_connection_channel_send_exit_status(uint8_t *work)
int32_t protocore_ssh_sig_build_window_adjust(uint32_t peer_id, uint32_t add, uint8_t *out, size_t cap, size_t *out_len)
CHANNEL_WINDOW_ADJUST granting add more bytes. Credit the window only once this is sent.
void protocore_ssh_connection_global_request_handle(uint8_t *work)
void(* SshScpOpenCb)(uint8_t slot, uint32_t channel, const char *cmd, size_t cmd_len)
An exec "scp …" request was accepted on channel (cmd is cmd_len bytes, not NUL-terminated).
Definition connection.h:247
int32_t protocore_ssh_sig_build_open_failure(uint8_t *out, size_t cap, uint32_t peer_id, uint32_t reason, size_t *out_len)
Start a channel's windows: ours at local_window, the peer's at what it advertised.
void protocore_ssh_connection_forward_begin(uint8_t *work)
int32_t protocore_ssh_sig_build_open_confirm(const SshFlow *f, uint32_t peer_id, uint32_t local_id, uint8_t *out, size_t cap, size_t *out_len)
CHANNEL_OPEN_CONFIRMATION, advertising our current window and maximum packet size.
void(* SshForwardDataCb)(uint8_t slot, uint32_t channel, const uint8_t *data, size_t len)
Inbound data on a direct-tcpip channel (the owner writes it to the forwarded TCP socket)....
Definition connection.h:204
void protocore_ssh_connection_channel_build_close(uint8_t *work)
uint8_t * protocore_ssh_connection_span(void)
The PROTOCORE_SSH_CONNECTION_BORROW bytes this module's state lives in.
enum PROTO_ENUM_PACKED SshChanType
Channel type (RFC 4254).
int32_t protocore_ssh_sig_build_data(SshFlow *f, uint32_t peer_id, const uint8_t *data, size_t len, uint8_t *out, size_t cap, size_t *out_len)
CHANNEL_DATA carrying len bytes, and account them against the peer's window.
void(* SshWindowChangeCb)(uint8_t i, uint32_t channel, uint32_t width_chars, uint32_t height_rows, uint32_t width_px, uint32_t height_px)
A "window-change" (sec 6.7) on a channel that already has a terminal.
Definition connection.h:382
void protocore_ssh_connection_set_rforward_cancel_cb(uint8_t *work)
void protocore_ssh_connection_flow_send_take(uint8_t *work)
void protocore_ssh_connection_channel_build_data(uint8_t *work)
void protocore_ssh_connection_req_strings_present(uint8_t *work)
void(* SshSftpOpenCb)(uint8_t slot, uint32_t channel)
Install the forwarded-tcpip open-confirmation callback (opt-in, ssh -R).
Definition connection.h:237
void protocore_ssh_connection_set_pty_req_cb(uint8_t *work)
void protocore_ssh_connection_pty_modes_valid(uint8_t *work)
void protocore_ssh_connection_channel_bind_service(uint8_t *work)
void(* SshScpDataCb)(uint8_t slot, uint32_t channel, const uint8_t *data, size_t len)
Inbound bytes on an SCP channel (the RCP protocol stream).
Definition connection.h:249
void protocore_ssh_connection_set_forward_policy_cb(uint8_t *work)
void protocore_ssh_connection_channel_pty(uint8_t *work)
void protocore_ssh_connection_channel_handle_window_adjust(uint8_t *work)
void protocore_ssh_connection_set_forward_data_cb(uint8_t *work)
@ SSH_CHAN_FORWARDED_TCPIP
"forwarded-tcpip" - server-initiated TCP forward (ssh -R)
Definition connection.h:137
@ SSH_CHAN_SERVICE_SFTP
subsystem "sftp" (PROTOCORE_ENABLE_SSH_SFTP)
Definition connection.h:150
@ SSH_CHAN_DIRECT_TCPIP
"direct-tcpip" - client-initiated TCP forward (ssh -L)
Definition connection.h:136
@ SSH_CHAN_SERVICE_SCP
exec "scp ..." (PROTOCORE_ENABLE_SSH_SCP)
Definition connection.h:151
@ SSH_CHAN_SERVICE_NONE
shell / exec output, handed to the channel-data callback
Definition connection.h:149
@ SSH_CHAN_SESSION
"session" - shell / exec / data
Definition connection.h:135
int32_t protocore_ssh_sig_build_close(uint32_t peer_id, uint8_t *out, size_t cap, size_t *out_len)
CHANNEL_CLOSE, as one 5-byte message.
SshConnectionVars SshConnectionV
The operands and the outcome.
void protocore_ssh_connection_set_forward_confirm_cb(uint8_t *work)
void protocore_ssh_connection_channel_handle_open_failure(uint8_t *work)
void(* SshSftpDataCb)(uint8_t slot, uint32_t channel, const uint8_t *data, size_t len)
Inbound bytes on an SFTP channel (the raw SSH_FXP_* stream) - kept out of the session data cb.
Definition connection.h:239
void protocore_ssh_connection_flow_init(uint8_t *work)
void protocore_ssh_connection_channel_handle_eof(uint8_t *work)
void protocore_ssh_connection_channel_handle_open_confirm(uint8_t *work)
void protocore_ssh_connection_pty_req_fields_present(uint8_t *work)
void protocore_ssh_connection_channel_send_close(uint8_t *work)
void protocore_ssh_connection_set_scp_open_cb(uint8_t *work)
void protocore_ssh_connection_forward_reset(uint8_t *work)
void protocore_ssh_connection_dispatch(uint8_t *work)
void protocore_ssh_connection_channel_send_open_forwarded(uint8_t *work)
void protocore_ssh_connection_flow_send_allows(uint8_t *work)
void protocore_ssh_connection_chan_alloc(uint8_t *work)
int(* SshRemoteForwardCancelCb)(uint8_t slot, const char *bind_addr, size_t addr_len, uint16_t bind_port)
"cancel-tcpip-forward" request (RFC 4254 §7.1): drop a remote forward.
Definition connection.h:222
int(* SshRemoteForwardOpenCb)(uint8_t slot, const char *bind_addr, size_t addr_len, uint16_t bind_port)
Install the direct-tcpip forward open-policy callback (opt-in).
Definition connection.h:219
void protocore_ssh_connection_channel_send_eof(uint8_t *work)
void protocore_ssh_connection_set_sftp_data_cb(uint8_t *work)
void protocore_ssh_connection_channel_send_data(uint8_t *work)
enum PROTO_ENUM_PACKED SshChanService
What a session channel's sec 6 request bound to it, if anything.
void protocore_ssh_connection_channel_handle_data(uint8_t *work)
void protocore_ssh_connection_window_change_parse(uint8_t *work)
void protocore_ssh_connection_flow_replenish_due(uint8_t *work)
void protocore_ssh_connection_channel_init(uint8_t *work)
void protocore_ssh_connection_chan_by_id(uint8_t *work)
void protocore_ssh_connection_pty_req_parse(uint8_t *work)
#define PROTOCORE_SSH_MAX_CHANNELS
Maximum concurrent SSH channels per connection (RFC 4254 multiplexing).
Root infrastructure: fixed widths, serializers, opcodes and sizes, for every layer above.
RFC 4254 sec 5 channels: what a channel call acts on.
Definition connection.h:574
uint8_t slot
the SSH slot
Definition connection.h:575
uint32_t exit_status
sec 6.10 exit-status
Definition connection.h:585
const uint8_t * payload
the message body
Definition connection.h:579
size_t out_len
what was written
Definition connection.h:583
size_t cap
how much room it has
Definition connection.h:584
uint32_t channel
the channel number on it
Definition connection.h:576
uint32_t rtype_len
its length
Definition connection.h:590
uint8_t * out
where a reply is written
Definition connection.h:582
const uint8_t * rtype
sec 5.4 request type
Definition connection.h:589
SshChanService service
the service a bind attaches
Definition connection.h:578
proto_bool core_dumped
whether it dumped core
Definition connection.h:587
uint32_t id
the channel a lookup names
Definition connection.h:577
const uint8_t * data
payload bytes a send carries
Definition connection.h:581
const char * err_msg
the message that accompanies it
Definition connection.h:588
const char * signal_name
sec 6.10 exit-signal
Definition connection.h:586
size_t len
how many bytes it has
Definition connection.h:580
Per-connection channel state.
Definition connection.h:156
uint32_t width_chars
terminal width, characters
Definition connection.h:174
proto_bool pty
A "pty-req" was accepted on this channel.
Definition connection.h:173
proto_bool pending
True for a server-initiated channel we opened, awaiting the client's confirmation.
Definition connection.h:158
proto_bool relay_eof
The peer sent CHANNEL_EOF.
Definition connection.h:165
SshChanType type
session, direct-tcpip, or forwarded-tcpip.
Definition connection.h:159
proto_bool close_received
The peer sent CHANNEL_CLOSE.
Definition connection.h:170
uint32_t height_rows
terminal height, rows
Definition connection.h:175
uint32_t local_id
Our channel id (== slot index).
Definition connection.h:161
proto_bool close_sent
We sent CHANNEL_CLOSE.
Definition connection.h:169
SshChanService service
What a sec 6 request bound over a session channel, if anything.
Definition connection.h:160
uint32_t width_px
terminal width, pixels
Definition connection.h:176
SshFlow flow
RFC 4254 sec 5.2 window pair (owner: ssh_flow_control.*).
Definition connection.h:163
uint32_t height_px
terminal height, pixels
Definition connection.h:177
uint32_t peer_id
Client's channel id.
Definition connection.h:162
proto_bool eof_sent
We sent CHANNEL_EOF (RFC 4254 sec 5.3).
Definition connection.h:164
proto_bool open
True once the channel is confirmed open both ways.
Definition connection.h:157
The entries.
Definition connection.h:678
void(*const flow_init)(uint8_t *work)
Definition connection.h:679
SshChanArgs chan
Definition connection.h:644
SshForwardConfirmCb forward_confirm_cb
Definition connection.h:663
SshChannel * found
Definition connection.h:651
SshWindowChangeCb window_change_cb
Definition connection.h:660
SshPtyReqCb pty_req_cb
Definition connection.h:659
SshForwardOpenCb forward_open_cb
Definition connection.h:661
SshRemoteForwardCancelCb rforward_cancel_cb
Definition connection.h:666
SshSftpDataCb sftp_data_cb
Definition connection.h:668
SshScpOpenCb scp_open_cb
Definition connection.h:669
SshSftpOpenCb sftp_open_cb
Definition connection.h:667
SshForwardPolicyCb forward_policy_cb
Definition connection.h:664
SshRemoteForwardOpenCb rforward_open_cb
Definition connection.h:665
SshScpDataCb scp_data_cb
Definition connection.h:670
SshForwardDataCb forward_data_cb
Definition connection.h:662
SshFlowArgs flow
Definition connection.h:643
SshChannelDataCb data_cb
Definition connection.h:658
Dispatch messages 80 to 127 (RFC 4254).
Definition connection.h:561
uint32_t peer_window
the peer's
Definition connection.h:564
uint32_t add
in: credit to add; out: what a replenish owes
Definition connection.h:567
uint32_t n
bytes a take accounts for
Definition connection.h:566
uint32_t local_window
our initial window
Definition connection.h:563
SshFlow * f
the window a call acts on
Definition connection.h:562
uint32_t want
bytes a send would like to put out
Definition connection.h:568
uint32_t peer_max_pkt
the largest packet it will take
Definition connection.h:565
size_t len
the length a send test measures
Definition connection.h:569
One channel's flow-control state (RFC 4254 sec 5.2).
Definition connection.h:22
uint32_t peer_max_pkt
Peer's maximum packet size; caps a single send independently of the window.
Definition connection.h:26
uint32_t local_max
The window we advertised, and replenish back up to.
Definition connection.h:24
uint32_t peer_window
Bytes we may still send the peer.
Definition connection.h:25
uint32_t local_window
Bytes the peer may still send us before we WINDOW_ADJUST.
Definition connection.h:23
RFC 4254 sec 7 TCP/IP forwarding: what a forwarding call names.
Definition connection.h:612
uint16_t orig_port
its port
Definition connection.h:617
const char * orig_addr
where the connection came from
Definition connection.h:616
const char * bind_addr
the address it bound
Definition connection.h:621
uint16_t bind_port
the port it bound
Definition connection.h:620
const char * conn_addr
the address connected to
Definition connection.h:614
uint16_t conn_port
its port
Definition connection.h:615
uint8_t out_slot
the slot that binding belongs to
Definition connection.h:619
uint8_t slot
the SSH slot a forward belongs to
Definition connection.h:613
uint8_t listener_idx
the listener row a binding lookup names
Definition connection.h:618
RFC 4254 sec 6.2 pty-req and sec 6.7 window-change: what a terminal call parses.
Definition connection.h:595
const uint8_t * modes
the encoded terminal modes
Definition connection.h:600
uint32_t height_rows
its height
Definition connection.h:605
uint32_t height_px
Definition connection.h:607
uint32_t width_chars
the reported terminal width
Definition connection.h:604
size_t len
how many
Definition connection.h:597
uint8_t n
strings a presence check counts
Definition connection.h:599
uint32_t width_px
the same in pixels
Definition connection.h:606
size_t off
where the fields start
Definition connection.h:598
uint32_t consumed
what a mode walk consumed
Definition connection.h:602
SshPtyRequest * req
where a parse lands
Definition connection.h:603
uint32_t modes_len
their length
Definition connection.h:601
const uint8_t * p
the request bytes
Definition connection.h:596
Open a server-initiated "forwarded-tcpip" channel (RFC 4254 §7.2, ssh -R).
Definition connection.h:345
uint32_t width_px
terminal width, pixels
Definition connection.h:349
uint32_t height_rows
terminal height, rows
Definition connection.h:348
uint32_t height_px
terminal height, pixels
Definition connection.h:350
uint32_t modes_len
length of modes
Definition connection.h:352
const uint8_t * modes
encoded terminal modes, pointing into the request
Definition connection.h:351
uint32_t width_chars
terminal width, characters
Definition connection.h:347
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97