예제 #1
0
        public static async Task ReadHtmlAsync(string url)
        {
            using (var client = new TcpClient())
            {
                Console.WriteLine($"Start get {url}");
                Uri uri = new Uri(url);

                var hostAdress = await Dns.GetHostAddressesAsync(uri.Host);

                IPAddress ipaddrress = hostAdress[0];
                Console.WriteLine($"Host: {uri.Host}, IP: {ipaddrress}");
                await client.ConnectAsync(ipaddrress.MapToIPv4(), uri.Port);

                Console.WriteLine("Connected");
                Console.WriteLine();


                Stream stream; // stream để đọc - gửi HTTP Message
                if (uri.Scheme == "https")
                {
                    // SslStream
                    stream = new SslStream(client.GetStream(), false,
                                           new RemoteCertificateValidationCallback(ValidateServerCertificate),
                                           null);
                    (stream as SslStream).AuthenticateAsClient(uri.Host);
                }
                else
                {
                    // NetworkStream
                    stream = client.GetStream();
                }

                // Xem: /psr-7-chuan-giao-dien-thong-diep-http.html#HTTPRequest
                StringBuilder header = new StringBuilder();
                header.Append($"GET {uri.PathAndQuery} HTTP/1.1\r\n");
                header.Append($"Host: {uri.Host}\r\n");
                header.Append($"\r\n");

                Console.WriteLine("Request:");
                Console.WriteLine(header);

                byte[] bsend = Encoding.UTF8.GetBytes(header.ToString());
                await stream.WriteAsync(bsend, 0, bsend.Length);

                await stream.FlushAsync();


                var     ms     = new MemoryStream();
                byte [] buffer = new byte[2048];
                int     bytes  = -1;
                do
                {
                    bytes = await stream.ReadAsync(buffer, 0, buffer.Length);

                    ms.Write(buffer, 0, bytes);
                    Array.Clear(buffer, 0, buffer.Length);
                } while (bytes > 0);

                ms.Seek(0, SeekOrigin.Begin);
                var    reader = new StreamReader(ms);
                string html   = reader.ReadToEnd();
                Console.WriteLine("Response:");
                Console.WriteLine(html);
            }
        }
예제 #2
0
        private async Task StartContainerAsync(Application application, Service service, DockerRunInfo docker, string?dockerNetwork)
        {
            var serviceDescription   = service.Description;
            var environmentArguments = "";
            var volumes          = "";
            var workingDirectory = docker.WorkingDirectory != null ? $"-w {docker.WorkingDirectory}" : "";
            var hostname         = "host.docker.internal";
            var dockerImage      = docker.Image ?? service.Description.Name;

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                // See: https://github.com/docker/for-linux/issues/264
                //
                // host.docker.internal is making it's way into linux docker but doesn't work yet
                // instead we use the machine IP
                var addresses = await Dns.GetHostAddressesAsync(Dns.GetHostName());

                hostname = addresses[0].ToString();
            }

            async Task RunDockerContainer(IEnumerable <(int ExternalPort, int Port, int?ContainerPort, string?Protocol)> ports, CancellationToken cancellationToken)
            {
                var hasPorts = ports.Any();

                var replica = service.Description.Name.ToLower() + "_" + Guid.NewGuid().ToString().Substring(0, 10).ToLower();
                var status  = new DockerStatus(service, replica);

                service.Replicas[replica] = status;

                service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Added, status));

                var environment = new Dictionary <string, string>();

                var portString = "";

                if (hasPorts)
                {
                    status.Ports    = ports.Select(p => p.Port);
                    status.Bindings = ports.Select(p => new ReplicaBinding()
                    {
                        Port = p.Port, ExternalPort = p.ExternalPort, Protocol = p.Protocol
                    }).ToList();

                    // These are the ports that the application should use for binding

                    // 1. Tell the docker container what port to bind to
                    portString = docker.Private ? "" : string.Join(" ", ports.Select(p => $"-p {p.Port}:{p.ContainerPort ?? p.Port}"));

                    if (docker.IsAspNet)
                    {
                        // 2. Configure ASP.NET Core to bind to those same ports
                        environment["ASPNETCORE_URLS"] = string.Join(";", ports.Select(p => $"{p.Protocol ?? "http"}://*:{p.ContainerPort ?? p.Port}"));

                        // Set the HTTPS port for the redirect middleware
                        foreach (var p in ports)
                        {
                            if (string.Equals(p.Protocol, "https", StringComparison.OrdinalIgnoreCase))
                            {
                                // We need to set the redirect URL to the exposed port so the redirect works cleanly
                                environment["HTTPS_PORT"] = p.ExternalPort.ToString();
                            }
                        }
                    }

                    // 3. For non-ASP.NET Core apps, pass the same information in the PORT env variable as a semicolon separated list.
                    environment["PORT"] = string.Join(";", ports.Select(p => $"{p.ContainerPort ?? p.Port}"));

                    // This the port for the container proxy (containerport:externalport)
                    environment["PROXY_PORT"] = string.Join(";", ports.Select(p => $"{p.ContainerPort ?? p.Port}:{p.ExternalPort}"));
                }

                // See: https://github.com/docker/for-linux/issues/264
                //
                // The way we do proxying here doesn't really work for multi-container scenarios on linux
                // without some more setup.
                application.PopulateEnvironment(service, (key, value) => environment[key] = value, hostname !);

                environment["APP_INSTANCE"]   = replica;
                environment["CONTAINER_HOST"] = hostname !;

                status.Environment = environment;

                foreach (var pair in environment)
                {
                    environmentArguments += $"-e \"{pair.Key}={pair.Value}\" ";
                }

                foreach (var volumeMapping in docker.VolumeMappings)
                {
                    if (volumeMapping.Source != null)
                    {
                        var sourcePath = Path.GetFullPath(Path.Combine(application.ContextDirectory, volumeMapping.Source));
                        volumes += $"-v \"{sourcePath}:{volumeMapping.Target}\" ";
                    }
                    else if (volumeMapping.Name != null)
                    {
                        volumes += $"-v \"{volumeMapping.Name}:{volumeMapping.Target}\" ";
                    }
                }

                var command = $"run -d {workingDirectory} {volumes} {environmentArguments} {portString} --name {replica} --restart=unless-stopped {dockerImage} {docker.Args ?? ""}";

                _logger.LogInformation("Running image {Image} for {Replica}", docker.Image, replica);

                service.Logs.OnNext($"[{replica}]: docker {command}");

                status.DockerCommand = command;
                status.DockerNetwork = dockerNetwork;

                WriteReplicaToStore(replica);
                var result = await ProcessUtil.RunAsync(
                    "docker",
                    command,
                    throwOnError : false,
                    cancellationToken : cancellationToken,
                    outputDataReceived : data => service.Logs.OnNext($"[{replica}]: {data}"),
                    errorDataReceived : data => service.Logs.OnNext($"[{replica}]: {data}"));

                if (result.ExitCode != 0)
                {
                    _logger.LogError("docker run failed for {ServiceName} with exit code {ExitCode}:" + result.StandardError, service.Description.Name, result.ExitCode);
                    service.Replicas.TryRemove(replica, out var _);
                    service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Removed, status));

                    PrintStdOutAndErr(service, replica, result);
                    return;
                }

                var containerId = (string?)result.StandardOutput.Trim();

                // There's a race condition that sometimes makes us miss the output
                // so keep trying to get the container id
                while (string.IsNullOrEmpty(containerId))
                {
                    // Try to get the ID of the container
                    result = await ProcessUtil.RunAsync("docker", $"ps --no-trunc -f name={replica} --format " + "{{.ID}}");

                    containerId = result.ExitCode == 0 ? result.StandardOutput.Trim() : null;
                }

                var shortContainerId = containerId.Substring(0, Math.Min(12, containerId.Length));

                status.ContainerId = shortContainerId;

                _logger.LogInformation("Running container {ContainerName} with ID {ContainerId}", replica, shortContainerId);

                if (!string.IsNullOrEmpty(dockerNetwork))
                {
                    status.DockerNetworkAlias = docker.NetworkAlias ?? serviceDescription !.Name;

                    var networkCommand = $"network connect {dockerNetwork} {replica} --alias {status.DockerNetworkAlias}";

                    service.Logs.OnNext($"[{replica}]: docker {networkCommand}");

                    _logger.LogInformation("Running docker command {Command}", networkCommand);

                    result = await ProcessUtil.RunAsync("docker", networkCommand);

                    PrintStdOutAndErr(service, replica, result);
                }

                var sentStartedEvent = false;

                while (!cancellationToken.IsCancellationRequested)
                {
                    if (sentStartedEvent)
                    {
                        using var restartCts = new CancellationTokenSource(DockerStopTimeout);
                        result = await ProcessUtil.RunAsync("docker", $"restart {containerId}", throwOnError : false, cancellationToken : restartCts.Token);

                        if (restartCts.IsCancellationRequested)
                        {
                            _logger.LogWarning($"Failed to restart container after {DockerStopTimeout.Seconds} seconds.", replica, shortContainerId);
                            break; // implement retry mechanism?
                        }
                        else if (result.ExitCode != 0)
                        {
                            _logger.LogWarning($"Failed to restart container due to exit code {result.ExitCode}.", replica, shortContainerId);
                            break;
                        }

                        service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Stopped, status));
                    }

                    using var stoppingCts      = new CancellationTokenSource();
                    status.StoppingTokenSource = stoppingCts;
                    service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Started, status));
                    sentStartedEvent = true;

                    await using var _ = cancellationToken.Register(() => status.StoppingTokenSource.Cancel());

                    _logger.LogInformation("Collecting docker logs for {ContainerName}.", replica);

                    var backOff = TimeSpan.FromSeconds(5);

                    while (!status.StoppingTokenSource.Token.IsCancellationRequested)
                    {
                        var logsRes = await ProcessUtil.RunAsync("docker", $"logs -f {containerId}",
                                                                 outputDataReceived : data => service.Logs.OnNext($"[{replica}]: {data}"),
                                                                 errorDataReceived : data => service.Logs.OnNext($"[{replica}]: {data}"),
                                                                 throwOnError : false,
                                                                 cancellationToken : status.StoppingTokenSource.Token);

                        if (logsRes.ExitCode != 0)
                        {
                            break;
                        }

                        if (!status.StoppingTokenSource.IsCancellationRequested)
                        {
                            try
                            {
                                // Avoid spamming logs if restarts are happening
                                await Task.Delay(backOff, status.StoppingTokenSource.Token);
                            }
                            catch (OperationCanceledException)
                            {
                                break;
                            }
                        }

                        backOff *= 2;
                    }

                    _logger.LogInformation("docker logs collection for {ContainerName} complete with exit code {ExitCode}", replica, result.ExitCode);

                    status.StoppingTokenSource = null;
                }

                // Docker has a tendency to get stuck so we're going to timeout this shutdown process
                var timeoutCts = new CancellationTokenSource(DockerStopTimeout);

                _logger.LogInformation("Stopping container {ContainerName} with ID {ContainerId}", replica, shortContainerId);

                result = await ProcessUtil.RunAsync("docker", $"stop {containerId}", throwOnError : false, cancellationToken : timeoutCts.Token);

                if (timeoutCts.IsCancellationRequested)
                {
                    _logger.LogWarning($"Failed to stop container after {DockerStopTimeout.Seconds} seconds, container will most likely be running.", replica, shortContainerId);
                }

                PrintStdOutAndErr(service, replica, result);

                if (sentStartedEvent)
                {
                    service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Stopped, status));
                }

                _logger.LogInformation("Stopped container {ContainerName} with ID {ContainerId} exited with {ExitCode}", replica, shortContainerId, result.ExitCode);

                result = await ProcessUtil.RunAsync("docker", $"rm {containerId}", throwOnError : false, cancellationToken : timeoutCts.Token);

                if (timeoutCts.IsCancellationRequested)
                {
                    _logger.LogWarning($"Failed to remove container after {DockerStopTimeout.Seconds} seconds, container will most likely still exist.", replica, shortContainerId);
                }

                PrintStdOutAndErr(service, replica, result);

                _logger.LogInformation("Removed container {ContainerName} with ID {ContainerId} exited with {ExitCode}", replica, shortContainerId, result.ExitCode);

                service.Replicas.TryRemove(replica, out var _);

                service.ReplicaEvents.OnNext(new ReplicaEvent(ReplicaState.Removed, status));
            };

            async Task DockerBuildAsync(CancellationToken cancellationToken)
            {
                if (docker.DockerFile != null)
                {
                    _logger.LogInformation("Building docker image {Image} from docker file", dockerImage);

                    void Log(string data)
                    {
                        _logger.LogInformation("[" + serviceDescription !.Name + "]:" + data);
                        service.Logs.OnNext(data);
                    }

                    var arguments = new StringBuilder($"build \"{docker.DockerFileContext?.FullName}\" -t {dockerImage} -f \"{docker.DockerFile}\"");

                    foreach (var buildArg in docker.BuildArgs)
                    {
                        arguments.Append($" --build-arg {buildArg.Key}={buildArg.Value}");
                    }

                    var dockerBuildResult = await ProcessUtil.RunAsync(
                        $"docker",
                        arguments.ToString(),
                        outputDataReceived : Log,
                        errorDataReceived : Log,
                        workingDirectory : docker.WorkingDirectory,
                        cancellationToken : cancellationToken,
                        throwOnError : false);

                    if (dockerBuildResult.ExitCode != 0)
                    {
                        throw new CommandException("'docker build' failed.");
                    }
                }
            }

            Task DockerRunAsync(CancellationToken cancellationToken)
            {
                var tasks = new Task[serviceDescription !.Replicas];

                if (serviceDescription.Bindings.Count > 0)
                {
                    // Each replica is assigned a list of internal ports, one mapped to each external
                    // port
                    for (var i = 0; i < serviceDescription.Replicas; i++)
                    {
                        var ports = new List <(int, int, int?, string?)>();
                        foreach (var binding in serviceDescription.Bindings)
                        {
                            if (binding.Port == null)
                            {
                                continue;
                            }

                            ports.Add((binding.Port.Value, binding.ReplicaPorts[i], binding.ContainerPort, binding.Protocol));
                        }

                        tasks[i] = RunDockerContainer(ports, cancellationToken);
                    }
                }
                else
                {
                    for (var i = 0; i < service.Description.Replicas; i++)
                    {
                        tasks[i] = RunDockerContainer(Enumerable.Empty <(int, int, int?, string?)>(), cancellationToken);
                    }
                }

                return(Task.WhenAll(tasks));
            }
