Go API Documentation

github.com/caddyserver/caddy/v2/modules/caddyhttp/proxyprotocol

No package summary is available.

Package

Files: 3. Third party imports: 1. Imports from organisation: 0. Tests: 0. Benchmarks: 0.

Constants

// as defined in: https://pkg.go.dev/github.com/pires/go-proxyproto@v0.7.0#Policy
const (
	// IGNORE address from PROXY header, but accept connection
	PolicyIGNORE	Policy	= iota
	// USE address from PROXY header
	PolicyUSE
	// REJECT connection when PROXY header is sent
	// Note: even though the first read on the connection returns an error if
	// a PROXY header is present, subsequent reads do not. It is the task of
	// the code using the connection to handle that case properly.
	PolicyREJECT
	// REQUIRE connection to send PROXY header, reject if not present
	// Note: even though the first read on the connection returns an error if
	// a PROXY header is not present, subsequent reads do not. It is the task
	// of the code using the connection to handle that case properly.
	PolicyREQUIRE
	// SKIP accepts a connection without requiring the PROXY header
	// Note: an example usage can be found in the SkipProxyHeaderForCIDR
	// function.
	PolicySKIP
)

Vars

var (
	_	caddy.Provisioner	= (*ListenerWrapper)(nil)
	_	caddy.Module		= (*ListenerWrapper)(nil)
	_	caddy.ListenerWrapper	= (*ListenerWrapper)(nil)
	_	caddyfile.Unmarshaler	= (*ListenerWrapper)(nil)
)
var errInvalidPolicy = errors.New("invalid policy")
var policyMap = map[Policy]string{
	PolicyUSE:	"USE",
	PolicyIGNORE:	"IGNORE",
	PolicyREJECT:	"REJECT",
	PolicyREQUIRE:	"REQUIRE",
	PolicySKIP:	"SKIP",
}
var policyMapRev = map[string]Policy{
	"USE":		PolicyUSE,
	"IGNORE":	PolicyIGNORE,
	"REJECT":	PolicyREJECT,
	"REQUIRE":	PolicyREQUIRE,
	"SKIP":		PolicySKIP,
}
var policyToGoProxyPolicy = map[Policy]goproxy.Policy{
	PolicyUSE:	goproxy.USE,
	PolicyIGNORE:	goproxy.IGNORE,
	PolicyREJECT:	goproxy.REJECT,
	PolicyREQUIRE:	goproxy.REQUIRE,
	PolicySKIP:	goproxy.SKIP,
}

Types

ListenerWrapper

ListenerWrapper provides PROXY protocol support to Caddy by implementing the caddy.ListenerWrapper interface. If a connection is received via Unix socket, it's trusted. Otherwise, it's checked against the Allow/Deny lists, then it's handled by the FallbackPolicy.

It must be loaded before the tls listener because the PROXY protocol encapsulates the TLS data.

Credit goes to https://github.com/mastercactapus/caddy2-proxyprotocol for having initially implemented this as a plugin.

type ListenerWrapper struct {
	// Timeout specifies an optional maximum time for
	// the PROXY header to be received.
	// If zero, timeout is disabled. Default is 5s.
	Timeout	caddy.Duration	`json:"timeout,omitempty"`

	// Allow is an optional list of CIDR ranges to
	// allow/require PROXY headers from.
	Allow	[]string	`json:"allow,omitempty"`
	allow	[]netip.Prefix

	// Deny is an optional list of CIDR ranges to
	// deny PROXY headers from.
	Deny	[]string	`json:"deny,omitempty"`
	deny	[]netip.Prefix

	// FallbackPolicy specifies the policy to use if the downstream
	// IP address is not in the Allow list nor is in the Deny list.
	//
	// NOTE: The generated docs which describe the value of this
	// field is wrong because of how this type unmarshals JSON in a
	// custom way. The field expects a string, not a number.
	//
	// Accepted values are: IGNORE, USE, REJECT, REQUIRE, SKIP
	//
	// - IGNORE: address from PROXY header, but accept connection
	//
	// - USE: address from PROXY header
	//
	// - REJECT: connection when PROXY header is sent
	//   Note: even though the first read on the connection returns an error if
	//   a PROXY header is present, subsequent reads do not. It is the task of
	//   the code using the connection to handle that case properly.
	//
	// - REQUIRE: connection to send PROXY header, reject if not present
	//   Note: even though the first read on the connection returns an error if
	//   a PROXY header is not present, subsequent reads do not. It is the task
	//   of the code using the connection to handle that case properly.
	//
	// - SKIP: accepts a connection without requiring the PROXY header.
	//   Note: an example usage can be found in the SkipProxyHeaderForCIDR
	//   function.
	//
	// Default: IGNORE
	//
	// Policy definitions are here: https://pkg.go.dev/github.com/pires/go-proxyproto@v0.7.0#Policy
	FallbackPolicy	Policy	`json:"fallback_policy,omitempty"`

	policy	goproxy.ConnPolicyFunc
}

