/// <summary>
        /// Get the response data
        /// </summary>
        /// <returns>The response.</returns>
        public int GetData(byte[] responseBuffer)
		{
			// Create and write the response header
			var dnsMessageHeader = new DnsMessageHeader (this.Query.Header.MessageId) {
				StatusCode = DnsQueryStatusCode.OK,
				AdditionalAnswerCount =  this.AdditionalAnswerCount,
				NameServerAnswerCount = this.NameServerAnswerCount,
				NormalAnswerCount = this.NormalAnswerCount,
				QuestionCount =  (uint)this.Query.Questions.Count,
				IsAuthorativeMessage = true,
				IsResponse = true,
				IsTruncated = false,
				RecursionDesired = false,
				RecursionSupported = false
			};
			dnsMessageHeader.WriteHeader (responseBuffer, 0);

			// After the header, copy the original request
			Buffer.BlockCopy (
				src: this.Query.OriginalQuestionData, 
				srcOffset: DnsMessageHeader.SizeInBytes, 
				dst: responseBuffer, 
				dstOffset: DnsMessageHeader.SizeInBytes, 
				count: this.Query.OriginalQuestionData.Length - DnsMessageHeader.SizeInBytes);

			// Now write the response
			var byteIndex = this.Query.OriginalQuestionData.Length;
            foreach (var answer in this.Answers)
            {
                byteIndex += answer.WriteAnswer(responseBuffer, byteIndex);
            }
            
            // Return the number of bytes written
            return byteIndex;
        }
Exemple #2
0
        /// <summary>
        /// Parse a DnsMessageHeader object from the given array
        /// </summary>
        /// <param name="array">Array.</param>
        public static DnsMessageHeader Parse(byte[] array, int offset)
        {
            // TODO: check length
            // HEADER: A total of 12 bytes
            // 2 bytes - Message ID
            byte[] messageId = new byte[2];
            messageId[0] = array[offset++];
            messageId[1] = array[offset++];

            var dnsMessageHeader = new DnsMessageHeader(messageId);

            // 1 bit - QR query response, should be set to 0
            var queryHeaderByte1 = array[offset++];
            var queryHeaderByte2 = array[offset++];
            var isQuestion       = ((queryHeaderByte1 >> 7) & 1) == 0;

            if (!isQuestion)
            {
                // INVALID DNS query
                return(null);
            }
            // 4 bits - Request type
            dnsMessageHeader.RequestType = (DnsQueryRequestType)DnsEncoder.Parse4BitNumeric(queryHeaderByte1, 1);
            // 1 bit - authorative answer
            dnsMessageHeader.IsAuthorativeMessage = 1 == ((queryHeaderByte1 >> 2) & 1);
            dnsMessageHeader.IsTruncated          = 1 == ((queryHeaderByte1 >> 1) & 1);
            dnsMessageHeader.RecursionDesired     = 1 == ((queryHeaderByte1 >> 0) & 1);
            dnsMessageHeader.RecursionSupported   = 1 == ((queryHeaderByte2 >> 7) & 1);

            // 2 bytes - QDCOUNT
            dnsMessageHeader.QuestionCount = DnsEncoder.ParseUint16(array, offset);
            // 4 bytes, skip
            offset += 6;
            // 2 bytes - Additional questions
            dnsMessageHeader.AdditionalQuestionCount = DnsEncoder.ParseUint16(array, offset);


            // TODO: what to do if number of questions is 0?
            // TODO: what to do if number of questions does not match

            return(dnsMessageHeader);
        }
Exemple #3
0
        /// <summary>
        /// Get the response data
        /// </summary>
        /// <returns>The response.</returns>
        public int GetData(byte[] responseBuffer)
        {
            // Create and write the response header
            var dnsMessageHeader = new DnsMessageHeader(this.Query.Header.MessageId)
            {
                StatusCode            = DnsQueryStatusCode.OK,
                AdditionalAnswerCount = this.AdditionalAnswerCount,
                NameServerAnswerCount = this.NameServerAnswerCount,
                NormalAnswerCount     = this.NormalAnswerCount,
                QuestionCount         = (uint)this.Query.Questions.Count,
                IsAuthorativeMessage  = true,
                IsResponse            = true,
                IsTruncated           = false,
                RecursionDesired      = false,
                RecursionSupported    = false
            };

            dnsMessageHeader.WriteHeader(responseBuffer, 0);

            // After the header, copy the original request
            Buffer.BlockCopy(
                src: this.Query.OriginalQuestionData,
                srcOffset: DnsMessageHeader.SizeInBytes,
                dst: responseBuffer,
                dstOffset: DnsMessageHeader.SizeInBytes,
                count: this.Query.OriginalQuestionData.Length - DnsMessageHeader.SizeInBytes);

            // Now write the response
            var byteIndex = this.Query.OriginalQuestionData.Length;

            foreach (var answer in this.Answers)
            {
                byteIndex += answer.WriteAnswer(responseBuffer, byteIndex);
            }

            // Return the number of bytes written
            return(byteIndex);
        }