예제 #3
0
        protected override async Task ProcessMessage(string json)
        {
            await base.ProcessMessage(json).ConfigureAwait(false);

            var msg    = JsonConvert.DeserializeObject <WebSocketMessage>(json);
            var opCode = (OpCodes)msg.Operation;

            switch (opCode)
            {
            case OpCodes.Ready:
            {
                if (State != ConnectionState.Connected)
                {
                    var payload = (msg.Payload as JToken).ToObject <ReadyEvent>(_serializer);
                    _heartbeatInterval = payload.HeartbeatInterval;
                    _ssrc = payload.SSRC;
                    var address = (await Dns.GetHostAddressesAsync(Host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault();
                    _endpoint = new IPEndPoint(address, payload.Port);

                    if (_config.EnableEncryption)
                    {
                        if (payload.Modes.Contains(EncryptedMode))
                        {
                            _encryptionMode = EncryptedMode;
                            _isEncrypted    = true;
                        }
                        else
                        {
                            throw new InvalidOperationException("Unexpected encryption format.");
                        }
                    }
                    else
                    {
                        _encryptionMode = UnencryptedMode;
                        _isEncrypted    = false;
                    }
                    _udp.Connect(_endpoint);

                    _sequence = 0;        // (ushort)_rand.Next(0, ushort.MaxValue);
                                          //No thread issue here because SendAsync doesn't start until _isReady is true
                    byte[] packet = new byte[70];
                    packet[0] = (byte)((_ssrc >> 24) & 0xFF);
                    packet[1] = (byte)((_ssrc >> 16) & 0xFF);
                    packet[2] = (byte)((_ssrc >> 8) & 0xFF);
                    packet[3] = (byte)((_ssrc >> 0) & 0xFF);
                    await _udp.SendAsync(packet, 70).ConfigureAwait(false);
                }
            }
            break;

            case OpCodes.Heartbeat:
            {
                long time    = EpochTime.GetMilliseconds();
                var  payload = (long)msg.Payload;
                _ping = (int)(payload - time);
                //TODO: Use this to estimate latency
            }
            break;

            case OpCodes.SessionDescription:
            {
                var payload = (msg.Payload as JToken).ToObject <SessionDescriptionEvent>(_serializer);
                _secretKey = payload.SecretKey;
                SendSetSpeaking(true);
                await EndConnect();
            }
            break;

            case OpCodes.Speaking:
            {
                var payload = (msg.Payload as JToken).ToObject <SpeakingEvent>(_serializer);
                RaiseIsSpeaking(payload.UserId, payload.IsSpeaking);
            }
            break;

            default:
                Logger.Warning($"Unknown Opcode: {opCode}");
                break;
            }
        }
예제 #4
0
        internal static async Task <IPAddress> ResolveIPAddress(string addrOrHost, byte[] subnet, AddressFamily family)
        {
            var loopback = family == AddressFamily.InterNetwork ? IPAddress.Loopback : IPAddress.IPv6Loopback;
            IList <IPAddress> nodeIps;

            // if the address is an empty string, just enumerate all ip addresses available
            // on this node
            if (string.IsNullOrEmpty(addrOrHost))
            {
                nodeIps = NetworkInterface.GetAllNetworkInterfaces()
                          .SelectMany(iface => iface.GetIPProperties().UnicastAddresses)
                          .Select(addr => addr.Address)
                          .Where(addr => addr.AddressFamily == family && !IPAddress.IsLoopback(addr))
                          .ToList();
            }
            else
            {
                // Fix StreamFilteringTests_SMS tests
                if (addrOrHost.Equals("loopback", StringComparison.OrdinalIgnoreCase))
                {
                    return(loopback);
                }

                // check if addrOrHost is a valid IP address including loopback (127.0.0.0/8, ::1) and any (0.0.0.0/0, ::) addresses
                IPAddress address;
                if (IPAddress.TryParse(addrOrHost, out address))
                {
                    return(address);
                }

                // Get IP address from DNS. If addrOrHost is localhost will
                // return loopback IPv4 address (or IPv4 and IPv6 addresses if OS is supported IPv6)
                nodeIps = await Dns.GetHostAddressesAsync(addrOrHost);
            }

            var candidates = new List <IPAddress>();

            foreach (var nodeIp in nodeIps.Where(x => x.AddressFamily == family))
            {
                // If the subnet does not match - we can't resolve this address.
                // If subnet is not specified - pick smallest address deterministically.
                if (subnet == null)
                {
                    candidates.Add(nodeIp);
                }
                else
                {
                    var ip = nodeIp;
                    if (subnet.Select((b, i) => ip.GetAddressBytes()[i] == b).All(x => x))
                    {
                        candidates.Add(nodeIp);
                    }
                }
            }
            if (candidates.Count > 0)
            {
                return(PickIPAddress(candidates));
            }
            var subnetStr = Utils.EnumerableToString(subnet, null, ".", false);

            throw new ArgumentException("Hostname '" + addrOrHost + "' with subnet " + subnetStr + " and family " + family + " is not a valid IP address or DNS name");
        }
        /// <summary>
        /// Connects to an endpoint.
        /// </summary>
        public async Task <bool> BeginConnect(Uri endpointUrl, EventHandler <SocketAsyncEventArgs> callback, object state)
        {
            if (endpointUrl == null)
            {
                throw new ArgumentNullException("endpointUrl");
            }

            if (m_socket != null)
            {
                throw new InvalidOperationException("The socket is already connected.");
            }

            // Get DNS host information.
            IPAddress[] hostAdresses = await Dns.GetHostAddressesAsync(endpointUrl.DnsSafeHost);

            // try IPv4 and IPv6 address
            IPAddress addressV4 = null;
            IPAddress addressV6 = null;

            foreach (IPAddress address in hostAdresses)
            {
                if (address.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    if (addressV6 == null)
                    {
                        addressV6 = address;
                    }
                }
                if (address.AddressFamily == AddressFamily.InterNetwork)
                {
                    if (addressV4 == null)
                    {
                        addressV4 = address;
                    }
                }
                if ((addressV4 != null) && (addressV6 != null))
                {
                    break;
                }
            }

            SocketError error = SocketError.NotInitialized;
            TaskCompletionSource <SocketError> tcs = new TaskCompletionSource <SocketError>();
            SocketAsyncEventArgs argsV4            = null;
            SocketAsyncEventArgs argsV6            = null;

            m_socketResponses = 0;

            lock (m_socketLock)
            {
                // ensure a valid port.
                int port = endpointUrl.Port;

                if (port <= 0 || port > UInt16.MaxValue)
                {
                    port = Utils.UaTcpDefaultPort;
                }

                // create sockets if IP address was provided
                if (addressV6 != null)
                {
                    argsV6                = new SocketAsyncEventArgs();
                    argsV6.UserToken      = state;
                    m_socketV6            = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
                    argsV6.RemoteEndPoint = new IPEndPoint(addressV6, port);
                    m_socketResponses++;
                    argsV6.Completed += (o, e) =>
                    {
                        lock (m_socketLock)
                        {
                            m_socketResponses--;
                            if (m_socketV6 != null)
                            {
                                if (m_socket == null &&
                                    (m_socketResponses == 0 || e.SocketError == SocketError.Success))
                                {
                                    m_socket = m_socketV6;
                                    tcs.SetResult(e.SocketError);
                                }
                                else
                                {
                                    m_socketV6.Dispose();
                                    e.UserToken = null;
                                }
                                m_socketV6 = null;
                            }
                            else
                            {
                                e.UserToken = null;
                            }
                        }
                    };
                    argsV6.Completed += callback;
                }
                if (addressV4 != null)
                {
                    argsV4                = new SocketAsyncEventArgs();
                    argsV4.UserToken      = state;
                    m_socketV4            = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    argsV4.RemoteEndPoint = new IPEndPoint(addressV4, port);
                    m_socketResponses++;
                    argsV4.Completed += (o, e) =>
                    {
                        lock (m_socketLock)
                        {
                            m_socketResponses--;
                            if (m_socketV4 != null)
                            {
                                if (m_socket == null &&
                                    (m_socketResponses == 0 || e.SocketError == SocketError.Success))
                                {
                                    m_socket = m_socketV4;
                                    tcs.SetResult(e.SocketError);
                                }
                                else
                                {
                                    m_socketV4.Dispose();
                                    e.UserToken = null;
                                }
                                m_socketV4 = null;
                            }
                            else
                            {
                                e.UserToken = null;
                            }
                        }
                    };
                    argsV4.Completed += callback;
                }

                bool connectV6Sync = true;
                bool connectV4Sync = true;
                if (m_socketV6 != null)
                {
                    connectV6Sync = !m_socketV6.ConnectAsync(argsV6);
                    if (connectV6Sync)
                    {
                        // I/O completed synchronously
                        callback(this, argsV6);
                        error = argsV6.SocketError;
                    }
                }
                if (m_socketV4 != null && error != SocketError.Success)
                {
                    connectV4Sync = !m_socketV4.ConnectAsync(argsV4);
                    if (connectV4Sync)
                    {
                        // I/O completed synchronously
                        callback(this, argsV4);
                        error = argsV4.SocketError;
                    }
                }

                if (connectV4Sync && connectV6Sync)
                {
                    return((error == SocketError.Success) ? true : false);
                }
            }

            error = await tcs.Task;

            return((error == SocketError.Success) ? true : false);
        }
예제 #6
0
        private async Task <string> GetIpAddressFromHostName()
        {
            IPAddress[] addresslist = await Dns.GetHostAddressesAsync(RemoteHostName);

            return(addresslist[0].ToString());
        }
예제 #7
0
 public Task <IPAddress[]> Lookup(string hostname)
 {
     return(Dns.GetHostAddressesAsync(hostname));
 }
예제 #8
0
파일: NetworkManager.cs 프로젝트: vvuk/Emby
        public async Task <IpAddressInfo[]> GetHostAddressesAsync(string host)
        {
            var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);

            return(addresses.Select(ToIpAddressInfo).ToArray());
        }
예제 #9
0
        public static void Main(string[] args)
        {
            string      community      = "public";
            bool        showHelp       = false;
            bool        showVersion    = false;
            VersionCode version        = VersionCode.V1;
            int         timeout        = 1000;
            int         retry          = 0;
            Levels      level          = Levels.Reportable;
            string      user           = string.Empty;
            string      contextName    = string.Empty;
            string      authentication = string.Empty;
            string      authPhrase     = string.Empty;
            string      privacy        = string.Empty;
            string      privPhrase     = string.Empty;
            bool        dump           = false;

            OptionSet p = new OptionSet()
                          .Add("c:", "Community name, (default is public)", delegate(string v) { if (v != null)
                                                                                                 {
                                                                                                     community = v;
                                                                                                 }
                               })
                          .Add("l:", "Security level, (default is noAuthNoPriv)", delegate(string v)
            {
                if (v.ToUpperInvariant() == "NOAUTHNOPRIV")
                {
                    level = Levels.Reportable;
                }
                else if (v.ToUpperInvariant() == "AUTHNOPRIV")
                {
                    level = Levels.Authentication | Levels.Reportable;
                }
                else if (v.ToUpperInvariant() == "AUTHPRIV")
                {
                    level = Levels.Authentication | Levels.Privacy | Levels.Reportable;
                }
                else
                {
                    throw new ArgumentException("no such security mode: " + v);
                }
            })
                          .Add("a:", "Authentication method (MD5 or SHA)", delegate(string v) { authentication = v; })
                          .Add("A:", "Authentication passphrase", delegate(string v) { authPhrase = v; })
                          .Add("x:", "Privacy method", delegate(string v) { privacy = v; })
                          .Add("X:", "Privacy passphrase", delegate(string v) { privPhrase = v; })
                          .Add("u:", "Security name", delegate(string v) { user = v; })
                          .Add("C:", "Context name", delegate(string v) { contextName = v; })
                          .Add("h|?|help", "Print this help information.", delegate(string v) { showHelp = v != null; })
                          .Add("V", "Display version number of this application.", delegate(string v) { showVersion = v != null; })
                          .Add("d", "Display message dump", delegate(string v) { dump = true; })
                          .Add("t:", "Timeout value (unit is second).", delegate(string v) { timeout = int.Parse(v) * 1000; })
                          .Add("r:", "Retry count (default is 0)", delegate(string v) { retry = int.Parse(v); })
                          .Add("v|version:", "SNMP version (1, 2, and 3 are currently supported)", delegate(string v)
            {
                if (v == "2c")
                {
                    v = "2";
                }

                switch (int.Parse(v))
                {
                case 1:
                    version = VersionCode.V1;
                    break;

                case 2:
                    version = VersionCode.V2;
                    break;

                case 3:
                    version = VersionCode.V3;
                    break;

                default:
                    throw new ArgumentException("no such version: " + v);
                }
            });

            if (args.Length == 0)
            {
                ShowHelp(p);
                return;
            }

            List <string> extra;

            try
            {
                extra = p.Parse(args);
            }
            catch (OptionException ex)
            {
                Console.WriteLine(ex.Message);
                return;
            }

            if (showHelp)
            {
                ShowHelp(p);
                return;
            }

            if (extra.Count < 2)
            {
                Console.WriteLine("invalid variable number: " + extra.Count);
                return;
            }

            if (showVersion)
            {
                Console.WriteLine(Assembly.GetEntryAssembly().GetCustomAttribute <AssemblyVersionAttribute>().Version);
                return;
            }

            IPAddress ip;
            bool      parsed = IPAddress.TryParse(extra[0], out ip);

            if (!parsed)
            {
                var addresses = Dns.GetHostAddressesAsync(extra[0]);
                addresses.Wait();
                foreach (IPAddress address in
                         addresses.Result.Where(address => address.AddressFamily == AddressFamily.InterNetwork))
                {
                    ip = address;
                    break;
                }

                if (ip == null)
                {
                    Console.WriteLine("invalid host or wrong IP address found: " + extra[0]);
                    return;
                }
            }

            try
            {
                List <Variable> vList = new List <Variable>();
                for (int i = 1; i < extra.Count; i++)
                {
                    Variable test = new Variable(new ObjectIdentifier(extra[i]));
                    vList.Add(test);
                }

                IPEndPoint receiver = new IPEndPoint(ip, 161);
                if (version != VersionCode.V3)
                {
                    foreach (
                        Variable variable in
                        Messenger.Get(version, receiver, new OctetString(community), vList, timeout))
                    {
                        Console.WriteLine(variable);
                    }

                    return;
                }

                if (string.IsNullOrEmpty(user))
                {
                    Console.WriteLine("User name need to be specified for v3.");
                    return;
                }

                IAuthenticationProvider auth = (level & Levels.Authentication) == Levels.Authentication
                                                   ? GetAuthenticationProviderByName(authentication, authPhrase)
                                                   : DefaultAuthenticationProvider.Instance;

                IPrivacyProvider priv;
                if ((level & Levels.Privacy) == Levels.Privacy)
                {
                    if (DESPrivacyProvider.IsSupported)
                    {
                        priv = new DESPrivacyProvider(new OctetString(privPhrase), auth);
                    }
                    else
                    {
                        Console.WriteLine("DES (ECB) is not supported by .NET Core.");
                        return;
                    }
                }
                else
                {
                    priv = new DefaultPrivacyProvider(auth);
                }

                Discovery     discovery = Messenger.GetNextDiscovery(SnmpType.GetRequestPdu);
                ReportMessage report    = discovery.GetResponse(timeout, receiver);

                GetRequestMessage request = new GetRequestMessage(VersionCode.V3, Messenger.NextMessageId, Messenger.NextRequestId, new OctetString(user), new OctetString(string.IsNullOrWhiteSpace(contextName) ? string.Empty : contextName), vList, priv, Messenger.MaxMessageSize, report);
                ISnmpMessage      reply   = request.GetResponse(timeout, receiver);
                if (dump)
                {
                    Console.WriteLine("Request message bytes:");
                    Console.WriteLine(ByteTool.Convert(request.ToBytes()));
                    Console.WriteLine("Response message bytes:");
                    Console.WriteLine(ByteTool.Convert(reply.ToBytes()));
                }

                if (reply is ReportMessage)
                {
                    if (reply.Pdu().Variables.Count == 0)
                    {
                        Console.WriteLine("wrong report message received");
                        return;
                    }

                    var id = reply.Pdu().Variables[0].Id;
                    if (id != Messenger.NotInTimeWindow)
                    {
                        var error = id.GetErrorMessage();
                        Console.WriteLine(error);
                        return;
                    }

                    // according to RFC 3414, send a second request to sync time.
                    request = new GetRequestMessage(VersionCode.V3, Messenger.NextMessageId, Messenger.NextRequestId, new OctetString(user), new OctetString(string.IsNullOrWhiteSpace(contextName) ? string.Empty : contextName), vList, priv, Messenger.MaxMessageSize, reply);
                    reply   = request.GetResponse(timeout, receiver);
                }
                else if (reply.Pdu().ErrorStatus.ToInt32() != 0) // != ErrorCode.NoError
                {
                    throw ErrorException.Create(
                              "error in response",
                              receiver.Address,
                              reply);
                }

                foreach (Variable v in reply.Pdu().Variables)
                {
                    Console.WriteLine(v);
                }
            }
            catch (SnmpException ex)
            {
                Console.WriteLine(ex);
            }
            catch (SocketException ex)
            {
                Console.WriteLine(ex);
            }
        }
        /// <summary>
        ///     Creates a TCP connection to server
        /// </summary>
        /// <param name="remoteHostName">The remote hostname.</param>
        /// <param name="remotePort">The remote port.</param>
        /// <param name="httpVersion">The http version to use.</param>
        /// <param name="isHttps">Is this a HTTPS request.</param>
        /// <param name="sslProtocol">The SSL protocol.</param>
        /// <param name="applicationProtocols">The list of HTTPS application level protocol to negotiate if needed.</param>
        /// <param name="isConnect">Is this a CONNECT request.</param>
        /// <param name="proxyServer">The current ProxyServer instance.</param>
        /// <param name="sessionArgs">The http session.</param>
        /// <param name="upStreamEndPoint">The local upstream endpoint to make request via.</param>
        /// <param name="externalProxy">The external proxy to make request via.</param>
        /// <param name="cacheKey">The connection cache key</param>
        /// <param name="prefetch">if set to <c>true</c> [prefetch].</param>
        /// <param name="cancellationToken">The cancellation token for this async task.</param>
        /// <returns></returns>
        private async Task <TcpServerConnection?> createServerConnection(string remoteHostName, int remotePort,
                                                                         Version httpVersion, bool isHttps, SslProtocols sslProtocol, List <SslApplicationProtocol>?applicationProtocols, bool isConnect,
                                                                         ProxyServer proxyServer, SessionEventArgsBase sessionArgs, IPEndPoint?upStreamEndPoint, IExternalProxy?externalProxy, string cacheKey,
                                                                         bool prefetch, CancellationToken cancellationToken)
        {
            // deny connection to proxy end points to avoid infinite connection loop.
            if (Server.ProxyEndPoints.Any(x => x.Port == remotePort) &&
                NetworkHelper.IsLocalIpAddress(remoteHostName))
            {
                throw new Exception($"A client is making HTTP request to one of the listening ports of this proxy {remoteHostName}:{remotePort}");
            }

            if (externalProxy != null)
            {
                if (Server.ProxyEndPoints.Any(x => x.Port == externalProxy.Port) &&
                    NetworkHelper.IsLocalIpAddress(externalProxy.HostName))
                {
                    throw new Exception($"A client is making HTTP request via external proxy to one of the listening ports of this proxy {remoteHostName}:{remotePort}");
                }
            }

            if (isHttps && sslProtocol == SslProtocols.None)
            {
                sslProtocol = proxyServer.SupportedSslProtocols;
            }

            bool useUpstreamProxy1 = false;

            // check if external proxy is set for HTTP/HTTPS
            if (externalProxy != null && !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort))
            {
                useUpstreamProxy1 = true;

                // check if we need to ByPass
                if (externalProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName, externalProxy.ProxyDnsRequests))
                {
                    useUpstreamProxy1 = false;
                }
            }

            if (!useUpstreamProxy1)
            {
                externalProxy = null;
            }

            Socket?          tcpServerSocket = null;
            HttpServerStream?stream          = null;

            SslApplicationProtocol negotiatedApplicationProtocol = default;

            bool retry = true;
            var  enabledSslProtocols = sslProtocol;

