-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add config options for
Deny
CIDR and fallback policy
- Loading branch information
1 parent
67e567b
commit bc04e74
Showing
3 changed files
with
141 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,18 +37,59 @@ type ListenerWrapper struct { | |
// Allow is an optional list of CIDR ranges to | ||
// allow/require PROXY headers from. | ||
Allow []string `json:"allow,omitempty"` | ||
allow []*net.IPNet | ||
|
||
policies []goproxy.PolicyFunc | ||
// Denby is an optional list of CIDR ranges to | ||
// deny PROXY headers from. | ||
Deny []string `json:"deny,omitempty"` | ||
deny []*net.IPNet | ||
|
||
// Accepted values are: ignore, use, reject, require, skip | ||
// default: ignore | ||
// Policy definitions are here: https://pkg.go.dev/github.com/pires/[email protected]#Policy | ||
FallbackPolicy Policy `json:"fallback_policy,omitempty"` | ||
|
||
policy goproxy.PolicyFunc | ||
} | ||
|
||
// Provision sets up the listener wrapper. | ||
func (pp *ListenerWrapper) Provision(ctx caddy.Context) error { | ||
if len(pp.Allow) > 0 { | ||
allowlist, err := goproxy.LaxWhiteListPolicy(pp.Allow) | ||
for _, cidr := range pp.Allow { | ||
_, ipnet, err := net.ParseCIDR(cidr) | ||
if err != nil { | ||
return err | ||
} | ||
pp.policies = append(pp.policies, allowlist) | ||
pp.allow = append(pp.allow, ipnet) | ||
} | ||
for _, cidr := range pp.Deny { | ||
_, ipnet, err := net.ParseCIDR(cidr) | ||
if err != nil { | ||
return err | ||
} | ||
pp.deny = append(pp.deny, ipnet) | ||
} | ||
pp.policy = func(upstream net.Addr) (goproxy.Policy, error) { | ||
ret := pp.FallbackPolicy | ||
host, _, err := net.SplitHostPort(upstream.String()) | ||
if err != nil { | ||
return goproxy.REJECT, err | ||
} | ||
ip := net.ParseIP(host) | ||
if ip == 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 | ||
} | ||
|
@@ -59,8 +100,6 @@ func (pp *ListenerWrapper) WrapListener(l net.Listener) net.Listener { | |
Listener: l, | ||
ReadHeaderTimeout: time.Duration(pp.Timeout), | ||
} | ||
if len(pp.policies) > 0 { | ||
pl.Policy = pp.policies[0] | ||
} | ||
pl.Policy = pp.policy | ||
return pl | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package proxyprotocol | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
goproxy "github.com/pires/go-proxyproto" | ||
) | ||
|
||
type Policy int | ||
|
||
// as defined in: https://pkg.go.dev/github.com/pires/[email protected]#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 | ||
) | ||
|
||
var policyToGoProxyPolicy = map[Policy]goproxy.Policy{ | ||
PolicyUSE: goproxy.USE, | ||
PolicyIGNORE: goproxy.IGNORE, | ||
PolicyREJECT: goproxy.REJECT, | ||
PolicyREQUIRE: goproxy.REQUIRE, | ||
PolicySKIP: goproxy.SKIP, | ||
} | ||
|
||
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, | ||
} | ||
|
||
// MarshalText implements the text marshaller method. | ||
func (x Policy) MarshalText() ([]byte, error) { | ||
return []byte(policyMap[x]), nil | ||
} | ||
|
||
// 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 | ||
} | ||
|
||
func parsePolicy(name string) (Policy, error) { | ||
if x, ok := policyMapRev[strings.ToUpper(name)]; ok { | ||
return x, nil | ||
} | ||
return Policy(0), fmt.Errorf("%s is %w", name, errInvalidPolicy) | ||
} | ||
|
||
var errInvalidPolicy = errors.New("invalid policy") |