DNS Classes in C#





DNS Classes in C#

The System.Net namespace contains the Dns class, which provides all the necessary DNS functions for C# programs. This section describes the Dns class methods and shows how they can be used in C# programs to utilize the DNS capabilities of the system.

Synchronous Methods

There are four synchronous methods defined in the Dns class:

GetHostName()

You have already seen this method in action back in Chapter 2. The GetHostName() method is used to determine the hostname of the local system the program is running on. This information is frequently needed for network programs, so you’ll see this method used a lot. The format is simple: there are no parameters to enter, and the result is a string object:

string hostname = Dns.GetHostName();

The information retrieved by GetHostName()hostname should be the same name that appears in the Registry Hostname data value, along with the Domain data value, to create the complete fully-qualified domain name (FQDN) of the system. The FQDN includes the local hostname, along with the full domain name information.

GetHostByName()

The GetHostByName() method performs a DNS query for a specified hostname using the default DNS server configured on the system. The format of the method is as follows:

IPHostEntry GetHostByName(string hostname)

The IPHostEntry that is returned by GetHostByName() is itself an interesting object. It associates a DNS hostname with an array of alias names and IP addresses. It contains three properties:

  • AddressList: An array of IPAddress objects, one for each assigned IP address

  • Aliases: An array of string objects, one for each alias

  • HostName: A string object for the hostname

The AddressList and Aliases objects must be separated into their individual array elements in order to retrieve the information stored. This is often done using the foreach function in C#.

Listing 4.5 is a sample program that demonstrates the GetHostByName() method.

Listing 4.5: The GetDNSHostInfo.cs program
Start example
using System;
using System.Net;
class GetDNSHostInfo
{
  public static void Main(string[] argv)
  {
   if (argv.Length != 1)
   {
    Console.WriteLine("Usage: GetDNSHostInfo hostname");
    return;
   }
   IPHostEntry results = Dns.GetHostByName(argv[0]);
   Console.WriteLine("Host name: {0}",
            results.HostName);
   foreach(string alias in results.Aliases)
   {
     Console.WriteLine("Alias: {0}", alias);
   }
   foreach(IPAddress address in results.AddressList)
   {
     Console.WriteLine("Address: {0}",
           address.ToString());
   }
  }
}
End example

The GetDNSHostInfo.cs program is fairly straightforward. It takes the parameter entered on the command line, attempts to use it to perform a GetHostByName(), and dumps the IPHostEntry object returned from the method. If there is more than one IP address assigned to the hostname, each address will appear in the AddressList property. The foreach function is used to extract each individual IP address and display it. The output from a sample session looks like this:

C:\>GetDNSHostInfo www.microsoft.com
Host name: www.microsoft.akadns.net
Alias: www.microsoft.com
Alias: www.microsoft.com
Address: 207.46.197.102
Address: 207.46.230.220
Address: 207.46.230.218
Address: 207.46.230.219
Address: 207.46.197.100
Address: 207.46.197.113
C:\>

The GetHostByName() method returned the same information that was received by the default nslookup command. In fact, you can run windump or analyzer and watch the DNS query generated by the GetHostByName() method. It should look similar to the one generated by the default nslookup example in Listing 4.4.

As shown in Chapter 2, Listing 2.4, the GetHostByName() method is often used with the GetHostName() method to determine the IP address of the local system, like this:

IPHostEntry localaddrs = Dns.GetHostByName(Dns.GetHostName());

The resulting IPHostEntry object will contain all the IP addresses configured for the local host in the AddressList property.

GetHostByAddress()

When you use the GetDNSHostInfo.cs program in Listing 4.5 and enter an IP address, it unfortunately does not produce the hostname:

C:\>GetDNSHostInfo 207.46.197.100
Host name: 207.46.197.100
Address: 207.46.197.100
C:\>

Not too exciting. Obviously, the GetHostByName() method only works for resolving hostnames.

