You have reached the legacy GHI Electronics, LLC website, for the new website please visit here. For the new forum please visit here.

This legacy website will be taken offline at the end of this year. If there is anything that you would like to archive and save for future reference please do so.

Very basic DNS-Client by glx

Jul. 7, 2016   |   Snippet   |   Licensed as Apache 2.0   |   1052 views

dns

Hi guys (and girls),
I wanted to use the NTP-service to set the system-time of my devices on startup and sync it every now and then via the TimeService-Class.
I don't know if I'm the only one with the problem, but I can't get any results using the System.Net.Dns-Class, it always crashed with a SocketException.
So I wrote my own small and very basic DNS-client, somehow it can't get a response on every request, but it simply tries as long until it gets one (normaly two times maximum). It uses a UDP-Socket-connection to any DNS-server you tell him (thats also the only thing, besides the hostname, you can tell him). Usage is very simple, just call the ResolveHostname(string Hostname)-Method and it returns an array of IPAdress-objects you can use.
It took me about one day to look for informations about the DNS-thing and write the code. Maybe someone can use this to save his time and do something more productive Smiley.

Comments or questions?   Discuss on the forum.



Author Version Date
glx 1 07/07 '16 at 02:56pm
1 — Source
  1. // This is a very basic DNS-client that returns IP-addresses of a hostname you tell him.
  2. // Somehow I can't get a response on every request I send, so it just asks as long until it gets a response.
  3. // I made this, because the System.Net.Dns-Class doesn't work on my NETMF-devices but I wanted to
  4. // use NTP to update the systemtime on startup by asking pool.ntp.org for a server.
  5. // It was about one day of work with looking for informations and playing around until it worked, so maybe
  6. // someone can use this and save his time for something better :). So if you need it, just use it.
  7. // As I'm no professional programmer or something, there maybe much space for improvements. If you notice
  8. // something, feel free to tell me.
  9. //
  10. // Following Namespaces are used:
  11. // System;
  12. // System.Collections;
  13. // System.Net;
  14. // System.Net.Sockets;
  15. // System.Threading;
  16. // Microsoft.SPOT;
  17.  
  18.  
  19.  
  20. /// <summary>
  21. /// Just set the DNS-server you want to use and call ResolveHostname().
  22. /// It's a very basic client, it doesn't have anything to configure (just the DNS-server yo want to use).
  23. /// </summary>
  24. class myDNS
  25. {
  26. static byte[] QTYPE = { 0x00, 0x01 }; //A-Record
  27. static byte[] QCLASS = { 0x00, 0x01 }; //Internet
  28. static byte[] NEWANSWER = { 0xC0, 0x0C }; //The (I think) begin of the 'new answer identifier'
  29.  
  30. public static string DNS_IP = "192.168.64.1";
  31. /// <summary>
  32. /// You give it a hostname and it returns an array of IP-addresses, that's all.
  33. /// </summary>
  34. /// <param name="Hostname"></param>
  35. /// <returns></returns>
  36. public static IPAddress[] ResolveHostname(string Hostname)
  37. {
  38. Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  39.  
  40. EndPoint ep = new IPEndPoint(IPAddress.Parse(DNS_IP), 53); //set the EndPoint to the DNS
  41.  
  42. socket.ReceiveTimeout = 1000;
  43. socket.SendTimeout = 500;
  44. //socket.Ttl = 255;
  45.  
  46. byte[] request = RequestCreator(Hostname); //create the request
  47.  
  48. int answLength = 0;
  49. byte[] answ = new byte[512]; //Byte-array for the answer. UDP-Packets can be 512 bytes long
  50. socket.Connect(ep);
  51. /*do this until something was received, somehow not after
  52.   * every request a response is received, so this just
  53.   * sends requests until it receives something */
  54.  
  55. while (answLength == 0)
  56. {
  57. socket.Send(request, request.Length, SocketFlags.None);
  58. try
  59. {
  60. answLength = socket.Receive(answ, SocketFlags.None);
  61. }
  62. catch (Exception ex) { Thread.Sleep(1000); }
  63. }
  64. socket.Close();
  65.  
  66. IPAddress[] IPs = ProcessResponse(answ); //give the answer to the response processor
  67.  
  68. return IPs;
  69. }
  70.  
  71. static byte[] RequestCreator(string HostToSolve)
  72. {
  73. ArrayList AList = new ArrayList(); //ArrayList to create the requst in, because there is no fixed lenght
  74.  
  75. byte[] MessageID = new byte[2]; //Generate two randdom bytes as message-id
  76. Random rnd = new Random();
  77. rnd.NextBytes(MessageID);
  78.  
  79. byte[] Head = //The start of every request
  80. {
  81. MessageID[0], //Every request has an two-byte ID, this is it.
  82. MessageID[1], //I couldn't find anything about this, so I just set two random bytes here
  83. 0x01, //Request-signature, in response it's that +128
  84. 0x00, //Request-signature, in response it's that +128
  85. 0x00, //There is one requested host -->
  86. 0x01, //--> There is one requested host
  87. 0x00, //leave 0, the response will use this
  88. 0x00, //leave 0, the response will use this
  89. 0x00, //leave 0, the response will use this
  90. 0x00, //leave 0, the response will use this
  91. 0x00, //leave 0, the response will use this
  92. 0x00 //leave 0, the response will use this
  93. };
  94.  
  95. byte[] Foot = //The end of every request
  96. {
  97. QTYPE[0], //specifies the type of the lookup
  98. QTYPE[1], //specifies the type of the lookup
  99. QCLASS[0],
  100. QCLASS[1]
  101. };
  102.  
  103. foreach (byte b in Head) { AList.Add(b); } //Add the Header
  104.  
  105. string[] TempHostArray = HostToSolve.Split(new char[] { '.' });
  106.  
  107. foreach (string s in TempHostArray) //Create the boby of the request
  108. {
  109. AList.Add((byte)s.Length); //The server wants to know, how long every part of the hostname is. This tells him
  110. char[] TempCharArray = s.ToCharArray(); //Convert the string to a char-array, that can be added to the request
  111. foreach (char c in TempCharArray) { AList.Add((byte)c); } //Add the chars
  112. }
  113. AList.Add((byte)0x00); //Marks the end of the body
  114.  
  115. foreach (byte b in Foot) { AList.Add(b); } //Add the bottom
  116.  
  117. return (byte[])AList.ToArray(typeof(byte)); //Convert the ArrayList to an Array an return it
  118. }
  119.  
  120. static IPAddress[] ProcessResponse(byte[] Response) //Takes the response and returns the containing IP-addresses
  121. {
  122. ArrayList AList = new ArrayList();
  123.  
  124. int[] AnswerPositions = GetIndexOfAnswers(Response); //Calls a function that looks for the positions of the answers
  125.  
  126. foreach (int i in AnswerPositions) //Bytes #12, 13, 14 and 15 are the IP-address-bytes, so this creates an IPAddress-object of these
  127. {
  128. IPAddress IPAdr = new IPAddress(
  129. new byte[] { Response[i + 12], Response[i + 13], Response[i + 14], Response[i + 15] }
  130. );
  131. AList.Add(IPAdr); //Adds the IPAddresses to an ArrayList
  132. }
  133.  
  134. return (IPAddress[])AList.ToArray(typeof(IPAddress)); //Converts the ArrayList to an IPAddress-Array and returns it
  135. }
  136.  
  137. static int[] GetIndexOfAnswers(byte[] Response) //looks for the byte-pattern in the response and returns the indexes of their startposition
  138. {
  139. ArrayList AList = new ArrayList();
  140.  
  141. for (int i = 0; i < (Response.Length - 8); i++)
  142. {
  143. if
  144. (
  145. Response[i] == NEWANSWER[0] &&
  146. Response[i + 1] == NEWANSWER[1] &&
  147. Response[i + 2] == QTYPE[0] &&
  148. Response[i + 3] == QTYPE[1] &&
  149. Response[i + 4] == QCLASS[0] &&
  150. Response[i + 5] == QCLASS[1]
  151. )
  152. AList.Add(i);
  153. }
  154. return (int[])AList.ToArray(typeof(int));
  155. }
  156. }