Click here to Skip to main content
15,896,436 members
Articles / Desktop Programming / MFC

DNS Resolver RFC 1035

Rate me:
Please Sign up or sign in to vote.
3.50/5 (11 votes)
14 Aug 20044 min read 96.1K   2.3K   20  
DNS resolving by RFC 1035; complete library for all versions of Windows.
#if(!defined(__NEURO__DNS__CLIENT__))
#define __NEURO__DNS__CLIENT__

#include "SocketClient.h"
#include "NeuroBuffer.h"
#include <afxtempl.h>

/***********************************************************************
LICENSE AGREEMENT AND POLICY

The following code is provided on AS IS basis, no claim should be made
if the code does any damage, the user using and modifying this code will 
be responsible for any kind of damange this code produces.

You can freely distribute, use this code as long as you insert this 
Agreement with each distribution.

The code should not be sold at any cases.

-Akash Kava
ackava@hotmail.com
************************************************************************/


/************************************************************************
		 
		 Name   : CDnsBuffer
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: Dns Results come in a binary format, length followed
		          by the data buffer. Complete data buffer is needed
		          to search Compressed Domain Names in buffer
		          
		          Dns protocol uses pointers in response to represent
		          repeated data, by expanding this pointers you will
		          get full names
************************************************************************/
class CDnsBuffer : public CNeuroBuffer {
public:


	// Buffer Pointer Management
	void Reset()
	{
		m_nPointer = 0;
	}

	int GetPointer()
	{
		return m_nPointer;
	}

	int Reset(int n)
	{
		int nOld = m_nPointer;
		m_nPointer = n;
		return nOld;
	}






	void operator = (CDnsBuffer & Buffer)
	{
		UnsafeClear();
		Allocate(Buffer.GetSize());
		Copy(Buffer.GetBuffer(),Buffer.GetSize());
	}


	// Appending Buffer Functions
	void operator << (unsigned __int8 c)
	{
		Append((BYTE *)&c,1);
	}

	void operator << (unsigned __int16 c)
	{
		c = htons(c);
		Append((BYTE *)&c,2);
	}

	void operator << (unsigned __int32 c)
	{
		c = htonl(c);
		Append((BYTE*)&c,4);
	}



	// Extracting Buffer Data, pointer moves ahead
	// Throws DNS Exception if pointer out of range
	void operator >> (unsigned __int8 & c)
	{
		Get(&c,1);
	}

	void operator >> (unsigned __int16 & c)
	{
		Get(&c,2);
		c = ntohs(c);
	}

	void operator >> (unsigned __int32 & c)
	{
		Get(&c,4);
		c = ntohl(c);
	}



	
	void operator ++()
	{
		m_nPointer ++;
	}

	void operator += (int n)
	{
		m_nPointer += n;
	}


	
	
	void Get(LPVOID Buffer,int size)
	{
		if(m_nPointer+size > m_nSize)
		{
			CString Text;
			Text.Format("Insufficient Data Pointer:%d  Size:%d  Total:%d",m_nPointer,size,m_nSize);
			throw new CSocketException (Text,NULL);
		}
		memcpy(Buffer,m_pBuffer+m_nPointer,size);
		m_nPointer += size;
	}

	
	void operator += (CDnsBuffer & Buffer)
	{
		Append(Buffer.GetBuffer(),Buffer.GetSize());
	}


	
	
	
	// DNS Name Extraction from buffer , Message Pointer Expansion
	// Call this member function with nPointer=0 while reading buffer
	// to get domain name.

	// This function calls same function recursively to extract message
	// from pointers and also sets pointer to next resource data to be read

