checker-reverse-zone/checker/dns_test.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)
}
}