/build/ldns-eVLWSH/ldns-1.8.4/net.c
Go to the documentation of this file.
/*
* net.c
*
* Network implementation
* All network related functions are grouped here
*
* a Net::DNS like library for C
*
* (c) NLnet Labs, 2004-2006
*
* See the file LICENSE for the license
*/
#include <ldns/config.h>
#include <ldns/ldns.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <sys/time.h>
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_POLL
#include <poll.h>
#endif
ldns_status
ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt)
{
ldns_buffer *qb;
ldns_status result;
ldns_rdf *tsig_mac = NULL;
qb = ldns_buffer_new(LDNS_MIN_BUFLEN);
if (query_pkt && ldns_pkt_tsig(query_pkt)) {
tsig_mac = ldns_rr_rdf(ldns_pkt_tsig(query_pkt), 3);
}
if (!query_pkt ||
ldns_pkt2buffer_wire(qb, query_pkt) != LDNS_STATUS_OK) {
result = LDNS_STATUS_ERR;
} else {
result = ldns_send_buffer(result_packet, r, qb, tsig_mac);
}
ldns_buffer_free(qb);
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);
}
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
}
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
}
static int
ldns_sock_wait(int sockfd, struct timeval timeout, int write)
{
int ret;
#ifndef HAVE_POLL
#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
#else
struct pollfd pfds[2];
memset(&pfds[0], 0, sizeof(pfds[0]) * 2);
pfds[0].fd = sockfd;
pfds[0].events = POLLIN|POLLERR;
if (write) {
pfds[0].events |= POLLOUT;
}
ret = poll(pfds, 1, (int)(timeout.tv_sec * 1000
+ timeout.tv_usec / 1000));
#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)) == SOCK_INVALID) {
return -1;
}
#endif
if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){
close_socket(sockfd);
return -1;
}
/* 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_socket(sockfd);
return -1;
}
#else /* USE_WINSOCK */
if(WSAGetLastError() != WSAEINPROGRESS &&
WSAGetLastError() != WSAEWOULDBLOCK) {
close_socket(sockfd);
return -1;
}
#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)) {
close_socket(sockfd);
return -1;
}
/* 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_socket(sockfd);
/* error in errno for our user */
errno = error;
return -1;
}
#else /* USE_WINSOCK */
if(error == WSAEINPROGRESS)
continue;
else if(error == WSAEWOULDBLOCK)
continue;
else if(error != 0) {
close_socket(sockfd);
errno = error;
return -1;
}
#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)
{
int s = ldns_tcp_connect_from(to, tolen, NULL, 0, timeout);
return s > 0 ? s : 0;
}
int
ldns_tcp_connect2(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 && ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
close_socket(sockfd);
return -1;
}
return sockfd;
}
int
ldns_tcp_bgsend(ldns_buffer *qbin,
const struct sockaddr_storage *to, socklen_t tolen,
struct timeval timeout)
{
int s = ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
return s > 0 ? s : 0;
}
int
ldns_tcp_bgsend2(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 == -1) {
return LDNS_STATUS_ERR;
}
answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
close_socket(sockfd);
if (!answer) {
/* oops */
return LDNS_STATUS_NETWORK_ERR;
}
*result = answer;
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))
== SOCK_INVALID) {
return 0;
}
#endif
return sockfd;
}
int
ldns_udp_connect2(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))
== SOCK_INVALID) {
return -1;
}
#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_connect2(to, timeout);
if (sockfd == -1) {
return -1;
}
if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){
close_socket(sockfd);
return -1;
}
if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
close_socket(sockfd);
return -1;
}
return sockfd;
}
int
ldns_udp_bgsend(ldns_buffer *qbin,
const struct sockaddr_storage *to , socklen_t tolen,
struct timeval timeout)
{
int s = ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
return s > 0 ? s : 0;
}
int
ldns_udp_bgsend2(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 == -1) {
return LDNS_STATUS_SOCKET_ERROR;
}
/* wait for an response*/
if(!ldns_sock_wait(sockfd, timeout, 0)) {
close_socket(sockfd);
return LDNS_STATUS_NETWORK_ERR;
}
/* set to nonblocking, so if the checksum is bad, it becomes
* an EAGAIN 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);
close_socket(sockfd);
if (!answer) {
/* 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 = 0;
struct sockaddr_storage *ns;
size_t ns_len;
struct timeval tv_s;
struct timeval tv_e;
ldns_rdf **ns_array;
size_t *rtt;
ldns_pkt *reply;
bool all_servers_rtt_inf;
uint8_t retries;
uint8_t *reply_bytes = NULL;
size_t reply_size = 0;
ldns_status status, send_status;
assert(r != NULL);
status = LDNS_STATUS_OK;
rtt = ldns_resolver_rtt(r);
ns_array = ldns_resolver_nameservers(r);
reply = NULL;
ns_len = 0;
all_servers_rtt_inf = true;
if (ldns_resolver_random(r)) {
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) {
/* not reachable nameserver! */
continue;
}
/* maybe verbosity setting?
printf("Sending to ");
ldns_rdf_print(stdout, ns_array[i]);
printf("\n");
*/
ns = ldns_rdf2native_sockaddr_storage(ns_array[i],
ldns_resolver_port(r), &ns_len);
#ifndef S_SPLINT_S
if ((ns->ss_family == AF_INET) &&
(ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) {
/* not reachable */
LDNS_FREE(ns);
continue;
}
if ((ns->ss_family == AF_INET6) &&
(ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) {
/* not reachable */
LDNS_FREE(ns);
continue;
}
#endif
all_servers_rtt_inf = false;
gettimeofday(&tv_s, NULL);
send_status = LDNS_STATUS_ERR;
/* reply_bytes implicitly handles our error */
if (ldns_resolver_usevc(r)) {
for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
send_status =
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;
}
}
} else {
for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
/* ldns_rdf_print(stdout, ns_array[i]); */
send_status =
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;
}
}
}
if (send_status != LDNS_STATUS_OK) {
ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF);
status = send_status;
}
/* obey the fail directive */
if (!reply_bytes) {
/* the current nameserver seems to have a problem, blacklist it */
if (ldns_resolver_fail(r)) {
if(src) {
LDNS_FREE(src);
}
LDNS_FREE(ns);
return LDNS_STATUS_ERR;
} else {
LDNS_FREE(ns);
continue;
}
}
status = ldns_wire2pkt(&reply, reply_bytes, reply_size);
if (status != LDNS_STATUS_OK) {
if(src) LDNS_FREE(src);
LDNS_FREE(reply_bytes);
LDNS_FREE(ns);
return status;
}
assert(reply);
LDNS_FREE(ns);
gettimeofday(&tv_e, NULL);
if (reply) {
ldns_pkt_set_querytime(reply, (uint32_t)
((tv_e.tv_sec - tv_s.tv_sec) * 1000) +
(tv_e.tv_usec - tv_s.tv_usec) / 1000);
ldns_pkt_set_answerfrom(reply,
ldns_rdf_clone(ns_array[i]));
ldns_pkt_set_timestamp(reply, tv_s);
ldns_pkt_set_size(reply, reply_size);
break;
} else {
if (ldns_resolver_fail(r)) {
/* if fail is set bail out, after the first
* one */
break;
}
}
/* wait retrans seconds... */
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;
}
#ifdef HAVE_SSL
if (tsig_mac && reply && reply_bytes) {
if (!ldns_pkt_tsig_verify(reply,
reply_bytes,
reply_size,
ldns_resolver_tsig_keyname(r),
ldns_resolver_tsig_keydata(r), tsig_mac)) {
status = LDNS_STATUS_CRYPTO_TSIG_BOGUS;
}
}
#else
(void)tsig_mac;
#endif /* HAVE_SSL */
LDNS_FREE(reply_bytes);
if (result) {
*result = reply;
}
return status;
}
ssize_t
ldns_tcp_send_query(ldns_buffer *qbin, int sockfd,
const struct sockaddr_storage *to, socklen_t tolen)
{
uint8_t *sendbuf;
ssize_t bytes;
/* add length of packet */
sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2);
if(!sendbuf) return 0;
ldns_write_uint16(sendbuf, ldns_buffer_position(qbin));
memcpy(sendbuf + 2, ldns_buffer_begin(qbin), ldns_buffer_position(qbin));
bytes = sendto(sockfd, (void*)sendbuf,
ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen);
LDNS_FREE(sendbuf);
if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) {
return 0;
}
return bytes;
}
/* don't wait for an answer */
ssize_t
ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to,
socklen_t tolen)
{
ssize_t bytes;
bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin),
ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen);
if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) {
return 0;
}
return bytes;
}
uint8_t *
ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from,
socklen_t *fromlen)
{
uint8_t *wire, *wireout;
ssize_t wire_size;
wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
if (!wire) {
*size = 0;
return NULL;
}
wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0,
(struct sockaddr *)from, fromlen);
/* recvfrom can also return 0 */
if (wire_size == -1 || wire_size == 0) {
*size = 0;
LDNS_FREE(wire);
return NULL;
}
*size = (size_t)wire_size;
wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size);
if(!wireout) LDNS_FREE(wire);
return wireout;
}
uint8_t *
ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout)
{
uint8_t *wire;
uint16_t wire_size;
ssize_t bytes = 0, rc = 0;
wire = LDNS_XMALLOC(uint8_t, 2);
if (!wire) {
*size = 0;
return NULL;
}
while (bytes < 2) {
if(!ldns_sock_wait(sockfd, timeout, 0)) {
*size = 0;
LDNS_FREE(wire);
return NULL;
}
rc = recv(sockfd, (void*) (wire + bytes),
(size_t) (2 - bytes), 0);
if (rc == -1 || rc == 0) {
*size = 0;
LDNS_FREE(wire);
return NULL;
}
bytes += rc;
}
wire_size = ldns_read_uint16(wire);
LDNS_FREE(wire);
wire = LDNS_XMALLOC(uint8_t, wire_size);
if (!wire) {
*size = 0;
return NULL;
}
bytes = 0;
while (bytes < (ssize_t) wire_size) {
if(!ldns_sock_wait(sockfd, timeout, 0)) {
*size = 0;
LDNS_FREE(wire);
return NULL;
}
rc = recv(sockfd, (void*) (wire + bytes),
(size_t) (wire_size - bytes), 0);
if (rc == -1 || rc == 0) {
LDNS_FREE(wire);
*size = 0;
return NULL;
}
bytes += rc;
}
*size = (size_t) bytes;
return wire;
}
uint8_t *
ldns_tcp_read_wire(int sockfd, size_t *size)
{
uint8_t *wire;
uint16_t wire_size;
ssize_t bytes = 0, rc = 0;
wire = LDNS_XMALLOC(uint8_t, 2);
if (!wire) {
*size = 0;
return NULL;
}
while (bytes < 2) {
rc = recv(sockfd, (void*) (wire + bytes),
(size_t) (2 - bytes), 0);
if (rc == -1 || rc == 0) {
*size = 0;
LDNS_FREE(wire);
return NULL;
}
bytes += rc;
}
wire_size = ldns_read_uint16(wire);
LDNS_FREE(wire);
wire = LDNS_XMALLOC(uint8_t, wire_size);
if (!wire) {
*size = 0;
return NULL;
}
bytes = 0;
while (bytes < (ssize_t) wire_size) {
rc = recv(sockfd, (void*) (wire + bytes),
(size_t) (wire_size - bytes), 0);
if (rc == -1 || rc == 0) {
LDNS_FREE(wire);
*size = 0;
return NULL;
}
bytes += rc;
}
*size = (size_t) bytes;
return wire;
}
#ifndef S_SPLINT_S
ldns_rdf *
ldns_sockaddr_storage2rdf(const struct sockaddr_storage *sock, uint16_t *port)
{
ldns_rdf *addr;
struct sockaddr_in *data_in;
struct sockaddr_in6 *data_in6;
switch(sock->ss_family) {
case AF_INET:
data_in = (struct sockaddr_in*)sock;
if (port) {
*port = ntohs((uint16_t)data_in->sin_port);
}
addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A,
LDNS_IP4ADDRLEN, &data_in->sin_addr);
break;
case AF_INET6:
data_in6 = (struct sockaddr_in6*)sock;
if (port) {
*port = ntohs((uint16_t)data_in6->sin6_port);
}
addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA,
LDNS_IP6ADDRLEN, &data_in6->sin6_addr);
break;
default:
if (port) {
*port = 0;
}
return NULL;
}
return addr;
}
#endif
/* code from resolver.c */
ldns_status
ldns_axfr_start(ldns_resolver *resolver, const 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;
ldns_status status;
if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) {
return LDNS_STATUS_ERR;
}
query = ldns_pkt_query_new(ldns_rdf_clone(domain), LDNS_RR_TYPE_AXFR, class, 0);
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 */
for (ns_i = 0;
ns_i < ldns_resolver_nameserver_count(resolver) &&
resolver->_socket == SOCK_INVALID;
ns_i++) {
if (ns != NULL) {
LDNS_FREE(ns);
}
ns = ldns_rdf2native_sockaddr_storage(
resolver->_nameservers[ns_i],
ldns_resolver_port(resolver), &ns_len);
#ifndef S_SPLINT_S
if ((ns->ss_family == AF_INET) &&
(ldns_resolver_ip6(resolver) == LDNS_RESOLV_INET6)) {
/* not reachable */
LDNS_FREE(ns);
ns = NULL;
continue;
}
if ((ns->ss_family == AF_INET6) &&
(ldns_resolver_ip6(resolver) == LDNS_RESOLV_INET)) {
/* not reachable */
LDNS_FREE(ns);
ns = NULL;
continue;
}
#endif
resolver->_socket = ldns_tcp_connect_from(
ns, (socklen_t)ns_len,
src, (socklen_t)src_len,
ldns_resolver_timeout(resolver));
}
if (src) {
LDNS_FREE(src);
}
if (resolver->_socket == SOCK_INVALID) {
ldns_pkt_free(query);
LDNS_FREE(ns);
return LDNS_STATUS_NETWORK_ERR;
}
#ifdef HAVE_SSL
if (ldns_resolver_tsig_keyname(resolver) && ldns_resolver_tsig_keydata(resolver)) {
status = ldns_pkt_tsig_sign(query,
ldns_resolver_tsig_keyname(resolver),
ldns_resolver_tsig_keydata(resolver),
300, ldns_resolver_tsig_algorithm(resolver), NULL);
if (status != LDNS_STATUS_OK) {
/* to prevent problems on subsequent calls to
* ldns_axfr_start we have to close the socket here! */
close_socket(resolver->_socket);
resolver->_socket = 0;
ldns_pkt_free(query);
LDNS_FREE(ns);
return LDNS_STATUS_CRYPTO_TSIG_ERR;
}
}
#endif /* HAVE_SSL */
/* Convert the query to a buffer
* Is this necessary?
*/
query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN);
if(!query_wire) {
ldns_pkt_free(query);
LDNS_FREE(ns);
close_socket(resolver->_socket);
return LDNS_STATUS_MEM_ERR;
}
status = ldns_pkt2buffer_wire(query_wire, query);
if (status != LDNS_STATUS_OK) {
ldns_pkt_free(query);
ldns_buffer_free(query_wire);
LDNS_FREE(ns);
/* to prevent problems on subsequent calls to ldns_axfr_start
* we have to close the socket here! */
close_socket(resolver->_socket);
resolver->_socket = 0;
return status;
}
/* Send the query */
if (ldns_tcp_send_query(query_wire, resolver->_socket, ns,
(socklen_t)ns_len) == 0) {
ldns_pkt_free(query);
ldns_buffer_free(query_wire);
LDNS_FREE(ns);
/* to prevent problems on subsequent calls to ldns_axfr_start
* we have to close the socket here! */
close_socket(resolver->_socket);
return LDNS_STATUS_NETWORK_ERR;
}
ldns_pkt_free(query);
ldns_buffer_free(query_wire);
LDNS_FREE(ns);
/*
* The AXFR is done once the second SOA record is sent
*/
resolver->_axfr_soa_count = 0;
return LDNS_STATUS_OK;
}
ldns_buffer_free
void ldns_buffer_free(ldns_buffer *buffer)
frees the buffer.
Definition buffer.c:137
ldns_buffer
struct ldns_struct_buffer ldns_buffer
Definition buffer.h:72
ldns_buffer_new
ldns_buffer * ldns_buffer_new(size_t capacity)
creates a new buffer with the specified capacity.
Definition buffer.c:16
LDNS_MIN_BUFLEN
#define LDNS_MIN_BUFLEN
number of initial bytes in buffer of which we cannot tell the size before hand
Definition buffer.h:33
ATTR_UNUSED
#define ATTR_UNUSED(x)
Definition common.h:72
config.h
close_socket
#define close_socket(_s)
Definition config.h:780
SOCK_INVALID
#define SOCK_INVALID
Definition config.h:779
FD_SET_T
#define FD_SET_T
Definition config.h:689
LDNS_STATUS_NETWORK_ERR
@ LDNS_STATUS_NETWORK_ERR
Definition error.h:46
LDNS_STATUS_SOCKET_ERROR
@ LDNS_STATUS_SOCKET_ERROR
Definition error.h:96
LDNS_STATUS_ERR
@ LDNS_STATUS_ERR
Definition error.h:37
LDNS_STATUS_MEM_ERR
@ LDNS_STATUS_MEM_ERR
Definition error.h:34
LDNS_STATUS_CRYPTO_TSIG_BOGUS
@ LDNS_STATUS_CRYPTO_TSIG_BOGUS
Definition error.h:64
LDNS_STATUS_ADDRESS_ERR
@ LDNS_STATUS_ADDRESS_ERR
Definition error.h:47
LDNS_STATUS_OK
@ LDNS_STATUS_OK
Definition error.h:26
LDNS_STATUS_CRYPTO_TSIG_ERR
@ LDNS_STATUS_CRYPTO_TSIG_ERR
Definition error.h:65
LDNS_STATUS_RES_NO_NS
@ LDNS_STATUS_RES_NO_NS
Definition error.h:70
ldns_status
enum ldns_enum_status ldns_status
Definition error.h:148
ldns_pkt2buffer_wire
ldns_status ldns_pkt2buffer_wire(ldns_buffer *output, const ldns_pkt *pkt)
Copies the packet data to the buffer in wire format.
Definition host2wire.c:376
LDNS_IP4ADDRLEN
#define LDNS_IP4ADDRLEN
Definition ldns.h:132
LDNS_IP6ADDRLEN
#define LDNS_IP6ADDRLEN
Definition ldns.h:133
LDNS_PORT
#define LDNS_PORT
Definition ldns.h:134
ldns_udp_connect
int ldns_udp_connect(const struct sockaddr_storage *to, struct timeval timeout __attribute__((unused)))
Definition net.c:372
ldns_udp_read_wire
uint8_t * ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from, socklen_t *fromlen)
Gives back a raw packet from the wire and reads the header data from the given socket.
Definition net.c:721
ldns_axfr_start
ldns_status ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class class)
Prepares the resolver for an axfr query The query is sent and the answers can be read with ldns_axfr_...
Definition net.c:895
ldns_send
ldns_status ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt)
Sends ptk to the nameserver at the resolver object.
Definition net.c:38
ldns_tcp_read_wire_timeout
uint8_t * ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout)
Gives back a raw packet from the wire and reads the header data from the given socket.
Definition net.c:751
ldns_tcp_read_wire
uint8_t * ldns_tcp_read_wire(int sockfd, size_t *size)
This routine may block.
Definition net.c:810
ldns_rdf2native_sockaddr_storage
struct sockaddr_storage * ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, uint16_t port, size_t *size)
returns the native sockaddr representation from the rdf.
Definition net.c:104
ldns_tcp_send_query
ssize_t ldns_tcp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen)
send a query via tcp to a server.
Definition net.c:681
ldns_sockaddr_storage2rdf
ldns_rdf * ldns_sockaddr_storage2rdf(const struct sockaddr_storage *sock, uint16_t *port)
returns an rdf with the sockaddr info.
Definition net.c:860
ldns_tcp_connect
int ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout)
Create a tcp socket to the specified address This function has the flaw that it returns 0 on failure,...
Definition net.c:283
ldns_tcp_connect2
int ldns_tcp_connect2(const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout)
Create a tcp socket to the specified address.
Definition net.c:291
ldns_send_buffer
ldns_status ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac)
Sends and ldns_buffer (presumably containing a packet to the nameserver at the resolver object.
Definition net.c:492
ldns_udp_bgsend
int ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout)
Send an udp query and don't wait for an answer but return the socket This function has the flaw that ...
Definition net.c:428
ldns_tcp_bgsend
int ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout)
Send an tcp query and don't wait for an answer but return the socket This function has the flaw that ...
Definition net.c:316
ldns_tcp_bgsend2
int ldns_tcp_bgsend2(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout)
Send an tcp query and don't wait for an answer but return the socket.
Definition net.c:325
ldns_udp_bgsend2
int ldns_udp_bgsend2(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, struct timeval timeout)
Send an udp query and don't wait for an answer but return the socket.
Definition net.c:437
ldns_udp_send
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)
Sends a buffer to an ip using udp and return the response as a ldns_pkt.
Definition net.c:483
ldns_tcp_send
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)
Sends a buffer to an ip using tcp and return the response as a ldns_pkt.
Definition net.c:363
ldns_udp_send_query
ssize_t ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, socklen_t tolen)
send a query via udp to a server.
Definition net.c:706
ldns_udp_connect2
int ldns_udp_connect2(const struct sockaddr_storage *to, struct timeval timeout __attribute__((unused)))
Definition net.c:387
LDNS_MAX_PACKETLEN
#define LDNS_MAX_PACKETLEN
Definition packet.h:24
ldns_pkt_free
void ldns_pkt_free(ldns_pkt *packet)
frees the packet structure and all data that it contains.
Definition packet.c:897
ldns_pkt_set_timestamp
void ldns_pkt_set_timestamp(ldns_pkt *p, struct timeval timeval)
Set the packet's timestamp.
Definition packet.c:599
ldns_pkt_set_size
void ldns_pkt_set_size(ldns_pkt *p, size_t s)
Set the packet's size.
Definition packet.c:606
ldns_pkt_set_answerfrom
void ldns_pkt_set_answerfrom(ldns_pkt *p, ldns_rdf *r)
Set the packet's answering server.
Definition packet.c:593
ldns_pkt_query_new
ldns_pkt * ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags)
creates a packet with a query in it for the given name, type and class.
Definition packet.c:1150
ldns_pkt
struct ldns_struct_pkt ldns_pkt
Definition packet.h:272
ldns_pkt_tsig
ldns_rr * ldns_pkt_tsig(const ldns_pkt *p)
Return the packet's tsig pseudo rr's.
Definition packet.c:465
ldns_pkt_set_querytime
void ldns_pkt_set_querytime(ldns_pkt *p, uint32_t t)
Set the packet's query time.
Definition packet.c:587
ldns_rdf_data
uint8_t * ldns_rdf_data(const ldns_rdf *rd)
returns the data of the rdf.
Definition rdata.c:38
ldns_rdf_clone
ldns_rdf * ldns_rdf_clone(const ldns_rdf *rd)
clones a rdf structure.
Definition rdata.c:222
ldns_rdf_get_type
ldns_rdf_type ldns_rdf_get_type(const ldns_rdf *rd)
returns the type of the rdf.
Definition rdata.c:31
ldns_rdf_new_frm_data
ldns_rdf * ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data)
allocates a new rdf structure and fills it.
Definition rdata.c:193
LDNS_RDF_TYPE_AAAA
@ LDNS_RDF_TYPE_AAAA
AAAA record.
Definition rdata.h:60
LDNS_RDF_TYPE_A
@ LDNS_RDF_TYPE_A
A record.
Definition rdata.h:58
ldns_rdf_size
size_t ldns_rdf_size(const ldns_rdf *rd)
returns the size of the rdf.
Definition rdata.c:24
ldns_rdf
struct ldns_struct_rdf ldns_rdf
Definition rdata.h:205
ldns_resolver_rtt
size_t * ldns_resolver_rtt(const ldns_resolver *r)
Return the used round trip times for the nameservers.
Definition resolver.c:177
ldns_resolver_tsig_keydata
const char * ldns_resolver_tsig_keydata(const ldns_resolver *r)
Return the tsig keydata as used by the nameserver.
Definition resolver.c:219
ldns_resolver_fail
signed char ldns_resolver_fail(const ldns_resolver *r)
Does the resolver only try the first nameserver.
Definition resolver.c:84
ldns_resolver_set_nameserver_rtt
void ldns_resolver_set_nameserver_rtt(ldns_resolver *r, size_t pos, size_t value)
Set round trip time for a specific nameserver.
Definition resolver.c:506
LDNS_RESOLV_RTT_INF
#define LDNS_RESOLV_RTT_INF
Definition resolver.h:53
ldns_resolver_tsig_keyname
const char * ldns_resolver_tsig_keyname(const ldns_resolver *r)
Return the tsig keyname as used by the nameserver.
Definition resolver.c:207
ldns_resolver_nameserver_count
size_t ldns_resolver_nameserver_count(const ldns_resolver *r)
How many nameserver are configured in the resolver.
Definition resolver.c:114
ldns_resolver_nameservers
ldns_rdf ** ldns_resolver_nameservers(const ldns_resolver *r)
Return the configured nameserver ip address.
Definition resolver.c:108
ldns_resolver_retrans
uint8_t ldns_resolver_retrans(const ldns_resolver *r)
Get the retransmit interval.
Definition resolver.c:48
ldns_resolver
struct ldns_struct_resolver ldns_resolver
Definition resolver.h:147
ldns_resolver_nameservers_randomize
void ldns_resolver_nameservers_randomize(ldns_resolver *r)
Randomize the nameserver list in the resolver.
Definition resolver.c:1541
ldns_resolver_timeout
struct timeval ldns_resolver_timeout(const ldns_resolver *r)
What is the timeout on socket connections.
Definition resolver.c:201
ldns_resolver_ip6
uint8_t ldns_resolver_ip6(const ldns_resolver *r)
Does the resolver use ip6 or ip4.
Definition resolver.c:60
ldns_resolver_random
signed char ldns_resolver_random(const ldns_resolver *r)
Does the resolver randomize the nameserver before usage.
Definition resolver.c:225
ldns_resolver_retry
uint8_t ldns_resolver_retry(const ldns_resolver *r)
Get the number of retries.
Definition resolver.c:42
ldns_resolver_source
ldns_rdf * ldns_resolver_source(const ldns_resolver *r)
Get the source address the resolver should use.
Definition resolver.c:30
LDNS_RESOLV_INET
#define LDNS_RESOLV_INET
Definition resolver.h:50
ldns_resolver_usevc
signed char ldns_resolver_usevc(const ldns_resolver *r)
Does the resolver use tcp or udp.
Definition resolver.c:171
ldns_resolver_tsig_algorithm
const char * ldns_resolver_tsig_algorithm(const ldns_resolver *r)
Return the tsig algorithm as used by the nameserver.
Definition resolver.c:213
ldns_resolver_port
uint16_t ldns_resolver_port(const ldns_resolver *r)
Get the port the resolver should use.
Definition resolver.c:24
LDNS_RESOLV_INET6
#define LDNS_RESOLV_INET6
Definition resolver.h:51
LDNS_RR_TYPE_AXFR
@ LDNS_RR_TYPE_AXFR
Definition rr.h:218
ldns_rr_rdf
ldns_rdf * ldns_rr_rdf(const ldns_rr *rr, size_t nr)
returns the rdata field member counter.
Definition rr.c:913
ldns_rr_class
enum ldns_enum_rr_class ldns_rr_class
Definition rr.h:61
ldns_struct_resolver::_socket
int _socket
Keep some things to make AXFR possible.
Definition resolver.h:117
ldns_struct_resolver::_nameservers
ldns_rdf ** _nameservers
Array of nameservers to query (IP addresses or dnames).
Definition resolver.h:65
ldns_struct_resolver::_axfr_soa_count
int _axfr_soa_count
Count the number of LDNS_RR_TYPE_SOA RRs we have seen so far (the second one signifies the end of the...
Definition resolver.h:121
ldns_pkt_tsig_verify
bool ldns_pkt_tsig_verify(ldns_pkt *pkt, const uint8_t *wire, size_t wire_size, const char *key_name, const char *key_data, const ldns_rdf *mac)
verifies the tsig rr for the given packet and key.
Definition tsig.c:288
ldns_pkt_tsig_sign
ldns_status ldns_pkt_tsig_sign(ldns_pkt *pkt, const char *key_name, const char *key_data, uint16_t fudge, const char *algorithm_name, const ldns_rdf *query_mac)
creates a tsig rr for the given packet and key.
Definition tsig.c:376
LDNS_FREE
#define LDNS_FREE(ptr)
Definition util.h:60
LDNS_MALLOC
#define LDNS_MALLOC(type)
Memory management macros.
Definition util.h:49
LDNS_XMALLOC
#define LDNS_XMALLOC(type, count)
Definition util.h:51
LDNS_XREALLOC
#define LDNS_XREALLOC(ptr, type, count)
Definition util.h:57
ldns_wire2pkt
ldns_status ldns_wire2pkt(ldns_pkt **packet, const uint8_t *data, size_t len)
converts the data on the uint8_t bytearray (in wire format) to a DNS packet.
Definition wire2host.c:403