netdb.pp 33 KB

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