DDRM is a DNS record monitor written in golang that notifies you via email when it detects that records have changed. It's designed to be very easy to configure if you need to deviate from the sensible defaults, and easy to operate.
Through configuration, you supply DDRM with fully-qualified domain names (FQDN), resource record (RR) types, and expected values. DDRM then asks a designated DNS server for the value(s) for that FQDN+RR pair, checks them against your expected values, and emails you if anything is different.
DDRM can optionally cache record state, using Redis, so that state can persist across different executions of DDRM.
After a record change has been recorded and an email notification is sent, when using the cache, DDRM considers the changed value as the one to monitor for changes to in the future. That lets it handle the case where a record changes for some reason, and then maybe changes back to the original expected value.
It sleeps between record fetches in the configuration set, and then sleeps for a different amount of time after it has checked all records.
As it is working, you can watch the current state of processing with DDRM's terminal UI. By default the UI updates once a second, asynchronously to the processing of records. Using the UI is optional if you want to run DDRM as a headless service.
DDRM builds into a statically linked single binary that's easy to deploy on any supported platform: just copy it to the target host machine and place it somewhere in the $PATH
. Release binaries are pre-built for FreeBSD, Linux and macOS for both amd64 and arm64 processor architectures.
It's designed to be run in a screen or tmux session with its user interface running, showing you the results of the record checks, however it can also be run without the UI as a headless service.
DDRM writes log messages to stdout
if the UI is disabled, or to stderr
if the UI is enabled. In UI mode it's recommended that you send stderr
somewhere useful. For example:
ddrm-client-release-darwin-x86_64 -config ./ddrm.conf -records ./ddrm-records.conf -cache -ui 2&>>error.log
By default, unless you pass -insecure
when starting DDRM, it will refuse to read configuration files that aren't mode 0400
(-r--
, read-only for the current user), because the main runtime configuration contains mailserver credentials.
It is highly recommended that you give DDRM access to a Redis database so that it can use it to memorise runtime state. That allows DDRM to keep going from the last known state if you need to restart it.
By default, keys are prefixed with ddrm
and are Redis sets that store all of the returned query data. Sorting is performed in the DDRM client, rather than using Redis sorted sets.
Key names are in the form <prefix>:<FQDN>:<RR type>
, for example, ddrm:sommefeldt.com:A
.
Without the cache, DDRM won't currently update its default expected values with the results of queries.
The terminal UI (TUI) is simple and designed to show you at-a-glance information about the processing state without showing you the full information for every record.
An x
in the first column before the FQDN indicates that the record is about to be processed again. The final three columns indicate whether an email was sent about a change, whether there was a change, or whether there was an error processing that record update.
Errors don't trigger any behaviour other than an entry in the debug log.
-uirate
controls how often the UI updates. When the UI is active, press x
to toggle a "fullscreen" mode that hides all other terminal text. Press q
to exit the TUI and DDRM completely.
You configure DDRM by editing and securing two JSON configuration files. The first one (ddrm.conf
) provides the main configuration that lets DDRM know how it should send email and who it should send email to, which DNS server it should use for queries, and how to talk to Redis if you're using it as a cache.
The second configuration file (ddrm-records.conf
) contains the list of records you want to check, each consisting of a fully qualified domain name, a DNS resource record type, and an optional set of expected values to check against.
If you don't provide any expected values to start with, DDRM will check against the first query results returned and start from there instead.
DDRM also supports a number of command line parameters for configuring various other bits of useful runtime state away from the hopefully sensible defaults.
A single JSON object containing the following members:
email_user
string
, username for authenticating with the configured mailserver
email_password
string
, password for authenticating with the configured mailserver
email_server_hostname
string
, hostname of the configured mailserver
email_server_port
string
, port number of the configured mailserver
email_user_name
string
, name that emails should appear to be sent from in the SMTP envelope
dns_server_1
string
, nameserver to query in<hostname>:<port>
format. For example:1.1.1.1:53
dns_server_2
string
, nameserver to query in<hostname>:<port>
format. For example:9.9.9.9:53
. Only used if configured and ifdns_server_1
returns an error. Leave blank to never use it.
email_sender_name
string
, name that appears in the body text of the email
email_link
string
, link that appears in clickable form at the bottom of the email
email_logo
string
, URL to an image to show as the logo in the email body
email_subject
string
, subject line of the email that is sent on a detected record change
redis_database
number
, integer value for the Redis database to use (defaults to0
)
redis_password
string
, password to use when connecting to the Redis instance
redis_server
string
, Redis server to use in<hostname>:<port>
format (defaults tolocalhost:6379
)
redis_key_prefix
string
, prefix to use when reading and writing Redis keys (defaults toddrm
)
See the ddrm.conf
example.
ddrm-records.conf
JSON configuration values
An array of JSON objects, containing the following members.
fqdn
string
, fully-qualified domain name to ask for a resource record for
type
string
, the resource record type to ask for values for. For example,CNAME
,A
, orTXT
expected_values
- An array (
[]
) ofstring
values, separated by comma (,
) if multiple values should be checked. Multiple values are lexically sorted before comparison and so they can be defined in any order.
- An array (
See the ddrm-records.conf
example.
To see the full list of resource record types that DDRM knows how to interpret, please see the ddrmRecordType
constants in the source code.
-4 Use IPv4 for DNS resolution (default true)
-6 Use IPv6 for DNS resolution
-cache
Use Redis for persistent rolling update cache
-config string
Config file path (default "ddrm.conf")
-debug
Enabled debug mode
-expand
Expand tabs and quoted characters in results
-imprecise
Allow imprecise string matches
-insecure
Allow an insecure config
-logrecords
Log record processing results
-plaintext
Send plaintext email
-quieter
Be quieter on output
-records string
Records config file path (default "ddrm-records.conf")
-sleep duration
Seconds to sleep between checks (default 1m0s)
-tabs int
Number of spaces to expand tabs to (default 4)
-tcp
Use TCP instead of UDP for DNS resolution
-testdns
Test the DNS client and exit(3)
-testemail
Send a test email and exit(2)
-timeout duration
Seconds to wait for DNS client reponses before moving on (default 2s)
-ui
Render the terminal UI
-uirate duration
Seconds between UI updates (default 1s)
Look at parseCliFlags()
in ddrm-config.go
to see what state values are set by each flag. You can see how they're used in the codebase if you need more details.
-imprecise
can help when a record query might return a value with a trailing .
character, which is the correct notation for domain names in the domain name system. Using it asks the record processor to ignore it, so that you can write the config without having to remember it.
-expand
will expand any tab characters it finds in records returned from DNS, to a specific number of spaces (default is 4, use -tabs
to adjust that).
-debug
is very useful if you're struggling to configure or operate DDRM. It's required to see the output of -testdns
.
-testdns
checks the MX
, A
, SOA
and TXT
records of sommefeldt.com
, prints the data, and then exit(3)
s.
Currently DDRM supports a fixed email template that looks like this on a record change notification. Future versions might allow for more customisation of the look and feel:
DDRM is a composition of various excellent libraries and infrastructure software that do all of the interesting heavy lifting, allowing DDRM to focus on its value: marshalling the record checks and letting you know if anything has changed.
It uses the following great libraries and other software:
What | Why |
---|---|
Bubbletea | golang Terminal UI library |
Lipgloss | golang Terminal UI styling |
Hermes | golang HTML email generator |
dns | golang DNS queries |
go-redis | golang Redis client |
zerolog | golang zero alloc logger |
go-cron | golang cron-like asynchronous task library |
Redis | Optional runtime cache |
Future versions of DDRM may do the following:
- support passing in the password credential outside of the JSON config
- allow you to detach the UI and go headless while it still operates
- allow you to reattach to a headless client (maybe with a caught signal?)
- support a Web UI
- support reconfiguration using the terminal or Web UIs
- support checking multiple DNS servers and reporting if they disagree with each other
- more email template theming
- support the runtime cached "follow along" mode without using Redis
- make
-imprecise
default to true - collect multiple record reports into the same digest email
- report on the number of email sending errors in the TUI
DDRM is MIT licensed.
DDRM stands for Dave's DNS Record Monitor, in honour of my good friend Dave, who mused one day that he'd love a free DNS record monitoring system.
This one is for you, Dave.