public void ApplyForwarders(HttpContext context) { // Gather expected headers. Enabled headers must have the same number of entries. string[] forwardedFor = null, forwardedProto = null, forwardedHost = null; bool checkFor = false, checkProto = false, checkHost = false; int entryCount = 0; if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedFor) == ForwardedHeaders.XForwardedFor) { checkFor = true; forwardedFor = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName); entryCount = Math.Max(forwardedFor.Length, entryCount); } if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedProto) == ForwardedHeaders.XForwardedProto) { checkProto = true; forwardedProto = context.Request.Headers.GetCommaSeparatedValues(XForwardedProtoHeaderName); if (_options.RequireHeaderSymmetry && checkFor && forwardedFor.Length != forwardedProto.Length) { _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); return; } entryCount = Math.Max(forwardedProto.Length, entryCount); } if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedHost) == ForwardedHeaders.XForwardedHost) { checkHost = true; forwardedHost = context.Request.Headers.GetCommaSeparatedValues(XForwardedHostHeaderName); if (_options.RequireHeaderSymmetry && ((checkFor && forwardedFor.Length != forwardedHost.Length) || (checkProto && forwardedProto.Length != forwardedHost.Length))) { _logger.LogDebug(1, "Parameter count mismatch between X-Forwarded-Host and X-Forwarded-For or X-Forwarded-Proto."); return; } entryCount = Math.Max(forwardedHost.Length, entryCount); } // Apply ForwardLimit, if any if (_options.ForwardLimit.HasValue && entryCount > _options.ForwardLimit) { entryCount = _options.ForwardLimit.Value; } // Group the data together. var sets = new SetOfForwarders[entryCount]; for (int i = 0; i < sets.Length; i++) { // They get processed in reverse order, right to left. var set = new SetOfForwarders(); if (checkFor && i < forwardedFor.Length) { set.IpAndPortText = forwardedFor[forwardedFor.Length - i - 1]; } if (checkProto && i < forwardedProto.Length) { set.Scheme = forwardedProto[forwardedProto.Length - i - 1]; } if (checkHost && i < forwardedHost.Length) { set.Host = forwardedHost[forwardedHost.Length - i - 1]; } sets[i] = set; } // Gather initial values var connection = context.Connection; var request = context.Request; var currentValues = new SetOfForwarders() { RemoteIpAndPort = connection.RemoteIpAddress != null ? new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort) : null, // Host and Scheme initial values are never inspected, no need to set them here. }; var checkKnownIps = _options.KnownNetworks.Count > 0 || _options.KnownProxies.Count > 0; bool applyChanges = false; int entriesConsumed = 0; for ( ; entriesConsumed < sets.Length; entriesConsumed++) { var set = sets[entriesConsumed]; if (checkFor) { // For the first instance, allow remoteIp to be null for servers that don't support it natively. if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address)) { // Stop at the first unknown remote IP, but still apply changes processed so far. _logger.LogDebug(1, $"Unknown proxy: {currentValues.RemoteIpAndPort}"); break; } IPEndPoint parsedEndPoint; if (IPEndPointParser.TryParse(set.IpAndPortText, out parsedEndPoint)) { applyChanges = true; set.RemoteIpAndPort = parsedEndPoint; currentValues.IpAndPortText = set.IpAndPortText; currentValues.RemoteIpAndPort = set.RemoteIpAndPort; } else if (_options.RequireHeaderSymmetry) { _logger.LogDebug(2, $"Failed to parse forwarded IPAddress: {currentValues.IpAndPortText}"); return; } } if (checkProto) { if (!string.IsNullOrEmpty(set.Scheme)) { applyChanges = true; currentValues.Scheme = set.Scheme; } else if (_options.RequireHeaderSymmetry) { _logger.LogDebug(3, $"Failed to parse forwarded scheme: {set.Scheme}"); return; } } if (checkHost) { if (!string.IsNullOrEmpty(set.Host)) { applyChanges = true; currentValues.Host = set.Host; } else if (_options.RequireHeaderSymmetry) { _logger.LogDebug(4, $"Failed to parse forwarded host: {set.Host}"); return; } } } if (applyChanges) { if (checkFor && currentValues.RemoteIpAndPort != null) { if (connection.RemoteIpAddress != null) { // Save the original request.Headers[XOriginalForName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString(); } if (forwardedFor.Length > entriesConsumed) { // Truncate the consumed header values request.Headers[XForwardedForHeaderName] = forwardedFor.Take(forwardedFor.Length - entriesConsumed).ToArray(); } else { // All values were consumed request.Headers.Remove(XForwardedForHeaderName); } connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address; connection.RemotePort = currentValues.RemoteIpAndPort.Port; } if (checkProto && currentValues.Scheme != null) { // Save the original request.Headers[XOriginalProtoName] = request.Scheme; if (forwardedProto.Length > entriesConsumed) { // Truncate the consumed header values request.Headers[XForwardedProtoHeaderName] = forwardedProto.Take(forwardedProto.Length - entriesConsumed).ToArray(); } else { // All values were consumed request.Headers.Remove(XForwardedProtoHeaderName); } request.Scheme = currentValues.Scheme; } if (checkHost && currentValues.Host != null) { // Save the original request.Headers[XOriginalHostName] = request.Host.ToString(); if (forwardedHost.Length > entriesConsumed) { // Truncate the consumed header values request.Headers[XForwardedHostHeaderName] = forwardedHost.Take(forwardedHost.Length - entriesConsumed).ToArray(); } else { // All values were consumed request.Headers.Remove(XForwardedHostHeaderName); } request.Host = HostString.FromUriComponent(currentValues.Host); } } }
/// <summary> /// ApplyForwarders /// </summary> public void ApplyForwarders(HttpContext context) { // Gather expected headers. string[] forwardedFor = null, forwardedPathBase = null, forwardedUrlBase = null; bool chenckPathBase = false, checkUrlBase = false; int entryCount = 0; forwardedFor = context.Request.Headers.GetCommaSeparatedValues(BasicForwardedHeadersDefaults.XForwardedForHeaderName); if (forwardedFor.Length == 0) // 已经有一个代理 { forwardedFor = context.Request.Headers.GetCommaSeparatedValues(BasicForwardedHeadersDefaults.XOriginalForHeaderName); } if ((_options.ForwardedHeaders & BasicForwardedHeaders.XForwardedPathBase) == BasicForwardedHeaders.XForwardedPathBase) { chenckPathBase = true; forwardedPathBase = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedPathBaseHeaderName); entryCount = Math.Max(forwardedFor.Length, entryCount); } _logger.LogWarning(1, "Parameter aaa" + forwardedPathBase.FirstOrDefault()); if ((_options.ForwardedHeaders & BasicForwardedHeaders.XForwardedBaseUrl) == BasicForwardedHeaders.XForwardedBaseUrl) { checkUrlBase = true; forwardedUrlBase = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedBaseUrlHeaderName); if (chenckPathBase && forwardedPathBase.Length != forwardedUrlBase.Length) { _logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto."); return; } entryCount = Math.Max(forwardedUrlBase.Length, entryCount); } // Apply ForwardLimit, if any if (_options.ForwardLimit.HasValue && entryCount > _options.ForwardLimit) { entryCount = _options.ForwardLimit.Value; } // Group the data together. var sets = new SetOfForwarders[entryCount]; for (int i = 0; i < sets.Length; i++) { // They get processed in reverse order, right to left. var set = new SetOfForwarders(); if (i < forwardedFor.Length) { set.IpAndPortText = forwardedFor[forwardedFor.Length - i - 1]; } if (chenckPathBase && i < forwardedPathBase.Length) { set.PathBase = forwardedPathBase[forwardedPathBase.Length - i - 1]; } if (checkUrlBase && i < forwardedUrlBase.Length) { var baseUrlString = forwardedUrlBase[forwardedUrlBase.Length - i - 1]; var baseUri = new Uri(baseUrlString); set.Host = baseUri.Host; set.Scheme = baseUri.Scheme; if (!chenckPathBase) { set.PathBase = baseUri.PathAndQuery; } } sets[i] = set; } // Gather initial values var connection = context.Connection; var request = context.Request; var currentValues = new SetOfForwarders() { RemoteIpAndPort = connection.RemoteIpAddress != null ? new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort) : null, // Host and Scheme initial values are never inspected, no need to set them here. }; var checkKnownIps = _options.KnownProxies.Count > 0; bool applyChanges = false; int entriesConsumed = 0; for ( ; entriesConsumed < sets.Length; entriesConsumed++) { var set = sets[entriesConsumed]; if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address)) { // Stop at the first unknown remote IP, but still apply changes processed so far. _logger.LogDebug(1, "Unknown proxy: {RemoteIpAndPort}", currentValues.RemoteIpAndPort); break; } if (chenckPathBase) { if (!string.IsNullOrEmpty(set.PathBase)) { applyChanges = true; currentValues.PathBase = set.PathBase; } else { _logger.LogWarning(3, $"Forwarded Pathbase is not present"); return; } } if (checkUrlBase) { applyChanges = true; if (!string.IsNullOrEmpty(set.Host)) { currentValues.Host = set.Host; } if (!string.IsNullOrEmpty(set.Scheme)) { currentValues.Scheme = set.Scheme; } if (!chenckPathBase && !string.IsNullOrEmpty(set.PathBase)) { currentValues.PathBase = set.PathBase; } } } if (applyChanges) { if (chenckPathBase && currentValues.PathBase != null) { // Save the original request.Headers[_options.OriginalPathHeaderName] = request.PathBase.ToString(); if (forwardedPathBase.Length > entriesConsumed) { // Truncate the consumed header values request.Headers[_options.ForwardedPathBaseHeaderName] = forwardedPathBase.Take(forwardedPathBase.Length - entriesConsumed).ToArray(); } else { // All values were consumed request.Headers.Remove(_options.ForwardedPathBaseHeaderName); } request.PathBase = new PathString(currentValues.PathBase); } if (checkUrlBase) { if (!request.Headers.ContainsKey(_options.OriginalHostHeaderName)) { request.Headers[_options.OriginalHostHeaderName] = request.Host.ToString(); } if (!string.IsNullOrEmpty(currentValues.Host) && !currentValues.Host.Equals(request.Host.ToString(), StringComparison.InvariantCultureIgnoreCase)) { request.Host = HostString.FromUriComponent(currentValues.Host); } if (!request.Headers.ContainsKey(_options.OriginalProtoHeaderName)) { request.Headers[_options.OriginalProtoHeaderName] = request.Scheme; } if (!string.IsNullOrEmpty(currentValues.Scheme) && !currentValues.Scheme.Equals(request.Scheme, StringComparison.InvariantCultureIgnoreCase)) { request.Scheme = currentValues.Scheme; } if (!chenckPathBase && !string.IsNullOrEmpty(currentValues.PathBase)) { request.PathBase = new PathString(currentValues.PathBase); } } } }