mirror of
https://github.com/fosrl/olm.git
synced 2026-02-07 21:46:40 +00:00
865 lines
23 KiB
Go
865 lines
23 KiB
Go
package dns
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
)
|
|
|
|
func TestWildcardMatching(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
pattern string
|
|
domain string
|
|
expected bool
|
|
}{
|
|
// Basic wildcard tests
|
|
{
|
|
name: "*.autoco.internal matches host.autoco.internal",
|
|
pattern: "*.autoco.internal.",
|
|
domain: "host.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "*.autoco.internal matches longerhost.autoco.internal",
|
|
pattern: "*.autoco.internal.",
|
|
domain: "longerhost.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "*.autoco.internal matches sub.host.autoco.internal",
|
|
pattern: "*.autoco.internal.",
|
|
domain: "sub.host.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "*.autoco.internal does NOT match autoco.internal",
|
|
pattern: "*.autoco.internal.",
|
|
domain: "autoco.internal.",
|
|
expected: false,
|
|
},
|
|
|
|
// Question mark wildcard tests
|
|
{
|
|
name: "host-0?.autoco.internal matches host-01.autoco.internal",
|
|
pattern: "host-0?.autoco.internal.",
|
|
domain: "host-01.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "host-0?.autoco.internal matches host-0a.autoco.internal",
|
|
pattern: "host-0?.autoco.internal.",
|
|
domain: "host-0a.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "host-0?.autoco.internal does NOT match host-0.autoco.internal",
|
|
pattern: "host-0?.autoco.internal.",
|
|
domain: "host-0.autoco.internal.",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "host-0?.autoco.internal does NOT match host-012.autoco.internal",
|
|
pattern: "host-0?.autoco.internal.",
|
|
domain: "host-012.autoco.internal.",
|
|
expected: false,
|
|
},
|
|
|
|
// Combined wildcard tests
|
|
{
|
|
name: "*.host-0?.autoco.internal matches sub.host-01.autoco.internal",
|
|
pattern: "*.host-0?.autoco.internal.",
|
|
domain: "sub.host-01.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "*.host-0?.autoco.internal matches prefix.host-0a.autoco.internal",
|
|
pattern: "*.host-0?.autoco.internal.",
|
|
domain: "prefix.host-0a.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "*.host-0?.autoco.internal does NOT match host-01.autoco.internal",
|
|
pattern: "*.host-0?.autoco.internal.",
|
|
domain: "host-01.autoco.internal.",
|
|
expected: false,
|
|
},
|
|
|
|
// Multiple asterisks
|
|
{
|
|
name: "*.*. autoco.internal matches any.thing.autoco.internal",
|
|
pattern: "*.*.autoco.internal.",
|
|
domain: "any.thing.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "*.*.autoco.internal does NOT match single.autoco.internal",
|
|
pattern: "*.*.autoco.internal.",
|
|
domain: "single.autoco.internal.",
|
|
expected: false,
|
|
},
|
|
|
|
// Asterisk in middle
|
|
{
|
|
name: "host-*.autoco.internal matches host-anything.autoco.internal",
|
|
pattern: "host-*.autoco.internal.",
|
|
domain: "host-anything.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "host-*.autoco.internal matches host-.autoco.internal (empty match)",
|
|
pattern: "host-*.autoco.internal.",
|
|
domain: "host-.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
|
|
// Multiple question marks
|
|
{
|
|
name: "host-??.autoco.internal matches host-01.autoco.internal",
|
|
pattern: "host-??.autoco.internal.",
|
|
domain: "host-01.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "host-??.autoco.internal does NOT match host-1.autoco.internal",
|
|
pattern: "host-??.autoco.internal.",
|
|
domain: "host-1.autoco.internal.",
|
|
expected: false,
|
|
},
|
|
|
|
// Exact match (no wildcards)
|
|
{
|
|
name: "exact.autoco.internal matches exact.autoco.internal",
|
|
pattern: "exact.autoco.internal.",
|
|
domain: "exact.autoco.internal.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "exact.autoco.internal does NOT match other.autoco.internal",
|
|
pattern: "exact.autoco.internal.",
|
|
domain: "other.autoco.internal.",
|
|
expected: false,
|
|
},
|
|
|
|
// Edge cases
|
|
{
|
|
name: "* matches anything",
|
|
pattern: "*",
|
|
domain: "anything.at.all.",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "*.* matches multi.level.",
|
|
pattern: "*.*",
|
|
domain: "multi.level.",
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := matchWildcard(tt.pattern, tt.domain)
|
|
if result != tt.expected {
|
|
t.Errorf("matchWildcard(%q, %q) = %v, want %v", tt.pattern, tt.domain, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDNSRecordStoreWildcard(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add wildcard records
|
|
wildcardIP := net.ParseIP("10.0.0.1")
|
|
err := store.AddRecord("*.autoco.internal", wildcardIP)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add wildcard record: %v", err)
|
|
}
|
|
|
|
// Add exact record
|
|
exactIP := net.ParseIP("10.0.0.2")
|
|
err = store.AddRecord("exact.autoco.internal", exactIP)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add exact record: %v", err)
|
|
}
|
|
|
|
// Test exact match takes precedence
|
|
ips := store.GetRecords("exact.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 1 {
|
|
t.Errorf("Expected 1 IP for exact match, got %d", len(ips))
|
|
}
|
|
if !ips[0].Equal(exactIP) {
|
|
t.Errorf("Expected exact IP %v, got %v", exactIP, ips[0])
|
|
}
|
|
|
|
// Test wildcard match
|
|
ips = store.GetRecords("host.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 1 {
|
|
t.Errorf("Expected 1 IP for wildcard match, got %d", len(ips))
|
|
}
|
|
if !ips[0].Equal(wildcardIP) {
|
|
t.Errorf("Expected wildcard IP %v, got %v", wildcardIP, ips[0])
|
|
}
|
|
|
|
// Test non-match (base domain)
|
|
ips = store.GetRecords("autoco.internal.", RecordTypeA)
|
|
if len(ips) != 0 {
|
|
t.Errorf("Expected 0 IPs for base domain, got %d", len(ips))
|
|
}
|
|
}
|
|
|
|
func TestDNSRecordStoreComplexWildcard(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add complex wildcard pattern
|
|
ip1 := net.ParseIP("10.0.0.1")
|
|
err := store.AddRecord("*.host-0?.autoco.internal", ip1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add wildcard record: %v", err)
|
|
}
|
|
|
|
// Test matching domain
|
|
ips := store.GetRecords("sub.host-01.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 1 {
|
|
t.Errorf("Expected 1 IP for complex wildcard match, got %d", len(ips))
|
|
}
|
|
if len(ips) > 0 && !ips[0].Equal(ip1) {
|
|
t.Errorf("Expected IP %v, got %v", ip1, ips[0])
|
|
}
|
|
|
|
// Test non-matching domain (missing prefix)
|
|
ips = store.GetRecords("host-01.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 0 {
|
|
t.Errorf("Expected 0 IPs for domain without prefix, got %d", len(ips))
|
|
}
|
|
|
|
// Test non-matching domain (wrong ? position)
|
|
ips = store.GetRecords("sub.host-012.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 0 {
|
|
t.Errorf("Expected 0 IPs for domain with wrong ? match, got %d", len(ips))
|
|
}
|
|
}
|
|
|
|
func TestDNSRecordStoreRemoveWildcard(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add wildcard record
|
|
ip := net.ParseIP("10.0.0.1")
|
|
err := store.AddRecord("*.autoco.internal", ip)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add wildcard record: %v", err)
|
|
}
|
|
|
|
// Verify it exists
|
|
ips := store.GetRecords("host.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 1 {
|
|
t.Errorf("Expected 1 IP before removal, got %d", len(ips))
|
|
}
|
|
|
|
// Remove wildcard record
|
|
store.RemoveRecord("*.autoco.internal", nil)
|
|
|
|
// Verify it's gone
|
|
ips = store.GetRecords("host.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 0 {
|
|
t.Errorf("Expected 0 IPs after removal, got %d", len(ips))
|
|
}
|
|
}
|
|
|
|
func TestDNSRecordStoreMultipleWildcards(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add multiple wildcard patterns that don't overlap
|
|
ip1 := net.ParseIP("10.0.0.1")
|
|
ip2 := net.ParseIP("10.0.0.2")
|
|
ip3 := net.ParseIP("10.0.0.3")
|
|
|
|
err := store.AddRecord("*.prod.autoco.internal", ip1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add first wildcard: %v", err)
|
|
}
|
|
|
|
err = store.AddRecord("*.dev.autoco.internal", ip2)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add second wildcard: %v", err)
|
|
}
|
|
|
|
// Add a broader wildcard that matches both
|
|
err = store.AddRecord("*.autoco.internal", ip3)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add third wildcard: %v", err)
|
|
}
|
|
|
|
// Test domain matching only the prod pattern and the broad pattern
|
|
ips := store.GetRecords("host.prod.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 2 {
|
|
t.Errorf("Expected 2 IPs (prod + broad), got %d", len(ips))
|
|
}
|
|
|
|
// Test domain matching only the dev pattern and the broad pattern
|
|
ips = store.GetRecords("service.dev.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 2 {
|
|
t.Errorf("Expected 2 IPs (dev + broad), got %d", len(ips))
|
|
}
|
|
|
|
// Test domain matching only the broad pattern
|
|
ips = store.GetRecords("host.test.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 1 {
|
|
t.Errorf("Expected 1 IP (broad only), got %d", len(ips))
|
|
}
|
|
}
|
|
|
|
func TestDNSRecordStoreIPv6Wildcard(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add IPv6 wildcard record
|
|
ip := net.ParseIP("2001:db8::1")
|
|
err := store.AddRecord("*.autoco.internal", ip)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add IPv6 wildcard record: %v", err)
|
|
}
|
|
|
|
// Test wildcard match for IPv6
|
|
ips := store.GetRecords("host.autoco.internal.", RecordTypeAAAA)
|
|
if len(ips) != 1 {
|
|
t.Errorf("Expected 1 IPv6 for wildcard match, got %d", len(ips))
|
|
}
|
|
if len(ips) > 0 && !ips[0].Equal(ip) {
|
|
t.Errorf("Expected IPv6 %v, got %v", ip, ips[0])
|
|
}
|
|
}
|
|
|
|
func TestHasRecordWildcard(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add wildcard record
|
|
ip := net.ParseIP("10.0.0.1")
|
|
err := store.AddRecord("*.autoco.internal", ip)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add wildcard record: %v", err)
|
|
}
|
|
|
|
// Test HasRecord with wildcard match
|
|
if !store.HasRecord("host.autoco.internal.", RecordTypeA) {
|
|
t.Error("Expected HasRecord to return true for wildcard match")
|
|
}
|
|
|
|
// Test HasRecord with non-match
|
|
if store.HasRecord("autoco.internal.", RecordTypeA) {
|
|
t.Error("Expected HasRecord to return false for base domain")
|
|
}
|
|
}
|
|
|
|
func TestDNSRecordStoreCaseInsensitive(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add record with mixed case
|
|
ip := net.ParseIP("10.0.0.1")
|
|
err := store.AddRecord("MyHost.AutoCo.Internal", ip)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add mixed case record: %v", err)
|
|
}
|
|
|
|
// Test lookup with different cases
|
|
testCases := []string{
|
|
"myhost.autoco.internal.",
|
|
"MYHOST.AUTOCO.INTERNAL.",
|
|
"MyHost.AutoCo.Internal.",
|
|
"mYhOsT.aUtOcO.iNtErNaL.",
|
|
}
|
|
|
|
for _, domain := range testCases {
|
|
ips := store.GetRecords(domain, RecordTypeA)
|
|
if len(ips) != 1 {
|
|
t.Errorf("Expected 1 IP for domain %q, got %d", domain, len(ips))
|
|
}
|
|
if len(ips) > 0 && !ips[0].Equal(ip) {
|
|
t.Errorf("Expected IP %v for domain %q, got %v", ip, domain, ips[0])
|
|
}
|
|
}
|
|
|
|
// Test wildcard with mixed case
|
|
wildcardIP := net.ParseIP("10.0.0.2")
|
|
err = store.AddRecord("*.Example.Com", wildcardIP)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add mixed case wildcard: %v", err)
|
|
}
|
|
|
|
wildcardTestCases := []string{
|
|
"host.example.com.",
|
|
"HOST.EXAMPLE.COM.",
|
|
"Host.Example.Com.",
|
|
"HoSt.ExAmPlE.CoM.",
|
|
}
|
|
|
|
for _, domain := range wildcardTestCases {
|
|
ips := store.GetRecords(domain, RecordTypeA)
|
|
if len(ips) != 1 {
|
|
t.Errorf("Expected 1 IP for wildcard domain %q, got %d", domain, len(ips))
|
|
}
|
|
if len(ips) > 0 && !ips[0].Equal(wildcardIP) {
|
|
t.Errorf("Expected IP %v for wildcard domain %q, got %v", wildcardIP, domain, ips[0])
|
|
}
|
|
}
|
|
|
|
// Test removal with different case
|
|
store.RemoveRecord("MYHOST.AUTOCO.INTERNAL", nil)
|
|
ips := store.GetRecords("myhost.autoco.internal.", RecordTypeA)
|
|
if len(ips) != 0 {
|
|
t.Errorf("Expected 0 IPs after removal, got %d", len(ips))
|
|
}
|
|
|
|
// Test HasRecord with different case
|
|
if !store.HasRecord("HOST.EXAMPLE.COM.", RecordTypeA) {
|
|
t.Error("Expected HasRecord to return true for mixed case wildcard match")
|
|
}
|
|
}
|
|
|
|
func TestPTRRecordIPv4(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add PTR record for IPv4
|
|
ip := net.ParseIP("192.168.1.1")
|
|
domain := "host.example.com."
|
|
err := store.AddPTRRecord(ip, domain)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add PTR record: %v", err)
|
|
}
|
|
|
|
// Test reverse DNS lookup
|
|
reverseDomain := "1.1.168.192.in-addr.arpa."
|
|
result, ok := store.GetPTRRecord(reverseDomain)
|
|
if !ok {
|
|
t.Error("Expected PTR record to be found")
|
|
}
|
|
if result != domain {
|
|
t.Errorf("Expected domain %q, got %q", domain, result)
|
|
}
|
|
|
|
// Test HasPTRRecord
|
|
if !store.HasPTRRecord(reverseDomain) {
|
|
t.Error("Expected HasPTRRecord to return true")
|
|
}
|
|
|
|
// Test non-existent PTR record
|
|
_, ok = store.GetPTRRecord("2.1.168.192.in-addr.arpa.")
|
|
if ok {
|
|
t.Error("Expected PTR record not to be found for different IP")
|
|
}
|
|
}
|
|
|
|
func TestPTRRecordIPv6(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add PTR record for IPv6
|
|
ip := net.ParseIP("2001:db8::1")
|
|
domain := "ipv6host.example.com."
|
|
err := store.AddPTRRecord(ip, domain)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add PTR record: %v", err)
|
|
}
|
|
|
|
// Test reverse DNS lookup
|
|
// 2001:db8::1 = 2001:0db8:0000:0000:0000:0000:0000:0001
|
|
// 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.
|
|
reverseDomain := "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."
|
|
result, ok := store.GetPTRRecord(reverseDomain)
|
|
if !ok {
|
|
t.Error("Expected IPv6 PTR record to be found")
|
|
}
|
|
if result != domain {
|
|
t.Errorf("Expected domain %q, got %q", domain, result)
|
|
}
|
|
|
|
// Test HasPTRRecord
|
|
if !store.HasPTRRecord(reverseDomain) {
|
|
t.Error("Expected HasPTRRecord to return true for IPv6")
|
|
}
|
|
}
|
|
|
|
func TestRemovePTRRecord(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add PTR record
|
|
ip := net.ParseIP("10.0.0.1")
|
|
domain := "test.example.com."
|
|
err := store.AddPTRRecord(ip, domain)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add PTR record: %v", err)
|
|
}
|
|
|
|
// Verify it exists
|
|
reverseDomain := "1.0.0.10.in-addr.arpa."
|
|
_, ok := store.GetPTRRecord(reverseDomain)
|
|
if !ok {
|
|
t.Error("Expected PTR record to exist before removal")
|
|
}
|
|
|
|
// Remove PTR record
|
|
store.RemovePTRRecord(ip)
|
|
|
|
// Verify it's gone
|
|
_, ok = store.GetPTRRecord(reverseDomain)
|
|
if ok {
|
|
t.Error("Expected PTR record to be removed")
|
|
}
|
|
|
|
// Test HasPTRRecord after removal
|
|
if store.HasPTRRecord(reverseDomain) {
|
|
t.Error("Expected HasPTRRecord to return false after removal")
|
|
}
|
|
}
|
|
|
|
func TestIPToReverseDNS(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
ip string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "IPv4 simple",
|
|
ip: "192.168.1.1",
|
|
expected: "1.1.168.192.in-addr.arpa.",
|
|
},
|
|
{
|
|
name: "IPv4 localhost",
|
|
ip: "127.0.0.1",
|
|
expected: "1.0.0.127.in-addr.arpa.",
|
|
},
|
|
{
|
|
name: "IPv4 with zeros",
|
|
ip: "10.0.0.1",
|
|
expected: "1.0.0.10.in-addr.arpa.",
|
|
},
|
|
{
|
|
name: "IPv6 simple",
|
|
ip: "2001:db8::1",
|
|
expected: "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.",
|
|
},
|
|
{
|
|
name: "IPv6 localhost",
|
|
ip: "::1",
|
|
expected: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ip := net.ParseIP(tt.ip)
|
|
if ip == nil {
|
|
t.Fatalf("Failed to parse IP: %s", tt.ip)
|
|
}
|
|
result := IPToReverseDNS(ip)
|
|
if result != tt.expected {
|
|
t.Errorf("IPToReverseDNS(%s) = %q, want %q", tt.ip, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestReverseDNSToIP(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
reverseDNS string
|
|
expectedIP string
|
|
shouldMatch bool
|
|
}{
|
|
{
|
|
name: "IPv4 simple",
|
|
reverseDNS: "1.1.168.192.in-addr.arpa.",
|
|
expectedIP: "192.168.1.1",
|
|
shouldMatch: true,
|
|
},
|
|
{
|
|
name: "IPv4 localhost",
|
|
reverseDNS: "1.0.0.127.in-addr.arpa.",
|
|
expectedIP: "127.0.0.1",
|
|
shouldMatch: true,
|
|
},
|
|
{
|
|
name: "IPv6 simple",
|
|
reverseDNS: "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.",
|
|
expectedIP: "2001:db8::1",
|
|
shouldMatch: true,
|
|
},
|
|
{
|
|
name: "Invalid IPv4 format",
|
|
reverseDNS: "1.1.168.in-addr.arpa.",
|
|
expectedIP: "",
|
|
shouldMatch: false,
|
|
},
|
|
{
|
|
name: "Invalid IPv6 format",
|
|
reverseDNS: "1.0.0.0.ip6.arpa.",
|
|
expectedIP: "",
|
|
shouldMatch: false,
|
|
},
|
|
{
|
|
name: "Not a reverse DNS domain",
|
|
reverseDNS: "example.com.",
|
|
expectedIP: "",
|
|
shouldMatch: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := reverseDNSToIP(tt.reverseDNS)
|
|
if tt.shouldMatch {
|
|
if result == nil {
|
|
t.Errorf("reverseDNSToIP(%q) returned nil, expected IP", tt.reverseDNS)
|
|
return
|
|
}
|
|
expectedIP := net.ParseIP(tt.expectedIP)
|
|
if !result.Equal(expectedIP) {
|
|
t.Errorf("reverseDNSToIP(%q) = %v, want %v", tt.reverseDNS, result, expectedIP)
|
|
}
|
|
} else {
|
|
if result != nil {
|
|
t.Errorf("reverseDNSToIP(%q) = %v, expected nil", tt.reverseDNS, result)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPTRRecordCaseInsensitive(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add PTR record with mixed case domain
|
|
ip := net.ParseIP("192.168.1.1")
|
|
domain := "MyHost.Example.Com"
|
|
err := store.AddPTRRecord(ip, domain)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add PTR record: %v", err)
|
|
}
|
|
|
|
// Test lookup with different cases in reverse DNS format
|
|
reverseDomain := "1.1.168.192.in-addr.arpa."
|
|
result, ok := store.GetPTRRecord(reverseDomain)
|
|
if !ok {
|
|
t.Error("Expected PTR record to be found")
|
|
}
|
|
// Domain should be normalized to lowercase
|
|
if result != "myhost.example.com." {
|
|
t.Errorf("Expected normalized domain %q, got %q", "myhost.example.com.", result)
|
|
}
|
|
|
|
// Test with uppercase reverse DNS
|
|
reverseDomainUpper := "1.1.168.192.IN-ADDR.ARPA."
|
|
result, ok = store.GetPTRRecord(reverseDomainUpper)
|
|
if !ok {
|
|
t.Error("Expected PTR record to be found with uppercase reverse DNS")
|
|
}
|
|
if result != "myhost.example.com." {
|
|
t.Errorf("Expected normalized domain %q, got %q", "myhost.example.com.", result)
|
|
}
|
|
}
|
|
|
|
func TestClearPTRRecords(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add some PTR records
|
|
ip1 := net.ParseIP("192.168.1.1")
|
|
ip2 := net.ParseIP("192.168.1.2")
|
|
store.AddPTRRecord(ip1, "host1.example.com.")
|
|
store.AddPTRRecord(ip2, "host2.example.com.")
|
|
|
|
// Add some A records too
|
|
store.AddRecord("test.example.com.", net.ParseIP("10.0.0.1"))
|
|
|
|
// Verify PTR records exist
|
|
if !store.HasPTRRecord("1.1.168.192.in-addr.arpa.") {
|
|
t.Error("Expected PTR record to exist before clear")
|
|
}
|
|
|
|
// Clear all records
|
|
store.Clear()
|
|
|
|
// Verify PTR records are gone
|
|
if store.HasPTRRecord("1.1.168.192.in-addr.arpa.") {
|
|
t.Error("Expected PTR record to be cleared")
|
|
}
|
|
if store.HasPTRRecord("2.1.168.192.in-addr.arpa.") {
|
|
t.Error("Expected PTR record to be cleared")
|
|
}
|
|
|
|
// Verify A records are also gone
|
|
if store.HasRecord("test.example.com.", RecordTypeA) {
|
|
t.Error("Expected A record to be cleared")
|
|
}
|
|
}
|
|
|
|
func TestAutomaticPTRRecordOnAdd(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add an A record - should automatically add PTR record
|
|
domain := "host.example.com."
|
|
ip := net.ParseIP("192.168.1.100")
|
|
err := store.AddRecord(domain, ip)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add A record: %v", err)
|
|
}
|
|
|
|
// Verify PTR record was automatically created
|
|
reverseDomain := "100.1.168.192.in-addr.arpa."
|
|
result, ok := store.GetPTRRecord(reverseDomain)
|
|
if !ok {
|
|
t.Error("Expected PTR record to be automatically created")
|
|
}
|
|
if result != domain {
|
|
t.Errorf("Expected PTR to point to %q, got %q", domain, result)
|
|
}
|
|
|
|
// Add AAAA record - should also automatically add PTR record
|
|
domain6 := "ipv6host.example.com."
|
|
ip6 := net.ParseIP("2001:db8::1")
|
|
err = store.AddRecord(domain6, ip6)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add AAAA record: %v", err)
|
|
}
|
|
|
|
// Verify IPv6 PTR record was automatically created
|
|
reverseDomain6 := "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."
|
|
result6, ok := store.GetPTRRecord(reverseDomain6)
|
|
if !ok {
|
|
t.Error("Expected IPv6 PTR record to be automatically created")
|
|
}
|
|
if result6 != domain6 {
|
|
t.Errorf("Expected PTR to point to %q, got %q", domain6, result6)
|
|
}
|
|
}
|
|
|
|
func TestAutomaticPTRRecordOnRemove(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add an A record (with automatic PTR)
|
|
domain := "host.example.com."
|
|
ip := net.ParseIP("192.168.1.100")
|
|
store.AddRecord(domain, ip)
|
|
|
|
// Verify PTR exists
|
|
reverseDomain := "100.1.168.192.in-addr.arpa."
|
|
if !store.HasPTRRecord(reverseDomain) {
|
|
t.Error("Expected PTR record to exist after adding A record")
|
|
}
|
|
|
|
// Remove the A record
|
|
store.RemoveRecord(domain, ip)
|
|
|
|
// Verify PTR was automatically removed
|
|
if store.HasPTRRecord(reverseDomain) {
|
|
t.Error("Expected PTR record to be automatically removed")
|
|
}
|
|
|
|
// Verify A record is also gone
|
|
ips := store.GetRecords(domain, RecordTypeA)
|
|
if len(ips) != 0 {
|
|
t.Errorf("Expected A record to be removed, got %d records", len(ips))
|
|
}
|
|
}
|
|
|
|
func TestAutomaticPTRRecordOnRemoveAll(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add multiple IPs for the same domain
|
|
domain := "host.example.com."
|
|
ip1 := net.ParseIP("192.168.1.100")
|
|
ip2 := net.ParseIP("192.168.1.101")
|
|
store.AddRecord(domain, ip1)
|
|
store.AddRecord(domain, ip2)
|
|
|
|
// Verify both PTR records exist
|
|
reverseDomain1 := "100.1.168.192.in-addr.arpa."
|
|
reverseDomain2 := "101.1.168.192.in-addr.arpa."
|
|
if !store.HasPTRRecord(reverseDomain1) {
|
|
t.Error("Expected first PTR record to exist")
|
|
}
|
|
if !store.HasPTRRecord(reverseDomain2) {
|
|
t.Error("Expected second PTR record to exist")
|
|
}
|
|
|
|
// Remove all records for the domain
|
|
store.RemoveRecord(domain, nil)
|
|
|
|
// Verify both PTR records were removed
|
|
if store.HasPTRRecord(reverseDomain1) {
|
|
t.Error("Expected first PTR record to be removed")
|
|
}
|
|
if store.HasPTRRecord(reverseDomain2) {
|
|
t.Error("Expected second PTR record to be removed")
|
|
}
|
|
}
|
|
|
|
func TestNoPTRForWildcardRecords(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add wildcard record - should NOT create PTR record
|
|
domain := "*.example.com."
|
|
ip := net.ParseIP("192.168.1.100")
|
|
err := store.AddRecord(domain, ip)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add wildcard record: %v", err)
|
|
}
|
|
|
|
// Verify no PTR record was created
|
|
reverseDomain := "100.1.168.192.in-addr.arpa."
|
|
_, ok := store.GetPTRRecord(reverseDomain)
|
|
if ok {
|
|
t.Error("Expected no PTR record for wildcard domain")
|
|
}
|
|
|
|
// Verify wildcard A record exists
|
|
if !store.HasRecord("host.example.com.", RecordTypeA) {
|
|
t.Error("Expected wildcard A record to exist")
|
|
}
|
|
}
|
|
|
|
func TestPTRRecordOverwrite(t *testing.T) {
|
|
store := NewDNSRecordStore()
|
|
|
|
// Add first domain with IP
|
|
domain1 := "host1.example.com."
|
|
ip := net.ParseIP("192.168.1.100")
|
|
store.AddRecord(domain1, ip)
|
|
|
|
// Verify PTR points to first domain
|
|
reverseDomain := "100.1.168.192.in-addr.arpa."
|
|
result, ok := store.GetPTRRecord(reverseDomain)
|
|
if !ok {
|
|
t.Fatal("Expected PTR record to exist")
|
|
}
|
|
if result != domain1 {
|
|
t.Errorf("Expected PTR to point to %q, got %q", domain1, result)
|
|
}
|
|
|
|
// Add second domain with same IP - should overwrite PTR
|
|
domain2 := "host2.example.com."
|
|
store.AddRecord(domain2, ip)
|
|
|
|
// Verify PTR now points to second domain (last one added)
|
|
result, ok = store.GetPTRRecord(reverseDomain)
|
|
if !ok {
|
|
t.Fatal("Expected PTR record to still exist")
|
|
}
|
|
if result != domain2 {
|
|
t.Errorf("Expected PTR to point to %q (overwritten), got %q", domain2, result)
|
|
}
|
|
|
|
// Remove first domain - PTR should remain pointing to second domain
|
|
store.RemoveRecord(domain1, ip)
|
|
result, ok = store.GetPTRRecord(reverseDomain)
|
|
if !ok {
|
|
t.Error("Expected PTR record to still exist after removing first domain")
|
|
}
|
|
if result != domain2 {
|
|
t.Errorf("Expected PTR to still point to %q, got %q", domain2, result)
|
|
}
|
|
|
|
// Remove second domain - PTR should now be gone
|
|
store.RemoveRecord(domain2, ip)
|
|
_, ok = store.GetPTRRecord(reverseDomain)
|
|
if ok {
|
|
t.Error("Expected PTR record to be removed after removing second domain")
|
|
}
|
|
}
|