Skip to content

Commit

Permalink
improve SNI handling when IP is passed in as DnsEndPoint to QuicListe…
Browse files Browse the repository at this point in the history
…ner (#57255)
  • Loading branch information
wfurt authored Aug 13, 2021
1 parent 293c7f6 commit 42af636
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -599,9 +599,28 @@ internal override ValueTask ConnectAsync(CancellationToken cancellationToken = d
}
else if (_remoteEndPoint is DnsEndPoint)
{
// We don't have way how to set separate SNI and name for connection at this moment.
targetHost = ((DnsEndPoint)_remoteEndPoint).Host;
port = ((DnsEndPoint)_remoteEndPoint).Port;
string dnsHost = ((DnsEndPoint)_remoteEndPoint).Host!;

// We don't have way how to set separate SNI and name for connection at this moment.
// If the name is actually IP address we can use it to make at least some cases work for people
// who want to bypass DNS but connect to specific virtual host.
if (!string.IsNullOrEmpty(_state.TargetHost) && !dnsHost.Equals(_state.TargetHost, StringComparison.InvariantCultureIgnoreCase) && IPAddress.TryParse(dnsHost, out IPAddress? address))
{
// This is form of IPAddress and _state.TargetHost is set to different string
SOCKADDR_INET quicAddress = MsQuicAddressHelpers.IPEndPointToINet(new IPEndPoint(address, port));
unsafe
{
Debug.Assert(!Monitor.IsEntered(_state));
status = MsQuicApi.Api.SetParamDelegate(_state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.REMOTE_ADDRESS, (uint)sizeof(SOCKADDR_INET), (byte*)&quicAddress);
QuicExceptionHelpers.ThrowIfFailed(status, "Failed to connect to peer.");
}
targetHost = _state.TargetHost!;
}
else
{
targetHost = dnsHost;
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ public State(QuicListenerOptions options)

internal MsQuicListener(QuicListenerOptions options)
{
if (options.ListenEndPoint == null)
{
throw new ArgumentNullException(nameof(options.ListenEndPoint));
}

_state = new State(options);
_stateHandle = GCHandle.Alloc(_state);
try
Expand Down
27 changes: 27 additions & 0 deletions src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,33 @@ public async Task ConnectWithCertificateCallback()
serverConnection.Dispose();
}

[Fact]
public async Task ConnectWithIpSetsSni()
{
X509Certificate2 certificate = System.Net.Test.Common.Configuration.Certificates.GetServerCertificate();
string expectedName = "foobar";
string? receivedHostName = null;

var listenerOptions = CreateQuicListenerOptions();
listenerOptions.ServerAuthenticationOptions.ServerCertificate = null;
listenerOptions.ServerAuthenticationOptions.ServerCertificateSelectionCallback = (sender, hostName) =>
{
receivedHostName = hostName;
return certificate;
};

using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, listenerOptions);

QuicClientConnectionOptions clientOptions = CreateQuicClientOptions();
clientOptions.ClientAuthenticationOptions.TargetHost = expectedName;
clientOptions.RemoteEndPoint = new DnsEndPoint("127.0.0.1", listener.ListenEndPoint.Port);

(QuicConnection clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection(clientOptions, listener);
Assert.Equal(expectedName, receivedHostName);
clientConnection.Dispose();
serverConnection.Dispose();
}

[Fact]
public async Task ConnectWithCertificateForDifferentName_Throws()
{
Expand Down

0 comments on commit 42af636

Please sign in to comment.