QUIC клиент не хочет подключаться по туннелю
Написал вот такой базовый сервер на QUIC который слушает 2 потока:
using System.Net;
using System.Net.Quic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace QuicServer
{
class Program
{
static async Task Main(string[] args)
{
bool isRunning = true;
X509Certificate2 serverCertificate = new X509Certificate2(@"C:\Users\sheud\source\repos\TESTQUICSERVER\certificate.pfx", "pswd");
if (!QuicListener.IsSupported)
{
Console.WriteLine("QUIC is not supported, check for presence of libmsquic and support of TLS 1.3.");
return;
}
var serverConnectionOptions = new QuicServerConnectionOptions
{
DefaultStreamErrorCode = 0x0A,
DefaultCloseErrorCode = 0x0B,
ServerAuthenticationOptions = new SslServerAuthenticationOptions
{
ApplicationProtocols = new List<SslApplicationProtocol>
{
new SslApplicationProtocol("threadone"),
new SslApplicationProtocol("threadtwo")
},
ServerCertificate = serverCertificate
}
};
var listener = await QuicListener.ListenAsync(new QuicListenerOptions
{
ListenEndPoint = new IPEndPoint(IPAddress.Any, 5555),
ApplicationProtocols = new List<SslApplicationProtocol>
{
new SslApplicationProtocol("threadone"),
new SslApplicationProtocol("threadtwo")
},
ConnectionOptionsCallback = (_, _, _) => ValueTask.FromResult(serverConnectionOptions)
});
Console.WriteLine("Server started...");
while (isRunning)
{
var connection = await listener.AcceptConnectionAsync();
Console.WriteLine($"Connection from {connection.RemoteEndPoint}");
_ = Task.Run(async () =>
{
try
{
var streamOne = await connection.AcceptInboundStreamAsync();
var streamTwo = await connection.AcceptInboundStreamAsync();
var readerOne = new StreamReader(streamOne);
var readerTwo = new StreamReader(streamTwo);
_ = Task.Run(async () =>
{
while (true)
{
var messageOne = await readerOne.ReadLineAsync();
if (messageOne == null) break;
Console.WriteLine($"Tunnel threadone received message: {messageOne}");
}
});
_ = Task.Run(async () =>
{
while (true)
{
var messageTwo = await readerTwo.ReadLineAsync();
if (messageTwo == null) break;
Console.WriteLine($"Tunnel threadtwo received message: {messageTwo}");
}
});
await Task.Delay(Timeout.Infinite);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
});
}
}
}
}
И клиент который отправляет сообщения каждую секунду в эти 2 потока:
using System.Net;
using System.Net.Quic;
using System.Net.Security;
namespace QuicClient
{
class Program
{
static async Task Main(string[] args)
{
bool isRunning = true;
if (!QuicConnection.IsSupported)
{
Console.WriteLine("QUIC is not supported, check for presence of libmsquic and support of TLS 1.3.");
return;
}
var clientConnectionOptions = new QuicClientConnectionOptions
{
RemoteEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5555),
DefaultStreamErrorCode = 0x0A,
DefaultCloseErrorCode = 0x0B,
MaxInboundUnidirectionalStreams = 10,
MaxInboundBidirectionalStreams = 100,
ClientAuthenticationOptions = new SslClientAuthenticationOptions
{
ApplicationProtocols = new List<SslApplicationProtocol>
{
new SslApplicationProtocol("threadone"),
new SslApplicationProtocol("threadtwo")
},
TargetHost = "localhost",
RemoteCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
}
};
QuicConnection? connection = null;
try
{
connection = await QuicConnection.ConnectAsync(clientConnectionOptions);
Console.WriteLine($"Connected {connection.LocalEndPoint} > {connection.RemoteEndPoint}");
var streamOne = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
var streamTwo = await connection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
var writerOne = new StreamWriter(streamOne);
var writerTwo = new StreamWriter(streamTwo);
while (isRunning)
{
await writerOne.WriteLineAsync("message1");
await writerOne.FlushAsync();
await writerTwo.WriteLineAsync("message2");
await writerTwo.FlushAsync();
await Task.Delay(1000);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error connecting: {ex}");
}
if (connection != null)
{
await connection.CloseAsync(0x0C);
await connection.DisposeAsync();
}
}
}
}
Этот код работает, однако когда пытаюсь подключаться не по локалхосту а через туннель (я использовал ngrok, он потдерживает TLS 1.3) подключение не устанавливаеться. Заменил:
RemoteEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5555),
на
RemoteEndPoint = new DnsEndPoint("4.tcp.eu.ngrok.io", 10956),
И я задал параметр TargetHost в 4.tcp.eu.ngrok.io
, однако при подключении получаю молчание, и спустя пару секунд ошибку о том что ввремя ожидания истекло. Имею подозрения о том что какие то проблемы с сертефикатом, создавал его с помощью:
New-SelfSignedCertificate -DnsName $env:computername,localhost -FriendlyName MsQuic-Test -KeyUsageProperty Sign -KeyUsage DigitalSignature -CertStoreLocation cert:\CurrentUser\My -HashAlgorithm SHA256 -Provider "Microsoft Software Key Storage Provider" -KeyExportPolicy Exportable
Но я не уверен что проблема именно с сертефикатом, пытался через WireShark прослушать порт 10956
и не увидел ничего, даже каких то попыток подключиться так что не уверен что проблема именно с сертефикатом
Ответы (1 шт):
Ошибка оказалась довольно простой: ngrok
банально не поддерживает UDP, а работа QUIC основана на UDP.
Открыл туннель через localtonet
, и все заработало, сертификат никак не менял для работы не по localhost
.