From: Charles-Henri Bruyand Date: Thu, 21 Jun 2018 12:16:53 +0000 (+0200) Subject: auth: lua records: document DNSName, DNSHeader, DNSResourceRecord API X-Git-Tag: auth-4.2.0-alpha1~19^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c052aac71b2ff336ca59421a5bee30564ce9562a;p=thirdparty%2Fpdns.git auth: lua records: document DNSName, DNSHeader, DNSResourceRecord API --- diff --git a/docs/dnsupdate.rst b/docs/dnsupdate.rst deleted file mode 100644 index 3d212acb2c..0000000000 --- a/docs/dnsupdate.rst +++ /dev/null @@ -1,519 +0,0 @@ -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 ` -- :doc:`gpgsql ` -- :doc:`gsqlite3 ` -- :doc:`goracle ` -- :doc:`godbc ` - -.. _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 ` 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-metadata: - -Per zone settings ------------------ - -For permissions, a number of per zone settings are available via the -:doc:`domain metadata ``. - -.. _metadata-allow-dnsupdate-from: - -ALLOW-DNSUPDATE-FROM -~~~~~~~~~~~~~~~~~~~~ - -This setting has the same function as described in the configuration -options (See ref:`above `). 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 < - 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 ` 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: - -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 ` -- 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 diff --git a/docs/indexTOC.rst b/docs/indexTOC.rst index 3bdb5485e3..a47aa950d6 100644 --- a/docs/indexTOC.rst +++ b/docs/indexTOC.rst @@ -17,7 +17,7 @@ PowerDNS Authoritative Server domainmetadata dnsupdate tsig - lua-records + lua-records/index guides/index backends/index http-api/index diff --git a/docs/lua-records.rst b/docs/lua-records/functions.rst similarity index 59% rename from docs/lua-records.rst rename to docs/lua-records/functions.rst index 740e8cc6f2..da4937f6c9 100644 --- a/docs/lua-records.rst +++ b/docs/lua-records/functions.rst @@ -1,179 +1,3 @@ -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 `_ 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 ---------------- @@ -341,7 +165,7 @@ Record creation functions See :func:`pickwhashed` for an example. Reverse DNS functions -~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~ .. warning:: The reverse DNS functions are under active development. **They may** @@ -480,7 +304,6 @@ Reverse DNS functions $ dig +short AAAA 2001-a-b--1.static6.example.com @ns1.example.com 2001:a:b::1 - Helper functions ~~~~~~~~~~~~~~~~ @@ -516,28 +339,3 @@ 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). diff --git a/docs/lua-records/index.rst b/docs/lua-records/index.rst new file mode 100644 index 0000000000..5f2a19a92f --- /dev/null +++ b/docs/lua-records/index.rst @@ -0,0 +1,207 @@ +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 `_ 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 diff --git a/docs/lua-records/reference/comboaddress.rst b/docs/lua-records/reference/comboaddress.rst new file mode 100644 index 0000000000..56156e2697 --- /dev/null +++ b/docs/lua-records/reference/comboaddress.rst @@ -0,0 +1,112 @@ +.. _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"}) diff --git a/docs/lua-records/reference/dnsheader.rst b/docs/lua-records/reference/dnsheader.rst new file mode 100644 index 0000000000..125de29bc6 --- /dev/null +++ b/docs/lua-records/reference/dnsheader.rst @@ -0,0 +1,60 @@ +.. _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 diff --git a/docs/lua-records/reference/dnsname.rst b/docs/lua-records/reference/dnsname.rst new file mode 100644 index 0000000000..2707269e27 --- /dev/null +++ b/docs/lua-records/reference/dnsname.rst @@ -0,0 +1,99 @@ +.. _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 diff --git a/docs/lua-records/reference/dnsresourcerecord.rst b/docs/lua-records/reference/dnsresourcerecord.rst new file mode 100644 index 0000000000..dba9428cb6 --- /dev/null +++ b/docs/lua-records/reference/dnsresourcerecord.rst @@ -0,0 +1,87 @@ +.. _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 diff --git a/docs/lua-records/reference/index.rst b/docs/lua-records/reference/index.rst new file mode 100644 index 0000000000..6cd1b8eaf7 --- /dev/null +++ b/docs/lua-records/reference/index.rst @@ -0,0 +1,12 @@ +LUA Reference +------------- + + .. toctree:: + :maxdepth: 2 + + comboaddress + dnsheader + dnsname + dnsresourcerecord + netmask + qtype diff --git a/docs/lua-records/reference/netmask.rst b/docs/lua-records/reference/netmask.rst new file mode 100644 index 0000000000..3b9c3961af --- /dev/null +++ b/docs/lua-records/reference/netmask.rst @@ -0,0 +1,105 @@ +.. _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. diff --git a/docs/lua-records/reference/qtype.rst b/docs/lua-records/reference/qtype.rst new file mode 100644 index 0000000000..5b22888127 --- /dev/null +++ b/docs/lua-records/reference/qtype.rst @@ -0,0 +1,39 @@ +.. _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 diff --git a/pdns/lua-base4.cc b/pdns/lua-base4.cc index ee596c8eb6..34be790dad 100644 --- a/pdns/lua-base4.cc +++ b/pdns/lua-base4.cc @@ -64,10 +64,9 @@ void BaseLua4::prepareContext() { d_lw->registerFunction("isPartOf", &DNSName::isPartOf); d_lw->registerFunction("getRawLabels", &DNSName::getRawLabels); d_lw->registerFunction("countLabels", [](const DNSName& name) { return name.countLabels(); }); - d_lw->registerFunction("wirelength", [](const DNSName& name) { return name.wirelength(); }); + d_lw->registerFunction("wireLength", [](const DNSName& name) { return name.wirelength(); }); d_lw->registerFunction("equal", [](const DNSName& lhs, const std::string& rhs) { return lhs==DNSName(rhs); }); d_lw->registerEqFunction(&DNSName::operator==); - d_lw->registerToStringFunction([](const DNSName&dn ) { return dn.toString(); }); d_lw->registerFunction("toString", [](const DNSName&dn ) { return dn.toString(); }); d_lw->registerFunction("toStringNoDot", [](const DNSName&dn ) { return dn.toStringNoDot(); }); @@ -88,14 +87,15 @@ void BaseLua4::prepareContext() { }); d_lw->registerEqFunction(&DNSResourceRecord::operator==); d_lw->registerFunction("__lt", &DNSResourceRecord::operator<); + d_lw->registerToStringFunction([](const DNSResourceRecord& rec) { return rec.getZoneRepresentation(); }); d_lw->registerFunction("toString", [](const DNSResourceRecord& rec) { return rec.getZoneRepresentation();} ); d_lw->registerFunction("qname", [](DNSResourceRecord& rec) { return rec.qname; }); - d_lw->registerFunction("wildcardname", [](DNSResourceRecord& rec) { return rec.wildcardname; }); + d_lw->registerFunction("wildcardName", [](DNSResourceRecord& rec) { return rec.wildcardname; }); d_lw->registerFunction("content", [](DNSResourceRecord& rec) { return rec.content; }); - d_lw->registerFunction("last_modified", [](DNSResourceRecord& rec) { return rec.last_modified; }); + d_lw->registerFunction("lastModified", [](DNSResourceRecord& rec) { return rec.last_modified; }); d_lw->registerFunction("ttl", [](DNSResourceRecord& rec) { return rec.ttl; }); d_lw->registerFunction("signttl", [](DNSResourceRecord& rec) { return rec.signttl; }); - d_lw->registerFunction("domain_id", [](DNSResourceRecord& rec) { return rec.domain_id; }); + d_lw->registerFunction("domainId", [](DNSResourceRecord& rec) { return rec.domain_id; }); d_lw->registerFunction("qtype", [](DNSResourceRecord& rec) { return rec.qtype.getCode(); }); d_lw->registerFunction("qclass", [](DNSResourceRecord& rec) { return rec.qclass; }); d_lw->registerFunction("scopeMask", [](DNSResourceRecord& rec) { return rec.scopeMask; }); @@ -105,13 +105,13 @@ void BaseLua4::prepareContext() { // ComboAddress d_lw->registerFunction("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; }); d_lw->registerFunction("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; }); + d_lw->registerFunction("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } ); d_lw->registerFunction("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); }); d_lw->registerFunction("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); }); d_lw->registerFunction("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); }); d_lw->registerFunction("toString", [](const ComboAddress& ca) { return ca.toString(); }); d_lw->registerToStringFunction([](const ComboAddress& ca) { return ca.toString(); }); d_lw->registerFunction("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); }); - d_lw->registerFunction("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } ); d_lw->registerFunction("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); @@ -122,9 +122,10 @@ void BaseLua4::prepareContext() { d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); }); typedef std::unordered_set cas_t; - d_lw->writeFunction("newCAS", []{ return cas_t(); }); + d_lw->registerFunction("equal", [](const ComboAddress& lhs, const ComboAddress& rhs) { return ComboAddress::addressOnlyEqual()(lhs, rhs); }); // cas_t + d_lw->writeFunction("newCAS", []{ return cas_t(); }); d_lw->registerFunction > >)>("add", [](cas_t& cas, const boost::variant > >& in) { @@ -142,7 +143,6 @@ void BaseLua4::prepareContext() { catch(std::exception& e) { g_log <registerFunction("check",[](const cas_t& cas, const ComboAddress&ca) { return cas.count(ca)>0; }); - d_lw->registerFunction("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; }); diff --git a/pdns/lua-record.cc b/pdns/lua-record.cc index ad070e8a9f..4a617a8a78 100644 --- a/pdns/lua-record.cc +++ b/pdns/lua-record.cc @@ -376,7 +376,6 @@ static ComboAddress pickclosest(const ComboAddress& bestwho, const vector ret; - g_log<