# Powerdns > We aim to have a release every six months. --- End of life statements ====================== We aim to have a release every six months. The latest release receives correctness, stability and security updates. The two releases before that get critical updates only. Older releases are marked end of life and receive no updates at all. Pre-releases do not receive immediate security updates. The currently supported release train of PowerDNS Authoritative Server is 5.0. PowerDNS Authoritative Server 4.9 will only receive critical updates; it will be end of life after PowerDNS Authoritative Server 5.2 is released. PowerDNS Authoritative Server 4.8 will only receive critical updates; it will be end of life after PowerDNS Authoritative Server 5.1 is released. PowerDNS Authoritative Server 4.0 through 4.7, 3.x, and 2.x are End of Life. Note: Users with a commercial agreement with PowerDNS.com B.V. or Open-Xchange can receive support for releases which are End Of Life. If you are such a user, these EOL statements do not apply to you. .. list-table:: PowerDNS Authoritative Server Release Life Cycle :header-rows: 1 * - Version - Release date - Critical-Only updates - End of Life * - 5.0 - 22nd of August 2025 - ~ March 2026 - ~ March 2027 * - 4.9 - 15th of March 2024 - 22nd of August 2025 - ~ September 2026 * - 4.8 - 1st of June 2023 - 15th of March 2024 - ~ March 2026 * - 4.7 - 20th of October 2022 - 1st of June 2023 - EOL August 2025 * - 4.6 - January 2022 - October 2022 - EOL March 2024 * - 4.5 - July 2021 - January 2022 - EOL June 2023 * - 4.4 - December 2020 - January 2022 - EOL October 2022 * - 4.3 - April 2020 - April 2021 - EOL January 2022 * - 4.2 - August 2019 - December 2020 - EOL July 2021 * - 4.1 and older - EOL - EOL - EOL PowerDNS Authoritative Server 3.x --------------------------------- 1st of December 2017 The PowerDNS Authoritative Server 3.x releases are no longer supported, and will not receive any further updates, not even for security purposes. All users are urged to upgrade to the latest version. To upgrade from 3.x or 4.x to 5.x, :doc:`follow these instructions <../upgrading>` If you need help with upgrading, we provide `migration services `__ to our supported users. If you are currently running 3.x and need help to tide you over, we can also provide that as part of a `support agreement `__. PowerDNS Authoritative Server 2.x --------------------------------- 21st of May 2015 (updated January 2017) PowerDNS Authoritative Server 2.9.22 was released in January 2009. Because of its immense and durable popularity, some patch releases have been provided, the last one of which (2.9.22.6) was made available in January 2012. The 2.9.22.x series contains a number of probable and actual violations of the DNS standards. In addition, some behaviours of 2.9.22.x are standards conforming but cause interoperability problems today. Finally, 2.9.22.4 and earlier are impacted by :doc:`PowerDNS Security Advisory 2012-01 <../security-advisories/powerdns-advisory-2012-01>`, which means PowerDNS can be used in a Denial of Service attack. Although we have long been telling users that we can no longer support the use of 2.x, and urging upgrading, with this statement we formally declare 2.x end of life. This means that any 2.x issues will not be addressed. This has been the case for a long time, but with this statement we make it formal. To upgrade to 3.x, please consult the `instructions on how to upgrade the database `__. To upgrade from 3.x or 4.x to 5.x, :doc:`follow these instructions <../upgrading>`. If you need help with upgrading, we provide `migration services `__ to our supported users. If you are currently running 2.9.22 and need help to tide you over, we can also provide that as part of a `support agreement `__. But we urge everyone to move on to PowerDNS Authoritative Server 5.x - it is a faster, more standards conforming and more powerful nameserver! --- Frequently Asked Questions ========================== This document lists categorized answers and questions with links to the relevant documentation. Replication ----------- Please note that not all PowerDNS Server backends support primary or secondary operation, see the :doc:`table of backends <../backends/index>`. My PowerDNS Authoritative Server does not send NOTIFY messages ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't forget to enable primary support by setting :ref:`setting-primary` to ``yes`` in your configuration. In :ref:`primary mode` PowerDNS Authoritative Server will send NOTIFYs to all nameservers that are listed as NS records in the zone by default. My PowerDNS Authoritative Server does not start AXFRs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't forget to enable secondary-support by setting :ref:`setting-secondary` to ``yes`` in your configuration. In :ref:`secondary mode` PowerDNS Authoritative Server listens for NOTIFYs from the primary IP for zones that are configured as secondary zones, and will also periodically check for SOA serial number changes at the primary. Can PowerDNS Server act as Secondary and Primary at the same time? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Yes totally, enable both by saying ``yes`` to :ref:`setting-primary` and :ref:`setting-secondary` in your configuration. How can I limit Zone Transfers (AXFR) per Domain? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ With the ALLOW-AXFR-FROM metadata, See :ref:`the documentation `. I have a working Autoprimary/Autosecondary setup but when I remove Zones from the Primary they still remain on the Secondary. Am I doing something wrong? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You're not doing anything wrong. This is the perfectly normal and expected behavior because the AXFR (DNS Zonetransfer) Protocol does not provide for zone deletion. You need to remove the zones from the secondary manually or via a custom script. Operational ----------- The ADDITIONAL is section different than BIND's answer, why? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The PowerDNS Authoritative Server by default does not 'trust' other zones in its own database. PowerDNS does not give authoritative answers, how come? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is almost always not the case. An authoritative answer is recognized by the 'AA' bit being set. Many tools prominently print the number of Authority records included in an answer, leading users to conclude that the absence or presence of these records indicates the authority of an answer. This is not the case. Verily, many misguided country code domain operators have fallen into this trap and demand authority records, even though these are fluff and quite often misleading. Invite such operators to look at :rfc:`section 6.2.1 of RFC 1034 <1034#section-6.2.1>`, which shows a correct authoritative answer without authority records. In fact, none of the non-deprecated authoritative answers shown have authority records! Primary or Secondary support is not working, PowerDNS is not picking up changes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The Primary/Secondary apparatus is off by default. Turn it on by adding a :ref:`setting-secondary` and/or :ref:`setting-primary` statement to the configuration file. Also, check that the configured backend is primary or secondary capable and you entered exactly the same string to the Domains tables without the ending dot. My primaries won't allow PowerDNS to access zones as it is using the wrong local IP address ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ By default, PowerDNS lets the kernel pick the source address. To set an explicit source address, use the :ref:`setting-query-local-address` setting. PowerDNS does not answer queries on all my IP addresses (and I've ignored the warning I got about that at startup) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Please don't ignore what PowerDNS says to you. Furthermore, see the documentation for the :ref:`setting-local-address` and :ref:`setting-local-ipv6` settings, and use it to specify which IP addresses PowerDNS should listen on. If this is a fail-over address, then the :ref:`setting-local-address-nonexist-fail` and :ref:`setting-local-ipv6-nonexist-fail` settings might interest you. Linux Netfilter says your conntrack table is full? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Thats a common problem with Netfilter Conntracking and DNS Servers, just tune your kernel variable (``/etc/sysctl.conf``) ``net.ipv4.netfilter.ip_conntrack_max`` up accordingly. Try setting it for a million if you don't mind spending some MB of RAM on it for example. I get an error about writing to /etc ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This may look something like "unable to open temporary zonefile '/etc/powerdns/zones/example.com.'". PowerDNS systemd units enable ``ProtectSystem=full`` by default, which disallows writes to ``/etc`` and ``/usr``, among other places. Either move your zone files to a safer place (``/var/lib/powerdns`` is a popular choice) or change the systemd protection settings. For more background on this, please see the systemd documentation on `ProtectSystem `_ and `ReadWritePaths `_. Backends -------- Does PowerDNS support splitting of TXT records (multipart or multiline) with the MySQL backend? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PowerDNS with the :doc:`../backends/generic-sql` do NOT support this. Simply make the "content" field in your database the appropriate size for the records you require. I see this a lot of "Failed to execute mysql_query" or similar log-entries ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Check your MySQL timeout, it may be set too low. This can be changed in the ``my.cnf`` file. Which backend should I use? There are so many! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you have no external constraints, the :doc:`../backends/generic-mysql`, :doc:`../backends/generic-postgresql` and :doc:`../backends/generic-sqlite3` ones are probably the most used and complete. The bindbackend is also pretty capable too in fact, but many prefer a relational database. Can I launch multiple backends simultaneously? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can. This might for example be useful to keep an existing BIND configuration around but to store new zones in, say MySQL. The syntax to use is ``launch=bind,gmysql``. Do note that multi-backend behaviour is not specified and might change between versions. This is especially true when DNSSEC is involved. I've added extra fields to the domains and/or records table. Will this eventually affect the resolution process in any way? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ No, the :doc:`../backends/generic-sql` use several default queries to provide the PowerDNS Server with data and all of those refer to specific field names, so as long as you don't change any of the predefined field names you are fine. Can I specify custom sql queries for the gmysql / gpgsql backend or are those hardcoded? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Yes you can override the :ref:`default queries `. --- Backend writers' guide ====================== PowerDNS backends are implemented via a simple yet powerful C++ interface. If your needs are not met by the regular backends, including the PipeBackend and the RemoteBackend, you may want to write your own. Before doing any PowerDNS development, please read `this blog post `__ which has a FAQ and several pictures that help explain what a backend is. A backend contains zero DNS logic. It need not look for CNAMEs, it need not return NS records unless explicitly asked for, etcetera. All DNS logic is contained within PowerDNS itself - backends should simply return records matching the description asked for. .. warning:: However, please note that your backend can get queries in aNy CAsE! If your database is case-sensitive, like most are (with the notable exception of MySQL), you must make sure that you do find answers which differ only in case. .. warning:: PowerDNS may instantiate multiple instances of your backend, or destroy existing copies and instantiate new ones. Backend code should therefore be thread-safe with respect to its static data. Additionally, it is wise if instantiation is a fast operation, with the possible exception of the first construction. Notes ----- Besides regular query types, the DNS also knows the 'ANY' query type. When a server receives a question for this ANY type, it should reply with all record types available. Backends should therefore implement being able to answer 'ANY' queries in this way, and supply all record types they have when they receive such an 'ANY' query. This is reflected in the sample script above, which for every qtype answers if the type matches, or if the query is for 'ANY'. However, since backends need to implement the ANY query anyhow, PowerDNS makes use of this. Since almost all DNS queries internally need to be translated first into a CNAME query and then into the actual query, possibly followed by a SOA or NS query (this is how DNS works internally), it makes sense for PowerDNS to speed this up, and just ask the ANY query of a backend. When it has done so, it gets the data about SOA, CNAME and NS records in one go. This speeds things up tremendously. The upshot of the above is that for any backend, including the PIPE backend, implementing the ANY query is NOT optional. And in fact, a backend may see almost exclusively ANY queries. This is not a bug. Simple read-only native backends -------------------------------- Implementing a backend consists of inheriting from the DNSBackend class. For read-only backends, which do not support secondary operation, only the following methods are relevant: .. code-block:: cpp class DNSBackend { public: virtual unsigned int getCapabilities()=0; virtual void lookup(const QType &qtype, const string &qdomain, domainid_t zoneId, DNSPacket *pkt_p=nullptr)=0; virtual bool list(const string &target, domainid_t domain_id)=0; virtual bool get(DNSResourceRecord &r)=0; virtual bool getSOA(const string &name, domainid_t zoneId, SOAData &soadata); }; Note that the first four methods must be implemented. ``getSOA()`` has a useful default implementation. The semantics are simple. Each instance of your class only handles one (1) query at a time. There is no need for locking as PowerDNS guarantees that your backend will never be called reentrantly. .. note:: Queries for wildcard names should be answered literally, without expansion. So, if a backend gets a question for "\*.powerdns.com", it should only answer with data if there is an actual "\*.powerdns.com" name. Some examples, a more formal specification can be found down below. A normal lookup starts like this: .. code-block:: cpp YourBackend yb; yb.lookup(QType::CNAME,"www.powerdns.com"); Your class should now do everything to start this query. Perform as much preparation as possible - handling errors at this stage is better for PowerDNS than doing so later on. A real error should be reported by throwing an exception. PowerDNS will then call the ``get()`` method to get ``DNSResourceRecord``\ s back. The following code illustrates a typical query: .. code-block:: cpp yb.lookup(QType::CNAME,"www.powerdns.com"); DNSResourceRecord rr; while(yb.get(rr)) cout<<"Found cname pointing to '"+rr.content+"'"<()); g_log << Logger::Info << "[randombackend] This is the random backend version " VERSION " reporting" << endl; } }; static RandomLoader randomloader; This simple backend can be used as an 'overlay'. In other words, it only knows about a single name, ``random.powerdns.com``, another loaded backend would have to know about the SOA and NS records for the ``powerdns.com`` zone and such. .. warning:: Spreading the content of a zone across multiple backends, described above as 'overlay', makes the zone incompatible with some operations that assume that a single zone is always entirely stored in the same backend. Such operations include zone transfers, listing and editing zone content via the API or :doc:`pdnsutil <../manpages/pdnsutil.1>`. .. warning:: When the content of a zone is spread across multiple backends, all the types for a given name should be delegated to the same backend. For example a backend can know about all the types for ``random.powerdns.com`` while another backend knows about all the types for ``random2.powerdns.com``, but it is not possible to let one backend handle only ``AAAA`` queries for all names while another one handles only ``A`` queries, for example. This limitation comes from the fact that PowerDNS uses ``ANY`` queries to fetch all types from the backend in one go and that it assumes that once one backend has returned records the other ones do not need to be called. It is also possible to have two backends providing records for the same name and types, for example if the first one does not support DNSSEC and the second does, but that requires some mechanism outside of PowerDNS to keep records in sync between the two backends. The first part of the code contains the actual logic and should be pretty straightforward. The second part is a boilerplate 'factory' class which PowerDNS calls to create randombackend instances. Note that a 'suffix' parameter is passed. Real life backends also declare parameters for the configuration file; these get the 'suffix' appended to them. Note that the "random" in the constructor denotes the name by which the backend will be known. The third part registers the RandomFactory with PowerDNS. This is a simple C++ trick which makes sure that this function is called on execution of the binary or when loading the dynamic module. .. note:: This simple backend neglects to handle case properly! Interface definition -------------------- Classes ~~~~~~~ .. cpp:class:: DNSResourceRecord .. cpp:member:: DNSName DNSResourceRecord::qname Name of this record .. cpp:member:: QType DNSResourceRecord::qtype Query type of this record .. cpp:member:: std::string DNSResourceRecord::content ASCII representation of the right-hand side .. cpp:member:: uint32_t DNSResourceRecord::ttl Time To Live of this record .. cpp:member:: domainid_t DNSResourceRecord::domain_id ID of the domain this record belongs to .. cpp:member:: time_t DNSResourceRecord::last_modified If non-zero, last time_t this record was changed .. cpp:member:: bool DNSResourceRecord::auth Used for DNSSEC operations. See :doc:`../dnssec/migration`. It is also useful to check out the ``rectifyZone()`` in pdnsutil.cc. .. cpp:member:: bool DNSResourceRecord::disabled If set, this record is not to be served to DNS clients. Backends should not make these records available to PowerDNS unless indicated otherwise. .. cpp:class:: SOAData .. cpp:member:: DNSName SOAData::nameserver Name of the primary nameserver of this zone .. cpp:member:: uint32_t SOAData::serial Serial number of this zone .. cpp:member:: uint32_t SOAData::refresh How often this zone should be refreshed .. cpp:member:: uint32_t SOAData::retry How often a failed zone pull should be retried. .. cpp:member:: u_int32_t SOAData::expire If zone pulls failed for this long, retire records .. cpp:member:: uint32_t SOAData::minimum Minimum acceptable value for TTL .. cpp:member:: domainid_t SOAData::domain_id The ID of the domain within this backend. Must be filled! .. cpp:member:: DNSBackend* SOAData::db Pointer to the backend that feels authoritative for a domain and can act as a secondary Methods ~~~~~~~ .. cpp:function:: unsigned int getCapabilities() This function returns a bitmask representing various capabilities of the backend. The currently used capabilities are: * `CAP_DNSSEC` Backend implements :ref:`backend-dnssec`. * `CAP_LIST` Backend implements `list`, for AXFR or `pdnsutil zone list` .. cpp:function:: void DNSBackend::lookup(const QType &qtype, const string &qdomain, domainid_t zoneId, DNSPacket *pkt=nullptr) This function is used to initiate a straight lookup for a record of name 'qdomain' and type 'qtype'. A QType can be converted into an integer by invoking its ``getCode()`` method and into a string with the ``getCode()``. The original question may or may not be passed in the pointer pkt. If it is, you can retrieve information about who asked the question with the ``pkt->getRemote()`` method. .. note:: Since 4.1.0, 'SOA' lookups are not passed this pointer anymore because PowerDNS doesn't support tailoring whether a whole zone exists or not based on who is asking. Note that **qdomain** can be of any case and that your backend should make sure it is in effect case-insensitive. Furthermore, the case of the original question should be retained in answers returned by ``get()``! Finally, the domain_id might also be passed indicating that only answers from the indicated zone need apply. This can both be used as a restriction or as a possible speedup, hinting your backend where the answer might be found. If initiated successfully, as indicated by returning **true**, answers should be made available over the ``get()`` method. Should throw an PDNSException if an error occurred accessing the database. Returning otherwise indicates that the query was started successfully. If it is known that no data is available, no exception should be thrown! An exception indicates that the backend considers itself broken - not that no answers are available for a question. It is legal to return here, and have the first call to ``get()`` return false. This is interpreted as 'no data'. .. cpp:function:: bool DNSBackend::list(domainid_t domain_id, bool include_disabled=false) Initiates a list of the indicated domain. Records should then be made available via the ``get()`` method. Need not include the SOA record. If it is, PowerDNS will not get confused. If include_disabled is given as true, records that are configured but should not be served to DNS clients must also be made available. Should return false if the backend does not consider itself authoritative for this zone. Should throw an PDNSException if an error occurred accessing the database. Returning true indicates that data is or should be available. .. cpp:function:: bool DNSBackend::get(DNSResourceRecord &rr) Request a DNSResourceRecord from a query started by ``get()`` of ``list()``. If this functions returns **true**, **rr** has been filled with data. When it returns false, no more data is available, and **rr** does not contain new data. A backend should make sure that it either fills out all fields of the DNSResourceRecord or resets them to their default values. The qname field of the DNSResourceRecord should be filled out with the exact ``qdomain`` passed to lookup, preserving its case. So if a query for 'CaSe.yourdomain.com' comes in and your database contains data for 'case.yourdomain.com', the qname field of rr should contain 'CaSe.yourdomain.com'! Should throw an PDNSException in case a database error occurred. .. cpp:function:: bool DNSBackend::getSOA(const string &name, domainid_t zoneId, SOAData &soadata) If the backend considers itself authoritative over domain ``name``, of id ``zoneId`` if known (otherwise, ``UnknownDomainID``), this method should fill out the passed **SOAData** structure and return true. If the backend is functioning correctly, but does not consider itself authoritative, it should return false. In case of errors, an PDNSException should be thrown. Reporting errors ---------------- To report errors, the Logger class is available which works mostly like an iostream. Example usage is as shown above in the RandomBackend. Note that it is very important that each line is ended with **endl** as your message won't be visible otherwise. To indicate the importance of an error, the standard syslog errorlevels are available. They can be set by outputting ``Logger::Critical``, ``Logger::Error``, ``Logger::Warning``, ``Logger::Notice``, ``Logger::Info`` or ``Logger::Debug`` to ``g_log``, in descending order of graveness. Declaring and reading configuration details ------------------------------------------- It is highly likely that a backend needs configuration details. On launch, these parameters need to be declared with PowerDNS so it knows it should accept them in the configuration file and on the command line. Furthermore, they will be listed in the output of ``--help``. Declaring arguments is done by implementing the member function ``declareArguments()`` in the factory class of your backend. PowerDNS will call this method after launching the backend. In the ``declareArguments()`` method, the function ``declare()`` is available. The exact definitions: .. cpp:function:: void BackendFactory::declareArguments(const string &suffix="") This method is called to allow a backend to register configurable parameters. The suffix is the sub-name of this module. There is no need to touch this suffix, just pass it on to the ``declare`` method. .. cpp:function:: void BackendFactory::declare(const string &suffix, const string ¶m, const string &explanation, const string &value) The suffix is passed to your method, and can be passed on to declare. **param** is the name of your parameter. **explanation** is what will appear in the output of --help. Furthermore, a default value can be supplied in the **value** parameter. A sample implementation: .. code-block:: cpp void declareArguments(const string &suffix) { declare(suffix,"dbname","Pdns backend database name to connect to","powerdns"); declare(suffix,"user","Pdns backend user to connect as","powerdns"); declare(suffix,"host","Pdns backend host to connect to",""); declare(suffix,"password","Pdns backend password to connect with",""); } After the arguments have been declared, they can be accessed from your backend using the ``mustDo()``, ``getArg()`` and ``getArgAsNum()`` methods. The are defined as follows in the DNSBackend class: .. cpp:function:: void DNSBackend::setArgPrefix(const string &prefix) Must be called before any of the other accessing functions are used. Typical usage is '``setArgPrefix("mybackend"+suffix)``' in the constructor of a backend. .. cpp:function:: bool DNSBackend::mustDo(const string &key) Returns true if the variable ``key`` is set to anything but 'no'. .. cpp:function:: const string& DNSBackend::getArg(const string &key) Returns the exact value of a parameter. .. cpp:function:: int DNSBackend::getArgAsNum(const string &key) Returns the numerical value of a parameter. Uses ``strtol()`` internally. Sample usage from the BIND backend: getting the 'check-interval' setting: .. code-block:: cpp if(!safeGetBBDomainInfo(i->name, &bbd)) { bbd.d_id=domain_id++; bbd.setCheckInterval(getArgAsNum("check-interval")); bbd.d_lastnotified=0; bbd.d_loaded=false; } .. _rw-slave: .. _rw-secondary: Read/write secondary-capable backends ------------------------------------- The backends above are 'natively capable' in that they contain all data relevant for a domain and do not pull in data from other nameservers. To enable storage of information, a backend must be able to do more. Before diving into the details of the implementation some theory is in order. Secondary domains are pulled from the primary. PowerDNS needs to know for which domains it is to be a secondary, and for each secondary domain, what the IP address of the primary is. A secondary zone is pulled from a primary, after which it is 'fresh', but this is only temporary. In the SOA record of a zone there is a field which specifies the 'refresh' interval. After that interval has elapsed, the secondary nameserver needs to check at the primary if the serial number there is greater than what is stored in the backend locally. If this is the case, PowerDNS dubs the domain 'stale', and schedules a transfer of data from the remote. This transfer remains scheduled until the serial numbers remote and locally are identical again. This theory is implemented by the ``getUnfreshSecondaryInfos`` method, which is called on all backends periodically. This method fills a vector of **DomainInfo**\ s with domains that are unfresh and possibly stale. PowerDNS then retrieves the SOA of those domains remotely and locally and creates a list of stale domains. For each of these domains, PowerDNS starts a zone transfer to resynchronise. Because zone transfers can fail, it is important that the interface to the backend allows for transaction semantics because a zone might otherwise be left in a halfway updated situation. The following excerpt from the DNSBackend shows the relevant functions: .. code-block:: cpp class DNSBackend { public: /* ... */ virtual bool getDomainInfo(const string &domain, DomainInfo &di, bool getSerial = true); virtual bool isPrimary(const ComboAddress& ipAddress); virtual bool startTransaction(const string &qname, domainid_t id); virtual bool commitTransaction(); virtual bool abortTransaction(); virtual bool feedRecord(const DNSResourceRecord &rr, const DNSName &ordername, bool ordernameIsNSEC3 = false); virtual void getUnfreshSecondaryInfos(vector* domains); virtual void setFresh(domainid_t id); /* ... */ } The mentioned DomainInfo struct looks like this: .. cpp:class:: DomainInfo .. cpp:member:: domainid_t DomainInfo::id ID of this zone within this backend .. cpp:member:: vector DomainInfo::primaries IP addresses of the primary of this domain (may be empty) .. cpp:member:: uint32_t DomainInfo::serial Serial number of this zone .. cpp:member:: uint32_t DomainInfo::notified_serial Last serial number of this zone that secondaries have seen .. cpp:member:: time_t DomainInfo::last_check Last time this zone was checked over at the primary for changes .. cpp:member:: enum DomainKind DomainInfo::kind Type of zone .. cpp:member:: DNSBackend* DomainInfo::backend Pointer to the backend that feels authoritative for a domain and can act as a secondary .. cpp:enum:: DomainKind The kind of domain, one of {Primary,Secondary,Native}. These functions all have a default implementation that returns false - which explains that these methods can be omitted in simple backends. Furthermore, unlike with simple backends, a secondary capable backend must make sure that the 'DNSBackend \*db' field of the SOAData record is filled out correctly - it is used to determine which backend will house this zone. .. cpp:function:: bool DomainInfo::isPrimary(const ComboAddress& ipAddress) If a backend considers itself a secondary for the given domain and if the IP address in **ipAddress** is indeed a primary, it should return true. False otherwise. This is a first line of checks to guard against reloading a domain unnecessarily. .. cpp:function:: void DomainInfo::getUnfreshSecondaryInfos(vector\* domains) When called, the backend should examine its list of secondary domains and add any unfresh ones to the domains vector. .. cpp:function:: bool DomainInfo::getDomainInfo(const string &name, DomainInfo & di, boot getSerial) This is like ``getUnfreshSecondaryInfos``, but for a specific domain. If the backend considers itself authoritative for the named zone, ``di`` should be filled out, and 'true' be returned. Otherwise, return false. .. cpp:function:: bool DomainInfo::startTransaction(const string &qname, domainid_t id) When called, the backend should start a transaction that can be committed or rolled back atomically later on. In SQL terms, this function should **BEGIN** a transaction, and **DELETE** all records for the domain matching the given ``id``, unless its value is ``UnknownDomainID``. .. cpp:function:: bool DomainInfo::feedRecord(const DNSResourceRecord &rr, const DNSName &ordername, bool ordernameIsNSEC3) Insert this record. .. cpp:function:: bool DomainInfo::commitTransaction() Make the changes effective. In SQL terms, execute **COMMIT**. .. cpp:function:: bool DomainInfo::abortTransaction() Abort changes. In SQL terms, execute **ABORT**. .. cpp:function:: bool DomainInfo::setFresh(domainid_t id) Indicate that a domain has either been updated or refreshed without the need for a retransfer. This causes the domain to vanish from the vector modified by ``getUnfreshSecondaryInfos()``. PowerDNS will always call ``startTransaction()`` before making calls to ``feedRecord()``. Although it is likely that ``abortTransaction()`` will be called in case of problems, backends should also be prepared to abort from their destructor. The actual code in PowerDNS is currently: .. code-block:: cpp Resolver resolver; resolver.axfr(remote,domain.c_str()); db->startTransaction(domain, domain_id); g_log<feedRecord(*i); } } db->commitTransaction(); db->setFresh(domain_id); g_log<&nsset, string *nameserver, string *account, DNSBackend **db) }; This function gets called with the IP address of the potential autoprimary, the domain it is sending a notification for and the set of NS records for this domain at that IP address. Using the supplied data, the backend needs to determine if this is a bonafide 'supernotification' which should be honoured. If it decides that it should, the supplied pointer to 'account' needs to be filled with the configured name of the autoprimary (if accounting is desired), and the db needs to be filled with a pointer to your backend. Autoprimary/autosecondary is a complicated concept, if this is all unclear see the :ref:`autoprimary-operation` documentation. Read/write primary-capable backends ----------------------------------- In order to be a useful primary for a domain, notifies must be sent out whenever a domain is changed. Periodically, PowerDNS queries backends for domains that may have changed, and sends out notifications to secondary nameservers. In order to do so, PowerDNS calls the ``getUpdatedPrimaries()`` method. Like the ``getUnfreshSecondaryInfos()`` function mentioned above, this should add changed domain names to the vector passed. The following excerpt from the DNSBackend shows the relevant functions: .. code-block:: cpp class DNSBackend { public: /* ... */ virtual void getUpdatedPrimaries(vector* domains, std::unordered_set &catalogs, CatalogHashMap &catalogHashes); virtual void setNotified(domainid_t id, uint32_t serial); /* ... */ } These functions all have a default implementation that doesn't do anything - which explains that these methods can be omitted in simple backends. Furthermore, unlike with simple backends, a secondary capable backend must make sure that the 'DNSBackend \*db' field of the SOAData record is filled out correctly - it is used to determine which backend will house this zone. .. cpp:function:: void DNSBackend::getUpdatedPrimaries(vector* domains, std::unordered_set &catalogs, CatalogHashMap &catalogHashes) When called, the backend should examine its list of primary domains and add any changed ones to the :cpp:class:`DomainInfo` vector. .. cpp:function:: void DNSBackend::setNotified(domainid_t domain_id, uint32_t serial) Indicate that notifications have been queued for this domain and that it need not be considered 'updated' anymore. DNS update support ------------------ To make your backend DNS update compatible, it needs to implement a number of new functions and functions already used for secondary operation. The new functions are not DNS update specific and might be used for other update/remove functionality at a later stage. .. code-block:: cpp class DNSBackend { public: /* ... */ virtual bool startTransaction(const DNSName &qname, domainid_t id); virtual bool commitTransaction(); virtual bool abortTransaction(); virtual bool feedRecord(const DNSResourceRecord &rr, DNSName &ordername, bool ordernameIsNSEC3); virtual bool replaceRRSet(domainid_t domain_id, const DNSName& qname, const QType& qt, const vector& rrset) virtual bool listSubZone(const DNSName &zone, domainid_t domain_id); /* ... */ } .. cpp:function:: virtual bool DNSBackend::startTransaction(const DNSName &qname, domainid_t id) See :cpp:func:`above `. Please note that if this function receives ``UnknownDomainID`` as the ``id``, the current zone data should NOT be deleted. .. cpp:function:: virtual bool DNSBackend::commitTransaction() See :cpp:func:`above `. .. cpp:function:: virtual bool DNSBackend::abortTransaction() See cpp:func:`above `. Method is called when an exception is received. .. cpp:function:: virtual bool DNSBackend::feedRecord(const DNSResourceRecord &rr, const DNSName &ordername, bool ordernameIsNSEC3) See :cpp:func:`above `. Please keep in mind that the zone is not empty because ``startTransaction()`` was called differently. .. cpp:function:: virtual bool DNSBackend::listSubZone(const DNSName &name, domainid_t domain_id) This method is needed for rectification of a zone after NS-records have been added. For DNSSEC, we need to know which records are below the currently added record. ``listSubZone()`` is used like ``list()``, which means PowerDNS will call ``get()`` after this method. The default SQL query looks something like this:: // First %s is 'sub.zone.com', second %s is '*.sub.zone.com' select content,ttl,prio,type,domain_id,name from records where (name='%s' OR name like '%s') and domain_id=%d The method is not only used when adding records, but also to correct ENT-records in PowerDNS. Make sure it returns every record in the tree below the given record. .. cpp:function:: virtual bool DNSBackend::replaceRRSet(domainid_t domain_id, const DNSName& qname, const QType& qt, const vector& rrset) This method should remove all the records with ``qname`` of type ``qt``. ``qt`` might also be ANY, which means all the records with that ``qname`` need to be removed. After removal, the records in ``rrset`` must be added to the zone. ``rrset`` can be empty in which case the method is used to remove a RRset. Domain metadata support ----------------------- As described in :doc:`../domainmetadata`, each served zone can have “metadata”. Such metadata determines how this zone behaves in certain circumstances. In order for a backend to support domain metadata, the following operations have to be implemented: .. code-block:: cpp class DNSBackend { public: /* ... */ virtual bool getAllDomainMetadata(const DNSName& name, std::map >& meta); virtual bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector& meta); virtual bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector& meta); /* ... */ } .. cpp:function:: virtual bool getAllDomainMetadata(const DNSName& name, std::map >& meta) Fills 'meta' with the value(s) of all kinds for zone 'name'. Returns true if the domain metadata operation are supported, regardless of whether there is any data for this zone. .. cpp:function:: virtual bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector& meta) Fills 'meta' with the value(s) of the specified kind for zone 'name'. Returns true if the domain metadata operation are supported, regardless of whether there is any data of this kind for this zone. .. cpp:function:: virtual bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector& meta) Store the values from 'meta' for the specified kind for zone 'name', discarding existing values if any. An empty meta is equivalent to a deletion request. Returns true if the values have been correctly stored, and false otherwise. TSIG keys --------- In order for a backend to support the storage of TSIG keys, the following operations have to be implemented: .. code-block:: cpp class DNSBackend { public: /* ... */ virtual bool getTSIGKey(const DNSName& name, DNSName& algorithm, string& content); virtual bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content); virtual bool deleteTSIGKey(const DNSName& name); virtual bool getTSIGKeys(std::vector< struct TSIGKey > &keys); /* ... */ } .. _backend-dnssec: DNSSEC support -------------- In order for a backend to support DNSSEC, quite a few number of additional operations have to be implemented: .. code-block:: cpp struct KeyData { std::string content; unsigned int id; unsigned int flags; bool active; bool published; }; class DNSBackend { public: virtual unsigned int getCapabilities(); /* ... */ virtual bool getBeforeAndAfterNamesAbsolute(domainid_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after); /* update operations */ virtual bool updateDNSSECOrderNameAndAuth(domainid_t domain_id, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t qtype, bool isNsec3); virtual bool updateEmptyNonTerminals(domainid_t domain_id, set& insert, set& erase, bool remove); virtual bool feedEnts(domainid_t domain_id, map &nonterm); virtual bool feedEnts3(domainid_t domain_id, const DNSName &domain, map &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow); /* keys management */ virtual bool getDomainKeys(const DNSName& name, std::vector& keys); virtual bool removeDomainKey(const DNSName& name, unsigned int id); virtual bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id); virtual bool activateDomainKey(const DNSName& name, unsigned int id); virtual bool deactivateDomainKey(const DNSName& name, unsigned int id); virtual bool publishDomainKey(const DNSName& name, unsigned int id); virtual bool unpublishDomainKey(const DNSName& name, unsigned int id); /* ... */ } In addition to these methods, the return value of `getCapabilities` must contain `CAP_DNSSEC` if that backend supports DNSSEC. .. cpp:function:: virtual bool getBeforeAndAfterNamesAbsolute(domainid_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) Asks the names before and after qname for NSEC and NSEC3. The qname will be hashed when using NSEC3. Care must be taken to handle wrap-around when qname is the first or last in the ordered list of zone names. Please note that in case the requested name is present in the zone, it should be returned as the "before" name. .. cpp:function:: virtual bool updateDNSSECOrderNameAndAuth(domainid_t domain_id, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t qtype, bool isNsec3) Updates the ordername and auth fields. .. cpp:function:: virtual bool updateEmptyNonTerminals(domainid_t domain_id, set& insert, set& erase, bool remove) Updates ENT after a zone has been rectified. If 'remove' is false, 'erase' contains a list of ENTs to remove from the zone before adding any. Otherwise, all ENTs should be removed from the zone before adding any. 'insert' contains the list of ENTs to add to the zone after the removals have been done. .. cpp:function:: virtual bool feedEnts(domainid_t domain_id, map &nonterm) This method is used by ``pdnsutil zone rectify`` to populate missing non-terminals. This is used when you have, say, record like _sip._upd.example.com, but no _udp.example.com. PowerDNS requires that there exists a non-terminal in between, and this instructs you to add one. .. cpp:function:: virtual bool feedEnts3(domainid_t domain_id, const DNSName &domain, map &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow) Same as feedEnts, but provides NSEC3 hashing parameters. .. cpp:function:: virtual bool getDomainKeys(const DNSName& name, std::vector& keys) Retrieves all DNSSEC keys. Content must be valid key record in format that PowerDNS understands. .. cpp:function:: virtual bool removeDomainKey(const DNSName& name, unsigned int id) Removes this key. .. cpp:function:: virtual bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id) Adds a new DNSSEC key for this domain. .. cpp:function:: virtual bool activateDomainKey(const DNSName& name, unsigned int id) Activates an inactive DNSSEC key for this domain. .. cpp:function:: virtual bool deactivateDomainKey(const DNSName& name, unsigned int id) Deactivates an active DNSSEC key for this domain. .. cpp:function:: virtual bool publishDomainKey(const DNSName& name, unsigned int id) Publishes a previously hidden DNSSEC key for this domain. .. cpp:function:: virtual bool unpublishDomainKey(const DNSName& name, unsigned int id) Hides a DNSSEC key for this domain. Hidden DNSSEC keys are used for signing but do not appear in the actual zone, and are useful for rollover operations. Miscellaneous ------------- ENT (Empty Non-Terminal) ~~~~~~~~~~~~~~~~~~~~~~~~ You are expected to reply with a DNSResourceRecord having ``qtype = 0``, ``ttl = 0`` and ``content`` should be empty string (string length 0) Storage classes ~~~~~~~~~~~~~~~ You may have noticed that PowerDNS has several C++ classes for holding DNS data. Some use presentation format, some use the wire format. Some just hold content, some hold a whole record. Below, we'll show the class definitions of each (with some details omitted, but with some useful words added) to help you find your way. .. code-block:: cpp struct DNSZoneRecord { domainid_t domain_id{UnknownDomainID}; uint8_t scopeMask{0}; int signttl{0}; DNSName wildcardname; bool auth{true}; bool disabled{false}; DNSRecord dr; }; ``DNSZoneRecord`` holds a record in the context of a zone. It is a wrapper around ``DNSRecord`` with some extra fields that PowerDNS might need to handle DNSSEC and ECS correctly. .. code-block:: cpp struct DNSRecord { DNSRecord() : d_type(0), d_class(QClass::IN), d_ttl(0), d_clen(0), d_place(DNSResourceRecord::ANSWER) {} explicit DNSRecord(const DNSResourceRecord& rr); DNSName d_name; std::shared_ptr d_content; uint16_t d_type; uint16_t d_class; uint32_t d_ttl; uint16_t d_clen; DNSResourceRecord::Place d_place; // this orders by name/type/class/ttl/lowercased zone representation bool operator<(const DNSRecord& rhs); // this orders in canonical order and keeps the SOA record on top static bool prettyCompare(const DNSRecord& a, const DNSRecord& b); bool operator==(const DNSRecord& rhs) const }; ``DNSRecord`` holds a DNS record. It has name, type, class, TTL, content length, and a content object of type ``DNSRecordContent``. .. code-block:: cpp class DNSRecordContent { public: static std::shared_ptr make(...); virtual std::string getZoneRepresentation(bool noDot=false) const = 0; virtual void toPacket(DNSPacketWriter& pw) const =0; string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false); virtual bool operator==(const DNSRecordContent& rhs); // compares presentation format static shared_ptr deserialize(const DNSName& qname, uint16_t qtype, const string& serialized, uint16_t qclass=QClass::IN); void doRecordCheck(const struct DNSRecord&){} virtual uint16_t getType() const = 0; }; ``DNSRecordContent`` holds DNS content, in individual fields for the various contents of record types. It is subclassed for all supported types: .. code-block:: cpp class SRVRecordContent : public DNSRecordContent { public: SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, DNSName target); includeboilerplate(SRV) uint16_t d_weight, d_port; DNSName d_target; uint16_t d_preference; }; .. code-block:: cpp class DNSResourceRecord { public: DNSResourceRecord() : last_modified(0), ttl(0), signttl(0), domain_id(UnknownDomainID), qclass(1), scopeMask(0), auth(true), disabled(false) {}; static DNSResourceRecord fromWire(const DNSRecord& d); void setContent(const string& content); string getZoneRepresentation(bool noDot=false) const; DNSName qname; //!< the name of this record, for example: www.powerdns.com DNSName ordername; DNSName wildcardname; string content; //!< what this record points to. Example: 10.1.2.3 uint32_t ttl; //!< Time To Live of this record uint32_t signttl; //!< If non-zero, use this TTL as original TTL in the RRSIG domainid_t domain_id; //!< If a backend implements this, the domain_id of the zone this record is in QType qtype; //!< qtype of this record, ie A, CNAME, MX etc uint16_t qclass; //!< class of this record uint8_t scopeMask; bool auth; bool disabled; bool operator==(const DNSResourceRecord& rhs); bool operator<(const DNSResourceRecord &b); ``DNSResourceRecord`` holds a DNS record with content in presentation format, as a string. --- Compiling PowerDNS ================== PowerDNS can be compiled with modules built in, or with modules designed to be loaded at runtime. All that is configured before compiling using the well known autoconf/automake system:: tar xf pdns-VERSION.tar.bz2 cd pdns-VERSION ./configure --with-modules=$MODULES --with-dynmodules=$DYNMODULES make make install To compile in modules, specify them as ``--with-modules='mod1 mod2 mod3'``, substituting the desired module names. See each :doc:`backend specific documentation <../backends/index>` for the module names. Each backend has a module name that you look up in this table. To compile a module for inclusion at runtime, which is great if you are a unix vendor, use ``--with-dynmodules='mod1 mod2 mod3'``. These modules then end up as .so files in the compiled ``libdir``. By default, the :doc:`bind <../../backends/bind>`, :doc:`mysql <../../backends/generic-mysql>` and :doc:`random <../../backends/random>` modules are compiled into the binary. The :doc:`pipe <../../backends/pipe>` is, by default, compiled as a runtime loadable module. Getting the sources ------------------- There are 3 ways of getting the source. If you want the bleeding edge, you can clone the `repository at GitHub `__ and run ``autoreconf -vi`` in the clone. You can also download `snapshot tarballs `__. You can also download releases on the `website `__. These releases are PGP-signed with one of these key-ids: .. include:: ../common/tarball-pgp-keys.rst Dependencies ------------ To build the PowerDNS Authoritative Server, a C++ compiler with support for C++ 2017 is required. This means gcc 7.1 and newer and clang 5 and newer. Furthermore, the Makefiles require GNU make, not BSD make. By default, the PowerDNS Authoritative Server requires the following libraries and headers: * `Boost `_ 1.54 or newer * `OpenSSL `_ To build from a Git repository clone, the following dependencies are also required: * `ragel `_ * `bison `_ * `flex `_ * `Python `_ 3.6 or newer, with the 'venv' package Optional dependencies --------------------- Several options that can be passed to ``./configure`` can enable and disable different features. These will require additional dependencies ed25519 support with libsodium ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The PowerDNS Authoritative Server can link with `libsodium `_ to support ed25519 (DNSSEC algorithm 15). To detect libsodium, use the ``--with-libsodium`` configure option. systemd notify support ^^^^^^^^^^^^^^^^^^^^^^ During configure, ``configure`` will attempt to detect the availability of `systemd or systemd-daemon `_ headers. To force the use of systemd (and failing configure if the headers do not exist), use ``--enable-systemd``. To set the directory where the unit files should be installed, use ``--with-systemd=/path/to/unit/dir``. --- Cryptographic software and export control ========================================= In certain legal climates, PowerDNS might potentially require an export control status, particularly since PowerDNS software contains cryptographic primitives. PowerDNS does not itself implement any cryptographic algorithms but relies on third-party implementations of AES, RSA, ECDSA, GOST, MD5 and various SHA-based hashing algorithms. Starting with 4.0.0, PowerDNS will link in hash and cryptographic primitives from the open source `OpenSSL `_ library. Optionally, PowerDNS can link in a copy of the open source `Botan `_ cryptographic library. Starting with 4.2.0, linking in Botan is no longer possible. Optionally, PowerDNS can link in a copy of the open source `Sodium `_ library. Specific United States Export Control Notes ------------------------------------------- PowerDNS is not "US Origin" software. For re-export, like most open source, publicly available "mass market" projects, PowerDNS is considered to be governed by section 740.13(e) of the US EAR, "Unrestricted encryption source code", under which PowerDNS source code would be considered re-exportable from the US without an export license under License Exception TSU (Technology and Software - Unrestricted). Like most open source projects containing some encryption, the ECCN that best fits PowerDNS software is 5D002. The official link to the publicly available source code is `https://downloads.powerdns.com/releases`. If absolute certainty is required, we recommend consulting an expert in US Export Control, or asking the BIS for confirmation. --- Internals ========= 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, a REFUSED is returned. --- Supported Record Types ====================== This chapter lists all record types PowerDNS supports, and how they are stored in backends. The list is mostly alphabetical but some types are grouped. .. warning:: Host names and the MNAME of a SOA records are NEVER terminated with a '.' in PowerDNS storage! If a trailing '.' is present it will inevitably cause problems, problems that may be hard to debug. Use ``pdnsutil zone check`` (or ``pdnsutil check-zone`` prior to version 5.0) to validate your zone data. .. note:: Whenever the storage format is mentioned, this relates only to the way that the record should be stored in one of the :doc:`generic SQL <../backends/generic-sql>` backends. The other backends should use their *native* format. The PowerDNS Recursor can serve and store all record types, regardless of whether these are explicitly supported. .. _types-a: A - The A record contains an IP address. It is stored as a decimal dotted quad string, for example: '203.0.113.210'. .. _types-aaaa: AAAA ---- The AAAA record contains an IPv6 address. An example: '2001:DB8:2000:bf0::1'. .. _types-afsdb: AFSDB ----- A specialised record type for the 'Andrew Filesystem'. Stored as: '#subtype hostname', where subtype is a number. .. _types-alias: ALIAS ----- The ALIAS pseudo-record type is supported to provide CNAME-like mechanisms on a zone's apex. See the :doc:`howto <../guides/alias>` for information on how to configure PowerDNS to serve records synthesized from ALIAS records. .. _types-apl: APL ----- The APL record, specified in :rfc:`3123`, is used to specify a DNS RR type "APL" for address prefix lists. .. _types-caa: CAA --- The "Certification Authority Authorization" record, specified in :rfc:`6844`, is used to specify Certificate Authorities that may issue certificates for a domain. .. _types-cert: CERT ---- Specialised record type for storing certificates, defined in :rfc:`2538`. .. _types-cdnskey: CDNSKEY ------- The CDNSKEY (:rfc:`Child DNSKEY <7344#section-3.2>`) type is supported. .. _types-cds: CDS --- The CDS (:rfc:`Child DS <7344#section-3.1>`) type is supported. .. _types-cname: CNAME ----- The CNAME record specifies the canonical name of a record. It is stored plainly. Like all other records, it is not terminated by a dot. A sample might be 'webserver-01.yourcompany.com'. .. _types-csync: CSYNC ----- The CSYNC record is used for 'Child-to-Parent Synchronization in DNS', as described in :rfc:`7477`. Right now it is only supported as zone content; no special processing is implemented. Note that SOA-EDIT is not applied to serial numbers in CSYNC content. .. _types-dnskey: DNSKEY ------ The DNSKEY DNSSEC record type is fully supported, as described in :rfc:`4034`. Enabling DNSSEC for domains can be done with :doc:`pdnsutil <../dnssec/pdnsutil>`. .. _types-dname: DNAME ----- The DNAME record, as specified in :rfc:`6672` is supported. However, :ref:`setting-dname-processing` has to be set to ``yes`` for PowerDNS to process these records. .. _types-ds: DS -- The DS DNSSEC record type is fully supported, as described in :rfc:`4034`. Enabling DNSSEC for domains can be done with :doc:`pdnsutil <../dnssec/pdnsutil>`. .. _types-hinfo: HINFO ----- Hardware Info record, used to specify CPU and operating system. Stored with a single space separating these two, example: 'i386 Linux'. .. _types-https: HTTPS ----- See :ref:`SVCB ` for more information. .. _types-key: KEY --- The KEY record is fully supported. For its syntax, see :rfc:`2535`. .. _types-loc: LOC --- The LOC record is fully supported. For its syntax, see :rfc:`1876`. A sample content would be: ``51 56 0.123 N 5 54 0.000 E 4.00m 1.00m 10000.00m 10.00m`` .. _types-mx: MX -- The MX record specifies a mail exchanger host for a domain. Each mail exchanger also has a priority or preference. For example ``10 mx.example.net``. In the generic SQL backends, the ``10`` should go in the 'priority field'. .. _types-naptr: NAPTR ----- Naming Authority Pointer, :rfc:`2915`. Stored as follows: :: '100 50 "s" "z3950+I2L+I2C" "" _z3950._tcp.gatech.edu'. The fields are: order, preference, flags, service, regex, replacement. Note that the replacement is not enclosed in quotes, and should not be. The replacement may be omitted, in which case it is empty. See also :rfc:`2916` for how to use NAPTR for ENUM (E.164) purposes. .. _types-ns: NS -- Nameserver record. Specifies nameservers for a domain. Stored plainly: ``ns1.powerdns.com``, as always without a terminating dot. NSEC, NSEC3, NSEC3PARAM ----------------------- The NSEC, NSEC3 and NSEC3PARAM DNSSEC record type are fully supported, as described in :rfc:`4034`. Enabling DNSSEC for domains can be done with :doc:`pdnsutil <../dnssec/pdnsutil>`. .. _types-openpgpkey: OPENPGPKEY ---------- The OPENPGPKEY records, specified in :rfc:`7929`, are used to bind OpenPGP certificates to email addresses. .. _types-ptr: PTR --- Reverse pointer, used to specify the host name belonging to an IP or IPv6 address. Name is stored plainly: ``www.powerdns.com``. As always, no terminating dot. .. _types-rp: RP -- Responsible Person record, as described in :rfc:`1183`. Stored with a single space between the mailbox name and the more-information pointer. Example: ``peter.powerdns.com peter.people.powerdns.com``, to indicate that ``peter@powerdns.com`` is responsible and that more information about peter is available by querying the TXT record of peter.people.powerdns.com. .. _types-rrsig: RRSIG ----- The RRSIG DNSSEC record type is fully supported, as described in :rfc:`4034`. .. _types-soa: SMIMEA ------ Since 4.1. The SMIMEA record type, specified in :rfc:`8162`, is used to bind S/MIME certificates to domains. .. _types-txt: SOA --- The Start of Authority record is one of the most complex available. It specifies a lot about a domain: the name of the primary nameserver ('the primary'), the hostmaster and a set of numbers indicating how the data in this domain expires and how often it needs to be checked. Further more, it contains a serial number which should rise on each change of the domain. The stored format is: :: primary hostmaster serial refresh retry expire minimum Besides the primary and the hostmaster, all fields are numerical. The fields have complicated and sometimes controversial meanings. .. _types-spf: SPF --- SPF records can be used to store Sender Policy Framework details (:rfc:`4408`). .. _types-sshfp: SSHFP ----- The SSHFP record type, used for storing Secure Shell (SSH) fingerprints, is fully supported. A sample from :rfc:`4255` is:: 2 1 123456789abcdef67890123456789abcdef67890 .. _types-srv: SRV --- SRV records can be used to encode the location and port of services on a domain name. When encoding, the priority field is used to encode the priority. For example, ``_ldap._tcp.dc._msdcs.conaxis.ch SRV 0 100 389 mars.conaxis.ch`` would be encoded with ``0`` in the priority field and ``100 389 mars.conaxis.ch`` in the content field. .. _types-svcb: SVCB, HTTPS ----------- .. versionadded:: 4.4.0 SVCB records, defined in (`draft-ietf-dnsop-svcb-https-07 `__) are used to facilitate the lookup of information needed to make connections to network services. SVCB records allow a service to be provided from multiple alternative endpoints, each with associated parameters (such as transport protocol configuration and keys for encrypting the TLS ClientHello). They also enable aliasing of apex domains, which is not possible with CNAME. The HTTPS RR is a variation of SVCB for HTTPS and HTTP origins. Additional processing is supported for these types. Some :doc:`PowerDNS extensions <../guides/svcb>` for automatic IP address hints exist as well. TKEY, TSIG ---------- The TKEY (:rfc:`2930`) and TSIG records (:rfc:`2845`), used for key-exchange and authenticated AXFRs, are supported. See the :doc:`../tsig` and `DNS update <../dnsupdate>` documentation for more information. .. _types-tlsa: TLSA ---- Since 3.0. The TLSA records, specified in :rfc:`6698`, are used to bind SSL/TLS certificate to named hosts and ports. .. _types-smimea: TXT --- The TXT field can be used to attach textual data to a domain. Text is stored plainly, PowerDNS understands content not enclosed in quotes. However, all quotes characters (``"``) in the TXT content must be preceded with a backslash (``\``).: :: "This \"is\" valid" For a literal backslash in the TXT record, escape it: :: "This is also \\ valid" Unicode characters can be added in two ways, either by adding the character itself or the escaped variant to the content field. e.g. ``"ç"`` is equal to ``"\195\167"``. When a TXT record is longer than 255 characters/bytes (excluding possible enclosing quotes), PowerDNS will cut up the content into 255 character/byte chunks for transmission to the client. .. _types-uri: URI --- The URI record, specified in :rfc:`7553`, is used to publish mappings from hostnames to URIs. ZONEMD ------ The ZONEMD record, specified in :rfc:`8976`, is used to validate zones. Other types ----------- The following, rarely used or obsolete record types, are also supported: - DHCID (:rfc:`4701`) - DLV (:rfc:`4431`) - EUI48/EUI64 (:rfc:`7043`) - IPSECKEY (:rfc:`4025`) - KEY (:rfc:`2535`, obsolete) - KX (:rfc:`2230`) - L32 (:rfc:`6742`) - L64 (:rfc:`6742`) - LP (:rfc:`6742`) - MINFO (:rfc:`1035`) - MR (:rfc:`1035`) - NID (:rfc:`6742`) - RKEY (`draft-reid-dnsext-rkey-00.txt `__) .. _types-unknown: Unknown DNS Resource Record (RR) Types -------------------------------------- PowerDNS supports (:rfc:`3597`) syntax for serving unknown record types. For example :: e.example. IN TYPE1 \# 4 0A000001 Beware that PowerDNS will attempt to parse known record types even if written in this syntax. This bug will be fixed in a future release. --- BIND zone file backend ====================== * Native: Yes * Primary: Yes * Secondary: Yes * Producer: No * Consumer: No * Autosecondary: Experimental * DNS Update: No * DNSSEC: Yes * Disabled data: No * Comments: No * Search: Yes * Views: No * API: Read-only * Multiple instances: No * Zone caching: Yes * Module name: bind * Launch: ``bind`` The BIND backend started life as a demonstration of the versatility of PowerDNS but quickly gained in importance when there appeared to be demand for a BIND 'work-alike'. The BIND backend parses a BIND-style ``named.conf`` and extracts information about zones from it. It makes no attempt to honour other configuration flags, which you should configure (when available) using the PowerDNS native configuration. Unique to this PowerDNS backend is that it serves from plain zone files, which allows for hand-crafting zone files, only takes a tiny footprint in terms of server resource usage while being :ref:`performant efficiently `. .. note:: Because this backend retrieves its configuration from plain files and not a database, the HTTP API is unable to process changes for this backend. This effectively makes the API read-only for zones hosted by the BIND backend. Configuration Parameters ------------------------ .. _setting-bind-config: ``bind-config`` ~~~~~~~~~~~~~~~ Location of the BIND configuration file to parse. PowerDNS does not support every directive supported by BIND. It supports the following blocks and directives: * ``options`` * ``directory`` * ``also-notify`` * ``zone`` * ``file`` * ``type`` * ``masters`` * ``primaries`` (added in version 4.9.0) * ``also-notify`` Unknown directives will be ignored. .. _setting-bind-check-interval: ``bind-check-interval`` ~~~~~~~~~~~~~~~~~~~~~~~ Interval in seconds to check for zone file changes. Default is 0 (disabled). See :ref:`bind-operation` section for more information. .. _setting-bind-dnssec-db: ``bind-dnssec-db`` ~~~~~~~~~~~~~~~~~~ Filename to store and access our DNSSEC metadatabase, empty for none. To run secondary DNSSEC-enabled domains (where the RRSIGS are in the AXFR), a ``bind-dnssec-db`` is required. This is because the :ref:`metadata-presigned` domain metadata is set during the zonetransfer. You can use ``pdnsutil create-bind-db`` to make this database file for you. .. warning:: If this is left empty on slaves and a presigned zone is transferred, it will (silently) serve it without DNSSEC. This in turn results in serving the domain as bogus. .. _setting-bind-dnssec-db-journal-mode: ``bind-dnssec-db-journal-mode`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SQLite3 journal mode to set. The default is WAL. Set to empty to leave the journal mode alone. .. _setting-bind-hybrid: ``bind-hybrid`` ~~~~~~~~~~~~~~~ Store DNSSEC keys and metadata storage in another backend. See the :ref:`dnssec-modes-hybrid-bind` documentation. .. _setting-bind-ignore-broken-records: ``bind-ignore-broken-records`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Setting this option to ``yes`` makes PowerDNS ignore out of zone records when loading zone files. Autoprimary support (experimental) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. _setting-bind-autoprimaries: ``bind-autoprimaries`` ~~~~~~~~~~~~~~~~~~~~~~ .. versionchanged:: 4.9.0 This was called ``bind-supermasters`` before 4.9.0. Specifies file where to read list of autoprimaries. BIND backend only checks IP address of primary server. The file must contain one IP and account per line, separated by whitespace. BIND backend can only read this file, not write it. .. _setting-bind-autoprimary-config: ``bind-autoprimary-config`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. versionchanged:: 4.9.0 This was called ``bind-supermaster-config`` before 4.9.0. When a new zone is configured via the autosecondary mechanism, bindbackend *writes* a zone entry to this file. Your ``bind-config`` file should have an ``include`` statement to make sure this file is read on startup. .. _setting-bind-autoprimary-destdir: ``bind-autoprimary-destdir`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. versionchanged:: 4.9.0 This was called ``bind-supermaster-destdir`` before 4.9.0. Each new zone configured via the autosecondary mechanism gets a zone file in this directory. This directory must be writable. .. _bind-operation: Operation --------- On launch, the BIND backend first parses the ``named.conf`` to determine which zones need to be loaded. These will then be parsed and made available for serving, as they are parsed. So a ``named.conf`` with 100.000 zones may take 20 seconds to load, but after 10 seconds, 50.000 zones will already be available. While a domain is being loaded, it is not yet available, to prevent incomplete answers. Reloading is currently done only when a request (or zone transfer) for a zone comes in, and then only after :ref:`setting-bind-check-interval` seconds have passed since the last check. If a change occurred, access to the zone is disabled, the file is reloaded, access is restored, and the question is answered. For regular zones, reloading is fast enough to answer the question which lead to the reload within the DNS timeout. If :ref:`setting-bind-check-interval` is specified as zero, no checks will be performed until the ``pdns_control reload`` command is issued. Please note that also the :ref:`setting-xfr-cycle-interval` setting controls how often a primary would notify a secondary about changes. Especially in 'hidden primary' configurations, where servers usually don't receive regular queries, you may want to lower that setting to a value as low as :ref:`setting-bind-check-interval`. pdns\_control commands ---------------------- ``bind-add-zone `` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Add zone ``domain`` from ``filename`` to PowerDNS's BIND backend. Zone will be loaded at first request. .. note:: This does not add the zone to the :ref:`setting-bind-config` file. ``bind-domain-extended-status [domain ...]`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. versionadded:: 4.3.0 Output an extended status of a domain or domains, containing much more information than the simple domain status, like the number of records currently loaded, whether pdns is primary or secondary for the domain, the list of primaries, various timers, etc ``bind-domain-status [domain ...]`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Output status of domain or domains. Can be one of: * ``seen in named.conf, not parsed``, * ``parsed successfully at