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 8.3 kB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
6 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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. namespace Shadowsocks.Controller
  10. {
  11. class UDPRelay : Listener.Service
  12. {
  13. private ShadowsocksController _controller;
  14. // TODO: choose a smart number
  15. private LRUCache<IPEndPoint, UDPHandler> _cache = new LRUCache<IPEndPoint, UDPHandler>(512);
  16. public long outbound = 0;
  17. public long inbound = 0;
  18. public UDPRelay(ShadowsocksController controller)
  19. {
  20. this._controller = controller;
  21. }
  22. public override bool Handle(byte[] firstPacket, int length, Socket socket, object state)
  23. {
  24. if (socket.ProtocolType != ProtocolType.Udp)
  25. {
  26. return false;
  27. }
  28. if (length < 4)
  29. {
  30. return false;
  31. }
  32. Listener.UDPState udpState = (Listener.UDPState)state;
  33. IPEndPoint remoteEndPoint = (IPEndPoint)udpState.remoteEndPoint;
  34. UDPHandler handler = _cache.get(remoteEndPoint);
  35. if (handler == null)
  36. {
  37. handler = new UDPHandler(socket, _controller.GetAServer(IStrategyCallerType.UDP, remoteEndPoint, null/*TODO: fix this*/), remoteEndPoint);
  38. handler.Receive();
  39. _cache.add(remoteEndPoint, handler);
  40. }
  41. handler.Send(firstPacket, length);
  42. return true;
  43. }
  44. public class UDPHandler
  45. {
  46. private Socket _local;
  47. private Socket _remote;
  48. private Server _server;
  49. private byte[] _buffer = new byte[65536];
  50. private IPEndPoint _localEndPoint;
  51. private IPEndPoint _remoteEndPoint;
  52. private IPAddress GetIPAddress()
  53. {
  54. switch (_remote.AddressFamily)
  55. {
  56. case AddressFamily.InterNetwork:
  57. return IPAddress.Any;
  58. case AddressFamily.InterNetworkV6:
  59. return IPAddress.IPv6Any;
  60. default:
  61. return IPAddress.Any;
  62. }
  63. }
  64. public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint)
  65. {
  66. _local = local;
  67. _server = server;
  68. _localEndPoint = localEndPoint;
  69. // TODO async resolving
  70. IPAddress ipAddress;
  71. bool parsed = IPAddress.TryParse(server.server, out ipAddress);
  72. if (!parsed)
  73. {
  74. IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server);
  75. ipAddress = ipHostInfo.AddressList[0];
  76. }
  77. _remoteEndPoint = new IPEndPoint(ipAddress, server.server_port);
  78. _remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
  79. _remote.Bind(new IPEndPoint(GetIPAddress(), 0));
  80. }
  81. public void Send(byte[] data, int length)
  82. {
  83. IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password);
  84. byte[] dataIn = new byte[length - 3];
  85. Array.Copy(data, 3, dataIn, 0, length - 3);
  86. byte[] dataOut = new byte[65536]; // enough space for AEAD ciphers
  87. int outlen;
  88. encryptor.EncryptUDP(dataIn, length - 3, dataOut, out outlen);
  89. Logging.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay");
  90. _remote?.SendTo(dataOut, outlen, SocketFlags.None, _remoteEndPoint);
  91. }
  92. public void Receive()
  93. {
  94. EndPoint remoteEndPoint = new IPEndPoint(GetIPAddress(), 0);
  95. Logging.Debug($"++++++Receive Server Port, size:" + _buffer.Length);
  96. _remote?.BeginReceiveFrom(_buffer, 0, _buffer.Length, 0, ref remoteEndPoint, new AsyncCallback(RecvFromCallback), null);
  97. }
  98. public void RecvFromCallback(IAsyncResult ar)
  99. {
  100. try
  101. {
  102. if (_remote == null) return;
  103. EndPoint remoteEndPoint = new IPEndPoint(GetIPAddress(), 0);
  104. int bytesRead = _remote.EndReceiveFrom(ar, ref remoteEndPoint);
  105. byte[] dataOut = new byte[bytesRead];
  106. int outlen;
  107. IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password);
  108. encryptor.DecryptUDP(_buffer, bytesRead, dataOut, out outlen);
  109. byte[] sendBuf = new byte[outlen + 3];
  110. Array.Copy(dataOut, 0, sendBuf, 3, outlen);
  111. Logging.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay");
  112. _local?.SendTo(sendBuf, outlen + 3, 0, _localEndPoint);
  113. Receive();
  114. }
  115. catch (ObjectDisposedException)
  116. {
  117. // TODO: handle the ObjectDisposedException
  118. }
  119. catch (Exception)
  120. {
  121. // TODO: need more think about handle other Exceptions, or should remove this catch().
  122. }
  123. finally
  124. {
  125. // No matter success or failed, we keep receiving
  126. }
  127. }
  128. public void Close()
  129. {
  130. try
  131. {
  132. _remote?.Close();
  133. }
  134. catch (ObjectDisposedException)
  135. {
  136. // TODO: handle the ObjectDisposedException
  137. }
  138. catch (Exception)
  139. {
  140. // TODO: need more think about handle other Exceptions, or should remove this catch().
  141. }
  142. }
  143. }
  144. }
  145. #region LRU cache
  146. // cc by-sa 3.0 http://stackoverflow.com/a/3719378/1124054
  147. class LRUCache<K, V> where V : UDPRelay.UDPHandler
  148. {
  149. private int capacity;
  150. private Dictionary<K, LinkedListNode<LRUCacheItem<K, V>>> cacheMap = new Dictionary<K, LinkedListNode<LRUCacheItem<K, V>>>();
  151. private LinkedList<LRUCacheItem<K, V>> lruList = new LinkedList<LRUCacheItem<K, V>>();
  152. public LRUCache(int capacity)
  153. {
  154. this.capacity = capacity;
  155. }
  156. [MethodImpl(MethodImplOptions.Synchronized)]
  157. public V get(K key)
  158. {
  159. LinkedListNode<LRUCacheItem<K, V>> node;
  160. if (cacheMap.TryGetValue(key, out node))
  161. {
  162. V value = node.Value.value;
  163. lruList.Remove(node);
  164. lruList.AddLast(node);
  165. return value;
  166. }
  167. return default(V);
  168. }
  169. [MethodImpl(MethodImplOptions.Synchronized)]
  170. public void add(K key, V val)
  171. {
  172. if (cacheMap.Count >= capacity)
  173. {
  174. RemoveFirst();
  175. }
  176. LRUCacheItem<K, V> cacheItem = new LRUCacheItem<K, V>(key, val);
  177. LinkedListNode<LRUCacheItem<K, V>> node = new LinkedListNode<LRUCacheItem<K, V>>(cacheItem);
  178. lruList.AddLast(node);
  179. cacheMap.Add(key, node);
  180. }
  181. private void RemoveFirst()
  182. {
  183. // Remove from LRUPriority
  184. LinkedListNode<LRUCacheItem<K, V>> node = lruList.First;
  185. lruList.RemoveFirst();
  186. // Remove from cache
  187. cacheMap.Remove(node.Value.key);
  188. node.Value.value.Close();
  189. }
  190. }
  191. class LRUCacheItem<K, V>
  192. {
  193. public LRUCacheItem(K k, V v)
  194. {
  195. key = k;
  196. value = v;
  197. }
  198. public K key;
  199. public V value;
  200. }
  201. #endregion
  202. }