Skip to content

Commit d51688b

Browse files
Fix DoGlobalRequestFwd and Add the regress tests
1 parent cdd6df0 commit d51688b

File tree

2 files changed

+237
-4
lines changed

2 files changed

+237
-4
lines changed

src/internal.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8496,16 +8496,35 @@ static int DoGlobalRequestFwd(WOLFSSH* ssh,
84968496
isCancel ? " cancel" : "", bindAddr, bindPort);
84978497
}
84988498

8499-
if (ret == WS_SUCCESS && wantReply) {
8500-
ret = SendGlobalRequestFwdSuccess(ssh, 1, bindPort);
8501-
}
8502-
85038499
if (ret == WS_SUCCESS) {
85048500
if (ssh->ctx->fwdCb) {
85058501
ret = ssh->ctx->fwdCb(isCancel ? WOLFSSH_FWD_REMOTE_CLEANUP :
85068502
WOLFSSH_FWD_REMOTE_SETUP,
85078503
ssh->fwdCbCtx, bindAddr, bindPort);
85088504
}
8505+
else {
8506+
WLOG(WS_LOG_WARN, "No forwarding callback set, rejecting request. "
8507+
"Set one with wolfSSH_CTX_SetFwdCb().");
8508+
ret = WS_UNIMPLEMENTED_E;
8509+
}
8510+
}
8511+
8512+
if (wantReply) {
8513+
if (ret == WS_SUCCESS) {
8514+
if (isCancel) {
8515+
ret = SendRequestSuccess(ssh, 1);
8516+
}
8517+
else {
8518+
ret = SendGlobalRequestFwdSuccess(ssh, 1, bindPort);
8519+
}
8520+
}
8521+
else {
8522+
ret = SendRequestSuccess(ssh, 0);
8523+
}
8524+
}
8525+
else if (ret != WS_SUCCESS) {
8526+
/* No reply expected; silently reject without terminating connection. */
8527+
ret = WS_SUCCESS;
85098528
}
85108529

85118530
if (bindAddr != NULL)

tests/regress.c

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,21 @@ static word32 BuildDirectTcpipExtra(const char* host, word32 hostPort,
231231

232232
return idx;
233233
}
234+
235+
static word32 BuildGlobalRequestFwdPacket(const char* bindAddr, word32 bindPort,
236+
int isCancel, byte wantReply, byte* out, word32 outSz)
237+
{
238+
byte payload[256];
239+
word32 idx = 0;
240+
const char* reqName = isCancel ? "cancel-tcpip-forward" : "tcpip-forward";
241+
242+
idx = AppendString(payload, sizeof(payload), idx, reqName);
243+
idx = AppendByte (payload, sizeof(payload), idx, wantReply);
244+
idx = AppendString(payload, sizeof(payload), idx, bindAddr);
245+
idx = AppendUint32(payload, sizeof(payload), idx, bindPort);
246+
247+
return WrapPacket(MSGID_GLOBAL_REQUEST, payload, idx, out, outSz);
248+
}
234249
#endif
235250

236251
/* Simple in-memory transport harness */
@@ -957,6 +972,94 @@ static void AssertChannelOpenFailResponse(const ChannelOpenHarness* harness,
957972
AssertTrue(harness->ssh->channelList == NULL);
958973
}
959974