	// This function is carefully designed and implemented, its tested 
	// perfectly, use it without modifying single line
	virtual CString GetName(int nPointer)
	{
		CString Name;
		unsigned __int8		nLen8;
		unsigned __int16	nLen16;

		int nOldPointer = GetPointer();
		if(nPointer!=0)
			Reset(nPointer);
		

		do
		{
			(*this) >> nLen8;
			
			if(nLen8==0)
			{
				break;
			}
			

			// Is this octate message pointer????
			if(nLen8 & 0xC0)
			{

				// YES
				nLen8 = nLen8 & 0x3F;
				nLen16 = nLen8;
				nLen16 <<= 8;
				(*this) >> nLen8;
				nLen16 |= nLen8;

				Name += GetName(nLen16);

				if(nPointer != 0)
					Reset(nOldPointer);

				return Name;

			}
			else
			{
				// NO
				char * cname = new char [nLen8+1];
				memset(cname,0,nLen8+1);
				Get(cname,nLen8);
				Name += cname;
				Name += ".";
			}
		
		}while(true);

		if(nPointer!=0)
			Reset(nOldPointer);

		if(!Name.IsEmpty())
		{
			if(Name.Right(1)==".")
				Name = Name.Left(Name.GetLength()-1);
		}

		return Name;
	}

};











/************************************************************************
		 
		 Name   : DnsHeaderFlags
		 Type   : Union
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: DNS Header Flags, its 16 bit value
		          Every bit field is explained below
************************************************************************/
union DnsHeaderFlags{
	unsigned __int16 Flag;
	struct{
		int QR		: 1 ;
		int OPCODE	: 4 ;
		int AA		: 1 ;
		int TC		: 1 ;
		int RD		: 1 ;
		int RA		: 1 ;
		int Z		: 3 ;
		int RCODE	: 4 ;
	}Flags;
};





/************************************************************************
		 
		 Name   : CDnsHeader
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: DNS Header Class which holds initial
		          header information

				  The pack and unpack method interacts with CDnsBuffer
				  and exchanges data according to protocol in every class
				  defined below

				  pack and unpack methods moves buffer pointer as well,
				  make sure you never write function which passes copy of
				  buffer rather then reference of buffer, always pass
				  reference of buffer to maintain integrity
************************************************************************/

class CDnsHeader{
public:
	unsigned __int16	ID;
	DnsHeaderFlags		Flags;
	unsigned __int16	QDCount;
	unsigned __int16	ANCount;
	unsigned __int16	NSCount;
	unsigned __int16	ARCount;

	void operator = ( CDnsHeader & Header )
	{
		ID = Header.ID;
		Flags.Flag = Header.Flags.Flag;
		QDCount = Header.QDCount;
		ANCount = Header.ANCount;
		NSCount = Header.NSCount;
		ARCount = Header.ARCount;
	}

	CDnsHeader()
	{
		ID = GetTickCount();
		Flags.Flag = 0;
		QDCount = 1;
		ANCount = 0;
		NSCount = 0;
		ARCount = 0;
	}

	CDnsBuffer Pack()
	{
		CDnsBuffer Buffer;
		Buffer << ID;
		Buffer << Flags.Flag;
		Buffer << QDCount;
		Buffer << ANCount;
		Buffer << NSCount;
		Buffer << ARCount;
		return Buffer;
	}

	void Unpack( CDnsBuffer & Buffer )
	{
		Buffer >> ID;
		Buffer >> Flags.Flag;
		Buffer >> QDCount;
		Buffer >> ANCount;
		Buffer >> NSCount;
		Buffer >> ARCount;
	}

	CString ToString()
	{
		CString Text;
		Text.Format("ID=%d\nQDCount=%d\nANCount=%d\nNSCount=%d\nARCount=%d\n",ID,QDCount,ANCount,NSCount,ARCount);
		return Text;
	}
};








/************************************************************************
		 
		 Name   : CDnsRR
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: DNS Response's Resource Record
		          This class holds Name,Type,Class,TTL and 
		          Length of RData, RData is Type dependent
		          which then appears in every derived class
		          from CDnsRR
		          
		          The pack and unpack method interacts with CDnsBuffer 
		          and exchanges data according to protocol in every class
		          defined below.

				  Please note, pack and unpack methods of all derived 
				  classes of CDnsRR does not call pack and unpack method
				  of CDnsRR anytime, its your responsibility to first
				  make object of CDnsRR and then process it with buffer,
				  make type dependent class of Resource Record and then
				  process it again for only RData.

				  Such complex method is designed only to get the 
				  compressed domain names in RData section of Resource
				  Record
************************************************************************/
class CDnsRR{
public:
	CString				Name;
	unsigned __int16	Type;
	unsigned __int16	Class;
	unsigned __int32	TTL;
	unsigned __int16	Length;

