Socks5UdpProxy.cs 7.6 KB

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