netdb.pp 28 KB

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