* resolv/res_init.c (res_setoptions): Recognize edns0 option.
authorUlrich Drepper <drepper@redhat.com>
Fri, 9 Feb 2007 23:46:29 +0000 (23:46 +0000)
committerUlrich Drepper <drepper@redhat.com>
Fri, 9 Feb 2007 23:46:29 +0000 (23:46 +0000)
* resolv/res_mkquery.c: Define __res_nopt.
* resolv/res_query.c (__libc_res_nquery): If RES_USE_EDNS0 is set
try adding EDNS0 record.
* resolv/res_send.c (send_dg): If request failed with FORMERR and
EDNS0 record was send make sure we don't try it again.
* resolv/resolv.h: Define RES_F_EDNS0ERR and RES_USE_EDNS0.
* include/resolv.h: Declare __res_nopt.

ChangeLog
include/resolv.h
resolv/res_init.c
resolv/res_mkquery.c
resolv/res_query.c
resolv/res_send.c
resolv/resolv.h

index 070da56..f1b6d3d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2007-02-09  Ulrich Drepper  <drepper@redhat.com>
+
+       * resolv/res_init.c (res_setoptions): Recognize edns0 option.
+       * resolv/res_mkquery.c: Define __res_nopt.
+       * resolv/res_query.c (__libc_res_nquery): If RES_USE_EDNS0 is set
+       try adding EDNS0 record.
+       * resolv/res_send.c (send_dg): If request failed with FORMERR and
+       EDNS0 record was send make sure we don't try it again.
+       * resolv/resolv.h: Define RES_F_EDNS0ERR and RES_USE_EDNS0.
+       * include/resolv.h: Declare __res_nopt.
+
 2007-02-08  Jakub Jelinek  <jakub@redhat.com>
 
        [BZ #3944]
index 189e4fb..c1c89f0 100644 (file)
@@ -48,6 +48,8 @@ extern void res_send_setrhook (res_send_rhook __hook);
 extern int res_ourserver_p (const res_state __statp,
                            const struct sockaddr_in6 *__inp);
 extern void __res_iclose (res_state statp, bool free_addr);
+extern int __res_nopt(res_state statp, int n0, u_char *buf, int buflen,
+                     int anslen);
 libc_hidden_proto (__res_ninit)
 libc_hidden_proto (__res_maybe_init)
 libc_hidden_proto (__res_nclose)
@@ -100,6 +102,7 @@ libresolv_hidden_proto (__ns_name_ntop)
 libresolv_hidden_proto (__ns_name_unpack)
 libresolv_hidden_proto (__ns_get16)
 libresolv_hidden_proto (__ns_get32)
+libresolv_hidden_proto (__res_nopt)
 
 extern const char *_res_opcodes[];
 libresolv_hidden_proto (_res_opcodes)
index b5a03d1..640e087 100644 (file)
@@ -510,6 +510,8 @@ res_setoptions(res_state statp, const char *options, const char *source) {
                } else if (!strncmp(cp, "no-check-names",
                                    sizeof("no-check-names") - 1)) {
                        statp->options |= RES_NOCHECKNAME;
+                } else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
+                       statp->options |= RES_USE_EDNS0;
                } else {
                        /* XXX - print a warning here? */
                }
index fd80569..3fa597f 100644 (file)
@@ -208,3 +208,49 @@ res_nmkquery(res_state statp,
        return (cp - buf);
 }
 libresolv_hidden_def (res_nmkquery)
