From aa928171161c715ac8b4b48f9fdf60db28a2db4f Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Thu, 6 Jul 2017 10:18:15 -0400 Subject: [PATCH] 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 --- docs/_functions/global/REV.md | 32 ++++++++++ pkg/js/helpers.js | 8 +++ pkg/js/js.go | 5 +- pkg/js/parse_tests/009-reverse.js | 2 +- pkg/js/static.go | 98 +++++++++++++++---------------- pkg/normalize/validate.go | 5 +- providers/bind/bindProvider.go | 2 + providers/bind/prettyzone.go | 30 +++++++++- providers/bind/prettyzone_test.go | 8 +++ 9 files changed, 135 insertions(+), 55 deletions(-) create mode 100644 docs/_functions/global/REV.md diff --git a/docs/_functions/global/REV.md b/docs/_functions/global/REV.md new file mode 100644 index 000000000..ca83ac3ef --- /dev/null +++ b/docs/_functions/global/REV.md @@ -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 %} diff --git a/pkg/js/helpers.js b/pkg/js/helpers.js index 421741dde..21ac528e3 100644 --- a/pkg/js/helpers.js +++ b/pkg/js/helpers.js @@ -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...) function TXT(name, target) { var mods = getModifiers(arguments,2) diff --git a/pkg/js/js.go b/pkg/js/js.go index 13f7afac6..b6840e797 100644 --- a/pkg/js/js.go +++ b/pkg/js/js.go @@ -19,7 +19,7 @@ func ExecuteJavascript(script string, devMode bool) (*models.DNSConfig, error) { vm := otto.New() vm.Set("require", require) - vm.Set("REVERSE", reverse) + vm.Set("REV", reverse) helperJs := GetHelpers(devMode) // 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 { 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() rev, err := transform.ReverseDomainName(dom) - fmt.Println(dom, rev, err) if err != nil { throw(call.Otto, err.Error()) } diff --git a/pkg/js/parse_tests/009-reverse.js b/pkg/js/parse_tests/009-reverse.js index d1146e514..8f4261afd 100644 --- a/pkg/js/parse_tests/009-reverse.js +++ b/pkg/js/parse_tests/009-reverse.js @@ -1 +1 @@ -D(REVERSE("1.2.0.0/16"),"none"); \ No newline at end of file +D(REV("1.2.0.0/16"),"none"); diff --git a/pkg/js/static.go b/pkg/js/static.go index 35ff5e161..4c7d394d8 100644 --- a/pkg/js/static.go +++ b/pkg/js/static.go @@ -190,57 +190,57 @@ var _escData = map[string]*_escFile{ "/helpers.js": { local: "pkg/js/helpers.js", - size: 9402, + size: 9590, modtime: 0, compressed: ` -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 `, }, diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 3e5ed3e1d..0af9ffcdf 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -57,6 +57,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin "MX": true, "TXT": true, "NS": true, + "PTR": true, "ALIAS": false, } _, ok := validTypes[rec.Type] @@ -141,6 +142,8 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) { if label == "@" { check(fmt.Errorf("cannot create NS record for bare domain. Use NAMESERVER instead")) } + case "PTR": + check(checkTarget(target)) case "ALIAS": check(checkTarget(target)) 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 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)) } return diff --git a/providers/bind/bindProvider.go b/providers/bind/bindProvider.go index 3825dbdc1..2a47792a9 100644 --- a/providers/bind/bindProvider.go +++ b/providers/bind/bindProvider.go @@ -81,6 +81,8 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo rc.Priority = v.Preference case *dns.NS: rc.Target = v.Ns + case *dns.PTR: + rc.Target = v.Ptr case *dns.SOA: old_serial = v.Serial if old_serial == 0 { diff --git a/providers/bind/prettyzone.go b/providers/bind/prettyzone.go index bb7eb8ec0..cf969fd2a 100644 --- a/providers/bind/prettyzone.go +++ b/providers/bind/prettyzone.go @@ -8,6 +8,7 @@ import ( "io" "log" "sort" + "strconv" "strings" "github.com/miekg/dns" @@ -180,6 +181,11 @@ func formatLine(lengths []int, fields []string) string { return strings.TrimRight(result, " ") } +func isNumeric(s string) bool { + _, err := strconv.ParseFloat(s, 64) + return err == nil +} + func zoneLabelLess(a, b string) bool { // 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. 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] { - 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. diff --git a/providers/bind/prettyzone_test.go b/providers/bind/prettyzone_test.go index 0631f6a35..f4bc7150f 100644 --- a/providers/bind/prettyzone_test.go +++ b/providers/bind/prettyzone_test.go @@ -266,6 +266,10 @@ func TestZoneLabelLess(t *testing.T) { mup a.mup bzt.mup + *.bzt.mup + 1.bzt.mup + 2.bzt.mup + 10.bzt.mup aaa.bzt.mup zzz.bzt.mup nnn.mup @@ -293,6 +297,10 @@ func TestZoneLabelLess(t *testing.T) { {"a.mup", "aa.mup", true}, {"zt.mup", "aaa.bzt.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}, {`www\.miek.nl`, `www.miek.nl`, false}, }