mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
@@ -32,7 +32,7 @@ func ReverseDomainName(cidr string) (string, error) {
|
||||
}
|
||||
toTrim = (total - bits) / 4
|
||||
} else {
|
||||
return "", fmt.Errorf("Invalid mask bit size: %d", total)
|
||||
return "", fmt.Errorf("Address is not IPv4 or IPv6: %v", cidr)
|
||||
}
|
||||
|
||||
parts := strings.SplitN(base, ".", toTrim+1)
|
||||
|
69
pkg/transform/ptr.go
Normal file
69
pkg/transform/ptr.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package transform
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func PtrNameMagic(name, domain string) (string, error) {
|
||||
// Implement the PTR name magic. If the name is a properly formed
|
||||
// IPv4 or IPv6 address, we replace it with the right string (i.e
|
||||
// reverse it and truncate it).
|
||||
|
||||
// If the name is already in-addr.arpa or ipv6.arpa,
|
||||
// make sure the domain matches.
|
||||
if strings.HasSuffix(name, ".in-addr.arpa.") || strings.HasSuffix(name, ".ip6.arpa.") {
|
||||
if strings.HasSuffix(name, "."+domain+".") {
|
||||
return strings.TrimSuffix(name, "."+domain+"."), nil
|
||||
} else {
|
||||
return name, errors.Errorf("PTR record %v in wrong domain (%v)", name, domain)
|
||||
}
|
||||
}
|
||||
|
||||
// If the domain is .arpa, we do magic.
|
||||
if strings.HasSuffix(domain, ".in-addr.arpa") {
|
||||
return ipv4magic(name, domain)
|
||||
} else if strings.HasSuffix(domain, ".ip6.arpa") {
|
||||
return ipv6magic(name, domain)
|
||||
} else {
|
||||
return name, nil
|
||||
}
|
||||
}
|
||||
|
||||
func ipv4magic(name, domain string) (string, error) {
|
||||
// Not a valid IPv4 address. Leave it alone.
|
||||
ip := net.ParseIP(name)
|
||||
if ip == nil || ip.To4() == nil || !strings.Contains(name, ".") {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// Reverse it.
|
||||
rev, err := ReverseDomainName(ip.String() + "/32")
|
||||
if err != nil {
|
||||
return name, err
|
||||
}
|
||||
if !strings.HasSuffix(rev, "."+domain) {
|
||||
err = errors.Errorf("ERROR: PTR record %v in wrong IPv4 domain (%v)", name, domain)
|
||||
}
|
||||
return strings.TrimSuffix(rev, "."+domain), err
|
||||
}
|
||||
|
||||
func ipv6magic(name, domain string) (string, error) {
|
||||
// Not a valid IPv6 address. Leave it alone.
|
||||
ip := net.ParseIP(name)
|
||||
if ip == nil || len(ip) != 16 || !strings.Contains(name, ":") {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// Reverse it.
|
||||
rev, err := ReverseDomainName(ip.String() + "/128")
|
||||
if err != nil {
|
||||
return name, err
|
||||
}
|
||||
if !strings.HasSuffix(rev, "."+domain) {
|
||||
err = errors.Errorf("ERROR: PTR record %v in wrong IPv6 domain (%v)", name, domain)
|
||||
}
|
||||
return strings.TrimSuffix(rev, "."+domain), err
|
||||
}
|
77
pkg/transform/ptr_test.go
Normal file
77
pkg/transform/ptr_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package transform
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// ptrmagic(name, domain string, al int) (string, error)
|
||||
|
||||
func TestPtrMagic(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
domain string
|
||||
output string
|
||||
fail bool
|
||||
}{
|
||||
// Magic IPv4:
|
||||
{"1.2.3.4", "3.2.1.in-addr.arpa", "4", false},
|
||||
{"1.2.3.4", "2.1.in-addr.arpa", "4.3", false},
|
||||
{"1.2.3.4", "1.in-addr.arpa", "4.3.2", false},
|
||||
|
||||
// No magic IPv4:
|
||||
{"1", "2.3.4.in-addr.arpa", "1", false},
|
||||
{"1.2", "3.4.in-addr.arpa", "1.2", false},
|
||||
{"1.2.3", "4.in-addr.arpa", "1.2.3", false},
|
||||
{"1.2.3.4", "in-addr.arpa", "1.2.3.4", false}, // Not supported, but it works.
|
||||
|
||||
// Magic IPv6:
|
||||
{"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", "1", false},
|
||||
{"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", "1.0", false},
|
||||
{"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", "1.0.0", false},
|
||||
{"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", "1.0.0.0", false},
|
||||
{"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", "1.0.0.0.0", false},
|
||||
{"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", "1.0.0.0.0.0", false},
|
||||
{"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", "1.0.0.0.0.0.0", false},
|
||||
{"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", "1.0.0.0.0.0.0.0", false},
|
||||
{"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", "1.0.0.0.0.0.0.0.0", false},
|
||||
{"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", "1.0.0.0.0.0.0.0.0.0", false},
|
||||
{"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", "1.0.0.0.0.0.0.0.0.0.0", false},
|
||||
{"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", "1.0.0.0.0.0.0.0.0.0.0.0", false},
|
||||
{"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", "1.0.0.0.0.0.0.0.0.0.0.0.0", false},
|
||||
{"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", "1.0.0.0.0.0.0.0.0.0.0.0.0.0", false},
|
||||
|
||||
// If it doesn't end in .arpa, the magic is disabled:
|
||||
{"1.2.3.4", "example.com", "1.2.3.4", false},
|
||||
{"1", "example.com", "1", false},
|
||||
{"1.0.0.0", "example.com", "1.0.0.0", false},
|
||||
{"1.0.0.0.0.0.0.0", "example.com", "1.0.0.0.0.0.0.0", false},
|
||||
|
||||
// User manually reversed addresses:
|
||||
{"1.1.1.1.in-addr.arpa.", "1.1.in-addr.arpa", "1.1", false},
|
||||
{"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.",
|
||||
"0.2.ip6.arpa", "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", false},
|
||||
|
||||
// Error cases:
|
||||
{"1.1.1.1.in-addr.arpa.", "2.2.in-addr.arpa", "", true},
|
||||
{"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.", "9.9.ip6.arpa", "", true},
|
||||
{"3.3.3.3", "4.4.in-addr.arpa", "", true},
|
||||
{"2001:db8::1", "9.9.ip6.arpa", "", true},
|
||||
|
||||
// These should be errors but we don't check for them at this time:
|
||||
//{"blurg", "3.4.in-addr.arpa", "blurg", true},
|
||||
//{"1", "3.4.in-addr.arpa", "1", true},
|
||||
}
|
||||
for _, tst := range tests {
|
||||
t.Run(fmt.Sprintf("%s %s", tst.name, tst.domain), func(t *testing.T) {
|
||||
o, errs := PtrNameMagic(tst.name, tst.domain)
|
||||
if errs != nil && !tst.fail {
|
||||
t.Errorf("Got error but expected none (%v)", errs)
|
||||
} else if errs == nil && tst.fail {
|
||||
t.Errorf("Expected error but got none (%v)", o)
|
||||
} else if errs == nil && o != tst.output {
|
||||
t.Errorf("Got (%v) expected (%v)", o, tst.output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user