Code Monkey home page Code Monkey logo

tdns's Introduction

tdns

tdns is a small authoritative nameserver written in Go to be used various experiments and tests. It is intended to be really simple to understand and modify as needed. The repo consists of three separate programs:

tdnsd

A simple authoritative DNS nameserver with some special features. See tdnsd/README.md

tdns-cli

A CLI tool to interact with tdnsd via a REST-ful API. See tdns-cli/README.md

dog

A CLI tool that seems like a very simplistic cousin to the much more powerful tool "dig", which is part of the BIND9 distribution from ISC. The primary raison d'etre for "dog" is that it understands the experimental new record types DSYNC and DELEG.

tdns's People

Contributors

johanix avatar peterthomassen avatar

Stargazers

Layal Jebran avatar

Watchers

Lars-Johan Liman avatar Layal Jebran avatar  avatar  avatar

tdns's Issues

Improve tdns-cli control over tdnsd/tdns-agent

At present it is necessary to kill and restart tdnsd/tdns-agent whenever the config is changed. That's primitive and not a workable long-term alternative. We need at least:

  • "tdns-cli start"
  • "tdns-cli restart". Preferably including "--update" to install new binary in the right place.
  • "tdns-cli config reload": reload tdns.yaml from scratch (is this possible?)
  • "tdns-cli config zonereload": reload tdns-zones.yaml, replacing what we have. Note that this is very much dependent on whether there have been changes made to zones (i.e. they are dirty). Dirty zones must be written to disk first, but that should probably require a "force" option.

Further cleanup of tdns-agent

  • Move more code into the tdns/ lib. RefreshEngine is one example.
  • Try to remove more stuff from agent/main.go
  • Would it be possible with a simpler RefreshEngine for tdns-agent?

Implement registrar mapping of DSYNC responses via db table lookup

  • Add config support for specifying a set of "known" registrars and their preferred DSYNC RRsets
  • Add support to tdns-cli for mapping child zones to "known registrars".
  • Add config support for mapping "registrars" to DSYNC targets.
  • Only registrars present in config are "known"
  • Load the mappings from DB table to memory on startup, to avoid the need for DB lookups in the query processing path.

Add support for general zone updates via DDNS

Right now we support update of child delegation information, signed by the child key. But we don't support other changes signed by a key separate from a child key. That would be useful.

  • Need to break up the AllowUpdates option into a general AllowUpdates + a more restricted AllowChildUpdates.
  • Need to tweak the TrustStore to be able to store non-child keys.
  • Need to update the UpdateResponder to understand both cases and DTRT in each case.

"tdns-cli keystore sig0 generate -z zone -a RSASHA256" doesn't work

Creating Ed25519 keys work fine, but RSASHA256 keys are generated, but the private key doesn't make it into the DB table. I suspect that the reason is with the parsing of the "bpk" data (Bind Private Key format), which is different for RSA keys than Ed25519 keys.

Exactly the same problem with "... keystore dnssec generate ...".

Restructure "tdns-cli ddns sync"

From the first experimental implementation the logic is a bit bass ackwards byt first deciding on DNS Update, then generating and signing the msg and finally figuring out where to send it.

"tdns-cli ddns sync" should be an API call into tdnsd; let tdnsd deal with the details:

  • Don't query for the child data, tdnsd already has that.
  • Cache the name of the parent and the parent servers in the ZoneData struct
  • Don't query for cached parent data
  • Query parent for child delegation data; if not in sync:
  • If not cached:lookup and cache the DSYNC data
  • Is DNS Update a supported scheme? If so:
  • Create msg
  • Sign msg
  • Send msg to (cached) DDNS target

Need more granular control over update policies.

  • Specify defined policies under the "updatepolicies:" tag in tdns.yaml
  • Refer to which policy to apply for a zone with the "updatepolicy:" key. Note that it has two sub keys, "childupdates:" and "zoneupdates:"
  • The child and zone update policies should be properties of the zone, i.e. part of the ZoneData.
  • The Approval functions should be receiver functions on ZoneData, not UpdatePolicy, and hence move to tdns.
  • ParseConfig() must be upgraded to correctly parse the new updatepolicies: key.

Receiving generalized notify from child

  • Support for receiving generalized notifications
  • On receipt of NOTIFY(CSYNC) do all the corresponding lookups of child NS RRset and A + AAAA in bailiwick glue
  • Verify all DNSSEC signatures
  • Config stuff for specifying approval policy
  • Apply approval policy
  • Update database of child delegation data
  • Update child delegation data in served version of parent zone
  • Send NOTIFY to parent zone signer

