mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
PTR should handle "Classless in-addr.arpa delegation" RFC2317 (#149)
* Handle IPv4 "Classless in-addr.arpa delegation" RFC2317 (partial). * Validate PTR name when in RFC2317 "Classless in-addr.arpa delegation" domains. * Update docs * Set CanUsePTR for Route53 and Google CloudDNS. * BIND: Replace "/" with "_" in filenames.
This commit is contained in:
@ -8,13 +8,54 @@ parameters:
|
|||||||
|
|
||||||
PTR adds a PTR record to the domain.
|
PTR adds a PTR record to the domain.
|
||||||
|
|
||||||
The name should be the relative label for the domain, or may be a FQDN that ends with `.`.
|
The name is normally a the relative label for the domain, or a FQDN that ends with `.`. If magic mode is enabled (see below) it can also be an IP address, which will be replaced by the proper string automatically, thus
|
||||||
|
saving the user from having to reverse the IP address manually.
|
||||||
* If the name is a valid IP address, DNSControl will *magically* replace it with a string that is appropriate for the domain. That is, if the domain ends with `in-addr.arpa` it will generate the IPv4-style reverse name; if the domain ends with `ipv6.arpa` it will generate the IPv6-style reverse name. DNSControl will truncate it as appropriate for the netmask.
|
|
||||||
* If the name ends with `in-addr.arpa.` or `ipv6.arpa.` (not the `.` at the end), DNSControl will truncate it as appropriate for the domain. If the FQDN does not fit within the domain, this will raise an error.
|
|
||||||
|
|
||||||
Target should be a string representing the FQDN of a host. Like all FQDNs in DNSControl, it must end with a `.`.
|
Target should be a string representing the FQDN of a host. Like all FQDNs in DNSControl, it must end with a `.`.
|
||||||
|
|
||||||
|
**Magic Mode:**
|
||||||
|
|
||||||
|
PTR records are complex and typos are common. Therefore DNSControl
|
||||||
|
enables features to save labor and
|
||||||
|
prevent typos. This magic is only
|
||||||
|
enabled when the domain ends with `in-addr.arpa.` or `ipv6.arpa.`.
|
||||||
|
|
||||||
|
*Automatic IP-to-reverse:* If the name is a valid IP address, DNSControl will replace it with
|
||||||
|
a string that is appropriate for the domain. That is, if the domain
|
||||||
|
ends with `in-addr.arpa` (no `.`) and name is a valid IPv4 address, the name
|
||||||
|
will be replaced with the correct string to make a reverse lookup for that address.
|
||||||
|
IPv6 is properly handled too.
|
||||||
|
|
||||||
|
*Extra Validation:* DNSControl considers it an error to include a name that
|
||||||
|
is inappropriate for the domain. For example
|
||||||
|
`PTR('1.2.3.4', 'f.co.')` is valid for the domain `D("3.2.1.in-addr.arpa',`
|
||||||
|
but DNSControl will generate an error if the domain is `D("9.9.9.in-addr.arpa',`.
|
||||||
|
This is because `1.2.3.4` is contained in `1.2.3.0/24` but not `9.9.9.0/24`.
|
||||||
|
This validation works for IPv6, IPv4, and
|
||||||
|
RFC2317 "Classless in-addr.arpa delegation" domains.
|
||||||
|
|
||||||
|
*Automatic truncation:* DNSControl will automatically truncate FQDNs
|
||||||
|
as needed.
|
||||||
|
If the name is a FQDN ending with `.`, DNSControl will verify that the
|
||||||
|
name is contained within the CIDR block implied by domain. For example
|
||||||
|
if name is `4.3.2.1.in-addr.arpa.` (note the trailing `.`)
|
||||||
|
and the domain is `2.1.in-addr.arpa` (no trailing `.`)
|
||||||
|
then the name will be replaced with `4.3`. Note that the output
|
||||||
|
of `REV('1.2.3.4')` is `4.3.2.1.in-addr.arpa.`, which means the following
|
||||||
|
are all equivalent:
|
||||||
|
|
||||||
|
* `PTR(REV('1.2.3.4'), `
|
||||||
|
* `PTR('4.3.2.1.in-addr.arpa.'), `
|
||||||
|
* `PTR('4.3',` // Assuming the domain is `2.1.in-addr.arpa`
|
||||||
|
|
||||||
|
All magic is RFC2317-aware. We use the first format listed in the
|
||||||
|
RFC for both `REV()` and `PTR()`. The format is
|
||||||
|
`FIRST/MASK.C.B.A.in-addr.arpa` where `FIRST` is the first IP address
|
||||||
|
of the zone, `MASK` is the netmask of the zone (25-31 inclusive),
|
||||||
|
and A, B, C are the first 3 octets of the IP address. For example
|
||||||
|
`172.20.18.130/27` is located in a zone named
|
||||||
|
`128/27.18.20.172.in-addr.arpa`
|
||||||
|
|
||||||
{% include startExample.html %}
|
{% include startExample.html %}
|
||||||
{% highlight js %}
|
{% highlight js %}
|
||||||
D(REV('1.2.3.0/24'), REGISTRAR, DnsProvider(BIND),
|
D(REV('1.2.3.0/24'), REGISTRAR, DnsProvider(BIND),
|
||||||
@ -25,6 +66,10 @@ D(REV('1.2.3.0/24'), REGISTRAR, DnsProvider(BIND),
|
|||||||
PTR('1.2.3.10', 'ten.example.com.'), // '10'
|
PTR('1.2.3.10', 'ten.example.com.'), // '10'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
D(REV('9.9.9.128/25'), REGISTRAR, DnsProvider(BIND),
|
||||||
|
PTR('9.9.9.129', 'first.example.com.'),
|
||||||
|
);
|
||||||
|
|
||||||
D(REV('2001:db8:302::/48'), REGISTRAR, DnsProvider(BIND),
|
D(REV('2001:db8:302::/48'), REGISTRAR, DnsProvider(BIND),
|
||||||
PTR('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0', 'foo.example.com.'), // 2001:db8:302::1
|
PTR('1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0', 'foo.example.com.'), // 2001:db8:302::1
|
||||||
// If the first parameter is a valid IP address, DNSControl will generate the correct name:
|
// If the first parameter is a valid IP address, DNSControl will generate the correct name:
|
||||||
|
@ -4,17 +4,30 @@ parameters:
|
|||||||
- address
|
- address
|
||||||
---
|
---
|
||||||
|
|
||||||
`REV` returns the reverse lookup domain for an IP network. For example `REV('1.2.3.0/24')` returns `3.2.1.in-addr.arpa.`
|
`REV` returns the reverse lookup domain for an IP network. For
|
||||||
and `REV('2001:db8:302::/48)` returns `2.0.3.0.8.b.d.0.1.0.0.2.ip6.arpa.`. This is used in `D()` functions to create
|
example `REV('1.2.3.0/24')` returns `3.2.1.in-addr.arpa.` and
|
||||||
reverse DNS (`PTR`) zones.
|
`REV('2001:db8:302::/48)` returns `2.0.3.0.8.b.d.0.1.0.0.2.ip6.arpa.`.
|
||||||
|
This is used in `D()` functions to create reverse DNS lookup zones.
|
||||||
|
|
||||||
This is a convenience function. You could specify `D('3.2.1.in-addr.arpa`, ...` if you like to do things manually
|
This is a convenience function. You could specify `D('3.2.1.in-addr.arpa`,
|
||||||
and permit typos to creep in.
|
...` if you like to do things manually but why would you risk making
|
||||||
|
typos?
|
||||||
|
|
||||||
The network portion of the IP address (`/24`) must always be specified.
|
`REV` complies with RFC2317, "Classless in-addr.arpa delegation"
|
||||||
|
for netmasks of size /25 through /31.
|
||||||
|
While the RFC permits any format, we abide by the recommended format:
|
||||||
|
`FIRST/MASK.C.B.A.in-addr.arpa` where `FIRST` is the first IP address
|
||||||
|
of the zone, `MASK` is the netmask of the zone (25-31 inclusive),
|
||||||
|
and A, B, C are the first 3 octets of the IP address. For example
|
||||||
|
`172.20.18.130/27` is located in a zone named
|
||||||
|
`128/27.18.20.172.in-addr.arpa`
|
||||||
|
|
||||||
Note that the lower bits are zeroed out automatically. Thus, `REV('1.2.3.4/24') is the same as `REV('1.2.3.0/24')`. This
|
If the address does not include a "/" then `REV` assumes /32 for IPv4 addresses
|
||||||
may generate warnings or errors in the future.
|
and /128 for IPv6 addresses.
|
||||||
|
|
||||||
|
Note that the lower bits (the ones outside the netmask) must be zeros. They are not
|
||||||
|
zeroed out automatically. Thus, `REV('1.2.3.4/24') is an error. This is done
|
||||||
|
to catch typos.
|
||||||
|
|
||||||
{% include startExample.html %}
|
{% include startExample.html %}
|
||||||
{% highlight js %}
|
{% highlight js %}
|
||||||
@ -29,8 +42,8 @@ D(REV('1.2.3.0/24'), REGISTRAR, DnsProvider(BIND),
|
|||||||
D(REV('2001:db8:302::/48'), REGISTRAR, DnsProvider(BIND),
|
D(REV('2001:db8:302::/48'), REGISTRAR, DnsProvider(BIND),
|
||||||
PTR("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", 'foo.example.com.'), // 2001:db8:302::1
|
PTR("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", 'foo.example.com.'), // 2001:db8:302::1
|
||||||
// These take advantage of DNSControl's ability to generate the right name:
|
// These take advantage of DNSControl's ability to generate the right name:
|
||||||
PTR("2001:db8:302::2", 'two.example.com.'), // 2.0.0. etc. etc.
|
PTR("2001:db8:302::2", 'two.example.com.'), // 2.0.0...
|
||||||
PTR("2001:db8:302::3", 'three.example.com.'), //
|
PTR("2001:db8:302::3", 'three.example.com.'), // 3.0.0...
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ReverseDomainName(cidr string) (string, error) {
|
func ReverseDomainName(cidr string) (string, error) {
|
||||||
@ -16,11 +18,26 @@ func ReverseDomainName(cidr string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
base = strings.TrimRight(base, ".")
|
base = strings.TrimRight(base, ".")
|
||||||
|
if !a.Equal(c.IP) {
|
||||||
|
return "", errors.Errorf("CIDR %v has 1 bits beyond the mask", cidr)
|
||||||
|
}
|
||||||
|
|
||||||
bits, total := c.Mask.Size()
|
bits, total := c.Mask.Size()
|
||||||
var toTrim int
|
var toTrim int
|
||||||
if bits == 0 {
|
if bits == 0 {
|
||||||
return "", fmt.Errorf("Cannot use /0 in reverse cidr")
|
return "", fmt.Errorf("Cannot use /0 in reverse cidr")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle IPv4 "Classless in-addr.arpa delegation" RFC2317:
|
||||||
|
if total == 32 && bits >= 25 && bits < 32 {
|
||||||
|
// first address / netmask . Class-b-arpa.
|
||||||
|
fparts := strings.Split(c.IP.String(), ".")
|
||||||
|
first := fparts[3]
|
||||||
|
bparts := strings.SplitN(base, ".", 2)
|
||||||
|
return fmt.Sprintf("%s/%d.%s", first, bits, bparts[1]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle IPv4 Class-full and IPv6:
|
||||||
if total == 32 {
|
if total == 32 {
|
||||||
if bits%8 != 0 {
|
if bits%8 != 0 {
|
||||||
return "", fmt.Errorf("IPv4 mask must be multiple of 8 bits")
|
return "", fmt.Errorf("IPv4 mask must be multiple of 8 bits")
|
||||||
|
@ -10,13 +10,15 @@ func TestReverse(t *testing.T) {
|
|||||||
out string
|
out string
|
||||||
}{
|
}{
|
||||||
{"174.136.107.0/24", false, "107.136.174.in-addr.arpa"},
|
{"174.136.107.0/24", false, "107.136.174.in-addr.arpa"},
|
||||||
|
{"174.136.107.1/24", true, "107.136.174.in-addr.arpa"},
|
||||||
|
|
||||||
{"174.136.0.0/16", false, "136.174.in-addr.arpa"},
|
{"174.136.0.0/16", false, "136.174.in-addr.arpa"},
|
||||||
{"174.136.43.0/16", false, "136.174.in-addr.arpa"}, //do bits set inside the masked range matter? Should this be invalid? Is there a shorter way to specify this?
|
{"174.136.43.0/16", true, "136.174.in-addr.arpa"},
|
||||||
|
|
||||||
{"174.0.0.0/8", false, "174.in-addr.arpa"},
|
{"174.0.0.0/8", false, "174.in-addr.arpa"},
|
||||||
{"174.136.43.0/8", false, "174.in-addr.arpa"},
|
{"174.136.43.0/8", true, "174.in-addr.arpa"},
|
||||||
{"174.136.43.0/8", false, "174.in-addr.arpa"},
|
{"174.136.0.44/8", true, "174.in-addr.arpa"},
|
||||||
|
{"174.136.45.45/8", true, "174.in-addr.arpa"},
|
||||||
|
|
||||||
{"2001::/16", false, "1.0.0.2.ip6.arpa"},
|
{"2001::/16", false, "1.0.0.2.ip6.arpa"},
|
||||||
{"2001:0db8:0123:4567:89ab:cdef:1234:5670/124", false, "7.6.5.4.3.2.1.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.8.b.d.0.1.0.0.2.ip6.arpa"},
|
{"2001:0db8:0123:4567:89ab:cdef:1234:5670/124", false, "7.6.5.4.3.2.1.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.8.b.d.0.1.0.0.2.ip6.arpa"},
|
||||||
@ -24,6 +26,51 @@ func TestReverse(t *testing.T) {
|
|||||||
{"174.136.107.14/32", false, "14.107.136.174.in-addr.arpa"},
|
{"174.136.107.14/32", false, "14.107.136.174.in-addr.arpa"},
|
||||||
{"2001:0db8:0123:4567:89ab:cdef:1234:5678/128", false, "8.7.6.5.4.3.2.1.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.8.b.d.0.1.0.0.2.ip6.arpa"},
|
{"2001:0db8:0123:4567:89ab:cdef:1234:5678/128", false, "8.7.6.5.4.3.2.1.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.8.b.d.0.1.0.0.2.ip6.arpa"},
|
||||||
|
|
||||||
|
// IPv4 "Classless in-addr.arpa delegation" RFC2317.
|
||||||
|
// From examples in the RFC:
|
||||||
|
{"192.0.2.0/25", false, "0/25.2.0.192.in-addr.arpa"},
|
||||||
|
{"192.0.2.128/26", false, "128/26.2.0.192.in-addr.arpa"},
|
||||||
|
{"192.0.2.192/26", false, "192/26.2.0.192.in-addr.arpa"},
|
||||||
|
// All the base cases:
|
||||||
|
{"174.1.0.0/25", false, "0/25.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.0/26", false, "0/26.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.0/27", false, "0/27.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.0/28", false, "0/28.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.0/29", false, "0/29.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.0/30", false, "0/30.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.0/31", false, "0/31.0.1.174.in-addr.arpa"},
|
||||||
|
// /25 (all cases)
|
||||||
|
{"174.1.0.0/25", false, "0/25.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.128/25", false, "128/25.0.1.174.in-addr.arpa"},
|
||||||
|
// /26 (all cases)
|
||||||
|
{"174.1.0.0/26", false, "0/26.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.64/26", false, "64/26.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.128/26", false, "128/26.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.192/26", false, "192/26.0.1.174.in-addr.arpa"},
|
||||||
|
// /27 (all cases)
|
||||||
|
{"174.1.0.0/27", false, "0/27.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.32/27", false, "32/27.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.64/27", false, "64/27.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.96/27", false, "96/27.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.128/27", false, "128/27.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.160/27", false, "160/27.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.192/27", false, "192/27.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.224/27", false, "224/27.0.1.174.in-addr.arpa"},
|
||||||
|
// /28 (first 2, last 2)
|
||||||
|
{"174.1.0.0/28", false, "0/28.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.16/28", false, "16/28.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.224/28", false, "224/28.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.240/28", false, "240/28.0.1.174.in-addr.arpa"},
|
||||||
|
// /29 (first 2 cases)
|
||||||
|
{"174.1.0.0/29", false, "0/29.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.8/29", false, "8/29.0.1.174.in-addr.arpa"},
|
||||||
|
// /30 (first 2 cases)
|
||||||
|
{"174.1.0.0/30", false, "0/30.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.4/30", false, "4/30.0.1.174.in-addr.arpa"},
|
||||||
|
// /31 (first 2 cases)
|
||||||
|
{"174.1.0.0/31", false, "0/31.0.1.174.in-addr.arpa"},
|
||||||
|
{"174.1.0.2/31", false, "2/31.0.1.174.in-addr.arpa"},
|
||||||
|
|
||||||
//Errror Cases:
|
//Errror Cases:
|
||||||
{"0.0.0.0/0", true, ""},
|
{"0.0.0.0/0", true, ""},
|
||||||
{"2001::/0", true, ""},
|
{"2001::/0", true, ""},
|
||||||
@ -37,7 +84,7 @@ func TestReverse(t *testing.T) {
|
|||||||
t.Error("Should not have errored ", err)
|
t.Error("Should not have errored ", err)
|
||||||
} else if tst.isError && err == nil {
|
} else if tst.isError && err == nil {
|
||||||
t.Errorf("Should have errored, but didn't. Got %s", d)
|
t.Errorf("Should have errored, but didn't. Got %s", d)
|
||||||
} else if d != tst.out {
|
} else if (!tst.isError) && d != tst.out {
|
||||||
t.Errorf("Expected '%s' but got '%s'", tst.out, d)
|
t.Errorf("Expected '%s' but got '%s'", tst.out, d)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package transform
|
package transform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -44,10 +47,56 @@ func ipv4magic(name, domain string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return name, err
|
return name, err
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(rev, "."+domain) {
|
result := strings.TrimSuffix(rev, "."+domain)
|
||||||
err = errors.Errorf("ERROR: PTR record %v in wrong IPv4 domain (%v)", name, domain)
|
|
||||||
|
// Are we in the right domain?
|
||||||
|
if strings.HasSuffix(rev, "."+domain) {
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
return strings.TrimSuffix(rev, "."+domain), err
|
if ipMatchesClasslessDomain(ip, domain) {
|
||||||
|
return strings.SplitN(rev, ".", 2)[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.Errorf("PTR record %v in wrong IPv4 domain (%v)", name, domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
var isRfc2317Format1 = regexp.MustCompile(`(\d{1,3})/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.in-addr\.arpa$`)
|
||||||
|
|
||||||
|
// ipMatchesClasslessDomain returns true if ip is appropriate for domain.
|
||||||
|
// domain is a reverse DNS lookup zone (in-addr.arpa) as described in RFC2317.
|
||||||
|
func ipMatchesClasslessDomain(ip net.IP, domain string) bool {
|
||||||
|
|
||||||
|
// The unofficial but preferred format in RFC2317:
|
||||||
|
m := isRfc2317Format1.FindStringSubmatch(domain)
|
||||||
|
if m != nil {
|
||||||
|
// IP: Domain:
|
||||||
|
// 172.20.18.27 128/27.18.20.172.in-addr.arpa
|
||||||
|
// A B C D F M X Y Z
|
||||||
|
// The following should be true:
|
||||||
|
// A==Z, B==Y, C==X.
|
||||||
|
// If you mask ip by M, the last octet should be F.
|
||||||
|
ii := ip.To4()
|
||||||
|
a, b, c, _ := ii[0], ii[1], ii[2], ii[3]
|
||||||
|
f, m, x, y, z := atob(m[1]), atob(m[2]), atob(m[3]), atob(m[4]), atob(m[5])
|
||||||
|
masked := ip.Mask(net.CIDRMask(int(m), 32))
|
||||||
|
if a == z && b == y && c == x && masked.Equal(net.IPv4(a, b, c, f)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To extend this to include other formats, add them here.
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// atob converts a to a byte value or panics.
|
||||||
|
func atob(s string) byte {
|
||||||
|
if i, err := strconv.Atoi(s); err == nil {
|
||||||
|
if i < 256 {
|
||||||
|
return byte(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("(%v) matched \\d{1,3} but is not a byte", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6magic(name, domain string) (string, error) {
|
func ipv6magic(name, domain string) (string, error) {
|
||||||
@ -63,7 +112,7 @@ func ipv6magic(name, domain string) (string, error) {
|
|||||||
return name, err
|
return name, err
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(rev, "."+domain) {
|
if !strings.HasSuffix(rev, "."+domain) {
|
||||||
err = errors.Errorf("ERROR: PTR record %v in wrong IPv6 domain (%v)", name, domain)
|
err = errors.Errorf("PTR record %v in wrong IPv6 domain (%v)", name, domain)
|
||||||
}
|
}
|
||||||
return strings.TrimSuffix(rev, "."+domain), err
|
return strings.TrimSuffix(rev, "."+domain), err
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,13 @@ func TestPtrMagic(t *testing.T) {
|
|||||||
{"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", 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},
|
{"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},
|
||||||
|
|
||||||
|
// RFC2317 (Classless)
|
||||||
|
// 172.20.18.160/27 is .160 - .191:
|
||||||
|
{"172.20.18.159", "160/27.18.20.172.in-addr.arpa", "", true},
|
||||||
|
{"172.20.18.160", "160/27.18.20.172.in-addr.arpa", "160", false},
|
||||||
|
{"172.20.18.191", "160/27.18.20.172.in-addr.arpa", "191", false},
|
||||||
|
{"172.20.18.192", "160/27.18.20.172.in-addr.arpa", "", true},
|
||||||
|
|
||||||
// If it doesn't end in .arpa, the magic is disabled:
|
// If it doesn't end in .arpa, the magic is disabled:
|
||||||
{"1.2.3.4", "example.com", "1.2.3.4", false},
|
{"1.2.3.4", "example.com", "1.2.3.4", false},
|
||||||
{"1", "example.com", "1", false},
|
{"1", "example.com", "1", false},
|
||||||
|
@ -181,7 +181,7 @@ func (c *Bind) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correcti
|
|||||||
// Read foundRecords:
|
// Read foundRecords:
|
||||||
foundRecords := make([]*models.RecordConfig, 0)
|
foundRecords := make([]*models.RecordConfig, 0)
|
||||||
var oldSerial, newSerial uint32
|
var oldSerial, newSerial uint32
|
||||||
zonefile := filepath.Join(*bindBaseDir, strings.ToLower(dc.Name)+".zone")
|
zonefile := filepath.Join(*bindBaseDir, strings.Replace(strings.ToLower(dc.Name), "/", "_", -1)+".zone")
|
||||||
foundFH, err := os.Open(zonefile)
|
foundFH, err := os.Open(zonefile)
|
||||||
zoneFileFound := err == nil
|
zoneFileFound := err == nil
|
||||||
if err != nil && !os.IsNotExist(os.ErrNotExist) {
|
if err != nil && !os.IsNotExist(os.ErrNotExist) {
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("GCLOUD", New)
|
providers.RegisterDomainServiceProviderType("GCLOUD", New, providers.CanUsePTR)
|
||||||
}
|
}
|
||||||
|
|
||||||
type gcloud struct {
|
type gcloud struct {
|
||||||
|
@ -42,7 +42,7 @@ func newRoute53(m map[string]string, metadata json.RawMessage) (providers.DNSSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("ROUTE53", newRoute53)
|
providers.RegisterDomainServiceProviderType("ROUTE53", newRoute53, providers.CanUsePTR)
|
||||||
}
|
}
|
||||||
func sPtr(s string) *string {
|
func sPtr(s string) *string {
|
||||||
return &s
|
return &s
|
||||||
|
Reference in New Issue
Block a user