Policy

This type doesn't have documentation.

type Policy int

Functions

func (*ListenerWrapper) Provision

Provision sets up the listener wrapper.

func (pp *ListenerWrapper) Provision(ctx caddy.Context) error {
	for _, cidr := range pp.Allow {
		ipnet, err := netip.ParsePrefix(cidr)
		if err != nil {
			return err
		}
		pp.allow = append(pp.allow, ipnet)
	}
	for _, cidr := range pp.Deny {
		ipnet, err := netip.ParsePrefix(cidr)
		if err != nil {
			return err
		}
		pp.deny = append(pp.deny, ipnet)
	}

	pp.policy = func(options goproxy.ConnPolicyOptions) (goproxy.Policy, error) {
		// trust unix sockets
		if network := options.Upstream.Network(); caddy.IsUnixNetwork(network) || caddy.IsFdNetwork(network) {
			return goproxy.USE, nil
		}
		ret := pp.FallbackPolicy
		host, _, err := net.SplitHostPort(options.Upstream.String())
		if err != nil {
			return goproxy.REJECT, err
		}

		ip, err := netip.ParseAddr(host)
		if err != nil {
			return goproxy.REJECT, err
		}
		for _, ipnet := range pp.deny {
			if ipnet.Contains(ip) {
				return goproxy.REJECT, nil
			}
		}
		for _, ipnet := range pp.allow {
			if ipnet.Contains(ip) {
				ret = PolicyUSE
				break
			}
		}
		return policyToGoProxyPolicy[ret], nil
	}
	return nil
}

Cognitive complexity: 27, Cyclomatic complexity: 13

Uses: goproxy.ConnPolicyOptions, goproxy.Policy, goproxy.REJECT, goproxy.USE, net.SplitHostPort, netip.ParseAddr, netip.ParsePrefix.

func (*ListenerWrapper) UnmarshalCaddyfile

UnmarshalCaddyfile sets up the listener Listenerwrapper from Caddyfile tokens. Syntax:

proxy_protocol {
	timeout <duration>
	allow <IPs...>
	deny <IPs...>
	fallback_policy <policy>
}

func (w *ListenerWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
	d.Next()	// consume wrapper name

	// No same-line options are supported
	if d.NextArg() {
		return d.ArgErr()
	}

	for d.NextBlock(0) {
		switch d.Val() {
		case "timeout":
			if !d.NextArg() {
				return d.ArgErr()
			}
			dur, err := caddy.ParseDuration(d.Val())
			if err != nil {
				return d.Errf("parsing proxy_protocol timeout duration: %v", err)
			}
			w.Timeout = caddy.Duration(dur)

		case "allow":
			w.Allow = append(w.Allow, d.RemainingArgs()...)
		case "deny":
			w.Deny = append(w.Deny, d.RemainingArgs()...)
		case "fallback_policy":
			if !d.NextArg() {
				return d.ArgErr()
			}
			p, err := parsePolicy(d.Val())
			if err != nil {
				return d.WrapErr(err)
			}
			w.FallbackPolicy = p
		default:
			return d.ArgErr()
		}
	}
	return nil
}

Cognitive complexity: 18, Cyclomatic complexity: 12

func (*ListenerWrapper) WrapListener

WrapListener adds PROXY protocol support to the listener.

func (pp *ListenerWrapper) WrapListener(l net.Listener) net.Listener {
	pl := &goproxy.Listener{
		Listener:		l,
		ReadHeaderTimeout:	time.Duration(pp.Timeout),
	}
	pl.ConnPolicy = pp.policy
	return pl
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: goproxy.Listener, time.Duration.

func (*Policy) UnmarshalText

UnmarshalText implements the text unmarshaller method.

func (x *Policy) UnmarshalText(text []byte) error {
	name := string(text)
	tmp, err := parsePolicy(name)
	if err != nil {
		return err
	}
	*x = tmp
	return nil
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (ListenerWrapper) CaddyModule

func (ListenerWrapper) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:	"caddy.listeners.proxy_protocol",
		New:	func() caddy.Module { return new(ListenerWrapper) },
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 1

func (Policy) MarshalText

MarshalText implements the text marshaller method.

func (x Policy) MarshalText() ([]byte, error) {
	return []byte(policyMap[x]), nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Private functions

func init

init ()

func parsePolicy

parsePolicy (name string) (Policy, error)
References: fmt.Errorf, strings.ToUpper.