🚀
DNSControl
🚀
DNSControl
  • Introduction to DNSControl
  • Getting Started
    • Overview
    • Examples
    • Migrating zones to DNSControl
    • TypeScript autocomplete and type checking
  • Language Reference
    • JavaScript DSL
    • Top Level Functions
      • D
      • DEFAULTS
      • DOMAIN_ELSEWHERE
      • DOMAIN_ELSEWHERE_AUTO
      • D_EXTEND
      • FETCH
      • HASH
      • IP
      • NewDnsProvider
      • NewRegistrar
      • PANIC
      • REV
      • REVCOMPAT
      • getConfiguredDomains
      • require
      • require_glob
    • Domain Modifiers
      • A
      • AAAA
      • ALIAS
      • AUTODNSSEC_OFF
      • AUTODNSSEC_ON
      • CAA
      • CAA_BUILDER
      • CNAME
      • DHCID
      • DNAME
      • DNSKEY
      • DISABLE_IGNORE_SAFETY_CHECK
      • DMARC_BUILDER
      • DS
      • DefaultTTL
      • DnsProvider
      • FRAME
      • HTTPS
      • IGNORE
      • IGNORE_NAME
      • IGNORE_TARGET
      • IMPORT_TRANSFORM
      • IMPORT_TRANSFORM_STRIP
      • INCLUDE
      • LOC
      • LOC_BUILDER_DD
      • LOC_BUILDER_DMM_STR
      • LOC_BUILDER_DMS_STR
      • LOC_BUILDER_STR
      • M365_BUILDER
      • MX
      • NAMESERVER
      • NAMESERVER_TTL
      • NAPTR
      • NO_PURGE
      • NS
      • PTR
      • PURGE
      • SOA
      • SPF_BUILDER
      • SRV
      • SSHFP
      • SVCB
      • TLSA
      • TXT
      • URL
      • URL301
      • Service Provider specific
        • Akamai Edge Dns
          • AKAMAICDN
        • Amazon Route 53
          • R53_ALIAS
        • Azure DNS
          • AZURE_ALIAS
        • Cloudflare DNS
          • CF_REDIRECT
          • CF_SINGLE_REDIRECT
          • CF_TEMP_REDIRECT
          • CF_WORKER_ROUTE
        • ClouDNS
          • CLOUDNS_WR
    • Record Modifiers
      • TTL
      • Service Provider specific
        • Amazon Route 53
          • R53_ZONE
          • R53_EVALUATE_TARGET_HEALTH
    • Why CNAME/MX/NS targets require a "dot"
  • Provider
    • Supported providers
    • Akamai Edge DNS
    • Amazon Route 53
    • AutoDNS
    • AXFR+DDNS
    • Azure DNS
    • Azure Private DNS
    • BIND
    • Bunny DNS
    • CentralNic Reseller (CNR) - formerly RRPProxy
    • Cloudflare
    • ClouDNS
    • CSC Global
    • deSEC
    • DigitalOcean
    • DNS Made Easy
    • DNSimple
    • DNS-over-HTTPS
    • DOMAINNAMESHOP
    • Dynadot
    • easyname
    • Exoscale
    • Gandi_v5
    • Gcore
    • Google Cloud DNS
    • Hetzner DNS Console
    • HEXONET
    • hosting.de
    • Huawei Cloud DNS
    • Hurricane Electric DNS
    • Internet.bs
    • INWX
    • Linode
    • Loopia
    • LuaDNS
    • Microsoft DNS Server on Microsoft Windows Server
    • Mythic Beasts
    • Namecheap
    • Name.com
    • Netcup
    • Netlify
    • NS1
    • OpenSRS
    • Oracle Cloud
    • OVH
    • Packetframe
    • Porkbun
    • PowerDNS
    • Realtime Register
    • RWTH DNS-Admin
    • Sakura Cloud
    • SoftLayer DNS
    • TransIP
    • Vultr
  • Commands
    • preview/push
    • check-creds
    • get-zones
    • get-certs
    • fmt
    • creds.json
    • Global Flag
    • Disabling Colors
  • Advanced features
    • CI/CD example for GitLab
    • CLI variables
    • Nameservers and Delegations
    • Notifications
    • Useful code tricks
    • JSON Reports
  • Developer info
    • Code Style Guide
    • Documentation Style Guide
    • DNSControl is an opinionated system
    • Writing new DNS providers
    • Creating new DNS Resource Types (rtypes)
    • Integration Tests
    • Test a branch
    • Unit Testing DNS Data
    • Bug Triage Process
    • Bring-Your-Own-Secrets for automated testing
    • Debugging with dlv
    • ALIAS Records
    • TXT record testing
    • DNS records ordering
  • Release
    • How to build and ship a release
    • Changelog v3.16.0
    • GitHub releases
Powered by GitBook
On this page
  • "Builders"
  • Trailing commas
  • Repeat records in many domains (macros)
  • Many domains with the exact same records
  • Caveats about getting too fancy
Edit on GitHub
  1. Advanced features

Useful code tricks

PreviousNotificationsNextJSON Reports

