/// <summary>
        /// Parses byte array data into a DNS message.
        /// </summary>
        /// <param name="resultData">The result data.</param>
        /// <param name="isRequest">If <b>true</b> the message is a request.</param>
        /// <param name="tsigKeySelector">The transaction signature key selector.</param>
        /// <param name="originalMac">The original MAC.</param>
        internal void Parse(byte[] resultData, bool isRequest, DnsServer.SelectTsigKey tsigKeySelector, byte[] originalMac)
        {
            int currentPosition = 0;

            this.TransactionID = DnsMessageBase.ParseUShort(resultData, ref currentPosition);
            this.Flags = DnsMessageBase.ParseUShort(resultData, ref currentPosition);

            int questionCount = DnsMessageBase.ParseUShort(resultData, ref currentPosition);
            int answerRecordCount = DnsMessageBase.ParseUShort(resultData, ref currentPosition);
            int authorityRecordCount = DnsMessageBase.ParseUShort(resultData, ref currentPosition);
            int additionalRecordCount = DnsMessageBase.ParseUShort(resultData, ref currentPosition);

            this.ParseQuestions(resultData, ref currentPosition, questionCount);
            DnsMessageBase.ParseSection(resultData, ref currentPosition, AnswerRecords, answerRecordCount);
            DnsMessageBase.ParseSection(resultData, ref currentPosition, AuthorityRecords, authorityRecordCount);
            DnsMessageBase.ParseSection(resultData, ref currentPosition, this.additionalRecords, additionalRecordCount);

            if (this.additionalRecords.Count > 0)
            {
                int tSigPos = this.additionalRecords.FindIndex(record => (record.RecordType == RecordType.TSig));
                if (tSigPos == (this.additionalRecords.Count - 1))
                {
                    this.TSigOptions = (TSigRecord)this.additionalRecords[tSigPos];

                    this.additionalRecords.RemoveAt(tSigPos);

                    this.TSigOptions.ValidationResult = this.ValidateTSig(resultData, tsigKeySelector, originalMac);
                }
            }

            this.FinishParsing();
        }
        /// <summary>
        /// Validates the transaction signature.
        /// </summary>
        /// <param name="resultData">The result data.</param>
        /// <param name="tsigKeySelector">The transaction signature key selector.</param>
        /// <param name="originalMac"></param>
        /// <returns>The original MAC.</returns>
        private ReturnCode ValidateTSig(byte[] resultData, DnsServer.SelectTsigKey tsigKeySelector, byte[] originalMac)
        {
            byte[] keyData;
            if ((this.TSigOptions.Algorithm == TSigAlgorithm.Unknown) || (tsigKeySelector == null) || ((keyData = tsigKeySelector(this.TSigOptions.Algorithm, this.TSigOptions.Name)) == null))
            {
                return ReturnCode.BadKey;
            }
            else if (((this.TSigOptions.TimeSigned - this.TSigOptions.Fudge) > DateTime.Now) || ((this.TSigOptions.TimeSigned + this.TSigOptions.Fudge) < DateTime.Now))
            {
                return ReturnCode.BadTime;
            }
            else if ((this.TSigOptions.Mac == null) || (this.TSigOptions.Mac.Length == 0))
            {
                return ReturnCode.BadSig;
            }
            else
            {
                this.TSigOptions.KeyData = keyData;

                // maxLength for the buffer to validate: Original (unsigned) dns message and encoded TSigOptions
                // because of compression of keyname, the size of the signed message can not be used
                int maxLength = this.TSigOptions.StartPosition + this.TSigOptions.MaximumLength;
                if (originalMac != null)
                {
                    // add length of mac on responses. MacSize not neccessary, this field is allready included in the size of the tsig options
                    maxLength += originalMac.Length;
                }

                byte[] validationBuffer = new byte[maxLength];

                int currentPosition = 0;

                // original mac if neccessary
                if ((originalMac != null) && (originalMac.Length > 0))
                {
                    EncodeUShort(validationBuffer, ref currentPosition, (ushort) originalMac.Length);
                    EncodeByteArray(validationBuffer, ref currentPosition, originalMac);
                }

                // original unsiged buffer
                Buffer.BlockCopy(resultData, 0, validationBuffer, currentPosition, this.TSigOptions.StartPosition);

                // update original transaction id and ar count in message
                DnsMessageBase.EncodeUShort(validationBuffer, currentPosition, this.TSigOptions.OriginalID);
                DnsMessageBase.EncodeUShort(validationBuffer, currentPosition + 10, (ushort)this.additionalRecords.Count);
                currentPosition += this.TSigOptions.StartPosition;

                // TSig Variables
                DnsMessageBase.EncodeDomainName(validationBuffer, 0, ref currentPosition, this.TSigOptions.Name, false, null);
                DnsMessageBase.EncodeUShort(validationBuffer, ref currentPosition, (ushort)this.TSigOptions.RecordClass);
                DnsMessageBase.EncodeInt(validationBuffer, ref currentPosition, (ushort)this.TSigOptions.TimeToLive);
                DnsMessageBase.EncodeDomainName(validationBuffer, 0, ref currentPosition, TSigAlgorithmHelper.GetDomainName(this.TSigOptions.Algorithm), false, null);
                TSigRecord.EncodeDateTime(validationBuffer, ref currentPosition, this.TSigOptions.TimeSigned);
                DnsMessageBase.EncodeUShort(validationBuffer, ref currentPosition, (ushort)this.TSigOptions.Fudge.TotalSeconds);
                DnsMessageBase.EncodeUShort(validationBuffer, ref currentPosition, (ushort)this.TSigOptions.Error);
                DnsMessageBase.EncodeUShort(validationBuffer, ref currentPosition, (ushort)this.TSigOptions.OtherData.Length);
                DnsMessageBase.EncodeByteArray(validationBuffer, ref currentPosition, this.TSigOptions.OtherData);

                // Validate MAC
                KeyedHashAlgorithm hashAlgorithm = TSigAlgorithmHelper.GetHashAlgorithm(this.TSigOptions.Algorithm);
                hashAlgorithm.Key = keyData;
                return (hashAlgorithm.ComputeHash(validationBuffer, 0, currentPosition).SequenceEqual(this.TSigOptions.Mac)) ? ReturnCode.NoError : ReturnCode.BadSig;
            }
        }
        /// <summary>
        /// Creates a DNS message.
        /// </summary>
        /// <param name="resultData">The result data.</param>
        /// <param name="isRequest">If <b>true</b> the message is a request.</param>
        /// <param name="tsigKeySelector">The transaction signature key selector.</param>
        /// <param name="originalMac">The original MAC.</param>
        /// <returns>The DNS message.</returns>
        internal static DnsMessageBase Create(byte[] resultData, bool isRequest, DnsServer.SelectTsigKey tsigKeySelector, byte[] originalMac)
        {
            int flagPosition = 2;
            ushort flags = DnsMessageBase.ParseUShort(resultData, ref flagPosition);

            DnsMessageBase res;

            switch ((OperationCode) ((flags & 0x7800) >> 11))
            {
                case OperationCode.Update:
                    res = new DnsUpdateMessage();
                    break;

                default:
                    res = new DnsMessage();
                    break;
            }

            res.Parse(resultData, isRequest, tsigKeySelector, originalMac);

            return res;
        }