	CDnsRR()
	{
	}

	CDnsRR(CDnsRR * pRR)
	{
		Name = pRR->Name;
		Type = pRR->Type;
		Class = pRR->Class;
		TTL = pRR->TTL;
		Length = pRR->Length;
	}

	CString GetString(int Number)
	{
		CString strNumber;
		strNumber.Format("%d",Number);
		return strNumber;
	}

	virtual void Unpack(CDnsBuffer & Buffer)
	{
		Name = Buffer.GetName(0);
		Buffer >> Type;
		Buffer >> Class;
		Buffer >> TTL;
		Buffer >> Length;
	}

	virtual CString ToString()
	{
		CString Text;

		Text = "Name=" + Name + "\n";
		Text += "TTL=" + GetString(TTL) + "\n";
		Text += "TYPE=" + GetString(Type) + "\n";
		return Text;
	}

	virtual void CopyRData(CDnsRR* pRR){
	};
};










/************************************************************************
		 
		 Name   : CDnsRRDefault
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: All Resource Record types are not programmed here
		          thats why This class serves as substitute for non-implemented
		          class types.
************************************************************************/

class CDnsRRDefault: public CDnsRR{
public:
	BYTE *			pRData;

	CDnsRRDefault()
	{
		pRData = NULL;
	}

	CDnsRRDefault(CDnsRR * pRR)
		: CDnsRR(pRR)
	{
		pRData = NULL;
	}

	~CDnsRRDefault()
	{
		if(pRData)
			delete pRData;
	}

	virtual void Unpack(CDnsBuffer & Buffer)
	{
		pRData = new BYTE [Length];
		Buffer.Get(pRData,Length);
	}

	virtual void CopyRData(CDnsRR* pRR){
		CDnsRRDefault * pRRD = (CDnsRRDefault *)pRR;
		pRData = new BYTE[Length];
		memcpy(pRData,pRRD->pRData,Length);
	};
};









/************************************************************************
		 
		 Name   : CDnsRRMX
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: Most widely used DNS class type, for mail exchange
************************************************************************/
class CDnsRRMX : public CDnsRR {
public:
	unsigned __int16	Preference;
	CString				Exchange;

	CDnsRRMX(CDnsRR * pRR)
		: CDnsRR(pRR)
	{
		
	}

	void Unpack(CDnsBuffer & Buffer)
	{
		int nPointer = Buffer.GetPointer();
		Buffer >> Preference;
		Exchange = Buffer.GetName(0);
		Buffer.Reset(nPointer + Length);
	}

	virtual CString ToString()
	{
		CString Text;
		Text += "MX Record\n";
		Text += CDnsRR::ToString();
		Text += "Preference=" + GetString(Preference) + "\n";
		Text += "Exchange=" + Exchange + "\n\n";
		return Text;
	}

	virtual void CopyRData(CDnsRR* pRR){
		CDnsRRMX * pRRMX = (CDnsRRMX*) pRR;
		Preference = pRRMX->Preference;
		Exchange = pRRMX->Exchange;
	}
};












/************************************************************************
		 
		 Name   : CDnsRRCNAME
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: Encapsulates Resource Record for Type CNAME
************************************************************************/
class CDnsRRCNAME : public CDnsRR {
public:
	CString Name;
	CDnsRRCNAME(CDnsRR * pRR)
		: CDnsRR(pRR)
	{
	}

	void Unpack(CDnsBuffer & Buffer)
	{
		Name = Buffer.GetName(0);
	}

	virtual CString ToString()
	{
		CString Text;
		Text = "CNAME Record:\n";
		Text += CDnsRR::ToString();
		Text += "CName=" + Name+ "\n\n";
		return Text;
	}

	virtual void CopyRData(CDnsRR* pRR){
		CDnsRRCNAME * pRRCNAME = (CDnsRRCNAME*) pRR;
		Name = pRRCNAME->Name;
	}
};









