/* Technitium DNS Server Copyright (C) 2023 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 System.Net; using TechnitiumLibrary.IO; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; namespace DnsServerCore.Dns.ResourceRecords { class AuthRecordInfo { #region variables public static readonly AuthRecordInfo Default = new AuthRecordInfo(); bool _disabled; IReadOnlyList _glueRecords; string _comments; DateTime _deletedOn; IReadOnlyList _primaryNameServers; DnsTransportProtocol _zoneTransferProtocol; string _tsigKeyName = string.Empty; bool _useSoaSerialDateScheme; DateTime _lastUsedOn; //not serialized #endregion #region constructor public AuthRecordInfo() { } public AuthRecordInfo(BinaryReader bR, bool isSoa) { byte version = bR.ReadByte(); switch (version) { case 1: _disabled = bR.ReadBoolean(); break; case 2: case 3: case 4: case 5: 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]; for (int i = 0; i < primaryNameServers.Length; i++) { DnsResourceRecord glueRecord = new DnsResourceRecord(bR.BaseStream); IPAddress address; 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 = primaryNameServers; } } else { 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; } } if (version >= 3) _comments = bR.ReadShortString(); if (version >= 4) _deletedOn = bR.ReadDateTime(); 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); _primaryNameServers = primaryNameServers; } } 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: throw new InvalidDataException("AuthRecordInfo format version not supported."); } } #endregion #region public public void WriteTo(BinaryWriter bW) { bW.Write((byte)8); //version bW.Write(_disabled); 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; } } #endregion } }