private HttpClient GetHttpClient(IProxyConfiguration proxy)
        {
            if (proxy.NewHttpClient)
            {
                return(new HttpClient(CreateHandler(proxy)));
            }
            if (_httpHandlers.TryGetValue(proxy.Target, out var httpHandler))
            {
                return(new HttpClient(httpHandler));
            }
            lock (_syncRoot) {
                if (_httpHandlers.TryGetValue(proxy.Target, out httpHandler))
                {
                    return(new HttpClient(httpHandler));
                }

                httpHandler = CreateHandler(proxy);
                _logger.LogInformation("HttpMessageHandler created");

                var newDictionary = new Dictionary <string, HttpMessageHandler>(StringComparer.Ordinal);
                foreach (var kv in _httpHandlers)
                {
                    newDictionary.Add(kv.Key, kv.Value);
                }
                newDictionary.Add(proxy.Target, httpHandler);
                Interlocked.MemoryBarrier();
                _httpHandlers = newDictionary;
            }
            return(new HttpClient(httpHandler));
        }
        public ProxyTypeGenerator(IProxyConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            _moduleBuilder = configuration.ProxyModuleBuilder;
        }
Beispiel #3
0
 public ProxyProvider(IProxyConfiguration configuration,
                      IProxyCollection collection,
                      IProxyTypeGenerator typeGenerator,
                      IProxyValidator validator)
 {
     _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
     _collection    = collection ?? throw new ArgumentNullException(nameof(collection));
     _generator     = typeGenerator ?? throw new ArgumentNullException(nameof(typeGenerator));
     _validator     = validator ?? throw new ArgumentNullException(nameof(validator));
 }
 public ProxyProvider(IProxyConfiguration configuration, bool isValid)
 {
     _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
     _collection    = new ProxyCollection();
     _generator     = new ProxyTypeGenerator(configuration);
     if (isValid)
     {
         _validator = new ProxyValidator();
     }
 }
Beispiel #5
0
        public IProxyFlare Use(IProxyConfigurationFactory configurationFactory)
        {
            if (configurationFactory == null)
            {
                throw new ArgumentNullException(nameof(configurationFactory));
            }

            _configuration = configurationFactory.BuildConfiguration();
            return(this);
        }
        public void When_ProxyConfiguration_Is_Null_Then_Constructor_Throws_ArgumentNullException()
        {
            // set up
            IProxyConfiguration proxyConfiguration = null;

            // execute
            var ex = Assert.Throws <ArgumentNullException>(() => new HttpClientCreator(proxyConfiguration));

            // verify
            Assert.Equal("proxyConfiguration", ex.ParamName);
        }
        private HttpMessageHandler CreateHandler(IProxyConfiguration proxy)
        {
            var handler = new SocketsHttpHandler()
            {
                AllowAutoRedirect      = false,
                UseProxy               = true,
                UseCookies             = false,
                AutomaticDecompression = DecompressionMethods.None,
            };

            handler.SslOptions.ApplicationProtocols = new List <SslApplicationProtocol>()
            {
                SslApplicationProtocol.Http11, SslApplicationProtocol.Http2
            };
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                handler.SslOptions.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12;
            }
            else
            {
                handler.SslOptions.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls13;
            }
            if (proxy.DisableTlsValidation)
            {
                handler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
            }
            else
            {
                handler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => ValidateServerCertificate(certificate, chain, sslPolicyErrors, proxy);
            }
            handler.UseProxy = proxy.UseProxy;
            if (proxy.UseProxy && !string.IsNullOrEmpty(proxy.ProxyUrl))
            {
                if (!Uri.TryCreate(proxy.ProxyUrl, UriKind.Absolute, out var proxyUri))
                {
                    throw new InvalidOperationException($"Invalid proxy url '{proxy.ProxyUrl}'.");
                }
                handler.Proxy = new CustomProxy(proxyUri);
            }

            //var handler = new HttpClientHandler() {
            //	AllowAutoRedirect = false,
            //	UseProxy = true,
            //	UseCookies = false,
            //	AutomaticDecompression = DecompressionMethods.None,
            //	SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
            //	ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => ValidateServerCertificate(certificate, chain, sslPolicyErrors, proxy)
            //};

            return(handler);
        }
 public HttpClientCreator(IProxyConfiguration proxyConfiguration)
 {
     _proxyConfiguration = proxyConfiguration ?? throw new ArgumentNullException(nameof(proxyConfiguration));
 }
