From cc9728764e610e6b546809dd006e73f2fe2edb7d Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 1 Jun 2024 17:56:10 +0530 Subject: [PATCH] AuthRecordInfo: refactored implementation to add specialized record info classes. --- .../Dns/ResourceRecords/AuthRecordInfo.cs | 381 ++++++++---------- .../DnsResourceRecordExtensions.cs | 127 +++++- .../Dns/ResourceRecords/GenericRecordInfo.cs | 121 ++++++ .../Dns/ResourceRecords/HistoryRecordInfo.cs | 89 ++++ .../Dns/ResourceRecords/NSRecordInfo.cs | 109 +++++ .../Dns/ResourceRecords/SOARecordInfo.cs | 158 ++++++++ .../Dns/ResourceRecords/SVCBRecordInfo.cs | 90 +++++ 7 files changed, 843 insertions(+), 232 deletions(-) create mode 100644 DnsServerCore/Dns/ResourceRecords/GenericRecordInfo.cs create mode 100644 DnsServerCore/Dns/ResourceRecords/HistoryRecordInfo.cs create mode 100644 DnsServerCore/Dns/ResourceRecords/NSRecordInfo.cs create mode 100644 DnsServerCore/Dns/ResourceRecords/SOARecordInfo.cs create mode 100644 DnsServerCore/Dns/ResourceRecords/SVCBRecordInfo.cs diff --git a/DnsServerCore/Dns/ResourceRecords/AuthRecordInfo.cs b/DnsServerCore/Dns/ResourceRecords/AuthRecordInfo.cs index 0d4eefbf..e35f377d 100644 --- a/DnsServerCore/Dns/ResourceRecords/AuthRecordInfo.cs +++ b/DnsServerCore/Dns/ResourceRecords/AuthRecordInfo.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 @@ -18,7 +18,6 @@ along with this program. If not, see . */ using System; -using System.Collections.Generic; using System.IO; using System.Net; using TechnitiumLibrary.IO; @@ -27,37 +26,60 @@ using TechnitiumLibrary.Net.Dns.ResourceRecords; namespace DnsServerCore.Dns.ResourceRecords { - class AuthRecordInfo + abstract class AuthRecordInfo { - #region variables + #region constructor - public static readonly AuthRecordInfo Default = new AuthRecordInfo(); + protected AuthRecordInfo() + { } - bool _disabled; - IReadOnlyList _glueRecords; - string _comments; - DateTime _deletedOn; - IReadOnlyList _primaryNameServers; - DnsTransportProtocol _zoneTransferProtocol; - string _tsigKeyName = string.Empty; - bool _useSoaSerialDateScheme; - - DateTime _lastUsedOn; //not serialized + protected AuthRecordInfo(BinaryReader bR) + { + byte version = bR.ReadByte(); + if (version >= 9) + ReadRecordInfoFrom(bR); + else + ReadOldFormatFrom(bR, version, this is SOARecordInfo); + } #endregion - #region constructor + #region static - public AuthRecordInfo() - { } - - public AuthRecordInfo(BinaryReader bR, bool isSoa) + public static GenericRecordInfo ReadGenericRecordInfoFrom(BinaryReader bR, DnsResourceRecordType type) + { + switch (type) + { + case DnsResourceRecordType.NS: + return new NSRecordInfo(bR); + + case DnsResourceRecordType.SOA: + return new SOARecordInfo(bR); + + case DnsResourceRecordType.SVCB: + case DnsResourceRecordType.HTTPS: + return new SVCBRecordInfo(bR); + + default: + return new GenericRecordInfo(bR); + } + } + + #endregion + + #region private + + private void ReadOldFormatFrom(BinaryReader bR, byte version, bool isSoa) { - byte version = bR.ReadByte(); switch (version) { case 1: - _disabled = bR.ReadBoolean(); + { + bool disabled = bR.ReadBoolean(); + + if (this is GenericRecordInfo info) + info.Disabled = disabled; + } break; case 2: @@ -67,94 +89,134 @@ namespace DnsServerCore.Dns.ResourceRecords case 6: case 7: case 8: - _disabled = bR.ReadBoolean(); - - if ((version < 5) && isSoa) { - //read old glue records as NameServerAddress in case of SOA record - int count = bR.ReadByte(); - if (count > 0) { - NameServerAddress[] primaryNameServers = new NameServerAddress[count]; + bool disabled = bR.ReadBoolean(); - for (int i = 0; i < primaryNameServers.Length; i++) + if (this is GenericRecordInfo info) + info.Disabled = disabled; + } + + if ((version < 5) && isSoa) + { + //read old glue records as NameServerAddress in case of SOA record + int count = bR.ReadByte(); + if (count > 0) { - DnsResourceRecord glueRecord = new DnsResourceRecord(bR.BaseStream); + NameServerAddress[] primaryNameServers = new NameServerAddress[count]; - IPAddress address; - - switch (glueRecord.Type) + for (int i = 0; i < primaryNameServers.Length; i++) { - case DnsResourceRecordType.A: - address = (glueRecord.RDATA as DnsARecordData).Address; - break; + DnsResourceRecord glueRecord = new DnsResourceRecord(bR.BaseStream); - case DnsResourceRecordType.AAAA: - address = (glueRecord.RDATA as DnsAAAARecordData).Address; - break; + IPAddress address; - default: - continue; + switch (glueRecord.Type) + { + case DnsResourceRecordType.A: + address = (glueRecord.RDATA as DnsARecordData).Address; + break; + + case DnsResourceRecordType.AAAA: + address = (glueRecord.RDATA as DnsAAAARecordData).Address; + break; + + default: + continue; + } + + primaryNameServers[i] = new NameServerAddress(address); } - primaryNameServers[i] = new NameServerAddress(address); + (this as SOARecordInfo).PrimaryNameServers = primaryNameServers; } - - _primaryNameServers = primaryNameServers; } - } - else - { - int count = bR.ReadByte(); - if (count > 0) + else { - DnsResourceRecord[] glueRecords = new DnsResourceRecord[count]; + int count = bR.ReadByte(); + if (count > 0) + { + DnsResourceRecord[] glueRecords = new DnsResourceRecord[count]; - for (int i = 0; i < glueRecords.Length; i++) - glueRecords[i] = new DnsResourceRecord(bR.BaseStream); + for (int i = 0; i < glueRecords.Length; i++) + glueRecords[i] = new DnsResourceRecord(bR.BaseStream); - _glueRecords = glueRecords; + if (this is NSRecordInfo info) + info.GlueRecords = glueRecords; + } } - } - if (version >= 3) - _comments = bR.ReadShortString(); - - if (version >= 4) - _deletedOn = bR.ReadDateTime(); - - if (version >= 5) - { - int count = bR.ReadByte(); - if (count > 0) + if (version >= 3) { - NameServerAddress[] primaryNameServers = new NameServerAddress[count]; + string comments = bR.ReadShortString(); - for (int i = 0; i < primaryNameServers.Length; i++) - primaryNameServers[i] = new NameServerAddress(bR); + if (this is GenericRecordInfo info) + info.Comments = comments; + } - _primaryNameServers = primaryNameServers; + if (version >= 4) + { + DateTime deletedOn = bR.ReadDateTime(); + + if (this is HistoryRecordInfo info) + info.DeletedOn = deletedOn; + } + + if (version >= 5) + { + int count = bR.ReadByte(); + if (count > 0) + { + NameServerAddress[] primaryNameServers = new NameServerAddress[count]; + + for (int i = 0; i < primaryNameServers.Length; i++) + primaryNameServers[i] = new NameServerAddress(bR); + + if (this is SOARecordInfo info) + info.PrimaryNameServers = primaryNameServers; + } + } + + if (version >= 7) + { + DnsTransportProtocol zoneTransferProtocol = (DnsTransportProtocol)bR.ReadByte(); + string tsigKeyName = bR.ReadShortString(); + + if (this is SOARecordInfo info) + { + if (zoneTransferProtocol != DnsTransportProtocol.Udp) + info.ZoneTransferProtocol = zoneTransferProtocol; + + if (tsigKeyName.Length > 0) + info.TsigKeyName = tsigKeyName; + } + } + else if (version >= 6) + { + DnsTransportProtocol zoneTransferProtocol = (DnsTransportProtocol)bR.ReadByte(); + + string tsigKeyName = bR.ReadShortString(); + _ = bR.ReadShortString(); //_tsigSharedSecret (obsolete) + _ = bR.ReadShortString(); //_tsigAlgorithm (obsolete) + + if (this is SOARecordInfo info) + { + if (zoneTransferProtocol != DnsTransportProtocol.Udp) + info.ZoneTransferProtocol = zoneTransferProtocol; + + if (tsigKeyName.Length > 0) + info.TsigKeyName = tsigKeyName; + } + } + + if (version >= 8) + { + bool useSoaSerialDateScheme = bR.ReadBoolean(); + + if (this is SOARecordInfo info) + info.UseSoaSerialDateScheme = useSoaSerialDateScheme; } } - - if (version >= 7) - { - _zoneTransferProtocol = (DnsTransportProtocol)bR.ReadByte(); - - _tsigKeyName = bR.ReadShortString(); - } - else if (version >= 6) - { - _zoneTransferProtocol = (DnsTransportProtocol)bR.ReadByte(); - - _tsigKeyName = bR.ReadShortString(); - _ = bR.ReadShortString(); //_tsigSharedSecret (obsolete) - _ = bR.ReadShortString(); //_tsigAlgorithm (obsolete) - } - - if (version >= 8) - _useSoaSerialDateScheme = bR.ReadBoolean(); - break; default: @@ -164,144 +226,21 @@ namespace DnsServerCore.Dns.ResourceRecords #endregion + #region protected + + protected abstract void ReadRecordInfoFrom(BinaryReader bR); + + protected abstract void WriteRecordInfoTo(BinaryWriter bW); + + #endregion + #region public public void WriteTo(BinaryWriter bW) { - bW.Write((byte)8); //version - bW.Write(_disabled); + bW.Write((byte)9); //version - if (_glueRecords is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_glueRecords.Count)); - - foreach (DnsResourceRecord glueRecord in _glueRecords) - glueRecord.WriteTo(bW.BaseStream); - } - - if (string.IsNullOrEmpty(_comments)) - bW.Write((byte)0); - else - bW.WriteShortString(_comments); - - bW.Write(_deletedOn); - - if (_primaryNameServers is null) - { - bW.Write((byte)0); - } - else - { - bW.Write(Convert.ToByte(_primaryNameServers.Count)); - - foreach (NameServerAddress nameServer in _primaryNameServers) - nameServer.WriteTo(bW); - } - - bW.Write((byte)_zoneTransferProtocol); - - bW.WriteShortString(_tsigKeyName); - - bW.Write(_useSoaSerialDateScheme); - } - - #endregion - - #region properties - - public bool Disabled - { - get { return _disabled; } - set { _disabled = value; } - } - - public IReadOnlyList GlueRecords - { - get { return _glueRecords; } - set - { - if ((value is null) || (value.Count == 0)) - _glueRecords = null; - else - _glueRecords = value; - } - } - - public string Comments - { - get { return _comments; } - set - { - if ((value is not null) && (value.Length > 255)) - throw new ArgumentOutOfRangeException(nameof(Comments), "Resource record comment text cannot exceed 255 characters."); - - _comments = value; - } - } - - public DateTime DeletedOn - { - get { return _deletedOn; } - set { _deletedOn = value; } - } - - public IReadOnlyList PrimaryNameServers - { - get { return _primaryNameServers; } - set - { - if ((value is null) || (value.Count == 0)) - _primaryNameServers = null; - else - _primaryNameServers = value; - } - } - - public DnsTransportProtocol ZoneTransferProtocol - { - get { return _zoneTransferProtocol; } - set - { - switch (value) - { - case DnsTransportProtocol.Tcp: - case DnsTransportProtocol.Tls: - case DnsTransportProtocol.Quic: - _zoneTransferProtocol = value; - break; - - default: - throw new NotSupportedException("Zone transfer protocol is not supported: XFR-over-" + value.ToString().ToUpper()); - } - } - } - - public string TsigKeyName - { - get { return _tsigKeyName; } - set - { - if (value is null) - _tsigKeyName = string.Empty; - else - _tsigKeyName = value; - } - } - - public bool UseSoaSerialDateScheme - { - get { return _useSoaSerialDateScheme; } - set { _useSoaSerialDateScheme = value; } - } - - public DateTime LastUsedOn - { - get { return _lastUsedOn; } - set { _lastUsedOn = value; } + WriteRecordInfoTo(bW); } #endregion diff --git a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtensions.cs b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtensions.cs index 671823d1..8a5306d1 100644 --- a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtensions.cs +++ b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtensions.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 @@ -53,7 +53,7 @@ namespace DnsServerCore.Dns.ResourceRecords } } - record.GetAuthRecordInfo().GlueRecords = glueRecords; + record.GetAuthNSRecordInfo().GlueRecords = glueRecords; } public static void SyncGlueRecords(this DnsResourceRecord record, IReadOnlyList allGlueRecords) @@ -78,7 +78,7 @@ namespace DnsServerCore.Dns.ResourceRecords } } - record.GetAuthRecordInfo().GlueRecords = foundGlueRecords; + record.GetAuthNSRecordInfo().GlueRecords = foundGlueRecords; } public static void SyncGlueRecords(this DnsResourceRecord record, IReadOnlyCollection deletedGlueRecords, IReadOnlyCollection addedGlueRecords) @@ -89,7 +89,7 @@ namespace DnsServerCore.Dns.ResourceRecords bool updated = false; List updatedGlueRecords = new List(); - IReadOnlyList existingGlueRecords = record.GetAuthRecordInfo().GlueRecords; + IReadOnlyList existingGlueRecords = record.GetAuthNSRecordInfo().GlueRecords; if (existingGlueRecords is not null) { foreach (DnsResourceRecord existingGlueRecord in existingGlueRecords) @@ -119,18 +119,123 @@ namespace DnsServerCore.Dns.ResourceRecords } if (updated) - record.GetAuthRecordInfo().GlueRecords = updatedGlueRecords; + record.GetAuthNSRecordInfo().GlueRecords = updatedGlueRecords; } - public static AuthRecordInfo GetAuthRecordInfo(this DnsResourceRecord record) + public static GenericRecordInfo GetAuthGenericRecordInfo(this DnsResourceRecord record) { - if (record.Tag is not AuthRecordInfo rrInfo) + if (record.Tag is null) { - rrInfo = new AuthRecordInfo(); - record.Tag = rrInfo; - } + GenericRecordInfo rrInfo; - return rrInfo; + switch (record.Type) + { + case DnsResourceRecordType.NS: + rrInfo = new NSRecordInfo(); + break; + + case DnsResourceRecordType.SOA: + rrInfo = new SOARecordInfo(); + break; + + case DnsResourceRecordType.SVCB: + case DnsResourceRecordType.HTTPS: + rrInfo = new SVCBRecordInfo(); + break; + + default: + rrInfo = new GenericRecordInfo(); + break; + } + + record.Tag = rrInfo; + + return rrInfo; + } + else if (record.Tag is GenericRecordInfo rrInfo) + { + return rrInfo; + } + else + { + throw new InvalidOperationException(); + } + } + + public static NSRecordInfo GetAuthNSRecordInfo(this DnsResourceRecord record) + { + if (record.Tag is null) + { + NSRecordInfo info = new NSRecordInfo(); + record.Tag = info; + + return info; + } + else if (record.Tag is NSRecordInfo nsInfo) + { + return nsInfo; + } + else + { + throw new InvalidOperationException(); + } + } + + public static SOARecordInfo GetAuthSOARecordInfo(this DnsResourceRecord record) + { + if (record.Tag is null) + { + SOARecordInfo info = new SOARecordInfo(); + record.Tag = info; + + return info; + } + else if (record.Tag is SOARecordInfo soaInfo) + { + return soaInfo; + } + else + { + throw new InvalidOperationException(); + } + } + + public static SVCBRecordInfo GetAuthSVCBRecordInfo(this DnsResourceRecord record) + { + if (record.Tag is null) + { + SVCBRecordInfo info = new SVCBRecordInfo(); + record.Tag = info; + + return info; + } + else if (record.Tag is SVCBRecordInfo svcbInfo) + { + return svcbInfo; + } + else + { + throw new InvalidOperationException(); + } + } + + public static HistoryRecordInfo GetAuthHistoryRecordInfo(this DnsResourceRecord record) + { + if (record.Tag is null) + { + HistoryRecordInfo info = new HistoryRecordInfo(); + record.Tag = info; + + return info; + } + else if (record.Tag is HistoryRecordInfo info) + { + return info; + } + else + { + throw new InvalidOperationException(); + } } public static CacheRecordInfo GetCacheRecordInfo(this DnsResourceRecord record) diff --git a/DnsServerCore/Dns/ResourceRecords/GenericRecordInfo.cs b/DnsServerCore/Dns/ResourceRecords/GenericRecordInfo.cs new file mode 100644 index 00000000..e2f0d6bb --- /dev/null +++ b/DnsServerCore/Dns/ResourceRecords/GenericRecordInfo.cs @@ -0,0 +1,121 @@ +/* +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 System; +using System.IO; +using TechnitiumLibrary.IO; + +namespace DnsServerCore.Dns.ResourceRecords +{ + class GenericRecordInfo : AuthRecordInfo + { + #region variables + + bool _disabled; + string _comments; + + DateTime _lastUsedOn; //not serialized + + #endregion + + #region constructor + + public GenericRecordInfo() + { } + + public GenericRecordInfo(BinaryReader bR) + : base(bR) + { } + + #endregion + + #region protected + + protected sealed override void ReadRecordInfoFrom(BinaryReader bR) + { + byte version = bR.ReadByte(); + switch (version) + { + case 1: + _disabled = bR.ReadBoolean(); + _comments = bR.ReadShortString(); + + ReadExtendedRecordInfoFrom(bR); + break; + + default: + throw new InvalidDataException("GenericRecordInfo format version not supported."); + } + } + + protected sealed override void WriteRecordInfoTo(BinaryWriter bW) + { + bW.Write((byte)1); //version + + bW.Write(_disabled); + + if (string.IsNullOrEmpty(_comments)) + bW.Write((byte)0); + else + bW.WriteShortString(_comments); + + WriteExtendedRecordInfoTo(bW); + } + + protected virtual void ReadExtendedRecordInfoFrom(BinaryReader bR) + { + _ = bR.ReadByte(); //read byte to move ahead + } + + protected virtual void WriteExtendedRecordInfoTo(BinaryWriter bW) + { + bW.Write((byte)0); //no extended info + } + + #endregion + + #region properties + + public bool Disabled + { + get { return _disabled; } + set { _disabled = value; } + } + + public string Comments + { + get { return _comments; } + set + { + if ((value is not null) && (value.Length > 255)) + throw new ArgumentOutOfRangeException(nameof(Comments), "Resource record comment text cannot exceed 255 characters."); + + _comments = value; + } + } + + public DateTime LastUsedOn + { + get { return _lastUsedOn; } + set { _lastUsedOn = value; } + } + + #endregion + } +} diff --git a/DnsServerCore/Dns/ResourceRecords/HistoryRecordInfo.cs b/DnsServerCore/Dns/ResourceRecords/HistoryRecordInfo.cs new file mode 100644 index 00000000..47f39b1d --- /dev/null +++ b/DnsServerCore/Dns/ResourceRecords/HistoryRecordInfo.cs @@ -0,0 +1,89 @@ +/* +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 System; +using System.IO; +using TechnitiumLibrary.IO; + +namespace DnsServerCore.Dns.ResourceRecords +{ + class HistoryRecordInfo : AuthRecordInfo + { + #region variables + + DateTime _deletedOn; + + #endregion + + #region constructor + + public HistoryRecordInfo() + { } + + public HistoryRecordInfo(BinaryReader bR) + : base(bR) + { } + + #endregion + + #region static + + public static HistoryRecordInfo ReadFrom(BinaryReader bR) + { + return new HistoryRecordInfo(bR); + } + + #endregion + + #region protected + + protected override void ReadRecordInfoFrom(BinaryReader bR) + { + byte version = bR.ReadByte(); + switch (version) + { + case 1: + _deletedOn = bR.ReadDateTime(); + break; + + default: + throw new InvalidDataException("HistoryRecordInfo format version not supported."); + } + } + + protected override void WriteRecordInfoTo(BinaryWriter bW) + { + bW.Write((byte)1); //version + + bW.Write(_deletedOn); + } + + #endregion + + #region properties + + public DateTime DeletedOn + { + get { return _deletedOn; } + set { _deletedOn = value; } + } + + #endregion + } +} diff --git a/DnsServerCore/Dns/ResourceRecords/NSRecordInfo.cs b/DnsServerCore/Dns/ResourceRecords/NSRecordInfo.cs new file mode 100644 index 00000000..a8cc2345 --- /dev/null +++ b/DnsServerCore/Dns/ResourceRecords/NSRecordInfo.cs @@ -0,0 +1,109 @@ +/* +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 System; +using System.Collections.Generic; +using System.IO; +using TechnitiumLibrary.Net.Dns.ResourceRecords; + +namespace DnsServerCore.Dns.ResourceRecords +{ + class NSRecordInfo : GenericRecordInfo + { + #region variables + + IReadOnlyList _glueRecords; + + #endregion + + #region constructor + + public NSRecordInfo() + { } + + public NSRecordInfo(BinaryReader bR) + : base(bR) + { } + + #endregion + + #region protected + + protected override void ReadExtendedRecordInfoFrom(BinaryReader bR) + { + byte version = bR.ReadByte(); + switch (version) + { + case 0: //no extended info + break; + + case 1: + int count = bR.ReadByte(); + if (count > 0) + { + DnsResourceRecord[] glueRecords = new DnsResourceRecord[count]; + + for (int i = 0; i < glueRecords.Length; i++) + glueRecords[i] = new DnsResourceRecord(bR.BaseStream); + + _glueRecords = glueRecords; + } + break; + + default: + throw new InvalidDataException("NSRecordInfo format version not supported."); + } + } + + protected override void WriteExtendedRecordInfoTo(BinaryWriter bW) + { + bW.Write((byte)1); //version + + if (_glueRecords is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(_glueRecords.Count)); + + foreach (DnsResourceRecord glueRecord in _glueRecords) + glueRecord.WriteTo(bW.BaseStream); + } + } + + #endregion + + #region properties + + public IReadOnlyList GlueRecords + { + get { return _glueRecords; } + set + { + if ((value is null) || (value.Count == 0)) + _glueRecords = null; + else + _glueRecords = value; + } + } + + #endregion + } +} diff --git a/DnsServerCore/Dns/ResourceRecords/SOARecordInfo.cs b/DnsServerCore/Dns/ResourceRecords/SOARecordInfo.cs new file mode 100644 index 00000000..83002a83 --- /dev/null +++ b/DnsServerCore/Dns/ResourceRecords/SOARecordInfo.cs @@ -0,0 +1,158 @@ +/* +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 System; +using System.Collections.Generic; +using System.IO; +using TechnitiumLibrary.IO; +using TechnitiumLibrary.Net.Dns; + +namespace DnsServerCore.Dns.ResourceRecords +{ + class SOARecordInfo : GenericRecordInfo + { + #region variables + + IReadOnlyList _primaryNameServers; + DnsTransportProtocol _zoneTransferProtocol; + string _tsigKeyName = string.Empty; + bool _useSoaSerialDateScheme; + + #endregion + + #region constructor + + public SOARecordInfo() + { } + + public SOARecordInfo(BinaryReader bR) + : base(bR) + { } + + #endregion + + #region protected + + protected override void ReadExtendedRecordInfoFrom(BinaryReader bR) + { + byte version = bR.ReadByte(); + switch (version) + { + case 0: //no extended info + break; + + case 1: + int count = bR.ReadByte(); + if (count > 0) + { + NameServerAddress[] primaryNameServers = new NameServerAddress[count]; + + for (int i = 0; i < primaryNameServers.Length; i++) + primaryNameServers[i] = new NameServerAddress(bR); + + _primaryNameServers = primaryNameServers; + } + + _zoneTransferProtocol = (DnsTransportProtocol)bR.ReadByte(); + _tsigKeyName = bR.ReadShortString(); + _useSoaSerialDateScheme = bR.ReadBoolean(); + break; + + default: + throw new InvalidDataException("SOARecordInfo format version not supported."); + } + } + + protected override void WriteExtendedRecordInfoTo(BinaryWriter bW) + { + bW.Write((byte)1); //version + + if (_primaryNameServers is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(_primaryNameServers.Count)); + + foreach (NameServerAddress nameServer in _primaryNameServers) + nameServer.WriteTo(bW); + } + + bW.Write((byte)_zoneTransferProtocol); + bW.WriteShortString(_tsigKeyName); + bW.Write(_useSoaSerialDateScheme); + } + + #endregion + + #region properties + + public IReadOnlyList PrimaryNameServers + { + get { return _primaryNameServers; } + set + { + if ((value is null) || (value.Count == 0)) + _primaryNameServers = null; + else + _primaryNameServers = value; + } + } + + public DnsTransportProtocol ZoneTransferProtocol + { + get { return _zoneTransferProtocol; } + set + { + switch (value) + { + case DnsTransportProtocol.Tcp: + case DnsTransportProtocol.Tls: + case DnsTransportProtocol.Quic: + _zoneTransferProtocol = value; + break; + + default: + throw new NotSupportedException("Zone transfer protocol is not supported: XFR-over-" + value.ToString().ToUpper()); + } + } + } + + public string TsigKeyName + { + get { return _tsigKeyName; } + set + { + if (value is null) + _tsigKeyName = string.Empty; + else + _tsigKeyName = value; + } + } + + public bool UseSoaSerialDateScheme + { + get { return _useSoaSerialDateScheme; } + set { _useSoaSerialDateScheme = value; } + } + + #endregion + } +} diff --git a/DnsServerCore/Dns/ResourceRecords/SVCBRecordInfo.cs b/DnsServerCore/Dns/ResourceRecords/SVCBRecordInfo.cs new file mode 100644 index 00000000..02aeb0af --- /dev/null +++ b/DnsServerCore/Dns/ResourceRecords/SVCBRecordInfo.cs @@ -0,0 +1,90 @@ +/* +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 System.IO; + +namespace DnsServerCore.Dns.ResourceRecords +{ + class SVCBRecordInfo : GenericRecordInfo + { + #region variables + + bool _autoIpv4Hint; + bool _autoIpv6Hint; + + #endregion + + #region constructor + + public SVCBRecordInfo() + { } + + public SVCBRecordInfo(BinaryReader bR) + : base(bR) + { } + + #endregion + + #region protected + + protected override void ReadExtendedRecordInfoFrom(BinaryReader bR) + { + byte version = bR.ReadByte(); + switch (version) + { + case 0: //no extended info + break; + + case 1: + _autoIpv4Hint = bR.ReadBoolean(); + _autoIpv6Hint = bR.ReadBoolean(); + break; + + default: + throw new InvalidDataException("SVCBRecordInfo format version not supported."); + } + } + + protected override void WriteExtendedRecordInfoTo(BinaryWriter bW) + { + bW.Write((byte)1); //version + + bW.Write(_autoIpv4Hint); + bW.Write(_autoIpv6Hint); + } + + #endregion + + #region properties + + public bool AutoIpv4Hint + { + get { return _autoIpv4Hint; } + set { _autoIpv4Hint = value; } + } + + public bool AutoIpv6Hint + { + get { return _autoIpv6Hint; } + set { _autoIpv6Hint = value; } + } + + #endregion + } +}