]> git.ipfire.org Git - thirdparty/ldns.git/commitdiff
Specify source address for udp
authorWillem Toorop <willem@NLnetLabs.nl>
Mon, 18 Mar 2013 15:58:34 +0000 (15:58 +0000)
committerWillem Toorop <willem@NLnetLabs.nl>
Mon, 18 Mar 2013 15:58:34 +0000 (15:58 +0000)
TODO: TCP and error handling

drill/drill.c
ldns/net.h.in
ldns/resolver.h
net.c
resolver.c

index 574c8b98c856c5867901d40b023c783c75ff9a17..cec7730eeea9f7d47dc507117a89bd380ef22586 100644 (file)
@@ -29,6 +29,7 @@ usage(FILE *stream, const char *progname)
        fprintf(stream, "\n\targuments may be placed in random order\n");
        fprintf(stream, "\n  Options:\n");
        fprintf(stream, "\t-D\t\tenable DNSSEC (DO bit)\n");
+       fprintf(stream, "\t-I\t\tsource address to query from\n");
 #ifdef HAVE_SSL
        fprintf(stream, "\t-T\t\ttrace from the root down to <name>\n");
        fprintf(stream, "\t-S\t\tchase signature(s) from <name> to a know key [*]\n");
@@ -103,6 +104,7 @@ main(int argc, char *argv[])
         ldns_pkt       *pkt;
         ldns_pkt       *qpkt;
         char           *serv;
+        char           *src = NULL;
         const char     *name;
         char           *name2;
        char            *progname;
@@ -110,6 +112,7 @@ main(int argc, char *argv[])
        char            *answer_file = NULL;
        ldns_buffer     *query_buffer = NULL;
        ldns_rdf        *serv_rdf;
+       ldns_rdf        *src_rdf = NULL;
         ldns_rr_type   type;
         ldns_rr_class  clas;
 #if 0
@@ -157,7 +160,7 @@ main(int argc, char *argv[])
 
        int_type = -1; serv = NULL; type = 0; 
        int_clas = -1; name = NULL; clas = 0;
-       qname = NULL; 
+       qname = NULL; src = NULL;
        progname = strdup(argv[0]);
 
 #ifdef USE_WINSOCK
@@ -195,7 +198,7 @@ main(int argc, char *argv[])
        /* global first, query opt next, option with parm's last
         * and sorted */ /*  "46DITSVQf:i:w:q:achuvxzy:so:p:b:k:" */
                                       