Beispiel #9
0
 public ErrorController(IProxyConfiguration configuration, IErrorPoster errorPoster)
 {
     _configuration = configuration;
     _errorPoster = errorPoster;
 }
Beispiel #10
0
 public IProxyTypeGenerator BuilderTypeGenerator(IProxyConfiguration configuration)
 {
     return(new ProxyTypeGenerator(configuration));
 }
        private async Task Proxy(IProxyConfiguration proxy, HttpContext context)
        {
            var    id   = Guid.NewGuid().ToString("D");
            string path = context.Request.Path + context.Request.QueryString;

            //_logger.LogInformation($"{id} start {context.Request.Method} {path}");

            path = CommonUtility.CombineWithSlash(proxy.Target, path.Substring(proxy.Path.Length));

            if (context.WebSockets.IsWebSocketRequest)
            {
                await HandleWebSocket(id, proxy, path, context);

                return;
            }

            HttpRequestMessage request = new HttpRequestMessage(GetHttpMethod(context.Request.Method, out var hasBody), path);

            //request.Version = HttpVersion.Version11;

            if (!hasBody.HasValue)
            {
                hasBody = context.Request.Headers.ContainsKey("Transfer-Encoding") || context.Request.Headers.ContainsKey("Content-Length");
            }
            HttpContent content = null;

            if (hasBody.Value)
            {
                content         = new StreamContent(context.Request.Body);
                request.Content = content;
            }

            if (proxy.Headers != null)
            {
                foreach (var kv in proxy.Headers)
                {
                    bool success;
                    if (kv.Key.StartsWith("Content-", StringComparison.Ordinal))
                    {
                        success = content?.Headers.TryAddWithoutValidation(kv.Key, kv.Value) ?? false;
                    }
                    else
                    {
                        success = request.Headers.TryAddWithoutValidation(kv.Key, kv.Value);
                    }
                    if (!success)
                    {
                        _logger.LogWarning($"Failed to add header {kv.Key}: {kv.Value}.");
                    }
                }
            }

            foreach (var kv in context.Request.Headers)
            {
                if (proxy.RemoveHeaders != null)
                {
                    if (proxy.RemoveHeaders.Contains(kv.Key))
                    {
                        continue;
                    }
                }
                // strip 'Transfer-Encoding: chunked' the whole request is send, we are not a transport level proxy
                if (string.Equals("Transfer-Encoding", kv.Key, StringComparison.Ordinal) ||
                    string.Equals("Expect", kv.Key, StringComparison.Ordinal) ||
                    string.Equals("Host", kv.Key, StringComparison.Ordinal))
                //string.Equals("Connection", kv.Key, StringComparison.Ordinal))
                {
                    _logger.LogDebug($"Stripping request {kv.Key}: {kv.Value}");
                    continue;
                }

                bool success;
                // Content-Length, Content-Type
                if (kv.Key.StartsWith("Content-", StringComparison.Ordinal))
                {
                    success = content?.Headers.TryAddWithoutValidation(kv.Key, (IEnumerable <string>)kv.Value) ?? false;
                }
                else
                {
                    success = request.Headers.TryAddWithoutValidation(kv.Key, (IEnumerable <string>)kv.Value);
                }
                if (!success && !kv.Key.StartsWith(":", StringComparison.Ordinal))
                {
                    _logger.LogWarning($"Failed to add header {kv.Key}: {kv.Value}.");
                }
            }

            var client = GetHttpClient(proxy);

            try {
                Task <HttpResponseMessage> responseTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
                HttpResponseMessage        response     = null;
                try {
                    response = await responseTask.ConfigureAwait(false);
                }
                catch (Exception ex) {
                    _logger.LogInformation($"{id} failed {context.Request.Method} {path} - {ex.Message}");
                    throw;
                }

                using (response) {
                    context.Response.StatusCode = (int)response.StatusCode;

                    foreach (var header in response.Headers)
                    {
                        // strip 'Transfer-Encoding: chunked' the whole response is read, we are not a transport level proxy
                        if (string.Equals("Transfer-Encoding", header.Key, StringComparison.Ordinal) ||
                            string.Equals("Expect", header.Key, StringComparison.Ordinal) ||
                            string.Equals("Host", header.Key, StringComparison.Ordinal))
                        //string.Equals("Connection", header.Key, StringComparison.Ordinal))
                        {
                            _logger.LogDebug($"Stripping response {header.Key}: {string.Join(", ", header.Value)}");
                            continue;
                        }
                        context.Response.Headers[header.Key] = header.Value.ToArray();
                    }

                    foreach (var header in response.Content.Headers)
                    {
                        context.Response.Headers[header.Key] = header.Value.ToArray();
                    }

                    using (var stream = await response.Content.ReadAsStreamAsync()) {
                        await stream.CopyToAsync(context.Response.Body);
                    }

                    //_logger.LogInformation($"{id} done {(int)response.StatusCode} {context.Request.Method} {path}");
                }
            }
            finally {
                if (proxy.NewHttpClient)
                {
                    client.Dispose();
                }
            }
        }
 public IntegratedTokenProvider(IProxyConfiguration proxyConfiguration)
 {
     this.ProxyConfiguration = proxyConfiguration;
 }
        private bool ValidateServerCertificate(X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors, IProxyConfiguration proxy)
        {
            // special handling for IP SAN
            if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch)
            {
                var certificate2 = (X509Certificate2)certificate;

                X509Chain chain2 = new X509Chain();
                chain2.ChainPolicy = chain.ChainPolicy;
                var result = chain2.Build(certificate2);
                if (!result)
                {
                    LogInvalidCertificate(certificate, chain2);
                    return(false);
                }

                HashSet <string> serverIps   = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
                HashSet <string> serverNames = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
                var uccSan = certificate2.Extensions["2.5.29.17"];
                if (uccSan != null)
                {
                    foreach (string nvp in uccSan.Format(true).Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (nvp.StartsWith("IP Address=", StringComparison.Ordinal))
                        {
                            var serverName = nvp.Substring(11);
                            if (!serverIps.Contains(serverName))
                            {
                                serverIps.Add(serverName);
                            }
                        }
                        else if (nvp.StartsWith("DNS Name=", StringComparison.Ordinal))
                        {
                            var serverName = nvp.Substring(9);
                            if (!serverIps.Contains(serverName))
                            {
                                serverNames.Add(serverName);
                            }
                        }
                    }
                }

                int    end       = proxy.Target.IndexOf("/", 8);
                string proxyHost = end > 0 ? proxy.Target.Substring(8, end - 8) : proxy.Target.Substring(8);
                if (!serverIps.Contains(proxyHost) && !(!string.IsNullOrEmpty(proxy.OverrideHost) && serverNames.Contains(proxy.OverrideHost)))
                {
                    _logger.LogWarning(string.Format("Failed to validate certificate '{0}'. expected: {1}" + (string.IsNullOrEmpty(proxy.OverrideHost) ? string.Empty : " or {2}") + ", serverIps: [{3}], serverNames: [{4}]", certificate.Subject, proxyHost, proxy.OverrideHost, string.Join(", ", serverIps), string.Join(", ", serverNames)));
                    return(false);
                }

                LogValidCertificate(certificate, chain);
                return(true);
            }
            // regular certificate validation
            if (sslPolicyErrors != SslPolicyErrors.None)
            {
                LogInvalidCertificate(certificate, sslPolicyErrors, chain);
                return(false);
            }
            LogValidCertificate(certificate, chain);
            return(true);
        }
