Jelajahi Sumber

feat: Support hostname in proxy address #59

Bruce Wayne 4 tahun lalu
induk
melakukan
604c0123d7

+ 7 - 3
NatTypeTester.ViewModels/RFC3489ViewModel.cs

@@ -47,11 +47,15 @@ namespace NatTypeTester.ViewModels
 		{
 			Verify.Operation(StunServer.TryParse(Config.StunServer, out var server), @"Wrong STUN Server!");
 
-			var proxyIpe = IPEndPoint.Parse(Config.ProxyServer);
+			if (!HostnameEndpoint.TryParse(Config.ProxyServer, out var proxyIpe))
+			{
+				throw new NotSupportedException(@"Unknown proxy address");
+			}
+
 			var socks5Option = new Socks5CreateOption
 			{
-				Address = proxyIpe.Address,
-				Port = (ushort)proxyIpe.Port,
+				Address = await DnsClient.QueryAsync(proxyIpe.Hostname, token),
+				Port = proxyIpe.Port,
 				UsernamePassword = new UsernamePassword
 				{
 					UserName = Config.ProxyUser,

+ 7 - 3
NatTypeTester.ViewModels/RFC5780ViewModel.cs

@@ -44,11 +44,15 @@ namespace NatTypeTester.ViewModels
 		{
 			Verify.Operation(StunServer.TryParse(Config.StunServer, out var server), @"Wrong STUN Server!");
 
-			var proxyIpe = IPEndPoint.Parse(Config.ProxyServer);
+			if (!HostnameEndpoint.TryParse(Config.ProxyServer, out var proxyIpe))
+			{
+				throw new NotSupportedException(@"Unknown proxy address");
+			}
+
 			var socks5Option = new Socks5CreateOption
 			{
-				Address = proxyIpe.Address,
-				Port = (ushort)proxyIpe.Port,
+				Address = await DnsClient.QueryAsync(proxyIpe.Hostname, token),
+				Port = proxyIpe.Port,
 				UsernamePassword = new UsernamePassword
 				{
 					UserName = Config.ProxyUser,

+ 77 - 0
STUN/HostnameEndpoint.cs

@@ -0,0 +1,77 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Net;
+using System.Net.Sockets;
+
+namespace STUN
+{
+	public class HostnameEndpoint
+	{
+		public string Hostname { get; }
+		public ushort Port { get; }
+
+		private HostnameEndpoint(string host, ushort port)
+		{
+			Hostname = host;
+			Port = port;
+		}
+
+		public static bool TryParse(string s, [NotNullWhen(true)] out HostnameEndpoint? result, ushort defaultPort = 0)
+		{
+			result = null;
+			if (string.IsNullOrEmpty(s))
+			{
+				return false;
+			}
+
+			var hostLength = s.Length;
+			var pos = s.LastIndexOf(':');
+
+			if (pos > 0)
+			{
+				if (s[pos - 1] is ']')
+				{
+					hostLength = pos;
+				}
+				else if (s.AsSpan(0, pos).LastIndexOf(':') is -1)
+				{
+					hostLength = pos;
+				}
+			}
+
+			var host = s[..hostLength];
+			var type = Uri.CheckHostName(host);
+			switch (type)
+			{
+				case UriHostNameType.Dns:
+				case UriHostNameType.IPv4:
+				case UriHostNameType.IPv6:
+				{
+					break;
+				}
+				default:
+				{
+					return false;
+				}
+			}
+
+			if (hostLength == s.Length || ushort.TryParse(s.AsSpan(hostLength + 1), out defaultPort))
+			{
+				result = new HostnameEndpoint(host, defaultPort);
+				return true;
+			}
+
+			return false;
+		}
+
+		public override string ToString()
+		{
+			if (IPAddress.TryParse(Hostname, out var ip) && ip.AddressFamily is AddressFamily.InterNetworkV6)
+			{
+				return $@"[{ip}]:{Port}";
+			}
+
+			return $@"{Hostname}:{Port}";
+		}
+	}
+}

+ 7 - 50
STUN/StunServer.cs

@@ -1,4 +1,3 @@
-using System;
 using System.Diagnostics.CodeAnalysis;
 using System.Net;
 using System.Net.Sockets;
@@ -18,64 +17,22 @@ namespace STUN
 			Port = DefaultPort;
 		}
 
-		private StunServer(string host, ushort port)
+		private StunServer(string hostname, ushort port)
 		{
-			Hostname = host;
+			Hostname = hostname;
 			Port = port;
 		}
 
-		public static bool TryParse(string str, [NotNullWhen(true)] out StunServer? server)
+		public static bool TryParse(string s, [NotNullWhen(true)] out StunServer? result)
 		{
-			server = null;
-			if (string.IsNullOrEmpty(str))
+			if (!HostnameEndpoint.TryParse(s, out var host, DefaultPort))
 			{
+				result = null;
 				return false;
 			}
 
-			var hostLength = str.Length;
-			var pos = str.LastIndexOf(':');
-
-			if (pos > 0)
-			{
-				if (str[pos - 1] is ']')
-				{
-					hostLength = pos;
-				}
-				else if (str.AsSpan(0, pos).LastIndexOf(':') is -1)
-				{
-					hostLength = pos;
-				}
-			}
-
-			var host = str[..hostLength];
-			var type = Uri.CheckHostName(host);
-			switch (type)
-			{
-				case UriHostNameType.Dns:
-				case UriHostNameType.IPv4:
-				case UriHostNameType.IPv6:
-				{
-					break;
-				}
-				default:
-				{
-					return false;
-				}
-			}
-
-			if (hostLength == str.Length)
-			{
-				server = new StunServer(host, DefaultPort);
-				return true;
-			}
-
-			if (ushort.TryParse(str.AsSpan(hostLength + 1), out var port))
-			{
-				server = new StunServer(host, port);
-				return true;
-			}
-
-			return false;
+			result = new StunServer(host.Hostname, host.Port);
+			return true;
 		}
 
 		public override string ToString()

+ 15 - 1
UnitTest/StunServerTest.cs → UnitTest/HostnameEndpointTest.cs

@@ -4,7 +4,7 @@ using STUN;
 namespace UnitTest
 {
 	[TestClass]
-	public class StunServerTest
+	public class HostnameEndpointTest
 	{
 		[TestMethod]
 		[DataRow(@"www.google.com", ushort.MinValue)]
@@ -66,5 +66,19 @@ namespace UnitTest
 			Assert.AreEqual(@"stun.syncthing.net", server.Hostname);
 			Assert.AreEqual(3478, server.Port);
 		}
+
+		[TestMethod]
+		[DataRow(@"stun.syncthing.net:114", @"stun.syncthing.net:114")]
+		[DataRow(@"stun.syncthing.net:3478", @"stun.syncthing.net:3478")]
+		[DataRow(@"[2001:db8:1234:5678:11:2233:4455:6677]", @"[2001:db8:1234:5678:11:2233:4455:6677]:0")]
+		[DataRow(@"[2001:db8:1234:5678:11:2233:4455:6677]:3478", @"[2001:db8:1234:5678:11:2233:4455:6677]:3478")]
+		[DataRow(@"1.1.1.1:3478", @"1.1.1.1:3478")]
+		[DataRow(@"1.1.1.1:1919", @"1.1.1.1:1919")]
+		public void HostnameEndpointToString(string str, string expected)
+		{
+			Assert.IsTrue(HostnameEndpoint.TryParse(str, out var server));
+			Assert.IsNotNull(server);
+			Assert.AreEqual(expected, server.ToString());
+		}
 	}
 }