Line data Source code
1 : #ifndef THINGER_HTTP_SERVER_TRUSTED_PROXIES_HPP
2 : #define THINGER_HTTP_SERVER_TRUSTED_PROXIES_HPP
3 :
4 : #include <boost/asio/ip/address.hpp>
5 : #include <string>
6 : #include <string_view>
7 : #include <vector>
8 :
9 : namespace thinger::http {
10 :
11 : class headers;
12 :
13 : // Header the trusted proxies use to report the client address. Only one is read: a proxy
14 : // that appends to one of them passes the other one through, as sent by the client. The
15 : // scheme comes with it: X-Forwarded-Proto with X-Forwarded-For, proto= with Forwarded.
16 : //
17 : // The client of a request, as a trusted proxy reports it (see trusted_proxies::resolve())
18 : struct forwarded_client {
19 : std::string ip;
20 : std::string scheme; // "http" or "https"
21 : };
22 :
23 : enum class forwarded_header {
24 : x_forwarded_for, // X-Forwarded-For: client, proxy1, proxy2 (and X-Forwarded-Proto: https)
25 : forwarded // Forwarded: for=client;proto=https, for=proxy1 (RFC 7239)
26 : };
27 :
28 : // Proxies (IPs and CIDR ranges, IPv4 and IPv6) allowed to report the address and the scheme
29 : // of the client they forward a request for
30 : class trusted_proxies {
31 : public:
32 90 : explicit trusted_proxies(forwarded_header header = forwarded_header::x_forwarded_for)
33 90 : : header_(header) {}
34 :
35 : // Trust an IP ("10.0.0.1", "::1") or a CIDR range ("10.0.0.0/8", "fd00::/8");
36 : // returns false if it is not valid
37 : bool add(std::string_view network);
38 :
39 : // Whether an address belongs to a trusted proxy (IPv4-mapped IPv6 addresses are
40 : // compared as IPv4); false for anything that is not an IP address
41 : bool contains(std::string_view ip) const;
42 :
43 222 : bool empty() const { return networks_.empty(); }
44 :
45 6 : forwarded_header header() const { return header_; }
46 :
47 : // Name of the header read ("X-Forwarded-For" or "Forwarded")
48 : const std::string& header_name() const;
49 :
50 :
51 : // Client address of a request received from `peer`, given the values of the forwarding
52 : // header (all its occurrences, in order). The peer itself unless it is trusted; then the
53 : // forwarded addresses are walked from right to left, skipping trusted proxies, and the
54 : // first untrusted one is returned (the leftmost if all of them are trusted). An entry
55 : // that is not an IP ("unknown") ends the walk at the address after it.
56 : std::string client_ip(const std::string& peer, const std::vector<std::string>& header_values) const;
57 :
58 : // Client address and scheme of a request received from `peer`, on a connection of
59 : // `scheme` ("http" or "https"), with the headers `request` (all the occurrences of the
60 : // forwarding headers, in order). The peer and the scheme of the connection unless the peer
61 : // is trusted; then one walk, as client_ip() does, gives both: the address where it stops,
62 : // and the scheme of the entry it stops at, the last one a trusted proxy wrote (the one
63 : // giving the client address, or one whose address is not an IP): its proto= with
64 : // Forwarded; with X-Forwarded-For, the X-Forwarded-Proto value in the same position when
65 : // both have as many values (each proxy appended to both), else the last one, written by
66 : // the nearest proxy (which overwrote it, or did not append to both). So what a client sends
67 : // ahead of a trusted proxy is never read, whether the proxy appends or overwrites. A scheme
68 : // other than http or https (case-insensitive), or none, leaves the one of the connection.
69 : forwarded_client resolve(const std::string& peer, std::string_view scheme, const headers& request) const;
70 :
71 : // Addresses in the forwarding headers, left to right, without ports nor brackets;
72 : // empty strings for entries that are not IP addresses
73 : static std::vector<std::string> parse_x_forwarded_for(std::string_view value);
74 : static std::vector<std::string> parse_forwarded(std::string_view value);
75 :
76 : // Scheme of a forwarded value ("http" or "https", lowercase), empty for anything else
77 : static std::string parse_scheme(std::string_view value);
78 :
79 : private:
80 : struct network {
81 : boost::asio::ip::address address;
82 : unsigned prefix;
83 : };
84 :
85 : static bool in_network(const boost::asio::ip::address& address, const network& net);
86 :
87 : std::vector<network> networks_;
88 : forwarded_header header_;
89 : };
90 :
91 : } // namespace thinger::http
92 :
93 : #endif // THINGER_HTTP_SERVER_TRUSTED_PROXIES_HPP
|