Пример #1
0
		/// <summary> Add a question to the message.</summary>
		internal void AddQuestion(DNSQuestion rec)
		{
			if (numAnswers > 0 || numAuthorities > 0 || numAdditionals > 0)
			{
				// TODO is this the right exception?
				throw new Exception("Questions must be added before answers");
			}
			numQuestions++;
			WriteQuestion(rec);
		}
Пример #2
0
 /// <summary> Add a question to the message.</summary>
 internal void AddQuestion(DNSQuestion rec)
 {
     if (numAnswers > 0 || numAuthorities > 0 || numAdditionals > 0)
     {
         // TODO is this the right exception?
         throw new Exception("Questions must be added before answers");
     }
     numQuestions++;
     WriteQuestion(rec);
 }
Пример #3
0
        /// <summary> Add a listener for a question. The listener will receive updates
        /// of answers to the question as they arrive, or from the cache if they
        /// are already available.
        /// </summary>
        internal virtual void AddListener(IDNSListener listener, DNSQuestion question)
        {
            long now = (DateTime.Now.Ticks - 621355968000000000) / 10000;

            // add the new listener
            lock (this)
            {
                listeners.Add(listener);
            }

            // report existing matched records
            if (question != null)
            {
                for (DNSCache.CacheNode i = cache.find(question.name); i != null; i = i.Next)
                {
                    DNSRecord c = (DNSRecord)i.Value;
                    if (question.IsAnsweredBy(c) && !c.IsExpired(now))
                    {
                        listener.UpdateRecord(this, now, c);
                    }
                }
            }
        }
Пример #4
0
        public virtual void start()
        {
            // According to draft-cheshire-dnsext-multicastdns.txt
            // chapter "8 Responding":
            // We respond immediately if we know for sure, that we are
            // the only one who can respond to the query.
            // In all other cases, we respond within 20-120 ms.
            //
            // According to draft-cheshire-dnsext-multicastdns.txt
            // chapter "7.2 Multi-Packet Known Answer Suppression":
            // We respond after 20-120 ms if the query is truncated.

            bool iAmTheOnlyOne = true;

            foreach (DNSEntry entry in in_Renamed.questions)
            {
                if (entry is DNSQuestion)
                {
                    DNSQuestion q = (DNSQuestion)entry;
                    logger.Debug("start() question=" + q);
                    iAmTheOnlyOne &= (q.type == DNSConstants.TYPE_SRV || q.type == DNSConstants.TYPE_TXT || q.type == DNSConstants.TYPE_A || q.type == DNSConstants.TYPE_AAAA || Enclosing_Instance.localHost.Name.ToUpper().Equals(q.name.ToUpper()) || Enclosing_Instance.services.Contains(q.name.ToLower()));
                    if (!iAmTheOnlyOne)
                    {
                        break;
                    }
                }
            }
            int delay = (iAmTheOnlyOne && !in_Renamed.Truncated)?0:DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + random.Next(DNSConstants.RESPONSE_MAX_WAIT_INTERVAL - DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + 1) - in_Renamed.ElapsedSinceArrival();

            if (delay < 0)
            {
                delay = 0;
            }
            logger.Debug("start() Responder chosen delay=" + delay);
            // TODO: check this
            Enclosing_Instance.Timer = new Timer(new TimerCallback(this.Run), null, delay, 0);
        }
