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
+ }
+}