Bruce Wayne 6 years ago
parent
commit
2cb36c49e0

+ 49 - 1
NatTypeTester-Console/Net/NetUtils.cs

@@ -1,4 +1,6 @@
-using System;
+using NatTypeTester_Console.Net.STUN.Client;
+using System;
+using System.Diagnostics;
 using System.Net;
 using System.Net.Sockets;
 
@@ -151,5 +153,51 @@ namespace NatTypeTester_Console.Net
 
 		#endregion
 
+		public const string DefaultLocalEnd = @"0.0.0.0:0";
+
+		public static IPEndPoint ParseEndpoint(string str)
+		{
+			var ipPort = str.Trim().Split(':');
+			if (ipPort.Length == 2)
+			{
+				if (IPAddress.TryParse(ipPort[0], out var ip))
+				{
+					if (ushort.TryParse(ipPort[1], out var port))
+					{
+						return new IPEndPoint(ip, port);
+					}
+				}
+			}
+
+			return null;
+		}
+
+		public static (string, string, string) NatTypeTestCore(string local, string server, int port)
+		{
+			try
+			{
+				if (string.IsNullOrWhiteSpace(server))
+				{
+					Debug.WriteLine(@"[ERROR]: Please specify STUN server !");
+					return (string.Empty, DefaultLocalEnd, string.Empty);
+				}
+
+				using var socketV4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+				var ipe = ParseEndpoint(local) ?? new IPEndPoint(IPAddress.Any, 0);
+				socketV4.Bind(ipe);
+				var result = StunClient.Query(server, port, socketV4);
+
+				return (
+						result.NatType.ToString(),
+						socketV4.LocalEndPoint.ToString(),
+						result.NatType != NatType.UdpBlocked ? result.PublicEndPoint.ToString() : string.Empty
+				);
+			}
+			catch (Exception ex)
+			{
+				Debug.WriteLine($@"[ERROR]: {ex}");
+				return (string.Empty, DefaultLocalEnd, string.Empty);
+			}
+		}
 	}
 }

+ 52 - 54
NatTypeTester-Console/Net/STUN/Client/StunClient.cs

@@ -36,26 +36,23 @@ namespace NatTypeTester_Console.Net.STUN.Client
 		/// <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 netwrok info.</returns>
+		/// <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("host");
+				throw new ArgumentNullException(nameof(host));
 			}
 			if (localEP == null)
 			{
-				throw new ArgumentNullException("localEP");
+				throw new ArgumentNullException(nameof(localEP));
 			}
 
-			using (var s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
-			{
-				s.Bind(localEP);
-
-				return Query(host, port, s);
-			}
+			using var s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+			s.Bind(localEP);
+			return Query(host, port, s);
 		}
 
 		/// <summary>
@@ -64,25 +61,25 @@ namespace NatTypeTester_Console.Net.STUN.Client
 		/// <param name="host">STUN server name or IP.</param>
 		/// <param name="port">STUN server port. Default port is 3478.</param>
 		/// <param name="socket">UDP socket to use.</param>
