[fpc-devel] resolve.pp in ver 2.0.4 (and a fix)

Pete Cervasio cervasio at airmail.net
Thu Aug 31 22:38:03 CEST 2006


Greetings.

I had been using version 2.0.2 (under Linux, if it matters) and noticed a 
problem with the THostResolver component.  It was giving incorrect (reversed) 
addresses for anything that had to come from DNS.  Entries out of /etc/hosts 
would work fine, though.  After fixing the problem here locally, I figured I 
ought to share.

In the process of getting ready to do that, I wound up upgrading to the latest 
stable version (2.0.4) and was happy to see that some attempt had already 
been made to fix that bug.  Unfortunately, it appears that the problem has 
been reversed instead of fixed.  Now lookups that come through DNS are 
showing up properly but the ones from /etc/hosts are not.

The fix is further down, but for reference here is a test program which will 
show the problem in action.  The original purpose of this test program was to 
develop/test a generic Lookup() function that would deal with short and full 
host names, which it does.  Feel free to use it, if it's helpful to you. :)

program resolver_test;
uses
  SysUtils, resolve, netdb;

function Lookup (WhatHost: String): String;
var
  TheHost: THostResolver;
begin
  Result := '';
  TheHost := THostResolver.Create(nil);
  try
    // First, attempt lookup using the name as given to us
    if TheHost.NameLookup(WhatHost) then
      Result := TheHost.AddressAsString;

    // If not found, and no dot in the name, tack on default domain
    if (Result = '') and  (pos('.', WhatHost) = 0) then
      if TheHost.NameLookup(WhatHost + '.' + DefaultDomainList) then
        Result := TheHost.AddressAsString;

  finally
    TheHost.free;
  end;
end;

procedure testlookup (What, Where, Expected: String);
var
  Res : String;
begin
  Res := Lookup (What);
  Write (Format('Lookup %-19s from %-10s : %-15s ', 
         [What, Where, Res]));
  if Res = Expected then
    writeln ('Success!')
  else
    writeln ('Failure!');
end;

begin
  Writeln ('default domain is ', DefaultDomainList);
  testlookup ('localhost', '/etc/hosts', '127.0.0.1');
  testlookup ('host85', 'dns', '192.168.1.85');
  testlookup ('delenn', '/etc/hosts', '192.168.1.92');
  testlookup ('www.freepascal.org', 'dns', '62.166.198.202');
end.

The "expected" values were all determined by "getent hosts" as follows:

for a in localhost host85 delenn www.freepascal.org ; do getent hosts $a; done

The "where" part comes from me knowing that there are only two non-comment 
lines in my /etc/hosts file.  :)

The incorrect results, as given by the above program compiled with the 2.0.4 
binary distribution:

default domain is sbcglobal.net
Lookup localhost           from /etc/hosts : 1.0.0.127       Failure!
Lookup host85              from dns        : 192.168.1.85    Success!
Lookup delenn              from /etc/hosts : 92.1.168.192    Failure!
Lookup www.freepascal.org  from dns        : 62.166.198.202  Success!

As you can see, the addresses that came from /etc/hosts are in the wrong 
order.  The problem is in the routines THostResolver.NameLookup and 
THostResolver.SaveHostEntry in resolve.pp.

In THostResolver.SaveHostEntry there are several calls of NetToHost(), as 
follows:

Procedure THostResolver.SaveHostEntry(Entry : Pointer);

Var
  PH : ^THostEntry;
  I : Integer;

begin
  PH:=ENtry;
  FName:=PH^.Name;
  FHostAddress:=NetToHost(PH^.Addr);
  FAddressCount:=1;
  GetMem(FAddresses,SizeOf(THostAddr));
  FAddresses[0]:=NetToHost(PH^.Addr);
  FAliases.CommaText:=PH^.Aliases;
end;

This is incorrect behavior, as some of the addresses passed to SaveHostEntry 
may already be in host order.  The two NetToHost() calls should be removed 
from this function, and instead, one should be added to the 
THostResolver.Namelookup function immediately after the ResolveHostByName() 
call, which returns addresses in network order.  Like so:


{$ifdef usenetdb}
Function THostResolver.NameLookup (Const S : String) : Boolean;

Var
  H : THostEntry;

begin
  Result:=Inherited NameLookup(S);
  If Result then
    begin
    Result:=GetHostByName(S,H);
    if not Result then
    begin
      Result:=ResolveHostByName(S,H);
      if Result then
        H.Addr:=NetToHost(H.Addr);
    end;
    If Result then
      SaveHostEntry(@H);
    end;
end;

... and the other fix, further down ...

Procedure THostResolver.SaveHostEntry(Entry : Pointer);

Var
  PH : ^THostEntry;
  I : Integer;

begin
  PH:=ENtry;
  FName:=PH^.Name;
  FHostAddress:=PH^.Addr;
  FAddressCount:=1;
  GetMem(FAddresses,SizeOf(THostAddr));
  FAddresses[0]:=PH^.Addr;
  FAliases.CommaText:=PH^.Aliases;
end;

After this change, the proper results are obtained:

~/devel/temp $./resolver_test
default domain is sbcglobal.net
Lookup localhost           from /etc/hosts : 127.0.0.1       Success!
Lookup host85              from dns        : 192.168.1.85    Success!
Lookup delenn              from /etc/hosts : 192.168.1.92    Success!
Lookup www.freepascal.org  from dns        : 62.166.198.202  Success!

I have not looked at any of the other T{foo}Resolver classes at all, since I 
don't use them, and do not know if they need similar changes.  In any event, 
I hope this proves helpful to the person maintaining this module.

Best regards,
Pete C.




More information about the fpc-devel mailing list