From 5e8cb1cbd17256b6ba166f144daba38ee6304958 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 20 Jun 2020 14:14:19 +0530 Subject: [PATCH] AuthZoneManager: zone loading sequence updated. update server domain done async. Fixed issue with GetForwarderResponse() to allow using subdomain FWD records. Updated LoadZoneFrom() to correctly loading old version stub zones. Fixed minor issues and refactoring done. --- .../Dns/ZoneManagers/AuthZoneManager.cs | 209 +++++++++++------- 1 file changed, 132 insertions(+), 77 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs index f99f7d0a..d05cf6bd 100644 --- a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs @@ -24,17 +24,19 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Text; +using System.Threading; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; namespace DnsServerCore.Dns.ZoneManagers { - public class AuthZoneManager : IDisposable + public sealed class AuthZoneManager : IDisposable { #region variables readonly DnsServer _dnsServer; - readonly string _serverDomain; + + string _serverDomain; readonly ZoneTree _root = new ZoneTree(); @@ -45,12 +47,8 @@ namespace DnsServerCore.Dns.ZoneManagers public AuthZoneManager(DnsServer dnsServer) { _dnsServer = dnsServer; - if (_dnsServer == null) - return; //allowed or blocked zone usage _serverDomain = _dnsServer.ServerDomain; - - LoadAllZoneFiles(); } #endregion @@ -59,7 +57,7 @@ namespace DnsServerCore.Dns.ZoneManagers bool _disposed; - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (_disposed) return; @@ -95,52 +93,67 @@ namespace DnsServerCore.Dns.ZoneManagers private void UpdateServerDomain(string serverDomain) { - //update authoritative zone SOA and NS records - List zones = ListZones(); - - foreach (AuthZoneInfo zone in zones) + ThreadPool.QueueUserWorkItem(delegate (object state) { - if (zone.Type != AuthZoneType.Primary) - continue; - - DnsResourceRecord record = zone.GetRecords(DnsResourceRecordType.SOA)[0]; - DnsSOARecord soa = record.RDATA as DnsSOARecord; - - if (soa.PrimaryNameServer.Equals(_serverDomain, StringComparison.OrdinalIgnoreCase)) + //update authoritative zone SOA and NS records + try { - string responsiblePerson = soa.ResponsiblePerson; - if (responsiblePerson.EndsWith(_serverDomain)) - responsiblePerson = responsiblePerson.Replace(_serverDomain, serverDomain); + List zones = ListZones(); - SetRecords(record.Name, record.Type, record.TtlValue, new DnsResourceRecordData[] { new DnsSOARecord(serverDomain, responsiblePerson, soa.Serial, soa.Refresh, soa.Retry, soa.Expire, soa.Minimum) }); - - //update NS records - IReadOnlyList nsResourceRecords = zone.GetRecords(DnsResourceRecordType.NS); - - foreach (DnsResourceRecord nsResourceRecord in nsResourceRecords) + foreach (AuthZoneInfo zone in zones) { - if ((nsResourceRecord.RDATA as DnsNSRecord).NameServer.Equals(_serverDomain, StringComparison.OrdinalIgnoreCase)) + if (zone.Type != AuthZoneType.Primary) + continue; + + DnsResourceRecord record = zone.GetRecords(DnsResourceRecordType.SOA)[0]; + DnsSOARecord soa = record.RDATA as DnsSOARecord; + + if (soa.PrimaryNameServer.Equals(_serverDomain, StringComparison.OrdinalIgnoreCase)) { - UpdateRecord(nsResourceRecord, new DnsResourceRecord(nsResourceRecord.Name, nsResourceRecord.Type, nsResourceRecord.Class, nsResourceRecord.TtlValue, new DnsNSRecord(serverDomain)) { Tag = nsResourceRecord.Tag }); - break; + string responsiblePerson = soa.ResponsiblePerson; + if (responsiblePerson.EndsWith(_serverDomain)) + responsiblePerson = responsiblePerson.Replace(_serverDomain, serverDomain); + + SetRecords(record.Name, record.Type, record.TtlValue, new DnsResourceRecordData[] { new DnsSOARecord(serverDomain, responsiblePerson, soa.Serial, soa.Refresh, soa.Retry, soa.Expire, soa.Minimum) }); + + //update NS records + IReadOnlyList nsResourceRecords = zone.GetRecords(DnsResourceRecordType.NS); + + foreach (DnsResourceRecord nsResourceRecord in nsResourceRecords) + { + if ((nsResourceRecord.RDATA as DnsNSRecord).NameServer.Equals(_serverDomain, StringComparison.OrdinalIgnoreCase)) + { + UpdateRecord(nsResourceRecord, new DnsResourceRecord(nsResourceRecord.Name, nsResourceRecord.Type, nsResourceRecord.Class, nsResourceRecord.TtlValue, new DnsNSRecord(serverDomain)) { Tag = nsResourceRecord.Tag }); + break; + } + } + + if (zone.Internal) + continue; //dont save internal zones to disk + + try + { + SaveZoneFile(zone.Name); + } + catch (Exception ex) + { + LogManager log = _dnsServer.LogManager; + if (log != null) + log.Write(ex); + } } } - - if (zone.Internal) - continue; //dont save internal zones to disk - - try - { - SaveZoneFile(zone.Name); - } - catch (Exception ex) - { - LogManager log = _dnsServer.LogManager; - if (log != null) - log.Write(ex); - } } - } + catch (Exception ex) + { + LogManager log = _dnsServer.LogManager; + if (log != null) + log.Write(ex); + } + + //update server domain + _serverDomain = serverDomain; + }); } private AuthZone CreateEmptyZone(AuthZoneInfo zoneInfo) @@ -254,7 +267,38 @@ namespace DnsServerCore.Dns.ZoneManagers return additionalRecords; } - private void LoadAllZoneFiles() + private DnsDatagram GetReferralResponse(DnsDatagram request, AuthZone delegationZone) + { + IReadOnlyList authority; + + if (delegationZone is StubZone) + authority = delegationZone.GetRecords(DnsResourceRecordType.NS); //stub zone has no authority so cant query + else + authority = delegationZone.QueryRecords(DnsResourceRecordType.NS); + + IReadOnlyList additional = GetAdditionalRecords(authority); + + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, null, authority, additional); + } + + private DnsDatagram GetForwarderResponse(DnsDatagram request, AuthZone zone, AuthZone forwarderZone) + { + IReadOnlyList authority = null; + + if (zone != null) + authority = zone.QueryRecords(DnsResourceRecordType.FWD); + + if ((authority == null) || (authority.Count == 0)) + authority = forwarderZone.QueryRecords(DnsResourceRecordType.FWD); + + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, null, authority); + } + + #endregion + + #region public + + public void LoadAllZoneFiles() { string zonesFolder = Path.Combine(_dnsServer.ConfigFolder, "zones"); if (!Directory.Exists(zonesFolder)) @@ -348,31 +392,6 @@ namespace DnsServerCore.Dns.ZoneManagers } } - private DnsDatagram GetReferralResponse(DnsDatagram request, AuthZone delegationZone) - { - IReadOnlyList authority; - - if (delegationZone is StubZone) - authority = delegationZone.GetRecords(DnsResourceRecordType.NS); //stub zone has no authority so cant query - else - authority = delegationZone.QueryRecords(DnsResourceRecordType.NS); - - IReadOnlyList additional = GetAdditionalRecords(authority); - - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, null, authority, additional); - } - - private DnsDatagram GetForwarderResponse(DnsDatagram request, AuthZone forwarderZone) - { - IReadOnlyList authority = forwarderZone.QueryRecords(DnsResourceRecordType.FWD); - - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, null, authority); - } - - #endregion - - #region public - public AuthZoneInfo CreatePrimaryZone(string domain, string primaryNameServer, bool @internal) { AuthZone authZone = new PrimaryZone(_dnsServer, domain, primaryNameServer, @internal); @@ -526,7 +545,13 @@ namespace DnsServerCore.Dns.ZoneManagers List glueRecords = new List(); if (additionalRecords != null) - glueRecords.AddRange(additionalRecords); + { + foreach (DnsResourceRecord additionalRecord in additionalRecords) + { + if (!glueRecords.Contains(additionalRecord)) + glueRecords.Add(additionalRecord); + } + } int i = 0; @@ -539,7 +564,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (record.Name.EndsWith(domain, StringComparison.OrdinalIgnoreCase)) newRecords.Add(record); - else + else if (!glueRecords.Contains(record)) glueRecords.Add(record); } @@ -786,7 +811,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (authZone is StubZone) return GetReferralResponse(request, authZone); else if (authZone is ForwarderZone) - return GetForwarderResponse(request, authZone); + return GetForwarderResponse(request, null, authZone); DnsResponseCode rCode = hasSubDomains ? DnsResponseCode.NoError : DnsResponseCode.NameError; IReadOnlyList authority = authZone.QueryRecords(DnsResourceRecordType.SOA); @@ -806,7 +831,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (authZone is StubZone) return GetReferralResponse(request, authZone); else if (authZone is ForwarderZone) - return GetForwarderResponse(request, authZone); + return GetForwarderResponse(request, zone, authZone); authority = authZone.QueryRecords(DnsResourceRecordType.SOA); additional = null; @@ -862,11 +887,27 @@ namespace DnsServerCore.Dns.ZoneManagers DnsResourceRecord[] records = new DnsResourceRecord[bR.ReadInt32()]; if (records.Length > 0) { + DnsResourceRecord soaRecord = null; + for (int i = 0; i < records.Length; i++) + { records[i] = new DnsResourceRecord(s); + if (records[i].Type == DnsResourceRecordType.SOA) + soaRecord = records[i]; + } + + if (soaRecord == null) + throw new InvalidDataException("Zone does not contain SOA record."); + //make zone info - AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, AuthZoneType.Primary, false); + AuthZoneType zoneType; + if (_dnsServer.ServerDomain.Equals((soaRecord.RDATA as DnsSOARecord).PrimaryNameServer, StringComparison.OrdinalIgnoreCase)) + zoneType = AuthZoneType.Primary; + else + zoneType = AuthZoneType.Stub; + + AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, zoneType, false); //create zone Zone authZone = CreateEmptyZone(zoneInfo); @@ -891,14 +932,28 @@ namespace DnsServerCore.Dns.ZoneManagers DnsResourceRecord[] records = new DnsResourceRecord[bR.ReadInt32()]; if (records.Length > 0) { + DnsResourceRecord soaRecord = null; + for (int i = 0; i < records.Length; i++) { records[i] = new DnsResourceRecord(s); records[i].Tag = new DnsResourceRecordInfo(bR); + + if (records[i].Type == DnsResourceRecordType.SOA) + soaRecord = records[i]; } + if (soaRecord == null) + throw new InvalidDataException("Zone does not contain SOA record."); + //make zone info - AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, AuthZoneType.Primary, zoneDisabled); + AuthZoneType zoneType; + if (_dnsServer.ServerDomain.Equals((soaRecord.RDATA as DnsSOARecord).PrimaryNameServer, StringComparison.OrdinalIgnoreCase)) + zoneType = AuthZoneType.Primary; + else + zoneType = AuthZoneType.Stub; + + AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, zoneType, zoneDisabled); //create zone Zone authZone = CreateEmptyZone(zoneInfo);