Пример #5
0
        public void Run(object state)
        {
            lock (Enclosing_Instance.IOLock)
            {
                if (Enclosing_Instance.PlannedAnswer == in_Renamed)
                {
                    Enclosing_Instance.PlannedAnswer = null;
                }

                // We use these sets to prevent duplicate records
                // FIXME - This should be moved into DNSOutgoing
                // TODO: check these for compatibility
                SupportClass.HashSetSupport questions = new SupportClass.HashSetSupport();
                SupportClass.HashSetSupport answers   = new SupportClass.HashSetSupport();


                if (Enclosing_Instance.State == DNSState.ANNOUNCED)
                {
                    try
                    {
                        long now            = (DateTime.Now.Ticks - 621355968000000000) / 10000;
                        long expirationTime = now + 1;                         //=now+DNSConstants.KNOWN_ANSWER_TTL;
                        bool isUnicast      = (port != DNSConstants.MDNS_PORT);


                        // Answer questions
                        foreach (DNSEntry entry in in_Renamed.questions)
                        {
                            if (entry is DNSQuestion)
                            {
                                DNSQuestion q = (DNSQuestion)entry;

                                // for unicast responses the question must be included
                                if (isUnicast)
                                {
                                    //out.addQuestion(q);
                                    questions.Add(q);
                                }

                                int type = q.type;
                                if (type == DNSConstants.TYPE_ANY || type == DNSConstants.TYPE_SRV)
                                {
                                    // I ama not sure of why there is a special case here [PJYF Oct 15 2004]
                                    if (Enclosing_Instance.localHost.Name.ToUpper().Equals(q.Name.ToUpper()))
                                    {
                                        // type = DNSConstants.TYPE_A;
                                        DNSRecord answer = Enclosing_Instance.localHost.DNS4AddressRecord;
                                        if (answer != null)
                                        {
                                            answers.Add(answer);
                                        }
                                        answer = Enclosing_Instance.localHost.DNS6AddressRecord;
                                        if (answer != null)
                                        {
                                            answers.Add(answer);
                                        }
                                        type = DNSConstants.TYPE_IGNORE;
                                    }
                                    else if (Enclosing_Instance.serviceTypes.Contains(q.Name.ToLower()))
                                    {
                                        type = DNSConstants.TYPE_PTR;
                                    }
                                }

                                switch (type)
                                {
                                case DNSConstants.TYPE_A:
                                {
                                    // Answer a query for a domain name
                                    //out = addAnswer( in, addr, port, out, host );
                                    DNSRecord answer = Enclosing_Instance.localHost.DNS4AddressRecord;
                                    if (answer != null)
                                    {
                                        answers.Add(answer);
                                    }
                                    break;
                                }

                                case DNSConstants.TYPE_AAAA:
                                {
                                    // Answer a query for a domain name
                                    DNSRecord answer = Enclosing_Instance.localHost.DNS6AddressRecord;
                                    if (answer != null)
                                    {
                                        answers.Add(answer);
                                    }
                                    break;
                                }

                                case DNSConstants.TYPE_PTR:
                                {
                                    // Answer a query for services of a given type

                                    // find matching services
                                    foreach (ServiceInfo info in Enclosing_Instance.services.Values)
                                    {
                                        if (info.State == DNSState.ANNOUNCED)
                                        {
                                            if (q.name.ToUpper().Equals(info.type.ToUpper()))
                                            {
                                                DNSRecord answer = Enclosing_Instance.localHost.DNS4AddressRecord;
                                                if (answer != null)
                                                {
                                                    answers.Add(answer);
                                                }
                                                answer = Enclosing_Instance.localHost.DNS6AddressRecord;
                                                if (answer != null)
                                                {
                                                    answers.Add(answer);
                                                }
                                                answers.Add(new Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.QualifiedName));
                                                answers.Add(new Service(info.QualifiedName, DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, Enclosing_Instance.localHost.Name));
                                                answers.Add(new Text(info.QualifiedName, DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.text));
                                            }
                                        }
                                    }
                                    if (q.name.ToUpper().Equals("_services._mdns._udp.local.".ToUpper()))
                                    {
                                        foreach (String s in Enclosing_Instance.serviceTypes.Values)
                                        {
                                            answers.Add(new Pointer("_services._mdns._udp.local.", DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, s));
                                        }
                                    }
                                    break;
                                }

                                case DNSConstants.TYPE_SRV:
                                case DNSConstants.TYPE_ANY:
                                case DNSConstants.TYPE_TXT:
                                {
                                    ServiceInfo info = (ServiceInfo)Enclosing_Instance.services[q.name.ToLower()];
                                    if (info != null && info.State == DNSState.ANNOUNCED)
                                    {
                                        DNSRecord answer = Enclosing_Instance.localHost.DNS4AddressRecord;
                                        if (answer != null)
                                        {
                                            answers.Add(answer);
                                        }
                                        answer = Enclosing_Instance.localHost.DNS6AddressRecord;
                                        if (answer != null)
                                        {
                                            answers.Add(answer);
                                        }
                                        answers.Add(new Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.QualifiedName));
                                        answers.Add(new Service(info.QualifiedName, DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, Enclosing_Instance.localHost.Name));
                                        answers.Add(new Text(info.QualifiedName, DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.text));
                                    }
                                    break;
                                }

                                default:
                                {
                                    //Console.WriteLine("JmDNSResponder.unhandled query:"+q);
                                    break;
                                }
                                }
                            }
                        }


                        // remove known answers, if the ttl is at least half of
                        // the correct value. (See Draft Cheshire chapter 7.1.).
                        foreach (DNSRecord knownAnswer in in_Renamed.answers)
                        {
                            bool tempBoolean;
                            tempBoolean = answers.Contains(knownAnswer);
                            answers.Remove(knownAnswer);
                            if (knownAnswer.ttl > DNSConstants.DNS_TTL / 2 && tempBoolean)
                            {
                                logger.Debug("JmDNS Responder Known Answer Removed");
                            }
                        }


                        // responde if we have answers
                        if (answers.Count != 0)
                        {
                            logger.Debug("run() JmDNS responding");
                            DNSOutgoing out_Renamed = null;
                            if (isUnicast)
                            {
                                out_Renamed = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA, false);
                            }

                            foreach (DNSQuestion question in questions)
                            {
                                out_Renamed.AddQuestion(question);
                            }
                            foreach (DNSRecord answer in answers)
                            {
                                out_Renamed = Enclosing_Instance.AddAnswer(in_Renamed, addr, port, out_Renamed, answer);
                            }
                            Enclosing_Instance.Send(out_Renamed);
                        }
                        // TODO: do we need this?
                        //cancel();
                    }
                    catch (Exception e)
                    {
                        logger.Warn("run() exception ", e);
                        Enclosing_Instance.Close();
                    }
                }
            }
        }
