netdb.pp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2003 by the Free Pascal development team
  5. Implement networking routines.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$h+}
  14. unit netdb;
  15. {
  16. WARNING
  17. This unit hardly does any error checking. For example, stringfromlabel
  18. could easily be exploited by someone sending malicious UDP packets in
  19. order to crash your program. So if you really want to depend on this
  20. in critical programs then you'd better fix a lot of code in here.
  21. Otherwise, it appears to work pretty well.
  22. }
  23. Interface
  24. { i hsh.inc} // disappears if part of resolve.pp !!
  25. Uses Sockets;
  26. Type
  27. THostAddr = in_addr; // historical aliases for these.
  28. THostAddr6= Tin6_addr;
  29. TNetAddr = THostAddr; // but in net order.
  30. Const
  31. DNSPort = 53;
  32. MaxServers = 4;
  33. MaxResolveAddr = 10;
  34. SResolveFile = '/etc/resolv.conf';
  35. SServicesFile = '/etc/services';
  36. SHostsFile = '/etc/hosts';
  37. SNetworksFile = '/etc/networks';
  38. SProtocolFile = '/etc/protocols';
  39. MaxRecursion = 10;
  40. MaxIP4Mapped = 10;
  41. Type
  42. TDNSServerArray = Array[1..MaxServers] of THostAddr;
  43. TServiceEntry = record
  44. Name : String;
  45. Protocol : String;
  46. Port : Word;
  47. Aliases : String;
  48. end;
  49. THostEntry = record
  50. Name : String;
  51. Addr : THostAddr;
  52. Aliases : String;
  53. end;
  54. TNetworkEntry = Record
  55. Name : String;
  56. Addr : TNetAddr;
  57. Aliases : String;
  58. end;
  59. TProtocolEntry = Record
  60. Name : String;
  61. Number : integer;
  62. Aliases : String;
  63. end;
  64. Var
  65. DNSServers : TDNSServerArray;
  66. DNSServerCount : Integer;
  67. DefaultDomainList : String;
  68. CheckResolveFileAge : Boolean;
  69. TimeOutS,TimeOutMS : Longint;
  70. Function GetDNSServers(FN : String) : Integer;
  71. Function ResolveName(HostName : String; Var Addresses : Array of THostAddr) : Integer;
  72. Function ResolveName6(HostName : String; Var Addresses : Array of THostAddr6) : Integer;
  73. Function ResolveAddress(HostAddr : THostAddr; Var Addresses : Array of String) : Integer;
  74. Function ResolveAddress6(HostAddr: THostAddr6; var Addresses: Array of string) : Integer;
  75. function IN6_IS_ADDR_V4MAPPED(HostAddr: THostAddr6): boolean;
  76. Function ResolveHostByName(HostName : String; Var H : THostEntry) : Boolean;
  77. Function ResolveHostByAddr(HostAddr : THostAddr; Var H : THostEntry) : Boolean;
  78. Function GetHostByName(HostName: String; Var H : THostEntry) : boolean;
  79. Function GetHostByAddr(Addr: THostAddr; Var H : THostEntry) : boolean;
  80. Function GetNetworkByName(NetName: String; Var N : TNetworkEntry) : boolean;
  81. Function GetNetworkByAddr(Addr: THostAddr; Var N : TNetworkEntry) : boolean;
  82. Function GetServiceByName(Const Name,Proto : String; Var E : TServiceEntry) : Boolean;
  83. Function GetServiceByPort(Port : Word;Const Proto : String; Var E : TServiceEntry) : Boolean;
  84. Function GetProtocolByName(ProtoName: String; Var H : TProtocolEntry) : boolean;
  85. Function GetProtocolByNumber(proto: Integer; Var H : TProtocolEntry) : boolean;
  86. Implementation
  87. uses
  88. {$ifdef VER1_0}
  89. Linux,
  90. {$else}
  91. BaseUnix,
  92. {$endif}
  93. sysutils;
  94. const
  95. { from http://www.iana.org/assignments/dns-parameters }
  96. DNSQRY_A = 1; // name to IP address
  97. DNSQRY_AAAA = 28; // name to IP6 address
  98. DNSQRY_A6 = 38; // name to IP6 (new)
  99. DNSQRY_PTR = 12; // IP address to name
  100. DNSQRY_MX = 15; // name to MX
  101. DNSQRY_TXT = 16; // name to TXT
  102. DNSQRY_CNAME = 5;
  103. // Flags 1
  104. QF_QR = $80;
  105. QF_OPCODE = $78;
  106. QF_AA = $04;
  107. QF_TC = $02; // Truncated.
  108. QF_RD = $01;
  109. // Flags 2
  110. QF_RA = $80;
  111. QF_Z = $70;
  112. QF_RCODE = $0F;
  113. Type
  114. TPayLoad = Array[0..511] of char;
  115. TQueryData = packed Record
  116. id : Array[0..1] of Byte;
  117. flags1 : Byte;
  118. flags2 : Byte;
  119. qdcount : word;
  120. ancount : word;
  121. nscount : word;
  122. arcount : word;
  123. Payload : TPayLoad;
  124. end;
  125. TRRData = Packed record // RR record
  126. Atype : Word; // Answer type
  127. AClass : Word;
  128. TTL : Cardinal;
  129. RDLength : Word;
  130. end;
  131. Var
  132. ResolveFileAge : Longint;
  133. ResolveFileName : String;
  134. { ---------------------------------------------------------------------
  135. Resolve.conf handling
  136. ---------------------------------------------------------------------}
  137. Function GetDNSServers(Fn : String) : Integer;
  138. Var
  139. R : Text;
  140. L : String;
  141. I : Integer;
  142. H : THostAddr;
  143. Function CheckDirective(Dir : String) : Boolean;
  144. Var
  145. P : Integer;
  146. begin
  147. P:=Pos(Dir,L);
  148. Result:=(P<>0);
  149. If Result then
  150. begin
  151. Delete(L,1,P+Length(Dir));
  152. L:=Trim(L);
  153. end;
  154. end;
  155. begin
  156. Result:=0;
  157. ResolveFileName:=Fn;
  158. ResolveFileAge:=FileAge(FN);
  159. {$i-}
  160. Assign(R,FN);
  161. Reset(R);
  162. {$i+}
  163. If (IOResult<>0) then
  164. exit;
  165. Try
  166. While not EOF(R) do
  167. begin
  168. Readln(R,L);
  169. I:=Pos('#',L);
  170. If (I<>0) then
  171. L:=Copy(L,1,I-1);
  172. If CheckDirective('nameserver') then
  173. begin
  174. H:=HostToNet(StrToHostAddr(L));
  175. If H.s_bytes[1]<>0 then
  176. begin
  177. Inc(Result);
  178. DNSServers[Result]:=H;
  179. end;
  180. end
  181. else if CheckDirective('domain') then
  182. DefaultDomainList:=L
  183. else if CheckDirective('search') then
  184. DefaultDomainList:=L;
  185. end;
  186. Finally
  187. Close(R);
  188. end;
  189. DNSServerCount:=Result;
  190. end;
  191. Procedure CheckResolveFile;
  192. Var
  193. F : Integer;
  194. begin
  195. If CheckResolveFileAge then
  196. begin
  197. F:=FileAge(ResolveFileName);
  198. If ResolveFileAge<F then
  199. GetDnsServers(ResolveFileName);
  200. end;
  201. end;
  202. { ---------------------------------------------------------------------
  203. Payload handling functions.
  204. ---------------------------------------------------------------------}
  205. Procedure DumpPayLoad(Q : TQueryData; L : Integer);
  206. Var
  207. i : Integer;
  208. begin
  209. Writeln('Payload : ',l);
  210. For I:=0 to L-1 do
  211. Write(Byte(Q.Payload[i]),' ');
  212. Writeln;
  213. end;
  214. Function BuildPayLoad(Var Q : TQueryData; Name : String; RR : Word; QClass : Word) : Integer;
  215. Var
  216. P : PByte;
  217. l,S : Integer;
  218. begin
  219. Result:=-1;
  220. If length(Name)>506 then
  221. Exit;
  222. Result:=0;
  223. P:[email protected];
  224. Repeat
  225. L:=Pos('.',Name);
  226. If (L=0) then
  227. S:=Length(Name)
  228. else
  229. S:=L-1;
  230. P[Result]:=S;
  231. Move(Name[1],P[Result+1],S);
  232. Inc(Result,S+1);
  233. If (L>0) then
  234. Delete(Name,1,L);
  235. Until (L=0);
  236. P[Result]:=0;
  237. rr := htons(rr);
  238. Move(rr,P[Result+1],2);
  239. Inc(Result,3);
  240. QClass := htons(QClass);
  241. Move(qclass,P[Result],2);
  242. Inc(Result,2);
  243. end;
  244. Function NextRR(Const PayLoad : TPayLoad;Var Start : LongInt; AnsLen : LongInt; Var RR : TRRData) : Boolean;
  245. Var
  246. I : Integer;
  247. HaveName : Boolean;
  248. PA : ^TRRData;
  249. begin
  250. Result:=False;
  251. I:=Start;
  252. // Skip labels and pointers. At least 1 label or pointer is present.
  253. Repeat
  254. HaveName:=True;
  255. If (Payload[i]>#63) then // Pointer, skip
  256. Inc(I,2)
  257. else If Payload[i]=#0 then // Null termination of label, skip.
  258. Inc(i)
  259. else
  260. begin
  261. Inc(I,Ord(Payload[i])+1); // Label, continue scan.
  262. HaveName:=False;
  263. end;
  264. Until HaveName or (I>(AnsLen-SizeOf(TRRData)));
  265. Result:=(I<=(AnsLen-SizeOf(TRRData)));
  266. // Check RR record.
  267. PA:=@Payload[i];
  268. RR:=PA^;
  269. Start:=I+SizeOf(TRRData);
  270. end;
  271. Function BuildName (Const PayLoad : TPayLoad; Start,len : Integer) : String;
  272. Const
  273. FIREDNS_POINTER_VALUE = $C000;
  274. Var
  275. I,O : Integer;
  276. P : Word;
  277. begin
  278. SetLength(Result,512);
  279. I:=Start;
  280. O:=1;
  281. // Copy labels and pointers. At least 1 label or pointer is present.
  282. Repeat
  283. If (Payload[i]>#63) then // Pointer, move.
  284. begin
  285. Move(Payload[i],P,2);
  286. I:=ntohs(p)-FIREDNS_POINTER_VALUE-12;
  287. end
  288. else if Payload[i]<>#0 then // Label, copy
  289. begin
  290. If O<>1 then
  291. begin
  292. Result[O]:='.';
  293. Inc(O);
  294. end;
  295. P:=Ord(Payload[i]);
  296. Move(Payload[i+1],Result[o],P);
  297. Inc(I,P+1);
  298. Inc(O,P);
  299. end;
  300. Until (Payload[I]=#0);
  301. end;
  302. { ---------------------------------------------------------------------
  303. QueryData handling functions
  304. ---------------------------------------------------------------------}
  305. Function CheckAnswer(Const Qry : TQueryData; Var Ans : TQueryData) : Boolean;
  306. begin
  307. Result:=False;
  308. With Ans do
  309. begin
  310. // Check ID.
  311. If (ID[1]<>QRY.ID[1]) or (ID[0]<>Qry.ID[0]) then
  312. exit;
  313. // Flags ?
  314. If (Flags1 and QF_QR)=0 then
  315. exit;
  316. if (Flags1 and QF_OPCODE)<>0 then
  317. exit;
  318. if (Flags2 and QF_RCODE)<>0 then
  319. exit;
  320. // Number of answers ?
  321. AnCount := htons(Ancount);
  322. If Ancount<1 then
  323. Exit;
  324. Result:=True;
  325. end;
  326. end;
  327. Function SkipAnsQueries(Var Ans : TQueryData; L : Integer) : integer;
  328. Var
  329. Q,I : Integer;
  330. begin
  331. Result:=0;
  332. With Ans do
  333. begin
  334. qdcount := htons(qdcount);
  335. i:=0;
  336. q:=0;
  337. While (Q<qdcount) and (i<l) do
  338. begin
  339. If Ord(Payload[i])>63 then
  340. begin
  341. Inc(I,6);
  342. Inc(Q);
  343. end
  344. else
  345. begin
  346. If Payload[i]=#0 then
  347. begin
  348. inc(q);
  349. Inc(I,5);
  350. end
  351. else
  352. Inc(I,Ord(Payload[i])+1);
  353. end;
  354. end;
  355. Result:=I;
  356. end;
  357. end;
  358. { ---------------------------------------------------------------------
  359. DNS Query functions.
  360. ---------------------------------------------------------------------}
  361. Function Query(Resolver : Integer; Var Qry,Ans : TQueryData; QryLen : Integer; Var AnsLen : Integer) : Boolean;
  362. Var
  363. SA : TInetSockAddr;
  364. Sock,L : Longint;
  365. Al,RTO : Longint;
  366. ReadFDS : {$ifdef VER1_0}FDSet{$ELSE}TFDSet{$ENDIF};
  367. begin
  368. Result:=False;
  369. With Qry do
  370. begin
  371. ID[0]:=Random(256);
  372. ID[1]:=Random(256);
  373. Flags1:=QF_RD;
  374. Flags2:=0;
  375. qdcount:=htons(1); // was 1 shl 8;
  376. ancount:=0;
  377. nscount:=0;
  378. arcount:=0;
  379. end;
  380. Sock:=Socket(PF_INET,SOCK_DGRAM,0);
  381. If Sock=-1 then
  382. exit;
  383. With SA do
  384. begin
  385. family:=AF_INET;
  386. port:=htons(DNSport);
  387. addr:=cardinal(DNSServers[Resolver]); // dnsservers already in net order
  388. end;
  389. sendto(sock,qry,qrylen+12,0,SA,SizeOf(SA));
  390. // Wait for answer.
  391. RTO:=TimeOutS*1000+TimeOutMS;
  392. {$ifdef VER1_0}FD_ZERO{$else}fpFD_ZERO{$endif}(ReadFDS);
  393. {$ifdef VER1_0}
  394. FD_Set(Sock,readfds);
  395. {$else}
  396. fpFD_Set(sock,readfds);
  397. {$endif}
  398. if {$ifdef ver1_0}Select{$else}fpSelect{$endif}(Sock+1,@readfds,Nil,Nil,RTO)<=0 then
  399. begin
  400. {$ifdef VER1_0}fdclose{$ELSE}fpclose{$endif}(Sock);
  401. exit;
  402. end;
  403. AL:=SizeOf(SA);
  404. L:=recvfrom(Sock,ans,SizeOf(Ans),0,SA,AL);
  405. {$ifdef VER1_0}fdclose{$ELSE}fpclose{$endif}(Sock);
  406. // Check lenght answer and fields in header data.
  407. If (L<12) or not CheckAnswer(Qry,Ans) Then
  408. exit;
  409. // Return Payload length.
  410. Anslen:=L-12;
  411. Result:=True;
  412. end;
  413. function stringfromlabel(pl: TPayLoad; start: integer): string;
  414. var
  415. l,i: integer;
  416. begin
  417. result := '';
  418. l := 0;
  419. i := 0;
  420. repeat
  421. l := ord(pl[start]);
  422. if l <> 0 then begin
  423. setlength(result,length(result)+l);
  424. move(pl[start+1],result[i+1],l);
  425. result := result + '.';
  426. inc(start,l); inc(start);
  427. inc(i,l); inc(i);
  428. end;
  429. until l = 0;
  430. if result[length(result)] = '.' then setlength(result,length(result)-1);
  431. end;
  432. Function ResolveNameAt(Resolver : Integer; HostName : String; Var Addresses : Array of THostAddr; Recurse: Integer) : Integer;
  433. Var
  434. Qry, Ans : TQueryData;
  435. MaxAnswer,I,QryLen,
  436. AnsLen,AnsStart : Longint;
  437. RR : TRRData;
  438. cname : string;
  439. begin
  440. Result:=0;
  441. QryLen:=BuildPayLoad(Qry,HostName,DNSQRY_A,1);
  442. If Not Query(Resolver,Qry,Ans,QryLen,AnsLen) then
  443. Result:=-1
  444. else
  445. begin
  446. AnsStart:=SkipAnsQueries(Ans,AnsLen);
  447. MaxAnswer:=Ans.AnCount-1;
  448. If MaxAnswer>High(Addresses) then
  449. MaxAnswer:=High(Addresses);
  450. I:=0;
  451. While (I<=MaxAnswer) and NextRR(Ans.Payload,AnsStart,AnsLen,RR) do
  452. begin
  453. if htons(rr.AClass) = 1 then
  454. case ntohs(rr.AType) of
  455. DNSQRY_A: begin
  456. Move(Ans.PayLoad[AnsStart],Addresses[i],SizeOf(THostAddr));
  457. inc(Result);
  458. Inc(AnsStart,htons(RR.RDLength));
  459. end;
  460. DNSQRY_CNAME: begin
  461. if Recurse >= MaxRecursion then begin
  462. Result := -1;
  463. exit;
  464. end;
  465. rr.rdlength := ntohs(rr.rdlength);
  466. setlength(cname, rr.rdlength);
  467. cname := stringfromlabel(ans.payload, ansstart);
  468. Result := ResolveNameAt(Resolver, cname, Addresses, Recurse+1);
  469. exit; // FIXME: what about other servers?!
  470. end;
  471. end;
  472. Inc(I);
  473. end;
  474. end;
  475. end;
  476. Function ResolveName(HostName : String; Var Addresses : Array of THostAddr) : Integer;
  477. Var
  478. I : Integer;
  479. begin
  480. CheckResolveFile;
  481. I:=1;
  482. Result:=0;
  483. While (Result<=0) and (I<=DNSServerCount) do
  484. begin
  485. Result:=ResolveNameAt(I,HostName,Addresses,0);
  486. Inc(I);
  487. end;
  488. end;
  489. //const NoAddress6 : array[0..7] of word = (0,0,0,0,0,0,0,0);
  490. Function ResolveNameAt6(Resolver : Integer; HostName : String; Var Addresses : Array of THostAddr6; Recurse: Integer) : Integer;
  491. Var
  492. Qry, Ans : TQueryData;
  493. MaxAnswer,I,QryLen,
  494. AnsLen,AnsStart : Longint;
  495. RR : TRRData;
  496. cname : string;
  497. LIP4mapped: array[0..MaxIP4Mapped-1] of THostAddr;
  498. LIP4count: Longint;
  499. begin
  500. Result:=0;
  501. QryLen:=BuildPayLoad(Qry,HostName,DNSQRY_AAAA,1);
  502. If Not Query(Resolver,Qry,Ans,QryLen,AnsLen) then begin
  503. // no answer? try IPv4 mapped addresses, maybe that will generate one
  504. LIP4Count := ResolveName(HostName, LIP4Mapped);
  505. if LIP4Count > 0 then begin
  506. inc(LIP4Count); // we loop to LIP4Count-1 later
  507. if LIP4Count > MaxIP4Mapped then LIP4Count := MaxIP4Mapped;
  508. {$ifdef VER1_0}
  509. if LIP4Count > High(Addresses)+1 then LIP4Count := High(Addresses)+1;
  510. {$else}
  511. if LIP4Count > Length(Addresses) then LIP4Count := Length(Addresses);
  512. {$endif}
  513. for i := 0 to LIP4Count-2 do begin
  514. Addresses[i] := NoAddress6;
  515. Addresses[i].u6_addr16[5] := $FFFF;
  516. Move(LIP4Mapped[i], Addresses[i].u6_addr16[6], 4);
  517. end;
  518. Result := LIP4Count;
  519. end else begin
  520. Result:=-1
  521. end;
  522. end else
  523. begin
  524. AnsStart:=SkipAnsQueries(Ans,AnsLen);
  525. MaxAnswer:=Ans.AnCount-1;
  526. If MaxAnswer>High(Addresses) then
  527. MaxAnswer:=High(Addresses);
  528. I:=0;
  529. While (I<=MaxAnswer) and NextRR(Ans.Payload,AnsStart,AnsLen,RR) do
  530. begin
  531. if (1=NtoHS(RR.AClass)) then
  532. case ntohs(rr.atype) of
  533. DNSQRY_AAAA: begin
  534. Move(Ans.PayLoad[AnsStart],Addresses[i],SizeOf(THostAddr6));
  535. inc(Result);
  536. rr.rdlength := ntohs(rr.rdlength);
  537. Inc(AnsStart,RR.RDLength);
  538. end;
  539. DNSQRY_CNAME: begin
  540. if Recurse >= MaxRecursion then begin
  541. Result := -1;
  542. exit;
  543. end;
  544. rr.rdlength := ntohs(rr.rdlength);
  545. setlength(cname, rr.rdlength);
  546. cname := stringfromlabel(ans.payload, ansstart);
  547. Result := ResolveNameAt6(Resolver, cname, Addresses, Recurse+1);
  548. exit; // FIXME: what about other servers?!
  549. end;
  550. end;
  551. Inc(I);
  552. end;
  553. end;
  554. end;
  555. Function ResolveName6(HostName: String; Var Addresses: Array of THostAddr6) : Integer;
  556. var
  557. i: Integer;
  558. begin
  559. CheckResolveFile;
  560. i := 1;
  561. Result := 0;
  562. while (Result <= 0) and (I<= DNSServerCount) do begin
  563. Result := ResolveNameAt6(I, Hostname, Addresses, 0);
  564. Inc(i);
  565. end;
  566. end;
  567. Function ResolveAddressAt(Resolver : Integer; Address : String; Var Names : Array of String) : Integer;
  568. Var
  569. Qry, Ans : TQueryData;
  570. MaxAnswer,I,QryLen,
  571. AnsLen,AnsStart : Longint;
  572. RR : TRRData;
  573. begin
  574. Result:=0;
  575. QryLen:=BuildPayLoad(Qry,Address,DNSQRY_PTR,1);
  576. If Not Query(Resolver,Qry,Ans,QryLen,AnsLen) then
  577. Result:=-1
  578. else
  579. begin
  580. AnsStart:=SkipAnsQueries(Ans,AnsLen);
  581. MaxAnswer:=Ans.AnCount-1;
  582. If MaxAnswer>High(Names) then
  583. MaxAnswer:=High(Names);
  584. I:=0;
  585. While (I<=MaxAnswer) and NextRR(Ans.Payload,AnsStart,AnsLen,RR) do
  586. begin
  587. if (Ntohs(RR.AType)=DNSQRY_PTR) and (1=NtoHS(RR.AClass)) then
  588. begin
  589. Names[i]:=BuildName(Ans.Payload,AnsStart,AnsLen);
  590. inc(Result);
  591. RR.RDLength := ntohs(RR.RDLength);
  592. Inc(AnsStart,RR.RDLength);
  593. end;
  594. Inc(I);
  595. end;
  596. end;
  597. end;
  598. Function ResolveAddress(HostAddr : THostAddr; Var Addresses : Array of String) : Integer;
  599. Var
  600. I : Integer;
  601. S : String;
  602. nt : tnetaddr;
  603. begin
  604. CheckResolveFile;
  605. I:=1;
  606. Result:=0;
  607. nt:=hosttonet(hostaddr);
  608. 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]]);
  609. While (Result=0) and (I<=DNSServerCount) do
  610. begin
  611. Result:=ResolveAddressAt(I,S,Addresses);
  612. Inc(I);
  613. end;
  614. end;
  615. Function ResolveAddress6(HostAddr : THostAddr6; Var Addresses : Array of String) : Integer;
  616. const
  617. hexdig: string[16] = '0123456789abcdef';
  618. Var
  619. I : Integer;
  620. S : ShortString;
  621. begin
  622. CheckResolveFile;
  623. Result:=0;
  624. 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';
  625. for i := 7 downto 0 do begin
  626. S[5+(7-i)*8] := hexdig[1+(HostAddr.u6_addr16[i] and $000F) shr 00];
  627. S[7+(7-i)*8] := hexdig[1+(HostAddr.u6_addr16[i] and $00F0) shr 04];
  628. S[1+(7-i)*8] := hexdig[1+(HostAddr.u6_addr16[i] and $0F00) shr 08];
  629. S[3+(7-i)*8] := hexdig[1+(HostAddr.u6_addr16[i] and $F000) shr 12];
  630. end;
  631. I := 1;
  632. While (Result=0) and (I<=DNSServerCount) do
  633. begin
  634. Result:=ResolveAddressAt(I,S,Addresses);
  635. Inc(I);
  636. end;
  637. end;
  638. function IN6_IS_ADDR_V4MAPPED(HostAddr: THostAddr6): boolean;
  639. begin
  640. Result :=
  641. (HostAddr.u6_addr16[0] = 0) and
  642. (HostAddr.u6_addr16[1] = 0) and
  643. (HostAddr.u6_addr16[2] = 0) and
  644. (HostAddr.u6_addr16[3] = 0) and
  645. (HostAddr.u6_addr16[4] = 0) and
  646. (HostAddr.u6_addr16[5] = $FFFF);
  647. end;
  648. Function ResolveHostByName(HostName : String; Var H : THostEntry) : Boolean;
  649. Var
  650. Address : Array[1..MaxResolveAddr] of THostAddr;
  651. L : Integer;
  652. begin
  653. L:=ResolveName(HostName,Address);
  654. Result:=(L>0);
  655. If Result then
  656. begin
  657. // We could add a reverse call here to get the real name and aliases.
  658. H.Name:=HostName;
  659. H.Addr:=Address[1];
  660. H.aliases:='';
  661. end;
  662. end;
  663. Function ResolveHostByAddr(HostAddr : THostAddr; Var H : THostEntry) : Boolean;
  664. Var
  665. Names : Array[1..MaxResolveAddr] of String;
  666. I,L : Integer;
  667. begin
  668. L:=ResolveAddress(HostAddr,Names);
  669. Result:=(L>0);
  670. If Result then
  671. begin
  672. H.Name:=Names[1];
  673. H.Addr:=HostAddr;
  674. H.Aliases:='';
  675. If (L>1) then
  676. For I:=2 to L do
  677. If (I=2) then
  678. H.Aliases:=Names[i]
  679. else
  680. H.Aliases:=H.Aliases+','+Names[i];
  681. end;
  682. end;
  683. { ---------------------------------------------------------------------
  684. Some Parsing routines
  685. ---------------------------------------------------------------------}
  686. Const
  687. Whitespace = [' ',#9];
  688. Function NextWord(Var Line : String) : String;
  689. Var
  690. I,J : Integer;
  691. begin
  692. I:=1;
  693. While (I<=Length(Line)) and (Line[i] in Whitespace) do
  694. inc(I);
  695. J:=I;
  696. While (J<=Length(Line)) and Not (Line[J] in WhiteSpace) do
  697. inc(j);
  698. Result:=Copy(Line,I,J-I);
  699. Delete(Line,1,J);
  700. end;
  701. Procedure StripComment(Var line : String);
  702. Var
  703. P : Integer;
  704. begin
  705. P:=Pos('#',Line);
  706. If (P<>0) then
  707. Line:=Trim(Copy(Line,1,P-1));
  708. end;
  709. Function MatchNameOrAlias(Const Entry,Name: String; Aliases : String) : Boolean;
  710. Var
  711. P : Integer;
  712. A : String;
  713. begin
  714. Result:=CompareText(Entry,Name)=0;
  715. If Not Result then
  716. While (Not Result) and (Length(Aliases)>0) do
  717. begin
  718. P:=Pos(',',Aliases);
  719. If (P=0) then
  720. P:=Length(Aliases)+1;
  721. A:=Copy(Aliases,1,P-1);
  722. Delete(Aliases,1,P);
  723. Result:=CompareText(A,Entry)=0;
  724. end;
  725. end;
  726. { ---------------------------------------------------------------------
  727. /etc/hosts handling.
  728. ---------------------------------------------------------------------}
  729. Function GetNextHostEntry(var F : Text; Var H : THostEntry): boolean;
  730. Var
  731. Line,S : String;
  732. begin
  733. Result:=False;
  734. Repeat
  735. ReadLn(F,Line);
  736. StripComment(Line);
  737. S:=NextWord(Line);
  738. If (S<>'') then
  739. begin
  740. H.Addr:=StrTonetAddr(S); // endianness problem here. (fixed)
  741. if (H.Addr.s_bytes[1]<>0) then
  742. begin
  743. S:=NextWord(Line);
  744. If (S<>'') then
  745. begin
  746. H.Name:=S;
  747. Result:=True;
  748. H.Aliases:='';
  749. Repeat
  750. S:=NextWord(line);
  751. If (S<>'') then
  752. If (H.Aliases='') then
  753. H.Aliases:=S
  754. else
  755. H.Aliases:=H.Aliases+','+S;
  756. until (S='');
  757. end;
  758. end;
  759. end;
  760. until Result or EOF(F);
  761. end;
  762. Function FindHostEntryInHostsFile(N: String; Addr: THostAddr; Var H : THostEntry) : boolean;
  763. Var
  764. F : Text;
  765. HE : THostEntry;
  766. begin
  767. Result:=False;
  768. If FileExists(SHostsFile) then
  769. begin
  770. Assign(F,SHostsFile);
  771. {$i-}
  772. Reset(F);
  773. {$i+}
  774. If (IOResult=0) then
  775. begin
  776. While Not Result and GetNextHostEntry(F,HE) do
  777. begin
  778. If (N<>'') then
  779. Result:=MatchNameOrAlias(N,HE.Name,HE.Aliases)
  780. else
  781. Result:=Cardinal(hosttonet(Addr))=Cardinal(HE.Addr);
  782. end;
  783. Close(f);
  784. If Result then
  785. begin
  786. H.Name:=HE.Name;
  787. H.Addr:=nettohost(HE.Addr);
  788. H.Aliases:=HE.Aliases;
  789. end;
  790. end;
  791. end;
  792. end;
  793. //const NoAddress : in_addr = (s_addr: 0);
  794. Function GetHostByName(HostName: String; Var H : THostEntry) : boolean;
  795. begin
  796. Result:=FindHostEntryInHostsFile(HostName,NoAddress,H);
  797. end;
  798. Function GetHostByAddr(Addr: THostAddr; Var H : THostEntry) : boolean;
  799. begin
  800. Result:=FindHostEntryInHostsFile('',Addr,H);
  801. end;
  802. { ---------------------------------------------------------------------
  803. /etc/protocols handling.
  804. ---------------------------------------------------------------------}
  805. Function GetNextProtoEntry(var F : Text; Var H : TProtocolEntry): boolean;
  806. Var
  807. Line,S : String;
  808. I : integer;
  809. begin
  810. Result:=False;
  811. Repeat
  812. ReadLn(F,Line);
  813. StripComment(Line);
  814. S:=NextWord(Line);
  815. If (S<>'') then
  816. begin
  817. H.Name:=S;
  818. S:=NextWord(Line);
  819. i:=strtointdef(s,-1);
  820. If (i<>-1) then
  821. begin
  822. H.number:=i;
  823. Result:=True;
  824. H.Aliases:='';
  825. Repeat
  826. S:=NextWord(line);
  827. If (S<>'') then
  828. If (H.Aliases='') then
  829. H.Aliases:=S
  830. else
  831. H.Aliases:=H.Aliases+','+S;
  832. until (S='');
  833. end;
  834. end;
  835. until Result or EOF(F);
  836. end;
  837. Function FindProtoEntryInProtoFile(N: String; prot: integer; Var H : TProtocolEntry) : boolean;
  838. Var
  839. F : Text;
  840. HE : TProtocolEntry;
  841. begin
  842. Result:=False;
  843. If FileExists(SProtocolFile) then
  844. begin
  845. Assign(F,SProtocolFile);
  846. {$i-}
  847. Reset(F);
  848. {$i+}
  849. If (IOResult=0) then
  850. begin
  851. While Not Result and GetNextProtoEntry(F,HE) do
  852. begin
  853. If (N<>'') then
  854. Result:=MatchNameOrAlias(N,HE.Name,HE.Aliases)
  855. else
  856. Result:=prot=he.number;
  857. end;
  858. Close(f);
  859. If Result then
  860. begin
  861. H.Name:=HE.Name;
  862. H.number:=he.number;
  863. H.Aliases:=HE.Aliases;
  864. end;
  865. end;
  866. end;
  867. end;
  868. Function GetProtocolByName(ProtoName: String; Var H : TProtocolEntry) : boolean;
  869. begin
  870. Result:=FindProtoEntryInProtoFile(ProtoName,0,H);
  871. end;
  872. Function GetProtocolByNumber(proto: Integer; Var H : TProtocolEntry) : boolean;
  873. begin
  874. Result:=FindProtoEntryInProtoFile('',Proto,H);
  875. end;
  876. { ---------------------------------------------------------------------
  877. /etc/networks handling
  878. ---------------------------------------------------------------------}
  879. function StrTonetpartial( IP : AnsiString) : in_addr ;
  880. Var
  881. Dummy : AnsiString;
  882. I,j,k : Longint;
  883. Temp : in_addr;
  884. begin
  885. strtonetpartial.s_addr:=0; //:=NoAddress;
  886. i:=0; j:=0;
  887. while (i<4) and (j=0) do
  888. begin
  889. J:=Pos('.',IP);
  890. if j=0 then j:=length(ip)+1;
  891. Dummy:=Copy(IP,1,J-1);
  892. Delete (IP,1,J);
  893. Val (Dummy,k,J);
  894. if j=0 then
  895. strtonetpartial.s_bytes[i+1]:=k;
  896. inc(i);
  897. end;
  898. if (i=0) then strtonetpartial.s_addr:=0;
  899. end;
  900. Function GetNextNetworkEntry(var F : Text; Var N : TNetworkEntry): boolean;
  901. Var
  902. NN,Line,S : String;
  903. A : TNetAddr;
  904. begin
  905. Result:=False;
  906. Repeat
  907. ReadLn(F,Line);
  908. StripComment(Line);
  909. S:=NextWord(Line);
  910. If (S<>'') then
  911. begin
  912. NN:=S;
  913. A:=StrTonetpartial(NextWord(Line));
  914. Result:=(NN<>'') and (A.s_bytes[1]<>0); // Valid addr.
  915. If result then
  916. begin
  917. N.Addr.s_addr:=A.s_addr; // keep it host.
  918. N.Name:=NN;
  919. N.Aliases:='';
  920. end;
  921. end;
  922. until Result or EOF(F);
  923. end;
  924. Function FindNetworkEntryInNetworksFile(Net: String; Addr: TNetAddr; Var N : TNetworkEntry) : boolean;
  925. Var
  926. F : Text;
  927. NE : TNetworkEntry;
  928. begin
  929. Result:=False;
  930. If FileExists(SNetworksFile) then
  931. begin
  932. Assign(F,SNetworksFile);
  933. {$i-}
  934. Reset(F);
  935. {$i+}
  936. If (IOResult=0) then
  937. begin
  938. While Not Result and GetNextNetworkEntry(F,NE) do
  939. begin
  940. If (Net<>'') then
  941. Result:=MatchNameOrAlias(Net,NE.Name,NE.Aliases)
  942. else
  943. Result:=Cardinal(Addr)=Cardinal(NE.Addr);
  944. end;
  945. Close(f);
  946. If Result then
  947. begin
  948. N.Name:=NE.Name;
  949. N.Addr:=nettohost(NE.Addr);
  950. N.Aliases:=NE.Aliases;
  951. end;
  952. end;
  953. end;
  954. end;
  955. Const NoNet : in_addr = (s_addr:0);
  956. Function GetNetworkByName(NetName: String; Var N : TNetworkEntry) : boolean;
  957. begin
  958. Result:=FindNetworkEntryInNetworksFile(NetName,NoNet,N);
  959. end;
  960. Function GetNetworkByAddr(Addr: THostAddr; Var N : TNetworkEntry) : boolean;
  961. begin
  962. Result:=FindNetworkEntryInNetworksFile('',Addr,N);
  963. end;
  964. { ---------------------------------------------------------------------
  965. /etc/services section
  966. ---------------------------------------------------------------------}
  967. Function GetNextServiceEntry(Var F : Text; Var E : TServiceEntry) : Boolean;
  968. Var
  969. Line,S : String;
  970. P : INteger;
  971. begin
  972. Result:=False;
  973. Repeat
  974. ReadLn(F,Line);
  975. StripComment(Line);
  976. S:=NextWord(Line);
  977. If (S<>'') then
  978. begin
  979. E.Name:=S;
  980. S:=NextWord(Line);
  981. P:=Pos('/',S);
  982. If (P<>0) then
  983. begin
  984. E.Port:=StrToIntDef(Copy(S,1,P-1),0);
  985. If (E.Port<>0) then
  986. begin
  987. E.Protocol:=Copy(S,P+1,Length(S)-P);
  988. Result:=length(E.Protocol)>0;
  989. E.Aliases:='';
  990. Repeat
  991. S:=NextWord(Line);
  992. If (S<>'') then
  993. If (Length(E.Aliases)=0) then
  994. E.aliases:=S
  995. else
  996. E.Aliases:=E.Aliases+','+S;
  997. until (S='');
  998. end;
  999. end;
  1000. end;
  1001. until Result or EOF(F);
  1002. end;
  1003. Function FindServiceEntryInFile(Const Name,Proto : String; Port : Integer; Var E : TServiceEntry) : Boolean;
  1004. Var
  1005. F : Text;
  1006. TE : TServiceEntry;
  1007. begin
  1008. Result:=False;
  1009. If FileExists(SServicesFile) then
  1010. begin
  1011. Assign(F,SServicesFile);
  1012. {$i-}
  1013. Reset(F);
  1014. {$i+}
  1015. If (IOResult=0) then
  1016. begin
  1017. While Not Result and GetNextServiceEntry(F,TE) do
  1018. begin
  1019. If (Port=-1) then
  1020. Result:=MatchNameOrAlias(Name,TE.Name,TE.Aliases)
  1021. else
  1022. Result:=(Port=TE.Port);
  1023. If Result and (Proto<>'') then
  1024. Result:=(Proto=TE.Protocol);
  1025. end;
  1026. Close(f);
  1027. If Result then
  1028. begin
  1029. E.Name:=TE.Name;
  1030. E.Port:=TE.Port;
  1031. E.Protocol:=TE.Protocol;
  1032. E.Aliases:=TE.Aliases;
  1033. end;
  1034. end;
  1035. end;
  1036. end;
  1037. Function GetServiceByName(Const Name,Proto : String; Var E : TServiceEntry) : Boolean;
  1038. begin
  1039. Result:=FindServiceEntryInFile(Name,Proto,-1,E);
  1040. end;
  1041. Function GetServiceByPort(Port : Word;Const Proto : String; Var E : TServiceEntry) : Boolean;
  1042. begin
  1043. Result:=FindServiceEntryInFile('',Proto,Port,E);
  1044. end;
  1045. { ---------------------------------------------------------------------
  1046. Initialization section
  1047. ---------------------------------------------------------------------}
  1048. Procedure InitResolver;
  1049. Var
  1050. I : Integer;
  1051. begin
  1052. TimeOutS :=5;
  1053. TimeOutMS:=0;
  1054. CheckResolveFileAge:=False;
  1055. If FileExists(SResolveFile) then
  1056. GetDNsservers(SResolveFile);
  1057. end;
  1058. begin
  1059. InitResolver;
  1060. end.
  1061. {
  1062. $Log$
  1063. Revision 1.17 2005-03-27 18:15:07 marco
  1064. * /etc/protocol support
  1065. Revision 1.16 2005/03/27 16:09:47 marco
  1066. * some order fixes to the hosts file functions. Also tested on OS X, but
  1067. no changes necessary on Mac.
  1068. Revision 1.15 2005/03/22 13:39:11 marco
  1069. * support for BSD style network files
  1070. Revision 1.14 2005/03/18 10:58:16 marco
  1071. * lots of endian fixes
  1072. Revision 1.12 2005/02/07 14:12:31 marco
  1073. * fixed endianess ugliness (3636)
  1074. Revision 1.11 2004/02/20 21:35:00 peter
  1075. * 1.0.x fix
  1076. Revision 1.10 2004/01/24 12:23:10 michael
  1077. + Patch from Johannes Berg
  1078. Revision 1.9 2003/12/12 20:50:18 michael
  1079. + Fixed trimming of nameserver entries
  1080. Revision 1.8 2003/11/22 23:17:50 michael
  1081. Patch for ipv6 and CNAME record support from Johannes Berg
  1082. Revision 1.7 2003/09/29 19:21:19 marco
  1083. * ; added to line 150
  1084. Revision 1.6 2003/09/29 07:44:11 michael
  1085. + Endian patch from bas [email protected]
  1086. Revision 1.5 2003/09/28 09:34:02 peter
  1087. * unix fix for 1.0.x
  1088. Revision 1.4 2003/09/18 16:30:23 marco
  1089. * unixreform fix
  1090. Revision 1.3 2003/05/17 20:54:03 michael
  1091. + uriparser unit added. Header/Footer blocks added
  1092. }