Example #1
0
        private static void HandleEncrypt(Argument arg)
        {
            var isEncrypting = arg.arg == "--encrypt";

            var alg = arg.GetParaOrThrow(0);
            var key = arg.GetParaOrThrow(1);

            var inputFile  = arg.GetParaOrNull(2);
            var outputFile = arg.GetParaOrNull(3) ?? (inputFile != null ? inputFile + ".enc" : null);
            var input      = inputFile.IsNullOrEmpty() ? Console.OpenStandardInput() : File.OpenRead(inputFile);
            var output     = outputFile.IsNullOrEmpty() ? Console.OpenStandardOutput() : File.Open(outputFile, FileMode.Create);

            var encryptStreamFunc = Ss.GetCipherByName(alg).GetEncryptionStreamFunc(key);

            IMyStream from, to;

            if (isEncrypting)
            {
                from = MyStream.FromStream(input);
                to   = encryptStreamFunc(MyStream.FromStream(output));
            }
            else
            {
                from = encryptStreamFunc(MyStream.FromStream(input));
                to   = MyStream.FromStream(output);
            }

            Task.Run(async() => {
                await MyStream.StreamCopy(from, to, -1, true);
                await output.FlushAsync();
                output.Dispose();
            }).Wait();
        }
Example #2
0
        public override async void OnNewConnection(TcpClient client)
        {
            var stream = GetMyStreamFromSocket(client.Client);

            try {
                var bs = BufferPool.GlobalGetBs(8 * 1024, false);
                var r  = await stream.ReadAsyncR(bs);

                if (r <= 0)
                {
                    return;
                }
                bs.Len = r;
                var ch = new TlsStream.ClientHello();
                TlsStream.ParseClientHelloRecord(bs, ref ch, out _);
                if (ch.Sni == null)
                {
                    return;
                }
                var conn = InConnectionTcp.Create(this, new AddrPort(ch.Sni, dest_port), new MyStreamWrapper(stream)
                {
                    Queue = bs
                });
                await HandleIncommingConnection(conn);
            } catch (Exception e) {
                Logger.exception(e, Logging.Level.Error, "OnNewConnection");
            } finally {
                MyStream.CloseWithTimeout(stream).Forget();
            }
        }
Example #3
0
        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;
            }
        }
Example #4
0
        public override async Task HandleTcpConnection(InConnectionTcp connection)
        {
            Exception     e             = null;
            ConnectResult connectResult = null;

            try {
                connectResult = await Connect(connection);
            } catch (Exception ex) when(if_failed != null)
            {
                Logging.exception(ex, Logging.Level.Error, $"{this}: {connection} failed ({connectResult.FailedReason}), redirecting to {if_failed}.");
                connection.RedirectTo(if_failed);
                return;
            }
            if (!connectResult.Ok && if_failed != null)
            {
                Logging.warning($": {connection} failed ({connectResult.FailedReason}), redirecting to {if_failed}.");
                connection.RedirectTo(if_failed);
                return;
            }
            try {
                if (connectResult.Ok)
                {
                    await connection.HandleAndPutStream(this, connectResult.Stream, connectResult.WhenCanRead);
                }
                else
                {
                    await connection.HandleAndGetStream(connectResult);
                }
            } finally {
                if (connectResult.Ok)
                {
                    MyStream.CloseWithTimeout(connectResult.Stream);
                }
            }
        }
Example #5
0
        protected override Task OnFinish()
        {
            var dataStream = DataStream;

            if (dataStream != null)
            {
                MyStream.CloseWithTimeout(dataStream).Forget();
            }
            return(base.OnFinish());
        }
Example #6
0
 private void SetCurrentConfig(LoadedConfig loadedConfig)
 {
     CurrentConfig = loadedConfig;
     if (!loadedConfig.SocketImpl.IsNullOrEmpty())
     {
         MyStream.SetSocketImpl(loadedConfig.SocketImpl);
     }
     MyStream.TwoWayCopier.DefaultUseLoggerAsVerboseLogger = IsDebugFlagEnabled("copier_v");
     Channel.Debug        = IsDebugFlagEnabled("mux_v");
     YASocket.Debug       = IsDebugFlagEnabled("ya_v");
     Logging.AsyncLogging = IsDebugFlagEnabled("asynclog");
     ConfigTomlLoaded?.Invoke(loadedConfig.TomlTable);
 }
Example #7
0
        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)));
        }
