Skip to content

Commit

Permalink
Add a way to allow for NAT64 mapped addresses
Browse files Browse the repository at this point in the history
This introduces the IPv6NAT64Prefix constant that can be passed to
WithAllowedV6Prefixes if so desired.
  • Loading branch information
daenney committed Jul 6, 2023
1 parent e23a15d commit d310348
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 0 deletions.
5 changes: 5 additions & 0 deletions cmd/ssrfgen/templates/ssrf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ var (
// assignments, i.e "the internet"
IPv6GlobalUnicast = netip.MustParsePrefix("{{ .V6GlobalUnicast }}")

// IPv6NAT64Prefix is the prefix set aside for NAT64. This allows a server
// to only have an IPv6 address but still be able to talk to an IPv4-only
// server through DNS64+NAT64
IPv6NAT64Prefix = netip.MustParsePrefix("64:ff9b::/96")

// IPv6DeniedPrefixes contains IPv6 special purpose IP prefixes from IANA
// within the IPv6 Global Unicast range that we wish to block by default
// https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
Expand Down
11 changes: 11 additions & 0 deletions ssrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ func WithAllowedV4Prefixes(prefixes ...netip.Prefix) Option {
// ranges outside of the global unicast range or connections to
// otherwise denied prefixes within the global unicast range.
//
// This function should be called with [IPv6NAT64Prefix] as one of the
// prefixes, if you run in an IPv6-only environment but provide IPv4
// connectivity through a combination of DNS64+NAT64. The NAT64 prefix
// is outside of the IPv6 global unicast range and as such blocked by
// default. Allowing it is typically harmless in dual-stack setups as
// your clients need an explicit route for 64:ff9b::/96 configured which
// won't be the case by default. Beware that allowing this prefix may
// allow for an address like 64:ff9b::7f00:1, i.e 127.0.0.1 mapped to
// NAT64. A NAT64 gateway should drop this. Ideally a DNS64 server
// would never generate an address for an RFC1918 IP in an A-record.
//
// This function overrides the allowed IPv6 prefixes, it does not accumulate.
func WithAllowedV6Prefixes(prefixes ...netip.Prefix) Option {
return func(g *Guardian) {
Expand Down
5 changes: 5 additions & 0 deletions ssrf_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ var (
// assignments, i.e "the internet"
IPv6GlobalUnicast = netip.MustParsePrefix("2000::/3")

// IPv6NAT64Prefix is the prefix set aside for NAT64. This allows a server
// to only have an IPv6 address but still be able to talk to an IPv4-only
// server through DNS64+NAT64
IPv6NAT64Prefix = netip.MustParsePrefix("64:ff9b::/96")

// IPv6DeniedPrefixes contains IPv6 special purpose IP prefixes from IANA
// within the IPv6 Global Unicast range that we wish to block by default
// https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
Expand Down
12 changes: 12 additions & 0 deletions ssrf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ func TestOptions(t *testing.T) {
Options: []Option{WithAllowedV6Prefixes(netip.MustParsePrefix("2002::/8"))},
Result: &Guardian{networks: []string{"tcp4", "tcp6"}, ports: []uint16{80, 443}, allowedv6Prefixes: []netip.Prefix{netip.MustParsePrefix("2002::/8")}, deniedv4Prefixes: IPv4DeniedPrefixes, deniedv6Prefixes: IPv6DeniedPrefixes, strNetworks: "tcp4, tcp6", strPorts: "80, 443"},
},
{
Name: "with allowed NAT64 prefix",
Options: []Option{WithAllowedV6Prefixes(IPv6NAT64Prefix)},
Result: &Guardian{networks: []string{"tcp4", "tcp6"}, ports: []uint16{80, 443}, allowedv6Prefixes: []netip.Prefix{IPv6NAT64Prefix}, deniedv4Prefixes: IPv4DeniedPrefixes, deniedv6Prefixes: IPv6DeniedPrefixes, strNetworks: "tcp4, tcp6", strPorts: "80, 443"},
},
{
Name: "with multiple allowed v6 prefix calls",
Options: []Option{WithAllowedV6Prefixes(netip.MustParsePrefix("2002::/23")), WithAllowedV6Prefixes(netip.MustParsePrefix("2002::/8"))},
Expand Down Expand Up @@ -155,6 +160,7 @@ func TestDefaultGuardian(t *testing.T) {
{Addr: "invalid network", Network: "udp6", Err: ErrProhibitedNetwork},
{Addr: "invalid address", Network: "tcp4", Err: ErrInvalidHostPort},
{Addr: "[::ffff:129.144.52.38]:80", Network: "tcp6", Err: ErrProhibitedIP},
{Addr: "[64:ff9b::7f00:1]:80", Network: "tcp6", Err: ErrProhibitedIP},
}

s := New()
Expand Down Expand Up @@ -224,6 +230,12 @@ func TestCustomGuardian(t *testing.T) {
Addr: "[2001::1]:80",
Network: "tcp6",
},
{
Name: "allow IPv6 NAT64 prefix",
Guardian: New(WithAllowedV6Prefixes(IPv6NAT64Prefix)),
Addr: "[64:ff9b::7f00:1]:80",
Network: "tcp6",
},
{
Name: "deny IPv4 prefix",
Guardian: New(WithDeniedV4Prefixes(netip.MustParsePrefix("8.8.8.0/24"))),
Expand Down

0 comments on commit d310348

Please sign in to comment.