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");
ldns_pkt *pkt;
ldns_pkt *qpkt;
char *serv;
+ char *src = NULL;
const char *name;
char *name2;
char *progname;
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
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
/* 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':
qdnssec = true;
break;
case 'I':
- /* reserved for backward compatibility */
+ src = optarg;
break;
case 'T':
if (PURPOSE == DRILL_CHASE) {
}
}
+ 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 */
}
/* 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 {
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);
* 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
* \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);
/**
char *_tsig_keydata;
/** TSIG signing algorithm */
char *_tsig_algorithm;
+
+ /** Source address to query from */
+ ldns_rdf *_source;
};
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
*/
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
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;
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) {
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;
}
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;
}
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;
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;
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);
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))
{
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)
{
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)
{
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