Dns Class

Dns Class
To connect to a server the IP address of the server is needed. Because IP addresses are not easy to remember and can change, we use DNS names. In Chapter 1 we saw the functionality of DNS, and how a DNS server resolves names to IP addresses.

For .NET applications the Dns class can be used to resolve domain names to IP addresses. This class not only uses DNS servers to resolve names to IP addresses, but we will see that there are other mechanisms too.

Resolve a Name to an IP Address
To get an IP address from a hostname we can use the static method Dns.Resolve(). For a single hostname multiple IP addresses can be configured. So Resolve() not only returns an IPAddress, but an IPHostEntry object. IPHostEntry holds an array of addresses, alias names, and the hostname itself.

In the example below, we resolve the IP addresses of the hostname www.microsoft.com with Dns.Resolve(). The IP addresses are written to the console by accessing the AddressList property that returns an array of IPAddress objects. Next we loop through all registered names with the Aliases property, and finally we write the real hostname to the console.


string hostname = "www.microsoft.com";
IPHostEntry entry = Dns.Resolve(hostname);

Console.WriteLine("IP Addresses for {0}: ", hostname);
foreach (IPAddress address in entry.AddressList)
Console.WriteLine(address.ToString());

Console.WriteLine("\nAlias names:");
foreach (string aliasName in entry.Aliases)
Console.WriteLine(aliasName);

Console.WriteLine("\nAnd the real hostname:");
Console.WriteLine(entry.HostName);

The output of this sample program shows that the hostname www.microsoft.com is only an alias for www.microsoft.akadns.com, and it has six IP addresses:


The Dns class has more static methods that return IPHostEntry objects. They differentiate mainly in the way the hostname can be passed:

Dns Static Method
Description

Resolve()
Accepts a DNS hostname or IP address in dotted quad-notation to resolve IP addresses.

GetHostByName()
This method only accepts the DNS hostname, but not an IP address.

GetHostByAddress()
This method returns an IPHostEntry object by passing either an IP address as a string in dotted quad-notation, or as an IPAddress object.


To get the hostname of the local computer, we can use the method Dns.GetHostName().

How is the IP Address Resolved?
There are many ways that an IP address can be resolved. You may have already wondered why a name was resolved although it was never configured with a DNS server-let's look at the ways in which IP addresses can be resolved.

With early versions of the TCP/IP network, hostnames were resolved only by a HOSTS file. A HOSTS file has a mapping from an IP address to the name of the host with optional additional alias names. Such a host file named hosts can also be found on a Windows 2000 PC in the directory \system32\drivers\etc.

Later the domain name system was introduced with DNS servers that know about the mapping of hostnames to IP addresses, and also the other way around-getting the hostname from an IP address is known as reverse lookup. Instead of changing every HOSTS file when a new IP address should be added, the new IP address need only be added to the DNS server. The client systems only need to be aware of the DNS server, and therefore the IP addresses can be resolved by asking the DNS server. The DNS server can be configured with the TCP/IP properties of the network configuration.

In order to free network administrators from the tiresome task of manually assigning IP addresses to every client on the network, a DHCP (Dynamic Host Configuration Protocol) server can be used. DHCP introduced dynamic IP addresses for PC clients. With DHCP, a client PC no longer has a fixed IP address. This introduced a new challenge for DNS servers and was the reason why Dynamic DNS was introduced with Windows 2000. Using Dynamic DNS, the IP address and hostname of a client PC can be set automatically in the DNS server as soon as the DHCP address is received.

To summarize, IP addresses are resolved with HOSTS files and DNS servers-but there are other ways. In a local network, in addition to a DNS name a NetBIOS hostname is used. If the DNS lookup fails, some NetBIOS naming mechanisms are used to get an IP address. Let us look at how this works.

NetBIOS Hostnames
In a Microsoft network, PCs not only have DNS hostnames, but also NetBIOS hostnames. NetBIOS functionality can also be used with TCP/IP; here it is called NBT-NetBIOS over TCP/IP. Normally the NetBIOS name is the same as the DNS name without the domain name extension.

For NetBIOS name resolution an LMHOSTS file is used, similar to the HOSTS file- it's in the same directory as the HOSTS file in fact. The file LMHOSTS.SAM you may find on your PC is just a sample file that shows what the LMHOSTS file can look like. If the hostname cannot be resolved with the LMHOSTS file, the NetBIOS name resolution depends on the NetBIOS node type. We can differentiate between four different node types:

