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
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
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.