155 lines
4.5 KiB
Go
155 lines
4.5 KiB
Go
package checker
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
)
|
|
|
|
func TestLowerFQDN(t *testing.T) {
|
|
cases := []struct {
|
|
in, want string
|
|
}{
|
|
{"Example.COM", "example.com."},
|
|
{"example.com.", "example.com."},
|
|
{"", "."},
|
|
{"X", "x."},
|
|
{"1.168.192.IN-ADDR.ARPA.", "1.168.192.in-addr.arpa."},
|
|
}
|
|
for _, c := range cases {
|
|
if got := lowerFQDN(c.in); got != c.want {
|
|
t.Errorf("lowerFQDN(%q)=%q, want %q", c.in, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsReverseArpa(t *testing.T) {
|
|
cases := []struct {
|
|
in string
|
|
want bool
|
|
}{
|
|
{"1.168.192.in-addr.arpa", true},
|
|
{"in-addr.arpa", true},
|
|
{"in-addr.arpa.", true},
|
|
{"IN-ADDR.ARPA", true},
|
|
{"ip6.arpa", true},
|
|
{"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", true},
|
|
{"example.com", false},
|
|
{"arpa", false},
|
|
{"in-addr.arpa.example.com", false},
|
|
{"", false},
|
|
}
|
|
for _, c := range cases {
|
|
if got := isReverseArpa(c.in); got != c.want {
|
|
t.Errorf("isReverseArpa(%q)=%v, want %v", c.in, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsIPv6Arpa(t *testing.T) {
|
|
cases := []struct {
|
|
in string
|
|
want bool
|
|
}{
|
|
{"ip6.arpa", true},
|
|
{"IP6.ARPA.", true},
|
|
{"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.", true},
|
|
{"1.168.192.in-addr.arpa", false},
|
|
{"in-addr.arpa", false},
|
|
{"example.com", false},
|
|
}
|
|
for _, c := range cases {
|
|
if got := isIPv6Arpa(c.in); got != c.want {
|
|
t.Errorf("isIPv6Arpa(%q)=%v, want %v", c.in, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReverseNameToIP_IPv4(t *testing.T) {
|
|
cases := []struct {
|
|
in string
|
|
want string // "" means nil
|
|
}{
|
|
{"42.1.168.192.in-addr.arpa", "192.168.1.42"},
|
|
{"42.1.168.192.IN-ADDR.ARPA.", "192.168.1.42"},
|
|
{"1.168.192.in-addr.arpa", ""}, // partial: only 3 labels
|
|
{"a.b.c.d.in-addr.arpa", ""}, // non-numeric
|
|
{"256.0.0.0.in-addr.arpa", ""}, // out of range parses with strconv but ParseIP fails
|
|
{"1.2.3.4.5.in-addr.arpa", ""}, // too many
|
|
{"in-addr.arpa", ""}, // apex, no labels
|
|
{"example.com", ""}, // unrelated
|
|
}
|
|
for _, c := range cases {
|
|
got := reverseNameToIP(c.in)
|
|
switch {
|
|
case c.want == "" && got != nil:
|
|
t.Errorf("reverseNameToIP(%q)=%v, want nil", c.in, got)
|
|
case c.want != "" && (got == nil || got.String() != c.want):
|
|
t.Errorf("reverseNameToIP(%q)=%v, want %s", c.in, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReverseNameToIP_IPv6(t *testing.T) {
|
|
// 2001:db8::1 expanded reverse:
|
|
// 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
|
|
full := "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"
|
|
got := reverseNameToIP(full)
|
|
if got == nil {
|
|
t.Fatalf("reverseNameToIP(%q) returned nil", full)
|
|
}
|
|
want := net.ParseIP("2001:db8::1")
|
|
if !got.Equal(want) {
|
|
t.Errorf("reverseNameToIP(%q)=%v, want %v", full, got, want)
|
|
}
|
|
|
|
// Partial / invalid IPv6 reverse names → nil.
|
|
partials := []string{
|
|
"d.0.1.0.0.2.ip6.arpa", // /24 zone, only 6 nibbles
|
|
"ip6.arpa", // apex
|
|
"x.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", // multi-char label
|
|
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.ip6.arpa", // 31 labels
|
|
}
|
|
for _, p := range partials {
|
|
if r := reverseNameToIP(p); r != nil {
|
|
t.Errorf("reverseNameToIP(%q)=%v, want nil", p, r)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIPEqual(t *testing.T) {
|
|
cases := []struct {
|
|
addr string
|
|
ip net.IP
|
|
want bool
|
|
}{
|
|
{"192.168.1.1", net.ParseIP("192.168.1.1"), true},
|
|
{"192.168.1.1", net.ParseIP("192.168.1.2"), false},
|
|
{"2001:db8::1", net.ParseIP("2001:0db8:0000::1"), true},
|
|
{"::ffff:192.168.1.1", net.ParseIP("192.168.1.1"), true},
|
|
{"not-an-ip", net.ParseIP("192.168.1.1"), false},
|
|
{"", net.ParseIP("192.168.1.1"), false},
|
|
}
|
|
for _, c := range cases {
|
|
if got := ipEqual(c.addr, c.ip); got != c.want {
|
|
t.Errorf("ipEqual(%q,%v)=%v, want %v", c.addr, c.ip, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSystemResolverFallback(t *testing.T) {
|
|
// Force the fallback path: even if /etc/resolv.conf exists, the fallback
|
|
// kicks in when the file is missing or has zero servers. We can't easily
|
|
// remove /etc/resolv.conf in a test, so just assert the result is a valid
|
|
// host:port and that FallbackResolver itself is well-formed.
|
|
host, port, err := net.SplitHostPort(FallbackResolver)
|
|
if err != nil {
|
|
t.Fatalf("FallbackResolver = %q is not host:port: %v", FallbackResolver, err)
|
|
}
|
|
if host == "" || port == "" {
|
|
t.Errorf("FallbackResolver = %q has empty host or port", FallbackResolver)
|
|
}
|
|
got := systemResolver()
|
|
if _, _, err := net.SplitHostPort(got); err != nil {
|
|
t.Errorf("systemResolver() = %q is not host:port: %v", got, err)
|
|
}
|
|
}
|