Example #8
0
            public async Task Run()
            {
                var       left              = Left;
                var       right             = Right;
                int       halfCloseTimeout  = (10 * 1000) + NaiveUtils.Random.Next(-1000, 1000);
                const int forceCloseTimeout = 10 * 1000;

                try {
                    var readFromRight = CopierFromRight.CopyAndShutdown();
                    var readFromLeft  = CopierFromLeft.CopyAndShutdown();
                    var tasks         = new Task[] { readFromRight, readFromLeft };
                    string stringFromTask(Task t) => t == readFromRight ? $"{right} -> {left}" : $"{left} -> {right}";

                    // waiting for half closing.
                    var compeletedTask = await Task.WhenAny(tasks).CAF();

                    if (compeletedTask.IsFaulted)
                    {
                        var exception = compeletedTask.Exception.InnerException;
                        Logger?.exception(exception, Logging.Level.Warning, $"stream copying exception, force closing. ({stringFromTask(compeletedTask)})");
                        return;
                    }

                    var anotherTask = compeletedTask == readFromRight ? readFromLeft : readFromRight;
                    // waiting for full closing with timeout.
                    if (await anotherTask.WithTimeout(halfCloseTimeout))
                    {
                        Logger?.warning($"keeping half closed for {halfCloseTimeout} ms, force closing. ({stringFromTask(anotherTask)})");
                    }
                    else
                    {
                        if (anotherTask.IsFaulted)
                        {
                            Logger?.exception(anotherTask.Exception.InnerException, Logging.Level.Warning, $"half closed waiting exception. {stringFromTask(anotherTask)}");
                        }
                    }
                } catch (Exception e) {
                    Logger?.exception(e, Logging.Level.Error, $"Relay task ({left.SafeToStr()} <-> {right.SafeToStr()})");
                } finally {
                    var t1 = MyStream.CloseWithTimeout(left, forceCloseTimeout);
                    var t2 = MyStream.CloseWithTimeout(right, forceCloseTimeout);
                    //await t1; await t2;
                }
            }
Example #9
0
        public override void Stop()
        {
            base.Stop();
            var stream = DataStream;

            if (stream == null)
            {
                stream = ConnectResult.Stream;
            }
            if (stream == null)
            {
                Controller.Logger.warning(this + ": Can not get the stream, failed to stop.");
            }
            else
            {
                Controller.Logger.info("Closing stream " + stream + " to stop connection " + this);
                MyStream.CloseWithTimeout(stream);
            }
        }
Example #10
0
        public override async Task <ConnectResult> ProtectedConnect(ConnectArgument arg)
        {
            var dest       = arg.Dest;
            var baseResult = await ConnectHelper.Connect(this, server, connect_timeout);

            if (!baseResult.Ok)
            {
                return(baseResult);
            }
            try {
                var dataStream = getEncryptionStream(baseResult.Stream);
                var bytes      = dest.ToSocks5Bytes();
                await dataStream.WriteAsync(bytes);

                return(CreateConnectResultWithStream(dataStream));
            } catch (Exception) {
                MyStream.CloseWithTimeout(baseResult.Stream);
                throw;
            }
        }
