1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright (c) 2003-2012 by AG-Software 											 *
3  * All Rights Reserved.																 *
4  * Contact information for AG-Software is available at http://www.ag-software.de	 *
5  *																					 *
6  * Licence:																			 *
7  * The agsXMPP SDK is released under a dual licence									 *
8  * agsXMPP can be used under either of two licences									 *
9  * 																					 *
10  * A commercial licence which is probably the most appropriate for commercial 		 *
11  * corporate use and closed source projects. 										 *
12  *																					 *
13  * The GNU Public License (GPL) is probably most appropriate for inclusion in		 *
14  * other open source projects.														 *
15  *																					 *
16  * See README.html for details.														 *
17  *																					 *
18  * For general enquiries visit our website at:										 *
19  * http://www.ag-software.de														 *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21 
22 //
23 // Bdev.Net.Dns by Rob Philpott, Big Developments Ltd. Please send all bugs/enhancements to
24 // rob@bigdevelopments.co.uk  This file and the code contained within is freeware and may be
25 // distributed and edited without restriction.
26 //
27 
28 using System;
29 using System.Net;
30 
31 namespace agsXMPP.Net.Dns
32 {
33 	/// <summary>
34 	/// A Response is a logical representation of the byte data returned from a DNS query
35 	/// </summary>
36 	public class Response
37 	{
38 		// these are fields we're interested in from the message
39 		private readonly ReturnCode			_returnCode;
40 		private readonly bool				_authoritativeAnswer;
41 		private readonly bool				_recursionAvailable;
42 		private readonly bool				_truncated;
43 		private readonly Question[]			_questions;
44 		private readonly Answer[]			_answers;
45 		private readonly NameServer[]		_nameServers;
46 		private readonly AdditionalRecord[]	_additionalRecords;
47 
48 		// these fields are readonly outside the assembly - use r/o properties
49 		public ReturnCode ReturnCode				{ get { return _returnCode;					}}
50 		public bool AuthoritativeAnswer				{ get { return _authoritativeAnswer;		}}
51 		public bool RecursionAvailable				{ get { return _recursionAvailable;			}}
52 		public bool MessageTruncated				{ get { return _truncated;					}}
53 		public Question[] Questions					{ get { return _questions;					}}
54 		public Answer[] Answers						{ get { return _answers;					}}
55 		public NameServer[] NameServers				{ get { return _nameServers;				}}
56 		public AdditionalRecord[] AdditionalRecords	{ get { return _additionalRecords;			}}
57 
58 		/// <summary>
59 		/// Construct a Response object from the supplied byte array
60 		/// </summary>
61 		/// <param name="message">a byte array returned from a DNS server query</param>
Response(byte[] message)62 		internal Response(byte[] message)
63 		{
64 			// the bit flags are in bytes 2 and 3
65 			byte flags1 = message[2];
66 			byte flags2 = message[3];
67 
68 			// get return code from lowest 4 bits of byte 3
69 			int returnCode = flags2 & 15;
70 
71 			// if its in the reserved section, set to other
72 			if (returnCode > 6) returnCode = 6;
73 			_returnCode = (ReturnCode)returnCode;
74 
75 			// other bit flags
76 			_authoritativeAnswer = ((flags1 & 4) != 0);
77 			_recursionAvailable = ((flags2 & 128) != 0);
78 			_truncated = ((flags1 & 2) != 0);
79 
80 			// create the arrays of response objects
81 			_questions = new Question[GetShort(message, 4)];
82 			_answers = new Answer[GetShort(message, 6)];
83 			_nameServers = new NameServer[GetShort(message, 8)];
84 			_additionalRecords = new AdditionalRecord[GetShort(message, 10)];
85 
86 			// need a pointer to do this, position just after the header
87 			Pointer pointer = new Pointer(message, 12);
88 
89 			// and now populate them, they always follow this order
90 			for (int index = 0; index < _questions.Length; index++)
91 			{
92 				try
93 				{
94 					// try to build a quesion from the response
95 					_questions[index] = new Question(pointer);
96 				}
97 				catch (Exception ex)
98 				{
99 					// something grim has happened, we can't continue
100 					throw new InvalidResponseException(ex);
101 				}
102 			}
103 			for (int index = 0; index < _answers.Length; index++)
104 			{
105 				_answers[index] = new Answer(pointer);
106 			}
107 			for (int index = 0; index < _nameServers.Length; index++)
108 			{
109 				_nameServers[index] = new NameServer(pointer);
110 			}
111 			for (int index = 0; index < _additionalRecords.Length; index++)
112 			{
113 				_additionalRecords[index] = new AdditionalRecord(pointer);
114 			}
115 		}
116 
117 		/// <summary>
118 		/// Convert 2 bytes to a short. It would have been nice to use BitConverter for this,
119 		/// it however reads the bytes in the wrong order (at least on Windows)
120 		/// </summary>
121 		/// <param name="message">byte array to look in</param>
122 		/// <param name="position">position to look at</param>
123 		/// <returns>short representation of the two bytes</returns>
GetShort(byte[] message, int position)124 		private static short GetShort(byte[] message, int position)
125 		{
126 			return (short)(message[position]<<8 | message[position+1]);
127 		}
128 	}
129 }
130