public async Task ExecuteWoLAsync(ThinClientConnectOptions connectOptions, string targetPcid, CancellationToken cancel = default)
    {
        if (connectOptions.ClientOptions.Flags.Bit(WideTunnelClientFlags.WoL) == false)
        {
            throw new CoresLibException("connectOptions.ClientOptions.Flags.Bit(WideTunnelClientFlags.WoL) == false");
        }

        await using WideTunnel wt = new WideTunnel(this.Options.WideTunnelOptions);

        // Mac アドレスリストの取得
        string macList = await wt.WideClientGetWoLMacList(targetPcid, cancel);

        // ターゲット PC に叩き起こし依頼
        await using WtcSocket? sock = await wt.WideClientConnectAsync(connectOptions.Pcid, connectOptions.ClientOptions, true, cancel);

        await using PipeStream? st = sock.GetStream(true);

        st.ReadTimeout = st.WriteTimeout = Consts.ThinClient.ProtocolCommTimeoutMsecs;

        Pack p = new Pack();

        p.AddInt("ClientVer", Consts.ThinClient.DummyClientVer);
        p.AddInt("ClientBuild", Consts.ThinClient.DummyClientBuild);
        p.AddBool("WoLMode", true);
        p.AddStr("mac_list", macList);

        await st._SendPackAsync(p, cancel);

        p = await st._RecvPackAsync(cancel);

        var err = p.GetErrorFromPack();

        err.ThrowIfError(p);
    }
    async Task <ThinClientConnection> DcConnectEx(WideTunnel wt, ThinClientConnectOptions connectOptions, CancellationToken cancel, bool checkPort, bool firstConnection,
                                                  Func <ThinClientAuthRequest, CancellationToken, Task <ThinClientAuthResponse> > authCallback,
                                                  Func <ThinClientOtpRequest, CancellationToken, Task <ThinClientOtpResponse> > otpCallback,
                                                  Func <ThinClientInspectRequest, CancellationToken, Task <ThinClientInspectResponse> > inspectCallback)
    {
        string     otpTicket     = "";
        string     inspectTicket = "";
        WtcSocket? sock          = null;
        PipeStream?st            = null;

        if (checkPort == false && connectOptions.DebugGuacMode == false)
        {
            throw new CoresLibException("checkPort == false && connectOptions.DebugGuacMode == false");
        }

        try
        {
            sock = await wt.WideClientConnectAsync(connectOptions.Pcid, connectOptions.ClientOptions, false, cancel);

            st = sock.GetStream(true);

            st.ReadTimeout = st.WriteTimeout = Consts.ThinClient.ProtocolCommTimeoutMsecs;

            // バージョンを送信
            Pack p = new Pack();
            p.AddInt("ClientVer", Consts.ThinClient.DummyClientVer);
            p.AddInt("ClientBuild", Consts.ThinClient.DummyClientBuild);
            p.AddBool("CheckPort", checkPort);
            p.AddBool("FirstConnection", firstConnection);
            p.AddBool("HasURDP2Client", true);
            p.AddBool("SupportOtp", true);
            p.AddBool("SupportOtpEnforcement", true);
            p.AddBool("SupportInspect", true);
            p.AddBool("SupportServerAllowedMacListErr", true);
            p.AddIp("ClientLocalIP", connectOptions.ClientIpAddress);
            p.AddUniStr("UserName", "HTML5 WebClient");
            p.AddUniStr("ComputerName", "HTML5 WebClient");
            p.AddBool("SupportWatermark", true);
            p.AddBool("GuacdMode", connectOptions.DebugGuacMode == false);

            GuaDnFlags flags = GuaDnFlags.None;
            if (connectOptions.GuaPreference?.EnableAlwaysWebp ?? false)
            {
                flags |= GuaDnFlags.AlwaysWebp;
            }
            p.AddInt("GuacdFlags", (uint)flags);

            await st._SendPackAsync(p, cancel);

            // 認証パラメータを受信
            p = await st._RecvPackAsync(cancel);

            var err = p.GetErrorFromPack();
            err.ThrowIfError(p);

            var authType                  = (ThinAuthType)p["AuthType"].SIntValueSafeNum;
            var svcType                   = (ThinSvcType)p["ServiceType"].SIntValueSafeNum;
            var svcPort                   = (int)p["ServicePort"].SIntValueSafeNum;
            var caps                      = (ThinServerCaps)p["DsCaps"].SIntValueSafeNum;
            var rand                      = p["Rand"].DataValueNonNull;
            var machineKey                = p["MachineKey"].DataValueNonNull;
            var isShareDisabled           = p["IsShareDisabled"].BoolValue;
            var useAdvancedSecurity       = p["UseAdvancedSecurity"].BoolValue;
            var isOtpEnabled              = p["IsOtpEnabled"].BoolValue;
            var runInspect                = p["RunInspect"].BoolValue;
            var lifeTime                  = p["Lifetime"].SInt64Value;
            var lifeTimeMsg               = p["LifeTimeMsg"].UniStrValueNonNull;
            var waterMarkStr1             = p["WatermarkStr1"].UniStrValueNonNull;
            var waterMarkStr2             = p["WatermarkStr2"].UniStrValueNonNull;
            var idleTimeout               = p["IdleTimeout"].SIntValueSafeNum;
            var isLimitedFirewallMandated = p["IsLimitedFirewallMandated"].BoolValue;

            if (isLimitedFirewallMandated)
            {
                // 完全閉域化 FW が強制されているが HTML5 版ではサポートされていない
                throw new VpnException(VpnError.ERR_DESK_GOVFW_HTML5_NO_SUPPORT);
            }

            if (isOtpEnabled)
            {
                // OTP 認証
                ThinClientOtpRequest otpReq = new ThinClientOtpRequest();

                var otpRes = await otpCallback(otpReq, cancel);

                p = new Pack();
                p.AddStr("Otp", otpRes.Otp._NonNull());
                await st._SendPackAsync(p, cancel);

                // 結果を受信
                p = await st._RecvPackAsync(cancel);

                p.ThrowIfError();

                // OTP チケットを保存
                otpTicket = p["OtpTicket"].StrValueNonNull;
            }

            if (runInspect)
            {
                // 検疫および MAC アドレス認証
                ThinClientInspectRequest inspectReq = new ThinClientInspectRequest();

                var inspectRes = await inspectCallback(inspectReq, cancel);

                p = new Pack();
                p.AddBool("AntiVirusOk", inspectRes.AntiVirusOk);
                p.AddBool("WindowsUpdateOk", inspectRes.WindowsUpdateOk);
                p.AddStr("MacAddressList", inspectRes.MacAddressList._NonNull());
                p.AddStr("Ticket", inspectRes.Ticket._NonNull());
                await st._SendPackAsync(p, cancel);

                // 結果を受信
                p = await st._RecvPackAsync(cancel);

                p.ThrowIfError();

                // OTP チケットを保存
                inspectTicket = p["InspectionTicket"].StrValueNonNull;
            }

            // ユーザー認証
            p = new Pack();

            if (useAdvancedSecurity == false)
            {
                // 古いユーザー認証
                if (authType == ThinAuthType.None)
                {
                    // 匿名認証
                    ThinClientAuthRequest authReq = new ThinClientAuthRequest
                    {
                        AuthType = ThinAuthType.None,
                    };

                    var authRes = await authCallback(authReq, cancel);
                }
                else if (authType == ThinAuthType.Password)
                {
                    // パスワード認証
                    ThinClientAuthRequest authReq = new ThinClientAuthRequest
                    {
                        AuthType = ThinAuthType.Password,
                    };

                    var authRes = await authCallback(authReq, cancel);

                    var passwordHash = Secure.HashSHA1(authRes.Password._GetBytes_UTF8());

                    p.AddData("SecurePassword", Secure.SoftEther_SecurePassword(passwordHash, rand));
                }
                else
                {
                    // そのような認証方法はサポートしていない
                    throw new VpnException(VpnError.ERR_AUTHTYPE_NOT_SUPPORTED);
                }
            }
            else
            {
                // 高度なユーザー認証
                ThinClientAuthRequest authReq = new ThinClientAuthRequest
                {
                    AuthType = ThinAuthType.Advanced,
                };

                var authRes = await authCallback(authReq, cancel);

                p.AddInt("authtype", 2); // CLIENT_AUTHTYPE_PLAIN_PASSWORD
                p.AddStr("username", authRes.Username);
                p.AddStr("plain_password", authRes.Password);
            }

            await st._SendPackAsync(p, cancel);

            // 結果を受信
            p = await st._RecvPackAsync(cancel);

            err = p.GetErrorFromPack();
            err.ThrowIfError(p);

            st.ReadTimeout = st.WriteTimeout = Timeout.Infinite;

            var misc = new ThinClientMiscParams(lifeTime, lifeTimeMsg, idleTimeout, isShareDisabled, caps.Bit(ThinServerCaps.AudioInSupported));

            return(new ThinClientConnection(sock, st, svcType, svcPort, isShareDisabled, caps, runInspect, otpTicket, inspectTicket, waterMarkStr1, waterMarkStr2, misc));
        }
        catch
        {
            await st._DisposeSafeAsync();

            await sock._DisposeSafeAsync();

            throw;
        }
    }