Example #11
0
        private async void UDPListen()
        {
            try {
                var anyEP  = new IPEndPoint(0, 0);
                var socket = new Socket(listen.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
                socket.Bind(listen);
                udpClient = MyStream.FromSocket(socket);
                while (true)
                {
                    var r = await udpClient.ReadFromAsyncR(64 * 1024, anyEP);

                    Task.Run(() => HandleUdpReceiveResult(r)).Forget();
                }
            } catch (Exception e) {
                Logger.exception(e, Logging.Level.Warning, "UDP listener stopped");
            } finally {
                udpClient?.Close();
                udpClient = null;
            }
        }
Example #12
0
            public async void Start()
            {
                try {
                    if (!await socks5svr.ProcessAsync())
                    {
                        return;
                    }
                    this.Dest.Host  = socks5svr.TargetAddr;
                    this.Dest.Port  = socks5svr.TargetPort;
                    this.DataStream = _stream;
                    if (_adapter.fastreply)
                    {
                        await OnConnectionResult(new ConnectResult(null, ConnectResultEnum.OK)).CAF();
                    }

                    await _adapter.HandleIncommingConnection(this, outRef);
                } catch (Exception e) {
                    _adapter.Logger.exception(e, Logging.Level.Warning, "listener");
                } finally {
                    MyStream.CloseWithTimeout(_stream).Forget();
                }
            }
Example #13
0
 public static IMyStream ToMyStream(this Stream stream)
 {
     return(MyStream.FromStream(stream));
 }
Example #14
0
 public static Stream ToStream(this IMyStream myStream)
 {
     return(MyStream.ToStream(myStream));
 }
Example #15
0
 public static Task RelayWith(this IMyStream stream1, IMyStream stream2)
 {
     return(MyStream.Relay(stream1, stream2));
 }
Example #16
0
        public async Task <SocketStream> ConnectAsync()
        {
            _socket = await NaiveUtils.ConnectTcpAsync(new AddrPort(_socksAddr, _socksPort), 0);

            var _ns = MyStream.FromSocket(_socket);

            var user = _username;
            var pass = _password ?? "";

            byte[] buffer =
                user == null
                ? new byte[] { SOCKS_VER, 1, NOAUTH }
                : new byte[] { SOCKS_VER, AUTH_METH_SUPPORT, NOAUTH, USER_PASS_AUTH };
            await _ns.WriteAsyncR(buffer);

            await _ns.ReadFullAsyncR(new BytesSegment(buffer, 0, 2));

            if (buffer[1] == NOAUTH)
            {
                // nothing to do.
            }
            else if (buffer[1] == USER_PASS_AUTH)
            {
                byte[] credentials = new byte[user.Length + pass.Length + 3];
                var    pos         = 0;
                credentials[pos++] = 1;
                credentials[pos++] = (byte)user.Length;
                pos += Encoding.ASCII.GetBytes(user, 0, user.Length, credentials, pos);
                credentials[pos++] = (byte)pass.Length;
                pos += Encoding.ASCII.GetBytes(pass, 0, pass.Length, credentials, pos);

                await _ns.WriteAsyncR(credentials);

                await _ns.ReadFullAsyncR(new BytesSegment(buffer, 0, 2));

                if (buffer[1] != SOCKS_CMD_SUCCSESS)
                {
                    throw new SocksRefuseException("Invalid username or password.");
                }
            }
            else
            {
                _socket.Close();
                throw new SocksAuthException();
            }

            byte addrType = GetAddressType();

            byte[] address = GetDestAddressBytes(addrType, _destAddr);
            byte[] port    = GetDestPortBytes(_destPort);
            buffer    = new byte[4 + port.Length + address.Length];
            buffer[0] = SOCKS_VER;
            buffer[1] = CMD_CONNECT;
            buffer[2] = 0x00; //reserved
            buffer[3] = addrType;
            address.CopyTo(buffer, 4);
            port.CopyTo(buffer, 4 + address.Length);
            await _ns.WriteAsyncR(buffer);

            buffer = new byte[256];
            await _ns.ReadFullAsyncR(new BytesSegment(buffer, 0, 4));

            if (buffer[1] != SOCKS_CMD_SUCCSESS)
            {
                throw new SocksRefuseException($"remote socks5 server returns {new BytesView(buffer, 0, 4)}");
            }
            switch (buffer[3])
            {
            case 1:
                await _ns.ReadFullAsyncR(new BytesSegment(buffer, 0, 4 + 2));

                break;

            case 3:
                await _ns.ReadFullAsyncR(new BytesSegment(buffer, 0, 1));

                await _ns.ReadFullAsyncR(new BytesSegment(buffer, 0, buffer[0]));

                break;

            case 4:
                await _ns.ReadFullAsyncR(new BytesSegment(buffer, 0, 16 + 2));

                break;

            default:
                throw new Exception("Not supported addr type: " + buffer[3]);
            }

            return(_ns);
        }
Example #17
0
 static SocketStream CreateUdpSocket() => MyStream.FromSocket(new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp));
