1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

Enable PTR records for BIND driver (#146)

* WIP

* Enable PTR records in dnsconfig.js, in BIND provider.

* Rename REVERSE() to REV().

* More accurate PTR target checking

* Document REV()

* Fix broken test
This commit is contained in:
Tom Limoncelli
2017-07-06 10:18:15 -04:00
committed by Craig Peterson
parent bce99a1c25
commit aa92817116
9 changed files with 135 additions and 55 deletions

View File

@ -0,0 +1,32 @@
---
name: REV
parameters:
- 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.`
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
reverse DNS (`PTR`) zones.
This is a convenience function. You could specify `D('3.2.1.in-addr.arpa`, ...` if you like to do things manually
and permit typos to creep in.
The network portion of the IP address (`/24`) must always be specified.
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
may generate warnings or errors in the future.
{% include startExample.html %}
{% highlight js %}
D(REV('1.2.3.0/24'), REGISTRAR, DnsProvider(BIND),
PTR("1", 'foo.example.com.'),
PTR("2", 'bar.example.com.'),
PTR("3", 'baz.example.com.'),
);
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
);
{%endhighlight%}
{% include endExample.html %}

View File

@ -165,6 +165,14 @@ function CNAME(name, target) {
} }
} }
// PTR(name,target, recordModifiers...)
function PTR(name, target) {
var mods = getModifiers(arguments,2)
return function(d) {
addRecord(d,"PTR",name,target,mods)
}
}
// TXT(name,target, recordModifiers...) // TXT(name,target, recordModifiers...)
function TXT(name, target) { function TXT(name, target) {
var mods = getModifiers(arguments,2) var mods = getModifiers(arguments,2)

View File

@ -19,7 +19,7 @@ func ExecuteJavascript(script string, devMode bool) (*models.DNSConfig, error) {
vm := otto.New() vm := otto.New()
vm.Set("require", require) vm.Set("require", require)
vm.Set("REVERSE", reverse) vm.Set("REV", reverse)
helperJs := GetHelpers(devMode) helperJs := GetHelpers(devMode)
// run helper script to prime vm and initialize variables // run helper script to prime vm and initialize variables
@ -75,11 +75,10 @@ func throw(vm *otto.Otto, str string) {
func reverse(call otto.FunctionCall) otto.Value { func reverse(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) != 1 { if len(call.ArgumentList) != 1 {
throw(call.Otto, "REVERSE takes exactly one argument") throw(call.Otto, "REV takes exactly one argument")
} }
dom := call.Argument(0).String() dom := call.Argument(0).String()
rev, err := transform.ReverseDomainName(dom) rev, err := transform.ReverseDomainName(dom)
fmt.Println(dom, rev, err)
if err != nil { if err != nil {
throw(call.Otto, err.Error()) throw(call.Otto, err.Error())
} }

View File

@ -1 +1 @@
D(REVERSE("1.2.0.0/16"),"none"); D(REV("1.2.0.0/16"),"none");

View File

@ -190,57 +190,57 @@ var _escData = map[string]*_escFile{
"/helpers.js": { "/helpers.js": {
local: "pkg/js/helpers.js", local: "pkg/js/helpers.js",
size: 9402, size: 9590,
modtime: 0, modtime: 0,
compressed: ` compressed: `
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
`, `,
}, },

View File

@ -57,6 +57,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
"MX": true, "MX": true,
"TXT": true, "TXT": true,
"NS": true, "NS": true,
"PTR": true,
"ALIAS": false, "ALIAS": false,
} }
_, ok := validTypes[rec.Type] _, ok := validTypes[rec.Type]
@ -141,6 +142,8 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
if label == "@" { if label == "@" {
check(fmt.Errorf("cannot create NS record for bare domain. Use NAMESERVER instead")) check(fmt.Errorf("cannot create NS record for bare domain. Use NAMESERVER instead"))
} }
case "PTR":
check(checkTarget(target))
case "ALIAS": case "ALIAS":
check(checkTarget(target)) check(checkTarget(target))
case "TXT", "IMPORT_TRANSFORM": case "TXT", "IMPORT_TRANSFORM":
@ -149,7 +152,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
//it is a valid custom type. We perform no validation on target //it is a valid custom type. We perform no validation on target
return return
} }
errs = append(errs, fmt.Errorf("Unimplemented record type (%v) domain=%v name=%v", errs = append(errs, fmt.Errorf("checkTargets: Unimplemented record type (%v) domain=%v name=%v",
rec.Type, domain, rec.Name)) rec.Type, domain, rec.Name))
} }
return return

