brazier/ip
Types
A request’s client address and scheme, from one parse of its forwarding
header (see client).
pub type Client {
Client(address: String, scheme: Result(String, String))
}
Constructors
-
Client(address: String, scheme: Result(String, String))
Which forwarding header the trusted proxies set.
pub type ForwardingHeader {
Forwarded
XForwardedFor
NoForwardingHeader
}
Constructors
-
ForwardedRFC 7239
Forwarded: for=...;proto=.... -
XForwardedForX-Forwarded-For: client, proxy1, ..., withX-Forwarded-Protofor the scheme. -
NoForwardingHeaderNo header is read: the socket peer is always the client address and the scheme is always
http. Proxies may still be listed: they are exempt from the per-IP connection cap.
A parsed list of trusted proxy networks, without a header. The listener uses it to exempt proxies from the per-IP connection cap.
pub type ProxyNetworks
What one request’s peer and forwarding headers resolved to, and the
trusted proxies that resolution honoured. A request that carries one
(server.Connection.resolved) is never resolved again against the same
proxies, so a problem in its forwarding header is logged once.
pub type Resolved {
Resolved(trusted: TrustedProxies, client: Client)
}
Constructors
-
Resolved(trusted: TrustedProxies, client: Client)
Trusted proxy networks and the one forwarding header they set.
pub opaque type TrustedProxies
Values
pub fn client(
peer: String,
headers: List(#(String, String)),
trusted: TrustedProxies,
) -> Client
client_address and client_scheme together, for a caller that needs
both (the WebSocket upgrade: its per-IP cap and its Origin check). The
configured header is parsed once, so a problem in it (a malformed hop,
an unconfigured header from a trusted proxy) is logged once per request,
not once per question asked about it.
pub fn client_address(
peer: String,
headers: List(#(String, String)),
trusted: TrustedProxies,
) -> String
Resolve the client address for a request.
peer is the socket peer address. headers are the request headers
(lower-case names). When the peer is not trusted the headers are
ignored. When it is, only the configured header is read. The other
forwarding header is never read; it is logged as a warning, because a
proxy that sets one header passes the other through from the client.
pub fn client_scheme(
peer: String,
headers: List(#(String, String)),
trusted: TrustedProxies,
) -> Result(String, String)
The scheme the client used to reach the outermost trusted proxy:
http or https.
When the peer is not trusted, or no forwarding header is configured,
no header is read and the scheme is http (Brazier does not terminate
TLS). Otherwise only the configured header’s scheme is read:
Forwarded: theproto=of the element that names the client (the elementclient_addressstops at), since the trusted proxy that appended it saw the client’s connection. An element withoutproto=ishttp.X-Forwarded-Protois not read.X-Forwarded-For: the left-most value of the oneX-Forwarded-Protoheader, as Django’sSECURE_PROXY_SSL_HEADERreads it, so the outermost proxy must overwrite that header.Forwardedis not read.
Errors when the scheme read is not http or https, the header is sent
twice, or an element repeats proto= (RFC 7239 section 4).
pub fn forwarding_header_to_string(
header: ForwardingHeader,
) -> String
The header name, for logs and error messages.
pub fn is_trusted(
address: String,
trusted: TrustedProxies,
) -> Bool
Is the (textual) address inside one of the trusted networks?
pub fn no_trusted_proxies() -> TrustedProxies
No trusted proxies: forwarding headers are never honoured.
pub fn parse_ip(text: String) -> Result(String, Nil)
Normalize a textual IP address (IPv4-mapped IPv6 becomes IPv4).
pub fn parse_proxy_networks(
entries: List(String),
) -> Result(ProxyNetworks, String)
Parse trusted proxy networks without a header, for the listener’s per-IP cap exemption. Any invalid entry is an error, returned for the caller to log once (the listener logs “Invalid listener options”).
pub fn parse_trusted_proxies(
entries: List(String),
header: ForwardingHeader,
) -> Result(TrustedProxies, String)
Parse trusted proxy entries such as "10.0.0.0/8", "127.0.0.1",
or "fd00::/8", with the header those proxies set. Any invalid entry is
an error: a typo in a proxy list must never silently widen or narrow
trust. A header with no proxies is an error too: it would never be read,
and the operator plainly expected it to be.
A refusal is returned, not logged: the caller logs it once, with its own context (“Invalid security limits: trusted_proxies: …” when the listener checks its limits), so one refusal makes one log line.