瀏覽代碼

Add mapping behavior test

Bruce Wayne 5 年之前
父節點
當前提交
52e08f355d
共有 5 個文件被更改,包括 107 次插入8 次删除
  1. 63 5
      STUN/Client/StunClient5389UDP.cs
  2. 13 0
      STUN/Enums/MappingBehavior.cs
  3. 1 0
      STUN/StunResult/StunResult5389.cs
  4. 9 1
      STUN/Utils/NetUtils.cs
  5. 21 2
      UnitTest/UnitTest.cs

+ 63 - 5
STUN/Client/StunClient5389UDP.cs

@@ -7,10 +7,15 @@ using System;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Net;
 using System.Net;
+using System.Net.Sockets;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
 namespace STUN.Client
 namespace STUN.Client
 {
 {
+    /// <summary>
+    /// https://tools.ietf.org/html/rfc5389#section-7.2.1
+    /// https://tools.ietf.org/html/rfc5780#section-4.2
+    /// </summary>
     public class StunClient5389UDP : StunClient3489
     public class StunClient5389UDP : StunClient3489
     {
     {
         public StunClient5389UDP(string server, ushort port = 3478, IPEndPoint local = null, IDnsQuery dnsQuery = null)
         public StunClient5389UDP(string server, ushort port = 3478, IPEndPoint local = null, IDnsQuery dnsQuery = null)
@@ -26,16 +31,18 @@ namespace STUN.Client
 
 
         public override async Task<IStunResult> QueryAsync()
         public override async Task<IStunResult> QueryAsync()
         {
         {
-            return await BindingTestAsync();
+            var (result, _) = await BindingTestAsync(RemoteEndPoint);
+            return result;
         }
         }
 
 
-        public async Task<StunResult5389> BindingTestAsync()
+        public async Task<(StunResult5389, IPEndPoint)> BindingTestAsync(IPEndPoint remote)
         {
         {
             BindingTestResult res;
             BindingTestResult res;
 
 
             var test = new StunMessage5389 { StunMessageType = StunMessageType.BindingRequest };
             var test = new StunMessage5389 { StunMessageType = StunMessageType.BindingRequest };
-            var (response1, _, local1) = await TestAsync(test, RemoteEndPoint, RemoteEndPoint);
+            var (response1, _, local1) = await TestAsync(test, remote, remote);
             var mappedAddress1 = AttributeExtensions.GetXorMappedAddressAttribute(response1);
             var mappedAddress1 = AttributeExtensions.GetXorMappedAddressAttribute(response1);
+            var otherAddress = AttributeExtensions.GetOtherAddressAttribute(response1);
 
 
             if (response1 == null)
             if (response1 == null)
             {
             {
@@ -50,12 +57,63 @@ namespace STUN.Client
                 res = BindingTestResult.Success;
                 res = BindingTestResult.Success;
             }
             }
 
 
-            return new StunResult5389
+            return (new StunResult5389
             {
             {
                 BindingTestResult = res,
                 BindingTestResult = res,
                 LocalEndPoint = local1 == null ? null : new IPEndPoint(local1, LocalEndPoint.Port),
                 LocalEndPoint = local1 == null ? null : new IPEndPoint(local1, LocalEndPoint.Port),
                 PublicEndPoint = mappedAddress1
                 PublicEndPoint = mappedAddress1
-            };
+            }, otherAddress);
+        }
+
+        public async Task<StunResult5389> MappingBehaviorTestAsync()
+        {
+            // test I
+            var (result1, otherAddress) = await BindingTestAsync(RemoteEndPoint);
+
+            if (result1.BindingTestResult != BindingTestResult.Success)
+            {
+                return result1;
+            }
+
+            if (otherAddress == null
+            || Equals(otherAddress.Address, RemoteEndPoint.Address)
+            || otherAddress.Port == RemoteEndPoint.Port)
+            {
+                result1.MappingBehavior = MappingBehavior.UnsupportedServer;
+                return result1;
+            }
+
+            if (Equals(result1.PublicEndPoint, result1.LocalEndPoint))
+            {
+                result1.MappingBehavior = MappingBehavior.Direct;
+                return result1;
+            }
+
+            // test II
+            var (result2, _) = await BindingTestAsync(new IPEndPoint(otherAddress.Address, RemoteEndPoint.Port));
+            if (result2.BindingTestResult != BindingTestResult.Success)
+            {
+                result1.MappingBehavior = MappingBehavior.Fail;
+                return result1;
+            }
+
+            if (Equals(result2.PublicEndPoint, result1.PublicEndPoint))
+            {
+                result1.MappingBehavior = MappingBehavior.EndpointIndependent;
+                return result1;
+            }
+
+            // test III
+            var (result3, _) = await BindingTestAsync(otherAddress);
+            if (result3.BindingTestResult != BindingTestResult.Success)
+            {
+                result1.MappingBehavior = MappingBehavior.Fail;
+                return result1;
+            }
+
+            result1.MappingBehavior = Equals(result3.PublicEndPoint, result2.PublicEndPoint) ? MappingBehavior.AddressDependent : MappingBehavior.AddressAndPortDependent;
+
+            return result1;
         }
         }
 
 
         private async Task<(StunMessage5389, IPEndPoint, IPAddress)> TestAsync(StunMessage5389 sendMessage, IPEndPoint remote, IPEndPoint receive)
         private async Task<(StunMessage5389, IPEndPoint, IPAddress)> TestAsync(StunMessage5389 sendMessage, IPEndPoint remote, IPEndPoint receive)

+ 13 - 0
STUN/Enums/MappingBehavior.cs

@@ -0,0 +1,13 @@
+namespace STUN.Enums
+{
+    public enum MappingBehavior
+    {
+        Unknown,
+        UnsupportedServer,
+        Direct,
+        EndpointIndependent,
+        AddressDependent,
+        AddressAndPortDependent,
+        Fail
+    }
+}

+ 1 - 0
STUN/StunResult/StunResult5389.cs

@@ -9,6 +9,7 @@ namespace STUN.StunResult
         public IPEndPoint PublicEndPoint { get; set; }
         public IPEndPoint PublicEndPoint { get; set; }
         public IPEndPoint LocalEndPoint { get; set; }
         public IPEndPoint LocalEndPoint { get; set; }
         public BindingTestResult BindingTestResult { get; set; } = BindingTestResult.Unknown;
         public BindingTestResult BindingTestResult { get; set; } = BindingTestResult.Unknown;
+        public MappingBehavior MappingBehavior { get; set; } = MappingBehavior.Unknown;
 
 
     }
     }
 }
 }

