server.randaddr_test.go Maven / Gradle / Ivy
The newest version!
package main
import (
"bytes"
"net"
"testing"
)
func mustParseCIDR(s string) *net.IPNet {
_, ipnet, err := net.ParseCIDR(s)
if err != nil {
panic(err)
}
return ipnet
}
func TestRandAddr(t *testing.T) {
outer:
for _, ipnet := range []*net.IPNet{
mustParseCIDR("127.0.0.1/0"),
mustParseCIDR("127.0.0.1/24"),
mustParseCIDR("127.0.0.55/32"),
mustParseCIDR("2001:db8::1234/0"),
mustParseCIDR("2001:db8::1234/32"),
mustParseCIDR("2001:db8::1234/128"),
// Non-canonical masks (that don't consist of 1s followed by 0s)
// work too, why not.
&net.IPNet{
IP: net.IP{1, 2, 3, 4},
Mask: net.IPMask{0x00, 0x07, 0xff, 0xff},
},
} {
for i := 0; i < 100; i++ {
ip, err := randIPAddr(ipnet)
if err != nil {
t.Errorf("%v returned error %v", ipnet, err)
continue outer
}
if !ipnet.Contains(ip) {
t.Errorf("%v does not contain %v", ipnet, ip)
continue outer
}
}
}
}
func TestRandAddrUnequalLengths(t *testing.T) {
for _, ipnet := range []*net.IPNet{
&net.IPNet{
IP: net.IP{1, 2, 3, 4},
Mask: net.CIDRMask(32, 128),
},
&net.IPNet{
IP: net.IP{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
Mask: net.CIDRMask(24, 32),
},
&net.IPNet{
IP: net.IP{1, 2, 3, 4},
Mask: net.IPMask{},
},
&net.IPNet{
IP: net.IP{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
Mask: net.IPMask{},
},
} {
_, err := randIPAddr(ipnet)
if err == nil {
t.Errorf("%v did not result in error, but should have", ipnet)
}
}
}
func BenchmarkRandAddr(b *testing.B) {
for _, test := range []struct {
label string
ipnet net.IPNet
}{
{"IPv4/32", net.IPNet{IP: net.IP{127, 0, 0, 1}, Mask: net.CIDRMask(32, 32)}},
{"IPv4/24", net.IPNet{IP: net.IP{127, 0, 0, 1}, Mask: net.CIDRMask(32, 32)}},
{"IPv6/64", net.IPNet{
IP: net.IP{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34},
Mask: net.CIDRMask(64, 128),
}},
{"IPv6/128", net.IPNet{
IP: net.IP{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34},
Mask: net.CIDRMask(128, 128),
}},
} {
b.Run(test.label, func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := randIPAddr(&test.ipnet)
if err != nil {
b.Fatal(err)
}
}
})
}
}
func ipNetEqual(a, b *net.IPNet) bool {
if !a.IP.Equal(b.IP) {
return false
}
// Comparing masks for equality is a little tricky because they may be
// different lengths. For masks in canonical form (those for which
// Size() returns other than (0, 0)), we consider two masks equal if the
// numbers of bits *not* covered by the prefix are equal; e.g.
// (120, 128) is equal to (24, 32), because they both have 8 bits not in
// the prefix. If either mask is not in canonical form, we require them
// to be equal as byte arrays (which includes length).
aOnes, aBits := a.Mask.Size()
bOnes, bBits := b.Mask.Size()
if aBits == 0 || bBits == 0 {
return bytes.Equal(a.Mask, b.Mask)
} else {
return aBits-aOnes == bBits-bOnes
}
}
func TestParseIPCIDR(t *testing.T) {
// Well-formed inputs.
for _, test := range []struct {
input string
expected *net.IPNet
}{
{"127.0.0.123", mustParseCIDR("127.0.0.123/32")},
{"127.0.0.123/0", mustParseCIDR("127.0.0.123/0")},
{"127.0.0.123/24", mustParseCIDR("127.0.0.123/24")},
{"127.0.0.123/32", mustParseCIDR("127.0.0.123/32")},
{"2001:db8::1234", mustParseCIDR("2001:db8::1234/128")},
{"2001:db8::1234/0", mustParseCIDR("2001:db8::1234/0")},
{"2001:db8::1234/32", mustParseCIDR("2001:db8::1234/32")},
{"2001:db8::1234/128", mustParseCIDR("2001:db8::1234/128")},
} {
ipnet, err := parseIPCIDR(test.input)
if err != nil {
t.Errorf("%q returned error %v", test.input, err)
continue
}
if !ipNetEqual(ipnet, test.expected) {
t.Errorf("%q → %v, expected %v", test.input, ipnet, test.expected)
}
}
// Bad inputs.
for _, input := range []string{
"",
"1.2.3",
"1.2.3/16",
"2001:db8:1234",
"2001:db8:1234/64",
"localhost",
} {
_, err := parseIPCIDR(input)
if err == nil {
t.Errorf("%q did not result in error, but should have", input)
}
}
}