Socks5UdpProxy.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.Net;
  6. using System.Net.NetworkInformation;
  7. using System.Net.Sockets;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. using STUN.Utils;
  11. namespace STUN.Proxy
  12. {
  13. class Socks5UdpProxy : IUdpProxy
  14. {
  15. TcpClient assoc = new TcpClient();
  16. IPEndPoint socksTcpEndPoint;
  17. IPEndPoint assocEndPoint;
  18. public TimeSpan Timeout
  19. {
  20. get => TimeSpan.FromMilliseconds(UdpClient.Client.ReceiveTimeout);
  21. set => UdpClient.Client.ReceiveTimeout = Convert.ToInt32(value.TotalMilliseconds);
  22. }
  23. public IPEndPoint LocalEndPoint { get => (IPEndPoint)UdpClient.Client.LocalEndPoint; }
  24. UdpClient UdpClient;
  25. string user;
  26. string password;
  27. public Socks5UdpProxy(IPEndPoint local, IPEndPoint proxy)
  28. {
  29. UdpClient = local == null ? new UdpClient() : new UdpClient(local);
  30. socksTcpEndPoint = proxy;
  31. }
  32. public Socks5UdpProxy(IPEndPoint local, IPEndPoint proxy, string user, string password) : this(local, proxy)
  33. {
  34. this.user = user;
  35. this.password = password;
  36. }
  37. public async Task ConnectAsync()
  38. {
  39. byte[] buf = new byte[1024];
  40. await assoc.ConnectAsync(socksTcpEndPoint.Address, socksTcpEndPoint.Port);
  41. try
  42. {
  43. var s = assoc.GetStream();
  44. bool requestPasswordAuth = !string.IsNullOrEmpty(user);
  45. #region Handshake
  46. // we have no gssapi support
  47. if (requestPasswordAuth)
  48. {
  49. // 5 authlen auth[](0=none, 2=userpasswd)
  50. s.Write(new byte[] { 5, 2, 0, 2 }, 0, 4);
  51. }
  52. else
  53. {
  54. s.Write(new byte[] { 5, 1, 0 }, 0, 3);
  55. }
  56. // 5 auth(ff=deny)
  57. if (s.Read(buf, 0, 2) != 2) throw new ProtocolViolationException();
  58. if (buf[0] != 5) throw new ProtocolViolationException();
  59. #endregion
  60. #region Auth
  61. var auth = buf[1];
  62. switch (auth)
  63. {
  64. case 0:
  65. break;
  66. case 2:
  67. byte[] ubyte = Encoding.UTF8.GetBytes(user);
  68. byte[] pbyte = Encoding.UTF8.GetBytes(password);
  69. buf[0] = 1;
  70. buf[1] = (byte)ubyte.Length;
  71. Array.Copy(ubyte, 0, buf, 2, ubyte.Length);
  72. buf[ubyte.Length + 3] = (byte)pbyte.Length;
  73. Array.Copy(pbyte, 0, buf, ubyte.Length + 4, pbyte.Length);
  74. // 1 userlen user passlen pass
  75. s.Write(buf, 0, ubyte.Length + pbyte.Length + 4);
  76. // 1 state(0=ok)
  77. if (s.Read(buf, 0, 2) != 2) throw new ProtocolViolationException();
  78. if (buf[0] != 1) throw new ProtocolViolationException();
  79. if (buf[1] != 0) throw new UnauthorizedAccessException();
  80. break;
  81. case 0xff:
  82. throw new UnauthorizedAccessException();
  83. default:
  84. throw new ProtocolViolationException();
  85. }
  86. #endregion
  87. #region UDP Assoc Send
  88. buf[0] = 5;
  89. buf[1] = 3;
  90. buf[2] = 0;
  91. int addrLen;
  92. byte[] abyte = GetEndPointByte(new IPEndPoint(IPAddress.Any, 0));
  93. addrLen = abyte.Length;
  94. Array.Copy(abyte, 0, buf, 3, addrLen);
  95. // 5 cmd(3=udpassoc) 0 atyp(1=v4 3=dns 4=v5) addr port
  96. s.Write(buf, 0, addrLen + 3);
  97. #endregion
  98. #region UDP Assoc Response
  99. if (s.Read(buf, 0, 4) != 4) throw new ProtocolViolationException();
  100. if (buf[0] != 5 || buf[2] != 0) throw new ProtocolViolationException();
  101. if (buf[1] != 0) throw new UnauthorizedAccessException();
  102. switch (buf[3])
  103. {
  104. case 1:
  105. addrLen = 4;
  106. break;
  107. case 4:
  108. addrLen = 16;
  109. break;
  110. default:
  111. throw new NotSupportedException();
  112. }
  113. byte[] addr = new byte[addrLen];
  114. if (s.Read(addr, 0, addrLen) != addrLen) throw new ProtocolViolationException();
  115. IPAddress assocIP = new IPAddress(addr);
  116. if (s.Read(buf, 0, 2) != 2) throw new ProtocolViolationException();
  117. int assocPort = buf[0] * 256 + buf[1];
  118. #endregion
  119. assocEndPoint = new IPEndPoint(assocIP, assocPort);
  120. }
  121. catch (Exception e)
  122. {
  123. Debug.WriteLine(e);
  124. assoc.Close();
  125. }
  126. }
  127. public async Task<(byte[], IPEndPoint, IPAddress)> RecieveAsync(byte[] bytes, IPEndPoint remote, EndPoint receive)
  128. {
  129. TcpState state = assoc.GetState();
  130. if (state != TcpState.Established)
  131. throw new InvalidOperationException("No UDP association, maybe already disconnected or not connected");
  132. byte[] remoteBytes = GetEndPointByte(remote);
  133. byte[] proxyBytes = new byte[bytes.Length + remoteBytes.Length + 3];
  134. Array.Copy(remoteBytes, 0, proxyBytes, 3, remoteBytes.Length);
  135. Array.Copy(bytes, 0, proxyBytes, remoteBytes.Length + 3, bytes.Length);
  136. await UdpClient.SendAsync(proxyBytes, proxyBytes.Length, assocEndPoint);
  137. var res = new byte[ushort.MaxValue];
  138. var flag = SocketFlags.None;
  139. EndPoint ep = new IPEndPoint(0, 0);
  140. var length = UdpClient.Client.ReceiveMessageFrom(res, 0, res.Length, ref flag, ref ep, out var ipPacketInformation);
  141. if (res[0] != 0 || res[1] != 0 || res[2] != 0)
  142. {
  143. throw new Exception();
  144. }
  145. int addrLen;
  146. switch (res[3])
  147. {
  148. case 1:
  149. addrLen = 4;
  150. break;
  151. case 4:
  152. addrLen = 16;
  153. break;
  154. default:
  155. throw new Exception();
  156. }
  157. byte[] ipbyte = new byte[addrLen];
  158. Array.Copy(res, 4, ipbyte, 0, addrLen);
  159. IPAddress ip = new IPAddress(ipbyte);
  160. int port = res[addrLen + 4] * 256 + res[addrLen + 5];
  161. byte[] ret = new byte[length - addrLen - 6];
  162. Array.Copy(res, addrLen + 6, ret, 0, length - addrLen - 6);
  163. return (
  164. ret,
  165. new IPEndPoint(ip, port),
  166. ipPacketInformation.Address);
  167. }
  168. public Task DisconnectAsync()
  169. {
  170. try
  171. {
  172. assoc.Close();
  173. }
  174. catch { }
  175. return Task.CompletedTask;
  176. }
  177. byte[] GetEndPointByte(IPEndPoint ep)
  178. {
  179. byte[] ipbyte = ep.Address.GetAddressBytes();
  180. byte[] ret = new byte[ipbyte.Length + 3];
  181. ret[0] = (byte)(ipbyte.Length == 4 ? 1 : 4);
  182. Array.Copy(ipbyte, 0, ret, 1, ipbyte.Length);
  183. ret[ipbyte.Length + 1] = (byte)(ep.Port / 256);
  184. ret[ipbyte.Length + 2] = (byte)(ep.Port % 256);
  185. return ret;
  186. }
  187. public void Dispose()
  188. {
  189. UdpClient?.Dispose();
  190. assoc?.Dispose();
  191. }
  192. }
  193. }