This document is about PowerDNS 4.X. If you have PowerDNS 3.X, please see the PowerDNS 3.X documentation

PowerDNS Internals

PowerDNS is normally launched by the init.d script but is actually a binary called pdns_server. This file is started by the start and monitor commands to the init.d script. Other commands are implemented using the controlsocket.

Controlsocket

The controlsocket is the means to contact a running PDNS daemon, or as we now know, a running pdns_server. Over this sockets, instructions can be sent using the pdns_control program. Like the pdns_server, this program is normally accessed via the init.d script.

pdns_control

To communicate with PowerDNS Authoritative Server over the controlsocket, the pdns_control command is used. The init.d script also calls pdns_control. The syntax is simple: pdns_control command arguments. Currently this is most useful for telling backends to rediscover domains or to force the transmission of notifications. See Master.

Besides the commands implemented by the init.d script, for which see Running The Authoritative Server, the following pdns_control commands are available:

ccounts

Returns counts on the contents of the cache.

current-config

Retrieves the current configuration settings from the Authoritative Server instance. This can be useful to generate a from a running instance.

The output has the same format as pdns_server --config. You'll notice that all the are uncommented. This is because PowerDNS simply has values, and the default isn't known at runtime.

cycle

Restart a PowerDNS instance. Only available when running in guardian mode.

notify DOMAIN

Adds a domain to the notification list, causing PowerDNS to send out notifications to the nameservers of a domain. Can be used if a slave missed previous notifications or is generally hard of hearing. Use * to send notifications for all (type=MASTER) zones to all slaves.

notify-host DOMAIN HOST

Same as above but with operator specified IP address as destination, to be used if you know better than PowerDNS.

ping

'PING' the powerdns-guardian. Will return 'PONG' when it is available. (Only works when you are running in guardian mode)

purge

Purges the entire Packet Cache - see Authoritative Server Performance.

purge RECORD

Purges all entries for this exact record name - see Authoritative Server Performance.

purge RECORD

Purges all cache entries ending on this name, effectively purging an entire domain - see Authoritative Server Performance.

purge

Purges the entire Packet Cache - see Authoritative Server Performance.

rping

'PING' the powerdns-instance. Will return 'PONG' when it is available.

rediscover

Instructs backends that new domains may have appeared in the database, or, in the case of the Bind backend, in named.conf.

reload

Instructs backends that the contents of domains may have changed. Many backends ignore this, the Bind backend will check timestamps for all zones (once queries come in for it) and reload if needed.

retrieve DOMAIN

Retrieve a slave domain from its master. Done nearly immediately.

set VARIABLE VALUE

Set a configuration parameter. Currently only the 'query-logging' parameter can be set.

token-login MODULE SLOT PIN

Logs on to a PKCS#11 slot. You only need to login once per slot, even if you have multiple keys on single slot.

uptime

Reports the uptime of the daemon in human readable form.

show VARIABLE

Show a specific statistic. Use * for all. (You may need to quote as '*' or \*).

version

Returns the version of a running pdns daemon.

status

Retrieves the status of PowerDNS. Only available when running with guardian.

Guardian

When launched by the init.d script, pdns_server wraps itself inside a 'guardian'. This guardian monitors the performance of the inner pdns_server instance which shows up in the process list of your OS as pdns_server-instance. It is also this guardian that pdns_control talks to. A STOP is interpreted by the guardian, which causes the guardian to sever the connection to the inner process and terminate it, after which it terminates itself. The init.d script DUMP and SHOW commands need to access the inner process, because the guardian itself does not run a nameserver. For this purpose, the guardian passes controlsocket requests to the control console of the inner process. This is the same console as seen with init.d MONITOR.

Modules & Backends

PowerDNS Authoritative Server has the concept of backends and modules. Non-static PowerDNS distributions have the ability to load new modules at runtime, while the static versions come with a number of modules built in, but cannot load more.

--help

Outputs all known parameters, including those of launched backends, see below.

--launch=backend,backend1,backend1:name

Launches backends. In its most simple form, supply all backends that need to be launched. If you find that you need to launch single backends multiple times, you can specify a name for later instantiations. In this case, there are 2 instances of backend1, and the second one is called 'name'. This means that --backend1-setting is available to configure the first or main instance, and --backend1-name-setting for the second one.

--load-modules=/directory/libyourbackend.so

If backends are available in nonstandard directories, specify their location here. Multiple files can be loaded if separated by commas. Only available in non-static distributions.

--list-modules

Will list all available modules, both compiled in and in dynamically loadable modules.

To run on the command line, use the pdns_server binary. For example, to see options for the gpgsql backend, use the following:

      $ /usr/sbin/pdns_server --launch=gpgsql --help=gpgsql

How PowerDNS translates DNS queries into backend queries

A DNS query is not a straightforward lookup. Many DNS queries need to check the backend for additional data, for example to determine if an unfound record should lead to an NXDOMAIN ('we know about this domain, but that record does not exist') or an unauthoritative response.

Simplified, without CNAME processing, wildcards, referrals and DNSSEC, the algorithm is like this:

When a query for a qname/qtype tuple comes in, PowerDNS queries backends to find the closest matching SOA, thus figuring out what backend owns this zone. When the right backend has been found, PowerDNS issues a qname/ANY query to the backend. If the response is empty, NXDOMAIN is concluded. If the response is not empty, any contents matching the original qtype are added to the list of records to return, and NOERROR is set.

Each of these records is now investigated to see if it needs 'additional processing'. This holds for example for MX records which may point to hosts for which the PowerDNS backends also contain data. This involves further lookups for A or AAAA records.

After all additional processing has been performed, PowerDNS sieves out all double records which may well have appeared. The resulting set of records is added to the answer packet, and sent out.

A zone transfer works by looking up the domain_id of the SOA record of the name and then listing all records of that domain_id. This is why all records in a domain need to have the same domain_id.

If no SOA was found, an unauthoritative no-error is returned.

PowerDNS (before 3.0) broke strict RFC compatibility by not always checking for the presence of a SOA record first. This was unlikely to lead to problems though.

Adding new DNS record types

Here are the full descriptions on how we added the TLSA record type to all PowerDNS products, with links to the actual source code.

First, define the TLSARecordContent class in dnsrecords.hh:

class TLSARecordContent : public DNSRecordContent
{
public:
  includeboilerplate(TLSA) 
  uint8_t d_certusage, d_selector, d_matchtype;
  string d_cert;
};

The 'includeboilerplate(TLSA)' generates the four methods that do everything PowerDNS would ever want to do with a record:

The actual parsing code:

boilerplate_conv(TLSA, 52,
                 conv.xfr8BitInt(d_certusage);
                 conv.xfr8BitInt(d_selector);
                 conv.xfr8BitInt(d_matchtype);
                 conv.xfrHexBlob(d_cert, true);
                 )

This code defines the TLSA rrtype number as 52. Secondly, it says there are 3 eight bit fields for Certificate Usage, Selector and Match type. Next, it defines that the rest of the record is the actual certificate (hash). 'conv' methods are supplied for all DNS data types in use.

Now add TLSRecordContent::report() to reportOtherTypes().

And that's it. For completeness, add TLSA and 52 to the QType enum in qtype.hh, which makes it easier to refer to the TLSA record in code if so required.