When you do need to find the hostname for a known IP address, use the GetHostByAddress() method. There are two formats for this method:

IPHostEntry GetHostByAddress(IPAddress address)
IPHostEntry GetHostByAddress(string address)

The first format is used when you have the IP address as an IPAddress object. The second format is used if you want to use the string representation of the dotted quad format of the IP address (such as 207.46.197.100).

The GetDNSAddressInfo.cs program shown in Listing 4.6 demonstrates the GetHostByAddress() method.

Listing 4.6: The GetDNSAddressInfo.cs program
Start example
using System;
using System.Net;
class GetDNSAddressInfo
{
  public static void Main(string)[] argv)
  {
   if (argv.Length != 1)
   {
     Console.WriteLine("Usage: GetDNSAddressInfo address");
     return;
   }
   IPAddress test = IPAddress.Parse(argv[0]);
   IPHostEntry iphe = Dns.GetHostByAddress(test);
   Console.WriteLine("Information for {0}",
           test.ToString());
   Console.WriteLine("Host name: {0}", iphe.HostName);
   foreach(string alias in iphe.Aliases)
   {
     Console.WriteLine("Alias: {0}", alias);
   }
   foreach(IPAddress address in iphe.AddressList)
   {
     Console.WriteLine("Address: {0}", address.ToString());
   }
  }
}
End example

Just for fun (and experience), this program converts the string argument into an IPAddress object, which is used as the parameter to the GetHostByAddress() method. The output should look something like this:

C:\>GetDNSAddressInfo 207.46.197.113
Information for 207.46.197.113
Host name: www.international.microsoft.com
Address: 207.46.197.113
C:\>

Here again, you can use windump or analyzer to watch the DNS network traffic generated by this query.

Warning 

The GetHostByAddress() method does not always work. You may run into many situations where an IP address does not resolve to a hostname. There are two common reasons for this. One is when there is no DNS hostname assigned to the address. Another is that, although a DNS A record might exist, the DNS administrator didn’t use a PTR record pointing the address back to the hostname.

Resolve()

As you saw in the preceding sections, the main disadvantage with the GetHostByName() and GetHostByAddress() methods is that they are specific to one or the other types of address information. If you feed an IP address into the GetHostByName() method, it returns only the address. Even worse, if you try to feed a string hostname to the GetHostByAddress() method, it will produce an Exception (because it uses the IPAddress.Parse() method on the supplied string IP address).

Suppose you are creating a program where customers are entering the address of a remote host—you might not know which form the customers will use. Instead of worrying about trying to figure out whether the input is numeric or text so that you can use the proper GetHostBy method, the Dns class offers a simple solution: the Resolve() method. Resolve() accepts an address in either hostname or IP address format and returns the DNS information in an IPHostEntry object. Listing 4.7 demonstrates this method.

Listing 4.7: The GetResolveInfo.cs program
Start example
using System;
using System.Net;
class GetResolveInfo
{
  public static void Main(string[] argv)
  {
   if (argv.Length != 1)
   {
     Console.WriteLine("Usage: GetResolveInfo address");
     return;
   }
   IPHostEntry iphe = Dns.Resolve(argv[0]);
   Console.WriteLine("Information for {0}", argv[0]);
   Console.WriteLine("Host name: {0}", iphe.HostName);
   foreach(string alias in iphe.Aliases)
   {
     Console.WriteLine("Alias: {0}", alias);
   }
   foreach(IPAddress address in iphe.AddressList)
   {
     Console.WriteLine("Address: {0}",
           address.ToString());
   }
  }
}
End example

The Resolve() method attempts to fill the IPHostEntry object with information regarding the address entered as the parameter. You can use either hostnames or IP addresses, and Resolve() will return the proper information. It’s a much friendlier way of handling any possible host information that a customer might throw at your program.

