Mega Search
23.2 Million


Sign Up

Make a donation  
Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock

I've got a friend who is a security specialist and he uses all kinds of
tools OTHER than Delphi to write his utilities. I ask him why he's not
using Delphi, when it should be able to do everything he's doing with
all these various tools.

So, he asks me to build a sample utility for him that looks up an IP
address, gets the domain name for it, and calls Whois to find out the
country information for the domain.

I figure this is a snap. 2 hours tops with Delphi and Indy. Then I find
out I am woefully ignorant in this area of Indy functionality and can't
find helpful reference information online.

When I get stuck on the first step, a reverse DNS to retrieve the
domain name from the IP address, I spend the entire weekend trying to
find current information and demos for Indy, including the mythically
referenced "DNSResolver demo".

The closest I get is some 8+ year old conversations about DNSResolver,
and a mention on Stack Overflow that simply doesn't resolve any IP
(reversed or not) into the actual domain name for me.

http://stackoverflow.com/questions/8277903/use-indy-to-perform-an-ipv6-reverse-dns-lookup

Perhaps I have some gaps in understanding that code snippet:
1. What is RSCodeQueryName supposed to be?
2. What does ParseReverseDNSResponse do?

So, I figured this is the best place to ask:
1. Is there a current Indy DNSResolver demo?
2. What's wrong with this code, if anything? I changed the code
referenced above in an attempt to simplify/update and work around the
missing info above:
function ReverseDNSLookup(IPAddress: String; DNSServer: String =
SDefaultDNS; Timeout: Integer = 30; Retries: Integer = 3) : string;
var
  AIdDNSResolver: TIdDNSResolver;
  RetryCount: Integer;
begin
  Result := '';
  IPAddress := ReverseIP(IPAddress);

  AIdDNSResolver := TIdDNSResolver.Create(nil);
  try
    AIdDNSResolver.QueryResult.Clear;
    AIdDNSResolver.WaitingTime := Timeout;
    AIdDNSResolver.QueryType := [qtPTR];
    AIdDNSResolver.Host := DNSServer;

    RetryCount := Retries;
    repeat
      try
        dec(RetryCount);

        AIdDNSResolver.Resolve(IPAddress);

        Break;
      except
        on e: Exception do
        begin
          if RetryCount <= 0 then
          begin
//            if SameText(e.Message, RSCodeQueryName) then
//              Result := FALSE
//            else
              raise Exception.Create(e.Message);
            Break;
          end;
        end;
      end;
    until false;

    if AIdDNSResolver.QueryResult.Count > 0 then
      Result := AIdDNSResolver.QueryResult.DomainName;
  finally
    FreeAndNil(AIdDNSResolver);
  end;
end;

Am I misunderstanding the purpose of QueryResult.DomainName? Shouldn't
that be the name of the domain that gets resolved? I'm seeing responses
like this for Google.com (using IP address 74.125.224.72):

'72.224.125.74.in-addr.arpa'
 

3. Comcast is my internet provider. Is something in my network setup
prohibiting me from successfully calling ReverseDNS?


Any pointers are greatly appreciated. I am afraid Delphi's reputation
is suffering already because of my ignorance in this area and I greatly
appreciate any pointers to good reference information!

-- 
John Kaster http://johnkaster.wordpress.com
http://transactis.com Seamless paper-free transactions

Vote for best question.
Score: 0  # Vote:  0
Date Posted: 6-Aug-2012, at 6:27 PM EST
From: John Kaster
 
Re: Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock
John wrote:

> 1. What is RSCodeQueryName supposed to be?

It is a resource string defined in the IdResourceStringsProtocols unit:

{code:delphi}
resourcestring
  ...
  RSCodeQueryName   = 'DNS Server Reports Query Name Error';
  ...
{code}

EIdDnsResolverError

> 2. What does ParseReverseDNSResponse do?

It is a user-defined function that "norgepaul" omitted from his SO question. 
 The TResultRecord.RData property contains the raw bytes of the a Resolve() 
result.  However, TIdDNSResolver already parses that data for you.  For a 
qtPTR request, the QueryResult will contain a TPTRRecord object (which is 
derived from TResultRecord), which has a HostName parameter, eg:

{code:delphi}
HostName := (AIdDNSResolver.QueryResult[0] as TPTRRecord).HostName; 
{code}

> 1. Is there a current Indy DNSResolver demo?

No.

> 2. What's wrong with this code, if anything? I changed the code
> referenced above in an attempt to simplify/update and work around the
> missing info above:

Try this:

function ReverseDNSLookup(IPAddress: String; DNSServer: String = SDefaultDNS; 
Timeout: Integer = 30; Retries: Integer = 3) : string;
var
  AIdDNSResolver: TIdDNSResolver;
