]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] allow setting local addr in dns_client
authorEvan Hunt <each@isc.org>
Wed, 13 Nov 2013 18:52:22 +0000 (10:52 -0800)
committerEvan Hunt <each@isc.org>
Wed, 13 Nov 2013 18:52:22 +0000 (10:52 -0800)
3672. [func] Local address can now be specified when using
dns_client API. [RT #34811]

CHANGES
bin/tests/system/resolver/ns1/named.conf
bin/tests/system/resolver/tests.sh [changed mode: 0644->0755]
lib/dns/client.c
lib/dns/include/dns/client.h
lib/samples/resolve.c

diff --git a/CHANGES b/CHANGES
index 04305d1a74c0675d07e72614e209e57b94cf6ada..a02ae9b3573c63583d00e69b0103049ed85c6d19 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+3672.  [func]          Local address can now be specified when using
+                       dns_client API. [RT #34811]
+
 3671.  [bug]           Don't allow dnssec-importkey overwrite a existing
                        non-imported private key.
 
index 411f4def357d64da844d38b7e349be3914ddc5d4..95d233e8c677300ddb25469556399f13845a13c3 100644 (file)
@@ -34,6 +34,7 @@ options {
        deny-answer-aliases { "example.org"; }
                except-from { "goodcname.example.net";
                              "gooddname.example.net"; };
+       allow-query {!10.53.0.8; any; };
 };
 
 zone "." {
old mode 100644 (file)
new mode 100755 (executable)
index 5e72fc0..189173f
@@ -39,6 +39,22 @@ echo "I:checking non-cachable NXDOMAIN response handling using dns_client"
    status=`expr $status + $ret`
 fi
 
+if [ -x ${RESOLVE} ] ; then
+echo "I:checking that local bound address can be set (Can't query from a denied address)"
+   ret=0
+   ${RESOLVE} -b 10.53.0.8 -p 5300 -t a -s 10.53.0.1 www.example.org 2> resolve.out || ret=1
+   grep "resolution failed: failure" resolve.out > /dev/null || ret=1
+   if [ $ret != 0 ]; then echo "I:failed"; fi
+   status=`expr $status + $ret`
+
+echo "I:checking that local bound address can be set (Can query from an allowed address)"
+   ret=0
+   ${RESOLVE} -b 10.53.0.1 -p 5300 -t a -s 10.53.0.1 www.example.org > resolve.out || ret=1
+   grep "www.example.org..*.192.0.2.1" resolve.out > /dev/null || ret=1
+   if [ $ret != 0 ]; then echo "I:failed"; fi
+   status=`expr $status + $ret`
+fi
+
 echo "I:checking non-cachable NODATA response handling"
 ret=0
 $DIG +tcp nodata.example.net @10.53.0.1 a -p 5300 > dig.out || ret=1
index e9e8bde28cdfaa67029c9a7e6b068b5d3cdf33d0..cee4fb268d71a28bdf18c082146d474178b2fd45 100644 (file)
@@ -249,13 +249,14 @@ static isc_result_t send_update(updatectx_t *uctx);
 static isc_result_t
 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
               isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
-              isc_boolean_t is_shared, dns_dispatch_t **dispp)
+              isc_boolean_t is_shared, dns_dispatch_t **dispp,
+              isc_sockaddr_t *localaddr)
 {
        unsigned int attrs, attrmask;
-       isc_sockaddr_t sa;
        dns_dispatch_t *disp;
        unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
        isc_result_t result;
+       isc_sockaddr_t anyaddr;
 
        attrs = 0;
        attrs |= DNS_DISPATCHATTR_UDP;
@@ -275,7 +276,10 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
        attrmask |= DNS_DISPATCHATTR_IPV4;
        attrmask |= DNS_DISPATCHATTR_IPV6;
 
-       isc_sockaddr_anyofpf(&sa, family);
+       if (localaddr == NULL) {
+               localaddr = &anyaddr;
+               isc_sockaddr_anyofpf(localaddr, family);
+       }
 
        buffersize = 4096;
        maxbuffers = is_shared ? 1000 : 8;
@@ -285,7 +289,7 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
 
        disp = NULL;
        result = dns_dispatch_getudp(dispatchmgr, socketmgr,
-                                    taskmgr, &sa,
+                                    taskmgr, localaddr,
                                     buffersize, maxbuffers, maxrequests,
                                     buckets, increment,
                                     attrs, attrmask, &disp);
@@ -421,6 +425,19 @@ isc_result_t
 dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
                   isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
                   unsigned int options, dns_client_t **clientp)
+{
+       isc_result_t result;
+       result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr,
+                                    options, clientp, NULL, NULL);
+       return (result);
+}
+
+isc_result_t
+dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
+                   isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr,
+                   isc_timermgr_t *timermgr, unsigned int options,
+                   dns_client_t **clientp, isc_sockaddr_t *localaddr4,
+                   isc_sockaddr_t *localaddr6)
 {
        dns_client_t *client;
        isc_result_t result;
@@ -460,17 +477,27 @@ dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
                goto cleanup;
        client->dispatchmgr = dispatchmgr;
 
-       /* TODO: whether to use dispatch v4 or v6 should be configurable */
+       /*
+        * If only one address family is specified, use it.
+        * If neither family is specified, or if both are, use both.
+        */
        client->dispatchv4 = NULL;
+       if (localaddr4 != NULL || localaddr6 == NULL) {
+               result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
+                                       taskmgr, ISC_TRUE,
+                                       &dispatchv4, localaddr4);
+               if (result == ISC_R_SUCCESS)
+                       client->dispatchv4 = dispatchv4;
+       }
+
        client->dispatchv6 = NULL;
