예제 #1
0
 /// <summary>
 /// Shallow copies the data members from the source message passed
 /// to this instance.
 /// </summary>
 /// <param name="source">The source message.</param>
 protected void CopyFrom(DnsMessage source)
 {
     this.qid         = source.qid;
     this.flags       = source.flags;
     this.qname       = source.qname;
     this.qtype       = source.qtype;
     this.qclass      = source.qclass;
     this.answers     = source.answers;
     this.authorities = source.authorities;
     this.additional  = source.additional;
 }
예제 #2
0
        private Dictionary <string, int> namePtrs;              // Set of existing name compression pointers

        /// <summary>
        /// This constructor initializes the message fields to default values.
        /// </summary>
        public DnsMessage()
        {
            this.qid         = 0;
            this.flags       = 0;
            this.qname       = null;
            this.qtype       = DnsQType.NULL;
            this.qclass      = DnsQClass.IN;
            this.answers     = null;
            this.authorities = null;
            this.additional  = null;
            this.namePtrs    = null;
        }
예제 #3
0
        /// <summary>
        /// Connstructs a typical Internet class DNS request.
        /// </summary>
        /// <param name="flags">Additional flag bits (the QR and OPCODE sections will be set automatically).</param>
        /// <param name="qname">The query name.</param>
        /// <param name="qtype">The query type.</param>
        /// <remarks>
        /// <para>
        /// By default, this constructor initializes the OPCODE section of the message flags to
        /// <see cref="DnsOpcode.QUERY" />, the query ID to zero, and the query class to
        /// <see cref="DnsQClass.IN" />.  These properties can be modified directly after
        /// construction if necessary.  Note that the <see cref="DnsResolver" /> class
        /// handles the assignment of a unique query ID so it generally not necessary
        /// to explicitly set this property.
        /// </para>
        /// </remarks>
        public DnsRequest(DnsFlag flags, string qname, DnsQType qtype)
            : base()
        {
            if (!qname.EndsWith("."))
            {
                throw new ArgumentException("Domain names must end with [.]", "qname");
            }

            this.Flags  = flags;
            this.QName  = qname;
            this.QType  = qtype;
            this.QClass = DnsQClass.IN;
        }
예제 #4
0
        /// <summary>
        /// Converts an RCODE value encoded in message flag bits into a human readable string.
        /// </summary>
        /// <param name="flags">The message flags.</param>
        /// <returns>The output string.</returns>
        private string RCODE2String(DnsFlag flags)
        {
            switch (flags & DnsFlag.RCODE_MASK)
            {
            case DnsFlag.RCODE_OK:      return("RCODE_OK");

            case DnsFlag.RCODE_FORMAT:  return("RCODE_FORMAT");

            case DnsFlag.RCODE_SERVER:  return("RCODE_SERVER");

            case DnsFlag.RCODE_NAME:    return("RCODE_NAME");

            case DnsFlag.RCODE_NOTIMPL: return("RCODE_NOTIMPL");

            case DnsFlag.RCODE_REFUSED: return("RCODE_REFUSED");

            default:                    return(string.Format("RCODE({0})", (int)(flags & DnsFlag.RCODE_MASK)));
            }
        }
예제 #5
0
        /// <summary>
        /// Serializes the message into a byte array formatted as a
        /// DNS protocol response packet as defined by RFC 1035.
        /// </summary>
        /// <param name="cb">Returns as the size of the formatted packet in bytes.</param>
        /// <returns>The <see cref="PacketSize" /> byte buffer with the formatted packet.</returns>
        public byte[] FormatPacket(out int cb)
        {
            var packet = new byte[PacketSize];
            int pos;

            try
            {
                // Initialize the name compression pointer table.

                namePtrs = new Dictionary <string, int>();

                // Write the message header

                pos = 0;

                Helper.WriteInt16(packet, ref pos, qid);
                Helper.WriteInt16(packet, ref pos, (int)flags);
                Helper.WriteInt16(packet, ref pos, 1);     // One question
                Helper.WriteInt16(packet, ref pos, (int)(answers == null ? 0 : answers.Count));
                Helper.WriteInt16(packet, ref pos, (int)(authorities == null ? 0 : authorities.Count));
                Helper.WriteInt16(packet, ref pos, (int)(additional == null ? 0 : additional.Count));

                Assertion.Test(pos == 12);

                // Write the question

                WriteName(packet, ref pos, qname);
                Helper.WriteInt16(packet, ref pos, (int)qtype);
                Helper.WriteInt16(packet, ref pos, (int)qclass);

                // Write the resource records

                if (answers != null)
                {
                    for (int i = 0; i < answers.Count; i++)
                    {
                        ((DnsRR)answers[i]).Write(this, packet, ref pos);
                    }
                }

                if (authorities != null)
                {
                    for (int i = 0; i < authorities.Count; i++)
                    {
                        ((DnsRR)authorities[i]).Write(this, packet, ref pos);
                    }
                }

                if (additional != null)
                {
                    for (int i = 0; i < additional.Count; i++)
                    {
                        ((DnsRR)additional[i]).Write(this, packet, ref pos);
                    }
                }
            }
            catch (IndexOutOfRangeException)
            {
                // $hack(jeff.lill):
                //
                // OK I know, using an exception to catch overflow
                // situations like this is a really bad idea but
                // give me a break, this is old code and I don't
                // want to mess with it right now.

                // Set the truncation bit in the response

                flags |= DnsFlag.TC;
                pos    = 2;
                Helper.WriteInt16(packet, ref pos, (int)flags);
                pos = PacketSize;
            }
            finally
            {
                namePtrs = null;
            }

            cb = pos;
            return(packet);
        }
