diff --git a/Apps/AutoPtrApp/App.cs b/Apps/AutoPtrApp/App.cs new file mode 100644 index 00000000..96a1e0ba --- /dev/null +++ b/Apps/AutoPtrApp/App.cs @@ -0,0 +1,144 @@ +/* +Technitium DNS Server +Copyright (C) 2023 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 DnsServerCore.ApplicationCommon; +using System.Net; +using System.Net.Sockets; +using System.Text.Json; +using System.Threading.Tasks; +using TechnitiumLibrary.Net; +using TechnitiumLibrary.Net.Dns; +using TechnitiumLibrary.Net.Dns.ResourceRecords; + +namespace AutoPtr +{ + public class App : IDnsApplication, IDnsAppRecordRequestHandler + { + #region IDisposable + + public void Dispose() + { + //do nothing + } + + #endregion + + #region public + + public Task InitializeAsync(IDnsServer dnsServer, string config) + { + return Task.CompletedTask; + } + + public Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData) + { + DnsQuestionRecord question = request.Question[0]; + + if (question.Type != DnsResourceRecordType.PTR) + return Task.FromResult(null); + + string qname = question.Name; + + if (qname.Length == appRecordName.Length) + return Task.FromResult(null); + + if (!IPAddressExtensions.TryParseReverseDomain(qname, out IPAddress address)) + return Task.FromResult(null); + + string domain = null; + + using (JsonDocument jsonDocument = JsonDocument.Parse(appRecordData)) + { + JsonElement jsonAppRecordData = jsonDocument.RootElement; + + string ipSeparator; + + if (jsonAppRecordData.TryGetProperty("ipSeparator", out JsonElement jsonSeparator) && (jsonSeparator.ValueKind != JsonValueKind.Null)) + ipSeparator = jsonSeparator.ToString(); + else + ipSeparator = string.Empty; + + switch (address.AddressFamily) + { + case AddressFamily.InterNetwork: + { + byte[] buffer = address.GetAddressBytes(); + + foreach (byte b in buffer) + { + if (domain is null) + domain = b.ToString(); + else + domain += ipSeparator + b.ToString(); + } + } + break; + + case AddressFamily.InterNetworkV6: + { + byte[] buffer = address.GetAddressBytes(); + + for (int i = 0; i < buffer.Length; i += 2) + { + if (domain is null) + domain = buffer[i].ToString("x2") + buffer[i + 1].ToString("x2"); + else + domain += ipSeparator + buffer[i].ToString("x2") + buffer[i + 1].ToString("x2"); + } + } + break; + + default: + return Task.FromResult(null); + } + + if (jsonAppRecordData.TryGetProperty("prefix", out JsonElement jsonPrefix) && (jsonPrefix.ValueKind != JsonValueKind.Null)) + domain = jsonPrefix.GetString() + domain; + + if (jsonAppRecordData.TryGetProperty("suffix", out JsonElement jsonSuffix) && (jsonSuffix.ValueKind != JsonValueKind.Null)) + domain += jsonSuffix.GetString(); + } + + DnsResourceRecord[] answer = new DnsResourceRecord[] { new DnsResourceRecord(qname, DnsResourceRecordType.PTR, DnsClass.IN, appRecordTtl, new DnsPTRRecordData(domain)) }; + + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answer)); + } + + #endregion + + #region properties + + public string Description + { get { return "Returns automatically generated response for a PTR request for both IPv4 and IPv6."; } } + + public string ApplicationRecordDataTemplate + { + get + { + return @"{ + ""prefix"": """", + ""suffix"": "".example.com"", + ""ipSeparator"": ""-"" +}"; + } + } + + #endregion + } +} diff --git a/Apps/AutoPtrApp/AutoPtrApp.csproj b/Apps/AutoPtrApp/AutoPtrApp.csproj new file mode 100644 index 00000000..0023f3ca --- /dev/null +++ b/Apps/AutoPtrApp/AutoPtrApp.csproj @@ -0,0 +1,39 @@ + + + + net7.0 + false + true + 1.0 + Technitium + Technitium DNS Server + Shreyas Zare + AutoPtrApp + AutoPtr + https://technitium.com/dns/ + https://github.com/TechnitiumSoftware/DnsServer + Allows creating APP records in a primary and forwarder zones that can return automatically generated response for a PTR request for both IPv4 and IPv6. + false + Library + + + + + false + + + + + + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll + false + + + + + + PreserveNewest + + + + diff --git a/Apps/AutoPtrApp/dnsApp.config b/Apps/AutoPtrApp/dnsApp.config new file mode 100644 index 00000000..7a2450c3 --- /dev/null +++ b/Apps/AutoPtrApp/dnsApp.config @@ -0,0 +1 @@ +#This app requires no config. \ No newline at end of file