PowerDNS server lua scripting
Let me help you all who are stuck with the non-existant documentation of LUA scripting in pdns.
Preface: all this is guesswork, since nothing really is documented. I'd say all feedbacks welcome, but nobody reads this blog anyway, so… there you are.
pdns-server and lua2 backend
PowerDNS is still a great thing, despite the change in leadership. After the (excellent person and programmer) lead architect left, it became more of a business-heavy, "you're on your own" open-source project. I really believe that it's worth helping people by using it, even if it's just to make sure that a few programs don't take over the DNS server field.
So. There is the lua2 backend, which seems documented, except it is not. There are no config examples, there are no code examples, basically it's a fair mix of guesswork, experience and trial and error, mainly error, and going on usually undecipherable error messages.
The first step is pretty straightforward. All you have to do is install the backend, and the distros usually make this process very easy. The easy part ends here.
Then, the server configuration. It is not complex, something like this shall be thrown into .../pdns.d/lua.conf:
launch += lua2 lua2-api = 2 lua2-filename = /etc/powerdns/pdns_backend.lua # for debugging, otherwise no lua2-query-logging = yes
And now let's see some lua example for that pdns_backend.lua:
-- you can run initialisation here pdnslog("I am your lua backend and I am definitely starting!") -- this is required function dns_lookup(qtype, qname, domain_id, context) pdnslog("I am processing your request") ret = {} table.insert(ret, { name=qname, type="A", content="9.8.7.6", ttl=666, domain_id=42, auth=true } ) table.insert(ret, { name=qname, type="A", content="5.4.3.2", ttl=668, domain_id=42, auth=true } ) if qtype:getName() == 'ANY" then table.insert(ret, { name=qname, type="AAAA", content="2001:db8:deaf:beef::42", ttl=420, domain_id=42, auth=true } ) end return ret end
"This is probably all I needed!" I can just picture you saying here and trying to go, but I'll hold on a little longer for you. Hey, if you give this a try, you'll see that pdns-server starts and answers questions, except your function never gets called. You'll just get a "REFUSED" message. Isn't it lovely?
Well, not exactly. The thing is, PDNS needs to have a clear picture of the domain in her little mind before she can start thinking about processing it. I'm sure there's a way to do that from the Lua script, but I'm not quite sure how yet.
Don't worry, this is going to be a breeze! All you need is a static
backend, and I usually use BindBackend for that. It gives PDNS some
basic fields to work with, especially SOA. There
are a bunch of documents out there that'll probably help you out. If
you're using pdns, chances are you've already got some static or SQL
backends set up. You can go ahead and create an empty zone with
just an SOA and maybe a few NSs. Then, you can try querying it and see
that…
*shazam!*
…pdns will call your lua function!
That is where you can start. There is the way better recursor lua documentation which can be useful about how to handle the args, and the server doc tells you which functions the lua script can use.
And now you can ask yourself: why haven't they told you that in the dcoumentation?