/************************************************************************
		 
		 Name   : CDnsRRA
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: Encapsulates Resource Record for Type A
		          CString A  of this class holds text
		          representation of IP address like 127.0.0.1
************************************************************************/
class CDnsRRA : public CDnsRR {
public:
	CString A;
	CDnsRRA(CDnsRR * pRR)
		: CDnsRR(pRR)
	{

	}

	void Unpack(CDnsBuffer & Buffer)
	{
		unsigned __int8 byte1;
		unsigned __int8 byte2;
		unsigned __int8 byte3;
		unsigned __int8 byte4;

		Buffer>>byte1;
		Buffer>>byte2;
		Buffer>>byte3;
		Buffer>>byte4;

		A.Format("%d.%d.%d.%d",byte1,byte2,byte3,byte4);

	}

	virtual CString ToString()
	{
		CString Text;
		Text = "A Record:\n";
		Text += CDnsRR::ToString();
		Text += "A=" + A + "\n\n";
		return Text;
	}

	BOOL operator == (LPCTSTR lpszName) const
	{
		return (Name.CompareNoCase(lpszName)==0);
	}

	virtual void CopyRData(CDnsRR* pRR){
		CDnsRRA * pRRA = (CDnsRRA*) pRR;
		A = pRRA->A;
	}
};














/************************************************************************
		 
		 Name   : CDnsRRNS
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: Encapsulates Resource Record for Type NS
		          CString NS  of this class holds domain
		          name of Authorized Name Server 
************************************************************************/
class CDnsRRNS : public CDnsRR {
public:
	CString NS;
	CDnsRRNS( CDnsRR * pRR )
		: CDnsRR(pRR)
	{
	}

	void Unpack(CDnsBuffer & Buffer)
	{
		NS = Buffer.GetName(0);
	}

	virtual CString ToString()
	{
		CString Text;
		Text += "NS Record:\n";
		Text += CDnsRR::ToString();
		Text += "NS=" + NS + "\n";
		return Text;
	}

	virtual void CopyRData(CDnsRR* pRR){
		CDnsRRNS * pRRNS = (CDnsRRNS*) pRR;
		NS = pRRNS->NS;
	}
};



















/************************************************************************
		 
		 Name   : CDnsQueryType
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: Returns int type number from string representation of type
		          Also returns new Resource Record Class Pointer
		          
		          This static function makes new object of specified type
		          and also copies contents of CDnsRR to type dependent
		          resource record object
************************************************************************/
class CDnsQueryType{
public:
	static int GetType( CString Name )
	{
		Name.MakeUpper();
		
		if(Name == "A")
			return 1;
		
		if(Name == "NS")
			return 2;

		if(Name == "MD")
			return 3;

		if(Name == "MF")
			return 4;

		if(Name == "CNAME")
			return 5;

		if(Name == "SOA")
			return 6;

		if(Name == "MB")
			return 7;

		if(Name == "MG")
			return 8;

		if(Name == "MR")
			return 9;

		if(Name == "NULL")
			return 10;

		if(Name == "WKS")
			return 11;

		if(Name == "PTR")
			return 12;

		if(Name == "HINFO")
			return 13;

		if(Name == "MINFO")
			return 14;

		if(Name == "MX")
			return 15;

		if(Name == "TXT")
			return 16;

		return -1;
	}

	static CDnsRR * GetNewRecord(CDnsRR * pRR)
	{
		switch(pRR->Type)
		{
		case 1:
			return new CDnsRRA(pRR);
		case 2:
			return new CDnsRRNS(pRR);
		case 5:
			return new CDnsRRCNAME(pRR);
		case 15:
			return new CDnsRRMX(pRR);

			// Rest you implement if you need it !! he he

		default:
			return new CDnsRRDefault(pRR);
		}
	}
};










/************************************************************************
		 
		 Name   : CDnsQuery
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: Dns Query Class
************************************************************************/
class CDnsQuery{
public:
	CStringList			Names;
	unsigned __int16	Type;
	unsigned __int16	Class;

