#include #include #include namespace base::http { asio::ip::address GetProxyAddress(asio::ip::address fallback, beast::http::request& req) { #ifdef BASE_HTTP_REVERSE_PROXY_SUPPORT auto forwarded_for = req[ #ifndef BASE_HTTP_CLOUDFLARE "X-Forwarded-For" #else "CF-Connecting-IP" #endif ]; if(forwarded_for == "") { // if no header was provided, just return that hop return fallback; } else { bsys::error_code ec; asio::ip::address ip; // X-Forwarded-For is a tokenized list, where the first element is always the client hop. // We only need to worry about the client hop. if(forwarded_for.find(',') != beast::string_view::npos) { ip = asio::ip::make_address(std::string_view(forwarded_for.data(), forwarded_for.find(',')), ec); } else { ip = asio::ip::make_address(std::string_view(forwarded_for.data(), forwarded_for.length()), ec); } // The X-Forwarded-For header is not controlled by user input (and should *not* be, with a properly written proxy server), // so if this CHECK fires, you're probably in a bad enough situation not worth continuing anyways. BASE_CHECK(!ec, "Invalid IP address in proxy IP header. Header: \"{}\"", std::string_view(forwarded_for.data(), forwarded_for.length())); return ip; } #else return fallback; #endif } } // namespace base::http