+++ /dev/null
-Dynamic DNS Update (RFC2136)
-============================
-
-Starting with the PowerDNS Authoritative Server 3.4.0, DNS update
-support is available. There are a number of items NOT supported:
-
-- There is no support for GSS\*TSIG and SIG (TSIG is supported);
-- WKS records are specifically mentioned in the RFC, we don't
- specifically care about WKS records;
-- Anything we forgot....
-
-The implementation requires the backend to support a number of new
-operations. Currently, the following backends have been modified to
-support DNS update:
-
-- :doc:`gmysql <backends/generic-mysql>`
-- :doc:`gpgsql <backends/generic-postgresql>`
-- :doc:`gsqlite3 <backends/generic-sqlite3>`
-- :doc:`goracle <backends/generic-oracle>`
-- :doc:`godbc <backends/generic-odbc>`
-
-.. _dnsupdate-configuration-options:
-
-Configuration options
----------------------
-
-There are two configuration parameters that can be used within the
-powerdns configuration file.
-
-``dnsupdate``
-~~~~~~~~~~~~~
-
-A setting to enable/disable DNS update support completely. The default
-is no, which means that DNS updates are ignored by PowerDNS (no message
-is logged about this!). Change the setting to ``dnsupdate=yes`` to
-enable DNS update support. Default is ``no``.
-
-``allow-dnsupdate-from``
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-A list of IP ranges that are allowed to perform updates on any domain.
-The default is ``127.0.0.0/8``, which means that all loopback addresses are accepted.
-Multiple entries can be used on this line
-(``allow-dnsupdate-from=198.51.100.0/8 203.0.113.2/32``). The option can
-be left empty to disallow everything, this then should be used in
-combination with the ``ALLOW-DNSUPDATE-FROM`` :doc:`domain metadata <domainmetadata>` setting per
-zone. Setting a range here and in ``ALLOW-DNSUPDATE-FROM`` enables updates
-from either address range.
-
-``forward-dnsupdate``
-~~~~~~~~~~~~~~~~~~~~~
-
-Tell PowerDNS to forward to the master server if the zone is configured
-as slave. Masters are determined by the masters field in the domains
-table. The default behaviour is enabled (yes), which means that it will
-try to forward. In the processing of the update packet, the
-``allow-dnsupdate-from`` and ``TSIG-ALLOW-DNSUPDATE`` are processed
-first, so those permissions apply before the ``forward-dnsupdate`` is
-used. It will try all masters that you have configured until one is
-successful.
-
-.. _dnsupdate-lua-dnsupdate-policy-script:
-
-``lua-dnsupdate-policy-script``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Use this Lua script containing function ``updatepolicy`` to validate
-each update. This will ``TURN OFF`` all other
-authorization methods, and you are expected to take care of everything
-yourself. See :ref:`dnsupdate-update-policy` for details and
-examples.
-
-The semantics are that first a dynamic update has to be allowed either
-by the global :ref:`setting-allow-dnsupdate-from` setting, or by a per-zone
-``ALLOW-DNSUPDATE-FROM`` metadata setting.
-
-Secondly, if a zone has a ``TSIG-ALLOW-DNSUPDATE`` metadata setting, that
-must match too.
-
-So to only allow dynamic DNS updates to a zone based on TSIG key, and
-regardless of IP address, set :ref:`setting-allow-dnsupdate-from` to empty, set
-``ALLOW-DNSUPDATE-FROM`` to "0.0.0.0/0" and "::/0" and set the
-``TSIG-ALLOW-DNSUPDATE`` to the proper key name.
-
-Further information can be found :ref:`below <dnsupdate-how-it-works>`.
-
-.. _dnsupdate-metadata:
-
-Per zone settings
------------------
-
-For permissions, a number of per zone settings are available via the
-:doc:`domain metadata `<domainmetadata>`.
-
-.. _metadata-allow-dnsupdate-from:
-
-ALLOW-DNSUPDATE-FROM
-~~~~~~~~~~~~~~~~~~~~
-
-This setting has the same function as described in the configuration
-options (See ref:`above <dnsupdate-configuration-options>`). Only one item is
-allowed per row, but multiple rows can be added. An example:
-
-::
-
- sql> select id from domains where name='example.org';
- 5
- sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘ALLOW-DNSUPDATE-FROM’,’198.51.100.0/8’);
- sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘ALLOW-DNSUPDATE-FROM’,’203.0.113.2/32’);
-
-This will allow 198.51.100.0/8 and 203.0.113.2/32 to send DNS update
-messages for the example.org domain.
-
-.. _metadata-tsig-allow-dnsupdate:
-
-TSIG-ALLOW-DNSUPDATE
-~~~~~~~~~~~~~~~~~~~~
-
-This setting allows you to set the TSIG key required to do an DNS
-update. If you have GSS-TSIG enabled, you can use Kerberos principals
-here. An example, using :program:`pdnsutil` to create the key:
-
-::
-
- pdnsutil generate-tsig-key test hmac-md5
- Create new TSIG key test hmac-md5 kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=
-
- sql> insert into tsigkeys (name, algorithm, secret) values ('test', 'hmac-md5', 'kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=');
- sql> select id from domains where name='example.org';
- 5
- sql> insert into domainmetadata (domain_id, kind, content) values (5, 'TSIG-ALLOW-DNSUPDATE', 'test');
-
-An example of how to use a TSIG key with the :program:`nsupdate` command:
-
-::
-
- nsupdate <<!
- server <ip> <port>
- zone example.org
- update add test1.example.org 3600 A 203.0.113.1
- key test kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=
- send
- !
-
-If a TSIG key is set for the domain, it is required to be used for the
-update. The TSIG is an alternative means of securing updates, instead of using the
-``ALLOW-DNSUPDATE-FROM`` setting. If a TSIG key is set, and if ``ALLOW-DNSUPDATE-FROM`` is set,
-the IP(-range) of the updater still needs to be allowed via ``ALLOW-DNSUPDATE-FROM``.
-
-.. _metadata-forward-dnsupdate:
-
-FORWARD-DNSUPDATE
-~~~~~~~~~~~~~~~~~
-
-See `Configuration options <dnsupdate-configuration-options>` for what it does,
-but per domain.
-
-::
-
- sql> select id from domains where name='example.org';
- 5
- sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘FORWARD-DNSUPDATE’,’’);
-
-There is no content, the existence of the entry enables the forwarding.
-This domain-specific setting is only useful when the configuration
-option :ref:`setting-forward-dnsupdate` is set to 'no', as that will disable it
-globally. Using the domainmetadata setting than allows you to enable it
-per domain.
-
-.. _metadata-notify-dnsupdate:
-
-NOTIFY-DNSUPDATE
-~~~~~~~~~~~~~~~~
-
-Send a notification to all slave servers after every update. This will
-speed up the propagation of changes and is very useful for acme
-verification.
-
-::
-
- sql> select id from domains where name='example.org';
- 5
- sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘NOTIFY-DNSUPDATE’,’1’);
-
-.. _metadata-soa-edit-dnsupdate:
-
-SOA-EDIT-DNSUPDATE
-~~~~~~~~~~~~~~~~~~
-
-This configures how the soa serial should be updated. See
-:ref:`below <dnsupdate-soa-serial-updates>`.
-
-.. _dnsupdate-soa-serial-updates:
-
-SOA Serial Updates
-------------------
-
-After every update, the soa serial is updated as this is required by
-section 3.7 of :rfc:`2136`. The behaviour is configurable via domainmetadata
-with the ``SOA-EDIT-DNSUPDATE`` option. It has a number of options listed
-below. If no behaviour is specified, DEFAULT is used.
-
-:rfc:`2136, Section 3.6 <2136#section-3.6>` defines some specific behaviour for updates of SOA
-records. Whenever the SOA record is updated via the update message, the
-logic to change the SOA is not executed.
-
-.. note::
- Powerdns will always use :ref:`metadata-soa-edit` when serving SOA
- records, thus a query for the SOA record of the recently update domain,
- might have an unexpected result due to a SOA-EDIT setting.
-
-An example:
-
-::
-
- sql> select id from domains where name='example.org';
- 5
- sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘SOA-EDIT-DNSUPDATE’,’INCREASE’);
-
-This will make the SOA Serial increase by one, for every successful
-update.
-
-SOA-EDIT-DNSUPDATE settings
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-These are the settings available for **SOA-EDIT-DNSUPDATE**.
-
-- DEFAULT: Generate a soa serial of YYYYMMDD01. If the current serial
- is lower than the generated serial, use the generated serial. If the
- current serial is higher or equal to the generated serial, increase
- the current serial by 1.
-- INCREASE: Increase the current serial by 1.
-- EPOCH: Change the serial to the number of seconds since the EPOCH,
- aka unixtime.
-- SOA-EDIT: Change the serial to whatever SOA-EDIT would provide. See
- :doc:`Domain metadata <domainmetadata>`
-- SOA-EDIT-INCREASE: Change the serial to whatever SOA-EDIT would
- provide. If what SOA-EDIT provides is lower than the current serial,
- increase the current serial by 1.
-
-DNS update How-to: Setup dyndns/rfc2136 with dhcpd
---------------------------------------------------
-
-DNS update is often used with DHCP to automatically provide a hostname
-whenever a new IP-address is assigned by the DHCP server. This section
-describes how you can setup PowerDNS to receive DNS updates from ISC's
-dhcpd (version 4.1.1-P1).
-
-Setting up dhcpd
-~~~~~~~~~~~~~~~~
-
-We're going to use a TSIG key for security. We're going to generate a
-key using the following command:
-
-::
-
- dnssec-keygen -a hmac-md5 -b 128 -n USER dhcpdupdate
-
-This generates two files (Kdhcpdupdate.*.key and
-Kdhcpdupdate.*.private). You're interested in the .key file:
-
-::
-
- # ls -l Kdhcp*
- -rw------- 1 root root 53 Aug 26 19:29 Kdhcpdupdate.+157+20493.key
- -rw------- 1 root root 165 Aug 26 19:29 Kdhcpdupdate.+157+20493.private
-
- # cat Kdhcpdupdate.+157+20493.key
- dhcpdupdate. IN KEY 0 3 157 FYhvwsW1ZtFZqWzsMpqhbg==
-
-The important bits are the name of the key (**dhcpdupdate**) and the
-hash of the key (**FYhvwsW1ZtFZqWzsMpqhbg==**
-
-Using the details from the key you've just generated. Add the following
-to your dhcpd.conf:
-
-::
-
- key "dhcpdupdate" {
- algorithm hmac-md5;
- secret "FYhvwsW1ZtFZqWzsMpqhbg==";
- };
-
-You must also tell dhcpd that you want dynamic dns to work, add the
-following section:
-
-::
-
- ddns-updates on;
- ddns-update-style interim;
- update-static-leases on;
-
-This tells dhcpd to:
-
-1. Enable Dynamic DNS
-2. Which style it must use (interim)
-3. Update static leases as well
-
-For more information on this, consult the dhcpd.conf manual.
-
-Per subnet, you also have to tell **dhcpd** which (reverse-)domain it
-should update and on which master domain server it is running.
-
-::
-
- ddns-domainname "example.org";
- ddns-rev-domainname "in-addr.arpa.";
-
- zone example.org {
- primary 127.0.0.1;
- key dhcpdupdate;
- }
-
- zone 1.168.192.in-addr.arpa. {
- primary 127.0.0.1;
- key dhcpdupdate;
- }
-
-This tells **dhcpd** a number of things:
-
-1. Which domain to use (**ddns-domainname "example.org";**)
-2. Which reverse-domain to use (**dnssec-rev-domainname
- "in-addr.arpa.";**)
-3. For the zones, where the primary master is located (**primary
- 127.0.0.1;**)
-4. Which TSIG key to use (**key dhcpdupdate;**). We defined the key
- earlier.
-
-This concludes the changes that are needed to the **dhcpd**
-configuration file.
-
-Setting up PowerDNS
-~~~~~~~~~~~~~~~~~~~
-
-A number of small changes are needed to powerdns to make it accept
-dynamic updates from **dhcpd**.
-
-Enabled DNS update (:rfc:`2136`) support functionality in PowerDNS by adding
-the following to the PowerDNS configuration file (pdns.conf).
-
-::
-
- dnsupdate=yes
- allow-dnsupdate-from=
-
-This tells PowerDNS to:
-
-1. Enable DNS update support(:ref:`setting-dnsupdate`)
-2. Allow updates from NO ip-address (":ref:`setting-allow-dnsupdate-from`\ =")
-
-We just told powerdns (via the configuration file) that we accept
-updates from nobody via the :ref:`setting-allow-dnsupdate-from`
-parameter. That's not very useful, so we're going to give permissions
-per zone (including the appropriate reverse zone), via the
-domainmetadata table.
-
-::
-
- sql> select id from domains where name='example.org';
- 5
- sql> insert into domainmetadata(domain_id, kind, content) values(5, 'ALLOW-DNSUPDATE-FROM','127.0.0.1');
- sql> select id from domains where name='1.168.192.in-addr.arpa';
- 6
- sql> insert into domainmetadata(domain_id, kind, content) values(6, 'ALLOW-DNSUPDATE-FROM','127.0.0.1');
-
-This gives the ip '127.0.0.1' access to send update messages. Make sure
-you use the ip address of the machine that runs **dhcpd**.
-
-Another thing we want to do, is add TSIG security. This can only be done
-via the domainmetadata table:
-
-::
-
- sql> insert into tsigkeys (name, algorithm, secret) values ('dhcpdupdate', 'hmac-md5', 'FYhvwsW1ZtFZqWzsMpqhbg==');
- sql> select id from domains where name='example.org';
- 5
- sql> insert into domainmetadata (domain_id, kind, content) values (5, 'TSIG-ALLOW-DNSUPDATE', 'dhcpdupdate');
- sql> select id from domains where name='1.168.192.in-addr.arpa';
- 6
- sql> insert into domainmetadata (domain_id, kind, content) values (6, 'TSIG-ALLOW-DNSUPDATE', 'dhcpdupdate');
-
-This will:
-
-1. Add the 'dhcpdupdate' key to our PowerDNSinstallation
-2. Associate the domains with the given TSIG key
-
-Restart PowerDNS and you should be ready to go!
-
-.. _dnsupdate-how-it-works:
-
-How it works
-------------
-
-This is a short description of how DNS update messages are processed by
-PowerDNS.
-
-1. The DNS update message is received. If it is TSIG signed, the TSIG
- is validated against the tsigkeys table. If it is not valid, Refused
- is returned to the requestor.
-2. A check is performed on the zone to see if it is a valid zone.
- ServFail is returned when not valid.
-3. The **dnsupdate** setting is checked. Refused is returned when the
- setting is 'no'.
-4. If update policy Lua script is provided then next two steps are
- skipped.
-5. If the **ALLOW-DNSUPDATE-FROM** has a value (from both
- domainmetadata and the configuration file), a check on the value is
- performed. If the requestor (sender of the update message) does not
- match the values in **ALLOW-DNSUPDATE-FROM**, Refused is returned.
-6. If the message is TSIG signed, the TSIG keyname is compared with the
- TSIG keyname in domainmetadata. If they do not match, a Refused is
- send. The TSIG-ALLOW-DNSUPDATE domainmetadata setting is used to
- find which key belongs to the domain.
-7. The backends are queried to find the backend for the given domain.
-8. If the domain is a slave domain, the **forward-dnsupdate** option
- and domainmetadata settings are checked. If forwarding to a master
- is enabled, the message is forward to the master. If that fails, the
- next master is tried until all masters are tried. If all masters
- fail, ServFail is returned. If a master succeeds, the result from
- that master is returned.
-9. A check is performed to make sure all updates/prerequisites are for
- the given zone. NotZone is returned if this is not the case.
-10. The transaction with the backend is started.
-11. The prerequisite checks are performed (section 3.2 of :rfc:`2136 <2136#section-3.2>`). If a
- check fails, the corresponding RCode is returned. No further
- processing will happen.
-12. Per record in the update message, a the prescan checks are
- performed. If the prescan fails, the corresponding RCode is
- returned. If the prescan for the record is correct, the actual
- update/delete/modify of the record is performed. If the update fails
- (for whatever reason), ServFail is returned. After changes to the
- records have been applied, the ordername and auth flag are set to
- make sure DNSSEC remains working. The cache for that record is
- purged.
-13. If there are records updated and the SOA record was not modified,
- the SOA serial is updated. See :ref:`dnsupdate-soa-serial-updates`. The cache for this record is
- purged.
-14. The transaction with the backend is committed. If this fails,
- ServFail is returned.
-15. NoError is returned.
-
-.. _dnsupdate-update-policy:
-
-Update policy
--------------
-
-.. versionadded:: 4.1.0
-
-You can define a Lua script to handle DNS UPDATE message
-authorization. The Lua script is to contain at least function called
-``updatepolicy`` which accepts one parameter. This parameter is an
-object, containing all the information for the request. To permit
-change, return true, otherwise return false. The script is called for
-each record at a time and you can approve or reject any or all.
-
-The object has following methods available:
-
-- DNSName getQName() - name to update
-- DNSName getZonename() - zone name
-- int getQType() - record type, it can be 255(ANY) for delete.
-- ComboAddress getLocal() - local socket address
-- ComboAddress getRemote() - remote socket address
-- Netmask getRealRemote() - real remote address (or netmask if EDNS Subnet is used)
-- DNSName getTsigName() - TSIG **key** name (you can assume it is validated here)
-- string getPeerPrincipal() - Return peer principal name (user@DOMAIN, service/machine.name@DOMAIN, host/MACHINE$@DOMAIN)
-
-There are many same things available as in recursor Lua scripts, but
-there is also resolve(qname, qtype) which returns array of records.
-Example:
-
-::
-
- resolve("www.google.com", pdns.A)
-
-You can use this to perform DNS lookups. If your resolver cannot find
-your local records, then this will not find them either. In other words,
-resolve does not perform local lookup.
-
-Simple example script:
-
-.. code:: lua
-
- --- This script is not suitable for production use
-
- function strpos (haystack, needle, offset)
- local pattern = string.format("(%s)", needle)
- local i = string.find (haystack, pattern, (offset or 0))
- return (i ~= nil and i or false)
- end
-
- function updatepolicy(input)
- princ = input:getPeerPrincipal()
-
- if princ == ""
- then
- return false
- end
-
- if princ == "admin@DOMAIN" or input:getRemote():toString() == "192.168.1.1"
- then
- return true
- end
-
- if (input:getQType() == pdns.A or input:getQType() == pdns.AAAA) and princ:sub(5,5) == '/' and strpos(princ, "@", 0) ~= false
- then
- i = strpos(princ, "@", 0)
- if princ:sub(i) ~= "@DOMAIN"
- then
- return false
- end
- hostname = princ:sub(6, i-1)
- if input:getQName():toString() == hostname .. "." or input:getQName():toString() == hostname .. "." .. input:getZoneName():toString()
- then
- return true
- end
- end
-
- return false
- end
domainmetadata
dnsupdate
tsig
- lua-records
+ lua-records/index
guides/index
backends/index
http-api/index
-Lua Records
-===========
-
-To facilitate dynamic behaviour, such as Global Server Load Balancing,
-PowerDNS Authoritative Server version 4.2 and later support dynamic DNS
-records.
-
-These records contain small snippets of configuration that enable dynamic
-behaviour based on requester IP address, requester's EDNS Client Subnet,
-server availability or other factors.
-
-Capabilities range from very simple to highly advanced multi-pool
-geographically & weighed load balanced IP address selection.
-
-Although users need not be aware, PowerDNS dynamic DNS records are actually
-tiny (or larger) `Lua <https://www.lua.org>`_ statements.
-
-.. note::
- This is a PowerDNS specific feature, and is not (yet) standardized by the
- IETF or other standards bodies. We are committed however to
- interoperability, and strive to turn this functionality into a broadly
- supported standard.
-
-To enable this feature, either set 'enable-lua-record' in the configuration,
-or set the 'ENABLE-LUA-RECORD' per-zone metadata item to 1.
-
-In addition, to benefit from the geographical features, make sure the PowerDNS
-launch statement includes the ``geoip`` backend.
-
-Examples
---------
-
-Before delving into the details, some examples may be of use to explain what
-dynamic records can do.
-
-Here is a very basic example::
-
- www IN LUA A "ifportup(443, {'192.0.2.1', '192.0.2.2'})"
-
-This turns the 'www' name within a zone into a special record that will
-randomly return 192.0.2.1 or 192.0.2.2, as long as both of these IP
-addresses listen on port 443.
-
-If either IP address stops listening, only the other address will be
-returned. If all IP addresses are down, all candidates are returned.
-
-Because DNS queries require rapid answers, server availability is not checked
-synchronously. In the background, a process periodically determines if IP
-addresses mentioned in availability rules are, in fact, available.
-
-Another example::
-
- www IN LUA A "pickclosest({'192.0.2.1','192.0.2.2','198.51.100.1'})"
-
-This uses the GeoIP backend to find indications of the geographical location of
-the requester and the listed IP addresses. It will return with one of the closest
-addresses.
-
-``pickclosest`` and ifportup can be combined as follows::
-
- www IN LUA A ("ifportup(443, {'192.0.2.1', '192.0.2.2', '198.51.100.1'}"
- ", {selector='pickclosest'}) ")
-
-This will pick from the viable IP addresses the one deemed closest to the user.
-
-Using LUA Records with Generic SQL backends
--------------------------------------------
-
-It's possible to use Lua records with the Generic SQL backends such as gmysql and gpgsql.
-
-Be aware that due to the fact that Lua records uses both double and single quotes, you will
-need to appropriately escape them in INSERT/UPDATE queries.
-
-Here is an example from the previous section (``pickclosest``) which should work
-for both **MySQL** and **PostgreSQL**::
-
- -- Create the zone example.com
- INSERT INTO domains (id, name, type) VALUES (1, 'example.com', 'NATIVE');
-
- -- Enable Lua records for the zone (if not enabled globally)
- INSERT INTO domainmetadata (domain_id, kind, content)
- VALUES (1, 'ENABLE-LUA-RECORD', 1);
-
- -- Create a pickClosest() Lua A record.
- -- Double single quotes are used to escape single quotes in both MySQL and PostgreSQL
- INSERT INTO records (domain_id, name, type, content, ttl)
- VALUES (
- 1,
- 'www.example.com',
- 'LUA',
- 'A "pickclosest({''192.0.2.1'',''192.0.2.2'',''198.51.100.1''})"',
- 600
- );
-
-The above queries create a zone ``example.com``, enable Lua records for the zone using ``ENABLE-LUA-RECORD``,
-and finally insert a LUA A record for the ``www`` subdomain using the previous pickclosest example.
-
-See `Details & Security`_ for more information about enabling Lua records, and the risks involved.
-
-Record format
--------------
-.. note::
- The fine authors of the Lua programming language insist that it is Lua and
- not LUA. Lua means 'moon' in Portuguese, and it is not an abbreviation.
- Sadly, it is DNS convention for record types to be all uppercase. Sorry.
-
-The LUA record consists of an initial query type, which is the selector on
-which the snippet will trigger. Optionally this query type itself can be LUA
-again for configuration scripts. The query type is then followed by the
-actual Lua snippet.
-
-LUA records can have TTL settings, and these will be honoured. In addition,
-LUA record output can be DNSSEC signed like any other record, but see below
-for further details.
-
-More powerful example
----------------------
-
-A more powerful example::
-
- west IN LUA A ( "ifurlup('https://www.lua.org/', "
- "{{'192.0.2.1', '192.0.2.2'}, {'198.51.100.1'}}, "
- "{stringmatch='Programming in Lua'}) " )
-
-In this case, IP addresses are tested to see if they will serve
-https for 'www.lua.org', and if that page contains the string 'Programming
-in Lua'.
-
-Two sets of IP addresses are supplied. If an IP address from the first set
-is available, it will be returned. If no addresses work in the first set,
-the second set is tried.
-
-This configuration makes sense in the following context::
-
- www IN LUA CNAME ( ";if(continent('EU')) then return 'west.powerdns.org' "
- "else return 'usa.powerdns.org' end" )
-
-
-This sends queries that are geolocated to Europe to 'west.powerdns.org', and
-the rest to 'usa.powerdns.org'. The configuration for that name would then
-be::
-
- usa IN LUA A ( "ifurlup('https://www.lua.org/', "
- "{{'198.51.100.1'}, {'192.0.2.1', '192.0.2.2'}}, "
- "{stringmatch='Programming in Lua'}) " )
-
-Note that the sets of IP addresses have reversed order - visitors geolocated
-outside of Europe will hit 198.51.100.1 as long as it is available, and the
-192.0.2.1 and 192.0.2.2 servers as backup.
-
-Advanced topics
----------------
-By default, LUA records are executed with 'return ' prefixed to them. This saves
-a lot of typing for common cases. To run actual Lua scripts, start a record with a ';'
-which indicates no 'return ' should be prepended.
-
-To keep records more concise and readable, configuration can be stored in
-separate records. The full example from above can also be written as::
-
- config IN LUA LUA ("settings={stringmatch='Programming in Lua'} "
- "EUips={'192.0.2.1', '192.0.2.2'} "
- "USAips={'198.51.100.1'} ")
-
- www IN LUA CNAME ( ";if(continent('EU')) then return 'west.powerdns.org' "
- "else return 'usa.powerdns.org' end" )
-
- usa IN LUA A ( ";include('config') "
- "return ifurlup('https://www.lua.org/', "
- "{USAips, EUips}, settings) " )
-
- west IN LUA A ( ";include('config') "
- "return ifurlup('https://www.lua.org/', "
- "{EUips, USAips}, settings) " )
-
-
-
Preset variables
----------------
See :func:`pickwhashed` for an example.
Reverse DNS functions
-~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~
.. warning::
The reverse DNS functions are under active development. **They may**
$ dig +short AAAA 2001-a-b--1.static6.example.com @ns1.example.com
2001:a:b::1
-
Helper functions
~~~~~~~~~~~~~~~~
Returns true if ``bestwho`` is within any of the listed subnets.
:param [string] netmasks: The list of IP addresses to check against
-
-Details & Security
-------------------
-LUA records are synthesized on query. They can also be transferred via AXFR
-to other PowerDNS servers.
-
-LUA records themselves can not be queried however, as this would allow third parties to see load balancing internals
-they do not need to see.
-
-A non-supporting DNS server will also serve a zone with LUA records, but
-they will not function, and will in fact leak the contents of the LUA record.
-
-.. note::
- Under NO circumstances serve LUA records from zones from untrusted sources!
- LUA records will be able to bring down your system and possible take over
- control of it. Use TSIG on AXFR even from trusted sources!
-
-LUA records can be DNSSEC signed, but because they are dynamic, it is not
-possible to combine pre-signed DNSSEC zone and LUA records. In other words,
-the signing key must be available on the server creating answers based on
-LUA records.
-
-Note that to protect operators, support for the LUA record must be enabled
-explicitly, either globally (``enable-lua-record``) or per zone
-(``ENABLE-LUA-RECORD`` = 1).
--- /dev/null
+Lua Records
+===========
+
+To facilitate dynamic behaviour, such as Global Server Load Balancing,
+PowerDNS Authoritative Server version 4.2 and later support dynamic DNS
+records.
+
+These records contain small snippets of configuration that enable dynamic
+behaviour based on requester IP address, requester's EDNS Client Subnet,
+server availability or other factors.
+
+Capabilities range from very simple to highly advanced multi-pool
+geographically & weighed load balanced IP address selection.
+
+Although users need not be aware, PowerDNS dynamic DNS records are actually
+tiny (or larger) `Lua <https://www.lua.org>`_ statements.
+
+.. note::
+ This is a PowerDNS specific feature, and is not (yet) standardized by the
+ IETF or other standards bodies. We are committed however to
+ interoperability, and strive to turn this functionality into a broadly
+ supported standard.
+
+To enable this feature, either set 'enable-lua-record' in the configuration,
+or set the 'ENABLE-LUA-RECORD' per-zone metadata item to 1.
+
+In addition, to benefit from the geographical features, make sure the PowerDNS
+launch statement includes the ``geoip`` backend.
+
+Examples
+--------
+
+Before delving into the details, some examples may be of use to explain what
+dynamic records can do.
+
+Here is a very basic example::
+
+ www IN LUA A "ifportup(443, {'192.0.2.1', '192.0.2.2'})"
+
+This turns the 'www' name within a zone into a special record that will
+randomly return 192.0.2.1 or 192.0.2.2, as long as both of these IP
+addresses listen on port 443.
+
+If either IP address stops listening, only the other address will be
+returned. If all IP addresses are down, all candidates are returned.
+
+Because DNS queries require rapid answers, server availability is not checked
+synchronously. In the background, a process periodically determines if IP
+addresses mentioned in availability rules are, in fact, available.
+
+Another example::
+
+ www IN LUA A "pickclosest({'192.0.2.1','192.0.2.2','198.51.100.1'})"
+
+This uses the GeoIP backend to find indications of the geographical location of
+the requester and the listed IP addresses. It will return with one of the closest
+addresses.
+
+``pickclosest`` and ifportup can be combined as follows::
+
+ www IN LUA A ("ifportup(443, {'192.0.2.1', '192.0.2.2', '198.51.100.1'}"
+ ", {selector='pickclosest'}) ")
+
+This will pick from the viable IP addresses the one deemed closest to the user.
+
+Using LUA Records with Generic SQL backends
+-------------------------------------------
+
+It's possible to use Lua records with the Generic SQL backends such as gmysql and gpgsql.
+
+Be aware that due to the fact that Lua records uses both double and single quotes, you will
+need to appropriately escape them in INSERT/UPDATE queries.
+
+Here is an example from the previous section (``pickclosest``) which should work
+for both **MySQL** and **PostgreSQL**::
+
+ -- Create the zone example.com
+ INSERT INTO domains (id, name, type) VALUES (1, 'example.com', 'NATIVE');
+
+ -- Enable Lua records for the zone (if not enabled globally)
+ INSERT INTO domainmetadata (domain_id, kind, content)
+ VALUES (1, 'ENABLE-LUA-RECORD', 1);
+
+ -- Create a pickClosest() Lua A record.
+ -- Double single quotes are used to escape single quotes in both MySQL and PostgreSQL
+ INSERT INTO records (domain_id, name, type, content, ttl)
+ VALUES (
+ 1,
+ 'www.example.com',
+ 'LUA',
+ 'A "pickclosest({''192.0.2.1'',''192.0.2.2'',''198.51.100.1''})"',
+ 600
+ );
+
+The above queries create a zone ``example.com``, enable Lua records for the zone using ``ENABLE-LUA-RECORD``,
+and finally insert a LUA A record for the ``www`` subdomain using the previous pickclosest example.
+
+See `Details & Security`_ for more information about enabling Lua records, and the risks involved.
+
+Record format
+-------------
+.. note::
+ The fine authors of the Lua programming language insist that it is Lua and
+ not LUA. Lua means 'moon' in Portuguese, and it is not an abbreviation.
+ Sadly, it is DNS convention for record types to be all uppercase. Sorry.
+
+The LUA record consists of an initial query type, which is the selector on
+which the snippet will trigger. Optionally this query type itself can be LUA
+again for configuration scripts. The query type is then followed by the
+actual Lua snippet.
+
+LUA records can have TTL settings, and these will be honoured. In addition,
+LUA record output can be DNSSEC signed like any other record, but see below
+for further details.
+
+More powerful example
+---------------------
+
+A more powerful example::
+
+ west IN LUA A ( "ifurlup('https://www.lua.org/', "
+ "{{'192.0.2.1', '192.0.2.2'}, {'198.51.100.1'}}, "
+ "{stringmatch='Programming in Lua'}) " )
+
+In this case, IP addresses are tested to see if they will serve
+https for 'www.lua.org', and if that page contains the string 'Programming
+in Lua'.
+
+Two sets of IP addresses are supplied. If an IP address from the first set
+is available, it will be returned. If no addresses work in the first set,
+the second set is tried.
+
+This configuration makes sense in the following context::
+
+ www IN LUA CNAME ( ";if(continent('EU')) then return 'west.powerdns.org' "
+ "else return 'usa.powerdns.org' end" )
+
+
+This sends queries that are geolocated to Europe to 'west.powerdns.org', and
+the rest to 'usa.powerdns.org'. The configuration for that name would then
+be::
+
+ usa IN LUA A ( "ifurlup('https://www.lua.org/', "
+ "{{'198.51.100.1'}, {'192.0.2.1', '192.0.2.2'}}, "
+ "{stringmatch='Programming in Lua'}) " )
+
+Note that the sets of IP addresses have reversed order - visitors geolocated
+outside of Europe will hit 198.51.100.1 as long as it is available, and the
+192.0.2.1 and 192.0.2.2 servers as backup.
+
+Advanced topics
+---------------
+By default, LUA records are executed with 'return ' prefixed to them. This saves
+a lot of typing for common cases. To run actual Lua scripts, start a record with a ';'
+which indicates no 'return ' should be prepended.
+
+To keep records more concise and readable, configuration can be stored in
+separate records. The full example from above can also be written as::
+
+ config IN LUA LUA ("settings={stringmatch='Programming in Lua'} "
+ "EUips={'192.0.2.1', '192.0.2.2'} "
+ "USAips={'198.51.100.1'} ")
+
+ www IN LUA CNAME ( ";if(continent('EU')) then return 'west.powerdns.org' "
+ "else return 'usa.powerdns.org' end" )
+
+ usa IN LUA A ( ";include('config') "
+ "return ifurlup('https://www.lua.org/', "
+ "{USAips, EUips}, settings) " )
+
+ west IN LUA A ( ";include('config') "
+ "return ifurlup('https://www.lua.org/', "
+ "{EUips, USAips}, settings) " )
+
+Details & Security
+------------------
+LUA records are synthesized on query. They can also be transferred via AXFR
+to other PowerDNS servers.
+
+LUA records themselves can not be queried however, as this would allow third parties to see load balancing internals
+they do not need to see.
+
+A non-supporting DNS server will also serve a zone with LUA records, but
+they will not function, and will in fact leak the contents of the LUA record.
+
+.. note::
+ Under NO circumstances serve LUA records from zones from untrusted sources!
+ LUA records will be able to bring down your system and possible take over
+ control of it. Use TSIG on AXFR even from trusted sources!
+
+LUA records can be DNSSEC signed, but because they are dynamic, it is not
+possible to combine pre-signed DNSSEC zone and LUA records. In other words,
+the signing key must be available on the server creating answers based on
+LUA records.
+
+Note that to protect operators, support for the LUA record must be enabled
+explicitly, either globally (``enable-lua-record``) or per zone
+(``ENABLE-LUA-RECORD`` = 1).
+
+Reference
+---------
+
+ .. toctree::
+ :maxdepth: 2
+
+ functions
+ reference/index
--- /dev/null
+.. _ComboAddress:
+
+ComboAddress objects
+^^^^^^^^^^^^^^^^^^^^
+
+IP addresses are moved around in a native format, called a ComboAddress.
+ComboAddresses can be IPv4 or IPv6, and unless you want to know, you don’t need to.
+
+Functions and methods of a ``ComboAddress``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. function:: newCA(address) -> ComboAddress
+
+ Returns a new :class:`ComboAddress` object based on address
+
+ :param string address: The IP address, with optional port, to represent
+
+ .. code-block:: lua
+
+ addr = newCA("1.2.3.4")
+
+.. class:: ComboAddress
+
+ A ``ComboAddress`` represents an IP address with possibly a port number.
+ The object can be an IPv4 or an IPv6 address.
+ It has these methods:
+
+ .. method:: ComboAddress:getPort() -> int
+
+ Returns the port number.
+
+ .. method:: ComboAddress:isIPv4() -> bool
+
+ Returns true if the address is an IPv4, false otherwise
+
+ .. method:: ComboAddress:isIPv6() -> bool
+
+ Returns true if the address is an IPv6, false otherwise
+
+ .. method:: ComboAddress:isMappedIPv4() -> bool
+
+ Returns true if the address is an IPv4 mapped into an IPv6, false otherwise
+
+ .. method:: ComboAddress:mapToIPv4() -> ComboAddress
+
+ Convert an IPv4 address mapped in a v6 one into an IPv4.
+ Returns a new ComboAddress
+
+ .. method:: ComboAddress:toString() -> string
+
+ Returns in human-friendly format
+
+ .. method:: ComboAddress:getRaw() -> string
+
+ Returns in raw bytes format format
+
+ .. method:: ComboAddress:toStringWithPort() -> string
+
+ Returns in human-friendly format, with port number
+
+ .. method:: ComboAddress:truncate(bits)
+
+ Truncate the ComboAddress to the specified number of bits.
+ This essentially zeroes all bits after ``bits``.
+
+ :param int bits: Amount of bits to truncate to
+
+.. _ComboAddressSet:
+
+ComboAddressSet objects
+^^^^^^^^^^^^^^^^^^^^^^^
+
+We provide a convenient object class that can store unique ComboAddresses in no particular
+order and allows fast retrieval of individual elements based on their values
+
+ .. code-block:: lua
+
+ addr = newCA("1.2.3.4")
+ myset = newCAS()
+ myset:add(addr)
+ if myset:check(addr) then -- prints "found!"
+ print('found!')
+ end
+
+Functions and methods of a ``ComboAddressSet``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. function:: newCAS() -> ComboAddressSet
+
+ Returns an empty :class:`ComboAddressSet` object
+
+.. class:: ComboAddressSet
+
+ A ``ComboAddressSet`` can store multiple `ComboAddress`
+
+ It has these methods:
+
+ .. method:: ComboAddressSet:add(addr)
+
+ Add the given `addr` to set. `addr` can be of the following types
+
+ :param ComboAddress addr: The `ComboAddress` object to add to set
+ :param string addr: Handy way to add `ComboAddress` from its string representation
+ :param [string] addr: Add the given list of addresses to the set
+
+ .. code-block:: lua
+
+ addr = newCA("1.2.3.4")
+ myset = newCAS()
+ myset:add(addr)
+ myset:add("5.6.7.8")
+ myset:add({"::1/128", "10.11.12.13"})
--- /dev/null
+.. _DNSHeader:
+
+DNSHeader (``dh``) object
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. class:: DNSHeader
+
+ This object holds a representation of a DNS packet's header.
+
+ .. method:: DNSHeader:getRD() -> bool
+
+ Get recursion desired flag.
+
+ .. method:: DNSHeader:getCD() -> bool
+
+ Get checking disabled flag.
+
+ .. method:: DNSHeader:getID() -> bool
+
+ Get header's ID
+
+ .. method:: DNSHeader:getTC() -> bool
+
+ Truncated message bit
+
+ .. method:: DNSHeader:getRA() -> bool
+
+ Recursion available
+
+ .. method:: DNSHeader:getAD() -> bool
+
+ Authenticated data from named
+
+ .. method:: DNSHeader:getAA() -> bool
+
+ Authoritative answer
+
+ .. method:: DNSHeader:getRCODE() -> int
+
+ Response code
+
+ .. method:: DNSHeader:getOPCODE() -> int
+
+ Purpose of message
+
+ .. method:: DNSHeader:getQDCOUNT() -> int
+
+ Number of question entries
+
+ .. method:: DNSHeader:getANCOUNT() -> int
+
+ Number of answer entries
+
+ .. method:: DNSHeader:getNSCOUNT() -> int
+
+ Number of authority entries
+
+ .. method:: DNSHeader:getARCOUNT() -> int
+
+ Number of resource entries
--- /dev/null
+.. _DNSName:
+
+DNSName objects
+^^^^^^^^^^^^^^^
+
+A :class:`DNSName` object represents a name in the DNS. It has serveral functions that can manipulate it without conversions to strings.
+Creating a ``DNSName`` is done with the :func:`newDN`::
+
+ myname = newDN("www.example.com")
+
+PowerDNS will complain loudly if the name is invalid (e.g. too long, dot in the wrong place).
+
+The ``myname`` variable has several functions to get information from it
+
+.. code-block:: lua
+
+ print(myname:countLabels()) -- prints "3"
+ print(myname:wireLength()) -- prints "17"
+ name2 = newDN("example.com")
+ if myname:isPartOf(name2) then -- prints "it is"
+ print('it is')
+ end
+
+Functions and methods of a ``DNSName``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. function:: newDN(name) -> DNSName
+
+ Returns the :class:`DNSName` object of ``name``.
+
+ :param string name: The name to create a DNSName for
+
+.. class:: DNSName
+
+ A ``DNSName`` object represents a name in the DNS.
+ It is returned by several functions and has several functions to programmatically interact with it.
+
+ .. method:: DNSName:canonCompare(name) -> bool
+
+ Performs a comparaison of DNS names in canonical order.
+ Returns true if the DNSName comes before ``name``.
+ See https://tools.ietf.org/html/rfc4034#section-6
+
+ :param DNSName name: The name to compare to
+
+ .. method:: DNSName:makeRelative(name) -> DNSName
+
+ Returns a new DNSName that is relative to ``name``
+
+ .. code-block:: lua
+
+ name = newDN("bb.a.example.com.")
+ parent = newDN("example.com.")
+ rel = name:makeRelative(parent) -- contains DNSName("bb.a.")
+
+ :param DNSName name: The name to compare to
+
+ .. method:: DNSName:isPartOf(name) -> bool
+
+ Returns true if the DNSName is part of the DNS tree of ``name``.
+
+ :param DNSName name: The name to check against
+
+ .. method:: DNSName:toString() -> string
+
+ Returns a human-readable form of the DNSName
+
+ .. method:: DNSName:toStringNoDot() -> string
+
+ Returns a human-readable form of the DNSName without the trailing dot
+
+ .. method:: DNSName:chopOff() -> bool
+
+ Removes the left-most label and returns ``true``.
+ ``false`` is returned if no label was removed
+
+ .. method:: DNSName:countLabels() -> int
+
+ Returns the number of DNSLabels in the name
+
+ .. method:: DNSName:wireLength() -> int
+
+ Returns the length in bytes of the DNSName as it would be on the wire.
+
+ .. method:: DNSName::getRawLabels() -> [ string ]
+
+ Returns a table that contains the raw labels of the DNSName
+
+ .. method:: DNSName::countLabels() -> int
+
+ Returns the number of labels of the DNSName
+
+ .. method:: DNSName::equal(name) -> bool
+
+ Perform a comparaison of the DNSName to the given ``name``.
+ You can also compare directly two DNSName objects using
+ the ``==`` operator
+
+ :param string name: The name to compare to
--- /dev/null
+.. _DNSResourceRecord:
+
+DNSResourceRecord objects
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A :class:`DNSResourceRecord` object represents a resource record in the DNS.
+Creating a ``DNSResourceRecord`` is done with the :func:`newDRR`.
+
+.. todo
+ Add a lua example and some useful things to do with that.
+
+Functions and methods of a ``DNSResourceRecord``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. function:: newDRR(name, type, ttl, content[, domainId[, auth]]) -> DNSResourceRecord
+
+ Returns a new :class:`DNSResourceRecord` object.
+ .. todo describe the auth param
+
+ :param DNSName name: The name to the new record
+ :param string type: The name to create a DNSName for
+ :param int ttl: The TTL of the record
+ :param string content: The content of the record
+ :param int domainId: The optional domain ID of the zone the record belongs to
+ :param int auth: ?
+
+ .. todo complete LUA example bellow
+ .. code-block:: lua
+
+ name = newDN("www.example.org.")
+ rr = new DRR(name, "IN", 3600, )
+
+.. class:: DNSResourceRecord
+
+ A ``DNSResourceRecord`` object represents a DNS record.
+
+ .. method:: DNSResourceRecord:toString() -> string
+
+ Returns the full content of the record as a string
+
+ .. method:: DNSResourceRecord:qname() -> DNSName
+
+ Returns the name of the record
+
+ .. method:: DNSResourceRecord:wildcardName() -> DNSName
+
+ Returns the wildcard name of the record the record was matched against
+
+ .. method:: DNSResourceRecord:content() -> string
+
+ Returns what the record points to
+
+ .. method:: DNSResourceRecord:lastModified() -> int
+
+ If unzero, last time this record was changed
+
+ .. method:: DNSResourceRecord:ttl() -> int
+
+ TTL (Time To Live) of this record
+
+ .. method:: DNSResourceRecord:signttl() -> int
+
+ If non-zero, TTL that will be used in the RRSIG of the record
+
+ .. method:: DNSResourceRecord:domainId() -> int
+
+ Backend related domain ID of the zone the record belongs to
+
+ .. method:: DNSResourceRecord:qtype() -> int
+
+ Type of the record (A, CNAME, MX, ...)
+
+ .. method:: DNSResourceRecord:qclass() -> int
+
+ Class of the record (IN, CH, ...)
+
+ .. method:: DNSResourceRecord:scopeMask() -> int
+
+ .. todo
+
+ .. method:: DNSResourceRecord:auth() -> bool
+
+ .. auth
+
+ .. method:: DNSResourceRecord:disabled() -> bool
+
+ .. todo
--- /dev/null
+LUA Reference
+-------------
+
+ .. toctree::
+ :maxdepth: 2
+
+ comboaddress
+ dnsheader
+ dnsname
+ dnsresourcerecord
+ netmask
+ qtype
--- /dev/null
+.. _scripting-netmasks:
+
+Netmasks and NetMaskGroups
+==========================
+
+There are two classes in the PowerDNS Recursor that can be used to match IP addresses against.
+
+Netmask class
+-------------
+The :class:`Netmask` class represents an IP netmask.
+
+.. code-block:: Lua
+
+ mask = newNetmask("192.0.2.1/24")
+ mask:isIPv4() -- true
+ mask:match("192.0.2.8") -- true
+
+.. function:: newNetmask(mask) -> Netmask
+
+ Creates a new :class:`Netmask`.
+
+ :param str mask: The mask to convert.
+
+.. class:: Netmask
+
+ Represents a netmask.
+
+ .. method:: Netmask:empty() -> bool
+
+ True if the netmask doesn't contain a valid address.
+
+ .. method:: Netmask:getBits() -> int
+
+ The number of bits in the address.
+
+ .. method:: Netmask:getNetwork() -> ComboAddress
+
+ Returns a :class:`ComboAddress` representing the network (no mask applied).
+
+ .. method:: Netmask:getMaskedNetwork() -> ComboAddress
+
+ Returns a :class:`ComboAddress` representing the network (truncating according to the mask).
+
+ .. method:: Netmask:isIpv4() -> bool
+
+ True if the netmask is an IPv4 netmask.
+
+ .. method:: Netmask:isIpv6() -> bool
+
+ True if the netmask is an IPv6 netmask.
+
+ .. method:: Netmask:match(address) -> bool
+
+ True if the address passed in address matches
+
+ :param str address: IP Address to match against.
+
+ .. method:: Netmask:toString() -> str
+
+ Returns a human-friendly representation.
+
+NetMaskGroup class
+------------------
+
+NetMaskGroups are more powerful than plain Netmasks.
+They can be matched against netmasks objects:
+
+.. code-block:: lua
+
+ nmg = newNMG()
+ nmg:addMask("127.0.0.0/8")
+ nmg:addMasks({"213.244.168.0/24", "130.161.0.0/16"})
+ nmg:addMasks(dofile("bad.ips")) -- contains return {"ip1","ip2"..}
+
+ if nmg:match(dq.remoteaddr) then
+ print("Intercepting query from ", dq.remoteaddr)
+ end
+
+Prefixing a mask with ``!`` excludes that mask from matching.
+
+.. function:: newNMG() -> NetMaskGroup
+
+ Returns a new, empty :class:`NetMaskGroup`.
+
+.. class:: NetMaskGroup
+
+ IP addresses are passed to Lua in native format.
+
+ .. method:: NetMaskGroup:addMask(mask)
+
+ Adds ``mask`` to the NetMaskGroup.
+
+ :param str mask: The mask to add.
+
+ .. method:: NetMaskGroup:addMasks(masks)
+
+ Adds ``masks`` to the NetMaskGroup.
+
+ :param {str} mask: The masks to add.
+
+ .. method:: NetMaskGroup:match(address) -> bool
+
+ Returns true if ``address`` matches any of the masks in the group.
+
+ :param ComboAddress address: The IP addres to match the netmasks against.
--- /dev/null
+.. _QType:
+
+QType objects
+=========================
+
+The QType class lets you deal easily with the different kind
+of resource types, like 'A', 'NS', 'CNAME', etc. These types have
+both a name and a number. This class helps seamlessly move
+between them.
+
+Functions and methods of a ``QType``
+----------------------------------------------
+
+.. function:: newQType(name) -> QType
+
+ Returns a new QType object from `name`. Name can either contain the code
+ of the type prefixed with a sharp character, or its name directly
+
+ :param string name: The name of the QType
+
+ .. code-block:: lua
+
+ type = newQType("CNAME")
+ anothertype = newQType("#5")
+ if type == anothertype then -- prints "equal!"
+ print('equal!')
+ end
+
+.. class:: QType
+
+ It has these methods:
+
+ .. method:: QType:getCode() -> int
+
+ Returns the numeric code corresponding to the type
+
+ .. method:: QType:getName() -> string
+
+ Returns the name of the type
d_lw->registerFunction("isPartOf", &DNSName::isPartOf);
d_lw->registerFunction("getRawLabels", &DNSName::getRawLabels);
d_lw->registerFunction<unsigned int(DNSName::*)()>("countLabels", [](const DNSName& name) { return name.countLabels(); });
- d_lw->registerFunction<size_t(DNSName::*)()>("wirelength", [](const DNSName& name) { return name.wirelength(); });
+ d_lw->registerFunction<size_t(DNSName::*)()>("wireLength", [](const DNSName& name) { return name.wirelength(); });
d_lw->registerFunction<bool(DNSName::*)(const std::string&)>("equal", [](const DNSName& lhs, const std::string& rhs) { return lhs==DNSName(rhs); });
d_lw->registerEqFunction(&DNSName::operator==);
-
d_lw->registerToStringFunction<string(DNSName::*)()>([](const DNSName&dn ) { return dn.toString(); });
d_lw->registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
d_lw->registerFunction<string(DNSName::*)()>("toStringNoDot", [](const DNSName&dn ) { return dn.toStringNoDot(); });
});
d_lw->registerEqFunction(&DNSResourceRecord::operator==);
d_lw->registerFunction("__lt", &DNSResourceRecord::operator<);
+ d_lw->registerToStringFunction<string(DNSResourceRecord::*)()>([](const DNSResourceRecord& rec) { return rec.getZoneRepresentation(); });
d_lw->registerFunction<string(DNSResourceRecord::*)()>("toString", [](const DNSResourceRecord& rec) { return rec.getZoneRepresentation();} );
d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("qname", [](DNSResourceRecord& rec) { return rec.qname; });
- d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("wildcardname", [](DNSResourceRecord& rec) { return rec.wildcardname; });
+ d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("wildcardName", [](DNSResourceRecord& rec) { return rec.wildcardname; });
d_lw->registerFunction<string(DNSResourceRecord::*)()>("content", [](DNSResourceRecord& rec) { return rec.content; });
- d_lw->registerFunction<time_t(DNSResourceRecord::*)()>("last_modified", [](DNSResourceRecord& rec) { return rec.last_modified; });
+ d_lw->registerFunction<time_t(DNSResourceRecord::*)()>("lastModified", [](DNSResourceRecord& rec) { return rec.last_modified; });
d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("ttl", [](DNSResourceRecord& rec) { return rec.ttl; });
d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("signttl", [](DNSResourceRecord& rec) { return rec.signttl; });
- d_lw->registerFunction<int(DNSResourceRecord::*)()>("domain_id", [](DNSResourceRecord& rec) { return rec.domain_id; });
+ d_lw->registerFunction<int(DNSResourceRecord::*)()>("domainId", [](DNSResourceRecord& rec) { return rec.domain_id; });
d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qtype", [](DNSResourceRecord& rec) { return rec.qtype.getCode(); });
d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qclass", [](DNSResourceRecord& rec) { return rec.qclass; });
d_lw->registerFunction<uint8_t(DNSResourceRecord::*)()>("scopeMask", [](DNSResourceRecord& rec) { return rec.scopeMask; });
// ComboAddress
d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; });
d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; });
+ d_lw->registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
d_lw->registerFunction<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); });
d_lw->registerFunction<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); });
d_lw->registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); });
d_lw->registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); });
d_lw->registerToStringFunction<string(ComboAddress::*)()>([](const ComboAddress& ca) { return ca.toString(); });
d_lw->registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
- d_lw->registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
d_lw->registerFunction<string(ComboAddress::*)()>("getRaw", [](const ComboAddress& ca) {
if(ca.sin4.sin_family == AF_INET) {
auto t=ca.sin4.sin_addr.s_addr; return string((const char*)&t, 4);
d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); });
typedef std::unordered_set<ComboAddress,ComboAddress::addressOnlyHash,ComboAddress::addressOnlyEqual> cas_t;
- d_lw->writeFunction("newCAS", []{ return cas_t(); });
+ d_lw->registerFunction<bool(ComboAddress::*)(const ComboAddress&)>("equal", [](const ComboAddress& lhs, const ComboAddress& rhs) { return ComboAddress::addressOnlyEqual()(lhs, rhs); });
// cas_t
+ d_lw->writeFunction("newCAS", []{ return cas_t(); });
d_lw->registerFunction<void(cas_t::*)(boost::variant<string,ComboAddress, vector<pair<unsigned int,string> > >)>("add",
[](cas_t& cas, const boost::variant<string,ComboAddress,vector<pair<unsigned int,string> > >& in)
{
catch(std::exception& e) { g_log <<Logger::Error<<e.what()<<endl; }
});
d_lw->registerFunction<bool(cas_t::*)(const ComboAddress&)>("check",[](const cas_t& cas, const ComboAddress&ca) { return cas.count(ca)>0; });
- d_lw->registerFunction<bool(ComboAddress::*)(const ComboAddress&)>("equal", [](const ComboAddress& lhs, const ComboAddress& rhs) { return ComboAddress::addressOnlyEqual()(lhs, rhs); });
// QType
d_lw->writeFunction("newQType", [](const string& s) { QType q; q = s; return q; });
getLatLon(bestwho.toString(), wlat, wlon);
// cout<<"bestwho "<<wlat<<", "<<wlon<<endl;
vector<string> ret;
- g_log<<Logger::Debug<< __FILE__ << ":" << __LINE__<< " " << __func__ << " wips.size()="<< wips.size() <<endl;
for(const auto& c : wips) {
double lat=0, lon=0;
getLatLon(c.toString(), lat, lon);
// cout<<" distance: "<<sqrt(dist2) * 40000.0/360<<" km"<<endl; // length of a degree
ranked[dist2].push_back(c);
}
- g_log<<Logger::Debug<< __FILE__ << ":" << __LINE__<< " " << __func__ << " ranked.size()="<< ranked.size()<<endl;
- ranked.begin()->second.size();
- g_log<<Logger::Debug<< __FILE__ << ":" << __LINE__<< " " << __func__ << " ranked.size()="<< ranked.size()<<endl;
return ranked.begin()->second[random() % ranked.begin()->second.size()];
}