Restructure code that makes zone modifications.

Right now we have code in lots of places that adds (or sometimes removes) RRs from a zone. In many there is also signing of a modified RRset. Finally there is locking when actually applying the changes to the zone data.

If we changed the code to only create (or modify) the RRset and then send it over to the UpdateEngine for possible signing and inclusion in the zone we would save a lot of code in a number of places. Another advantage would be that in the case where the zone cannot be modified and we need to store the changes (as a "todo-list") for an operator to apply manually, then that is also only done in one place instead of all over.

The only real drawback is the the UpdaterEngine at present deals with updates to zone data mostly structured as DNS UPDATEs stored inside an UpdateRequest blob. Either we add another format to what UpdaterEngine understands or we just construct the UpdateRequest blob when needed. The latter is probably best.

  • Restructure publish/unpublish KEY in child zones
  • Restructure publish/unpublish DSYNC in parent zones
  • Restructure publication of DNSKEY in signed zones
  • Restructure publication of CSYNC in child zones

Note: TDNS doesn't support CDS yet (as it cannot roll DNSKEYs yet).

Implement support for a "tdns plugin" to MUSIC (the MUlti-SIgner Controller)

MUSIC has a rather simple interface requirement (as described in https://github.com/DNSSEC-Provisioning/music/blob/main/music/updater.go). It essentially boils down to implementing three API calls:

Update(), FetchRRset() and RemoveRRset().

Each of these deal with DNS RRs in [][]dns.RR. An "updater plugin" in MUSIC will need to implement the existing interface and translate that to API calls into TDNS-{SERVER,AGENT}. TDNS doesn't really use []dns.RR much and instead uses its own RRset struct. Whether the conversion between []dns.RR and RRset is done in the plugin or in the TDNS end doesn't really matter.

However, if the RRset struct is a better alternative than []dns.RR then that's an argument for perhaps even converting MUSIC to use RRset instead of []dns.RR, but that's a separate discussion.

In the TDNS end we need three new endpoints:

  • /multisigner/update: MUSIC wants to send lists of dns.RRs to add and/or remove. TDNS has support for add/remove operations (as part of the DNS UPDATE support), so this is mostly a question of conversion of datastructures.
  • /multisigner/fetch-rrset: return a single RRset from a zone that TDNS serves.
  • /multisigner/remove-rrset: delete a single RRset from a zone that TDNS serves.

Then on the MUSIC side the actual plugin that accesses these endpoints need to be implemented. See DNSSEC-Provisioning/music#218

Receiving SIG(0) signed DNS updates from child to parent

  • Support for receiving DNS updates
  • Support for validating DNS updates
  • Configuration stuff for describing a policy for approval
  • Implementation of approval policy
  • Adding validated and approved updates to DB of updated delegation data
  • Apply updated delegation data to served parent zone data
  • CLI support for trusting/untrusting child SIG(0) keys
  • Config stuff for describing policy for approval of initial SIG(0) key during child bootstrap
  • Implementation of bootstrap policy

Implement KEY and CDS lookups as API requests

Initial bootstrap of KEY and/or CDS RRsets require distributed lookup and validation. It is therefore necessary for one TDNSD (the "primary") to be able to request other TDNSD (in other locations, the "secondaries") to do such lookups and validation and report on the results.

The only way to issue such requests is via the API.

  • Expose API endpoints for KEY and CDS lookup and validation.
  • Secure the API with TLS.
  • Implement a cert structure that allows one TDNSD to issue requests to another (i.e. as a client).

Restructuring the scanner

Right now the scanner is mixing collecting information (from existing data structures or from DNS queries) with computing the difference between "old" and "new" or between "child" and "parent". This makes distributing the scanner more difficult (as a remote scanner will not necessarily have access to the complete zonedata).

There are two immediate alternatives for a redesign:

  1. the scan request can provide the data to compare against (i.e. the parent primary has the "current" parent-side data for the child and fans out the collection of child-side data and comparison to one or more remote scanners. The report back is the child-side data plus the difference.
  2. the scan request does not provide the data to compare against, and the report back is only current child-side data. The computation of difference has to be done back at the parent primary.

Alternative 1 seems to be the better choice. Things to do:

  • Design a data structure for "current" parent-side data for the child.
  • Update the scan request infrastructure to supply the current data.
  • Update the scanner(s) to make all comparisons against supplied data rather than looking at the parent zone data (which may not be available).
  • Update the DelegationSync engine to analyse what it gets back from the scanner and DTRT depending on what it is.

Restructure the delegation sync in TDNSD

We have code in tdnsd that does most of what we want (tdnsd/delegation.go:), but it is geared towards dealing with API requests. We detect that a delegation is out of sync down in the tdns lib (tdns.FetchFromFile() and tdns.FetchFromUpstream() notice that delegation is out of sync anc call tdns.SyncWithParent()). But that's the wrong place, because down in the tdns lib we don't have access to the KeyStore...

Let's change this to:

  • Create a small DelegationManager goroutine. It accepts tasks via a channel.
  • Provide the channel to where the out-of-sync is detected (i.e. down via RefreshEngine-> zd.Refresh() -> zd.FetchFrom{File,Upstream).
  • When need to sync is detected, request this via the channel and forget about it. It is now the responsibility of the DelegationManager.
  • Clean up the SyncZoneDelegation() and SyncZoneDelegationViaUpdate and move them under DM control.
  • Update the API receiver to send a sync request to DM rather than call the SyncZoneDelegation* functions.
  • Declare victory.

Implement a first cut at automatic SIG(0) KEY bootstrap.

For a first cut it is sufficient to query for "child.parent. KEY" once if it is dnssec signed below a signed delegation and validation succeeds.

If the KEY record is not signed we must query N times with M seconds in between. M is the lesser of the KEY ttl or a configured delay.

  • Add config support for specifying N and M.
  • Implement key bootstrap using N and M.
  • Add config and implementation for requiring TCP query transport.

Later on we will add the ability to query from multiple vantage points by having one tdnsd request another tdnsd (via API) to lookup the KEY RR. See issue #41.

Modify the contents of a primary zone when receiving an approved update

If an update is approved we currently just update the DB, but not the actual zone data. A possible alternative would be:

  • If the zone is a primary zone; and
  • If there is a policy for the zone that allows updates (i.e. essentially "allow ddns" and not "frozen").

then we could actually:

  • Update the the zone contents (i.e. update the delegation data for this particular child).
  • Update the SOA.
  • Write the zone back to disk.

Todo:

  • Add support for "allow updates" and "[not] frozen" to the ZoneData struct.
  • Add support to tdns-cli to freeze/thaw.
  • Add ability to write zonefile to disk on "freeze".
  • Disable reload if allow updates and not frozen.
  • Disable child UPDATE and child NOTIFY if !allow updates or frozen.
  • If "dirty" write updated zone to disk before exiting. Note that it must be a "safe" write, i.e. write to new file then mv into place.

Sending SIG(0) signed DNS updates on changed delegation data

  • Analysis of changes to delegation data on zone reload from disk
  • Analysis of changes on zone transfer from primary
  • Analysis of changes on DDNS update received from CLI tool or similar
  • Look up parent DSYNC record to locate parent update target
  • Generate DNS update message
  • Sign DNS update message with key from keystore
  • Send DNS update message
  • CLI support for adding and removing SIG(0) private keys to keystore.

More detailed model for SIG(0) keys

It would help to have a couple more bits for both keystore keys and truststore keys. Like:

  • A keystore bit that indicates that the key id trusted by the parent
  • Rather than looking in first the TrustStore and then the KeyStore for a key needed for validation, keys in the KeyStore should have their public parts also inserted in the TrustStore automatically.

Updates should contain an OPT RR to enable the responder to provide an EDE in the response.

  • Add an OPT to outbound DNS UPDATE messages
  • When receiving an UPDATE, check whether it contains an OPT and if so add an (initially empty) OPT to the response.
  • When composing various types of negative responses (unknown key, known but untrusted key, etc) add a suitable EDE option to the list of options in the OPT RR.
  • Check whether the EDE spec has any interval of opt codes that are reserved for private use and if so create new EDEs as needed in that interval.

Add TLS to protect the API communication

The interesting question is whether to just self-sign or to set up a local CA. In the latter case, should we let tdnsd generate certs or should we use some external CA software?

Sending generalized notify to parent on change to child delegation data

  • Analysis of change to delegation data (same as for the DNS Update case)
  • Generate and publish CSYNC record in unsigned zone
  • Send notify to signer (which is configured as a bump-on-the-wire secondary)
  • Verify that signed CSYNC is published
  • Look up DSYNC record to locate notification target
  • Send NOTIFY(CSYNC) to parent notification target
  • Examine response to NOTIFY from parent

Detect changes to DNSKEY RRset and send NOTIFY(DNSKEY) if in multi-signer mode.

  • Implement config support for multisigner configs
  • Implement config mapping between zones and multisigner configs
  • Implement basic sanity checking for multisigner configs and mappings (configs must be useable, mapping only to workable configs, etc)
  • Detect changes to the DNSKEY RRset in agent mode
  • Detect changes to the DNSKEY RRset when in primary mode (i.e. we ourselves add or remove keys for some reason).
  • When there is a change, send a NOTIFY(DNSKEY) to the multisigner controller

Implemented for the agent case, but not yet tested so I'm sure there are bugs.

In zd.FetchFromUpstream() we check for changes to the DNSKEY RRset when receiving the zone from the primary and if there are changes a SYNC-DNSKEY-RRSET request is sent to the DelegationSyncher(). DelegationSYncher() checks whether the zone is a multi-signer zone and if so sends a NotifyRequest to the Notifier() with the multisigner controller addresses as the notification targets.

Improve the signer

  • The DNSKEY RRset should be added to the zone
  • The signer should understand the possibility of a KSK/ZSK split and if there is an active ZSK then use that for signing everything except the DNSKEY RRset.
  • Don't sign child delegations. Duh!
  • Don't sign child in-bailiwick glue.
  • If there are multiple active KSKs or ZSKs then sign with all of them (i.e. sign the DNSKEY RRset with all active KSKs, etc).
  • Don't bother with twiddling the NSEC chain, we will do black-lies instead.
  • Keep the zone signed. I.e. periodically check whether any signatures need refreshing. How should the resigning interval be decided?
  • A zone that has the "sign-zone" option set should be signed automatically when loaded.
  • If any RRset was resigned then bump the SOA serial and re-sign the SOA
  • If any RRset was re-signed then notify downstreams.

Signing a DNS UPDATE with multiple active SIG(0) keys doesn't work; must only use one

I think the problem is that the SIG signs the entire message, except for itself. That will fail when a second signature adds more data to the message after the first SIG was created. So this is a reasonable limitation, but it means that we must ensure only to sign with one key at a time.

  • Ensure that we only sign with one active SIG(0) key
  • Ensure that only one SIG(0) key can be active at any one time

multi-signer prep

There are a number of things needed for tdnsd to be a viable "signer" in a multi-signer context. Among them:

  • A more sophisticated model for a zone's DNSKEYs. Must include a distinction between internal keys (that may be rolled) and external keys that belong to another signer and should just be kept in the RRset.
  • Same thing for the NS RRset: internal and external NS.
  • Either add support for TSIG or add SIG(0) support to MUSIC or add API support to both so that they communicate. API support probably best alternative.
  • Add support for sending NOTIFY(DNSKEY) sideways (to either a central MUSIC or a sidecar MUSIC) when the contents of the DNSKEY RRset changes.

Initially we will not add any key rollover support to TDNSD.

Improve the keystore

  • If a zone should be signed but the keystore has no active DNSSEC keys then promote some existing keys to active.
  • If a zone should be signed but the keystore has no DNSSEC keys at all, then it should generate new key pairs, just as it does for SIG(0) keys.
  • The "internal" key generator code doesn't work anymore (after some significant refactoring). The external generator is clumsy, getting the internal generator working is important.
  • I think there is still some corner case where we seem to store the contents of a bind .private file as the private key in the keystore. Find the bug.
  • For ED25519 keys it is sufficient to store the "private key" in a field in the Keystore db table, but for other algorithms (eg. RSASHA256, see #46) this doesn't work. So we most likely really need to store the entire "bind private key" format stuff somewhere. I think the best alternative is to put all the private key data in a separate table, {Sig0,Dnssec}PrivateKeys or something, and no longer mix it up with all the other data in the Keystore tables.

Agent improvements

There are clearly limitiations to what the tdns-agent is able to do. In particular it is unable to modify the zone. As some of the feature require zone modifications this creates a problem. The best we can do, AFAIK, is to make it clear exactly what zone modifications are needed so that they can be done elsewhere (in the primary) by other means (typically manually).

Enabling child-parent synchronization:

  • Add a table with needed changes, per zone.
  • When a KEY RR should be created (and usually signed), but it cannot be added to the zone because we're an agent, then add the KEY RR to the above table instead.
  • When a DSYNC RRset should be created (and usually signed), add it to the above table instead.

Results from child-parent synchronization:

  • When an UPDATE has been verified by a trusted key and approved by local policy and we're an agent, then add the complete new delegation data to the above table instead.
  • When a NOTIFY has been processed, and the subsequent lookups in the child all verify and are approved, then add the complete new delegation data to the above table instead.

Accessing the queued up changes:

  • Add API support for extracting the queued changes per zone.
  • Add CLI support for accessing and presenting this data via the API.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.