Hacking DNS

Submitted by Larry on 18 June 2005 - 8:00am

At the end of my last entry, I hinted at some network restructuring I'd done in the fallout of Yahoo deciding to take its network and go home. To be more specific I was just putting the last finishing touches on what was already (I think) a cool use (or abuse, I'm sure some would claim) of the DNS network. While my setup has evolved a bit over time, I am going to explain its current, theoretically final incarnation in the hopes that it proves useful to others who wish to go nuts with DNS in order to run fancy servers on a dynamic IP address.

DNS in a Nutshell

A brief introduction to DNS is, I suppose, useful for those not familiar with it. If you are already familiar with DNS you can skip this section, or else read it so that you can poke fun at my attempts at describing it.

DNS stands for Domain Name System, and it is the network of servers around the world that is responsible for turning human-readable names such as "www.garfieldtech.com" into computer-readable IP addresses like such as 209.68.52.180. Like most of the core protocols of the Internet, it is standardized by the Internet Engineering Task Force (IETF) through a series of RFCs (or "Request for Comments", a rather silly name since by the time an RFC is published the time for comments has long-since passed). The earliest reference I could find to DNS (although it is not referred to by that name explicitly) is RFC 0799 dating from 1981. It's not a very normative document, and in fact ends with the the amusing phrase "This memorandum is intended to stimulate discussion, not simulate it. " Many RFCs then established various editions of the DNS concept, although I believe RFC 1034 (description of the system) and RFC 1035 (description of the protocol), both dating from 1987, are the ones currenty in use (mostly). Dozens of later RFCs edited and tweaked and supplemented the system. (It seems the policy of the RFC editor to never fully document anything when you can just publish an add-on or supplement or extension RFC instead and let implementers figure out how it all works together.)

In its modern incarnation DNS is a centrally-controlled hierarchical recursive system. At the "top" of the network is the Internet Corporation for Assigned Names and Numbers (ICANN), a theoretically non-profit organization run by major technology companies. ICANN runs a large network of "root servers" around the world that are the authoritative source for the "." root domain. That is, those servers can tell you the authoritative servers that know all about top-level-domains (TLDs) such as "com.", "edu.", "org.", and so on. Each of those TLDs is controlled by some other organization that can tell you the authoritative servers that know about "yahoo.com.", "mit.edu.", or "fsf.org.". Each of those servers... you get the idea. At any point you can also specify the actual IP address of a system, that is, say that "yahoo.com." translates to some IP address. (There really is a period at the end of a Fully Qualified Domain Name (FQDN), although in virtually all programs it's safe to omit it as the software will silently assume it's there.)

Each authoritative server can have a number of records associated with it of various types. We're only interested in a few:

  • An A record is simply a basic "this name maps to this IP" record.
  • A CNAME record refers to a "canonical name", that is, it defines an alias. You can then tell the system that "foo.garfieldtech.com" is really an alias for "bar.garfieldtech.com", and the system will dutifully treat them the same. Note, however, that having a CNAME point to another name that is defined as a CNAME is an error, as things then get weird.
  • An MX record is a "Mail Exchange" record. That is, it says that e-mail sent to an @thisdomain address should be send to a specific server by name, usually something like mail.garfieldtech.com or smtp.garfieldtech.com. Naturally that domain name should resolve to an actual IP address.

Every time a program (web browser, ssh client, instant messaging program, anything) tries to connect to a given server by name, it first asks the operating system to convert it into an IP address. The OS, in turn, is configured with one or more DNS servers to use (defined in /etc/resolv.conf in most *nix systems) that it will ask to turn the name, www.garfieldtech.com, for instance, into an IP address. The DNS server will check to see if it knows what IP address that refers to already. If not, it will ask the root servers if they know what server(s) are responsible for "com.". The root servers will direct the DNS server to one of the many authoritative servers for that TLD. The DNS server will then ask one of those servers if it knows the IP address of www.garfieldtech.com, and if not what server is authoritiative for "garfieldtech.com.". The "com." server will respond with the server(s) responsible for "garfieldtech.com.", and the DNS server will then ask that server if it know the IP address of "www.garfieldtech.com.". That server does, and will return an IP address. The DNS server will return that IP address to the computer that asked it in the first place, which will then return that IP address to the program so that it can go ahead and contact the remote server it asked for in the first place, blissfully ignorant of the complicated multi-step process involved.

