Added new feature (rfc2671)
authorhpopescu@ixiacom.com <hpopescu@ixiacom.com>
Fri, 10 Aug 2012 09:06:09 +0000 (12:06 +0300)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 16 Aug 2012 22:54:47 +0000 (00:54 +0200)
12 files changed:
Makefile.inc
ares.h
ares_create_query.3 [new file with mode: 0644]
ares_create_query.c [new file with mode: 0644]
ares_dns.h
ares_init.c
ares_mkquery.3
ares_mkquery.c
ares_private.h
ares_process.c
ares_query.c
ares_send.c

index ec0cba4b84c30903d7bb3bc689f30d802680d558..81686a8b43a264c1d86cc9ee695dd6c9e74c63f8 100644 (file)
@@ -20,6 +20,7 @@ CSOURCES = ares__close_sockets.c      \
   ares_library_init.c                  \
   ares_llist.c                         \
   ares_mkquery.c                       \
+  ares_create_query.c                  \
   ares_nowarn.c                                \
   ares_options.c                       \
   ares_parse_a_reply.c                 \
@@ -92,6 +93,7 @@ MANPAGES = ares_cancel.3              \
   ares_library_cleanup.3               \
   ares_library_init.3                  \
   ares_mkquery.3                       \
+  ares_create_query.3                  \
   ares_parse_a_reply.3                 \
   ares_parse_aaaa_reply.3              \
   ares_parse_mx_reply.3                        \
@@ -133,6 +135,7 @@ HTMLPAGES = ares_cancel.html                \
   ares_library_cleanup.html            \
   ares_library_init.html               \
   ares_mkquery.html                    \
+  ares_create_query.html                       \
   ares_parse_a_reply.html              \
   ares_parse_aaaa_reply.html           \
   ares_parse_mx_reply.html             \
@@ -173,6 +176,7 @@ PDFPAGES = ares_cancel.pdf          \
   ares_library_cleanup.pdf             \
   ares_library_init.pdf                        \
   ares_mkquery.pdf                     \
+  ares_create_query.pdf                        \
   ares_parse_a_reply.pdf               \
   ares_parse_aaaa_reply.pdf            \
   ares_parse_mx_reply.pdf              \
