PageRenderTime 62ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/ProSnooperFx_src/indy10.0.52_source/Protocols/IdDNSServer.pas

http://github.com/lookias/ProSnooper
Pascal | 4049 lines | 3310 code | 269 blank | 470 comment | 196 complexity | 578e8e1fa30ee866d6d6ba8e0a7036dd MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 13802: IdDNSServer.pas
  11. {
  12. { Rev 1.33 2004.10.27 9:17:46 AM czhower
  13. { For TIdStrings
  14. }
  15. {
  16. { Rev 1.32 10/26/2004 9:06:32 PM JPMugaas
  17. { Updated references.
  18. }
  19. {
  20. { Rev 1.31 2004.10.26 1:06:26 PM czhower
  21. { Further fixes for aliaser
  22. }
  23. {
  24. { Rev 1.30 2004.10.26 12:01:32 PM czhower
  25. { Resolved alias conflict.
  26. }
  27. {
  28. Rev 1.29 9/15/2004 4:59:52 PM DSiders
  29. Added localization comments.
  30. }
  31. {
  32. { Rev 1.28 22/07/2004 18:14:22 ANeillans
  33. { Fixed compile error.
  34. }
  35. {
  36. { Rev 1.27 7/21/04 2:38:04 PM RLebeau
  37. { Removed redundant string copying in TIdDNS_ProcessThread constructor and
  38. { procedure QueryDomain() method
  39. {
  40. { Removed local variable from TIdDNS_ProcessThread.SendData(), not needed
  41. }
  42. {
  43. { Rev 1.26 2004/7/21 ¤U¤È 06:37:48 DChang
  44. { Fix compile error in TIdDNS_ProcessThread.SendData, and mark a case statment
  45. { to comments in TIdDNS_ProcessThread.SaveToCache.
  46. }
  47. {
  48. { Rev 1.25 2004/7/19 ¤U¤È 09:55:52 DChang
  49. { 1. Move all textmoderecords to IdDNSCommon.pas
  50. { 2.Making DNS Server load the domain definition file while DNS Server
  51. { component is active.
  52. { 3. Add a new event : OnAfterCacheSaved
  53. { 4. Add Full name condition to indicate if a domain is empty
  54. { (ConvertDNtoString)
  55. { 5. Make Query request processed with independent thread.
  56. { 6. Rewrite TIdDNSServer into multiple thread mode, all queries will search
  57. { and assemble the answer, and then share the TIdSocketHandle to send answer
  58. { back.
  59. { 7. Add version information in TIdDNSServer, so class CHAOS can be taken, but
  60. { only for the label : "version.bind.".
  61. { 8. Fix TIdRR_TXT.BinQueryRecord, to make sure it can be parsed in DNS client.
  62. { 9. Modify the AXFR function, reduce the response data size and quantity.
  63. { 10. Move all TIdTextModeResourceRecord and derived classes to IdDNSCommon.pas
  64. }
  65. {
  66. { Rev 1.24 7/8/04 11:43:54 PM RLebeau
  67. { Updated TIdDNS_TCPServer.DoConnect() to use new BytesToString() parameters
  68. }
  69. {
  70. { Rev 1.23 7/7/04 1:45:16 PM RLebeau
  71. { Compiler fixes
  72. }
  73. {
  74. { Rev 1.22 6/29/04 1:43:30 PM RLebeau
  75. { Bug fixes for various property setters
  76. }
  77. {
  78. { Rev 1.21 2004.05.20 1:39:32 PM czhower
  79. { Last of the IdStream updates
  80. }
  81. {
  82. { Rev 1.20 2004.03.01 9:37:06 PM czhower
  83. { Fixed name conflicts for .net
  84. }
  85. {
  86. { Rev 1.19 2004.02.07 5:03:32 PM czhower
  87. { .net fixes.
  88. }
  89. {
  90. { Rev 1.18 2/7/2004 5:39:44 AM JPMugaas
  91. { IdDNSServer should compile in both DotNET and WIn32.
  92. }
  93. {
  94. { Rev 1.17 2004.02.03 5:45:58 PM czhower
  95. { Name changes
  96. }
  97. {
  98. { Rev 1.16 1/22/2004 8:26:40 AM JPMugaas
  99. { Ansi* calls changed.
  100. }
  101. {
  102. { Rev 1.15 1/21/2004 2:12:48 PM JPMugaas
  103. { InitComponent
  104. }
  105. {
  106. { Rev 1.14 12/7/2003 8:07:26 PM VVassiliev
  107. { string -> TIdBytes
  108. }
  109. {
  110. { Rev 1.13 2003.10.24 10:38:24 AM czhower
  111. { UDP Server todos
  112. }
  113. {
  114. Rev 1.12 10/19/2003 12:16:30 PM DSiders
  115. Added localization comments.
  116. }
  117. {
  118. { Rev 1.11 2003.10.12 3:50:40 PM czhower
  119. { Compile todos
  120. }
  121. {
  122. { Rev 1.10 2003/5/14 ¤W¤È 01:17:36 DChang
  123. { Fix a flag named denoted in the function which check if a domain correct.
  124. { Update the logic of UpdateTree functions (make them unified).
  125. { Update the TextRecord function of all TIdRR_ classes, it checks if the RRName
  126. { the same as FullName, if RRName = FullName, it will not append the Fullname
  127. { to RRName.
  128. }
  129. {
  130. { Rev 1.9 2003/5/10 ¤W¤È 01:09:42 DChang
  131. { Patch the domainlist update when axfr action.
  132. }
  133. {
  134. { Rev 1.8 2003/5/9 ¤W¤È 10:03:36 DChang
  135. { Modify the sequence of records. To make sure when we resolve MX record, the
  136. { mail host A record can be additional record section.
  137. }
  138. {
  139. { Rev 1.7 2003/5/8 ¤U¤È 08:11:34 DChang
  140. { Add TIdDNSMap, TIdDomainNameServerMapping to monitor primary DNS, and
  141. { detecting if the primary DNS record changed, it will update automatically if
  142. { necessary.
  143. }
  144. {
  145. { Rev 1.6 2003/5/2 ¤U¤È 03:39:38 DChang
  146. { Fix all compile warnings and hints.
  147. }
  148. {
  149. { Rev 1.5 4/29/2003 08:26:30 PM DenniesChang
  150. { Fix TIdDNSServer Create, the older version miss to create the FBindings.
  151. { fix AXFR procedure, fully support BIND 8 AXFR procedures.
  152. }
  153. { Rev 1.4 4/28/2003 02:30:58 PM JPMugaas
  154. { reverted back to the old one as the new one checked will not compile, has
  155. { problametic dependancies on Contrs and Dialogs (both not permitted).
  156. }
  157. { Rev 1.3 04/28/2003 01:15:10 AM DenniesChang
  158. }
  159. {
  160. { Rev 1.2 4/28/2003 07:00:18 AM JPMugaas
  161. { Should now compile.
  162. }
  163. {
  164. { Rev 1.0 11/14/2002 02:18:42 PM JPMugaas
  165. }
  166. {
  167. // Ver: 2003-04-28-0115
  168. // Combine TCP, UDP Tunnel into single TIdDNSServer component.
  169. // Update TIdDNSServer from TIdUDPServer to TComponent.
  170. // Ver: 2003-04-26-1810
  171. // Add AXFR command.
  172. // Ver: 2002-10-30-1253
  173. // Add TIdRR_AAAA class, RFC 1884 (Ipv6 AAAA)
  174. // and add the coresponding fix in TIdDNSServer, but left
  175. // external search option for future.
  176. // Ver: 2002-07-10-1610
  177. // Add a new event : OnAfterSendBack to handle all
  178. // data logged after query result is sent back to
  179. // the client.
  180. // Ver: 2002-05-27-0910
  181. // Add a check function in SOA loading function.
  182. // Ver: 2002-04-25-1530
  183. // IdDNSServer. Ver: 2002-03-12-0900
  184. // To-do: RFC 2136 Zone transfer must be implemented.
  185. // Add FindHandedNodeByName to pass the TIdDNTreeNode Object back.
  186. // Append a blank char when ClearQuota, to avoid the possible of
  187. // losting a field.
  188. // Add IdDNTree.SaveToFile
  189. // Fix SOA RRName assignment.
  190. // Fix PTRName RRName assignment.
  191. // Fix TIdDNTreeNode RemoveChild
  192. // IdDNSServer. Ver: 2002-02-26-1420
  193. // Convert the DN Tree Node type, earlier verison just
  194. // store the A, PTR in the upper domain node, current
  195. // version save SOA and its subdomain in upper node.
  196. //
  197. // Moreover, move Cached_Tree, Handed_Tree to public
  198. // section, for using convinent.
  199. //
  200. // I forget return CName data, fixed.
  201. // Seperate the seaching of Cache and handled tree into 2
  202. // parts with a flag.
  203. //IdDNSServer. Ver: 2002-02-24-1715
  204. // Move TIdDNSServer protected property RootDNS_NET to public
  205. //IdDNSServer. Ver: 2002-02-23-1800
  206. Original Programmer: Dennies Chang <dennies@ms4.hinet.net>
  207. No Copyright. Code is given to the Indy Pit Crew.
  208. This DNS Server supports only IN record, but not Chaos system.
  209. Most of resource records in DNS server was stored with text mode,
  210. event the TREE structure, it's just for convininet.
  211. Why I did it with this way is tring to increase the speed for
  212. implementation, with Delphi/Kylix internal class and object,
  213. we can promise the compatible in Windows and Linux.
  214. Started: Jan. 20, 2002.
  215. First Finished: Feb. 23, 2002.
  216. RFC 1035 WKS record is not implemented.
  217. ToDO: Load Master File automaticlly when DNS Server Active.
  218. ToDO: patch WKS record data type.
  219. ToDO: prepare a Tree Editor for DNS Server Construction. (optional)
  220. }
  221. unit IdDNSServer;
  222. interface
  223. uses
  224. Classes,
  225. IdContainers,
  226. SysUtils,
  227. IdAssignedNumbers,
  228. IdSocketHandle,
  229. IdIOHandlerSocket,
  230. IdGlobal,
  231. IdGlobalProtocols,
  232. IdBaseComponent,
  233. IdComponent,
  234. IdContext,
  235. IdUDPBase, IdResourceStrings,
  236. IdExceptionCore,
  237. IdDNSResolver,
  238. IdUDPServer,
  239. IdTCPServer,
  240. IdThread,
  241. IdDNSCommon,
  242. IdTStrings;
  243. type
  244. TIdDomainExpireCheckThread = class (TIdThread)
  245. protected
  246. FInterval: Cardinal;
  247. FSender: TObject;
  248. FTimerEvent: TNotifyEvent;
  249. FBusy : boolean;
  250. FDomain : string;
  251. FHost : string;
  252. //
  253. procedure Run; override;
  254. procedure TimerEvent;
  255. end;
  256. // forward declaration.
  257. TIdDNSMap = class;
  258. TIdDNS_UDPServer = class;
  259. // This class is to record the mapping of Domain and its primary DNS IP
  260. TIdDomainNameServerMapping = class (TObject)
  261. private
  262. FHost: string;
  263. FDomainName: string;
  264. FBusy : boolean;
  265. FInterval: Cardinal;
  266. FList: TIdDNSMap;
  267. procedure SetHost(const Value: string);
  268. procedure SetInterval(const Value: Cardinal);
  269. protected
  270. CheckScheduler : TIdDomainExpireCheckThread;
  271. property Interval : Cardinal read FInterval write SetInterval;
  272. property List : TIdDNSMap read FList write FList;
  273. public
  274. constructor Create(List :TIdDNSMap);
  275. destructor Destroy; override;
  276. published
  277. procedure SyncAndUpdate (Sender : TObject);
  278. property Host : string read FHost write SetHost;
  279. property DomainName : string read FDomainName write FDomainName;
  280. end;
  281. TIdDNSMap = class (TIdObjectList)
  282. private
  283. FServer: TIdDNS_UDPServer;
  284. function GetItem(Index: Integer): TIdDomainNameServerMapping;
  285. procedure SetItem(Index: Integer;
  286. const Value: TIdDomainNameServerMapping);
  287. procedure SetServer(const Value: TIdDNS_UDPServer);
  288. public
  289. constructor Create(Server: TIdDNS_UDPServer);
  290. destructor Destroy; override;
  291. property Server : TIdDNS_UDPServer read FServer write SetServer;
  292. property Items[Index: Integer]: TIdDomainNameServerMapping read GetItem write SetItem; default;
  293. end;
  294. TIdMWayTreeNodeClass = class of TIdMWayTreeNode;
  295. TIdMWayTreeNode = class (TObject)
  296. private
  297. SubTree : TIdObjectList;
  298. FFundmentalClass: TIdMWayTreeNodeClass;
  299. function GetTreeNode(Index: integer): TIdMWayTreeNode;
  300. procedure SetFundmentalClass(const Value: TIdMWayTreeNodeClass);
  301. procedure SetTreeNode(Index: integer; const Value: TIdMWayTreeNode);
  302. public
  303. constructor Create(NodeClass : TIdMWayTreeNodeClass); virtual;
  304. destructor Destroy; override;
  305. property FundmentalClass : TIdMWayTreeNodeClass read FFundmentalClass write SetFundmentalClass;
  306. property Children[Index : integer] : TIdMWayTreeNode read GetTreeNode write SetTreeNode;
  307. function AddChild : TIdMWayTreeNode;
  308. function InsertChild(Index : integer) : TIdMWayTreeNode;
  309. procedure RemoveChild(Index : integer);
  310. end;
  311. TIdDNTreeNode = class (TIdMWayTreeNode)
  312. private
  313. FCLabel : AnsiString;
  314. FRRs: TIdTextModeRRs;
  315. FChildIndex: TStrings;
  316. FParentNode: TIdDNTreeNode;
  317. FAutoSortChild: boolean;
  318. procedure SetCLabel(const Value: AnsiString);
  319. procedure SetRRs(const Value: TIdTextModeRRs);
  320. function GetNode(Index: integer): TIdDNTreeNode;
  321. procedure SetNode(Index: integer; const Value: TIdDNTreeNode);
  322. procedure SetChildIndex(const Value: TStrings);
  323. function GetFullName: string;
  324. function ConvertToDNString : string;
  325. function DumpAllBinaryData(var RecordCount:integer) : TIdBytes;
  326. public
  327. property ParentNode : TIdDNTreeNode read FParentNode write FParentNode;
  328. property CLabel : AnsiString read FCLabel write SetCLabel;
  329. property RRs : TIdTextModeRRs read FRRs write SetRRs;
  330. property Children[Index : integer] : TIdDNTreeNode read GetNode write SetNode;
  331. property ChildIndex : TStrings read FChildIndex write SetChildIndex;
  332. property AutoSortChild : boolean read FAutoSortChild write FAutoSortChild;
  333. property FullName : string read GetFullName;
  334. constructor Create(ParentNode : TIdDNTreeNode); reintroduce;
  335. destructor Destroy; override;
  336. function AddChild : TIdDNTreeNode;
  337. function InsertChild(Index : integer) : TIdDNTreeNode;
  338. procedure RemoveChild(Index : integer);
  339. procedure SortChildren;
  340. procedure Clear;
  341. procedure SaveToFile(Filename : TFilename);
  342. function IndexByLabel(CLabel : AnsiString): integer;
  343. function IndexByNode(ANode : TIdDNTreeNode) : integer;
  344. end;
  345. TIdDNS_TCPServer = class (TIdTCPServer)
  346. protected
  347. FAccessList: TIdStrings;
  348. FAccessControl: boolean;
  349. //
  350. procedure DoConnect(AThread: TIdContext); override;
  351. procedure InitComponent; override;
  352. procedure SetAccessList(const Value: TIdStrings);
  353. public
  354. destructor Destroy; override;
  355. published
  356. property AccessList : TIdStrings read FAccessList write SetAccessList;
  357. property AccessControl : boolean read FAccessControl write FAccessControl;
  358. end;
  359. TIdDNS_ProcessThread = class (TIdThread)
  360. protected
  361. FMyBinding: TIdSocketHandle;
  362. FMainBinding: TIdSocketHandle;
  363. FMyData: TStream;
  364. FData : string;
  365. FDataSize : integer;
  366. FServer: TIdDNS_UDPServer;
  367. procedure SetMyBinding(const Value: TIdSocketHandle);
  368. procedure SetMyData(const Value: TStream);
  369. procedure SetServer(const Value: TIdDNS_UDPServer);
  370. procedure ComposeErrorResult(var Final: TIdBytes;
  371. OriginalHeader: TDNSHeader; OriginalQuestion : TIdBytes;
  372. ErrorStatus: integer);
  373. function CombineAnswer(Header : TDNSHeader; EQuery, Answer : TIdBytes): TIdBytes;
  374. procedure InternalSearch(Header: TDNSHeader; QName: string; QType: Word;
  375. var Answer: TIdBytes; IfMainQuestion: boolean; IsSearchCache: boolean = false;
  376. IsAdditional: boolean = false; IsWildCard : boolean = false;
  377. WildCardOrgName: string = '');
  378. procedure ExternalSearch(aDNSResolver: TIdDNSResolver; Header: TDNSHeader;
  379. Question: TIdBytes; var Answer: TIdBytes);
  380. function CompleteQuery(DNSHeader: TDNSHeader; Question: string;
  381. OriginalQuestion: TIdBytes; var Answer : TIdBytes; QType, QClass : word;
  382. DNSResolver : TIdDNSResolver) : string;
  383. procedure SaveToCache(ResourceRecord : string; QueryName : string; OriginalQType : Word);
  384. function SearchTree(Root : TIdDNTreeNode; QName : String; QType : Word): TIdDNTreeNode;
  385. procedure Run; override;
  386. procedure QueryDomain;
  387. procedure SendData;
  388. public
  389. property MyBinding : TIdSocketHandle read FMyBinding write SetMyBinding;
  390. property MyData: TStream read FMyData write SetMyData;
  391. property Server : TIdDNS_UDPServer read FServer write SetServer;
  392. constructor Create(ACreateSuspended: Boolean = True;
  393. Data : String = ''; DataSize : integer = 0;
  394. MainBinding : TIdSocketHandle = nil;
  395. Binding : TIdSocketHandle = nil;
  396. Server : TIdDNS_UDPServer = nil); reintroduce; overload;
  397. destructor Destroy; override;
  398. end;
  399. TIdDNSBeforeQueryEvent = procedure(ABinding: TIdSocketHandle;
  400. ADNSHeader: TDNSHeader; var ADNSQuery: string) of object;
  401. TIdDNSAfterQueryEvent = procedure(ABinding: TIdSocketHandle;
  402. ADNSHeader: TDNSHeader; var QueryResult: string; ResultCode: string;
  403. Query : string) of object;
  404. TIdDNSAfterCacheSaved = procedure(CacheRoot : TIdDNTreeNode) of object;
  405. TIdDNS_UDPServer = class (TIdUDPServer)
  406. private
  407. FBusy: boolean;
  408. protected
  409. FAutoUpdateZoneInfo: boolean;
  410. FZoneMasterFiles: TIdStrings;
  411. FRootDNS_NET: TIdStrings;
  412. FCacheUnknowZone: boolean;
  413. FCached_Tree: TIdDNTreeNode;
  414. FHanded_Tree: TIdDNTreeNode;
  415. FHanded_DomainList: TIdStrings;
  416. FAutoLoadMasterFile: Boolean;
  417. FOnAfterQuery: TIdDNSAfterQueryEvent;
  418. FOnBeforeQuery: TIdDNSBeforeQueryEvent;
  419. FCS: TIdCriticalSection;
  420. FOnAfterSendBack: TIdDNSAfterQueryEvent;
  421. FOnAfterCacheSaved: TIdDNSAfterCacheSaved;
  422. FGlobalCS: TIdCriticalSection;
  423. FDNSVersion: string;
  424. FofferDNSVersion: boolean;
  425. procedure DoBeforeQuery(ABinding: TIdSocketHandle;
  426. ADNSHeader: TDNSHeader; var ADNSQuery : String); dynamic;
  427. procedure DoAfterQuery(ABinding: TIdSocketHandle;
  428. ADNSHeader: TDNSHeader; var QueryResult : String;
  429. ResultCode : String; Query : string); dynamic;
  430. procedure DoAfterSendBack(ABinding: TIdSocketHandle;
  431. ADNSHeader: TDNSHeader; var QueryResult : String;
  432. ResultCode : String; Query : string); dynamic;
  433. procedure DoAfterCacheSaved(CacheRoot : TIdDNTreeNode); dynamic;
  434. procedure SetZoneMasterFiles(const Value: TIdStrings);
  435. procedure SetRootDNS_NET(const Value: TIdStrings);
  436. procedure SetHanded_DomainList(const Value: TIdStrings);
  437. procedure InternalSearch(Header: TDNSHeader; QName: string; QType: Word;
  438. var Answer: TIdBytes; IfMainQuestion: boolean; IsSearchCache: boolean = false;
  439. IsAdditional: boolean = false; IsWildCard : boolean = false;
  440. WildCardOrgName: string = '');
  441. procedure ExternalSearch(aDNSResolver: TIdDNSResolver; Header: TDNSHeader;
  442. Question: TIdBytes; var Answer: TIdBytes);
  443. //modified in May 2004 by Dennies Chang.
  444. //procedure SaveToCache(ResourceRecord : string);
  445. procedure SaveToCache(ResourceRecord : string; QueryName : string; OriginalQType : Word);
  446. procedure UpdateTree(TreeRoot : TIdDNTreeNode; RR : TResultRecord); overload;
  447. procedure InitComponent; override;
  448. // Hide this property temporily, this property is prepared to maintain the
  449. // TTL expired record auto updated;
  450. property AutoUpdateZoneInfo : boolean read FAutoUpdateZoneInfo write FAutoUpdateZoneInfo;
  451. property CS: TIdCriticalSection read FCS;
  452. public
  453. destructor Destroy; override;
  454. function AXFR(Header : TDNSHeader; Question : string; var Answer :TIdBytes) : string;
  455. function CompleteQuery(DNSHeader: TDNSHeader; Question: string;
  456. OriginalQuestion: TIdBytes; var Answer : TIdBytes; QType, QClass : word;
  457. DNSResolver : TIdDNSResolver) : string;
  458. function LoadZoneFromMasterFile(MasterFileName : TFileName) : boolean;
  459. function LoadZoneStrings(FileStrings: TIdStrings; Filename : TFilename;
  460. TreeRoot : TIdDNTreeNode): boolean;
  461. function SearchTree(Root : TIdDNTreeNode; QName : String; QType : Word): TIdDNTreeNode;
  462. procedure UpdateTree(TreeRoot : TIdDNTreeNode; RR : TIdTextModeResourceRecord); overload;
  463. function FindNodeFullName(Root : TIdDNTreeNode; QName : String; QType : Word) : string;
  464. function FindHandedNodeByName(QName : String; QType : Word) : TIdDNTreeNode;
  465. //procedure DoUDPRead(AData: TStream; ABinding: TIdSocketHandle); override;
  466. property RootDNS_NET : TIdStrings read FRootDNS_NET write SetRootDNS_NET;
  467. property Cached_Tree : TIdDNTreeNode read FCached_Tree {write SetCached_Tree};
  468. property Handed_Tree : TIdDNTreeNode read FHanded_Tree {write SetHanded_Tree};
  469. property Busy : boolean read FBusy;
  470. property GlobalCS : TIdCriticalSection read FGlobalCS;
  471. published
  472. property DefaultPort default IdPORT_DOMAIN;
  473. property AutoLoadMasterFile : Boolean read FAutoLoadMasterFile write FAutoLoadMasterFile Default False;
  474. //property AutoUpdateZoneInfo : boolean read FAutoUpdateZoneInfo write SetAutoUpdateZoneInfo;
  475. property ZoneMasterFiles : TIdStrings read FZoneMasterFiles write SetZoneMasterFiles;
  476. property CacheUnknowZone : boolean read FCacheUnknowZone write FCacheUnknowZone default False;
  477. property Handed_DomainList : TIdStrings read FHanded_DomainList write SetHanded_DomainList;
  478. property DNSVersion : string read FDNSVersion write FDNSVersion;
  479. property offerDNSVersion : boolean read FofferDNSVersion write FofferDNSVersion;
  480. property OnBeforeQuery : TIdDNSBeforeQueryEvent read FOnBeforeQuery write FOnBeforeQuery;
  481. property OnAfterQuery :TIdDNSAfterQueryEvent read FOnAfterQuery write FOnAfterQuery;
  482. property OnAfterSendBack :TIdDNSAfterQueryEvent read FOnAfterSendBack write FOnAfterSendBack;
  483. property OnAfterCacheSaved : TIdDNSAfterCacheSaved read FOnAfterCacheSaved write FOnAfterCacheSaved;
  484. end;
  485. TIdDNSServer = class (TIdComponent)
  486. protected
  487. FActive: boolean;
  488. FTCPACLActive: boolean;
  489. FServerType: TDNSServerTypes;
  490. FTCPTunnel: TIdDNS_TCPServer;
  491. FUDPTunnel: TIdDNS_UDPServer;
  492. FAccessList: TIdStrings;
  493. FBindings: TIdSocketHandles;
  494. procedure SetAccessList(const Value: TIdStrings);
  495. procedure SetActive(const Value: boolean);
  496. procedure SetTCPACLActive(const Value: boolean);
  497. procedure SetBindings(const Value: TIdSocketHandles);
  498. procedure TimeToUpdateNodeData(Sender : TObject);
  499. procedure InitComponent; override;
  500. public
  501. BackupDNSMap : TIdDNSMap;
  502. destructor Destroy; override;
  503. procedure CheckIfExpire(Sender: TObject);
  504. published
  505. property Active : boolean read FActive write SetActive;
  506. property AccessList : TIdStrings read FAccessList write SetAccessList;
  507. property Bindings: TIdSocketHandles read FBindings write SetBindings;
  508. property TCPACLActive : boolean read FTCPACLActive write SetTCPACLActive;
  509. property ServerType: TDNSServerTypes read FServerType write FServerType;
  510. property TCPTunnel : TIdDNS_TCPServer read FTCPTunnel write FTCPTunnel;
  511. property UDPTunnel : TIdDNS_UDPServer read FUDPTunnel write FUDPTunnel;
  512. end;
  513. // CompareItems is to compare TIdDNTreeNode
  514. function CompareItems(Item1, Item2: TObject): Integer;
  515. function FetchBytes(var AInput: TIdBytes; const ADelim: TIdBytes;
  516. const ADelete: Boolean = IdFetchDeleteDefault): TIdBytes;
  517. function PosBytes(const SubBytes, SBytes: TIdBytes): integer;
  518. function SameArray(const B1, B2: TIdBytes): boolean;
  519. implementation
  520. uses
  521. IdIOHandler, IdStack;
  522. {Common Utilities}
  523. function CompareItems(Item1, Item2: TObject): Integer;
  524. var LObj1, LObj2 : TIdDNTreeNode;
  525. begin
  526. LObj1 := Item1 as TIdDNTreeNode;
  527. LObj2 := Item2 as TIdDNTreeNode;
  528. Result := CompareText((LObj1 as TIdDNTreeNode).CLabel, (LObj2 as TIdDNTreeNode).CLabel);
  529. end;
  530. function SameArray(const B1, B2: TIdBytes): boolean;
  531. var
  532. i, l1: integer;
  533. begin
  534. Result := False;
  535. l1 := Length(B1);
  536. if l1 <> Length(B2) then
  537. Exit; //Different length
  538. for i := 0 to l1 - 1 do
  539. begin
  540. if B1[i] <> B2[i] then
  541. Exit;
  542. end;
  543. Result := True;
  544. end;
  545. function PosBytes(const SubBytes, SBytes: TIdBytes): integer;
  546. var
  547. i, l: integer;
  548. begin
  549. Result := -1;
  550. l := Length(SubBytes);
  551. for i := 0 to Length(SBytes) - l do
  552. begin
  553. if SameArray(SubBytes, copy(SBytes, i, l)) then
  554. begin
  555. Result := i;
  556. Exit;
  557. end;
  558. end;
  559. end;
  560. function FetchBytes(var AInput: TIdBytes; const ADelim: TIdBytes;
  561. const ADelete: Boolean = IdFetchDeleteDefault): TIdBytes;
  562. var
  563. LPos: integer;
  564. begin
  565. LPos := PosBytes(ADelim, AInput);
  566. if LPos = -1 then begin
  567. Result := AInput;
  568. if ADelete then begin
  569. SetLength(AInput, 0);
  570. end;
  571. end
  572. else begin
  573. Result := Copy(AInput, 0, LPos);
  574. if ADelete then begin
  575. //slower Delete(AInput, 1, LPos + Length(ADelim) - 1);
  576. AInput:=Copy(AInput, LPos + Length(ADelim), MaxInt);
  577. end;
  578. end;
  579. end;
  580. { TIdMWayTreeNode }
  581. function TIdMWayTreeNode.AddChild: TIdMWayTreeNode;
  582. begin
  583. Result := Self.FundmentalClass.Create(FundmentalClass);
  584. Self.SubTree.Add(Result);
  585. end;
  586. constructor TIdMWayTreeNode.Create(NodeClass : TIdMWayTreeNodeClass);
  587. begin
  588. inherited Create;
  589. Self.FundmentalClass := NodeClass;
  590. Self.SubTree := TIdObjectList.Create;
  591. end;
  592. destructor TIdMWayTreeNode.Destroy;
  593. begin
  594. SubTree.Free;
  595. inherited;
  596. end;
  597. function TIdMWayTreeNode.GetTreeNode(Index: integer): TIdMWayTreeNode;
  598. begin
  599. Result := TIdMWayTreeNode(Self.SubTree.Items[Index]);
  600. end;
  601. function TIdMWayTreeNode.InsertChild(Index: integer): TIdMWayTreeNode;
  602. begin
  603. Result := Self.FundmentalClass.Create(FundmentalClass);
  604. Self.SubTree.Insert(Index, Result);
  605. end;
  606. procedure TIdMWayTreeNode.RemoveChild(Index: integer);
  607. begin
  608. Self.SubTree.Remove(SubTree.Items[Index]);
  609. end;
  610. procedure TIdMWayTreeNode.SetFundmentalClass(
  611. const Value: TIdMWayTreeNodeClass);
  612. begin
  613. FFundmentalClass := Value;
  614. end;
  615. procedure TIdMWayTreeNode.SetTreeNode(Index: integer;
  616. const Value: TIdMWayTreeNode);
  617. begin
  618. Self.SubTree.Items[Index] := Value;
  619. end;
  620. { TIdDNTreeNode }
  621. function TIdDNTreeNode.AddChild: TIdDNTreeNode;
  622. begin
  623. Result := TIdDNTreeNode.Create(Self);
  624. Self.SubTree.Add(Result);
  625. end;
  626. procedure TIdDNTreeNode.Clear;
  627. var
  628. Stop, Start : integer;
  629. begin
  630. Start := Self.SubTree.Count - 1;
  631. for Stop := Start downto 0 do begin
  632. Self.RemoveChild(Stop);
  633. end;
  634. end;
  635. function TIdDNTreeNode.ConvertToDNString: string;
  636. var
  637. Count : integer;
  638. MyString, ChildString : string;
  639. begin
  640. ChildString := '';
  641. MyString := '';
  642. MyString := '$ORIGIN ' + Self.FullName + #13+#10; {do not localize}
  643. for Count := 0 to Self.RRs.Count -1 do begin
  644. MyString := MyString + Self.RRs.Items[Count].TextRecord(Self.FullName);
  645. end;
  646. for Count := 0 to Self.FChildIndex.Count -1 do begin
  647. ChildString := ChildString + Self.Children[Count].ConvertToDNString;
  648. end;
  649. Result := MyString + ChildString;
  650. end;
  651. constructor TIdDNTreeNode.Create(ParentNode : TIdDNTreeNode);
  652. begin
  653. Inherited Create(TIdDNTreeNode);
  654. Self.FRRs := TIdTextModeRRs.Create;
  655. Self.FChildIndex := TIdStringList.Create;
  656. Self.ParentNode := ParentNode;
  657. end;
  658. destructor TIdDNTreeNode.Destroy;
  659. begin
  660. Self.FRRs.Free;
  661. Self.FChildIndex.Free;
  662. inherited;
  663. end;
  664. function TIdDNTreeNode.DumpAllBinaryData(var RecordCount:integer): TIdBytes;
  665. var
  666. Count, ChildCount : integer;
  667. MyString, ChildString : TIdBytes;
  668. begin
  669. SetLength(ChildString, 0);
  670. SetLength(MyString, 0);
  671. RecordCount := RecordCount + Self.RRs.Count + 1;
  672. for Count := 0 to Self.RRs.Count -1 do
  673. begin
  674. AppendBytes(MyString, Self.RRs.Items[Count].BinQueryRecord(Self.FullName));
  675. end;
  676. for Count := 0 to Self.FChildIndex.Count -1 do
  677. begin
  678. AppendBytes(ChildString, Self.Children[Count].DumpAllBinaryData(ChildCount));
  679. RecordCount := RecordCount + ChildCount;
  680. end;
  681. if Self.RRs.Count > 0 then
  682. begin
  683. if (Self.RRs.Items[0] is TIdRR_SOA) then
  684. begin
  685. RecordCount := RecordCount + 1;
  686. AppendBytes(MyString, Self.RRs.Items[0].BinQueryRecord(Self.FullName));
  687. end;
  688. end;
  689. Result := MyString;
  690. AppendBytes(Result, ChildString);
  691. AppendBytes(Result, Self.RRs.Items[0].BinQueryRecord(Self.FullName));
  692. end;
  693. function TIdDNTreeNode.GetFullName: string;
  694. begin
  695. if Self.ParentNode = nil then
  696. if Self.CLabel = '.' then
  697. Result := ''
  698. else
  699. Result := Self.CLabel
  700. else
  701. Result := Self.CLabel + '.' +Self.ParentNode.FullName;
  702. end;
  703. function TIdDNTreeNode.GetNode(Index: integer): TIdDNTreeNode;
  704. begin
  705. Result := TIdDNTreeNode(Self.SubTree.Items[Index]);
  706. end;
  707. function TIdDNTreeNode.IndexByLabel(CLabel: AnsiString): integer;
  708. begin
  709. Result := Self.FChildIndex.IndexOf(CLabel);
  710. end;
  711. function TIdDNTreeNode.IndexByNode(ANode: TIdDNTreeNode): integer;
  712. begin
  713. Result := Self.SubTree.IndexOf(ANode);
  714. end;
  715. function TIdDNTreeNode.InsertChild(Index: integer): TIdDNTreeNode;
  716. begin
  717. Result := TIdDNTreeNode.Create(Self);
  718. Self.SubTree.Insert(Index, Result);
  719. end;
  720. procedure TIdDNTreeNode.RemoveChild(Index: integer);
  721. begin
  722. Self.SubTree.Remove(Self.SubTree.Items[Index]);
  723. Self.FChildIndex.Delete(Index);
  724. end;
  725. procedure TIdDNTreeNode.SaveToFile(Filename: TFilename);
  726. var
  727. DNSs : TIdStrings;
  728. begin
  729. DNSs := TIdStringList.Create;
  730. try
  731. DNSs.Add(Self.ConvertToDNString);
  732. DNSs.SaveToFile(Filename);
  733. finally
  734. DNSs.Free;
  735. end;
  736. end;
  737. procedure TIdDNTreeNode.SetChildIndex(const Value: TStrings);
  738. begin
  739. Self.FChildIndex.Assign(Value);
  740. end;
  741. procedure TIdDNTreeNode.SetCLabel(const Value: AnsiString);
  742. begin
  743. FCLabel := Value;
  744. if Self.ParentNode <> nil then
  745. Self.ParentNode.ChildIndex.Insert(ParentNode.SubTree.IndexOf(Self), Value);
  746. if Self.AutoSortChild then Self.SortChildren;
  747. end;
  748. procedure TIdDNTreeNode.SetNode(Index: integer;
  749. const Value: TIdDNTreeNode);
  750. begin
  751. Self.SubTree.Items[Index] := Value;
  752. end;
  753. procedure TIdDNTreeNode.SetRRs(const Value: TIdTextModeRRs);
  754. begin
  755. FRRs.Assign(Value);
  756. end;
  757. procedure TIdDNTreeNode.SortChildren;
  758. begin
  759. Self.SubTree.BubbleSort(CompareItems);
  760. TStringList(Self.FChildIndex).Sort;
  761. end;
  762. { TIdDNSServer }
  763. function TIdDNS_UDPServer.CompleteQuery(DNSHeader : TDNSHeader; Question: string;
  764. OriginalQuestion: TIdBytes; var Answer: TIdBytes; QType, QClass: word;
  765. DNSResolver : TIdDNSResolver): string;
  766. var
  767. IsMyDomains : boolean;
  768. lAnswer: TIdBytes;
  769. WildQuestion, TempDomain : string;
  770. begin
  771. // QClass = 1 => IN, we support only "IN" class now.
  772. // QClass = 2 => CS,
  773. // QClass = 3 => CH,
  774. // QClass = 4 => HS.
  775. TempDomain := IndyLowerCase(Question);
  776. IsMyDomains := (Self.Handed_DomainList.IndexOf(TempDomain) > -1);
  777. if not IsMyDomains then
  778. begin
  779. Fetch(TempDomain, '.');
  780. end;
  781. IsMyDomains := (Self.Handed_DomainList.IndexOf(TempDomain) > -1);
  782. if (QClass = 1) then begin
  783. if IsMyDomains then begin
  784. Self.InternalSearch(DNSHeader, Question, QType, lAnswer, True, False, False);
  785. Answer := lAnswer;
  786. if ((QType = TypeCode_A) or (QType = TypeCode_AAAA)) and
  787. (Length(Answer) = 0) then begin
  788. Self.InternalSearch(DNSHeader, Question, TypeCode_CNAME, lAnswer, True, False, True);
  789. AppendBytes(Answer, lAnswer);
  790. end;
  791. //if lAnswer = '' then begin
  792. WildQuestion := Question;
  793. fetch(WildQuestion, '.');
  794. WildQuestion := '*.' + WildQuestion;
  795. Self.InternalSearch(DNSHeader, WildQuestion, QType, lAnswer, True, False, False, true, Question);
  796. AppendBytes(Answer, lAnswer);
  797. //end;
  798. if Length(Answer) > 0 then
  799. Result := cRCodeQueryOK
  800. else Result := cRCodeQueryNotFound;
  801. end else begin
  802. Self.InternalSearch(DNSHeader, Question, QType, Answer, True, True, False);
  803. if ((QType = TypeCode_A) or (QType = TypeCode_AAAA)) and
  804. (Length(Answer) = 0) then begin
  805. Self.InternalSearch(DNSHeader, Question, TypeCode_CNAME, lAnswer, True, True, False);
  806. AppendBytes(Answer, lAnswer);
  807. end;
  808. if Length(Answer) > 0 then
  809. Result := cRCodeQueryCacheOK
  810. else begin
  811. QType := TypeCode_Error;
  812. Self.InternalSearch(DNSHeader, Question, QType, Answer, True, True, False);
  813. if BytesToString(Answer) = 'Error' then begin {do not localize}
  814. Result := cRCodeQueryCacheFindError;
  815. end else begin
  816. Self.ExternalSearch(DNSResolver, DNSHeader, OriginalQuestion, Answer);
  817. if Length(Answer) > 0 then
  818. Result := cRCodeQueryReturned
  819. else Result := cRCodeQueryNotImplement;
  820. end;
  821. end;
  822. end
  823. end else begin
  824. Result := cRCodeQueryNotImplement;
  825. end;
  826. end;
  827. procedure TIdDNS_UDPServer.InitComponent;
  828. begin
  829. inherited;
  830. Self.FRootDNS_NET := TIdStringList.Create;
  831. Self.FRootDNS_NET.Add('209.92.33.150'); // nic.net {do not localize}
  832. Self.FRootDNS_NET.Add('209.92.33.130'); // nic.net {do not localize}
  833. Self.FRootDNS_NET.Add('203.37.255.97'); // apnic.net {do not localize}
  834. Self.FRootDNS_NET.Add('202.12.29.131'); // apnic.net {do not localize}
  835. Self.FRootDNS_NET.Add('12.29.20.2'); // nanic.net {do not localize}
  836. Self.FRootDNS_NET.Add('204.145.119.2'); // nanic.net {do not localize}
  837. Self.FRootDNS_NET.Add('140.111.1.2'); // a.twnic.net.tw {do not localize}
  838. Self.FCached_Tree := TIdDNTreeNode.Create(nil);
  839. Self.FCached_Tree.AutoSortChild := True;
  840. Self.FCached_Tree.CLabel := '.';
  841. Self.FHanded_Tree := TIdDNTreeNode.Create(nil);
  842. Self.FHanded_Tree.AutoSortChild := True;
  843. Self.FHanded_Tree.CLabel := '.';
  844. Self.FHanded_DomainList := TIdStringList.Create;
  845. Self.FZoneMasterFiles := TIdStringList.Create;
  846. DefaultPort := IdPORT_DOMAIN;
  847. Self.FCS := TIdCriticalSection.Create;
  848. Self.FGlobalCS := TIdCriticalSection.Create;
  849. Self.FBusy := False;
  850. end;
  851. destructor TIdDNS_UDPServer.Destroy;
  852. begin
  853. Self.FCached_Tree.Free;
  854. Self.FHanded_Tree.Free;
  855. Self.FRootDNS_NET.Free;
  856. Self.FHanded_DomainList.Free;
  857. Self.FZoneMasterFiles.Free;
  858. Self.FCS.Free;
  859. Self.FGlobalCS.Free;
  860. inherited;
  861. end;
  862. procedure TIdDNS_UDPServer.DoAfterQuery(ABinding: TIdSocketHandle;
  863. ADNSHeader: TDNSHeader; var QueryResult: String; ResultCode : String;
  864. Query : string);
  865. begin
  866. if Assigned(FOnAfterQuery) then begin
  867. FOnAfterQuery(ABinding, ADNSHeader, QueryResult, ResultCode, Query);
  868. end;
  869. end;
  870. procedure TIdDNS_UDPServer.DoBeforeQuery(ABinding: TIdSocketHandle;
  871. ADNSHeader: TDNSHeader; var ADNSQuery: String);
  872. begin
  873. if Assigned(FOnBeforeQuery) then begin
  874. FOnBeforeQuery(ABinding, ADNSHeader, ADNSQuery);
  875. end;
  876. end;
  877. (*procedure TIdDNS_UDPServer.DoUDPRead(AData: TStream;
  878. ABinding: TIdSocketHandle);
  879. var
  880. ExternalQuery, QName, QLabel, Answer, RString, FinalResult : string;
  881. DNSHeader_Processing : TDNSHeader;
  882. QType, QClass : Word;
  883. QPos, QLength, LLength : integer;
  884. DNSResolver : TIdDNSResolver;
  885. begin
  886. inherited DoUDPRead(AData, ABinding);
  887. //Self.CS.Acquire;
  888. SetLength(ExternalQuery, AData.Size);
  889. AData.Read(ExternalQuery[1], AData.Size);
  890. FinalResult := '';
  891. if AData.Size >= 12 then begin
  892. DNSHeader_Processing := TDNSHeader.Create;
  893. DNSResolver := TIdDNSResolver.Create(Self);
  894. DNSResolver.WaitingTime := 10000;
  895. try
  896. if DNSHeader_Processing.ParseQuery(ExternalQuery) <> 0 then begin
  897. //FinalResult := ComposeErrorResult
  898. DoAfterQuery(ABinding, DNSHeader_Processing, FinalResult, RString, ExternalQuery)
  899. end else begin
  900. if DNSHeader_Processing.QDCount > 0 then begin
  901. QPos := 13;
  902. QLength := Length(ExternalQuery);
  903. if (QLength > 12) then begin
  904. QName := '';
  905. repeat
  906. Answer := '';
  907. LLength := Byte(ExternalQuery[QPos]);
  908. Inc(QPos);
  909. QLabel := Copy(ExternalQuery, QPos, LLength);
  910. Inc(QPos, LLength);
  911. if QName <> '' then
  912. QName := QName + QLabel + '.'
  913. else
  914. QName := QLabel + '.';
  915. until ((QPos >= QLength) or (ExternalQuery[QPos] = #0));
  916. //HD_QDPos := QPos;
  917. Inc(QPos);
  918. QType := TwoCharToWord(ExternalQuery[QPos], ExternalQuery[QPos + 1]);
  919. Inc(QPos, 2);
  920. QClass := TwoCharToWord(ExternalQuery[QPos], ExternalQuery[QPos + 1]);
  921. DoBeforeQuery(ABinding, DNSHeader_Processing, ExternalQuery);
  922. RString := Self.CompleteQuery(DNSHeader_Processing, QName, ExternalQuery, Answer, QType, QClass, DNSResolver);
  923. if RString = cRCodeQueryNotImplement then begin
  924. ComposeErrorResult(FinalResult, DNSHeader_Processing, ExternalQuery, iRCodeQueryNotImplement);
  925. end else begin
  926. if (RString = cRCodeQueryReturned) then
  927. FinalResult := Answer
  928. else begin
  929. if (RString = cRCodeQueryNotFound) then
  930. ComposeErrorResult(FinalResult, DNSHeader_Processing, ExternalQuery, iRCodeQueryNotFound)
  931. else
  932. FinalResult := CombineAnswer(DNSHeader_Processing, ExternalQuery, Answer);
  933. end;
  934. end;
  935. DoAfterQuery(ABinding, DNSHeader_Processing, FinalResult, RString, ExternalQuery);
  936. end;
  937. end;
  938. end;
  939. finally
  940. try
  941. //Self.SendBuffer(ABinding.PeerIP, ABinding.Port, FinalResult[1], length(FinalResult));
  942. with ABinding do begin
  943. SendTo(PeerIP, PeerPort, FinalResult[1], length(FinalResult));
  944. end;
  945. DoAfterSendBack(ABinding, DNSHeader_Processing, FinalResult, RString, ExternalQuery);
  946. if (((Self.CacheUnknowZone) and (RString = cRCodeQueryReturned)) or
  947. (RString = cRCodeQueryCacheOK)) then
  948. Self.SaveToCache(FinalResult);
  949. finally
  950. DNSResolver.Free;
  951. DNSHeader_Processing.Free;
  952. end;
  953. end;
  954. end;
  955. //Self.CS.Release;
  956. end;
  957. *)
  958. procedure TIdDNS_UDPServer.ExternalSearch(aDNSResolver : TIdDNSResolver;
  959. Header: TDNSHeader; Question: TIdBytes; var Answer: TIdBytes);
  960. var
  961. Server_Index : integer;
  962. MyDNSResolver : TIdDNSResolver;
  963. begin
  964. Server_Index := 0;
  965. if (aDNSResolver = nil) then
  966. begin
  967. MyDNSResolver := TIdDNSResolver.Create(Self);
  968. MyDNSResolver.WaitingTime := 5000;
  969. end else
  970. begin
  971. MyDNSResolver := aDNSResolver;
  972. end;
  973. repeat
  974. MyDNSResolver.Host := Self.RootDNS_NET.Strings[Server_Index];
  975. try
  976. MyDNSResolver.InternalQuery := Question;
  977. MyDNSResolver.Resolve('');
  978. Answer := MyDNSResolver.PlainTextResult;
  979. except
  980. // Todo: Create DNS server interal resolver error.
  981. on EIdDnsResolverError do
  982. begin
  983. //Empty Event, for user to custom the event handle.
  984. end;
  985. on EIdSocketError do
  986. begin
  987. end;
  988. else
  989. begin
  990. end;
  991. end;
  992. Inc(Server_Index);
  993. until ((Server_Index >= Self.RootDNS_NET.Count) or (Length(Answer) > 0));
  994. if (aDNSResolver = nil) then
  995. begin
  996. MyDNSResolver.Free
  997. end;
  998. end;
  999. function TIdDNS_UDPServer.FindHandedNodeByName(QName: String;
  1000. QType: Word): TIdDNTreeNode;
  1001. begin
  1002. Result := Self.SearchTree(Self.Handed_Tree, QName, QType);
  1003. end;
  1004. function TIdDNS_UDPServer.FindNodeFullName(Root: TIdDNTreeNode;
  1005. QName: String; QType : Word): string;
  1006. var
  1007. MyNode : TIdDNTreeNode;
  1008. begin
  1009. MyNode := Self.SearchTree(Root, QName, QType);
  1010. if MyNode = nil then Result := ''
  1011. else begin
  1012. Result := MyNode.FullName;
  1013. end;
  1014. end;
  1015. function TIdDNS_UDPServer.LoadZoneFromMasterFile(
  1016. MasterFileName: TFileName): boolean;
  1017. var
  1018. FileStrings : TIdStrings;
  1019. begin
  1020. {MakeTagList;}
  1021. Result := FileExists(MasterFileName);
  1022. if Result then begin
  1023. FileStrings := TIdStringList.Create;
  1024. FileStrings.LoadFromFile(MasterFileName);
  1025. Result := LoadZoneStrings(FileStrings, MasterFileName, Self.Handed_Tree);
  1026. {
  1027. Result := IsValidMasterFile;
  1028. // IsValidMasterFile is used in local, so I design with not
  1029. // any parameter.
  1030. if Result then begin
  1031. Result := LoadMasterFile;
  1032. end;
  1033. }
  1034. FileStrings.Free;
  1035. end;
  1036. {FreeTagList;}
  1037. end;
  1038. function TIdDNS_UDPServer.LoadZoneStrings(FileStrings: TIdStrings; Filename : TFilename;
  1039. TreeRoot : TIdDNTreeNode): boolean;
  1040. var
  1041. TagList : TIdStrings;
  1042. function IsMSDNSFileName(theFileName : TFilename; var DN:string) : boolean;
  1043. var
  1044. namepart : TIdStrings;
  1045. Fullname : string;
  1046. Count : integer;
  1047. begin
  1048. Fullname := theFilename;
  1049. repeat
  1050. if (Pos('\', Fullname) > 0) then fetch(Fullname, '\');
  1051. until (Pos('\', Fullname) = 0);
  1052. namepart := TIdStringList.Create;
  1053. repeat
  1054. namepart.Add(fetch(Fullname,'.'));
  1055. until Fullname = '';
  1056. Result := (namepart.Strings[namepart.Count -1] = 'dns'); {do not localize}
  1057. if Result then begin
  1058. Count := 0;
  1059. DN := namepart.Strings[Count];
  1060. repeat
  1061. Inc(Count);
  1062. if Count <= namepart.Count -2 then begin
  1063. DN := DN + '.' + namepart.Strings[Count];
  1064. end;
  1065. until Count >= namepart.Count -2;
  1066. end;
  1067. namepart.Free;
  1068. end;
  1069. procedure MakeTagList;
  1070. begin
  1071. TagList := TIdStringList.Create;
  1072. TagList.Add(cAAAA);
  1073. TagList.Add(cA);
  1074. TagList.Add(cNS);
  1075. TagList.Add(cMD);
  1076. TagList.Add(cMF);
  1077. TagList.Add(cCName);
  1078. TagList.Add(cSOA);
  1079. TagList.Add(cMB);
  1080. TagList.Add(cMG);
  1081. TagList.Add(cMR);
  1082. TagList.Add(cNULL);
  1083. TagList.Add(cWKS);
  1084. TagList.Add(cPTR);
  1085. TagList.Add(cHINFO);
  1086. TagList.Add(cMINFO);
  1087. TagList.Add(cMX);
  1088. TagList.Add(cTXT);
  1089. // The Following Tags are used in master file, but not Resource Record.
  1090. TagList.Add(cOrigin);
  1091. TagList.Add(cInclude);
  1092. //TagList.Add(cAt);
  1093. end;
  1094. procedure FreeTagList;
  1095. begin
  1096. TagList.Free;
  1097. end;
  1098. function ClearDoubleQutoa (Strs : TIdStrings): boolean;
  1099. var
  1100. SSCount : integer;
  1101. Mark : boolean;
  1102. begin
  1103. SSCount := 0;
  1104. Mark := False;
  1105. while (SSCount <= Strs.Count -1) do begin
  1106. repeat
  1107. if Pos('"', Strs.Strings[SSCount]) > 0 then begin
  1108. Mark := Mark xor (Pos('"', Strs.Strings[SSCount]) > 0);
  1109. Strs.Strings[SSCount] := ReplaceSpecString(Strs.Strings[SSCount], '"', '', False);
  1110. end;
  1111. until (Pos('"', Strs.Strings[SSCount]) = 0);
  1112. if not Mark then Inc(SSCount)
  1113. else begin
  1114. Strs.Strings[SSCount] := Strs.Strings[SSCount] + ' ' +
  1115. Strs.Strings[SSCount + 1];
  1116. Strs.Delete(SSCount + 1);
  1117. end;
  1118. end;
  1119. Result := not Mark;
  1120. end;
  1121. function IsValidMasterFile : boolean;
  1122. var
  1123. EachLinePart : TIdStrings;
  1124. CurrentLineNum, TagField, Count : integer;
  1125. LineData, DataBody, Comment, FPart, Tag : string;
  1126. denoted, Stop, PassQuota : boolean;
  1127. begin
  1128. EachLinePart := TIdStringList.Create;
  1129. CurrentLineNum := 0;
  1130. Stop := False;
  1131. // Check Denoted;
  1132. denoted := false;
  1133. if FileStrings.Count > 0 then begin
  1134. repeat
  1135. LineData := Trim(FileStrings.Strings[CurrentLineNum]);
  1136. DataBody := Fetch(LineData, ';');
  1137. Comment := LineData;
  1138. PassQuota := Pos('(', DataBody) = 0;
  1139. // Split each item into TIdStrings.
  1140. repeat
  1141. if not PassQuota then begin
  1142. Inc(CurrentLineNum);
  1143. LineData := Trim(FileStrings.Strings[CurrentLineNum]);
  1144. DataBody := DataBody + ' ' + Fetch(LineData, ';');
  1145. PassQuota := Pos(')', DataBody) > 0;
  1146. end;
  1147. until PassQuota or (CurrentLineNum > (FileStrings.Count -1));
  1148. Stop := not PassQuota;
  1149. if not Stop then begin
  1150. EachLinePart.Clear;
  1151. DataBody := ReplaceSpecString(DataBody, '(', '');
  1152. DataBody := ReplaceSpecString(DataBody, ')', '');
  1153. repeat
  1154. DataBody := Trim(DataBody);
  1155. FPart := Fetch(DataBody, #9);
  1156. repeat
  1157. FPart := Trim(FPart);
  1158. Tag := Fetch(FPart,' ');
  1159. if (Tag <> '') and (Tag <> '(') and (Tag <> ')') then
  1160. EachLinePart.Add(Tag);
  1161. until (FPart='');
  1162. until (DataBody= '');
  1163. if not denoted then begin
  1164. if EachLinePart.Count > 1 then
  1165. denoted := (EachLinePart.Strings[0] = cOrigin) or (EachLinePart.IndexOf(cSOA) <> -1)
  1166. else
  1167. denoted := False;
  1168. end;
  1169. // Check Syntax;
  1170. if not ( (EachLinePart.Count > 0) and
  1171. (EachLinePart.Strings[0] = cOrigin) ) then begin
  1172. if not denoted then begin
  1173. if EachLinePart.Count > 0 then
  1174. Stop := ((EachLinePart.Count > 0) and (EachLinePart.IndexOf(cSOA)= -1))
  1175. else Stop := False;
  1176. end else begin
  1177. //TagField := -1;
  1178. //FieldCount := 0;
  1179. // Search Tag Named 'IN';
  1180. TagField := EachLinePart.IndexOf('IN'); {do not localize}
  1181. if TagField = -1 then begin
  1182. Count := 0;
  1183. repeat
  1184. if EachLinePart.Count > 0 then
  1185. TagField := TagList.IndexOf(EachLinePart.Strings[Count]);
  1186. Inc(Count);
  1187. until (Count >= EachLinePart.Count -1) or (TagField <> -1);
  1188. if TagField <> -1 then TagField := Count;
  1189. end else begin
  1190. if TagList.IndexOf(EachLinePart.Strings[TagField + 1]) = -1 then
  1191. TagField := -1
  1192. else Inc(TagField);
  1193. end;
  1194. if TagField > -1 then begin
  1195. case TagList.IndexOf(EachLinePart.Strings[TagField]) of
  1196. // Check ip
  1197. TypeCode_A : Stop := not IsValidIP(EachLinePart.Strings[TagField + 1]);
  1198. // Check ip v6
  1199. 0 : Stop := not IsValidIPv6(EachLinePart.Strings[TagField + 1]);
  1200. // Check Domain Name
  1201. TypeCode_CName, TypeCode_NS, TypeCode_MR,
  1202. TypeCode_MD, TypeCode_MB, TypeCode_MG,
  1203. TypeCode_MF: Stop := not IsHostName(EachLinePart.Strings[TagField + 1]);
  1204. // Can be anything
  1205. TypeCode_TXT, TypeCode_NULL: Stop := False;
  1206. // Must be FQDN.
  1207. TypeCode_PTR: Stop := not IsFQDN(EachLinePart.Strings[TagField + 1]);
  1208. // HINFO should has 2 fields : CPU and OS. but TIdStrings
  1209. // is 0 base, so that we have to minus one
  1210. TypeCode_HINFO: begin
  1211. Stop := not (ClearDoubleQutoa(EachLinePart) and
  1212. (EachLinePart.Count - TagField-1 = 2));
  1213. end;
  1214. // Check RMailBX and EMailBX but TIdStrings
  1215. // is 0 base, so that we have to minus one
  1216. TypeCode_MINFO: begin
  1217. Stop := (EachLinePart.Count - TagField-1 <> 2);
  1218. if not Stop then begin
  1219. Stop := not (IsHostName(EachLinePart.Strings[TagField + 1]) and
  1220. IsHostName(EachLinePart.Strings[TagField + 2]));
  1221. end;
  1222. end;
  1223. // Check Pref(Numeric) and Exchange. but TIdStrings
  1224. // is 0 base, so that we have to minus one
  1225. TypeCode_MX: begin
  1226. Stop := (EachLinePart.Count - TagField-1 <> 2);
  1227. if not Stop then begin
  1228. Stop := not (IsNumeric(EachLinePart.Strings[TagField + 1]) and
  1229. IsHostName(EachLinePart.Strings[TagField + 2]));
  1230. end;
  1231. end;
  1232. // TIdStrings is 0 base, so that we have to minus one
  1233. TypeCode_SOA: begin
  1234. Stop := (EachLinePart.Count - TagField-1 <> 7);
  1235. if not Stop then begin
  1236. Stop := not (IsHostName(EachLinePart.Strings[TagField + 1]) and
  1237. IsHostName(EachLinePart.Strings[TagField + 2]) and
  1238. IsNumeric(EachLinePart.Strings[TagField + 3]) and
  1239. IsNumeric(EachLinePart.Strings[TagField + 4]) and
  1240. IsNumeric(EachLinePart.Strings[TagField + 5]) and
  1241. IsNumeric(EachLinePart.Strings[TagField + 6]) and
  1242. IsNumeric(EachLinePart.Strings[TagField + 7])
  1243. );
  1244. end;
  1245. end;
  1246. TypeCode_WKS: Stop := (EachLinePart.Count - TagField = 1);
  1247. end;
  1248. end else begin
  1249. if EachLinePart.Count > 0 then
  1250. Stop := True;
  1251. end;
  1252. end;
  1253. end;
  1254. end;
  1255. Inc(CurrentLineNum);
  1256. until (CurrentLineNum > (FileStrings.Count -1)) or Stop;
  1257. end;
  1258. Result := not Stop;
  1259. EachLinePart.Free;
  1260. end;
  1261. function LoadMasterFile : boolean;
  1262. var
  1263. Checks, EachLinePart, DenotedDomain : TIdStrings;
  1264. CurrentLineNum, FieldCount, TagField, Count, LastTTL : integer;
  1265. LineData, DataBody, Comment, FPart, Tag,
  1266. RName, LastDenotedDomain, LastTag, NewDomain, SingleHostName, PrevDNTag : string;
  1267. denoted, Stop, PassQuota, Found, canChangPrevDNTag : boolean;
  1268. LLRR_A : TIdRR_A;
  1269. LLRR_AAAA : TIdRR_AAAA;
  1270. LLRR_NS : TIdRR_NS;
  1271. LLRR_MB : TIdRR_MB;
  1272. LLRR_Name : TIdRR_CName;
  1273. LLRR_SOA : TIdRR_SOA;
  1274. LLRR_MG : TIdRR_MG;
  1275. LLRR_MR : TIdRR_MR;
  1276. LLRR_PTR : TIdRR_PTR;
  1277. LLRR_HINFO : TIdRR_HINFO;
  1278. LLRR_MINFO : TIdRR_MINFO;
  1279. LLRR_MX : TIdRR_MX;
  1280. LLRR_TXT : TIdRR_TXT;
  1281. begin
  1282. EachLinePart := TIdStringList.Create;
  1283. DenotedDomain := TIdStringList.Create;
  1284. CurrentLineNum := 0;
  1285. LastDenotedDomain := '';
  1286. LastTag := '';
  1287. NewDomain := '';
  1288. PrevDNTag := '';
  1289. Stop := False;
  1290. //canChangPrevDNTag := True;
  1291. if IsMSDNSFileName(FileName, LastDenotedDomain) then begin
  1292. …

Large files files are truncated, but you can click here to view the full file