aboutsummaryrefslogtreecommitdiff
path: root/contrib/ldns/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ldns/net.c')
-rw-r--r--contrib/ldns/net.c796
1 files changed, 441 insertions, 355 deletions
diff --git a/contrib/ldns/net.c b/contrib/ldns/net.c
index 6b444da677bc..b8a5385e1c20 100644
--- a/contrib/ldns/net.c
+++ b/contrib/ldns/net.c
@@ -56,11 +56,417 @@ ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt)
return result;
}
+/* code from rdata.c */
+static struct sockaddr_storage *
+ldns_rdf2native_sockaddr_storage_port(
+ const ldns_rdf *rd, uint16_t port, size_t *size)
+{
+ struct sockaddr_storage *data;
+ struct sockaddr_in *data_in;
+ struct sockaddr_in6 *data_in6;
+
+ data = LDNS_MALLOC(struct sockaddr_storage);
+ if (!data) {
+ return NULL;
+ }
+ /* zero the structure for portability */
+ memset(data, 0, sizeof(struct sockaddr_storage));
+
+ switch(ldns_rdf_get_type(rd)) {
+ case LDNS_RDF_TYPE_A:
+#ifndef S_SPLINT_S
+ data->ss_family = AF_INET;
+#endif
+ data_in = (struct sockaddr_in*) data;
+ data_in->sin_port = (in_port_t)htons(port);
+ memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd));
+ *size = sizeof(struct sockaddr_in);
+ return data;
+ case LDNS_RDF_TYPE_AAAA:
+#ifndef S_SPLINT_S
+ data->ss_family = AF_INET6;
+#endif
+ data_in6 = (struct sockaddr_in6*) data;
+ data_in6->sin6_port = (in_port_t)htons(port);
+ memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd));
+ *size = sizeof(struct sockaddr_in6);
+ return data;
+ default:
+ LDNS_FREE(data);
+ return NULL;
+ }
+}
+
+struct sockaddr_storage *
+ldns_rdf2native_sockaddr_storage(
+ const ldns_rdf *rd, uint16_t port, size_t *size)
+{
+ return ldns_rdf2native_sockaddr_storage_port(
+ rd, (port == 0 ? (uint16_t)LDNS_PORT : port), size);
+}
+
+/** best effort to set nonblocking */
+static void
+ldns_sock_nonblock(int sockfd)
+{
+#ifdef HAVE_FCNTL
+ int flag;
+ if((flag = fcntl(sockfd, F_GETFL)) != -1) {
+ flag |= O_NONBLOCK;
+ if(fcntl(sockfd, F_SETFL, flag) == -1) {
+ /* ignore error, continue blockingly */
+ }
+ }
+#elif defined(HAVE_IOCTLSOCKET)
+ unsigned long on = 1;
+ if(ioctlsocket(sockfd, FIONBIO, &on) != 0) {
+ /* ignore error, continue blockingly */
+ }
+#endif
+}
+
+/** best effort to set blocking */
+static void
+ldns_sock_block(int sockfd)
+{
+#ifdef HAVE_FCNTL
+ int flag;
+ if((flag = fcntl(sockfd, F_GETFL)) != -1) {
+ flag &= ~O_NONBLOCK;
+ if(fcntl(sockfd, F_SETFL, flag) == -1) {
+ /* ignore error, continue */
+ }
+ }
+#elif defined(HAVE_IOCTLSOCKET)
+ unsigned long off = 0;
+ if(ioctlsocket(sockfd, FIONBIO, &off) != 0) {
+ /* ignore error, continue */
+ }
+#endif
+}
+
+/** wait for a socket to become ready */
+static int
+ldns_sock_wait(int sockfd, struct timeval timeout, int write)
+{
+ int ret;
+#ifndef S_SPLINT_S
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(FD_SET_T sockfd, &fds);
+ if(write)
+ ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
+ else
+ ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
+#endif
+ if(ret == 0)
+ /* timeout expired */
+ return 0;
+ else if(ret == -1)
+ /* error */
+ return 0;
+ return 1;
+}
+
+
+static int
+ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen,
+ const struct sockaddr_storage *from, socklen_t fromlen,
+ struct timeval timeout)
+{
+ int sockfd;
+
+#ifndef S_SPLINT_S
+ if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM,
+ IPPROTO_TCP)) == -1) {
+ return 0;
+ }
+#endif
+ if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){
+ return 0;
+ }
+
+ /* perform nonblocking connect, to be able to wait with select() */
+ ldns_sock_nonblock(sockfd);
+ if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) {
+#ifndef USE_WINSOCK
+#ifdef EINPROGRESS
+ if(errno != EINPROGRESS) {
+#else
+ if(1) {
+#endif
+ close(sockfd);
+ return 0;
+ }
+#else /* USE_WINSOCK */
+ if(WSAGetLastError() != WSAEINPROGRESS &&
+ WSAGetLastError() != WSAEWOULDBLOCK) {
+ closesocket(sockfd);
+ return 0;
+ }
+#endif
+ /* error was only telling us that it would block */
+ }
+
+ /* wait(write) until connected or error */
+ while(1) {
+ int error = 0;
+ socklen_t len = (socklen_t)sizeof(error);
+
+ if(!ldns_sock_wait(sockfd, timeout, 1)) {
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+ return 0;
+ }
+
+ /* check if there is a pending error for nonblocking connect */
+ if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error,
+ &len) < 0) {
+#ifndef USE_WINSOCK
+ error = errno; /* on solaris errno is error */
+#else
+ error = WSAGetLastError();
+#endif
+ }
+#ifndef USE_WINSOCK
+#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
+ if(error == EINPROGRESS || error == EWOULDBLOCK)
+ continue; /* try again */
+#endif
+ else if(error != 0) {
+ close(sockfd);
+ /* error in errno for our user */
+ errno = error;
+ return 0;
+ }
+#else /* USE_WINSOCK */
+ if(error == WSAEINPROGRESS)
+ continue;
+ else if(error == WSAEWOULDBLOCK)
+ continue;
+ else if(error != 0) {
+ closesocket(sockfd);
+ errno = error;
+ return 0;
+ }
+#endif /* USE_WINSOCK */
+ /* connected */
+ break;
+ }
+
+ /* set the socket blocking again */
+ ldns_sock_block(sockfd);
+
+ return sockfd;
+}
+
+int
+ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen,
+ struct timeval timeout)
+{
+ return ldns_tcp_connect_from(to, tolen, NULL, 0, timeout);
+}
+
+static int
+ldns_tcp_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;
+
+ sockfd = ldns_tcp_connect_from(to, tolen, from, fromlen, timeout);
+
+ if (sockfd == 0) {
+ return 0;
+ }
+
+ if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+ return 0;
+ }
+
+ return sockfd;
+}
+
+int
+ldns_tcp_bgsend(ldns_buffer *qbin,
+ const struct sockaddr_storage *to, socklen_t tolen,
+ struct timeval timeout)
+{
+ return ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
+}
+
+
+/* keep in mind that in DNS tcp messages the first 2 bytes signal the
+ * amount data to expect
+ */
+static ldns_status
+ldns_tcp_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_tcp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
+
+ if (sockfd == 0) {
+ return LDNS_STATUS_ERR;
+ }
+
+ answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+
+ if (*answer_size == 0) {
+ /* oops */
+ return LDNS_STATUS_NETWORK_ERR;
+ }
+
+ /* resize accordingly */
+ *result = LDNS_XREALLOC(answer, uint8_t, (size_t)*answer_size);
+ if(!*result) {
+ LDNS_FREE(answer);
+ return LDNS_STATUS_MEM_ERR;
+ }
+ return LDNS_STATUS_OK;
+}
+
+ldns_status
+ldns_tcp_send(uint8_t **result, ldns_buffer *qbin,
+ const struct sockaddr_storage *to, socklen_t tolen,
+ struct timeval timeout, size_t *answer_size)
+{
+ return ldns_tcp_send_from(result, qbin,
+ to, tolen, NULL, 0, timeout, answer_size);
+}
+
+int
+ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
+{
+ int sockfd;
+
+#ifndef S_SPLINT_S
+ if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
+ IPPROTO_UDP))
+ == -1) {
+ return 0;
+ }
+#endif
+ return sockfd;
+}
+
+static 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)
+{
+ int sockfd;
+
+ sockfd = ldns_udp_connect(to, timeout);
+
+ if (sockfd == 0) {
+ return 0;
+ }
+
+ if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){
+ return 0;
+ }
+
+ if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+ return 0;
+ }
+ 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);
+}
+
+static 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 *answer_size)
+{
+ int sockfd;
+ uint8_t *answer;
+
+ sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
+
+ if (sockfd == 0) {
+ return LDNS_STATUS_SOCKET_ERROR;
+ }
+
+ /* wait for an response*/
+ if(!ldns_sock_wait(sockfd, timeout, 0)) {
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+ return LDNS_STATUS_NETWORK_ERR;
+ }
+
+ /* set to nonblocking, so if the checksum is bad, it becomes
+ * an EGAIN error and the ldns_udp_send function does not block,
+ * but returns a 'NETWORK_ERROR' much like a timeout. */
+ ldns_sock_nonblock(sockfd);
+
+ answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
+#ifndef USE_WINSOCK
+ close(sockfd);
+#else
+ closesocket(sockfd);
+#endif
+
+ if (*answer_size == 0) {
+ /* oops */
+ return LDNS_STATUS_NETWORK_ERR;
+ }
+
+ *result = answer;
+ 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);
+}
+
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 +496,11 @@ 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_port(
+ 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) {
@@ -129,12 +540,14 @@ ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf
send_status = LDNS_STATUS_ERR;
/* reply_bytes implicitly handles our error */
- if (1 == ldns_resolver_usevc(r)) {
+ if (ldns_resolver_usevc(r)) {
for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
send_status =
- ldns_tcp_send(&reply_bytes, qb, ns,
- (socklen_t)ns_len, ldns_resolver_timeout(r),
- &reply_size);
+ ldns_tcp_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;
}
@@ -143,10 +556,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 +615,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;
@@ -227,241 +644,6 @@ ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf
return status;
}
-/** best effort to set nonblocking */
-static void
-ldns_sock_nonblock(int sockfd)
-{
-#ifdef HAVE_FCNTL
- int flag;
- if((flag = fcntl(sockfd, F_GETFL)) != -1) {
- flag |= O_NONBLOCK;
- if(fcntl(sockfd, F_SETFL, flag) == -1) {
- /* ignore error, continue blockingly */
- }
- }
-#elif defined(HAVE_IOCTLSOCKET)
- unsigned long on = 1;
- if(ioctlsocket(sockfd, FIONBIO, &on) != 0) {
- /* ignore error, continue blockingly */
- }
-#endif
-}
-
-/** best effort to set blocking */
-static void
-ldns_sock_block(int sockfd)
-{
-#ifdef HAVE_FCNTL
- int flag;
- if((flag = fcntl(sockfd, F_GETFL)) != -1) {
- flag &= ~O_NONBLOCK;
- if(fcntl(sockfd, F_SETFL, flag) == -1) {
- /* ignore error, continue */
- }
- }
-#elif defined(HAVE_IOCTLSOCKET)
- unsigned long off = 0;
- if(ioctlsocket(sockfd, FIONBIO, &off) != 0) {
- /* ignore error, continue */
- }
-#endif
-}
-
-/** wait for a socket to become ready */
-static int
-ldns_sock_wait(int sockfd, struct timeval timeout, int write)
-{
- int ret;
-#ifndef S_SPLINT_S
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(FD_SET_T sockfd, &fds);
- if(write)
- ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
- else
- ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
-#endif
- if(ret == 0)
- /* timeout expired */
- return 0;
- else if(ret == -1)
- /* error */
- return 0;
- return 1;
-}
-
-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)
-{
- int sockfd;
- uint8_t *answer;
-
- sockfd = ldns_udp_bgsend(qbin, to, tolen, timeout);
-
- if (sockfd == 0) {
- return LDNS_STATUS_SOCKET_ERROR;
- }
-
- /* wait for an response*/
- if(!ldns_sock_wait(sockfd, timeout, 0)) {
-#ifndef USE_WINSOCK
- close(sockfd);
-#else
- closesocket(sockfd);
-#endif
- return LDNS_STATUS_NETWORK_ERR;
- }
-
- /* set to nonblocking, so if the checksum is bad, it becomes
- * an EGAIN error and the ldns_udp_send function does not block,
- * but returns a 'NETWORK_ERROR' much like a timeout. */
- ldns_sock_nonblock(sockfd);
-
- answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
-#ifndef USE_WINSOCK
- close(sockfd);
-#else
- closesocket(sockfd);
-#endif
-
- if (*answer_size == 0) {
- /* oops */
- return LDNS_STATUS_NETWORK_ERR;
- }
-
- *result = answer;
- return LDNS_STATUS_OK;
-}
-
-int
-ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen,
- struct timeval timeout)
-{
- int sockfd;
-
- sockfd = ldns_udp_connect(to, timeout);
-
- if (sockfd == 0) {
- return 0;
- }
-
- if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
-#ifndef USE_WINSOCK
- close(sockfd);
-#else
- closesocket(sockfd);
-#endif
- return 0;
- }
- return sockfd;
-}
-
-int
-ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
-{
- int sockfd;
-
-#ifndef S_SPLINT_S
- if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
- IPPROTO_UDP))
- == -1) {
- return 0;
- }
-#endif
- return sockfd;
-}
-
-int
-ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen,
- struct timeval timeout)
-{
- int sockfd;
-
-#ifndef S_SPLINT_S
- if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM,
- IPPROTO_TCP)) == -1) {
- return 0;
- }
-#endif
-
- /* perform nonblocking connect, to be able to wait with select() */
- ldns_sock_nonblock(sockfd);
- if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) {
-#ifndef USE_WINSOCK
-#ifdef EINPROGRESS
- if(errno != EINPROGRESS) {
-#else
- if(1) {
-#endif
- close(sockfd);
- return 0;
- }
-#else /* USE_WINSOCK */
- if(WSAGetLastError() != WSAEINPROGRESS &&
- WSAGetLastError() != WSAEWOULDBLOCK) {
- closesocket(sockfd);
- return 0;
- }
-#endif
- /* error was only telling us that it would block */
- }
-
- /* wait(write) until connected or error */
- while(1) {
- int error = 0;
- socklen_t len = (socklen_t)sizeof(error);
-
- if(!ldns_sock_wait(sockfd, timeout, 1)) {
-#ifndef USE_WINSOCK
- close(sockfd);
-#else
- closesocket(sockfd);
-#endif
- return 0;
- }
-
- /* check if there is a pending error for nonblocking connect */
- if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error,
- &len) < 0) {
-#ifndef USE_WINSOCK
- error = errno; /* on solaris errno is error */
-#else
- error = WSAGetLastError();
-#endif
- }
-#ifndef USE_WINSOCK
-#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
- if(error == EINPROGRESS || error == EWOULDBLOCK)
- continue; /* try again */
-#endif
- else if(error != 0) {
- close(sockfd);
- /* error in errno for our user */
- errno = error;
- return 0;
- }
-#else /* USE_WINSOCK */
- if(error == WSAEINPROGRESS)
- continue;
- else if(error == WSAEWOULDBLOCK)
- continue;
- else if(error != 0) {
- closesocket(sockfd);
- errno = error;
- return 0;
- }
-#endif /* USE_WINSOCK */
- /* connected */
- break;
- }
-
- /* set the socket blocking again */
- ldns_sock_block(sockfd);
-
- return sockfd;
-}
-
ssize_t
ldns_tcp_send_query(ldns_buffer *qbin, int sockfd,
const struct sockaddr_storage *to, socklen_t tolen)
@@ -643,110 +825,6 @@ ldns_tcp_read_wire(int sockfd, size_t *size)
return wire;
}
-/* keep in mind that in DNS tcp messages the first 2 bytes signal the
- * amount data to expect
- */
-ldns_status
-ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to,
- socklen_t tolen, struct timeval timeout, size_t *answer_size)
-{
- int sockfd;
- uint8_t *answer;
-
- sockfd = ldns_tcp_bgsend(qbin, to, tolen, timeout);
-
- if (sockfd == 0) {
- return LDNS_STATUS_ERR;
- }
-
- answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
-#ifndef USE_WINSOCK
- close(sockfd);
-#else
- closesocket(sockfd);
-#endif
-
- if (*answer_size == 0) {
- /* oops */
- return LDNS_STATUS_NETWORK_ERR;
- }
-
- /* resize accordingly */
- *result = LDNS_XREALLOC(answer, uint8_t, (size_t)*answer_size);
- if(!*result) {
- LDNS_FREE(answer);
- return LDNS_STATUS_MEM_ERR;
- }
- return LDNS_STATUS_OK;
-}
-
-int
-ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen,
- struct timeval timeout)
-{
- int sockfd;
-
- sockfd = ldns_tcp_connect(to, tolen, timeout);
-
- if (sockfd == 0) {
- return 0;
- }
-
- if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
-#ifndef USE_WINSOCK
- close(sockfd);
-#else
- closesocket(sockfd);
-#endif
- return 0;
- }
-
- return sockfd;
-}
-
-/* code from rdata.c */
-struct sockaddr_storage *
-ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, uint16_t port, size_t *size)
-{
- struct sockaddr_storage *data;
- struct sockaddr_in *data_in;
- struct sockaddr_in6 *data_in6;
-
- data = LDNS_MALLOC(struct sockaddr_storage);
- if (!data) {
- return NULL;
- }
- /* zero the structure for portability */
- memset(data, 0, sizeof(struct sockaddr_storage));
- if (port == 0) {
- port = LDNS_PORT;
- }
-
- switch(ldns_rdf_get_type(rd)) {
- case LDNS_RDF_TYPE_A:
-#ifndef S_SPLINT_S
- data->ss_family = AF_INET;
-#endif
- data_in = (struct sockaddr_in*) data;
- data_in->sin_port = (in_port_t)htons(port);
- memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd));
- *size = sizeof(struct sockaddr_in);
- return data;
- case LDNS_RDF_TYPE_AAAA:
-#ifndef S_SPLINT_S
- data->ss_family = AF_INET6;
-#endif
- data_in6 = (struct sockaddr_in6*) data;
- data_in6->sin6_port = (in_port_t)htons(port);
- memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd));
- *size = sizeof(struct sockaddr_in6);
- return data;
- default:
- LDNS_FREE(data);
- return NULL;
- }
-}
-
#ifndef S_SPLINT_S
ldns_rdf *
ldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port)
@@ -789,6 +867,8 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class)
ldns_pkt *query;
ldns_buffer *query_wire;
+ struct sockaddr_storage *src = NULL;
+ size_t src_len = 0;
struct sockaddr_storage *ns = NULL;
size_t ns_len = 0;
size_t ns_i;
@@ -803,6 +883,10 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class)
if (!query) {
return LDNS_STATUS_ADDRESS_ERR;
}
+ if(ldns_resolver_source(resolver)) {
+ src = ldns_rdf2native_sockaddr_storage_port(
+ ldns_resolver_source(resolver), 0, &src_len);
+ }
/* For AXFR, we have to make the connection ourselves */
/* try all nameservers (which usually would mean v4 fallback if
* @hostname is used */
@@ -817,7 +901,9 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class)
resolver->_nameservers[ns_i],
ldns_resolver_port(resolver), &ns_len);
- resolver->_socket = ldns_tcp_connect(ns, (socklen_t)ns_len,
+ resolver->_socket = ldns_tcp_connect_from(
+ ns, (socklen_t)ns_len,
+ src, (socklen_t)src_len,
ldns_resolver_timeout(resolver));
}
@@ -834,8 +920,8 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class)
ldns_resolver_tsig_keydata(resolver),
300, ldns_resolver_tsig_algorithm(resolver), NULL);
if (status != LDNS_STATUS_OK) {
- /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
- we have to close the socket here! */
+ /* to prevent problems on subsequent calls to
+ * ldns_axfr_start we have to close the socket here! */
#ifndef USE_WINSOCK
close(resolver->_socket);
#else
@@ -873,8 +959,8 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class)
ldns_buffer_free(query_wire);
LDNS_FREE(ns);
- /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
- we have to close the socket here! */
+ /* to prevent problems on subsequent calls to ldns_axfr_start
+ * we have to close the socket here! */
#ifndef USE_WINSOCK
close(resolver->_socket);
#else
@@ -891,8 +977,8 @@ ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class)
ldns_buffer_free(query_wire);
LDNS_FREE(ns);
- /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
- we have to close the socket here! */
+ /* to prevent problems on subsequent calls to ldns_axfr_start
+ * we have to close the socket here! */
#ifndef USE_WINSOCK
close(resolver->_socket);