B-Node (Broadcast)

With B-nodes a broadcast is used to resolve the NetBIOS hostname. If IP routers are used that don't forward name registration and name queries, the name cannot be resolved. B-nodes are a bad option for large networks because they load the network with broadcasts.

P-Node (Point to Point)

Using P-nodes a WINS server is used to register the hostname. A WINS server is similar to a DNS server, except that it resolves NetBIOS names to IP addresses rather than DNS names to IP addresses. A client can ask the WINS server to get the IP address for a hostname. This method reduces the network traffic, but fails if the WINS server cannot be reached.

M-Node (Mixed)

M-node configuration is a mixture of B-node and P-node. As a first try a broadcast is used; if the broadcast doesn't work because the target host is not in the same network, a WINS server is asked to resolve the hostname. This configuration is useful with many small sub-networks that communicate across slow links.

H-Node (Hybrid)

An H-node is also a mixture of B-node and P-node, but here the P-node mechanism is used first, before the B-node mechanism. A broadcast is used as a last resort only if other mechanisms fail.

You can look at the node-type that is configured for your system with the command-line utility ipconfig /all. The default is the typically best performing node-type H-node.

If that naming resolution is not complex enough it is also possible to edit some entries in the Registry to change the order of DNS name lookup and NetBIOS name lookup-however, caution is advised with this, as it's a good idea not to mess up these Registry keys. The configuration of these values can be found in


HKLM\System\CurrentControlSet\Services\NetBT\Parameters.

If the variable DhcpNodeType is set to 4, this specifies an H-node.

Resolving the IP Address Asynchronously
Querying a DNS server can take some time; the methods we have seen so far are all synchronous. The Dns class has built-in support for asynchronous DNS lookups: the methods Resolve() and GetHostByName() have asynchronous versions. We will only discuss the asynchronous versions of the GetHostByName() method, but the Resolve() method is similar.

The asynchronous versions of the GetHostByName() method are BeginGetHostByName() and EndGetHostByName(). The BeginGetHostByName() method starts the name query but doesn't wait for a successful query or a timeout-it returns immediately. Besides passing the hostname (similar to GetHostByName()) this method accepts an AsyncCallback delegate that defines what method should be called as soon as the hostname is resolved, or the timeout happens. Here I'm using the class method DnsLookupCompleted() that has the return type and signature as it is defined by the AsyncCallback delegate.


using System;
using System.Net;

class AsyncDnsDemo
{
private static string hostname = "www.wrox.com";

static void Main(string[] args)
{
if (args.Length != 0)
hostname = args[0];

Dns.BeginGetHostByName(hostname,
new AsyncCallback(DnsLookupCompleted), null);

Console.WriteLine("Waiting for the results...");
Console.ReadLine();
}

As soon as the DNS lookup is finished, the DnsLookupCompleted() method gets called, and we get the result of the name lookup by calling Dns.EndGetHostByName(). Then we can access all IP addresses, alias names, and the real hostname as in the synchronous example:

private static void DnsLookupCompleted(IAsyncResult ar)
{
IPHostEntry entry = Dns.EndGetHostByName(ar);

Console.WriteLine("IP Addresses for {0}: ", hostname);
foreach (IPAddress address in entry.AddressList)
Console.WriteLine(address.ToString());

Console.WriteLine("\nAlias names:");
foreach (string aliasName in entry.Aliases)
Console.WriteLine(aliasName);

Console.WriteLine("\nAnd the real hostname:");
Console.WriteLine(entry.HostName);
}
}
As an alternative to passing a delegate to the BeginGetHostByName() method we can use a reference to the IAsyncResult interface that is returned to check for the completed DNS lookup using the IsCompleted property. As soon as the lookup is finished, we invoke the same method we have done previously to read the IP addresses and hostname: DnsLookupCompleted().

static void Main(string[] args)
{
if (args.Length != 0)
hostname = args[0];

IAsyncResult ar = Dns.BeginGetHostByName(hostname, null, null);

while (!ar.IsCompleted)
{
Console.WriteLine("Can do something else...");
System.Threading.Thread.Sleep(100);
}
DnsLookupCompleted(ar);