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 шт):

Автор решения: Sheud

Ошибка оказалась довольно простой: ngrok банально не поддерживает UDP, а работа QUIC основана на UDP.

Открыл туннель через localtonet, и все заработало, сертификат никак не менял для работы не по localhost.

→ Ссылка