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);