begin
  Result := '';
  IPAddress := ReverseIP(IPAddress); // what is this doing?
  AIdDNSResolver := TIdDNSResolver.Create(nil);
  try
    AIdDNSResolver.WaitingTime := Timeout;
    AIdDNSResolver.QueryType := [qtPTR];
    AIdDNSResolver.Host := DNSServer;
    repeat
      try
        Dec(Retries);
        AIdDNSResolver.Resolve(IPAddress);
        Result := (AIdDNSResolver.QueryResult[0] as TPTRResult).HostName;
        Exit;
      except
        on e: EIdDnsResolverError do
        begin
          if (Retries <= 0) and TextIsSame(e.Message, RSCodeQueryName) then
            Exit;
          raise;
        end;
      end;
    until Retries <= 0;
  finally
    FreeAndNil(AIdDNSResolver);
  end;
end;
{code}

> Am I misunderstanding the purpose of QueryResult.DomainName?
> Shouldn't that be the name of the domain that gets resolved?
> I'm seeing responses like this for Google.com (using IP address 74.125.224.72):
>
> '72.224.125.74.in-addr.arpa'

What you are missing is the fact that your DNS is returning an intermediate 
gateway address that then needs to be resolved further.  Have a look at RFC 
1035 (http://tools.ietf.org/html/rfc1035) Section 3.5.  It talks about the 
'in-addr.arpa' domain and how it relates to PTR queries.

> 3. Comcast is my internet provider. Is something in my network setup
> prohibiting me from successfully calling ReverseDNS?

No.

--
Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 7-Aug-2012, at 11:59 AM EST
From: Remy Lebeau (TeamB)
 
Re: Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock
Remy Lebeau (TeamB) wrote:

> It is a resource string defined in the IdResourceStringsProtocols
> unit:
> 
> {code:delphi}
> resourcestring
>   ...
>   RSCodeQueryName   = 'DNS Server Reports Query Name Error';
>   ...
> {code}

.... thanks ...
> {code:delphi}
> HostName := (AIdDNSResolver.QueryResult[0] as TPTRRecord).HostName; 
> {code}

.... thanks ...

> > 1. Is there a current Indy DNSResolver demo?
> 
> No.

Bummer :)

> > 2. What's wrong with this code, if anything? I changed the code
> > referenced above in an attempt to simplify/update and work around
> > the missing info above:
> 
> Try this:

Thanks again. And ReverseIP() was basically doing the
'72.224.125.74.in-addr.arpa' code in a Delphi routine. Shouldn't have
been in the posted snippet, sorry for the distraction.

New version (changed TPTRResult in your code to TPTRRecord. I think
that was correct):
{code:delphi}
function ReverseDNSLookup(IPAddress: String; DNSServer: String =
SDefaultDNS;
Timeout: Integer = 30; Retries: Integer = 3) : string;
var
  AIdDNSResolver: TIdDNSResolver;
begin
  Result := '';
  AIdDNSResolver := TIdDNSResolver.Create(nil);
  try
    AIdDNSResolver.WaitingTime := Timeout;
    AIdDNSResolver.QueryType := [qtPTR];
    AIdDNSResolver.Host := DNSServer;
    repeat
      try
        Dec(Retries);
        AIdDNSResolver.Resolve(IPAddress);
        Result := (AIdDNSResolver.QueryResult[0] as
TPTRRecord).HostName;
        Exit;
      except
        on e: EIdDnsResolverError do
        begin
          if (Retries <= 0) and SameText(e.Message, RSCodeQueryName)
then
            Exit;
          raise;
        end;
      end;
    until Retries <= 0;
  finally
    FreeAndNil(AIdDNSResolver);
  end;
end;
{code}

> What you are missing is the fact that your DNS is returning an
> intermediate gateway address that then needs to be resolved further.
> Have a look at RFC 1035 (http://tools.ietf.org/html/rfc1035) Section
> 3.5.  It talks about the 'in-addr.arpa' domain and how it relates to
> PTR queries.

I was wondering if I was going to have to keep going down the chain.
Thanks for verifying. I'll read up on the RFC.

-- 
John Kaster http://johnkaster.wordpress.com
http://transactis.com Seamless paper-free transactions

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 7-Aug-2012, at 6:25 PM EST
From: John Kaster
 
Re: Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock
Panagiotis Drivilas wrote:

> I don't know about that specific component but you can lookup IPv4 to
> hostname with the following:

Thanks very much for the sample code. I will preserve it in case I need
to take this route. I'm planning for something I can eventually build
for both Linux and Windows, so I'm hoping Indy usage will get me closer
to that goal ;)

-- 
John Kaster http://johnkaster.wordpress.com
http://transactis.com Seamless paper-free transactions

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 7-Aug-2012, at 6:26 PM EST
From: John Kaster
 