retry:
            try
            {
                bool   socks    = externalProxy != null && externalProxy.ProxyType != ExternalProxyType.Http;
                string hostname = remoteHostName;
                int    port     = remotePort;

                if (externalProxy != null)
                {
                    hostname = externalProxy.HostName;
                    port     = externalProxy.Port;
                }

                var ipAddresses = await Dns.GetHostAddressesAsync(hostname);

                if (ipAddresses == null || ipAddresses.Length == 0)
                {
                    if (prefetch)
                    {
                        return(null);
                    }

                    throw new Exception($"Could not resolve the hostname {hostname}");
                }

                if (sessionArgs != null)
                {
                    sessionArgs.TimeLine["Dns Resolved"] = DateTime.UtcNow;
                }

                Array.Sort(ipAddresses, (x, y) => x.AddressFamily.CompareTo(y.AddressFamily));

                Exception?lastException = null;
                for (int i = 0; i < ipAddresses.Length; i++)
                {
                    try
                    {
                        var ipAddress     = ipAddresses[i];
                        var addressFamily = upStreamEndPoint?.AddressFamily ?? ipAddress.AddressFamily;

                        if (socks)
                        {
                            var proxySocket = new ProxySocket.ProxySocket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
                            proxySocket.ProxyType = externalProxy !.ProxyType == ExternalProxyType.Socks4
                                ? ProxyTypes.Socks4
                                : ProxyTypes.Socks5;

                            proxySocket.ProxyEndPoint = new IPEndPoint(ipAddress, port);
                            if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null)
                            {
                                proxySocket.ProxyUser = externalProxy.UserName;
                                proxySocket.ProxyPass = externalProxy.Password;
                            }

                            tcpServerSocket = proxySocket;
                        }
                        else
                        {
                            tcpServerSocket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
                        }

                        if (upStreamEndPoint != null)
                        {
                            tcpServerSocket.Bind(upStreamEndPoint);
                        }

                        tcpServerSocket.NoDelay        = proxyServer.NoDelay;
                        tcpServerSocket.ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000;
                        tcpServerSocket.SendTimeout    = proxyServer.ConnectionTimeOutSeconds * 1000;
                        tcpServerSocket.LingerState    = new LingerOption(true, proxyServer.TcpTimeWaitSeconds);

                        if (proxyServer.ReuseSocket && RunTime.IsSocketReuseAvailable)
                        {
                            tcpServerSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                        }

                        Task connectTask;

                        if (socks)
                        {
                            if (externalProxy !.ProxyDnsRequests)
                            {
                                connectTask = ProxySocketConnectionTaskFactory.CreateTask((ProxySocket.ProxySocket)tcpServerSocket, remoteHostName, remotePort);
                            }
                            else
                            {
                                // todo: resolve only once when the SOCKS proxy has multiple addresses (and the first address fails)
                                var remoteIpAddresses = await Dns.GetHostAddressesAsync(remoteHostName);

                                if (remoteIpAddresses == null || remoteIpAddresses.Length == 0)
                                {
                                    throw new Exception($"Could not resolve the SOCKS remote hostname {remoteHostName}");
                                }

                                // todo: use the 2nd, 3rd... remote addresses when first fails
                                connectTask = ProxySocketConnectionTaskFactory.CreateTask((ProxySocket.ProxySocket)tcpServerSocket, remoteIpAddresses[0], remotePort);
                            }
                        }
                        else
                        {
                            connectTask = SocketConnectionTaskFactory.CreateTask(tcpServerSocket, ipAddress, port);
                        }

                        await Task.WhenAny(connectTask, Task.Delay(proxyServer.ConnectTimeOutSeconds * 1000, cancellationToken));

                        if (!connectTask.IsCompleted || !tcpServerSocket.Connected)
                        {
                            // here we can just do some cleanup and let the loop continue since
                            // we will either get a connection or wind up with a null tcpClient
                            // which will throw
                            try
                            {
                                connectTask.Dispose();
                            }
                            catch
                            {
                                // ignore
                            }

                            try
                            {
#if NET45
                                tcpServerSocket?.Close();
#else
                                tcpServerSocket?.Dispose();
#endif
                                tcpServerSocket = null;
                            }
                            catch
                            {
                                // ignore
                            }

                            continue;
                        }

                        break;
                    }
                    catch (Exception e)
                    {
                        // dispose the current TcpClient and try the next address
                        lastException = e;
#if NET45
                        tcpServerSocket?.Close();
#else
                        tcpServerSocket?.Dispose();
#endif
                        tcpServerSocket = null;
                    }
                }