C:\>GetResolveInfo www.microsoft.com
Information for www.microsoft.com
Host name: www.microsoft.akadns.net
Alias: www.microsoft.com
Alias: www.microsoft.com
Address: 207.46.230.219
Address: 207.46.230.218
Address: 207.46.197.100
Address: 207.46.197.102
Address: 207.46.230.220
Address: 207.46.197.113
C:\>GetResolveInfo 207.46.197.100
Information for 207.46.197.100
Host name: microsoft.com
Address: 207.46.197.100
C:\>

Asynchronous Methods

The regular Dns methods might cause a problem for your C# program because they use blocking mode to communicate with the remote DNS server. If you ran the example programs offered earlier in this section on the DNS classes, you may have noticed that it often takes a few seconds for the DNS information to be returned from the remote DNS server. This may not seem like much of a problem, but it can cause serious difficulties in Windows programs that allow the user to do other things at the same time. While the program is waiting for the DNS server response, the user is prevented from clicking any buttons or entering any information in TextBox fields. For some applications, this can mean unacceptable performance.

Chapter 3, “C# Network Programming Classes,” describes techniques that can be used to prevent network blocking calls. One of the techniques is to use the asynchronous socket methods (described in more detail in Chapter 8, “Asynchronous Socket Programming). These methods allow you to start a network function and specify a delegate to call when the network function completes. Meanwhile, the rest of the program can go happily on its way doing other things. When the network function is completed, it signals the program to run the delegate method.

The Dns class provides the following asynchronous methods to allow your programs to perform asynchronous DNS function calls:

  • BeginGetHostByName()

  • BeginResolve()

  • EndGetHostByName()

  • EndResolve()

Each of the asynchronous methods parallels the equivalent synchronous method. At this time there is no asynchronous GetHostByAddress() call.

The methods are called in pairs. The Beginxxx method is called from the program and points to a delegate method, which contains the Endxxx method. For example, BeginResolve() uses the following format:

public static IAsyncResult BeginResolve(string hostname,
    AsyncCallback requestCallback, object stateObject)

The method uses three parameters:

  • A string representation, hostname, of a hostname or IP address

  • An AsyncCallback object, requestCallback, which defines the delegate

  • A generic object, stateObject, which defines the method state

The AsyncCallback object is created to point to the delegate method used when the DNS results are returned. To do this, you must first create the AsyncCallback object, then assign the delegate method to it:

private AsyncCallback OnResolved;
OnResolved = new AsyncCallback(Resolved);
Object state = new Object();
.
.
Dns.BeginResolve(addr, OnResolved, state);
.
}
private void Resolved(IasyncResult ar)
{
IPHostEntry iphe = Dns.EndResolve(ar);
}

The OnResolved AsyncCallback object points to the delegate method Resolved, which will contain the EndResolve() method to complete the DNS call. The state object allows you to pass information to the delegate method. The EndResolve() method has this format:

public static IPHostEntry EndResolve(IasyncResult ar)

The IAsyncResult object ar is what refers the EndResolve() method to the original BeginResolve() method. The result of the EndResolve() method is the standard IPHostEntry object, which can then be broken down to extract the returned information, similar to the standard Resolve() method discussed earlier.

Listing 4.8 shows a sample program that uses the BeginResolve() and EndResolve() methods in a Windows Forms environment.