View File

@ -81,6 +81,8 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
rc.Priority = v.Preference rc.Priority = v.Preference
case *dns.NS: case *dns.NS:
rc.Target = v.Ns rc.Target = v.Ns
case *dns.PTR:
rc.Target = v.Ptr
case *dns.SOA: case *dns.SOA:
old_serial = v.Serial old_serial = v.Serial
if old_serial == 0 { if old_serial == 0 {

View File

@ -8,6 +8,7 @@ import (
"io" "io"
"log" "log"
"sort" "sort"
"strconv"
"strings" "strings"
"github.com/miekg/dns" "github.com/miekg/dns"
@ -180,6 +181,11 @@ func formatLine(lengths []int, fields []string) string {
return strings.TrimRight(result, " ") return strings.TrimRight(result, " ")
} }
func isNumeric(s string) bool {
_, err := strconv.ParseFloat(s, 64)
return err == nil
}
func zoneLabelLess(a, b string) bool { func zoneLabelLess(a, b string) bool {
// Compare two zone labels for the purpose of sorting the RRs in a Zone. // Compare two zone labels for the purpose of sorting the RRs in a Zone.
@ -221,8 +227,30 @@ func zoneLabelLess(a, b string) bool {
// Skip the matching highest elements, then compare the next item. // Skip the matching highest elements, then compare the next item.
for i, j := ia, ib; min >= 0; i, j, min = i-1, j-1, min-1 { for i, j := ia, ib; min >= 0; i, j, min = i-1, j-1, min-1 {
// Compare as[i] < bs[j]
// Sort @ at the top, then *, then everything else.
// i.e. @ always is less. * is is less than everything but @.
// If both are numeric, compare as integers, otherwise as strings.
if as[i] != bs[j] { if as[i] != bs[j] {
return as[i] < bs[j]
// If the first element is *, it is always less.
if i == 0 && as[i] == "*" {
return true
}
if j == 0 && bs[j] == "*" {
return false
}
// If the elements are both numeric, compare as integers:
au, aerr := strconv.ParseUint(as[i], 10, 64)
bu, berr := strconv.ParseUint(bs[j], 10, 64)
if aerr == nil && berr == nil {
return au < bu
} else {
// otherwise, compare as strings:
return as[i] < bs[j]
}
} }
} }
// The min top elements were equal, so the shorter name is less. // The min top elements were equal, so the shorter name is less.

View File

@ -266,6 +266,10 @@ func TestZoneLabelLess(t *testing.T) {
mup mup
a.mup a.mup
bzt.mup bzt.mup
*.bzt.mup
1.bzt.mup
2.bzt.mup
10.bzt.mup
aaa.bzt.mup aaa.bzt.mup
zzz.bzt.mup zzz.bzt.mup
nnn.mup nnn.mup
@ -293,6 +297,10 @@ func TestZoneLabelLess(t *testing.T) {
{"a.mup", "aa.mup", true}, {"a.mup", "aa.mup", true},
{"zt.mup", "aaa.bzt.mup", false}, {"zt.mup", "aaa.bzt.mup", false},
{"aaa.bzt.mup", "mup", false}, {"aaa.bzt.mup", "mup", false},
{"*.bzt.mup", "aaa.bzt.mup", true},
{"1.bzt.mup", "aaa.bzt.mup", true},
{"1.bzt.mup", "2.bzt.mup", true},
{"10.bzt.mup", "2.bzt.mup", false},
{"nnn.mup", "aaa.bzt.mup", false}, {"nnn.mup", "aaa.bzt.mup", false},
{`www\.miek.nl`, `www.miek.nl`, false}, {`www\.miek.nl`, `www.miek.nl`, false},
} }