예제 #11
0
        public async Task ConnectAsync_DnsEndPoint_Success(int mode)
        {
            using (var client = new DerivedTcpClient())
            {
                Assert.False(client.Connected);
                Assert.False(client.Active);

                string host = System.Net.Test.Common.Configuration.Sockets.SocketServer.IdnHost;
                int    port = System.Net.Test.Common.Configuration.Sockets.SocketServer.Port;

                IPAddress[] addresses;
                switch (mode)
                {
                case 0:
                    await client.ConnectAsync(host, port);

                    break;

                case 1:
                    addresses = await Dns.GetHostAddressesAsync(host);

                    await client.ConnectAsync(addresses[0], port);

                    break;

                case 2:
                    addresses = await Dns.GetHostAddressesAsync(host);

                    await client.ConnectAsync(addresses, port);

                    break;

                case 3:
                    await Task.Factory.FromAsync(client.BeginConnect, client.EndConnect, host, port, null);

                    break;

                case 4:
                    addresses = await Dns.GetHostAddressesAsync(host);

                    await Task.Factory.FromAsync(client.BeginConnect, client.EndConnect, addresses[0], port, null);

                    break;

                case 5:
                    addresses = await Dns.GetHostAddressesAsync(host);

                    await Task.Factory.FromAsync(client.BeginConnect, client.EndConnect, addresses, port, null);

                    break;

                case 6:
                    await client.ConnectAsync(host, port, CancellationToken.None);

                    break;

                case 7:
                    addresses = await Dns.GetHostAddressesAsync(host);

                    await client.ConnectAsync(addresses[0], port, CancellationToken.None);

                    break;

                case 8:
                    addresses = await Dns.GetHostAddressesAsync(host);

                    await client.ConnectAsync(new IPEndPoint(addresses[0], port));

                    break;

                case 9:
                    addresses = await Dns.GetHostAddressesAsync(host);

                    await client.ConnectAsync(new IPEndPoint(addresses[0], port), CancellationToken.None);

                    break;

                case 10:
                    addresses = await Dns.GetHostAddressesAsync(host);

                    await client.ConnectAsync(addresses, port, CancellationToken.None);

                    break;
                }

                Assert.True(client.Active);
                Assert.True(client.Connected);
                Assert.NotNull(client.Client);
                Assert.Same(client.Client, client.Client);

                using (NetworkStream s = client.GetStream())
                {
                    byte[] getRequest = "GET / HTTP/1.1\r\n\r\n" u8.ToArray();
                    await s.WriteAsync(getRequest, 0, getRequest.Length);

                    Assert.NotEqual(-1, s.ReadByte()); // just verify we successfully get any data back
                }
            }
        }
