Prior to the middle 1980's all machines connected to the ``internet'' used a common HOSTS.TXT file that provided all the hostnames and addresses in use. The file was flat and hostnames had to be unique in the file. As the number of hosts attached to the internet began to grow at an increasing rate, the central HOSTS.TXT file became more and more of a problem.
When a user types a hostname into some application, a resolution must occur before the requested host can be contacted. With the hosts file, one could simply search the file for the given hostname and utilize the corresponding address.
For machines to actually communicate with eachother they need to use IP addresses. Hostnames must be resolved into IP addresses before those machines can send traffic back and forth. Some applications require that hostnames and IP addresses point to each other exclusively for security reasons. Obtaining a hostname from an IP address is thus required.

bfs.cs.colorado.edu
bfs.cs.colorado.edu.NULL
bfs.cs.colorado.edu.

A zone is that portion of a Domain Name Space sub-tree that is managed by a single entity. Note that this definition might include sub-domains of the parent if those domains have not been delegated.
This may depend on the size of the sub-domain and/or the desire of that sub-domain's admins. Large, active sub-domains might require their own zone management, while small or un-used sub-domains can be administered just as well by the parent domain.
The Bind Documentation defines a zone as follows:
a zone is a point of delegation in the DNS tree. A zone consists of those contiguous parts of the domain tree for which a name server has complete information and over which it has authority. It contains all domain names from a certain point downward in the domain tree except those which are delegated to other zones. A delegation point is marked by one or more NS records in the parent zone, which should be matched by equivalent NS records at the root of the delegated zone.
See below under Resource Records for more information about NS records.

This is done despite that fact that all the hostnames involved are in a single Forward zone. The issue is one of organization of the DNS database zone files which we talk about further below. For example, the CS department's host are all in the 'cs.colorado.edu' forward zone, but each subnet (e.g. the 128.138.202/24, the 128.138.192.0/24, etc) has its own reverse zone. This makes more sense if you actually draw out the in-addr.arpa sub-trees involved - you'll see that the reverse zones are often distinct sub-trees; that they aren't always adjacent in terms of sibling nodes. For example, the CS department has authority over the 128.138.192.0/24, the 128.138.193.0/24, and the 128.138.198.0/24. But we do not have authority over the zones in between, like 128.138.195.0/24.
SOA "Start of Authority" record
NS "Name Server" record
I categorize the most common records as 'host' records
A Address record
PTR Pointer record
CNAME "Canonical Name" record
MX "Mail eXchange" record
KEY Public Key record
NXT Next record
SIG Signature record
% nslookup <domain-name>
% nslookup <domain-name> <server>
coatl % nslookup Default Server: mroe-fs.cs.colorado.edu Address: 128.138.242.197
>
coatl % nslookup - suod-fs Default Server: suod-fs.cs.colorado.edu Address: 128.138.242.200
>
> bfs Server: suod-fs.cs.colorado.edu Address: 128.138.242.200
Name: bfs.cs.colorado.edu Address: 128.138.202.9
>
> set type=MX > bfs Server: suod-fs.cs.colorado.edu Address: 128.138.242.200
bfs.cs.colorado.edu preference = 10, mail exchanger =
nago.cs.colorado.edu
bfs.cs.colorado.edu preference = 99, mail exchanger =
cs.colorado.edu
...
Despite being non-RFC-compliant, stealth servers are in common use and there is every reason to do so. These servers can reduce the overall traffic load on local your network infrastructure and there is no need for the rest of the world to use them or even know about them.
Additionally, there is no reason stealth servers can't also be authoritative. Their 'stealthness' simply means that parent-zone NS records don't reference them.
A common arrangement between two sites (who have different ISPs) is to swap secondaries so that each provides authoritave (via a secondary server) name service for the other. This is done for overall robustness of the DNS distributed system.
That is, incoming packets with a destination TCP port number for DNS. Reply traffic with a source port for DNS is a different deal. One safer way to allow it is to use a Stateful firewall rule that works for UDP (Like the OpenBSD PF).
Non-forwarding servers will follow recursive queries, and thus end up recieving referals, thus causing subsequent queries to other name servers.
Note that this is a configurable value, but that is also the well-known port number on which resolver libraries (i.e. client applications) expect to find DNS servers listening. Zone transfers (when a secondary server gets an entire set of zone data from a primary server) sometimes utilize a different port (1053 seems to be common) to allow for more specific firewall rules.
coatlicue% grep domain /etc/services domain 53/tcp nameserver # name-domain server domain 53/udp nameserver

The header is described below. Not all of the remaining sections must have any data. For queries, only the 'question' section will have anything in it. Answers to standard (A,PTR,CNAME) queries will be found in the 'answers' section. Answers that are NS records are in the 'authority' section. Answers to other queries will be in the 'additional' section.