+ 9 - 1
STUN/Utils/NetUtils.cs

@@ -100,7 +100,15 @@ namespace STUN.Utils
             await client.SendAsync(bytes, bytes.Length, remote);
             await client.SendAsync(bytes, bytes.Length, remote);
             var res = new ArraySegment<byte>(new byte[ushort.MaxValue]);
             var res = new ArraySegment<byte>(new byte[ushort.MaxValue]);
 
 
-            var result = await client.Client.ReceiveMessageFromAsync(res, SocketFlags.None, receive);
+            var task = client.Client.ReceiveMessageFromAsync(res, SocketFlags.None, receive);
+
+            var resTask = await Task.WhenAny(Task.Delay(client.Client.ReceiveTimeout), task);
+            if (resTask != task)
+            {
+                throw new Exception(@"Receive timeout");
+            }
+
+            var result = task.Result;
 
 
             var local = result.PacketInformation.Address;
             var local = result.PacketInformation.Address;
 
 

+ 21 - 2
UnitTest/UnitTest.cs

@@ -1,10 +1,12 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
 using STUN.Client;
 using STUN.Client;
 using STUN.Enums;
 using STUN.Enums;
 using STUN.Message.Attributes;
 using STUN.Message.Attributes;
 using System.Linq;
 using System.Linq;
 using System.Net;
 using System.Net;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using STUN.StunResult;
 using STUN.Utils;
 using STUN.Utils;
 
 
 namespace UnitTest
 namespace UnitTest
@@ -84,12 +86,29 @@ namespace UnitTest
         public async Task BindingTest()
         public async Task BindingTest()
         {
         {
             var client = new StunClient5389UDP(@"stun.syncthing.net", 3478, new IPEndPoint(IPAddress.Any, 0));
             var client = new StunClient5389UDP(@"stun.syncthing.net", 3478, new IPEndPoint(IPAddress.Any, 0));
-            var result = await client.BindingTestAsync();
+            var result = (StunResult5389)await client.QueryAsync();
 
 
             Assert.AreEqual(result.BindingTestResult, BindingTestResult.Success);
             Assert.AreEqual(result.BindingTestResult, BindingTestResult.Success);
             Assert.IsNotNull(result.LocalEndPoint);
             Assert.IsNotNull(result.LocalEndPoint);
             Assert.IsNotNull(result.PublicEndPoint);
             Assert.IsNotNull(result.PublicEndPoint);
             Assert.AreNotEqual(result.LocalEndPoint.Address, IPAddress.Any);
             Assert.AreNotEqual(result.LocalEndPoint.Address, IPAddress.Any);
         }
         }
+
+        [TestMethod]
+        public async Task MappingBehaviorTest()
+        {
+            var client = new StunClient5389UDP(@"stun.syncthing.net", 3478, new IPEndPoint(IPAddress.Any, 0));
+            var result = await client.MappingBehaviorTestAsync();
+
+            Assert.AreEqual(result.BindingTestResult, BindingTestResult.Success);
+            Assert.IsNotNull(result.LocalEndPoint);
+            Assert.IsNotNull(result.PublicEndPoint);
+            Assert.AreNotEqual(result.LocalEndPoint.Address, IPAddress.Any);
+            Assert.IsTrue(result.MappingBehavior == MappingBehavior.Direct
+            || result.MappingBehavior == MappingBehavior.EndpointIndependent
+            || result.MappingBehavior == MappingBehavior.AddressDependent
+            || result.MappingBehavior == MappingBehavior.AddressAndPortDependent
+            );
+        }
     }
     }
 }
 }