	CDnsQuery( LPCTSTR lpszHost , LPCTSTR lpszType )
	{
		CString host(lpszHost);
		int i;
		do
		{
			i = host.Find('.');
			if(i != -1)
			{
				Names.AddTail(host.Mid(0,i));
				host = host.Mid(i+1);
			}
			else
			{
				Names.AddTail(host);
				break;
			}
		}while(true);

		Type = CDnsQueryType::GetType(lpszType);
		Class = 1;
	}

	CDnsBuffer Pack()
	{

		CDnsBuffer Buffer;

		POSITION Pos = Names.GetHeadPosition();
		while(Pos)
		{
			CString Name = Names.GetNext(Pos);
			unsigned __int8 Len = Name.GetLength();
			Buffer << Len;
			Buffer.Append((unsigned char *)(LPCTSTR)Name,Len);

		}

		unsigned __int8 n = 0;
		Buffer << n;

		Buffer << Type;
		Buffer << Class;
		return Buffer;
	}

	void Unpack( CDnsBuffer & Buffer )
	{
		CString Name = Buffer.GetName(0);
		Buffer >> Type;
		Buffer >> Class;

	}
};











/************************************************************************
		 
		 Name   : CDnsRRPtrList
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: All Resource Records are hold in a CList class which holds 
		          pointers of all objects. And also implements CHostSearch 
		          and returns IP address found in A records if any

				  Users who use the record pointer are requested to keep
				  copy of Resource Record according to type because when
				  This clas gets destroys it deletes its pointers !!
************************************************************************/
class CDnsRRPtrList :public  CList<CDnsRR*,CDnsRR*>{
public:

	~CDnsRRPtrList ()
	{
		while(!IsEmpty())
		{
			CDnsRR * pRR = RemoveHead();
			delete pRR;
		}
	}

};







/************************************************************************
		 
		 Name   : CDnsClient
		 Type   : Class
------------------------------------------------------------------------
		 Author : Akash Kava
		 Purpose: The final DnsClient class
		          
		          It can be used in 2 ways.
		          
		          1) Directly Query MX records and CStringList by calling 
		          static member function. No hastle of pointer management.
		          
		          2) Call another static function Get to get result of type 
				  requested The CDnsRRPtrList supplied gets all required 
				  resource records. It searches recursivly of found names 
				  servers so you dont need to worry about nameservers 
				  returned in query. What you will get is the final result 
				  after 10 tries. Or else domain does not exist.
		              The list returned has pointers to CDnsRR derived class
		          depending upon type. While using it, please copy the 
				  relevant content and then processing because everything 
				  will get destroyed as soon as CDnsRRPtrList goes out of 
				  scope.
		          
		          2) Create Object of class and query, you will need to do all 
		          recursive nameserver processing etc so just forget it.
************************************************************************/
class CDnsClient{
public:

	CString				Log;
	CSocketClient		Client;
	CDnsBuffer			Buffer;

	int					QueryType;
	CDnsHeader			Header;
	CDnsRRPtrList		Questions;
	CDnsRRPtrList		Answers;
	CDnsRRPtrList		Authorities;
	CDnsRRPtrList		Additionals;

	
	BOOL Query(LPCTSTR lpszServer, LPCTSTR lpszHost, LPCTSTR lpszType)
	{

		try
		{

			unsigned __int16 size;

			// Build The query
			CDnsQuery Query(lpszHost,lpszType);


			// Make the Buffer
			Buffer += Header.Pack();
			Buffer += Query.Pack();


			// Try to connect to server, if failed, will give an exception
			Client.ConnectTo(lpszServer,53);

			
			// Write Buffer to end client
			size = Buffer.GetSize();
			Client.WriteInt16(size);
			Client.WriteBytes(Buffer.GetBuffer(),Buffer.GetSize());


			// Dns Response send buffer length first, read it
			// then read buffer
			size = Client.ReadInt16();
			Client.ReadBytes(Buffer.GetBufferSetLength(size),size);


			// Cool now Socket is not needed, close it
			Client.Close();

			// Put Buffer's pointer to 0 and start reading things now.
			Buffer.Reset(0);


			// First Extract Header from buffer
			Header.Unpack(Buffer);

			// Dns Query is sent again by server, uselessly..
			// Extract it, what else we an do...
			Query.Unpack(Buffer);
			QueryType = Query.Type;

			

			// Read rest of Records
			GetRecords(Answers,Header.ANCount);
			GetRecords(Authorities,Header.NSCount);
			GetRecords(Additionals,Header.ARCount);

			return true;
		}
		catch(CSocketException * pE)
		{
			Log += pE->m_strError + "\n";
			return false;
		}
	}


