[nsd-users] ldns bind to source patch

Bryan Duff bduff at ecessa.com
Mon Oct 15 19:07:54 CEST 2012


This allows binding the connection (UDP only in the patch) to a source 
IP (with the purpose of altering routing).

Since this will cause API breakage, I suppose we'll want to alter this 
as a separate function call(s) in net and resolver.

This patch includes updating drill to use this.

Thanks.

-Bryan
-------------- next part --------------
Index: resolver.c
===================================================================
--- resolver.c	(revision 3757)
+++ resolver.c	(working copy)
@@ -26,6 +26,12 @@
 	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 @@
 	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)
 {
Index: drill/drill.c
===================================================================
--- drill/drill.c	(revision 3757)
+++ drill/drill.c	(working copy)
@@ -29,6 +29,7 @@
 	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 @@
         ldns_pkt	*pkt;
         ldns_pkt	*qpkt;
         char 		*serv;
+        char 		*src;
         const char 	*name;
         char 		*name2;
 	char		*progname;
@@ -110,6 +112,7 @@
 	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 @@
 
 	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 @@
 	/* 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 @@
 				qdnssec = true;
 				break;
 			case 'I':
-				/* reserved for backward compatibility */
+				src = optarg;
 				break;
 			case 'T':
 				if (PURPOSE == DRILL_CHASE) {
@@ -480,6 +483,14 @@
 		}
 	}
 
+	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 */
@@ -541,6 +552,9 @@
 	}
 	/* 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 {
@@ -924,6 +938,7 @@
 
 	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: ldns/net.h.in
===================================================================
--- ldns/net.h.in	(revision 3757)
+++ ldns/net.h.in	(working copy)
@@ -39,7 +39,7 @@
  * \param[out] result packet with the answer
  * \return status
  */
-ldns_status ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout, size_t *answersize);
+ldns_status ldns_udp_send(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);
 
 /**
  * Send an udp query and don't wait for an answer but return
@@ -51,7 +51,7 @@
  * \return the socket used
  */
 
-int ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout);
+int ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *from, socklen_t fromlen, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout);
 
 /**
  * Send an tcp query and don't wait for an answer but return
Index: ldns/resolver.h
===================================================================
--- ldns/resolver.h	(revision 3757)
+++ ldns/resolver.h	(working copy)
@@ -61,6 +61,9 @@
 	/**  Port to send queries to */
 	uint16_t _port;
 
+	/** Source address to query from */
+	ldns_rdf *_source;
+
 	/** Array of nameservers to query (IP addresses or dnames) */
 	ldns_rdf **_nameservers;
 	/** Number of nameservers in \c _nameservers */
@@ -152,6 +155,13 @@
 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
  * \return true if so, otherwise false
@@ -338,6 +348,13 @@
 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
  * \param[in] b true: set to recurse, false: unset
Index: net.c
===================================================================
--- net.c	(revision 3757)
+++ net.c	(working copy)
@@ -60,7 +60,9 @@
 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_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) {
@@ -144,9 +150,8 @@
 				/* 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);
-				
+							(socklen_t)ns_len, src, (socklen_t)src_len,
+							ldns_resolver_timeout(r), &reply_size);
 				if (send_status == LDNS_STATUS_OK) {
 					break;
 				}
@@ -201,6 +206,9 @@
 		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;
@@ -292,12 +300,13 @@
 
 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)
+		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(qbin, from, fromlen, to, tolen, timeout);
 
 	if (sockfd == 0) {
 		return LDNS_STATUS_SOCKET_ERROR;
@@ -335,7 +344,8 @@
 }
 
 int
-ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, 
+ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *from, socklen_t fromlen, 
+		const struct sockaddr_storage *to, socklen_t tolen, 
 		struct timeval timeout)
 {
 	int sockfd;
@@ -346,6 +356,12 @@
 		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);


More information about the nsd-users mailing list