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