-		/// <returns>Returns UDP netwrok info.</returns>
+		/// <returns>Returns UDP network info.</returns>
 		/// <exception cref="Exception">Throws exception if unexpected error happens.</exception>
 		public static StunResult Query(string host, int port, Socket socket)
 		{
 			if (host == null)
 			{
-				throw new ArgumentNullException("host");
+				throw new ArgumentNullException(nameof(host));
 			}
 			if (socket == null)
 			{
-				throw new ArgumentNullException("socket");
+				throw new ArgumentNullException(nameof(socket));
 			}
 			if (port < 1)
 			{
-				throw new ArgumentException("Port value must be >= 1 !");
+				throw new ArgumentException(@"Port value must be >= 1 !");
 			}
 			if (socket.ProtocolType != ProtocolType.Udp)
 			{
-				throw new ArgumentException("Socket must be UDP socket !");
+				throw new ArgumentException(@"Socket must be UDP socket !");
 			}
 
 			var remoteEndPoint = new IPEndPoint(Dns.GetHostAddresses(host)[0], port);
@@ -145,35 +142,36 @@ namespace NatTypeTester_Console.Net.STUN.Client
 			try
 			{
 				// Test I
-				var test1 = new StunMessage();
-				test1.Type = StunMessageType.BindingRequest;
-				var test1response = DoTransaction(test1, socket, remoteEndPoint, 1600);
+				var test1 = new StunMessage { Type = StunMessageType.BindingRequest };
+				var test1Response = DoTransaction(test1, socket, remoteEndPoint, 1600);
 
 				// UDP blocked.
-				if (test1response == null)
+				if (test1Response == null)
 				{
 					return new StunResult(NatType.UdpBlocked, null);
 				}
 				else
 				{
 					// Test II
-					var test2 = new StunMessage();
-					test2.Type = StunMessageType.BindingRequest;
-					test2.ChangeRequest = new StunChangeRequest(true, true);
+					var test2 = new StunMessage
+					{
+						Type = StunMessageType.BindingRequest,
+						ChangeRequest = new StunChangeRequest(true, true)
+					};
 
 					// No NAT.
-					if (socket.LocalEndPoint.Equals(test1response.MappedAddress))
+					if (socket.LocalEndPoint.Equals(test1Response.MappedAddress))
 					{
 						var test2Response = DoTransaction(test2, socket, remoteEndPoint, 1600);
 						// Open Internet.
 						if (test2Response != null)
 						{
-							return new StunResult(NatType.OpenInternet, test1response.MappedAddress);
+							return new StunResult(NatType.OpenInternet, test1Response.MappedAddress);
 						}
 						// Symmetric UDP firewall.
 						else
 						{
-							return new StunResult(NatType.SymmetricUdpFirewall, test1response.MappedAddress);
+							return new StunResult(NatType.SymmetricUdpFirewall, test1Response.MappedAddress);
 						}
 					}
 					// NAT
@@ -184,7 +182,7 @@ namespace NatTypeTester_Console.Net.STUN.Client
 						// Full cone NAT.
 						if (test2Response != null)
 						{
-							return new StunResult(NatType.FullCone, test1response.MappedAddress);
+							return new StunResult(NatType.FullCone, test1Response.MappedAddress);
 						}
 						else
 						{
@@ -194,38 +192,39 @@ namespace NatTypeTester_Console.Net.STUN.Client
                             */
 
 							// Test I(II)
-							var test12 = new StunMessage();
-							test12.Type = StunMessageType.BindingRequest;
+							var test12 = new StunMessage { Type = StunMessageType.BindingRequest };
 
-							var test12Response = DoTransaction(test12, socket, test1response.ChangedAddress, 1600);
+							var test12Response = DoTransaction(test12, socket, test1Response.ChangedAddress, 1600);
 							if (test12Response == null)
 							{
-								throw new Exception("STUN Test I(II) dind't get resonse !");
+								throw new Exception(@"STUN Test I(II) didn't get response !");
 							}
 							else
 							{
 								// Symmetric NAT
-								if (!test12Response.MappedAddress.Equals(test1response.MappedAddress))
+								if (!test12Response.MappedAddress.Equals(test1Response.MappedAddress))
 								{
-									return new StunResult(NatType.Symmetric, test1response.MappedAddress);
+									return new StunResult(NatType.Symmetric, test1Response.MappedAddress);
 								}
 								else
 								{
 									// Test III
-									var test3 = new StunMessage();
-									test3.Type = StunMessageType.BindingRequest;
-									test3.ChangeRequest = new StunChangeRequest(false, true);
+									var test3 = new StunMessage
+									{
+										Type = StunMessageType.BindingRequest,
+										ChangeRequest = new StunChangeRequest(false, true)
+									};
 
-									var test3Response = DoTransaction(test3, socket, test1response.ChangedAddress, 1600);
+									var test3Response = DoTransaction(test3, socket, test1Response.ChangedAddress, 1600);
 									// Restricted
 									if (test3Response != null)
 									{
-										return new StunResult(NatType.RestrictedCone, test1response.MappedAddress);
+										return new StunResult(NatType.RestrictedCone, test1Response.MappedAddress);
 									}
 									// Port restricted
 									else
 									{
-										return new StunResult(NatType.PortRestrictedCone, test1response.MappedAddress);
+										return new StunResult(NatType.PortRestrictedCone, test1Response.MappedAddress);
 									}
 								}
 							}
@@ -267,19 +266,19 @@ namespace NatTypeTester_Console.Net.STUN.Client
 		{
 			if (stunServer == null)
 			{
-				throw new ArgumentNullException("stunServer");
+				throw new ArgumentNullException(nameof(stunServer));
 			}
-			if (stunServer == "")
+			if (stunServer == string.Empty)
 			{
-				throw new ArgumentException("Argument 'stunServer' value must be specified.");
+				throw new ArgumentException(@"Argument 'stunServer' value must be specified.");
 			}
 			if (port < 1)
 			{
-				throw new ArgumentException("Invalid argument 'port' value.");
+				throw new ArgumentException(@"Invalid argument 'port' value.");
 			}
 			if (localIP == null)
 			{
-				throw new ArgumentNullException("localIP");
+				throw new ArgumentNullException(nameof(localIP));
 			}
 
 			if (!NetUtils.IsPrivateIP(localIP))
@@ -293,7 +292,7 @@ namespace NatTypeTester_Console.Net.STUN.Client
 				return result.PublicEndPoint.Address;
 			}
 
-			throw new IOException("Failed to STUN public IP address. STUN server name is invalid or firewall blocks STUN.");
+			throw new IOException(@"Failed to STUN public IP address. STUN server name is invalid or firewall blocks STUN.");
 		}
 
 		#endregion
@@ -314,23 +313,23 @@ namespace NatTypeTester_Console.Net.STUN.Client
 		{
 			if (stunServer == null)
 			{
-				throw new ArgumentNullException("stunServer");
+				throw new ArgumentNullException(nameof(stunServer));
 			}
-			if (stunServer == "")
+			if (stunServer == string.Empty)
 			{
-				throw new ArgumentException("Argument 'stunServer' value must be specified.");
+				throw new ArgumentException(@"Argument 'stunServer' value must be specified.");
 			}
 			if (port < 1)
 			{
-				throw new ArgumentException("Invalid argument 'port' value.");
+				throw new ArgumentException(@"Invalid argument 'port' value.");
 			}
 			if (socket == null)
 			{
-				throw new ArgumentNullException("socket");
+				throw new ArgumentNullException(nameof(socket));
 			}
 			if (socket.ProtocolType != ProtocolType.Udp)
 			{
-				throw new ArgumentException("Socket must be UDP socket !");
+				throw new ArgumentException(@"Socket must be UDP socket !");
 			}
 
 			var remoteEndPoint = new IPEndPoint(Dns.GetHostAddresses(stunServer)[0], port);
@@ -338,21 +337,20 @@ namespace NatTypeTester_Console.Net.STUN.Client
 			try
 			{
 				// Test I
-				var test1 = new StunMessage();
-				test1.Type = StunMessageType.BindingRequest;
+				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.");
+					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.");
+				throw new IOException(@"Failed to STUN public IP address. STUN server name is invalid or firewall blocks STUN.");
 			}
 			finally
 			{
@@ -380,7 +378,7 @@ namespace NatTypeTester_Console.Net.STUN.Client
 		/// <param name="request">STUN message.</param>
 		/// <param name="socket">Socket to use for send/receive.</param>
 		/// <param name="remoteEndPoint">Remote end point.</param>
-		/// <param name="timeout">Timeout in milli seconds.</param>
+		/// <param name="timeout">Timeout in milliseconds.</param>
 		/// <returns>Returns transaction response or null if transaction failed.</returns>
 		private static StunMessage DoTransaction(StunMessage request, Socket socket, IPEndPoint remoteEndPoint, int timeout)
 		{

+ 4 - 25
NatTypeTester-Console/Net/STUN/Message/StunChangeRequest.cs

@@ -5,16 +5,6 @@
 	/// </summary>
 	public class StunChangeRequest
 	{
-		private bool _mChangeIp = true;
-		private bool _mChangePort = true;
-
-		/// <summary>
-		/// Default constructor.
-		/// </summary>
-		public StunChangeRequest()
-		{
-		}
-
 		/// <summary>
 		/// Default constructor.
 		/// </summary>
@@ -22,32 +12,21 @@
 		/// <param name="changePort">Specifies if STUN server must send response to different port than request was received.</param>
 		public StunChangeRequest(bool changeIp, bool changePort)
 		{
-			_mChangeIp = changeIp;
-			_mChangePort = changePort;
+			ChangeIp = changeIp;
+			ChangePort = changePort;
 		}
 
-
 		#region Properties Implementation
 
 		/// <summary>
 		/// Gets or sets if STUN server must send response to different IP than request was received.
 		/// </summary>
-		public bool ChangeIp
-		{
-			get => _mChangeIp;
-
-			set => _mChangeIp = value;
-		}
+		public bool ChangeIp { get; set; }
 
 		/// <summary>
 		/// Gets or sets if STUN server must send response to different port than request was received.
 		/// </summary>
-		public bool ChangePort
-		{
-			get => _mChangePort;
-
-			set => _mChangePort = value;
-		}
+		public bool ChangePort { get; set; }
 
 		#endregion
 

+ 13 - 12
NatTypeTester-Console/Net/STUN/Message/StunMessage.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Net;
 using System.Text;
 
@@ -41,8 +42,8 @@ namespace NatTypeTester_Console.Net.STUN.Message
 		/// </summary>
 		private enum IpFamily
 		{
-			Pv4 = 0x01,
-			Pv6 = 0x02
+			IPv4 = 0x01,
+			IPv6 = 0x02
 		}
 
 		#endregion
@@ -67,7 +68,7 @@ namespace NatTypeTester_Console.Net.STUN.Message
 		{
 			if (data == null)
 			{
-				throw new ArgumentNullException("data");
+				throw new ArgumentNullException(nameof(data));
 			}
 
 			/* RFC 5389 6.             
@@ -93,7 +94,7 @@ namespace NatTypeTester_Console.Net.STUN.Message
 
 			if (data.Length < 20)
 			{
-				throw new ArgumentException("Invalid STUN message value !");
+				throw new ArgumentException(@"Invalid STUN message value !");
 			}
 
 			var offset = 0;
@@ -128,7 +129,7 @@ namespace NatTypeTester_Console.Net.STUN.Message
 			}
 			else
 			{
-				throw new ArgumentException("Invalid STUN message type value !");
+				throw new ArgumentException(@"Invalid STUN message type value !");
 			}
 
 			// Message Length
@@ -199,7 +200,7 @@ namespace NatTypeTester_Console.Net.STUN.Message
 			msg[offset++] = (byte)((MagicCookie >> 24) & 0xFF);
 			msg[offset++] = (byte)((MagicCookie >> 16) & 0xFF);
 			msg[offset++] = (byte)((MagicCookie >> 8) & 0xFF);
-			msg[offset++] = (byte)((MagicCookie >> 0) & 0xFF);
+			msg[offset++] = (byte)(MagicCookie & 0xFF);
 
 			// Transaction ID (16 bytes)
 			Array.Copy(TransactionId, 0, msg, offset, 12);
@@ -322,7 +323,7 @@ namespace NatTypeTester_Console.Net.STUN.Message
 				msg[offset++] = 0;
 				msg[offset++] = 0;
 				// Class
-				msg[offset++] = (byte)Math.Floor((double)(ErrorCode.Code / 100));
+				msg[offset++] = (byte)Math.Floor(ErrorCode.Code / 100.0);
 				// Number
 				msg[offset++] = (byte)(ErrorCode.Code & 0xFF);
 				// ReasonPhrase
@@ -338,7 +339,7 @@ namespace NatTypeTester_Console.Net.STUN.Message
 			msg[2] = (byte)((offset - 20) >> 8);
 			msg[3] = (byte)((offset - 20) & 0xFF);
 
-			// Make reatval with actual size.
+			// Make retVal with actual size.
 			var retVal = new byte[offset];
 			Array.Copy(msg, retVal, retVal.Length);
 
@@ -492,12 +493,12 @@ namespace NatTypeTester_Console.Net.STUN.Message
 		#region method ParseEndPoint
 
 		/// <summary>
-		/// Pasrses IP endpoint attribute.
+		/// Parses IP endpoint attribute.
 		/// </summary>
 		/// <param name="data">STUN message data.</param>
 		/// <param name="offset">Offset in data.</param>
 		/// <returns>Returns parsed IP end point.</returns>
-		private IPEndPoint ParseEndPoint(byte[] data, ref int offset)
+		private static IPEndPoint ParseEndPoint(IReadOnlyList<byte> data, ref int offset)
 		{
 			/*
                 It consists of an eight bit address family, and a sixteen bit
@@ -540,7 +541,7 @@ namespace NatTypeTester_Console.Net.STUN.Message
 		/// <param name="endPoint">IP end point.</param>
 		/// <param name="message">Buffer where to store.</param>
 		/// <param name="offset">Offset in buffer.</param>
-		private void StoreEndPoint(AttributeType type, IPEndPoint endPoint, byte[] message, ref int offset)
+		private static void StoreEndPoint(AttributeType type, IPEndPoint endPoint, IList<byte> message, ref int offset)
 		{
 			/*
                 It consists of an eight bit address family, and a sixteen bit
@@ -564,7 +565,7 @@ namespace NatTypeTester_Console.Net.STUN.Message
 			// Unused
 			message[offset++] = 0;
 			// Family
-			message[offset++] = (byte)IpFamily.Pv4;
+			message[offset++] = (byte)IpFamily.IPv4;
 			// Port
 			message[offset++] = (byte)(endPoint.Port >> 8);
 			message[offset++] = (byte)(endPoint.Port & 0xFF);

+ 1 - 1
NatTypeTester-Console/Net/STUN/Message/StunMessageType.cs

@@ -16,7 +16,7 @@
 		BindingResponse = 0x0101,
 
 		/// <summary>
-		/// STUN message is binding requesr error response.
+		/// STUN message is binding request error response.
 		/// </summary>
 		BindingErrorResponse = 0x0111,
 

+ 15 - 5
NatTypeTester-Console/Program.cs

@@ -1,4 +1,5 @@
-using System;
+using NatTypeTester_Console.Net;
+using System;
 
 namespace NatTypeTester_Console
 {
@@ -6,10 +7,19 @@ namespace NatTypeTester_Console
 	{
 		private static void Main(string[] args)
 		{
-			var res = Utils.NatTypeTestCore(Utils.DefaultLocalEnd, @"stun.miwifi.com", 3478);
-			Console.WriteLine(res.Item1);
-			Console.WriteLine(res.Item2);
-			Console.WriteLine(res.Item3);
+			var server = @"stun.miwifi.com";
+			ushort port = 3478;
+			if (args.Length > 0)
+			{
+				server = args[0];
+			}
+			if (args.Length > 1)
+			{
+				ushort.TryParse(args[1], out port);
+			}
+			var res = NetUtils.NatTypeTestCore(NetUtils.DefaultLocalEnd, server, port);
+			var natType = res.Item1;
+			Console.WriteLine(string.IsNullOrWhiteSpace(natType) ? @"Error" : natType);
 		}
 	}
 }

+ 0 - 60
NatTypeTester-Console/Utils.cs

@@ -1,60 +0,0 @@
-using NatTypeTester_Console.Net.STUN.Client;
-using System;
-using System.Diagnostics;
-using System.Net;
-using System.Net.Sockets;
-
-namespace NatTypeTester_Console
-{
-	public static class Utils
-	{
-		public const string DefaultLocalEnd = @"0.0.0.0:0";
-
-		public static IPEndPoint ParseEndpoint(string str)
-		{
-			var ipPort = str.Trim().Split(':');
-			if (ipPort.Length == 2)
-			{
-				if (IPAddress.TryParse(ipPort[0], out var ip))
-				{
-					if (ushort.TryParse(ipPort[1], out var port))
-					{
-						return new IPEndPoint(ip, port);
-					}
-				}
-			}
-
-			return null;
-		}
-
-		public static (string, string, string) NatTypeTestCore(string local, string server, int port)
-		{
-			try
-			{
-				if (string.IsNullOrWhiteSpace(server))
-				{
-					Debug.WriteLine(@"[ERROR]: Please specify STUN server !");
-					return (string.Empty, DefaultLocalEnd, string.Empty);
-				}
-
-				using (var socketV4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
-				{
-					var ipe = ParseEndpoint(local) ?? new IPEndPoint(IPAddress.Any, 0);
-					socketV4.Bind(ipe);
-					var result = StunClient.Query(server, port, socketV4);
-
-					return (
-							result.NatType.ToString(),
-							socketV4.LocalEndPoint.ToString(),
-							result.NatType != NatType.UdpBlocked ? result.PublicEndPoint.ToString() : string.Empty
-					);
-				}
-			}
-			catch (Exception ex)
-			{
-				Debug.WriteLine($@"[ERROR]: {ex}");
-				return (string.Empty, DefaultLocalEnd, string.Empty);
-			}
-		}
-	}
-}

+ 10 - 5
README.md

@@ -1,9 +1,14 @@
-# STUN Server
-Docker
+# NatTypeTester
+
+- [x] RFC 3489
+- [ ] RFC 5389
+
+## Preview
+![](pic/1.png)
+
+## STUN Server
+### Docker
 ```
 docker pull hmbsbige/stunserver
 docker run -d --restart=always --net=host --name=stunserver hmbsbige/stunserver --mode full --primaryinterface $IP1 --altinterface $IP2
 ```
-
-# STUN Client Preview
-![](pic/1.png)