ares_mkquery.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /* $Id$ */
  2. /* Copyright 1998 by the Massachusetts Institute of Technology.
  3. *
  4. * Permission to use, copy, modify, and distribute this
  5. * software and its documentation for any purpose and without
  6. * fee is hereby granted, provided that the above copyright
  7. * notice appear in all copies and that both that copyright
  8. * notice and this permission notice appear in supporting
  9. * documentation, and that the name of M.I.T. not be used in
  10. * advertising or publicity pertaining to distribution of the
  11. * software without specific, written prior permission.
  12. * M.I.T. makes no representations about the suitability of
  13. * this software for any purpose. It is provided "as is"
  14. * without express or implied warranty.
  15. */
  16. #include "setup.h"
  17. #ifdef HAVE_SYS_SOCKET_H
  18. # include <sys/socket.h>
  19. #endif
  20. #ifdef HAVE_NETINET_IN_H
  21. # include <netinet/in.h>
  22. #endif
  23. #ifdef HAVE_ARPA_NAMESER_H
  24. # include <arpa/nameser.h>
  25. #else
  26. # include "nameser.h"
  27. #endif
  28. #ifdef HAVE_ARPA_NAMESER_COMPAT_H
  29. # include <arpa/nameser_compat.h>
  30. #endif
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include "ares.h"
  34. #include "ares_dns.h"
  35. #include "ares_private.h"
  36. /* Header format, from RFC 1035:
  37. * 1 1 1 1 1 1
  38. * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  39. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  40. * | ID |
  41. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  42. * |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
  43. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  44. * | QDCOUNT |
  45. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  46. * | ANCOUNT |
  47. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  48. * | NSCOUNT |
  49. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  50. * | ARCOUNT |
  51. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  52. *
  53. * AA, TC, RA, and RCODE are only set in responses. Brief description
  54. * of the remaining fields:
  55. * ID Identifier to match responses with queries
  56. * QR Query (0) or response (1)
  57. * Opcode For our purposes, always QUERY
  58. * RD Recursion desired
  59. * Z Reserved (zero)
  60. * QDCOUNT Number of queries
  61. * ANCOUNT Number of answers
  62. * NSCOUNT Number of name server records
  63. * ARCOUNT Number of additional records
  64. *
  65. * Question format, from RFC 1035:
  66. * 1 1 1 1 1 1
  67. * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  68. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  69. * | |
  70. * / QNAME /
  71. * / /
  72. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  73. * | QTYPE |
  74. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  75. * | QCLASS |
  76. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  77. *
  78. * The query name is encoded as a series of labels, each represented
  79. * as a one-byte length (maximum 63) followed by the text of the
  80. * label. The list is terminated by a label of length zero (which can
  81. * be thought of as the root domain).
  82. */
  83. int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
  84. int rd, unsigned char **buf, int *buflen)
  85. {
  86. int len;
  87. unsigned char *q;
  88. const char *p;
  89. /* Set our results early, in case we bail out early with an error. */
  90. *buflen = 0;
  91. *buf = NULL;
  92. /* Compute the length of the encoded name so we can check buflen.
  93. * Start counting at 1 for the zero-length label at the end. */
  94. len = 1;
  95. for (p = name; *p; p++)
  96. {
  97. if (*p == '\\' && *(p + 1) != 0)
  98. p++;
  99. len++;
  100. }
  101. /* If there are n periods in the name, there are n + 1 labels, and
  102. * thus n + 1 length fields, unless the name is empty or ends with a
  103. * period. So add 1 unless name is empty or ends with a period.
  104. */
  105. if (*name && *(p - 1) != '.')
  106. len++;
  107. /* Immediately reject names that are longer than the maximum of 255
  108. * bytes that's specified in RFC 1035 ("To simplify implementations,
  109. * the total length of a domain name (i.e., label octets and label
  110. * length octets) is restricted to 255 octets or less."). We aren't
  111. * doing this just to be a stickler about RFCs. For names that are
  112. * too long, 'dnscache' closes its TCP connection to us immediately
  113. * (when using TCP) and ignores the request when using UDP, and
  114. * BIND's named returns ServFail (TCP or UDP). Sending a request
  115. * that we know will cause 'dnscache' to close the TCP connection is
  116. * painful, since that makes any other outstanding requests on that
  117. * connection fail. And sending a UDP request that we know
  118. * 'dnscache' will ignore is bad because resources will be tied up
  119. * until we time-out the request.
  120. */
  121. if (len > MAXCDNAME)
  122. return ARES_EBADNAME;
  123. *buflen = len + HFIXEDSZ + QFIXEDSZ;
  124. *buf = malloc(*buflen);
  125. if (!*buf)
  126. return ARES_ENOMEM;
  127. /* Set up the header. */
  128. q = *buf;
  129. memset(q, 0, HFIXEDSZ);
  130. DNS_HEADER_SET_QID(q, id);
  131. DNS_HEADER_SET_OPCODE(q, QUERY);
  132. if (rd) {
  133. DNS_HEADER_SET_RD(q, 1);
  134. }
  135. else {
  136. DNS_HEADER_SET_RD(q, 0);
  137. }
  138. DNS_HEADER_SET_QDCOUNT(q, 1);
  139. /* A name of "." is a screw case for the loop below, so adjust it. */
  140. if (strcmp(name, ".") == 0)
  141. name++;
  142. /* Start writing out the name after the header. */
  143. q += HFIXEDSZ;
  144. while (*name)
  145. {
  146. if (*name == '.')
  147. return ARES_EBADNAME;
  148. /* Count the number of bytes in this label. */
  149. len = 0;
  150. for (p = name; *p && *p != '.'; p++)
  151. {
  152. if (*p == '\\' && *(p + 1) != 0)
  153. p++;
  154. len++;
  155. }
  156. if (len > MAXLABEL)
  157. return ARES_EBADNAME;
  158. /* Encode the length and copy the data. */
  159. *q++ = (unsigned char)len;
  160. for (p = name; *p && *p != '.'; p++)
  161. {
  162. if (*p == '\\' && *(p + 1) != 0)
  163. p++;
  164. *q++ = *p;
  165. }
  166. /* Go to the next label and repeat, unless we hit the end. */
  167. if (!*p)
  168. break;
  169. name = p + 1;
  170. }
  171. /* Add the zero-length label at the end. */
  172. *q++ = 0;
  173. /* Finish off the question with the type and class. */
  174. DNS_QUESTION_SET_TYPE(q, type);
  175. DNS_QUESTION_SET_CLASS(q, dnsclass);
  176. return ARES_SUCCESS;
  177. }