netdb.pp 33 KB

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