	void GetRecords( CDnsRRPtrList & List , int Total )
	{
		if(Total==0)
			return;
		for(int i=0;i<Total;i++)
		{
			CDnsRR RR;
			RR.Unpack(Buffer);

			CDnsRR * pRR = CDnsQueryType::GetNewRecord(&RR);

			pRR->Unpack(Buffer);

			List.AddTail(pRR);
			TRACE0(pRR->ToString());
		}
	}





	/************************************************************************
			 FUNCTION
			 Name   : Get
			 Author : Akash Kava
			 Purpose: Call this function to retrive answers of query, this function
					  does recursive processing upto specified number of trials
					  
					  While calling this function, please pass the Reference parameters
					  as explained
	========================================================================
			 Params : Server	: Name of the name server to connect
					  Name		: Domain name to query
					  Type		: Type of query, case insensitive, MX or mx
					  Answers	: Resource Record Object List , please pass empty 
									List here, it will return all answers
					  Additional: Resource Record Object List, please pass empty
									List here , it will pass additional A record entries
					  NSTried	: Please pass empty CStringList here
					  Log		: Please pass empty CString here
					  nTries	: Make sure you pass atleast 5 trials
	------------------------------------------------------------------------
			 Returns: True if successful , false if failed
	************************************************************************/
	static BOOL Get(
					LPCTSTR lpszServer,		
					LPCTSTR lpszName,		
					LPCTSTR lpszType,		
			CDnsRRPtrList&	Answers,	
			CDnsRRPtrList&	Additionals,
			CStringList&	NSTried,	
				CString&	Log,		
					int&	nTries		
					)
	{

		
		if(lpszServer==NULL)
		{
			// If you dont specify servers then try root servers.. too costly!!!


			if(Get("A.GTLD-SERVERS.net",lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
				return true;
			if(nTries==0)
				return false;

		
			nTries = 10;
			if(Get("B.GTLD-SERVERS.net",lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
				return true;
			if(nTries==0)
				return false;

		
	
			nTries = 10;
			if(Get("C.GTLD-SERVERS.net",lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
				return true;
			if(nTries==0)
				return false;

		
	
			nTries = 10;
			if(Get("D.GTLD-SERVERS.net",lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
				return true;
			if(nTries==0)
				return false;

		
	
			nTries = 10;
			if(Get("E.GTLD-SERVERS.net",lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
				return true;
			if(nTries==0)
				return false;

		
	
			nTries = 10;
			if(Get("F.GTLD-SERVERS.net",lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
				return true;
			if(nTries==0)
				return false;

		
	
			nTries = 10;
			if(Get("G.GTLD-SERVERS.net",lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
				return true;
			if(nTries==0)
				return false;

		
	
			nTries = 10;
			if(Get("H.GTLD-SERVERS.net",lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
				return true;
			if(nTries==0)
				return false;

		
	
			nTries = 10;
			if(Get("I.GTLD-SERVERS.net",lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
				return true;
			if(nTries==0)
				return false;

		
	
			return false;
		}

		
		// Tries over, fine, return true to indicate end of process
		if(nTries<=0)
		{
			Log += lpszName;
			Log += " Domain Does not exist Probably\n";
			return true;
		}


		nTries--;

		
		// Resolve DNS
		CDnsClient Client;
		if(!Client.Query(lpszServer,lpszName,lpszType))
			return false;


		// Found Answers, cool, Make a copy and return
		if(Client.Answers.GetCount()!=0)
		{
			POSITION Pos = Client.Answers.GetHeadPosition();
			while(Pos)
			{
				CDnsRR * pRR = (CDnsRR*) Client.Answers.GetNext(Pos);

				// Allocate new Record from CDnsQueryType and also copy initial content
				//		that is without RData
				CDnsRR * pNewRR = CDnsQueryType::GetNewRecord(pRR);

				// Copy RData to new object
				pNewRR->CopyRData(pRR);

				// Add it to Answer List
				Answers.AddTail(pNewRR);
			}


			// Add additional entries from here of all A records only
			Pos = Client.Additionals.GetHeadPosition();
			while(Pos)
			{
				CDnsRR * pRR = Client.Additionals.GetNext(Pos);
				if(pRR->Type == 1)
				{

					// Allocate new record from CDnsQueryType and also copy
					//      initiail conent without RData
					CDnsRR * pNewRR = CDnsQueryType::GetNewRecord(pRR);

					// Copy RData to new object
					pNewRR->CopyRData(pRR);

					Additionals.AddTail(pNewRR);
				}
			}
			return true;
		}


		// If the Name Server we queried is already authorized
		// return true, may be domain expired !!
		if(Client.Header.Flags.Flags.AA == 1)
			return true;


		// Recursive Query , The DNS client returns NS records
		// which contains name server information, get it and
		// query them to find answer
		POSITION Pos = Client.Authorities.GetHeadPosition();
		while(Pos)
		{
			CDnsRRNS * pRRNS = (CDnsRRNS *)Client.Authorities.GetNext(Pos);
			
			// Choose only Name Servers , or else goto next
			if(pRRNS->Type != 2)
				continue;

			// Get IP , put less load on System DNS Resolver, forget it now..
			//CString NS = Client.Additionals.GetHostIP(pRRNS->NS);
			CString NS = pRRNS->NS;


			// Make sure you visit Name server only once
			// if you have already tried then leave, goto next
			if(NSTried.Find(NS)!=NULL)
				continue;

			// Add this name server into Tried List
			NSTried.AddTail(NS);


			// If recursive query returns true then return true,
			// either it was successful
			// or it gave empty result and domain expired
			if(Get(NS,lpszName,lpszType,Answers,Additionals,NSTried,Log,nTries))
			{
				return true;
			}

			// In case there are any resource records in answer
			// go and return true
			if(!Answers.IsEmpty())
				return true;

		}

		// Even if you didnt find anything in Name servers
		// might be cilent couldnt connect to name server
		// try next, just return false
		return false;
	}



	

	// whooooooo baby, the most important , MX search
	// Just searches the MX of domain, returns IP address only,
	// however you can use Get function to get detailed MX records
	// CStringList receives all host addresses for MX
	static CString GetMX(LPCTSTR lpszServer,LPCTSTR lpszHost,CStringList & List)
	{

		List.RemoveAll();

		CString Log;
		CStringList NSTried;
		int nTries=10;

		CDnsRRPtrList Answers;
		CDnsRRPtrList Additionals;

		if(Get(lpszServer,lpszHost,"MX",Answers,Additionals,NSTried,Log,nTries))
		{
			Log.Empty();
			while(!Answers.IsEmpty())
			{
				CDnsRRMX * pRR = (CDnsRRMX*)Answers.RemoveHead();
				
				SearchARecords(pRR->Exchange,Additionals,List);

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


	static void SearchARecords( CString & Domain , CDnsRRPtrList & Additionals, CStringList & IPList)
	{

		BOOL bFound = false;

		POSITION Pos = Additionals.GetHeadPosition();
		while(Pos)
		{
			CDnsRR * pRR = (CDnsRR*) Additionals.GetNext(Pos);
			if(pRR->Type!=1)
				continue;

			CDnsRRA * pRRA = (CDnsRRA*) pRR;
			if(pRRA->Name.CompareNoCase(Domain)==0)
			{
				IPList.AddTail(pRRA->A);
				bFound = true;
			}
		}

		if(!bFound)
			IPList.AddTail(Domain);
	}

};

#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Programmer with WILL

Comments and Discussions