| | 11556 | <sect2><title>Modifying a slave zone using a script</title> |
| | 11557 | <para> |
| | 11558 | As of version 3.0, the PowerDNS Authoritative Server can invoke a Lua script on an incoming AXFR zone transfer. |
| | 11559 | The user-defined function axfrfilter within your script is invoked for each resource record read during the transfer, |
| | 11560 | and the outcome of the function defines what PowerDNS does with the records. |
| | 11561 | </para> |
| | 11562 | <para>(idea and documentation contributed by Jan-Piet Mens)</para> |
| | 11563 | <para> |
| | 11564 | What you can accomplish using a Lua script: |
| | 11565 | <itemizedlist> |
| | 11566 | <listitem><para>Ensure consistent values on SOA</para></listitem> |
| | 11567 | <listitem><para>Change incoming SOA serial number to a YYYYMMDDnn format</para></listitem> |
| | 11568 | <listitem><para>Ensure consistent NS RRset</para></listitem> |
| | 11569 | <listitem><para>Timestamp the zone transfer with a TXT record</para></listitem> |
| | 11570 | </itemizedlist> |
| | 11571 | </para> |
| | 11572 | <para> |
| | 11573 | To enable a Lua script for a particular slave zone, determine the domain_id for the zone from the `domains` table, and add a row to the `domainmetadata` table for the domain. Supposing the domain we want has an `id` of 3, the following SQL statement will enable the Lua script `my.lua` for that domain: |
| | 11574 | <programlisting> |
| | 11575 | INSERT INTO domainmetadata (domain_id, kind, content) VALUES (3, "LUA-AXFR-SCRIPT", "/lua/my.lua"); |
| | 11576 | </programlisting> |
| | 11577 | </para> |
| | 11578 | <para> |
| | 11579 | The Lua script must both exist and be syntactically correct; if not, the zone transfer is not performed. |
| | 11580 | </para> |
| | 11581 | <para>Your Lua functions have access to the query codes through a pre-defined Lua table called `pdns`. |
| | 11582 | For example if you want to check for a CNAME record you can either compare `qtype` to the numeric constant 5 or the value |
| | 11583 | `pdns.CNAME` -- they are equivalent.</para> |
| | 11584 | <para> |
| | 11585 | If your function decides to handle a resource record it must return a result code of 0 together with a Lua table |
| | 11586 | containing one or more replacement records to be stored in the back-end database. If, on the other hand, your |
| | 11587 | function decides not to modify a record, it must return -1 and an empty table indicating that PowerDNS should |
| | 11588 | handle the incoming record as normal. |
| | 11589 | </para> |
| | 11590 | <para> |
| | 11591 | Consider the following simple example: |
| | 11592 | <programlisting> |
| | 11593 | function axfrfilter(remoteip, zone, qname, qtype, ttl, prio, content) |
| | 11594 | |
| | 11595 | -- Replace each HINFO records with this TXT |
| | 11596 | if qtype == pdns.HINFO then |
| | 11597 | resp = {} |
| | 11598 | resp[1] = { qname = qname, |
| | 11599 | qtype = pdns.TXT, |
| | 11600 | ttl = 99, |
| | 11601 | content = "Hello Ahu!" |
| | 11602 | } |
| | 11603 | return 0, resp |
| | 11604 | end |
| | 11605 | |
| | 11606 | -- Grab each _tstamp TXT record and add a time stamp |
| | 11607 | if qtype == pdns.TXT and string.starts(qname, "_tstamp.") then |
| | 11608 | resp = {} |
| | 11609 | resp[1] = { |
| | 11610 | qname = qname, |
| | 11611 | qtype = qtype, |
| | 11612 | ttl = ttl, |
| | 11613 | content = os.date("Ver %Y%m%d-%H:%M") |
| | 11614 | } |
| | 11615 | return 0, resp |
| | 11616 | end |
| | 11617 | |
| | 11618 | resp = {} |
| | 11619 | return -1, resp |
| | 11620 | end |
| | 11621 | |
| | 11622 | function string.starts(s, start) |
| | 11623 | return s.sub(s, 1, s.len(start)) == start |
| | 11624 | end |
| | 11625 | </programlisting> |
| | 11626 | Upon an incoming AXFR, PowerDNS calls our `axfrfilter` function for each record. All HINFO records |
| | 11627 | are replaced by a TXT record with a TTL of 99 seconds and the specified string. TXT Records with |
| | 11628 | names starting with `_tstamp.` get their value (_rdata_) set to the current time stamp. |
| | 11629 | All other records are unhandled. |
| | 11630 | </para> |
| | 11631 | </sect2> |