예제 #12
0
        public static async Task <Socket> ConnectAsync(string host, int port, IPEndPoint localEndPoint, bool doAsync, CancellationToken cancellationToken)
        {
            IPAddress[] ipAddresses;

            cancellationToken.ThrowIfCancellationRequested();

            if (doAsync)
            {
                ipAddresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
            }
            else
            {
                ipAddresses = Dns.GetHostAddressesAsync(host).GetAwaiter().GetResult();
            }

            for (int i = 0; i < ipAddresses.Length; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var socket = new Socket(ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                try {
                    if (localEndPoint != null)
                    {
                        socket.Bind(localEndPoint);
                    }

#if NETSTANDARD_2_0 || NET_4_5 || __MOBILE__
                    if (doAsync || cancellationToken.CanBeCanceled)
                    {
                        var tcs = new TaskCompletionSource <bool> ();

                        using (var registration = cancellationToken.Register(() => tcs.TrySetCanceled(), false)) {
                            var ar = socket.BeginConnect(ipAddresses[i], port, e => tcs.TrySetResult(true), null);

                            if (doAsync)
                            {
                                await tcs.Task.ConfigureAwait(false);
                            }
                            else
                            {
                                tcs.Task.GetAwaiter().GetResult();
                            }

                            socket.EndConnect(ar);
                        }
                    }
                    else
                    {
                        socket.Connect(ipAddresses[i], port);
                    }
#else
                    socket.Connect(ipAddresses[i], port);
#endif

                    return(socket);
                } catch (OperationCanceledException) {
                    socket.Dispose();
                    throw;
                } catch {
                    socket.Dispose();

                    if (i + 1 == ipAddresses.Length)
                    {
                        throw;
                    }
                }
            }

            throw new IOException(string.Format("Failed to resolve host: {0}", host));
        }
예제 #13
0
        /// <summary>
        /// Creates a new Listener obejct from a given listener name and a given listener parameter string.
        /// </summary>
        /// <param name="type">The type of object to instantiate.</param>
        /// <param name="cpars"></param>
        /// <returns></returns>
        public Listener CreateListener(string type, string cpars)
        {
            try
            {
                string[] parts = cpars.Split(';');
                object[] pars = new object[parts.Length];
                string   oval = null, otype = null;
                int      ret;
                // Start instantiating the objects to give to the constructor
                for (int i = 0; i < parts.Length; i++)
                {
                    ret = parts[i].IndexOf(':');
                    if (ret >= 0)
                    {
                        otype = parts[i].Substring(0, ret);
                        oval  = parts[i].Substring(ret + 1);
                    }
                    else
                    {
                        otype = parts[i];
                    }
                    switch (otype.ToLower())
                    {
                    case "int":
                        pars[i] = int.Parse(oval);
                        break;

                    case "host":
                        if (oval == "0.0.0.0")
                        {
                            pars[i] = IPAddress.Any;
                        }
                        else
                        {
                            pars[i] = Dns.GetHostAddressesAsync(oval).Result[0];
                        }
                        break;

                    case "authlist":
                        pars[i] = Config.UserList;
                        break;

                    case "null":
                        pars[i] = null;
                        break;

                    case "string":
                        pars[i] = oval;
                        break;

                    case "ip":
                        pars[i] = IPAddress.Parse(oval);
                        break;

                    default:
                        pars[i] = null;
                        break;
                    }
                }
                return((Listener)Activator.CreateInstance(Type.GetType(type), pars));
            }
            catch (Exception ex)
            {
                Console.WriteLine("[WARN] " + ex.Message + "\r\n" + ex.StackTrace);
                return(null);
            }
        }
예제 #14
0
파일: UPnP.cs 프로젝트: ys8090/NEU
 public static async Task ForwardPortAsync(int port, ProtocolType protocol, string description)
 {
     if (string.IsNullOrEmpty(_serviceUrl))
     {
         throw new Exception("No UPnP service available or Discover() has not been called");
     }
     XmlDocument xdoc = await SOAPRequestAsync(_serviceUrl, "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" +
                                               "<NewRemoteHost></NewRemoteHost><NewExternalPort>" + port.ToString() + "</NewExternalPort><NewProtocol>" + protocol.ToString().ToUpper() + "</NewProtocol>" +
                                               "<NewInternalPort>" + port.ToString() + "</NewInternalPort><NewInternalClient>" + (await Dns.GetHostAddressesAsync(Dns.GetHostName())).First(p => p.AddressFamily == AddressFamily.InterNetwork).ToString() +
                                               "</NewInternalClient><NewEnabled>1</NewEnabled><NewPortMappingDescription>" + description +
                                               "</NewPortMappingDescription><NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping>", "AddPortMapping");
 }
예제 #15
0
        /// <summary>
        ///     Creates a TCP connection to server
        /// </summary>
        /// <param name="remoteHostName">The remote hostname.</param>
        /// <param name="remotePort">The remote port.</param>
        /// <param name="httpVersion">The http version to use.</param>
        /// <param name="isHttps">Is this a HTTPS request.</param>
        /// <param name="applicationProtocols">The list of HTTPS application level protocol to negotiate if needed.</param>
        /// <param name="isConnect">Is this a CONNECT request.</param>
        /// <param name="proxyServer">The current ProxyServer instance.</param>
        /// <param name="session">The http session.</param>
        /// <param name="upStreamEndPoint">The local upstream endpoint to make request via.</param>
        /// <param name="externalProxy">The external proxy to make request via.</param>
        /// <param name="cancellationToken">The cancellation token for this async task.</param>
        /// <returns></returns>
        private async Task <TcpServerConnection> createServerConnection(string remoteHostName, int remotePort,
                                                                        Version httpVersion, bool isHttps, List <SslApplicationProtocol> applicationProtocols, bool isConnect,
                                                                        ProxyServer proxyServer, SessionEventArgsBase session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
                                                                        CancellationToken cancellationToken)
        {
            //deny connection to proxy end points to avoid infinite connection loop.
            if (server.ProxyEndPoints.Any(x => x.Port == remotePort) &&
                NetworkHelper.IsLocalIpAddress(remoteHostName))
            {
                throw new Exception($"A client is making HTTP request to one of the listening ports of this proxy {remoteHostName}:{remotePort}");
            }

            if (externalProxy != null)
            {
                if (server.ProxyEndPoints.Any(x => x.Port == externalProxy.Port) &&
                    NetworkHelper.IsLocalIpAddress(externalProxy.HostName))
                {
                    throw new Exception($"A client is making HTTP request via external proxy to one of the listening ports of this proxy {remoteHostName}:{remotePort}");
                }
            }

            bool useUpstreamProxy = false;

            // check if external proxy is set for HTTP/HTTPS
            if (externalProxy != null &&
                !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort))
            {
                useUpstreamProxy = true;

                // check if we need to ByPass
                if (externalProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName))
                {
                    useUpstreamProxy = false;
                }
            }

            TcpClient            tcpClient = null;
            CustomBufferedStream stream    = null;

            SslApplicationProtocol negotiatedApplicationProtocol = default;

            try
            {
                tcpClient = new TcpClient(upStreamEndPoint)
                {
                    ReceiveTimeout    = proxyServer.ConnectionTimeOutSeconds * 1000,
                    SendTimeout       = proxyServer.ConnectionTimeOutSeconds * 1000,
                    SendBufferSize    = proxyServer.BufferSize,
                    ReceiveBufferSize = proxyServer.BufferSize,
                    LingerState       = new LingerOption(true, proxyServer.TcpTimeWaitSeconds)
                };

                //linux has a bug with socket reuse in .net core.
                if (proxyServer.ReuseSocket && RunTime.IsWindows || RunTime.IsRunningOnMono)
                {
                    tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                }

                var hostname = useUpstreamProxy ? externalProxy.HostName : remoteHostName;
                var port     = useUpstreamProxy ? externalProxy.Port : remotePort;

                var ipAddresses = await Dns.GetHostAddressesAsync(hostname);

                if (ipAddresses == null || ipAddresses.Length == 0)
                {
                    throw new Exception($"Could not resolve the hostname {hostname}");
                }

                if (session != null)
                {
                    session.TimeLine["Dns Resolved"] = DateTime.Now;
                }

                for (int i = 0; i < ipAddresses.Length; i++)
                {
                    try
                    {
                        await tcpClient.ConnectAsync(ipAddresses[i], port);

                        break;
                    }
                    catch (Exception e)
                    {
                        if (i == ipAddresses.Length - 1)
                        {
                            throw new Exception($"Could not establish connection to {hostname}", e);
                        }
                    }
                }

                if (session != null)
                {
                    session.TimeLine["Connection Established"] = DateTime.Now;
                }

                await proxyServer.InvokeConnectionCreateEvent(tcpClient, false);

                stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferPool, proxyServer.BufferSize);

                if (useUpstreamProxy && (isConnect || isHttps))
                {
                    var writer         = new HttpRequestWriter(stream, proxyServer.BufferPool, proxyServer.BufferSize);
                    var connectRequest = new ConnectRequest
                    {
                        OriginalUrl = $"{remoteHostName}:{remotePort}",
                        HttpVersion = httpVersion
                    };

                    connectRequest.Headers.AddHeader(KnownHeaders.Connection, KnownHeaders.ConnectionKeepAlive);

                    if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null)
                    {
                        connectRequest.Headers.AddHeader(HttpHeader.ProxyConnectionKeepAlive);
                        connectRequest.Headers.AddHeader(
                            HttpHeader.GetProxyAuthorizationHeader(externalProxy.UserName, externalProxy.Password));
                    }

                    await writer.WriteRequestAsync(connectRequest, cancellationToken : cancellationToken);

                    string httpStatus = await stream.ReadLineAsync(cancellationToken);

                    Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription);

                    if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK") &&
                        !statusDescription.EqualsIgnoreCase("Connection Established"))
                    {
                        throw new Exception("Upstream proxy failed to create a secure tunnel");
                    }

                    await stream.ReadAndIgnoreAllLinesAsync(cancellationToken);
                }

                if (isHttps)
                {
                    var sslStream = new SslStream(stream, false, proxyServer.ValidateServerCertificate,
                                                  proxyServer.SelectClientCertificate);
                    stream = new CustomBufferedStream(sslStream, proxyServer.BufferPool, proxyServer.BufferSize);

                    var options = new SslClientAuthenticationOptions
                    {
                        ApplicationProtocols           = applicationProtocols,
                        TargetHost                     = remoteHostName,
                        ClientCertificates             = null,
                        EnabledSslProtocols            = proxyServer.SupportedSslProtocols,
                        CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation
                    };
                    await sslStream.AuthenticateAsClientAsync(options, cancellationToken);

#if NETCOREAPP2_1
                    negotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif

                    if (session != null)
                    {
                        session.TimeLine["HTTPS Established"] = DateTime.Now;
                    }
                }
            }
            catch (Exception)
            {
                stream?.Dispose();
                tcpClient?.Close();
                throw;
            }

            return(new TcpServerConnection(proxyServer, tcpClient)
            {
                UpStreamProxy = externalProxy,
                UpStreamEndPoint = upStreamEndPoint,
                HostName = remoteHostName,
                Port = remotePort,
                IsHttps = isHttps,
                NegotiatedApplicationProtocol = negotiatedApplicationProtocol,
                UseUpstreamProxy = useUpstreamProxy,
                StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferPool, proxyServer.BufferSize),
                Stream = stream,
                Version = httpVersion
            });
        }
        private async Task <RegistrationOperationStatus> ProvisionOverTcpCommonAsync(
            ProvisioningTransportRegisterMessage message,
            ClientTlsSettings tlsSettings,
            CancellationToken cancellationToken)
        {
            var tcs = new TaskCompletionSource <RegistrationOperationStatus>();

            Bootstrap bootstrap = new Bootstrap()
                                  .Group(s_eventLoopGroup)
                                  .Channel <TcpSocketChannel>()
                                  .Option(ChannelOption.TcpNodelay, true)
                                  .Option(ChannelOption.Allocator, UnpooledByteBufferAllocator.Default)
                                  .Handler(new ActionChannelInitializer <ISocketChannel>(ch =>
            {
                ch.Pipeline.AddLast(
                    new ReadTimeoutHandler(ReadTimeoutSeconds),
                    new TlsHandler(tlsSettings),
                    MqttEncoder.Instance,
                    new MqttDecoder(isServer: false, maxMessageSize: MaxMessageSize),
                    new LoggingHandler(LogLevel.DEBUG),
                    new ProvisioningChannelHandlerAdapter(message, tcs, cancellationToken));
            }));

            if (Logging.IsEnabled)
            {
                Logging.Associate(bootstrap, this);
            }

            IPAddress[] addresses = await Dns.GetHostAddressesAsync(message.GlobalDeviceEndpoint).ConfigureAwait(false);

            if (Logging.IsEnabled)
            {
                Logging.Info(this, $"DNS resolved {addresses.Length} addresses.");
            }

            IChannel  channel       = null;
            Exception lastException = null;

            foreach (IPAddress address in addresses)
            {
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    if (Logging.IsEnabled)
                    {
                        Logging.Info(this, $"Connecting to {address.ToString()}.");
                    }
                    channel = await bootstrap.ConnectAsync(address, Port).ConfigureAwait(false);

                    break;
                }
                catch (AggregateException ae)
                {
                    ae.Handle((ex) =>
                    {
                        if (ex is ConnectException)     // We will handle DotNetty.Transport.Channels.ConnectException
                        {
                            lastException = ex;
                            if (Logging.IsEnabled)
                            {
                                Logging.Info(
                                    this,
                                    $"ConnectException trying to connect to {address.ToString()}: {ex.ToString()}");
                            }
                            return(true);
                        }

                        return(false); // Let anything else stop the application.
                    });
                }
            }

            if (channel == null)
            {
                string errorMessage = "Cannot connect to Provisioning Service.";
                if (Logging.IsEnabled)
                {
                    Logging.Error(this, errorMessage);
                }
                ExceptionDispatchInfo.Capture(lastException).Throw();
            }

            return(await tcs.Task.ConfigureAwait(false));
        }