-       while ((c = getopt(argc, argv, "46ab:c:d:Df:hi:Ik:o:p:q:Qr:sStTuvV:w:xy:z")) != -1) {
+       while ((c = getopt(argc, argv, "46ab:c:d:Df:hi:I:k:o:p:q:Qr:sStTuvV:w:xy:z")) != -1) {
                switch(c) {
                        /* global options */
                        case '4':
@@ -208,7 +211,7 @@ main(int argc, char *argv[])
                                qdnssec = true;
                                break;
                        case 'I':
-                               /* reserved for backward compatibility */
+                               src = optarg;
                                break;
                        case 'T':
                                if (PURPOSE == DRILL_CHASE) {
@@ -482,6 +485,14 @@ main(int argc, char *argv[])
                }
        }
 
+       if (src) {
+               src_rdf = ldns_rdf_new_addr_frm_str(src);
+               if(!src_rdf) {
+                       fprintf(stderr, "-I must be (or resolve) to a valid IP[v6] address.\n");
+                       exit(EXIT_FAILURE);
+               }
+       }
+
        /* set the nameserver to use */
        if (!serv) {
                /* no server given make a resolver from /etc/resolv.conf */
@@ -543,6 +554,9 @@ main(int argc, char *argv[])
        }
        /* set the resolver options */
        ldns_resolver_set_port(res, qport);
+       if(src_rdf) {
+               ldns_resolver_set_source(res, src_rdf);
+       }
        if (verbosity >= 5) {
                ldns_resolver_set_debug(res, true);
        } else {
@@ -926,6 +940,7 @@ main(int argc, char *argv[])
 
        exit:
        ldns_rdf_deep_free(qname);
+       ldns_rdf_deep_free(src_rdf);
        ldns_resolver_deep_free(res);
        ldns_resolver_deep_free(cmdline_res);
        ldns_rr_list_deep_free(key_list);
index cd4cfdec9c64c5dbe05342babffbac9ac27a63fa..22f53791eba7b9730d62e7b4e33e96e9c6aedd13 100644 (file)
@@ -29,6 +29,20 @@ extern "C" {
  * Contains functions to send and receive packets over a network.
  */
 
+/**
+ * Sends a buffer to an ip using udp and return the respons as a ldns_pkt
+ * \param[in] qbin the ldns_buffer to be send
+ * \param[in] to the ip addr to send to
+ * \param[in] tolen length of the ip addr
+ * \param[in] from the ip addr to send from
+ * \param[in] fromlen length of the ip addr
+ * \param[in] timeout the timeout value for the network
+ * \param[out] answersize size of the packet
+ * \param[out] result packet with the answer
+ * \return status
+ */
+ldns_status ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, const struct sockaddr_storage *from, socklen_t fromlen, struct timeval timeout, size_t *answersize);
+
 /**
  * Sends a buffer to an ip using udp and return the respons as a ldns_pkt
  * \param[in] qbin the ldns_buffer to be send
@@ -47,10 +61,22 @@ ldns_status ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sock
  * \param[in] qbin the ldns_buffer to be send
  * \param[in] to the ip addr to send to
  * \param[in] tolen length of the ip addr
+ * \param[in] from the ip addr to send from
+ * \param[in] fromlen length of the ip addr
  * \param[in] timeout *unused*, was the timeout value for the network
  * \return the socket used
  */
+int ldns_udp_bgsend_from(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, const struct sockaddr_storage *from, socklen_t fromlen, struct timeval timeout);
 
+/**
+ * Send an udp query and don't wait for an answer but return
+ * the socket
+ * \param[in] qbin the ldns_buffer to be send
+ * \param[in] to the ip addr to send to
+ * \param[in] tolen length of the ip addr
+ * \param[in] timeout *unused*, was the timeout value for the network
+ * \return the socket used
+ */
 int ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout);
 
 /**
index 7af5d401e65caca8cb48f68ad2a973d393b9c006..7423425f8d6c6bfd6f7c6c30f24671c8debdf511 100644 (file)
@@ -138,6 +138,9 @@ struct ldns_struct_resolver
        char *_tsig_keydata;
        /** TSIG signing algorithm */
        char *_tsig_algorithm;
+
+       /** Source address to query from */
+       ldns_rdf *_source;
 };
 typedef struct ldns_struct_resolver ldns_resolver;
 
@@ -151,6 +154,13 @@ typedef struct ldns_struct_resolver ldns_resolver;
  */
 uint16_t ldns_resolver_port(const ldns_resolver *r);
 
+/**
+ * Get the source address the resolver should use
+ * \param[in] r the resolver
+ * \return the source rdf
+ */
+ldns_rdf *ldns_resolver_source(const ldns_resolver *r);
+
 /**
  * Is the resolver set to recurse
  * \param[in] r the resolver
@@ -337,6 +347,13 @@ size_t ldns_resolver_searchlist_count(const ldns_resolver *r);
  */
 void ldns_resolver_set_port(ldns_resolver *r, uint16_t p);
 
+/**
+ * Set the source rdf (address) the resolver should use
+ * \param[in] r the resolver
+ * \param[in] s the source address
+ */
+void ldns_resolver_set_source(ldns_resolver *r, ldns_rdf *s);
+
 /**
  * Set the resolver recursion
  * \param[in] r the resolver
diff --git a/net.c b/net.c
index 723d006408f5760be73b9a7ee83c0d97967a1a00..c55284493f5cea63bfc2d658dac4dc2ee7321ae5 100644 (file)
--- a/net.c
+++ b/net.c
@@ -60,7 +60,9 @@ ldns_status
 ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac)
 {
        uint8_t i;
-       
+
+       struct sockaddr_storage *src = NULL;
+       size_t src_len;
        struct sockaddr_storage *ns;
        size_t ns_len;
        struct timeval tv_s;
@@ -90,6 +92,10 @@ ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf
                ldns_resolver_nameservers_randomize(r);
        }
 
+       if(ldns_resolver_source(r)) {
+               src = ldns_rdf2native_sockaddr_storage(ldns_resolver_source(r), 0, &src_len);
+       }
+
        /* loop through all defined nameservers */
        for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
                if (rtt[i] == LDNS_RESOLV_RTT_INF) {
@@ -143,10 +149,11 @@ ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf
                        for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
                                /* ldns_rdf_print(stdout, ns_array[i]); */
                                send_status = 
-                                       ldns_udp_send(&reply_bytes, qb, ns, 
-                                                       (socklen_t)ns_len, ldns_resolver_timeout(r), 
-                                                       &reply_size);
-                               
+                                       ldns_udp_send_from(&reply_bytes, qb,
+                                               ns,  (socklen_t)ns_len,
+                                               src, (socklen_t)src_len,
+                                               ldns_resolver_timeout(r),
+                                               &reply_size);
                                if (send_status == LDNS_STATUS_OK) {
                                        break;
                                }
@@ -201,6 +208,9 @@ ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf
                sleep((unsigned int) ldns_resolver_retrans(r));
        }
 
+       if(src) {
+               LDNS_FREE(src);
+       }
        if (all_servers_rtt_inf) {
                LDNS_FREE(reply_bytes);
                return LDNS_STATUS_RES_NO_NS;
@@ -291,13 +301,15 @@ ldns_sock_wait(int sockfd, struct timeval timeout, int write)
 }
 
 ldns_status
-ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to,
-               socklen_t tolen, struct timeval timeout, size_t *answer_size)
+ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin,
+               const struct sockaddr_storage *to  , socklen_t tolen,
+               const struct sockaddr_storage *from, socklen_t fromlen,
+               struct timeval timeout, size_t *answer_size)
 {
        int sockfd;
        uint8_t *answer;
 
-       sockfd = ldns_udp_bgsend(qbin, to, tolen, timeout);
+       sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
 
        if (sockfd == 0) {
                return LDNS_STATUS_SOCKET_ERROR;
@@ -334,8 +346,20 @@ ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage
        return LDNS_STATUS_OK;
 }
 
+ldns_status
+ldns_udp_send(uint8_t **result, ldns_buffer *qbin,
+               const struct sockaddr_storage *to  , socklen_t tolen,
+               struct timeval timeout, size_t *answer_size)
+{
+       return ldns_udp_send_from(result, qbin, to, tolen, NULL, 0,
+                       timeout, answer_size);
+}
+
+
 int
-ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, 
+ldns_udp_bgsend_from(ldns_buffer *qbin,
+               const struct sockaddr_storage *to  , socklen_t tolen, 
+               const struct sockaddr_storage *from, socklen_t fromlen, 
                struct timeval timeout)
 {
        int sockfd;
@@ -346,6 +370,12 @@ ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t
                return 0;
        }
 
+       if (from) {
+               if (bind(sockfd, (const struct sockaddr*)from, fromlen)) {
+                       return 0;
+               }
+       }
+
        if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
 #ifndef USE_WINSOCK
                close(sockfd);
@@ -357,6 +387,14 @@ ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t
        return sockfd;
 }
 
