[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