예제 #17
0
        private async Task <bool> OpenTcpSocketAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            foreach (var hostname in cs.Hostnames)
            {
                IPAddress[] ipAddresses;
                try
                {
#if NETSTANDARD1_3
// Dns.GetHostAddresses isn't available until netstandard 2.0: https://github.com/dotnet/corefx/pull/11950
                    ipAddresses = await Dns.GetHostAddressesAsync(hostname).ConfigureAwait(false);
#else
                    if (ioBehavior == IOBehavior.Asynchronous)
                    {
                        ipAddresses = await Dns.GetHostAddressesAsync(hostname).ConfigureAwait(false);
                    }
                    else
                    {
                        ipAddresses = Dns.GetHostAddresses(hostname);
                    }
#endif
                }
                catch (SocketException)
                {
                    // name couldn't be resolved
                    continue;
                }

                // need to try IP Addresses one at a time: https://github.com/dotnet/corefx/issues/5829
                foreach (var ipAddress in ipAddresses)
                {
                    TcpClient tcpClient = null;
                    try
                    {
                        tcpClient = new TcpClient(ipAddress.AddressFamily);

                        using (cancellationToken.Register(() => tcpClient?.Client?.Dispose()))
                        {
                            try
                            {
                                if (ioBehavior == IOBehavior.Asynchronous)
                                {
                                    await tcpClient.ConnectAsync(ipAddress, cs.Port).ConfigureAwait(false);
                                }
                                else
                                {
#if NETSTANDARD1_3
                                    await tcpClient.ConnectAsync(ipAddress, cs.Port).ConfigureAwait(false);
#else
                                    if (Utility.IsWindows())
                                    {
                                        tcpClient.Connect(ipAddress, cs.Port);
                                    }
                                    else
                                    {
                                        // non-windows platforms block on synchronous connect, use send/receive timeouts: https://github.com/dotnet/corefx/issues/20954
                                        var originalSendTimeout    = tcpClient.Client.SendTimeout;
                                        var originalReceiveTimeout = tcpClient.Client.ReceiveTimeout;
                                        tcpClient.Client.SendTimeout    = cs.ConnectionTimeoutMilliseconds;
                                        tcpClient.Client.ReceiveTimeout = cs.ConnectionTimeoutMilliseconds;
                                        tcpClient.Connect(ipAddress, cs.Port);
                                        tcpClient.Client.SendTimeout    = originalSendTimeout;
                                        tcpClient.Client.ReceiveTimeout = originalReceiveTimeout;
                                    }
#endif
                                }
                            }
                            catch (ObjectDisposedException ex) when(cancellationToken.IsCancellationRequested)
                            {
                                throw new MySqlException("Connect Timeout expired.", ex);
                            }
                        }
                    }
                    catch (SocketException)
                    {
                        tcpClient?.Client?.Dispose();
                        continue;
                    }

                    m_hostname      = hostname;
                    m_tcpClient     = tcpClient;
                    m_socket        = m_tcpClient.Client;
                    m_networkStream = m_tcpClient.GetStream();
                    SerializationUtility.SetKeepalive(m_socket, cs.Keepalive);
                    lock (m_lock)
                        m_state = State.Connected;
                    return(true);
                }
            }
            return(false);
        }
예제 #18
0
        public async Task <IPEndPoint> ResolveAsync(string endpoint, int port, IPVersion ipVersion = IPVersion.IPV4, CancellationToken token = default(CancellationToken))
        {
            string cacheKey = $"{endpoint}:{port}:{ipVersion}";

            if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
            {
                throw new ArgumentOutOfRangeException(nameof(port));
            }

            if (cache.HasKey(cacheKey))
            {
                return(cache.Get <IPEndPoint>(cacheKey));
            }

            var addressFamily = ipVersion.HasFlag(IPVersion.IPV4)
                ? AddressFamily.InterNetwork
                : AddressFamily.InterNetworkV6;


            token.ThrowIfCancellationRequested();

            IPEndPoint ipEndpoint;

            var ipAddress = TryGetIpAddress(endpoint);

            if (ipAddress != null)
            {
                ipEndpoint = new IPEndPoint(ipAddress, port);
                cache.Add(cacheKey, ipEndpoint, TimeSpan.FromMinutes(60));
                return(ipEndpoint);
            }

            try
            {
                var allAddresses = await Dns.GetHostAddressesAsync(endpoint);

                var firstAddressInFamily = allAddresses.FirstOrDefault(x => x.AddressFamily == addressFamily);
                if (firstAddressInFamily != null)
                {
                    ipEndpoint = new IPEndPoint(firstAddressInFamily, port);
                    cache.Add(cacheKey, ipEndpoint, TimeSpan.FromMinutes(60));
                    return(ipEndpoint);
                }


                if (addressFamily == AddressFamily.InterNetwork && ipVersion.HasFlag(IPVersion.IPV6))
                {
                    ipEndpoint = await ResolveAsync(endpoint, port, IPVersion.IPV6, token);

                    if (ipEndpoint != null)
                    {
                        cache.Add(cacheKey, ipEndpoint, TimeSpan.FromMinutes(60));
                        return(ipEndpoint);
                    }
                }

                var firstAddress = allAddresses.FirstOrDefault();
                if (firstAddress == null)
                {
                    return(null);
                }

                switch (firstAddress.AddressFamily)
                {
                case AddressFamily.InterNetwork:
                    ipEndpoint = new IPEndPoint(firstAddress.MapToIPv6(), port);
                    break;

                case AddressFamily.InterNetworkV6:
                    ipEndpoint = new IPEndPoint(firstAddress.MapToIPv4(), port);
                    break;

                default:
                    return(null);
                }

                cache.Add(cacheKey, ipEndpoint, TimeSpan.FromMinutes(60));

                return(ipEndpoint);
            }
            catch
            {
                return(null);
            }
        }
예제 #19
0
 /// <summary>
 /// Resolves a hostname to an IP-Address.
 /// If an IP-Address is given the IP-Address will be returned.
 /// </summary>
 public static string ResolveToIp(string hostOrIp)
 {
     return(Dns.GetHostAddressesAsync(hostOrIp).Result.First().ToString());
 }
예제 #20
0
        private void InitEnvorimentAndVerify()
        {
            if (Entities == null || Entities.Count == 0)
            {
                this.Log("Count of entity is 0.", LogLevel.Error);
                throw new SpiderException("Count of entity is 0.");
            }

            if (EntityPipelines == null || EntityPipelines.Count == 0)
            {
                this.Log("Need at least one entity pipeline.", LogLevel.Error);
                throw new SpiderException("Need at least one entity pipeline.");
            }

            if (RedialExecutor != null)
            {
                RedialExecutor.Init();
                NetworkCenter.Current.Executor = RedialExecutor;
            }

            if (string.IsNullOrEmpty(RedisHost))
            {
                RedisHost     = Configuration.GetValue("redisHost");
                RedisPassword = Configuration.GetValue("redisPassword");
                int port;
                RedisPort = int.TryParse(Configuration.GetValue("redisPort"), out port) ? port : 6379;
            }

            if (!string.IsNullOrEmpty(RedisHost))
            {
                var confiruation = new ConfigurationOptions()
                {
                    ServiceName     = "DotnetSpider",
                    Password        = RedisPassword,
                    ConnectTimeout  = 65530,
                    KeepAlive       = 8,
                    ConnectRetry    = 3,
                    ResponseTimeout = 3000
                };
#if NET_CORE
                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    // Lewis: This is a Workaround for .NET CORE can't use EndPoint to create Socket.
                    var address = Dns.GetHostAddressesAsync(RedisHost).Result.FirstOrDefault();
                    if (address == null)
                    {
                        this.Log($"Can't resovle host: {RedisHost}", LogLevel.Error);
                        throw new SpiderException($"Can't resovle host: {RedisHost}");
                    }
                    confiruation.EndPoints.Add(new IPEndPoint(address, RedisPort));
                }
                else
                {
                    confiruation.EndPoints.Add(new DnsEndPoint(RedisHost, RedisPort));
                }
#else
                confiruation.EndPoints.Add(new DnsEndPoint(RedisHost, RedisPort));
#endif
                Redis = ConnectionMultiplexer.Connect(confiruation);
                Db    = Redis.GetDatabase(1);
            }
        }
예제 #21
0
        public async Task <IActionResult> Maintenance(MaintenanceViewModel vm, string command)
        {
            if (!ModelState.IsValid)
            {
                return(View(vm));
            }
            vm.SetConfiguredSSH(_Options.SSHSettings);
            if (command == "changedomain")
            {
                if (string.IsNullOrWhiteSpace(vm.DNSDomain))
                {
                    ModelState.AddModelError(nameof(vm.DNSDomain), $"Required field");
                    return(View(vm));
                }
                vm.DNSDomain = vm.DNSDomain.Trim().ToLowerInvariant();
                if (vm.DNSDomain.Equals(this.Request.Host.Host, StringComparison.OrdinalIgnoreCase))
                {
                    return(View(vm));
                }
                if (IPAddress.TryParse(vm.DNSDomain, out var unused))
                {
                    ModelState.AddModelError(nameof(vm.DNSDomain), $"This should be a domain name");
                    return(View(vm));
                }
                if (vm.DNSDomain.Equals(this.Request.Host.Host, StringComparison.InvariantCultureIgnoreCase))
                {
                    ModelState.AddModelError(nameof(vm.DNSDomain), $"The server is already set to use this domain");
                    return(View(vm));
                }
                var builder = new UriBuilder();
                using (var client = new HttpClient(new HttpClientHandler()
                {
                    ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
                }))
                {
                    try
                    {
                        builder.Scheme = this.Request.Scheme;
                        builder.Host   = vm.DNSDomain;
                        var addresses1 = Dns.GetHostAddressesAsync(this.Request.Host.Host);
                        var addresses2 = Dns.GetHostAddressesAsync(vm.DNSDomain);
                        await Task.WhenAll(addresses1, addresses2);

                        var addressesSet     = addresses1.GetAwaiter().GetResult().Select(c => c.ToString()).ToHashSet();
                        var hasCommonAddress = addresses2.GetAwaiter().GetResult().Select(c => c.ToString()).Any(s => addressesSet.Contains(s));
                        if (!hasCommonAddress)
                        {
                            ModelState.AddModelError(nameof(vm.DNSDomain), $"Invalid host ({vm.DNSDomain} is not pointing to this BTCPay instance)");
                            return(View(vm));
                        }
                    }
                    catch (Exception ex)
                    {
                        var messages = new List <object>();
                        messages.Add(ex.Message);
                        if (ex.InnerException != null)
                        {
                            messages.Add(ex.InnerException.Message);
                        }
                        ModelState.AddModelError(nameof(vm.DNSDomain), $"Invalid domain ({string.Join(", ", messages.ToArray())})");
                        return(View(vm));
                    }
                }

                var error = RunSSH(vm, $"changedomain.sh {vm.DNSDomain}");
                if (error != null)
                {
                    return(error);
                }

                builder.Path  = null;
                builder.Query = null;
                StatusMessage = $"Domain name changing... the server will restart, please use \"{builder.Uri.AbsoluteUri}\"";
            }
            else if (command == "update")
            {
                var error = RunSSH(vm, $"btcpay-update.sh");
                if (error != null)
                {
                    return(error);
                }
                StatusMessage = $"The server might restart soon if an update is available...";
            }
            else
            {
                return(NotFound());
            }
            return(RedirectToAction(nameof(Maintenance)));
        }
예제 #22
0
 private static Task <IPAddress[]> GetIpAddresses(string hostName)
 {
     return(Dns.GetHostAddressesAsync(hostName));
 }
