 So, hello everyone. My name is Anthony Eden. I work for Chimp. I'm going to talk a little bit about DNS hackery with Power DNS and Ruby. At Chimp, we actually are a top-level domain. We have the rights to sell the .mp domain or give away, which case we do with Chimp. So some of the problems that we have to deal with are a little bit unique amongst web applications and web providers because we don't just deal with a single website. We deal with potentially an unlimited number of websites. And for us, one of the key tools that we found in order to provide a service that essentially looks like we're providing potentially millions of websites is Power DNS backed by Postgres and Ruby. So what we do is we have multiple root DNS servers that all run Power DNS and they're backed initially by Postgres. Power DNS has a plug-in. Does anybody here familiar with Power DNS? Probably not. DNS is one of those black magic things that most people go, oh yeah, I do my DNS through GoDaddy. And that's where they leave it. And there's actually DNS, whether you realize it or not, is basically, if it doesn't work, your internet doesn't work. It's everything. You know, if I shut down the name servers for Chimp or for the .NETLV, if I shut them down, then everything we do goes away. Chimp goes away. All the domains we serve up go away everything. So it's a lot of responsibility to keep those things up. So anyways, what we have set up is Postgres handled static domains that never really change. So for example, the Chimp CHI .mp always goes to a particular IP address. So we have a fixed A record. Nick .mp, which is basically the core registry, goes to a specific address. So we use Postgres. We put the records in Postgres. We don't ever have to touch those. But we found cases where we need to do special things where you can't put it in the database because you can't generate all of the domains that can potentially exist because they're an unlimited number of domains. So what we've done is we've used what's in power DNS that's called co-processes. And you can use any scripting language or programming language. You could write it C if you wanted to. But in most cases you write scripting language and it comes with an example of using Perl. So what I did is I converted those Perl examples to Ruby. Now this actually, you know, get back to the Ruby socks performance wise. In the case of power DNS, you don't care because it does an immense amount of caching all over the place. And so it rarely hits the script. But so I'm going to go through and walk through a few examples. This is not from our code. However, I started with our code and then sort of ripped a few things out to give you a few examples of how it might be interesting to you if you're doing work like this. So in the first example, I actually, we use SQL, the SQL library, S-E-Q-E-L, as opposed to SQL. We use that on the servers as a quick way to get into the Postgres servers. But in this particular example, we actually don't even need that. But essentially we run this as a Ruby script. The first thing that it does really is we set the sync for standard in and standard out to true. So that means it's basically going to not cat. It's not going to hold data before it writes to this. It's going to run it straight away. Now the code process API basically says, okay, power DNS is going to pass you text. And they're one line and they're going to pass it a line of time. And it's going to be tab-separated text. Pretty easy to work with text. First line it sends is hello. Okay, I wish I could get this in a way that doesn't. Let's try this. There we go. That's better. So the first example, it gets hello. If it doesn't get that, it's going to say, hey, I fail. I'm leaving right away. If it does that, it's going to say, okay, we're firing up the custom backend. That's right here. So it writes that to standard out. Then you go down and it starts reading from standard in. Pretty simple. This is just some basic Ruby stuff going on here. We can write to standard error for log messages. Or we can continue on import and we continue on here. We basically chop the line, split it by the tabs. If we don't have six arcs, then we send the end command, which says, I can't respond. And essentially if the server gets to that point, it's going to send a serve fail, which is a fast fail way of saying, no, I can't respond to that query. We go down a little further and it'll split the query by tabs into the important ones are the queue name, the queue class, and the queue type. So that's the query and the name they're looking for. That would be something like yourdomain.com is the name they're looking up. Queue class is going to be, that's not that important. IN in almost all cases. DNS can actually handle different classes of data. IN is actually, I believe, internet. And then queue type is going to be a record, which is basically a pointer to an IP address. C name record, which is going to be a pointer to another name record. Or any of the other kinds of things that DNS can support. So once we've broken that down into an array to basically into six elements, then we can start doing things like this where, I'm going to see here, that's big enough to see. Can I shrink that down just a little? See if that'll work. You should still be able to see. So what we're doing here is we're saying, okay, I'm going to use a regular expression and I'm going to grab out in this example the first part of the names. This is the third level domain. Okay, I'm going to store that here in short name. Okay. At that point, I said, all right, if you're querying me because a query can say, give me records of type NS or A, or it can say give me any record type. Well, in this case, I'm going to say, okay, if you ask for an NS record or any, I'm going to give back NS1.sumdomain.com. That's my domain name servers, right? So I always have to give it, if it asks for NS records and I have them, I need to give it to it. If it asks for any type of records, I need to give it plus any other records I can do. Now here's the part that's actually getting interesting why we couldn't do something like this in a database. Here we're going to say, okay, if your type is an A record and your short name starts with letters A through M, go to this IP address. But if your short name, which is basically the third level domain, starts with N through Z, go to this IP address. So what we could potentially do here is use this for a sharding setup, okay, where it could send domains with certain letters over to one set of servers and domains with certain letters over to another set of servers. So that might be one example, and then it has a follow over IP address. You can say, oh yeah, anything else send over to here. So that's for something that wouldn't fall on that. Maybe if it starts with a number, okay, something like that. And then I write a little error message here and say, okay, we sent this address for this short name and then we actually write the data. Now in the case of that co-process API, you write literally the word data followed by a tab, followed by the queue name, the queue class, the data type that you're sending back in this case, so it'd be an A record. The time to live, which is going to be, in this case, 3,600 seconds. And then that's six minutes essentially, right? If I know. Anyway, 30 minutes, whatever. I don't think about this stuff too often. The negative one, we throw away and then the address that we're dealing with. So that's going to be the IP address. So now if I go over here and I don't have power DNS running right now on this machine, but I'll give you an example of running this here. So I'm running now that little script. I'm going to grab some sample data here. It just responded to all of that and I'll show exactly what it did. So here are the four lines of what it sent initially and then it's okay, our customer back ends firing up. We receive this record. We sent this address and there's the data. This was written to standard out. So in the case of power DNS, that would actually return that record when you query power DNS with something like dig or NS lookup or something like that. And so on and so forth. Then it goes end of data. We hit end. All right. Now we have the next one, which is the first one asked for Quentin, which is a queue. So it goes to the second IP address. The next one asked for Aaron, which is the IP address ending in dot one. So it returns that address. And then the third one actually said give me any record for Aaron. It also gave me the name server records and the IP and the A record. So that's one example of how you might be able to use it. Another example. In this case, this case we actually do need the SQL. So I set up a little database in Postgres and it looks right now something like this. Pretty straightforward. But in this case, we actually don't need it for this example, but we'll use it for the third example. But I set the data there and it says, okay, this is the same thing essentially. This case it stores the prefix, but it says, hey, this line here. Go into the table users, filter and find me the login that matches short name. Okay. And then essentially it says, okay, I'm going to get the short name and I'm going to send either the NS records or in this case, actually we do need it because I'm going to grab the host out. So that was that host record in there. So now, rather than doing something simple, which is by letter, you could have a system that will, for example, would over time it would shard your database. So let's say your first 100,000 users are on your first shard and your second 100,000 users are on your second and so on and so forth. Well, you could store a record alongside of it that says here's the server that they live on and then you could serve them up from that. So that would be, that's another example of how to do it. And I could use the same text in the same example here of let's go over here. So this is example two and I'm going to paste in that same thing and you see here this time it says, okay, Quinten was on 1.2.3.4 and Aaron was on 5.6.7.8. That's these records right here and those match up with what's in the database. So now we can actually return the information based on a record that we have in the database. The final example I want to show you that might be interesting is something we actually do use in our system. So in the case of Chimp we basically give away second level domain. So mine is Anthony.mp. Well, when I'm testing it I need to retain that Anthony.mp but we have a staging server and I want to go to that. So we have staging.anthony.mp. Well, in this case though we still need to know that that middle part the first thing we need to know is the staging server. That's all we really care about. So when we're going to keep the rest of the domain we'll parse that in our Rails app to determine how to map you up to your data. But here you can see right here there's the query. So it says if we start with staging and then in return a specific C name record. Now in this case notice I skipped the A records and I went straight to C names. C names points into another domain. The word staging. Some chunk of text.sumdomain.com I want to send that with a C name record over to the staging server and it says okay send back the same data except it says C name staging.sumdomain.com and then you would have an L statement or LSIF in this case to say oh do the same thing you did in example 2 if you wanted to shard to your other servers. So that's pretty much it. Essentially anything that you could do with Ruby you could write something that could totally modify your DNS or send back custom results based on the query. So that's a little bit of DNS hackery for you. Are there any questions? If not then I will pass. Yes. Did you consider bind and NS update? So yes we did consider bind. There's one thing that I'm not telling you that we do that wasn't possible with bind it's basically it's needed to do this in a stars. We would have had to push to the bind server and basically reloaded the zone file our night isn't a reload right? So we would have to have something that pushes to that in this case we never have to touch the DNS because we can essentially wildcard things in ways that make it so as soon as you set up your chimp site you're done and I keep those but there's no DNS it works right there and so that's one of the main reasons we did it plus PowerDNS is actually a pretty darn stable server I don't know if you guys are familiar with the DNS hacks that came out last year or the vulnerabilities that were there for poisoning and things like that they were the ones who they fixed first they basically provided the patch that's here to everybody how you do it so they're very responsive very fast server and it just doesn't have the crop that bind has plus not nearly as many people attack it in the way they do bind because DNS is one of the most often attacked parts of any system so it's fundamental right? If you've ever seen we sort of heard a little about what Verisign had to do to me basically they bought what was the name of the name servers or like locked in faults and stuff like biometric security just think about it for a second somebody poisons the root DNS servers and that's it they can essentially bring down the entire name there are thousands of other root DNS servers aren't there regional root DNS servers with those names? so there's 13 of the core the root name servers that are labeled A through whatever they are I think 13 or maybe more now the problem is they all sync from each other but there's not just one A the reason we chose it was just because of the things we could do that we couldn't do with bind and we didn't have to deal with the crop to bind thank you very much