Example #18
0
        static void MainContinued(ArgParseResult ar, Controller controller)
        {
            LogFileWriter logWriter = null;

            ar.TryGetValue("--cmd", out var argcmd);
            if (argcmd == null)
            {
                Logging.info(NameWithVertionText);
                if (GuiMode)
                {
                    Logging.info("(GUI mode)");
                    LogStdout = false;
                }
            }
            if (ar.TryGetValue("--log-file", out var logFile))
            {
                Logging.info($"Logging file: {logFile.FirstParaOrThrow}");
                logWriter = new LogFileWriter(logFile.FirstParaOrThrow, Logging.RootLogger);
                logWriter.Start();
                logWriter.WriteHistoryLog();
            }
            if (ar.TryGetValue("-c", out var v))
            {
                specifiedConfigPath = v.FirstParaOrThrow;
                Logging.info($"configuation file: {specifiedConfigPath}");
            }
            else if (ar.ContainsKey("--config-stdin"))
            {
                Logging.info("reading configuration from stdin until EOF...");
                specifiedConfigContent = Console.In.ReadToEnd();
                Logging.info($"configuration read {specifiedConfigContent.Length} chars");
            }

            if (ar.TryGetValue("--socket-impl", out var socketImpl))
            {
                MyStream.SetSocketImpl(socketImpl.FirstParaOrThrow);
            }

            long lastPackets = 0, lastBytes = 0;

            void updateTitle()
            {
                lock (CmdConsole.ConsoleOnStdIO.Lock) {
                    var p = MyStream.TotalCopiedPackets;
                    var b = MyStream.TotalCopiedBytes;
                    Console.Title = $"{controller.RunningConnections}/{controller.TotalHandledConnections} current/total connections | relayed {p:N0} Δ{p - lastPackets:N0} packets / {b:N0} Δ{b - lastBytes:N0} bytes - {BuildInfo.AppName}";
                    lastPackets   = p;
                    lastBytes     = b;
                }
            }

            bool  titleUpdateRunning = false;
            Timer titleUpdateTimer   = null;

            titleUpdateTimer = new Timer((x) => {
                if (titleUpdateRunning)
                {
                    updateTitle();
                }
                else
                {
                    titleUpdateTimer.Change(-1, -1);
                    Console.Title = BuildInfo.AppName;
                }
            });
            controller.ConfigTomlLoaded += (x) => {
                if (x.TryGetValue <string>("log_file", out var log_file))
                {
                    log_file = controller.ProcessFilePath(log_file);
                    if (logWriter?.LogFile != log_file)
                    {
                        logWriter?.Stop();
                        if (log_file != null)
                        {
                            logWriter = new LogFileWriter(log_file, Logging.RootLogger);
                            logWriter.Start();
                        }
                    }
                }
                var toRun = x.TryGetValue("update_title", Environment.OSVersion.Platform == PlatformID.Win32NT) && !GuiMode;
                if (toRun != titleUpdateRunning)
                {
                    if (toRun)
                    {
                        titleUpdateRunning = true;
                        titleUpdateTimer.Change(1000, 1000);
                    }
                    else
                    {
                        titleUpdateRunning = false;
                    }
                }
            };

            if (ar.ContainsKey("--force-jit"))
            {
                ForceJit();
            }
            else if (ar.ContainsKey("--force-jit-async"))
            {
                Task.Run(() => ForceJit());
            }


            if (argcmd == null || specifiedConfigPath != null || specifiedConfigContent != null)
            {
                if (specifiedConfigPath != null)
                {
                    Commands.loadController(controller, specifiedConfigPath);
                }
                else if (specifiedConfigContent != null)
                {
                    controller.FuncGetConfigFile = () => Controller.ConfigFile.FromContent(specifiedConfigContent);
                    controller.Load();
                    controller.Start();
                }
                else
                {
                    var paths = GetConfigFilePaths();
                    controller.LoadConfigFileFromMultiPaths(paths);
                    controller.Start();
                }
            }
            var cmdHub = new CommandHub();

            CommandHub    = cmdHub;
            cmdHub.Prompt = $"{BuildInfo.AppName}>";
            Commands.AddCommands(cmdHub, controller, null, new string[] { "all" });
            cmdHub.AddCmdHandler("newbie", (cmd) => Commands.NewbieWizard(cmd, controller, specifiedConfigPath ?? configFilePath));
            cmdHub.AddCmdHandler("ver", (cmd) => cmd.WriteLine(NameWithVertionText));
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                cmdHub.AddCmdHandler("openfolder", (cmd) => {
                    if (cmd.args.Length == 0)
                    {
                        Process.Start("explorer", ".");
                    }
                    else if (cmd.args.Length > 1)
                    {
                        goto WRONT_ARG;
                    }
                    else if (cmd.args[0] == "exe")
                    {
                        OpenFolerAndShowFile(Process.GetCurrentProcess().MainModule.FileName);
                    }
                    else if (cmd.args[0] == "config")
                    {
                        OpenFolerAndShowFile(controller.CurrentConfig.FilePath);
                    }
                    else
                    {
                        goto WRONT_ARG;
                    }
                    return;

                    WRONT_ARG:
                    cmd.statusCode = 1;
                    cmd.WriteLine("wrong arguments");
                    void OpenFolerAndShowFile(string fileName) => Process.Start("explorer", $"/select, \"{fileName}\"");
                }, "Usage: openfolder [exe|config]");
            }
            if (argcmd != null)
            {
                HandleArgCmd(argcmd, cmdHub);
                return;
            }