예제 #23
0
        /// <summary>
        ///     This is called when client is aware of proxy
        ///     So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
        /// </summary>
        /// <param name="endPoint">The explicit endpoint.</param>
        /// <param name="clientConnection">The client connection.</param>
        /// <returns>The task.</returns>
        private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection)
        {
            var cancellationTokenSource = new CancellationTokenSource();
            var cancellationToken       = cancellationTokenSource.Token;

            var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken);

            Task <TcpServerConnection>?prefetchConnectionTask = null;
            bool closeServerConnection = false;

            try
            {
                TunnelConnectSessionEventArgs?connectArgs = null;

                var method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken);

                if (clientStream.IsClosed)
                {
                    return;
                }

                // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
                if (method == KnownMethod.Connect)
                {
                    // read the first line HTTP command
                    var requestLine = await clientStream.ReadRequestLine(cancellationToken);

                    if (requestLine.IsEmpty())
                    {
                        return;
                    }

                    var connectRequest = new ConnectRequest(requestLine.RequestUri)
                    {
                        RequestUriString8 = requestLine.RequestUri,
                        HttpVersion       = requestLine.Version
                    };

                    await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken);

                    connectArgs             = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest, clientStream, cancellationTokenSource);
                    clientStream.DataRead  += (o, args) => connectArgs.OnDataSent(args.Buffer, args.Offset, args.Count);
                    clientStream.DataWrite += (o, args) => connectArgs.OnDataReceived(args.Buffer, args.Offset, args.Count);

                    await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc);

                    // filter out excluded host names
                    bool decryptSsl  = endPoint.DecryptSsl && connectArgs.DecryptSsl;
                    bool sendRawData = !decryptSsl;

                    if (connectArgs.DenyConnect)
                    {
                        if (connectArgs.HttpClient.Response.StatusCode == 0)
                        {
                            connectArgs.HttpClient.Response = new Response
                            {
                                HttpVersion       = HttpHeader.Version11,
                                StatusCode        = (int)HttpStatusCode.Forbidden,
                                StatusDescription = "Forbidden"
                            };
                        }

                        // send the response
                        await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken);

                        return;
                    }

                    if (await checkAuthorization(connectArgs) == false)
                    {
                        await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc);

                        // send the response
                        await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken);

                        return;
                    }

                    // write back successful CONNECT response
                    var response = ConnectResponse.CreateSuccessfulConnectResponse(connectRequest.HttpVersion);

                    // Set ContentLength explicitly to properly handle HTTP 1.0
                    response.ContentLength = 0;
                    response.Headers.FixProxyHeaders();
                    connectArgs.HttpClient.Response = response;

                    await clientStream.WriteResponseAsync(response, cancellationToken);

                    var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);

                    if (clientStream.IsClosed)
                    {
                        return;
                    }

                    bool isClientHello = clientHelloInfo != null;
                    if (clientHelloInfo != null)
                    {
                        connectRequest.TunnelType      = TunnelType.Https;
                        connectRequest.ClientHelloInfo = clientHelloInfo;
                    }

                    await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello);

                    if (decryptSsl && clientHelloInfo != null)
                    {
                        connectRequest.IsHttps = true; // todo: move this line to the previous "if"
                        clientStream.Connection.SslProtocol = clientHelloInfo.SslProtocol;

                        bool http2Supported = false;

                        if (EnableHttp2)
                        {
                            var alpn = clientHelloInfo.GetAlpn();
                            if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2))
                            {
                                // test server HTTP/2 support
                                try
                                {
                                    // todo: this is a hack, because Titanium does not support HTTP protocol changing currently
                                    var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
                                                                                                    true, SslExtensions.Http2ProtocolAsList,
                                                                                                    true, cancellationToken);

                                    http2Supported = connection.NegotiatedApplicationProtocol ==
                                                     SslApplicationProtocol.Http2;

                                    // release connection back to pool instead of closing when connection pool is enabled.
                                    await tcpConnectionFactory.Release(connection, true);
                                }
                                catch (Exception)
                                {
                                    // ignore
                                }
                            }
                        }

                        if (EnableTcpServerConnectionPrefetch)
                        {
                            IPAddress[]? ipAddresses = null;
                            try
                            {
                                // make sure the host can be resolved before creating the prefetch task
                                ipAddresses = await Dns.GetHostAddressesAsync(connectArgs.HttpClient.Request.RequestUri.Host);
                            }
                            catch (SocketException) { }

                            if (ipAddresses != null && ipAddresses.Length > 0)
                            {
                                // don't pass cancellation token here
                                // it could cause floating server connections when client exits
                                prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs,
                                                                                                  true, null, false,
                                                                                                  CancellationToken.None);
                            }
                        }

                        string connectHostname = requestLine.RequestUri.GetString();
                        int    idx             = connectHostname.IndexOf(":");
                        if (idx >= 0)
                        {
                            connectHostname = connectHostname.Substring(0, idx);
                        }

                        X509Certificate2?certificate = null;
                        SslStream?       sslStream   = null;
                        try
                        {
                            sslStream = new SslStream(clientStream, false);

                            string certName = HttpHelper.GetWildCardDomainName(connectHostname);
                            certificate = endPoint.GenericCertificate ??
                                          await CertificateManager.CreateServerCertificate(certName);

                            // Successfully managed to authenticate the client using the fake certificate
                            var options = new SslServerAuthenticationOptions();
                            if (EnableHttp2 && http2Supported)
                            {
                                options.ApplicationProtocols = clientHelloInfo.GetAlpn();
                                if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0)
                                {
                                    options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList;
                                }
                            }

                            options.ServerCertificate              = certificate;
                            options.ClientCertificateRequired      = false;
                            options.EnabledSslProtocols            = SupportedSslProtocols;
                            options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck;
                            await sslStream.AuthenticateAsServerAsync(options, cancellationToken);

#if NETSTANDARD2_1
                            clientStream.Connection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif

                            // HTTPS server created - we can now decrypt the client's traffic
                            clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool, cancellationToken);
                            sslStream    = null; // clientStream was created, no need to keep SSL stream reference

                            clientStream.DataRead  += (o, args) => connectArgs.OnDecryptedDataSent(args.Buffer, args.Offset, args.Count);
                            clientStream.DataWrite += (o, args) => connectArgs.OnDecryptedDataReceived(args.Buffer, args.Offset, args.Count);
                        }
                        catch (Exception e)
                        {
                            sslStream?.Dispose();

                            var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false);
                            throw new ProxyConnectException(
                                      $"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs);
                        }

                        method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken);

                        if (clientStream.IsClosed)
                        {
                            return;
                        }

                        if (method == KnownMethod.Invalid)
                        {
                            sendRawData = true;
                            await tcpConnectionFactory.Release(prefetchConnectionTask, true);

                            prefetchConnectionTask = null;
                        }
                    }
                    else if (clientHelloInfo == null)
                    {
                        method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken);

                        if (clientStream.IsClosed)
                        {
                            return;
                        }
                    }

                    if (cancellationTokenSource.IsCancellationRequested)
                    {
                        throw new Exception("Session was terminated by user.");
                    }

                    if (method == KnownMethod.Invalid)
                    {
                        sendRawData = true;
                    }

                    // Hostname is excluded or it is not an HTTPS connect
                    if (sendRawData)
                    {
                        // create new connection to server.
                        // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
                        // this connection should not be HTTPS.
                        var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
                                                                                        true, null,
                                                                                        true, cancellationToken);

                        try
                        {
                            if (isClientHello)
                            {
                                int available = clientStream.Available;
                                if (available > 0)
                                {
                                    // send the buffered data
                                    var data = BufferPool.GetBuffer();

                                    try
                                    {
                                        // clientStream.Available should be at most BufferSize because it is using the same buffer size
                                        int read = await clientStream.ReadAsync(data, 0, available, cancellationToken);

                                        if (read != available)
                                        {
                                            throw new Exception("Internal error.");
                                        }

                                        await connection.Stream.WriteAsync(data, 0, available, true, cancellationToken);
                                    }
                                    finally
                                    {
                                        BufferPool.ReturnBuffer(data);
                                    }
                                }

                                var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken);

                                ((ConnectResponse)connectArgs.HttpClient.Response).ServerHelloInfo = serverHelloInfo;
                            }

                            if (!clientStream.IsClosed && !connection.Stream.IsClosed)
                            {
                                await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool,
                                                        null, null, connectArgs.CancellationTokenSource, ExceptionFunc);
                            }
                        }
                        finally
                        {
                            await tcpConnectionFactory.Release(connection, true);
                        }

                        return;
                    }
                }

                if (connectArgs != null && method == KnownMethod.Pri)
                {
                    // todo
                    string?httpCmd = await clientStream.ReadLineAsync(cancellationToken);

                    if (httpCmd == "PRI * HTTP/2.0")
                    {
                        connectArgs.HttpClient.ConnectRequest !.TunnelType = TunnelType.Http2;

                        // HTTP/2 Connection Preface
                        string?line = await clientStream.ReadLineAsync(cancellationToken);

                        if (line != string.Empty)
                        {
                            throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
                        }

                        line = await clientStream.ReadLineAsync(cancellationToken);

                        if (line != "SM")
                        {
                            throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received");
                        }

                        line = await clientStream.ReadLineAsync(cancellationToken);

                        if (line != string.Empty)
                        {
                            throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
                        }

                        var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
                                                                                        true, SslExtensions.Http2ProtocolAsList,
                                                                                        true, cancellationToken);

                        try
                        {
#if NETSTANDARD2_1
                            var connectionPreface = new ReadOnlyMemory <byte>(Http2Helper.ConnectionPreface);
                            await connection.Stream.WriteAsync(connectionPreface, cancellationToken);

                            await Http2Helper.SendHttp2(clientStream, connection.Stream,
                                                        () => new SessionEventArgs(this, endPoint, clientStream, connectArgs?.HttpClient.ConnectRequest, cancellationTokenSource)
                            {
                                UserData = connectArgs?.UserData
                            },
                                                        async args => { await onBeforeRequest(args); },
                                                        async args => { await onBeforeResponse(args); },
                                                        connectArgs.CancellationTokenSource, clientStream.Connection.Id, ExceptionFunc);
#endif
                        }
                        finally
                        {
                            await tcpConnectionFactory.Release(connection, true);
                        }
                    }
                }

                var prefetchTask = prefetchConnectionTask;
                prefetchConnectionTask = null;

                // Now create the request
                await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource, connectArgs, prefetchTask);
            }
            catch (ProxyException e)
            {
                closeServerConnection = true;
                onException(clientStream, e);
            }
            catch (IOException e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Connection was aborted", e));
            }
            catch (SocketException e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Could not connect", e));
            }
            catch (Exception e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Error occured in whilst handling the client", e));
            }
            finally
            {
                if (!cancellationTokenSource.IsCancellationRequested)
                {
                    cancellationTokenSource.Cancel();
                }

                await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection);

                clientStream.Dispose();
            }
        }
예제 #24
0
        protected async Task EnsureConnected()
        {
            try
            {
                if (IsConnected())
                {
                    return;
                }

                // Recreate the TCP client
                this.stream?.Dispose();
                this.client?.Close();

                // Allow connections to be made via IPv4 or IPv6. With just the default constructor,
                // only IPv4 can be used. To support both, we must specify the AddressFamily.InterNetworkV6
                // and set the DualMode property on the underlying socket to true. The DualMode property
                // can only be set to true when the AddressFamily is set to InterNetworkV6.
                //
                // But there is another caveat. If you call the .Connect() method overload that takes in a
                // DNS host name and port number, that method's code will first make a call to resolve the
                // DNS host name to an IP address (or addresses). It then validates that one of the resolved
                // IP addresses' AddressFamily type matches the AddressFamily type that was specified when
                // the TcpClient was constructed. If it doesn't find a match, for example, because we specify
                // AddressFamily.InterNetworkV6 and the DNS host name only resolves to an IPv4 address, it
                // will throw an error. Essentially, the .Connect() method that takes in a DNS host name and
                // port does not take into consideration the DualMode property that we set to true.
                //
                // All other .Connect() methods take in some form of IPAddress/IPEndPoint, which gets passed
                // directly down to the underlying socket, which is where the DualMode property exists.
                // Therefore, it is properly utilized and will work with either IPv4 or IPv6.
                //
                // So, we will make a call to resolve the DNS host name ourselves and call the .Connect()
                // method that takes in the array of IP addresses. That way, it will try each of them and will
                // work regardless of if the DNS host name resolved to an IPv4 or IPv6.
                this.client = new TcpClient(AddressFamily.InterNetworkV6);
                this.client.Client.DualMode = true;

                // If the Host name specified is already an IP address, then that is what will be returned.
                var hostAddresses = await Dns.GetHostAddressesAsync(this.Host).ConfigureAwait(false);

                // If we're running on Linux, only try to set keep-alives if they are wanted (in
                // that case we resolved the hostname to an IP in the ctor)
                // See https://github.com/dotnet/corefx/issues/26840
                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || this.enableKeepAlive)
                {
                    this.client.Client.SetSocketOption(SocketOptionLevel.Socket,
                                                       SocketOptionName.KeepAlive, this.enableKeepAlive);
                }

                // Reduce latency to a minimum
                this.client.NoDelay = true;

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    // Windows can support multiple connection attempts, thereby allowing us to pass in an
                    // array of addresses. See:
                    // https://github.com/dotnet/runtime/blob/release/5.0/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs#L5071
                    await this.client.ConnectAsync(hostAddresses, this.Port).ConfigureAwait(false);
                }
                else
                {
                    // However, multiple connection attempts is not guaranteed on other platforms. So we'll
                    // be cautious and only use the first IP address. If for whatever reason the caller was
                    // hoping that the second or some other IP address would be used, then they will just
                    // have to change their DNS so that the IP address they want will be resolved with the
                    // highest priority.
                    await this.client.ConnectAsync(hostAddresses.First(), this.Port).ConfigureAwait(false);
                }

                this.stream = await GetStream(this.client.GetStream()).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                // Attempt to provide meaningful diagnostic messages for common connection problems
                HandleConnectError(ex);
                throw;
            }
        }
