Domain Name Server Configuration Utilities -- NSC 5.0 (c) 1997--2019 Martin Mares ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ----------------------------------------------------------------------- WARNING: There were several incompatible changes between major versions See NEWS for the summary of changes. ----------------------------------------------------------------------- NSC is a set of shell and M4 scripts for easy maintenance of DNS zone files and name server daemon configuration (currently available only for BIND 8.x/9.x, but easily portable for other daemons). It has been designed to make administration of a DNS server a piece of cake (unlike other utilities which resemble more an English pudding :-) ), which includes automatic generation of reverse records for all your hosts, handling of classless reverse delegations and support for IPv6 (AAAA and PTR in ip6.arpa, not A6 and DNAME which seem to be dying out). NSC requires GNU m4, GNU Bash, the `md5sum' and `sha1sum' utilities (which are present for example in GNU coreutils), and utilities distributed with BIND. Some of the extra utilities require Perl 5. I've tested everything on Linux (Debian Stretch), but the whole package should run on other unices as well. The whole package can be used and distributed according to the terms of the GNU General Public License, version 2 or higher. See file COPYING in any of the GNU utility archives (you should have one as you are expected to have at least GNU M4 ;-)). 0. Quick Howto for the Impatient ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (everything will be explained in more detail in the subsequent sections) - Create a directory where all NSC files will reside (e.g., /etc/named) and copy everything from the NSC distribution here. - Add an include directive to your BIND configuration file (usually /etc/bind/named.conf), referring to /etc/named/named.conf. - Change directory to /etc/named - Edit cf/domains to suit your needs -- replace the example domains by your entries. - Create cf/ for all domains (again, you can easily follow the example domains). - If you are using BIND 9.x, make the `bak' directory writable by the bind user. - Run bin/nsconfig (Makefile and named.conf will be generated). - Run make. - Enjoy your new DNS setup. If everything goes OK, be happy. Else write a bug report :-) - Every time you modify the domain files, re-run make. If you have added or removed domains or changed options which affect named.conf, re-run bin/nsconfig before make. An interesting companion to this package is the DNS Sleuth -- a DNS zone consistency checker. It's a simple utility written in Perl with help of the DNS module and it should be able to detect all common errors in DNS setup (I have written it after much disappointment with the other checkers). The Sleuth is available from http://mj.ucw.cz/sw/sleuth/. However, I haven't updated Sleuth for a long time, so it does not know about DNSSEC yet. 1. Directory structure ~~~~~~~~~~~~~~~~~~~~~~ The NSC directory (/etc/named in the above example) contains the following files and subdirectories: cf/ - user-defined configuration files cf/domains - the domain list (see Section 2) cf/config - global settings (see Section 3) cf/ - each domain has its own config file bin/ - commands (e.g., nsconfig) m4/ - M4 scripts (used by the commands) zone/ - primary zone files bak/ - backups of zones we serve as a secondary NS for ver/ - version files where NSC remembers version numbers of the primary zones tmp/ - temporary files hash/ - hashes of zone files used for detection of changes dss/ - DNSSEC DS records keys// - DNSSEC keys khash/ - hashes of DNSSEC keys used for detection of changes How are different files created: - You create everything in cf/. - Then you run bin/nsconfig. - If you want to use DNSSEC, create keys (see section 8) - Makefile and named.conf gets created according to cf/domains. - You run make. - The Makefile creates primary zone files in zone/ and version files in ver/ and tells BIND to reload its configuration. - BIND downloads contents of secondary zones and puts them to bak/. 2. The Domain List File ~~~~~~~~~~~~~~~~~~~~~~~ The domain list contains configuration commands describing all domains handled by your server and their parameters. In fact, it's a M4 script, but viewing it as a config file is a good approximation (however, see Section 8 for some caveats). Lines starting with a semicolon are treated as comments and ignored. Text outside declarations is silently ignored. You can specify: PRIMARY(zone, [extra-files...]) Define a zone (domain) we run a primary name server for. The contents of the zone are described in cf/ and possibly in other specified cf files (all files are concatenated to produce a single configuration). See the next section for a look inside these files. When the zone name contains a slash (as happens in classless reverse zones), it is replaced by "@" in the cf file name. SECONDARY(zone, primary) Define a zone we run a secondary name server for. "primary" is an IP address of the primary name server. REVERSE(network, primary-files...) Define a reverse zone for the given network. The network name consists of several numbers separated by dots, just like an IP address does, but the network usually has only 3 components. Each reverse zone has its own config file cf/ which can of course specify the contents of the zone. However, there is a more convenient method to generate the PTR records directly from the A records: just specify the REVERSE directive in cf/ and then include all the config files for the primary zones containing hosts from this network. The automatic concatenation of multiple primary-files comes very handy for that. In fact, REVERSE(network, p-f...) is almost an equivalent of PRIMARY(REV(network), p-f...) where REV(network) is a macro translating network numbers to names of the corresponding reverse zones [e.g., REV(1.2.3) equals 3.2.1.in-addr.arpa]. The only difference is that although the domain name is translated by REV, the config file is still named according to the network. You can also use the REV macro explicitly, which can be handy for example in SECONDARY declarations. FORWARDED(zone, ip...) Define a forwarding zone. All queries are forwarded to the specified name servers. BLACKHOLE(zone) Define an empty zone according to RFC 6303. This is usually done for zones for which clients are known to erroneously ask queries (e.g., reverse resolving of link-local addresses). The contents served for these zones is taken from cf/blackhole. ZONE_OPTIONS(`options; more options; ') Define options to be inserted to all subsequent zone declarations until the next ZONE_OPTIONS command. Please keep in mind that the semicolon character act as M4 comment, so you need to put the closing quote at a separate line. See our example cf/domains. CONFIG(...) Insert user data to named.conf, again beware of semicolons. MAKEFILE(...) Insert user data to Makefile. DNSSEC(`declarations...') Request DNSSEC signing for all zones declared within the block. DSFOR(zone) Declare dependency of the previous PRIMARY/REVERSE domain on DS records for the given zone configured in dss/*. 3. The Domain Files ~~~~~~~~~~~~~~~~~~~ The domain files contain descriptions of all DNS records for the given domain, starting with the SOA record. Again, these are M4 scripts and the declarations are macro calls. Lines starting with a semicolon are treated as comments and just copied to the generated zone file. Text outside declarations is copied to the zone file as well, so you can spice up the NSC output with your own records. All host or domain names are either names relative to the current domain with no dots inside or absolute names (in this case, NSC automatically ensures that the trailing dot is present in the resource records). If you really need a relative name with dots, escape all dots as "\.". Your menu: SOA(domain-name) Generate a SOA record for the domain. This must be the first declaration in the config file. The parameters of the SOA are taken from configuration variables (see below). The serial number is calculated from the version number remembered in the version file, following the usual practice of encoding current date and a sequence number within the current day in the serial number, which is guaranteed to be strictly increasing unless you perform more than 99 updates in a single day (in which case NSC stops and tells you to tweak the serial number manually). The SOA record otherwise acts like a sub-domain (D) declaration, therefore it can be followed by other records like NS (mandatory) or MX. H(host) Start declaration of a host. Doesn't generate anything, only remembers the host's name. ADDR(addr...) Specify addresses for the current host. In the normal mode, it creates A/AAAA records, in the reverse mode, PTR records. H(host, addr...) A shortcut for H(host) ADDR(addr...) -- in many cases everything you need for a single host. DADDR(addr...) Like ADDR, but suppresses PTR records. (This one is useful if you have a single IP address used for zillions of names and you want to avoid having zillions of PTR records for the same address.) DH(host, addr...) A shortcut for H(host) DADDR(addr...) D(domain) Start declaration of a sub-domain. Technically the same as H(domain), but this one should be more intuitive. GLUE(ns, addr...) Specify a glue record for a name server contained within a sub-domain it's a primary for. Currently it's an equivalent of DH(ns, addr...). NS(ns...) Specify a list of name server names for the current domain (started by either a SOA or D declaration). Generates NS records. DS() DS(dsset) Include DS records for the current sub-domain. With no arguments, they are loaded from dss/. If the name of the sub-domain does not match the name of the DSset (as it frequently happens with reverse zones), you can specify the DSset name explicitly. MX(mx...) Specify a list of mail exchangers for the current host or domain. Each mail exchanger should be preceded by a priority. Generates MX records. HI(hw,os) Specify a HINFO record for the current host. Very rare in the today's Internet. ALIAS(alias...) Specify a list of aliases for the current host or domain. Generates a series of CNAME records pointing from the aliases to the current host/domain. TXT(text) Specify a TXT record for the current host or domain. RP(mail, txt) Specify a RP (responsible person) record for the current host or domain. The first argument is a mail address in DNS notation (with `@' replaced by `.' as in the SOA record), the second one is a name of a TXT record with contact information. SRV(service, protocol, priority, weight, port, target) Specify a SRV (service) record for the current host or domain. CNAME(src, dest) Generate a CNAME record -- "src" points to "dest". PTR(src, dest) Generate a PTR record -- "src" points to "dest". It's a common record in reverse zones (and although it's legal in forward zones as well, such use is very rare), however it's more convenient to have your PTR's generated by the REVERSE directive. But if you need anything special, here is the tool. REVBLOCK(subdomain, min, max) Generate a series of CNAME records numbered from `min' to `max' and pointing to the same name in the given sub-domain, finally declaring the sub-domain as well, so you can continue with its NS records. Example: REVBLOCK(a, 16, 18) NS(ns.xyzzy.org) yields 16 CNAME 16.a 17 CNAME 17.a 18 CNAME 18.a a NS ns.xyzzy.org. This is a very common construct for classless reverse delegations, see Section 6 for more details. REVERSE(network) Switch to reverse mode. From this point on, all output is suppressed except for ADDR declarations belonging to the specified network which are automatically converted to PTR records. With help of this feature, defining reverse zones can be as easy as: ; Reverse zone for 10.0.0.0/24 a.k.a. 0.0.10.in-addr.arpa. SOA(REV(10.0.0)) NS(ns1.example.com, ns2.example.com) REVERSE(10.0.0) ; Include all primary zones containing ADDR's from this range, ; which can be accomplished by a multi-file REVERSE declaration ; in cf/domains. 4. Configuration variables ~~~~~~~~~~~~~~~~~~~~~~~~~~ There is a fair amount of configuration variables (which are in reality normal M4 macros). Each variable has a hard-wired default value which can be overridden in cf/config by re-defining the variable. Also, all other config files can specify their local definitions, but you need to be careful to change the variable before it is used for the first time. To change the setting, use define(`variable', `value') As usually, even this config file is a M4 script. Comments can be started by semicolons, text outside macros is ignored. The following variables are available: NAMED_RESTART_CMD Shell command for restarting the name server daemon (default: rndc reload) CFDIR Directory with config files (default: cf) REFRESH SOA record parameters RETRY EXPIRE MINTTL NSNAME Origin server (default: hostname of your machine) MAINTNAME Domain maintainer name (default: root@NSNAME) KEYGEN_OPTIONS Extra options given to dnssec-keygen (by default, it selects key type and key size). SIGNZONE_OPTIONS Extra options given to dnssec-signzone (by default, it specifies signature validity of 365 days). DSFROMKEY_OPTIONS Extra options given to dnssec-dsfromkey (by default, there are none). For the timing parameters, the following shortcuts are available: HOURS(n) Convert hours to seconds MINUTES(n) Convert minutes to seconds DAYS(n) Convert days to seconds 5. Makefile targets ~~~~~~~~~~~~~~~~~~~ The Makefile generated by NSC offers the following targets: all (default) - update all zone files and reload the daemon clean - clean all generated zone files, backups, and hashes clobber - clean + delete Makefile and named.conf (wise to do after major reconfigurations) distclean - clobber + delete all version files (use only if you really know what you are doing as the serial number information in newly generated files might be inconsistent then). 6. Classless reverse delegations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NSC also supports classless delegations for reverse zones using the mechanism described in RFC 2317, i.e. by putting CNAME records to the reverse zone which point to records of the same name in a sub-domain which you can delegate directly. For example if you want to delegate 64-127 in 0.0.10.in-addr.arpa to ns.example.net, you create a 64/26 sub-domain (26 is the network prefix length) and add the following records to 0.0.10.in-addr.arpa: 64 CNAME 64.64/26.0.0.10.in-addr.arpa. 65 CNAME 65.64/26.0.0.10.in-addr.arpa. ... 127 CNAME 127.64/26.0.0.10.in-addr.arpa. 64/26 NS ns.example.net. Then you configure ns.example.net to be a primary name server for the zone 64/26.0.0.10.in-addr.arpa and put the PTR records there: 64 PTR sixty-four.example.net. 65 PTR sixty-five.example.net. ... 127 PTR two-to-seven-minus-one.example.net. NSC offers special primitives for configuring such delegations, but not limited to the sub-domain name syntax shown above (which is recommended by the RFC, but it's far from being the only one used in the real world, other possibilities being for example 64-127, 64+64 etc.). The CNAME block can be generated by the REVBLOCK(subdomain-name, low-addr, high-addr) directive in the configuration of the whole reverse zone. The example above would be written as: REVBLOCK(64/26, 64, 127) The sub-zone can be created automatically like any another reverse zone, you only need to use the three-parameter form of the REVERSE directive to specify the address range in order to filter out possible hosts falling outside your range. CAVEAT: The slashes in zone names are automatically translated to @'s when forming file names. Again for the example above, you need to put the following to cf/domains: REVERSE(10.0.0.64/26, ) And to cf/64@26.0.0.10: SOA(REV(10.0.0.64/26)) NS() REVERSE(10.0.0, 64, 127) NOTE: It's usually helpful to configure the primary name server for the parent domain (i.e., the one where you configure the delegation and create the CNAME's) as a secondary for the sub-zone as well, so if it replies with the CNAME, it will include the PTR record pointed to by the CNAME in the additional section of its reply, eliminating the need for an extra query. 7. Support for IPv6 ~~~~~~~~~~~~~~~~~~~ NSC also supports IPv6 in a pretty straightforward form: wherever you can write an IPv4 address, you can use an IPv6 address as well. Incomplete IP addresses or ranges used for specifying address blocks for reverse delegations are replaced by network prefixes of the standard form
/. Example: H(ianus, 1.2.3.4, fec0::1234:5678:9abc:def0) specifies a dual-stack host with both an A record and an AAAA record. CAVEAT: The backward-compatible IPv6 address syntax with ":v.w.x.y" at the end is not supported. All other syntaxes and quirks hopefully are. 8. DNSSEC support ~~~~~~~~~~~~~~~~~ NSC knows the basics of DNSSEC. It does not handle key management (you need to schedule generation and retirement of your keys by other means), but once the keys are in place, it uses them for signing zones. === Key management === Keys live in keys//*.(key|private) and they are stored in the usual BIND format. To generate a zone-signing key, you can use the following command after writing at least rudimentary cf/: bin/key-gen If you want a key-signing key, use: bin/key-gen -f KSK (Generally, you can add arbitrary arguments for BIND's dnssec-keygen. Default keygen options can be set in cf/config, see section 4.) To detect key changes, NSC keeps a hash of all keys for each domain. If you edit the keys manually (e.g., to delete a key), you need to recalculate the hash by: bin/key-update (or without a zone to update all hashes). === Domain signing === All domains whose declarations in cf/domains are wrapped by DNSSEC(`...') are automatically signed using all set up keys. If you specify key validity period when generating the key, it is respected, but the domains are not re-signed automatically when a key becomes valid / ceases to be. If you want to modify dnssec-signzone arguments, you can do so in cf/config. Beware that all signatures have a limited lifetime (even if the keys do not expire). The default lifetime is 365 days, so you need to re-sign your zones at least once in a year. The recommended solution is to set up a cron job, which touches keys/resign-stamp. A change of timestamp of this file forces a re-sign on the next run of make. === Subdomains === If you want to delegate a signed sub-domain, you need to include DS records in the parent zone. Add a DS() macro after declaration of the sub-domain in the parent. It loads DS records from dss/. If the sub-domain is also maintained by NSC, you can generate the DS record set automatically by: bin/key-delegate === Reverse zones === Unlike primary/secondary zones, reverse zones have file names which differ from the full domain name. In such cases, keys are named after the file name and NSC constructs the full name whenever necessary. There is one exception where automatic construction is not available: delegation of sub-domain keys. In such cases, you need to pass the file name of the sub-zone to the DS macro. 9. Interaction with M4 ~~~~~~~~~~~~~~~~~~~~~~ All config files are fully-fledged M4 scripts, so you can use any M4 features you need, the most helpful one being definition of your own macros by define(`macro_name', `expansion') However, there is a couple of things you need to care about: o The comment character is redefined to `;'. I.e., wherever a semicolon occurs, the rest of the line is a comment which is copied verbatim to the output file (if the output is not suppressed like in case of the cf/domains file). o Names starting with 'nsc_' or spelled in all caps are reserved for the NSC itself and unless documented, messing with them can bring surprising results. If you need to use such a name in your zone file (maybe you like to shout in your host names :-) ), quote it like `this'. o Don't use commas, quotes nor parentheses in your record names. 9. Other utilities ~~~~~~~~~~~~~~~~~~ convert A simple Perl script for conversion of zone files to NSC domain files. Requires the Net::DNS module (available from CPAN at ftp.cpan.org; present in recent versions of Perl). Keep in mind that the script is very simple and its craft is of a very limited kind, so check its output carefully. chkdel A simple Perl script for checking of domain delegations -- it checks all PRIMARY and SECONDARY records in cf/domains against NS records. Requires the Net::DNS module and also some tweaking of parameters at the top of the script.