From 90fd8302d63345feb0533d6936e8329e759d3114 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Mon, 18 Mar 2013 15:58:34 +0000 Subject: [PATCH] Specify source address for udp TODO: TCP and error handling --- drill/drill.c | 21 ++++++++++++++++--- ldns/net.h.in | 26 +++++++++++++++++++++++ ldns/resolver.h | 17 +++++++++++++++ net.c | 56 +++++++++++++++++++++++++++++++++++++++++-------- resolver.c | 13 ++++++++++++ 5 files changed, 121 insertions(+), 12 deletions(-) diff --git a/drill/drill.c b/drill/drill.c index 574c8b98..cec7730e 100644 --- a/drill/drill.c +++ b/drill/drill.c @@ -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 \n"); fprintf(stream, "\t-S\t\tchase signature(s) from 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); diff --git a/ldns/net.h.in b/ldns/net.h.in index cd4cfdec..22f53791 100644 --- a/ldns/net.h.in +++ b/ldns/net.h.in @@ -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); /** diff --git a/ldns/resolver.h b/ldns/resolver.h index 7af5d401..7423425f 100644 --- a/ldns/resolver.h +++ b/ldns/resolver.h @@ -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 723d0064..c5528449 100644 --- 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)) { diff --git a/resolver.c b/resolver.c index b564e5db..9fe14d9f 100644 --- a/resolver.c +++ b/resolver.c @@ -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 -- 2.47.3