Pull request: 3142 custom private subnets
Merge in DNS/adguard-home from 3142-custom-subnets to master Updates #3142. Squashed commit of the following: commit 11469ade75b9dc32ee6d93e3aa35cf79dbaa28b2 Author: Eugene Burkov <E.Burkov@AdGuard.COM> Date: Thu Mar 17 19:56:02 2022 +0300 all: upd golibs, use subnet set
This commit is contained in:
@@ -1,158 +0,0 @@
|
||||
package aghnet
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// SubnetDetector describes IP address properties.
|
||||
type SubnetDetector struct {
|
||||
// spNets is the collection of special-purpose address registries as defined
|
||||
// by RFC 6890.
|
||||
spNets []*net.IPNet
|
||||
|
||||
// locServedNets is the collection of locally-served networks as defined by
|
||||
// RFC 6303.
|
||||
locServedNets []*net.IPNet
|
||||
}
|
||||
|
||||
// NewSubnetDetector returns a new IP detector.
|
||||
//
|
||||
// TODO(a.garipov): Decide whether an error is actually needed.
|
||||
func NewSubnetDetector() (snd *SubnetDetector, err error) {
|
||||
spNets := []string{
|
||||
// "This" network.
|
||||
"0.0.0.0/8",
|
||||
// Private-Use Networks.
|
||||
"10.0.0.0/8",
|
||||
// Shared Address Space.
|
||||
"100.64.0.0/10",
|
||||
// Loopback.
|
||||
"127.0.0.0/8",
|
||||
// Link Local.
|
||||
"169.254.0.0/16",
|
||||
// Private-Use Networks.
|
||||
"172.16.0.0/12",
|
||||
// IETF Protocol Assignments.
|
||||
"192.0.0.0/24",
|
||||
// DS-Lite.
|
||||
"192.0.0.0/29",
|
||||
// TEST-NET-1
|
||||
"192.0.2.0/24",
|
||||
// 6to4 Relay Anycast.
|
||||
"192.88.99.0/24",
|
||||
// Private-Use Networks.
|
||||
"192.168.0.0/16",
|
||||
// Network Interconnect Device Benchmark Testing.
|
||||
"198.18.0.0/15",
|
||||
// TEST-NET-2.
|
||||
"198.51.100.0/24",
|
||||
// TEST-NET-3.
|
||||
"203.0.113.0/24",
|
||||
// Reserved for Future Use.
|
||||
"240.0.0.0/4",
|
||||
// Limited Broadcast.
|
||||
"255.255.255.255/32",
|
||||
|
||||
// Loopback.
|
||||
"::1/128",
|
||||
// Unspecified.
|
||||
"::/128",
|
||||
// IPv4-IPv6 Translation Address.
|
||||
"64:ff9b::/96",
|
||||
|
||||
// IPv4-Mapped Address. Since this network is used for mapping
|
||||
// IPv4 addresses, we don't include it.
|
||||
// "::ffff:0:0/96",
|
||||
|
||||
// Discard-Only Prefix.
|
||||
"100::/64",
|
||||
// IETF Protocol Assignments.
|
||||
"2001::/23",
|
||||
// TEREDO.
|
||||
"2001::/32",
|
||||
// Benchmarking.
|
||||
"2001:2::/48",
|
||||
// Documentation.
|
||||
"2001:db8::/32",
|
||||
// ORCHID.
|
||||
"2001:10::/28",
|
||||
// 6to4.
|
||||
"2002::/16",
|
||||
// Unique-Local.
|
||||
"fc00::/7",
|
||||
// Linked-Scoped Unicast.
|
||||
"fe80::/10",
|
||||
}
|
||||
|
||||
// TODO(e.burkov): It's a subslice of the slice above. Should be done
|
||||
// smarter.
|
||||
locServedNets := []string{
|
||||
// IPv4.
|
||||
"10.0.0.0/8",
|
||||
"172.16.0.0/12",
|
||||
"192.168.0.0/16",
|
||||
"127.0.0.0/8",
|
||||
"169.254.0.0/16",
|
||||
"192.0.2.0/24",
|
||||
"198.51.100.0/24",
|
||||
"203.0.113.0/24",
|
||||
"255.255.255.255/32",
|
||||
// IPv6.
|
||||
"::/128",
|
||||
"::1/128",
|
||||
"fe80::/10",
|
||||
"2001:db8::/32",
|
||||
"fd00::/8",
|
||||
}
|
||||
|
||||
snd = &SubnetDetector{
|
||||
spNets: make([]*net.IPNet, len(spNets)),
|
||||
locServedNets: make([]*net.IPNet, len(locServedNets)),
|
||||
}
|
||||
for i, ipnetStr := range spNets {
|
||||
var ipnet *net.IPNet
|
||||
_, ipnet, err = net.ParseCIDR(ipnetStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
snd.spNets[i] = ipnet
|
||||
}
|
||||
for i, ipnetStr := range locServedNets {
|
||||
var ipnet *net.IPNet
|
||||
_, ipnet, err = net.ParseCIDR(ipnetStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
snd.locServedNets[i] = ipnet
|
||||
}
|
||||
|
||||
return snd, nil
|
||||
}
|
||||
|
||||
// anyNetContains ranges through the given ipnets slice searching for the one
|
||||
// which contains the ip. For internal use only.
|
||||
//
|
||||
// TODO(e.burkov): Think about memoization.
|
||||
func anyNetContains(ipnets *[]*net.IPNet, ip net.IP) (is bool) {
|
||||
for _, ipnet := range *ipnets {
|
||||
if ipnet.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsSpecialNetwork returns true if IP address is contained by any of
|
||||
// special-purpose IP address registries. It's safe for concurrent use.
|
||||
func (snd *SubnetDetector) IsSpecialNetwork(ip net.IP) (is bool) {
|
||||
return anyNetContains(&snd.spNets, ip)
|
||||
}
|
||||
|
||||
// IsLocallyServedNetwork returns true if IP address is contained by any of
|
||||
// locally-served IP address registries. It's safe for concurrent use.
|
||||
func (snd *SubnetDetector) IsLocallyServedNetwork(ip net.IP) (is bool) {
|
||||
return anyNetContains(&snd.locServedNets, ip)
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
package aghnet
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSubnetDetector_DetectSpecialNetwork(t *testing.T) {
|
||||
snd, err := NewSubnetDetector()
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ip net.IP
|
||||
want bool
|
||||
}{{
|
||||
name: "not_specific",
|
||||
ip: net.ParseIP("8.8.8.8"),
|
||||
want: false,
|
||||
}, {
|
||||
name: "this_host_on_this_network",
|
||||
ip: net.ParseIP("0.0.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "private-Use",
|
||||
ip: net.ParseIP("10.0.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "shared_address_space",
|
||||
ip: net.ParseIP("100.64.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "loopback",
|
||||
ip: net.ParseIP("127.0.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "link_local",
|
||||
ip: net.ParseIP("169.254.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "private-use",
|
||||
ip: net.ParseIP("172.16.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "ietf_protocol_assignments",
|
||||
ip: net.ParseIP("192.0.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "ds-lite",
|
||||
ip: net.ParseIP("192.0.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "documentation_(test-net-1)",
|
||||
ip: net.ParseIP("192.0.2.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "6to4_relay_anycast",
|
||||
ip: net.ParseIP("192.88.99.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "private-use",
|
||||
ip: net.ParseIP("192.168.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "benchmarking",
|
||||
ip: net.ParseIP("198.18.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "documentation_(test-net-2)",
|
||||
ip: net.ParseIP("198.51.100.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "documentation_(test-net-3)",
|
||||
ip: net.ParseIP("203.0.113.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "reserved",
|
||||
ip: net.ParseIP("240.0.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "limited_broadcast",
|
||||
ip: net.ParseIP("255.255.255.255"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "loopback_address",
|
||||
ip: net.ParseIP("::1"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "unspecified_address",
|
||||
ip: net.ParseIP("::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "ipv4-ipv6_translation",
|
||||
ip: net.ParseIP("64:ff9b::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "discard-only_address_block",
|
||||
ip: net.ParseIP("100::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "ietf_protocol_assignments",
|
||||
ip: net.ParseIP("2001::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "teredo",
|
||||
ip: net.ParseIP("2001::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "benchmarking",
|
||||
ip: net.ParseIP("2001:2::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "documentation",
|
||||
ip: net.ParseIP("2001:db8::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "orchid",
|
||||
ip: net.ParseIP("2001:10::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "6to4",
|
||||
ip: net.ParseIP("2002::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "unique-local",
|
||||
ip: net.ParseIP("fc00::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "linked-scoped_unicast",
|
||||
ip: net.ParseIP("fe80::"),
|
||||
want: true,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Equal(t, tc.want, snd.IsSpecialNetwork(tc.ip))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubnetDetector_DetectLocallyServedNetwork(t *testing.T) {
|
||||
snd, err := NewSubnetDetector()
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ip net.IP
|
||||
want bool
|
||||
}{{
|
||||
name: "not_specific",
|
||||
ip: net.ParseIP("8.8.8.8"),
|
||||
want: false,
|
||||
}, {
|
||||
name: "private-Use",
|
||||
ip: net.ParseIP("10.0.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "loopback",
|
||||
ip: net.ParseIP("127.0.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "link_local",
|
||||
ip: net.ParseIP("169.254.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "private-use",
|
||||
ip: net.ParseIP("172.16.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "documentation_(test-net-1)",
|
||||
ip: net.ParseIP("192.0.2.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "private-use",
|
||||
ip: net.ParseIP("192.168.0.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "documentation_(test-net-2)",
|
||||
ip: net.ParseIP("198.51.100.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "documentation_(test-net-3)",
|
||||
ip: net.ParseIP("203.0.113.0"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "limited_broadcast",
|
||||
ip: net.ParseIP("255.255.255.255"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "loopback_address",
|
||||
ip: net.ParseIP("::1"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "unspecified_address",
|
||||
ip: net.ParseIP("::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "documentation",
|
||||
ip: net.ParseIP("2001:db8::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "linked-scoped_unicast",
|
||||
ip: net.ParseIP("fe80::"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "locally_assigned",
|
||||
ip: net.ParseIP("fd00::1"),
|
||||
want: true,
|
||||
}, {
|
||||
name: "not_locally_assigned",
|
||||
ip: net.ParseIP("fc00::1"),
|
||||
want: false,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Equal(t, tc.want, snd.IsLocallyServedNetwork(tc.ip))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubnetDetector_Detect_parallel(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
snd, err := NewSubnetDetector()
|
||||
require.NoError(t, err)
|
||||
|
||||
testFunc := func() {
|
||||
for _, ip := range []net.IP{
|
||||
net.IPv4allrouter,
|
||||
net.IPv4allsys,
|
||||
net.IPv4bcast,
|
||||
net.IPv4zero,
|
||||
net.IPv6interfacelocalallnodes,
|
||||
net.IPv6linklocalallnodes,
|
||||
net.IPv6linklocalallrouters,
|
||||
net.IPv6loopback,
|
||||
net.IPv6unspecified,
|
||||
} {
|
||||
_ = snd.IsSpecialNetwork(ip)
|
||||
_ = snd.IsLocallyServedNetwork(ip)
|
||||
}
|
||||
}
|
||||
|
||||
const goroutinesNum = 50
|
||||
for i := 0; i < goroutinesNum; i++ {
|
||||
go testFunc()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user