Example #3
0
    public async Task StartWtcAsync(CancellationToken cancel = default)
    {
        if (Started.IsFirstCall() == false)
        {
            throw new ApplicationException("Already started.");
        }

        LowerStream.ReadTimeout  = CoresConfig.WtcConfig.ConnectingTimeoutMsec;
        LowerStream.WriteTimeout = CoresConfig.WtcConfig.ConnectingTimeoutMsec;

        // シグネチャをアップロードする
        HttpHeader h = new HttpHeader("POST", "/widetunnel/connect.cgi", "HTTP/1.1");

        h.ValueList.Add("Content-Type", "image/jpeg");
        h.ValueList.Add("Connection", "Keep-Alive");

        // 透かしデータのアップロード
        int randSize = Util.RandSInt31() % 2000;
        MemoryBuffer <byte> water = new MemoryBuffer <byte>();

        water.Write(this.WideTunnel.Options.WaterMark);
        water.Write(Util.Rand(randSize));
        await h.PostHttpAsync(LowerStream, water, cancel);

        // Hello パケットのダウンロード
        var hello = await LowerStream._HttpClientRecvPackAsync(cancel);

        if (hello["hello"].BoolValue == false)
        {
            throw new CoresLibException("Hello packet recv error.");
        }

        // 接続パラメータの送信
        var p = new Pack();

        p.AddData("client_id", WideTunnel.Options.ClientId);
        p.AddStr("method", "connect_session");
        p.AddBool("use_compress", false);
        p.AddData("session_id", this.Options.ConnectParam.SessionId);
        p.AddSInt("ver", CoresConfig.WtcConfig.PseudoVer);
        p.AddSInt("build", CoresConfig.WtcConfig.PseudoBuild);
        p.AddStr("name_suite", this.WideTunnel.Options.NameSuite);
        p.AddBool("support_timeout_param", true);

        var clientOptions = Options.ConnectParam.ClientOptions;

        if (clientOptions.RealClientIp._IsFilled())
        {
            p.AddBool("is_trusted", true);
            p.AddStr("trusted_real_client_ip", clientOptions.RealClientIp._NonNullTrim());
            p.AddStr("trusted_real_client_fqdn", clientOptions.RealClientFqdn._NonNullTrim());
            p.AddInt("trusted_real_client_port", (uint)clientOptions.RealClientPort);

            string auth_str = $"{clientOptions.RealClientIp._NonNullTrim()}/{clientOptions.RealClientFqdn._NonNullTrim()}/{(uint)clientOptions.RealClientPort}/{this.WideTunnel.Options.ControllerGateSecretKey}";
            p.AddData("trusted_auth_sha1", auth_str._HashSHA1());
        }

        await LowerStream._HttpClientSendPackAsync(p, cancel);

        // 結果の受信
        p = await LowerStream._HttpClientRecvPackAsync(cancel);

        int      code = p["code"].SIntValue;
        VpnError err  = (VpnError)code;

        err.ThrowIfError(p);

        int  tunnelTimeout              = Consts.WideTunnelConsts.TunnelTimeout;
        int  tunnelKeepalive            = Consts.WideTunnelConsts.TunnelKeepAlive;
        bool tunnelUseAggressiveTimeout = false;

        int  tunnelTimeout2              = p["tunnel_timeout"].SIntValue;
        int  tunnelKeepAlive2            = p["tunnel_keepalive"].SIntValue;
        bool tunnelUseAggressiveTimeout2 = p["tunnel_use_aggressive_timeout"].BoolValue;

        if (tunnelTimeout2 >= 1 && tunnelKeepAlive2 >= 1)
        {
            tunnelTimeout              = tunnelTimeout2;
            tunnelKeepalive            = tunnelKeepAlive2;
            tunnelUseAggressiveTimeout = tunnelUseAggressiveTimeout2;
        }

        this.WebSocketUrl = p["websocket_url"].StrValue !;
        if (this.WebSocketUrl._IsEmpty())
        {
            throw new CoresLibException("This version of the destination ThinGate has no WebSocket capability.");
        }

        LowerStream.ReadTimeout  = tunnelTimeout;
        LowerStream.WriteTimeout = Timeout.Infinite;

        this.SendTask = SendLoopAsync(tunnelKeepalive)._LeakCheck();
        this.RecvTask = RecvLoopAsync()._LeakCheck();
    }