Пример #6
0
 internal void WriteQuestion(DNSQuestion question)
 {
     WriteName(question.name);
     WriteShort(question.type);
     WriteShort(question.clazz);
 }
Пример #7
0
		internal void WriteQuestion(DNSQuestion question)
		{
			WriteName(question.name);
			WriteShort(question.type);
			WriteShort(question.clazz);
		}
Пример #8
0
		/// <summary> Add a listener for a question. The listener will receive updates
		/// of answers to the question as they arrive, or from the cache if they
		/// are already available.
		/// </summary>
		internal virtual void AddListener(IDNSListener listener, DNSQuestion question)
		{
			long now = (DateTime.Now.Ticks - 621355968000000000) / 10000;
			
			// add the new listener
			lock (this)
			{
				listeners.Add(listener);
			}
			
			// report existing matched records
			if (question != null)
			{
				for (DNSCache.CacheNode i = cache.find(question.name); i != null; i = i.Next)
				{
					DNSRecord c = (DNSRecord) i.Value;
					if (question.IsAnsweredBy(c) && !c.IsExpired(now))
					{
						listener.UpdateRecord(this, now, c);
					}
				}
			}
		}
Пример #9
0
		/// <summary> Parse a message from a datagram packet.</summary>
		internal DNSIncoming(SupportClass.PacketSupport packet)
		{
			this.packet = packet;
			this.data = SupportClass.ToSByteArray(packet.Data);
			this.len = packet.Length;
			// TODO: will this always be 0 in .NET??
			this.off = 0;
			this.questions = ArrayList.ReadOnly(new ArrayList());
			this.answers = ArrayList.ReadOnly(new ArrayList());
			this.receivedTime = (DateTime.Now.Ticks - 621355968000000000) / 10000;
			
			try
			{
				id = ReadUnsignedShort();
				flags = ReadUnsignedShort();
				numQuestions = ReadUnsignedShort();
				numAnswers = ReadUnsignedShort();
				numAuthorities = ReadUnsignedShort();
				numAdditionals = ReadUnsignedShort();
				
				// parse questions
				if (numQuestions > 0)
				{
					questions = ArrayList.Synchronized(new ArrayList(numQuestions));
					for (int i = 0; i < numQuestions; i++)
					{
						DNSQuestion question = new DNSQuestion(ReadName(), ReadUnsignedShort(), ReadUnsignedShort());
						questions.Add(question);
					}
				}
				
				// parse answers
				int n = numAnswers + numAuthorities + numAdditionals;
				if (n > 0)
				{
					answers = ArrayList.Synchronized(new ArrayList(n));
					for (int i = 0; i < n; i++)
					{
						string domain = ReadName();
						int type = ReadUnsignedShort();
						int clazz = ReadUnsignedShort();
						int ttl = ReadInt();
						int len = ReadUnsignedShort();
						int end = off + len;
						DNSRecord rec = null;
						
						switch (type)
						{
							
							case DNSConstants.TYPE_A: 
							// IPv4
							case DNSConstants.TYPE_AAAA:  // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested
								rec = new Address(domain, type, clazz, ttl, ReadBytes(off, len));
								break;
							
							case DNSConstants.TYPE_CNAME: 
							case DNSConstants.TYPE_PTR: 
								rec = new Pointer(domain, type, clazz, ttl, ReadName());
								break;
							
							case DNSConstants.TYPE_TXT: 
								rec = new Text(domain, type, clazz, ttl, ReadBytes(off, len));
								break;
							
							case DNSConstants.TYPE_SRV: 
								rec = new Service(domain, type, clazz, ttl, ReadUnsignedShort(), ReadUnsignedShort(), ReadUnsignedShort(), ReadName());
								break;
							
							case DNSConstants.TYPE_HINFO: 
								// Maybe we should do something with those
								break;
							
							default: 
								logger.Debug("DNSIncoming() unknown type:" + type);
								break;
							
						}
						
						if (rec != null)
						{
							// Add a record, if we were able to create one.
							answers.Add(rec);
						}
						else
						{
							// Addjust the numbers for the skipped record
							if (answers.Count < numAnswers)
							{
								numAnswers--;
							}
							else if (answers.Count < numAnswers + numAuthorities)
							{
								numAuthorities--;
							}
							else if (answers.Count < numAnswers + numAuthorities + numAdditionals)
							{
								numAdditionals--;
							}
						}
						off = end;
					}
				}
			}
			catch (IOException e)
			{
				logger.Warn("DNSIncoming() dump " + Print(true) + "\n exception ", e);
				throw e;
			}
		}
