fix(06-08): classify IPv6 transition addresses
- Decode embedded IPv4 from NAT64 well-known and local-use prefixes - Reapply private and reserved IPv4 policy to 6to4 destinations - Fail closed on malformed RFC 6052 local-use encodings
This commit is contained in:
@@ -22,16 +22,26 @@ var privateV6 = []netip.Prefix{
|
|||||||
netip.MustParsePrefix("fc00::/7"),
|
netip.MustParsePrefix("fc00::/7"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
nat64WellKnownPrefix = netip.MustParsePrefix("64:ff9b::/96")
|
||||||
|
nat64LocalUsePrefix = netip.MustParsePrefix("64:ff9b:1::/48")
|
||||||
|
sixToFourPrefix = netip.MustParsePrefix("2002::/16")
|
||||||
|
)
|
||||||
|
|
||||||
// isReservedOrPrivate classifies addr against the PHP private/loopback/
|
// isReservedOrPrivate classifies addr against the PHP private/loopback/
|
||||||
// reserved/CGNAT table. The caller must pass an already-Unmap()-ed address
|
// reserved/CGNAT table, including IPv4 embedded in supported IPv6 transition
|
||||||
// (fetch.go's dial hook); this function does not Unmap.
|
// formats.
|
||||||
func isReservedOrPrivate(addr netip.Addr) bool {
|
func isReservedOrPrivate(addr netip.Addr) bool {
|
||||||
if !addr.IsValid() {
|
if !addr.IsValid() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
addr = addr.Unmap()
|
||||||
if addr.IsMulticast() || addr.IsUnspecified() {
|
if addr.IsMulticast() || addr.IsUnspecified() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if embedded, ok := embeddedTransitionIPv4(addr); ok {
|
||||||
|
return isReservedOrPrivate(embedded)
|
||||||
|
}
|
||||||
table := privateV4
|
table := privateV4
|
||||||
if !addr.Is4() {
|
if !addr.Is4() {
|
||||||
table = privateV6
|
table = privateV6
|
||||||
@@ -43,3 +53,26 @@ func isReservedOrPrivate(addr netip.Addr) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// embeddedTransitionIPv4 extracts IPv4 from the transition formats supported
|
||||||
|
// by fetchguard. A recognized but malformed RFC 6052 /48 address returns an
|
||||||
|
// invalid address with ok=true so the classifier fails closed.
|
||||||
|
func embeddedTransitionIPv4(addr netip.Addr) (netip.Addr, bool) {
|
||||||
|
if !addr.Is6() {
|
||||||
|
return netip.Addr{}, false
|
||||||
|
}
|
||||||
|
b := addr.As16()
|
||||||
|
switch {
|
||||||
|
case nat64WellKnownPrefix.Contains(addr):
|
||||||
|
return netip.AddrFrom4([4]byte{b[12], b[13], b[14], b[15]}), true
|
||||||
|
case nat64LocalUsePrefix.Contains(addr):
|
||||||
|
if b[8] != 0 {
|
||||||
|
return netip.Addr{}, true
|
||||||
|
}
|
||||||
|
return netip.AddrFrom4([4]byte{b[6], b[7], b[9], b[10]}), true
|
||||||
|
case sixToFourPrefix.Contains(addr):
|
||||||
|
return netip.AddrFrom4([4]byte{b[2], b[3], b[4], b[5]}), true
|
||||||
|
default:
|
||||||
|
return netip.Addr{}, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user