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; }
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(); } }
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)); }
public ErrorController(IProxyConfiguration configuration, IErrorPoster errorPoster) { _configuration = configuration; _errorPoster = errorPoster; }
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); }
public ProductAPIProxy(IProxyConfiguration configuration, Func <Type, MediaTypeFormatter> getFormatter, IHttpClientFactory factory) { _configuration = configuration; _getFormatter = getFormatter; _factory = factory; }
// 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; } } } } }