using System; using System.Collections.Generic; using System.Net; using Ubiety.Dns.Core.Common; namespace Ubiety.Dns.Core { /// /// DNS Record header /// public class Header { // internal flag private UInt16 _flags; /// /// Initializes a new instance of the class /// public Header() { } /// /// Initializes a new instance of the class /// /// of the record public Header(RecordReader rr) { Id = rr.ReadUInt16(); _flags = rr.ReadUInt16(); QuestionCount = rr.ReadUInt16(); AnswerCount = rr.ReadUInt16(); NameserverCount = rr.ReadUInt16(); AdditionalRecordsCount = rr.ReadUInt16(); } /// /// Gets or sets the unique identifier of the record /// public UInt16 Id { get; set; } /// /// Gets or sets the number of questions in the record /// public UInt16 QuestionCount { get; set; } /// /// Gets or sets the number of answers in the record /// public UInt16 AnswerCount { get; set; } /// /// Gets or sets the number of name servers in the record /// public UInt16 NameserverCount { get; set; } /// /// Gets or sets the number of additional records in the record /// public UInt16 AdditionalRecordsCount { get; set; } /// /// Gets or sets a value indicating whether the record is a query or response /// public Boolean QueryResponse { get => GetBits(_flags, 15, 1) == 1; set => _flags = SetBits(_flags, 15, 1, value); } /// /// Gets or sets the record opcode flag /// public OperationCode OpCode { get => (OperationCode)GetBits(_flags, 11, 4); set => _flags = SetBits(_flags, 11, 4, (UInt16)value); } /// /// Gets or sets a value indicating whether the record is an authoritative answer /// public Boolean AuthoritativeAnswer { get => GetBits(_flags, 10, 1) == 1; set => _flags = SetBits(_flags, 10, 1, value); } /// /// Gets or sets a value indicating whether the truncation flag is set /// public Boolean Truncation { get => GetBits(_flags, 9, 1) == 1; set => _flags = SetBits(_flags, 9, 1, value); } /// /// Gets or sets a value indicating whether the recursion flag is set /// public Boolean Recursion { get => GetBits(_flags, 8, 1) == 1; set => _flags = SetBits(_flags, 8, 1, value); } /// /// Gets or sets a value indicating whether the recursion available flag is set /// public Boolean RA { get => GetBits(_flags, 7, 1) == 1; set => _flags = SetBits(_flags, 7, 1, value); } /// /// Gets or sets a record reserved flag /// public UInt16 Z { get => GetBits(_flags, 4, 3); set => _flags = SetBits(_flags, 4, 3, value); } /// /// Gets or sets the record response code /// public ResponseCode ResponseCode { get => (ResponseCode)GetBits(_flags, 0, 4); set => _flags = SetBits(_flags, 0, 4, (UInt16)value); } /// /// Gets the header as a byte array /// /// Byte array of the header data public IEnumerable GetData() { var data = new List(); data.AddRange(WriteShort(Id)); data.AddRange(WriteShort(_flags)); data.AddRange(WriteShort(QuestionCount)); data.AddRange(WriteShort(AnswerCount)); data.AddRange(WriteShort(NameserverCount)); data.AddRange(WriteShort(AdditionalRecordsCount)); return data.ToArray(); } private static UInt16 SetBits(UInt16 oldValue, Int32 position, Int32 length, Boolean blnValue) { return SetBits(oldValue, position, length, blnValue ? (UInt16)1 : (UInt16)0); } private static UInt16 SetBits(UInt16 oldValue, Int32 position, Int32 length, UInt16 newValue) { // sanity check if (length <= 0 || position >= 16) { return oldValue; } // get some mask to put on var mask = (2 << (length - 1)) - 1; // clear out value oldValue &= (UInt16)~(mask << position); // set new value oldValue |= (UInt16)((newValue & mask) << position); return oldValue; } private static UInt16 GetBits(UInt16 oldValue, Int32 position, Int32 length) { // sanity check if (length <= 0 || position >= 16) { return 0; } // get some mask to put on var mask = (2 << (length - 1)) - 1; // shift down to get some value and mask it return (UInt16)((oldValue >> position) & mask); } private static IEnumerable WriteShort(UInt16 value) { return BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int16)value)); } } }