ZoneTree.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /*
  2. Technitium DNS Server
  3. Copyright (C) 2022 Shreyas Zare (shreyas@technitium.com)
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  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. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. using DnsServerCore.Dns.Zones;
  16. using System.Collections.Generic;
  17. using System.Threading;
  18. namespace DnsServerCore.Dns.Trees
  19. {
  20. abstract class ZoneTree<TNode, TSubDomainZone, TApexZone> : DomainTree<TNode> where TNode : class where TSubDomainZone : Zone where TApexZone : Zone
  21. {
  22. #region private
  23. private static Node GetNextChildZoneNode(Node current, int baseDepth)
  24. {
  25. int k = 0;
  26. while ((current is not null) && (current.Depth >= baseDepth))
  27. {
  28. if ((current.K != 0) || (current.Depth == baseDepth)) //[.] skip this node's children as its last for current sub zone
  29. {
  30. Node[] children = current.Children;
  31. if (children is not null)
  32. {
  33. //find child node
  34. Node child = null;
  35. for (int i = k; i < children.Length; i++)
  36. {
  37. child = Volatile.Read(ref children[i]);
  38. if (child is not null)
  39. {
  40. if (child.Value is not null)
  41. return child; //child has value so return it
  42. if (child.K == 0) //[.]
  43. return child; //child node is last for current sub zone
  44. if (child.Children is not null)
  45. break;
  46. }
  47. }
  48. if (child is not null)
  49. {
  50. //make found child as current
  51. k = 0;
  52. current = child;
  53. continue; //start over
  54. }
  55. }
  56. }
  57. //no child nodes available; move up to parent node
  58. k = current.K + 1;
  59. current = current.Parent;
  60. }
  61. return null;
  62. }
  63. private static byte[] GetNodeKey(Node node)
  64. {
  65. byte[] key = new byte[node.Depth];
  66. int i = node.Depth - 1;
  67. while (i > -1)
  68. {
  69. key[i--] = node.K;
  70. node = node.Parent;
  71. }
  72. return key;
  73. }
  74. private static bool KeysMatch(byte[] mainKey, byte[] testKey, bool matchWildcard)
  75. {
  76. if (matchWildcard)
  77. {
  78. //com.example.*.
  79. //com.example.*.www.
  80. //com.example.abc.www.
  81. int i = 0;
  82. int j = 0;
  83. while ((i < mainKey.Length) && (j < testKey.Length))
  84. {
  85. if (mainKey[i] == 1) //[*]
  86. {
  87. if (i == mainKey.Length - 2)
  88. return true;
  89. //skip j to next label
  90. while (j < testKey.Length)
  91. {
  92. if (testKey[j] == 0) //[.]
  93. break;
  94. j++;
  95. }
  96. i++;
  97. continue;
  98. }
  99. if (mainKey[i] != testKey[j])
  100. return false;
  101. i++;
  102. j++;
  103. }
  104. return (i == mainKey.Length) && (j == testKey.Length);
  105. }
  106. else
  107. {
  108. //exact match
  109. if (mainKey.Length != testKey.Length)
  110. return false;
  111. for (int i = 0; i < mainKey.Length; i++)
  112. {
  113. if (mainKey[i] != testKey[i])
  114. return false;
  115. }
  116. return true;
  117. }
  118. }
  119. #endregion
  120. #region protected
  121. protected static bool IsKeySubDomain(byte[] mainKey, byte[] testKey, bool matchWildcard)
  122. {
  123. if (matchWildcard)
  124. {
  125. //com.example.*.
  126. //com.example.*.www.
  127. //com.example.abc.www.
  128. int i = 0;
  129. int j = 0;
  130. while ((i < mainKey.Length) && (j < testKey.Length))
  131. {
  132. if (mainKey[i] == 1) //[*]
  133. {
  134. //skip j to next label
  135. while (j < testKey.Length)
  136. {
  137. if (testKey[j] == 0) //[.]
  138. break;
  139. j++;
  140. }
  141. i++;
  142. continue;
  143. }
  144. if (mainKey[i] != testKey[j])
  145. return false;
  146. i++;
  147. j++;
  148. }
  149. return (i == mainKey.Length) && (j < testKey.Length);
  150. }
  151. else
  152. {
  153. //exact match
  154. if (mainKey.Length > testKey.Length)
  155. return false;
  156. for (int i = 0; i < mainKey.Length; i++)
  157. {
  158. if (mainKey[i] != testKey[i])
  159. return false;
  160. }
  161. return mainKey.Length < testKey.Length;
  162. }
  163. }
  164. protected TNode FindZoneNode(byte[] key, bool matchWildcard, out Node currentNode, out Node closestSubDomainNode, out Node closestAuthorityNode, out TSubDomainZone closestSubDomain, out TSubDomainZone closestDelegation, out TApexZone closestAuthority)
  165. {
  166. currentNode = _root;
  167. closestSubDomainNode = null;
  168. closestAuthorityNode = null;
  169. closestSubDomain = null;
  170. closestDelegation = null;
  171. closestAuthority = null;
  172. Node wildcard = null;
  173. int i = 0;
  174. while (i <= key.Length)
  175. {
  176. //inspect the current node
  177. NodeValue value = currentNode.Value;
  178. if ((value is not null) && (value.Key.Length <= key.Length))
  179. {
  180. TNode zoneNode = value.Value;
  181. if ((zoneNode is not null) && IsKeySubDomain(value.Key, key, matchWildcard))
  182. {
  183. //find closest values
  184. GetClosestValuesForZone(zoneNode, out TSubDomainZone subDomain, out TSubDomainZone delegation, out TApexZone authority);
  185. if (subDomain is not null)
  186. {
  187. closestSubDomain = subDomain;
  188. closestSubDomainNode = currentNode;
  189. wildcard = null; //clear previous wildcard node
  190. }
  191. if (delegation is not null)
  192. {
  193. closestDelegation = delegation;
  194. wildcard = null; //clear previous wildcard node
  195. }
  196. if (authority is not null)
  197. {
  198. closestAuthority = authority;
  199. closestAuthorityNode = currentNode;
  200. closestSubDomain = null; //clear previous closest sub domain
  201. closestSubDomainNode = null;
  202. wildcard = null; //clear previous wildcard node
  203. }
  204. }
  205. }
  206. if (i == key.Length)
  207. break;
  208. Node[] children = currentNode.Children;
  209. if (children is null)
  210. break;
  211. Node child;
  212. if (matchWildcard)
  213. {
  214. child = Volatile.Read(ref children[1]); //[*]
  215. if (child is not null)
  216. wildcard = child;
  217. }
  218. child = Volatile.Read(ref children[key[i]]);
  219. if (child is null)
  220. {
  221. //no child found
  222. if (wildcard is null)
  223. return null; //no child or wildcard found
  224. //use wildcard node
  225. //skip to next label
  226. while (++i < key.Length)
  227. {
  228. if (key[i] == 0) //[.]
  229. break;
  230. }
  231. currentNode = wildcard;
  232. wildcard = null;
  233. continue;
  234. }
  235. currentNode = child;
  236. i++;
  237. }
  238. {
  239. NodeValue value = currentNode.Value;
  240. if (value is not null)
  241. {
  242. //match exact + wildcard keys
  243. if (KeysMatch(value.Key, key, matchWildcard))
  244. {
  245. //find closest values since the matched zone may be apex zone
  246. TNode zoneNode = value.Value;
  247. if (zoneNode is not null)
  248. {
  249. GetClosestValuesForZone(zoneNode, out TSubDomainZone subDomain, out TSubDomainZone delegation, out TApexZone authority);
  250. if (subDomain is not null)
  251. {
  252. closestSubDomain = subDomain;
  253. closestSubDomainNode = currentNode;
  254. }
  255. if (delegation is not null)
  256. closestDelegation = delegation;
  257. if (authority is not null)
  258. {
  259. closestAuthority = authority;
  260. closestAuthorityNode = currentNode;
  261. closestSubDomain = null; //clear previous closest sub domain
  262. closestSubDomainNode = null;
  263. }
  264. }
  265. return value.Value; //found matching value
  266. }
  267. if (wildcard is not null)
  268. {
  269. NodeValue wildcardValue = wildcard.Value;
  270. if (wildcardValue is not null)
  271. {
  272. if (IsKeySubDomain(wildcardValue.Key, value.Key, matchWildcard))
  273. {
  274. //value is a subdomain of wildcard so wildcard is not valid
  275. wildcard = null;
  276. }
  277. }
  278. }
  279. }
  280. }
  281. if (wildcard is not null)
  282. {
  283. //inspect wildcard node value
  284. NodeValue value = wildcard.Value;
  285. if (value is null)
  286. {
  287. //find value from next [.] node
  288. Node[] children = wildcard.Children;
  289. if (children is not null)
  290. {
  291. Node child = Volatile.Read(ref children[0]); //[.]
  292. if (child is not null)
  293. {
  294. value = child.Value;
  295. if (value is not null)
  296. {
  297. //match wildcard keys
  298. if (KeysMatch(value.Key, key, true))
  299. {
  300. //find closest values
  301. TNode zoneNode = value.Value;
  302. if (zoneNode is not null)
  303. {
  304. GetClosestValuesForZone(zoneNode, out TSubDomainZone subDomain, out TSubDomainZone delegation, out TApexZone authority);
  305. if (subDomain is not null)
  306. {
  307. closestSubDomain = subDomain;
  308. closestSubDomainNode = currentNode;
  309. }
  310. if (delegation is not null)
  311. closestDelegation = delegation;
  312. if (authority is not null)
  313. {
  314. closestAuthority = authority;
  315. closestAuthorityNode = currentNode;
  316. closestSubDomain = null; //clear previous closest sub domain
  317. closestSubDomainNode = null;
  318. }
  319. }
  320. return value.Value; //found matching wildcard value
  321. }
  322. }
  323. }
  324. }
  325. }
  326. else
  327. {
  328. //match wildcard keys
  329. if (KeysMatch(value.Key, key, true))
  330. {
  331. //find closest values
  332. TNode zoneNode = value.Value;
  333. if (zoneNode is not null)
  334. {
  335. GetClosestValuesForZone(zoneNode, out TSubDomainZone subDomain, out TSubDomainZone delegation, out TApexZone authority);
  336. if (subDomain is not null)
  337. {
  338. closestSubDomain = subDomain;
  339. closestSubDomainNode = currentNode;
  340. }
  341. if (delegation is not null)
  342. closestDelegation = delegation;
  343. if (authority is not null)
  344. {
  345. closestAuthority = authority;
  346. closestAuthorityNode = currentNode;
  347. closestSubDomain = null; //clear previous closest sub domain
  348. closestSubDomainNode = null;
  349. }
  350. }
  351. return value.Value; //found matching wildcard value
  352. }
  353. }
  354. }
  355. //value not found
  356. return null;
  357. }
  358. protected abstract void GetClosestValuesForZone(TNode zoneValue, out TSubDomainZone closestSubDomain, out TSubDomainZone closestDelegation, out TApexZone closestAuthority);
  359. #endregion
  360. #region public
  361. public void ListSubDomains(string domain, List<string> subDomains)
  362. {
  363. byte[] bKey = ConvertToByteKey(domain);
  364. _ = _root.FindNodeValue(bKey, out Node currentNode);
  365. Node current = currentNode;
  366. NodeValue value;
  367. do
  368. {
  369. value = current.Value;
  370. if (value is not null)
  371. {
  372. if (IsKeySubDomain(bKey, value.Key, false))
  373. {
  374. string label = ConvertKeyToLabel(value.Key, bKey.Length);
  375. if (label is not null)
  376. subDomains.Add(label);
  377. }
  378. }
  379. else if ((current.K == 0) && (current.Depth > currentNode.Depth)) //[.]
  380. {
  381. byte[] nodeKey = GetNodeKey(current);
  382. if (IsKeySubDomain(bKey, nodeKey, false))
  383. {
  384. string label = ConvertKeyToLabel(nodeKey, bKey.Length);
  385. if (label is not null)
  386. subDomains.Add(label);
  387. }
  388. }
  389. current = GetNextChildZoneNode(current, currentNode.Depth);
  390. }
  391. while (current is not null);
  392. }
  393. #endregion
  394. }
  395. }