netdb.pp 24 KB

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