diff --git a/Shadowsocks.Net/Crypto/AEAD/AEADCrypto.cs b/Shadowsocks.Net/Crypto/AEAD/AEADCrypto.cs index 201012ad..9ac79f2c 100644 --- a/Shadowsocks.Net/Crypto/AEAD/AEADCrypto.cs +++ b/Shadowsocks.Net/Crypto/AEAD/AEADCrypto.cs @@ -1,5 +1,6 @@ using Shadowsocks.Net.Crypto.Exception; using Shadowsocks.Net.Crypto.Stream; +using Splat; using System; using System.Collections.Generic; using System.Net; @@ -8,9 +9,8 @@ using System.Text; namespace Shadowsocks.Net.Crypto.AEAD { - public abstract class AEADCrypto : CryptoBase + public abstract class AEADCrypto : CryptoBase, IEnableLogger { - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); // We are using the same saltLen and keyLen private const string Info = "ss-subkey"; private static readonly byte[] InfoBytes = Encoding.ASCII.GetBytes(Info); @@ -60,8 +60,8 @@ namespace Shadowsocks.Net.Crypto.AEAD // Initialize all-zero nonce for each connection nonce = new byte[nonceLen]; - logger.Dump($"masterkey {instanceId}", masterKey, keyLen); - logger.Dump($"nonce {instanceId}", nonce, keyLen); + this.Log().Debug($"masterkey {instanceId} {masterKey} {keyLen}"); + this.Log().Debug($"nonce {instanceId} {nonce} {keyLen}"); } protected abstract Dictionary GetCiphers(); @@ -92,8 +92,8 @@ namespace Shadowsocks.Net.Crypto.AEAD CryptoUtils.HKDF(keyLen, masterKey, salt, InfoBytes).CopyTo(sessionKey, 0); - logger.Dump($"salt {instanceId}", salt, saltLen); - logger.Dump($"sessionkey {instanceId}", sessionKey, keyLen); + this.Log().Debug($"salt {instanceId}", salt, saltLen); + this.Log().Debug($"sessionkey {instanceId}", sessionKey, keyLen); } public abstract int CipherEncrypt(ReadOnlySpan plain, Span cipher); @@ -138,7 +138,7 @@ namespace Shadowsocks.Net.Crypto.AEAD // if not, keep buf for next run, at this condition, buffer is not empty if (outlength + ChunkOverhead > cipher.Length) { - logger.Debug("enc outbuf almost full, giving up"); + this.Log().Debug("enc outbuf almost full, giving up"); // write rest data to head of shared buffer tmp.CopyTo(buffer); @@ -150,7 +150,7 @@ namespace Shadowsocks.Net.Crypto.AEAD bufSize = tmp.Length; if (bufSize <= 0) { - logger.Debug("No more data to encrypt, leaving"); + this.Log().Debug("No more data to encrypt, leaving"); return outlength; } } @@ -165,7 +165,7 @@ namespace Shadowsocks.Net.Crypto.AEAD cipher.CopyTo(tmp.Slice(bufPtr)); int bufSize = tmp.Length; - logger.Debug($"{instanceId} decrypt tcp, read salt: {!saltReady}"); + this.Log().Debug($"{instanceId} decrypt tcp, read salt: {!saltReady}"); if (!saltReady) { // check if we get the leading salt @@ -191,7 +191,7 @@ namespace Shadowsocks.Net.Crypto.AEAD // check if we have any data if (bufSize <= 0) { - logger.Trace("No data in buffer"); + this.Log().Debug("No data in buffer"); return outlength; } @@ -200,23 +200,23 @@ namespace Shadowsocks.Net.Crypto.AEAD { // so we only have chunk length and its tag? // wait more - logger.Trace($"{instanceId} not enough data to decrypt chunk. write {tmp.Length} byte back to buffer."); + this.Log().Debug($"{instanceId} not enough data to decrypt chunk. write {tmp.Length} byte back to buffer."); tmp.CopyTo(buffer); bufPtr = tmp.Length; return outlength; } - logger.Trace($"{instanceId} try decrypt to offset {outlength}"); + this.Log().Debug($"{instanceId} try decrypt to offset {outlength}"); int len = ChunkDecrypt(plain.Slice(outlength), tmp); if (len <= 0) { - logger.Trace($"{instanceId} no chunk decrypted, write {tmp.Length} byte back to buffer."); + this.Log().Debug($"{instanceId} no chunk decrypted, write {tmp.Length} byte back to buffer."); // no chunk decrypted tmp.CopyTo(buffer); bufPtr = tmp.Length; return outlength; } - logger.Trace($"{instanceId} decrypted {len} to offset {outlength}"); + this.Log().Debug($"{instanceId} decrypted {len} to offset {outlength}"); // drop decrypted data tmp = tmp.Slice(ChunkLengthBytes + tagLen + len + tagLen); @@ -225,7 +225,7 @@ namespace Shadowsocks.Net.Crypto.AEAD // logger.Debug("aead dec outlength " + outlength); if (outlength + ChunkOverhead > cipher.Length) { - logger.Trace($"{instanceId} output almost full, write {tmp.Length} byte back to buffer."); + this.Log().Debug($"{instanceId} output almost full, write {tmp.Length} byte back to buffer."); tmp.CopyTo(buffer); bufPtr = tmp.Length; return outlength; @@ -235,7 +235,7 @@ namespace Shadowsocks.Net.Crypto.AEAD if (bufSize <= 0) { bufPtr = 0; - logger.Debug($"{instanceId} no data in buffer, already all done"); + this.Log().Debug($"{instanceId} no data in buffer, already all done"); return outlength; } } @@ -266,7 +266,7 @@ namespace Shadowsocks.Net.Crypto.AEAD { if (plain.Length > ChunkLengthMask) { - logger.Error("enc chunk too big"); + this.Log().Error("enc chunk too big"); throw new CryptoErrorException(); } @@ -289,14 +289,14 @@ namespace Shadowsocks.Net.Crypto.AEAD if (chunkLength > ChunkLengthMask) { // we get invalid chunk - logger.Error($"{instanceId} Invalid chunk length: {chunkLength}"); + this.Log().Error($"{instanceId} Invalid chunk length: {chunkLength}"); throw new CryptoErrorException(); } // logger.Debug("Get the real chunk len:" + chunkLength); int bufSize = cipher.Length; if (bufSize < ChunkLengthBytes + tagLen /* we haven't remove them */+ chunkLength + tagLen) { - logger.Debug($"{instanceId} need {ChunkLengthBytes + tagLen + chunkLength + tagLen}, but have {cipher.Length}"); + this.Log().Debug($"{instanceId} need {ChunkLengthBytes + tagLen + chunkLength + tagLen}, but have {cipher.Length}"); return 0; } CryptoUtils.SodiumIncrement(nonce); @@ -304,7 +304,7 @@ namespace Shadowsocks.Net.Crypto.AEAD // drop chunk len and its tag from buffer int len = CipherDecrypt(plain, cipher.Slice(ChunkLengthBytes + tagLen, chunkLength + tagLen)); CryptoUtils.SodiumIncrement(nonce); - logger.Trace($"{instanceId} decrypted {len} byte chunk used {ChunkLengthBytes + tagLen + chunkLength + tagLen} from {cipher.Length}"); + this.Log().Debug($"{instanceId} decrypted {len} byte chunk used {ChunkLengthBytes + tagLen + chunkLength + tagLen} from {cipher.Length}"); return len; } } diff --git a/Shadowsocks.Net/Crypto/Stream/StreamCrypto.cs b/Shadowsocks.Net/Crypto/Stream/StreamCrypto.cs index 385b404a..29b086fe 100644 --- a/Shadowsocks.Net/Crypto/Stream/StreamCrypto.cs +++ b/Shadowsocks.Net/Crypto/Stream/StreamCrypto.cs @@ -1,3 +1,4 @@ +using Splat; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -5,10 +6,8 @@ using System.Text; namespace Shadowsocks.Net.Crypto.Stream { - public abstract class StreamCrypto : CryptoBase + public abstract class StreamCrypto : CryptoBase, IEnableLogger { - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - // shared by TCP decrypt UDP encrypt and decrypt protected static byte[] sharedBuffer = new byte[65536]; @@ -34,7 +33,7 @@ namespace Shadowsocks.Net.Crypto.Stream InitKey(password); - logger.Dump($"key {instanceId}", key, keyLen); + this.Log().Debug($"key {instanceId} {key} {keyLen}"); } protected abstract Dictionary GetCiphers(); @@ -93,7 +92,7 @@ namespace Shadowsocks.Net.Crypto.Stream public override int Encrypt(ReadOnlySpan plain, Span cipher) { int cipherOffset = 0; - logger.Trace($"{instanceId} encrypt TCP, generate iv: {!ivReady}"); + this.Log().Debug($"{instanceId} encrypt TCP, generate iv: {!ivReady}"); if (!ivReady) { // Generate IV @@ -106,9 +105,9 @@ namespace Shadowsocks.Net.Crypto.Stream } int clen = CipherEncrypt(plain, cipher); - logger.DumpBase64($"plain {instanceId}", plain); - logger.DumpBase64($"cipher {instanceId}", cipher.Slice(0, clen)); - logger.Dump($"iv {instanceId}", iv, ivLen); + this.Log().Debug($"plain {instanceId} {Convert.ToBase64String(plain)}"); + this.Log().Debug($"cipher {instanceId} {Convert.ToBase64String(cipher.Slice(0, clen))}"); + this.Log().Debug($"iv {instanceId} {iv} {ivLen}"); return clen + cipherOffset; } @@ -116,7 +115,7 @@ namespace Shadowsocks.Net.Crypto.Stream [MethodImpl(MethodImplOptions.Synchronized)] public override int Decrypt(Span plain, ReadOnlySpan cipher) { - logger.Trace($"{instanceId} decrypt TCP, read iv: {!ivReady}"); + this.Log().Debug($"{instanceId} decrypt TCP, read iv: {!ivReady}"); int cipherOffset = 0; // is first packet, need read iv @@ -149,9 +148,9 @@ namespace Shadowsocks.Net.Crypto.Stream // read all data from buffer int len = CipherDecrypt(plain, cipher.Slice(cipherOffset)); - logger.DumpBase64($"cipher {instanceId}", cipher.Slice(cipherOffset)); - logger.DumpBase64($"plain {instanceId}", plain.Slice(0, len)); - logger.Dump($"iv {instanceId}", iv, ivLen); + this.Log().Debug($"cipher {instanceId} {Convert.ToBase64String(cipher.Slice(cipherOffset))}"); + this.Log().Debug($"plain {instanceId} {Convert.ToBase64String(plain.Slice(0, len))}"); + this.Log().Debug($"iv {instanceId} {iv} {ivLen}"); return len; } diff --git a/Shadowsocks.Net/Proxy/HttpProxy.cs b/Shadowsocks.Net/Proxy/HttpProxy.cs index c7e88332..126ef2f9 100644 --- a/Shadowsocks.Net/Proxy/HttpProxy.cs +++ b/Shadowsocks.Net/Proxy/HttpProxy.cs @@ -1,3 +1,4 @@ +using Splat; using System; using System.Net; using System.Net.Sockets; @@ -5,14 +6,11 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using NLog; namespace Shadowsocks.Net.Proxy { - public class HttpProxy : IProxy + public class HttpProxy : IProxy, IEnableLogger { - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - public EndPoint LocalEndPoint => _remote.LocalEndPoint; public EndPoint ProxyEndPoint { get; private set; } public EndPoint DestEndPoint { get; private set; } @@ -45,7 +43,7 @@ namespace Shadowsocks.Net.Proxy private bool OnLineRead(string line, object state) { - logger.Trace(line); + this.Log().Debug(line); if (_respondLineCount == 0) { diff --git a/Shadowsocks.Net/Shadowsocks.Net.csproj b/Shadowsocks.Net/Shadowsocks.Net.csproj index 7e0a2c6c..cc75b0b7 100644 --- a/Shadowsocks.Net/Shadowsocks.Net.csproj +++ b/Shadowsocks.Net/Shadowsocks.Net.csproj @@ -7,6 +7,11 @@ + + + + + diff --git a/Shadowsocks.Net/TCPListener.cs b/Shadowsocks.Net/TCPListener.cs index 34e3f69b..04c78e40 100644 --- a/Shadowsocks.Net/TCPListener.cs +++ b/Shadowsocks.Net/TCPListener.cs @@ -1,4 +1,4 @@ -using NLog; +using Splat; using System; using System.Collections.Generic; using System.Linq; @@ -28,10 +28,8 @@ namespace Shadowsocks.Net public virtual void Stop() { } } - public class TCPListener + public class TCPListener : IEnableLogger { - private static Logger logger = LogManager.GetCurrentClassLogger(); - public class UDPState { public UDPState(Socket s) @@ -44,15 +42,13 @@ namespace Shadowsocks.Net public EndPoint remoteEndPoint; } - Configuration _config; - bool _shareOverLAN; + IPEndPoint _localEndPoint; Socket _tcpSocket; IEnumerable _services; - public TCPListener(Configuration config, IEnumerable services) + public TCPListener(IPEndPoint localEndPoint, IEnumerable services) { - _config = config; - _shareOverLAN = config.shareOverLan; + _localEndPoint = localEndPoint; _services = services; } @@ -64,28 +60,22 @@ namespace Shadowsocks.Net public void Start() { - if (CheckIfPortInUse(_config.localPort)) - { - throw new Exception(I18N.GetString("Port {0} already in use", this._config.localPort)); - } + if (CheckIfPortInUse(_localEndPoint.Port)) + throw new Exception($"Port {_localEndPoint.Port} already in use"); try { // Create a TCP/IP socket. - _tcpSocket = new Socket(_config.isIPv6Enabled ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _tcpSocket = new Socket(_localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - IPEndPoint localEndPoint = null; - localEndPoint = _shareOverLAN - ? new IPEndPoint(_config.isIPv6Enabled ? IPAddress.IPv6Any : IPAddress.Any, this._config.localPort) - : new IPEndPoint(_config.isIPv6Enabled ? IPAddress.IPv6Loopback : IPAddress.Loopback, this._config.localPort); // Bind the socket to the local endpoint and listen for incoming connections. - _tcpSocket.Bind(localEndPoint); + _tcpSocket.Bind(_localEndPoint); _tcpSocket.Listen(1024); // Start an asynchronous socket to listen for connections. - logger.Info($"Shadowsocks started TCP ({UpdateChecker.Version})"); - logger.Debug(Encryption.EncryptorFactory.DumpRegisteredEncryptor()); + this.Log().Info($"Shadowsocks started TCP"); + this.Log().Debug(Crypto.CryptoFactory.DumpRegisteredEncryptor()); _tcpSocket.BeginAccept(new AsyncCallback(AcceptCallback), _tcpSocket); } catch (SocketException) @@ -126,7 +116,7 @@ namespace Shadowsocks.Net } catch (Exception e) { - logger.LogUsefulException(e); + this.Log().Error(e, ""); } finally { @@ -142,7 +132,7 @@ namespace Shadowsocks.Net } catch (Exception e) { - logger.LogUsefulException(e); + this.Log().Error(e, ""); } } } @@ -177,7 +167,7 @@ namespace Shadowsocks.Net } catch (Exception e) { - logger.LogUsefulException(e); + this.Log().Error(e, ""); conn.Close(); } } diff --git a/Shadowsocks.Net/TCPRelay.cs b/Shadowsocks.Net/TCPRelay.cs index c288f9d8..713f4c6d 100644 --- a/Shadowsocks.Net/TCPRelay.cs +++ b/Shadowsocks.Net/TCPRelay.cs @@ -1,45 +1,36 @@ +using Splat; +using Shadowsocks.Net.Crypto; +using Shadowsocks.Net.Crypto.AEAD; +using Shadowsocks.Net.Proxy; using System; using System.Buffers; using System.Collections.Generic; -using System.Diagnostics; using System.Net; using System.Net.Sockets; -using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; -using NLog; - -using Shadowsocks.Controller.Strategy; -using Shadowsocks.Net.Crypto; -using Shadowsocks.Net.Crypto.AEAD; -using Shadowsocks.Model; -using Shadowsocks.Net.Proxy; -using Shadowsocks.Net.Sockets; - using static Shadowsocks.Net.Crypto.CryptoBase; +using Shadowsocks.Models; namespace Shadowsocks.Net { - class TCPRelay : StreamService + class TCPRelay : StreamService, IEnableLogger { public event EventHandler OnConnected; public event EventHandler OnInbound; public event EventHandler OnOutbound; public event EventHandler OnFailed; - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - private readonly ShadowsocksController _controller; + private Server _server; private DateTime _lastSweepTime; - private readonly Configuration _config; public ISet Handlers { get; set; } - public TCPRelay(ShadowsocksController controller, Configuration conf) + public TCPRelay(Server server) { - _controller = controller; - _config = conf; + _server = server; Handlers = new HashSet(); _lastSweepTime = DateTime.Now; } @@ -58,7 +49,7 @@ namespace Shadowsocks.Net socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); - TCPHandler handler = new TCPHandler(_controller, _config, socket); + TCPHandler handler = new TCPHandler(_server, socket); IList handlersToClose = new List(); lock (Handlers) @@ -75,7 +66,7 @@ namespace Shadowsocks.Net } foreach (TCPHandler handler1 in handlersToClose) { - logger.Debug("Closing timed out TCP connection."); + this.Log().Debug("Closing timed out TCP connection."); handler1.Close(); } @@ -102,7 +93,7 @@ namespace Shadowsocks.Net } socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); - TCPHandler handler = new TCPHandler(_controller, _config, socket); + TCPHandler handler = new TCPHandler(_server, socket); handler.OnConnected += OnConnected; handler.OnInbound += OnInbound; @@ -135,7 +126,7 @@ namespace Shadowsocks.Net } foreach (TCPHandler handler1 in handlersToClose) { - logger.Debug("Closing timed out TCP connection."); + this.Log().Debug("Closing timed out TCP connection."); handler1.Close(); } @@ -191,7 +182,7 @@ namespace Shadowsocks.Net } } - internal class TCPHandler + internal class TCPHandler : IEnableLogger { public event EventHandler OnConnected; public event EventHandler OnInbound; @@ -199,8 +190,6 @@ namespace Shadowsocks.Net public event EventHandler OnClosed; public event EventHandler OnFailed; - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private readonly int _serverTimeout; private readonly int _proxyTimeout; @@ -216,14 +205,14 @@ namespace Shadowsocks.Net public DateTime lastActivity; - private readonly ShadowsocksController _controller; - private readonly ForwardProxyConfig _config; + // TODO: forward proxy + //private readonly ForwardProxyConfig _config; + private readonly Server _server; private readonly Socket _connection; private IProxy _remote; - private IEncryptor encryptor; + private ICrypto encryptor; // workaround - private IEncryptor decryptor; - private Server _server; + private ICrypto decryptor; private byte[] _firstPacket; private int _firstPacketLength; @@ -240,28 +229,25 @@ namespace Shadowsocks.Net private readonly object _closeConnLock = new object(); // TODO: decouple controller - public TCPHandler(ShadowsocksController controller, Configuration config, Socket socket) + public TCPHandler(Server server, Socket socket) { - _controller = controller; - _config = config.proxy; + _server = server; _connection = socket; - _proxyTimeout = config.proxy.proxyTimeout * 1000; - _serverTimeout = config.GetCurrentServer().timeout * 1000; + _proxyTimeout = 5000; + _serverTimeout = 5000; lastActivity = DateTime.Now; } public void CreateRemote(EndPoint destination) { - Server server = _controller.GetAServer(IStrategyCallerType.TCP, (IPEndPoint)_connection.RemoteEndPoint, destination); - if (server == null || server.server == "") + if (_server == null || _server.Host == "") { throw new ArgumentException("No server configured"); } - encryptor = EncryptorFactory.GetEncryptor(server.method, server.password); - decryptor = EncryptorFactory.GetEncryptor(server.method, server.password); - _server = server; + encryptor = CryptoFactory.GetEncryptor(_server.Method, _server.Password); + decryptor = CryptoFactory.GetEncryptor(_server.Method, _server.Password); } public async Task StartAsync(byte[] firstPacket, int length) @@ -283,7 +269,7 @@ namespace Shadowsocks.Net private void ErrorClose(Exception e) { - Logger.LogUsefulException(e); + this.Log().Error(e, ""); Close(); } @@ -308,7 +294,7 @@ namespace Shadowsocks.Net } catch (Exception e) { - Logger.LogUsefulException(e); + this.Log().Error(e, ""); } } @@ -330,7 +316,7 @@ namespace Shadowsocks.Net { // reject socks 4 response = new byte[] { 0, 91 }; - Logger.Error("socks 5 protocol error"); + this.Log().Error("socks5 protocol error"); } await _connection.SendAsync(response, SocketFlags.None); @@ -452,11 +438,12 @@ namespace Shadowsocks.Net CreateRemote(destination); IProxy remote; EndPoint proxyEP = null; - EndPoint serverEP = new DnsEndPoint(_server.server, _server.server_port); - EndPoint pluginEP = _controller.GetPluginLocalEndPointIfConfigured(_server); + EndPoint serverEP = new DnsEndPoint(_server.Host, _server.Port); + EndPoint pluginEP = null; // TODO: plugin local end point + remote = new DirectConnect(); // TODO: forward proxy NetworkCredential auth = null; - if (_config.useAuth) + /*if (_config.useAuth) { auth = new NetworkCredential(_config.authUser, _config.authPwd); } @@ -478,8 +465,7 @@ namespace Shadowsocks.Net else { remote = new DirectConnect(); - } - + }*/ CancellationTokenSource cancelProxy = new CancellationTokenSource(_proxyTimeout * 1000); @@ -488,13 +474,13 @@ namespace Shadowsocks.Net if (!(remote is DirectConnect)) { - Logger.Debug($"Socket connected to proxy {remote.ProxyEndPoint}"); + this.Log().Debug($"Socket connected to proxy {remote.ProxyEndPoint}"); } var _startConnectTime = DateTime.Now; CancellationTokenSource cancelServer = new CancellationTokenSource(_serverTimeout * 1000); await remote.ConnectRemoteAsync(serverEP, cancelServer.Token); - Logger.Debug($"Socket connected to ss server: {_server}"); + this.Log().Debug($"Socket connected to ss server: {_server}"); TimeSpan latency = DateTime.Now - _startConnectTime; OnConnected?.Invoke(this, new SSTCPConnectedEventArgs(_server, latency)); diff --git a/Shadowsocks.Net/UDPListener.cs b/Shadowsocks.Net/UDPListener.cs index 0ed972fe..f2030632 100644 --- a/Shadowsocks.Net/UDPListener.cs +++ b/Shadowsocks.Net/UDPListener.cs @@ -1,4 +1,5 @@ -using System; +using Splat; +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -6,10 +7,8 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; -using NLog; -using Shadowsocks.Model; -namespace Shadowsocks.Controller +namespace Shadowsocks.Net { public interface IDatagramService { @@ -25,10 +24,8 @@ namespace Shadowsocks.Controller public virtual void Stop() { } } - public class UDPListener + public class UDPListener : IEnableLogger { - private static Logger logger = LogManager.GetCurrentClassLogger(); - public class UDPState { public UDPState(Socket s) @@ -41,18 +38,15 @@ namespace Shadowsocks.Controller public EndPoint remoteEndPoint; } - Configuration _config; - bool _shareOverLAN; + IPEndPoint _localEndPoint; Socket _udpSocket; IEnumerable _services; CancellationTokenSource tokenSource = new CancellationTokenSource(); - public UDPListener(Configuration config, IEnumerable services) + public UDPListener(IPEndPoint localEndPoint, IEnumerable services) { - this._config = config; - this._shareOverLAN = _config.shareOverLan; - - this._services = services; + _localEndPoint = localEndPoint; + _services = services; } private bool CheckIfPortInUse(int port) @@ -63,23 +57,19 @@ namespace Shadowsocks.Controller public void Start() { - if (CheckIfPortInUse(this._config.localPort)) - throw new Exception(I18N.GetString("Port {0} already in use", this._config.localPort)); + if (CheckIfPortInUse(_localEndPoint.Port)) + throw new Exception($"Port {_localEndPoint.Port} already in use"); // Create a TCP/IP socket. - _udpSocket = new Socket(_config.isIPv6Enabled ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + _udpSocket = new Socket(_localEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); _udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - IPEndPoint localEndPoint = null; - localEndPoint = _shareOverLAN - ? new IPEndPoint(_config.isIPv6Enabled ? IPAddress.IPv6Any : IPAddress.Any, this._config.localPort) - : new IPEndPoint(_config.isIPv6Enabled ? IPAddress.IPv6Loopback : IPAddress.Loopback, this._config.localPort); // Bind the socket to the local endpoint and listen for incoming connections. - _udpSocket.Bind(localEndPoint); + _udpSocket.Bind(_localEndPoint); // Start an asynchronous socket to listen for connections. - logger.Info($"Shadowsocks started UDP ({UpdateChecker.Version})"); - logger.Debug(Encryption.EncryptorFactory.DumpRegisteredEncryptor()); + this.Log().Info($"Shadowsocks started UDP"); + this.Log().Debug(Crypto.CryptoFactory.DumpRegisteredEncryptor()); UDPState udpState = new UDPState(_udpSocket); // _udpSocket.BeginReceiveFrom(udpState.buffer, 0, udpState.buffer.Length, 0, ref udpState.remoteEndPoint, new AsyncCallback(RecvFromCallback), udpState); Task.Run(() => WorkLoop(tokenSource.Token)); diff --git a/Shadowsocks.Net/UDPRelay.cs b/Shadowsocks.Net/UDPRelay.cs index cd2e317f..4f6e8be0 100644 --- a/Shadowsocks.Net/UDPRelay.cs +++ b/Shadowsocks.Net/UDPRelay.cs @@ -1,3 +1,6 @@ +using Shadowsocks.Models; +using Shadowsocks.Net.Crypto; +using Splat; using System; using System.Buffers; using System.Collections.Generic; @@ -6,24 +9,21 @@ using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks; -using NLog; -using Shadowsocks.Net.Crypto; -namespace Shadowsocks.Controller +namespace Shadowsocks.Net { class UDPRelay : DatagramService { - private ShadowsocksController _controller; - + Server _server; // TODO: choose a smart number private LRUCache _cache = new LRUCache(512); public long outbound = 0; public long inbound = 0; - public UDPRelay(ShadowsocksController controller) + public UDPRelay(Server server) { - this._controller = controller; + _server = server; } public override async Task Handle(Memory packet, Socket socket, EndPoint client) @@ -40,7 +40,7 @@ namespace Shadowsocks.Controller UDPHandler handler = _cache.get(remoteEndPoint); if (handler == null) { - handler = new UDPHandler(socket, _controller.GetAServer(IStrategyCallerType.UDP, remoteEndPoint, null/*TODO: fix this*/), remoteEndPoint); + handler = new UDPHandler(socket, _server, remoteEndPoint); handler.Receive(); _cache.add(remoteEndPoint, handler); } @@ -48,9 +48,8 @@ namespace Shadowsocks.Controller return true; } - public class UDPHandler + public class UDPHandler : IEnableLogger { - private static Logger logger = LogManager.GetCurrentClassLogger(); private static MemoryPool pool = MemoryPool.Shared; private Socket _local; private Socket _remote; @@ -81,25 +80,25 @@ namespace Shadowsocks.Controller _localEndPoint = localEndPoint; // TODO async resolving - bool parsed = IPAddress.TryParse(server.server, out IPAddress ipAddress); + bool parsed = IPAddress.TryParse(server.Host, out IPAddress ipAddress); if (!parsed) { - IPHostEntry ipHostInfo = Dns.GetHostEntry(server.server); + IPHostEntry ipHostInfo = Dns.GetHostEntry(server.Host); ipAddress = ipHostInfo.AddressList[0]; } - _remoteEndPoint = new IPEndPoint(ipAddress, server.server_port); + _remoteEndPoint = new IPEndPoint(ipAddress, server.Port); _remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); _remote.Bind(new IPEndPoint(ListenAddress, 0)); } public async Task SendAsync(ReadOnlyMemory data) { - IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); + ICrypto encryptor = CryptoFactory.GetEncryptor(_server.Method, _server.Password); using IMemoryOwner mem = pool.Rent(data.Length + 1000); // byte[] dataOut = new byte[slicedData.Length + 1000]; int outlen = encryptor.EncryptUDP(data.Span[3..], mem.Memory.Span); - logger.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay up"); + this.Log().Debug($"{_localEndPoint} {_remoteEndPoint} {outlen} UDP Relay up"); if (!MemoryMarshal.TryGetArray(mem.Memory[..outlen], out ArraySegment outData)) { throw new InvalidOperationException("Can't extract underly array segment"); @@ -110,7 +109,7 @@ namespace Shadowsocks.Controller public async Task ReceiveAsync() { EndPoint remoteEndPoint = new IPEndPoint(ListenAddress, 0); - logger.Debug($"++++++Receive Server Port, size:" + _buffer.Length); + this.Log().Debug($"++++++Receive Server Port, size:" + _buffer.Length); try { while (true) @@ -121,9 +120,9 @@ namespace Shadowsocks.Controller using IMemoryOwner owner = pool.Rent(bytesRead + 3); Memory o = owner.Memory; - IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); + ICrypto encryptor = CryptoFactory.GetEncryptor(_server.Method, _server.Password); int outlen = encryptor.DecryptUDP(o.Span[3..], _buffer.AsSpan(0, bytesRead)); - logger.Debug(_remoteEndPoint, _localEndPoint, outlen, "UDP Relay down"); + this.Log().Debug($"{_remoteEndPoint} {_localEndPoint} {outlen} UDP Relay down"); if (!MemoryMarshal.TryGetArray(o[..(outlen + 3)], out ArraySegment data)) { throw new InvalidOperationException("Can't extract underly array segment"); @@ -134,7 +133,7 @@ namespace Shadowsocks.Controller } catch (Exception e) { - logger.LogUsefulException(e); + this.Log().Warn(e, ""); } }