@@ -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 */
@@ -922,6 +937,15 @@ static void AssertChannelOpenFailResponse(const ChannelOpenHarness* harness,
922937 AssertTrue (harness -> ssh -> channelList == NULL );
923938}
924939
940+ #ifdef WOLFSSH_FWD
941+ static void AssertGlobalRequestReply (const ChannelOpenHarness * harness ,
942+ byte expectedMsgId )
943+ {
944+ AssertTrue (harness -> io .outSz > 0 );
945+ AssertIntEQ (ParseMsgId (harness -> io .out , harness -> io .outSz ), expectedMsgId );
946+ }
947+ #endif
948+
925949static int RejectChannelOpenCb (WOLFSSH_CHANNEL * channel , void * ctx )
926950{
927951 (void )channel ;
@@ -943,6 +967,17 @@ static int RejectDirectTcpipSetup(WS_FwdCbAction action, void* ctx,
943967
944968 return WS_SUCCESS ;
945969}
970+
971+ static int AcceptFwdCb (WS_FwdCbAction action , void * ctx ,
972+ const char * host , word32 port )
973+ {
974+ (void )action ;
975+ (void )ctx ;
976+ (void )host ;
977+ (void )port ;
978+
979+ return WS_SUCCESS ;
980+ }
946981#endif
947982
948983
@@ -1184,6 +1219,101 @@ static void TestDirectTcpipRejectSendsOpenFail(void)
11841219
11851220 FreeChannelOpenHarness (& harness );
11861221}
1222+
1223+ static void TestGlobalRequestFwdNoCbSendsFailure (void )
1224+ {
1225+ ChannelOpenHarness harness ;
1226+ byte in [256 ];
1227+ word32 inSz ;
1228+ int ret ;
1229+
1230+ inSz = BuildGlobalRequestFwdPacket ("0.0.0.0" , 2222 , 0 , 1 , in , sizeof (in ));
1231+ InitChannelOpenHarness (& harness , in , inSz );
1232+ /* no fwdCb registered */
1233+
1234+ ret = DoReceive (harness .ssh );
1235+
1236+ AssertIntEQ (ret , WS_SUCCESS );
1237+ AssertGlobalRequestReply (& harness , MSGID_REQUEST_FAILURE );
1238+
1239+ FreeChannelOpenHarness (& harness );
1240+ }
1241+
1242+ static void TestGlobalRequestFwdNoCbNoReplyKeepsConnection (void )
1243+ {
1244+ ChannelOpenHarness harness ;
1245+ byte in [256 ];
1246+ word32 inSz ;
1247+ int ret ;
1248+
1249+ /* wantReply=0: no reply sent, connection must stay alive */
1250+ inSz = BuildGlobalRequestFwdPacket ("0.0.0.0" , 2222 , 0 , 0 , in , sizeof (in ));
1251+ InitChannelOpenHarness (& harness , in , inSz );
1252+ /* no fwdCb registered */
1253+
1254+ ret = DoReceive (harness .ssh );
1255+
1256+ AssertIntEQ (ret , WS_SUCCESS );
1257+ AssertIntEQ (harness .io .outSz , 0 ); /* no reply sent */
1258+
1259+ FreeChannelOpenHarness (& harness );
1260+ }
1261+
1262+ static void TestGlobalRequestFwdWithCbSendsSuccess (void )
1263+ {
1264+ ChannelOpenHarness harness ;
1265+ byte in [256 ];
1266+ word32 inSz ;
1267+ int ret ;
1268+
1269+ inSz = BuildGlobalRequestFwdPacket ("0.0.0.0" , 2222 , 0 , 1 , in , sizeof (in ));
1270+ InitChannelOpenHarness (& harness , in , inSz );
1271+ AssertIntEQ (wolfSSH_CTX_SetFwdCb (harness .ctx , AcceptFwdCb , NULL ), WS_SUCCESS );
1272+
1273+ ret = DoReceive (harness .ssh );
1274+
1275+ AssertIntEQ (ret , WS_SUCCESS );
1276+ AssertGlobalRequestReply (& harness , MSGID_REQUEST_SUCCESS );
1277+
1278+ FreeChannelOpenHarness (& harness );
1279+ }
1280+
1281+ static void TestGlobalRequestFwdCancelNoCbSendsFailure (void )
1282+ {
1283+ ChannelOpenHarness harness ;
1284+ byte in [256 ];
1285+ word32 inSz ;
1286+ int ret ;
1287+
1288+ inSz = BuildGlobalRequestFwdPacket ("0.0.0.0" , 2222 , 1 , 1 , in , sizeof (in ));
1289+ InitChannelOpenHarness (& harness , in , inSz );
1290+
1291+ ret = DoReceive (harness .ssh );
1292+
1293+ AssertIntEQ (ret , WS_SUCCESS );
1294+ AssertGlobalRequestReply (& harness , MSGID_REQUEST_FAILURE );
1295+
1296+ FreeChannelOpenHarness (& harness );
1297+ }
1298+
1299+ static void TestGlobalRequestFwdCancelWithCbSendsSuccess (void )
1300+ {
1301+ ChannelOpenHarness harness ;
1302+ byte in [256 ];
1303+ word32 inSz ;
1304+ int ret ;
1305+
1306+ inSz = BuildGlobalRequestFwdPacket ("0.0.0.0" , 2222 , 1 , 1 , in , sizeof (in ));
1307+ InitChannelOpenHarness (& harness , in , inSz );
1308+ AssertIntEQ (wolfSSH_CTX_SetFwdCb (harness .ctx , AcceptFwdCb , NULL ), WS_SUCCESS );
1309+
1310+ ret = DoReceive (harness .ssh );
1311+
1312+ AssertIntEQ (ret , WS_SUCCESS );
1313+ AssertGlobalRequestReply (& harness , MSGID_REQUEST_SUCCESS );
1314+
1315+ FreeChannelOpenHarness (& harness );
1316+ }
11871317#endif
11881318
11891319#ifdef WOLFSSH_AGENT
@@ -1648,6 +1778,11 @@ int main(int argc, char** argv)
16481778 TestChannelOpenCallbackRejectSendsOpenFail ();
16491779#ifdef WOLFSSH_FWD
16501780 TestDirectTcpipRejectSendsOpenFail ();
1781+ TestGlobalRequestFwdNoCbSendsFailure ();
1782+ TestGlobalRequestFwdNoCbNoReplyKeepsConnection ();
1783+ TestGlobalRequestFwdWithCbSendsSuccess ();
1784+ TestGlobalRequestFwdCancelNoCbSendsFailure ();
1785+ TestGlobalRequestFwdCancelWithCbSendsSuccess ();
16511786#endif
16521787#ifdef WOLFSSH_AGENT
16531788 TestAgentChannelNullAgentSendsOpenFail ();
0 commit comments