Introduction

One of the things I needed to complete my self-written spam-stopper, which acts like an SMTP proxy, is resolving DNS queries, reading SPF1 records, doing reversed lookups, etc. On the .NET (2.0) framework, there is a simple implementation of a DNS component. But it is far from complete. The other project on DNS resolving on CodeProject, C# .NET DNS query component, by Rob Philpott is old, buggy, incomplete, and not supported anymore. It was time to take the official RFCs on DNS and build the application from ground up. I must admit, the influence of Rob's project is there, but the code is definitely not the same.

Background

As mentioned before, the basics of DNS is explained in RFCs. (Request For Comments). These are the RFCs I used for the initial project:

Using the Code

The main core of DNS resolving is the 'resolver'. This class wraps queries into DNS packets and sends them to any DNS server. The response is then decoded into some useful information (at least for programmers, or for me in special https://www.codeproject.com/script/Forums/Images/smiley_wink.gif ). All my DNS stuff uses the namespace Heijden.DNS. Don't change it in your applications, it gives me some comfort knowing my name is stored in some nice other projects. Don't forget to let me know.

Because I don't want to go immediately into details in this article, I only show the usage of the resolver component to warm you up. As the best way to do this, I have built a Dig class which acts like the good-old-Unix-style dig. Its acts like dig, but it is not a complete dig implementation. It does, however, do everything you want it to, presenting the output in more or less the same format.

The resolver uses the default DNS servers which are used on your Windows machine. A good alternative is to use Resolve.DefaultDnsServers which are the two servers from www.opendns.com and are free to use. The resolver accepts any DNS server, or servers. You can add as many as you need, specifying any IP and/or port number.

The main method to do queries to DNS servers is Query. In the dig example, I used a stopwatch to measure the total roundtrip time.

Give Me More Details

Okay, Dig is good. But, the workhorse is the Resolver class. It has got so many secrets. I will try to reveal all of them.

The resolver uses two main classes to do its work. It uses a Query class and delivers a Response class. Querying a DNS server can be done by the TCP or UDP transport protocols. The main DNS methods can be used synchronously and asynchronously. This took me really much typing work. Some headaches and no sleep to do it right. All responses can be stored in a real-time response cache. It uses the Time-To-Live properties of the response records which can be viewed in the Dig application by doing the same queries over and over again (it counts down the TTL values). The caching of records speeds up applications tremendously.

Public constants, constructors, properties, and methods which can be used on the resolver:

That's about it. The classes in the project are more or less well documented. So, programming must not be so difficult.

Points of Interest

Nowadays, networks have started using the IPv6 range more and more. In this project, IPv6 is 100% supported. An example of this is when doing lookups for the AAAA record or PTR lookups, like this one (PTR on 2001:0610:0000:800a:b192:0087https://www.codeproject.com/script/Forums/Images/smiley_redface.gif .5.0.152):

In the Dig example, the translation of the phone-number is done automatically when using NAPTR lookups (can be switched off by the checkbox). The example ANSWER output is edited to protect some data, shown as .... ---- and ++++ , but it works in real-life https://www.codeproject.com/script/Forums/Images/smiley_wink.gif

History

As of writing, the version of this project is 1.0.0.0:

April 4, 2008: Thanks to Martin G C Davies for fixing the GetDNSServers routine to take only the 'OperationalStatus.Up' interfaces.

April 4, 2008: Thanks to 'gbonnet' for pointing me to the 'NAPTR' records, it is added to the project.

May 20, 2008: Jon Webster has fixed the duplicate entries in DNS servers.

July 18, 2008: Added some handy code to do NAPTR lookups.

Version: 1.0.0.1

May 20, 2008: The source code / demo code is much newer than this article. Almost any possible DNS record is added to the project. But implementation is not complete. Anyone is invited to implement the 'empty' DNS record types. https://www.codeproject.com/script/Forums/Images/smiley_wink.gif

Share

About the Author

I'm Alphons van der Heijden, living in Lelystad, Netherlands, Europa, Earth. And currently I'm retiring from hard working ( ;- ), owning my own company. Because I'm full of energy, and a little to young to relax ...., I don't sit down, but create and recreate software solutions, that I like. Reinventing the wheel is my second nature. My interest is in the area of Internet technologies, .NET etc. I was there in 1992 when Mosaic came out, and from that point, my life changed dramatically, and so did the world, in fact. (Y)

Comments and Discussions

Hi i'm trying to do a query agains b.barracudacentral.org but i get very inconsistent results.When i try to do a dns lookup in for example node i get the correct result.At first i thought it war barracuda that where strange but after trying in node and several other services online and code i get consistent result there but this gives me answer, no answer, answer, answer, answer, no answer. I feels like cahce (a bad one ) but it isn't.

I find this library very helpful and end up using in a project. For some cases (that are not very clear to me), I get a stackoverflow exception caused by ReadDomainName method . Do you have any thoughts on how this could be addressed? I might be able to provide you some data in order to reproduce the problem (in case you wanna have a look).

We tried to use your Dig.NET component to perform DNS queries. We need to perform some query about DNSSEC, RRSIG, etc, but it seems these features have not been implemented in your component. Do you have any idea how we can solve this problem? Would you please guide me how I can perform an IPSEC query using your component?

First of all, thanks so much this is fantastic, would love to see more of the project it was implemented for but it's great to have code this complete and of high quality available for everyone, gave 5 stars.

1 very small point, I wanted to be able to sort the responses from the resolver query, I noticed the 1st time I queried MX records for a domain they came back in random priority - 20 then 30 then 10. After this they all came back in the correct order, this may be done on the dns server side not sure. I wanted to be confident that the first mx record in the answers list was always the highest priority (10) so I called .Answers.Sort() in the query response, of course this threw an error as it had no way of comparing the list items. Long story short I implemented the IComparable interface in the RR class and just compared the toString() methods which did the job.

ICANN doesn't allow you to run a script against their servers to see if a domain is registered. Is there a way to use DNS to determine whether a given domain is registered? I realize that such a technique may not be 100% accurate but what would you check using DNS to determine if a Domain is registered that would give at least some proability that the result is correct?

First: Thank you very much for this great work. And thank you much more that you offer it as Open Source.

Now to the 'bug' I believe I found:

For a small project of DNS logfile analysis I implemented your class to do lookup the DNS A records since I had the feeling as if the .NET own functionality doesn't work as stable as I hoped it does.

Using the DNS.NET Resolver does result in a better, but still very unsatisfying result.

If I start to fire several requests against 8.8.8.8 (Google DNS) or any other, open DNS - even against my own, every 30 to 50 requests, the whole lookup stands virtually freezes. After a minute or more, it goes on in working as if nothing happened at all.

To me it seems as if the problem is with non-existing IPs (in terms of existing IPs but with no related DNS entry), but I wasn't able to pin it down to that point at all...

If I do the lookup with nslookup, e.g. with the following IP's, everything works fast and reliable.

maybe there is some bandwidth throttling in between. because of DOS attacks the DNS servers gets more and more protection against it. without any stack trace I can not debug this issue. look at your settings of modem / router and tcp/ip stack of your computer, maybe some buildin parameter is holding you back.

I did not do any performance check myself. If the code is lacking, please contact me.