Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2006-08

resolve.pp in ver 2.0.4 (and a fix)

1 message · 1 person ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Pete Cervasio

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.

Reply by email