Query A records before AAAA records in getaddrinfo() when AF_UNSPEC
authorHiroki Sato <hrs@dragonflybsd.org>
Wed, 2 Feb 2005 15:10:55 +0000 (15:10 +0000)
committerHiroki Sato <hrs@dragonflybsd.org>
Wed, 2 Feb 2005 15:10:55 +0000 (15:10 +0000)
is specified.  Some broken DNS servers return NXDOMAIN against
non-existent AAAA queries, even when it should return NOERROR
with empty return records.  This is a problem for an IPv4/IPv6 dual
stack node since the NXDOMAIN returned by the first query of
an AAAA record makes it give up querying the A record.  Also, this
behavior has been recognized as a potential denial-of-service attack.

Note that although the query order has been changed, the result
linked-list of (struct addrinfo) set by getaddrinfo() is still
in order of AF_INET6 -> AF_INET.

Reference: http://www.kb.cert.org/vuls/id/714121

lib/libc/net/getaddrinfo.c

index f1cfafc..dcc71e8 100644 (file)
@@ -1,5 +1,5 @@
 /*     $FreeBSD: src/lib/libc/net/getaddrinfo.c,v 1.9.2.14 2002/11/08 17:49:31 ume Exp $       */
-/*     $DragonFly: src/lib/libc/net/getaddrinfo.c,v 1.4 2005/01/31 22:29:33 dillon Exp $       */
+/*     $DragonFly: src/lib/libc/net/getaddrinfo.c,v 1.5 2005/02/02 15:10:55 hrs Exp $  */
 /*     $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $    */
 
 /*
@@ -1519,16 +1519,15 @@ _dns_getaddrinfo(pai, hostname, res)
 
        switch (pai->ai_family) {
        case AF_UNSPEC:
-               /* prefer IPv6 */
                q.name = name;
                q.qclass = C_IN;
-               q.qtype = T_AAAA;
+               q.qtype = T_A;
                q.answer = buf->buf;
                q.anslen = sizeof(buf->buf);
                q.next = &q2;
                q2.name = name;
                q2.qclass = C_IN;
-               q2.qtype = T_A;
+               q2.qtype = T_AAAA;
                q2.answer = buf2->buf;
                q2.anslen = sizeof(buf2->buf);
                break;
@@ -1556,17 +1555,19 @@ _dns_getaddrinfo(pai, hostname, res)
                free(buf2);
                return EAI_NODATA;
        }
-       ai = getanswer(buf, q.n, q.name, q.qtype, pai);
-       if (ai) {
-               cur->ai_next = ai;
-               while (cur && cur->ai_next)
-                       cur = cur->ai_next;
-       }
+       /* prefer IPv6 */
        if (q.next) {
                ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
-               if (ai)
+               if (ai) {
                        cur->ai_next = ai;
+                       while (cur && cur->ai_next)
+                               cur = cur->ai_next;
+               }
        }
+
+       ai = getanswer(buf, q.n, q.name, q.qtype, pai);
+       if (ai)
+               cur->ai_next = ai;
        free(buf);
        free(buf2);
        if (sentinel.ai_next == NULL)