Пример #10
0
        /// <summary> Parse a message from a datagram packet.</summary>
        internal DNSIncoming(SupportClass.PacketSupport packet)
        {
            this.packet = packet;
            this.data   = SupportClass.ToSByteArray(packet.Data);
            this.len    = packet.Length;
            // TODO: will this always be 0 in .NET??
            this.off          = 0;
            this.questions    = ArrayList.ReadOnly(new ArrayList());
            this.answers      = ArrayList.ReadOnly(new ArrayList());
            this.receivedTime = (DateTime.Now.Ticks - 621355968000000000) / 10000;

            try
            {
                id             = ReadUnsignedShort();
                flags          = ReadUnsignedShort();
                numQuestions   = ReadUnsignedShort();
                numAnswers     = ReadUnsignedShort();
                numAuthorities = ReadUnsignedShort();
                numAdditionals = ReadUnsignedShort();

                // parse questions
                if (numQuestions > 0)
                {
                    questions = ArrayList.Synchronized(new ArrayList(numQuestions));
                    for (int i = 0; i < numQuestions; i++)
                    {
                        DNSQuestion question = new DNSQuestion(ReadName(), ReadUnsignedShort(), ReadUnsignedShort());
                        questions.Add(question);
                    }
                }

                // parse answers
                int n = numAnswers + numAuthorities + numAdditionals;
                if (n > 0)
                {
                    answers = ArrayList.Synchronized(new ArrayList(n));
                    for (int i = 0; i < n; i++)
                    {
                        string    domain = ReadName();
                        int       type   = ReadUnsignedShort();
                        int       clazz  = ReadUnsignedShort();
                        int       ttl    = ReadInt();
                        int       len    = ReadUnsignedShort();
                        int       end    = off + len;
                        DNSRecord rec    = null;

                        switch (type)
                        {
                        case DNSConstants.TYPE_A:
                        // IPv4
                        case DNSConstants.TYPE_AAAA:                                  // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested
                            rec = new Address(domain, type, clazz, ttl, ReadBytes(off, len));
                            break;

                        case DNSConstants.TYPE_CNAME:
                        case DNSConstants.TYPE_PTR:
                            rec = new Pointer(domain, type, clazz, ttl, ReadName());
                            break;

                        case DNSConstants.TYPE_TXT:
                            rec = new Text(domain, type, clazz, ttl, ReadBytes(off, len));
                            break;

                        case DNSConstants.TYPE_SRV:
                            rec = new Service(domain, type, clazz, ttl, ReadUnsignedShort(), ReadUnsignedShort(), ReadUnsignedShort(), ReadName());
                            break;

                        case DNSConstants.TYPE_HINFO:
                            // Maybe we should do something with those
                            break;

                        default:
                            logger.Debug("DNSIncoming() unknown type:" + type);
                            break;
                        }

                        if (rec != null)
                        {
                            // Add a record, if we were able to create one.
                            answers.Add(rec);
                        }
                        else
                        {
                            // Addjust the numbers for the skipped record
                            if (answers.Count < numAnswers)
                            {
                                numAnswers--;
                            }
                            else if (answers.Count < numAnswers + numAuthorities)
                            {
                                numAuthorities--;
                            }
                            else if (answers.Count < numAnswers + numAuthorities + numAdditionals)
                            {
                                numAdditionals--;
                            }
                        }
                        off = end;
                    }
                }
            }
            catch (IOException e)
            {
                logger.Warn("DNSIncoming() dump " + Print(true) + "\n exception ", e);
                throw e;
            }
        }