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.

UDPRelay.cs 7.4 kB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using System.Runtime.CompilerServices;
  6. using Shadowsocks.Controller.Strategy;
  7. using Shadowsocks.Encryption;
  8. using Shadowsocks.Model;
  9. using Shadowsocks.Util;
  10. namespace Shadowsocks.Controller
  11. {
  12. class UDPRelay : Listener.Service
  13. {
  14. private ShadowsocksController _controller;
  15. private LRUCache<IPEndPoint, UDPHandler> _cache;
  16. public long outbound = 0;
  17. public long inbound = 0;
  18. public UDPRelay(ShadowsocksController controller)
  19. {
  20. this._controller = controller;
  21. this._cache = new LRUCache<IPEndPoint, UDPHandler>(512); // todo: choose a smart number
  22. }
  23. public bool Handle(byte[] firstPacket, int length, Socket socket, object state)
  24. {
  25. if (socket.ProtocolType != ProtocolType.Udp)
  26. {
  27. return false;
  28. }
  29. if (length < 4)
  30. {
  31. return false;
  32. }
  33. Listener.UDPState udpState = (Listener.UDPState)state;
  34. IPEndPoint remoteEndPoint = (IPEndPoint)udpState.remoteEndPoint;
  35. UDPHandler handler = _cache.get(remoteEndPoint);
  36. if (handler == null)
  37. {
  38. handler = new UDPHandler(socket, _controller.GetAServer(IStrategyCallerType.UDP, remoteEndPoint), remoteEndPoint);
  39. _cache.add(remoteEndPoint, handler);
  40. }
  41. handler.Send(firstPacket, length);
  42. handler.Receive();
  43. return true;
  44. }
  45. public class UDPHandler
  46. {
  47. private Socket _local;
  48. private Socket _remote;
  49. private Server _server;
  50. private byte[] _buffer = new byte[1500];
  51. private IPEndPoint _localEndPoint;
  52. private EndPoint _remoteEndPoint;
  53. public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint)
  54. {
  55. _local = local;
  56. _server = server;
  57. _localEndPoint = localEndPoint;
  58. _remoteEndPoint = SocketUtil.GetEndPoint(server.server, server.server_port);
  59. _remote = SocketUtil.CreateSocket(_remoteEndPoint, ProtocolType.Udp);
  60. }
  61. public void Send(byte[] data, int length)
  62. {
  63. IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password, _server.auth, true);
  64. byte[] dataIn = new byte[length - 3 + IVEncryptor.ONETIMEAUTH_BYTES];
  65. Array.Copy(data, 3, dataIn, 0, length - 3);
  66. byte[] dataOut = new byte[length - 3 + 16 + IVEncryptor.ONETIMEAUTH_BYTES];
  67. int outlen;
  68. encryptor.Encrypt(dataIn, length - 3, dataOut, out outlen);
  69. Logging.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay");
  70. _remote?.SendTo(dataOut, outlen, SocketFlags.None, _remoteEndPoint);
  71. }
  72. public void Receive()
  73. {
  74. EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
  75. Logging.Debug($"++++++Receive Server Port, size:" + _buffer.Length);
  76. _remote?.BeginReceiveFrom(_buffer, 0, _buffer.Length, 0, ref remoteEndPoint, new AsyncCallback(RecvFromCallback), null);
  77. }
  78. public void RecvFromCallback(IAsyncResult ar)
  79. {
  80. try
  81. {
  82. if (_remote == null) return;
  83. EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
  84. int bytesRead = _remote.EndReceiveFrom(ar, ref remoteEndPoint);
  85. byte[] dataOut = new byte[bytesRead];
  86. int outlen;
  87. IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password, _server.auth, true);
  88. encryptor.Decrypt(_buffer, bytesRead, dataOut, out outlen);
  89. byte[] sendBuf = new byte[outlen + 3];
  90. Array.Copy(dataOut, 0, sendBuf, 3, outlen);
  91. Logging.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay");
  92. _local?.SendTo(sendBuf, outlen + 3, 0, _localEndPoint);
  93. Receive();
  94. }
  95. catch (ObjectDisposedException)
  96. {
  97. // TODO: handle the ObjectDisposedException
  98. }
  99. catch (Exception)
  100. {
  101. // TODO: need more think about handle other Exceptions, or should remove this catch().
  102. }
  103. finally
  104. {
  105. }
  106. }
  107. public void Close()
  108. {
  109. try
  110. {
  111. _remote?.Close();
  112. }
  113. catch (ObjectDisposedException)
  114. {
  115. // TODO: handle the ObjectDisposedException
  116. }
  117. catch (Exception)
  118. {
  119. // TODO: need more think about handle other Exceptions, or should remove this catch().
  120. }
  121. finally
  122. {
  123. }
  124. }
  125. }
  126. }
  127. // cc by-sa 3.0 http://stackoverflow.com/a/3719378/1124054
  128. class LRUCache<K, V> where V : UDPRelay.UDPHandler
  129. {
  130. private int capacity;
  131. private Dictionary<K, LinkedListNode<LRUCacheItem<K, V>>> cacheMap = new Dictionary<K, LinkedListNode<LRUCacheItem<K, V>>>();
  132. private LinkedList<LRUCacheItem<K, V>> lruList = new LinkedList<LRUCacheItem<K, V>>();
  133. public LRUCache(int capacity)
  134. {
  135. this.capacity = capacity;
  136. }
  137. [MethodImpl(MethodImplOptions.Synchronized)]
  138. public V get(K key)
  139. {
  140. LinkedListNode<LRUCacheItem<K, V>> node;
  141. if (cacheMap.TryGetValue(key, out node))
  142. {
  143. V value = node.Value.value;
  144. lruList.Remove(node);
  145. lruList.AddLast(node);
  146. return value;
  147. }
  148. return default(V);
  149. }
  150. [MethodImpl(MethodImplOptions.Synchronized)]
  151. public void add(K key, V val)
  152. {
  153. if (cacheMap.Count >= capacity)
  154. {
  155. RemoveFirst();
  156. }
  157. LRUCacheItem<K, V> cacheItem = new LRUCacheItem<K, V>(key, val);
  158. LinkedListNode<LRUCacheItem<K, V>> node = new LinkedListNode<LRUCacheItem<K, V>>(cacheItem);
  159. lruList.AddLast(node);
  160. cacheMap.Add(key, node);
  161. }
  162. private void RemoveFirst()
  163. {
  164. // Remove from LRUPriority
  165. LinkedListNode<LRUCacheItem<K, V>> node = lruList.First;
  166. lruList.RemoveFirst();
  167. // Remove from cache
  168. cacheMap.Remove(node.Value.key);
  169. node.Value.value.Close();
  170. }
  171. }
  172. class LRUCacheItem<K, V>
  173. {
  174. public LRUCacheItem(K k, V v)
  175. {
  176. key = k;
  177. value = v;
  178. }
  179. public K key;
  180. public V value;
  181. }
  182. }