App.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. Technitium DNS Server
  3. Copyright (C) 2024 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.ApplicationCommon;
  16. using System.Net;
  17. using System.Net.Sockets;
  18. using System.Text.Json;
  19. using System.Threading.Tasks;
  20. using TechnitiumLibrary.Net;
  21. using TechnitiumLibrary.Net.Dns;
  22. using TechnitiumLibrary.Net.Dns.ResourceRecords;
  23. namespace AutoPtr
  24. {
  25. public sealed class App : IDnsApplication, IDnsAppRecordRequestHandler
  26. {
  27. #region variables
  28. IDnsServer _dnsServer;
  29. #endregion
  30. #region IDisposable
  31. public void Dispose()
  32. {
  33. //do nothing
  34. }
  35. #endregion
  36. #region public
  37. public Task InitializeAsync(IDnsServer dnsServer, string config)
  38. {
  39. _dnsServer = dnsServer;
  40. return Task.CompletedTask;
  41. }
  42. public async Task<DnsDatagram> ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData)
  43. {
  44. DnsQuestionRecord question = request.Question[0];
  45. string qname = question.Name;
  46. if (qname.Length == appRecordName.Length)
  47. return null;
  48. if (!IPAddressExtensions.TryParseReverseDomain(qname.ToLowerInvariant(), out IPAddress address))
  49. return null;
  50. if (question.Type != DnsResourceRecordType.PTR)
  51. {
  52. //NODATA reponse
  53. DnsDatagram soaResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(zoneName, DnsResourceRecordType.SOA, DnsClass.IN));
  54. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, soaResponse.Answer);
  55. }
  56. string domain = null;
  57. using (JsonDocument jsonDocument = JsonDocument.Parse(appRecordData))
  58. {
  59. JsonElement jsonAppRecordData = jsonDocument.RootElement;
  60. string ipSeparator;
  61. if (jsonAppRecordData.TryGetProperty("ipSeparator", out JsonElement jsonSeparator) && (jsonSeparator.ValueKind != JsonValueKind.Null))
  62. ipSeparator = jsonSeparator.ToString();
  63. else
  64. ipSeparator = string.Empty;
  65. switch (address.AddressFamily)
  66. {
  67. case AddressFamily.InterNetwork:
  68. {
  69. byte[] buffer = address.GetAddressBytes();
  70. foreach (byte b in buffer)
  71. {
  72. if (domain is null)
  73. domain = b.ToString();
  74. else
  75. domain += ipSeparator + b.ToString();
  76. }
  77. }
  78. break;
  79. case AddressFamily.InterNetworkV6:
  80. {
  81. byte[] buffer = address.GetAddressBytes();
  82. for (int i = 0; i < buffer.Length; i += 2)
  83. {
  84. if (domain is null)
  85. domain = buffer[i].ToString("x2") + buffer[i + 1].ToString("x2");
  86. else
  87. domain += ipSeparator + buffer[i].ToString("x2") + buffer[i + 1].ToString("x2");
  88. }
  89. }
  90. break;
  91. default:
  92. return null;
  93. }
  94. if (jsonAppRecordData.TryGetProperty("prefix", out JsonElement jsonPrefix) && (jsonPrefix.ValueKind != JsonValueKind.Null))
  95. domain = jsonPrefix.GetString() + domain;
  96. if (jsonAppRecordData.TryGetProperty("suffix", out JsonElement jsonSuffix) && (jsonSuffix.ValueKind != JsonValueKind.Null))
  97. domain += jsonSuffix.GetString();
  98. }
  99. DnsResourceRecord[] answer = new DnsResourceRecord[] { new DnsResourceRecord(qname, DnsResourceRecordType.PTR, DnsClass.IN, appRecordTtl, new DnsPTRRecordData(domain)) };
  100. return new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answer);
  101. }
  102. #endregion
  103. #region properties
  104. public string Description
  105. { get { return "Returns automatically generated response for a PTR request for both IPv4 and IPv6."; } }
  106. public string ApplicationRecordDataTemplate
  107. {
  108. get
  109. {
  110. return @"{
  111. ""prefix"": """",
  112. ""suffix"": "".example.com"",
  113. ""ipSeparator"": ""-""
  114. }";
  115. }
  116. }
  117. #endregion
  118. }
  119. }