 Okay, so do you have my slides? Well, it would help. There we go. All right. Hi. Sorry about the technology. Yes. I know. Oh, hi. I'm Peter. I work for Power DNS. And I'm also running here the deaf room with Peter and the other folks. And I'm here to tell you a little bit about the new feature in Power DNS Authortator Server 4.2 where you can use Lua to generate answers. But not only that because, you know, that's boring. We've been doing this in the Recursor for all time. But you can even aches a far out this Lua to the other servers. So you have it all inside your zone. And I'm going to tell you all the cool things that you can do with it. So the big problem with DNS and DNS records in general is it's mostly static. People are trying to do some dynamic things like round robin, which sucks because then the resolver might have two addresses. But due to the cache, we'll hand them out in a certain order for a certain amount of time. You cannot really do failovers with SRV records and services that support it. You can, of course, have multiple servers and failover between them on the DNS level. However, HTTP does not do SRV, which is the service that is most used, of course. You cannot really have a more specific answer per requester. So there is EDNS Client Subnet that I'll discuss a little bit later as well that enables this. But by default, it's not in the DNS or within the zone. And there is no real way to do dynamic answers or as Paul Vicks likes to call it, stupid DNS tricks. Even though they're stupid, we like them and they're kind of needed in the internet of today. So there are many solutions to these issues. There are alias records. There is CNAME FLEPNING. There is FLEPNING at the APEX. We have a bunch of non-portable solutions as well. We have a GOIP backend that you configure in YAML to do things. We have a remote backend that just calls a script where you can return records in any way, shape or form. We have a pipe backend that does the same but then as a sub-process. We have a Lua backend where you can type Lua and do all these things. And bind as GOIP features in 9.10 and on, which is a little bit more implemented as a view. And all these features, they're not compatible. If I want to do the same things in bind as I want to do in a PowerDNS GOIP backend, I need a completely different configuration and I also need to provide each server in my cluster with that configuration. There is no way for me to just use in-band AXFR to push this information to my slaves. So we would like to have something that can generate these answers dynamically. Exists within the zone file so there is no separate thing outside of the process. It can be AXFR between different implementations and probably requires no changes in recursors because you don't control those on the internet so you shouldn't just, you should just ignore them at that point. So this is the solution we came up with and they're called Lua records. And as we said before, we apologize to the Lua people because Lua has to be spelled with one capital L and small UA. However, in DNS everything is capitalized. So we call it Lua in full capitals. So what you see here is a small example zone. It has a Lua A record and a Lua Quad A record and it already shows you some of the features that we've implemented. So if this server would get a query for example, for A.example, which we assume is the zone, it will execute this bit of Lua which says if port up 443, sorry the HTTP port on one of these two IP addresses, it will return the address that is up. And if both are up, a random address is returned or you can select or you can have an extra option that will select which one should be returned. And the same goes for Quad A. Again, we check if the port is up or not. We check this I think every second from the name server and if it's down we mark it as down and we do the redirection like that. And if you do short TTLs, that is very cool. So Lua records, they're actually very tiny Lua scripts that are embedded in the zone. The processing happens at runtime so there is no pre-flight things that you need to do before provisioning the zone. You just put the Lua in there and it works. And we have a bunch of helper functions defined where for certain types like A, Quad A, like if port up that is an IP thing. For TXT we have some lock things. If you use GOIP we can actually send you the lock record where we think your resolver is. So like I said, Lua, why this is a programming language, why would we want this? So it's a very tiny language that you can embed everywhere. We have embedded it in DNS-TIST, it's in the recurser, it's already in the authoritative server in the form of an AXFR filter where you can actually filter records that you get from an inbound AXFR. And it is super tiny. There are no batteries included. And you get a huge standard library. And it's quite big. It's good. But with Lua you get almost nothing. You get a programming language and there is no standard library. You can just make whatever you want. And it's super-duper embeddable. So like I said, we've already have it in the recurser and DNS-TIST. And it has many language bindings. You can run Lua in GO, you can run Lua in Python because all these bindings just exist. We have a wrapper called LuaRapper, it's for C++ and it allows you to just wrap C++ functions directly to Lua functions. And we're very, very happy with it, which makes it super easy for us to actually just implement this in a same way. So how do they look like those Lua records in action? So we have a couple of variables that you get every time a script is invoked. That is who, ECS who and best who. Well, the names already say it. So who is the client IP address that you get? I'm not 100% sure about the interaction we have with XPF, but I'm pretty sure we will give you the... I hear Bert grumbling a bit, but we'll have to check that. So who will tell you the client IP address? ECS who if you have EDNS client subnet enabled and you get an EDNS client subnet option. ECS who will be filled with that address. And best who will be ECS who when it exists or who otherwise. So if you always use best who, you always have an answer there. And then we have a couple of functions that we have to create address records. So we have pick random. You just supply it with a list of IP addresses and it will just randomly hand out one. Pick W random. It will hand out a random IP address from a list, but the list is weighted. So you can have... I will have examples later on as well. So you can have a record with a weight of 20 and one with a weight of 10. And we will return the records with a weight of 20 twice as often as the one with 10. There's pick W hashed, which is again a weighted system, but we use the hash of the client to determine which address we're going to send. So we're not picking a random one. We will always send the same answer to the same client. And we have pick closest. If you're using the G-O-I-P module, we will actually send the address that G-O-I-P considers the closest for this user. We ask G-O-I-P. So we supply G-O-I-P with the IP information. We send an answer and we interpret that and then send off the response. So it's the interaction between it. But the information comes from G-O-I-P. There's some other functions. There is the view, which I found to be actually pretty powerful because you can implement views based on the source address as bind can do this in a configuration. However, you now have it in your zone. So you can just distribute this out to your slaves. And you have let long. This returns the G-O-I-P latitude, longitude if we have it. So how would you configure this? This is actually a working pdns.conf. You just, well, you bind to a few ports. You turn on edns subnet processing. You enable Lua records. They're disabled by default in 402. For one, they're experimental. And two, there are some security concerns. Well, what I'll get to later as well. And in this case, I'm running everything from a bind back end because writing zone files is easy and it's easy to show you. However, Lua records can live within PowerDN as in any back end because they're just records. So named.conf example.nl. I have two reverse zones that I'll show some things for as well. So this is the whole zone. Just put it here. So if you get the slide, you can just copy, paste it out and it will work. So for example.nl, I created a Lua A record with PIC random with a couple of addresses. And so I wanted to give a live demo, but I don't really like the demo gods. And then people, and then Fossum came, yeah, you need an HDMI connector and they don't have HDMI on my laptop. So I was like, well, then I'll just do the slide where you're just going to have to believe me and use a configuration to do it yourself. So as you can see, PIC random, I have a list of three addresses and every time I run a dig against the name server, I get a random answer. Super easy. You can also do things with, if you don't use the functions immediately in your configuration, you need to use a semicolon as you see there because we imply a return. So PIC closes will return something, but you don't have to explicitly tell Lua to return it because we imply that. If you do a semicolon, we will not add a return. So you have to return yourself. So you can do if, then, else, or even way more code. So here you see another function. It's called netmask. It does, it takes best who and tests if it is in this netmask. If it is, well, it takes a true path. If it's not, it takes the false path. And as you can see from the dig as well, if I query it, so this is running on the local loopback, so if I query it, I get the false path and if I add an ednsclient subnet option, which falls in the netmask, it will return the answer I wanted to return. But that's, of course, ugly. That's why we implemented view. So with view, it's very similar. As you can see, no semicolon because this has a return. I have three subnets. One of them is the fallback. And then based, and it will return actually a C name because as you can see it is service to Lua C name. And based on this subnet, it will return a different C name for the name service to. So if I just send a normal dig, you see it takes the default path because there is no client subnet information attached. For the system 2, you can combine all these Lua records. So I have an FIF port up there. And I will also use the GUIP functionality to pick the closest address to the user if the ports are up for both. As you can see, I am doing a query with a subnet. I will get the system 2.exe. Donal C name, then I end up at O5 because, apparently, O5 was up. Oh, so in the demo, I would actually show you the log of the server that said, hey, this one is up, this one is down when I take services in an auto production. And if I use a subnet that is not within that range, you indeed see, again, that you get the default. Similarly, for an A record in another, for the other view, for the other part of the view, you indeed see the other records that you get back. So this was an up-down. At this point, only this one was up, and at this point both were up. But unfortunately, it's not a real demo, so you have to believe me and try it yourself. So, PTR, there are a bunch of drafts. I'm pretty sure they're all expired to automatically create reverse records in zones. So within Bind, you can use $Generate if you want to have certain names generated. And there's also the bulk RR draft, which is something that you... So you put a kind of template in your zone, and then it will generate the name for you. We have done this within Lua. We have a couple of functions where you can generate default hostnames for IPv4, IPv6 addresses, and the other way around, you can do a wildcard record for Create Forward. So let me show you that as well. So I have this zone. I can create a reverse record, which takes all the octets that it gets from the DNS. And if I would put a start of host.example.nl in the example.nl zone, would they create forward with the same syntax? It will generate a forward... It will generate the name... It will generate the address for the same name. So you can have it both ways. So if I do a dig for something within the first... Let's see, 10.5, yeah. So within the first wildcard, it returns the octets in the reverse order, so in the IP address order name. If I do a dig for the start of one, I'm using a different formatting option there, and it actually uses dashes. And if you use the %6 formatting option, we will put the hex value of the IP address in the name. Same goes for IPv6. Again, we just have a zone with a single wildcard record, which has created reverse 6% 33. It's 33 because 1 through 32 are all the different nibbles you can get from the name. So you can even flip them around in the answer, which would be quite interesting. So if I would dig for this IP address, and I use %33, it will just take the address, replace all the columns with dashes, and append the host.example.nl to it. So on the security of these Lua records, like I said, at the moment, it's very much an experimental feature. There's no sandboxing. They can be enabled globally or per domain. If anybody has access to your master and can slave Lua records to you and you have enabled Lua records, they can just run arbitrary code within the context of the authoritative server. So this is something you should keep in mind. You can write a Bitcoin miner in Lua. That's no problem. Although we have limited Lua records to 1,000 Lua instructions per call, which is still quite a lot, but will allow you to do many of the things that you want to do. And of course, they use many more CPU cycles than regular records. So you would prefer to keep the TTL a bit high to not overload your authoritative server at that point. The current state. So as I was writing all these slides, I was playing around with it and the user is just quite rough. Error messages are not super good. Right now, if you need to use the GUIP magic, you need to start the GUIP backend. We'd like to take this out and just enable GUIP from the server configuration without needing the GUIP backend. There are no pre-flight checks. If you put Lua in there, you will only see an error once the record is retrieved. So there is no checking at the moment of whether or not your Lua is correct. But it works, and you can do a lot of fun experiments with it. And I think on Lua.powardiness.org, looking at that, there's a website with some configuration. Go to powardiness.org and there's a link there. Yes, where you can see all the latitude, longitude and all other kinds of fun things. So what's next for this? Because this is interesting stuff, but what do we want to do with it? So we're going to release authoritative server 420 somewhere soon. Alpha 1 is out now. We expect this to be like a month. We want to get some operational experience with Lua records, see what works, see if we can change security model, et cetera. Then we can polish the implementation. And we would like to create a set, a minimal set of useful things and maybe specify a little bit of how Lua should work and come up with a proper specification of a version 1 of Lua records and hopefully put that out to the ITF or at least to other implementers so we can have this whole thing interoperable and have dynamic record generation for everybody. And that's it. So if anybody has any questions. Thank you. Klaus. Thanks a lot for this cool feature. I'm a bit concerned of how does this if port up for example check works like in the background because it has to be scheduled regularly. So how often is it done and is it configurable and what if it's... I'm a bit concerned. Can there be some scenarios where it will block my standard DNS responses? No, the checking is running separately from the query processes. So it runs separately. It checks every second. It is not configurable at the moment. We would like to make it configurable eventually. Something I didn't show, by the way, apart from if port up, there's also if URL up where you can actually state a full URL. It will do a HTTP request and it can even check if there is a certain string in the response to see if it is properly up or not. And it will do it once a second. Yes. And what if this checks for some reason does not work and somebody queries like this label which has the Lua record, will it then get a surf fail or just... It will get a surf fail. If either Lua is incorrect, if the server is down, it depends on your backup selection there. So you can specify, okay, if everything is down, just send this IP address. But if it's up, then send this IP address. So you can actually redirect your users to a sorry page, if you want. Like, sorry, it's broken at the moment. Please try again later. I'm not concerned of the website is broken, but maybe the Lua feature in PowerDNS is broken, so that at least... Because now you're checking the website, but what is more stable? The website or the Lua check in PowerDNS? So of course the check in PowerDNS... It is not Lua doing the check. There is just a bunch of C++ codes running in the background. Yes. The implementation in PowerDNS must be more available, or higher available than the website itself. Otherwise it doesn't make sense to put in dysfunction in PowerDNS. Well, yes. Except that you can easily run two names, sir. And you can run two web servers that will not love that themselves. And also, we can surveil on this, so then your recurser will actually pick the next authoritative at that point. Who would hopefully not surveil? Yeah, if it's also PowerDNS with the same Lua record, it may have the same problem. Maybe some of the other vendors in here can help them. Ching? Just a quick question. Can you give different R codes for different values? Not right now. So you can't implement full views? No. Do you have T6 support? Well, we have T6 support on the aches of our end, but we don't have T6 support within the Lua records. I see. Okay. Almost there. Well, we accept this question. You're asking if the Lua codes can see if the query had a T6? I like that, but we don't... Could have these two features and you could replace fine views, which would be quite awesome. Go ahead. I'll ask a simple question. Have you tried dynamically updating Lua records? I have not tried. The reason why I asked the question is that I used to work for a place that did stupid DNS tricks professionally. And... Well... That's in policy now. But part of the problem was executing what Lua is doing. Part of it, though, was our customers keep wanting what would be the Lua instructions. So we constantly might change the instructions. I'm curious about how quickly you could change it. So from the view of the name server, it is just another record in the zone. Because Lua... So we squat a private code point for Lua. So it is just a different record in the zone, so it can be dynamically updated if your server is configured to allow this. Now, the people at home won't hear you. So for stuff like the PTR records and other things, can you do dynamic DNS as well? Yes. Everything is signed. That comes out of it. Everything is signed, although if you combine with AXFR, it got a tricky story. Yes. Then you still need the keys online on your slave, because the answers are dynamically generated. But yes. Have you done some benchmarking regarding the checks? Because when you say the checks are run every second. So if I have a tons of Lua in there, which is producing the checks. So Lua is not producing the checks. Once the function is called in the background we will just check it every second. And this state is available to the Lua. There is no checking at that point anymore. True, true. But it's going to produce load on the system. So the answer is no, we have not checked this. However, if your web server cannot handle one request a second, you have a problem. True, true. But the question is what's the upper limit or how many Lua? So like I said, this is experimental. We like to polish it. We like to get experience. So if you want to measure this, then please do. Because this is also good data for us. Thank you. Any other questions? Bert? You wrote this. You don't have a question, you have a comment. So actually my comment is more of a question. Can you tell me, Peter, does this stuff also support load balancing on a subsystem number, countries and continents with an exciting syntax to make sure that if people are not served by a local server, they will automatically fill over to a remote cluster? Yes. Yes. Anybody else? Any vendors willing to commit to an implementation now? No? Oh, it's too bad. Thank you.