diff --git a/DnsServerCore/Dns/Zones/SecondaryForwarderZone.cs b/DnsServerCore/Dns/Zones/SecondaryForwarderZone.cs new file mode 100644 index 00000000..27815a91 --- /dev/null +++ b/DnsServerCore/Dns/Zones/SecondaryForwarderZone.cs @@ -0,0 +1,160 @@ +/* +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 . + +*/ + +using DnsServerCore.Dns.ResourceRecords; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using TechnitiumLibrary.Net.Dns; +using TechnitiumLibrary.Net.Dns.ResourceRecords; + +namespace DnsServerCore.Dns.Zones +{ + class SecondaryForwarderZone : SecondaryZone + { + #region constructor + + public SecondaryForwarderZone(DnsServer dnsServer, AuthZoneInfo zoneInfo) + : base(dnsServer, zoneInfo) + { } + + public SecondaryForwarderZone(DnsServer dnsServer, string name, IReadOnlyList primaryNameServerAddresses, DnsTransportProtocol primaryZoneTransferProtocol = DnsTransportProtocol.Tcp, string primaryZoneTransferTsigKeyName = null) + : base(dnsServer, name, primaryNameServerAddresses, primaryZoneTransferProtocol, primaryZoneTransferTsigKeyName, false) + { + InitZone(); + } + + #endregion + + #region protected + + protected virtual void InitZone() + { + //init secondary forwarder zone with dummy SOA record + DnsSOARecordData soa = new DnsSOARecordData(_dnsServer.ServerDomain, "invalid", 0, 900, 300, 604800, 900); + DnsResourceRecord soaRecord = new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, 0, soa); + soaRecord.GetAuthGenericRecordInfo().LastModified = DateTime.UtcNow; + + _entries[DnsResourceRecordType.SOA] = [soaRecord]; + } + + protected override Task FinalizeZoneTransferAsync() + { + //secondary forwarder does not maintain zone history + return Task.CompletedTask; + } + + protected override Task FinalizeIncrementalZoneTransferAsync(IReadOnlyList historyRecords) + { + //secondary forwarder does not maintain zone history + return Task.CompletedTask; + } + + #endregion + + #region public + + public override string GetZoneTypeName() + { + return "Secondary Forwarder"; + } + + public override IReadOnlyList QueryRecords(DnsResourceRecordType type, bool dnssecOk) + { + if (type == DnsResourceRecordType.SOA) + return []; //secondary forwarder zone is not authoritative and contains dummy SOA record + + return base.QueryRecords(type, dnssecOk); + } + + #endregion + + #region properties + + public override bool OverrideCatalogPrimaryNameServers + { + get { throw new InvalidOperationException(); } + set { throw new InvalidOperationException(); } + } + + public override AuthZoneQueryAccess QueryAccess + { + get { return base.QueryAccess; } + set + { + switch (value) + { + case AuthZoneQueryAccess.AllowOnlyZoneNameServers: + case AuthZoneQueryAccess.AllowZoneNameServersAndUseSpecifiedNetworkACL: + throw new ArgumentException("The Query Access option is invalid for Secondary Conditional Forwarder zones: " + value.ToString(), nameof(QueryAccess)); + } + + base.QueryAccess = value; + } + } + + public override AuthZoneTransfer ZoneTransfer + { + get { return base.ZoneTransfer; } + set { throw new InvalidOperationException(); } + } + + public override AuthZoneNotify Notify + { + get { return base.Notify; } + set { throw new InvalidOperationException(); } + } + + public override AuthZoneUpdate Update + { + get { return base.Update; } + set + { + switch (value) + { + case AuthZoneUpdate.AllowOnlyZoneNameServers: + case AuthZoneUpdate.AllowZoneNameServersAndUseSpecifiedNetworkACL: + throw new ArgumentException("The Dynamic Updates option is invalid for Secondary Conditional Forwarder zones: " + value.ToString(), nameof(Update)); + } + + base.Update = value; + } + } + + public override IReadOnlyList PrimaryNameServerAddresses + { + get { return base.PrimaryNameServerAddresses; } + set + { + if ((value is null) || (value.Count == 0)) + throw new ArgumentException("At least one primary name server address must be specified for " + GetZoneTypeName() + " zone.", nameof(PrimaryNameServerAddresses)); + + base.PrimaryNameServerAddresses = value; + } + } + + public override bool ValidateZone + { + get { return base.ValidateZone; } + set { throw new InvalidOperationException(); } + } + + #endregion + } +}