Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added new feature (rfc2671)

  • Loading branch information...
commit 90364defb038d5d6b97acf9df9ed152d2393a863 1 parent e447bc5
authored August 10, 2012 bagder committed August 17, 2012
4  Makefile.inc
@@ -20,6 +20,7 @@ CSOURCES = ares__close_sockets.c	\
20 20
   ares_library_init.c			\
21 21
   ares_llist.c				\
22 22
   ares_mkquery.c			\
  23
+  ares_create_query.c			\
23 24
   ares_nowarn.c				\
24 25
   ares_options.c			\
25 26
   ares_parse_a_reply.c			\
@@ -92,6 +93,7 @@ MANPAGES = ares_cancel.3		\
92 93
   ares_library_cleanup.3		\
93 94
   ares_library_init.3			\
94 95
   ares_mkquery.3			\
  96
+  ares_create_query.3			\
95 97
   ares_parse_a_reply.3			\
96 98
   ares_parse_aaaa_reply.3		\
97 99
   ares_parse_mx_reply.3			\
@@ -133,6 +135,7 @@ HTMLPAGES = ares_cancel.html		\
133 135
   ares_library_cleanup.html		\
134 136
   ares_library_init.html		\
135 137
   ares_mkquery.html			\
  138
+  ares_create_query.html			\
136 139
   ares_parse_a_reply.html		\
137 140
   ares_parse_aaaa_reply.html		\
138 141
   ares_parse_mx_reply.html		\
@@ -173,6 +176,7 @@ PDFPAGES = ares_cancel.pdf		\
173 176
   ares_library_cleanup.pdf		\
174 177
   ares_library_init.pdf			\
175 178
   ares_mkquery.pdf			\
  179
+  ares_create_query.pdf			\
176 180
   ares_parse_a_reply.pdf		\
177 181
   ares_parse_aaaa_reply.pdf		\
178 182
   ares_parse_mx_reply.pdf		\
