BIND: Implement AutoDNSSEC (#648)

There's a philosophy issue here around what is the Bind output meant to
do.  Since AFAIK we're not integrating into Bind's catalog zones or the
like, we're just targeting the zonefiles, we're not in a position to do
_anything_ relating to registrar options such as setting up DS glue.

So at one level, enabling AutoDNSSEC for Bind is a lie. But without
this, folks can't target a Bind zone as a secondary provider for their
domain, to get debug dumps of the zone output, because the checks for
"Can" block it.  So I think this commit achieves a happy compromise: we
write a comment into the Bind zonefile, indicating that DNSSEC was
requested.

Actually: we add support for arbitrary zone comments to be written into
a zonefile via a slightly ugly "can be `nil`" parameter.  We then write
in a generation timestamp comment, and if AutoDNSSEC was requested we
then write that in too.
This commit is contained in:
Phil Pennock 2020-02-22 13:27:24 -05:00 committed by GitHub
parent 7384743f6d
commit 3c41a39252
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 41 additions and 12 deletions

View file

@ -151,11 +151,11 @@ func GetZone(args GetZoneArgs) error {
for i, recs := range zoneRecs {
zoneName := zones[i]
z := prettyzone.PrettySort(recs, zoneName, 0)
z := prettyzone.PrettySort(recs, zoneName, 0, nil)
switch args.OutputFormat {
case "pretty":
fmt.Fprintf(w, "$ORIGIN %s.\n", zoneName)
prettyzone.WriteZoneFileRC(w, z.Records, zoneName)
prettyzone.WriteZoneFileRC(w, z.Records, zoneName, nil)
fmt.Fprintln(w)
case "dsl":

View file

@ -313,7 +313,9 @@
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Provider can automatically manage DNSSEC">AUTODNSSEC</th>
<td><i class="fa fa-minus dim"></i></td>
<td><i class="fa fa-minus dim"></i></td>
<td><i class="fa fa-minus dim"></i></td>
<td class="success" data-toggle="tooltip" data-container="body" data-placement="top" title="Just writes out a comment indicating DNSSEC was requested">
<i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i>
</td>
<td><i class="fa fa-minus dim"></i></td>
<td><i class="fa fa-minus dim"></i></td>
<td><i class="fa fa-minus dim"></i></td>
@ -981,8 +983,8 @@
<td class="info">
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
</td>
<td class="info">
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
<td class="success">
<i class="fa fa-check text-success" aria-hidden="true"></i>
</td>
<td><i class="fa fa-minus dim"></i></td>
<td class="info">

View file

@ -45,11 +45,11 @@ func mostCommonTTL(records models.Records) uint32 {
// WriteZoneFileRR is a helper for when you have []dns.RR instead of models.Records
func WriteZoneFileRR(w io.Writer, records []dns.RR, origin string, serial uint32) error {
return WriteZoneFileRC(w, models.RRstoRCs(records, origin, serial), origin)
return WriteZoneFileRC(w, models.RRstoRCs(records, origin, serial), origin, nil)
}
// WriteZoneFileRC writes a beautifully formatted zone file.
func WriteZoneFileRC(w io.Writer, records models.Records, origin string) error {
func WriteZoneFileRC(w io.Writer, records models.Records, origin string, comments []string) error {
// This function prioritizes beauty over output size.
// * The zone records are sorted by label, grouped by subzones to
// be easy to read and pleasant to the eye.
@ -61,18 +61,19 @@ func WriteZoneFileRC(w io.Writer, records models.Records, origin string) error {
// * $TTL is used to eliminate clutter. The most common TTL value is used.
// * "@" is used instead of the apex domain name.
z := PrettySort(records, origin, mostCommonTTL(records))
z := PrettySort(records, origin, mostCommonTTL(records), comments)
return z.generateZoneFileHelper(w)
}
func PrettySort(records models.Records, origin string, defaultTTL uint32) *zoneGenData {
func PrettySort(records models.Records, origin string, defaultTTL uint32, comments []string) *zoneGenData {
if defaultTTL == 0 {
defaultTTL = mostCommonTTL(records)
}
z := &zoneGenData{
Origin: origin + ".",
DefaultTTL: defaultTTL,
Comments: comments,
}
z.Records = nil
for _, r := range records {
@ -88,6 +89,13 @@ func (z *zoneGenData) generateZoneFileHelper(w io.Writer) error {
sort.Sort(z)
fmt.Fprintln(w, "$TTL", z.DefaultTTL)
for _, comment := range z.Comments {
for _, line := range strings.Split(comment, "\n") {
if line != "" {
fmt.Fprintln(w, ";", line)
}
}
}
for i, rr := range z.Records {
// Fake types are commented out.

View file

@ -295,8 +295,12 @@ func TestWriteZoneFileSynth(t *testing.T) {
recs = append(recs, rsynz)
buf := &bytes.Buffer{}
WriteZoneFileRC(buf, recs, "bosun.org")
WriteZoneFileRC(buf, recs, "bosun.org", []string{"c1", "c2", "c3\nc4"})
expected := `$TTL 300
; c1
; c2
; c3
; c4
@ IN A 192.30.252.153
IN A 192.30.252.154
;myalias IN R53_ALIAS type= zone_id=

View file

@ -16,6 +16,7 @@ type zoneGenData struct {
Origin string
DefaultTTL uint32
Records models.Records
Comments []string
}
func (z *zoneGenData) Len() int { return len(z.Records) }

View file

@ -3,7 +3,7 @@ package bind
/*
bind -
Generate zonefiles suitiable for BIND.
Generate zonefiles suitable for BIND.
The zonefiles are read and written to the directory -bind_dir
@ -21,6 +21,7 @@ import (
"os"
"path/filepath"
"strings"
"time"
"github.com/miekg/dns"
@ -38,6 +39,7 @@ var features = providers.DocumentationNotes{
providers.CanUseSSHFP: providers.Can(),
providers.CanUseTLSA: providers.Can(),
providers.CanUseTXTMulti: providers.Can(),
providers.CanAutoDNSSEC: providers.Can("Just writes out a comment indicating DNSSEC was requested"),
providers.CantUseNOPURGE: providers.Cannot(),
providers.DocCreateDomains: providers.Can("Driver just maintains list of zone files. It should automatically add missing ones."),
providers.DocDualHost: providers.Can(),
@ -214,10 +216,19 @@ func (c *Bind) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correcti
// foundDiffRecords < foundRecords
// diff.Inc...(foundDiffRecords, expectedDiffRecords )
comments := make([]string, 0, 5)
comments = append(comments,
fmt.Sprintf("generated with dnscontrol %s", time.Now().Format(time.RFC3339)),
)
foundRecords, err := c.GetZoneRecords(dc.Name)
if err != nil {
return nil, err
}
if dc.AutoDNSSEC {
comments = append(comments, "Automatic DNSSEC signing requested")
}
// Normalize
models.PostProcessRecords(foundRecords)
@ -262,7 +273,10 @@ func (c *Bind) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correcti
if err != nil {
log.Fatalf("Could not create zonefile: %v", err)
}
err = prettyzone.WriteZoneFileRC(zf, dc.Records, dc.Name)
// Beware that if there are any fake types, then they will
// be commented out on write, but we don't reverse that when
// reading, so there will be a diff on every invocation.
err = prettyzone.WriteZoneFileRC(zf, dc.Records, dc.Name, comments)
if err != nil {
log.Fatalf("WriteZoneFile error: %v\n", err)