You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Socks5Handler.cs 10 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. using System;
  2. using System.Linq;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using Shadowsocks.Model;
  6. using Shadowsocks.Util.Sockets;
  7. namespace Shadowsocks.Controller.Service
  8. {
  9. class Socks5HandlerFactory : ITCPHandlerFactory
  10. {
  11. public bool CanHandle(byte[] firstPacket, int length)
  12. {
  13. return length >= 2 && firstPacket[0] == 5;
  14. }
  15. public TCPHandler NewHandler(ShadowsocksController controller, Configuration config, TCPRelay tcprelay, Socket socket)
  16. {
  17. return new Socks5Handler(controller, config, tcprelay, socket);
  18. }
  19. }
  20. class Socks5Handler : TCPHandler
  21. {
  22. private byte _command;
  23. private int _firstPacketLength;
  24. public Socks5Handler(ShadowsocksController controller, Configuration config, TCPRelay tcprelay, Socket socket) : base(controller, config, tcprelay, socket, false)
  25. {
  26. }
  27. public override void StartHandshake(byte[] firstPacket, int length)
  28. {
  29. if (Closed) return;
  30. try
  31. {
  32. int bytesRead = length;
  33. if (bytesRead > 1)
  34. {
  35. byte[] response = { 5, 0 };
  36. if (firstPacket[0] != 5)
  37. {
  38. // reject socks 4
  39. response = new byte[] { 0, 91 };
  40. Logging.Error("socks 5 protocol error");
  41. }
  42. Connection.BeginSend(response, 0, response.Length, SocketFlags.None, HandshakeSendCallback, null);
  43. }
  44. else
  45. Close();
  46. }
  47. catch (Exception e)
  48. {
  49. Logging.LogUsefulException(e);
  50. Close();
  51. }
  52. }
  53. private void HandshakeSendCallback(IAsyncResult ar)
  54. {
  55. if (Closed) return;
  56. try
  57. {
  58. Connection.EndSend(ar);
  59. // +-----+-----+-------+------+----------+----------+
  60. // | VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
  61. // +-----+-----+-------+------+----------+----------+
  62. // | 1 | 1 | X'00' | 1 | Variable | 2 |
  63. // +-----+-----+-------+------+----------+----------+
  64. // Skip first 3 bytes, and read 2 more bytes to analysis the address.
  65. // 2 more bytes is designed if address is domain then we don't need to read once more to get the addr length.
  66. // TODO validate
  67. Connection.BeginReceive(ConnetionRecvBuffer, 0, 3 + 2, SocketFlags.None,
  68. handshakeReceive2Callback, null);
  69. }
  70. catch (Exception e)
  71. {
  72. Logging.LogUsefulException(e);
  73. Close();
  74. }
  75. }
  76. private void handshakeReceive2Callback(IAsyncResult ar)
  77. {
  78. if (Closed) return;
  79. try
  80. {
  81. int bytesRead = Connection.EndReceive(ar);
  82. if (bytesRead >= 5)
  83. {
  84. _command = ConnetionRecvBuffer[1];
  85. if (_command != 1 && _command != 3)
  86. {
  87. Logging.Debug("Unsupported CMD=" + _command);
  88. Close();
  89. }
  90. else
  91. {
  92. int atyp = ConnetionRecvBuffer[3];
  93. switch (atyp)
  94. {
  95. case 1: // IPv4 address, 4 bytes
  96. ReadAddress(4 + 2 - 1);
  97. break;
  98. case 3: // domain name, length + str
  99. int len = ConnetionRecvBuffer[4];
  100. ReadAddress(len + 2);
  101. break;
  102. case 4: // IPv6 address, 16 bytes
  103. ReadAddress(16 + 2 - 1);
  104. break;
  105. default:
  106. Logging.Debug("Unsupported ATYP=" + atyp);
  107. Close();
  108. break;
  109. }
  110. }
  111. }
  112. else
  113. {
  114. Logging.Debug("failed to recv data in Shadowsocks.Controller.TCPHandler.handshakeReceive2Callback()");
  115. Close();
  116. }
  117. }
  118. catch (Exception e)
  119. {
  120. Logging.LogUsefulException(e);
  121. Close();
  122. }
  123. }
  124. private void ReadAddress(int bytesRemain)
  125. {
  126. Array.Copy(ConnetionRecvBuffer, 3, ConnetionRecvBuffer, 0, 2);
  127. // Read the remain address bytes
  128. Connection.BeginReceive(ConnetionRecvBuffer, 2, RecvSize - 2, SocketFlags.None, OnAddressFullyRead, bytesRemain);
  129. }
  130. private void OnAddressFullyRead(IAsyncResult ar)
  131. {
  132. if (Closed) return;
  133. try
  134. {
  135. int bytesRead = Connection.EndReceive(ar);
  136. int bytesRemain = (int)ar.AsyncState;
  137. if (bytesRead >= bytesRemain)
  138. {
  139. _firstPacketLength = bytesRead + 2;
  140. int atyp = ConnetionRecvBuffer[0];
  141. string dst_addr = "Unknown";
  142. int dst_port = -1;
  143. switch (atyp)
  144. {
  145. case 1: // IPv4 address, 4 bytes
  146. dst_addr = new IPAddress(ConnetionRecvBuffer.Skip(1).Take(4).ToArray()).ToString();
  147. dst_port = (ConnetionRecvBuffer[5] << 8) + ConnetionRecvBuffer[6];
  148. break;
  149. case 3: // domain name, length + str
  150. int len = ConnetionRecvBuffer[1];
  151. dst_addr = System.Text.Encoding.UTF8.GetString(ConnetionRecvBuffer, 2, len);
  152. dst_port = (ConnetionRecvBuffer[len + 2] << 8) + ConnetionRecvBuffer[len + 3];
  153. break;
  154. case 4: // IPv6 address, 16 bytes
  155. dst_addr = $"[{new IPAddress(ConnetionRecvBuffer.Skip(1).Take(16).ToArray())}]";
  156. dst_port = (ConnetionRecvBuffer[17] << 8) + ConnetionRecvBuffer[18];
  157. break;
  158. }
  159. if (Config.isVerboseLogging)
  160. {
  161. Logging.Info($"connect to {dst_addr}:{dst_port}");
  162. }
  163. var destEndPoint = SocketUtil.GetEndPoint(dst_addr, dst_port);
  164. if (_command == 1)
  165. {
  166. byte[] response = { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
  167. Connection.BeginSend(response, 0, response.Length, SocketFlags.None,
  168. ResponseCallback, destEndPoint);
  169. }
  170. else if (_command == 3)
  171. {
  172. HandleUDPAssociate();
  173. }
  174. }
  175. else
  176. {
  177. Logging.Debug("failed to recv data in Shadowsocks.Controller.TCPHandler.OnAddressFullyRead()");
  178. Close();
  179. }
  180. }
  181. catch (Exception e)
  182. {
  183. Logging.LogUsefulException(e);
  184. Close();
  185. }
  186. }
  187. private void HandleUDPAssociate()
  188. {
  189. IPEndPoint endPoint = (IPEndPoint)Connection.LocalEndPoint;
  190. byte[] address = endPoint.Address.GetAddressBytes();
  191. int port = endPoint.Port;
  192. byte[] response = new byte[4 + address.Length + 2];
  193. response[0] = 5;
  194. switch (endPoint.AddressFamily)
  195. {
  196. case AddressFamily.InterNetwork:
  197. response[3] = 1;
  198. break;
  199. case AddressFamily.InterNetworkV6:
  200. response[3] = 4;
  201. break;
  202. }
  203. address.CopyTo(response, 4);
  204. response[response.Length - 1] = (byte)(port & 0xFF);
  205. response[response.Length - 2] = (byte)((port >> 8) & 0xFF);
  206. Connection.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(ReadAll), true);
  207. }
  208. private void ReadAll(IAsyncResult ar)
  209. {
  210. if (Closed) return;
  211. try
  212. {
  213. if (ar.AsyncState != null)
  214. {
  215. Connection.EndSend(ar);
  216. Connection.BeginReceive(ConnetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
  217. }
  218. else
  219. {
  220. int bytesRead = Connection.EndReceive(ar);
  221. if (bytesRead > 0)
  222. {
  223. Connection.BeginReceive(ConnetionRecvBuffer, 0, RecvSize, SocketFlags.None, new AsyncCallback(ReadAll), null);
  224. }
  225. else
  226. Close();
  227. }
  228. }
  229. catch (Exception e)
  230. {
  231. Logging.LogUsefulException(e);
  232. Close();
  233. }
  234. }
  235. private void ResponseCallback(IAsyncResult ar)
  236. {
  237. try
  238. {
  239. Connection.EndSend(ar);
  240. StartConnect((EndPoint) ar.AsyncState);
  241. }
  242. catch (Exception e)
  243. {
  244. Logging.LogUsefulException(e);
  245. Close();
  246. }
  247. }
  248. protected override void OnServerConnected(AsyncSession session)
  249. {
  250. BeginSendToServer(_firstPacketLength, session, FirstPackageSendCallback);
  251. }
  252. private void FirstPackageSendCallback(IAsyncResult ar)
  253. {
  254. if (Closed) return;
  255. try
  256. {
  257. var session = EndSendToServer(ar);
  258. StartPipe(session);
  259. }
  260. catch (Exception e)
  261. {
  262. Logging.LogUsefulException(e);
  263. Close();
  264. }
  265. }
  266. }
  267. }