12  ares.h
@@ -143,6 +143,7 @@ extern "C" {
143 143
 #define ARES_FLAG_NOSEARCH      (1 << 5)
144 144
 #define ARES_FLAG_NOALIASES     (1 << 6)
145 145
 #define ARES_FLAG_NOCHECKRESP   (1 << 7)
  146
+#define ARES_FLAG_EDNS          (1 << 8)
146 147
 
147 148
 /* Option mask values */
148 149
 #define ARES_OPT_FLAGS          (1 << 0)
@@ -160,6 +161,7 @@ extern "C" {
160 161
 #define ARES_OPT_SOCK_RCVBUF    (1 << 12)
161 162
 #define ARES_OPT_TIMEOUTMS      (1 << 13)
162 163
 #define ARES_OPT_ROTATE         (1 << 14)
  164
+#define ARES_OPT_EDNSPSZ        (1 << 15)
163 165
 
164 166
 /* Nameinfo flag values */
165 167
 #define ARES_NI_NOFQDN                  (1 << 0)
@@ -265,6 +267,7 @@ struct ares_options {
265 267
   void *sock_state_cb_data;
266 268
   struct apattern *sortlist;
267 269
   int nsort;
  270
+  int ednspsz;
268 271
 };
269 272
 
270 273
 struct hostent;
@@ -403,6 +406,15 @@ CARES_EXTERN void ares_process_fd(ares_channel channel,
403 406
                                   ares_socket_t read_fd,
404 407
                                   ares_socket_t write_fd);
405 408
 
  409
+CARES_EXTERN int ares_create_query(const char *name,
  410
+                                   int dnsclass,
  411
+                                   int type,
  412
+                                   unsigned short id,
  413
+                                   int rd,
  414
+                                   unsigned char **buf,
  415
+                                   int *buflen,
  416
+                                   int max_udp_size);
  417
+
406 418
 CARES_EXTERN int ares_mkquery(const char *name,
407 419
                               int dnsclass,
408 420
                               int type,
79  ares_create_query.3
... ...
@@ -0,0 +1,79 @@
  1
+.\"
  2
+.\" Copyright 1998, 2000 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
+.TH ARES_CREATE_QUERY 3 "20 Nov 2009"
  17
+.SH NAME
  18
+ares_create_query \- Compose a single-question DNS query buffer
  19
+.SH SYNOPSIS
  20
+.nf
  21
+.B #include <ares.h>
  22
+.PP
  23
+.B int ares_create_query(const char *\fIname\fP, int \fIdnsclass\fP,\
  24
+                         int \fItype\fP,
  25
+.B		                   unsigned short \fIid\fP, int \fIrd\fP,\
  26
+                         unsigned char **\fIbuf\fP,
  27
+.B		                   int *\fIbuflen\fP, int \fImax_udp_size\fP)
  28
+.fi
  29
+.SH DESCRIPTION
  30
+The
  31
+.B ares_create_query
  32
+function composes a DNS query with a single question.
  33
+The parameter
  34
+.I name
  35
+gives the query name as a NUL-terminated C string of period-separated
  36
+labels optionally ending with a period; periods and backslashes within
  37
+a label must be escaped with a backlash.  The parameters
  38
+.I dnsclass
  39
+and
  40
+.I type
  41
+give the class and type of the query using the values defined in
  42
+.BR <arpa/nameser.h> .
  43
+The parameter
  44
+.I id
  45
+gives a 16-bit identifier for the query.  The parameter
  46
+.I rd
  47
+should be nonzero if recursion is desired, zero if not.  The query
  48
+will be placed in an allocated buffer, a pointer to which will be
  49
+stored in the variable pointed to by
  50
+.IR buf ,
  51
+and the length of which will be stored in the variable pointed to by
  52
+.IR buflen .
  53
+It is the caller's responsibility to free this buffer using
  54
+\fIares_free_string(3)\fP when it is no longer needed.
  55
+The parameter
  56
+.I max_udp_size
  57
+should be nonzero to activate EDNS. Usage of \fIares_create_query(3)\fP\ with
  58
+.I max_udp_size
  59
+set to zero is equivalent to \fIares_mkquery(3)\fP.
  60
+.SH RETURN VALUES
  61
+.B ares_create_query
  62
+can return any of the following values:
  63
+.TP 15
  64
+.B ARES_SUCCESS
  65
+Construction of the DNS query succeeded.
  66
+.TP 15
  67
+.B ARES_EBADNAME
  68
+The query name
  69
+.I name
  70
+could not be encoded as a domain name, either because it contained a
  71
+zero-length label or because it contained a label of more than 63
  72
+characters.
  73
+.TP 15
  74
+.B ARES_ENOMEM
  75
+Memory was exhausted.
  76
+.SH SEE ALSO
  77
+.BR ares_expand_name (3),
  78
+.BR ares_free_string (3)
  79
+.SH AUTHOR
209  ares_create_query.c
... ...
@@ -0,0 +1,209 @@
  1
+
  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
+
  17
+#include "ares_setup.h"
  18
+
  19
+#ifdef HAVE_SYS_SOCKET_H
  20
+#  include <sys/socket.h>
  21
+#endif
  22
+#ifdef HAVE_NETINET_IN_H
  23
+#  include <netinet/in.h>
  24
+#endif
  25
+#ifdef HAVE_ARPA_NAMESER_H
  26
+#  include <arpa/nameser.h>
  27
+#else
  28
+#  include "nameser.h"
  29
+#endif
  30
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
  31
+#  include <arpa/nameser_compat.h>
  32
+#endif
  33
+
  34
+#include <stdlib.h>
  35
+#include <string.h>
  36
+#include "ares.h"
  37
+#include "ares_dns.h"
  38
+#include "ares_private.h"
  39
+
  40
+/* Header format, from RFC 1035:
  41
+ *                                  1  1  1  1  1  1
  42
+ *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
  43
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  44
+ *  |                      ID                       |
  45
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  46
+ *  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
  47
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  48
+ *  |                    QDCOUNT                    |
  49
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  50
+ *  |                    ANCOUNT                    |
  51
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  52
+ *  |                    NSCOUNT                    |
  53
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  54
+ *  |                    ARCOUNT                    |
  55
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  56
+ *
  57
+ * AA, TC, RA, and RCODE are only set in responses.  Brief description
  58
+ * of the remaining fields:
  59
+ *      ID      Identifier to match responses with queries
  60
+ *      QR      Query (0) or response (1)
  61
+ *      Opcode  For our purposes, always QUERY
  62
+ *      RD      Recursion desired
  63
+ *      Z       Reserved (zero)
  64
+ *      QDCOUNT Number of queries
  65
+ *      ANCOUNT Number of answers
  66
+ *      NSCOUNT Number of name server records
  67
+ *      ARCOUNT Number of additional records
  68
+ *
  69
+ * Question format, from RFC 1035:
  70
+ *                                  1  1  1  1  1  1
  71
+ *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
  72
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  73
+ *  |                                               |
  74
+ *  /                     QNAME                     /
  75
+ *  /                                               /
  76
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  77
+ *  |                     QTYPE                     |
  78
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  79
+ *  |                     QCLASS                    |
  80
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  81
+ *
  82
+ * The query name is encoded as a series of labels, each represented
  83
+ * as a one-byte length (maximum 63) followed by the text of the
  84
+ * label.  The list is terminated by a label of length zero (which can
  85
+ * be thought of as the root domain).
  86
+ */
  87
+
  88
+int ares_create_query(const char *name, int dnsclass, int type,
  89
+                      unsigned short id, int rd, unsigned char **buf,
  90
+                      int *buflen, int max_udp_size)
  91
+{
  92
+  int len;
  93
+  unsigned char *q;
  94
+  const char *p;
  95
+
  96
+  /* Set our results early, in case we bail out early with an error. */
  97
+  *buflen = 0;
  98
+  *buf = NULL;
  99
+
  100
+  /* Compute the length of the encoded name so we can check buflen.
  101
+   * Start counting at 1 for the zero-length label at the end. */
  102
+  len = 1;
  103
+  for (p = name; *p; p++)
  104
+    {
  105
+      if (*p == '\\' && *(p + 1) != 0)
  106
+        p++;
  107
+      len++;
  108
+    }
  109
+  /* If there are n periods in the name, there are n + 1 labels, and
  110
+   * thus n + 1 length fields, unless the name is empty or ends with a
  111
+   * period.  So add 1 unless name is empty or ends with a period.
  112
+   */
  113
+  if (*name && *(p - 1) != '.')
  114
+    len++;
  115
+
  116
+  /* Immediately reject names that are longer than the maximum of 255
  117
+   * bytes that's specified in RFC 1035 ("To simplify implementations,
  118
+   * the total length of a domain name (i.e., label octets and label
  119
+   * length octets) is restricted to 255 octets or less."). We aren't
  120
+   * doing this just to be a stickler about RFCs. For names that are
  121
+   * too long, 'dnscache' closes its TCP connection to us immediately
  122
+   * (when using TCP) and ignores the request when using UDP, and
  123
+   * BIND's named returns ServFail (TCP or UDP). Sending a request
  124
+   * that we know will cause 'dnscache' to close the TCP connection is
  125
+   * painful, since that makes any other outstanding requests on that
  126
+   * connection fail. And sending a UDP request that we know
  127
+   * 'dnscache' will ignore is bad because resources will be tied up
  128
+   * until we time-out the request.
  129
+   */
  130
+  if (len > MAXCDNAME)
  131
+    return ARES_EBADNAME;
  132
+
  133
+  *buflen = len + HFIXEDSZ + QFIXEDSZ + (max_udp_size ? EDNSFIXEDSZ : 0);
  134
+  *buf = malloc(*buflen);
  135
+  if (!*buf)
  136
+      return ARES_ENOMEM;
  137
+
  138
+  /* Set up the header. */
  139
+  q = *buf;
  140
+  memset(q, 0, HFIXEDSZ);
  141
+  DNS_HEADER_SET_QID(q, id);
  142
+  DNS_HEADER_SET_OPCODE(q, QUERY);
  143
+  if (rd) {
  144
+    DNS_HEADER_SET_RD(q, 1);
  145
+  }
  146
+  else {
  147
+    DNS_HEADER_SET_RD(q, 0);
  148
+  }
  149
+  DNS_HEADER_SET_QDCOUNT(q, 1);
  150
+
  151
+  if (max_udp_size) {
  152
+      DNS_HEADER_SET_ARCOUNT(q, 1);
  153
+  }
  154
+
  155
+  /* A name of "." is a screw case for the loop below, so adjust it. */
  156
+  if (strcmp(name, ".") == 0)
  157
+    name++;
  158
+
  159
+  /* Start writing out the name after the header. */
  160
+  q += HFIXEDSZ;
  161
+  while (*name)
  162
+    {
  163
+      if (*name == '.')
  164
+        return ARES_EBADNAME;
  165
+
  166
+      /* Count the number of bytes in this label. */
  167
+      len = 0;
  168
+      for (p = name; *p && *p != '.'; p++)
  169
+        {
  170
+          if (*p == '\\' && *(p + 1) != 0)
  171
+            p++;
  172
+          len++;
  173
+        }
  174
+      if (len > MAXLABEL)
  175
+        return ARES_EBADNAME;
  176
+
  177
+      /* Encode the length and copy the data. */
  178
+      *q++ = (unsigned char)len;
  179
+      for (p = name; *p && *p != '.'; p++)
  180
+        {
  181
+          if (*p == '\\' && *(p + 1) != 0)
  182
+            p++;
  183
+          *q++ = *p;
  184
+        }
  185
+
  186
+      /* Go to the next label and repeat, unless we hit the end. */
  187
+      if (!*p)
  188
+        break;
  189
+      name = p + 1;
  190
+    }
  191
+
  192
+  /* Add the zero-length label at the end. */
  193
+  *q++ = 0;
  194
+
  195
+  /* Finish off the question with the type and class. */
  196
+  DNS_QUESTION_SET_TYPE(q, type);
  197
+  DNS_QUESTION_SET_CLASS(q, dnsclass);
  198
+
  199
+  if (max_udp_size)
  200
+  {
  201
+      q += QFIXEDSZ;
  202
+      memset(q, 0, EDNSFIXEDSZ);
  203
+      q++;
  204
+      DNS_RR_SET_TYPE(q, ns_t_opt);
  205
+      DNS_RR_SET_CLASS(q, max_udp_size);
  206
+  }
  207
+
  208
+  return ARES_SUCCESS;
  209
+}
8  ares_dns.h
@@ -95,9 +95,9 @@
95 95
 #define DNS_RR_LEN(r)                   DNS__16BIT((r) + 8)
96 96
 
97 97
 /* Macros for constructing the fixed part of a DNS resource record */
98  
-#define DNS_RR_SET_TYPE(r)              DNS__SET16BIT(r, v)
99  
-#define DNS_RR_SET_CLASS(r)             DNS__SET16BIT((r) + 2, v)
100  
-#define DNS_RR_SET_TTL(r)               DNS__SET32BIT((r) + 4, v)
101  
-#define DNS_RR_SET_LEN(r)               DNS__SET16BIT((r) + 8, v)
  98
+#define DNS_RR_SET_TYPE(r, v)           DNS__SET16BIT(r, v)
  99
+#define DNS_RR_SET_CLASS(r, v)          DNS__SET16BIT((r) + 2, v)
  100
+#define DNS_RR_SET_TTL(r, v)            DNS__SET32BIT((r) + 4, v)
  101
+#define DNS_RR_SET_LEN(r, v)            DNS__SET16BIT((r) + 8, v)
102 102
 
103 103
 #endif /* HEADER_CARES_DNS_H */
7  ares_init.c
@@ -163,6 +163,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
163 163
   channel->rotate = -1;
164 164
   channel->udp_port = -1;
165 165
   channel->tcp_port = -1;
  166
+  channel->ednspsz = -1;
166 167
   channel->socket_send_buffer_size = -1;
167 168
   channel->socket_receive_buffer_size = -1;
168 169
   channel->nservers = -1;
@@ -453,6 +454,9 @@ static int init_by_options(ares_channel channel,
453 454
       && channel->socket_receive_buffer_size == -1)
454 455
     channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
455 456
 
  457
+  if ((optmask & ARES_OPT_EDNSPSZ) && channel->ednspsz == -1)
  458
+    channel->ednspsz = options->ednspsz;
  459
+
456 460
   /* Copy the IPv4 servers, if given. */
457 461
   if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
458 462
     {
@@ -1358,6 +1362,9 @@ static int init_by_defaults(ares_channel channel)
1358 1362
   if (channel->tcp_port == -1)
1359 1363
     channel->tcp_port = htons(NAMESERVER_PORT);
1360 1364
 
  1365
+  if (channel->ednspsz == -1)
  1366
+    channel->ednspsz = EDNSPACKETSZ;
  1367
+
1361 1368
   if (channel->nservers == -1) {
1362 1369
     /* If nobody specified servers, try a local named. */
1363 1370
     channel->servers = malloc(sizeof(struct server_state));
7  ares_mkquery.3
@@ -25,6 +25,8 @@ ares_mkquery \- Compose a single-question DNS query buffer
25 25
 .B	int *\fIbuflen\fP)
26 26
 .fi
27 27
 .SH DESCRIPTION
  28
+Deprecated function. See \fIares_create_query(3)\fP instead!
  29
+
28 30
 The
29 31
 .B ares_mkquery
30 32
 function composes a DNS query with a single question.
@@ -50,6 +52,11 @@ and the length of which will be stored in the variable pointed to by
50 52
 .IR buflen .
51 53
 It is the caller's responsibility to free this buffer using
52 54
 \fIares_free_string(3)\fP when it is no longer needed.
  55
+
  56
+Usage of \fIares_mkquery(3)\fP is deprecated, whereas the function is
  57
+equivalent to \fIares_create_query(3)\fP with \fBmax_udp_size\fP set to
  58
+0.
  59
+
53 60
 .SH RETURN VALUES
54 61
 .B ares_mkquery
55 62
 can return any of the following values:
173  ares_mkquery.c
@@ -15,181 +15,10 @@
15 15
  */
16 16
 
17 17
 #include "ares_setup.h"
18  
-
19  
-#ifdef HAVE_SYS_SOCKET_H
20  
-#  include <sys/socket.h>
21  
-#endif
22  
-#ifdef HAVE_NETINET_IN_H
23  
-#  include <netinet/in.h>
24  
-#endif
25  
-#ifdef HAVE_ARPA_NAMESER_H
26  
-#  include <arpa/nameser.h>
27  
-#else
28  
-#  include "nameser.h"
29  
-#endif
30  
-#ifdef HAVE_ARPA_NAMESER_COMPAT_H
31  
-#  include <arpa/nameser_compat.h>
32  
-#endif
33  
-
34  
-#include <stdlib.h>
35  
-#include <string.h>
36 18
 #include "ares.h"
37  
-#include "ares_dns.h"
38  
-#include "ares_private.h"
39  
-
40  
-/* Header format, from RFC 1035:
41  
- *                                  1  1  1  1  1  1
42  
- *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
43  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
44  
- *  |                      ID                       |
45  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
46  
- *  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
47  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
48  
- *  |                    QDCOUNT                    |
49  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
50  
- *  |                    ANCOUNT                    |
51  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
52  
- *  |                    NSCOUNT                    |
53  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
54  
- *  |                    ARCOUNT                    |
55  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
56  
- *
57  
- * AA, TC, RA, and RCODE are only set in responses.  Brief description
58  
- * of the remaining fields:
59  
- *      ID      Identifier to match responses with queries
60  
- *      QR      Query (0) or response (1)
61  
- *      Opcode  For our purposes, always QUERY
62  
- *      RD      Recursion desired
63  
- *      Z       Reserved (zero)
64  
- *      QDCOUNT Number of queries
65  
- *      ANCOUNT Number of answers
66  
- *      NSCOUNT Number of name server records
67  
- *      ARCOUNT Number of additional records
68  
- *
69  
- * Question format, from RFC 1035:
70  
- *                                  1  1  1  1  1  1
71  
- *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
72  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
73  
- *  |                                               |
74  
- *  /                     QNAME                     /
75  
- *  /                                               /
76  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
77  
- *  |                     QTYPE                     |
78  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
79  
- *  |                     QCLASS                    |
80  
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
81  
- *
82  
- * The query name is encoded as a series of labels, each represented
83  
- * as a one-byte length (maximum 63) followed by the text of the
84  
- * label.  The list is terminated by a label of length zero (which can
85  
- * be thought of as the root domain).
86  
- */
87 19
 
88 20
 int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
89 21
                  int rd, unsigned char **buf, int *buflen)
90 22
 {
91  
-  int len;
92  
-  unsigned char *q;
93  
-  const char *p;
94  
-
95  
-  /* Set our results early, in case we bail out early with an error. */
96  
-  *buflen = 0;
97  
-  *buf = NULL;
98  
-
99  
-  /* Compute the length of the encoded name so we can check buflen.
100  
-   * Start counting at 1 for the zero-length label at the end. */
101  
-  len = 1;
102  
-  for (p = name; *p; p++)
103  
-    {
104  
-      if (*p == '\\' && *(p + 1) != 0)
105  
-        p++;
106  
-      len++;
107  
-    }
108  
-  /* If there are n periods in the name, there are n + 1 labels, and
109  
-   * thus n + 1 length fields, unless the name is empty or ends with a
110  
-   * period.  So add 1 unless name is empty or ends with a period.
111  
-   */
112  
-  if (*name && *(p - 1) != '.')
113  
-    len++;
114  
-
115  
-  /* Immediately reject names that are longer than the maximum of 255
116  
-   * bytes that's specified in RFC 1035 ("To simplify implementations,
117  
-   * the total length of a domain name (i.e., label octets and label
118  
-   * length octets) is restricted to 255 octets or less."). We aren't
119  
-   * doing this just to be a stickler about RFCs. For names that are
120  
-   * too long, 'dnscache' closes its TCP connection to us immediately
121  
-   * (when using TCP) and ignores the request when using UDP, and
122  
-   * BIND's named returns ServFail (TCP or UDP). Sending a request
123  
-   * that we know will cause 'dnscache' to close the TCP connection is
124  
-   * painful, since that makes any other outstanding requests on that
125  
-   * connection fail. And sending a UDP request that we know
126  
-   * 'dnscache' will ignore is bad because resources will be tied up
127  
-   * until we time-out the request.
128  
-   */
129  
-  if (len > MAXCDNAME)
130  
-    return ARES_EBADNAME;
131  
-
132  
-  *buflen = len + HFIXEDSZ + QFIXEDSZ;
133  
-  *buf = malloc(*buflen);
134  
-  if (!*buf)
135  
-      return ARES_ENOMEM;
136  
-
137  
-  /* Set up the header. */
138  
-  q = *buf;
139  
-  memset(q, 0, HFIXEDSZ);
140  
-  DNS_HEADER_SET_QID(q, id);
141  
-  DNS_HEADER_SET_OPCODE(q, QUERY);
142  
-  if (rd) {
143  
-    DNS_HEADER_SET_RD(q, 1);
144  
-  }
145  
-  else {
146  
-    DNS_HEADER_SET_RD(q, 0);
147  
-  }
148  
-  DNS_HEADER_SET_QDCOUNT(q, 1);
149  
-
150  
-  /* A name of "." is a screw case for the loop below, so adjust it. */
151  
-  if (strcmp(name, ".") == 0)
152  
-    name++;
153  
-
154  
-  /* Start writing out the name after the header. */
155  
-  q += HFIXEDSZ;
156  
-  while (*name)
157  
-    {
158  
-      if (*name == '.')
159  
-        return ARES_EBADNAME;
160  
-
161  
-      /* Count the number of bytes in this label. */
162  
-      len = 0;
163  
-      for (p = name; *p && *p != '.'; p++)
164  
-        {
165  
-          if (*p == '\\' && *(p + 1) != 0)
166  
-            p++;
167  
-          len++;
168  
-        }
169  
-      if (len > MAXLABEL)
170  
-        return ARES_EBADNAME;
171  
-
172  
-      /* Encode the length and copy the data. */
173  
-      *q++ = (unsigned char)len;
174  
-      for (p = name; *p && *p != '.'; p++)
175  
-        {
176  
-          if (*p == '\\' && *(p + 1) != 0)
177  
-            p++;
178  
-          *q++ = *p;
179  
-        }
180  
-
181  
-      /* Go to the next label and repeat, unless we hit the end. */
182  
-      if (!*p)
183  
-        break;
184  
-      name = p + 1;
185  
-    }
186  
-
187  
-  /* Add the zero-length label at the end. */
188  
-  *q++ = 0;
189  
-
190  
-  /* Finish off the question with the type and class. */
191  
-  DNS_QUESTION_SET_TYPE(q, type);
192  
-  DNS_QUESTION_SET_CLASS(q, dnsclass);
193  
-
194  
-  return ARES_SUCCESS;
  23
+  return ares_create_query(name, dnsclass, type, id, rd, buf, buflen, 0);
195 24
 }
8  ares_private.h
@@ -113,6 +113,13 @@
113 113
 #  define writev(s,ptr,cnt) ares_writev(s,ptr,cnt)
114 114
 #endif
115 115
 
  116
+/********* EDNS defines section ******/
  117
+#define EDNSPACKETSZ   1280  /* Reasonable UDP payload size, as suggested
  118
+                                in RFC2671 */
  119
+#define MAXENDSSZ      4096  /* Maximum (local) limit for edns packet size */
  120
+#define EDNSFIXEDSZ    11    /* Size of EDNS header */
  121
+/********* EDNS defines section ******/
  122
+
116 123
 struct ares_addr {
117 124
   int family;
118 125
   union {
@@ -260,6 +267,7 @@ struct ares_channeldata {
260 267
   struct apattern *sortlist;
261 268
   int nsort;
262 269
   char *lookups;
  270
+  int ednspsz;
263 271
 
264 272
   /* For binding to local devices and/or IP addresses.  Leave
265 273
    * them null/zero for no binding.
33  ares_process.c
@@ -430,7 +430,7 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
430 430
   struct server_state *server;
431 431
   int i;
432 432
   ssize_t count;
433  
-  unsigned char buf[PACKETSZ + 1];
  433
+  unsigned char buf[MAXENDSSZ + 1];
434 434
 #ifdef HAVE_RECVFROM
435 435
   ares_socklen_t fromlen;
436 436
   union {
@@ -541,7 +541,7 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
541 541
                            int alen, int whichserver, int tcp,
542 542
                            struct timeval *now)
543 543
 {
544  
-  int tc, rcode;
  544
+  int tc, rcode, packetsz;
545 545
   unsigned short id;
546 546
   struct query *query;
547 547
   struct list_node* list_head;
@@ -578,11 +578,34 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
578 578
   if (!query)
579 579
     return;
580 580
 
  581
+  packetsz = PACKETSZ;
  582
+  /* If we use EDNS and server answers with one of these RCODES, the protocol
  583
+   * extension is not understood by the responder. We must retry the query
  584
+   * without EDNS enabled.
  585
+   */
  586
+  if (channel->flags & ARES_FLAG_EDNS)
  587
+  {
  588
+      packetsz = channel->ednspsz;
  589
+      if (rcode == NOTIMP || rcode == FORMERR || rcode == SERVFAIL)
  590
+      {
  591
+          int qlen = alen - EDNSFIXEDSZ;
  592
+          channel->flags ^= ARES_FLAG_EDNS;
  593
+          query->tcplen -= EDNSFIXEDSZ;
  594
+          query->qlen -= EDNSFIXEDSZ;
  595
+          query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff);
  596
+          query->tcpbuf[1] = (unsigned char)(qlen & 0xff);
  597
+          DNS_HEADER_SET_ARCOUNT(query->tcpbuf + 2, 0);
  598
+          query->tcpbuf = realloc(query->tcpbuf, query->tcplen);
  599
+          ares__send_query(channel, query, now);
  600
+          return;
  601
+      }
  602
+  }
  603
+
581 604
   /* If we got a truncated UDP packet and are not ignoring truncation,
582 605
    * don't accept the packet, and switch the query to TCP if we hadn't
583 606
    * done so already.
584 607
    */
585  
-  if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
  608
+  if ((tc || alen > packetsz) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
586 609
     {
587 610
       if (!query->using_tcp)
588 611
         {
@@ -595,8 +618,8 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
595 618
   /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we
596 619
    * are ignoring truncation.
597 620
    */
598  
-  if (alen > PACKETSZ && !tcp)
599  
-    alen = PACKETSZ;
  621
+  if (alen > packetsz && !tcp)
  622
+      alen = packetsz;
600 623
 
601 624
   /* If we aren't passing through all error packets, discard packets
602 625
    * with SERVFAIL, NOTIMP, or REFUSED response codes.
4  ares_query.c
@@ -114,8 +114,8 @@ void ares_query(ares_channel channel, const char *name, int dnsclass,
114 114
 
115 115
   /* Compose the query. */
116 116
   rd = !(channel->flags & ARES_FLAG_NORECURSE);
117  
-  status = ares_mkquery(name, dnsclass, type, channel->next_id, rd, &qbuf,
118  
-                        &qlen);
  117
+  status = ares_create_query(name, dnsclass, type, channel->next_id, rd, &qbuf,
  118
+              &qlen, (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : 0);
119 119
   if (status != ARES_SUCCESS)
120 120
     {
121 121
       if (qbuf != NULL) free(qbuf);
7  ares_send.c
@@ -42,7 +42,7 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
42 42
                ares_callback callback, void *arg)
43 43
 {
44 44
   struct query *query;
45  
-  int i;
  45
+  int i, packetsz;
46 46
   struct timeval now;
47 47
 
48 48
   /* Verify that the query is at least long enough to hold the header. */
@@ -109,7 +109,10 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
109 109
       query->server_info[i].skip_server = 0;
110 110
       query->server_info[i].tcp_connection_generation = 0;
111 111
     }
112  
-  query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ;
  112
+
  113
+  packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ;
  114
+  query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > packetsz;
  115
+
113 116
   query->error_status = ARES_ECONNREFUSED;
114 117
   query->timeouts = 0;
115 118
 

0 notes on commit 90364de

Please sign in to comment.
Something went wrong with that request. Please try again.