private void ParseInternal(byte[] data, DnsServer.SelectTsigKey tsigKeySelector, byte[] originalMac) { int currentPosition = 0; TransactionID = ParseUShort(data, ref currentPosition); Flags = ParseUShort(data, ref currentPosition); int questionCount = ParseUShort(data, ref currentPosition); int answerRecordCount = ParseUShort(data, ref currentPosition); int authorityRecordCount = ParseUShort(data, ref currentPosition); int additionalRecordCount = ParseUShort(data, ref currentPosition); ParseQuestions(data, ref currentPosition, questionCount); ParseSection(data, ref currentPosition, AnswerRecords, answerRecordCount); ParseSection(data, ref currentPosition, AuthorityRecords, authorityRecordCount); ParseSection(data, ref currentPosition, _additionalRecords, additionalRecordCount); if (_additionalRecords.Count > 0) { int tSigPos = _additionalRecords.FindIndex(record => (record.RecordType == RecordType.TSig)); if (tSigPos == (_additionalRecords.Count - 1)) { TSigOptions = (TSigRecord)_additionalRecords[tSigPos]; _additionalRecords.RemoveAt(tSigPos); TSigOptions.ValidationResult = ValidateTSig(data, tsigKeySelector, originalMac); } } FinishParsing(); }
private TSigRecord generateTSigRecord(ushort transactionID) { TSigRecord record = null; if (tsigName != null && tsigKey != null) { record = new TSigRecord(tsigName, tsigAlg, DateTime.Now, new TimeSpan(0, 5, 0), transactionID, ReturnCode.NoError, null, tsigKey); } return(record); }
private DnsMessageBase ProcessMessage(DnsMessageBase query, IPAddress ipAddress, ProtocolType protocolType) { if (query.TSigOptions != null) { switch (query.TSigOptions.ValidationResult) { case ReturnCode.BadKey: case ReturnCode.BadSig: query.IsQuery = false; query.ReturnCode = ReturnCode.NotAuthoritive; query.TSigOptions.Error = query.TSigOptions.ValidationResult; query.TSigOptions.KeyData = null; if (InvalidSignedMessageReceived != null) { InvalidSignedMessageReceived(this, new InvalidSignedMessageEventArgs(query)); } return(query); case ReturnCode.BadTime: query.IsQuery = false; query.ReturnCode = ReturnCode.NotAuthoritive; query.TSigOptions.Error = query.TSigOptions.ValidationResult; query.TSigOptions.OtherData = new byte[6]; int tmp = 0; TSigRecord.EncodeDateTime(query.TSigOptions.OtherData, ref tmp, DateTime.Now); if (InvalidSignedMessageReceived != null) { InvalidSignedMessageReceived(this, new InvalidSignedMessageEventArgs(query)); } return(query); } } return(_processQueryDelegate(query, ipAddress, protocolType)); }
internal int Encode(bool addLengthPrefix, byte[] originalTsigMac, bool isSubSequentResponse, out byte[] messageData, out byte[] newTSigMac) { PrepareEncoding(); int offset = 0; int messageOffset = offset; int maxLength = addLengthPrefix ? 2 : 0; originalTsigMac = originalTsigMac ?? new byte[] { }; if (TSigOptions != null) { if (!IsQuery) { offset += 2 + originalTsigMac.Length; maxLength += 2 + originalTsigMac.Length; } maxLength += TSigOptions.MaximumLength; } #region Get Message Length maxLength += 12; maxLength += Questions.Sum(question => question.MaximumLength); maxLength += AnswerRecords.Sum(record => record.MaximumLength); maxLength += AuthorityRecords.Sum(record => record.MaximumLength); maxLength += _additionalRecords.Sum(record => record.MaximumLength); #endregion messageData = new byte[maxLength]; int currentPosition = offset; Dictionary <string, ushort> domainNames = new Dictionary <string, ushort>(); EncodeUShort(messageData, ref currentPosition, TransactionID); EncodeUShort(messageData, ref currentPosition, Flags); EncodeUShort(messageData, ref currentPosition, (ushort)Questions.Count); EncodeUShort(messageData, ref currentPosition, (ushort)AnswerRecords.Count); EncodeUShort(messageData, ref currentPosition, (ushort)AuthorityRecords.Count); EncodeUShort(messageData, ref currentPosition, (ushort)_additionalRecords.Count); foreach (DnsQuestion question in Questions) { question.Encode(messageData, offset, ref currentPosition, domainNames); } foreach (DnsRecordBase record in AnswerRecords) { record.Encode(messageData, offset, ref currentPosition, domainNames); } foreach (DnsRecordBase record in AuthorityRecords) { record.Encode(messageData, offset, ref currentPosition, domainNames); } foreach (DnsRecordBase record in _additionalRecords) { record.Encode(messageData, offset, ref currentPosition, domainNames); } if (TSigOptions == null) { newTSigMac = null; } else { if (!IsQuery) { EncodeUShort(messageData, messageOffset, (ushort)originalTsigMac.Length); Buffer.BlockCopy(originalTsigMac, 0, messageData, messageOffset + 2, originalTsigMac.Length); } EncodeUShort(messageData, offset, TSigOptions.OriginalID); int tsigVariablesPosition = currentPosition; if (isSubSequentResponse) { TSigRecord.EncodeDateTime(messageData, ref tsigVariablesPosition, TSigOptions.TimeSigned); EncodeUShort(messageData, ref tsigVariablesPosition, (ushort)TSigOptions.Fudge.TotalSeconds); } else { EncodeDomainName(messageData, offset, ref tsigVariablesPosition, TSigOptions.Name, false, null); EncodeUShort(messageData, ref tsigVariablesPosition, (ushort)TSigOptions.RecordClass); EncodeInt(messageData, ref tsigVariablesPosition, (ushort)TSigOptions.TimeToLive); EncodeDomainName(messageData, offset, ref tsigVariablesPosition, TSigAlgorithmHelper.GetDomainName(TSigOptions.Algorithm), false, null); TSigRecord.EncodeDateTime(messageData, ref tsigVariablesPosition, TSigOptions.TimeSigned); EncodeUShort(messageData, ref tsigVariablesPosition, (ushort)TSigOptions.Fudge.TotalSeconds); EncodeUShort(messageData, ref tsigVariablesPosition, (ushort)TSigOptions.Error); EncodeUShort(messageData, ref tsigVariablesPosition, (ushort)TSigOptions.OtherData.Length); EncodeByteArray(messageData, ref tsigVariablesPosition, TSigOptions.OtherData); } KeyedHashAlgorithm hashAlgorithm = TSigAlgorithmHelper.GetHashAlgorithm(TSigOptions.Algorithm); //byte[] mac; if ((hashAlgorithm != null) && (TSigOptions.KeyData != null) && (TSigOptions.KeyData.Length > 0)) { hashAlgorithm.Key = TSigOptions.KeyData; newTSigMac = hashAlgorithm.ComputeHash(messageData, messageOffset, tsigVariablesPosition); } else { newTSigMac = new byte[] { }; } EncodeUShort(messageData, offset, TransactionID); EncodeUShort(messageData, offset + 10, (ushort)(_additionalRecords.Count + 1)); TSigOptions.Encode(messageData, offset, ref currentPosition, domainNames, newTSigMac); if (!IsQuery) { Buffer.BlockCopy(messageData, offset, messageData, messageOffset, (currentPosition - offset)); currentPosition -= (2 + originalTsigMac.Length); } } if (addLengthPrefix) { Buffer.BlockCopy(messageData, 0, messageData, 2, currentPosition); EncodeUShort(messageData, 0, (ushort)(currentPosition)); currentPosition += 2; } return(currentPosition); }
private ReturnCode ValidateTSig(byte[] resultData, DnsServer.SelectTsigKey tsigKeySelector, byte[] originalMac) { byte[] keyData; if ((TSigOptions.Algorithm == TSigAlgorithm.Unknown) || (tsigKeySelector == null) || ((keyData = tsigKeySelector(TSigOptions.Algorithm, TSigOptions.Name)) == null)) { return(ReturnCode.BadKey); } else if (((TSigOptions.TimeSigned - TSigOptions.Fudge) > DateTime.Now) || ((TSigOptions.TimeSigned + TSigOptions.Fudge) < DateTime.Now)) { return(ReturnCode.BadTime); } else if ((TSigOptions.Mac == null) || (TSigOptions.Mac.Length == 0)) { return(ReturnCode.BadSig); } else { 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 = TSigOptions.StartPosition + 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, TSigOptions.StartPosition); // update original transaction id and ar count in message EncodeUShort(validationBuffer, currentPosition, TSigOptions.OriginalID); EncodeUShort(validationBuffer, currentPosition + 10, (ushort)_additionalRecords.Count); currentPosition += TSigOptions.StartPosition; // TSig Variables EncodeDomainName(validationBuffer, 0, ref currentPosition, TSigOptions.Name, false, null); EncodeUShort(validationBuffer, ref currentPosition, (ushort)TSigOptions.RecordClass); EncodeInt(validationBuffer, ref currentPosition, (ushort)TSigOptions.TimeToLive); EncodeDomainName(validationBuffer, 0, ref currentPosition, TSigAlgorithmHelper.GetDomainName(TSigOptions.Algorithm), false, null); TSigRecord.EncodeDateTime(validationBuffer, ref currentPosition, TSigOptions.TimeSigned); EncodeUShort(validationBuffer, ref currentPosition, (ushort)TSigOptions.Fudge.TotalSeconds); EncodeUShort(validationBuffer, ref currentPosition, (ushort)TSigOptions.Error); EncodeUShort(validationBuffer, ref currentPosition, (ushort)TSigOptions.OtherData.Length); EncodeByteArray(validationBuffer, ref currentPosition, TSigOptions.OtherData); // Validate MAC KeyedHashAlgorithm hashAlgorithm = TSigAlgorithmHelper.GetHashAlgorithm(TSigOptions.Algorithm); hashAlgorithm.Key = keyData; return((hashAlgorithm.ComputeHash(validationBuffer, 0, currentPosition).SequenceEqual(TSigOptions.Mac)) ? ReturnCode.NoError : ReturnCode.BadSig); } }
public override bool unregisterService(ServiceName serviceName) { DomainName dnsName = serviceName.toDnsName(); DomainName typeName = DomainName.Parse(serviceName.getType().toDnsString()) + registrationDomain; List <DomainName> subtypes = new List <DomainName>(serviceName.getType().getSubtypes().Count); foreach (String subtype in serviceName.getType().toDnsStringsWithSubtype()) { subtypes.Add(DomainName.Parse(subtype) + registrationDomain); } DnsUpdateMessage msg = new DnsUpdateMessage(); msg.ZoneName = registrationDomain; // XXX Should really be the zone (SOA) for the RRs we are about to add msg.Prequisites.Add(new RecordExistsPrequisite(dnsName, RecordType.Any)); msg.Updates.Add(new DeleteRecordUpdate(new PtrRecord(typeName, timeToLive, dnsName))); foreach (DomainName subtype in subtypes) { msg.Updates.Add(new DeleteRecordUpdate(new PtrRecord(subtype, timeToLive, dnsName))); } msg.Updates.Add(new DeleteAllRecordsUpdate(dnsName)); TSigRecord tsigRecord = generateTSigRecord(msg.TransactionID); if (tsigRecord != null) { msg.TSigOptions = tsigRecord; } DnsUpdateMessage response = resolver.SendUpdate(msg); if (response != null) { switch (response.ReturnCode) { case ReturnCode.NoError: //flushCache(update); break; case ReturnCode.YXDomain: // Prerequisite failed, the service already exists. return(false); default: throw new DnsSDException("Failed to send DNS update to server. Server returned error code: " + response.ReturnCode.ToString()); } } else { throw new DnsSDException("Failed to send DNS update to server. Server time out"); } // Remove the service type if there are no instances left msg = new DnsUpdateMessage(); msg.ZoneName = registrationDomain; // XXX Should really be the zone (SOA) for the RRs we are about to add msg.Prequisites.Add(new RecordNotExistsPrequisite(typeName, RecordType.Any)); msg.Updates.Add(new DeleteRecordUpdate(new PtrRecord(servicesName, timeToLive, typeName))); tsigRecord = generateTSigRecord(msg.TransactionID); if (tsigRecord != null) { msg.TSigOptions = tsigRecord; } response = resolver.SendUpdate(msg); if (response != null) { switch (response.ReturnCode) { case ReturnCode.NoError: //flushCache(update); Log.Info(String.Format("Removed service type record {0}", typeName)); break; case ReturnCode.YXDomain: // Prerequisite failed, service instances exists Log.Info(String.Format("Did not remove service type record {0}, instances left.", typeName)); break; default: Log.Error(String.Format("Failed to remove service type {0}, server returned status {1}", typeName, response.ReturnCode.ToString())); break; } } else { throw new DnsSDException("Failed to send DNS update to server. Server time out"); } return(true); }
public override bool registerService(ServiceData serviceData) { ServiceName serviceName = serviceData.getName(); DomainName dnsName = serviceName.toDnsName(); DomainName typeName = DomainName.Parse(serviceName.getType().toDnsString()) + registrationDomain; List <DomainName> subtypes = new List <DomainName>(serviceName.getType().getSubtypes().Count); foreach (String subtype in serviceName.getType().toDnsStringsWithSubtype()) { subtypes.Add(DomainName.Parse(subtype) + registrationDomain); } DomainName target = DomainName.Parse(serviceData.getHost()); List <String> strings = new List <String>(); foreach (var entry in serviceData.getProperties()) { StringBuilder sb = new StringBuilder(); sb.Append(entry.Key); if (entry.Key != null) { sb.Append('=').Append(entry.Value); } strings.Add(sb.ToString()); } if (strings.Count <= 0) { // Must not be empty strings.Add(""); } DnsUpdateMessage msg = new DnsUpdateMessage(); msg.ZoneName = registrationDomain; // XXX Should really be the zone (SOA) for the RRs we are about to add msg.Prequisites.Add(new RecordNotExistsPrequisite(dnsName, RecordType.Any)); msg.Updates.Add(new AddRecordUpdate(new PtrRecord(servicesName, timeToLive, typeName))); msg.Updates.Add(new AddRecordUpdate(new PtrRecord(typeName, timeToLive, dnsName))); foreach (DomainName subtype in subtypes) { msg.Updates.Add(new AddRecordUpdate(new PtrRecord(subtype, timeToLive, dnsName))); } msg.Updates.Add(new AddRecordUpdate(new SrvRecord(dnsName, timeToLive, 0, 0, Convert.ToUInt16(serviceData.getPort()), target))); msg.Updates.Add(new AddRecordUpdate(new TxtRecord(dnsName, timeToLive, strings))); TSigRecord tsigRecord = generateTSigRecord(msg.TransactionID); if (tsigRecord != null) { msg.TSigOptions = tsigRecord; } DnsUpdateMessage response = resolver.SendUpdate(msg); if (response != null) { switch (response.ReturnCode) { case ReturnCode.NoError: //flushCache(update); return(true); case ReturnCode.YXDomain: // Prerequisite failed, the service already exists. return(false); default: throw new DnsSDException("Failed to send DNS update to server. Server returned error code: " + response.ReturnCode.ToString()); } } else { throw new DnsSDException("Failed to send DNS update to server. Server time out"); } }