From 2db9337d36dd49d55a2db365e05ba98bb602025f Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 27 Jun 2020 15:35:35 +0530 Subject: [PATCH] DomainTree: implemented independent class to traverse domain name to be reuseable. --- DnsServerCore/Dns/Zones/DomainTree.cs | 195 ++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 DnsServerCore/Dns/Zones/DomainTree.cs diff --git a/DnsServerCore/Dns/Zones/DomainTree.cs b/DnsServerCore/Dns/Zones/DomainTree.cs new file mode 100644 index 00000000..7407c1a4 --- /dev/null +++ b/DnsServerCore/Dns/Zones/DomainTree.cs @@ -0,0 +1,195 @@ +/* +Technitium DNS Server +Copyright (C) 2020 Shreyas Zare (shreyas@technitium.com) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +using System; +using System.Text; +using TechnitiumLibrary.ByteTree; +using TechnitiumLibrary.Net.Dns; + +namespace DnsServerCore.Dns.Zones +{ + class DomainTree : ByteTree where T : class + { + #region variables + + readonly static byte[] _keyMap; + readonly static byte[] _reverseKeyMap; + + #endregion + + #region constructor + + static DomainTree() + { + _keyMap = new byte[256]; + _reverseKeyMap = new byte[40]; + + for (int i = 0; i < _keyMap.Length; i++) + { + if ((i >= 97) && (i <= 122)) //[a-z] + { + _keyMap[i] = (byte)(i - 97); + _reverseKeyMap[_keyMap[i]] = (byte)i; + } + else if ((i >= 65) && (i <= 90)) //[a-z] + { + _keyMap[i] = (byte)(i - 65); + _reverseKeyMap[_keyMap[i]] = (byte)i; + } + else if ((i >= 48) && (i <= 57)) //[0-9] + { + _keyMap[i] = (byte)(26 + i - 48); + _reverseKeyMap[_keyMap[i]] = (byte)i; + } + else if (i == 45) //[-] + { + _keyMap[i] = 36; + _reverseKeyMap[36] = 45; + } + else if (i == 95) //[_] + { + _keyMap[i] = 37; + _reverseKeyMap[37] = 95; + } + else if (i == 42) //[*] + { + _keyMap[i] = 0xff; //skipped value 38 for optimization + _reverseKeyMap[38] = 42; + } + else if (i == 46) //[.] + { + _keyMap[i] = 39; + _reverseKeyMap[39] = 46; + } + else + { + _keyMap[i] = 0xff; + } + } + } + + public DomainTree() + : base(40) + { } + + #endregion + + #region protected + + protected override byte[] ConvertToByteKey(string domain) + { + if (domain.Length == 0) + return Array.Empty(); + + if (domain.Length > 255) + throw new DnsClientException("Invalid domain name [" + domain + "]: length cannot exceed 255 bytes."); + + byte[] key = new byte[domain.Length + 1]; + int keyOffset = 0; + int labelStart; + int labelEnd = domain.Length - 1; + int labelLength; + int labelChar; + byte labelKeyCode; + int i; + + do + { + if (labelEnd < 0) + labelEnd = 0; + + labelStart = domain.LastIndexOf('.', labelEnd); + labelLength = labelEnd - labelStart; + + if (labelLength == 0) + throw new DnsClientException("Invalid domain name [" + domain + "]: label length cannot be 0 byte."); + + if (labelLength > 63) + throw new DnsClientException("Invalid domain name [" + domain + "]: label length cannot exceed 63 bytes."); + + if (domain[labelStart + 1] == '-') + throw new DnsClientException("Invalid domain name [" + domain + "]: label cannot start with hyphen."); + + if (domain[labelEnd] == '-') + throw new DnsClientException("Invalid domain name [" + domain + "]: label cannot end with hyphen."); + + if ((labelLength == 1) && (domain[labelStart + 1] == '*')) + { + key[keyOffset++] = 38; + } + else + { + for (i = labelStart + 1; i <= labelEnd; i++) + { + labelChar = domain[i]; + if (labelChar >= _keyMap.Length) + throw new DnsClientException("Invalid domain name [" + domain + "]: invalid character [" + labelChar + "] was found."); + + labelKeyCode = _keyMap[labelChar]; + if (labelKeyCode == 0xff) + throw new DnsClientException("Invalid domain name [" + domain + "]: invalid character [" + labelChar + "] was found."); + + key[keyOffset++] = labelKeyCode; + } + } + + key[keyOffset++] = 39; + labelEnd = labelStart - 1; + } + while (labelStart > -1); + + return key; + } + + protected static string ConvertKeyToLabel(byte[] key, int startIndex) + { + byte[] domain = new byte[key.Length - startIndex]; + int i; + int k; + + for (i = 0; i < domain.Length; i++) + { + k = key[i + startIndex]; + if (k == 39) + break; + + domain[i] = _reverseKeyMap[k]; + } + + return Encoding.ASCII.GetString(domain, 0, i); + } + + #endregion + + #region public + + public override bool TryRemove(string key, out T value) + { + if (TryRemove(key, out value, out Node closestNode)) + { + closestNode.CleanThisBranch(); + return true; + } + + return false; + } + + #endregion + } +}