From 17844b7b596806ed6df30a956996227abec67ce3 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Sep 2024 17:49:48 +0530 Subject: [PATCH] ForwarderSubDomainZone: updated implementation to support zone versioning and notify features. Added validation to prevent adding DNSSEC related records. --- .../Dns/Zones/ForwarderSubDomainZone.cs | 85 ++++++++++++++++--- 1 file changed, 72 insertions(+), 13 deletions(-) diff --git a/DnsServerCore/Dns/Zones/ForwarderSubDomainZone.cs b/DnsServerCore/Dns/Zones/ForwarderSubDomainZone.cs index 525f99b7..410a9fd5 100644 --- a/DnsServerCore/Dns/Zones/ForwarderSubDomainZone.cs +++ b/DnsServerCore/Dns/Zones/ForwarderSubDomainZone.cs @@ -1,6 +1,6 @@ /* Technitium DNS Server -Copyright (C) 2023 Shreyas Zare (shreyas@technitium.com) +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 @@ -17,6 +17,7 @@ along with this program. If not, see . */ +using System; using System.Collections.Generic; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -47,12 +48,26 @@ namespace DnsServerCore.Dns.Zones switch (type) { case DnsResourceRecordType.SOA: + throw new InvalidOperationException("Cannot set SOA record on sub domain."); + case DnsResourceRecordType.DS: - throw new DnsServerException("The record type is not supported by forwarder zones."); + case DnsResourceRecordType.DNSKEY: + case DnsResourceRecordType.RRSIG: + case DnsResourceRecordType.NSEC: + case DnsResourceRecordType.NSEC3PARAM: + case DnsResourceRecordType.NSEC3: + throw new InvalidOperationException("Cannot set DNSSEC records."); default: - base.SetRecords(type, records); - _forwarderZone.UpdateLastModified(); + if (records[0].OriginalTtlValue > _forwarderZone.GetZoneSoaExpire()) + throw new DnsServerException("Failed to set records: TTL cannot be greater than SOA EXPIRE."); + + if (!TrySetRecords(type, records, out IReadOnlyList deletedRecords)) + throw new DnsServerException("Failed to set records. Please try again."); + + _forwarderZone.CommitAndIncrementSerial(deletedRecords, records); + + _forwarderZone.TriggerNotify(); break; } } @@ -62,20 +77,37 @@ namespace DnsServerCore.Dns.Zones switch (record.Type) { case DnsResourceRecordType.DS: - throw new DnsServerException("The record type is not supported by forwarder zones."); + case DnsResourceRecordType.DNSKEY: + case DnsResourceRecordType.RRSIG: + case DnsResourceRecordType.NSEC: + case DnsResourceRecordType.NSEC3PARAM: + case DnsResourceRecordType.NSEC3: + throw new InvalidOperationException("Cannot add DNSSEC record."); default: - base.AddRecord(record); - _forwarderZone.UpdateLastModified(); + if (record.OriginalTtlValue > _forwarderZone.GetZoneSoaExpire()) + throw new DnsServerException("Failed to add record: TTL cannot be greater than SOA EXPIRE."); + + AddRecord(record, out IReadOnlyList addedRecords, out IReadOnlyList deletedRecords); + + if (addedRecords.Count > 0) + { + _forwarderZone.CommitAndIncrementSerial(deletedRecords, addedRecords); + + _forwarderZone.TriggerNotify(); + } break; } } public override bool DeleteRecords(DnsResourceRecordType type) { - if (base.DeleteRecords(type)) + if (_entries.TryRemove(type, out IReadOnlyList removedRecords)) { - _forwarderZone.UpdateLastModified(); + _forwarderZone.CommitAndIncrementSerial(removedRecords); + + _forwarderZone.TriggerNotify(); + return true; } @@ -84,9 +116,12 @@ namespace DnsServerCore.Dns.Zones public override bool DeleteRecord(DnsResourceRecordType type, DnsResourceRecordData rdata) { - if (base.DeleteRecord(type, rdata)) + if (TryDeleteRecord(type, rdata, out DnsResourceRecord deletedRecord)) { - _forwarderZone.UpdateLastModified(); + _forwarderZone.CommitAndIncrementSerial([deletedRecord]); + + _forwarderZone.TriggerNotify(); + return true; } @@ -95,8 +130,32 @@ namespace DnsServerCore.Dns.Zones public override void UpdateRecord(DnsResourceRecord oldRecord, DnsResourceRecord newRecord) { - base.UpdateRecord(oldRecord, newRecord); - _forwarderZone.UpdateLastModified(); + switch (oldRecord.Type) + { + case DnsResourceRecordType.SOA: + throw new InvalidOperationException("Cannot update record: use SetRecords() for " + oldRecord.Type.ToString() + " record."); + + default: + if (oldRecord.Type != newRecord.Type) + throw new InvalidOperationException("Old and new record types do not match."); + + if (newRecord.OriginalTtlValue > _forwarderZone.GetZoneSoaExpire()) + throw new DnsServerException("Failed to update record: TTL cannot be greater than SOA EXPIRE."); + + if (!TryDeleteRecord(oldRecord.Type, oldRecord.RDATA, out DnsResourceRecord deletedRecord)) + throw new InvalidOperationException("Cannot update record: the record does not exists to be updated."); + + AddRecord(newRecord, out IReadOnlyList addedRecords, out IReadOnlyList deletedRecords); + + List allDeletedRecords = new List(deletedRecords.Count + 1); + allDeletedRecords.Add(deletedRecord); + allDeletedRecords.AddRange(deletedRecords); + + _forwarderZone.CommitAndIncrementSerial(allDeletedRecords, addedRecords); + + _forwarderZone.TriggerNotify(); + break; + } } #endregion