trustedproxy

package
v0.17.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package trustedproxy takes a client's address from the proxy in front of Atlas, and from nobody else (ADR-0448).

Behind a load balancer every connection comes from the balancer. The login throttle then charges every person to one bucket (ADR-0197), and every audit line names the balancer as the client — the one fact about a request an audit trail exists to keep. The balancer knows the real address and can say so, in one of two ways depending on what it is:

  • A balancer that speaks HTTP appends it to X-Forwarded-For.
  • A balancer that forwards TCP — and so cannot add a header to a TLS stream it does not decrypt — writes a PROXY protocol header in front of the stream.

Both are things a client can also write. What makes either believable is the connection it arrived on, so both are read only on a connection from an address the operator listed, and from the side the nearest proxy controls: the PROXY header must be the very first bytes, and X-Forwarded-For is walked from the right. A connection from anywhere else is left exactly as it was — its first bytes are not even peeked at.

An empty Set, which is what a server started without --trusted-proxies has, changes nothing at all: Listener returns the listener and Handler the handler.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Client

func Client(r *http.Request) (string, bool)

Client is the client address a trusted proxy vouched for, and whether one did. Where none did, the request's own connection is the answer, and the caller reads it there.

func ConnContext

func ConnContext(ctx context.Context, c net.Conn) context.Context

ConnContext is the http.Server hook that lets the handler see through a PROXY header to the balancer that wrote it. It only records the connection — reading the header can wait for a client, and this runs on the server's accept loop, which must not.

func Via

func Via(r *http.Request) string

Via is the trusted proxy that named the client, or empty where none did — the balancer's own address, which an audit line keeps beside the client's so a request that came round the balancer can be told from one that came through it.

Types

type Set

type Set struct {
	// contains filtered or unexported fields
}

Set is the proxies whose word about a client's address is taken.

func Parse

func Parse(spec string) (Set, error)

Parse reads a list of addresses and CIDR prefixes, separated by commas or spaces. An address is the prefix of its own full length.

A prefix that covers every address is refused: trusting everybody to name the client is trusting the client to name itself, which is the one thing the list exists to rule out. Anything that does not parse is refused too, rather than dropped — a list that silently lost an entry trusts less than its operator believes, and one that silently grew would trust more.

func (Set) Contains

func (s Set) Contains(a netip.Addr) bool

Contains reports whether a is one of the trusted proxies. An IPv4 address carried in IPv6 is the IPv4 address. One with a zone is never trusted: fe80::1 on one interface is not fe80::1 on another, and the list cannot say which interface it meant.

func (Set) Empty

func (s Set) Empty() bool

Empty reports whether nothing is trusted.

func (Set) Handler

func (s Set) Handler(next http.Handler) http.Handler

Handler resolves each request's client address before next sees it.

The request's own RemoteAddr is the starting point — after the PROXY listener that is already the client a balancer declared. Where that address is itself a trusted proxy, X-Forwarded-For is walked from the right: each entry a trusted proxy appended is passed over, and the first one that is not a trusted proxy is the client. Everything to its left is what the client wrote about itself and is never read. An entry that cannot be read ends the walk where it stands, because past it there is nothing left that a trusted hop vouched for.

Only X-Forwarded-For is read. RFC 7239's Forwarded carries the same fact in a grammar no balancer in front of Atlas has needed yet; it is an amendment when one does.

func (Set) Listener

func (s Set) Listener(ln net.Listener) net.Listener

Listener reads a PROXY header, where there is one, from every connection a trusted proxy opens, and leaves every other connection untouched. The header is optional: a balancer in HTTP mode, or a TCP health check that sends nothing, arrives exactly as it did before.

func (Set) String

func (s Set) String() string

String is the list as the server understood it, for the startup log.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL