123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866 |
- /*
- Technitium DNS Server
- Copyright (C) 2024 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 <http://www.gnu.org/licenses/>.
- */
- using DnsServerCore.Dns.ResourceRecords;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
- using System.Threading.Tasks;
- using TechnitiumLibrary;
- using TechnitiumLibrary.Net;
- using TechnitiumLibrary.Net.Dns;
- using TechnitiumLibrary.Net.Dns.ResourceRecords;
- namespace DnsServerCore.Dns.Zones
- {
- class SecondaryCatalogZone : SecondaryForwarderZone
- {
- #region events
- public event EventHandler<SecondaryCatalogEventArgs> ZoneAdded;
- public event EventHandler<SecondaryCatalogEventArgs> ZoneRemoved;
- #endregion
- #region variables
- readonly static IReadOnlyCollection<NetworkAccessControl> _allowACL =
- [
- new NetworkAccessControl(IPAddress.Any, 0),
- new NetworkAccessControl(IPAddress.IPv6Any, 0)
- ];
- readonly static IReadOnlyCollection<NetworkAccessControl> _queryAccessAllowOnlyPrivateNetworksACL =
- [
- new NetworkAccessControl(IPAddress.Parse("127.0.0.0"), 8),
- new NetworkAccessControl(IPAddress.Parse("10.0.0.0"), 8),
- new NetworkAccessControl(IPAddress.Parse("100.64.0.0"), 10),
- new NetworkAccessControl(IPAddress.Parse("169.254.0.0"), 16),
- new NetworkAccessControl(IPAddress.Parse("172.16.0.0"), 12),
- new NetworkAccessControl(IPAddress.Parse("192.168.0.0"), 16),
- new NetworkAccessControl(IPAddress.Parse("2000::"), 3, true),
- new NetworkAccessControl(IPAddress.IPv6Any, 0)
- ];
- readonly static IReadOnlyCollection<NetworkAccessControl> _allowOnlyZoneNameServersACL =
- [
- new NetworkAccessControl(IPAddress.Parse("224.0.0.0"), 32)
- ];
- readonly static IReadOnlyCollection<NetworkAccessControl> _denyACL =
- [
- new NetworkAccessControl(IPAddress.Parse("127.0.0.0"), 8),
- new NetworkAccessControl(IPAddress.Parse("::1"), 128)
- ];
- readonly static NetworkAccessControl _allowZoneNameServersAndUseSpecifiedNetworkACL = new NetworkAccessControl(IPAddress.Parse("224.0.0.0"), 32);
- Dictionary<string, string> _membersIndex = new Dictionary<string, string>();
- #endregion
- #region constructor
- public SecondaryCatalogZone(DnsServer dnsServer, AuthZoneInfo zoneInfo)
- : base(dnsServer, zoneInfo)
- { }
- public SecondaryCatalogZone(DnsServer dnsServer, string name, IReadOnlyList<NameServerAddress> primaryNameServerAddresses, DnsTransportProtocol primaryZoneTransferProtocol = DnsTransportProtocol.Tcp, string primaryZoneTransferTsigKeyName = null)
- : base(dnsServer, name, primaryNameServerAddresses, primaryZoneTransferProtocol, primaryZoneTransferTsigKeyName)
- { }
- #endregion
- #region protected
- protected override void InitZone()
- {
- //init secondary catalog zone with dummy SOA and NS records
- DnsSOARecordData soa = new DnsSOARecordData("invalid", "invalid", 0, 300, 60, 604800, 900);
- DnsResourceRecord soaRecord = new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, 0, soa);
- soaRecord.GetAuthGenericRecordInfo().LastModified = DateTime.UtcNow;
- _entries[DnsResourceRecordType.SOA] = [soaRecord];
- _entries[DnsResourceRecordType.NS] = [new DnsResourceRecord(_name, DnsResourceRecordType.NS, DnsClass.IN, 0, new DnsNSRecordData("invalid"))];
- }
- #endregion
- #region internal
- internal void BuildMembersIndex()
- {
- Dictionary<string, string> membersIndex = new Dictionary<string, string>();
- foreach (KeyValuePair<string, string> memberEntry in EnumerateCatalogMemberZones(_dnsServer))
- membersIndex.TryAdd(memberEntry.Key.ToLowerInvariant(), memberEntry.Value);
- _membersIndex = membersIndex;
- }
- #endregion
- #region secondary catalog
- public IReadOnlyCollection<string> GetAllMemberZoneNames()
- {
- return _membersIndex.Keys;
- }
- protected override async Task FinalizeZoneTransferAsync()
- {
- //secondary catalog does not maintain zone history; no need to call base method
- string version = GetVersion();
- if ((version is null) || !version.Equals("2", StringComparison.OrdinalIgnoreCase))
- {
- _dnsServer.LogManager?.Write("Failed to provision Secondary Catalog zone '" + ToString() + "': catalog version not supported.");
- return;
- }
- Dictionary<string, string> updatedMembersIndex = new Dictionary<string, string>();
- foreach (KeyValuePair<string, string> memberEntry in EnumerateCatalogMemberZones(_dnsServer))
- updatedMembersIndex.TryAdd(memberEntry.Key, memberEntry.Value);
- Dictionary<string, object> membersToRemove = new Dictionary<string, object>();
- Dictionary<string, string> membersToAdd = new Dictionary<string, string>();
- foreach (KeyValuePair<string, string> memberEntry in _membersIndex)
- {
- if (!updatedMembersIndex.TryGetValue(memberEntry.Key, out string updatedMembersZoneDomain))
- {
- //member was removed from catalog zone; remove local zone
- membersToRemove.Add(memberEntry.Key, null);
- }
- else if (!memberEntry.Value.Equals(updatedMembersZoneDomain, StringComparison.OrdinalIgnoreCase))
- {
- //member exists but label does not match; reprovision zone
- membersToRemove.Add(memberEntry.Key, null);
- membersToAdd.Add(memberEntry.Key, updatedMembersZoneDomain);
- }
- }
- foreach (KeyValuePair<string, string> updatedMemberEntry in updatedMembersIndex)
- {
- if (_membersIndex.TryGetValue(updatedMemberEntry.Key, out _))
- {
- ApexZone apexZone = _dnsServer.AuthZoneManager.GetApexZone(updatedMemberEntry.Key);
- if (apexZone is not null)
- continue; //zone already exists; do nothing
- }
- //member was added to catalog zone; provision zone
- membersToAdd.TryAdd(updatedMemberEntry.Key, updatedMemberEntry.Value);
- }
- //set global custom properties
- UpdateGlobalAllowQueryProperty();
- UpdateGlobalAllowTransferAndTsigKeyNamesProperties();
- //add and remove member zones
- if ((membersToRemove.Count > 0) || (membersToAdd.Count > 0))
- await AddAndRemoveMemberZonesAsync(membersToRemove, membersToAdd);
- //set member zone custom properties
- if (updatedMembersIndex.Count > 0)
- UpdateMemberZoneCustomProperties(updatedMembersIndex);
- _membersIndex = updatedMembersIndex;
- _dnsServer.AuthZoneManager.SaveZoneFile(_name);
- }
- protected override async Task FinalizeIncrementalZoneTransferAsync(IReadOnlyList<DnsResourceRecord> historyRecords)
- {
- //secondary catalog does not maintain zone history; no need to call base method
- string version = GetVersion();
- if ((version is null) || !version.Equals("2", StringComparison.OrdinalIgnoreCase))
- {
- _dnsServer.LogManager?.Write("Failed to provision Secondary Catalog zone '" + ToString() + "': catalog version not supported.");
- return;
- }
- bool isAddHistoryRecord = false;
- bool updateGlobalAllowQueryProperty = false;
- bool updateGlobalAllowTransferAndTsigKeyNamesProperties = false;
- Dictionary<string, object> membersToRemove = new Dictionary<string, object>();
- Dictionary<string, string> membersToAdd = new Dictionary<string, string>();
- Dictionary<string, string> membersToUpdate = new Dictionary<string, string>();
- //inspect records in history
- for (int i = 1; i < historyRecords.Count; i++)
- {
- DnsResourceRecord historyRecord = historyRecords[i];
- if (historyRecord.Type == DnsResourceRecordType.SOA)
- {
- isAddHistoryRecord = true; //removed records completed
- continue;
- }
- if (historyRecord.Name.Length == _name.Length)
- continue; //skip apex records
- string subdomain = historyRecord.Name.Substring(0, historyRecord.Name.Length - _name.Length - 1).ToLowerInvariant();
- string[] labels = subdomain.Split('.');
- Array.Reverse(labels);
- switch (labels[0])
- {
- case "ext":
- if (labels.Length > 1)
- {
- switch (labels[1])
- {
- case "allow-query":
- updateGlobalAllowQueryProperty = true;
- break;
- case "allow-transfer":
- case "transfer-tsig-key-names":
- updateGlobalAllowTransferAndTsigKeyNamesProperties = true;
- break;
- }
- }
- break;
- case "zones":
- if (labels.Length == 2)
- {
- if (historyRecord.Type == DnsResourceRecordType.PTR)
- {
- string memberZoneName = (historyRecord.RDATA as DnsPTRRecordData).Domain.ToLowerInvariant();
- if (isAddHistoryRecord)
- {
- string memberZoneDomain = subdomain + "." + _name;
- membersToAdd.TryAdd(memberZoneName, memberZoneDomain);
- membersToUpdate.TryAdd(memberZoneName, memberZoneDomain);
- }
- else
- {
- membersToRemove.TryAdd(memberZoneName, null);
- }
- }
- }
- else if (labels.Length > 2)
- {
- switch (labels[2])
- {
- case "ext":
- case "coo":
- string memberZoneDomain = labels[1] + "." + labels[0] + "." + _name;
- DnsResourceRecord prevHistoryRecord = historyRecords[i - 1];
- if (prevHistoryRecord.Name.EndsWith(memberZoneDomain))
- break; //skip since its same member zone's custom property
- IReadOnlyList<DnsResourceRecord> ptrRecords = _dnsServer.AuthZoneManager.GetRecords(_name, memberZoneDomain, DnsResourceRecordType.PTR);
- if (ptrRecords.Count > 0)
- membersToUpdate.TryAdd((ptrRecords[0].RDATA as DnsPTRRecordData).Domain.ToLowerInvariant(), memberZoneDomain);
- break;
- }
- }
- break;
- }
- }
- //apply changes
- if (updateGlobalAllowQueryProperty)
- UpdateGlobalAllowQueryProperty();
- if (updateGlobalAllowTransferAndTsigKeyNamesProperties)
- UpdateGlobalAllowTransferAndTsigKeyNamesProperties();
- if ((membersToRemove.Count > 0) || (membersToAdd.Count > 0))
- await AddAndRemoveMemberZonesAsync(membersToRemove, membersToAdd);
- if (membersToUpdate.Count > 0)
- UpdateMemberZoneCustomProperties(membersToUpdate);
- if ((membersToRemove.Count > 0) || (membersToAdd.Count > 0))
- {
- //update members index
- Dictionary<string, string> updatedMembersIndex = new Dictionary<string, string>(_membersIndex);
- foreach (KeyValuePair<string, object> removedMember in membersToRemove)
- updatedMembersIndex.Remove(removedMember.Key);
- foreach (KeyValuePair<string, string> addedMember in membersToAdd)
- updatedMembersIndex.TryAdd(addedMember.Key, addedMember.Value);
- _membersIndex = updatedMembersIndex;
- }
- _dnsServer.AuthZoneManager.SaveZoneFile(_name);
- }
- private async Task AddAndRemoveMemberZonesAsync(Dictionary<string, object> membersToRemove, Dictionary<string, string> membersToAdd)
- {
- //remove zones
- foreach (KeyValuePair<string, object> removeMember in membersToRemove)
- {
- ApexZone apexZone = _dnsServer.AuthZoneManager.GetApexZone(removeMember.Key);
- if ((apexZone is not null) && _name.Equals(apexZone.CatalogZoneName, StringComparison.OrdinalIgnoreCase))
- DeleteMemberZone(apexZone);
- }
- //add zones
- List<Task<AuthZoneInfo>> addZoneTasks = new List<Task<AuthZoneInfo>>();
- foreach (KeyValuePair<string, string> addMember in membersToAdd)
- {
- ApexZone apexZone = _dnsServer.AuthZoneManager.GetApexZone(addMember.Key);
- if (apexZone is null)
- {
- //create zone
- AuthZoneType zoneType = GetZoneTypeProperty(addMember.Value);
- switch (zoneType)
- {
- case AuthZoneType.Primary:
- {
- //create secondary zone
- IReadOnlyList<NameServerAddress> primaryNameServerAddresses;
- DnsTransportProtocol primaryZoneTransferProtocol;
- string primaryZoneTransferTsigKeyName;
- IReadOnlyList<Tuple<IPAddress, string>> primaries = GetPrimariesProperty(addMember.Value);
- if (primaries.Count == 0)
- primaries = GetPrimariesProperty(_name);
- if (primaries.Count == 0)
- {
- primaryNameServerAddresses = PrimaryNameServerAddresses;
- primaryZoneTransferProtocol = PrimaryZoneTransferProtocol;
- primaryZoneTransferTsigKeyName = PrimaryZoneTransferTsigKeyName;
- }
- else
- {
- Tuple<IPAddress, string> primary = primaries[0];
- primaryNameServerAddresses = [new NameServerAddress(primary.Item1, DnsTransportProtocol.Tcp)];
- primaryZoneTransferProtocol = DnsTransportProtocol.Tcp;
- primaryZoneTransferTsigKeyName = primary.Item2;
- }
- addZoneTasks.Add(_dnsServer.AuthZoneManager.CreateSecondaryZoneAsync(addMember.Key, primaryNameServerAddresses, primaryZoneTransferProtocol, primaryZoneTransferTsigKeyName, false, true));
- }
- break;
- case AuthZoneType.Stub:
- {
- //create stub zone
- IReadOnlyList<NameServerAddress> primaryNameServerAddresses = GetPrimaryAddressesProperty(addMember.Value);
- addZoneTasks.Add(_dnsServer.AuthZoneManager.CreateStubZoneAsync(addMember.Key, primaryNameServerAddresses, true));
- }
- break;
- case AuthZoneType.Forwarder:
- {
- //create secondary forwarder zone
- addZoneTasks.Add(Task.FromResult(_dnsServer.AuthZoneManager.CreateSecondaryForwarderZone(addMember.Key, PrimaryNameServerAddresses, PrimaryZoneTransferProtocol, PrimaryZoneTransferTsigKeyName)));
- }
- break;
- }
- }
- }
- await Task.WhenAll(addZoneTasks);
- //finalize add zone tasks
- foreach (Task<AuthZoneInfo> task in addZoneTasks)
- {
- try
- {
- AuthZoneInfo zoneInfo = await task;
- //set as catalog zone member
- zoneInfo.ApexZone.CatalogZoneName = _name;
- //raise event
- ZoneAdded?.Invoke(this, new SecondaryCatalogEventArgs(zoneInfo));
- //write log
- _dnsServer.LogManager?.Write(zoneInfo.TypeName + " zone '" + zoneInfo.DisplayName + "' was added via Secondary Catalog zone '" + ToString() + "' sucessfully.");
- }
- catch (Exception ex)
- {
- _dnsServer.LogManager?.Write(ex);
- }
- }
- }
- private void UpdateGlobalAllowQueryProperty()
- {
- //allow query global custom property
- IReadOnlyCollection<NetworkAccessControl> globalAllowQueryACL = GetAllowQueryProperty(_name);
- if (globalAllowQueryACL.Count > 0)
- {
- _queryAccess = GetQueryAccessType(globalAllowQueryACL);
- switch (_queryAccess)
- {
- case AuthZoneQueryAccess.UseSpecifiedNetworkACL:
- QueryAccessNetworkACL = globalAllowQueryACL;
- break;
- case AuthZoneQueryAccess.AllowZoneNameServersAndUseSpecifiedNetworkACL:
- QueryAccessNetworkACL = GetFilteredACL(globalAllowQueryACL);
- break;
- default:
- QueryAccessNetworkACL = null;
- break;
- }
- }
- else
- {
- _queryAccess = AuthZoneQueryAccess.Allow;
- QueryAccessNetworkACL = null;
- }
- }
- private void UpdateGlobalAllowTransferAndTsigKeyNamesProperties()
- {
- //allow transfer global custom property
- IReadOnlyCollection<NetworkAccessControl> globalAllowTransferACL = GetAllowTransferProperty(_name);
- if (globalAllowTransferACL.Count > 0)
- {
- _zoneTransfer = GetZoneTransferType(globalAllowTransferACL);
- switch (_zoneTransfer)
- {
- case AuthZoneTransfer.UseSpecifiedNetworkACL:
- ZoneTransferNetworkACL = globalAllowTransferACL;
- break;
- case AuthZoneTransfer.AllowZoneNameServersAndUseSpecifiedNetworkACL:
- ZoneTransferNetworkACL = GetFilteredACL(globalAllowTransferACL);
- break;
- default:
- ZoneTransferNetworkACL = null;
- break;
- }
- //zone tranfer tsig key names global custom property
- ZoneTransferTsigKeyNames = GetZoneTransferTsigKeyNamesProperty(_name);
- }
- else
- {
- _zoneTransfer = AuthZoneTransfer.Deny;
- ZoneTransferNetworkACL = null;
- ZoneTransferTsigKeyNames = null;
- }
- }
- private void UpdateMemberZoneCustomProperties(Dictionary<string, string> membersToUpdate)
- {
- foreach (KeyValuePair<string, string> updatedMemberEntry in membersToUpdate)
- {
- ApexZone memberApexZone = _dnsServer.AuthZoneManager.GetApexZone(updatedMemberEntry.Key);
- if ((memberApexZone is not null) && _name.Equals(memberApexZone.CatalogZoneName, StringComparison.OrdinalIgnoreCase))
- {
- //change of ownership property
- {
- string newCatalogZoneName = GetChangeOfOwnershipProperty(updatedMemberEntry.Value);
- if (newCatalogZoneName is not null)
- {
- ApexZone catalogApexZone = _dnsServer.AuthZoneManager.GetApexZone(newCatalogZoneName);
- if (catalogApexZone is SecondaryCatalogZone secondaryCatalogZone)
- {
- //found secondary catalog zone; transfer ownership to it
- memberApexZone.CatalogZoneName = secondaryCatalogZone._name;
- }
- else
- {
- //no such secondary catalog zone exists; delete member zone
- DeleteMemberZone(memberApexZone);
- continue;
- }
- }
- }
- //allow query member zone custom property
- {
- IReadOnlyCollection<NetworkAccessControl> allowQueryACL = GetAllowQueryProperty(updatedMemberEntry.Value);
- if (allowQueryACL.Count > 0)
- {
- memberApexZone.QueryAccess = GetQueryAccessType(allowQueryACL);
- switch (memberApexZone.QueryAccess)
- {
- case AuthZoneQueryAccess.UseSpecifiedNetworkACL:
- memberApexZone.QueryAccessNetworkACL = allowQueryACL;
- break;
- case AuthZoneQueryAccess.AllowZoneNameServersAndUseSpecifiedNetworkACL:
- memberApexZone.QueryAccessNetworkACL = GetFilteredACL(allowQueryACL);
- break;
- default:
- memberApexZone.QueryAccessNetworkACL = null;
- break;
- }
- memberApexZone.OverrideCatalogQueryAccess = true;
- }
- else
- {
- memberApexZone.OverrideCatalogQueryAccess = false;
- memberApexZone.QueryAccess = AuthZoneQueryAccess.Allow;
- memberApexZone.QueryAccessNetworkACL = null;
- }
- }
- if (memberApexZone is StubZone stubZone)
- {
- //primary addresses property
- stubZone.PrimaryNameServerAddresses = GetPrimaryAddressesProperty(updatedMemberEntry.Value);
- }
- else if (memberApexZone is SecondaryForwarderZone)
- {
- //do nothing
- }
- else if (memberApexZone is SecondaryZone secondaryZone)
- {
- //primaries property
- IReadOnlyList<Tuple<IPAddress, string>> primaries = GetPrimariesProperty(updatedMemberEntry.Value);
- if (primaries.Count == 0)
- primaries = GetPrimariesProperty(_name);
- if (primaries.Count > 0)
- {
- Tuple<IPAddress, string> primary = primaries[0];
- secondaryZone.PrimaryNameServerAddresses = [new NameServerAddress(primary.Item1, DnsTransportProtocol.Tcp)];
- secondaryZone.PrimaryZoneTransferProtocol = DnsTransportProtocol.Tcp;
- secondaryZone.PrimaryZoneTransferTsigKeyName = primary.Item2;
- secondaryZone.OverrideCatalogPrimaryNameServers = true;
- }
- else
- {
- secondaryZone.OverrideCatalogPrimaryNameServers = false;
- secondaryZone.PrimaryNameServerAddresses = null;
- secondaryZone.PrimaryZoneTransferProtocol = DnsTransportProtocol.Tcp;
- secondaryZone.PrimaryZoneTransferTsigKeyName = null;
- }
- //allow transfer member zone custom property
- IReadOnlyCollection<NetworkAccessControl> allowTransferACL = GetAllowTransferProperty(updatedMemberEntry.Value);
- if (allowTransferACL.Count > 0)
- {
- memberApexZone.ZoneTransfer = GetZoneTransferType(allowTransferACL);
- switch (memberApexZone.ZoneTransfer)
- {
- case AuthZoneTransfer.UseSpecifiedNetworkACL:
- memberApexZone.ZoneTransferNetworkACL = allowTransferACL;
- break;
- case AuthZoneTransfer.AllowZoneNameServersAndUseSpecifiedNetworkACL:
- memberApexZone.ZoneTransferNetworkACL = GetFilteredACL(allowTransferACL);
- break;
- default:
- memberApexZone.ZoneTransferNetworkACL = null;
- break;
- }
- //zone tranfer tsig key names member zone custom property
- memberApexZone.ZoneTransferTsigKeyNames = GetZoneTransferTsigKeyNamesProperty(updatedMemberEntry.Value);
- memberApexZone.OverrideCatalogZoneTransfer = true;
- }
- else
- {
- memberApexZone.OverrideCatalogZoneTransfer = false;
- memberApexZone.ZoneTransfer = AuthZoneTransfer.Deny;
- memberApexZone.ZoneTransferNetworkACL = null;
- memberApexZone.ZoneTransferTsigKeyNames = null;
- }
- }
- _dnsServer.AuthZoneManager.SaveZoneFile(memberApexZone.Name);
- }
- }
- }
- private void DeleteMemberZone(ApexZone apexZone)
- {
- AuthZoneInfo zoneInfo = new AuthZoneInfo(apexZone);
- if (_dnsServer.AuthZoneManager.DeleteZone(zoneInfo, true))
- {
- ZoneRemoved?.Invoke(this, new SecondaryCatalogEventArgs(zoneInfo));
- _dnsServer.LogManager?.Write(apexZone.GetZoneTypeName() + " zone '" + apexZone.ToString() + "' was removed via Secondary Catalog zone '" + ToString() + "' sucessfully.");
- }
- }
- private string GetVersion()
- {
- string domain = "version." + _name;
- IReadOnlyList<DnsResourceRecord> records = _dnsServer.AuthZoneManager.GetRecords(_name, domain, DnsResourceRecordType.TXT);
- if (records.Count > 0)
- return (records[0].RDATA as DnsTXTRecordData).GetText();
- return null;
- }
- private string GetChangeOfOwnershipProperty(string memberZoneDomain)
- {
- string domain = "coo." + memberZoneDomain;
- IReadOnlyList<DnsResourceRecord> records = _dnsServer.AuthZoneManager.GetRecords(_name, domain, DnsResourceRecordType.PTR);
- if (records.Count > 0)
- return (records[0].RDATA as DnsPTRRecordData).Domain;
- return null;
- }
- private AuthZoneType GetZoneTypeProperty(string memberZoneDomain)
- {
- string domain = "zone-type.ext." + memberZoneDomain;
- IReadOnlyList<DnsResourceRecord> records = _dnsServer.AuthZoneManager.GetRecords(_name, domain, DnsResourceRecordType.TXT);
- if (records.Count > 0)
- return Enum.Parse<AuthZoneType>((records[0].RDATA as DnsTXTRecordData).GetText(), true);
- return AuthZoneType.Primary;
- }
- private List<Tuple<IPAddress, string>> GetPrimariesProperty(string memberZoneDomain)
- {
- string domain = "primaries.ext." + memberZoneDomain;
- List<Tuple<IPAddress, string>> primaries = new List<Tuple<IPAddress, string>>(2);
- AuthZone authZone = _dnsServer.AuthZoneManager.GetAuthZone(_name, domain);
- if (authZone is not null)
- {
- foreach (DnsResourceRecord record in authZone.GetRecords(DnsResourceRecordType.A))
- primaries.Add(new Tuple<IPAddress, string>((record.RDATA as DnsARecordData).Address, null));
- foreach (DnsResourceRecord record in authZone.GetRecords(DnsResourceRecordType.AAAA))
- primaries.Add(new Tuple<IPAddress, string>((record.RDATA as DnsAAAARecordData).Address, null));
- }
- List<string> subdomains = new List<string>();
- _dnsServer.AuthZoneManager.ListSubDomains(domain, subdomains);
- foreach (string subdomain in subdomains)
- {
- AuthZone subZone = _dnsServer.AuthZoneManager.GetAuthZone(_name, subdomain + "." + domain);
- if (subZone is null)
- continue;
- string tsigKeyName = null;
- IReadOnlyList<DnsResourceRecord> szTXTRecords = subZone.GetRecords(DnsResourceRecordType.TXT);
- if (szTXTRecords.Count > 0)
- tsigKeyName = (szTXTRecords[0].RDATA as DnsTXTRecordData).GetText();
- foreach (DnsResourceRecord record in subZone.GetRecords(DnsResourceRecordType.A))
- primaries.Add(new Tuple<IPAddress, string>((record.RDATA as DnsARecordData).Address, tsigKeyName));
- foreach (DnsResourceRecord record in subZone.GetRecords(DnsResourceRecordType.AAAA))
- primaries.Add(new Tuple<IPAddress, string>((record.RDATA as DnsAAAARecordData).Address, tsigKeyName));
- }
- return primaries;
- }
- private IReadOnlyList<NameServerAddress> GetPrimaryAddressesProperty(string memberZoneDomain)
- {
- string domain = "primary-addresses.ext." + memberZoneDomain;
- IReadOnlyList<DnsResourceRecord> records = _dnsServer.AuthZoneManager.GetRecords(_name, domain, DnsResourceRecordType.TXT);
- if (records.Count > 0)
- return (records[0].RDATA as DnsTXTRecordData).CharacterStrings.Convert(NameServerAddress.Parse);
- return [];
- }
- private IReadOnlyCollection<NetworkAccessControl> GetAllowQueryProperty(string memberZoneDomain)
- {
- string domain = "allow-query.ext." + memberZoneDomain;
- IReadOnlyList<DnsResourceRecord> records = _dnsServer.AuthZoneManager.GetRecords(_name, domain, DnsResourceRecordType.APL);
- if (records.Count > 0)
- return NetworkAccessControl.ConvertFromAPLRecordData(records[0].RDATA as DnsAPLRecordData);
- return [];
- }
- private IReadOnlyCollection<NetworkAccessControl> GetAllowTransferProperty(string memberZoneDomain)
- {
- string domain = "allow-transfer.ext." + memberZoneDomain;
- IReadOnlyList<DnsResourceRecord> records = _dnsServer.AuthZoneManager.GetRecords(_name, domain, DnsResourceRecordType.APL);
- if (records.Count > 0)
- return NetworkAccessControl.ConvertFromAPLRecordData(records[0].RDATA as DnsAPLRecordData);
- return [];
- }
- private Dictionary<string, object> GetZoneTransferTsigKeyNamesProperty(string memberZoneDomain)
- {
- string domain = "transfer-tsig-key-names.ext." + memberZoneDomain;
- IReadOnlyList<DnsResourceRecord> records = _dnsServer.AuthZoneManager.GetRecords(_name, domain, DnsResourceRecordType.PTR);
- Dictionary<string, object> keyNames = new Dictionary<string, object>(records.Count);
- foreach (DnsResourceRecord record in records)
- keyNames.TryAdd((record.RDATA as DnsPTRRecordData).Domain.ToLowerInvariant(), null);
- return keyNames;
- }
- private static AuthZoneQueryAccess GetQueryAccessType(IReadOnlyCollection<NetworkAccessControl> acl)
- {
- if (acl.HasSameItems(_allowACL))
- return AuthZoneQueryAccess.Allow;
- if (acl.HasSameItems(_queryAccessAllowOnlyPrivateNetworksACL))
- return AuthZoneQueryAccess.AllowOnlyPrivateNetworks;
- if (acl.HasSameItems(_allowOnlyZoneNameServersACL))
- return AuthZoneQueryAccess.AllowOnlyZoneNameServers;
- if ((acl.Count > 1) && acl.Contains(_allowZoneNameServersAndUseSpecifiedNetworkACL))
- return AuthZoneQueryAccess.AllowZoneNameServersAndUseSpecifiedNetworkACL;
- if (acl.HasSameItems(_denyACL))
- return AuthZoneQueryAccess.Deny;
- return AuthZoneQueryAccess.UseSpecifiedNetworkACL;
- }
- private static AuthZoneTransfer GetZoneTransferType(IReadOnlyCollection<NetworkAccessControl> acl)
- {
- if (acl.HasSameItems(_allowACL))
- return AuthZoneTransfer.Allow;
- if (acl.HasSameItems(_allowOnlyZoneNameServersACL))
- return AuthZoneTransfer.AllowOnlyZoneNameServers;
- if ((acl.Count > 1) && acl.Contains(_allowZoneNameServersAndUseSpecifiedNetworkACL))
- return AuthZoneTransfer.AllowZoneNameServersAndUseSpecifiedNetworkACL;
- if (acl.HasSameItems(_denyACL))
- return AuthZoneTransfer.Deny;
- return AuthZoneTransfer.UseSpecifiedNetworkACL;
- }
- private static List<NetworkAccessControl> GetFilteredACL(IReadOnlyCollection<NetworkAccessControl> acl)
- {
- List<NetworkAccessControl> filteredACL = new List<NetworkAccessControl>(acl.Count);
- foreach (NetworkAccessControl ac in acl)
- {
- if (ac.Equals(_allowZoneNameServersAndUseSpecifiedNetworkACL))
- continue;
- filteredACL.Add(ac);
- }
- return filteredACL;
- }
- #endregion
- #region public
- public override string GetZoneTypeName()
- {
- return "Secondary Catalog";
- }
- public override IReadOnlyList<DnsResourceRecord> QueryRecords(DnsResourceRecordType type, bool dnssecOk)
- {
- return []; //secondary catalog zone is not queriable
- }
- #endregion
- #region properties
- public override string CatalogZoneName
- {
- get { return base.CatalogZoneName; }
- set { throw new InvalidOperationException(); }
- }
- public override bool OverrideCatalogQueryAccess
- {
- get { throw new InvalidOperationException(); }
- set { throw new InvalidOperationException(); }
- }
- public override AuthZoneQueryAccess QueryAccess
- {
- get { return _queryAccess; }
- set { throw new InvalidOperationException(); }
- }
- public override AuthZoneTransfer ZoneTransfer
- {
- get { return _zoneTransfer; }
- set { throw new InvalidOperationException(); }
- }
- public override AuthZoneUpdate Update
- {
- get { return base.Update; }
- set { throw new InvalidOperationException(); }
- }
- #endregion
- }
- public class SecondaryCatalogEventArgs : EventArgs
- {
- #region variables
- readonly AuthZoneInfo _zoneInfo;
- #endregion
- #region constructor
- public SecondaryCatalogEventArgs(AuthZoneInfo zoneInfo)
- {
- _zoneInfo = zoneInfo;
- }
- #endregion
- #region properties
- public AuthZoneInfo ZoneInfo
- { get { return _zoneInfo; } }
- #endregion
- }
- }
|