예제 #6
0
        /// <summary>
        /// This method parses the raw DNS message packet passed and initializes
        /// the message properties.
        /// </summary>
        /// <param name="packet">The raw DNS packet received.</param>
        /// <param name="cbPacket">Number of bytes in that packet.</param>
        /// <returns>True on success.</returns>
        public bool ParsePacket(byte[] packet, int cbPacket)
        {
            uint qdCount;
            uint anCount;
            uint nsCount;
            uint arCount;
            int  pos;

            // Read the message header

            pos      = 0;
            this.qid = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket)
            {
                return(false);
            }
            this.flags = (DnsFlag)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket)
            {
                return(false);
            }
            qdCount = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket)
            {
                return(false);
            }
            anCount = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket)
            {
                return(false);
            }
            nsCount = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket)
            {
                return(false);
            }
            arCount = (ushort)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket)
            {
                return(false);
            }

            Assertion.Test(pos == 12);

            // Check for unsupported packets

            if ((this.flags & DnsFlag.TC) != 0)     // truncation bit is set
            {
                return(false);
            }

            if (this.Opcode != DnsOpcode.QUERY)     // only accept standard queries
            {
                return(false);
            }

            if (qdCount != 1)                       // only supporting one question
            {
                return(false);
            }

            // Parse the question

            if (!ReadName(packet, ref pos, out this.qname))
            {
                return(false);
            }

            if (pos > cbPacket)
            {
                return(false);
            }

            this.qtype = (DnsQType)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket)
            {
                return(false);
            }
            this.qclass = (DnsQClass)Helper.ReadInt16(packet, ref pos); if (pos > cbPacket)
            {
                return(false);
            }

            // We're only going to accept Internet queries

            if (this.qclass != DnsQClass.IN)
            {
                return(false);
            }

            // Parse the answer records

            for (int i = 0; i < anCount; i++)
            {
                var rr = DnsRR.Parse(this, packet, ref pos);

                if (rr == null || pos > cbPacket)
                {
                    return(false);
                }

                this.Answers.Add(rr);
            }

            // Parse the authority records

            for (int i = 0; i < nsCount; i++)
            {
                var rr = DnsRR.Parse(this, packet, ref pos);

                if (rr == null || pos > cbPacket)
                {
                    return(false);
                }

                this.Authorities.Add(rr);
            }

            // Parse the additional records

            for (int i = 0; i < arCount; i++)
            {
                var rr = DnsRR.Parse(this, packet, ref pos);

                if (rr == null || pos > cbPacket)
                {
                    return(false);
                }

                this.Additional.Add(rr);
            }

            // $todo(jeff.lill):
            //
            // Delete this once we've figured out why the DNS server
            // sometimes get requests with NULL QNAME properties.

            if (this.QName == null)
            {
                var packetBytes     = Helper.Extract(packet, cbPacket);
                var hexDump         = Helper.HexDump(packetBytes, 16, HexDumpOption.ShowAll);
                var diagnostics     = GetTraceDetails(IPAddress.Any);
                var extendedLogInfo = new StringSysLogEntryExtension(diagnostics + "\r\n\r\nPacket:\r\n\r\n" + hexDump);

                SysLog.LogWarning(extendedLogInfo, "DNS Packet with QNAME=NULL");
            }

            return(true);
        }
예제 #7
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="rcode">The DNS response code.</param>
 public DnsException(DnsFlag rcode)
     : base(errMsgs[(int)rcode])
 {
     this.rcode = rcode;
 }