in src/envoy/http/service_control/handler_utils.cc [371:424]
absl::StatusOr<std::string> extractIPFromForwardedHeader(
const Envoy::Http::RequestHeaderMap& headers) {
const auto values = headers.get(kForwardedHeader);
if (values.size() == 0) {
return Envoy::EMPTY_STRING;
}
// Only support one header value.
// Need to extract the last one, could not define the last one for multiple
// header values.
if (values.size() > 1) {
return absl::InvalidArgumentError("more than one forwarded headers.");
}
absl::string_view source = values[0]->value().getStringView();
// Multiple proxy sections are separated by comma. Use the last one.
const absl::string_view::size_type pos = source.find_last_of(',');
if (pos != absl::string_view::npos) {
source.remove_prefix(pos + 1);
}
// Each section may have multiple fields, they are separated by semicolon.
// For example: by=abc;for=1.2.3.4;host=abc;proto=http
// Extract ip from the "for=" field.
for (absl::string_view s : absl::StrSplit(source, ';')) {
absl::string_view token = absl::StripAsciiWhitespace(s);
if (absl::StartsWith(token, kForwardedIPTokenPrefix)) {
absl::string_view ip = token.substr(kForwardedIPTokenPrefix.size());
// IPv2 address is wrapped with \"[]\".
// Remove double quote.
if (ip[0] == '"' && ip[ip.size() - 1] == '"') {
ip = ip.substr(1, ip.size() - 2);
}
// Remove [].
if (ip[0] == '[' && ip[ip.size() - 1] == ']') {
ip = ip.substr(1, ip.size() - 2);
}
std::string ip_str(ip);
// Verify it is a valid IP.
const auto address =
Envoy::Network::Utility::parseInternetAddressNoThrow(ip_str);
if (address == nullptr) {
return absl::InvalidArgumentError(
absl::StrCat(ip_str, "is not a valid ip address"));
}
return ip_str;
}
}
return absl::InvalidArgumentError(
absl::StrCat("could not find IP from: ", source));
}