The ID value is arbitrarily chosen by the machine that generates the query, it is propogated into server responses. The QR bit is set to one for queries, and zero for answers. The opcode has only three possible values (at this time):
0 A standard query
1 An inverse query
2 A server status request
Other values are reserved for future use
The AA bit specifies that the name server's answer is authoritative. The TC bit indicates that the message has been truncated (due to MTU length being exceeded, usually). The RD bit specifies that the query is a recursive one, that the name server should recursively query other name servers for the answer. The RA bit is set by a name server to indicate that it is willing to answer recursive queries. The Z field is reserved and currently MUST be zero. The Rcode value indicates an error condition from the responding server.
The remaining 'count' fields indicate the number of queries or answers present in the respective message fields.
Although some Directives (not resource records) will not be recognized by different (older) implementations. Also older implementations may not recognize certain resource records (such as the security records).
That is, the amount of time (in seconds) that remote name servers will cache data that this (the local) name server has sent them.
$TTL 7200
The $TTL is no longer specified in the SOA record (it used to be the 'negative answer' value).
[name] [ttl] [class] type data
Although not always (the $ORIGIN directive can be used to change it).
When names are specified they MUST start in column one of the text file.
bfs.cs.colorado.edu.cs.colorado.edu
Two other classes are CH and HS. CH was for a defunct ChaosNet project. HS was for a slightly less defunct database project called Hesiod. Both from MIT, as I recall..
Note well, though, that named will re-order all of your records based on a canonical ordering (mostly alphabetic). The sorted records only exist in the in-RAM version of the zone on your primary. The sorting is done to enable 'negative' responses using NXT records.
@ IN SOA cs.colorado.edu. admin.cs.colorado.edu. (
20010421 ; Serial Number
86400 ; Refresh - every 24 hours
1800 ; Retry - 30 minutes
1209600 ; Expire - 2 weeks
7200 ) ; Negative answers - 2 hours
Note that while the configuration file for the name server specifies the domain of origin (that is, the ORIGIN) for zone file that gets loaded, it can also be specified in the zone file itself. (To change what gets appended to unqualified hostnames, for example.
Note also (as stated above) that the FQDNs that are specified in the zone file MUST be terminated with a dot. If you do not terminate them with a dot, then the ORIGIN will get appended to the names, with results like:
cs.colorado.edu.cs.colorado.edu
20020403
2002040301
Whacked on the head means something like a massive failure or a system upgrade that fails. Basically, if the primary server is out for a week, DNS should still continue to function.
This is important to avoid silly conditions where a client queries for some A record that doesn't exist. The local name server didn't cache the non-existance of the record, so when the flailing client application repeatedly asks for the record, it happily sends the query out only to get back an negative answer again... negative answer caching was implemented to avoid this problem.
This is the master zone file for my own domain, xbalanque.net:
; start of authority record for xbalanque.net
$TTL 7200
@ IN SOA cs.colorado.edu. admin.cs.colorado.edu. (
20010421 ; Serial Number
86400 ; Refresh - every 24 hours
1800 ; Retry - 30 minutes
1209600 ; Expire - 2 weeks
7200 ) ; Negative answers - 2 hours
IN A 198.11.19.5
IN MX 10 @
IN NS cs.colorado.edu.
IN NS ns.village.org.
IN TXT "432 Gateway"
localhost IN A 127.0.0.1
coatlicue IN A 198.11.19.5
IN MX 10 @
IN HINFO "SPARCstation Classic" "OpenBSD 2.8"
ftp IN CNAME coatlicue www IN CNAME coatlicue mail IN CNAME coatlicue xibalba IN MX 10 @ xbalanque IN MX 10 @ feanor IN MX 10 @
Note that the ORIGIN (@) is 'xbalanque.net'. Note also that I have an NS record that points to an off-site name server (ns.village.org). You have to make sure that all of the FQDNs specified in the zone file are terminated with dots.
There are a bunch of hostnames (e.g. 'xibalba' and 'feanor') that don't have IP addresses (no A records) but are simple MX records that have the ORIGIN as there only preference. I do this so that, if by chance I send mail from one of those hosts and the reply goes back to it directly, then the mail will just get sent to my gateway host.
The primary name server for xbalanque.net is 'cs.colorado.edu' (I don't manage the zone from my home machine, I manage it from work :). This a case where none of the authoritative name servers for the zone actually resides in the zone!
Another thing to point out is that I do not have a reverse zone. The University's ITS department controls the reverse zone for the entire 198.11.19.0/24 subnet. It would be a major pain for them to delegate out single IP address reverse zones to each person who wanted a static IP address. As a result they maintain the PTR record for my IP address.
coatl % nslookup 198.11.19.5 Server: mroe-fs.cs.colorado.edu Address: 128.138.242.197
Name: coatlicue.Colorado.EDU Address: 198.11.19.5
I also run a stealth server inside my NAT'd home network. This server is not accessible from the outside world (which would be useless anyhow, because it resolves names for an RFC 1918 subnet!). Here is the Forward zone for my stealth server:
; start of authority record for xbalanque.net
$TTL 3600
$ORIGIN xbalanque.net. ; added for clarity
@ IN SOA xbalanque.net. tor.cs.colorado.edu. (
2001031300 ; Serial Number
7200 ; Refresh - check every 2 hours for now
1800 ; Retry - 30 minutes
604800 ; Expire - 1 week (was 2 weeks)
7200 ) ; Minimum - 2 hours for now
IN A 10.0.0.1
IN NS @
IN TXT "stealth DNS server for xbalanque.net"
localhost IN A 127.0.0.1
coatlicue IN A 10.0.0.1 coalticue IN CNAME coatlicue xibalba IN CNAME coatlicue www IN CNAME coatlicue quetzel IN A 10.0.0.3 xoxitl IN A 10.0.0.4 xbalanque IN CNAME coatlicue bunky IN CNAME coatlicue hunapu IN A 10.0.0.6 boonie IN CNAME hunapu home-eye IN A 10.0.0.7 judith IN A 10.0.0.32 mydhcp-33 IN A 10.0.0.33 feanor IN A 10.0.0.34 tala IN A 10.0.0.35 db-wired IN A 10.0.0.36 mydhcp-37 IN A 10.0.0.37 mydhcp-38 IN A 10.0.0.38 dbw IN A 10.0.0.39 db-wireless IN CNAME dbw mp3 IN A 10.0.0.40
$GENERATE 41-128 mydhcp-$ A 10.0.0.$ ; dhcp address
The only really interesting thing to point out is the $GENERATE directive. This is a like a FOREACH loop to generate similar resource records. The second field specifies the range of values. the 'name' 'type' and 'data' portions of the record are given. A single '$' dollar-sign get's replaced with each value in the range. (Use a backslash to escape the dollar-sign if you actually want one in your names. This particular loop generates Address Records that look like:
mydhcp-50 IN A 10.0.0.50
feanor % nslookup 10.0.0.50 Server: coatlicue.xbalanque.net Address: 10.0.0.1
Name: mydhcp-50.xbalanque.net Address: 10.0.0.50
The Internet class (IN) is implicit. Only a few records can be generated this way. Notably, NS, A, CNAME and PTR records can be.
Here is the Reverse zone file for my stealth server:
; start of authority record for xbalanque.net reverse zone
$TTL 3600
$ORIGIN 0.0.10.in-addr.arpa. ; added for clarity
@ IN SOA xbalanque.net. tor.cs.colorado.edu. (
2001031300 ; Serial Number
7200 ; Refresh - check every 2 hours for now
1800 ; Retry - 30 minutes
604800 ; Expire - 1 week (was 2 weeks)
7200 ) ; Minimum - 2 hours for now
IN NS xbalanque.net.
1 IN PTR coatlicue.xbalanque.net. 3 IN PTR quetzel.xbalanque.net. 4 IN PTR xoxitl-old.xbalanque.net. 6 IN PTR hunapu.xbalanque.net. 7 IN PTR home-eye.xbalanque.net. 32 IN PTR judith.xbalanque.net. 33 IN PTR mydhcp-33.xbalanque.net. 34 IN PTR feanor.xbalanque.net. 35 IN PTR tala.xbalanque.net. 36 IN PTR db-wired.xbalanque.net. 37 IN PTR mydhcp-37.xbalanque.net. 38 IN PTR mydhcp-38.xbalanque.net. 39 IN PTR dbw.xbalanque.net. 40 IN PTR mp3.xbalanque.net. $GENERATE 41-128 $ PTR mydhcp-$.xbalanque.net.
dig @server domain.name [record-type] [class]
coatl % dig @mroe-fs xbalanque.net soa
; <<>> DiG 8.3 <<>> @mroe-fs xbalanque.net soa
; (1 server found)
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1,
AUTHORITY: 2, ADDITIONAL: 2
;; QUERY SECTION:
;; xbalanque.net, type = SOA, class = IN
; ANSWER SECTION:
xbalanque.net. 2H IN SOA cs.colorado.edu.
hostmaster.cs.colorado.edu. (
20010421 ; serial
1D ; refresh
30M ; retry
2W ; expiry
2H ) ; minimum
;; AUTHORITY SECTION: xbalanque.net. 2H IN NS cs.colorado.edu. xbalanque.net. 2H IN NS ns.village.org.
;; ADDITIONAL SECTION: cs.colorado.edu. 2H IN A 128.138.243.151 ns.village.org. 8H IN A 204.144.255.51
;; Total query time: 2 msec ;; FROM: coatl to SERVER: mroe-fs 128.138.242.197 ;; WHEN: Wed Apr 3 13:42:45 2002 ;; MSG SIZE sent: 31 rcvd: 167
coatl %
Notice that dig shows you each seperate section of the DNS message as well as the records that were contained in that section. Dig, of course, supports lots of other options. Read the manual page that ships with bind for further details.
If you have an old or slow name server machine and you don't require the advanced features of Bind-9, you may want to just go with the newest Bind-8.
Bind 8 installs named into /usr/sbin. Bind 9 installs into /usr/local/sbin. Other utilitites will be in usual places below /usr or /usr/local (for bind8 or bind9 respectively).
Note that the above './configure' line is adequate for many setups, but it is NOT adequate if you need to use any advanced cryptographic features. In that case, you need to explicitely turn on use of OpenSSL (and make sure it is installed). In the example below, simply turning it on is sufficient for OpenBSD.
So, for example, I downloaded the current bind9 source (as of 1 April 2002 that was bind-9.2.1rc2 - rc=release candidate). Then I uncompress and untarred the archive, changed directories into it and ran the above commands:
coatlicue% tar -zxf bind-9.2.1rc2.tar.gz coatlicue% cd bind-9.2.1rc2 coatlicue% ./configure --with-openssl ... coatlicue% make ... coatlicue% sudo make install ...
Note that for openbsd, the default bind9 install is somewhat orthogonal to either bind8 or the default bind4 because bind9 installs into /usr/local. If you install bind8, then the default 'make install' will stomp on the existing bind4 installation. (I found that this was perfectly reasonable when I installed bind8, as I wanted nothing to do with bind4!)
rndc is the bind9 control utility. The bind8 version is called 'ndc'. Bind4 can only be minimally controlled using the 'kill' command and certain signals. Bind 8 & 9 also respond to signals sent with the kill command. See the documentation.
The default named.boot for OpenBSD lives in /var/named if you want to look at it or whatever.
This is also a configurable thing. Many sites run named in a 'chroot'd environment, which we look at below. The chrooted '/' would be /var/named, for example.
Bind8 also offers the '-g <group>' command line option. That option is not available in bind9 as it just uses the primary group of the named user specified with the -u option. Note also in Bind 9 that '-g' forces named to run in the foreground (i.e. not as a daemon) for debugging
As for any server daemon, you should take efforts to avoid running the daemon as 'root' or as any priviledged user. The reason is to forestall any possible exploit whereby the attacker gains shell or other access to the system through a bug in the daemon. Such bugs are bound to be discovered every now and then so it is vital to do everything you can to mitigate the potential damage that such an intrusion could wreak on your system(s). The next section is another general approach that is done as part of this sort of security strategy.
Look in /var/named on a stock OpenBSD system. This is the environment that named needs when its root is /var/named. For Solaris named's this directory would also probably have a 'usr' and a 'lib' directory populated with libraries and other things necessary for named to function.
For example, here is an 'ls -lR' of the default /var/named on an OpenBSD-3.0 system:
feanor % cd /var/ feanor % ls -lRa named total 380 drwxr-xr-x 5 root wheel 512 Feb 4 00:19 ./ drwxr-xr-x 24 root wheel 512 Oct 1 2001 ../ drwxr-xr-x 2 root wheel 512 Oct 18 14:24 dev/ drwxr-xr-x 2 root wheel 512 Oct 18 14:24 etc/ -r-xr-xr-x 1 root bin 176128 Oct 18 14:27 named-xfer* -rw-r--r-- 1 root wheel 822 Oct 18 14:24 named.boot drwxr-xr-x 2 named bin 512 Feb 4 00:19 namedb/
named/dev: total 4 drwxr-xr-x 2 root wheel 512 Oct 18 14:24 ./ drwxr-xr-x 5 root wheel 512 Feb 4 00:19 ../
named/etc: total 4 drwxr-xr-x 2 root wheel 512 Oct 18 14:24 ./ drwxr-xr-x 5 root wheel 512 Feb 4 00:19 ../
named/namedb: total 12 drwxr-xr-x 2 named bin 512 Feb 4 00:19 ./ drwxr-xr-x 5 root wheel 512 Feb 4 00:19 ../ -rw-r--r-- 1 named wheel 256 Oct 18 14:24 localhost.rev -rw-r--r-- 1 named wheel 2769 Oct 18 14:24 root.cache feanor %
Note that files and directories that 'named' needs to write are owned by the named user. The files in the namedb subdirectory are special. Both of them are necessary for ALL name servers. The first, 'localhost.rev', provides the in-addr.arpa reverse zone record for the localhost (127.0.0.0/8) zone. The second file, 'root.cache', is called the the 'hints' file and contains Address Records for the thirteen ROOT dns servers.
The executable, named-xfer, does what you might expect: it is used for transferring an entire zone from a remote server. It is almost always just invoked by named itself and not by hand (except for debugging).
For my bind8 installation, there are a few other things that I needed to provide in the chrooted environment. In /dev (that would be the real directory /var/named/dev, if you are following all of this :) There is a /dev/null device file as well as a unix pipe file used for loggining:
coatlicue% cd /var/named coatlicue% ls -l dev total 0 srw-rw-rw- 1 root wheel 0 Mar 6 09:51 log= crw-rw-rw- 1 root wheel 2, 2 Jul 15 2001 null
The /etc directory is also a bit more populated, although not much:
coatlicue% ls -l etc total 32 -r--r--r-- 1 root bin 877 Apr 28 2001 localtime -rw-r--r-- 1 root wheel 1075 Apr 3 14:35 named.conf -rw-r--r-- 1 root wheel 4438 Jul 15 2001 protocols -rw-r--r-- 1 root wheel 7764 Jul 15 2001 services
Note the 'named.conf' file. I like to keep my bind config file in the /var/named area for organizational reasons. I create a symlink in the real /etc that points to the config file:
coatlicue% ls -l /etc/named.conf
lrwxr-xr-x 1 root wheel 25 Jul 15 2001 /etc/named.conf@ ->
/var/named/etc/named.conf
Of course you should try to run a version of bind that is patched for all known exploits! The chroot should be insurance against future bug discoveries.
if [ -f /etc/named.conf -a \
-x /usr/local/sbin/named ]; then
/usr/local/sbin/named -t /var/named -u bind
fi
This would start the named server in /usr/local/sbin, presumably a bind9 server. The server would run as the user 'named' in the chrooted area below /var/named.
This command can propogate the 'start' and 'stop' args that a sysV runlevel script would receive. Actually, only bind8's 'ndc' command has the 'start' functionality right now. You have to start bind9 as indicated above for OpenBSD. The bind9 rndc utility does 'stop' named however. See below for more details.
This is the only way you can control Bind 4. There are other signals you can send. See the named manual page for more information. Note that Bind 9 responds to very few signals, SIGINT or SIGTERM to shut it down, SIGHUP to reload the config file.
By default it only listens to a Unix Pipe (/var/run/ndc). You use the 'controls' bind configuration statement to configure on exactly what Unix Pipe or TCP Socket named will listen for ndc. For TCP you can also configure which interface, port number (953 by default) and IP addresses will be allowed.
HMAC stands for Hash-based Message Authentication Code. The point is not to be able to un-uncrypt the secret at the other end, the point is that each end can derive the encrypted text on their own (because of the shared secret key) and compare that with the other end's.
We will look at the /etc/rndc.conf file in detail below under Bind Config.
stop stops named, duh ;)
stats dump stats to a file
reload [zone] reload zone files
status display server status info
There are a number of other commands, many common to both bind 8 and 9. The html web documentation that comes with bind describes their usage.
% rndc <options> <cmnd> [<cmnd>]
Options may be:
-c config specify an alternate config file
-s server specify an alternate server (than the
default server spec'd in the config file)
-p port specify an altenate port to connect to
-y key specify a key-id, def'd in config file
Again, we will see how to set up the /etc/rndc.conf file when we look at bind configuration in general, next. The two are of course very similar.
# Shell-style comments on a single line
// C++ style comments on a single line
/* C-style comments which may span
*
* multiple lines
*/
Note Well that the semi-colon ';' is NOT used for comments like it is in zone files.
That's why the semi-colon isn't used to introduce comments!
Here are all the statements used in the named.conf file. A basic setup could get away with using only the options and zone statements.
acl include options key trusted-keys server controls zone logging view
Before looking at the various configuration file statements it is important to understant the meaning and syntax of an Address Match List. This list just specifies a set of IP addresses or networks. Access Control Lists (acl) are just labeled versions of these lists.
acl <acl-id> {
! 1.2.3.4; 1.2.3/24; localhost;
};
Remember that address match lists are successful on a first-match basis, so order matters. In the above example, the negated host must occur before the allowed subnet.
Also, an ACL must be defined with an acl statement before it is used in the config file. The acl statement must be top-level (that is, not embedded within some other statement. For that reason, acl statements are usually made first at the top of the configuration file.
include "/path/to/file";
Of course, if you are not running a chrooted named, then the path is simply relative to the machines '/' root directory. You really should consider running a chrooted named instead!
The included file is simply added at the point of the include statement in the made config file (as you might expect). Obviously, the included configuration information MUST be syntactically correct for the point at which it is inserted into the configuration file.
For example, the global behavior for the nameserver can be configured to accept only NON-recursive queries (like a root nameserver does). Then, within specific zone statements, recursive-query acceptance can be turned on for specific subnets (using an ACL, eh?).
options {
version "we're not telling!";
directory "/";
};
The debate rages on over whether to set this to something else or not. The argument for changing it to something else (as shown above) is simply to avoid revealing information that might be of benefit to a hacker. The other side of the argument claims that ``security through obscurity'' is worthless and such tactics may harm legitimate attempts to map server types on the net. I personally tend to the former view, although I agree that security through obscurity is indeed not of much value. But it is definately not of NO value... whatevah
You can use 'dig' to query for the version string from a remote server. Here is the version information from my home stealth server:
feanor % dig @xbalanque.net version.bind txt chaos
; <<>> DiG 2.2 <<>> @xbalanque.net version.bind txt chaos ; (1 server found) ;; res options: init recurs defnam dnsrch ;; got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60927 ;; flags: qr aa rd ra; Ques: 1, Ans: 1, Auth: 0, Addit: 0 ;; QUESTIONS: ;; version.bind, type = TXT, class = CHAOS
;; ANSWERS: VERSION.BIND. 0 TXT "8.2.3-REL"
;; Total query time: 5 msec ;; FROM: feanor to SERVER: xbalanque.net 10.0.0.1 ;; WHEN: Mon Apr 8 11:27:02 2002 ;; MSG SIZE sent: 30 rcvd: 64
Here is the version information from the CS dept primary:
feanor % dig @cs.colorado.edu version.bind txt chaos
; <<>> DiG 2.2 <<>> @cs.colorado.edu version.bind txt chaos ; (1 server found) ;; res options: init recurs defnam dnsrch ;; got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65000 ;; flags: qr aa rd ra; Ques: 1, Ans: 1, Auth: 0, Addit: 0 ;; QUESTIONS: ;; version.bind, type = TXT, class = CHAOS
;; ANSWERS: VERSION.BIND. 0 TXT "wouldn't you like to know..."
;; Total query time: 39 msec ;; FROM: feanor to SERVER: cs.colorado.edu 128.138.243.151 ;; WHEN: Mon Apr 8 11:28:42 2002 ;; MSG SIZE sent: 30 rcvd: 83
The default is to simply remain in the invocation directory, where ever that may be.
Or use the correct path for your dns zone files, whatever that is.
options {
. . .
notify yes;
also-notify { IP1 port 1053; IP2; };
allow-notify { acl_id1; };
};
You need to explicitely turn it on for Bind 8. This causes the primary to notify secondaries when they need to reload zone information (because the serial number of the zone's SOA record has changed.) Bind 9 servers may need to turn notify OFF for specific secondaries that are known to not support asynchronous notifications. (This would be done on a per-server basis using the 'server' statement.)
Because stealth servers don't have NS records pointing at them, you need to tell the primary server to send notifications to them by using the 'also-notify' clause. Assuming of course that you want your stealth servers to have current DNS zone information...
This statement is typically used when a there are several tiers of nameservers at a site. Third tier nameservers will load their zone data from a second tier of secondary nameservers. This is where you need to tell the third tier nameservers to allow notifications from the second tier secondaries. The second tier nameservers don't need this clause because they will be transferring their zone data directly from the primary (i.e. the first tier).
options {
. . .
recursion yes; // this is the default
allow-recursion { acl_id2; };
};
Sites might disable normal query service for queries that come from off site. The theory is that those off-site queries really ought to be going to some nameserver that is local to the query source (i.e. that person's ISP). Recursion is then re-enabled for specific local networks.
options {
. . .
listen-on [port NN] { acl_id3; };
query-source [ address * ] [ port * ];
};
The default is the 'domain' port from /etc/services, port 53. Change this value only when you have a good reason to. Nameserver may change the port numbers they query from and listen to for talking with specific other nameservers, which can allow a more restrictive firewall perhaps.
You may specify the IP address of the interface. Perhaps this is only the local host interface, 127.0.0.1 (you might be able to just type the word 'localhost', but I'm not sure).
listen-on { 127.0.0.1; };
You can also specify a CIDR block for a local subnet, and named will just pick the interface with the relevant address. For my home stealth-server, I could do something like this:
listen on { 10.0.0/24; };
By default it just picks a random high-numbered UDP port and uses that. You can restrict to something like '53' or '1053' to allow for a more restrictive firewall, for example.
options {
. . .
forwarders { IP1; IP2; ... };
forward only; // or first
};
Note that this violates the normal DNS behavior for the local nameservers that contact the forwarders. They always contact the forwarders to resolve names (for which they are not authoritative already), instead of resolving the names themselves (e.g. by contacting the root server and following the referals.)
Be careful that the forwarders aren't themselves forwarders, or at least be careful to avoid forwarding LOOPS!
The default is 'forward first' which allows the nameserver to default back to normal DNS behavior if its forwarders are unreachable.
options {
. . .
allow-query { acl_id4 };
allow-transfer { acl_id5; };
blackhole { acl_id6; };
};
Note that all other query sources get an error message returned to them, stating that such service is disabled.
This option is becoming increasingly important to utilize as hackers take and abuse as much information as they can get their hot little hands on! Disabling zone-transfers except from specific other nameservers makes their job of mapping your network significantly harder than a simple data transfer process.
This is different from the behavior of hosts not in the 'allow-query' set. Blackholed hosts don't receive any notification for lack-of-service, they completely ignored, their packets dropped into the bit-bucket..
key key_id {
algorithm hmac-md5; // the only alg
secret "XYZZY";
};
The secret is an UNencrypted BASE-64 encoded binary string. The algorithm choice is currently only 'hmac-md5'. The 'key_id' is an arbitrary label for the key.
And they must be top-level statements in the configuration file.
Typically, the key statements are kept in seperate files that can have restrictive (0400) unix file permissions. Those files are then sucked into the main config file with 'include' statements.
We will see below several different ways that keys are used by bind 9.
trusted-keys {
domain flags protocol algorithm key;
. . .
};
server IP_ADDR {
option1 .. ;
option2 .. ;
};
The point is that you specify specific options that change your server's interaction with the specified server. In general, of course, you only specify those options that change the behavior from the global default for your server.
We will look at an example of setting up shared-secret keys when we look at TSIG, one of the newer DNS security features.
Or it configures access for 'ndc' if you are using Bind 8.
controls {
inet IP_ADDR [port N] allow { acl_id8 }
keys { key_id1; key_id2; };
};
Replicated here for your viewing pleasure:
key key_id {
algorithm hmac-md5; // the only alg
secret "XYZZY";
};
options {
default-server localhost;
default-key key_id;
};
zone "domain_name" {
type master; // or slave
file "path/to/zone/file";
};
Other possible types are: 'stub', 'forward', and 'hint'
zone "." {
type hint;
file "path/to/hints/file";
};
zone "0.0.127.in-addr.arpa" {
type master;
file "localhost";
notify no;
};
view "view_name" {
. . .
};
For example, a site may want to present one set of data to its internal clients and a different (sanitized) set of data to external clients. Small private networks can make use of views in a big way by presenting full DNS information inside the network pertaining to the private addresses used on the network (one view). The server, for the same zone, can present different data records to the outside world (an external view), which is important when most internal hosts are not reachable on the net anyway.
The categories are pre-defined in the Bind source. There are about 20. There is a list of categories given in TPB (page 472). This list can also be found in the Bind Administrator Reference Manual. Categories range from 'os' for Operating System related problems to 'xfer-in' for messages relating to incoming zone transfers.
logging {
<channel-definition-1>;
<channel-definition-2>;
. . .
category <category-a> {
<channel-name-1>;
. . .
};
category <category-b> {
<channel-name-2>;
. . .
};
. . .
};
channel <channel-name> {
file /file/path [versions N | unlimited] [size M];
syslog <facility>;
severity <severity>;
print-category yes; // or no
print-severity yes; // or no
print-time yes; // or no
};
default_syslog logs with facility 'daemon'
and severity 'info' and worse
default_debug logs to a file called 'named.run'
with 'dynamic' severity
logging {
category default { default_syslog; default_debug; };
};
Here is the configuration for my current home network stealth server. This server is version 8.2.3. I am in *slightly* less haste to upgrade the server because it doesn't listen to queries from the Internet.
/* * named master conf file for xbalanque.net * * stealth server for a private network * * RCS: $Id: dns.pmp,v 1.4 2003/03/26 19:19:20 tor Exp tor $ */
options {
directory "/";
pid-file "/named.pid";
listen-on { 10.0.0.1; 127.0.0.1; };
forward first;
forwarders { 128.138.129.76; 128.138.243.151; };
query-source port 1053;
};
zone "xbalanque.net" {
type master;
file "xbalanque.forward";
allow-transfer { 10.0.0.5; };
};
zone "0.0.10.in-addr.arpa" {
type master;
file "xbalanque.reverse";
};
zone "." {
type hint;
file "cache.db";
};
zone "0.0.127.in-addr.arpa" {
type master;
file "localhost";
notify no;
};
logging {
channel syslog_info {
syslog local3;
severity info;
};
channel syslog_tor {
syslog local1;
severity info;
};
channel no_info_messages {
syslog local2;
severity notice;
};
category parser { syslog_tor; };
category security { syslog_tor; };
category load { no_info_messages; };
category lame-servers { no_info_messages; };
category default { syslog_info; };
};
I plan to upgrade to Bind 9 soon, and use 'view' statements to present 10.0-net data inside and real xbalanque.net data outside. The internal view will be a primary server for the zone, while the external view will be a secondary server (the real primary is cs.colorado.edu).
The CS department currently runs to separate nameserver processes to facilitate the 'views' concept (they are Bind 8 servers, so no 'view' statement). Yes, we plan to upgrade soon... Here is the current config file for the external server:
//
// ACL's
acl CUnets {
128.138/16; 198.11.16/24; 204.228.69/24; 127.0.0.1;
};
acl rfc1597 {
10/8; 172.16/12; 192.168/16;
};
//
// Global options
options {
version "wouldn't you like to know...";
directory "/";
pid-file "/named-external.pid";
named-xfer "/named-xfer";
notify yes;
/*
* Since this daemon serves external hosts we bind to the
* external address, 128.138.243.151.
*/
listen-on { 128.138.243.151; };
transfer-source 128.138.243.151;
/*
* If there is a firewall between you and nameservers you want
* to talk to, you might need to uncomment the query-source
* directive below. Previous versions of BIND always asked
* questions using port 53, but BIND 8.1 uses an unprivileged
* port by default.
*/
query-source address 128.138.243.151 port 53;
/*
* Choose local name servers over off-site ones.
*/
topology {
localhost;
localnets;
CUnets;
};
/*
* Don't listen to known broken nameservers
*/
blackhole {
209.234.73.115;
209.234.73.116;
209.234.73.117;
209.234.73.118;
};
};
//
// Logging
logging {
// We want syslog stuff to go to local3
channel syslog_info {
syslog local3;
severity info;
};
// We don't care about people's broken name servers
category lame-servers { null; };
// Use syslog_info channel unless we get a more specific match
category default { syslog_info; };
};
//
// Root servers cache
zone "." in {
type hint;
file "named.cache";
};
// // Primaries //
//
// localhost
zone "0.0.127.in-addr.arpa" in {
type master;
notify no;
file "localhost";
};
//
// CS
zone "cs.colorado.edu" in {
type master;
file "forward-external/cs.colorado.edu";
};
//
// CS reverse records (128.138.X.X)
zone "245.138.128.in-addr.arpa" in {
type master;
file "reverse/245.138.128";
};
zone "244.138.128.in-addr.arpa" in {
type master;
file "reverse/244.138.128";
};
// ... many other reverse zones edited out ...
//
// catbelly.com for garnett (garnett@catbelly.com)
zone "catbelly.com" in {
type master;
file "catbelly/catbelly.com";
};
//
// xbalanque.net for tor (tor@xbalanque.net)
zone "xbalanque.net" in {
type master;
file "xbalanque/xbalanque.net";
};
// ... other zones for which we are primary deleted ...
// // Secondaries //
//
// colorado.edu top level
zone "colorado.edu" in {
type slave;
file "secondary/colorado.edu";
allow-transfer { none; };
masters {
128.138.240.1;
128.138.238.18;
};
};
// ... other zones for which we are secondary deleted (about 50) ...
You can see that the CS department primary nameserver has a lot of duties! We are primary for a dozen or more different domains (like mine) and secondary for many dozens more.
% dnssec-keygen -a hmac-md5 -b 128 -n HOST hostA-hostB
Note that this host key has NO relationship with an SSH host key whatsoever. They are entirely different beasts!
Typically, the key is named for and stored in a file that contains both of the hostnames for which the key will be used. That is, if the key will be used to authenticate transactions between host A and host B, then the keyfile name should be ``hostA-hostB'' or something to that effect.
coatlicue% dnssec-keygen -a hmac-md5 -b 128 -n HOST hostA-hostB Khosta-hostb.+157+03361
For the above example, here are the contents of the two files:
coatlicue% cat Khosta-hostb.+157+03361.key hostA-hostB. IN KEY 512 3 157 EPsVoeqIeY0JAd3F/tyXLQ==
coatlicue% cat Khosta-hostb.+157+03361.private Private-key-format: v1.2 Algorithm: 157 (HMAC_MD5) Key: EPsVoeqIeY0JAd3F/tyXLQ==
Note that even though dnssec-keygen produces two key files, the keys are the same in each file. These are NOT a private/public keypair. The dnssec-keygen IS also capable of generating such keys, as we will see below under DNSSEC.
key hostA-hostB. {
algorithm hmac-md5;
secret "EPsVoeqIeY0JAd3F/tyXLQ==";
};
Here is what a 'controls' statement might look like that uses the above defined key:
controls {
inet IP_ADDR allow { localhost; }
keys { hostA-hostB.; };
};
Here is what a complete /etc/rndc.conf file might look like:
key hostA-hostB. {
algorithm hmac-md5;
secret "EPsVoeqIeY0JAd3F/tyXLQ==";
};
options {
default-server localhost;
default-key hostA-hostB.;
};
The point is to 'authenticate' the data, not to encrypt it. DNS is, by definition 'public' data; there may be a conceivable need to encrypt DNS data, but not in general. TSIG generates a checksum of the data being being transmitted incorporating the secret key at the same time. This value can ONLY be generated or verified by someone who also has a copy of the same secret key. In this way, the data can be verfied as authentic.
server hostB-IP-addr {
keys { hostA-hostB.; };
};
server hostA-IP-addr {
keys { hostA-hostB.; };
};
zone mydomain.com {
type master;
file "mydomain.com-forward";
allow-transfer { key hostA-hostB.; };
};
Because IP addresses can be spoofed more easily than secret keys!
Updaters may also modify (and add or delete) Resource Record sets (RRsets) which are groups of resource records that share the same name, class and type. That is, the same domain name (like www.yahoo.com) can map to multiple A records; all the host's A records taken together comprise an RRset. Such groups are allways returned together as the result of a query for that hostname: there is no way to get only one of the records. Typically (by default) these records are always returned in a round-robin fashion, rotating which record gets returned first for each answer.
Obviously this is an unsafe method as IP address may be easily spoofed (especially by someone who already has access to you local networks.
Clearly this is a superior method, although it doesn't protect against compromised servers. Nor does it handle an authenticated server that is itself simply 'forwarding' a zone update to the master. Finally, TSIG can really only be used in local scenarios under you control, due to the non-scalability of TSIG's reliance on shared-secrets.
Typically, the journal file is named after the zone file with '.jrn' appended to it.
And, of course, when you halt the server in a graceful way (with the rndc stop command or using the SIGTERM signal).
Both 'nsupdate' and version 3 of the ISC dhcpd server are capable of using TSIG for authenticating updates.
This is important as it protects your primary zone's data integrity - you wouldn't want an updater (maliciously or not) to change the records for you webserver, for example!
zone dyn.xbalanque.net {
. . .
allow-update { acl_id1; acl_id2; };
};
. . .
allow-update { key dhcpd_key; };
. . .
That is, from an updater like 'nsupdate' or 'dhcpd'.
Note that the key name is not required - if it is not specified, no matches will be made in any policy rules, as they require a key. That is, if you specify a key-name for the identity. You can simply specify an IP address or hostname here if you really insist..
record(s) being updated
grant|deny identity nametype name [types];
It should be named for the domain-name of the updater, in most cases.
There are four possibilities for the nametype field:
name
'name' means that the domain-name being updated must be the same as the name specified in the name field of the policy-rule.
subdomain
'subdomain' means that the domain-name being updated must be a proper subdomain of the name in the name field of the policy-rule. Note that the domain-name being updated must still be legally within the authority of the dynamic zone!
wildcard
'wildcard' means that the domain-name being updated must match the wildcard expression in the name field of the policy-rule.
self
'self' is slightly different: the domain-name being updated must be the same as the name in the 'identity' field! This means that the name of the key (i.e. the contents of the identity field) must be the same as the domain-name - obviously..
Here is an example bind config file for a dynamic zone in the CS department called 'vpn.cs.colorado.edu' that is used for offsite VPN presence. The updaters are shell scripts wrapped around the 'nsupdate' command.
// Nameservice config file for CS VPNs
options {
version "wouldn't you like to know...";
directory "/local/namedb";
notify yes;
};
zone "." {
type hint;
file "named.root";
};
zone "vpn.cs.colorado.edu" {
type master;
file "vpn.cs.colorado.edu";
update-policy {
grant *.vpn.cs.colorado.edu. self *.vpn.cs.colorado.edu. A;
};
};
include "named.keys";
The following example is lifted directly from the v3 dhcpd.conf manual page. The example illustrates the config bits for the dhcp server when it is running on the same machine as the nameserver. Additionally, the dhcpd server will request updates for both A and PTR records because both zones are defined in the config file.
key DHCP_UPDATER {
algorithm HMAC-MD5.SIG-ALG.REG.INT;
secret pRP5FapFoJ95JEL06sv4PQ==;
};
zone EXAMPLE.ORG. {
primary 127.0.0.1;
key DHCP_UPDATER;
}
zone 17.127.10.in-addr.arpa. {
primary 127.0.0.1;
key DHCP_UPDATER;
}
Note also that the 'loggin' statement has been removed for clarity.
acl my_net {
10.0.0.0/24;
};
acl off_site {
!10.0.0.0/24; any; localhost;
};
/* mroe.cs.colorado.edu is the
* real primary for xbalanque.net
*/
acl mroe {
128.138.243.151;
};
options {
// we're starting in a chrooted area
directory "/";
pid-file "/named.pid";
// disabling forwarders to build a big local cache:
// forwarders { "mroe"; 128.138.129.76; };
// forward first;
// specific query source for the firewall
query-source port 1053;
// disabling recursion in general
recursion no;
};
view "internal" {
match-clients { "my_net"; };
recursion yes;
zone "xbalanque.net" {
type master;
file "xbalanque.forward";
};
zone "0.0.10.in-addr.arpa" {
type master;
file "xbalanque.reverse";
};
zone "." {
type hint;
file "cache.db";
};
zone "0.0.127.in-addr.arpa" {
type master;
file "localhost";
notify no;
};
};
view "external" {
match-clients { "off-site"; };
zone "xbalanque.net" {
type secondary;
file "xbalanque.fwd.external"; // cache file
masters { "mroe"; };
};
// the real reverse zone is admin'd by colorado.edu
zone "." {
type hint;
file "cache.db";
};
zone "0.0.127.in-addr.arpa" {
type master;
file "localhost";
notify no;
};
};
Without being able to verify the source of the data, the integrity of it is irrelevant, because the source provides the signitures that verify the integrity. If the source is unknown, then all bets are off.
Confidentiality CAN be done, but Bind 9 doesn't use it, on the theory that the data is public. The point is to be able RELY on the public data.
We'll look at how that works below.
% dnssec-keygen -a RSA -b 512 -n ZONE xbalanque.net. Kxbalanque.net.+001+53599
Recall that the algorithm is the middle (001) number, while the last number is fingerprint of the key. Also recall that two files are generated, and this time it makes more sense.
coatlicue% ls Kxbalanque.net.* Kxbalanque.net.+001+53599.key Kxbalanque.net.+001+53599.private
The public '.key' file, as mentioned above, is a DNS KEY Resource Record. Here is what it looks like (the file has ONE line in it, it is split apart for readability).
coatlicue% cat Kxbalanque.net.+001+53599.key
xbalanque.net. IN KEY 256 3 1 AQPjRG1hINd3E7sw/F
/cM4B2ZDOM+GWQoxeRLucwjLhin8TLdo552YjB
wAXTllDUbbpfljIS7JeY5TGcyMUK0V/F
The name of the key is the 'domain name' for the KEY record. The class as usual is IN for Internet. The type, of course, is KEY. The remaining four values in the record are 'flags', 'protocol', 'algorithm' and 'key'. The flags field is a 16-bit value that designates the type of key and the uses for which the key is suitable (e.g. authentication, confidentiality). The 'protocol' field, 8 bits, designates the key use. A protocol value of '3' indicates DNSSEC. Other key uses might be IPsec or TLS. The 'algorithm' field value of '1' indicates that RSA is the algorithm. (You'll see a '3' for DSA). The 'key' field is public key.
% dnssec-makekeyset -t 172800 \
Kxbalanque.net.+001+53599.key
keyset-xbalanque.net.
coatlicue% cat keyset-xbalanque.net.
$ORIGIN .
$TTL 172800 ; 2 days
xbalanque.net IN KEY 256 3 1 (
AQPjRG1hINd3E7sw/F/cM4B2ZDOM+GWQoxeRLucwjLhi
n8TLdo552YjBwAXTllDUbbpfljIS7JeY5TGcyMUK0V/F
) ; key id = 53599
SIG KEY 1 2 172800 20020510193643 (
20020410193643 53599 xbalanque.net.
A4cZvEo9IynJo/K7GzEE1OsaIr1BkCXFx3SSjoBLVf1F
vZfn+FU50Dvttgozfw6GY8mu7biVTjJ8nnlo9xiQ/w== )
If you can.. The secure method of transfer is necessary until the root and TLD zones start signing child zone keys. When that happens, less paranoid methods may potentially employed. Although in the case of the initial signing of a child zone by its parent, some secure method of getting the child's public key to the parent is still necessary.
In the example above, a KEY record is being signed and the algorithm is '1' or RSA. I have no idea what the '2' represents, that follows the algorithm number. I'll look into it... oh no, wait. It is the 'labels' field, and it indicates how many labels are in the name of the SIG record. For 'xbalanque.net.' we have two labels and thus the number two appears.
These are the next three numbers (172800 20020510193643 20020410193643). The validity end and start (in that order) times have a format of yyyymmddhhssss. The TTL is of course in seconds (172800 is two days).
The number following these values (53599, above) is the key's fingerprint.
% dnssec-signkey keyset-xbalanque.net \
Knet.+001+12345.private
That is obviously a fake example..
$INCLUDE Kxbalanque.net.+001+53599.key
i.e. by using the 'trusted-keys' statement
trusted-keys {
domain flags protocol algorithm key;
. . .
};
Which is of course, usually the name of the keyfile base too.
For the key we generated above, they would be 256, 3, & 1, respectively.
% cd /var/named % dnssec-signzone -o xbalanque.net xbalanque.fwd xbalanque.fwd.signed
If it exists in the current directory. You may also specify private key(s)
as additional arguments on the command line (after the zone file).
; File written on Wed Apr 10 15:18:22 2002
; dnssec_signzone version 9.2.1rc2
xbalanque.net. 3600 IN SOA xbalanque.net. tor.cs.colorado.edu. (
2001031300 ; serial
7200 ; refresh (2 hours)
1800 ; retry (30 minutes)
604800 ; expire (1 week)
7200 ; minimum (2 hours)
)
3600 SIG SOA 1 2 3600 20020510211822 (
20020410211822 53599 xbalanque.net.
ueU49qSRlEsyC3pK4FjD0oHiQPGbn92KtIfN
uhfPljKJpJbAy6lZCYHtBS1IdP3GnSz0/lSt
oFp+vD/4MUAX4A== )
3600 NS xbalanque.net.
3600 SIG NS 1 2 3600 20020510211822 (
20020410211822 53599 xbalanque.net.
sbq/63PxSKWaCHfC/H7OFb/t9n6cIku6i7wg
X0ypxbGmsPJMi02GKerecnOv5o45p/aXppWu
Pwemkzopp1Xk6g== )
3600 A 10.0.0.1
3600 SIG A 1 2 3600 20020510211822 (
20020410211822 53599 xbalanque.net.
ZkviPvqc4zfNWSRsBFttXrYV6E3hkYtO3hOo
OmcgDciqetTNC5RUr6suZPUcC5uQ1x76whIQ
J1fHC9RrFgoVTA== )
3600 TXT "stealth DNS server for xbalanque.net"
3600 SIG TXT 1 2 3600 20020510211822 (
20020410211822 53599 xbalanque.net.
HnxatPQJ8XPYxaAe1btjyso1NE+mtZKXTcVi
uKZANzE3yOsnUYxPuPBsqsUxR+fKdRxAuX5u
ceVGQUpsehjoeA== )
3600 KEY 256 3 1 (
AQPjRG1hINd3E7sw/F/cM4B2ZDOM+GWQoxeR
LucwjLhin8TLdo552YjBwAXTllDUbbpfljIS
7JeY5TGcyMUK0V/F
) ; key id = 53599
3600 NXT boonie.xbalanque.net. A NS SOA TXT SIG KEY NXT
3600 SIG NXT 1 2 3600 20020510211822 (
20020410211822 53599 xbalanque.net.
FMZcmL8agk+nD1wVjcsNcLe5qc9wM5nJ0ZcD
56f42fsj6Dq/frFEg2EuqZ35cWFkimBQHbXS
Jp264fmPOHSPQQ== )
boonie.xbalanque.net. 3600 IN CNAME hunapu.xbalanque.net.
3600 SIG CNAME 1 3 3600 20020510211822 (
20020410211822 53599 xbalanque.net.
SHIUy5UIb0yIBB+hO5o8+j/rMRAOv8k0uD+6
QtgyoXaj6oUq6LODHY2r5YOHBy9M/fktLcXb
wtz4GDqie5m/oQ== )
3600 NXT bunky.xbalanque.net. CNAME SIG NXT
3600 SIG NXT 1 3 3600 20020510211822 (
20020410211822 53599 xbalanque.net.
sNTRT4OBueAph+P4rlJzQ7Bk1C3F74n1hmXJ
fFk+AM4Cs2YLdVxX8CAc4VvXjViGO+tJyNjZ
So, if a remote server received signed records like those above, it MUST already have the public key that was used to sign them in a 'trusted-keys' statement. Using that public key, the records can be authenticated. Until the 'chain of trust' is set up and the root servers sign the child zone keys and so on, the only way to guarantee authenticity is to securely obtain public keys from the servers you want to get authentic data from and install them into your own server.
Also take note of the NXT records, above. The NXT record is used to respond in the negative for some query. If, for example, a host B doesn't exist, then a query for B's address would return a NXT record. The record that gets returned is the NXT record that specifies where the record would have been if it were to exist (this is based on the canonical ordering of the zone data. So, if Hosts A and C exist, but B does not as we have already stated, then a NXT record like this might be returned:
host-A 3600 IN NXT host-C
The record indicates that host-B doesn't exist, based on the canonical ordering.