Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions tokenizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ type tokenizer struct {
// RequireFlySrc will reject requests without a fly-src when set.
RequireFlySrc bool

// allowPrivateUpstreams disables the denial of private, loopback, and
// fdaa::/8 upstream addresses. Only for tests.
// allowPrivateUpstreams disables the denial of private, loopback,
// unspecified, link-local, and fdaa::/8 upstream addresses. Only for tests.
allowPrivateUpstreams bool

// tokenizerHostnames is a list of hostnames where tokenizer can be reached.
Expand Down Expand Up @@ -81,8 +81,9 @@ func OpenProxy() Option {
}
}

// AllowPrivateUpstreams permits dialing private, loopback, and fdaa::/8
// upstream addresses. Only for tests that run their upstream on loopback.
// AllowPrivateUpstreams permits dialing private, loopback, unspecified,
// link-local, and fdaa::/8 upstream addresses. Only for tests that run their
// upstream on loopback.
func AllowPrivateUpstreams() Option {
return func(t *tokenizer) {
t.allowPrivateUpstreams = true
Expand Down Expand Up @@ -503,8 +504,8 @@ func errorResponse(err error) *http.Response {

// dialFunc returns a function for dialing network addresses. Ours does a few
// special things.
// - It denies connections to private, loopback, and fdaa::/8 addresses
// unless allowPrivate is set.
// - It denies connections to private, loopback, unspecified, link-local, and
// fdaa::/8 addresses unless allowPrivate is set.
// - It denies connections to the given set of IP addresses. This is to prevent
// circular requests back to tokenizer. Invalid IPs are ignored.
// - It rejects requests for TLS upstreams. We need to see/modify requests, so
Expand Down Expand Up @@ -543,6 +544,10 @@ func dialFunc(badAddrs []string, allowPrivate bool) func(string, string) (net.Co
return fmt.Errorf("%w: dialing private address %s denied", ErrBadRequest, address)
case ip.IsLoopback():
return fmt.Errorf("%w: dialing loopback address %s denied", ErrBadRequest, address)
case ip.IsUnspecified():
return fmt.Errorf("%w: dialing unspecified address %s denied", ErrBadRequest, address)
case ip.IsLinkLocalUnicast(), ip.IsLinkLocalMulticast(), ip.IsInterfaceLocalMulticast():
return fmt.Errorf("%w: dialing link-local address %s denied", ErrBadRequest, address)
case fdaaNet.Contains(ip):
return fmt.Errorf("%w: dialing fdaa::/8 address %s denied", ErrBadRequest, address)
default:
Expand Down
5 changes: 5 additions & 0 deletions tokenizer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,11 @@ func TestDialFuncDeniesInternalAddresses(t *testing.T) {
{"fdaa without bad addrs", nil, false, "[fdaa::1]:1"},
{"loopback with bad addrs", []string{"203.0.113.5"}, false, "127.0.0.1:1"},
{"bad addr", []string{"203.0.113.5"}, false, "203.0.113.5:1"},
{"link-local v4", nil, false, "169.254.169.254:1"},
{"link-local v6", nil, false, "[fe80::1]:1"},
{"unspecified v4", nil, false, "0.0.0.0:1"},
{"unspecified v6", nil, false, "[::]:1"},
{"ipv4-mapped loopback", nil, false, "[::ffff:127.0.0.1]:1"},
{"bad addr with private allowed", []string{"203.0.113.5"}, true, "203.0.113.5:1"},
}

Expand Down
Loading