Domain Name System

[ LiB ]

Domain Name System

IP addresses are like phone numbers. However, IP addresses are longer than phone numbers most of the time, and it is virtually impossible to remember them. Humans are typically bad at remembering long strings of numbers ; words are much easier to remember.

Therefore, the designers of the Internet figured out a way to reference IP addresses by names . They decided to create a hierarchical system called the Domain Name System (DNS).

DNS is hierarchical, which makes lookups easy to do. For example, in the beginning, the Internet had seven Top-Level Domains (TLDs); most should be familiar to you. They are listed in Table 2.11.

Table 2.11. Original Top-Level Domains




Commercial use


Network providers, mostly ISPs


Nonprofit organizations


Educational institutions


United States military sites


United States government sites


International sites

As you can see, the domains were largely U.S.-centric, which led to many problems once the Internet became a worldwide construct. Because of this, each country has been assigned its own two-letter TLD, which it should use. Using the old domains is discouraged, although that's not stopping anyone . Some examples of these TLDs are .us (USA), .uk (United Kingdom), .fr (France), .de (Germany), .au (Australia), and even .ax (Antarcticadon't ask).

You can imagine that all of these addresses are at the top level of a tree. Figure 2.9 shows this. The next part of the DNS hierarchy is the domain level. For, this would be "google." Essentially, each root DNS server keeps track of the IP address of every domain.

Figure 2.9. A partial hierarchy of the DNS system.


So when you ask your DNS server for the address of, it goes to the .com server, looks up "google," and then returns the result. At the time of writing, could be found at, but that might change by the time you read this.

That's not all a DNS server can do, however. For example, you're probably used to seeing addresses like "" That "www" at the front is the name of a specific machine on Google's network. So when your DNS server looks up "," it then contacts the DNS server on Google's main machine ( and asks it for the address of the machine named "www." At the time of writing, that is returning Again, that might change by the time you read this.

To further illustrate my point, "news" resolves to, and "images" resolves to All three of those services"www," "news," and "images"are running on different machines in the Google network. The root .com DNS server doesn't know about the different machines (it doesn't need to know about them); the server only knows about the root DNS server. Pretty cool, right?

As you look at Figure 2.9, you can see that it's possible to chain on servers if you want. Look at the two .edu entries on the right. You can construct an address using that tree going to, or

So that's my tiny intro to DNS. DNS is a huge subject, and if you're interested, I suggest a good networking book.

Now, how do you use DNS in the Sockets API? You might think it's possible to do something like this:

 unsigned long google = inet_addr( "" ); 

But you'd be wrong. The inet_addr function converts only standard format IP addresses to a number; it doesn't look up DNSs.

Performing a DNS Lookup

As with everything in the Sockets API, the function of getting an IP address from a DNS lookup is just plain weird and ugly. Once again, the function introduces another strange structure: hostent . Here is what hostent looks like:

 struct hostent {   char*    h_name;   char**   h_aliases;   short    h_addrtype;   short    h_length;   char**   h_addr_list; }; 

ARGH! Almost makes you want to throw a brick at something, doesn't it? Honestly, since I'm not going to be using this structure for anything other than looking up IP addresses, I really don't care to know what all those things mean.

Here is the gethostbyname function, which performs a DNS lookup:

 struct hostent* gethostbyname( const char* name ); 

gethostbyname accepts a string for the name and returns a pointer to the hostent structure. So how the heck do you get an IP address out of that? Well, the IP address is stored as the first four bytes of the two-dimensional array h_addr_list . Here is one way to get the address:

 struct hostent* host; host = gethostbyname( "" ); unsigned long addr = *((unsigned long*)host->h_addr_list[0]); 

The code is maddeningly ugly, but it's a necessary evil. The last line gets the address of the first character in the 2D array, h_addr_list , converts that into an unsigned long pointer, and finally, dereferences it. If you have no idea what I just said, it doesn't matter. Just know that it works, and you'll be fine.

The helpful folks who designed the Sockets API decided to make things a tad easier for us. Before you celebrate, though, you should be warned that it's not that much of an improvement. They created a macro, named h_addr , which is really just h_addr_list[0] . So, instead of that huge ugly line I showed you previously, you can now have a slightly smaller ugly line:

 unsigned long addr = *((unsigned long*)host->h_addr); 

Well, I'll give them an "A" for effortor maybe not.

If there was an error, the function returns NULL instead of a pointer to the hostent . However, you can't look up the error using errno or WSAGetLastError() . Why would the designers make things easy for you?

Instead, you must retrieve errors through a variable called h_errno . There is one saving grace to this horrible mess of an API, however: h_errno works on both the Sockets API and Winsock. Hooray!

Table 2.12 lists the error codes that are returned by h_errno if gethostbyname fails.

Table 2.12. gethostbyname() Error Codes




The address didn't resolve to anything.


The DNS server failed, but the address still might be resolvable. Try again.


An unrecoverable error has occurred.


There is no data available about the address.

There is one other thing you should know: The function cannot resolve addresses if they are already in IP form. For example, trying to resolve "" fails, since it is already an IP address. Just something to remember.

Now, the cool thing about DNS is that you can do reverse lookups, too; you give DNS an IP address, and the system tries to find the DNS entry that matches. This is accomplished by using the gethostbyaddr() function:

 struct hostent* gethostbyaddr( const char* addr, int len, int type ); 

Again with the hostent structuresigh. The first parameter is a pointer to the address that you want to resolve, in NBO. Note that you'll need to do some casting, since NBO wants a char pointer, instead of a pointer to an unsigned long . This is to ensure flexibility, so that the function isn't bound to any specific type of address. The second parameter is the length of the address, and since we're using IPv4, this will be 4. Finally, the type of the address is the last parameter; since you're using IPv4, this is going to be AF_INET . For example, this is how you would call the function:

 unsigned long address = inet_addr( "" ); struct hostent* host; host = gethostbyaddr( (char*)&address, 4, AF_INET ); 

If the function succeeds, you can retrieve the string result of the lookup by accessing the h_name variable inside your hostent structure. If the function fails, 0 is returned, and you can access the error code through h_errno . This function uses the same error codes that are listed in Table 2.12.

By the way, you should not attempt to modify or delete the hostent structures returned by either function; the Sockets API owns and manages them. Unfortunately, that means the structures might be overwritten without notice, so you should copy the data you need from them immediately.

That's pretty much all you need to know about DNS, so on to the fun stuff!

[ LiB ]

MUD Game Programming
MUD Game Programming (Premier Press Game Development)
ISBN: 1592000908
EAN: 2147483647
Year: 2003
Pages: 147
Authors: Ron Penton

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: