Bruce Wayne před 5 roky
rodič
revize
214832d702

+ 6 - 4
NatTypeTester.sln

@@ -14,11 +14,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STUN", "STUN\STUN.csproj", "{BF8F4960-AA76-4A0F-BA6D-EDF26DEFB9CA}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTest", "UnitTest\UnitTest.csproj", "{AA8AF9BF-5CFB-4725-B42A-7B3B3890A279}"
+EndProject
 Global
-	GlobalSection(SharedMSBuildProjectFiles) = preSolution
-		Common\Common.projitems*{b5104123-eb01-4079-8865-2a99dd91dc24}*SharedItemsImports = 5
-		Common\Common.projitems*{cc6be2e2-81cb-4c0b-ba17-4bb48dd403ac}*SharedItemsImports = 5
-	EndGlobalSection
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
@@ -36,6 +34,10 @@ Global
 		{BF8F4960-AA76-4A0F-BA6D-EDF26DEFB9CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{BF8F4960-AA76-4A0F-BA6D-EDF26DEFB9CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{BF8F4960-AA76-4A0F-BA6D-EDF26DEFB9CA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AA8AF9BF-5CFB-4725-B42A-7B3B3890A279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AA8AF9BF-5CFB-4725-B42A-7B3B3890A279}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AA8AF9BF-5CFB-4725-B42A-7B3B3890A279}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AA8AF9BF-5CFB-4725-B42A-7B3B3890A279}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 0 - 146
STUN/Client/StunClient.cs

@@ -2,7 +2,6 @@
 using STUN.Message.Enums;
 using STUN.Utils;
 using System;
-using System.IO;
 using System.Net;
 using System.Net.Sockets;
 
