Search code examples
delphidnsindy10

Delphi / Indy resolve DNS domain by host name lookup


I'm trying to use a hardcoded AName, some code using JNI on Delphi 10.1 update 2, and TIdDNSResolver to do the following:

1) Get the device DNS server(s) from the device interface config (works!)

2) Do a lookup on the DNS server to retrieve that server's domain name (fails!)

3) Append the DNS Domain to the hardcoded AName (not there yet)

4) Use the FQDN AName to lookup the server IP Address (not there yet)

So far using JNI functions in Delphi I can get the DNS server(s) IP Address. When I try to lookup the domain name I'm failing. Here's my code:

dns.Host := s;
dns.WaitingTime := 2048;
dns.QueryType := [qtDName];
dns.Resolve('hard_coded_server_name');
for i := 0 to Pred(dns.QueryResult.Count) do
begin
  r := dns.QueryResult[i];
  case r.RecType of
    qtDName:  begin
                txt := TTextRecord(r);
                Memo1.Lines.AddStrings(txt.Text);
              end;
  end;
end;

I'm certain that I'm using the TResultRecord incorrectly, but couldn't find docs on how to do this correctly. Could someone (Remy?) please explain how to do this?

Thanks.


Solution

  • TIdDNSResolver does not use TTextRecord for qtDName response records. TTextRecord is only used for qtTXT and qtHINFO records (THINFORecord derives from TTextRecord).

    Looking at the source code for TIdDNSResolver, I see that DNAME is actually an unhandled response type (I do not know why), so TIdDNSResolver will end up using the TResultRecord class as-is for DNAME records. And because of that, DNAME record data will not be parsed at all, and r.RecType will not be qtDName like you are expecting (technically, it will actually be unassigned and default to 0, which happens to be qtA). However, the raw answer data will be in r.RData, at least.

    Note that a DNAME lookup may result in CNAME response records (amongst others). CNAME records are represented in QueryResult as TNAMERecord objects, where r.RecType will be qtName.

    I have checked in a fix (SVN rev 5377):

    • added a new TDNAMERecord class for parsing DNAME data.
    • made sure the TResultRecord.RecType property is assigned a value for known record types (even if they are not parsed).
    • added a new TResultRecord.TypeCode property for unknown record types that cannot be expressed in the TResultRecord.RecType property.

    For example:

    dns.Host := s;
    dns.WaitingTime := 2048;
    dns.QueryType := [qtDName];
    dns.Resolve('hard_coded_server_name');
    for i := 0 to Pred(dns.QueryResult.Count) do
    begin
      r := dns.QueryResult[i];
      case r.RecType of
        qtName: begin
          Memo1.Lines.Add('CNAME: ' + TNAMERecord(r).HostName);
        end;
        qtDName: begin
          Memo1.Lines.Add('DNAME: ' + TDNAMERecord(r).HostName);
        end;
        // other types as needed ...
      else
        Memo1.Lines.Add(IntToStr(r.TypeCode) + ': ' + ToHex(r.RData));
      end;
    end;