HMBSbige 5 年之前
父節點
當前提交
42c701a7b9

+ 24 - 23
NatTypeTester/MainWindow.xaml.cs

@@ -1,12 +1,11 @@
-using System;
-using System.Diagnostics;
+using NatTypeTester.ViewModels;
+using ReactiveUI;
+using System;
 using System.Reactive;
 using System.Reactive.Disposables;
 using System.Reactive.Linq;
 using System.Windows;
 using System.Windows.Input;
-using NatTypeTester.ViewModels;
-using ReactiveUI;
 
 namespace NatTypeTester
 {
@@ -17,70 +16,72 @@ namespace NatTypeTester
             InitializeComponent();
             ViewModel = new MainWindowViewModel();
 
-            this.WhenActivated(disposableRegistration =>
+            this.WhenActivated(d =>
             {
                 #region Server
 
                 this.Bind(ViewModel,
                         vm => vm.StunServer,
                         v => v.ServersComboBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.OneWayBind(ViewModel,
                         vm => vm.StunServers,
                         v => v.ServersComboBox.ItemsSource
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 #endregion
 
+                #region Proxy
 
                 this.OneWayBind(ViewModel,
                         vm => vm.CanConfigProxy,
                         v => v.ProxyConfigGrid.IsEnabled
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.Bind(ViewModel,
                         vm => vm.ProxyServer,
                         v => v.ProxyServerTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.Bind(ViewModel,
                         vm => vm.ProxyUser,
                         v => v.ProxyUsernameTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.Bind(ViewModel,
                         vm => vm.ProxyPassword,
                         v => v.ProxyPasswordTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
+                #endregion
 
                 #region RFC3489
 
                 this.OneWayBind(ViewModel,
                         vm => vm.ClassicNatType,
                         v => v.NatTypeTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.Bind(ViewModel,
                         vm => vm.LocalEnd,
                         v => v.LocalEndTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.OneWayBind(ViewModel,
                         vm => vm.PublicEnd,
                         v => v.PublicEndTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.BindCommand(ViewModel,
                                 viewModel => viewModel.TestClassicNatType,
                                 view => view.TestButton)
-                        .DisposeWith(disposableRegistration);
+                        .DisposeWith(d);
 
                 RFC3489Tab.Events().KeyDown
                         .Where(x => x.Key == Key.Enter && TestButton.IsEnabled)
                         .Subscribe(y => { TestButton.Command.Execute(Unit.Default); })
-                        .DisposeWith(disposableRegistration);
+                        .DisposeWith(d);
 
                 #endregion
 
@@ -89,37 +90,37 @@ namespace NatTypeTester
                 this.OneWayBind(ViewModel,
                         vm => vm.BindingTest,
                         v => v.BindingTestTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.OneWayBind(ViewModel,
                         vm => vm.MappingBehavior,
                         v => v.MappingBehaviorTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.OneWayBind(ViewModel,
                         vm => vm.FilteringBehavior,
                         v => v.FilteringBehaviorTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.Bind(ViewModel,
                         vm => vm.LocalAddress,
                         v => v.LocalAddressTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.OneWayBind(ViewModel,
                         vm => vm.MappingAddress,
                         v => v.MappingAddressTextBox.Text
-                ).DisposeWith(disposableRegistration);
+                ).DisposeWith(d);
 
                 this.BindCommand(ViewModel,
                                 viewModel => viewModel.DiscoveryNatType,
                                 view => view.DiscoveryButton)
-                        .DisposeWith(disposableRegistration);
+                        .DisposeWith(d);
 
                 RFC5780Tab.Events().KeyDown
                         .Where(x => x.Key == Key.Enter && DiscoveryButton.IsEnabled)
                         .Subscribe(y => { DiscoveryButton.Command.Execute(Unit.Default); })
-                        .DisposeWith(disposableRegistration);
+                        .DisposeWith(d);
 
                 #endregion
             });

+ 5 - 14
STUN/Client/StunClient3489.cs

@@ -8,7 +8,6 @@ using System;
 using System.Diagnostics;
 using System.Linq;
 using System.Net;
-using System.Net.Sockets;
 using System.Reactive.Linq;
 using System.Reactive.Subjects;
 using System.Threading.Tasks;
@@ -51,9 +50,8 @@ namespace STUN.Client
 
         public StunClient3489(string server, ushort port = 3478, IPEndPoint local = null, IUdpProxy proxy = null, IDnsQuery dnsQuery = null)
         {
-            Proxy = proxy ?? new NoneUdpProxy(local, null);
+            Proxy = proxy ?? new NoneUdpProxy(local);
 
-            Func<string, IPAddress> dnsQuery1;
             if (string.IsNullOrEmpty(server))
             {
                 throw new ArgumentException(@"Please specify STUN server !");
@@ -64,16 +62,9 @@ namespace STUN.Client
                 throw new ArgumentException(@"Port value must be >= 1 !");
             }
 
-            if (dnsQuery != null)
-            {
-                dnsQuery1 = dnsQuery.Query;
-            }
-            else
-            {
-                dnsQuery1 = new DefaultDnsQuery().Query;
-            }
+            dnsQuery ??= new DefaultDnsQuery();
 
-            Server = dnsQuery1(server);
+            Server = dnsQuery.Query(server);
             if (Server == null)
             {
                 throw new ArgumentException(@"Wrong STUN server !");
@@ -210,8 +201,8 @@ namespace STUN.Client
                 //var t = DateTime.Now;
 
                 // Simple retransmissions
-                //https://tools.ietf.org/html/rfc5389#section-7.2.1
-                //while (t + TimeSpan.FromSeconds(6) > DateTime.Now)
+                //https://tools.ietf.org/html/rfc3489#section-9.3
+                //while (t + TimeSpan.FromSeconds(3) > DateTime.Now)
                 {
                     try
                     {

+ 0 - 3
STUN/Client/StunClient5389UDP.cs

@@ -1,12 +1,9 @@
 using STUN.Enums;
 using STUN.Interfaces;
 using STUN.Message;
-using STUN.Proxy;
 using STUN.StunResult;
 using STUN.Utils;
 using System;
-using System.Diagnostics;
-using System.Linq;
 using System.Net;
 using System.Reactive.Linq;
 using System.Reactive.Subjects;

+ 1 - 1
STUN/Proxy/IUdpProxy.cs → STUN/Interfaces/IUdpProxy.cs

@@ -2,7 +2,7 @@
 using System.Net;
 using System.Threading.Tasks;
 
-namespace STUN.Proxy
+namespace STUN.Interfaces
 {
     public interface IUdpProxy : IDisposable
     {

+ 5 - 7
STUN/Proxy/NoneUdpProxy.cs

@@ -1,28 +1,26 @@
-using System;
-using System.Collections.Generic;
+using STUN.Interfaces;
+using System;
 using System.Diagnostics;
 using System.Linq;
 using System.Net;
 using System.Net.Sockets;
-using System.Text;
 using System.Threading.Tasks;
 
 namespace STUN.Proxy
 {
-    class NoneUdpProxy : IUdpProxy
+    public class NoneUdpProxy : IUdpProxy
     {
-
         public TimeSpan Timeout
         {
             get => TimeSpan.FromMilliseconds(UdpClient.Client.ReceiveTimeout);
             set => UdpClient.Client.ReceiveTimeout = Convert.ToInt32(value.TotalMilliseconds);
         }
 
-        public IPEndPoint LocalEndPoint { get => (IPEndPoint)UdpClient.Client.LocalEndPoint; }
+        public IPEndPoint LocalEndPoint => (IPEndPoint)UdpClient.Client.LocalEndPoint;
 
         protected UdpClient UdpClient;
 
-        public NoneUdpProxy(IPEndPoint local, IPEndPoint proxy)
+        public NoneUdpProxy(IPEndPoint local)
         {
             UdpClient = local == null ? new UdpClient() : new UdpClient(local);
         }

+ 8 - 12
STUN/Proxy/ProxyFactory.cs

@@ -1,8 +1,7 @@
-using System;
-using System.Collections.Generic;
+using STUN.Enums;
+using STUN.Interfaces;
+using System;
 using System.Net;
-using System.Text;
-using STUN.Enums;
 
 namespace STUN.Proxy
 {
@@ -10,15 +9,12 @@ namespace STUN.Proxy
     {
         public static IUdpProxy CreateProxy(ProxyType type, IPEndPoint local, IPEndPoint proxy, string user, string password)
         {
-            switch (type)
+            return type switch
             {
-                case ProxyType.Plain:
-                    return new NoneUdpProxy(local, null);
-                case ProxyType.Socks5:
-                    return new Socks5UdpProxy(local, proxy);
-                default:
-                    throw new NotSupportedException(type.ToString());
-            }
+                ProxyType.Plain => new NoneUdpProxy(local),
+                ProxyType.Socks5 => new Socks5UdpProxy(local, proxy, user, password),
+                _ => throw new NotSupportedException(type.ToString())
+            };
         }
     }
 }

+ 85 - 75
STUN/Proxy/Socks5UdpProxy.cs

@@ -1,54 +1,56 @@
-using System;
-using System.Collections.Generic;
+using STUN.Interfaces;
+using STUN.Utils;
+using System;
 using System.Diagnostics;
-using System.Globalization;
 using System.Net;
 using System.Net.NetworkInformation;
 using System.Net.Sockets;
 using System.Text;
 using System.Threading.Tasks;
-using STUN.Utils;
 
 namespace STUN.Proxy
 {
-    class Socks5UdpProxy : IUdpProxy
+    public class Socks5UdpProxy : IUdpProxy
     {
-        TcpClient assoc = new TcpClient();
-        IPEndPoint socksTcpEndPoint;
+        private readonly TcpClient _assoc = new TcpClient();
+        private readonly IPEndPoint _socksTcpEndPoint;
 
-        IPEndPoint assocEndPoint;
+        private IPEndPoint _assocEndPoint;
 
         public TimeSpan Timeout
         {
-            get => TimeSpan.FromMilliseconds(UdpClient.Client.ReceiveTimeout);
-            set => UdpClient.Client.ReceiveTimeout = Convert.ToInt32(value.TotalMilliseconds);
+            get => TimeSpan.FromMilliseconds(_udpClient.Client.ReceiveTimeout);
+            set => _udpClient.Client.ReceiveTimeout = Convert.ToInt32(value.TotalMilliseconds);
         }
 
-        public IPEndPoint LocalEndPoint { get => (IPEndPoint)UdpClient.Client.LocalEndPoint; }
+        public IPEndPoint LocalEndPoint => (IPEndPoint)_udpClient.Client.LocalEndPoint;
+
+        private readonly UdpClient _udpClient;
 
-        UdpClient UdpClient;
+        private readonly string _user;
+        private readonly string _password;
 
-        string user;
-        string password;
         public Socks5UdpProxy(IPEndPoint local, IPEndPoint proxy)
         {
-            UdpClient = local == null ? new UdpClient() : new UdpClient(local);
-            socksTcpEndPoint = proxy;
+            _udpClient = local == null ? new UdpClient() : new UdpClient(local);
+            _socksTcpEndPoint = proxy;
         }
+
         public Socks5UdpProxy(IPEndPoint local, IPEndPoint proxy, string user, string password) : this(local, proxy)
         {
-            this.user = user;
-            this.password = password;
+            _user = user;
+            _password = password;
         }
+
         public async Task ConnectAsync()
         {
-            byte[] buf = new byte[1024];
+            var buf = new byte[1024];
 
-            await assoc.ConnectAsync(socksTcpEndPoint.Address, socksTcpEndPoint.Port);
+            await _assoc.ConnectAsync(_socksTcpEndPoint.Address, _socksTcpEndPoint.Port);
             try
             {
-                var s = assoc.GetStream();
-                bool requestPasswordAuth = !string.IsNullOrEmpty(user);
+                var s = _assoc.GetStream();
+                var requestPasswordAuth = !string.IsNullOrEmpty(_user);
 
                 #region Handshake
                 // we have no gssapi support
@@ -62,8 +64,10 @@ namespace STUN.Proxy
                     s.Write(new byte[] { 5, 1, 0 }, 0, 3);
                 }
                 // 5 auth(ff=deny)
-                if (s.Read(buf, 0, 2) != 2) throw new ProtocolViolationException();
-                if (buf[0] != 5) throw new ProtocolViolationException();
+                if (s.Read(buf, 0, 2) != 2)
+                    throw new ProtocolViolationException();
+                if (buf[0] != 5)
+                    throw new ProtocolViolationException();
                 #endregion
 
                 #region Auth
@@ -73,8 +77,8 @@ namespace STUN.Proxy
                     case 0:
                         break;
                     case 2:
-                        byte[] ubyte = Encoding.UTF8.GetBytes(user);
-                        byte[] pbyte = Encoding.UTF8.GetBytes(password);
+                        var ubyte = Encoding.UTF8.GetBytes(_user);
+                        var pbyte = Encoding.UTF8.GetBytes(_password);
                         buf[0] = 1;
                         buf[1] = (byte)ubyte.Length;
                         Array.Copy(ubyte, 0, buf, 2, ubyte.Length);
@@ -83,9 +87,12 @@ namespace STUN.Proxy
                         // 1 userlen user passlen pass
                         s.Write(buf, 0, ubyte.Length + pbyte.Length + 4);
                         // 1 state(0=ok)
-                        if (s.Read(buf, 0, 2) != 2) throw new ProtocolViolationException();
-                        if (buf[0] != 1) throw new ProtocolViolationException();
-                        if (buf[1] != 0) throw new UnauthorizedAccessException();
+                        if (s.Read(buf, 0, 2) != 2)
+                            throw new ProtocolViolationException();
+                        if (buf[0] != 1)
+                            throw new ProtocolViolationException();
+                        if (buf[1] != 0)
+                            throw new UnauthorizedAccessException();
                         break;
                     case 0xff:
                         throw new UnauthorizedAccessException();
@@ -100,7 +107,7 @@ namespace STUN.Proxy
                 buf[2] = 0;
 
                 int addrLen;
-                byte[] abyte = GetEndPointByte(new IPEndPoint(IPAddress.Any, 0));
+                var abyte = GetEndPointByte(new IPEndPoint(IPAddress.Any, 0));
                 addrLen = abyte.Length;
                 Array.Copy(abyte, 0, buf, 3, addrLen);
                 // 5 cmd(3=udpassoc) 0 atyp(1=v4 3=dns 4=v5) addr port
@@ -108,9 +115,12 @@ namespace STUN.Proxy
                 #endregion
 
                 #region UDP Assoc Response
-                if (s.Read(buf, 0, 4) != 4) throw new ProtocolViolationException();
-                if (buf[0] != 5 || buf[2] != 0) throw new ProtocolViolationException();
-                if (buf[1] != 0) throw new UnauthorizedAccessException();
+                if (s.Read(buf, 0, 4) != 4)
+                    throw new ProtocolViolationException();
+                if (buf[0] != 5 || buf[2] != 0)
+                    throw new ProtocolViolationException();
+                if (buf[1] != 0)
+                    throw new UnauthorizedAccessException();
 
                 switch (buf[3])
                 {
@@ -124,64 +134,60 @@ namespace STUN.Proxy
                         throw new NotSupportedException();
                 }
 
-                byte[] addr = new byte[addrLen];
-                if (s.Read(addr, 0, addrLen) != addrLen) throw new ProtocolViolationException();
-                IPAddress assocIP = new IPAddress(addr);
-                if (s.Read(buf, 0, 2) != 2) throw new ProtocolViolationException();
-                int assocPort = buf[0] * 256 + buf[1];
+                var addr = new byte[addrLen];
+                if (s.Read(addr, 0, addrLen) != addrLen)
+                    throw new ProtocolViolationException();
+                var assocIP = new IPAddress(addr);
+                if (s.Read(buf, 0, 2) != 2)
+                    throw new ProtocolViolationException();
+                var assocPort = buf[0] * 256 + buf[1];
                 #endregion
 
-                assocEndPoint = new IPEndPoint(assocIP, assocPort);
+                _assocEndPoint = new IPEndPoint(assocIP, assocPort);
             }
             catch (Exception e)
             {
                 Debug.WriteLine(e);
-                assoc.Close();
+                _assoc.Close();
             }
         }
 
         public async Task<(byte[], IPEndPoint, IPAddress)> ReceiveAsync(byte[] bytes, IPEndPoint remote, EndPoint receive)
         {
-            TcpState state = assoc.GetState();
+            var state = _assoc.GetState();
             if (state != TcpState.Established)
                 throw new InvalidOperationException("No UDP association, maybe already disconnected or not connected");
 
-            byte[] remoteBytes = GetEndPointByte(remote);
-            byte[] proxyBytes = new byte[bytes.Length + remoteBytes.Length + 3];
+            var remoteBytes = GetEndPointByte(remote);
+            var proxyBytes = new byte[bytes.Length + remoteBytes.Length + 3];
             Array.Copy(remoteBytes, 0, proxyBytes, 3, remoteBytes.Length);
             Array.Copy(bytes, 0, proxyBytes, remoteBytes.Length + 3, bytes.Length);
 
-            await UdpClient.SendAsync(proxyBytes, proxyBytes.Length, assocEndPoint);
+            await _udpClient.SendAsync(proxyBytes, proxyBytes.Length, _assocEndPoint);
             var res = new byte[ushort.MaxValue];
             var flag = SocketFlags.None;
             EndPoint ep = new IPEndPoint(0, 0);
-            var length = UdpClient.Client.ReceiveMessageFrom(res, 0, res.Length, ref flag, ref ep, out var ipPacketInformation);
+            var length = _udpClient.Client.ReceiveMessageFrom(res, 0, res.Length, ref flag, ref ep, out var ipPacketInformation);
 
             if (res[0] != 0 || res[1] != 0 || res[2] != 0)
             {
                 throw new Exception();
             }
 
-            int addrLen;
-            switch (res[3])
+            var addressLen = res[3] switch
             {
-                case 1:
-                    addrLen = 4;
-                    break;
-                case 4:
-                    addrLen = 16;
-                    break;
-                default:
-                    throw new Exception();
-            }
-
-            byte[] ipbyte = new byte[addrLen];
-            Array.Copy(res, 4, ipbyte, 0, addrLen);
-
-            IPAddress ip = new IPAddress(ipbyte);
-            int port = res[addrLen + 4] * 256 + res[addrLen + 5];
-            byte[] ret = new byte[length - addrLen - 6];
-            Array.Copy(res, addrLen + 6, ret, 0, length - addrLen - 6);
+                1 => 4,
+                4 => 16,
+                _ => throw new Exception()
+            };
+
+            var ipByte = new byte[addressLen];
+            Array.Copy(res, 4, ipByte, 0, addressLen);
+
+            var ip = new IPAddress(ipByte);
+            var port = res[addressLen + 4] * 256 + res[addressLen + 5];
+            var ret = new byte[length - addressLen - 6];
+            Array.Copy(res, addressLen + 6, ret, 0, length - addressLen - 6);
             return (
                 ret,
                 new IPEndPoint(ip, port),
@@ -192,27 +198,31 @@ namespace STUN.Proxy
         {
             try
             {
-                assoc.Close();
+                _assoc.Close();
             }
-            catch { }
+            catch
+            {
+                // ignored
+            }
+
             return Task.CompletedTask;
         }
 
-        byte[] GetEndPointByte(IPEndPoint ep)
+        private static byte[] GetEndPointByte(IPEndPoint ep)
         {
-            byte[] ipbyte = ep.Address.GetAddressBytes();
-            byte[] ret = new byte[ipbyte.Length + 3];
-            ret[0] = (byte)(ipbyte.Length == 4 ? 1 : 4);
-            Array.Copy(ipbyte, 0, ret, 1, ipbyte.Length);
-            ret[ipbyte.Length + 1] = (byte)(ep.Port / 256);
-            ret[ipbyte.Length + 2] = (byte)(ep.Port % 256);
+            var ipByte = ep.Address.GetAddressBytes();
+            var ret = new byte[ipByte.Length + 3];
+            ret[0] = (byte)(ipByte.Length == 4 ? 1 : 4);
+            Array.Copy(ipByte, 0, ret, 1, ipByte.Length);
+            ret[ipByte.Length + 1] = (byte)(ep.Port / 256);
+            ret[ipByte.Length + 2] = (byte)(ep.Port % 256);
             return ret;
         }
 
         public void Dispose()
         {
-            UdpClient?.Dispose();
-            assoc?.Dispose();
+            _udpClient?.Dispose();
+            _assoc?.Dispose();
         }
     }
 }

+ 1 - 47
STUN/Utils/NetUtils.cs

@@ -1,7 +1,5 @@
 using STUN.Client;
 using STUN.StunResult;
-using System;
-using System.Diagnostics;
 using System.Linq;
 using System.Net;
 using System.Net.NetworkInformation;
@@ -50,56 +48,12 @@ namespace STUN.Utils
             return await client.QueryAsync();
         }
 
-        public static (byte[], IPEndPoint, IPAddress) UdpReceive(this UdpClient client, byte[] bytes, IPEndPoint remote, EndPoint receive)
-        {
-            var localEndPoint = (IPEndPoint)client.Client.LocalEndPoint;
-
-            Debug.WriteLine($@"{localEndPoint} => {remote} {bytes.Length} 字节");
-
-            client.Send(bytes, bytes.Length, remote);
-
-            var res = new byte[ushort.MaxValue];
-            var flag = SocketFlags.None;
-
-            var length = client.Client.ReceiveMessageFrom(res, 0, res.Length, ref flag, ref receive, out var ipPacketInformation);
-
-            var local = ipPacketInformation.Address;
-
-            Debug.WriteLine($@"{(IPEndPoint)receive} => {local} {length} 字节");
-
-            return (res.Take(length).ToArray(),
-                    (IPEndPoint)receive
-                    , local);
-        }
-
-        public static async Task<(byte[], IPEndPoint, IPAddress)> UdpReceiveAsync(this UdpClient client, byte[] bytes, IPEndPoint remote, EndPoint receive)
-        {
-            var localEndPoint = (IPEndPoint)client.Client.LocalEndPoint;
-
-            Debug.WriteLine($@"{localEndPoint} => {remote} {bytes.Length} 字节");
-
-            await client.SendAsync(bytes, bytes.Length, remote);
-
-            var res = new byte[ushort.MaxValue];
-            var flag = SocketFlags.None;
-
-            var length = client.Client.ReceiveMessageFrom(res, 0, res.Length, ref flag, ref receive, out var ipPacketInformation);
-
-            var local = ipPacketInformation.Address;
-
-            Debug.WriteLine($@"{(IPEndPoint)receive} => {local} {length} 字节");
-
-            return (res.Take(length).ToArray(),
-                    (IPEndPoint)receive
-                    , local);
-        }
-
         public static TcpState GetState(this TcpClient tcpClient)
         {
             var foo = IPGlobalProperties.GetIPGlobalProperties()
               .GetActiveTcpConnections()
               .SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint));
-            return foo != null ? foo.State : TcpState.Unknown;
+            return foo?.State ?? TcpState.Unknown;
         }
     }
 }