diff --git a/src/core/connection.c b/src/core/connection.c index adb3f66697..d0c9edfd87 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -306,6 +306,36 @@ QuicConnAlloc( return Status; } +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicConnCreateOOB( + _In_ QUIC_REGISTRATION* Registration, + _Inout_ uint32_t* BufferLength, + _Out_writes_bytes_opt_(*BufferLength) + void* Buffer + ) +{ + UNREFERENCED_PARAMETER(Registration); + UNREFERENCED_PARAMETER(BufferLength); + UNREFERENCED_PARAMETER(Buffer); + return QUIC_STATUS_NOT_SUPPORTED; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicConnSetOOB( + _In_ QUIC_CONNECTION* Connection, + _In_ uint32_t BufferLength, + _In_reads_bytes_(BufferLength) + const void* Buffer + ) +{ + UNREFERENCED_PARAMETER(Connection); + UNREFERENCED_PARAMETER(BufferLength); + UNREFERENCED_PARAMETER(Buffer); + return QUIC_STATUS_NOT_SUPPORTED; +} + _IRQL_requires_max_(DISPATCH_LEVEL) void QuicConnFree( @@ -6614,6 +6644,10 @@ QuicConnParamSet( return QUIC_STATUS_SUCCESS; } +case QUIC_PARAM_CONN_OOB_INFO: + Status = QuicConnSetOOB(Connection, BufferLength, Buffer); + break; + // // Private // diff --git a/src/core/connection.h b/src/core/connection.h index bfff21972a..dbe4163eba 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -991,6 +991,20 @@ QuicConnAlloc( QUIC_CONNECTION** NewConnection ); +// +// Creates a new (server side) out-of-band connection and writes the info to the +// output buffer for the peer (client) may use it to create an outgoing +// connection. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicConnCreateOOB( + _In_ QUIC_REGISTRATION* Registration, + _Inout_ uint32_t* BufferLength, + _Out_writes_bytes_opt_(*BufferLength) + void* Buffer + ); + // // Called to free the memory for a connection. // diff --git a/src/core/listener.c b/src/core/listener.c index 8466f8302f..8b166990ac 100644 --- a/src/core/listener.c +++ b/src/core/listener.c @@ -855,6 +855,11 @@ QuicListenerParamGet( Status = QUIC_STATUS_SUCCESS; break; + case QUIC_PARAM_LISTENER_OOB_CONNECTION: + Status = + QuicConnCreateOOB(Listener->Registration, BufferLength, Buffer); + break; + default: Status = QUIC_STATUS_INVALID_PARAMETER; break; diff --git a/src/inc/msquic.h b/src/inc/msquic.h index d9c25b8933..366b7d8d82 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -884,6 +884,7 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W { #define QUIC_PARAM_LISTENER_STATS 0x04000001 // QUIC_LISTENER_STATISTICS #ifdef QUIC_API_ENABLE_PREVIEW_FEATURES #define QUIC_PARAM_LISTENER_CIBIR_ID 0x04000002 // uint8_t[] {offset, id[]} +#define QUIC_PARAM_LISTENER_OOB_CONNECTION 0x04000003 // uint8_t[] #endif // @@ -918,6 +919,9 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W { #define QUIC_PARAM_CONN_STATISTICS_V2 0x05000016 // QUIC_STATISTICS_V2 #define QUIC_PARAM_CONN_STATISTICS_V2_PLAT 0x05000017 // QUIC_STATISTICS_V2 #define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018 // uint8_t[] +#ifdef QUIC_API_ENABLE_PREVIEW_FEATURES +#define QUIC_PARAM_CONN_OOB_INFO 0x05000019 // uint8_t[] +#endif // // Parameters for TLS. diff --git a/src/test/MsQuicTests.h b/src/test/MsQuicTests.h index f75e1a8aa7..e5c5e402dc 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -284,6 +284,13 @@ QuicTestShutdownDuringHandshake( _In_ bool ClientShutdown ); +#ifdef QUIC_API_ENABLE_PREVIEW_FEATURES +void +QuicTestOOBHandshake( + _In_ int Family + ); +#endif + // // Negative Handshake Tests // @@ -1330,4 +1337,8 @@ typedef struct { QUIC_CTL_CODE(125, METHOD_BUFFERED, FILE_WRITE_DATA) // BOOLEAN - EnableResumption -#define QUIC_MAX_IOCTL_FUNC_CODE 125 +#define IOCTL_QUIC_RUN_OOB_HANDSHAKE \ + QUIC_CTL_CODE(126, METHOD_BUFFERED, FILE_WRITE_DATA) + // int - Family + +#define QUIC_MAX_IOCTL_FUNC_CODE 126 diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index c717d79bb2..b70531a384 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1496,6 +1496,17 @@ TEST_P(WithHandshakeArgs4, RandomLossResumeRejection) { #endif // QUIC_DISABLE_RESUMPTION #endif // QUIC_TEST_DATAPATH_HOOKS_ENABLED +#ifdef QUIC_API_ENABLE_PREVIEW_FEATURES +TEST_P(WithFamilyArgs, OOBHandshake) { + TestLoggerT<ParamType> Logger("QuicTestOOBHandshake", GetParam()); + if (TestingKernelMode) { + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_OOB_HANDSHAKE, GetParam().Family)); + } else { + QuicTestOOBHandshake(GetParam().Family); + } +} +#endif + TEST_P(WithFamilyArgs, Unreachable) { if (GetParam().Family == 4 && IsWindows2019()) GTEST_SKIP(); // IPv4 unreachable doesn't work on 2019 TestLoggerT<ParamType> Logger("QuicTestConnectUnreachable", GetParam()); diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index 839457729c..b31ba8d8bc 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -524,6 +524,7 @@ size_t QUIC_IOCTL_BUFFER_SIZES[] = 0, 0, sizeof(BOOLEAN), + sizeof(INT32), }; CXPLAT_STATIC_ASSERT( @@ -1483,6 +1484,11 @@ QuicTestCtlEvtIoDeviceControl( QuicTestCtlRun(QuicTestTlsHandshakeInfo(Params->EnableResumption != 0)); break; + case IOCTL_QUIC_RUN_OOB_HANDSHAKE: + CXPLAT_FRE_ASSERT(Params != nullptr); + QuicTestCtlRun(QuicTestOOBHandshake(Params->Family)); + break; + default: Status = STATUS_NOT_IMPLEMENTED; break; diff --git a/src/test/lib/HandshakeTest.cpp b/src/test/lib/HandshakeTest.cpp index 71cddd74c5..e596f03d33 100644 --- a/src/test/lib/HandshakeTest.cpp +++ b/src/test/lib/HandshakeTest.cpp @@ -4023,3 +4023,41 @@ QuicTestHandshakeSpecificLossPatterns( Listener.LastConnection->Shutdown(0, QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT); } } + +void +QuicTestOOBHandshake( + _In_ int Family + ) +{ + MsQuicRegistration Registration; + TEST_QUIC_SUCCEEDED(Registration.GetInitStatus()); + + MsQuicSettings Settings; + Settings.SetIdleTimeoutMs(60000) + .SetDisconnectTimeoutMs(60000) + .SetInitialRttMs(20); + + MsQuicConfiguration ServerConfiguration(Registration, "MsQuicTest", Settings, ServerSelfSignedCredConfig); + TEST_QUIC_SUCCEEDED(ServerConfiguration.GetInitStatus()); + + MsQuicConfiguration ClientConfiguration(Registration, "MsQuicTest", Settings, MsQuicCredentialConfig()); + TEST_QUIC_SUCCEEDED(ClientConfiguration.GetInitStatus()); + + QuicAddr ServerLocalAddr((Family == 4) ? QUIC_ADDRESS_FAMILY_INET : QUIC_ADDRESS_FAMILY_INET6); + MsQuicAutoAcceptListener Listener(Registration, ServerConfiguration, MsQuicConnection::NoOpCallback); + TEST_QUIC_SUCCEEDED(Listener.Start("MsQuicTest", &ServerLocalAddr.SockAddr)); + TEST_QUIC_SUCCEEDED(Listener.GetInitStatus()); + TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr)); + + uint32_t OOBLength = 0; + TEST_QUIC_SUCCEEDED(Listener.GetParam(QUIC_PARAM_LISTENER_OOB_CONNECTION, &OOBLength, nullptr)); + UniquePtr<uint8_t[]> OOBData(new(std::nothrow) uint8_t[OOBLength]); + TEST_QUIC_SUCCEEDED(Listener.GetParam(QUIC_PARAM_LISTENER_OOB_CONNECTION, &OOBLength, OOBData.get())); + + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + TEST_QUIC_SUCCEEDED(Connection.SetParam(QUIC_PARAM_CONN_OOB_INFO, OOBLength, OOBData.get())); + TEST_QUIC_SUCCEEDED(Connection.Start(ClientConfiguration, ServerLocalAddr.GetFamily(), QUIC_TEST_LOOPBACK_FOR_AF(ServerLocalAddr.GetFamily()), ServerLocalAddr.GetPort())); + TEST_TRUE(Connection.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(Connection.HandshakeComplete); +}