#if NS_WINFORM
            cmdHub.AddCmdHandler("gui", (cmd) => {
                var winform = new WinForm.WinFormController(controller);
                winform.StartUIThread();
                winform.Invoke(() => winform.ShowControllerForm(false));
            });
            if (GuiMode)
            {
                return;
            }
#endif
            if (ar.ContainsKey("--no-cli"))
            {
                goto WAITFOREVER;
            }
            if (InteractiveConsole(cmdHub))
            {
                Environment.Exit(0);
                return;
            }

WAITFOREVER:
#if NS_WINFORM
            if (GuiMode)
            {
                return;
            }
#endif
            while (true)
            {
                Thread.Sleep(int.MaxValue);
            }
        }
Example #19
0
        private async Task <Tuple <IMsgStream, ImuxSession> > GetMsgStream(HttpConnection p, Settings settings, NaiveProtocol.Request req)
        {
            var realKey = settings.realKey;

            const string XumPrefix   = "chs2:";
            bool         isImux      = req.additionalString.StartsWith(XumPrefix);
            ImuxSession  imux        = null;
            string       encryptType = "";

            if (req.extraStrings.Length > 0)
            {
                encryptType = req.extraStrings[0];
            }
            if (!isImux && req.additionalString != "channels")
            {
                Logger.warning($"{p.remoteEP}: protocol not supported");
                return(null);
            }
            IMsgStream msgStream = null;

            if (isImux)
            {
                var arr = NaiveUtils.DeserializeArray(req.additionalString.Substring(XumPrefix.Length));
                var sessionId = arr[0];
                int wsCount = Int32.Parse(arr[1]), wssoCount = 0, httpCount = 0;
                var connId = Int32.Parse(arr[2]);
                if (arr.Count > 3)
                {
                    wssoCount = Int32.Parse(arr[3]);
                    httpCount = Int32.Parse(arr[4]);
                }
                var connCount = wsCount + wssoCount + httpCount;
                int imuxMax   = settings.imux_max;
                if (imuxMax < 0)
                {
                    imuxMax = 16;
                }
                if (connCount > imuxMax)
                {
                    Logger.warning($"{p.remoteEP}: IMUX count requesting ({connCount}) > imux_max ({imuxMax})");
                    return(null);
                }
                IMsgStream wsOrHttp;
                if (connId < connCount - httpCount)
                {
                    wsOrHttp = await HandleWebsocket(p, realKey, encryptType);
                }
                else
                {
                    p.setStatusCode("200 OK");
                    p.setHeader(HttpHeaders.KEY_Transfer_Encoding, HttpHeaders.VALUE_Transfer_Encoding_chunked);
                    await p.EndResponseAsync();

                    var baseStream = MyStream.FromStream(p.SwitchProtocol());
                    var msf        = new HttpChunkedEncodingMsgStream(baseStream);
                    NaiveProtocol.ApplyEncryption(msf, realKey, encryptType);
                    wsOrHttp = msf;
                }
                lock (imuxSessions) {
                    if (imuxSessions.TryGetValue(sessionId, out imux) == false)
                    {
                        imux = new ImuxSession(sessionId, connCount)
                        {
                            WsCount   = wsCount,
                            WssoCount = wssoCount,
                            HttpCount = httpCount
                        };
                        imuxSessions.Add(sessionId, imux);
                        NaiveUtils.SetTimeout(10 * 1000, () => {
                            if (imux.ConnectedCount != imux.Count)
                            {
                                Logger.warning($"IMUX (id={imux.SessionId}, count={imux.ConnectedCount}/{imux.Count}) timed out");
                                imux.WhenEnd.SetResult(null);
                            }
                        });
                    }
                    if (imux.HandleConnection(wsOrHttp, connId))
                    {
                        // all connections are connected to the imux session, return the msg stream.
                        msgStream = imux.MuxStream;
                    }
                }

                if (msgStream == null)
                {
                    // wait for the end of the imux session, prevent it from being disconncected.
                    await imux.WhenEnd.Task;
                    return(null);
                }
            }
            else
            {
                msgStream = await HandleWebsocket(p, realKey, encryptType);
            }
            return(Tuple.Create(msgStream, imux));
        }
Example #20
0
 public IMyStream GetMyStreamFromSocket(Socket socket) => MyStream.FromSocket(socket, socket_impl);