Of course, it would be disgustingly inefficient to go through that complicated multi-step process every time you refreshed Slashdot.org. Therefore, DNS servers will cache every record they see for some period, 12 hours by default. That keeps the entire network reasonably clippy, and in general you will never see it in action except for the brief "looking up host www.garfieldtech.com" message that flashes by in your web browser's status bar when viewing a new web site.

There is, of course, much more to DNS but that's enough for our needs and I suspect you're already bored, so I'll get back to how to twist DNS into weird shapes that scare small children and make end-runs around greedy ISPs.

Dynamic problems

The caching of domain names speeds the system up considerably (it would be functionally useless without it), but does make one rather large assumption: Domain Name to IP address mappings change very rarely, and when they do the few days it takes to percolate through the entire worldwide network is acceptable. (Two! Two rather large assumptions!) That's fine if you have a static IP address, but most ISPs today don't give out static IP addresses to home users unless they pay some obscene amount of money, and even then only if you're on broadband. What about people who want to run a server at home that people can actually access?

The most common solution is something called "Dynamic DNS". Many organizations have sprung up offering dynamic DNS service. That is, you install some small program on your computer. Every time your computer connects to the Internet, it phones home to the provider's DNS server and gives it your computer's new IP address. The DNS server is already configured to have a very short cache time (and to tell other servers not to cache data it provides for very long), so changes percolate through the system in an hour or so instead of days.

The other challenge, of course, is that home users with multiple systems (such as yours truly) generally run a NAT firewall (Network Address Translation) in order to allow them to mask multiple computers as having only one IP address visible to the outside world. Besides making it possible to run multiple computers on a single broadband account, it adds a layer of security since remote systems can't connect to systems behind the NAT box without the NAT box being specially configured for it. Of course, that also makes accessing them when you actually want to more difficult.

Dynamic plans

So, with all of that background out of the way, here's what I set out to accomplish:

  1. DNS-based access to my home network remotely via SSH.
  2. A home web server where I can control the environment completely.
  3. A remote web server where I don't need to worry about traffic flooding my poor broadband upstream speed.
  4. A private mail server hosted at home with @garfieldtech.com mail addresses.
  5. A private Jabber server hosted at home with @garfieldtech.com Jabber IDs.
  6. All of the above to be reasonably transparent.

The main catch being that my home address is semi-dynamic and changes sometimes when my cable modem is restarted, and all my systems are behind a NAT firewall. (TWO! The Two main catches are...) At first blush it sounds easy. Just use one of them new-fangled dynamic DNS services. Ah, but it's not quite that easy. That works for points 1, 2, and 3, but not 4, 5, or 6. Something trickier is needed.

OK, so we need to run a DNS server. I can't run it at home, however, because DNS servers have to be on really-static IP addresses, and if other servers can't look up my IP address because it's dynamic then how are they going to look up my IP address to get my DNS server in order to look up my IP address?

Instead we get a full DNS host, one that will offer a real DNS server that I can configure. There are many many DNS providers out there. Personally, I use Pair Networks. Pair offers web hosting as well as DNS registration and hosting via its sister company PairNIC. They're not the cheapest host, but they're very reliable, offer good service, are all FreeBSD-based, and host free (and fast!) mirrors for Debian and various BSDs as good corporate citizens, so I'm willing to support them. They also offer almost everything I need to setup my inside-out network.

Dynamic solutions