Re: Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock
John Kaster wrote:

> I was wondering if I was going to have to keep going down the chain.
> Thanks for verifying. I'll read up on the RFC.

Thanks to both of you for this thread; I'm bookmarking it for when I
revisit DNS resolution.

-- 
Dave Nottage [TeamB]

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 7-Aug-2012, at 6:29 PM EST
From: Dave Nottage
 
Re: Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock
Dave Nottage wrote:

> Thanks to both of you for this thread; I'm bookmarking it for when I
> revisit DNS resolution.

I may need to read section 3.5 multiple times ;)

-- 
John Kaster http://johnkaster.wordpress.com
http://transactis.com Seamless paper-free transactions

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 7-Aug-2012, at 6:40 PM EST
From: John Kaster
 
Re: Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock
John wrote:

> Thanks very much for the sample code. I will preserve it in case I
> need to take this route. I'm planning for something I can eventually
> build for both Linux and Windows, so I'm hoping Indy usage will get me
> closer to that goal ;)

The Indy equivilent to Panagiotis's code would be the TIdStack.HostByAddress() 
method, eg:

{code:delphi}
uses
  ..., IdGlobal, IdStack;

function ReverseDNSLookup(const IPAddress: string; const IPVersion: TIdIPVersion): 
string;
begin
  Result := '';
  TIdStack.IncUsage;
  try
    Result := GStack.HostByAddress(Address, IPVersion);
  finally
    TIdStack.DecUsage;
  end;
end;
{code}

{code}
Hostname := ReverseDNSLookup('74.125.224.72', Id_IPv4);
{code}

Or, you can utilize the TIdIPAddress class to hellp determine the IP version:

{code:delphi}
uses
  ..., IdIPAddress, IdStack;

function ReverseDNSLookup(const IPAddress: string): string;
var
  Addr: TIdIPAddress;
begin
  Result := '';
  TIdStack.IncUsage;
  try
    Addr := TIdIPAddress.MakeAddressObject(IPAddress);
    if Addr <> nil then
    try
      Result := GStack.HostByAddress(Address, Addr.AddrType);
    finally
      Addr.Free;
    end;
  finally
    TIdStack.DecUsage;
  end;
end;
{code}

{code}
Hostname := ReverseDNSLookup('74.125.224.72');
{code}

--
Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 7-Aug-2012, at 7:23 PM EST
From: Remy Lebeau (TeamB)
 
Re: Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock
Remy Lebeau (TeamB) wrote:

> Hostname := ReverseDNSLookup('74.125.224.72');

Thanks very much. That does indeed work. Is this more efficient than
the code I was using? Seems to be cleaner.

Perhaps I asked the wrong question or provided a detour with sample
code I was using in my original post. I want to get from 74.125.224.72
to "google.com". What's the best path to get there with Indy?

I tried using 'nuq04s07-in-f8.1e100.net' as the DNS server name for the
second DNS resolution request, but that just returns no result. So I
guess I'm still not understanding how to walk through the servers
listed in section 3.5. I've read it a few times and it's not clicking
yet, which is quite annoying. :)

-- 
John Kaster http://johnkaster.wordpress.com
http://transactis.com Seamless paper-free transactions

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 7-Aug-2012, at 7:49 PM EST
From: John Kaster
 
Re: Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock
John wrote:

> Thanks very much. That does indeed work. Is this more efficient than
> the code I was using? Seems to be cleaner.

It relies on the OS performing the actual DNS query instead of Indy.  So 
on the one hand, it is simpler and cleaner, but on the other hand, you lose 
control over the behavior of the query.  You cannot implement timeouts, retries, 
recursive results, etc.  It is whatever the OS decides to use.  For most 
use cases, that is fine.  Just be aware that it is a blocking operation, 
like any other.

> I tried using 'nuq04s07-in-f8.1e100.net' as the DNS server name for
> the second DNS resolution request, but that just returns no result. So
> I guess I'm still not understanding how to walk through the servers
> listed in section 3.5.

You use the same DNS server every time, you simply Resolve() each returned 
address until you reach the result you are looking for.

--
Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 7-Aug-2012, at 11:45 PM EST
From: Remy Lebeau (TeamB)
 
Re: Indy DNSResolver  
News Group: embarcadero.public.delphi.internet.winsock
Remy Lebeau (TeamB) wrote:

> You use the same DNS server every time, you simply Resolve() each
> returned address until you reach the result you are looking for.

Heh. Ok. seems simple enough. Seemed like the returned address was not
any different than the one I had before, but I'll try it. Thanks.

-- 
John Kaster http://johnkaster.wordpress.com
http://transactis.com Seamless paper-free transactions

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 8-Aug-2012, at 8:17 PM EST
From: John Kaster