DNS Resolver RFC 1035

Environment: VC6

Introduction

I searched for a DNS Resolver for quite a long time. I got the solution, but it was too uncomfortable to use it. Thus, I made my own DNS Resolver; it's is very compact in size and is free from the exceptions and errors we usually encounter with CSocket.

DNS Protocol Explanation (RFC 1035)

To query any type of domain name (for example, MX for mail exchange), the request is sent in the form of a binary record having a predefined bits and bytes pattern. Then, the server sends a response. If the server has the answer, it sends answers in the response records; otherwise, it sends other name servers that you then can query and get the answer from them. If other name servers don't have an answer, they in turn will again send other name servers. This process is endless, so we have to query recursively only up to a certain depth (I have chosen a depth of 10).

Library Source Code

The Dns.h file contains all DNS-related source code; it uses other libraries, such as SocketEx.h, SocketClient.h, and NeuroBuffer.h.

Library File Name Description
CSocketEx Sockets functions wrapper class (CSocket is very heavy and unreliable if you don't have the exact idea of how it works). All the functions are of same name as of CSocket. You can use this class directly.
CSocketClient Derived from CSocketEx and throws Proper exceptions with details of winsock errors. It defines two operators, >> and <<, for easy send and receive. It also changes network to host and host to a network order of bytes, if required.
CNeuroBuffer Because DNS response-request cycles are in binary form, a bytes buffer is used here.
CDnsBuffer DNS responses contain domain names; these domain names are compressed with an LZW type of compression. It means that, rather than repeating names, it just gives a pointer to the previous name that occurred in the buffer. So, to extract, it's very important to follow this protocol. The CDnsBuffer class manages this decompression and gives you an expanded domain name.
** CDnsClient This is the main class; you can either create an object of CDnsClient to query a single name server without any recursion, or you can call its static members Get and GetMX. It's better that you call static members only.
CDnsRR This is the base class of response of the DNS request, which then is derived further for particular types.
CDnsRRMX This is the response record of Type MX. It has the Exchange and Preference fields used for MX.
CDnsRRA Response record for type A.
CDnsRRNS Response record of type NS.
CDnsRRDefault I have not programmed all classes of DNS here. I have programmed only particular classes, the rest of which are not programmed. You will find it in the CDnsRRDefault class; it stores the length of the buffer and the data buffer pointer.
CDnsRRPtrList When you interact with CDnsClient, the responses are returned in CDnsRRPtrList, which is a CList of the CDnsRR* pointer. You have to be careful while accessing the data of pointer. When CDnsRRPtrList gets destroyed, it automatically deletes all pointers!! So, you must keep a copy of the response record's data, which you need. Because these pointers you get are in the form of CDnsRR* only, you will need to cast according to Type. If you query for MX, you must cast CDnsRRMX * pMX = (CDnsRR*) pRR, and so forth. and then access data from pMX. You can find the type in the Type field of the response record "pRR->Type".
Note: I don't usually program in the form of different .h and .cpp files beause using them somewhere else the next time is a big problem. You have to move both files here and there, so I put all the code of my in .h file only; I don't write to the .cpp file unless it's required. You need only to copy the SocketEx.h, SocketClient.h, NeuroBuffer.h, and Dns.h files into your project's directory, and add the line
#include "dns.h"
after your
#if !defined(.....
and so forth code of your Visual Studio-generated file. If you put it above this, you will get n number of errors.

Here's the main body of code:

[
  #include "Dns.h"

  void main(int nArgs,char * pcArgs[])
  {
    CStringList MXs;
    CString Log;
    Log = CDnsClient::GetMX("codeguru.com",MXs);
    while(!MXs.IsEmpty())
    {
      printf("MX=%s\n",(LPCTSTR)MXs.RemoveHead());
    }

    // Other Way
    // Additional Records sent by DNS Server usually contains
    // A records of all names, A records gives IP Addresses
    CDnsRRPtrList RRs,Additionals;

    // NSTried List, you must give this as an empty list.
    // All name servers have to be queried only once; this
    // maintains all name servers tried...
    CStringList NSTried;
    int nTries = 10;
    BOOL bResult =
      CDnsClient::Get(
                  NULL,            // Put null if you don't know
                                   // ther server's name
                  "codeguru.com",
                  "MX",
                  RRs,             // Answers
                  Additionals,     // Additional
                  NSTried,
                  Log,
                  nTries
                )

    POSITION Pos = RRs.GetHeadPosition();
    while(Pos)
    {
      CDnsRR * pRR = RRs.GetNext(Pos);
      if(pRR->Type!=CDnsQueryType::GetType("MX"))
        continue;
      CDnsRRMX * pRRMX = (CDnsRRMX*) pRR;
      printf("MX=%s\n",(LPCTSTR)MXs.RemoveHead());
    }
  }
]

Downloads

Download demo project - 16 Kb
Download source - 39 Kb


Comments

  • Bug in CSocketEx::Close() method

    Posted by elo on 12/12/2006 10:25am

    One more problem in the code that results in sockets not being properly closed - BOOL Close() { SOCKET hSocket = m_hSocket; m_hSocket = INVALID_SOCKET; if(hSocket != INVALID_SOCKET) //was: if(m_hSocket != INVALID_SOCKET) { return (closesocket(hSocket) != SOCKET_ERROR); } return true; } Pesah Spector

    Reply
  • Little Bug

    Posted by Legacy on 02/19/2004 12:00am

    Originally posted by: Jos� Herrera

    Function CString GetMX(LPCTSTR lpszServer,LPCTSTR lpszHost,CStringList & List)
    
    has a little bug, when you search additionals records.
    Try with this domain : wayna.rcp.net.pe and you will get an assertion.

    Log.Empty();
    while(!Answers.IsEmpty())
    {
    CDnsRRMX * pRR = (CDnsRRMX*)Answers.RemoveHead();
    //probably pRR is not CDnsRRMX and
    //pRR->Exchange could be present
    SearchARecords(pRR->Exchange,Additionals,List);

    Log += pRR->ToString();
    delete pRR;
    }


    Solution:
    CDnsRR *DnsRR = Answers.RemoveHead();
    CDnsRRMX *pRR = dynamic_cast<CDnsRRMX *>(DnsRR);

    if (pRR && pRR->Type == 15) //pRR->Type == 15 is enough
    {
    SearchARecords(pRR->Exchange,Additionals,List);
    Log += pRR->ToString();
    }
    else
    {
    Log += DnsRR->ToString();
    }

    Reply
  • Memory leaks fixed

    Posted by Legacy on 07/30/2003 12:00am

    Originally posted by: Petko Popov

    Three months later I finally got the opportunity to return to this code and finish rewriting it without reference to MFC; with the help of STL it took just a few hours to have this done.


    During this process I have discovered many memory leaks in the original code. They have two reasons:

    1. CNeuroBuffer::GetBufferSetLength(int) doesn't check if m_pBuffer reallocates the buffer even if it has been previously allocated when the method was called. Free it before Allocate() or don't call UnsafeClear(), either works.

    2. This one is much more generic. CDnsRR is a base class to several other classes, but it does not have a destructor. The compiler provides one but does not apply the modifier "virtual" to the generated destructor. As a result, the destructorcalls to all pointers to the child classes that are intentionally cast to the base class will not call the child class destructors. All data members of the child classes are not released. Fix: as simple as adding an empty virtual destructor to the CDnsRR class.


    <added 20030721>
    There's also a delete that has to be added at the end of this block:

    {
    // NO
    char * cname = new char [nLen8+1];
    memset(cname,0,nLen8+1);
    Get(cname,nLen8);
    Name += cname;
    Name += ".";
    delete[] cname; // missing in original DNS.H
    }


    Reply
  • Bug

    Posted by Legacy on 04/15/2003 12:00am

    Originally posted by: Manish Jaggi

    Hello ,
    I am creating a project and have implemented a DNS client.
    It was not working with domains like sify.com. I tested the same on your code and the resluts were same.

    Please try to find out MX for sify.com (satyam)

    I dont know how to communicate with a proxyserver have you tried? Do you know the protocol

    And btw buddy what do u do?

    Manish

    Reply
  • Wonderful!

    Posted by Legacy on 04/08/2003 12:00am

    Originally posted by: Petko Popov

    Impressive work and a very beautiful solution. Works on all my testing machines statring from Windows 95 OSR2. Thank you so much, I was looking all day today exactly for such a piece of code.

    In order to use this I will have to get rid of MFC, wrap everything in exception handlers, remove all string operations, make compatible with Unicode. I am going to put this in a DLL and optionally build it with all libraries statically or dynamically linked. This is minor work because all the functionality I need is there, I just will repackage it.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The exponential growth of data, along with virtualization, is bringing a disruptive level of complexity to your IT infrastructure. Having multiple point solutions for data protection is not the answer, as it adds to the chaos and impedes on your ability to deliver consistent SLAs. Read this white paper to learn how a more holistic view of the infrastructure can help you to unify the data protection schemas by properly evaluating your business needs in order to gain a thorough understanding of the applications …

  • The impact of a data loss event can be significant. Real-time data is essential to remaining competitive. Many companies can no longer afford to rely on a truck arriving each day to take backup tapes offsite. For most companies, a cloud backup and recovery solution will eliminate, or significantly reduce, IT resources related to the mundane task of backup and allow your resources to be redeployed to more strategic projects. The cloud - can now be comfortable for you – with 100% recovery from anywhere all …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds