Bruce Wayne 5 年之前
父节点
当前提交
2a85185975
共有 3 个文件被更改,包括 93 次插入63 次删除
  1. 51 39
      NatTypeTester/Model/StunServer.cs
  2. 40 22
      STUN/Client/StunClient3489.cs
  3. 2 2
      STUN/Utils/AttributeExtensions.cs

+ 51 - 39
NatTypeTester/Model/StunServer.cs

@@ -1,44 +1,56 @@
-namespace NatTypeTester.Model
+using System;
+
+namespace NatTypeTester.Model
 {
-	public class StunServer
-	{
-		public string Hostname;
-		public ushort Port;
+    public class StunServer
+    {
+        public string Hostname;
+        public ushort Port;
+
+        public StunServer()
+        {
+            Hostname = @"stun.qq.com";
+            Port = 3478;
+        }
 
-		public StunServer()
-		{
-			Hostname = @"stun.qq.com";
-			Port = 3478;
-		}
+        public bool Parse(string str)
+        {
+            var ipPort = str.Trim().Split(':', ':');
+            var host = ipPort[0].Trim();
+            if (Uri.CheckHostName(host) != UriHostNameType.Dns)
+            {
+                return false;
+            }
+            switch (ipPort.Length)
+            {
+                case 2:
+                {
+                    if (ushort.TryParse(ipPort[1], out var port))
+                    {
+                        Hostname = host;
+                        Port = port;
+                        return true;
+                    }
+                    break;
+                }
+                case 1:
+                {
+                    Hostname = host;
+                    Port = 3478;
+                    return true;
+                }
+            }
 
-		public bool Parse(string str)
-		{
-			var ipPort = str.Trim().Split(':', ':');
-			if (ipPort.Length == 2)
-			{
-				if (!string.IsNullOrWhiteSpace(ipPort[0]) && ushort.TryParse(ipPort[1], out var port))
-				{
-					Hostname = ipPort[0];
-					Port = port;
-					return true;
-				}
-			}
-			if (ipPort.Length == 1)
-			{
-				Hostname = ipPort[0];
-				Port = 3478;
-				return true;
-			}
-			return false;
-		}
+            return false;
+        }
 
-		public override string ToString()
-		{
-			if (Port == 3478)
-			{
-				return Hostname;
-			}
-			return $@"{Hostname}:{Port}";
-		}
-	}
+        public override string ToString()
+        {
+            if (Port == 3478)
+            {
+                return Hostname;
+            }
+            return $@"{Hostname}:{Port}";
+        }
+    }
 }

+ 40 - 22
STUN/Client/StunClient3489.cs

@@ -49,11 +49,15 @@ namespace STUN.Client
             var test1 = new StunMessage5389 { StunMessageType = StunMessageType.BindingRequest, MagicCookie = 0 };
 
             var (response1, remote1) = Test(test1);
+            if (response1 == null)
+            {
+                return new ClassicStunResult(NatType.UdpBlocked, null);
+            }
             var mappedAddress1 = AttributeExtensions.GetMappedAddressAttribute(response1);
             var changedAddress1 = AttributeExtensions.GetChangedAddressAttribute(response1);
             if (mappedAddress1 == null || changedAddress1 == null)
             {
-                return new ClassicStunResult(NatType.UdpBlocked, null);
+                return new ClassicStunResult(NatType.UnsupportedServer, null);
             }
 
             var test2 = new StunMessage5389
@@ -71,12 +75,12 @@ namespace STUN.Client
             if (Equals(mappedAddress1, LocalEndPoint))
             {
                 // No NAT
-                var type = mappedAddress2 == null ? NatType.SymmetricUdpFirewall : NatType.OpenInternet;
+                var type = response2 == null ? NatType.SymmetricUdpFirewall : NatType.OpenInternet;
                 return new ClassicStunResult(type, mappedAddress2);
             }
 
             // NAT
-            if (mappedAddress2 != null && changedAddress2 != null)
+            if (response2 != null)
             {
                 // 有些单 IP 服务器并不能测 NAT 类型,比如 Google 的
                 var type = Equals(remote1.Address, remote2.Address) || Equals(remote1.Port, remote2.Port) ? NatType.UnsupportedServer : NatType.FullCone;
@@ -121,27 +125,41 @@ namespace STUN.Client
             try
             {
                 var b1 = sendMessage.Bytes.ToArray();
+                var t = DateTime.Now;
 
-                if (remote == null)
-                {
-                    Debug.WriteLine($@"{LocalEndPoint} => {_server}:{_port} {b1.Length} 字节");
-                    _udpClient.Send(b1, b1.Length, _server, _port);
-                }
-                else
-                {
-                    Debug.WriteLine($@"{LocalEndPoint} => {remote} {b1.Length} 字节");
-                    _udpClient.Send(b1, b1.Length, remote);
-                }
-
-                IPEndPoint ipe = null;
-
-                var receive1 = _udpClient.Receive(ref ipe);
-
-                var message = new StunMessage5389();
-                if (message.TryParse(receive1) && message.ClassicTransactionId.IsEqual(sendMessage.ClassicTransactionId))
+                // Simple retransmissions
+                //https://tools.ietf.org/html/rfc3489#section-9.3
+                while (t + TimeSpan.FromSeconds(3) > DateTime.Now)
                 {
-                    Debug.WriteLine($@"收到 {ipe} {receive1.Length} 字节");
-                    return (message, ipe);
+                    try
+                    {
+                        if (remote == null)
+                        {
+                            Debug.WriteLine($@"{LocalEndPoint} => {_server}:{_port} {b1.Length} 字节");
+                            _udpClient.Send(b1, b1.Length, _server, _port);
+                        }
+                        else
+                        {
+                            Debug.WriteLine($@"{LocalEndPoint} => {remote} {b1.Length} 字节");
+                            _udpClient.Send(b1, b1.Length, remote);
+                        }
+
+                        IPEndPoint ipe = null;
+
+                        var receive1 = _udpClient.Receive(ref ipe);
+
+                        var message = new StunMessage5389();
+                        if (message.TryParse(receive1) &&
+                            message.ClassicTransactionId.IsEqual(sendMessage.ClassicTransactionId))
+                        {
+                            Debug.WriteLine($@"收到 {ipe} {receive1.Length} 字节");
+                            return (message, ipe);
+                        }
+                    }
+                    catch
+                    {
+                        // ignored
+                    }
                 }
             }
             catch (Exception ex)

+ 2 - 2
STUN/Utils/AttributeExtensions.cs

@@ -20,7 +20,7 @@ namespace STUN.Utils
 
         public static IPEndPoint GetMappedAddressAttribute(StunMessage5389 response)
         {
-            var mappedAddressAttribute = response?.Attributes.First(t => t.Type == AttributeType.MappedAddress);
+            var mappedAddressAttribute = response?.Attributes.FirstOrDefault(t => t.Type == AttributeType.MappedAddress);
 
             if (mappedAddressAttribute == null) return null;
 
@@ -30,7 +30,7 @@ namespace STUN.Utils
 
         public static IPEndPoint GetChangedAddressAttribute(StunMessage5389 response)
         {
-            var changedAddressAttribute = response?.Attributes.First(t => t.Type == AttributeType.ChangedAddress);
+            var changedAddressAttribute = response?.Attributes.FirstOrDefault(t => t.Type == AttributeType.ChangedAddress);
 
             if (changedAddressAttribute == null) return null;