Beispiel #14
0
 public ProductAPIProxy(IProxyConfiguration configuration, Func <Type, MediaTypeFormatter> getFormatter, IHttpClientFactory factory)
 {
     _configuration = configuration;
     _getFormatter  = getFormatter;
     _factory       = factory;
 }
Beispiel #15
0
 // The ProxyConfiguration and Proxy will be injected the the DI framework
 public HomeController(IProxyConfiguration proxyConfiguration, IProxy proxy)
 {
     this.injectedProxyConfiguration = proxyConfiguration;
     this.injectedProxy = proxy;
 }
 public IProxyProvider BuilderProvider(IProxyConfiguration configuration)
 {
     return(new ProxyProvider(configuration, _isValid));
 }
 public ServiceAccountTokenProvider(IProxyConfiguration proxyConfiguration)
 {
     this.ProxyConfiguration = proxyConfiguration;
 }
        private async Task HandleWebSocket(string id, IProxyConfiguration proxy, string path, HttpContext context)
        {
            using (var localSocket = await context.WebSockets.AcceptWebSocketAsync()) {
                _logger.LogInformation($"{id} accepted websocket connection {proxy.Path}");

                using (var remoteSocket = new ClientWebSocket()) {
                    foreach (var kv in context.Request.Headers)
                    {
                        if (proxy.RemoveHeaders != null)
                        {
                            if (proxy.RemoveHeaders.Contains(kv.Key))
                            {
                                continue;
                            }
                        }
                        // strip 'Transfer-Encoding: chunked' the whole request is send, we are not a transport level proxy
                        if (string.Equals("Transfer-Encoding", kv.Key, StringComparison.Ordinal) ||
                            string.Equals("Expect", kv.Key, StringComparison.Ordinal) ||
                            string.Equals("Host", kv.Key, StringComparison.Ordinal) ||
                            string.Equals("Connection", kv.Key, StringComparison.Ordinal) ||
                            string.Equals("Upgrade", kv.Key, StringComparison.Ordinal) ||
                            kv.Key.StartsWith("Sec-WebSocket-", StringComparison.Ordinal))
                        {
                            _logger.LogDebug($"Stripping request {kv.Key}: {kv.Value}");
                            continue;
                        }

                        remoteSocket.Options.SetRequestHeader(kv.Key, kv.Value);
                    }

                    if (proxy.DisableTlsValidation)
                    {
                        remoteSocket.Options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
                    }
                    else
                    {
                        remoteSocket.Options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => ValidateServerCertificate(certificate, chain, sslPolicyErrors, proxy);
                    }
                    if (!proxy.UseProxy)
                    {
                        remoteSocket.Options.Proxy = new NoProxy();
                    }
                    //else {
                    //	remoteSocket.Options.Proxy = HttpClient.DefaultProxy;
                    //}
                    if (proxy.UseProxy && !string.IsNullOrEmpty(proxy.ProxyUrl))
                    {
                        if (!Uri.TryCreate(proxy.ProxyUrl, UriKind.Absolute, out var proxyUri))
                        {
                            throw new InvalidOperationException($"Invalid proxy url '{proxy.ProxyUrl}'.");
                        }
                        remoteSocket.Options.Proxy = new CustomProxy(proxyUri);
                    }

                    if (path.StartsWith("https://", StringComparison.Ordinal))
                    {
                        await remoteSocket.ConnectAsync(new Uri("wss" + path.Substring(5), UriKind.Absolute), CancellationToken.None);
                    }
                    else if (path.StartsWith("http://", StringComparison.Ordinal))
                    {
                        await remoteSocket.ConnectAsync(new Uri("ws" + path.Substring(4), UriKind.Absolute), CancellationToken.None);
                    }
                    else
                    {
                        throw new NotSupportedException(proxy.Target);
                    }

                    _logger.LogInformation($"{id} connected to remote websocket {path}");

                    var buffer1 = new byte[1024];
                    var buffer2 = new byte[1024];

                    var task1 = localSocket.ReceiveAsync(buffer1, context.RequestAborted);
                    var task2 = remoteSocket.ReceiveAsync(buffer2, context.RequestAborted);

                    while (true)
                    {
                        var completed = await Task.WhenAny(task1, task2);

                        if (completed.Status != TaskStatus.RanToCompletion)
                        {
                            _logger.LogInformation(completed.Exception, $"{id} websocket did not complete {path}");
                            return;
                        }

                        WebSocket socket1;
                        WebSocket socket2;
                        byte[]    buffer;

                        if (completed == task1)
                        {
                            socket1 = localSocket;
                            socket2 = remoteSocket;
                            buffer  = buffer1;
                        }
                        else if (completed == task2)
                        {
                            socket1 = remoteSocket;
                            socket2 = localSocket;
                            buffer  = buffer2;
                        }
                        else
                        {
                            throw new InvalidOperationException("WhenAny unknown task");
                        }

                        var close   = false;
                        var message = completed.Result;
                        while (true)
                        {
                            if (message.MessageType == WebSocketMessageType.Close)
                            {
                                close = true;
                            }

                            await socket2.SendAsync(new ArraySegment <byte>(buffer, 0, message.Count),
                                                    message.MessageType,
                                                    message.EndOfMessage,
                                                    context.RequestAborted);

                            if (message.EndOfMessage)
                            {
                                break;
                            }

                            message = await socket1.ReceiveAsync(buffer, context.RequestAborted);
                        }

                        if (close)
                        {
                            await socket2.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, message.CloseStatusDescription, context.RequestAborted);

                            return;
                        }

                        var newTask = socket1.ReceiveAsync(buffer, context.RequestAborted);
                        if (completed == task1)
                        {
                            task1 = newTask;
                        }
                        else if (completed == task2)
                        {
                            task1 = newTask;
                        }
                    }
                }
            }
        }