-       result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
-                               taskmgr, ISC_TRUE, &dispatchv4);
-       if (result == ISC_R_SUCCESS)
-               client->dispatchv4 = dispatchv4;
-       result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
-                               taskmgr, ISC_TRUE, &dispatchv6);
-       if (result == ISC_R_SUCCESS)
-               client->dispatchv6 = dispatchv6;
+       if (localaddr6 != NULL || localaddr4 == NULL) {
+               result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
+                                       taskmgr, ISC_TRUE,
+                                       &dispatchv6, localaddr6);
+               if (result == ISC_R_SUCCESS)
+                       client->dispatchv6 = dispatchv6;
+       }
 
        /* We need at least one of the dispatchers */
        if (dispatchv4 == NULL && dispatchv6 == NULL) {
index d21dff788ddea4c1d9bfbff183c970ed98ebd125..d8fdccc188f2c5c0b76a61100bfb3f8aca2e138b 100644 (file)
@@ -149,6 +149,13 @@ isc_result_t
 dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
                   isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
                   unsigned int options, dns_client_t **clientp);
+
+isc_result_t
+dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx, 
+          isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr, 
+          isc_timermgr_t *timermgr, unsigned int options,
+          dns_client_t **clientp,
+          isc_sockaddr_t *localaddr4, isc_sockaddr_t *localaddr6);
 /*%<
  * Create a DNS client.  These functions create a new client object with
  * minimal internal resources such as the default 'view' for the IN class and
@@ -161,6 +168,12 @@ dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
  * dns_client_create() is expected to be used by an application that only needs
  * simple synchronous services or by a thread-based application.
  *
+ * dns_client_createx2 takes two additional parameters, 'localaddr4' and
+ * 'localaddr6', to specify the local address to use for each family. If
+ * both are set to NULL, then wildcard addresses will be used for both
+ * families. If only one is NULL, then the other address will be used
+ * as the local address, and the other protocol family will not be used.
+ *
  * If the DNS_CLIENTCREATEOPT_USECACHE flag is set in 'options',
  * dns_client_create(x) will create a cache database with the view.
  *
index 8aefd6d00854adfec9901b2a95b72f04ffb45139..ca68f30a6ce3487400f36b1cb48e8146381844aa 100644 (file)
 #include <isc/mem.h>
 #include <isc/sockaddr.h>
 #include <isc/util.h>
+#include <isc/app.h>
+#include <isc/task.h>
+#include <isc/socket.h>
+#include <isc/timer.h>
 
 #include <irs/resconf.h>
 #include <irs/netdb.h>
@@ -87,7 +91,7 @@ usage(void) {
        fprintf(stderr, "resolve [-t RRtype] "
                "[[-a algorithm] [-e] -k keyname -K keystring] "
                "[-S domain:serveraddr_for_domain ] [-s server_address]"
-               "hostname\n");
+               "[-b address[#port]] hostname\n");
 
        exit(1);
 }
@@ -251,8 +255,16 @@ main(int argc, char *argv[]) {
        isc_boolean_t is_sep = ISC_FALSE;
        const char *port = "53";
        isc_mem_t *mctx = NULL;
-
-       while ((ch = getopt(argc, argv, "a:es:t:k:K:p:S:")) != -1) {
+       isc_appctx_t *actx = NULL;
+       isc_taskmgr_t *taskmgr = NULL;
+       isc_socketmgr_t *socketmgr = NULL;
+       isc_timermgr_t *timermgr = NULL;
+       struct in_addr in4;
+       struct in6_addr in6;
+       isc_sockaddr_t a4, a6;
+       isc_sockaddr_t *addr4 = NULL, *addr6 = NULL;
+
+       while ((ch = getopt(argc, argv, "a:b:es:t:k:K:p:S:")) != -1) {
                switch (ch) {
                case 't':
                        tr.base = optarg;
@@ -267,6 +279,29 @@ main(int argc, char *argv[]) {
                case 'a':
                        algname = optarg;
                        break;
+               case 'b':
+                       if (inet_pton(AF_INET, optarg, &in4) == 1) {
+                               if (addr4 != NULL) {
+                                       fprintf(stderr, "only one local "
+                                                       "address per family "
+                                                       "can be specified\n");
+                                       exit(1);
+                               }
+                               isc_sockaddr_fromin(&a4, &in4, 0);
+                               addr4 = &a4;
+                       } else if (inet_pton(AF_INET6, optarg, &in6) == 1) {
+                               if (addr6 != NULL) {
+                                       fprintf(stderr, "only one local "
+                                                       "address per family "
+                                                       "can be specified\n");
+                                       exit(1);
+                               }
+                               isc_sockaddr_fromin6(&a6, &in6, 0);
+                               addr6 = &a6;
+                       } else {
+                               fprintf(stderr, "invalid address %s\n", optarg);
+                               exit(1);
+                       }
                case 'e':
                        is_sep = ISC_TRUE;
                        break;
@@ -334,10 +369,28 @@ main(int argc, char *argv[]) {
                exit(1);
        }
 
+       result = isc_appctx_create(mctx, &actx);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+       result = isc_app_ctxstart(actx);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+       result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+       result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+       result = isc_timermgr_createinctx(mctx, actx, &timermgr);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
        clientopt = 0;
-       result = dns_client_create(&client, clientopt);
+       result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr, 
+                                   clientopt, &client, addr4, addr6);
        if (result != ISC_R_SUCCESS) {
-               fprintf(stderr, "dns_client_create failed: %d\n", result);
+               fprintf(stderr, "dns_client_create failed: %d, %s\n", result, 
+                       isc_result_totext(result));
                exit(1);
        }
 
@@ -356,10 +409,12 @@ main(int argc, char *argv[]) {
                result = dns_client_setservers(client, dns_rdataclass_in,
                                               NULL, nameservers);
                if (result != ISC_R_SUCCESS) {
+                       irs_resconf_destroy(&resconf);
                        fprintf(stderr, "dns_client_setservers failed: %d\n",
                                result);
                        exit(1);
                }
+               irs_resconf_destroy(&resconf);
        } else {
                addserver(client, server, port, NULL);
        }
@@ -390,7 +445,7 @@ main(int argc, char *argv[]) {
                fprintf(stderr, "failed to convert qname: %d\n", result);
 
        /* Perform resolution */
-       resopt = 0;
+       resopt = DNS_CLIENTRESOPT_ALLOWRUN;
        if (keynamestr == NULL)
                resopt |= DNS_CLIENTRESOPT_NODNSSEC;
        ISC_LIST_INIT(namelist);
@@ -413,7 +468,19 @@ main(int argc, char *argv[]) {
        dns_client_freeresanswer(client, &namelist);
 
        /* Cleanup */
+cleanup:
        dns_client_destroy(&client);
+
+       if (taskmgr != NULL)
+               isc_taskmgr_destroy(&taskmgr);
+       if (timermgr != NULL)
+               isc_timermgr_destroy(&timermgr);
+       if (socketmgr != NULL)
+               isc_socketmgr_destroy(&socketmgr);
+       if (actx != NULL)
+               isc_appctx_destroy(&actx);
+       isc_mem_detach(&mctx);
+
        if (keynamestr != NULL)
                isc_mem_destroy(&keymctx);
        dns_lib_shutdown();