@@ -1118,6 +1118,18 @@ static void AssertGlobalRequestReply(const ChannelOpenHarness* harness,
11181118 }
11191119 }
11201120}
1121+
1122+ static word32 ParseGlobalRequestSuccessPort (const byte * packet , word32 packetSz )
1123+ {
1124+ word32 port ;
1125+
1126+ AssertNotNull (packet );
1127+ AssertTrue (packetSz >= 10 );
1128+ AssertIntEQ (packet [5 ], MSGID_REQUEST_SUCCESS );
1129+ WMEMCPY (& port , packet + 6 , sizeof (port ));
1130+
1131+ return ntohl (port );
1132+ }
11211133#endif
11221134
11231135static int RejectChannelOpenCb (WOLFSSH_CHANNEL * channel , void * ctx )
@@ -1130,7 +1142,7 @@ static int RejectChannelOpenCb(WOLFSSH_CHANNEL* channel, void* ctx)
11301142
11311143#ifdef WOLFSSH_FWD
11321144static int RejectDirectTcpipSetup (WS_FwdCbAction action , void * ctx ,
1133- const char * host , word32 port )
1145+ const char * host , word32 * port )
11341146{
11351147 (void )ctx ;
11361148 (void )host ;
@@ -1143,7 +1155,7 @@ static int RejectDirectTcpipSetup(WS_FwdCbAction action, void* ctx,
11431155}
11441156
11451157static int AcceptFwdCb (WS_FwdCbAction action , void * ctx ,
1146- const char * host , word32 port )
1158+ const char * host , word32 * port )
11471159{
11481160 (void )action ;
11491161 (void )ctx ;
@@ -1152,6 +1164,35 @@ static int AcceptFwdCb(WS_FwdCbAction action, void* ctx,
11521164
11531165 return WS_SUCCESS ;
11541166}
1167+
1168+ #define REGRESS_FWD_ALLOC_PORT 49152
1169+
1170+ static int AllocatePortFwdCb (WS_FwdCbAction action , void * ctx ,
1171+ const char * host , word32 * port )
1172+ {
1173+ (void )ctx ;
1174+ (void )host ;
1175+
1176+ if (action == WOLFSSH_FWD_REMOTE_SETUP && port != NULL && * port == 0 )
1177+ * port = REGRESS_FWD_ALLOC_PORT ;
1178+
1179+ return WS_SUCCESS ;
1180+ }
1181+
1182+ /* Accepts the remote setup but never reports an allocated port. Records
1183+ * whether the server asks it to clean the setup back up. */
1184+ static int NoPortFwdCb (WS_FwdCbAction action , void * ctx ,
1185+ const char * host , word32 * port )
1186+ {
1187+ int * cleanupCalled = (int * )ctx ;
1188+ (void )host ;
1189+ (void )port ;
1190+
1191+ if (action == WOLFSSH_FWD_REMOTE_CLEANUP && cleanupCalled != NULL )
1192+ * cleanupCalled = 1 ;
1193+
1194+ return WS_SUCCESS ;
1195+ }
11551196#endif
11561197
11571198
@@ -1523,6 +1564,56 @@ static void TestGlobalRequestFwdWithCbSendsSuccess(void)
15231564 FreeChannelOpenHarness (& harness );
15241565}
15251566
1567+ static void TestGlobalRequestFwdPort0ReturnsAllocatedPort (void )
1568+ {
1569+ ChannelOpenHarness harness ;
1570+ byte in [256 ];
1571+ word32 inSz ;
1572+ int ret ;
1573+
1574+ /* A bind port of 0 asks the server to allocate a port. The success reply
1575+ * must carry the port the callback allocated, not the requested 0. */
1576+ inSz = BuildGlobalRequestFwdPacket ("0.0.0.0" , 0 , 0 , 1 , in , sizeof (in ));
1577+ InitChannelOpenHarness (& harness , in , inSz );
1578+ AssertIntEQ (wolfSSH_CTX_SetFwdCb (harness .ctx , AllocatePortFwdCb , NULL ),
1579+ WS_SUCCESS );
1580+
1581+ ret = DoReceive (harness .ssh );
1582+
1583+ AssertIntEQ (ret , WS_SUCCESS );
1584+ AssertGlobalRequestReply (& harness , MSGID_REQUEST_SUCCESS );
1585+ AssertIntEQ (ParseGlobalRequestSuccessPort (harness .io .out , harness .io .outSz ),
1586+ REGRESS_FWD_ALLOC_PORT );
1587+
1588+ FreeChannelOpenHarness (& harness );
1589+ }
1590+
1591+ static void TestGlobalRequestFwdPort0NoAllocSendsFailure (void )
1592+ {
1593+ ChannelOpenHarness harness ;
1594+ byte in [256 ];
1595+ word32 inSz ;
1596+ int ret ;
1597+ int cleanupCalled = 0 ;
1598+
1599+ /* The peer asked the server to choose a port (0), but the callback
1600+ * accepts without reporting one. The server must reject and tear the
1601+ * setup back down rather than reply with a non-compliant port 0. */
1602+ inSz = BuildGlobalRequestFwdPacket ("0.0.0.0" , 0 , 0 , 1 , in , sizeof (in ));
1603+ InitChannelOpenHarness (& harness , in , inSz );
1604+ AssertIntEQ (wolfSSH_CTX_SetFwdCb (harness .ctx , NoPortFwdCb , NULL ),
1605+ WS_SUCCESS );
1606+ AssertIntEQ (wolfSSH_SetFwdCbCtx (harness .ssh , & cleanupCalled ), WS_SUCCESS );
1607+
1608+ ret = DoReceive (harness .ssh );
1609+
1610+ AssertIntEQ (ret , WS_SUCCESS );
1611+ AssertGlobalRequestReply (& harness , MSGID_REQUEST_FAILURE );
1612+ AssertIntEQ (cleanupCalled , 1 );
1613+
1614+ FreeChannelOpenHarness (& harness );
1615+ }
1616+
15261617static void TestGlobalRequestFwdCancelNoCbSendsFailure (void )
15271618{
15281619 ChannelOpenHarness harness ;
@@ -3416,6 +3507,8 @@ int main(int argc, char** argv)
34163507 TestGlobalRequestFwdNoCbSendsFailure ();
34173508 TestGlobalRequestFwdNoCbNoReplyKeepsConnection ();
34183509 TestGlobalRequestFwdWithCbSendsSuccess ();
3510+ TestGlobalRequestFwdPort0ReturnsAllocatedPort ();
3511+ TestGlobalRequestFwdPort0NoAllocSendsFailure ();
34193512 TestGlobalRequestFwdCancelNoCbSendsFailure ();
34203513 TestGlobalRequestFwdCancelWithCbSendsSuccess ();
34213514 TestRequestSuccessWithPortParsesCorrectly ();
0 commit comments