From 2d8604f1b68c93a7ebb79f8068bfc31e80dd0373 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Sep 2024 17:35:33 +0530 Subject: [PATCH] AuthZoneInfo: updated code to add support for Secondary Forwarder, Catalog, and Secondary Catalog zones. Added support for Query Access feature, zone transfer ACL, and update ACL. Added support to store secondary zone parameters for primary server connectivity. Added support for ZONEMD validation. Code refactoring done. --- DnsServerCore/Dns/Zones/AuthZoneInfo.cs | 2094 ++++++++++++++++------- 1 file changed, 1437 insertions(+), 657 deletions(-) diff --git a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs index 068d637b..036f6ddd 100644 --- a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs +++ b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs @@ -24,7 +24,6 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; -using System.Threading.Tasks; using TechnitiumLibrary.IO; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; @@ -38,7 +37,10 @@ namespace DnsServerCore.Dns.Zones Primary = 1, Secondary = 2, Stub = 3, - Forwarder = 4 + Forwarder = 4, + SecondaryForwarder = 5, + Catalog = 6, + SecondaryCatalog = 7 } public sealed class AuthZoneInfo : IComparable @@ -49,20 +51,40 @@ namespace DnsServerCore.Dns.Zones readonly string _name; readonly AuthZoneType _type; + readonly DateTime _lastModified; readonly bool _disabled; + + readonly string _catalogZoneName; + readonly bool _overrideCatalogQueryAccess; + readonly bool _overrideCatalogZoneTransfer; + readonly bool _overrideCatalogNotify; + readonly bool _overrideCatalogPrimaryNameServers; //only for secondary zones + + readonly AuthZoneQueryAccess _queryAccess; + readonly IReadOnlyCollection _queryAccessNetworkACL; + readonly AuthZoneTransfer _zoneTransfer; - readonly IReadOnlyCollection _zoneTransferNameServers; + readonly IReadOnlyCollection _zoneTransferNetworkACL; + readonly IReadOnlyDictionary _zoneTransferTsigKeyNames; + readonly IReadOnlyList _zoneHistory; //for IXFR support + readonly AuthZoneNotify _notify; readonly IReadOnlyCollection _notifyNameServers; + readonly AuthZoneUpdate _update; - readonly IReadOnlyCollection _updateIpAddresses; - readonly DateTime _lastModified; - readonly DateTime _expiry; - readonly bool _validationFailed; //only for secondary zones - readonly IReadOnlyList _zoneHistory; //for IXFR support - readonly IReadOnlyDictionary _zoneTransferTsigKeyNames; + readonly IReadOnlyCollection _updateNetworkACL; readonly IReadOnlyDictionary>> _updateSecurityPolicies; - readonly IReadOnlyCollection _dnssecPrivateKeys; + + readonly IReadOnlyCollection _dnssecPrivateKeys; //only for primary zones + + readonly IReadOnlyList _primaryNameServerAddresses; //only for secondary and stub zones + readonly DnsTransportProtocol _primaryZoneTransferProtocol; //only for secondary zones + readonly string _primaryZoneTransferTsigKeyName; //only for secondary zones + + readonly DateTime _expiry; //only for secondary and stub zones + + readonly bool _validateZone; //only for secondary zones + readonly bool _validationFailed; //only for secondary zones #endregion @@ -72,7 +94,9 @@ namespace DnsServerCore.Dns.Zones { _name = name; _type = type; + _lastModified = DateTime.UtcNow; _disabled = disabled; + _queryAccess = AuthZoneQueryAccess.Allow; switch (_type) { @@ -106,338 +130,497 @@ namespace DnsServerCore.Dns.Zones case 9: case 10: case 11: - case 12: - _name = bR.ReadShortString(); - _type = (AuthZoneType)bR.ReadByte(); - _disabled = bR.ReadBoolean(); - - if (version >= 2) { + _name = bR.ReadShortString(); + _type = (AuthZoneType)bR.ReadByte(); + _disabled = bR.ReadBoolean(); + + _queryAccess = AuthZoneQueryAccess.Allow; + + if (version >= 2) { - _zoneTransfer = (AuthZoneTransfer)bR.ReadByte(); - - int count = bR.ReadByte(); - if (count > 0) { - NetworkAddress[] networks = new NetworkAddress[count]; + _zoneTransfer = (AuthZoneTransfer)bR.ReadByte(); - if (version >= 9) - { - for (int i = 0; i < count; i++) - networks[i] = NetworkAddress.ReadFrom(bR); - } - else - { - for (int i = 0; i < count; i++) - { - IPAddress address = IPAddressExtensions.ReadFrom(bR); - - switch (address.AddressFamily) - { - case AddressFamily.InterNetwork: - networks[i] = new NetworkAddress(address, 32); - break; - - case AddressFamily.InterNetworkV6: - networks[i] = new NetworkAddress(address, 128); - break; - - default: - throw new InvalidOperationException(); - } - } - } - - _zoneTransferNameServers = networks; - } - } - - { - _notify = (AuthZoneNotify)bR.ReadByte(); - - int count = bR.ReadByte(); - if (count > 0) - { - IPAddress[] nameServers = new IPAddress[count]; - - for (int i = 0; i < count; i++) - nameServers[i] = IPAddressExtensions.ReadFrom(bR); - - _notifyNameServers = nameServers; - } - } - - if (version >= 6) - { - _update = (AuthZoneUpdate)bR.ReadByte(); - - int count = bR.ReadByte(); - if (count > 0) - { - NetworkAddress[] networks = new NetworkAddress[count]; - - if (version >= 9) - { - for (int i = 0; i < count; i++) - networks[i] = NetworkAddress.ReadFrom(bR); - } - else - { - for (int i = 0; i < count; i++) - { - IPAddress address = IPAddressExtensions.ReadFrom(bR); - - switch (address.AddressFamily) - { - case AddressFamily.InterNetwork: - networks[i] = new NetworkAddress(address, 32); - break; - - case AddressFamily.InterNetworkV6: - networks[i] = new NetworkAddress(address, 128); - break; - - default: - throw new InvalidOperationException(); - } - } - } - - _updateIpAddresses = networks; - } - } - } - else - { - switch (_type) - { - case AuthZoneType.Primary: - _zoneTransfer = AuthZoneTransfer.AllowOnlyZoneNameServers; - _notify = AuthZoneNotify.ZoneNameServers; - _update = AuthZoneUpdate.Deny; - break; - - default: - _zoneTransfer = AuthZoneTransfer.Deny; - _notify = AuthZoneNotify.None; - _update = AuthZoneUpdate.Deny; - break; - } - } - - if (version >= 8) - _lastModified = bR.ReadDateTime(); - else - _lastModified = lastModified; - - switch (_type) - { - case AuthZoneType.Primary: - if (version >= 3) - { - int count = bR.ReadInt32(); - DnsResourceRecord[] zoneHistory = new DnsResourceRecord[count]; - - if (version >= 11) - { - for (int i = 0; i < count; i++) - { - zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); - - if (bR.ReadBoolean()) - zoneHistory[i].Tag = new HistoryRecordInfo(bR); - } - } - else - { - for (int i = 0; i < count; i++) - { - zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); - zoneHistory[i].Tag = new HistoryRecordInfo(bR); - } - } - - _zoneHistory = zoneHistory; - } - - if (version >= 4) - { - int count = bR.ReadByte(); - Dictionary tsigKeyNames = new Dictionary(count); - - for (int i = 0; i < count; i++) - tsigKeyNames.Add(bR.ReadShortString(), null); - - _zoneTransferTsigKeyNames = tsigKeyNames; - } - - if (version >= 7) - { - int count = bR.ReadByte(); - Dictionary>> updateSecurityPolicies = new Dictionary>>(count); - - for (int i = 0; i < count; i++) - { - string tsigKeyName = bR.ReadShortString().ToLower(); - - if (!updateSecurityPolicies.TryGetValue(tsigKeyName, out IReadOnlyDictionary> policyMap)) - { - policyMap = new Dictionary>(); - updateSecurityPolicies.Add(tsigKeyName, policyMap); - } - - int policyCount = bR.ReadByte(); - - for (int j = 0; j < policyCount; j++) - { - string domain = bR.ReadShortString().ToLower(); - - if (!policyMap.TryGetValue(domain, out IReadOnlyList types)) - { - types = new List(); - (policyMap as Dictionary>).Add(domain, types); - } - - int typeCount = bR.ReadByte(); - - for (int k = 0; k < typeCount; k++) - (types as List).Add((DnsResourceRecordType)bR.ReadUInt16()); - } - } - - _updateSecurityPolicies = updateSecurityPolicies; - } - else if (version >= 6) - { - int count = bR.ReadByte(); - Dictionary>> updateSecurityPolicies = new Dictionary>>(count); - - Dictionary> defaultAllowPolicy = new Dictionary>(1); - defaultAllowPolicy.Add(_name, new List() { DnsResourceRecordType.ANY }); - defaultAllowPolicy.Add("*." + _name, new List() { DnsResourceRecordType.ANY }); - - for (int i = 0; i < count; i++) - updateSecurityPolicies.Add(bR.ReadShortString().ToLower(), defaultAllowPolicy); - - _updateSecurityPolicies = updateSecurityPolicies; - } - - if (version >= 5) - { int count = bR.ReadByte(); if (count > 0) { - List dnssecPrivateKeys = new List(count); + NetworkAddress[] networks = new NetworkAddress[count]; - for (int i = 0; i < count; i++) - dnssecPrivateKeys.Add(DnssecPrivateKey.ReadFrom(bR)); - - _dnssecPrivateKeys = dnssecPrivateKeys; - } - } - - break; - - case AuthZoneType.Secondary: - _expiry = bR.ReadDateTime(); - - if (version >= 12) - _validationFailed = bR.ReadBoolean(); - - if (version >= 4) - { - int count = bR.ReadInt32(); - DnsResourceRecord[] zoneHistory = new DnsResourceRecord[count]; - - if (version >= 11) - { - for (int i = 0; i < count; i++) + if (version >= 9) { - zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); - - if (bR.ReadBoolean()) - zoneHistory[i].Tag = new HistoryRecordInfo(bR); + for (int i = 0; i < count; i++) + networks[i] = NetworkAddress.ReadFrom(bR); } - } - else - { - for (int i = 0; i < count; i++) + else { - zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); - zoneHistory[i].Tag = new HistoryRecordInfo(bR); - } - } - - _zoneHistory = zoneHistory; - } - - if (version >= 4) - { - int count = bR.ReadByte(); - Dictionary tsigKeyNames = new Dictionary(count); - - for (int i = 0; i < count; i++) - tsigKeyNames.Add(bR.ReadShortString(), null); - - _zoneTransferTsigKeyNames = tsigKeyNames; - } - - if (version == 6) - { - //MUST skip old version data - int count = bR.ReadByte(); - Dictionary tsigKeyNames = new Dictionary(count); - - for (int i = 0; i < count; i++) - tsigKeyNames.Add(bR.ReadShortString(), null); - } - - break; - - case AuthZoneType.Stub: - _expiry = bR.ReadDateTime(); - break; - - case AuthZoneType.Forwarder: - if (version >= 10) - { - int count = bR.ReadByte(); - Dictionary>> updateSecurityPolicies = new Dictionary>>(count); - - for (int i = 0; i < count; i++) - { - string tsigKeyName = bR.ReadShortString().ToLower(); - - if (!updateSecurityPolicies.TryGetValue(tsigKeyName, out IReadOnlyDictionary> policyMap)) - { - policyMap = new Dictionary>(); - updateSecurityPolicies.Add(tsigKeyName, policyMap); - } - - int policyCount = bR.ReadByte(); - - for (int j = 0; j < policyCount; j++) - { - string domain = bR.ReadShortString().ToLower(); - - if (!policyMap.TryGetValue(domain, out IReadOnlyList types)) + for (int i = 0; i < count; i++) { - types = new List(); - (policyMap as Dictionary>).Add(domain, types); + IPAddress address = IPAddressExtensions.ReadFrom(bR); + + switch (address.AddressFamily) + { + case AddressFamily.InterNetwork: + networks[i] = new NetworkAddress(address, 32); + break; + + case AddressFamily.InterNetworkV6: + networks[i] = new NetworkAddress(address, 128); + break; + + default: + throw new InvalidOperationException(); + } + } + } + + _zoneTransferNetworkACL = ConvertDenyAllowToACL(null, networks); + } + } + + { + _notify = (AuthZoneNotify)bR.ReadByte(); + + int count = bR.ReadByte(); + if (count > 0) + { + IPAddress[] nameServers = new IPAddress[count]; + + for (int i = 0; i < count; i++) + nameServers[i] = IPAddressExtensions.ReadFrom(bR); + + _notifyNameServers = nameServers; + } + } + + if (version >= 6) + { + _update = (AuthZoneUpdate)bR.ReadByte(); + + int count = bR.ReadByte(); + if (count > 0) + { + NetworkAddress[] networks = new NetworkAddress[count]; + + if (version >= 9) + { + for (int i = 0; i < count; i++) + networks[i] = NetworkAddress.ReadFrom(bR); + } + else + { + for (int i = 0; i < count; i++) + { + IPAddress address = IPAddressExtensions.ReadFrom(bR); + + switch (address.AddressFamily) + { + case AddressFamily.InterNetwork: + networks[i] = new NetworkAddress(address, 32); + break; + + case AddressFamily.InterNetworkV6: + networks[i] = new NetworkAddress(address, 128); + break; + + default: + throw new InvalidOperationException(); + } + } + } + + _updateNetworkACL = ConvertDenyAllowToACL(null, networks); + } + } + } + else + { + switch (_type) + { + case AuthZoneType.Primary: + _zoneTransfer = AuthZoneTransfer.AllowOnlyZoneNameServers; + _notify = AuthZoneNotify.ZoneNameServers; + _update = AuthZoneUpdate.Deny; + break; + + default: + _zoneTransfer = AuthZoneTransfer.Deny; + _notify = AuthZoneNotify.None; + _update = AuthZoneUpdate.Deny; + break; + } + } + + if (version >= 8) + _lastModified = bR.ReadDateTime(); + else + _lastModified = lastModified; + + switch (_type) + { + case AuthZoneType.Primary: + { + if (version >= 3) + { + int count = bR.ReadInt32(); + DnsResourceRecord[] zoneHistory = new DnsResourceRecord[count]; + + if (version >= 11) + { + for (int i = 0; i < count; i++) + { + zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); + + if (bR.ReadBoolean()) + zoneHistory[i].Tag = new HistoryRecordInfo(bR); + } + } + else + { + for (int i = 0; i < count; i++) + { + zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); + zoneHistory[i].Tag = new HistoryRecordInfo(bR); + } } - int typeCount = bR.ReadByte(); + _zoneHistory = zoneHistory; + } - for (int k = 0; k < typeCount; k++) - (types as List).Add((DnsResourceRecordType)bR.ReadUInt16()); + if (version >= 4) + { + int count = bR.ReadByte(); + Dictionary tsigKeyNames = new Dictionary(count); + + for (int i = 0; i < count; i++) + tsigKeyNames.Add(bR.ReadShortString(), null); + + _zoneTransferTsigKeyNames = tsigKeyNames; + } + + if (version >= 7) + { + int count = bR.ReadByte(); + Dictionary>> updateSecurityPolicies = new Dictionary>>(count); + + for (int i = 0; i < count; i++) + { + string tsigKeyName = bR.ReadShortString().ToLowerInvariant(); + + if (!updateSecurityPolicies.TryGetValue(tsigKeyName, out IReadOnlyDictionary> policyMap)) + { + policyMap = new Dictionary>(); + updateSecurityPolicies.Add(tsigKeyName, policyMap); + } + + int policyCount = bR.ReadByte(); + + for (int j = 0; j < policyCount; j++) + { + string domain = bR.ReadShortString().ToLowerInvariant(); + + if (!policyMap.TryGetValue(domain, out IReadOnlyList types)) + { + types = new List(); + (policyMap as Dictionary>).Add(domain, types); + } + + int typeCount = bR.ReadByte(); + + for (int k = 0; k < typeCount; k++) + (types as List).Add((DnsResourceRecordType)bR.ReadUInt16()); + } + } + + _updateSecurityPolicies = updateSecurityPolicies; + } + else if (version >= 6) + { + int count = bR.ReadByte(); + Dictionary>> updateSecurityPolicies = new Dictionary>>(count); + + Dictionary> defaultAllowPolicy = new Dictionary>(1); + defaultAllowPolicy.Add(_name, new List() { DnsResourceRecordType.ANY }); + defaultAllowPolicy.Add("*." + _name, new List() { DnsResourceRecordType.ANY }); + + for (int i = 0; i < count; i++) + updateSecurityPolicies.Add(bR.ReadShortString().ToLowerInvariant(), defaultAllowPolicy); + + _updateSecurityPolicies = updateSecurityPolicies; + } + + if (version >= 5) + { + int count = bR.ReadByte(); + if (count > 0) + { + List dnssecPrivateKeys = new List(count); + + for (int i = 0; i < count; i++) + dnssecPrivateKeys.Add(DnssecPrivateKey.ReadFrom(bR)); + + _dnssecPrivateKeys = dnssecPrivateKeys; + } } } + break; - _updateSecurityPolicies = updateSecurityPolicies; - } - break; + case AuthZoneType.Secondary: + { + _expiry = bR.ReadDateTime(); + + if (version >= 4) + { + int count = bR.ReadInt32(); + DnsResourceRecord[] zoneHistory = new DnsResourceRecord[count]; + + if (version >= 11) + { + for (int i = 0; i < count; i++) + { + zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); + + if (bR.ReadBoolean()) + zoneHistory[i].Tag = new HistoryRecordInfo(bR); + } + } + else + { + for (int i = 0; i < count; i++) + { + zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); + zoneHistory[i].Tag = new HistoryRecordInfo(bR); + } + } + + _zoneHistory = zoneHistory; + } + + if (version >= 4) + { + int count = bR.ReadByte(); + Dictionary tsigKeyNames = new Dictionary(count); + + for (int i = 0; i < count; i++) + tsigKeyNames.Add(bR.ReadShortString(), null); + + _zoneTransferTsigKeyNames = tsigKeyNames; + } + + if (version == 6) + { + //MUST skip old version data + int count = bR.ReadByte(); + Dictionary tsigKeyNames = new Dictionary(count); + + for (int i = 0; i < count; i++) + tsigKeyNames.Add(bR.ReadShortString(), null); + } + } + break; + + case AuthZoneType.Stub: + { + _expiry = bR.ReadDateTime(); + } + break; + + case AuthZoneType.Forwarder: + { + if (version >= 10) + { + int count = bR.ReadByte(); + Dictionary>> updateSecurityPolicies = new Dictionary>>(count); + + for (int i = 0; i < count; i++) + { + string tsigKeyName = bR.ReadShortString().ToLowerInvariant(); + + if (!updateSecurityPolicies.TryGetValue(tsigKeyName, out IReadOnlyDictionary> policyMap)) + { + policyMap = new Dictionary>(); + updateSecurityPolicies.Add(tsigKeyName, policyMap); + } + + int policyCount = bR.ReadByte(); + + for (int j = 0; j < policyCount; j++) + { + string domain = bR.ReadShortString().ToLowerInvariant(); + + if (!policyMap.TryGetValue(domain, out IReadOnlyList types)) + { + types = new List(); + (policyMap as Dictionary>).Add(domain, types); + } + + int typeCount = bR.ReadByte(); + + for (int k = 0; k < typeCount; k++) + (types as List).Add((DnsResourceRecordType)bR.ReadUInt16()); + } + } + + _updateSecurityPolicies = updateSecurityPolicies; + } + } + break; + } } + break; + case 12: + { + _name = bR.ReadShortString(); + _type = (AuthZoneType)bR.ReadByte(); + _lastModified = bR.ReadDateTime(); + _disabled = bR.ReadBoolean(); + + switch (_type) + { + case AuthZoneType.Primary: + _catalogZoneName = bR.ReadShortString(); + if (_catalogZoneName.Length == 0) + _catalogZoneName = null; + + _overrideCatalogQueryAccess = bR.ReadBoolean(); + _overrideCatalogZoneTransfer = bR.ReadBoolean(); + _overrideCatalogNotify = bR.ReadBoolean(); + + _queryAccess = (AuthZoneQueryAccess)bR.ReadByte(); + _queryAccessNetworkACL = ReadNetworkACLFrom(bR); + + _zoneTransfer = (AuthZoneTransfer)bR.ReadByte(); + _zoneTransferNetworkACL = ReadNetworkACLFrom(bR); + _zoneTransferTsigKeyNames = ReadZoneTransferTsigKeyNamesFrom(bR); + _zoneHistory = ReadZoneHistoryFrom(bR); + + _notify = (AuthZoneNotify)bR.ReadByte(); + _notifyNameServers = ReadIPAddressesFrom(bR); + + _update = (AuthZoneUpdate)bR.ReadByte(); + _updateNetworkACL = ReadNetworkACLFrom(bR); + _updateSecurityPolicies = ReadUpdateSecurityPoliciesFrom(bR); + + _dnssecPrivateKeys = ReadDnssecPrivateKeysFrom(bR); + break; + + case AuthZoneType.Secondary: + _catalogZoneName = bR.ReadShortString(); + if (_catalogZoneName.Length == 0) + _catalogZoneName = null; + + _overrideCatalogPrimaryNameServers = bR.ReadBoolean(); + + _queryAccess = (AuthZoneQueryAccess)bR.ReadByte(); + _queryAccessNetworkACL = ReadNetworkACLFrom(bR); + + _zoneTransfer = (AuthZoneTransfer)bR.ReadByte(); + _zoneTransferNetworkACL = ReadNetworkACLFrom(bR); + _zoneTransferTsigKeyNames = ReadZoneTransferTsigKeyNamesFrom(bR); + _zoneHistory = ReadZoneHistoryFrom(bR); + + _notify = (AuthZoneNotify)bR.ReadByte(); + _notifyNameServers = ReadIPAddressesFrom(bR); + + _update = (AuthZoneUpdate)bR.ReadByte(); + _updateNetworkACL = ReadNetworkACLFrom(bR); + + _primaryNameServerAddresses = ReadNameServerAddressesFrom(bR); + _primaryZoneTransferProtocol = (DnsTransportProtocol)bR.ReadByte(); + _primaryZoneTransferTsigKeyName = bR.ReadShortString(); + if (_primaryZoneTransferTsigKeyName.Length == 0) + _primaryZoneTransferTsigKeyName = null; + + _expiry = bR.ReadDateTime(); + _validateZone = bR.ReadBoolean(); + _validationFailed = bR.ReadBoolean(); + break; + + case AuthZoneType.Stub: + _catalogZoneName = bR.ReadShortString(); + if (_catalogZoneName.Length == 0) + _catalogZoneName = null; + + _overrideCatalogQueryAccess = bR.ReadBoolean(); + + _queryAccess = (AuthZoneQueryAccess)bR.ReadByte(); + _queryAccessNetworkACL = ReadNetworkACLFrom(bR); + + _primaryNameServerAddresses = ReadNameServerAddressesFrom(bR); + + _expiry = bR.ReadDateTime(); + break; + + case AuthZoneType.Forwarder: + _catalogZoneName = bR.ReadShortString(); + if (_catalogZoneName.Length == 0) + _catalogZoneName = null; + + _overrideCatalogQueryAccess = bR.ReadBoolean(); + _overrideCatalogZoneTransfer = bR.ReadBoolean(); + _overrideCatalogNotify = bR.ReadBoolean(); + + _queryAccess = (AuthZoneQueryAccess)bR.ReadByte(); + _queryAccessNetworkACL = ReadNetworkACLFrom(bR); + + _zoneTransfer = (AuthZoneTransfer)bR.ReadByte(); + _zoneTransferNetworkACL = ReadNetworkACLFrom(bR); + _zoneTransferTsigKeyNames = ReadZoneTransferTsigKeyNamesFrom(bR); + _zoneHistory = ReadZoneHistoryFrom(bR); + + _notify = (AuthZoneNotify)bR.ReadByte(); + _notifyNameServers = ReadIPAddressesFrom(bR); + + _update = (AuthZoneUpdate)bR.ReadByte(); + _updateNetworkACL = ReadNetworkACLFrom(bR); + _updateSecurityPolicies = ReadUpdateSecurityPoliciesFrom(bR); + break; + + case AuthZoneType.SecondaryForwarder: + _catalogZoneName = bR.ReadShortString(); + if (_catalogZoneName.Length == 0) + _catalogZoneName = null; + + _queryAccess = (AuthZoneQueryAccess)bR.ReadByte(); + _queryAccessNetworkACL = ReadNetworkACLFrom(bR); + + _update = (AuthZoneUpdate)bR.ReadByte(); + _updateNetworkACL = ReadNetworkACLFrom(bR); + + _primaryNameServerAddresses = ReadNameServerAddressesFrom(bR); + _primaryZoneTransferProtocol = (DnsTransportProtocol)bR.ReadByte(); + _primaryZoneTransferTsigKeyName = bR.ReadShortString(); + if (_primaryZoneTransferTsigKeyName.Length == 0) + _primaryZoneTransferTsigKeyName = null; + + _expiry = bR.ReadDateTime(); + break; + + case AuthZoneType.Catalog: + _queryAccess = (AuthZoneQueryAccess)bR.ReadByte(); + _queryAccessNetworkACL = ReadNetworkACLFrom(bR); + + _zoneTransfer = (AuthZoneTransfer)bR.ReadByte(); + _zoneTransferNetworkACL = ReadNetworkACLFrom(bR); + _zoneTransferTsigKeyNames = ReadZoneTransferTsigKeyNamesFrom(bR); + _zoneHistory = ReadZoneHistoryFrom(bR); + + _notify = (AuthZoneNotify)bR.ReadByte(); + _notifyNameServers = ReadIPAddressesFrom(bR); + break; + + case AuthZoneType.SecondaryCatalog: + _primaryNameServerAddresses = ReadNameServerAddressesFrom(bR); + _primaryZoneTransferProtocol = (DnsTransportProtocol)bR.ReadByte(); + _primaryZoneTransferTsigKeyName = bR.ReadShortString(); + if (_primaryZoneTransferTsigKeyName.Length == 0) + _primaryZoneTransferTsigKeyName = null; + + _expiry = bR.ReadDateTime(); + break; + } + } break; default: @@ -449,86 +632,486 @@ namespace DnsServerCore.Dns.Zones { _apexZone = apexZone; _name = _apexZone.Name; + _lastModified = _apexZone.LastModified; + _disabled = _apexZone.Disabled; if (_apexZone is PrimaryZone primaryZone) { _type = AuthZoneType.Primary; - if (loadHistory) - _zoneHistory = primaryZone.GetZoneHistory(); + _catalogZoneName = _apexZone.CatalogZoneName; + _overrideCatalogQueryAccess = _apexZone.OverrideCatalogQueryAccess; + _overrideCatalogZoneTransfer = _apexZone.OverrideCatalogZoneTransfer; + _overrideCatalogNotify = _apexZone.OverrideCatalogNotify; + + _queryAccess = _apexZone.QueryAccess; + _queryAccessNetworkACL = _apexZone.QueryAccessNetworkACL; + + _zoneTransfer = _apexZone.ZoneTransfer; + _zoneTransferNetworkACL = _apexZone.ZoneTransferNetworkACL; + _zoneTransferTsigKeyNames = _apexZone.ZoneTransferTsigKeyNames; + + if (loadHistory) + _zoneHistory = _apexZone.GetZoneHistory(); + + _notify = _apexZone.Notify; + _notifyNameServers = _apexZone.NotifyNameServers; + + _update = _apexZone.Update; + _updateNetworkACL = _apexZone.UpdateNetworkACL; + _updateSecurityPolicies = _apexZone.UpdateSecurityPolicies; - _zoneTransferTsigKeyNames = primaryZone.ZoneTransferTsigKeyNames; - _updateSecurityPolicies = primaryZone.UpdateSecurityPolicies; _dnssecPrivateKeys = primaryZone.DnssecPrivateKeys; } + else if (_apexZone is SecondaryCatalogZone secondaryCatalogZone) + { + _type = AuthZoneType.SecondaryCatalog; + + _primaryNameServerAddresses = secondaryCatalogZone.PrimaryNameServerAddresses; + _primaryZoneTransferProtocol = secondaryCatalogZone.PrimaryZoneTransferProtocol; + _primaryZoneTransferTsigKeyName = secondaryCatalogZone.PrimaryZoneTransferTsigKeyName; + + _expiry = secondaryCatalogZone.Expiry; + } + else if (_apexZone is SecondaryForwarderZone secondaryForwarderZone) + { + _type = AuthZoneType.SecondaryForwarder; + + _catalogZoneName = _apexZone.CatalogZoneName; + + _queryAccess = _apexZone.QueryAccess; + _queryAccessNetworkACL = _apexZone.QueryAccessNetworkACL; + + _update = _apexZone.Update; + _updateNetworkACL = _apexZone.UpdateNetworkACL; + + _primaryNameServerAddresses = secondaryForwarderZone.PrimaryNameServerAddresses; + _primaryZoneTransferProtocol = secondaryForwarderZone.PrimaryZoneTransferProtocol; + _primaryZoneTransferTsigKeyName = secondaryForwarderZone.PrimaryZoneTransferTsigKeyName; + + _expiry = secondaryForwarderZone.Expiry; + } else if (_apexZone is SecondaryZone secondaryZone) { _type = AuthZoneType.Secondary; + _catalogZoneName = _apexZone.CatalogZoneName; + _overrideCatalogPrimaryNameServers = secondaryZone.OverrideCatalogPrimaryNameServers; + + _queryAccess = _apexZone.QueryAccess; + _queryAccessNetworkACL = _apexZone.QueryAccessNetworkACL; + + _zoneTransfer = _apexZone.ZoneTransfer; + _zoneTransferNetworkACL = _apexZone.ZoneTransferNetworkACL; + _zoneTransferTsigKeyNames = _apexZone.ZoneTransferTsigKeyNames; + if (loadHistory) - _zoneHistory = secondaryZone.GetZoneHistory(); + _zoneHistory = _apexZone.GetZoneHistory(); + + _notify = _apexZone.Notify; + _notifyNameServers = _apexZone.NotifyNameServers; + + _update = _apexZone.Update; + _updateNetworkACL = _apexZone.UpdateNetworkACL; + + _primaryNameServerAddresses = secondaryZone.PrimaryNameServerAddresses; + _primaryZoneTransferProtocol = secondaryZone.PrimaryZoneTransferProtocol; + _primaryZoneTransferTsigKeyName = secondaryZone.PrimaryZoneTransferTsigKeyName; _expiry = secondaryZone.Expiry; + _validateZone = secondaryZone.ValidateZone; _validationFailed = secondaryZone.ValidationFailed; - _zoneTransferTsigKeyNames = secondaryZone.ZoneTransferTsigKeyNames; } else if (_apexZone is StubZone stubZone) { _type = AuthZoneType.Stub; + + _catalogZoneName = _apexZone.CatalogZoneName; + _overrideCatalogQueryAccess = _apexZone.OverrideCatalogQueryAccess; + + _queryAccess = _apexZone.QueryAccess; + _queryAccessNetworkACL = _apexZone.QueryAccessNetworkACL; + + _primaryNameServerAddresses = stubZone.PrimaryNameServerAddresses; + _expiry = stubZone.Expiry; } - else if (_apexZone is ForwarderZone forwarderZone) + else if (_apexZone is CatalogZone) + { + _type = AuthZoneType.Catalog; + + _queryAccess = _apexZone.QueryAccess; + _queryAccessNetworkACL = _apexZone.QueryAccessNetworkACL; + + _zoneTransfer = _apexZone.ZoneTransfer; + _zoneTransferNetworkACL = _apexZone.ZoneTransferNetworkACL; + _zoneTransferTsigKeyNames = _apexZone.ZoneTransferTsigKeyNames; + + if (loadHistory) + _zoneHistory = _apexZone.GetZoneHistory(); + + _notify = _apexZone.Notify; + _notifyNameServers = _apexZone.NotifyNameServers; + } + else if (_apexZone is ForwarderZone) { _type = AuthZoneType.Forwarder; - _updateSecurityPolicies = forwarderZone.UpdateSecurityPolicies; + + _catalogZoneName = _apexZone.CatalogZoneName; + _overrideCatalogQueryAccess = _apexZone.OverrideCatalogQueryAccess; + _overrideCatalogZoneTransfer = _apexZone.OverrideCatalogZoneTransfer; + _overrideCatalogNotify = _apexZone.OverrideCatalogNotify; + + _queryAccess = _apexZone.QueryAccess; + _queryAccessNetworkACL = _apexZone.QueryAccessNetworkACL; + + _zoneTransfer = _apexZone.ZoneTransfer; + _zoneTransferNetworkACL = _apexZone.ZoneTransferNetworkACL; + _zoneTransferTsigKeyNames = _apexZone.ZoneTransferTsigKeyNames; + + if (loadHistory) + _zoneHistory = _apexZone.GetZoneHistory(); + + _notify = _apexZone.Notify; + _notifyNameServers = _apexZone.NotifyNameServers; + + _update = _apexZone.Update; + _updateNetworkACL = _apexZone.UpdateNetworkACL; + _updateSecurityPolicies = _apexZone.UpdateSecurityPolicies; } else { _type = AuthZoneType.Unknown; } + } - _disabled = _apexZone.Disabled; - _zoneTransfer = _apexZone.ZoneTransfer; - _zoneTransferNameServers = _apexZone.ZoneTransferNameServers; - _notify = _apexZone.Notify; - _notifyNameServers = _apexZone.NotifyNameServers; - _update = _apexZone.Update; - _updateIpAddresses = _apexZone.UpdateIpAddresses; - _lastModified = _apexZone.LastModified; + #endregion + + #region static + + public static string GetZoneTypeName(AuthZoneType type) + { + switch (type) + { + case AuthZoneType.SecondaryForwarder: + return "Secondary Forwarder"; + + case AuthZoneType.SecondaryCatalog: + return "Secondary Catalog"; + + default: + return type.ToString(); + } + } + + internal static NameServerAddress[] ReadNameServerAddressesFrom(BinaryReader bR) + { + int count = bR.ReadByte(); + if (count < 1) + return null; + + NameServerAddress[] nameServerAddresses = new NameServerAddress[count]; + + for (int i = 0; i < count; i++) + nameServerAddresses[i] = new NameServerAddress(bR); + + return nameServerAddresses; + } + + internal static void WriteNameServerAddressesTo(IReadOnlyCollection nameServerAddresses, BinaryWriter bW) + { + if (nameServerAddresses is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(nameServerAddresses.Count)); + + foreach (NameServerAddress network in nameServerAddresses) + network.WriteTo(bW); + } + } + + internal static NetworkAccessControl[] ReadNetworkACLFrom(BinaryReader bR) + { + int count = bR.ReadByte(); + if (count < 1) + return null; + + NetworkAccessControl[] acl = new NetworkAccessControl[count]; + + for (int i = 0; i < count; i++) + acl[i] = NetworkAccessControl.ReadFrom(bR); + + return acl; + } + + internal static void WriteNetworkACLTo(IReadOnlyCollection acl, BinaryWriter bW) + { + if (acl is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(acl.Count)); + + foreach (NetworkAccessControl nac in acl) + nac.WriteTo(bW); + } + } + + internal static NetworkAddress[] ReadNetworkAddressesFrom(BinaryReader bR) + { + int count = bR.ReadByte(); + if (count < 1) + return null; + + NetworkAddress[] networks = new NetworkAddress[count]; + + for (int i = 0; i < count; i++) + networks[i] = NetworkAddress.ReadFrom(bR); + + return networks; + } + + internal static void WriteNetworkAddressesTo(IReadOnlyCollection networkAddresses, BinaryWriter bW) + { + if (networkAddresses is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(networkAddresses.Count)); + + foreach (NetworkAddress network in networkAddresses) + network.WriteTo(bW); + } + } + + internal static IPAddress[] ReadIPAddressesFrom(BinaryReader bR) + { + int count = bR.ReadByte(); + if (count < 1) + return null; + + IPAddress[] ipAddresses = new IPAddress[count]; + + for (int i = 0; i < count; i++) + ipAddresses[i] = IPAddressExtensions.ReadFrom(bR); + + return ipAddresses; + } + + internal static void WriteIPAddressesTo(IReadOnlyCollection ipAddresses, BinaryWriter bW) + { + if (ipAddresses is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(ipAddresses.Count)); + + foreach (IPAddress ipAddress in ipAddresses) + ipAddress.WriteTo(bW); + } + } + + internal static List ConvertDenyAllowToACL(NetworkAddress[] deniedNetworks, NetworkAddress[] allowedNetworks) + { + List acl = new List(); + + if (deniedNetworks is not null) + { + foreach (NetworkAddress network in deniedNetworks) + acl.Add(new NetworkAccessControl(network, true)); + } + + if (allowedNetworks is not null) + { + foreach (NetworkAddress network in allowedNetworks) + acl.Add(new NetworkAccessControl(network)); + } + + if (acl.Count > 0) + return acl; + + return null; + } + + #endregion + + #region private + + private static Dictionary ReadZoneTransferTsigKeyNamesFrom(BinaryReader bR) + { + int count = bR.ReadByte(); + Dictionary zoneTransferTsigKeyNames = new Dictionary(count); + + for (int i = 0; i < count; i++) + zoneTransferTsigKeyNames.Add(bR.ReadShortString(), null); + + return zoneTransferTsigKeyNames; + } + + private void WriteZoneTransferTsigKeyNamesTo(BinaryWriter bW) + { + if (_zoneTransferTsigKeyNames is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(_zoneTransferTsigKeyNames.Count)); + + foreach (KeyValuePair tsigKeyName in _zoneTransferTsigKeyNames) + bW.WriteShortString(tsigKeyName.Key); + } + } + + private static DnsResourceRecord[] ReadZoneHistoryFrom(BinaryReader bR) + { + int count = bR.ReadInt32(); + DnsResourceRecord[] zoneHistory = new DnsResourceRecord[count]; + + for (int i = 0; i < count; i++) + { + zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); + + if (bR.ReadBoolean()) + zoneHistory[i].Tag = new HistoryRecordInfo(bR); + } + + return zoneHistory; + } + + private void WriteZoneHistoryTo(BinaryWriter bW) + { + if (_zoneHistory is null) + { + bW.Write(0); + } + else + { + bW.Write(_zoneHistory.Count); + + foreach (DnsResourceRecord record in _zoneHistory) + { + record.WriteTo(bW.BaseStream); + + if (record.Tag is HistoryRecordInfo rrInfo) + { + bW.Write(true); + rrInfo.WriteTo(bW); + } + else + { + bW.Write(false); + } + } + } + } + + private static Dictionary>> ReadUpdateSecurityPoliciesFrom(BinaryReader bR) + { + int count = bR.ReadInt32(); + Dictionary>> updateSecurityPolicies = new Dictionary>>(count); + + for (int i = 0; i < count; i++) + { + string tsigKeyName = bR.ReadShortString().ToLowerInvariant(); + + if (!updateSecurityPolicies.TryGetValue(tsigKeyName, out IReadOnlyDictionary> policyMap)) + { + policyMap = new Dictionary>(); + updateSecurityPolicies.Add(tsigKeyName, policyMap); + } + + int policyCount = bR.ReadByte(); + + for (int j = 0; j < policyCount; j++) + { + string domain = bR.ReadShortString().ToLowerInvariant(); + + if (!policyMap.TryGetValue(domain, out IReadOnlyList types)) + { + types = new List(); + (policyMap as Dictionary>).Add(domain, types); + } + + int typeCount = bR.ReadByte(); + + for (int k = 0; k < typeCount; k++) + (types as List).Add((DnsResourceRecordType)bR.ReadUInt16()); + } + } + + return updateSecurityPolicies; + } + + private void WriteUpdateSecurityPoliciesTo(BinaryWriter bW) + { + if (_updateSecurityPolicies is null) + { + bW.Write(0); + } + else + { + bW.Write(_updateSecurityPolicies.Count); + + foreach (KeyValuePair>> updateSecurityPolicy in _updateSecurityPolicies) + { + bW.WriteShortString(updateSecurityPolicy.Key); + bW.Write(Convert.ToByte(updateSecurityPolicy.Value.Count)); + + foreach (KeyValuePair> policyMap in updateSecurityPolicy.Value) + { + bW.WriteShortString(policyMap.Key); + bW.Write(Convert.ToByte(policyMap.Value.Count)); + + foreach (DnsResourceRecordType type in policyMap.Value) + bW.Write((ushort)type); + } + } + } + } + + private static DnssecPrivateKey[] ReadDnssecPrivateKeysFrom(BinaryReader bR) + { + int count = bR.ReadByte(); + if (count < 1) + return null; + + DnssecPrivateKey[] dnssecPrivateKeys = new DnssecPrivateKey[count]; + + for (int i = 0; i < count; i++) + dnssecPrivateKeys[i] = DnssecPrivateKey.ReadFrom(bR); + + return dnssecPrivateKeys; + } + + private void WriteDnssecPrivateKeysTo(BinaryWriter bW) + { + if (_dnssecPrivateKeys is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(_dnssecPrivateKeys.Count)); + + foreach (DnssecPrivateKey dnssecPrivateKey in _dnssecPrivateKeys) + dnssecPrivateKey.WriteTo(bW); + } } #endregion #region public - public IReadOnlyList GetApexRecords(DnsResourceRecordType type) - { - if (_apexZone is null) - throw new InvalidOperationException(); - - return _apexZone.GetRecords(type); - } - - public void TriggerNotify() - { - if (_apexZone is null) - throw new InvalidOperationException(); - - switch (_type) - { - case AuthZoneType.Primary: - (_apexZone as PrimaryZone).TriggerNotify(); - break; - - case AuthZoneType.Secondary: - (_apexZone as SecondaryZone).TriggerNotify(); - break; - - default: - throw new InvalidOperationException(); - } - } - public void TriggerRefresh() { if (_apexZone is null) @@ -537,6 +1120,8 @@ namespace DnsServerCore.Dns.Zones switch (_type) { case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: (_apexZone as SecondaryZone).TriggerRefresh(); break; @@ -557,6 +1142,8 @@ namespace DnsServerCore.Dns.Zones switch (_type) { case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: (_apexZone as SecondaryZone).TriggerResync(); break; @@ -569,22 +1156,6 @@ namespace DnsServerCore.Dns.Zones } } - public Task> GetPrimaryNameServerAddressesAsync(DnsServer dnsServer) - { - if (_apexZone is null) - throw new InvalidOperationException(); - - return _apexZone.GetPrimaryNameServerAddressesAsync(dnsServer); - } - - public Task> GetSecondaryNameServerAddressesAsync(DnsServer dnsServer) - { - if (_apexZone is null) - throw new InvalidOperationException(); - - return _apexZone.GetSecondaryNameServerAddressesAsync(dnsServer); - } - public void WriteTo(BinaryWriter bW) { if (_apexZone is null) @@ -594,201 +1165,131 @@ namespace DnsServerCore.Dns.Zones bW.WriteShortString(_name); bW.Write((byte)_type); - bW.Write(_disabled); - bW.Write((byte)_zoneTransfer); - - if (_zoneTransferNameServers is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_zoneTransferNameServers.Count)); - foreach (NetworkAddress networkAddress in _zoneTransferNameServers) - networkAddress.WriteTo(bW); - } - - bW.Write((byte)_notify); - - if (_notifyNameServers is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_notifyNameServers.Count)); - foreach (IPAddress nameServer in _notifyNameServers) - nameServer.WriteTo(bW); - } - - bW.Write((byte)_update); - - if (_updateIpAddresses is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_updateIpAddresses.Count)); - foreach (NetworkAddress networkAddress in _updateIpAddresses) - networkAddress.WriteTo(bW); - } - bW.Write(_lastModified); + bW.Write(_disabled); switch (_type) { case AuthZoneType.Primary: - { - if (_zoneHistory is null) - { - bW.Write(0); - } - else - { - bW.Write(_zoneHistory.Count); + bW.Write(_catalogZoneName ?? ""); + bW.Write(_overrideCatalogQueryAccess); + bW.Write(_overrideCatalogZoneTransfer); + bW.Write(_overrideCatalogNotify); - foreach (DnsResourceRecord record in _zoneHistory) - { - record.WriteTo(bW.BaseStream); + bW.Write((byte)_queryAccess); + WriteNetworkACLTo(_queryAccessNetworkACL, bW); - if (record.Tag is HistoryRecordInfo rrInfo) - { - bW.Write(true); - rrInfo.WriteTo(bW); - } - else - { - bW.Write(false); - } - } - } + bW.Write((byte)_zoneTransfer); + WriteNetworkACLTo(_zoneTransferNetworkACL, bW); + WriteZoneTransferTsigKeyNamesTo(bW); + WriteZoneHistoryTo(bW); - if (_zoneTransferTsigKeyNames is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_zoneTransferTsigKeyNames.Count)); + bW.Write((byte)_notify); + WriteIPAddressesTo(_notifyNameServers, bW); - foreach (KeyValuePair tsigKeyName in _zoneTransferTsigKeyNames) - bW.WriteShortString(tsigKeyName.Key); - } + bW.Write((byte)_update); + WriteNetworkACLTo(_updateNetworkACL, bW); + WriteUpdateSecurityPoliciesTo(bW); - if (_updateSecurityPolicies is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_updateSecurityPolicies.Count)); - - foreach (KeyValuePair>> updateSecurityPolicy in _updateSecurityPolicies) - { - bW.WriteShortString(updateSecurityPolicy.Key); - bW.Write(Convert.ToByte(updateSecurityPolicy.Value.Count)); - - foreach (KeyValuePair> policyMap in updateSecurityPolicy.Value) - { - bW.WriteShortString(policyMap.Key); - bW.Write(Convert.ToByte(policyMap.Value.Count)); - - foreach (DnsResourceRecordType type in policyMap.Value) - bW.Write((ushort)type); - } - } - } - - if (_dnssecPrivateKeys is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_dnssecPrivateKeys.Count)); - - foreach (DnssecPrivateKey dnssecPrivateKey in _dnssecPrivateKeys) - dnssecPrivateKey.WriteTo(bW); - } - } + WriteDnssecPrivateKeysTo(bW); break; case AuthZoneType.Secondary: - { - bW.Write(_expiry); - bW.Write(_validationFailed); + bW.Write(_catalogZoneName ?? ""); + bW.Write(_overrideCatalogPrimaryNameServers); - if (_zoneHistory is null) - { - bW.Write(0); - } - else - { - bW.Write(_zoneHistory.Count); + bW.Write((byte)_queryAccess); + WriteNetworkACLTo(_queryAccessNetworkACL, bW); - foreach (DnsResourceRecord record in _zoneHistory) - { - record.WriteTo(bW.BaseStream); + bW.Write((byte)_zoneTransfer); + WriteNetworkACLTo(_zoneTransferNetworkACL, bW); + WriteZoneTransferTsigKeyNamesTo(bW); + WriteZoneHistoryTo(bW); - if (record.Tag is HistoryRecordInfo rrInfo) - { - bW.Write(true); - rrInfo.WriteTo(bW); - } - else - { - bW.Write(false); - } - } - } + bW.Write((byte)_notify); + WriteIPAddressesTo(_notifyNameServers, bW); - if (_zoneTransferTsigKeyNames is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_zoneTransferTsigKeyNames.Count)); + bW.Write((byte)_update); + WriteNetworkACLTo(_updateNetworkACL, bW); - foreach (KeyValuePair tsigKeyName in _zoneTransferTsigKeyNames) - bW.WriteShortString(tsigKeyName.Key); - } - } + WriteNameServerAddressesTo(_primaryNameServerAddresses, bW); + bW.Write((byte)_primaryZoneTransferProtocol); + bW.Write(_primaryZoneTransferTsigKeyName ?? ""); + + bW.Write(_expiry); + bW.Write(_validateZone); + bW.Write(_validationFailed); break; case AuthZoneType.Stub: - { - bW.Write(_expiry); - } + bW.Write(_catalogZoneName ?? ""); + bW.Write(_overrideCatalogQueryAccess); + + bW.Write((byte)_queryAccess); + WriteNetworkACLTo(_queryAccessNetworkACL, bW); + + WriteNameServerAddressesTo(_primaryNameServerAddresses, bW); + + bW.Write(_expiry); break; case AuthZoneType.Forwarder: - { - if (_updateSecurityPolicies is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_updateSecurityPolicies.Count)); + bW.Write(_catalogZoneName ?? ""); + bW.Write(_overrideCatalogQueryAccess); + bW.Write(_overrideCatalogZoneTransfer); + bW.Write(_overrideCatalogNotify); - foreach (KeyValuePair>> updateSecurityPolicy in _updateSecurityPolicies) - { - bW.WriteShortString(updateSecurityPolicy.Key); - bW.Write(Convert.ToByte(updateSecurityPolicy.Value.Count)); + bW.Write((byte)_queryAccess); + WriteNetworkACLTo(_queryAccessNetworkACL, bW); - foreach (KeyValuePair> policyMap in updateSecurityPolicy.Value) - { - bW.WriteShortString(policyMap.Key); - bW.Write(Convert.ToByte(policyMap.Value.Count)); + bW.Write((byte)_zoneTransfer); + WriteNetworkACLTo(_zoneTransferNetworkACL, bW); + WriteZoneTransferTsigKeyNamesTo(bW); + WriteZoneHistoryTo(bW); - foreach (DnsResourceRecordType type in policyMap.Value) - bW.Write((ushort)type); - } - } - } - } + bW.Write((byte)_notify); + WriteIPAddressesTo(_notifyNameServers, bW); + + bW.Write((byte)_update); + WriteNetworkACLTo(_updateNetworkACL, bW); + WriteUpdateSecurityPoliciesTo(bW); + break; + + case AuthZoneType.SecondaryForwarder: + bW.Write(_catalogZoneName ?? ""); + + bW.Write((byte)_queryAccess); + WriteNetworkACLTo(_queryAccessNetworkACL, bW); + + bW.Write((byte)_update); + WriteNetworkACLTo(_updateNetworkACL, bW); + + WriteNameServerAddressesTo(_primaryNameServerAddresses, bW); + bW.Write((byte)_primaryZoneTransferProtocol); + bW.Write(_primaryZoneTransferTsigKeyName ?? ""); + + bW.Write(_expiry); + break; + + case AuthZoneType.Catalog: + bW.Write((byte)_queryAccess); + WriteNetworkACLTo(_queryAccessNetworkACL, bW); + + bW.Write((byte)_zoneTransfer); + WriteNetworkACLTo(_zoneTransferNetworkACL, bW); + WriteZoneTransferTsigKeyNamesTo(bW); + WriteZoneHistoryTo(bW); + + bW.Write((byte)_notify); + WriteIPAddressesTo(_notifyNameServers, bW); + break; + + case AuthZoneType.SecondaryCatalog: + WriteNameServerAddressesTo(_primaryNameServerAddresses, bW); + bW.Write((byte)_primaryZoneTransferProtocol); + bW.Write(_primaryZoneTransferTsigKeyName ?? ""); + + bW.Write(_expiry); break; } } @@ -816,7 +1317,7 @@ namespace DnsServerCore.Dns.Zones public override string ToString() { - return _name; + return _name.Length == 0 ? "" : _name; ; } #endregion @@ -829,9 +1330,26 @@ namespace DnsServerCore.Dns.Zones public string Name { get { return _name; } } + public string DisplayName + { get { return _name.Length == 0 ? "" : _name; } } + public AuthZoneType Type { get { return _type; } } + public string TypeName + { get { return GetZoneTypeName(_type); } } + + public DateTime LastModified + { + get + { + if (_apexZone is null) + return _lastModified; + + return _apexZone.LastModified; + } + } + public bool Disabled { get @@ -850,14 +1368,141 @@ namespace DnsServerCore.Dns.Zones } } - public bool IsActive + public string CatalogZoneName { get + { + if (_apexZone is null) + return _catalogZoneName; + + return _apexZone.CatalogZoneName; + } + } + + public bool OverrideCatalogQueryAccess + { + get + { + if (_apexZone is null) + return _overrideCatalogQueryAccess; + + return _apexZone.OverrideCatalogQueryAccess; + } + set { if (_apexZone is null) throw new InvalidOperationException(); - return _apexZone.IsActive; + _apexZone.OverrideCatalogQueryAccess = value; + } + } + + public bool OverrideCatalogZoneTransfer + { + get + { + if (_apexZone is null) + return _overrideCatalogZoneTransfer; + + return _apexZone.OverrideCatalogZoneTransfer; + } + set + { + if (_apexZone is null) + throw new InvalidOperationException(); + + _apexZone.OverrideCatalogZoneTransfer = value; + } + } + + public bool OverrideCatalogNotify + { + get + { + if (_apexZone is null) + return _overrideCatalogNotify; + + return _apexZone.OverrideCatalogNotify; + } + set + { + if (_apexZone is null) + throw new InvalidOperationException(); + + _apexZone.OverrideCatalogNotify = value; + } + } + + public bool OverrideCatalogPrimaryNameServers + { + get + { + if (_apexZone is null) + return _overrideCatalogPrimaryNameServers; + + switch (_type) + { + case AuthZoneType.Secondary: + return (_apexZone as SecondaryZone).OverrideCatalogPrimaryNameServers; + + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: + return false; + + default: + throw new InvalidOperationException(); + } + } + set + { + if (_apexZone is null) + throw new InvalidOperationException(); + + switch (_type) + { + case AuthZoneType.Secondary: + (_apexZone as SecondaryZone).OverrideCatalogPrimaryNameServers = value; + break; + + default: + throw new InvalidOperationException(); + } + } + } + + public AuthZoneQueryAccess QueryAccess + { + get + { + if (_apexZone is null) + return _queryAccess; + + return _apexZone.QueryAccess; + } + set + { + if (_apexZone is null) + throw new InvalidOperationException(); + + _apexZone.QueryAccess = value; + } + } + + public IReadOnlyCollection QueryAccessNetworkACL + { + get + { + if (_apexZone is null) + return _queryAccessNetworkACL; + + return _apexZone.QueryAccessNetworkACL; + } + set + { + if (_apexZone is null) + throw new InvalidOperationException(); + + _apexZone.QueryAccessNetworkACL = value; } } @@ -879,21 +1524,61 @@ namespace DnsServerCore.Dns.Zones } } - public IReadOnlyCollection ZoneTransferNameServers + public IReadOnlyCollection ZoneTransferNetworkACL { get { if (_apexZone is null) - return _zoneTransferNameServers; + return _zoneTransferNetworkACL; - return _apexZone.ZoneTransferNameServers; + return _apexZone.ZoneTransferNetworkACL; } set { if (_apexZone is null) throw new InvalidOperationException(); - _apexZone.ZoneTransferNameServers = value; + _apexZone.ZoneTransferNetworkACL = value; + } + } + + public IReadOnlyDictionary ZoneTransferTsigKeyNames + { + get + { + if (_apexZone is null) + return _zoneTransferTsigKeyNames; + + return _apexZone.ZoneTransferTsigKeyNames; + } + set + { + if (_apexZone is null) + throw new InvalidOperationException(); + + switch (_type) + { + case AuthZoneType.Primary: + case AuthZoneType.Secondary: + case AuthZoneType.Forwarder: + case AuthZoneType.Catalog: + _apexZone.ZoneTransferTsigKeyNames = value; + break; + + default: + throw new InvalidOperationException(); + } + } + } + + public IReadOnlyList ZoneHistory + { + get + { + if (_apexZone is null) + return _zoneHistory; + + return _apexZone.GetZoneHistory(); } } @@ -951,109 +1636,21 @@ namespace DnsServerCore.Dns.Zones } } - public IReadOnlyCollection UpdateIpAddresses + public IReadOnlyCollection UpdateNetworkACL { get { if (_apexZone is null) - return _updateIpAddresses; + return _updateNetworkACL; - return _apexZone.UpdateIpAddresses; + return _apexZone.UpdateNetworkACL; } set { if (_apexZone is null) throw new InvalidOperationException(); - _apexZone.UpdateIpAddresses = value; - } - } - - public DateTime LastModified - { - get - { - if (_apexZone is null) - return _lastModified; - - return _apexZone.LastModified; - } - } - - public DateTime Expiry - { - get - { - if (_apexZone is null) - return _expiry; - - switch (_type) - { - case AuthZoneType.Secondary: - return (_apexZone as SecondaryZone).Expiry; - - case AuthZoneType.Stub: - return (_apexZone as StubZone).Expiry; - - default: - throw new InvalidOperationException(); - } - } - } - - public bool ValidationFailed - { - get - { - if (_apexZone is null) - return _validationFailed; - - switch (_type) - { - case AuthZoneType.Secondary: - return (_apexZone as SecondaryZone).ValidationFailed; - - default: - throw new InvalidOperationException(); - } - } - } - - public IReadOnlyList ZoneHistory - { - get - { - if (_apexZone is null) - return _zoneHistory; - - return _apexZone.GetZoneHistory(); - } - } - - public IReadOnlyDictionary ZoneTransferTsigKeyNames - { - get - { - if (_apexZone is null) - return _zoneTransferTsigKeyNames; - - return _apexZone.ZoneTransferTsigKeyNames; - } - set - { - if (_apexZone is null) - throw new InvalidOperationException(); - - switch (_type) - { - case AuthZoneType.Primary: - case AuthZoneType.Secondary: - _apexZone.ZoneTransferTsigKeyNames = value; - break; - - default: - throw new InvalidOperationException(); - } + _apexZone.UpdateNetworkACL = value; } } @@ -1102,14 +1699,195 @@ namespace DnsServerCore.Dns.Zones } } - public AuthZoneDnssecStatus DnssecStatus + public IReadOnlyList PrimaryNameServerAddresses { get + { + if (_apexZone is null) + return _primaryNameServerAddresses; + + switch (_type) + { + case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: + return (_apexZone as SecondaryZone).PrimaryNameServerAddresses; + + case AuthZoneType.Stub: + return (_apexZone as StubZone).PrimaryNameServerAddresses; + + default: + throw new InvalidOperationException(); + } + } + set { if (_apexZone is null) throw new InvalidOperationException(); - return _apexZone.DnssecStatus; + switch (_type) + { + case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: + (_apexZone as SecondaryZone).PrimaryNameServerAddresses = value; + break; + + case AuthZoneType.Stub: + (_apexZone as StubZone).PrimaryNameServerAddresses = value; + break; + + default: + throw new InvalidOperationException(); + } + } + } + + public DnsTransportProtocol PrimaryZoneTransferProtocol + { + get + { + if (_apexZone is null) + return _primaryZoneTransferProtocol; + + switch (_type) + { + case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: + return (_apexZone as SecondaryZone).PrimaryZoneTransferProtocol; + + default: + throw new InvalidOperationException(); + } + } + set + { + if (_apexZone is null) + throw new InvalidOperationException(); + + switch (_type) + { + case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: + (_apexZone as SecondaryZone).PrimaryZoneTransferProtocol = value; + break; + + default: + throw new InvalidOperationException(); + } + } + } + + public string PrimaryZoneTransferTsigKeyName + { + get + { + if (_apexZone is null) + return _primaryZoneTransferTsigKeyName; + + switch (_type) + { + case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: + return (_apexZone as SecondaryZone).PrimaryZoneTransferTsigKeyName; + + default: + throw new InvalidOperationException(); + } + } + set + { + if (_apexZone is null) + throw new InvalidOperationException(); + + switch (_type) + { + case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: + (_apexZone as SecondaryZone).PrimaryZoneTransferTsigKeyName = value; + break; + + default: + throw new InvalidOperationException(); + } + } + } + + public DateTime Expiry + { + get + { + if (_apexZone is null) + return _expiry; + + switch (_type) + { + case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: + return (_apexZone as SecondaryZone).Expiry; + + case AuthZoneType.Stub: + return (_apexZone as StubZone).Expiry; + + default: + throw new InvalidOperationException(); + } + } + } + + public bool ValidateZone + { + get + { + if (_apexZone is null) + return _validateZone; + + switch (_type) + { + case AuthZoneType.Secondary: + return (_apexZone as SecondaryZone).ValidateZone; + + default: + throw new InvalidOperationException(); + } + } + set + { + if (_apexZone is null) + throw new InvalidOperationException(); + + switch (_type) + { + case AuthZoneType.Secondary: + (_apexZone as SecondaryZone).ValidateZone = value; + break; + + default: + throw new InvalidOperationException(); + } + } + } + + public bool ValidationFailed + { + get + { + if (_apexZone is null) + return _validationFailed; + + switch (_type) + { + case AuthZoneType.Secondary: + return (_apexZone as SecondaryZone).ValidationFailed; + + default: + throw new InvalidOperationException(); + } } } @@ -1159,6 +1937,8 @@ namespace DnsServerCore.Dns.Zones switch (_type) { case AuthZoneType.Secondary: + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: return (_apexZone as SecondaryZone).IsExpired; case AuthZoneType.Stub: @@ -1180,10 +1960,10 @@ namespace DnsServerCore.Dns.Zones switch (_type) { case AuthZoneType.Primary: - return (_apexZone as PrimaryZone).NotifyFailed; - case AuthZoneType.Secondary: - return (_apexZone as SecondaryZone).NotifyFailed; + case AuthZoneType.Forwarder: + case AuthZoneType.Catalog: + return _apexZone.NotifyFailed; default: throw new InvalidOperationException(); @@ -1201,10 +1981,10 @@ namespace DnsServerCore.Dns.Zones switch (_type) { case AuthZoneType.Secondary: - return (_apexZone as SecondaryZone).SyncFailed; - + case AuthZoneType.SecondaryForwarder: + case AuthZoneType.SecondaryCatalog: case AuthZoneType.Stub: - return (_apexZone as StubZone).SyncFailed; + return _apexZone.SyncFailed; default: throw new InvalidOperationException();