/// <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; }