12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2003 by the Free Pascal development team
- Implement networking routines.
-
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$mode objfpc}
- {$h+}
- unit netdb;
- {
- WARNING
- This unit hardly does any error checking. For example, stringfromlabel
- could easily be exploited by someone sending malicious UDP packets in
- order to crash your program. So if you really want to depend on this
- in critical programs then you'd better fix a lot of code in here.
- Otherwise, it appears to work pretty well.
- }
- Interface
- { i hsh.inc} // disappears if part of resolve.pp !!
- Uses Sockets;
- Type
- THostAddr = in_addr; // historical aliases for these.
- THostAddr6= Tin6_addr;
- TNetAddr = THostAddr; // but in net order.
- Const
- DNSPort = 53;
- MaxResolveAddr = 10;
- SResolveFile = '/etc/resolv.conf';
- SServicesFile = '/etc/services';
- SHostsFile = '/etc/hosts';
- SNetworksFile = '/etc/networks';
- SProtocolFile = '/etc/protocols';
- MaxRecursion = 10;
- MaxIP4Mapped = 10;
-
- Type
- TDNSServerArray = Array of THostAddr;
- TServiceEntry = record
- Name : String;
- Protocol : String;
- Port : Word;
- Aliases : String;
- end;
-
- THostEntry = record
- Name : String;
- Addr : THostAddr;
- Aliases : String;
- end;
- PHostEntry = ^THostEntry;
- THostEntryArray = Array of THostEntry;
- THostEntry6 = record
- Name : String;
- Addr : THostAddr6;
- Aliases : String;
- end;
- PHostEntry6 = ^THostEntry6;
- THostEntry6Array = Array of THostEntry6;
-
- TNetworkEntry = Record
- Name : String;
- Addr : TNetAddr;
- Aliases : String;
- end;
- PNetworkEntry = ^TNetworkEntry;
- TProtocolEntry = Record
- Name : String;
- Number : integer;
- Aliases : String;
- end;
- PProtocolEntry = ^TProtocolEntry;
- PHostListEntry = ^THostListEntry;
- THostListEntry = Record
- Entry : THostEntry;
- Next : PHostListEntry;
- end;
- Var
- DNSServers : TDNSServerArray;
- DefaultDomainList : String;
- CheckResolveFileAge : Boolean;
- CheckHostsFileAge : Boolean;
- TimeOutS,TimeOutMS : Longint;
-
-
- Function GetDNSServers(FN : String) : Integer;
- Function ResolveName(HostName : String; Var Addresses : Array of THostAddr) : Integer;
- Function ResolveName6(HostName : String; Var Addresses : Array of THostAddr6) : Integer;
- Function ResolveAddress(HostAddr : THostAddr; Var Addresses : Array of String) : Integer;
- Function ResolveAddress6(HostAddr: THostAddr6; var Addresses: Array of string) : Integer;
- function IN6_IS_ADDR_V4MAPPED(HostAddr: THostAddr6): boolean;
- Function ResolveHostByName(HostName : String; Var H : THostEntry) : Boolean;
- Function ResolveHostByAddr(HostAddr : THostAddr; Var H : THostEntry) : Boolean;
- Function ResolveHostByName6(Hostname : String; Var H : THostEntry6) : Boolean;
- Function ResolveHostByAddr6(HostAddr : THostAddr6; Var H : THostEntry6) : Boolean;
- Function GetHostByName(HostName: String; Var H : THostEntry) : boolean;
- Function GetHostByAddr(Addr: THostAddr; Var H : THostEntry) : boolean;
- Function GetNetworkByName(NetName: String; Var N : TNetworkEntry) : boolean;
- Function GetNetworkByAddr(Addr: THostAddr; Var N : TNetworkEntry) : boolean;
- Function GetServiceByName(Const Name,Proto : String; Var E : TServiceEntry) : Boolean;
- Function GetServiceByPort(Port : Word;Const Proto : String; Var E : TServiceEntry) : Boolean;
- Function GetProtocolByName(ProtoName: String; Var H : TProtocolEntry) : boolean;
- Function GetProtocolByNumber(proto: Integer; Var H : TProtocolEntry) : boolean;
- Function ProcessHosts(FileName : String) : PHostListEntry;
- Function FreeHostsList(var List : PHostListEntry) : Integer;
- Procedure HostsListToArray(var List : PHostListEntry; Var Hosts : THostEntryArray; FreeList : Boolean);
- Implementation
- uses
- BaseUnix,
- sysutils;
- const
- { from http://www.iana.org/assignments/dns-parameters }
- DNSQRY_A = 1; // name to IP address
- DNSQRY_AAAA = 28; // name to IP6 address
- DNSQRY_A6 = 38; // name to IP6 (new)
- DNSQRY_PTR = 12; // IP address to name
- DNSQRY_MX = 15; // name to MX
- DNSQRY_TXT = 16; // name to TXT
- DNSQRY_CNAME = 5;
- // Flags 1
- QF_QR = $80;
- QF_OPCODE = $78;
- QF_AA = $04;
- QF_TC = $02; // Truncated.
- QF_RD = $01;
- // Flags 2
- QF_RA = $80;
- QF_Z = $70;
- QF_RCODE = $0F;
-
- Type
- TPayLoad = Array[0..511] of Byte;
- TQueryData = packed Record
- id : Array[0..1] of Byte;
- flags1 : Byte;
- flags2 : Byte;
- qdcount : word;
- ancount : word;
- nscount : word;
- arcount : word;
- Payload : TPayLoad;
- end;
-
- PRRData = ^TRRData;
- TRRData = Packed record // RR record
- Atype : Word; // Answer type
- AClass : Word;
- TTL : Cardinal;
- RDLength : Word;
- end;
- { ---------------------------------------------------------------------
- Some Parsing routines
- ---------------------------------------------------------------------}
- Const
- Whitespace = [' ',#9];
- Function NextWord(Var Line : String) : String;
- Var
- I,J : Integer;
- begin
- I:=1;
- While (I<=Length(Line)) and (Line[i] in Whitespace) do
- inc(I);
- J:=I;
- While (J<=Length(Line)) and Not (Line[J] in WhiteSpace) do
- inc(j);
- Result:=Copy(Line,I,J-I);
- Delete(Line,1,J);
- end;
-
- Function StripComment(var L : String) : Boolean;
- Var
- i : Integer;
- begin
- I:=Pos('#',L);
- If (I<>0) then
- L:=Copy(L,1,I-1)
- else
- begin
- I:=Pos(';',L);
- If (I<>0) then
- L:=Copy(L,1,I-1)
- end;
- Result:=Length(L)>0;
- end;
- Function MatchNameOrAlias(Const Entry,Name: String; Aliases : String) : Boolean;
- Var
- P : Integer;
- A : String;
- begin
- Result:=CompareText(Entry,Name)=0;
- If Not Result then
- While (Not Result) and (Length(Aliases)>0) do
- begin
- P:=Pos(',',Aliases);
- If (P=0) then
- P:=Length(Aliases)+1;
- A:=Copy(Aliases,1,P-1);
- Delete(Aliases,1,P);
- Result:=CompareText(A,Entry)=0;
- end;
- end;
- { ---------------------------------------------------------------------
- hosts processing
- ---------------------------------------------------------------------}
- Function GetAddr(Var L : String; Var Addr : THostAddr) : Boolean;
- Var
- S : String;
- // i,p,a : Integer;
-
- begin
- Result:=True;
- S:=NextWord(L);
- Addr:=StrToNetAddr(S);
- // Writeln(s,'->',Addr.s_bytes[1],'.',Addr.s_bytes[2],'.',Addr.s_bytes[3],'.',Addr.s_bytes[4]);
- Result:=Addr.s_bytes[1]<>0;
- end;
- Function FillHostEntry (Var Entry : THostEntry; L: String) : boolean;
- Var
- H : String;
- begin
- Result := False;
- Repeat
- H:=NextWord(L);
- If (H<>'') then begin
- if (Entry.Name='') then
- Entry.Name:=H
- else
- begin
- If (Entry.Aliases<>'') then
- Entry.Aliases:=Entry.Aliases+',';
- Entry.Aliases:=Entry.Aliases+H;
- end;
- Result := True;
- end;
- until (H='');
- end;
- Function ProcessHosts(FileName : String) : PHostListEntry;
- Var
- F : Text;
- L : String;
- A : THostAddr;
- T : PHostListEntry;
-
- begin
- Result:=Nil;
- Assign(F,FileName);
- {$I-}
- Reset(F);
- {$I+};
- If (IOResult<>0) then
- Exit;
- Try
- While Not EOF(F) do
- begin
- Readln(F,L);
- If StripComment(L) then
- begin
- If GetAddr(L,A) then
- begin
- T:=New(PHostListEntry);
- T^.Entry.Addr:=A;
- FillHostEntry(T^.Entry,L);
- T^.Next:=Result;
- Result:=T;
- end;
- end;
- end;
- Finally
- Close(F);
- end;
- end;
- { Internal lookup, used in GetHostByName and friends. }
- Var
- HostsList : PHostListEntry = Nil;
- HostsFileAge : Longint;
- // HostsFileName : String;
- Function FreeHostsList(var List : PHostListEntry) : Integer;
- Var
- P : PHostListEntry;
- begin
- Result:=0;
- While (List<>Nil) do
- begin
- Inc(Result);
- P:=List^.Next;
- Dispose(List);
- List:=P;
- end;
- end;
- Procedure HostsListToArray(var List : PHostListEntry; Var Hosts : THostEntryArray; FreeList : Boolean);
- Var
- P : PHostListEntry;
- Len : Integer;
- begin
- Len:=0;
- P:=List;
- While P<> Nil do
- begin
- Inc(Len);
- P:=P^.Next;
- end;
- SetLength(Hosts,Len);
- If (Len>0) then
- begin
- Len:=0;
- P:=List;
- While (P<>Nil) do
- begin
- Hosts[Len]:=P^.Entry;
- P:=P^.Next;
- Inc(Len);
- end;
- end;
- If FreeList then
- FreeHostsList(List);
- end;
- Procedure CheckHostsFile;
- Var
- F : Integer;
- begin
- If CheckHostsFileAge then
- begin
- F:=FileAge(SHostsFile);
- If HostsFileAge<F then
- begin
- // Rescan.
- FreeHostsList(HostsList);
- HostsList:=ProcessHosts(SHostsFile);
- HostsFileAge:=F;
- end;
- end;
- end;
- Function FindHostEntryInHostsFile(N: String; Addr: THostAddr; Var H : THostEntry) : boolean;
- Var
- // F : Text;
- HE : THostEntry;
- P : PHostListEntry;
-
- begin
- Result:=False;
- CheckHostsFile;
- P:=HostsList;
- While (Not Result) and (P<>Nil) do
- begin
- HE:=P^.Entry;
- If (N<>'') then
- Result:=MatchNameOrAlias(N,HE.Name,HE.Aliases)
- else
- Result:=Cardinal(hosttonet(Addr))=Cardinal(HE.Addr);
- P:=P^.Next;
- end;
- If Result then
- begin
- H.Name:=HE.Name;
- H.Addr:=nettohost(HE.Addr);
- H.Aliases:=HE.Aliases;
- end;
- end;
- { ---------------------------------------------------------------------
- Resolve.conf handling
- ---------------------------------------------------------------------}
- Var
- ResolveFileAge : Longint;
- ResolveFileName : String;
-
- Function GetDNSServers(Fn : String) : Integer;
- Var
- R : Text;
- L : String;
- // I : Integer;
- H : THostAddr;
- E : THostEntry;
-
- Function CheckDirective(Dir : String) : Boolean;
-
- Var
- P : Integer;
-
- begin
- P:=Pos(Dir,L);
- Result:=(P<>0);
- If Result then
- begin
- Delete(L,1,P+Length(Dir));
- L:=Trim(L);
- end;
- end;
-
- begin
- Result:=0;
- ResolveFileName:=Fn;
- ResolveFileAge:=FileAge(FN);
- {$i-}
- Assign(R,FN);
- Reset(R);
- {$i+}
- If (IOResult<>0) then
- exit;
- Try
- While not EOF(R) do
- begin
- Readln(R,L);
- if StripComment(L) then
- If CheckDirective('nameserver') then
- begin
- H:=HostToNet(StrToHostAddr(L));
- If (H.s_bytes[1]<>0) then
- begin
- setlength(DNSServers,Result+1);
- DNSServers[Result]:=H;
- Inc(Result);
- end
- else if FindHostEntryInHostsFile(L,H,E) then
- begin
- setlength(DNSServers,Result+1);
- DNSServers[Result]:=E.Addr;
- Inc(Result);
- end;
- end
- else if CheckDirective('domain') then
- DefaultDomainList:=L
- else if CheckDirective('search') then
- DefaultDomainList:=L;
- end;
- Finally
- Close(R);
- end;
- end;
- Procedure CheckResolveFile;
- Var
- F : Integer;
- begin
- If CheckResolveFileAge then
- begin
- F:=FileAge(ResolveFileName);
- If ResolveFileAge<F then
- GetDnsServers(ResolveFileName);
- end;
- end;
- { ---------------------------------------------------------------------
- Payload handling functions.
- ---------------------------------------------------------------------}
-
- Procedure DumpPayLoad(Q : TQueryData; L : Integer);
- Var
- i : Integer;
- begin
- Writeln('Payload : ',l);
- For I:=0 to L-1 do
- Write(Q.Payload[i],' ');
- Writeln;
- end;
-
- Function BuildPayLoad(Var Q : TQueryData; Name : String; RR : Word; QClass : Word) : Integer;
- Var
- P : PByte;
- l,S : Integer;
-
- begin
- Result:=-1;
- If length(Name)>506 then
- Exit;
- Result:=0;
- P:[email protected][0];
- Repeat
- L:=Pos('.',Name);
- If (L=0) then
- S:=Length(Name)
- else
- S:=L-1;
- P[Result]:=S;
- Move(Name[1],P[Result+1],S);
- Inc(Result,S+1);
- If (L>0) then
- Delete(Name,1,L);
- Until (L=0);
- P[Result]:=0;
- rr := htons(rr);
- Move(rr,P[Result+1],2);
- Inc(Result,3);
- QClass := htons(QClass);
- Move(qclass,P[Result],2);
- Inc(Result,2);
- end;
- Function NextRR(Const PayLoad : TPayLoad;Var Start : LongInt; AnsLen : LongInt; Var RR : TRRData) : Boolean;
- Var
- I : Integer;
- HaveName : Boolean;
- PA : PRRData;
-
- begin
- Result:=False;
- I:=Start;
- // Skip labels and pointers. At least 1 label or pointer is present.
- Repeat
- HaveName:=True;
- If (Payload[i]>63) then // Pointer, skip
- Inc(I,2)
- else If Payload[i]=0 then // Null termination of label, skip.
- Inc(i)
- else
- begin
- Inc(I,Payload[i]+1); // Label, continue scan.
- HaveName:=False;
- end;
- Until HaveName or (I>(AnsLen-SizeOf(TRRData)));
- Result:=(I<=(AnsLen-SizeOf(TRRData)));
- // Check RR record.
- PA:=PRRData(@Payload[i]);
- RR:=PA^;
- Start:=I+SizeOf(TRRData);
- end;
- Function BuildName (Const PayLoad : TPayLoad; Start,len : Integer) : String;
- Const
- FIREDNS_POINTER_VALUE = $C000;
-
- Var
- I,O : Integer;
- P : Word;
-
- begin
- SetLength(Result,512);
- I:=Start;
- O:=1;
- // Copy labels and pointers. At least 1 label or pointer is present.
- Repeat
- If (Payload[i]>63) then // Pointer, move.
- begin
- Move(Payload[i],P,2);
- I:=ntohs(p)-FIREDNS_POINTER_VALUE-12;
- end
- else if Payload[i]<>0 then // Label, copy
- begin
- If O<>1 then
- begin
- Result[O]:='.';
- Inc(O);
- end;
- P:=Payload[i];
- Move(Payload[i+1],Result[o],P);
- Inc(I,P+1);
- Inc(O,P);
- end;
- Until (Payload[I]=0);
- setlength(result,o-1);
- end;
- { ---------------------------------------------------------------------
- QueryData handling functions
- ---------------------------------------------------------------------}
-
- Function CheckAnswer(Const Qry : TQueryData; Var Ans : TQueryData) : Boolean;
- begin
- Result:=False;
- With Ans do
- begin
- // Check ID.
- If (ID[1]<>QRY.ID[1]) or (ID[0]<>Qry.ID[0]) then
- exit;
- // Flags ?
- If (Flags1 and QF_QR)=0 then
- exit;
- if (Flags1 and QF_OPCODE)<>0 then
- exit;
- if (Flags2 and QF_RCODE)<>0 then
- exit;
- // Number of answers ?
- AnCount := htons(Ancount);
- If Ancount<1 then
- Exit;
- Result:=True;
- end;
- end;
- Function SkipAnsQueries(Var Ans : TQueryData; L : Integer) : integer;
- Var
- Q,I : Integer;
- begin
- Result:=0;
- With Ans do
- begin
- qdcount := htons(qdcount);
- i:=0;
- q:=0;
- While (Q<qdcount) and (i<l) do
- begin
- If Payload[i]>63 then
- begin
- Inc(I,6);
- Inc(Q);
- end
- else
- begin
- If Payload[i]=0 then
- begin
- inc(q);
- Inc(I,5);
- end
- else
- Inc(I,Payload[i]+1);
- end;
- end;
- Result:=I;
- end;
- end;
- { ---------------------------------------------------------------------
- DNS Query functions.
- ---------------------------------------------------------------------}
-
- Function Query(Resolver : Integer; Var Qry,Ans : TQueryData; QryLen : Integer; Var AnsLen : Integer) : Boolean;
- Var
- SA : TInetSockAddr;
- Sock,L : Longint;
- Al,RTO : Longint;
- ReadFDS : TFDSet;
-
- begin
- Result:=False;
- With Qry do
- begin
- ID[0]:=Random(256);
- ID[1]:=Random(256);
- Flags1:=QF_RD;
- Flags2:=0;
- qdcount:=htons(1); // was 1 shl 8;
- ancount:=0;
- nscount:=0;
- arcount:=0;
- end;
- Sock:=Socket(PF_INET,SOCK_DGRAM,0);
- If Sock=-1 then
- exit;
- With SA do
- begin
- family:=AF_INET;
- port:=htons(DNSport);
- addr:=cardinal(DNSServers[Resolver]); // dnsservers already in net order
- end;
- sendto(sock,qry,qrylen+12,0,SA,SizeOf(SA));
- // Wait for answer.
- RTO:=TimeOutS*1000+TimeOutMS;
- fpFD_ZERO(ReadFDS);
- fpFD_Set(sock,readfds);
- if fpSelect(Sock+1,@readfds,Nil,Nil,RTO)<=0 then
- begin
- fpclose(Sock);
- exit;
- end;
- AL:=SizeOf(SA);
- L:=recvfrom(Sock,ans,SizeOf(Ans),0,SA,AL);
- fpclose(Sock);
- // Check lenght answer and fields in header data.
- If (L<12) or not CheckAnswer(Qry,Ans) Then
- exit;
- // Return Payload length.
- Anslen:=L-12;
- Result:=True;
- end;
- function stringfromlabel(pl: TPayLoad; start: integer): string;
- var
- l,i: integer;
- begin
- result := '';
- l := 0;
- i := 0;
- repeat
- l := ord(pl[start]);
- { compressed reply }
- while (l >= 192) do
- begin
- { the -12 is because of the reply header length }
- start := (l and not(192)) shl 8 + ord(pl[start+1]) - 12;
- l := ord(pl[start]);
- end;
- if l <> 0 then begin
- setlength(result,length(result)+l);
- move(pl[start+1],result[i+1],l);
- result := result + '.';
- inc(start,l); inc(start);
- inc(i,l); inc(i);
- end;
- until l = 0;
- if result[length(result)] = '.' then setlength(result,length(result)-1);
- end;
- Function ResolveNameAt(Resolver : Integer; HostName : String; Var Addresses : Array of THostAddr; Recurse: Integer) : Integer;
- Var
- Qry, Ans : TQueryData;
- MaxAnswer,I,QryLen,
- AnsLen,AnsStart : Longint;
- RR : TRRData;
- cname : string;
- begin
- Result:=0;
- QryLen:=BuildPayLoad(Qry,HostName,DNSQRY_A,1);
- If Not Query(Resolver,Qry,Ans,QryLen,AnsLen) then
- Result:=-1
- else
- begin
- AnsStart:=SkipAnsQueries(Ans,AnsLen);
- MaxAnswer:=Ans.AnCount-1;
- If MaxAnswer>High(Addresses) then
- MaxAnswer:=High(Addresses);
- I:=0;
- While (I<=MaxAnswer) and NextRR(Ans.Payload,AnsStart,AnsLen,RR) do
- begin
- if htons(rr.AClass) = 1 then
- case ntohs(rr.AType) of
- DNSQRY_A: begin
- Move(Ans.PayLoad[AnsStart],Addresses[i],SizeOf(THostAddr));
- inc(Result);
- Inc(AnsStart,htons(RR.RDLength));
- end;
- DNSQRY_CNAME: begin
- if Recurse >= MaxRecursion then begin
- Result := -1;
- exit;
- end;
- rr.rdlength := ntohs(rr.rdlength);
- setlength(cname, rr.rdlength);
- cname := stringfromlabel(ans.payload, ansstart);
- Result := ResolveNameAt(Resolver, cname, Addresses, Recurse+1);
- exit; // FIXME: what about other servers?!
- end;
- end;
- Inc(I);
- end;
- end;
- end;
- Function ResolveName(HostName : String; Var Addresses : Array of THostAddr) : Integer;
- Var
- I : Integer;
- begin
- CheckResolveFile;
- I:=0;
- Result:=0;
- While (Result<=0) and (I<=high(DNSServers)) do
- begin
- Result:=ResolveNameAt(I,HostName,Addresses,0);
- Inc(I);
- end;
- end;
- //const NoAddress6 : array[0..7] of word = (0,0,0,0,0,0,0,0);
- Function ResolveNameAt6(Resolver : Integer; HostName : String; Var Addresses : Array of THostAddr6; Recurse: Integer) : Integer;
-
- Var
- Qry, Ans : TQueryData;
- MaxAnswer,I,QryLen,
- AnsLen,AnsStart : Longint;
- RR : TRRData;
- cname : string;
- LIP4mapped: array[0..MaxIP4Mapped-1] of THostAddr;
- LIP4count: Longint;
-
- begin
- Result:=0;
- QryLen:=BuildPayLoad(Qry,HostName,DNSQRY_AAAA,1);
- If Not Query(Resolver,Qry,Ans,QryLen,AnsLen) then begin
- // no answer? try IPv4 mapped addresses, maybe that will generate one
- LIP4Count := ResolveName(HostName, LIP4Mapped);
- if LIP4Count > 0 then begin
- inc(LIP4Count); // we loop to LIP4Count-1 later
- if LIP4Count > MaxIP4Mapped then LIP4Count := MaxIP4Mapped;
- if LIP4Count > Length(Addresses) then LIP4Count := Length(Addresses);
- for i := 0 to LIP4Count-2 do begin
- Addresses[i] := NoAddress6;
- Addresses[i].u6_addr16[5] := $FFFF;
- Move(LIP4Mapped[i], Addresses[i].u6_addr16[6], 4);
- end;
- Result := LIP4Count;
- end else begin
- Result:=-1
- end;
- end else
- begin
- AnsStart:=SkipAnsQueries(Ans,AnsLen);
- MaxAnswer:=Ans.AnCount-1;
- If MaxAnswer>High(Addresses) then
- MaxAnswer:=High(Addresses);
- I:=0;
- While (I<=MaxAnswer) and NextRR(Ans.Payload,AnsStart,AnsLen,RR) do
- begin
- if (1=NtoHS(RR.AClass)) then
- case ntohs(rr.atype) of
- DNSQRY_AAAA: begin
- Move(Ans.PayLoad[AnsStart],Addresses[i],SizeOf(THostAddr6));
- inc(Result);
- rr.rdlength := ntohs(rr.rdlength);
- Inc(AnsStart,RR.RDLength);
- end;
- DNSQRY_CNAME: begin
- if Recurse >= MaxRecursion then begin
- Result := -1;
- exit;
- end;
- rr.rdlength := ntohs(rr.rdlength);
- setlength(cname, rr.rdlength);
- cname := stringfromlabel(ans.payload, ansstart);
- Result := ResolveNameAt6(Resolver, cname, Addresses, Recurse+1);
- exit; // FIXME: what about other servers?!
- end;
- end;
- Inc(I);
- end;
- end;
- end;
-
- Function ResolveName6(HostName: String; Var Addresses: Array of THostAddr6) : Integer;
- var
- i: Integer;
- begin
- CheckResolveFile;
- i := 0;
- Result := 0;
- while (Result <= 0) and (I<= high(DNSServers)) do begin
- Result := ResolveNameAt6(I, Hostname, Addresses, 0);
- Inc(i);
- end;
- end;
- Function ResolveAddressAt(Resolver : Integer; Address : String; Var Names : Array of String) : Integer;
- Var
- Qry, Ans : TQueryData;
- MaxAnswer,I,QryLen,
- AnsLen,AnsStart : Longint;
- RR : TRRData;
- begin
- Result:=0;
- QryLen:=BuildPayLoad(Qry,Address,DNSQRY_PTR,1);
- If Not Query(Resolver,Qry,Ans,QryLen,AnsLen) then
- Result:=-1
- else
- begin
- AnsStart:=SkipAnsQueries(Ans,AnsLen);
- MaxAnswer:=Ans.AnCount-1;
- If MaxAnswer>High(Names) then
- MaxAnswer:=High(Names);
- I:=0;
- While (I<=MaxAnswer) and NextRR(Ans.Payload,AnsStart,AnsLen,RR) do
- begin
- if (Ntohs(RR.AType)=DNSQRY_PTR) and (1=NtoHS(RR.AClass)) then
- begin
- Names[i]:=BuildName(Ans.Payload,AnsStart,AnsLen);
- inc(Result);
- RR.RDLength := ntohs(RR.RDLength);
- Inc(AnsStart,RR.RDLength);
- end;
- Inc(I);
- end;
- end;
- end;
- Function ResolveAddress(HostAddr : THostAddr; Var Addresses : Array of String) : Integer;
- Var
- I : Integer;
- S : String;
- nt : tnetaddr;
-
- begin
- CheckResolveFile;
- I:=0;
- Result:=0;
- nt:=hosttonet(hostaddr);
- S:=Format('%d.%d.%d.%d.in-addr.arpa',[nt.s_bytes[4],nt.s_bytes[3],nt.s_bytes[2],nt.s_bytes[1]]);
- While (Result=0) and (I<=high(DNSServers)) do
- begin
- Result:=ResolveAddressAt(I,S,Addresses);
- Inc(I);
- end;
- end;
- Function ResolveAddress6(HostAddr : THostAddr6; Var Addresses : Array of String) : Integer;
- const
- hexdig: string[16] = '0123456789abcdef';
-
- Var
- I : Integer;
- S : ShortString;
-
- begin
- CheckResolveFile;
- Result:=0;
- S := '0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.int';
- for i := 7 downto 0 do begin
- S[5+(7-i)*8] := hexdig[1+(HostAddr.u6_addr16[i] and $000F) shr 00];
- S[7+(7-i)*8] := hexdig[1+(HostAddr.u6_addr16[i] and $00F0) shr 04];
- S[1+(7-i)*8] := hexdig[1+(HostAddr.u6_addr16[i] and $0F00) shr 08];
- S[3+(7-i)*8] := hexdig[1+(HostAddr.u6_addr16[i] and $F000) shr 12];
- end;
- I := 0;
- While (Result=0) and (I<=high(DNSServers)) do
- begin
- Result:=ResolveAddressAt(I,S,Addresses);
- Inc(I);
- end;
- end;
- function IN6_IS_ADDR_V4MAPPED(HostAddr: THostAddr6): boolean;
- begin
- Result :=
- (HostAddr.u6_addr16[0] = 0) and
- (HostAddr.u6_addr16[1] = 0) and
- (HostAddr.u6_addr16[2] = 0) and
- (HostAddr.u6_addr16[3] = 0) and
- (HostAddr.u6_addr16[4] = 0) and
- (HostAddr.u6_addr16[5] = $FFFF);
- end;
- Function ResolveHostByName(HostName : String; Var H : THostEntry) : Boolean;
- Var
- Address : Array[1..MaxResolveAddr] of THostAddr;
- L : Integer;
-
- begin
- L:=ResolveName(HostName,Address);
- Result:=(L>0);
- If Result then
- begin
- // We could add a reverse call here to get the real name and aliases.
- H.Name:=HostName;
- H.Addr:=Address[1];
- H.aliases:='';
- end;
- end;
- Function ResolveHostByName6(HostName : String; Var H : THostEntry6) : Boolean;
- Var
- Address : Array[1..MaxResolveAddr] of THostAddr6;
- L : Integer;
-
- begin
- L:=ResolveName6(HostName,Address);
- Result:=(L>0);
- If Result then
- begin
- // We could add a reverse call here to get the real name and aliases.
- H.Name:=HostName;
- H.Addr:=Address[1];
- H.aliases:='';
- end;
- end;
- Function ResolveHostByAddr(HostAddr : THostAddr; Var H : THostEntry) : Boolean;
- Var
- Names : Array[1..MaxResolveAddr] of String;
- I,L : Integer;
-
- begin
- L:=ResolveAddress(HostAddr,Names);
- Result:=(L>0);
- If Result then
- begin
- H.Name:=Names[1];
- H.Addr:=HostAddr;
- H.Aliases:='';
- If (L>1) then
- For I:=2 to L do
- If (I=2) then
- H.Aliases:=Names[i]
- else
- H.Aliases:=H.Aliases+','+Names[i];
- end;
- end;
- Function ResolveHostByAddr6(HostAddr : THostAddr6; Var H : THostEntry6) : Boolean;
- Var
- Names : Array[1..MaxResolveAddr] of String;
- I,L : Integer;
-
- begin
- L:=ResolveAddress6(HostAddr,Names);
- Result:=(L>0);
- If Result then
- begin
- H.Name:=Names[1];
- H.Addr:=HostAddr;
- H.Aliases:='';
- If (L>1) then
- For I:=2 to L do
- If (I=2) then
- H.Aliases:=Names[i]
- else
- H.Aliases:=H.Aliases+','+Names[i];
- end;
- end;
- //const NoAddress : in_addr = (s_addr: 0);
- Function GetHostByName(HostName: String; Var H : THostEntry) : boolean;
- begin
- Result:=FindHostEntryInHostsFile(HostName,NoAddress,H);
- end;
- Function GetHostByAddr(Addr: THostAddr; Var H : THostEntry) : boolean;
- begin
- Result:=FindHostEntryInHostsFile('',Addr,H);
- end;
- { ---------------------------------------------------------------------
- /etc/protocols handling.
- ---------------------------------------------------------------------}
- Function GetNextProtoEntry(var F : Text; Var H : TProtocolEntry): boolean;
- Var
- Line,S : String;
- I : integer;
-
- begin
- Result:=False;
- Repeat
- ReadLn(F,Line);
- StripComment(Line);
- S:=NextWord(Line);
- If (S<>'') then
- begin
- H.Name:=S;
- S:=NextWord(Line);
- i:=strtointdef(s,-1);
- If (i<>-1) then
- begin
- H.number:=i;
- Result:=True;
- H.Aliases:='';
- Repeat
- S:=NextWord(line);
- If (S<>'') then
- If (H.Aliases='') then
- H.Aliases:=S
- else
- H.Aliases:=H.Aliases+','+S;
- until (S='');
- end;
- end;
- until Result or EOF(F);
- end;
- Function FindProtoEntryInProtoFile(N: String; prot: integer; Var H : TProtocolEntry) : boolean;
- Var
- F : Text;
- HE : TProtocolEntry;
-
- begin
- Result:=False;
- If FileExists(SProtocolFile) then
- begin
- Assign(F,SProtocolFile);
- {$i-}
- Reset(F);
- {$i+}
- If (IOResult=0) then
- begin
- While Not Result and GetNextProtoEntry(F,HE) do
- begin
- If (N<>'') then
- Result:=MatchNameOrAlias(N,HE.Name,HE.Aliases)
- else
- Result:=prot=he.number;
- end;
- Close(f);
- If Result then
- begin
- H.Name:=HE.Name;
- H.number:=he.number;
- H.Aliases:=HE.Aliases;
- end;
- end;
- end;
- end;
- Function GetProtocolByName(ProtoName: String; Var H : TProtocolEntry) : boolean;
- begin
- Result:=FindProtoEntryInProtoFile(ProtoName,0,H);
- end;
- Function GetProtocolByNumber(proto: Integer; Var H : TProtocolEntry) : boolean;
- begin
- Result:=FindProtoEntryInProtoFile('',Proto,H);
- end;
- { ---------------------------------------------------------------------
- /etc/networks handling
- ---------------------------------------------------------------------}
- function StrTonetpartial( IP : AnsiString) : in_addr ;
- Var
- Dummy : AnsiString;
- I,j,k : Longint;
- // Temp : in_addr;
- begin
- strtonetpartial.s_addr:=0; //:=NoAddress;
- i:=0; j:=0;
- while (i<4) and (j=0) do
- begin
- J:=Pos('.',IP);
- if j=0 then j:=length(ip)+1;
- Dummy:=Copy(IP,1,J-1);
- Delete (IP,1,J);
- Val (Dummy,k,J);
- if j=0 then
- strtonetpartial.s_bytes[i+1]:=k;
- inc(i);
- end;
- if (i=0) then strtonetpartial.s_addr:=0;
- end;
- Function GetNextNetworkEntry(var F : Text; Var N : TNetworkEntry): boolean;
- Var
- NN,Line,S : String;
- A : TNetAddr;
-
- begin
- Result:=False;
- Repeat
- ReadLn(F,Line);
- StripComment(Line);
- S:=NextWord(Line);
- If (S<>'') then
- begin
- NN:=S;
- A:=StrTonetpartial(NextWord(Line));
- Result:=(NN<>'') and (A.s_bytes[1]<>0); // Valid addr.
- If result then
- begin
- N.Addr.s_addr:=A.s_addr; // keep it host.
- N.Name:=NN;
- N.Aliases:='';
- end;
- end;
- until Result or EOF(F);
- end;
- Function FindNetworkEntryInNetworksFile(Net: String; Addr: TNetAddr; Var N : TNetworkEntry) : boolean;
- Var
- F : Text;
- NE : TNetworkEntry;
-
- begin
- Result:=False;
- If FileExists(SNetworksFile) then
- begin
- Assign(F,SNetworksFile);
- {$i-}
- Reset(F);
- {$i+}
- If (IOResult=0) then
- begin
- While Not Result and GetNextNetworkEntry(F,NE) do
- begin
- If (Net<>'') then
- Result:=MatchNameOrAlias(Net,NE.Name,NE.Aliases)
- else
- Result:=Cardinal(Addr)=Cardinal(NE.Addr);
- end;
- Close(f);
- If Result then
- begin
- N.Name:=NE.Name;
- N.Addr:=nettohost(NE.Addr);
- N.Aliases:=NE.Aliases;
- end;
- end;
- end;
- end;
- Const NoNet : in_addr = (s_addr:0);
-
- Function GetNetworkByName(NetName: String; Var N : TNetworkEntry) : boolean;
- begin
- Result:=FindNetworkEntryInNetworksFile(NetName,NoNet,N);
- end;
- Function GetNetworkByAddr(Addr: THostAddr; Var N : TNetworkEntry) : boolean;
- begin
- Result:=FindNetworkEntryInNetworksFile('',Addr,N);
- end;
- { ---------------------------------------------------------------------
- /etc/services section
- ---------------------------------------------------------------------}
- Function GetNextServiceEntry(Var F : Text; Var E : TServiceEntry) : Boolean;
- Var
- Line,S : String;
- P : INteger;
-
- begin
- Result:=False;
- Repeat
- ReadLn(F,Line);
- StripComment(Line);
- S:=NextWord(Line);
- If (S<>'') then
- begin
- E.Name:=S;
- S:=NextWord(Line);
- P:=Pos('/',S);
- If (P<>0) then
- begin
- E.Port:=StrToIntDef(Copy(S,1,P-1),0);
- If (E.Port<>0) then
- begin
- E.Protocol:=Copy(S,P+1,Length(S)-P);
- Result:=length(E.Protocol)>0;
- E.Aliases:='';
- Repeat
- S:=NextWord(Line);
- If (S<>'') then
- If (Length(E.Aliases)=0) then
- E.aliases:=S
- else
- E.Aliases:=E.Aliases+','+S;
- until (S='');
- end;
- end;
- end;
- until Result or EOF(F);
- end;
- Function FindServiceEntryInFile(Const Name,Proto : String; Port : Integer; Var E : TServiceEntry) : Boolean;
- Var
- F : Text;
- TE : TServiceEntry;
-
- begin
- Result:=False;
- If FileExists(SServicesFile) then
- begin
- Assign(F,SServicesFile);
- {$i-}
- Reset(F);
- {$i+}
- If (IOResult=0) then
- begin
- While Not Result and GetNextServiceEntry(F,TE) do
- begin
- If (Port=-1) then
- Result:=MatchNameOrAlias(Name,TE.Name,TE.Aliases)
- else
- Result:=(Port=TE.Port);
- If Result and (Proto<>'') then
- Result:=(Proto=TE.Protocol);
- end;
- Close(f);
- If Result then
- begin
- E.Name:=TE.Name;
- E.Port:=TE.Port;
- E.Protocol:=TE.Protocol;
- E.Aliases:=TE.Aliases;
- end;
- end;
- end;
- end;
- Function GetServiceByName(Const Name,Proto : String; Var E : TServiceEntry) : Boolean;
- begin
- Result:=FindServiceEntryInFile(Name,Proto,-1,E);
- end;
- Function GetServiceByPort(Port : Word;Const Proto : String; Var E : TServiceEntry) : Boolean;
- begin
- Result:=FindServiceEntryInFile('',Proto,Port,E);
- end;
- { ---------------------------------------------------------------------
- Initialization section
- ---------------------------------------------------------------------}
- Procedure InitResolver;
- //Var
- // I : Integer;
- begin
- TimeOutS :=5;
- TimeOutMS:=0;
- CheckHostsFileAge:=False;
- If FileExists(SHostsFile) then
- HostsList:=ProcessHosts(SHostsFile);
- CheckResolveFileAge:=False;
- If FileExists(SResolveFile) then
- GetDNsservers(SResolveFile);
- end;
- Procedure DoneResolver;
- begin
- FreeHostsList(HostsList);
- end;
- Initialization
- InitResolver;
- Finalization
- DoneResolver;
- end.
|