Here, then, is the magical incantation to run any server on a static domain name on a dynamic IP address without anyone knowing, in 10 easy steps. (Yes, we're finally getting to the point of this whole article. Yay!)

Step 1: garfieldtech.dyndns.org
First, we register a dynamic DNS name with DynDNS.org. There are many other dynamic DNS services out there that would work, but DynDNS.org works well, is reasonably popular, and their client is pre-included with IPCop. IPCop, incidentally, is a Linux distribution used for building NAT firewalls. Highly recommended.
Step 2: garfieldtech.com
This was the easy part, since I'd done it years ago. garfieldtech.com was already registered with Pair Networks and hosted by them, with both www.garfieldtech.com and garfieldtech.com pointing to the same static IP on their network.
Step 3: Enable Custom DNS
The next step involved telling PairNIC, who runs the DNS servers for Pair Networks, that I wanted custom DNS. That's fortunatelly just a confirmation button (true at most sites), after which I had complete control over the domain name settings for garfieldtech.com. Most DNS hosts provide a web front end to configure your domain settings, which is good because the config file syntax for the most common DNS servers was designed by The Spanish Inquisition (you didn't expect that, did you?) as the less pleasant alternative to burning at the stake. Some, however, also restrict the types of records you can create. That was the main problem with the popular free domain hosting service ZoneEdit. Fortunately PairNIC gives me almost complete freedom to do the weirdness that follows.
Step 4: CNAME. CNAME go. Go CNAME Go.
The CNAME alias is the crux of trickery. It's actually very simple. home.garfieldtech.com is set up as a CNAME to garfieldtech.dyndns.org. Now home.garfieldtech.com will always point to my home router, and I can access it from anywhere. Score. While I'm at it, let's set up a few other home-server-pointing names for other services. Figuring out what other fun names we could have is left as an exercise to the reader.
Step 5: mail.garfieldtech.com
Here's the second trick, and the most controvercial. mail.garfieldtech.com is also a CNAME to garfieldtech.dyndns.org. Then, we set up an MX record for garfieldtech.com to point to mail.garfieldtech.com. So now, the Mail Exchange for any @garfieldtech.com e-mail addresses is my home network, whatever its IP address happens to be. Now there is at most an hour or so downtime if my IP ever changes, and the e-mail system is designed to handle short delys like that without a hiccup. (The details of the e-mail network are for now best left to Vincent Price movies.) Now, some people argue that setting an MX record to a CNAME is a Bad Thing(tm), and in fact some DNS hosts (like ZoneEdit) are setup in such a way that you can't. However, I was unable to find any statement in the RFCs to say that it was completely forbidden, and in practice it's worked just fine. The closest statement is in RFC 0974, which states:

Note that the algorithm to delete irrelevant RRs breaks if LOCAL has a alias and the alias is listed in the MX records for REMOTE. (E.g. REMOTE has an MX of ALIAS, where ALIAS has a CNAME of LOCAL). This can be avoided if aliases are never used in the data section of MX RRs.

Since I'm not playing fancy games with LOCAL and REMOTE, only with CNAME, it doesn't seem to cause a problem. If, however, this step offends your sensibilities you are free to not run your own mail server on a dynamic IP address, and then renumber the following steps accordingly. (The latter is left as an exercise to the reader.)

