/// <summary>
        /// Send a custom message to the DNS server and returns the answer.
        /// </summary>
        /// <param name="message"> Message, that should be send to the DNS server </param>
        /// <returns> The complete response of the DNS server </returns>
        public DnsMessage SendMessage(DnsMessage message)
        {
            if (message == null)
                throw new ArgumentNullException("message");

            if ((message.Questions == null) || (message.Questions.Count == 0))
                throw new ArgumentException("At least one question must be provided", "message");

            return this.SendMessage<DnsMessage>(message);
        }
        /// <summary>
        /// Queries a DNS server for specified records.
        /// </summary>
        /// <param name="name"> Domain, that should be queried </param>
        /// <param name="localAddress">The local IP address.</param>
        /// <param name="serverAddress">The server IP address.</param>
        /// <param name="recordType"> Type the should be queried </param>
        /// <param name="recordClass"> Class the should be queried </param>
        /// <returns> The complete response of the DNS server </returns>
        public DnsMessage Resolve(string name, IPAddress localAddress, IPAddress serverAddress, RecordType recordType, RecordClass recordClass)
        {
            if (String.IsNullOrEmpty(name))
            {
                throw new ArgumentException("The name is missing.", "name");
            }

            DnsMessage message = new DnsMessage() { IsQuery = true, OperationCode = OperationCode.Query, IsRecursionDesired = true };
            message.Questions.Add(new DnsQuestion(name, recordType, recordClass));

            return SendMessage(message, localAddress, serverAddress);
        }
        /// <summary>
        /// Queries a DNS server for specified records asynchronously.
        /// </summary>
        /// <param name="name"> Domain, that should be queried </param>
        /// <param name="localAddress">The local IP address.</param>
        /// <param name="serverAddress">The server IP address.</param>
        /// <param name="recordType"> Type the should be queried </param>
        /// <param name="recordClass"> Class the should be queried </param>
        /// <param name="requestCallback"> An <see cref="System.AsyncCallback" /> delegate that references the method to invoked then the operation is complete. </param>
        /// <param name="state"> A user-defined object that contains information about the receive operation. This object is passed to the <paramref
        ///  name="requestCallback" /> delegate when the operation is complete. </param>
        /// <returns> An <see cref="System.IAsyncResult" /> IAsyncResult object that references the asynchronous receive. </returns>
        public IAsyncResult BeginResolve(string name, IPAddress localAddress, IPAddress serverAddress, RecordType recordType, RecordClass recordClass, AsyncCallback requestCallback, object state)
        {
            if (String.IsNullOrEmpty(name))
            {
                throw new ArgumentException("Name must be provided", "name");
            }

            DnsMessage message = new DnsMessage() { IsQuery = true, OperationCode = OperationCode.Query, IsRecursionDesired = true };
            message.Questions.Add(new DnsQuestion(name, recordType, recordClass));

            return this.BeginSendMessage(message, localAddress, serverAddress, requestCallback, state);
        }
        /// <summary>
        /// Send a custom message to the DNS server and returns the answer asynchronously.
        /// </summary>
        /// <param name="message"> Message, that should be send to the DNS server </param>
        /// <param name="requestCallback"> An <see cref="System.AsyncCallback" /> delegate that references the method to invoked then the operation is complete. </param>
        /// <param name="state"> A user-defined object that contains information about the receive operation. This object is passed to the <paramref
        ///  name="requestCallback" /> delegate when the operation is complete. </param>
        /// <returns> An <see cref="System.IAsyncResult" /> IAsyncResult object that references the asynchronous receive. </returns>
        public IAsyncResult BeginSendMessage(DnsMessage message, AsyncCallback requestCallback, object state)
        {
            if (message == null)
                throw new ArgumentNullException("message");

            if ((message.Questions == null) || (message.Questions.Count == 0))
                throw new ArgumentException("At least one question must be provided", "message");

            return this.BeginSendMessage<DnsMessage>(message, requestCallback, state);
        }
        /// <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;
        }