Gate forwarded-tcpip opens like direct-tcpip

- forwarded-tcpip was never gated; fell through to default-accept channelOpenCb.
- Require fwdCb for both forwarding channel types, failing closed without it.
- Reject server-side forwarded-tcpip opens before any policy hook runs.
- Add regress coverage for both rejections.

Issue: F-6275
pull/1042/head
John Safranek 2026-06-24 13:57:01 -07:00 committed by Paul Adelsbach
parent 673b2d25e7
commit 616eb681e7
2 changed files with 70 additions and 17 deletions

View File

@ -9266,23 +9266,45 @@ static int DoChannelOpen(WOLFSSH* ssh,
else {
ChannelUpdatePeer(newChannel, peerChannelId,
peerInitialWindowSz, peerMaxPacketSz);
if (ssh->ctx->channelOpenCb) {
ret = ssh->ctx->channelOpenCb(newChannel, ssh->channelOpenCtx);
}
else {
WLOG(WS_LOG_WARN, "No channel open callback set "
"(call wolfSSH_CTX_SetChannelOpenCb()), accepting "
"channel open by default; typeId=%u, peerChannelId=%u",
(word32)typeId, peerChannelId);
}
if (ssh->channelListSz == 0)
ssh->defaultPeerChannelId = peerChannelId;
#ifdef WOLFSSH_FWD
if (typeId == ID_CHANTYPE_TCPIP_DIRECT) {
ChannelUpdateForward(newChannel,
host, hostPort, origin, originPort, isDirect);
/* A forwarded-tcpip open is a server-to-client message sent in
* response to a tcpip-forward request, so only a client should
* ever receive one. Reject opens arriving in the wrong direction
* up front, before any policy callback runs or channel state is
* updated. direct-tcpip is intentionally not direction-checked:
* either forwarding side may legitimately request a direct
* forward. */
if (typeId == ID_CHANTYPE_TCPIP_FORWARD &&
ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {
WLOG(WS_LOG_WARN, "Rejecting forwarded-tcpip channel open "
"received by a server (wrong direction)");
fail_reason = OPEN_ADMINISTRATIVELY_PROHIBITED;
ret = WS_ERROR;
}
#endif /* WOLFSSH_FWD */
if (ret == WS_SUCCESS) {
if (ssh->ctx->channelOpenCb) {
ret = ssh->ctx->channelOpenCb(newChannel,
ssh->channelOpenCtx);
}
else {
WLOG(WS_LOG_WARN, "No channel open callback set "
"(call wolfSSH_CTX_SetChannelOpenCb()), accepting "
"channel open by default; typeId=%u, "
"peerChannelId=%u",
(word32)typeId, peerChannelId);
}
if (ssh->channelListSz == 0)
ssh->defaultPeerChannelId = peerChannelId;
}
#ifdef WOLFSSH_FWD
if (ret == WS_SUCCESS &&
(typeId == ID_CHANTYPE_TCPIP_DIRECT ||
typeId == ID_CHANTYPE_TCPIP_FORWARD)) {
if (ssh->ctx->fwdCb) {
ChannelUpdateForward(newChannel,
host, hostPort, origin, originPort, isDirect);
ret = ssh->ctx->fwdCb(WOLFSSH_FWD_LOCAL_SETUP,
ssh->fwdCbCtx, host, hostPort);
if (ret == WS_SUCCESS) {
@ -9291,8 +9313,11 @@ static int DoChannelOpen(WOLFSSH* ssh,
}
}
else {
WLOG(WS_LOG_WARN, "No forward callback set for direct-tcpip channel,"
" failing channel open");
/* Both forwarding channel types require an explicit policy
* callback; without one, fail closed rather than letting
* the default-accept channelOpenCb path admit them. */
WLOG(WS_LOG_WARN, "No forward callback set for forwarding "
"channel, failing channel open");
fail_reason = OPEN_ADMINISTRATIVELY_PROHIBITED;
ret = WS_ERROR;
}

View File

@ -1525,6 +1525,33 @@ static void TestDirectTcpipNoFwdCbSendsOpenFail(void)
FreeChannelOpenHarness(&harness);
}
static void TestForwardedTcpipOnServerSendsOpenFail(void)
{
ChannelOpenHarness harness;
byte extra[128];
byte in[192];
word32 extraSz;
word32 inSz;
int ret;
/* forwarded-tcpip is only ever sent server-to-client. A server receiving
* one is the wrong direction and must be rejected even with a fwdCb set,
* before the forwarding policy hook runs. */
extraSz = BuildDirectTcpipExtra("127.0.0.1", 8080, "127.0.0.1", 2222,
extra, sizeof(extra));
inSz = BuildChannelOpenPacket("forwarded-tcpip", 9, 0x4000, 0x8000,
extra, extraSz, in, sizeof(in));
InitChannelOpenHarness(&harness, in, inSz);
AssertIntEQ(wolfSSH_CTX_SetFwdCb(harness.ctx, AcceptFwdCb, NULL),
WS_SUCCESS);
ret = DoReceive(harness.ssh);
AssertChannelOpenFailResponse(&harness, ret);
FreeChannelOpenHarness(&harness);
}
static void TestGlobalRequestFwdNoCbSendsFailure(void)
{
ChannelOpenHarness harness;
@ -4133,6 +4160,7 @@ int main(int argc, char** argv)
#ifdef WOLFSSH_FWD
TestDirectTcpipRejectSendsOpenFail();
TestDirectTcpipNoFwdCbSendsOpenFail();
TestForwardedTcpipOnServerSendsOpenFail();
TestGlobalRequestFwdNoCbSendsFailure();
TestGlobalRequestFwdNoCbNoReplyKeepsConnection();
TestGlobalRequestFwdWithCbSendsSuccess();