netdb.pp 36 KB

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