diff --git a/ares.h b/ares.h
index c5e40695f18aa1b1ab955fab25defb762ca903f3..f0cc82494eb8153c116a338a72d5f7b3d9b777d4 100644 (file)
--- a/ares.h
+++ b/ares.h
@@ -143,6 +143,7 @@ extern "C" {
 #define ARES_FLAG_NOSEARCH      (1 << 5)
 #define ARES_FLAG_NOALIASES     (1 << 6)
 #define ARES_FLAG_NOCHECKRESP   (1 << 7)
+#define ARES_FLAG_EDNS          (1 << 8)
 
 /* Option mask values */
 #define ARES_OPT_FLAGS          (1 << 0)
@@ -160,6 +161,7 @@ extern "C" {
 #define ARES_OPT_SOCK_RCVBUF    (1 << 12)
 #define ARES_OPT_TIMEOUTMS      (1 << 13)
 #define ARES_OPT_ROTATE         (1 << 14)
+#define ARES_OPT_EDNSPSZ        (1 << 15)
 
 /* Nameinfo flag values */
 #define ARES_NI_NOFQDN                  (1 << 0)
@@ -265,6 +267,7 @@ struct ares_options {
   void *sock_state_cb_data;
   struct apattern *sortlist;
   int nsort;
+  int ednspsz;
 };
 
 struct hostent;
@@ -403,6 +406,15 @@ CARES_EXTERN void ares_process_fd(ares_channel channel,
                                   ares_socket_t read_fd,
                                   ares_socket_t write_fd);
 
+CARES_EXTERN int ares_create_query(const char *name,
+                                   int dnsclass,
+                                   int type,
+                                   unsigned short id,
+                                   int rd,
+                                   unsigned char **buf,
+                                   int *buflen,
+                                   int max_udp_size);
+
 CARES_EXTERN int ares_mkquery(const char *name,
                               int dnsclass,
                               int type,
diff --git a/ares_create_query.3 b/ares_create_query.3
new file mode 100644 (file)
index 0000000..d01b8d8
--- /dev/null
@@ -0,0 +1,79 @@
+.\"
+.\" Copyright 1998, 2000 by the Massachusetts Institute of Technology.
+.\"
+.\" Permission to use, copy, modify, and distribute this
+.\" software and its documentation for any purpose and without
+.\" fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright
+.\" notice and this permission notice appear in supporting
+.\" documentation, and that the name of M.I.T. not be used in
+.\" advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.TH ARES_CREATE_QUERY 3 "20 Nov 2009"
+.SH NAME
+ares_create_query \- Compose a single-question DNS query buffer
+.SH SYNOPSIS
+.nf
+.B #include <ares.h>
+.PP
+.B int ares_create_query(const char *\fIname\fP, int \fIdnsclass\fP,\
+                         int \fItype\fP,
+.B                                unsigned short \fIid\fP, int \fIrd\fP,\
+                         unsigned char **\fIbuf\fP,
+.B                                int *\fIbuflen\fP, int \fImax_udp_size\fP)
+.fi
+.SH DESCRIPTION
+The
+.B ares_create_query
+function composes a DNS query with a single question.
+The parameter
+.I name
+gives the query name as a NUL-terminated C string of period-separated
+labels optionally ending with a period; periods and backslashes within
+a label must be escaped with a backlash.  The parameters
+.I dnsclass
+and
+.I type
+give the class and type of the query using the values defined in
+.BR <arpa/nameser.h> .
+The parameter
+.I id
+gives a 16-bit identifier for the query.  The parameter
+.I rd
+should be nonzero if recursion is desired, zero if not.  The query
+will be placed in an allocated buffer, a pointer to which will be
+stored in the variable pointed to by
+.IR buf ,
+and the length of which will be stored in the variable pointed to by
+.IR buflen .
+It is the caller's responsibility to free this buffer using
+\fIares_free_string(3)\fP when it is no longer needed.
+The parameter
+.I max_udp_size
+should be nonzero to activate EDNS. Usage of \fIares_create_query(3)\fP\ with
+.I max_udp_size
+set to zero is equivalent to \fIares_mkquery(3)\fP.
+.SH RETURN VALUES
+.B ares_create_query
+can return any of the following values:
+.TP 15
+.B ARES_SUCCESS
+Construction of the DNS query succeeded.
+.TP 15
+.B ARES_EBADNAME
+The query name
+.I name
+could not be encoded as a domain name, either because it contained a
+zero-length label or because it contained a label of more than 63
+characters.
+.TP 15
+.B ARES_ENOMEM
+Memory was exhausted.
+.SH SEE ALSO
+.BR ares_expand_name (3),
+.BR ares_free_string (3)
+.SH AUTHOR
diff --git a/ares_create_query.c b/ares_create_query.c
new file mode 100644 (file)
index 0000000..ef48ad8
--- /dev/null
@@ -0,0 +1,209 @@
+
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#include "ares_setup.h"
+
+#ifdef HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#  include <arpa/nameser.h>
+#else
+#  include "nameser.h"
+#endif
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+#  include <arpa/nameser_compat.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "ares.h"
+#include "ares_dns.h"
+#include "ares_private.h"
+
+/* Header format, from RFC 1035:
+ *                                  1  1  1  1  1  1
+ *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *  |                      ID                       |
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *  |                    QDCOUNT                    |
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *  |                    ANCOUNT                    |
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *  |                    NSCOUNT                    |
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *  |                    ARCOUNT                    |
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *
+ * AA, TC, RA, and RCODE are only set in responses.  Brief description
+ * of the remaining fields:
+ *      ID      Identifier to match responses with queries
+ *      QR      Query (0) or response (1)
+ *      Opcode  For our purposes, always QUERY
+ *      RD      Recursion desired
+ *      Z       Reserved (zero)
+ *      QDCOUNT Number of queries
+ *      ANCOUNT Number of answers
+ *      NSCOUNT Number of name server records
+ *      ARCOUNT Number of additional records
+ *
+ * Question format, from RFC 1035:
+ *                                  1  1  1  1  1  1
+ *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *  |                                               |
+ *  /                     QNAME                     /
+ *  /                                               /
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *  |                     QTYPE                     |
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *  |                     QCLASS                    |
+ *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ *
+ * The query name is encoded as a series of labels, each represented
+ * as a one-byte length (maximum 63) followed by the text of the
+ * label.  The list is terminated by a label of length zero (which can
+ * be thought of as the root domain).
+ */
+
+int ares_create_query(const char *name, int dnsclass, int type,
+                      unsigned short id, int rd, unsigned char **buf,
+                      int *buflen, int max_udp_size)
+{
+  int len;
+  unsigned char *q;
+  const char *p;
+
+  /* Set our results early, in case we bail out early with an error. */
+  *buflen = 0;
+  *buf = NULL;
+
+  /* Compute the length of the encoded name so we can check buflen.
+   * Start counting at 1 for the zero-length label at the end. */
+  len = 1;
+  for (p = name; *p; p++)
+    {
+      if (*p == '\\' && *(p + 1) != 0)
+        p++;
+      len++;
+    }
+  /* If there are n periods in the name, there are n + 1 labels, and
+   * thus n + 1 length fields, unless the name is empty or ends with a
+   * period.  So add 1 unless name is empty or ends with a period.
+   */
+  if (*name && *(p - 1) != '.')
+    len++;
+
+  /* Immediately reject names that are longer than the maximum of 255
+   * bytes that's specified in RFC 1035 ("To simplify implementations,
+   * the total length of a domain name (i.e., label octets and label
+   * length octets) is restricted to 255 octets or less."). We aren't
+   * doing this just to be a stickler about RFCs. For names that are
+   * too long, 'dnscache' closes its TCP connection to us immediately
+   * (when using TCP) and ignores the request when using UDP, and
+   * BIND's named returns ServFail (TCP or UDP). Sending a request
+   * that we know will cause 'dnscache' to close the TCP connection is
+   * painful, since that makes any other outstanding requests on that
+   * connection fail. And sending a UDP request that we know
+   * 'dnscache' will ignore is bad because resources will be tied up
+   * until we time-out the request.
+   */
+  if (len > MAXCDNAME)
+    return ARES_EBADNAME;
+
+  *buflen = len + HFIXEDSZ + QFIXEDSZ + (max_udp_size ? EDNSFIXEDSZ : 0);
+  *buf = malloc(*buflen);
+  if (!*buf)
+      return ARES_ENOMEM;
+
+  /* Set up the header. */
+  q = *buf;
+  memset(q, 0, HFIXEDSZ);
+  DNS_HEADER_SET_QID(q, id);
+  DNS_HEADER_SET_OPCODE(q, QUERY);
+  if (rd) {
+    DNS_HEADER_SET_RD(q, 1);
+  }
+  else {
+    DNS_HEADER_SET_RD(q, 0);
+  }
+  DNS_HEADER_SET_QDCOUNT(q, 1);
+
+  if (max_udp_size) {
+      DNS_HEADER_SET_ARCOUNT(q, 1);
+  }
+
+  /* A name of "." is a screw case for the loop below, so adjust it. */
+  if (strcmp(name, ".") == 0)
+    name++;
+
+  /* Start writing out the name after the header. */
+  q += HFIXEDSZ;
+  while (*name)
+    {
+      if (*name == '.')
+        return ARES_EBADNAME;
+
+      /* Count the number of bytes in this label. */
+      len = 0;
+      for (p = name; *p && *p != '.'; p++)
+        {
+          if (*p == '\\' && *(p + 1) != 0)
+            p++;
+          len++;
+        }
+      if (len > MAXLABEL)
+        return ARES_EBADNAME;
+
+      /* Encode the length and copy the data. */
+      *q++ = (unsigned char)len;
+      for (p = name; *p && *p != '.'; p++)
+        {
+          if (*p == '\\' && *(p + 1) != 0)
+            p++;
+          *q++ = *p;
+        }
+
+      /* Go to the next label and repeat, unless we hit the end. */
+      if (!*p)
+        break;
+      name = p + 1;
+    }
+
+  /* Add the zero-length label at the end. */
+  *q++ = 0;
+
+  /* Finish off the question with the type and class. */
+  DNS_QUESTION_SET_TYPE(q, type);
+  DNS_QUESTION_SET_CLASS(q, dnsclass);
+
+  if (max_udp_size)
+  {
+      q += QFIXEDSZ;
+      memset(q, 0, EDNSFIXEDSZ);
+      q++;
+      DNS_RR_SET_TYPE(q, ns_t_opt);
+      DNS_RR_SET_CLASS(q, max_udp_size);
+  }
+
+  return ARES_SUCCESS;
+}
index 34cf790df78aa096471b68c813e9b61477e002f2..79f993b9048d08168dca564157ffd8d26be775ee 100644 (file)
@@ -95,9 +95,9 @@
 #define DNS_RR_LEN(r)                   DNS__16BIT((r) + 8)
 
 /* Macros for constructing the fixed part of a DNS resource record */
-#define DNS_RR_SET_TYPE(r)              DNS__SET16BIT(r, v)
-#define DNS_RR_SET_CLASS(r)             DNS__SET16BIT((r) + 2, v)
-#define DNS_RR_SET_TTL(r)               DNS__SET32BIT((r) + 4, v)
-#define DNS_RR_SET_LEN(r)               DNS__SET16BIT((r) + 8, v)
+#define DNS_RR_SET_TYPE(r, v)           DNS__SET16BIT(r, v)
+#define DNS_RR_SET_CLASS(r, v)          DNS__SET16BIT((r) + 2, v)
+#define DNS_RR_SET_TTL(r, v)            DNS__SET32BIT((r) + 4, v)
+#define DNS_RR_SET_LEN(r, v)            DNS__SET16BIT((r) + 8, v)
 
 #endif /* HEADER_CARES_DNS_H */
index f9eb05450037d112f547aced084f6a1dfbc33175..a94a917ce0d5ddfa3e1290db5efdbd1b060f6a1a 100644 (file)
@@ -163,6 +163,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   channel->rotate = -1;
   channel->udp_port = -1;
   channel->tcp_port = -1;
+  channel->ednspsz = -1;
   channel->socket_send_buffer_size = -1;
   channel->socket_receive_buffer_size = -1;
   channel->nservers = -1;
@@ -453,6 +454,9 @@ static int init_by_options(ares_channel channel,
       && channel->socket_receive_buffer_size == -1)
     channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
 
+  if ((optmask & ARES_OPT_EDNSPSZ) && channel->ednspsz == -1)
+    channel->ednspsz = options->ednspsz;
+
   /* Copy the IPv4 servers, if given. */
   if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
     {
@@ -1358,6 +1362,9 @@ static int init_by_defaults(ares_channel channel)
   if (channel->tcp_port == -1)
     channel->tcp_port = htons(NAMESERVER_PORT);
 
+  if (channel->ednspsz == -1)
+    channel->ednspsz = EDNSPACKETSZ;
+
   if (channel->nservers == -1) {
     /* If nobody specified servers, try a local named. */
     channel->servers = malloc(sizeof(struct server_state));
index f7c5413612b45e2e98442b3b1db43a06b2afd36f..b2c90a93912508e9437624d50bd5de6ee841a831 100644 (file)
@@ -25,6 +25,8 @@ ares_mkquery \- Compose a single-question DNS query buffer
 .B     int *\fIbuflen\fP)
 .fi
 .SH DESCRIPTION
+Deprecated function. See \fIares_create_query(3)\fP instead!
+
 The
 .B ares_mkquery
 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
 .IR buflen .
 It is the caller's responsibility to free this buffer using
 \fIares_free_string(3)\fP when it is no longer needed.
+
+Usage of \fIares_mkquery(3)\fP is deprecated, whereas the function is
+equivalent to \fIares_create_query(3)\fP with \fBmax_udp_size\fP set to
+0.
+
 .SH RETURN VALUES
 .B ares_mkquery
 can return any of the following values:
index e33f13ff223216f263dd8e84434e629862d685bc..5aea914bd0ed8f1c40ebdf9726ec349e88ecf953 100644 (file)
  */
 
 #include "ares_setup.h"
-
-#ifdef HAVE_SYS_SOCKET_H
-#  include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#  include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_NAMESER_H
-#  include <arpa/nameser.h>
-#else
-#  include "nameser.h"
-#endif
-#ifdef HAVE_ARPA_NAMESER_COMPAT_H
-#  include <arpa/nameser_compat.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
 #include "ares.h"
-#include "ares_dns.h"
-#include "ares_private.h"
-
-/* Header format, from RFC 1035:
- *                                  1  1  1  1  1  1
- *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |                      ID                       |
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |                    QDCOUNT                    |
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |                    ANCOUNT                    |
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |                    NSCOUNT                    |
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |                    ARCOUNT                    |
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *
- * AA, TC, RA, and RCODE are only set in responses.  Brief description
- * of the remaining fields:
- *      ID      Identifier to match responses with queries
- *      QR      Query (0) or response (1)
- *      Opcode  For our purposes, always QUERY
- *      RD      Recursion desired
- *      Z       Reserved (zero)
- *      QDCOUNT Number of queries
- *      ANCOUNT Number of answers
- *      NSCOUNT Number of name server records
- *      ARCOUNT Number of additional records
- *
- * Question format, from RFC 1035:
- *                                  1  1  1  1  1  1
- *    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |                                               |
- *  /                     QNAME                     /
- *  /                                               /
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |                     QTYPE                     |
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *  |                     QCLASS                    |
- *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- *
- * The query name is encoded as a series of labels, each represented
- * as a one-byte length (maximum 63) followed by the text of the
- * label.  The list is terminated by a label of length zero (which can
- * be thought of as the root domain).
- */
 
 int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
                  int rd, unsigned char **buf, int *buflen)
 {
-  int len;
-  unsigned char *q;
-  const char *p;
-
-  /* Set our results early, in case we bail out early with an error. */
-  *buflen = 0;
-  *buf = NULL;
-
-  /* Compute the length of the encoded name so we can check buflen.
-   * Start counting at 1 for the zero-length label at the end. */
-  len = 1;
-  for (p = name; *p; p++)
-    {
-      if (*p == '\\' && *(p + 1) != 0)
-        p++;
-      len++;
-    }
-  /* If there are n periods in the name, there are n + 1 labels, and
-   * thus n + 1 length fields, unless the name is empty or ends with a
-   * period.  So add 1 unless name is empty or ends with a period.
-   */
-  if (*name && *(p - 1) != '.')
-    len++;
-
-  /* Immediately reject names that are longer than the maximum of 255
-   * bytes that's specified in RFC 1035 ("To simplify implementations,
-   * the total length of a domain name (i.e., label octets and label
-   * length octets) is restricted to 255 octets or less."). We aren't
-   * doing this just to be a stickler about RFCs. For names that are
-   * too long, 'dnscache' closes its TCP connection to us immediately
-   * (when using TCP) and ignores the request when using UDP, and
-   * BIND's named returns ServFail (TCP or UDP). Sending a request
-   * that we know will cause 'dnscache' to close the TCP connection is
-   * painful, since that makes any other outstanding requests on that
-   * connection fail. And sending a UDP request that we know
-   * 'dnscache' will ignore is bad because resources will be tied up
-   * until we time-out the request.
-   */
-  if (len > MAXCDNAME)
-    return ARES_EBADNAME;
-
-  *buflen = len + HFIXEDSZ + QFIXEDSZ;
-  *buf = malloc(*buflen);
-  if (!*buf)
-      return ARES_ENOMEM;
-
-  /* Set up the header. */
-  q = *buf;
-  memset(q, 0, HFIXEDSZ);
-  DNS_HEADER_SET_QID(q, id);
-  DNS_HEADER_SET_OPCODE(q, QUERY);
-  if (rd) {
-    DNS_HEADER_SET_RD(q, 1);
-  }
-  else {
-    DNS_HEADER_SET_RD(q, 0);
-  }
-  DNS_HEADER_SET_QDCOUNT(q, 1);
-
-  /* A name of "." is a screw case for the loop below, so adjust it. */
-  if (strcmp(name, ".") == 0)
-    name++;
-
-  /* Start writing out the name after the header. */
-  q += HFIXEDSZ;
-  while (*name)
-    {
-      if (*name == '.')
-        return ARES_EBADNAME;
-
-      /* Count the number of bytes in this label. */
-      len = 0;
-      for (p = name; *p && *p != '.'; p++)
-        {
-          if (*p == '\\' && *(p + 1) != 0)
-            p++;
-          len++;
-        }
-      if (len > MAXLABEL)
-        return ARES_EBADNAME;
-
-      /* Encode the length and copy the data. */
-      *q++ = (unsigned char)len;
-      for (p = name; *p && *p != '.'; p++)
-        {
-          if (*p == '\\' && *(p + 1) != 0)
-            p++;
-          *q++ = *p;
-        }
-
-      /* Go to the next label and repeat, unless we hit the end. */
-      if (!*p)
-        break;
-      name = p + 1;
-    }
-
-  /* Add the zero-length label at the end. */
-  *q++ = 0;
-
-  /* Finish off the question with the type and class. */
-  DNS_QUESTION_SET_TYPE(q, type);
-  DNS_QUESTION_SET_CLASS(q, dnsclass);
-
-  return ARES_SUCCESS;
+  return ares_create_query(name, dnsclass, type, id, rd, buf, buflen, 0);
 }
index 3c56bbcf3b2128e99f372102b1d4680c8fcf7816..8c8a08f0cbae44be7f0abb07739e2bb519cf303e 100644 (file)
 #  define writev(s,ptr,cnt) ares_writev(s,ptr,cnt)
 #endif
 
+/********* EDNS defines section ******/
+#define EDNSPACKETSZ   1280  /* Reasonable UDP payload size, as suggested
+                                in RFC2671 */
+#define MAXENDSSZ      4096  /* Maximum (local) limit for edns packet size */
+#define EDNSFIXEDSZ    11    /* Size of EDNS header */
+/********* EDNS defines section ******/
+
 struct ares_addr {
   int family;
   union {
@@ -260,6 +267,7 @@ struct ares_channeldata {
   struct apattern *sortlist;
   int nsort;
   char *lookups;
+  int ednspsz;
 
   /* For binding to local devices and/or IP addresses.  Leave
    * them null/zero for no binding.
index 0d29d002b038f033bde3a58001ee81fe5b47a729..b7c0bca29fe75f9d2b2a8d4c55af3baf13357979 100644 (file)
@@ -430,7 +430,7 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
   struct server_state *server;
   int i;
   ssize_t count;
-  unsigned char buf[PACKETSZ + 1];
+  unsigned char buf[MAXENDSSZ + 1];
 #ifdef HAVE_RECVFROM
   ares_socklen_t fromlen;
   union {
@@ -541,7 +541,7 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
                            int alen, int whichserver, int tcp,
                            struct timeval *now)
 {
-  int tc, rcode;
+  int tc, rcode, packetsz;
   unsigned short id;
   struct query *query;
   struct list_node* list_head;
@@ -578,11 +578,34 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
   if (!query)
     return;
 
+  packetsz = PACKETSZ;
+  /* If we use EDNS and server answers with one of these RCODES, the protocol
+   * extension is not understood by the responder. We must retry the query
+   * without EDNS enabled.
+   */
+  if (channel->flags & ARES_FLAG_EDNS)
+  {
+      packetsz = channel->ednspsz;
+      if (rcode == NOTIMP || rcode == FORMERR || rcode == SERVFAIL)
+      {
+          int qlen = alen - EDNSFIXEDSZ;
+          channel->flags ^= ARES_FLAG_EDNS;
+          query->tcplen -= EDNSFIXEDSZ;
+          query->qlen -= EDNSFIXEDSZ;
+          query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff);
+          query->tcpbuf[1] = (unsigned char)(qlen & 0xff);
+          DNS_HEADER_SET_ARCOUNT(query->tcpbuf + 2, 0);
+          query->tcpbuf = realloc(query->tcpbuf, query->tcplen);
+          ares__send_query(channel, query, now);
+          return;
+      }
+  }
+
   /* If we got a truncated UDP packet and are not ignoring truncation,
    * don't accept the packet, and switch the query to TCP if we hadn't
    * done so already.
    */
-  if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
+  if ((tc || alen > packetsz) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
     {
       if (!query->using_tcp)
         {
@@ -595,8 +618,8 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
   /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we
    * are ignoring truncation.
    */
-  if (alen > PACKETSZ && !tcp)
-    alen = PACKETSZ;
+  if (alen > packetsz && !tcp)
+      alen = packetsz;
 
   /* If we aren't passing through all error packets, discard packets
    * with SERVFAIL, NOTIMP, or REFUSED response codes.
index 63652e229d274b6eba21ad076399c979318f5ac2..ed6b6e87a87a34247dfa910aa5e1125426fad13a 100644 (file)
@@ -114,8 +114,8 @@ void ares_query(ares_channel channel, const char *name, int dnsclass,
 
   /* Compose the query. */
   rd = !(channel->flags & ARES_FLAG_NORECURSE);
-  status = ares_mkquery(name, dnsclass, type, channel->next_id, rd, &qbuf,
-                        &qlen);
+  status = ares_create_query(name, dnsclass, type, channel->next_id, rd, &qbuf,
+              &qlen, (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : 0);
   if (status != ARES_SUCCESS)
     {
       if (qbuf != NULL) free(qbuf);
index 75a84f687e592106b913d10fe483f03d89a208a8..d3f734fdacf7035e2626b92fe40b01074587311c 100644 (file)
@@ -42,7 +42,7 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
                ares_callback callback, void *arg)
 {
   struct query *query;
-  int i;
+  int i, packetsz;
   struct timeval now;
 
   /* 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,
       query->server_info[i].skip_server = 0;
       query->server_info[i].tcp_connection_generation = 0;
     }
-  query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ;
+
+  packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ;
+  query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > packetsz;
+
   query->error_status = ARES_ECONNREFUSED;
   query->timeouts = 0;