Last updated 5 months ago

"Builders"

Problem: It is difficult to get CAA and other records exactly right.

Solution: Use a "builder" to construct it for you.

Trailing commas

You might encounter D() statements in code examples that include END at the end, such as:

dnsconfig.js
D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
  A("test", "1.2.3.4"),
END);

As of , the END statements are no longer necessary. These were originally included for historical reasons that are now irrelevant. You can safely remove them from your configurations.

Repeat records in many domains (macros)

Problem: I have a set of records I'd like to include in many domains.

Solution: Assign a list to a var and use the var in each domain.

Example:

Domains that use Google G-Suite require a specific list of MX records, plus there are some CNAMEs that are useful (but we only want the CNAMEs on a subset of domains).

dnsconfig.js
var GOOGLE_APPS_DOMAIN_MX = [
  MX("@", 1, "aspmx.l.google.com."),
  MX("@", 5, "alt1.aspmx.l.google.com."),
  MX("@", 5, "alt2.aspmx.l.google.com."),
  MX("@", 10, "alt3.aspmx.l.google.com."),
  MX("@", 10, "alt4.aspmx.l.google.com."),
];
var GOOGLE_APPS_DOMAIN_SITES = [
  CNAME("groups", "ghs.googlehosted.com."),
  CNAME("drive", "ghs.googlehosted.com."),
  CNAME("calendar", "ghs.googlehosted.com."),
  CNAME("mail", "ghs.googlehosted.com."),
  CNAME("sites", "ghs.googlehosted.com."),
  CNAME("start", "ghs.googlehosted.com."),
];

D("primarydomain.tld", REG_NAMECOM, DnsProvider(DSP_MY_PROVIDER),
   GOOGLE_APPS_DOMAIN_MX,
   GOOGLE_APPS_DOMAIN_SITES,
   A(...),
   CNAME(...)
}

D("aliasdomain.tld", REG_NAMECOM, DnsProvider(DSP_MY_PROVIDER),
   GOOGLE_APPS_DOMAIN_MX,
   // FYI: GOOGLE_APPS_DOMAIN_SITES is not used here.
   A(...),
   CNAME(...)
}

Many domains with the exact same records

Problem: We have many domains, each should have the exact same records.

Solution 1: Use a macro.

function PARKED_R53(name) {
    D(name, REG_NAMECOM, DnsProvider(DSP_MY_PROVIDER),
       A("@", "10.2.3.4"),
       CNAME("www", "@"),
        SPF_NONE, //deters spammers from using the domain in From: lines.
        );
}

PARKED_R53("example1.tld");
PARKED_R53("example2.tld");
PARKED_R53("example3.tld");

Solution 2: Use a loop. (Note: See caveats below.)

dnsconfig.js
// The domains are parked. Use the exact same records for each.
_.each(
  [
    "example1.tld",
    "example2.tld",
    "example3.tld",
  ],
  function (d) {
    D(d, REG_NAMECOM, DnsProvider(DSP_MY_PROVIDER),
       A("@", "10.2.3.4"),
       CNAME("www", "@"),
    );
  }
);

Caveats about getting too fancy

The dnsconfig.js language is JavaScript. On the plus side, this means you can use loops and variables and anything else you want.

However, we don't recommend you get too fancy.

A new JS interpreter may break your code

Loops and macros are fine. Just don't get too fancy.

Complexity is a killer

As Brian Kernighan wrote, "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."

Sure, you can do a lot of neat tricks with if/thens and macros and loops. Yes, YOU understand the code. However, think about your coworkers who will be the next person to edit the file. Are you setting them up for failure?

And what about You Six Months From Now (YSMFN)? Have you met YSMFN? They're a great person. You'll meet them soon. In about 6 months, I predict. That person is a lot like you, but definitely won't remember how all those clever tricks work. That person also might be tired, sleepy, and possibly drunk. You really want to keep the configuration file simple for YSMFN.

The goal of DNSControl is to empower non-experts to safely make DNS changes. A DNS expert should create the initial configuration, but your non-expert coworkers should be able to send PR and make changes without too much hand-holding. Complexity prevents that.

What to do instead?

Isolate the clever stuff from what a typical user will need to edit.

At Stack Overflow, we put all our macro definitions and fancy stuff at the top of the file. The domains are later in the file.

We name the macros to be easy to understand for the user. For example, we have a few macros named SPF_NONE, SPF_GSUITE, and SPF_domain_tld (where domain_tld is the name of a domain). I bet you can guess which to use for a new domain without seeing the definition.

We also comment extensively. Most records have a comment at the end of the line with the ticket number of the request related to the record. Before each domain there is a long comment explaining why the domain exists, who requested it, any associated ticket numbers, and so on.

Some day we may change from the to something else. This may break your configuration if you depend on unusual or obscure behavior of Otto.

We also comment the individual parts of a record. Look at the example. Each part of the SPF record has a comment.

CAA_BUILDER
DMARC_BUILDER
M365_BUILDER
SPF_BUILDER
DNSControl v4.15.0
Otto JS interpreter
SPF Optimizer