975+
#ifdef WOLFSSH_FWD
976+
static word32 ParsePayloadLen(const byte* packet, word32 packetSz)
977+
{
978+
word32 packetLen;
979+
byte padLen;
980+
981+
AssertNotNull(packet);
982+
AssertTrue(packetSz >= 6);
983+
984+
WMEMCPY(&packetLen, packet, sizeof(packetLen));
985+
packetLen = ntohl(packetLen);
986+
padLen = packet[4];
987+
988+
AssertTrue(packetLen >= (word32)padLen + 1);
989+
AssertTrue(packetSz >= packetLen + 4);
990+
991+
return packetLen - padLen - 1;
992+
}
993+
994+
static const byte* ParseGlobalRequestName(const byte* packet, word32 packetSz,
995+
word32* nameSz)
996+
{
997+
word32 packetLen;
998+
word32 payloadLen;
999+
word32 strSz;
1000+
const byte* payload;
1001+
1002+
AssertNotNull(packet);
1003+
AssertNotNull(nameSz);
1004+
AssertTrue(packetSz >= 10);
1005+
1006+
WMEMCPY(&packetLen, packet, sizeof(packetLen));
1007+
packetLen = ntohl(packetLen);
1008+
AssertTrue(packetSz >= packetLen + 4);
1009+
1010+
payloadLen = ParsePayloadLen(packet, packetSz);
1011+
payload = packet + 5;
1012+
1013+
AssertTrue(payloadLen >= 1 + sizeof(word32));
1014+
AssertIntEQ(payload[0], MSGID_GLOBAL_REQUEST);
1015+
1016+
WMEMCPY(&strSz, payload + 1, sizeof(strSz));
1017+
strSz = ntohl(strSz);
1018+
AssertTrue(payloadLen >= 1 + sizeof(word32) + strSz);
1019+
1020+
*nameSz = strSz;
1021+
return payload + 1 + sizeof(word32);
1022+
}
1023+
1024+
static void AssertGlobalRequestReply(const ChannelOpenHarness* harness,
1025+
byte expectedMsgId)
1026+
{
1027+
byte msgId;
1028+
word32 payloadLen;
1029+
1030+
AssertTrue(harness->io.outSz > 0);
1031+
msgId = ParseMsgId(harness->io.out, harness->io.outSz);
1032+
AssertIntEQ(msgId, expectedMsgId);
1033+
1034+
payloadLen = ParsePayloadLen(harness->io.out, harness->io.outSz);
1035+
if (expectedMsgId == MSGID_REQUEST_FAILURE) {
1036+
AssertIntEQ(payloadLen, 1);
1037+
}
1038+
else if (expectedMsgId == MSGID_REQUEST_SUCCESS) {
1039+
const byte* reqName;
1040+
word32 reqNameSz;
1041+
1042+
reqName = ParseGlobalRequestName(harness->io.in, harness->io.inSz,
1043+
&reqNameSz);
1044+
1045+
if (reqNameSz == sizeof("tcpip-forward") - 1 &&
1046+
WMEMCMP(reqName, "tcpip-forward",
1047+
sizeof("tcpip-forward") - 1) == 0) {
1048+
AssertIntEQ(payloadLen, 5);
1049+
}
1050+
else if (reqNameSz == sizeof("cancel-tcpip-forward") - 1 &&
1051+
WMEMCMP(reqName, "cancel-tcpip-forward",
1052+
sizeof("cancel-tcpip-forward") - 1) == 0) {
1053+
AssertIntEQ(payloadLen, 1);
1054+
}
1055+
else {
1056+
Fail(("unexpected global request name"),
1057+
("%.*s", (int)reqNameSz, reqName));
1058+
}
1059+
}
1060+
}
1061+
#endif
1062+
9601063
static int RejectChannelOpenCb(WOLFSSH_CHANNEL* channel, void* ctx)
9611064
{
9621065
(void)channel;
@@ -978,6 +1081,17 @@ static int RejectDirectTcpipSetup(WS_FwdCbAction action, void* ctx,
9781081

9791082
return WS_SUCCESS;
9801083
}
1084+
1085+
static int AcceptFwdCb(WS_FwdCbAction action, void* ctx,
1086+
const char* host, word32 port)
1087+
{
1088+
(void)action;
1089+
(void)ctx;
1090+
(void)host;
1091+
(void)port;
1092+
1093+
return WS_SUCCESS;
1094+
}
9811095
#endif
9821096

9831097

@@ -1242,6 +1356,101 @@ static void TestDirectTcpipNoFwdCbSendsOpenFail(void)
12421356

12431357
FreeChannelOpenHarness(&harness);
12441358
}
1359+
1360+
static void TestGlobalRequestFwdNoCbSendsFailure(void)
1361+
{
1362+
ChannelOpenHarness harness;
1363+
byte in[256];
1364+
word32 inSz;
1365+
int ret;
1366+
1367+
inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 0, 1, in, sizeof(in));
1368+
InitChannelOpenHarness(&harness, in, inSz);
1369+
/* no fwdCb registered */
1370+
1371+
ret = DoReceive(harness.ssh);
1372+
1373+
AssertIntEQ(ret, WS_SUCCESS);
1374+
AssertGlobalRequestReply(&harness, MSGID_REQUEST_FAILURE);
1375+
1376+
FreeChannelOpenHarness(&harness);
1377+
}
1378+
1379+
static void TestGlobalRequestFwdNoCbNoReplyKeepsConnection(void)
1380+
{
1381+
ChannelOpenHarness harness;
1382+
byte in[256];
1383+
word32 inSz;
1384+
int ret;
1385+
1386+
/* wantReply=0: no reply sent, connection must stay alive */
1387+
inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 0, 0, in, sizeof(in));
1388+
InitChannelOpenHarness(&harness, in, inSz);
1389+
/* no fwdCb registered */
1390+
1391+
ret = DoReceive(harness.ssh);
1392+
1393+
AssertIntEQ(ret, WS_SUCCESS);
1394+
AssertIntEQ(harness.io.outSz, 0); /* no reply sent */
1395+
1396+
FreeChannelOpenHarness(&harness);
1397+
}
1398+
1399+
static void TestGlobalRequestFwdWithCbSendsSuccess(void)
1400+
{
1401+
ChannelOpenHarness harness;
1402+
byte in[256];
1403+
word32 inSz;
1404+
int ret;
1405+
1406+
inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 0, 1, in, sizeof(in));
1407+
InitChannelOpenHarness(&harness, in, inSz);
1408+
AssertIntEQ(wolfSSH_CTX_SetFwdCb(harness.ctx, AcceptFwdCb, NULL), WS_SUCCESS);
1409+
1410+
ret = DoReceive(harness.ssh);
1411+
1412+
AssertIntEQ(ret, WS_SUCCESS);
1413+
AssertGlobalRequestReply(&harness, MSGID_REQUEST_SUCCESS);
1414+
1415+
FreeChannelOpenHarness(&harness);
1416+
}
1417+
1418+
static void TestGlobalRequestFwdCancelNoCbSendsFailure(void)
1419+
{
1420+
ChannelOpenHarness harness;
1421+
byte in[256];
1422+
word32 inSz;
1423+
int ret;
1424+
1425+
inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 1, 1, in, sizeof(in));
1426+
InitChannelOpenHarness(&harness, in, inSz);
1427+
1428+
ret = DoReceive(harness.ssh);
1429+
1430+
AssertIntEQ(ret, WS_SUCCESS);
1431+
AssertGlobalRequestReply(&harness, MSGID_REQUEST_FAILURE);
1432+
1433+
FreeChannelOpenHarness(&harness);
1434+
}
1435+
1436+
static void TestGlobalRequestFwdCancelWithCbSendsSuccess(void)
1437+
{
1438+
ChannelOpenHarness harness;
1439+
byte in[256];
1440+
word32 inSz;
1441+
int ret;
1442+
1443+
inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 1, 1, in, sizeof(in));
1444+
InitChannelOpenHarness(&harness, in, inSz);
1445+
AssertIntEQ(wolfSSH_CTX_SetFwdCb(harness.ctx, AcceptFwdCb, NULL), WS_SUCCESS);
1446+
1447+
ret = DoReceive(harness.ssh);
1448+
1449+
AssertIntEQ(ret, WS_SUCCESS);
1450+
AssertGlobalRequestReply(&harness, MSGID_REQUEST_SUCCESS);
1451+
1452+
FreeChannelOpenHarness(&harness);
1453+
}
12451454
#endif
12461455

12471456
#ifdef WOLFSSH_AGENT
@@ -1707,6 +1916,11 @@ int main(int argc, char** argv)
17071916
#ifdef WOLFSSH_FWD
17081917
TestDirectTcpipRejectSendsOpenFail();
17091918
TestDirectTcpipNoFwdCbSendsOpenFail();
1919+
TestGlobalRequestFwdNoCbSendsFailure();
1920+
TestGlobalRequestFwdNoCbNoReplyKeepsConnection();
1921+
TestGlobalRequestFwdWithCbSendsSuccess();
1922+
TestGlobalRequestFwdCancelNoCbSendsFailure();
1923+
TestGlobalRequestFwdCancelWithCbSendsSuccess();
17101924
#endif
17111925
#ifdef WOLFSSH_AGENT
17121926
TestAgentChannelNullAgentSendsOpenFail();

0 commit comments

Comments
 (0)