PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/Ethernet/Dns.cpp

https://github.com/bygreencn/Arduino
C++ | 423 lines | 279 code | 43 blank | 101 comment | 64 complexity | 7709e3512c6b8ce02b3fc737bf56f0a5 MD5 | raw file
  1. // Arduino DNS client for WizNet5100-based Ethernet shield
  2. // (c) Copyright 2009-2010 MCQN Ltd.
  3. // Released under Apache License, version 2.0
  4. #include "w5100.h"
  5. #include "EthernetUdp.h"
  6. #include "util.h"
  7. #include "Dns.h"
  8. #include <string.h>
  9. //#include <stdlib.h>
  10. #include "Arduino.h"
  11. #define SOCKET_NONE 255
  12. // Various flags and header field values for a DNS message
  13. #define UDP_HEADER_SIZE 8
  14. #define DNS_HEADER_SIZE 12
  15. #define TTL_SIZE 4
  16. #define QUERY_FLAG (0)
  17. #define RESPONSE_FLAG (1<<15)
  18. #define QUERY_RESPONSE_MASK (1<<15)
  19. #define OPCODE_STANDARD_QUERY (0)
  20. #define OPCODE_INVERSE_QUERY (1<<11)
  21. #define OPCODE_STATUS_REQUEST (2<<11)
  22. #define OPCODE_MASK (15<<11)
  23. #define AUTHORITATIVE_FLAG (1<<10)
  24. #define TRUNCATION_FLAG (1<<9)
  25. #define RECURSION_DESIRED_FLAG (1<<8)
  26. #define RECURSION_AVAILABLE_FLAG (1<<7)
  27. #define RESP_NO_ERROR (0)
  28. #define RESP_FORMAT_ERROR (1)
  29. #define RESP_SERVER_FAILURE (2)
  30. #define RESP_NAME_ERROR (3)
  31. #define RESP_NOT_IMPLEMENTED (4)
  32. #define RESP_REFUSED (5)
  33. #define RESP_MASK (15)
  34. #define TYPE_A (0x0001)
  35. #define CLASS_IN (0x0001)
  36. #define LABEL_COMPRESSION_MASK (0xC0)
  37. // Port number that DNS servers listen on
  38. #define DNS_PORT 53
  39. // Possible return codes from ProcessResponse
  40. #define SUCCESS 1
  41. #define TIMED_OUT -1
  42. #define INVALID_SERVER -2
  43. #define TRUNCATED -3
  44. #define INVALID_RESPONSE -4
  45. void DNSClient::begin(const IPAddress& aDNSServer)
  46. {
  47. iDNSServer = aDNSServer;
  48. iRequestId = 0;
  49. }
  50. int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult)
  51. {
  52. // See if we've been given a valid IP address
  53. const char* p =aIPAddrString;
  54. while (*p &&
  55. ( (*p == '.') || (*p >= '0') || (*p <= '9') ))
  56. {
  57. p++;
  58. }
  59. if (*p == '\0')
  60. {
  61. // It's looking promising, we haven't found any invalid characters
  62. p = aIPAddrString;
  63. int segment =0;
  64. int segmentValue =0;
  65. while (*p && (segment < 4))
  66. {
  67. if (*p == '.')
  68. {
  69. // We've reached the end of a segment
  70. if (segmentValue > 255)
  71. {
  72. // You can't have IP address segments that don't fit in a byte
  73. return 0;
  74. }
  75. else
  76. {
  77. aResult[segment] = (byte)segmentValue;
  78. segment++;
  79. segmentValue = 0;
  80. }
  81. }
  82. else
  83. {
  84. // Next digit
  85. segmentValue = (segmentValue*10)+(*p - '0');
  86. }
  87. p++;
  88. }
  89. // We've reached the end of address, but there'll still be the last
  90. // segment to deal with
  91. if ((segmentValue > 255) || (segment > 3))
  92. {
  93. // You can't have IP address segments that don't fit in a byte,
  94. // or more than four segments
  95. return 0;
  96. }
  97. else
  98. {
  99. aResult[segment] = (byte)segmentValue;
  100. return 1;
  101. }
  102. }
  103. else
  104. {
  105. return 0;
  106. }
  107. }
  108. int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult)
  109. {
  110. int ret =0;
  111. // See if it's a numeric IP address
  112. if (inet_aton(aHostname, aResult))
  113. {
  114. // It is, our work here is done
  115. return 1;
  116. }
  117. // Check we've got a valid DNS server to use
  118. if (iDNSServer == INADDR_NONE)
  119. {
  120. return INVALID_SERVER;
  121. }
  122. // Find a socket to use
  123. if (iUdp.begin(1024+(millis() & 0xF)) == 1)
  124. {
  125. // Try up to three times
  126. int retries = 0;
  127. // while ((retries < 3) && (ret <= 0))
  128. {
  129. // Send DNS request
  130. ret = iUdp.beginPacket(iDNSServer, DNS_PORT);
  131. if (ret != 0)
  132. {
  133. // Now output the request data
  134. ret = BuildRequest(aHostname);
  135. if (ret != 0)
  136. {
  137. // And finally send the request
  138. ret = iUdp.endPacket();
  139. if (ret != 0)
  140. {
  141. // Now wait for a response
  142. int wait_retries = 0;
  143. ret = TIMED_OUT;
  144. while ((wait_retries < 3) && (ret == TIMED_OUT))
  145. {
  146. ret = ProcessResponse(5000, aResult);
  147. wait_retries++;
  148. }
  149. }
  150. }
  151. }
  152. retries++;
  153. }
  154. // We're done with the socket now
  155. iUdp.stop();
  156. }
  157. return ret;
  158. }
  159. uint16_t DNSClient::BuildRequest(const char* aName)
  160. {
  161. // Build header
  162. // 1 1 1 1 1 1
  163. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  164. // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  165. // | ID |
  166. // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  167. // |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
  168. // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  169. // | QDCOUNT |
  170. // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  171. // | ANCOUNT |
  172. // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  173. // | NSCOUNT |
  174. // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  175. // | ARCOUNT |
  176. // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  177. // As we only support one request at a time at present, we can simplify
  178. // some of this header
  179. iRequestId = millis(); // generate a random ID
  180. uint16_t twoByteBuffer;
  181. // FIXME We should also check that there's enough space available to write to, rather
  182. // FIXME than assume there's enough space (as the code does at present)
  183. iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId));
  184. twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG);
  185. iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
  186. twoByteBuffer = htons(1); // One question record
  187. iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
  188. twoByteBuffer = 0; // Zero answer records
  189. iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
  190. iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
  191. // and zero additional records
  192. iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
  193. // Build question
  194. const char* start =aName;
  195. const char* end =start;
  196. uint8_t len;
  197. // Run through the name being requested
  198. while (*end)
  199. {
  200. // Find out how long this section of the name is
  201. end = start;
  202. while (*end && (*end != '.') )
  203. {
  204. end++;
  205. }
  206. if (end-start > 0)
  207. {
  208. // Write out the size of this section
  209. len = end-start;
  210. iUdp.write(&len, sizeof(len));
  211. // And then write out the section
  212. iUdp.write((uint8_t*)start, end-start);
  213. }
  214. start = end+1;
  215. }
  216. // We've got to the end of the question name, so
  217. // terminate it with a zero-length section
  218. len = 0;
  219. iUdp.write(&len, sizeof(len));
  220. // Finally the type and class of question
  221. twoByteBuffer = htons(TYPE_A);
  222. iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
  223. twoByteBuffer = htons(CLASS_IN); // Internet class of question
  224. iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
  225. // Success! Everything buffered okay
  226. return 1;
  227. }
  228. uint16_t DNSClient::ProcessResponse(int aTimeout, IPAddress& aAddress)
  229. {
  230. uint32_t startTime = millis();
  231. // Wait for a response packet
  232. while(iUdp.parsePacket() <= 0)
  233. {
  234. if((millis() - startTime) > aTimeout)
  235. return TIMED_OUT;
  236. delay(50);
  237. }
  238. // We've had a reply!
  239. // Read the UDP header
  240. uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header
  241. // Check that it's a response from the right server and the right port
  242. if ( (iDNSServer != iUdp.remoteIP()) ||
  243. (iUdp.remotePort() != DNS_PORT) )
  244. {
  245. // It's not from who we expected
  246. return INVALID_SERVER;
  247. }
  248. // Read through the rest of the response
  249. if (iUdp.available() < DNS_HEADER_SIZE)
  250. {
  251. return TRUNCATED;
  252. }
  253. iUdp.read(header, DNS_HEADER_SIZE);
  254. uint16_t header_flags = htons(*((uint16_t*)&header[2]));
  255. // Check that it's a response to this request
  256. if ( ( iRequestId != (*((uint16_t*)&header[0])) ) ||
  257. (header_flags & QUERY_RESPONSE_MASK != RESPONSE_FLAG) )
  258. {
  259. // Mark the entire packet as read
  260. iUdp.flush();
  261. return INVALID_RESPONSE;
  262. }
  263. // Check for any errors in the response (or in our request)
  264. // although we don't do anything to get round these
  265. if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) )
  266. {
  267. // Mark the entire packet as read
  268. iUdp.flush();
  269. return -5; //INVALID_RESPONSE;
  270. }
  271. // And make sure we've got (at least) one answer
  272. uint16_t answerCount = htons(*((uint16_t*)&header[6]));
  273. if (answerCount == 0 )
  274. {
  275. // Mark the entire packet as read
  276. iUdp.flush();
  277. return -6; //INVALID_RESPONSE;
  278. }
  279. // Skip over any questions
  280. for (int i =0; i < htons(*((uint16_t*)&header[4])); i++)
  281. {
  282. // Skip over the name
  283. uint8_t len;
  284. do
  285. {
  286. iUdp.read(&len, sizeof(len));
  287. if (len > 0)
  288. {
  289. // Don't need to actually read the data out for the string, just
  290. // advance ptr to beyond it
  291. while(len--)
  292. {
  293. iUdp.read(); // we don't care about the returned byte
  294. }
  295. }
  296. } while (len != 0);
  297. // Now jump over the type and class
  298. for (int i =0; i < 4; i++)
  299. {
  300. iUdp.read(); // we don't care about the returned byte
  301. }
  302. }
  303. // Now we're up to the bit we're interested in, the answer
  304. // There might be more than one answer (although we'll just use the first
  305. // type A answer) and some authority and additional resource records but
  306. // we're going to ignore all of them.
  307. for (int i =0; i < answerCount; i++)
  308. {
  309. // Skip the name
  310. uint8_t len;
  311. do
  312. {
  313. iUdp.read(&len, sizeof(len));
  314. if ((len & LABEL_COMPRESSION_MASK) == 0)
  315. {
  316. // It's just a normal label
  317. if (len > 0)
  318. {
  319. // And it's got a length
  320. // Don't need to actually read the data out for the string,
  321. // just advance ptr to beyond it
  322. while(len--)
  323. {
  324. iUdp.read(); // we don't care about the returned byte
  325. }
  326. }
  327. }
  328. else
  329. {
  330. // This is a pointer to a somewhere else in the message for the
  331. // rest of the name. We don't care about the name, and RFC1035
  332. // says that a name is either a sequence of labels ended with a
  333. // 0 length octet or a pointer or a sequence of labels ending in
  334. // a pointer. Either way, when we get here we're at the end of
  335. // the name
  336. // Skip over the pointer
  337. iUdp.read(); // we don't care about the returned byte
  338. // And set len so that we drop out of the name loop
  339. len = 0;
  340. }
  341. } while (len != 0);
  342. // Check the type and class
  343. uint16_t answerType;
  344. uint16_t answerClass;
  345. iUdp.read((uint8_t*)&answerType, sizeof(answerType));
  346. iUdp.read((uint8_t*)&answerClass, sizeof(answerClass));
  347. // Ignore the Time-To-Live as we don't do any caching
  348. for (int i =0; i < TTL_SIZE; i++)
  349. {
  350. iUdp.read(); // we don't care about the returned byte
  351. }
  352. // And read out the length of this answer
  353. // Don't need header_flags anymore, so we can reuse it here
  354. iUdp.read((uint8_t*)&header_flags, sizeof(header_flags));
  355. if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) )
  356. {
  357. if (htons(header_flags) != 4)
  358. {
  359. // It's a weird size
  360. // Mark the entire packet as read
  361. iUdp.flush();
  362. return -9;//INVALID_RESPONSE;
  363. }
  364. iUdp.read(aAddress.raw_address(), 4);
  365. return SUCCESS;
  366. }
  367. else
  368. {
  369. // This isn't an answer type we're after, move onto the next one
  370. for (int i =0; i < htons(header_flags); i++)
  371. {
  372. iUdp.read(); // we don't care about the returned byte
  373. }
  374. }
  375. }
  376. // Mark the entire packet as read
  377. iUdp.flush();
  378. // If we get here then we haven't found an answer
  379. return -10;//INVALID_RESPONSE;
  380. }