Exemple #4
0
        /// <summary>
        /// Parse the DnsQuery from the given UdpReceiveResult
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static DnsQuery Parse(byte[] buffer, IPAddress remoteEndpoint)
        {
            // Create the query
            var query = new DnsQuery();

            query.Status          = DnsQueryStatus.OK;
            query.ClientIPAddress = remoteEndpoint;

            // Parse the dns request header
            query.Header = DnsMessageHeader.Parse(buffer, 0);

            // DNS QUESTIONS:
            int offset = 12;

            for (int i = 0; i < query.Header.QuestionCount; i++)
            {
                try
                {
                    // Save the question
                    DnsQuestion question;
                    offset += DnsQuestion.Parse(out question, buffer, offset);
                    if (question != null)
                    {
                        query.Questions.Add(question);
                    }
                }
                catch (Exception e) {
                    Console.WriteLine(e.Message);
                    Console.WriteLine(e.StackTrace);
                    query.Status = DnsQueryStatus.ParsingError;
                    break;
                }
            }

            // Save the original question data to include it in the answer
            query.OriginalQuestionData = new byte[offset];
            Buffer.BlockCopy(buffer, 0, query.OriginalQuestionData, 0, offset);

            // Parse the additional EDNS question
            // For now, we only support a single additional question
            if (query.Header.AdditionalQuestionCount > 0)
            {
                //Console.WriteLine("Reading OPT");
                try
                {
                    int bytesProcessed = 0;
                    query.EdnsQuestion = EdnsQuestion.Parse(buffer, offset, ref bytesProcessed);
                    offset            += bytesProcessed;

                    // If the question was validely parsed, try using the subnet to assign the IP based on the user's location instead of the
                    // dns proxy server
                    if (query.EdnsQuestion != null)
                    {
                        var clientSubnetOption = (EdnsClientSubnetOption)query.EdnsQuestion.GetOption(EdnsOptionCode.ClientSubnet);
                        if (clientSubnetOption != null)
                        {
                            query.ClientIPAddress = clientSubnetOption.IPAddress;
                        }
                    }
                }
                catch (Exception e) {
                    Console.WriteLine(e.Message);
                    Console.WriteLine(e.StackTrace);
                    // If this fails, we still try to proceed normally
                    // TODO: log
                }
            }

            return(query);
        }
		/// <summary>
		/// Parse a DnsMessageHeader object from the given array
		/// </summary>
		/// <param name="array">Array.</param>
		public static DnsMessageHeader Parse(byte[] array, int offset)
		{
			// TODO: check length
			// HEADER: A total of 12 bytes
			// 2 bytes - Message ID
			byte[] messageId = new byte[2];
			messageId[0] = array[offset++];
			messageId[1] = array[offset++];

			var dnsMessageHeader = new DnsMessageHeader (messageId);

			// 1 bit - QR query response, should be set to 0
			var queryHeaderByte1 = array[offset++];
			var queryHeaderByte2 = array[offset++];
			var isQuestion = ((queryHeaderByte1 >> 7) & 1) == 0;
			if (!isQuestion) {
				// INVALID DNS query
				return null;
			}
			// 4 bits - Request type
			dnsMessageHeader.RequestType = (DnsQueryRequestType)DnsEncoder.Parse4BitNumeric(queryHeaderByte1, 1);
			// 1 bit - authorative answer
			dnsMessageHeader.IsAuthorativeMessage = 1 == ((queryHeaderByte1 >> 2) & 1);
			dnsMessageHeader.IsTruncated = 1 == ((queryHeaderByte1 >> 1) & 1);
			dnsMessageHeader.RecursionDesired = 1 == ((queryHeaderByte1 >> 0) & 1);
			dnsMessageHeader.RecursionSupported = 1 == ((queryHeaderByte2 >> 7) & 1);

            // 2 bytes - QDCOUNT
            dnsMessageHeader.QuestionCount = DnsEncoder.ParseUint16(array, offset);
            // 4 bytes, skip
            offset += 6;
            // 2 bytes - Additional questions
            dnsMessageHeader.AdditionalQuestionCount = DnsEncoder.ParseUint16(array, offset);


            // TODO: what to do if number of questions is 0?
            // TODO: what to do if number of questions does not match

            return dnsMessageHeader;
		}