public void Shutdown(SocketShutdown direction) { lock (_syncRoot) { if (direction == SocketShutdown.Send || direction == SocketShutdown.Both) { if (!MState.HasShutdown) { MState |= MyStreamState.LocalShutdown; var ls = lastSend; if (ls?.IsCompleted == false) { lastSend = NaiveUtils.RunAsyncTask(async() => { try { await ls; } catch (Exception) { ; } SendFin().Forget(); }); } else { SendFin().Forget(); } } } if (direction == SocketShutdown.Receive || direction == SocketShutdown.Both) { MState |= MyStreamState.RemoteShutdown; } } }
public override void Update(BytesSegment bs) { bs.CheckAsParameter(); var pos = (uint)bs.Offset; var end = pos + (uint)bs.Len; fixed(Context *ctx = &this.ctx) fixed(byte *bytes = bs.Bytes) { while (pos < end) { var remainningKeystream = KeystreamBufferSize - keystreamBufferPos; if (remainningKeystream == 0) { keystreamBufferPos = 0; remainningKeystream = KeystreamBufferSize; NextKeystreamBuffer(ctx); } var count = end - pos; count = count < remainningKeystream ? count : remainningKeystream; NaiveUtils.XorBytesUnsafe(ctx->keyStreamBuffer + keystreamBufferPos, bytes + pos, count); pos += count; keystreamBufferPos += count; } } }
public override void Update(BytesSegment bs) { bs.CheckAsParameter(); var pos = bs.Offset; var end = pos + bs.Len; var keyStreamBuf = this.keyStreamBuf; fixed(byte *bytes = bs.Bytes) { while (pos < end) { var remainningKeystream = KeystreamBufferSize - keystreamBufferPos; if (remainningKeystream == 0) { keystreamBufferPos = 0; remainningKeystream = KeystreamBufferSize; var ksb = keyStreamBuf; for (int i = 0; i < KsBlockCount; i++) { ksb[i] = counter; if (++counter.v1 == 0) { ++counter.v0; } Cipher.encrypt_64_128(keys, &ksb[i]); } } var count = end - pos; count = count < remainningKeystream ? count : remainningKeystream; NaiveUtils.XorBytesUnsafe((byte *)keyStreamBuf + keystreamBufferPos, bytes + pos, (uint32)count); pos += count; keystreamBufferPos += count; } } }
public override void Update(BytesSegment bs) { bs.CheckAsParameter(); var pos = bs.Offset; var end = pos + bs.Len; while (pos < end) { var remainningFeed = toBeFeedBack.Length - feedingPos; if (remainningFeed == 0) { feedingPos = 0; remainningFeed = toBeFeedBack.Length; EcbTransform.TransformBlock(toBeFeedBack, 0, toBeFeedBack.Length, feedingBack, 0); } var feedEnd = pos + remainningFeed; var thisBlockEnd = (feedEnd < end) ? feedEnd : end; var count = thisBlockEnd - pos; if (IsEncrypting) { NaiveUtils.XorBytes(feedingBack, feedingPos, bs.Bytes, pos, (uint)count); NaiveUtils.CopyBytes(bs.Bytes, pos, toBeFeedBack, feedingPos, count); } else { NaiveUtils.CopyBytes(bs.Bytes, pos, toBeFeedBack, feedingPos, count); NaiveUtils.XorBytes(feedingBack, feedingPos, bs.Bytes, pos, (uint)count); } pos += count; feedingPos += count; } }
protected override Task <int> ReadAsyncImpl(BytesSegment bs) { var e = readArgPool.GetValue(); var userToken = ((ReadUserToken)e.UserToken); var tcs = _unusedReadTcs ?? new TaskCompletionSource <int>(); _unusedReadTcs = null; userToken.tcs = tcs; var sw = userToken.sw = this; e.SetBuffer(bs.Bytes, bs.Offset, bs.Len); try { if (Socket.ReceiveAsync(e)) // if opearation not completed synchronously { return(tcs.Task); } } catch (Exception) { recycleReadArgs(e, userToken); throw; } var r = ReadCompleted(e, userToken, sw, out var ex); if (r < 0) { throw ex; } _unusedReadTcs = tcs; return(NaiveUtils.GetCachedTaskInt(r)); }
// HKDF_SHA1 // libsscrypto/hkdf.c mbedtls_hkdf public static byte[] GetAeadSubkey(byte[] key, byte[] salt, byte[] info, int outputLen) { byte[] prk; using (var h = new HMACSHA1(salt)) { prk = h.ComputeHash(key); } var N = outputLen / prk.Length; if (outputLen % prk.Length != 0) { N++; } var T = new byte[0]; var c = new byte[1]; var output = new byte[outputLen]; var cur = 0; using (var h = new HMACSHA1(prk)) { for (int i = 0; i < N; i++) { h.TransformBlock(T, 0, T.Length, T, 0); h.TransformBlock(info, 0, info.Length, info, 0); c[0] = (byte)i; T = h.TransformFinalBlock(c, 0, 1); NaiveUtils.CopyBytes(T, 0, output, cur, (i < N) ? T.Length : outputLen - cur); cur += T.Length; } } return(output); }
public override async Task <ConnectResult> ProtectedConnect(ConnectArgument arg) { var dest = arg.Dest; var baseResult = await ConnectHelper.Connect(this, server.WithDefaultPort(80), connect_timeout); if (!baseResult.Ok) { return(baseResult); } try { var dataStream = baseResult.Stream; var asStream = MyStream.ToStream(dataStream); var sw = new StringWriter(new StringBuilder(1024)); var destStr = dest.ToString(); HttpClient.WriteHttpRequestHeader(sw, "CONNECT", destStr, new Dictionary <string, string> { ["Host"] = destStr }); await dataStream.WriteAsync(NaiveUtils.GetUTF8Bytes(sw.ToString())); var responseStr = await NaiveUtils.ReadStringUntil(asStream, NaiveUtils.DoubleCRLFBytes); var sr = new StringReader(responseStr); var response = HttpClient.ReadHttpResponseHeader(sr); if (response.StatusCode != "200") { throw new Exception($"remote server response '{response.StatusCode} {response.ReasonPhrase}'"); } return(CreateConnectResultWithStream(dataStream)); } catch (Exception) { MyStream.CloseWithTimeout(baseResult.Stream); throw; } }
static void Update(byte *bytes, uint len, QWords128 *keyStreamBuf, ref uint keystreamBufferPos, ref QWords128 counter, Keys128128 keys) { while (len > 0) { var remainningKeystream = KeystreamBufferSize - keystreamBufferPos; if (remainningKeystream == 0) { keystreamBufferPos = 0; remainningKeystream = KeystreamBufferSize; var ksb = keyStreamBuf; for (uint i = 0; i < KsBlockCount; i += 4) { for (uint j = 0; j < 4; j++) { ksb[i + j] = counter; if (++counter.v1 == 0) { ++counter.v0; } } Cipher.encrypt_128_128_4blocks(keys, &ksb[i]); } } var count = len < remainningKeystream ? len : remainningKeystream; NaiveUtils.XorBytesUnsafe((byte *)keyStreamBuf + keystreamBufferPos, bytes, count); bytes += count; len -= count; keystreamBufferPos += count; } }
public async Task <int> _readAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (IsChunkedEncoding) { if (remainingChunkSize == -1) { throw new EndOfStreamException(); } if (remainingChunkSize == 0) { var str = await NaiveUtils.ReadStringUntil(baseStream, NaiveUtils.CRLFBytes, maxLength : 32, withPattern : false); remainingChunkSize = Convert.ToInt64(str, 16); if (remainingChunkSize == 0) { remainingChunkSize = -1; // EOF return(0); } } int bytesToRead = (int)Math.Min(count, remainingChunkSize); var ret = await baseStream.ReadAsync(buffer, offset, bytesToRead, cancellationToken).CAF(); if (ret == 0) { throw new DisconnectedException("unexpected EOF while reading chunked http request content."); } readedLength += ret; remainingChunkSize -= ret; if (remainingChunkSize == 0) { var read = 0; do // read CRLF { read += await baseStream.ReadAsync(new byte[2], read, 2 - read); } while (read < 2); } return(ret); } else { int bytesToRead = (int)(count < RemainingLength ? count : RemainingLength); if (bytesToRead > 0) { var ret = await baseStream.ReadAsync(buffer, offset, bytesToRead, cancellationToken).CAF(); if (ret == 0) { throw new DisconnectedException("unexpected EOF while reading http request content."); } readedLength += ret; return(ret); } else { return(0); } } }
public async Task <bool> ReadNextPartHeader() { if (IsReadingPart) { throw new InvalidOperationException("cannot read next part while IsReadingPart == true"); } if (!firstBoundaryRead) { await NaiveUtils.ReadStringUntil(BaseStream, Boundary, withPattern : false); Boundary = NaiveUtils.ConcatBytes(NaiveUtils.CRLFBytes, Boundary); firstBoundaryRead = true; } var twoBytes = new byte[2]; await myStream.ReadFullAsyncR(twoBytes); bool noMoreParts = false; if (twoBytes[0] == '-' && twoBytes[1] == '-') { noMoreParts = true; // read the last CRLF to buf await myStream.ReadFullAsyncR(twoBytes); } if (twoBytes[0] != '\r' || twoBytes[1] != '\n') { throw new Exception($"unexcepted data: {twoBytes[0]}({(char)twoBytes[0]}), {twoBytes[1]}({(char)twoBytes[1]})"); } if (noMoreParts) { return(false); } CurrentPartRawHeader = (await NaiveUtils.ReadStringUntil(BaseStream, NaiveUtils.DoubleCRLFBytes, withPattern: true)); var headers = CurrentPartRawHeader.Split(separator, StringSplitOptions.None); var i = 0; while (HttpConnection.ParseHeader(headers[i++], out var key, out var value)) { CurrentPartHeaders[key] = value; } var content_disposition = CurrentPartHeaders["Content-Disposition"]; var regexResult = re_Content_Disposition.Match(content_disposition); if (regexResult.Success == false) { throw new Exception("bad Content-Disposition"); } CurrentPartName = regexResult.Groups[1].Value; CurrentPartFileName = regexResult.Groups[2].Value; state = 0; _position = 0; IsReadingPart = true; return(true); }
public async Task HandshakeAsync(bool enterRecvLoop, Dictionary <string, string> addHeaders) { var wskey = Guid.NewGuid().ToString("D"); var headers = new Dictionary <string, string> { ["Upgrade"] = "websocket", ["Connection"] = "Upgrade", ["Sec-WebSocket-Version"] = "13", ["Sec-WebSocket-Key"] = wskey }; if (Host != null) { headers.Add("Host", Host); } if (addHeaders != null) { foreach (var item in addHeaders) { headers[item.Key] = item.Value; } } var strw = new StringWriter(new StringBuilder(1024)); HttpClient.WriteHttpRequestHeader(strw, "GET", Path, headers); await BaseStream.WriteAsync(NaiveUtils.GetUTF8Bytes(strw.ToString())); var responseString = await NaiveUtils.ReadStringUntil(BaseStream.ToStream(), NaiveUtils.DoubleCRLFBytes); HttpResponse response; try { response = HttpClient.ReadHttpResponseHeader(new StringReader(responseString)); } catch (Exception e) { throw new Exception("error parsing response:\n" + responseString, e); } var statusCode = response.StatusCode.Split(' ')[0]; if (statusCode == "101" && response.TestHeader("Connection", "Upgrade") && response.TestHeader("Upgrade", "websocket") && response.TestHeader("Sec-WebSocket-Accept", GetWebsocketAcceptKey(wskey)) ) { ConnectionState = States.Open; if (enterRecvLoop) { await recvLoopAsync(); } } else { throw new Exception($"websocket handshake failed ({response.StatusCode})"); } }
public static Task SendString(this IMsgStream ms, string str) { if (ms is IMsgStreamStringSupport isss) { return(isss.SendString(str)); } return(NaiveUtils.RunAsyncTask(async() => { var buf = NaiveUtils.GetUTF8Bytes_AllocFromPool(str); await ms.SendMsg(new BytesView(buf.Bytes, 0, buf.Len)); BufferPool.GlobalPut(buf.Bytes); })); }
public override Task <int> ReadAsync(BytesSegment bs) { int r = TryDequeue(bs); if (r > 0) { return(NaiveUtils.GetCachedTaskInt(r)); } if (WaitBeforeRead.IsCompleted == false || ReadEventRegistered) { return(ComplexRead(bs)); } return(BaseStream.ReadAsync(bs)); }
public static async Task <ConnectResult> Connect(IAdapter adapter, AddrPort dest, int timeoutSeconds) { Socket socket; try { socket = await NaiveUtils.ConnectTcpAsync(dest, timeoutSeconds * 1000); } catch (Exception e) { return(new ConnectResult(adapter, ConnectResultEnum.Failed) { FailedReason = e.Message, Exception = e }); } return(new ConnectResult(adapter, MyStream.FromSocket(socket, adapter.GetAdapter().socket_impl))); }
private Task SendMsg(Msg msg) { if (ivSent) { return(ws.SendMsg(msg)); } ivSent = true; return(NaiveUtils.RunAsyncTask(async() => { var writeEnc = enc(true); await ws.SendBytesAsync(writeEnc.IV); ws.AddWriteFilter(FilterBase.GetStreamFilterFromIVEncryptor(true, writeEnc, true)); await ws.SendMsg(msg); })); }
public static async Task <WebSocketClient> ConnectToAsync(AddrPort dest, string path, int timeout, CancellationToken ct) { Socket socket = await NaiveUtils.ConnectTcpAsync(dest, timeout, async x => x, ct); try { var socketStream = MyStream.FromSocket(socket); var ws = new WebSocketClient(MyStream.ToStream(socketStream), path); ws.Host = dest.Host; return(ws); } catch (Exception) { socket.Dispose(); throw; } }
private static async Task SaveResponseToFile(string filepath, HttpWebResponse resp) { string tmpPath = filepath + ".downloading"; using (var fs = File.Open(tmpPath, FileMode.Create, FileAccess.ReadWrite)) { await NaiveUtils.StreamCopyAsync(resp.GetResponseStream(), fs); } if (File.Exists(filepath)) { File.Replace(tmpPath, filepath, null, true); } else { File.Move(tmpPath, filepath); } }
public async Task Listen() { try { IsRunning = true; try { tcpListener.Start(); } catch (Exception e) { Logger.error($"starting listening on {localEP}: {e.Message}"); return; } if (LogInfo) { Logger.info($"listening on {localEP}"); } while (true) { try { var client = await tcpListener.AcceptTcpClientAsync(); NaiveUtils.ConfigureSocket(client.Client); Task.Run(() => server.HandleAcceptedTcp(client)).Forget(); } catch (Exception e) { if (IsRunning) { server.logException(e, Logging.Level.Error, $"({localEP}) accepting connection:"); await Task.Delay(300); } else { return; } } } } catch (Exception e) { if (IsRunning) { server.logException(e, Logging.Level.Error, $"({localEP}) Run():"); } } finally { IsRunning = false; if (LogInfo) { server.log($"({localEP}) listening thread exiting", Logging.Level.Warning); } } }
public static async Task <WebSocketClient> ConnectToTlsAsync(AddrPort dest, string path, int timeout, CancellationToken ct) { var stream = await NaiveUtils.ConnectTlsAsync(dest, timeout, System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12, ct); try { var ws = new WebSocketClient(stream, path); ws.Host = dest.Host; return(ws); } catch (Exception) { stream.Dispose(); throw; } }
public static AwaitableWrapper WriteMultipleAsyncR(this IMyStream myStream, BytesView bv) { if (myStream is IMyStreamMultiBuffer bvs) { return(bvs.WriteMultipleAsyncR(bv)); } else { return(new AwaitableWrapper(NaiveUtils.RunAsyncTask(async() => { foreach (var item in bv) { if (item.len > 0) { await myStream.WriteAsync(new BytesSegment(item)); } } }))); } }
public override Task <int> ReadAsync(BytesSegment bs) { // We use an internal read-ahead buffer to reduce many read() syscalls when bs.Len is very small. // It's important since there is a hardware bug named 'Meltdown' in Intel CPUs. // TESTED: This optimization made ReadAsync 20x faster when bs.Len == 4, // on Windows 10 x64 16299.192 with a laptop Haswell CPU. var ret = PreReadAsync(ref bs, false); if (ret > 0) { return(NaiveUtils.GetCachedTaskInt(ret)); } if ((ret = TryReadNonblocking(bs)) > 0) { Interlocked.Increment(ref ctr.Rsync); return(NaiveUtils.GetCachedTaskInt(ret)); } Interlocked.Increment(ref ctr.Rasync); return(ReadAsyncImpl(bs)); }
public override unsafe void Update(BytesSegment bs) { uint i = (uint)bs.Offset; uint len = (uint)bs.Len; uint end = i + len; var realEncryptedCounterPos = this.encryptedCounterPos; this.encryptedCounterPos = (realEncryptedCounterPos + (uint)bs.Len) % keystreamSize; fixed(byte *encCtr = keystream) fixed(byte *bytes = bs.Bytes) while (i < end) { var unusedEncryptedCounter = keystreamSize - realEncryptedCounterPos; if (unusedEncryptedCounter == 0) { realEncryptedCounterPos = 0; if (keystreamSize > blockSize) { for (int j = 0; j < keystreamSize; j += blockSize) { Buffer.BlockCopy(Counter, 0, counterBlocks, j, blockSize); IncrementCounter(); } } else { IncrementCounter(); } EcbTransform.TransformBlock(counterBlocks, 0, (int)keystreamSize, keystream, 0); unusedEncryptedCounter = keystreamSize; } uint blockEnd = i + unusedEncryptedCounter; uint blocksEnd = (blockEnd < end) ? blockEnd : end; var count = blocksEnd - i; NaiveUtils.XorBytesUnsafe(encCtr + realEncryptedCounterPos, bytes + i, count); realEncryptedCounterPos += count; i = blocksEnd; } }
public static Action <BytesView> GetDeflateFilter(bool isCompress) { return((bv) => { using (var tostream = new MemoryStream()) { using (var ds = new DeflateStream( isCompress ? tostream : new MemoryStream(bv.bytes, bv.offset, bv.len), isCompress ? CompressionMode.Compress : CompressionMode.Decompress)) { if (isCompress) { ds.Write(bv.bytes, bv.offset, bv.len); ds.Flush(); } else { NaiveUtils.StreamToStream(ds, tostream); } } bv.Set(tostream.ToArray()); } }); }
private void CopyEncoded(string text) { var srcBytes = NaiveUtils.GetUTF8Bytes_AllocFromPool(text); byte[] gzBytes; int len; using (var ms = new MemoryStream()) { using (var gz = new GZipStream(ms, CompressionLevel.Optimal, true)) { gz.Write(srcBytes); BufferPool.GlobalPut(srcBytes.Bytes); } gzBytes = ms.GetBuffer(); len = (int)ms.Length; } var encoded = Base64GzTag + Convert.ToBase64String(gzBytes, 0, len); var cs = this.GetSystemService(Context.ClipboardService) as ClipboardManager; cs.PrimaryClip = ClipData.NewPlainText("text", encoded); Toast.MakeText(this, R.String.copied, ToastLength.Short).Show(); }
public static async Task HandleSeekableStreamAsync(this HttpConnection p, Stream stream) { var fileLength = stream.Length; long beginpos = 0; long endpos = fileLength - 1; p.ResponseHeaders["Accept-Ranges"] = "bytes"; if (p.RequestHeaders["Range"] is string ranges) { var match = regexBytes.Match(ranges); beginpos = Convert.ToInt64(match.Groups[1].Value); if (match.Groups[2].Success) { endpos = Convert.ToInt64(match.Groups[2].Value); } p.ResponseStatusCode = "206 Partial Content"; p.ResponseHeaders["Content-Range"] = $"bytes {beginpos}-{endpos}/{fileLength}"; } if (p.Method == "HEAD") { await p.outputStream.SwitchToKnownLengthModeAsync(fileLength); await p.EndResponseAsync(); } else { long realLength = endpos - beginpos + 1; if (p.outputStream.CurrentCompressionType == CompressionType.None) { await p.outputStream.SwitchToKnownLengthModeAsync(realLength); } else { await p.outputStream.SwitchToChunkedModeAsync(); } stream.Position = beginpos; await NaiveUtils.StreamCopyAsync(from : stream, to : p.outputStream, size : realLength, bs : (int)Math.Min(64 * 1024, realLength)); } }
public async Task Run(int backlog) { stopping = false; EndPoint ep; try { BaseListener.Server.NoDelay = true; BaseListener.Start(backlog); ep = BaseListener.LocalEndpoint; } catch (Exception e) { Logger.error($"starting on {BaseListener.LocalEndpoint}: {e.Message}"); return; } if (LogInfo) { Logger.info($"listening on {ep}"); } while (true) { TcpClient cli = null; try { try { cli = await BaseListener.AcceptTcpClientAsync().CAF(); NaiveUtils.ConfigureSocket(cli.Client); } catch (Exception) when(stopping) { if (LogInfo) { Logger.info($"stopped on {ep}"); } return; } Accepted?.Invoke(cli); } catch (Exception e) { Logger.exception(e, Logging.Level.Error, ep?.ToString()); } } }
public static Task <ConnectResult> ConnectWrapper(IConnectionHandler handler, ConnectArgument arg) { var tcs = new TaskCompletionSource <ConnectResult>(); var newinc = InConnectionTcp.Create(arg.InAdapter, arg.Dest, async(r) => { if (r.Ok) { var stream = new LoopbackStream(); r.Stream = stream; tcs.SetResult(r); return(stream.Another); } else { tcs.SetResult(r); return(null); } }); newinc.Url = arg.Url; newinc.DestOriginalName = arg.DestOriginalName; NaiveUtils.RunAsyncTask(async() => { try { await handler.HandleTcpConnection(newinc).CAF(); } catch (Exception e) { tcs.SetException(e); return; } if (newinc.IsRedirected && tcs.Task.IsCompleted == false) { tcs.SetResult(ConnectResult.RedirectTo(handler, newinc.Redirected)); } else { tcs.SetException(new Exception("handleConnection() did nothing.")); } }); return(tcs.Task); }
private void parseRequest(string requestLine) { var splits = requestLine.Split(' '); if (splits.Length != 3) { throw new Exception("Bad Request: " + requestLine); } foreach (var item in splits) { if (item.Length == 0) { throw new Exception("Bad Request: " + requestLine); } } Method = splits[0]; RealUrl = Url = splits[1]; HttpVersion = splits[2]; IsHttp1_1 = HttpVersion == "HTTP/1.1"; NaiveUtils.SplitUrl(Url, out var path, out Url_qstr); RealPathEscaped = path; RealPath = Url_path = HttpUtil.UrlDecode(path); }
public Task <Msg> RecvMsg(BytesView buf) { if (PreReadEnabled && recvTasks == null) { recvTasks = new Task <Msg> [recvStreams.Length]; for (int i = 0; i < recvStreams.Length; i++) { var i2 = i; recvTasks[i] = Task.Run(() => recvStreams[i2].RecvMsg(null)); } } if (nextRecv == recvStreams.Length) { nextRecv = 0; } var curRecv2 = nextRecv++; if (recvTasks != null) { var task = recvTasks[curRecv2]; recvTasks[curRecv2] = (!task.IsCompleted) ? NaiveUtils.RunAsyncTask(async(s) => { await s.prevTask; return(await s.curStream.RecvMsg(null)); }, new recvArgs { prevTask = task, curStream = recvStreams[curRecv2] }) //? task.ContinueWith((t, s) => s.CastTo<IMsgStream>().RecvMsg(null), recvStreams[curRecv2], TaskContinuationOptions.ExecuteSynchronously).Unwrap() : recvStreams[curRecv2].RecvMsg(null); return(task); } else { return(recvStreams[curRecv2].RecvMsg(buf)); } }
private void InitAdapters() { dnsResolver = null; socksInAdapter = null; var controller = Bg.Controller; if (VpnConfig.Handler == null) { socksInAdapter = controller.FindAdapter <SocksInAdapter>(VpnConfig.Socks) ?? throw new Exception($"SocksInAdapter '{VpnConfig.Socks}' not found."); } else { var existVpn = controller.FindAdapter <NaiveSocks.Adapter>("VPN"); if (existVpn != null) { throw new Exception("adapter 'VPN' already exists."); } else { var handlerRef = controller.AdapterRefFromName(VpnConfig.Handler); if (handlerRef.Adapter == null) { throw new Exception("Handler not found."); } socksInAdapter = new SocksInAdapter() { Name = "VPN", listen = NaiveUtils.ParseIPEndPoint("127.1:" + VpnConfig.SocksPort), @out = handlerRef }; AddInAdapter(controller, socksInAdapter); } } if (VpnConfig.DnsResolver != null) { dnsResolver = controller.FindAdapter <NaiveSocks.Adapter>(VpnConfig.DnsResolver) as NaiveSocks.IAdapter; if (dnsResolver == null) { Logging.warning($"Specified DNS resolver '{VpnConfig.DnsResolver}' is not found!"); } } else { dnsResolver = controller.FindAdapter <NaiveSocks.IAdapter>(VpnConfig.Handler); } if (VpnConfig.LocalDnsPort > 0 && dnsResolver == null) { throw new Exception("local dns is enabled but cannot find a dns resolver. Check Handler or DnsResolver in configuration."); } Logging.info("VPN connections handler: " + socksInAdapter.QuotedName); if (VpnConfig.LocalDnsPort > 0) { InitLocalDns(controller); } if (VpnConfig.UdpRelay) { var relay = new UdpRelay() { Name = "VPNUDP", listen = new IPEndPoint(IPAddress.Loopback, VpnConfig.SocksPort), redirect_dns = new IPEndPoint(IPAddress.Loopback, VpnConfig.LocalDnsPort) }; AddInAdapter(controller, relay); } }