+
+
+/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
+#ifndef T_OPT
+#define T_OPT   41
+#endif
+
+int
+__res_nopt(res_state statp,
+          int n0,                /* current offset in buffer */
+          u_char *buf,           /* buffer to put query */
+          int buflen,            /* size of buffer */
+          int anslen)            /* UDP answer buffer size */
+{
+       u_int16_t flags = 0;
+
+#ifdef DEBUG
+       if ((statp->options & RES_DEBUG) != 0U)
+               printf(";; res_nopt()\n");
+#endif
+
+       HEADER *hp = (HEADER *) buf;
+       u_char *cp = buf + n0;
+       u_char *ep = buf + buflen;
+
+       if ((ep - cp) < 1 + RRFIXEDSZ)
+               return -1;
+
+       *cp++ = 0;      /* "." */
+
+       ns_put16(T_OPT, cp);    /* TYPE */
+       cp += INT16SZ;
+       ns_put16(anslen & 0xffff, cp);  /* CLASS = UDP payload size */
+       cp += INT16SZ;
+       *cp++ = NOERROR;        /* extended RCODE */
+       *cp++ = 0;              /* EDNS version */
+       /* XXX Once we support DNSSEC we change the flag value here.  */
+       ns_put16(flags, cp);
+       cp += INT16SZ;
+       ns_put16(0, cp);        /* RDLEN */
+       cp += INT16SZ;
+       hp->arcount = htons(ntohs(hp->arcount) + 1);
+
+       return cp - buf;
+}
+libresolv_hidden_def (__res_nopt)
index 85bad97..4371af5 100644 (file)
@@ -120,10 +120,13 @@ __libc_res_nquery(res_state statp,
        u_char *buf;
        HEADER *hp = (HEADER *) answer;
        int n, use_malloc = 0;
+        u_int oflags = statp->_flags;
 
-       hp->rcode = NOERROR;    /* default */
+       size_t bufsize = QUERYSIZE;
+       buf = alloca (bufsize);
 
-       buf = alloca (QUERYSIZE);
+ again:
+       hp->rcode = NOERROR;    /* default */
 
 #ifdef DEBUG
        if (statp->options & RES_DEBUG)
@@ -131,18 +134,30 @@ __libc_res_nquery(res_state statp,
 #endif
 
        n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
-                        buf, QUERYSIZE);
-       if (__builtin_expect (n <= 0, 0)) {
+                        buf, bufsize);
+       if (n > 0
+           && (oflags & RES_F_EDNS0ERR) == 0
+           && (statp->options & RES_USE_EDNS0) != 0)
+               n = __res_nopt(statp, n, buf, bufsize, anslen);
+       if (__builtin_expect (n <= 0, 0) && !use_malloc) {
                /* Retry just in case res_nmkquery failed because of too
                   short buffer.  Shouldn't happen.  */
-               buf = malloc (MAXPACKET);
+               bufsize = MAXPACKET;
+               buf = malloc (bufsize);
                if (buf != NULL) {
                        use_malloc = 1;
-                       n = res_nmkquery(statp, QUERY, name, class, type, NULL,
-                                        0, NULL, buf, MAXPACKET);
+                       goto again;
                }
        }
        if (__builtin_expect (n <= 0, 0)) {
+               /* If the query choked with EDNS0, retry without EDNS0.  */
+               if ((statp->options & RES_USE_EDNS0) != 0
+                   && ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
+                       statp->_flags |= RES_F_EDNS0ERR;
+                       if (statp->options & RES_DEBUG)
+                               printf(";; res_nquery: retry without EDNS0\n");
+                        goto again;
+               }
 #ifdef DEBUG
                if (statp->options & RES_DEBUG)
                        printf(";; res_query: mkquery failed\n");
index 887d048..f38c399 100644 (file)
@@ -986,6 +986,24 @@ send_dg(res_state statp,
                                ans, (resplen > anssiz) ? anssiz : resplen);
                        goto wait;
                }
+#ifdef RES_USE_EDNS0
+               if (anhp->rcode == FORMERR
+                   && (statp->options & RES_USE_EDNS0) != 0U) {
+                       /*
+                        * Do not retry if the server do not understand
+                        * EDNS0.  The case has to be captured here, as
+                        * FORMERR packet do not carry query section, hence
+                        * res_queriesmatch() returns 0.
+                        */
+                       DprintQ(statp->options & RES_DEBUG,
+                               (stdout,
+                                "server rejected query with EDNS0:\n"),
+                               ans, (resplen > anssiz) ? anssiz : resplen);
+                       /* record the error */
+                       statp->_flags |= RES_F_EDNS0ERR;
+                       goto err_out;
+        }
+#endif
                if (!(statp->options & RES_INSECURE2) &&
                    !res_queriesmatch(buf, buf + buflen,
                                      ans, ans + anssiz)) {
index d7cda11..9aa09b8 100644 (file)
@@ -180,6 +180,7 @@ struct res_sym {
  */
 #define        RES_F_VC        0x00000001      /* socket is TCP */
 #define        RES_F_CONN      0x00000002      /* socket is connected */
+#define RES_F_EDNS0ERR 0x00000004      /* EDNS0 caused errors */
 
 /* res_findzonecut() options */
 #define        RES_EXHAUSTIVE  0x00000001      /* always do all queries */
@@ -209,6 +210,7 @@ struct res_sym {
                                           strings */
 #define RES_NOIP6DOTINT        0x00080000      /* Do not use .ip6.int in IPv6
                                           reverse lookup */
+#define RES_USE_EDNS0  0x00100000      /* Use EDNS0.  */
 
 #define RES_DEFAULT    (RES_RECURSE|RES_DEFNAMES|RES_DNSRCH|RES_NOIP6DOTINT)