Browse Source

fix: tcp NAT test

Bruce Wayne 2 years ago
parent
commit
8645b8b799

+ 1 - 0
NatTypeTester.ViewModels/MainWindowViewModel.cs

@@ -22,6 +22,7 @@ public class MainWindowViewModel : ViewModelBase, IScreen
 	private readonly IEnumerable<string> _defaultServers = new HashSet<string>
 	{
 		@"stunserver.stunprotocol.org",
+		@"stun.hot-chilli.net",
 		@"stun.syncthing.net",
 		@"stun.qq.com",
 		@"stun.miwifi.com"

+ 4 - 5
STUN/Client/StunClient5389TCP.cs

@@ -17,7 +17,7 @@ public class StunClient5389TCP : IStunClient5389
 	public TimeSpan ConnectTimeout { get; set; } = TimeSpan.FromSeconds(3);
 
 	private readonly IPEndPoint _remoteEndPoint;
-	private readonly IPEndPoint _initLocalEndPoint;
+	private IPEndPoint _lastLocalEndPoint;
 
 	private readonly ITcpProxy _proxy;
 
@@ -32,7 +32,7 @@ public class StunClient5389TCP : IStunClient5389
 
 		_remoteEndPoint = server;
 
-		_initLocalEndPoint = local;
+		_lastLocalEndPoint = local;
 		State.LocalEndPoint = local;
 	}
 
@@ -155,11 +155,9 @@ public class StunClient5389TCP : IStunClient5389
 		{
 			using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 			cts.CancelAfter(ConnectTimeout);
-			IDuplexPipe pipe = await _proxy.ConnectAsync(_initLocalEndPoint, remote, cts.Token);
+			IDuplexPipe pipe = await _proxy.ConnectAsync(_lastLocalEndPoint, remote, cts.Token);
 			try
 			{
-				_initLocalEndPoint.Port = default;
-
 				using IMemoryOwner<byte> memoryOwner = MemoryPool<byte>.Shared.Rent(sendMessage.Length);
 				Memory<byte> buffer = memoryOwner.Memory;
 				int length = sendMessage.WriteTo(buffer.Span);
@@ -174,6 +172,7 @@ public class StunClient5389TCP : IStunClient5389
 					IPEndPoint? local = _proxy.CurrentLocalEndPoint;
 					if (local is not null)
 					{
+						_lastLocalEndPoint = local;
 						return new StunResponse(message, remote, local);
 					}
 				}

+ 10 - 7
STUN/Proxy/DirectTcpProxy.cs

@@ -37,11 +37,7 @@ public class DirectTcpProxy : ITcpProxy, IDisposableObservable
 	{
 		Verify.NotDisposed(this);
 
-		if (_tcpClient is not null)
-		{
-			CloseClient();
-			_tcpClient = default;
-		}
+		CloseClient();
 
 		return default;
 	}
@@ -53,8 +49,15 @@ public class DirectTcpProxy : ITcpProxy, IDisposableObservable
 			return;
 		}
 
-		_tcpClient.Client.Close(0);
-		_tcpClient.Dispose();
+		try
+		{
+			_tcpClient.Client.Close(0);
+		}
+		finally
+		{
+			_tcpClient.Dispose();
+			_tcpClient = default;
+		}
 	}
 
 	public bool IsDisposed { get; private set; }

+ 9 - 3
STUN/Proxy/Socks5TcpProxy.cs

@@ -70,9 +70,15 @@ public class Socks5TcpProxy : ITcpProxy, IDisposableObservable
 			return;
 		}
 
-		GetTcpClient()?.Client.Close(0);
-		_socks5Client.Dispose();
-		_socks5Client = default;
+		try
+		{
+			GetTcpClient()?.Client.Close(0);
+		}
+		finally
+		{
+			_socks5Client.Dispose();
+			_socks5Client = default;
+		}
 	}
 
 	public bool IsDisposed { get; private set; }

+ 34 - 0
UnitTest/StunClient5389TCPTest.cs

@@ -1,6 +1,7 @@
 using Dns.Net.Abstractions;
 using Dns.Net.Clients;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
+using STUN;
 using STUN.Client;
 using STUN.Enums;
 using STUN.StunResult;
@@ -49,4 +50,37 @@ public class StunClient5389TCPTest
 		Assert.IsNull(response.LocalEndPoint);
 		Assert.IsNull(response.OtherEndPoint);
 	}
+
+	[TestMethod]
+	public async Task TestServerAsync()
+	{
+		const string url = @"https://raw.githubusercontent.com/pradt2/always-online-stun/master/valid_hosts_tcp.txt";
+		HttpClient httpClient = new();
+		string listRaw = await httpClient.GetStringAsync(url);
+		string[] list = listRaw.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+
+		foreach (string host in list)
+		{
+			if (!HostnameEndpoint.TryParse(host, out HostnameEndpoint? hostEndpoint, 3478))
+			{
+				continue;
+			}
+
+			IPAddress ip = await _dnsClient.QueryAsync(hostEndpoint.Hostname);
+			using IStunClient5389 client = new StunClient5389TCP(new IPEndPoint(ip, hostEndpoint.Port), Any);
+			try
+			{
+				await client.QueryAsync();
+			}
+			catch
+			{
+				// ignored
+			}
+
+			if (client.State.MappingBehavior is MappingBehavior.AddressAndPortDependent or MappingBehavior.AddressDependent or MappingBehavior.EndpointIndependent or MappingBehavior.Direct)
+			{
+				Console.WriteLine(host);
+			}
+		}
+	}
 }