@@ -32,31 +31,6 @@ namespace STUN.Client
     {
         #region static method Query
 
-        /// <summary>
-        /// Gets NAT info from STUN server.
-        /// </summary>
-        /// <param name="host">STUN server name or IP.</param>
-        /// <param name="port">STUN server port. Default port is 3478.</param>
-        /// <param name="localEP">Local IP end point.</param>
-        /// <returns>Returns UDP network info.</returns>
-        /// <exception cref="Exception">Is raised when <b>host</b> or <b>localEP</b> is null reference.</exception>
-        /// <exception cref="ArgumentNullException">Throws exception if unexpected error happens.</exception>
-        public static StunResult Query(string host, int port, IPEndPoint localEP)
-        {
-            if (host == null)
-            {
-                throw new ArgumentNullException(nameof(host));
-            }
-            if (localEP == null)
-            {
-                throw new ArgumentNullException(nameof(localEP));
-            }
-
-            using var s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
-            s.Bind(localEP);
-            return Query(host, port, s);
-        }
-
         /// <summary>
         /// Gets NAT info from STUN server.
         /// </summary>
@@ -252,126 +226,6 @@ namespace STUN.Client
 
         #endregion
 
-        #region method GetPublicIP
-
-        /// <summary>
-        /// Resolves local IP to public IP using STUN.
-        /// </summary>
-        /// <param name="stunServer">STUN server.</param>
-        /// <param name="port">STUN server port. Default port is 3478.</param>
-        /// <param name="localIP">Local IP address.</param>
-        /// <returns>Returns public IP address.</returns>
-        /// <exception cref="ArgumentNullException">Is raised when <b>stunServer</b> or <b>localIP</b> is null reference.</exception>
-        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
-        /// <exception cref="IOException">Is raised when no connection to STUN server.</exception>
-        public static IPAddress GetPublicIP(string stunServer, int port, IPAddress localIP)
-        {
-            if (stunServer == null)
-            {
-                throw new ArgumentNullException(nameof(stunServer));
-            }
-            if (stunServer == string.Empty)
-            {
-                throw new ArgumentException(@"Argument 'stunServer' value must be specified.");
-            }
-            if (port < 1)
-            {
-                throw new ArgumentException(@"Invalid argument 'port' value.");
-            }
-            if (localIP == null)
-            {
-                throw new ArgumentNullException(nameof(localIP));
-            }
-
-            if (!NetUtils.IsPrivateIP(localIP))
-            {
-                return localIP;
-            }
-
-            var result = Query(stunServer, port, NetUtils.CreateSocket(new IPEndPoint(localIP, 0), ProtocolType.Udp));
-            if (result.PublicEndPoint != null)
-            {
-                return result.PublicEndPoint.Address;
-            }
-
-            throw new IOException(@"Failed to STUN public IP address. STUN server name is invalid or firewall blocks STUN.");
-        }
-
-        #endregion
-
-        #region method GetPublicEP
-
-        /// <summary>
-        /// Resolves socket local end point to public end point.
-        /// </summary>
-        /// <param name="stunServer">STUN server.</param>
-        /// <param name="port">STUN server port. Default port is 3478.</param>
-        /// <param name="socket">UDP socket to use.</param>
-        /// <returns>Returns public IP end point.</returns>
-        /// <exception cref="ArgumentNullException">Is raised when <b>stunServer</b> or <b>socket</b> is null reference.</exception>
-        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
-        /// <exception cref="IOException">Is raised when no connection to STUN server.</exception>
-        public static IPEndPoint GetPublicEP(string stunServer, int port, Socket socket)
-        {
-            if (stunServer == null)
-            {
-                throw new ArgumentNullException(nameof(stunServer));
-            }
-            if (stunServer == string.Empty)
-            {
-                throw new ArgumentException(@"Argument 'stunServer' value must be specified.");
-            }
-            if (port < 1)
-            {
-                throw new ArgumentException(@"Invalid argument 'port' value.");
-            }
-            if (socket == null)
-            {
-                throw new ArgumentNullException(nameof(socket));
-            }
-            if (socket.ProtocolType != ProtocolType.Udp)
-            {
-                throw new ArgumentException(@"Socket must be UDP socket !");
-            }
-
-            var remoteEndPoint = new IPEndPoint(Dns.GetHostAddresses(stunServer)[0], port);
-
-            try
-            {
-                // Test I
-                var test1 = new StunMessage { Type = StunMessageType.BindingRequest };
-                var test1response = DoTransaction(test1, socket, remoteEndPoint, 1000);
-
-                // UDP blocked.
-                if (test1response == null)
-                {
-                    throw new IOException(@"Failed to STUN public IP address. STUN server name is invalid or firewall blocks STUN.");
-                }
-
-                return test1response.SourceAddress;
-            }
-            catch
-            {
-                throw new IOException(@"Failed to STUN public IP address. STUN server name is invalid or firewall blocks STUN.");
-            }
-            finally
-            {
-                // Junk all late responses.
-                var startTime = DateTime.Now;
-                while (startTime.AddMilliseconds(200) > DateTime.Now)
-                {
-                    // We got response.
-                    if (socket.Poll(1, SelectMode.SelectRead))
-                    {
-                        var receiveBuffer = new byte[512];
-                        socket.Receive(receiveBuffer);
-                    }
-                }
-            }
-        }
-
-        #endregion
-
         #region method DoTransaction
 
         /// <summary>

+ 1 - 1
STUN/Message/Enums/IpFamily.cs

@@ -1,7 +1,7 @@
 namespace STUN.Message.Enums
 {
     /// <summary>
-    /// Specifies IP address family.
+    /// https://tools.ietf.org/html/rfc5389#section-15.1
     /// </summary>
     public enum IpFamily : byte
     {

+ 1 - 2
STUN/Message/StunMessage.cs

@@ -7,10 +7,9 @@ using System.Text;
 namespace STUN.Message
 {
     /// <summary>
-    /// Implements STUN message. Defined in RFC 3489, 5389.
+    /// Implements STUN message. Defined in RFC 5389.
     /// </summary>
     /// <remarks>
-    /// https://tools.ietf.org/html/rfc3489#section-11.1
     /// https://tools.ietf.org/html/rfc5389#section-6
     /// </remarks>
     public class StunMessage

+ 66 - 0
UnitTest/UnitTest.cs

@@ -0,0 +1,66 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using STUN.Message.Attributes;
+using STUN.Message.Enums;
+using System.Linq;
+using System.Net;
+
+namespace UnitTest
+{
+    [TestClass]
+    public class UnitTest
+    {
+        private readonly byte[] _magicCookie = { 0x21, 0x12, 0xa4, 0x42 };
+        private readonly byte[] _transactionId =
+        {
+                0xb7, 0xe7, 0xa7, 0x01,
+                0xbc, 0x34, 0xd6, 0x86,
+                0xfa, 0x87, 0xdf, 0xae
+        };
+
+        private static readonly byte[] XorPort = { 0xa1, 0x47 };
+        private static readonly byte[] XorIPv4 = { 0xe1, 0x12, 0xa6, 0x43 };
+        private static readonly byte[] XorIPv6 =
+        {
+                0x01, 0x13, 0xa9, 0xfa,
+                0xa5, 0xd3, 0xf1, 0x79,
+                0xbc, 0x25, 0xf4, 0xb5,
+                0xbe, 0xd2, 0xb9, 0xd9
+        };
+
+        private const ushort Port = 32853;
+        private readonly IPAddress IPv4 = IPAddress.Parse(@"192.0.2.1");
+        private readonly IPAddress IPv6 = IPAddress.Parse(@"2001:db8:1234:5678:11:2233:4455:6677");
+
+        private readonly byte[] _ipv4Response = new byte[] { 0x00, (byte)IpFamily.IPv4 }.Concat(XorPort).Concat(XorIPv4).ToArray();
+        private readonly byte[] _ipv6Response = new byte[] { 0x00, (byte)IpFamily.IPv6 }.Concat(XorPort).Concat(XorIPv6).ToArray();
+
+        /// <summary>
+        /// https://tools.ietf.org/html/rfc5769.html
+        /// </summary>
+        [TestMethod]
+        public void TestXorMapped()
+        {
+            var t = new XorMappedAddressAttribute(_magicCookie, _transactionId)
+            {
+                Port = Port,
+                Family = IpFamily.IPv4,
+                Address = IPv4
+            };
+            Assert.IsTrue(_ipv4Response.SequenceEqual(t.Bytes));
+
+            t = new XorMappedAddressAttribute(_magicCookie, _transactionId);
+            Assert.IsTrue(t.TryParse(_ipv4Response));
+            Assert.AreEqual(t.Port, Port);
+            Assert.AreEqual(t.Family, IpFamily.IPv4);
+            Assert.AreEqual(t.Address, IPv4);
+
+            t = new XorMappedAddressAttribute(_magicCookie, _transactionId);
+            Assert.IsTrue(t.TryParse(_ipv6Response));
+            Assert.AreEqual(t.Port, Port);
+            Assert.AreEqual(t.Family, IpFamily.IPv6);
+            Assert.AreEqual(t.Address, IPv6);
+
+            Assert.IsTrue(_ipv6Response.SequenceEqual(t.Bytes));
+        }
+    }
+}

+ 25 - 0
UnitTest/UnitTest.csproj

@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
+    <PackageReference Include="MSTest.TestAdapter" Version="2.1.0" />
+    <PackageReference Include="MSTest.TestFramework" Version="2.1.0" />
+    <PackageReference Include="coverlet.collector" Version="1.2.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\STUN\STUN.csproj" />
+  </ItemGroup>
+
+</Project>