Changeset View
Changeset View
Standalone View
Standalone View
contrib/ldns/net.c
Show First 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen, | ||||
const struct sockaddr_storage *from, socklen_t fromlen, | const struct sockaddr_storage *from, socklen_t fromlen, | ||||
struct timeval timeout) | struct timeval timeout) | ||||
{ | { | ||||
int sockfd; | int sockfd; | ||||
#ifndef S_SPLINT_S | #ifndef S_SPLINT_S | ||||
if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM, | if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM, | ||||
IPPROTO_TCP)) == SOCK_INVALID) { | IPPROTO_TCP)) == SOCK_INVALID) { | ||||
return 0; | return -1; | ||||
} | } | ||||
#endif | #endif | ||||
if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == SOCK_INVALID){ | if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == SOCK_INVALID){ | ||||
return 0; | close_socket(sockfd); | ||||
return -1; | |||||
} | } | ||||
/* perform nonblocking connect, to be able to wait with select() */ | /* perform nonblocking connect, to be able to wait with select() */ | ||||
ldns_sock_nonblock(sockfd); | ldns_sock_nonblock(sockfd); | ||||
if (connect(sockfd, (struct sockaddr*)to, tolen) == SOCK_INVALID) { | if (connect(sockfd, (struct sockaddr*)to, tolen) == SOCK_INVALID) { | ||||
#ifndef USE_WINSOCK | #ifndef USE_WINSOCK | ||||
#ifdef EINPROGRESS | #ifdef EINPROGRESS | ||||
if(errno != EINPROGRESS) { | if(errno != EINPROGRESS) { | ||||
#else | #else | ||||
if(1) { | if(1) { | ||||
#endif | #endif | ||||
close_socket(sockfd); | close_socket(sockfd); | ||||
return 0; | return -1; | ||||
} | } | ||||
#else /* USE_WINSOCK */ | #else /* USE_WINSOCK */ | ||||
if(WSAGetLastError() != WSAEINPROGRESS && | if(WSAGetLastError() != WSAEINPROGRESS && | ||||
WSAGetLastError() != WSAEWOULDBLOCK) { | WSAGetLastError() != WSAEWOULDBLOCK) { | ||||
close_socket(sockfd); | close_socket(sockfd); | ||||
return 0; | return -1; | ||||
} | } | ||||
#endif | #endif | ||||
/* error was only telling us that it would block */ | /* error was only telling us that it would block */ | ||||
} | } | ||||
/* wait(write) until connected or error */ | /* wait(write) until connected or error */ | ||||
while(1) { | while(1) { | ||||
int error = 0; | int error = 0; | ||||
socklen_t len = (socklen_t)sizeof(error); | socklen_t len = (socklen_t)sizeof(error); | ||||
if(!ldns_sock_wait(sockfd, timeout, 1)) { | if(!ldns_sock_wait(sockfd, timeout, 1)) { | ||||
close_socket(sockfd); | close_socket(sockfd); | ||||
return 0; | return -1; | ||||
} | } | ||||
/* check if there is a pending error for nonblocking connect */ | /* check if there is a pending error for nonblocking connect */ | ||||
if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error, | if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error, | ||||
&len) < 0) { | &len) < 0) { | ||||
#ifndef USE_WINSOCK | #ifndef USE_WINSOCK | ||||
error = errno; /* on solaris errno is error */ | error = errno; /* on solaris errno is error */ | ||||
#else | #else | ||||
error = WSAGetLastError(); | error = WSAGetLastError(); | ||||
#endif | #endif | ||||
} | } | ||||
#ifndef USE_WINSOCK | #ifndef USE_WINSOCK | ||||
#if defined(EINPROGRESS) && defined(EWOULDBLOCK) | #if defined(EINPROGRESS) && defined(EWOULDBLOCK) | ||||
if(error == EINPROGRESS || error == EWOULDBLOCK) | if(error == EINPROGRESS || error == EWOULDBLOCK) | ||||
continue; /* try again */ | continue; /* try again */ | ||||
#endif | #endif | ||||
else if(error != 0) { | else if(error != 0) { | ||||
close_socket(sockfd); | close_socket(sockfd); | ||||
/* error in errno for our user */ | /* error in errno for our user */ | ||||
errno = error; | errno = error; | ||||
return 0; | return -1; | ||||
} | } | ||||
#else /* USE_WINSOCK */ | #else /* USE_WINSOCK */ | ||||
if(error == WSAEINPROGRESS) | if(error == WSAEINPROGRESS) | ||||
continue; | continue; | ||||
else if(error == WSAEWOULDBLOCK) | else if(error == WSAEWOULDBLOCK) | ||||
continue; | continue; | ||||
else if(error != 0) { | else if(error != 0) { | ||||
close_socket(sockfd); | close_socket(sockfd); | ||||
errno = error; | errno = error; | ||||
return 0; | return -1; | ||||
} | } | ||||
#endif /* USE_WINSOCK */ | #endif /* USE_WINSOCK */ | ||||
/* connected */ | /* connected */ | ||||
break; | break; | ||||
} | } | ||||
/* set the socket blocking again */ | /* set the socket blocking again */ | ||||
ldns_sock_block(sockfd); | ldns_sock_block(sockfd); | ||||
return sockfd; | return sockfd; | ||||
} | } | ||||
int | int | ||||
ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, | ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, | ||||
struct timeval timeout) | 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); | return ldns_tcp_connect_from(to, tolen, NULL, 0, timeout); | ||||
} | } | ||||
static int | static int | ||||
ldns_tcp_bgsend_from(ldns_buffer *qbin, | ldns_tcp_bgsend_from(ldns_buffer *qbin, | ||||
const struct sockaddr_storage *to, socklen_t tolen, | const struct sockaddr_storage *to, socklen_t tolen, | ||||
const struct sockaddr_storage *from, socklen_t fromlen, | const struct sockaddr_storage *from, socklen_t fromlen, | ||||
struct timeval timeout) | struct timeval timeout) | ||||
{ | { | ||||
int sockfd; | int sockfd; | ||||
sockfd = ldns_tcp_connect_from(to, tolen, from, fromlen, timeout); | sockfd = ldns_tcp_connect_from(to, tolen, from, fromlen, timeout); | ||||
if (sockfd == 0) { | if (sockfd >= 0 && ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) { | ||||
return 0; | |||||
} | |||||
if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) { | |||||
close_socket(sockfd); | close_socket(sockfd); | ||||
return 0; | return -1; | ||||
} | } | ||||
return sockfd; | return sockfd; | ||||
} | } | ||||
int | int | ||||
ldns_tcp_bgsend(ldns_buffer *qbin, | ldns_tcp_bgsend(ldns_buffer *qbin, | ||||
const struct sockaddr_storage *to, socklen_t tolen, | const struct sockaddr_storage *to, socklen_t tolen, | ||||
struct timeval timeout) | 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); | 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 | /* keep in mind that in DNS tcp messages the first 2 bytes signal the | ||||
* amount data to expect | * amount data to expect | ||||
*/ | */ | ||||
static ldns_status | static ldns_status | ||||
ldns_tcp_send_from(uint8_t **result, ldns_buffer *qbin, | ldns_tcp_send_from(uint8_t **result, ldns_buffer *qbin, | ||||
const struct sockaddr_storage *to, socklen_t tolen, | const struct sockaddr_storage *to, socklen_t tolen, | ||||
const struct sockaddr_storage *from, socklen_t fromlen, | const struct sockaddr_storage *from, socklen_t fromlen, | ||||
struct timeval timeout, size_t *answer_size) | struct timeval timeout, size_t *answer_size) | ||||
{ | { | ||||
int sockfd; | int sockfd; | ||||
uint8_t *answer; | uint8_t *answer; | ||||
sockfd = ldns_tcp_bgsend_from(qbin, to, tolen, from, fromlen, timeout); | sockfd = ldns_tcp_bgsend_from(qbin, to, tolen, from, fromlen, timeout); | ||||
if (sockfd == 0) { | if (sockfd == -1) { | ||||
return LDNS_STATUS_ERR; | return LDNS_STATUS_ERR; | ||||
} | } | ||||
answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout); | answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout); | ||||
close_socket(sockfd); | close_socket(sockfd); | ||||
if (*answer_size == 0) { | if (!answer) { | ||||
/* oops */ | /* oops */ | ||||
return LDNS_STATUS_NETWORK_ERR; | return LDNS_STATUS_NETWORK_ERR; | ||||
} | } | ||||
/* resize accordingly */ | *result = answer; | ||||
*result = LDNS_XREALLOC(answer, uint8_t, (size_t)*answer_size); | |||||
if(!*result) { | |||||
LDNS_FREE(answer); | |||||
return LDNS_STATUS_MEM_ERR; | |||||
} | |||||
return LDNS_STATUS_OK; | return LDNS_STATUS_OK; | ||||
} | } | ||||
ldns_status | ldns_status | ||||
ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, | ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, | ||||
const struct sockaddr_storage *to, socklen_t tolen, | const struct sockaddr_storage *to, socklen_t tolen, | ||||
struct timeval timeout, size_t *answer_size) | struct timeval timeout, size_t *answer_size) | ||||
{ | { | ||||
return ldns_tcp_send_from(result, qbin, | return ldns_tcp_send_from(result, qbin, | ||||
to, tolen, NULL, 0, timeout, answer_size); | to, tolen, NULL, 0, timeout, answer_size); | ||||
} | } | ||||
int | int | ||||
ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout)) | ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout)) | ||||
{ | { | ||||
int sockfd; | int sockfd; | ||||
#ifndef S_SPLINT_S | #ifndef S_SPLINT_S | ||||
if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM, | if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM, | ||||
IPPROTO_UDP)) | IPPROTO_UDP)) | ||||
== -1) { | == SOCK_INVALID) { | ||||
return 0; | return 0; | ||||
} | } | ||||
#endif | #endif | ||||
return sockfd; | 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 | static int | ||||
ldns_udp_bgsend_from(ldns_buffer *qbin, | ldns_udp_bgsend_from(ldns_buffer *qbin, | ||||
const struct sockaddr_storage *to , socklen_t tolen, | const struct sockaddr_storage *to , socklen_t tolen, | ||||
const struct sockaddr_storage *from, socklen_t fromlen, | const struct sockaddr_storage *from, socklen_t fromlen, | ||||
struct timeval timeout) | struct timeval timeout) | ||||
{ | { | ||||
int sockfd; | int sockfd; | ||||
sockfd = ldns_udp_connect(to, timeout); | sockfd = ldns_udp_connect2(to, timeout); | ||||
if (sockfd == 0) { | if (sockfd == -1) { | ||||
return 0; | return -1; | ||||
} | } | ||||
if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){ | if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){ | ||||
return 0; | close_socket(sockfd); | ||||
return -1; | |||||
} | } | ||||
if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) { | if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) { | ||||
close_socket(sockfd); | close_socket(sockfd); | ||||
return 0; | return -1; | ||||
} | } | ||||
return sockfd; | return sockfd; | ||||
} | } | ||||
int | int | ||||
ldns_udp_bgsend(ldns_buffer *qbin, | ldns_udp_bgsend(ldns_buffer *qbin, | ||||
const struct sockaddr_storage *to , socklen_t tolen, | const struct sockaddr_storage *to , socklen_t tolen, | ||||
struct timeval timeout) | 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); | return ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout); | ||||
} | } | ||||
static ldns_status | static ldns_status | ||||
ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin, | ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin, | ||||
const struct sockaddr_storage *to , socklen_t tolen, | const struct sockaddr_storage *to , socklen_t tolen, | ||||
const struct sockaddr_storage *from, socklen_t fromlen, | const struct sockaddr_storage *from, socklen_t fromlen, | ||||
struct timeval timeout, size_t *answer_size) | struct timeval timeout, size_t *answer_size) | ||||
{ | { | ||||
int sockfd; | int sockfd; | ||||
uint8_t *answer; | uint8_t *answer; | ||||
sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout); | sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout); | ||||
if (sockfd == 0) { | if (sockfd == -1) { | ||||
return LDNS_STATUS_SOCKET_ERROR; | return LDNS_STATUS_SOCKET_ERROR; | ||||
} | } | ||||
/* wait for an response*/ | /* wait for an response*/ | ||||
if(!ldns_sock_wait(sockfd, timeout, 0)) { | if(!ldns_sock_wait(sockfd, timeout, 0)) { | ||||
close_socket(sockfd); | close_socket(sockfd); | ||||
return LDNS_STATUS_NETWORK_ERR; | return LDNS_STATUS_NETWORK_ERR; | ||||
} | } | ||||
/* set to nonblocking, so if the checksum is bad, it becomes | /* set to nonblocking, so if the checksum is bad, it becomes | ||||
* an EGAIN error and the ldns_udp_send function does not block, | * an EAGAIN error and the ldns_udp_send function does not block, | ||||
* but returns a 'NETWORK_ERROR' much like a timeout. */ | * but returns a 'NETWORK_ERROR' much like a timeout. */ | ||||
ldns_sock_nonblock(sockfd); | ldns_sock_nonblock(sockfd); | ||||
answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL); | answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL); | ||||
close_socket(sockfd); | close_socket(sockfd); | ||||
if (*answer_size == 0) { | if (!answer) { | ||||
/* oops */ | /* oops */ | ||||
return LDNS_STATUS_NETWORK_ERR; | return LDNS_STATUS_NETWORK_ERR; | ||||
} | } | ||||
*result = answer; | *result = answer; | ||||
return LDNS_STATUS_OK; | return LDNS_STATUS_OK; | ||||
} | } | ||||
ldns_status | ldns_status | ||||
ldns_udp_send(uint8_t **result, ldns_buffer *qbin, | ldns_udp_send(uint8_t **result, ldns_buffer *qbin, | ||||
const struct sockaddr_storage *to , socklen_t tolen, | const struct sockaddr_storage *to , socklen_t tolen, | ||||
struct timeval timeout, size_t *answer_size) | struct timeval timeout, size_t *answer_size) | ||||
{ | { | ||||
return ldns_udp_send_from(result, qbin, to, tolen, NULL, 0, | return ldns_udp_send_from(result, qbin, to, tolen, NULL, 0, | ||||
timeout, answer_size); | timeout, answer_size); | ||||
} | } | ||||
ldns_status | ldns_status | ||||
ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac) | ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac) | ||||
{ | { | ||||
uint8_t i; | uint8_t i; | ||||
struct sockaddr_storage *src = NULL; | struct sockaddr_storage *src = NULL; | ||||
size_t src_len; | size_t src_len = 0; | ||||
struct sockaddr_storage *ns; | struct sockaddr_storage *ns; | ||||
size_t ns_len; | size_t ns_len; | ||||
struct timeval tv_s; | struct timeval tv_s; | ||||
struct timeval tv_e; | struct timeval tv_e; | ||||
ldns_rdf **ns_array; | ldns_rdf **ns_array; | ||||
size_t *rtt; | size_t *rtt; | ||||
ldns_pkt *reply; | ldns_pkt *reply; | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | if (send_status != LDNS_STATUS_OK) { | ||||
ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF); | ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF); | ||||
status = send_status; | status = send_status; | ||||
} | } | ||||
/* obey the fail directive */ | /* obey the fail directive */ | ||||
if (!reply_bytes) { | if (!reply_bytes) { | ||||
/* the current nameserver seems to have a problem, blacklist it */ | /* the current nameserver seems to have a problem, blacklist it */ | ||||
if (ldns_resolver_fail(r)) { | if (ldns_resolver_fail(r)) { | ||||
if(src) { | |||||
LDNS_FREE(src); | |||||
} | |||||
LDNS_FREE(ns); | LDNS_FREE(ns); | ||||
return LDNS_STATUS_ERR; | return LDNS_STATUS_ERR; | ||||
} else { | } else { | ||||
LDNS_FREE(ns); | LDNS_FREE(ns); | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
status = ldns_wire2pkt(&reply, reply_bytes, reply_size); | status = ldns_wire2pkt(&reply, reply_bytes, reply_size); | ||||
if (status != LDNS_STATUS_OK) { | if (status != LDNS_STATUS_OK) { | ||||
if(src) LDNS_FREE(src); | |||||
LDNS_FREE(reply_bytes); | LDNS_FREE(reply_bytes); | ||||
LDNS_FREE(ns); | LDNS_FREE(ns); | ||||
return status; | return status; | ||||
} | } | ||||
assert(reply); | |||||
LDNS_FREE(ns); | LDNS_FREE(ns); | ||||
gettimeofday(&tv_e, NULL); | gettimeofday(&tv_e, NULL); | ||||
if (reply) { | if (reply) { | ||||
ldns_pkt_set_querytime(reply, (uint32_t) | ldns_pkt_set_querytime(reply, (uint32_t) | ||||
((tv_e.tv_sec - tv_s.tv_sec) * 1000) + | ((tv_e.tv_sec - tv_s.tv_sec) * 1000) + | ||||
(tv_e.tv_usec - tv_s.tv_usec) / 1000); | (tv_e.tv_usec - tv_s.tv_usec) / 1000); | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, | ||||
ssize_t bytes; | ssize_t bytes; | ||||
bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin), | bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin), | ||||
ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen); | ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen); | ||||
if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) { | if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) { | ||||
return 0; | return 0; | ||||
} | } | ||||
if ((size_t) bytes != ldns_buffer_position(qbin)) { | |||||
return 0; | |||||
} | |||||
return bytes; | return bytes; | ||||
} | } | ||||
uint8_t * | uint8_t * | ||||
ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from, | ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from, | ||||
socklen_t *fromlen) | socklen_t *fromlen) | ||||
{ | { | ||||
uint8_t *wire, *wireout; | uint8_t *wire, *wireout; | ||||
▲ Show 20 Lines • Show All 222 Lines • ▼ Show 20 Lines | if ((ns->ss_family == AF_INET6) && | ||||
continue; | continue; | ||||
} | } | ||||
#endif | #endif | ||||
resolver->_socket = ldns_tcp_connect_from( | resolver->_socket = ldns_tcp_connect_from( | ||||
ns, (socklen_t)ns_len, | ns, (socklen_t)ns_len, | ||||
src, (socklen_t)src_len, | src, (socklen_t)src_len, | ||||
ldns_resolver_timeout(resolver)); | ldns_resolver_timeout(resolver)); | ||||
} | |||||
if (src) { | |||||
LDNS_FREE(src); | |||||
} | } | ||||
if (resolver->_socket == SOCK_INVALID) { | if (resolver->_socket == SOCK_INVALID) { | ||||
ldns_pkt_free(query); | ldns_pkt_free(query); | ||||
LDNS_FREE(ns); | LDNS_FREE(ns); | ||||
return LDNS_STATUS_NETWORK_ERR; | return LDNS_STATUS_NETWORK_ERR; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 71 Lines • Show Last 20 Lines |