예제 #25
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="serverName">Server name</param>
        /// <param name="port">TCP port number</param>
        /// <param name="timerExpire">Connection timer expiration</param>
        /// <param name="callbackObject">Callback object</param>
        public SNITCPHandle(string serverName, int port, long timerExpire, object callbackObject, bool parallel)
        {
            _writeScheduler   = new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler;
            _writeTaskFactory = new TaskFactory(_writeScheduler);
            _callbackObject   = callbackObject;
            _targetServer     = serverName;

            try
            {
                TimeSpan ts = default(TimeSpan);

                // In case the Timeout is Infinite, we will receive the max value of Int64 as the tick count
                // The infinite Timeout is a function of ConnectionString Timeout=0
                bool isInfiniteTimeOut = long.MaxValue == timerExpire;
                if (!isInfiniteTimeOut)
                {
                    ts = DateTime.FromFileTime(timerExpire) - DateTime.Now;
                    ts = ts.Ticks < 0 ? TimeSpan.FromTicks(0) : ts;
                }

                Task <Socket> connectTask;
                if (parallel)
                {
                    Task <IPAddress[]> serverAddrTask = Dns.GetHostAddressesAsync(serverName);
                    serverAddrTask.Wait(ts);
                    IPAddress[] serverAddresses = serverAddrTask.Result;

                    if (serverAddresses.Length > MaxParallelIpAddresses)
                    {
                        // Fail if above 64 to match legacy behavior
                        ReportTcpSNIError(0, SNICommon.MultiSubnetFailoverWithMoreThan64IPs, string.Empty);
                        return;
                    }

                    connectTask = ParallelConnectAsync(serverAddresses, port);
                }
                else
                {
                    connectTask = ConnectAsync(serverName, port);
                }

                if (!(isInfiniteTimeOut ? connectTask.Wait(-1) : connectTask.Wait(ts)))
                {
                    ReportTcpSNIError(0, SNICommon.ConnOpenFailedError, string.Empty);
                    return;
                }

                _socket = connectTask.Result;
                if (_socket == null || !_socket.Connected)
                {
                    if (_socket != null)
                    {
                        _socket.Dispose();
                        _socket = null;
                    }
                    ReportTcpSNIError(0, SNICommon.ConnOpenFailedError, string.Empty);
                    return;
                }

                _socket.NoDelay = true;
                _tcpStream      = new NetworkStream(_socket, true);

                _sslOverTdsStream = new SslOverTdsStream(_tcpStream);
                _sslStream        = new SslStream(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
            }
            catch (SocketException se)
            {
                ReportTcpSNIError(se);
                return;
            }
            catch (Exception e)
            {
                ReportTcpSNIError(e);
                return;
            }

            _stream = _tcpStream;
            _status = TdsEnums.SNI_SUCCESS;
        }
예제 #26
0
        private async Task InitializeOnceAsync(CancellationToken cancellationToken)
        {
            // Build the options for our Redis client.
            var redisOptions = new ConfigurationOptions
            {
                ResolveDns = true,
                Password   = configuration.RedisPassword
            };

            // Resolve the IPs for all the Redis servers.
            var resolveServersTasks = this.configuration.RedisServers.Select(kv =>
                                                                             new KeyValuePair <Task <IPAddress[]>, int>(Dns.GetHostAddressesAsync(kv.Key), kv.Value)).ToList();

            await Task.WhenAll(resolveServersTasks.Select(kv => kv.Key));

            // Add them to the Redis options.
            var ipRedisServers = resolveServersTasks
                                 .Where(t => t.Key.Result != null)
                                 .SelectMany(kv => kv.Key.Result
                                             .Where(ip => ip.AddressFamily == AddressFamily.InterNetwork)
                                             .Select(ip => new KeyValuePair <IPAddress, int>(ip, kv.Value)))
                                 .ToList();

            foreach (var kv in ipRedisServers)
            {
                redisOptions.EndPoints.Add(kv.Key, kv.Value);
            }

            // Try to connect to the redis instance.
            var connection = await ConnectionMultiplexer.ConnectAsync(redisOptions);

            this.database = connection.GetDatabase();

            // Create the resource store based on that connection.
            this.Users = new RedisCacheStore <CacheUser>(this.jsonHelpers, this.configuration, this.database);
        }
예제 #27
0
 public Task <IPAddress[]> GetHostAddressesAsync(string hostNameOrAddress)
 {
     return(Dns.GetHostAddressesAsync(hostNameOrAddress));
 }
예제 #28
0
        /// <summary>
        /// Connect to the specified host
        /// </summary>
        /// <param name="host">The host to connect to</param>
        /// <param name="port">The port to connect to</param>
        /// <param name="ipVersions">Internet Protocol versions to support during the connection phase</param>
        /// <param name="token">Cancellation Token</param>
        public async Task ConnectAsync(string host, int port, FtpIpVersion ipVersions, CancellationToken token)
        {
            IPAddress[] addresses = await Dns.GetHostAddressesAsync(host);

            if (ipVersions == 0)
            {
                throw new ArgumentException("The ipVersions parameter must contain at least 1 flag.");
            }
            for (int i = 0; i < addresses.Length; i++)
            {
                // we don't need to do this check unless
                // a particular version of IP has been
                // omitted so we won't.
                if (ipVersions != FtpIpVersion.ANY)
                {
                    switch (addresses[i].AddressFamily)
                    {
                    case AddressFamily.InterNetwork:
                        if ((ipVersions & FtpIpVersion.IPv4) != FtpIpVersion.IPv4)
                        {
#if DEBUG
                            this.Client.LogStatus(FtpTraceLevel.Verbose, "Skipped IPV4 address : " + addresses[i].ToString());
#endif
                            continue;
                        }
                        break;

                    case AddressFamily.InterNetworkV6:
                        if ((ipVersions & FtpIpVersion.IPv6) != FtpIpVersion.IPv6)
                        {
#if DEBUG
                            this.Client.LogStatus(FtpTraceLevel.Verbose, "Skipped IPV6 address : " + addresses[i].ToString());
#endif
                            continue;
                        }
                        break;
                    }
                }

                if (FtpTrace.LogIP)
                {
                    this.Client.LogStatus(FtpTraceLevel.Info, "Connecting to " + addresses[i].ToString() + ":" + port);
                }
                else
                {
                    this.Client.LogStatus(FtpTraceLevel.Info, "Connecting to ***:" + port);
                }

                m_socket = new Socket(addresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);
#if CORE
                await EnableCancellation(m_socket.ConnectAsync(addresses[i], port), token, () => m_socket.Dispose());

                break;
#else
                var connectResult = m_socket.BeginConnect(addresses[i], port, null, null);
                await EnableCancellation(Task.Factory.FromAsync(connectResult, m_socket.EndConnect), token, () => m_socket.Close());

                break;
#endif
            }

            // make sure that we actually connected to
            // one of the addresses returned from GetHostAddresses()
            if (m_socket == null || !m_socket.Connected)
            {
                Close();
                throw new IOException("Failed to connect to host.");
            }

            m_netStream             = new NetworkStream(m_socket);
            m_netStream.ReadTimeout = m_readTimeout;
            m_lastActivity          = DateTime.Now;
        }
예제 #29
0
        /// <summary>
        /// Connect to the specified host
        /// </summary>
        /// <param name="host">The host to connect to</param>
        /// <param name="port">The port to connect to</param>
        /// <param name="ipVersions">Internet Protocol versions to support during the connection phase</param>
        public void Connect(string host, int port, FtpIpVersion ipVersions)
        {
#if CORE
            IPAddress[] addresses = Dns.GetHostAddressesAsync(host).Result;
#else
            IAsyncResult ar        = null;
            IPAddress[]  addresses = Dns.GetHostAddresses(host);
#endif

            if (ipVersions == 0)
            {
                throw new ArgumentException("The ipVersions parameter must contain at least 1 flag.");
            }

            for (int i = 0; i < addresses.Length; i++)
            {
                // we don't need to do this check unless
                // a particular version of IP has been
                // omitted so we won't.
                if (ipVersions != FtpIpVersion.ANY)
                {
                    switch (addresses[i].AddressFamily)
                    {
                    case AddressFamily.InterNetwork:
                        if ((ipVersions & FtpIpVersion.IPv4) != FtpIpVersion.IPv4)
                        {
#if DEBUG
                            FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Skipped IPV4 address : " + addresses[i].ToString());
#endif
                            continue;
                        }
                        break;

                    case AddressFamily.InterNetworkV6:
                        if ((ipVersions & FtpIpVersion.IPv6) != FtpIpVersion.IPv6)
                        {
#if DEBUG
                            FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Skipped IPV6 address : " + addresses[i].ToString());
#endif
                            continue;
                        }
                        break;
                    }
                }

                if (FtpTrace.LogIP)
                {
                    FtpTrace.WriteStatus(FtpTraceLevel.Info, "Connecting to " + addresses[i].ToString() + ":" + port);
                }
                else
                {
                    FtpTrace.WriteStatus(FtpTraceLevel.Info, "Connecting to ***:" + port);
                }

                m_socket = new Socket(addresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);
#if CORE
                m_socket.ConnectAsync(addresses[i], port).Wait();
                break;
#else
                ar = m_socket.BeginConnect(addresses[i], port, null, null);
                if (!ar.AsyncWaitHandle.WaitOne(m_connectTimeout, true))
                {
                    Close();

                    // check to see if we're out of addresses, and throw a TimeoutException
                    if ((i + 1) == addresses.Length)
                    {
                        throw new TimeoutException("Timed out trying to connect!");
                    }
                }
                else
                {
                    m_socket.EndConnect(ar);
                    // we got a connection, break out
                    // of the loop.
                    break;
                }
#endif
            }

            // make sure that we actually connected to
            // one of the addresses returned from GetHostAddresses()
            if (m_socket == null || !m_socket.Connected)
            {
                Close();
                throw new IOException("Failed to connect to host.");
            }

            m_netStream             = new NetworkStream(m_socket);
            m_netStream.ReadTimeout = m_readTimeout;
            m_lastActivity          = DateTime.Now;
        }
예제 #30
0
 public async Task Dns_GetHostAddressesAsync_NullHost_Fail()
 {
     await Assert.ThrowsAsync <ArgumentNullException>(() => Dns.GetHostAddressesAsync(null));
 }