Listing 4.8: The AsyncResolve.cs program
Start example
using System;
using System.Drawing;
using System.Net;
using System.Text;
using System.Windows.Forms;
class AsyncResolve    Form:
{
  TextBox address;
  ListBox results;
  private AsyncCallback OnResolved;
  public AsyncResolve()
  {
   Text = "DNS Address Resolver";
   Size = new Size(400,380);
   OnResolved = new AsyncCallback(Resolved);
   Label label1 = new Label();
   label1.Parent = this;
   label1.Text = "Enter address to resolve:";
   label1.AutoSize = true;
   label1.Location = new Point(10, 10);
   address = new TextBox();
   address.Parent = this;
   address.Size = new Size(200, 2 * Font.Height);
   address.Location = new Point(10, 35);
   results = new ListBox();
   results.Parent = this;
   results.Location = new Point(10, 65);
   results.Size = new Size(350, 20 * Font.Height);
   Button checkit = new Button();
   checkit.Parent = this;
   checkit.Text = "Resolve";
   checkit.Location = new Point(235,32);
   checkit.Size = new Size(7 * Font.Height, 2 * Font.Height);
   checkit.Click += new EventHandler(ButtonResolveOnClick);
  }
  void ButtonResolveOnClick(object obj, EventArgs ea)
  {
   results.Items.Clear();
   string addr = address.Text;
   Object state = new Object();
   Dns.BeginResolve(addr, OnResolved, state);
  }
  private void Resolved(IAsyncResult ar)
  {
   string buffer;
   IPHostEntry iphe = Dns.EndResolve(ar);
   buffer = "Host name: " + iphe.HostName;
   results.Items.Add(buffer);
   foreach(string alias in iphe.Aliases)
   {
     buffer = "Alias: " + alias;
     results.Items.Add(buffer);
   }
   foreach(IPAddress addrs in iphe.AddressList)
   {
     buffer = "Address: " + addrs.ToString();
     results.Items.Add(buffer);
   }
  }
  public static void Main()
  {
   Application.Run(new AsyncResolve());
  }
}
End example

Because Windows Forms programs operate in a graphical environment, they work more efficiently using asynchronous Dns methods rather than the synchronous methods. The first part of the AsyncResolve.cs program defines the constructor for the class. The constructor defines a standard Windows Form and adds four controls:

  • A Label object to display some instructional text

  • A TextBox object to allow the customer to enter the address to resolve

  • A ListBox object to easily return the output of the DNS query to the customer

  • A Button object to allow the customer to start the DNS query

After the constructor, two methods are defined. The ButtonResolveOnClick() method is registered as a delegate for the button using the Click property:

checkit.Click += new EventHandler(ButtonResolveOnClick);

Notice that the EventHandler object is added to the existing list of event handlers for the control. The EventHandler object references the delegate to call when the button Click event is detected.

When the Button object is clicked, the ButtonResolveOnClick() delegate is performed. It reads the value entered into the TextBox object and calls the BeginResolve() method using the value of the object, the AsyncCallback object created earlier, and an empty state object:

Dns.BeginResolve(addr, OnResolved, state);

The OnResolved parameter is defined as an AsyncCallback object, and defines the Resolved() method in the program class:

private AsyncCallback OnResolved = null;
OnResolved = new AsyncCallback(Resolved);

The Resolved() method calls the EndResolve() Dns class method, which completes the BeginResolve/EndResolve pair. It must use the IasyncResult object parameter as the parameter value:

private void Resolved(IAsyncResult ar)
  {
   string buffer;
   IPHostEntry iphe = Dns.EndResolve(ar);

The IPHostEntry object is then dissected using the standard methods used in the other DNS programs in this chapter, to find the hostname, any aliases, and any IP addresses returned from the DNS query. To make life a little simpler, the results are easily written to a ListBox object. Figure shows a sample output from the program.

Click To expand
Figure: AsyncResult program results, written to a ListBox object

The AsyncResult program can show results from both hostname and IP address queries. Each time another address is queried, the ListBox is cleared to make it easier for the new information to be read. If you prefer to keep a log of all the queries processed, you can remove the following line from the ButtonResolveOnClick() method:

results.Items.Clear();

If you do this, you might also want to add some type of separator line after the DNS query information is written to the ListBox, to help distinguish between queries. Here’s an example:

results.Items.Add("—————");

When the query log is too long for the ListBox, a vertical scrollbar will appear, allowing you to scroll through the entire query log. Pretty neat payoff for a short amount of code!


 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows