netdb.pp 27 KB

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