]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1280. [func] libbind: res_update can now update IPv6 servers,
authorMark Andrews <marka@isc.org>
Mon, 6 May 2002 04:12:55 +0000 (04:12 +0000)
committerMark Andrews <marka@isc.org>
Mon, 6 May 2002 04:12:55 +0000 (04:12 +0000)
                        new function res_findzonecut2().

CHANGES
lib/bind/include/resolv.h
lib/bind/resolv/res_findzonecut.c
lib/bind/resolv/res_update.c

diff --git a/CHANGES b/CHANGES
index faae6c3b0911bfde52d9fc63e489ff2c97ee97be..107f9efe05b9566c647d9e1c19855d875cc5b346 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+1280.  [func]          libbind: res_update can now update IPv6 servers,
+                       new function res_findzonecut2().
+
 1279.  [bug]           libbind: get_salen() IPv6 support was broken for OSs
                        w/o sa_len.
 
index d5f752c4a84917cca01a05102153da9bc6776e97..4894a3b30260e0a34e7a4383a8ff0fa694f6c3a4 100644 (file)
@@ -50,7 +50,7 @@
 
 /*
  *     @(#)resolv.h    8.1 (Berkeley) 6/2/93
- *     $Id: resolv.h,v 1.13 2001/11/02 23:23:34 marka Exp $
+ *     $Id: resolv.h,v 1.14 2002/05/06 04:12:52 marka Exp $
  */
 
 #ifndef _RESOLV_H_
@@ -211,8 +211,10 @@ union res_sockaddr_union {
 #define        RES_F_CONN      0x00000002      /* socket is connected */
 #define        RES_F_EDNS0ERR  0x00000004      /* EDNS0 caused errors */
 
-/* res_findzonecut() options */
+/* res_findzonecut2() options */
 #define        RES_EXHAUSTIVE  0x00000001      /* always do all queries */
+#define        RES_IPV4ONLY    0x00000002      /* IPv4 only */
+#define        RES_IPV6ONLY    0x00000004      /* IPv6 only */
 
 /*
  * Resolver options (keep these in synch with res_debug.c, please)
@@ -353,6 +355,7 @@ extern const struct res_sym __p_rcode_syms[];
 #define putshort               __putshort
 #define res_dnok               __res_dnok
 #define res_findzonecut                __res_findzonecut
+#define res_findzonecut2       __res_findzonecut2
 #define res_hnok               __res_hnok
 #define res_hostalias          __res_hostalias
 #define res_mailok             __res_mailok
@@ -443,6 +446,9 @@ int         res_nsendsigned __P((res_state, const u_char *, int,
                                     ns_tsig_key *, u_char *, int));
 int            res_findzonecut __P((res_state, const char *, ns_class, int,
                                     char *, size_t, struct in_addr *, int));
+int            res_findzonecut2 __P((res_state, const char *, ns_class, int,
+                                     char *, size_t,
+                                     union res_sockaddr_union *, int));
 void           res_nclose __P((res_state));
 int            res_nopt __P((res_state, int, u_char *, int, int));
 void           res_send_setqhook __P((res_send_qhook hook));
index a67c42fb13a6263279a6b751749081b7015916e4..68a40499dc7c629259f409037a56ce5590c0d486 100644 (file)
@@ -1,5 +1,5 @@
 #if !defined(lint) && !defined(SABER)
-static const char rcsid[] = "$Id: res_findzonecut.c,v 1.3 2001/11/01 05:15:27 marka Exp $";
+static const char rcsid[] = "$Id: res_findzonecut.c,v 1.4 2002/05/06 04:12:55 marka Exp $";
 #endif /* not lint */
 
 /*
@@ -34,7 +34,6 @@ static const char rcsid[] = "$Id: res_findzonecut.c,v 1.3 2001/11/01 05:15:27 ma
 #include <errno.h>
 #include <limits.h>
 #include <netdb.h>
-#include <resolv.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -44,35 +43,40 @@ static const char rcsid[] = "$Id: res_findzonecut.c,v 1.3 2001/11/01 05:15:27 ma
 
 #include "port_after.h"
 
+#include <resolv.h>
+
 /* Data structures. */
 
 typedef struct rr_a {
        LINK(struct rr_a)       link;
-       struct in_addr          addr;
+       union res_sockaddr_union                addr;
 } rr_a;
 typedef LIST(rr_a) rrset_a;
 
 typedef struct rr_ns {
        LINK(struct rr_ns)      link;
        const char *            name;
+       int                     have_v4;
+       int                     have_v6;
        rrset_a                 addrs;
 } rr_ns;
 typedef LIST(rr_ns) rrset_ns;
 
 /* Forward. */
 
-static int     satisfy(res_state,
-                       const char *, rrset_ns *, struct in_addr *, int);
-static int     add_addrs(res_state, rr_ns *, struct in_addr *, int);
-static int     get_soa(res_state, const char *, ns_class,
+static int     satisfy(res_state, const char *, rrset_ns *,
+                       union res_sockaddr_union *, int);
+static int     add_addrs(res_state, rr_ns *,
+                         union res_sockaddr_union *, int);
+static int     get_soa(res_state, const char *, ns_class, int,
                        char *, size_t, char *, size_t,
                        rrset_ns *);
-static int     get_ns(res_state, const char *, ns_class, rrset_ns *);
-static int     get_glue(res_state, ns_class, rrset_ns *);
+static int     get_ns(res_state, const char *, ns_class, int, rrset_ns *);
+static int     get_glue(res_state, ns_class, int, rrset_ns *);
 static int     save_ns(res_state, ns_msg *, ns_sect,
-                       const char *, ns_class, rrset_ns *);
+                       const char *, ns_class, int, rrset_ns *);
 static int     save_a(res_state, ns_msg *, ns_sect,
-                      const char *, ns_class, rrset_a *);
+                      const char *, ns_class, int, rr_ns *);
 static void    free_nsrrset(rrset_ns *);
 static void    free_nsrr(rrset_ns *, rr_ns *);
 static rr_ns * find_ns(rrset_ns *, const char *);