+int
+ldns_udp_bgsend(ldns_buffer *qbin,
+               const struct sockaddr_storage *to  , socklen_t tolen, 
+               struct timeval timeout)
+{
+       return ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
+}
+
 int
 ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
 {
index b564e5db694d765b8847b47b3ec52c3f13ebf9aa..9fe14d9fe578719d81e60922d1cd516c3e37a286 100644 (file)
@@ -26,6 +26,12 @@ ldns_resolver_port(const ldns_resolver *r)
        return r->_port;
 }
 
+ldns_rdf *
+ldns_resolver_source(const ldns_resolver *r)
+{
+       return r->_source;
+}
+
 uint16_t
 ldns_resolver_edns_udp_size(const ldns_resolver *r)
 {
@@ -234,6 +240,12 @@ ldns_resolver_set_port(ldns_resolver *r, uint16_t p)
        r->_port = p;
 }
 
+void
+ldns_resolver_set_source(ldns_resolver *r, ldns_rdf *s)
+{
+       r->_source = s;
+}
+
 ldns_rdf *
 ldns_resolver_pop_nameserver(ldns_resolver *r)
 {
@@ -625,6 +637,7 @@ ldns_resolver_new(void)
        ldns_resolver_set_igntc(r, false);
        ldns_resolver_set_recursive(r, false);
        ldns_resolver_set_dnsrch(r, true);
+       ldns_resolver_set_source(r, NULL);
 
        /* randomize the nameserver to be queried
         * when there are multiple