Exemple #1
0
        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();
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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));
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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);
            }
        }
Exemple #6
0
        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);
        }
Exemple #7
0
        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");
            }
        }