@@ -145,7 +149,32 @@ static void        res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
 
 int
 res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
-               char *zname, size_t zsize, struct in_addr *addrs, int naddrs)
+               char *zname, size_t zsize, struct in_addr *addrs, int naddrs) {
+       int result, i;
+       union res_sockaddr_union *u;
+
+       
+       opts |= RES_IPV4ONLY;
+       opts &= ~RES_IPV6ONLY;
+
+       u = calloc(naddrs, sizeof(*u));
+       if (u == NULL)
+               return(-1);
+
+       result = res_findzonecut2(statp, dname, class, opts, zname, zsize,
+                                 u, naddrs);
+
+       for (i = 0; i < result; i++) {
+               addrs[i] = u[i].sin.sin_addr;
+       }
+       free(u);
+       return (result);
+}
+
+int
+res_findzonecut2(res_state statp, const char *dname, ns_class class, int opts,
+                char *zname, size_t zsize, union res_sockaddr_union *addrs,
+                int naddrs)
 {
        char mname[NS_MAXDNAME];
        u_long save_pfcode;
@@ -161,20 +190,20 @@ res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
        INIT_LIST(nsrrs);
 
        DPRINTF(("get the soa, and see if it has enough glue"));
-       if ((n = get_soa(statp, dname, class, zname, zsize,
+       if ((n = get_soa(statp, dname, class, opts, zname, zsize,
                         mname, sizeof mname, &nsrrs)) < 0 ||
            ((opts & RES_EXHAUSTIVE) == 0 &&
             (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
                goto done;
 
        DPRINTF(("get the ns rrset and see if it has enough glue"));
-       if ((n = get_ns(statp, zname, class, &nsrrs)) < 0 ||
+       if ((n = get_ns(statp, zname, class, opts, &nsrrs)) < 0 ||
            ((opts & RES_EXHAUSTIVE) == 0 &&
             (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
                goto done;
 
        DPRINTF(("get the missing glue and see if it's finally enough"));
-       if ((n = get_glue(statp, class, &nsrrs)) >= 0)
+       if ((n = get_glue(statp, class, opts, &nsrrs)) >= 0)
                n = satisfy(statp, mname, &nsrrs, addrs, naddrs);
 
  done:
@@ -187,8 +216,8 @@ res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
 /* Private. */
 
 static int
-satisfy(res_state statp,
-       const char *mname, rrset_ns *nsrrsp, struct in_addr *addrs, int naddrs)
+satisfy(res_state statp, const char *mname, rrset_ns *nsrrsp,
+       union res_sockaddr_union *addrs, int naddrs)
 {
        rr_ns *nsrr;
        int n, x;
@@ -215,7 +244,9 @@ satisfy(res_state statp,
 }
 
 static int
-add_addrs(res_state statp, rr_ns *nsrr, struct in_addr *addrs, int naddrs) {
+add_addrs(res_state statp, rr_ns *nsrr,
+         union res_sockaddr_union *addrs, int naddrs)
+{
        rr_a *arr;
        int n = 0;
 
@@ -231,7 +262,7 @@ add_addrs(res_state statp, rr_ns *nsrr, struct in_addr *addrs, int naddrs) {
 }
 
 static int
-get_soa(res_state statp, const char *dname, ns_class class,
+get_soa(res_state statp, const char *dname, ns_class class, int opts,
        char *zname, size_t zsize, char *mname, size_t msize,
        rrset_ns *nsrrsp)
 {
@@ -332,7 +363,7 @@ get_soa(res_state statp, const char *dname, ns_class class,
                                return (-1);
                        }
                        if (save_ns(statp, &msg, ns_s_ns,
-                                   zname, class, nsrrsp) < 0) {
+                                   zname, class, opts, nsrrsp) < 0) {
                                DPRINTF(("get_soa: save_ns failed"));
                                return (-1);
                        }
@@ -359,7 +390,9 @@ get_soa(res_state statp, const char *dname, ns_class class,
 }
 
 static int
-get_ns(res_state statp, const char *zname, ns_class class, rrset_ns *nsrrsp) {
+get_ns(res_state statp, const char *zname, ns_class class, int opts,
+      rrset_ns *nsrrsp)
+{
        u_char resp[NS_PACKETSZ];
        ns_msg msg;
        int n;
@@ -373,7 +406,7 @@ get_ns(res_state statp, const char *zname, ns_class class, rrset_ns *nsrrsp) {
        }
 
        /* Remember the NS RRs and associated A RRs that came back. */
-       if (save_ns(statp, &msg, ns_s_an, zname, class, nsrrsp) < 0) {
+       if (save_ns(statp, &msg, ns_s_an, zname, class, opts, nsrrsp) < 0) {
                DPRINTF(("get_ns save_ns('%s', %s) failed",
                         zname, p_class(class)));
                return (-1);
@@ -383,7 +416,7 @@ get_ns(res_state statp, const char *zname, ns_class class, rrset_ns *nsrrsp) {
 }
 
 static int
-get_glue(res_state statp, ns_class class, rrset_ns *nsrrsp) {
+get_glue(res_state statp, ns_class class, int opts, rrset_ns *nsrrsp) {
        rr_ns *nsrr, *nsrr_n;
 
        /* Go and get the A RRs for each empty NS RR on our list. */
@@ -394,7 +427,7 @@ get_glue(res_state statp, ns_class class, rrset_ns *nsrrsp) {
 
                nsrr_n = NEXT(nsrr, link);
 
-               if (EMPTY(nsrr->addrs)) {
+               if (!nsrr->have_v4) {
                        n = do_query(statp, nsrr->name, class, ns_t_a,
                                     resp, &msg);
                        if (n < 0) {
@@ -408,25 +441,47 @@ get_glue(res_state statp, ns_class class, rrset_ns *nsrrsp) {
                                         nsrr->name, p_class(class)));
                        }
                        if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
-                                  &nsrr->addrs) < 0) {
+                                  opts, nsrr) < 0) {
                                DPRINTF(("get_glue: save_r('%s', %s) failed",
                                         nsrr->name, p_class(class)));
                                return (-1);
                        }
-                       /* If it's still empty, it's just chaff. */
-                       if (EMPTY(nsrr->addrs)) {
-                               DPRINTF(("get_glue: removing empty '%s' NS",
-                                        nsrr->name));
-                               free_nsrr(nsrrsp, nsrr);
+               }
+
+               if (!nsrr->have_v6) {
+                       n = do_query(statp, nsrr->name, class, ns_t_aaaa,
+                                    resp, &msg);
+                       if (n < 0) {
+                               DPRINTF(("get_glue: do_query('%s', %s') failed",
+                                        nsrr->name, p_class(class)));
+                               return (-1);
+                       }
+                       if (n > 0) {
+                               DPRINTF((
+                       "get_glue: do_query('%s', %s') CNAME or DNAME found",
+                                        nsrr->name, p_class(class)));
+                       }
+                       if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+                                  opts, nsrr) < 0) {
+                               DPRINTF(("get_glue: save_r('%s', %s) failed",
+                                        nsrr->name, p_class(class)));
+                               return (-1);
                        }
                }
+
+               /* If it's still empty, it's just chaff. */
+               if (EMPTY(nsrr->addrs)) {
+                       DPRINTF(("get_glue: removing empty '%s' NS",
+                                nsrr->name));
+                       free_nsrr(nsrrsp, nsrr);
+               }
        }
        return (0);
 }
 
 static int
 save_ns(res_state statp, ns_msg *msg, ns_sect sect,
-       const char *owner, ns_class class,
+       const char *owner, ns_class class, int opts,
        rrset_ns *nsrrsp)
 {
        int i;
@@ -471,10 +526,12 @@ save_ns(res_state statp, ns_msg *msg, ns_sect sect,
                        }
                        INIT_LINK(nsrr, link);
                        INIT_LIST(nsrr->addrs);
+                       nsrr->have_v4 = 0;
+                       nsrr->have_v6 = 0;
                        APPEND(*nsrrsp, nsrr, link);
                }
                if (save_a(statp, msg, ns_s_ar,
-                          nsrr->name, class, &nsrr->addrs) < 0) {
+                          nsrr->name, class, opts, nsrr) < 0) {
                        DPRINTF(("save_ns: save_r('%s', %s) failed",
                                 nsrr->name, p_class(class)));
                        return (-1);
@@ -485,8 +542,8 @@ save_ns(res_state statp, ns_msg *msg, ns_sect sect,
 
 static int
 save_a(res_state statp, ns_msg *msg, ns_sect sect,
-       const char *owner, ns_class class,
-       rrset_a *arrsp)
+       const char *owner, ns_class class, int opts,
+       rr_ns *nsrr)
 {
        int i;
 
@@ -499,19 +556,46 @@ save_a(res_state statp, ns_msg *msg, ns_sect sect,
                                 p_section(sect, ns_o_query), i));
                        return (-1);
                }
-               if (ns_rr_type(rr) != ns_t_a ||
+               if ((ns_rr_type(rr) != ns_t_a && ns_rr_type(rr) != ns_t_aaaa) ||
                    ns_rr_class(rr) != class ||
                    ns_samename(ns_rr_name(rr), owner) != 1 ||
                    ns_rr_rdlen(rr) != NS_INADDRSZ)
                        continue;
+               if ((opts & RES_IPV6ONLY) != 0 && ns_rr_type(rr) != ns_t_aaaa)
+                       continue;
+               if ((opts & RES_IPV4ONLY) != 0 && ns_rr_type(rr) != ns_t_a)
+                       continue;
                arr = malloc(sizeof *arr);
                if (arr == NULL) {
                        DPRINTF(("save_a: malloc failed"));
                        return (-1);
                }
                INIT_LINK(arr, link);
-               memcpy(&arr->addr, ns_rr_rdata(rr), NS_INADDRSZ);
-               APPEND(*arrsp, arr, link);
+               memset(&arr->addr, 0, sizeof(arr->addr));
+               switch (ns_rr_type(rr)) {
+               case ns_t_a:
+                       arr->addr.sin.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+                       arr->addr.sin.sin_len = sizeof(arr->addr.sin);
+#endif
+                       memcpy(&arr->addr.sin.sin_addr, ns_rr_rdata(rr),
+                              NS_INADDRSZ);
+                       arr->addr.sin.sin_port = htons(NAMESERVER_PORT);
+                       nsrr->have_v4 = 1;
+                       break;
+               case ns_t_aaaa:
+                       arr->addr.sin6.sin6_family = AF_INET6;
+#ifdef HAVE_SA_LEN
+                       arr->addr.sin6.sin6_len = sizeof(arr->addr.sin6);
+#endif
+                       memcpy(&arr->addr.sin6.sin6_addr, ns_rr_rdata(rr), 16);
+                       arr->addr.sin.sin_port = htons(NAMESERVER_PORT);
+                       nsrr->have_v6 = 1;
+                       break;
+               default:
+                       abort();
+               }
+               APPEND(nsrr->addrs, arr, link);
        }
        return (0);
 }
index cf5234c72cd3fe1b8b90bae98596d0e83fd12c8f..221f62e09b0ccc7de81dc2c6a0f5004fd39291c5 100644 (file)
@@ -1,5 +1,5 @@
 #if !defined(lint) && !defined(SABER)
-static const char rcsid[] = "$Id: res_update.c,v 1.8 2002/02/26 05:03:10 marka Exp $";
+static const char rcsid[] = "$Id: res_update.c,v 1.9 2002/05/06 04:12:54 marka Exp $";
 #endif /* not lint */
 
 /*
@@ -103,34 +103,17 @@ res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
        memset(&tgrp, 0, sizeof (tgrp));
        for (rrecp = rrecp_in; rrecp;
             rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) {
-               struct in_addr addrs[MAXNS];
-               int i, nscnt;
-               /* XXX need to rewrite res_findzonecut */
-               for (i = 0; i < MAXNS; i++) {
-                       addrs[i].s_addr = 0;
-                       if (tgrp.z_nsaddrs[i].sin.sin_family == AF_INET)
-                               addrs[i] = tgrp.z_nsaddrs[i].sin.sin_addr;
-               }
+               int nscnt;
                /* Find the origin for it if there is one. */
                tgrp.z_class = rrecp->r_class;
-               nscnt = res_findzonecut(statp, rrecp->r_dname, tgrp.z_class,
-                                       RES_EXHAUSTIVE, tgrp.z_origin,
-                                       sizeof tgrp.z_origin, addrs, MAXNS);
+               nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class,
+                                        RES_EXHAUSTIVE, tgrp.z_origin,
+                                        sizeof tgrp.z_origin, 
+                                        tgrp.z_nsaddrs, MAXNS);
                if (nscnt <= 0) {
                        DPRINTF(("res_findzonecut failed (%d)", nscnt));
                        goto done;
                }
-               for (i = 0; i < nscnt; i++) {
-                       memset(&tgrp.z_nsaddrs[i], 0,
-                              sizeof(tgrp.z_nsaddrs[i]));
-                       tgrp.z_nsaddrs[i].sin.sin_addr = addrs[i];
-                       tgrp.z_nsaddrs[i].sin.sin_family = AF_INET;
-#ifdef HAVE_SA_LEN
-                       tgrp.z_nsaddrs[i].sin.sin_len =
-                                        sizeof(tgrp.z_nsaddrs[i].sin);
-#endif
-                       tgrp.z_nsaddrs[i].sin.sin_port = htons(53);
-               }
                tgrp.z_nscount = nscnt;
                /* Find the group for it if there is one. */
                for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link))