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.

TCPRelay.cs 20 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. using Splat;
  2. using Shadowsocks.Net.Crypto;
  3. using Shadowsocks.Net.Crypto.AEAD;
  4. using Shadowsocks.Net.Proxy;
  5. using System;
  6. using System.Buffers;
  7. using System.Collections.Generic;
  8. using System.Net;
  9. using System.Net.Sockets;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using static Shadowsocks.Net.Crypto.CryptoBase;
  14. using Shadowsocks.Models;
  15. namespace Shadowsocks.Net
  16. {
  17. public class TCPRelay : StreamService, IEnableLogger
  18. {
  19. public event EventHandler<SSTCPConnectedEventArgs> OnConnected;
  20. public event EventHandler<SSTransmitEventArgs> OnInbound;
  21. public event EventHandler<SSTransmitEventArgs> OnOutbound;
  22. public event EventHandler<SSRelayEventArgs> OnFailed;
  23. private Server _server;
  24. private DateTime _lastSweepTime;
  25. public ISet<TCPHandler> Handlers { get; set; }
  26. public TCPRelay(Server server)
  27. {
  28. _server = server;
  29. Handlers = new HashSet<TCPHandler>();
  30. _lastSweepTime = DateTime.Now;
  31. }
  32. public override bool Handle(CachedNetworkStream stream, object state)
  33. {
  34. byte[] fp = new byte[256];
  35. int len = stream.ReadFirstBlock(fp);
  36. var socket = stream.Socket;
  37. if (socket.ProtocolType != ProtocolType.Tcp
  38. || (len < 2 || fp[0] != 5))
  39. return false;
  40. socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
  41. TCPHandler handler = new TCPHandler(_server, socket);
  42. IList<TCPHandler> handlersToClose = new List<TCPHandler>();
  43. lock (Handlers)
  44. {
  45. Handlers.Add(handler);
  46. DateTime now = DateTime.Now;
  47. if (now - _lastSweepTime > TimeSpan.FromSeconds(1))
  48. {
  49. _lastSweepTime = now;
  50. foreach (TCPHandler handler1 in Handlers)
  51. if (now - handler1.lastActivity > TimeSpan.FromSeconds(900))
  52. handlersToClose.Add(handler1);
  53. }
  54. }
  55. foreach (TCPHandler handler1 in handlersToClose)
  56. {
  57. this.Log().Debug("Closing timed out TCP connection.");
  58. handler1.Close();
  59. }
  60. /*
  61. * Start after we put it into Handlers set. Otherwise if it failed in handler.Start()
  62. * then it will call handler.Close() before we add it into the set.
  63. * Then the handler will never release until the next Handle call. Sometimes it will
  64. * cause odd problems (especially during memory profiling).
  65. */
  66. // handler.Start(fp, len);
  67. _ = handler.StartAsync(fp, len);
  68. return true;
  69. // return Handle(fp, len, stream.Socket, state);
  70. }
  71. [Obsolete]
  72. public override bool Handle(byte[] firstPacket, int length, Socket socket, object state)
  73. {
  74. if (socket.ProtocolType != ProtocolType.Tcp
  75. || (length < 2 || firstPacket[0] != 5))
  76. {
  77. return false;
  78. }
  79. socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
  80. TCPHandler handler = new TCPHandler(_server, socket);
  81. handler.OnConnected += OnConnected;
  82. handler.OnInbound += OnInbound;
  83. handler.OnOutbound += OnOutbound;
  84. handler.OnFailed += OnFailed;
  85. handler.OnClosed += (h, arg) =>
  86. {
  87. lock (Handlers)
  88. {
  89. Handlers.Remove(handler);
  90. }
  91. };
  92. IList<TCPHandler> handlersToClose = new List<TCPHandler>();
  93. lock (Handlers)
  94. {
  95. Handlers.Add(handler);
  96. DateTime now = DateTime.Now;
  97. if (now - _lastSweepTime > TimeSpan.FromSeconds(1))
  98. {
  99. _lastSweepTime = now;
  100. foreach (TCPHandler handler1 in Handlers)
  101. {
  102. if (now - handler1.lastActivity > TimeSpan.FromSeconds(900))
  103. {
  104. handlersToClose.Add(handler1);
  105. }
  106. }
  107. }
  108. }
  109. foreach (TCPHandler handler1 in handlersToClose)
  110. {
  111. this.Log().Debug("Closing timed out TCP connection.");
  112. handler1.Close();
  113. }
  114. /*
  115. * Start after we put it into Handlers set. Otherwise if it failed in handler.Start()
  116. * then it will call handler.Close() before we add it into the set.
  117. * Then the handler will never release until the next Handle call. Sometimes it will
  118. * cause odd problems (especially during memory profiling).
  119. */
  120. // handler.Start(firstPacket, length);
  121. _ = handler.StartAsync(firstPacket, length);
  122. return true;
  123. }
  124. public override void Stop()
  125. {
  126. List<TCPHandler> handlersToClose = new List<TCPHandler>();
  127. lock (Handlers)
  128. {
  129. handlersToClose.AddRange(Handlers);
  130. }
  131. handlersToClose.ForEach(h => h.Close());
  132. }
  133. }
  134. public class SSRelayEventArgs : EventArgs
  135. {
  136. public readonly Server server;
  137. public SSRelayEventArgs(Server server)
  138. {
  139. this.server = server;
  140. }
  141. }
  142. public class SSTransmitEventArgs : SSRelayEventArgs
  143. {
  144. public readonly long length;
  145. public SSTransmitEventArgs(Server server, long length) : base(server)
  146. {
  147. this.length = length;
  148. }
  149. }
  150. public class SSTCPConnectedEventArgs : SSRelayEventArgs
  151. {
  152. public readonly TimeSpan latency;
  153. public SSTCPConnectedEventArgs(Server server, TimeSpan latency) : base(server)
  154. {
  155. this.latency = latency;
  156. }
  157. }
  158. public class TCPHandler : IEnableLogger
  159. {
  160. public event EventHandler<SSTCPConnectedEventArgs> OnConnected;
  161. public event EventHandler<SSTransmitEventArgs> OnInbound;
  162. public event EventHandler<SSTransmitEventArgs> OnOutbound;
  163. public event EventHandler<SSRelayEventArgs> OnClosed;
  164. public event EventHandler<SSRelayEventArgs> OnFailed;
  165. private readonly int _serverTimeout;
  166. private readonly int _proxyTimeout;
  167. private readonly MemoryPool<byte> pool = MemoryPool<byte>.Shared;
  168. // each recv size.
  169. public const int RecvSize = 16384;
  170. // overhead of one chunk, reserved for AEAD ciphers
  171. public const int ChunkOverheadSize = 100;//16 * 2 /* two tags */ + AEADEncryptor.ChunkLengthBytes;
  172. // In general, the ciphertext length, we should take overhead into account
  173. public const int SendSize = 32768;
  174. public DateTime lastActivity;
  175. // TODO: forward proxy
  176. //private readonly ForwardProxyConfig _config;
  177. private readonly Server _server;
  178. private readonly Socket _connection;
  179. private IProxy _remote;
  180. private ICrypto encryptor;
  181. // workaround
  182. private ICrypto decryptor;
  183. private byte[] _firstPacket;
  184. private int _firstPacketLength;
  185. private const int CMD_CONNECT = 0x01;
  186. private const int CMD_BIND = 0x02;
  187. private const int CMD_UDP_ASSOC = 0x03;
  188. private bool _closed = false;
  189. // instance-based lock without static
  190. private readonly object _encryptionLock = new object();
  191. private readonly object _decryptionLock = new object();
  192. private readonly object _closeConnLock = new object();
  193. // TODO: decouple controller
  194. public TCPHandler(Server server, Socket socket)
  195. {
  196. _server = server;
  197. _connection = socket;
  198. _proxyTimeout = 5000;
  199. _serverTimeout = 5000;
  200. lastActivity = DateTime.Now;
  201. }
  202. public void CreateRemote(EndPoint destination)
  203. {
  204. if (_server == null || _server.Host == "")
  205. {
  206. throw new ArgumentException("No server configured");
  207. }
  208. encryptor = CryptoFactory.GetEncryptor(_server.Method, _server.Password);
  209. decryptor = CryptoFactory.GetEncryptor(_server.Method, _server.Password);
  210. }
  211. public async Task StartAsync(byte[] firstPacket, int length)
  212. {
  213. _firstPacket = firstPacket;
  214. _firstPacketLength = length;
  215. (int cmd, EndPoint dst) = await Socks5Handshake();
  216. if (cmd == CMD_CONNECT)
  217. {
  218. await ConnectRemote(dst);
  219. await SendAddress(dst);
  220. await Forward();
  221. }
  222. else if (cmd == CMD_UDP_ASSOC)
  223. {
  224. await DrainConnection();
  225. }
  226. }
  227. private void ErrorClose(Exception e)
  228. {
  229. this.Log().Error(e, "");
  230. Close();
  231. }
  232. public void Close()
  233. {
  234. lock (_closeConnLock)
  235. {
  236. if (_closed)
  237. {
  238. return;
  239. }
  240. _closed = true;
  241. }
  242. OnClosed?.Invoke(this, new SSRelayEventArgs(_server));
  243. try
  244. {
  245. _connection.Shutdown(SocketShutdown.Both);
  246. _connection.Close();
  247. encryptor?.Dispose();
  248. decryptor?.Dispose();
  249. }
  250. catch (Exception e)
  251. {
  252. this.Log().Error(e, "");
  253. }
  254. }
  255. async Task<(int cmd, EndPoint destination)> Socks5Handshake()
  256. {
  257. // not so strict here
  258. // 5 2 1 2 should return 5 255
  259. // 5 1 0 5 / 1 0 1 127 0 0 1 0 80 will cause handshake fail
  260. int bytesRead = _firstPacketLength;
  261. if (bytesRead <= 1)
  262. {
  263. Close();
  264. return (0, default);
  265. }
  266. byte[] response = { 5, 0 };
  267. if (_firstPacket[0] != 5)
  268. {
  269. // reject socks 4
  270. response = new byte[] { 0, 91 };
  271. this.Log().Error("socks5 protocol error");
  272. }
  273. await _connection.SendAsync(response, SocketFlags.None);
  274. using var bufOwner = pool.Rent(512);
  275. var buf = bufOwner.Memory;
  276. if (await _connection.ReceiveAsync(buf.Slice(0, 5), SocketFlags.None) != 5)
  277. {
  278. Close();
  279. return (0, default);
  280. }
  281. var cmd = buf.Span[1];
  282. EndPoint dst = default;
  283. switch (cmd)
  284. {
  285. case CMD_CONNECT:
  286. await _connection.SendAsync(new byte[] { 5, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, SocketFlags.None);
  287. dst = await ReadAddress(buf);
  288. // start forward
  289. break;
  290. case CMD_UDP_ASSOC:
  291. dst = await ReadAddress(buf);
  292. await SendUdpAssociate();
  293. // drain
  294. break;
  295. default:
  296. Close();
  297. break;
  298. }
  299. return (cmd, dst);
  300. }
  301. async Task DrainConnection()
  302. {
  303. if (_closed)
  304. {
  305. return;
  306. }
  307. using var b = pool.Rent(512);
  308. try
  309. {
  310. int l;
  311. do
  312. {
  313. l = await _connection.ReceiveAsync(b.Memory, SocketFlags.None);
  314. }
  315. while (l > 0);
  316. Close();
  317. }
  318. catch (Exception e)
  319. {
  320. ErrorClose(e);
  321. }
  322. }
  323. private async Task<EndPoint> ReadAddress(Memory<byte> buf)
  324. {
  325. var atyp = buf.Span[3];
  326. var maybeDomainLength = buf.Span[4];
  327. buf.Span[0] = atyp;
  328. buf.Span[1] = maybeDomainLength;
  329. int toRead = atyp switch
  330. {
  331. ATYP_IPv4 => 4,
  332. ATYP_IPv6 => 16,
  333. ATYP_DOMAIN => maybeDomainLength + 1,
  334. _ => throw new NotSupportedException(),
  335. } + 2 - 1;
  336. await _connection.ReceiveAsync(buf.Slice(2, toRead), SocketFlags.None);
  337. return GetSocks5EndPoint(buf.ToArray());
  338. }
  339. private int ReadPort(byte[] arr, long offset)
  340. {
  341. return (arr[offset] << 8) + arr[offset + 1];
  342. }
  343. private EndPoint GetSocks5EndPoint(byte[] buf)
  344. {
  345. int maybeDomainLength = buf[1] + 2;
  346. return (buf[0]) switch
  347. {
  348. ATYP_IPv4 => new IPEndPoint(new IPAddress(buf[1..5]), ReadPort(buf, 5)),
  349. ATYP_IPv6 => new IPEndPoint(new IPAddress(buf[1..17]), ReadPort(buf, 17)),
  350. ATYP_DOMAIN => new DnsEndPoint(Encoding.ASCII.GetString(buf[2..maybeDomainLength]), ReadPort(buf, maybeDomainLength)),
  351. _ => throw new NotSupportedException(),
  352. };
  353. }
  354. private async Task SendUdpAssociate()
  355. {
  356. IPEndPoint endPoint = (IPEndPoint)_connection.LocalEndPoint;
  357. byte[] address = endPoint.Address.GetAddressBytes();
  358. int port = endPoint.Port;
  359. byte[] response = new byte[4 + address.Length + ADDR_PORT_LEN];
  360. response[0] = 5;
  361. switch (endPoint.AddressFamily)
  362. {
  363. case AddressFamily.InterNetwork:
  364. response[3] = ATYP_IPv4;
  365. break;
  366. case AddressFamily.InterNetworkV6:
  367. response[3] = ATYP_IPv6;
  368. break;
  369. }
  370. address.CopyTo(response, 4);
  371. response[^1] = (byte)(port & 0xFF);
  372. response[^2] = (byte)((port >> 8) & 0xFF);
  373. await _connection.SendAsync(response, SocketFlags.None);
  374. }
  375. private async Task ConnectRemote(EndPoint destination)
  376. {
  377. CreateRemote(destination);
  378. IProxy remote;
  379. EndPoint proxyEP = null;
  380. EndPoint serverEP = new DnsEndPoint(_server.Host, _server.Port);
  381. EndPoint pluginEP = null; // TODO: plugin local end point
  382. remote = new DirectConnect(); // TODO: forward proxy
  383. NetworkCredential auth = null;
  384. /*if (_config.useAuth)
  385. {
  386. auth = new NetworkCredential(_config.authUser, _config.authPwd);
  387. }
  388. if (pluginEP != null)
  389. {
  390. serverEP = pluginEP;
  391. remote = new DirectConnect();
  392. }
  393. else if (_config.useProxy)
  394. {
  395. remote = _config.proxyType switch
  396. {
  397. ForwardProxyConfig.PROXY_SOCKS5 => new Socks5Proxy(),
  398. ForwardProxyConfig.PROXY_HTTP => new HttpProxy(),
  399. _ => throw new NotSupportedException("Unknown forward proxy."),
  400. };
  401. proxyEP = new DnsEndPoint(_config.proxyServer, _config.proxyPort);
  402. }
  403. else
  404. {
  405. remote = new DirectConnect();
  406. }*/
  407. CancellationTokenSource cancelProxy = new CancellationTokenSource(_proxyTimeout * 1000);
  408. await remote.ConnectProxyAsync(proxyEP, auth, cancelProxy.Token);
  409. _remote = remote;
  410. if (!(remote is DirectConnect))
  411. {
  412. this.Log().Debug($"Socket connected to proxy {remote.ProxyEndPoint}");
  413. }
  414. var _startConnectTime = DateTime.Now;
  415. CancellationTokenSource cancelServer = new CancellationTokenSource(_serverTimeout * 1000);
  416. await remote.ConnectRemoteAsync(serverEP, cancelServer.Token);
  417. this.Log().Debug($"Socket connected to ss server: {_server}");
  418. TimeSpan latency = DateTime.Now - _startConnectTime;
  419. OnConnected?.Invoke(this, new SSTCPConnectedEventArgs(_server, latency));
  420. }
  421. private async Task SendAddress(EndPoint dest)
  422. {
  423. byte[] dstByte = GetSocks5EndPointByte(dest);
  424. using var t = pool.Rent(512);
  425. try
  426. {
  427. int addrlen = encryptor.Encrypt(dstByte, t.Memory.Span);
  428. await _remote.SendAsync(t.Memory.Slice(0, addrlen));
  429. }
  430. catch (Exception e)
  431. {
  432. ErrorClose(e);
  433. }
  434. }
  435. private byte[] GetSocks5EndPointByte(EndPoint dest)
  436. {
  437. if (dest is DnsEndPoint d)
  438. {
  439. byte[] r = new byte[d.Host.Length + 4];
  440. r[0] = 3;
  441. r[1] = (byte)d.Host.Length;
  442. Encoding.ASCII.GetBytes(d.Host, r.AsSpan(2));
  443. r[^2] = (byte)(d.Port / 256);
  444. r[^1] = (byte)(d.Port % 256);
  445. return r;
  446. }
  447. else if (dest is IPEndPoint i)
  448. {
  449. if (i.AddressFamily == AddressFamily.InterNetwork)
  450. {
  451. byte[] r = new byte[7];
  452. r[0] = 1;
  453. i.Address.GetAddressBytes().CopyTo(r, 1);
  454. r[^2] = (byte)(i.Port / 256);
  455. r[^1] = (byte)(i.Port % 256);
  456. return r;
  457. }
  458. else if (i.AddressFamily == AddressFamily.InterNetworkV6)
  459. {
  460. byte[] r = new byte[19];
  461. r[0] = 1;
  462. i.Address.GetAddressBytes().CopyTo(r, 1);
  463. r[^2] = (byte)(i.Port / 256);
  464. r[^1] = (byte)(i.Port % 256);
  465. return r;
  466. }
  467. }
  468. throw new NotImplementedException();
  469. }
  470. private async Task Forward()
  471. {
  472. try
  473. {
  474. await Task.WhenAll(ForwardInbound(), ForwardOutbound());
  475. Close();
  476. }
  477. catch (Exception e)
  478. {
  479. ErrorClose(e);
  480. }
  481. }
  482. private async Task ForwardInbound()
  483. {
  484. using var cipherOwner = pool.Rent(RecvSize);
  485. using var plainOwner = pool.Rent(SendSize);
  486. var plain = plainOwner.Memory;
  487. var cipher = cipherOwner.Memory;
  488. try
  489. {
  490. while (true)
  491. {
  492. int len = await _remote.ReceiveAsync(cipher);
  493. if (len == 0) break;
  494. int plen = decryptor.Decrypt(plain.Span, cipher.Span.Slice(0, len));
  495. if (plen == 0) continue;
  496. int len2 = await _connection.SendAsync(plain.Slice(0, plen), SocketFlags.None);
  497. if (len2 == 0) break;
  498. OnInbound?.Invoke(this, new SSTransmitEventArgs(_server, plen));
  499. }
  500. }
  501. catch (Exception e)
  502. {
  503. ErrorClose(e);
  504. }
  505. }
  506. private async Task ForwardOutbound()
  507. {
  508. using var plainOwner = pool.Rent(RecvSize);
  509. using var cipherOwner = pool.Rent(SendSize);
  510. var plain = plainOwner.Memory;
  511. var cipher = cipherOwner.Memory;
  512. while (true)
  513. {
  514. int len = await _connection.ReceiveAsync(plain, SocketFlags.None);
  515. if (len == 0) break;
  516. int clen = encryptor.Encrypt(plain.Span.Slice(0, len), cipher.Span);
  517. int len2 = await _remote.SendAsync(cipher.Slice(0, clen));
  518. if (len2 == 0) break;
  519. OnOutbound?.Invoke(this, new SSTransmitEventArgs(_server, len));
  520. }
  521. _remote.Shutdown(SocketShutdown.Send);
  522. }
  523. }
  524. }