.. include:: /shared/substitution.rst Configure BIND DNS =================== This part is focused to get |bind| to work as a master nameserver, dnssec doesn't get setup for the moment but it will be added later! Before starting to configure things it's time to point out some good measures and pitfalls. .. note:: **FreeBSD specific stuff** after the packages got installed the configuration will be under |nameddir|. Enable and start |bind| for the first time --------------------------------------------- So first things first, let's enable |bind|, so it will start up on boot time. After this |bind| will create some directories and files we need or simply going to rename/remove in the process. .. code-block:: bash :caption: enable bind service and start it # sysrc named_enable=YES named_enable: NO -> YES # service named start Starting named. # service named status named is running as pid 71596. At this point named should be up and running but a few changes need to be made before it can act as a dns master. So let's stop the service for now and continue with preperations. .. code-block:: bash :caption: Stop the service # service named stop .. hint:: the name for |bind| in the system is named so we enable, start, restart or stop the service with the name :code:`named`! Setting up file and folder structure ---------------------------------------- The default installation will place a :code:`primary` folder in |nameddir| but since this is a master and master zone lets rename it to master. .. code-block:: bash # cd /usr/local/etc/named # mv ./primary ./master Also rename the :code:`working` directory to :code:`workdir`. .. code-block:: bash # mv ./working ./workdir Next create a directory for the zone, its good practice to name it like the domain. .. code-block:: bash # mkdir ./master/yourdomain.tld Create a rndc.conf file --------------------------- Every change made to the zones need to be updated in |bind|, to communicate with |bind| the rndc tool will be used. The tool communicates over TCP/IP with |bind| so a secure way has to be setup to do so. First generate a configuration for rndc. .. code-block:: bash :caption: create the actual rndc.conf file # rndc-confgen This will generate a file called :code:`rndc.conf` in |nameddir| with the following content. .. code-block:: bash :caption: the content of the created rndc.conf file # less /usr/local/etc/namedb/rndc.conf key "rndc-key" { algorithm hmac-sha256; secret "your_very_secret_key"; }; options { default-key "rndc-key"; default-server your_server_ip; default-port 953; }; .. note:: The values in the example are not the one created by rndc-confgen! The key is used in |namedconf| to enable |bind| to accept commands from the rndc tool. Create a zone file ------------------- At this point the zone file can be created and the needed informations can be added. As before, with the directory, the zone file is named like the domain. .. code-block:: bash # touch ./master/yourdomain.tld/yourdomain.tld Now there should be a file named :code:`yourdomain.tld` in a directory :code:`yourdomain.tld` under :code:`/usr/local/etc/namedb/master`. .. code-block:: bash # vi ./master/youdomain.tld/yourdomain.tld .. code-block:: vim :caption: content of the zone file, the bare minimum to run a zone ... $ORIGIN . $TTL 3600 ; 1 hour yourdomain.tld IN SOA ns1.he.net. you.yourdomain.tld. ( 3000300 ; serial 14400 ; refresh (4 hours) 3600 ; retry (1 hour) 3600000 ; expire (5 weeks 6 days 16 hours) 3600 ; minimum (1 hour) ) NS ns1.he.net. NS ns2.he.net. NS ns3.he.net. NS ns4.he.net. NS ns5.he.net. NS ns2.afraid.org. A your_server_ip $ORIGIN yourdomain.tld. your_server_name IN A your_server_ip ;you don't need the next line but usally someone wants to run a webpage too www IN CNAME your_server_name .. note:: comments in a zone file are started with a :code:`;` So lets break down the content just a little, most of the following notes can be found in the |bind| documentation too but for good measure let's point them out anyway. .. code-block:: vim $ORIGIN . . . . $ORIGIN yourdomain.tld. The :code:`$ORIGIN` keyword acts as a substitution for the string that follows the definition on that line. So that it won't be necessary to write the string in all subsequencial entries. So instead of writing .. code:: www.yourdomain.tld. IN CNAME your_server_name It's possible to write the following in our zone definition. .. code:: www IN CNAME your_server_name The next keword is :code:`$TTL` and should be pretty easy to understand, it defines the time to live for a record and is a value in seconds. .. code:: $TTL 3600 ; 1 hour The last line is the so called |soa| record and it stands for :code:`Start Of Authority`. It has a few arguments that define how records for this authoritive zone should be handled. The RFC 1035 defines the SOA record data as followed. .. code-block:: vim +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / MNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / RNAME / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | SERIAL | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | REFRESH | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | RETRY | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | EXPIRE | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | MINIMUM | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ .. raw:: latex \newpage And this translates to the values in the zone file as shown below. .. code-block:: vim +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ yourdomain.tld IN SOA / ns1.he.net. / you.yourdomain.tld. / ( / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | | 3000300 | +--+--+--+--+--+--+ | 14400 | | | +--+--+--+--+--+--+ | 3600 | | | +--+--+--+--+--+--+ | 3600000 | | | +--+--+--+--+--+--+ | 3600 | | | +--+--+--+--+--+--+ ) Since the RFC isn't really pointing out the brackets, that enclose the values from serial to minimum, it's possible that it's just a way for the configuration parser to determine that the values belong to the values from the previous line. To get an explaination for every value you can take a look at `RFC 1035 `_ . This record is important for zone transfers to other namservers! .. important:: the serial needs to be increase on every change that is made to the zone file!!! The next entries under the SOA records are the name servers that will serve dns data for the zone when clients query for data. .. code-block:: bash NS ns1.he.net. NS ns2.he.net. NS ns3.he.net. NS ns4.he.net. NS ns5.he.net. NS ns2.afraid.org. Later we create slave zones on those servers so redundance is provided for our zone. The last entry for the SOA record is the :code:`A` record for our own server. .. code-block:: bash A your_server_ip With this entry we associate :code:`yourdomain.tld.` with :code:`your_server_ip` so we can do a lookup. .. note:: We don't have a MX record under the SOA record, this is because we don't have a MTA setup for now. At this point the authoritive part of the zone file is done and it's time to add the next records for our zone. Again the :code:`$ORIGIN` is defined first to ease the part of defining the records. The pattern is also the same as before the only difference is that there are no values like on the |soa| record. .. code-block:: vim $ORIGIN yourdomain.tld. your_server_name IN A your_server_ip ;you don't need the next line but usally someone wants to run a webpage too www IN CNAME your_server_name With this minimal zone file in place it's time to move on to confiure the zone in |namedconf|. Configure |namedconf| to use the zone file ------------------------------------------- .. note:: named.conf is only shown partly in this section! First of let's add the :code:`rndc key` so it's possible to issue commands to |bind| from the :code:`rndc cli tool`. .. code-block:: vim :caption: named.conf - rndc key key "rndc-key" { algorithm hmac-sha256; secret "your_very_secret_key; }; The next directive is necessary to define what servers or keys can control the configuration of |bind|. Bind will listen on tcp port 953 on the external ipv4 address followed by a list of the allowed servers and keys. .. code-block:: vim :caption: named.conf - controls controls { inet your_server_ip port 953 allow {your_server_ip; 127.0.0.1; 69.65.50.192; keys { "rndc-key"; }; }; Next setup are a few access control lists, those are needed to declare what servers can issue normal or recursive queries to our server. .. note:: acl is a convinient way to substitute a list of servers so DRY can be applied to declare access to those servers. .. code-block:: vim :caption: named.conf - acl acl bogon { 0.0.0.0/8; // Null address 1.0.0.0/8; // IANA reserved, popular fakes 2.0.0.0/8; 192.0.2.0/24; // Test address 224.0.0.0/3; // Multicast address }; acl hurricane_slaves { // This fetches from my master server 216.218.133.2; // slave.dns.he.net 2001:470:600::2; // This will do all zone transfers from our stealth master }; acl hurricane_all_servers { // ALL Hurricane server 216.218.130.2; // ns1.he.net - We send notify to this and use it in our SOA 2001:470:100::2; // ns1.he.net 216.218.131.2; // ns2.he.net - A slave answering for my domain 2001:470:200::2; // ns2.he.net 216.218.132.2; // ns3.he.net 2001:470:300::2; // ns3.he.net 216.66.1.2; // ns4.he.net 2001:470:400::2; // ns4.he.net 216.66.80.18; // ns5.he.net 2001:470:500::2; // ns5.he.net 216.218.133.2; // slave.dns.he.net 2001:470:600::2; // This will do all zone transfers from our stealth master }; acl afraid_servers { 69.65.50.192; 2001:1850:1:5:800::6b; }; acl internal_nets { 10.0.0.0/8; 172.16.0.0/12; 192.168.0.0/16; 2001:470:dc5d::/48; 2001:470:28:10c::/64; 82.182.181.104/31; 155.4.8.28/32; }; In the :code:`option` part some files and directories are defined that are needed to run |bind|. The more important part, working torward more security, are the the :code:`allow-` options. These options define what servers can query |bind| for zone related information. .. code-block:: vim :caption: named.conf - options options { directory "/usr/local/etc/namedb/workdir"; pid-file "/var/run/named/pid"; dump-file "/var/dump/named_dump.db"; statistics-file "/var/stats/named.stats"; listen-on port 53 { any; }; //listen-on-v6 { ::1; }; allow-query { localhost; internal_nets; hurricane_all_servers; afraid_servers; }; allow-recursion { localhost; internal_nets; hurricane_all_servers; afraid_servers; }; rate-limit { responses-per-second 6; log-only yes; }; }; After the :code:`option` part we get a lot of predefined zones before we start adding our information at the end of the |namedconf| file. First we add another config file with the :code:`include` statement. This simply copies the content of :code:`log.conf` into the |namedconf| on |bind| startup. .. code-block:: vim :caption: named.conf - add some logging // A lot of logging going to /var/log/named/* include "/usr/local/etc/namedb/log.conf"; Next we need to add the the key that will be use to allow the slave servers to pull updates from the master. .. code-block:: vim :caption: named.conf - TSIG key key "yourdomain.tld" { algorithm hmac-sha256; secret "your_very_secret_key"; }; And finally we define our zone by simply providing the name and the zone file we created earlier. We also define who is allowed to transfer zone data. .. code-block:: vim :caption: named.conf - zone zone "yourdomain.tld" { type master; file "/usr/local/etc/namedb/master/yourdomain.tld/yourdomain.tld"; allow-transfer { localhost; internal_nets; afraid_servers; }; notify explicit; also-notify { 216.218.130.2; 2001:470:100::2; 69.65.50.223; }; }; .. _slavezone: Setup slave servers ------------------------ For now |he| got a master zone but the new master zone is configured on the |bind| now. This means the zone at the |he| server can be removed and instead a slave zone will defined. |he| +++++ .. image:: /images/dns007.png As shown in the picture we use the TSIG Key defined in |namedconf| to allow the transfer of zone data from the master to the slave. .. important:: The name of the key in the mask has to match the name of the key in |namedconf| .. raw:: latex \newpage After the zone is successfully created the |he| web UI should show a new entry. .. image:: /images/dns008.png To check if the |he| update the zone its good practice to check the zone transfer logs on the master. .. code-block:: bash # tail -f /var/log/named/zone_transfers 06-Dec-2023 20:30:29.673 xfer-out: info: client @0x84680b760 216.218.133.2#37197/key yourdomain.tld (yourdomain.tld): transfer of 'yourdomain.tld/IN': AXFR started: TSIG yourdomain.tld (serial 3000309) 06-Dec-2023 20:30:29.674 xfer-out: info: client @0x84680b760 216.218.133.2#37197/key yourdomain.tld (yourdomain.tld): transfer of 'yourdomain.tld/IN': AXFR ended: 1 messages, 44 records, 3055 bytes, 0.001 secs (3055000 bytes/sec) (serial 3000309) afraid.org ++++++++++++++ The afraid.org slave dns can't be configured to use TSIG keys but we defined, in the acl section, the ip that can pull updates from the master server. So after creating an account on afraid.org it's possible to define a backup dns in the web UI. .. image:: /images/dns010.png .. image:: /images/dns011.png When the creation was successful and afraid.org was able to pull dns data from the master it will look like the following picture. .. image:: /images/dns012.png The logs on the master server will also show the transfer to afraid.org. .. code-block:: bash # tail -f /var/log/named/zone_transfers 09-Dec-2023 18:06:50.014 xfer-out: info: client @0x84680a960 69.65.50.192#27773 (yourdomain.tld): transfer of 'yourdomain.tld/IN': IXFR started (serial 3000550 -> 3000570) 09-Dec-2023 18:06:50.014 xfer-out: info: client @0x84680a960 69.65.50.192#27773 (yourdomain.tld): transfer of 'yourdomain.tld/IN': IXFR ended: 1 messages, 10 records, 776 bytes, 0.001 secs (776000 bytes/sec) (serial 3000570) Testing the setup ------------------- Now that we configured |bind| to serve our domain we want to make sure everything is working accordingly. To do this some tools provided by the operating system like :code:`dig`, :code:`ping` and :code:`ping6` can be used. .. note:: For some tests it might be nessesary to wait a while after starting |bind| since the zone informations need to be promoted to the allowed nameservers. .. important:: Testing of |bind| needs to be done on a different machine then the one that runs the service! There won't be much of a detailed explaination of the commands or the output since this is not about the :code:`dig` or :code:`ping` tool. First example is simply looking up the |soa| of the domain and if successful the output should look like the example. .. code-block:: bash $ dig yourdomain.tld soa ; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> yourdomain.tld soa ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37434 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;yourdomain.tld. IN SOA ;; ANSWER SECTION: yourdomain.tld. 3552 IN SOA ns1.he.net. you.yourdomain.tld. 3000308 14400 3600 3600000 3600 ;; Query time: 88 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) ;; WHEN: Tue Dec 05 16:43:30 CET 2023 ;; MSG SIZE rcvd: 92 This can be shorten to the most important bit of the query by the :code:`+short` argument. .. code-block:: bash $ dig yourdomain.tld soa +short ns1.he.net. you.yourdomain.tld. 3000308 14400 3600 3600000 3600 If the query fails then a :code:`SERVFAIL` status will be returned. In this example there is no connection to the network so the local resolver on the machine will try to go out and try to resolve the name but won't get a response. .. code-block:: bash $ dig yourdomain.tld soa ; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> yourdomain.tld soa ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 8952 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;yourdomain.tld. IN SOA ;; Query time: 0 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) ;; WHEN: Tue Dec 05 17:10:20 CET 2023 ;; MSG SIZE rcvd: 43 Another example to look up information about the domain and no specific record is requested. Again the local resolver queries the nameservers of the domain and gets :code:`your_server_ip` as the answer. .. code-block:: bash $ dig yourdomain.tld ; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> yourdomain.tld ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54169 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;yourdomain.tld. IN A ;; ANSWER SECTION: yourdomain.tld. 2767 IN A your_server_ip ;; Query time: 0 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) ;; WHEN: Tue Dec 05 16:56:44 CET 2023 ;; MSG SIZE rcvd: 59 And again, if the noise isn't needed there is a way to shorten the output. .. code-block:: bash $ dig yourdomain.tld +short your_server_ip Let's check the nameservers that will answer to queries about the domain. .. note:: there is no entry for the actual master on the machine, only the |he| and afraif.org servers are listed! .. code-block:: bash $ dig yourdomain.tld ns ; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> yourdomain.tld ns ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1089 ;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 13 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;yourdomain.tld. IN NS ;; ANSWER SECTION: yourdomain.tld. 2698 IN NS ns3.he.net. yourdomain.tld. 2698 IN NS ns1.he.net. yourdomain.tld. 2698 IN NS ns2.afraid.org. yourdomain.tld. 2698 IN NS ns5.he.net. yourdomain.tld. 2698 IN NS ns4.he.net. yourdomain.tld. 2698 IN NS ns2.he.net. ;; ADDITIONAL SECTION: ns2.afraid.org. 260 IN A 69.65.50.223 ns2.afraid.org. 214 IN AAAA 2001:1850:1:5:800::6b ns5.he.net. 39113 IN A 216.66.80.18 ns5.he.net. 42971 IN AAAA 2001:470:500::2 ns4.he.net. 39142 IN A 216.66.1.2 ns4.he.net. 41287 IN AAAA 2001:470:400::2 ns2.he.net. 70043 IN A 216.218.131.2 ns2.he.net. 85350 IN AAAA 2001:470:200::2 ns3.he.net. 70052 IN A 216.218.132.2 ns3.he.net. 5138 IN AAAA 2001:470:300::2 ns1.he.net. 40053 IN A 216.218.130.2 ns1.he.net. 46936 IN AAAA 2001:470:100::2 ;; Query time: 51 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) ;; WHEN: Tue Dec 05 16:59:10 CET 2023 ;; MSG SIZE rcvd: 431 The short version again. .. code-block:: bash $ dig yourdomain.tld ns +short ns2.he.net. ns3.he.net. ns1.he.net. ns2.afraid.org. ns5.he.net. ns4.he.net. A simple ping to the machine is also possible. If you don't get a response here you might need to check your package filter software for blocking of :code:`icmp` packages. .. code-block:: bash $ ping yourdomain.tld PING yourdomain.tld (your_server_ip) 56(84) bytes of data. 64 bytes from your_server_name.yourdomain.tld (your_server_ip): icmp_seq=1 ttl=47 time=48.0 ms 64 bytes from your_server_name.yourdomain.tld (your_server_ip): icmp_seq=2 ttl=47 time=72.6 ms 64 bytes from your_server_name.yourdomain.tld (your_server_ip): icmp_seq=3 ttl=47 time=52.0 ms --- yourdomain.tld ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2004ms rtt min/avg/max/mdev = 48.043/57.553/72.649/10.793 ms .. todo:: add more examples ...