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.6 kB

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