Refuse [::], 0.0.0.0, IPv6 multicast and documentation space (closes #341)
check / check (push) Successful in 3m20s
check / check (push) Successful in 3m20s
On Linux a connection to the unspecified address [::] or 0.0.0.0 reaches the host's own loopback, and the SSRF guard let [::] through. Both unspecified addresses now sit in alwaysBlockedNetworks, so an allowlist reaches loopback only by naming it; ::/128 joins the default blocklist beside 0.0.0.0/8. IPv6 multicast (ff00::/8) and documentation space (2001:db8::/32) are refused by default. Every default blocklist entry gets a one-line comment, and the README, the rules above each list and the two pinning tests follow. Model: opus-5-5
This commit is contained in:
@@ -158,19 +158,20 @@ WireServer, which serves an Azure VM its credentials. Because it is a
|
|||||||
public address, listing it in `ALLOWED_EGRESS_CIDRS` reopens it.
|
public address, listing it in `ALLOWED_EGRESS_CIDRS` reopens it.
|
||||||
|
|
||||||
That is all the default blocklist covers: the IPv4 private and reserved
|
That is all the default blocklist covers: the IPv4 private and reserved
|
||||||
ranges; of IPv6, only loopback (`::1`), unique local addresses
|
ranges; of IPv6, only loopback (`::1`), the unspecified address (`::`),
|
||||||
(`fc00::/7`) and link-local addresses (`fe80::/10`); and certain public
|
unique local addresses (`fc00::/7`), link-local addresses (`fe80::/10`),
|
||||||
addresses. A public address belongs on the default blocklist only if it
|
multicast (`ff00::/8`) and documentation space (`2001:db8::/32`); and
|
||||||
hands credentials, user data or bootstrap material to whatever can reach
|
certain public addresses. A public address belongs on the default
|
||||||
it, without the caller presenting anything. A provider's other public
|
blocklist only if it hands credentials, user data or bootstrap material
|
||||||
addresses are not refused. IBM Cloud, for example, serves its package
|
to whatever can reach it, without the caller presenting anything. A
|
||||||
mirrors, time servers and object storage on `161.26.0.0/16`, and the
|
provider's other public addresses are not refused. IBM Cloud, for
|
||||||
private endpoints of its own cloud services on `166.8.0.0/14`. Neither
|
example, serves its package mirrors, time servers and object storage on
|
||||||
range hands out credentials that way: the token service among those
|
`161.26.0.0/16`, and the private endpoints of its own cloud services on
|
||||||
endpoints issues a token only in exchange for something the caller
|
`166.8.0.0/14`. Neither range hands out credentials that way: the token
|
||||||
presents, such as an API key. Reaching these services can be a
|
service among those endpoints issues a token only in exchange for
|
||||||
legitimate delivery, and every cloud has some, so a partial list would
|
something the caller presents, such as an API key. Reaching these
|
||||||
promise coverage it does not give.
|
services can be a legitimate delivery, and every cloud has some, so a
|
||||||
|
partial list would promise coverage it does not give.
|
||||||
|
|
||||||
That default is also inconvenient for the thing webhooker is mostly
|
That default is also inconvenient for the thing webhooker is mostly
|
||||||
for: taking a public webhook and forwarding it to something on your own
|
for: taking a public webhook and forwarding it to something on your own
|
||||||
@@ -210,16 +211,16 @@ Two things this setting cannot do:
|
|||||||
the list is always an allowlist; an empty list (the default) means
|
the list is always an allowlist; an empty list (the default) means
|
||||||
every private and reserved range stays refused. Note that
|
every private and reserved range stays refused. Note that
|
||||||
`0.0.0.0/0` gets you most of the way there anyway, per above.
|
`0.0.0.0/0` gets you most of the way there anyway, per above.
|
||||||
- **It cannot open link-local, or a cloud metadata endpoint at a
|
- **It cannot open link-local, the unspecified addresses, or a cloud
|
||||||
non-public address that discloses credentials or user data.** An
|
metadata endpoint at a non-public address that discloses credentials
|
||||||
address is on the list below when it is not a public address and both
|
or user data.** A metadata address is on the list below when it is not
|
||||||
of these hold: the provider fixes it, so it cannot collide with
|
a public address and both of these hold: the provider fixes it, so it
|
||||||
anything you run; and reaching it hands out credentials, user data or
|
cannot collide with anything you run; and reaching it hands out
|
||||||
bootstrap material. Those stay blocked no matter what you list,
|
credentials, user data or bootstrap material. Those stay blocked no
|
||||||
including when you list them outright or list a supernet such as
|
matter what you list, including when you list them outright or list a
|
||||||
`0.0.0.0/0`, `::/0`, `fd00::/8` or `100.64.0.0/10`. Treat this as best
|
supernet such as `0.0.0.0/0`, `::/0`, `fd00::/8` or `100.64.0.0/10`.
|
||||||
effort rather than a guarantee — it is a hand-maintained list and the
|
Treat this as best effort rather than a guarantee — it is a
|
||||||
caveat below the table applies:
|
hand-maintained list and the caveat below the table applies:
|
||||||
|
|
||||||
| Blocked unconditionally | What it is |
|
| Blocked unconditionally | What it is |
|
||||||
| ----------------------- | ---------- |
|
| ----------------------- | ---------- |
|
||||||
@@ -233,14 +234,22 @@ Two things this setting cannot do:
|
|||||||
| `fd00:a9fe:a9fe::1/128` | Linode/Akamai metadata over IPv6 |
|
| `fd00:a9fe:a9fe::1/128` | Linode/Akamai metadata over IPv6 |
|
||||||
| `100.100.100.200/32` | Alibaba Cloud metadata, inside CGNAT |
|
| `100.100.100.200/32` | Alibaba Cloud metadata, inside CGNAT |
|
||||||
| `192.0.0.192/32` | Oracle Cloud Classic metadata |
|
| `192.0.0.192/32` | Oracle Cloud Classic metadata |
|
||||||
|
| `0.0.0.0/32` | IPv4 unspecified address, which reaches this host's loopback on Linux |
|
||||||
|
| `::/128` | IPv6 unspecified address, which reaches this host's loopback on Linux |
|
||||||
| `::a9fe:a9fe/128` | `169.254.169.254` as an IPv4-compatible IPv6 address |
|
| `::a9fe:a9fe/128` | `169.254.169.254` as an IPv4-compatible IPv6 address |
|
||||||
| `64:ff9b::a9fe:a9fe/128` | `169.254.169.254` behind the NAT64 well-known prefix |
|
| `64:ff9b::a9fe:a9fe/128` | `169.254.169.254` behind the NAT64 well-known prefix |
|
||||||
|
|
||||||
The IPv4-mapped form `::ffff:169.254.169.254` is covered by the
|
The IPv4-mapped form `::ffff:169.254.169.254` is covered by the
|
||||||
`169.254.0.0/16` entry. Reaching any of these is credential or
|
`169.254.0.0/16` entry. Reaching any of these but the two unspecified
|
||||||
user-data theft rather than delivery to an internal service. Every
|
addresses is credential or user-data theft rather than delivery to an
|
||||||
entry outside the two link-local blocks is a single address, so
|
internal service. Every entry outside the two link-local blocks is a
|
||||||
blocking it costs you nothing else on the network around it.
|
single address, so blocking it costs you nothing else on the network
|
||||||
|
around it.
|
||||||
|
|
||||||
|
The unspecified addresses `0.0.0.0` and `::` hand out nothing
|
||||||
|
themselves, but no host can have either, and on Linux a connection to
|
||||||
|
one reaches this host's own loopback. They are listed so that the only
|
||||||
|
way to open loopback is to name it, as `127.0.0.0/8` or `::1`.
|
||||||
|
|
||||||
The six ULA entries, all inside `fd00::/8`, are why this matters in
|
The six ULA entries, all inside `fd00::/8`, are why this matters in
|
||||||
practice: `fd00::/8` is an ordinary block to allowlist for your own
|
practice: `fd00::/8` is an ordinary block to allowlist for your own
|
||||||
@@ -3093,7 +3102,8 @@ check, see [The login endpoint](#the-login-endpoint).
|
|||||||
route through a single decision function, so they cannot disagree
|
route through a single decision function, so they cannot disagree
|
||||||
about a destination. An operator can permit specific blocks with
|
about a destination. An operator can permit specific blocks with
|
||||||
[`ALLOWED_EGRESS_CIDRS`](#allowing-egress-to-your-own-network); the
|
[`ALLOWED_EGRESS_CIDRS`](#allowing-egress-to-your-own-network); the
|
||||||
guard cannot be switched off, and link-local plus a
|
guard cannot be switched off, and link-local, the unspecified
|
||||||
|
addresses `0.0.0.0` and `::`, and a
|
||||||
[pinned set](#allowing-egress-to-your-own-network) of known cloud
|
[pinned set](#allowing-egress-to-your-own-network) of known cloud
|
||||||
metadata endpoints — several of which are ULAs outside link-local —
|
metadata endpoints — several of which are ULAs outside link-local —
|
||||||
stay blocked whatever is listed, though listing `0.0.0.0/0` or
|
stay blocked whatever is listed, though listing `0.0.0.0/0` or
|
||||||
|
|||||||
@@ -196,10 +196,11 @@ type Config struct {
|
|||||||
// otherwise refuse. The guard itself is always on: there is no
|
// otherwise refuse. The guard itself is always on: there is no
|
||||||
// setting that disables SSRF protection, and delivery's
|
// setting that disables SSRF protection, and delivery's
|
||||||
// alwaysBlockedNetworks stays blocked no matter what is listed
|
// alwaysBlockedNetworks stays blocked no matter what is listed
|
||||||
// here. That set is link-local plus the cloud metadata
|
// here. That set is link-local, the unspecified addresses
|
||||||
// endpoints outside it that disclose credentials or user data
|
// 0.0.0.0 and ::, and the cloud metadata endpoints outside
|
||||||
// at a provider-fixed, non-public address; it is not
|
// link-local that disclose credentials or user data at a
|
||||||
// exhaustive of every cloud's metadata address. See
|
// provider-fixed, non-public address; it is not exhaustive of
|
||||||
|
// every cloud's metadata address. See
|
||||||
// alwaysBlockedNetworks for the authoritative list and the
|
// alwaysBlockedNetworks for the authoritative list and the
|
||||||
// criterion it is built from.
|
// criterion it is built from.
|
||||||
AllowedEgressCIDRs []netip.Prefix
|
AllowedEgressCIDRs []netip.Prefix
|
||||||
|
|||||||
+50
-10
@@ -37,8 +37,8 @@ var (
|
|||||||
"blocked cloud metadata address",
|
"blocked cloud metadata address",
|
||||||
)
|
)
|
||||||
errBlockedMetadata = errors.New(
|
errBlockedMetadata = errors.New(
|
||||||
"blocked link-local or cloud instance metadata " +
|
"blocked link-local, cloud instance metadata or " +
|
||||||
"address: ALLOWED_EGRESS_CIDRS cannot open it",
|
"unspecified address: ALLOWED_EGRESS_CIDRS cannot open it",
|
||||||
)
|
)
|
||||||
errInvalidScheme = errors.New(
|
errInvalidScheme = errors.New(
|
||||||
"only http and https are allowed",
|
"only http and https are allowed",
|
||||||
@@ -72,14 +72,16 @@ var blockedNetworks []*net.IPNet
|
|||||||
var blockedPublicNetworks []*net.IPNet
|
var blockedPublicNetworks []*net.IPNet
|
||||||
|
|
||||||
// alwaysBlockedNetworks are the ranges no configuration can
|
// alwaysBlockedNetworks are the ranges no configuration can
|
||||||
// open: the link-local blocks and the cloud instance metadata
|
// open: the link-local blocks, the cloud instance metadata
|
||||||
// endpoints that live outside them. Reaching one is credential
|
// endpoints that live outside them, and the unspecified
|
||||||
// or user-data theft rather than delivery to an internal
|
// addresses. Reaching a metadata endpoint is credential or
|
||||||
// service, so a supplied CIDR that covers such an address still
|
// user-data theft rather than delivery to an internal service,
|
||||||
// leaves it blocked.
|
// so a supplied CIDR that covers such an address still leaves it
|
||||||
|
// blocked.
|
||||||
//
|
//
|
||||||
// Inclusion criterion — an address belongs here only if BOTH
|
// Inclusion criterion — an address belongs here only if BOTH
|
||||||
// hold, and every entry below satisfies both:
|
// hold, and every entry below but the unspecified addresses
|
||||||
|
// satisfies both:
|
||||||
//
|
//
|
||||||
// 1. It is a fixed address assigned by the provider, or a
|
// 1. It is a fixed address assigned by the provider, or a
|
||||||
// range reserved by IANA — never one the operator chose.
|
// range reserved by IANA — never one the operator chose.
|
||||||
@@ -112,6 +114,12 @@ var blockedPublicNetworks []*net.IPNet
|
|||||||
// This is a criterion, not an enumeration of every metadata
|
// This is a criterion, not an enumeration of every metadata
|
||||||
// address in existence.
|
// address in existence.
|
||||||
//
|
//
|
||||||
|
// The unspecified addresses 0.0.0.0 and :: fail (2) and are here
|
||||||
|
// anyway. No host can have either, and on Linux a connection to
|
||||||
|
// one reaches this host's own loopback, so an allowlist opens
|
||||||
|
// loopback only by naming it (127.0.0.0/8, ::1/128). Nothing else
|
||||||
|
// lives at either address, so refusing them costs nothing.
|
||||||
|
//
|
||||||
// Every entry is either already in blockedNetworks — this list is
|
// Every entry is either already in blockedNetworks — this list is
|
||||||
// what makes it unconditional — or an alternate encoding of
|
// what makes it unconditional — or an alternate encoding of
|
||||||
// 169.254.169.254 that Contains does not match against
|
// 169.254.169.254 that Contains does not match against
|
||||||
@@ -131,23 +139,46 @@ var alwaysBlockedNetworks []*net.IPNet
|
|||||||
//nolint:gochecknoinits // init is the idiomatic way to parse CIDRs once at startup
|
//nolint:gochecknoinits // init is the idiomatic way to parse CIDRs once at startup
|
||||||
func init() {
|
func init() {
|
||||||
blockedNetworks = mustParseCIDRs([]string{
|
blockedNetworks = mustParseCIDRs([]string{
|
||||||
|
// IPv4 loopback.
|
||||||
"127.0.0.0/8",
|
"127.0.0.0/8",
|
||||||
|
// RFC 1918 private network.
|
||||||
"10.0.0.0/8",
|
"10.0.0.0/8",
|
||||||
|
// RFC 1918 private network.
|
||||||
"172.16.0.0/12",
|
"172.16.0.0/12",
|
||||||
|
// RFC 1918 private network.
|
||||||
"192.168.0.0/16",
|
"192.168.0.0/16",
|
||||||
|
// IPv4 link-local.
|
||||||
"169.254.0.0/16",
|
"169.254.0.0/16",
|
||||||
|
// "This network", holding the IPv4 unspecified address 0.0.0.0.
|
||||||
"0.0.0.0/8",
|
"0.0.0.0/8",
|
||||||
|
// Carrier-grade NAT shared address space.
|
||||||
"100.64.0.0/10",
|
"100.64.0.0/10",
|
||||||
|
// IETF protocol assignments.
|
||||||
"192.0.0.0/24",
|
"192.0.0.0/24",
|
||||||
|
// IPv4 documentation (TEST-NET-1).
|
||||||
"192.0.2.0/24",
|
"192.0.2.0/24",
|
||||||
|
// Benchmarking.
|
||||||
"198.18.0.0/15",
|
"198.18.0.0/15",
|
||||||
|
// IPv4 documentation (TEST-NET-2).
|
||||||
"198.51.100.0/24",
|
"198.51.100.0/24",
|
||||||
|
// IPv4 documentation (TEST-NET-3).
|
||||||
"203.0.113.0/24",
|
"203.0.113.0/24",
|
||||||
|
// IPv4 multicast.
|
||||||
"224.0.0.0/4",
|
"224.0.0.0/4",
|
||||||
|
// Reserved, including the broadcast address.
|
||||||
"240.0.0.0/4",
|
"240.0.0.0/4",
|
||||||
|
// IPv6 loopback.
|
||||||
"::1/128",
|
"::1/128",
|
||||||
|
// IPv6 unspecified address.
|
||||||
|
"::/128",
|
||||||
|
// IPv6 unique local addresses.
|
||||||
"fc00::/7",
|
"fc00::/7",
|
||||||
|
// IPv6 link-local.
|
||||||
"fe80::/10",
|
"fe80::/10",
|
||||||
|
// IPv6 multicast.
|
||||||
|
"ff00::/8",
|
||||||
|
// IPv6 documentation.
|
||||||
|
"2001:db8::/32",
|
||||||
})
|
})
|
||||||
|
|
||||||
blockedPublicNetworks = mustParseCIDRs([]string{
|
blockedPublicNetworks = mustParseCIDRs([]string{
|
||||||
@@ -207,6 +238,14 @@ func init() {
|
|||||||
// allowlist from opening it.
|
// allowlist from opening it.
|
||||||
"192.0.0.192/32",
|
"192.0.0.192/32",
|
||||||
|
|
||||||
|
// The unspecified addresses, each of which reaches this
|
||||||
|
// host's loopback on Linux.
|
||||||
|
//
|
||||||
|
// IPv4 unspecified address, inside the blocked 0.0.0.0/8.
|
||||||
|
"0.0.0.0/32",
|
||||||
|
// IPv6 unspecified address.
|
||||||
|
"::/128",
|
||||||
|
|
||||||
// 169.254.169.254 as an IPv4-compatible IPv6 address.
|
// 169.254.169.254 as an IPv4-compatible IPv6 address.
|
||||||
"::a9fe:a9fe/128",
|
"::a9fe:a9fe/128",
|
||||||
// 169.254.169.254 behind the NAT64 well-known prefix.
|
// 169.254.169.254 behind the NAT64 well-known prefix.
|
||||||
@@ -343,8 +382,9 @@ func (g *Guard) allows(ip net.IP) bool {
|
|||||||
// The order is the policy:
|
// The order is the policy:
|
||||||
//
|
//
|
||||||
// 1. alwaysBlockedNetworks is refused before the allowlist is
|
// 1. alwaysBlockedNetworks is refused before the allowlist is
|
||||||
// consulted, so no configured CIDR reaches link-local or a
|
// consulted, so no configured CIDR reaches link-local, a
|
||||||
// cloud metadata endpoint at a non-public address.
|
// cloud metadata endpoint at a non-public address, or an
|
||||||
|
// unspecified address.
|
||||||
// 2. The allowlist is consulted next, so a listed private
|
// 2. The allowlist is consulted next, so a listed private
|
||||||
// network, or a listed public address on the default
|
// network, or a listed public address on the default
|
||||||
// blocklist, becomes reachable.
|
// blocklist, becomes reachable.
|
||||||
|
|||||||
@@ -524,6 +524,10 @@ func TestAlwaysBlockedNetworks_PinnedSet(t *testing.T) {
|
|||||||
// Oracle Cloud Classic metadata, inside the blocked
|
// Oracle Cloud Classic metadata, inside the blocked
|
||||||
// 192.0.0.0/24.
|
// 192.0.0.0/24.
|
||||||
"192.0.0.192/32",
|
"192.0.0.192/32",
|
||||||
|
// The IPv4 and IPv6 unspecified addresses, each of
|
||||||
|
// which reaches this host's loopback on Linux.
|
||||||
|
"0.0.0.0/32",
|
||||||
|
"::/128",
|
||||||
// 169.254.169.254 as an IPv4-compatible IPv6 address.
|
// 169.254.169.254 as an IPv4-compatible IPv6 address.
|
||||||
"::a9fe:a9fe/128",
|
"::a9fe:a9fe/128",
|
||||||
// 169.254.169.254 behind the NAT64 well-known prefix.
|
// 169.254.169.254 behind the NAT64 well-known prefix.
|
||||||
@@ -556,7 +560,8 @@ func TestDefaultBlocklist_PinnedSet(t *testing.T) {
|
|||||||
{cidr: "172.16.0.0/12", reopenable: true},
|
{cidr: "172.16.0.0/12", reopenable: true},
|
||||||
{cidr: "192.168.0.0/16", reopenable: true},
|
{cidr: "192.168.0.0/16", reopenable: true},
|
||||||
{cidr: linkLocalIPv4, reopenable: false},
|
{cidr: linkLocalIPv4, reopenable: false},
|
||||||
{cidr: "0.0.0.0/8", reopenable: true},
|
// Its first address, 0.0.0.0, is in the unconditional set.
|
||||||
|
{cidr: "0.0.0.0/8", reopenable: false},
|
||||||
{cidr: "100.64.0.0/10", reopenable: true},
|
{cidr: "100.64.0.0/10", reopenable: true},
|
||||||
{cidr: "192.0.0.0/24", reopenable: true},
|
{cidr: "192.0.0.0/24", reopenable: true},
|
||||||
{cidr: "192.0.2.0/24", reopenable: true},
|
{cidr: "192.0.2.0/24", reopenable: true},
|
||||||
@@ -566,8 +571,11 @@ func TestDefaultBlocklist_PinnedSet(t *testing.T) {
|
|||||||
{cidr: "224.0.0.0/4", reopenable: true},
|
{cidr: "224.0.0.0/4", reopenable: true},
|
||||||
{cidr: "240.0.0.0/4", reopenable: true},
|
{cidr: "240.0.0.0/4", reopenable: true},
|
||||||
{cidr: "::1/128", reopenable: true},
|
{cidr: "::1/128", reopenable: true},
|
||||||
|
{cidr: "::/128", reopenable: false},
|
||||||
{cidr: "fc00::/7", reopenable: true},
|
{cidr: "fc00::/7", reopenable: true},
|
||||||
{cidr: "fe80::/10", reopenable: false},
|
{cidr: "fe80::/10", reopenable: false},
|
||||||
|
{cidr: "ff00::/8", reopenable: true},
|
||||||
|
{cidr: "2001:db8::/32", reopenable: true},
|
||||||
{cidr: "168.63.129.16/32", public: true, reopenable: true},
|
{cidr: "168.63.129.16/32", public: true, reopenable: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,42 @@ func TestValidateTargetURL_Blocked(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestDefaultGuard_RefusesUnspecifiedMulticastAndDocumentation
|
||||||
|
// covers the unspecified addresses and the IPv6 multicast and
|
||||||
|
// documentation ranges: with no allowlist set, each is refused
|
||||||
|
// both when a target is created and when a delivery dials it.
|
||||||
|
func TestDefaultGuard_RefusesUnspecifiedMulticastAndDocumentation(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
guard := delivery.NewTestGuard()
|
||||||
|
|
||||||
|
targets := []string{
|
||||||
|
// The unspecified addresses. On Linux a connection to
|
||||||
|
// either reaches this host's loopback.
|
||||||
|
"http://0.0.0.0:8080/hook",
|
||||||
|
"http://[::]:8080/hook",
|
||||||
|
// IPv6 multicast, all nodes.
|
||||||
|
"http://[ff02::1]/hook",
|
||||||
|
// IPv6 documentation.
|
||||||
|
"http://[2001:db8::1]/hook",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, target := range targets {
|
||||||
|
t.Run(target, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
require.Error(t,
|
||||||
|
guard.ValidateTargetURL(context.Background(), target),
|
||||||
|
"%s must be refused at target creation", target,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertDialRefused(t, guard, target)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidateTargetURL_Allowed(t *testing.T) {
|
func TestValidateTargetURL_Allowed(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -1569,10 +1569,11 @@ func (h *Handlers) validateTargetURL(
|
|||||||
msg := "Invalid target URL: " + err.Error()
|
msg := "Invalid target URL: " + err.Error()
|
||||||
|
|
||||||
// Only a private or reserved address's refusal says how
|
// Only a private or reserved address's refusal says how
|
||||||
// to allow it. Metadata refusals never do: link-local and
|
// to allow it. Other refusals never do: link-local, the
|
||||||
// the other unconditional metadata addresses cannot be
|
// unspecified addresses and the other unconditional
|
||||||
// opened, and the default blocklist's public addresses,
|
// metadata addresses cannot be opened, and the default
|
||||||
// which listing does open, hand out credentials.
|
// blocklist's public addresses, which listing does open,
|
||||||
|
// hand out credentials.
|
||||||
if errors.Is(err, delivery.ErrBlockedPrivateOrReservedIP) {
|
if errors.Is(err, delivery.ErrBlockedPrivateOrReservedIP) {
|
||||||
msg += ". Private and reserved addresses are refused " +
|
msg += ". Private and reserved addresses are refused " +
|
||||||
"by default; the server's ALLOWED_EGRESS_CIDRS " +
|
"by default; the server's ALLOWED_EGRESS_CIDRS " +
|
||||||
|
|||||||
Reference in New Issue
Block a user