Step 6: www.garfieldtech.com
Here's another easy one. For the externally hosted web site, where I put stuff I don't want sucked through my broadband's upstream straw (like this blog), my web host already provides a static IP address that maps to my shared host. So we just create an A record for www.garfieldtech.com to that static IP, and the external site continues unabaited.
Step 7: garfieldtech.com, Take 2
So far everything is working wonderfully, but there's one catch. E-mail is the only modern Internet protocol that has special status with DNS. If I want to run anything else publicly available on my home system (Jabber, for instance), then I have to use some other method than a DNS record to direct it home. Oh sure, I could just use jabber.garfieldtech.com and CNAME it the same way everything else is CNAMEd, but what fun is that? Instead, garfieldtech.com is pointed directly to my home system via an A record. Why not a CNAME? Well, that would be better but it seems that @ records (that is, the domain itself, such as garfieldtech.com) can't be CNAMEs. At least PairNIC won't let me make it a CNAME. Since most other protocols are not as screwy as e-mail, I'd notice any problems immediately and the short downtime to manually reset the record would be acceptable. Great, so now garfieldtech.com points home and I can run anything I want there.
Step 8: Web Forwarding
Of course, many people will type a domain name into a web browser without the "www." and expect it to "magically" figure out that it should go to www.whatever.com. Normally that magic is just a CNAME from www.garfieldtech.com to garfieldtech.com, but wait, those are now different places! Instead, we have to move down a level and use different magic. We let garfieldtech.com traffic get directed to the home system and get to the home web server. However, we then set up the web server on that system to automatically forward "garfield.com" host requests to "www.garfieldtech.com". So, while the request still gets sent through the home network it's very small traffic, and the user is none-the-wiser. home.garfieldtech.com, however, will still access the home server as if nothing is wrong, and indeed nothing is.
Step 9: The firewall
This part has nothing to do with DNS, but I'll mention it anyway. Remember that NAT box that's sitting between my home server and the rest of the world? So far, all incoming traffic is stopped there. To allow it to actually get to the server, we just set up a few port forwarding rules. The most important are port 80 (aka HTTP, aka "The Intarweb"), port 25 (SMTP, aka e-mail), an alternative port for ssh (22 is the default, but why use the default for something like that?) and ports 5222, 5223, and 5269 (XMPP, aka Jabber). All of those get forwarded to the appropriate IP within my private network at home. Outside users never know the difference, and people e-mailing me don't need to know that I'm running my own mail server on a cable modem.
Step 10: Brag about it on your blog
This step is not strictly necessary to the proper functioning of the system, but it can be fun and hopefully educational for others who wish to setup a similar network.

So what exactly does this buy us? It allows me to have access to my home network via SSH or a web browser as well as have a "real" site hosted by a professional hosting company, and still have larry@garfieldtech.com as an e-mail address and as a Jabber address. And all without paying extra for a static IP address. That's just cool. In geek parlance, it's a "cleaver hack", from which most cool ideas are born (as well as many stupid recursive acronyms, but we won't get into that). If you feel like asking for more details, you can already reach me by Jabber at larry@garfieldtech.com, which I'm happy to say is now fully functional.

What? You don't know what Jabber is? Well, I guess that's a topic for another time.

Richard Lynch (not verified)

8 August 2005 - 11:17pm

I used to have a similar setup...

However, the sheer volume of attempts by spammers to use port 25 were, in effect, creating a Denial of Service to my cable-modem...

This might have been caused by allowing wildcard email addresses at my domains. This does allow more junk, but it has saved my [bleep] on more than one occasion where somebody else mis-typed an email address. I still get it, and can correct the problem while still dealing with the email.

You may (or may not) want to consider hacking your pair setup to forward to some port other than 25 for the email, and shutting down port 25 on the home box...

Or, for that matter, shift the email back to the "real" server that has the bandwidth to handle it. I mean, yeah, sure, it's a pain to use that silly GUI to add/edit email addresses and forwarding, but it's not that horrible.

Hi, Richard. I hadn't noticed that people were actually posting comments. :-)

The reason I run the server myself is that I want to have a full IMAP archive of all my mail. If I were just using POP then sure, let my ISP/webhost/someone else deal with it. But I doubt that Pair would like me keeping 2 GB of mail (not much compared to some servers, but that's just for me personally) on their servers. It would also be much slower to access over IMAP from my desktop that way, too.

I wasn't aware that DNS could talk ports, however. How would I tell "all servers" to send to port 26 (or 2525, or whatever) instead of 25, without half of them not listening?

Hello, I am trying to do the same thing you outline in your post, however I am not having much success. My webhost does not think a CNAME will work. They have set one up, however it is not working. Do you have any suggestions to get it working? I have pointed support to your post.

Thanks,
Brennan