xref: /dflybsd-src/contrib/ldns/net.c (revision 7733acb50455a11cc2ee36edd926ff0fa3361e9a)
1825eb42bSJan Lentfer /*
2825eb42bSJan Lentfer  * net.c
3825eb42bSJan Lentfer  *
4825eb42bSJan Lentfer  * Network implementation
5825eb42bSJan Lentfer  * All network related functions are grouped here
6825eb42bSJan Lentfer  *
7825eb42bSJan Lentfer  * a Net::DNS like library for C
8825eb42bSJan Lentfer  *
9825eb42bSJan Lentfer  * (c) NLnet Labs, 2004-2006
10825eb42bSJan Lentfer  *
11825eb42bSJan Lentfer  * See the file LICENSE for the license
12825eb42bSJan Lentfer  */
13825eb42bSJan Lentfer 
14825eb42bSJan Lentfer #include <ldns/config.h>
15825eb42bSJan Lentfer 
16825eb42bSJan Lentfer #include <ldns/ldns.h>
17825eb42bSJan Lentfer 
18825eb42bSJan Lentfer #ifdef HAVE_NETINET_IN_H
19825eb42bSJan Lentfer #include <netinet/in.h>
20825eb42bSJan Lentfer #endif
21825eb42bSJan Lentfer #ifdef HAVE_SYS_SOCKET_H
22825eb42bSJan Lentfer #include <sys/socket.h>
23825eb42bSJan Lentfer #endif
24825eb42bSJan Lentfer #ifdef HAVE_NETDB_H
25825eb42bSJan Lentfer #include <netdb.h>
26825eb42bSJan Lentfer #endif
27825eb42bSJan Lentfer #ifdef HAVE_ARPA_INET_H
28825eb42bSJan Lentfer #include <arpa/inet.h>
29825eb42bSJan Lentfer #endif
30825eb42bSJan Lentfer #include <sys/time.h>
31825eb42bSJan Lentfer #include <errno.h>
32825eb42bSJan Lentfer #include <fcntl.h>
335340022aSzrj #ifdef HAVE_POLL
345340022aSzrj #include <poll.h>
355340022aSzrj #endif
36825eb42bSJan Lentfer 
37825eb42bSJan Lentfer ldns_status
ldns_send(ldns_pkt ** result_packet,ldns_resolver * r,const ldns_pkt * query_pkt)38825eb42bSJan Lentfer ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt)
39825eb42bSJan Lentfer {
40825eb42bSJan Lentfer 	ldns_buffer *qb;
41825eb42bSJan Lentfer 	ldns_status result;
42825eb42bSJan Lentfer 	ldns_rdf *tsig_mac = NULL;
43825eb42bSJan Lentfer 
44825eb42bSJan Lentfer 	qb = ldns_buffer_new(LDNS_MIN_BUFLEN);
45825eb42bSJan Lentfer 
46825eb42bSJan Lentfer 	if (query_pkt && ldns_pkt_tsig(query_pkt)) {
47825eb42bSJan Lentfer 		tsig_mac = ldns_rr_rdf(ldns_pkt_tsig(query_pkt), 3);
48825eb42bSJan Lentfer 	}
49825eb42bSJan Lentfer 
50825eb42bSJan Lentfer 	if (!query_pkt ||
51825eb42bSJan Lentfer 	    ldns_pkt2buffer_wire(qb, query_pkt) != LDNS_STATUS_OK) {
52825eb42bSJan Lentfer 		result = LDNS_STATUS_ERR;
53825eb42bSJan Lentfer 	} else {
54825eb42bSJan Lentfer         	result = ldns_send_buffer(result_packet, r, qb, tsig_mac);
55825eb42bSJan Lentfer 	}
56825eb42bSJan Lentfer 
57825eb42bSJan Lentfer 	ldns_buffer_free(qb);
58825eb42bSJan Lentfer 
59825eb42bSJan Lentfer 	return result;
60825eb42bSJan Lentfer }
61825eb42bSJan Lentfer 
625340022aSzrj /* code from rdata.c */
635340022aSzrj static struct sockaddr_storage *
ldns_rdf2native_sockaddr_storage_port(const ldns_rdf * rd,uint16_t port,size_t * size)645340022aSzrj ldns_rdf2native_sockaddr_storage_port(
655340022aSzrj 		const ldns_rdf *rd, uint16_t port, size_t *size)
665340022aSzrj {
675340022aSzrj         struct sockaddr_storage *data;
685340022aSzrj         struct sockaddr_in  *data_in;
695340022aSzrj         struct sockaddr_in6 *data_in6;
705340022aSzrj 
715340022aSzrj         data = LDNS_MALLOC(struct sockaddr_storage);
725340022aSzrj         if (!data) {
735340022aSzrj                 return NULL;
745340022aSzrj         }
755340022aSzrj 	/* zero the structure for portability */
765340022aSzrj 	memset(data, 0, sizeof(struct sockaddr_storage));
775340022aSzrj 
785340022aSzrj         switch(ldns_rdf_get_type(rd)) {
795340022aSzrj                 case LDNS_RDF_TYPE_A:
805340022aSzrj #ifndef S_SPLINT_S
815340022aSzrj                         data->ss_family = AF_INET;
825340022aSzrj #endif
835340022aSzrj                         data_in = (struct sockaddr_in*) data;
845340022aSzrj                         data_in->sin_port = (in_port_t)htons(port);
855340022aSzrj                         memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd));
865340022aSzrj                         *size = sizeof(struct sockaddr_in);
875340022aSzrj                         return data;
885340022aSzrj                 case LDNS_RDF_TYPE_AAAA:
895340022aSzrj #ifndef S_SPLINT_S
905340022aSzrj                         data->ss_family = AF_INET6;
915340022aSzrj #endif
925340022aSzrj                         data_in6 = (struct sockaddr_in6*) data;
935340022aSzrj                         data_in6->sin6_port = (in_port_t)htons(port);
945340022aSzrj                         memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd));
955340022aSzrj                         *size = sizeof(struct sockaddr_in6);
965340022aSzrj                         return data;
975340022aSzrj                 default:
985340022aSzrj                         LDNS_FREE(data);
995340022aSzrj                         return NULL;
1005340022aSzrj         }
1015340022aSzrj }
1025340022aSzrj 
1035340022aSzrj struct sockaddr_storage *
ldns_rdf2native_sockaddr_storage(const ldns_rdf * rd,uint16_t port,size_t * size)1045340022aSzrj ldns_rdf2native_sockaddr_storage(
1055340022aSzrj 		const ldns_rdf *rd, uint16_t port, size_t *size)
1065340022aSzrj {
1075340022aSzrj 	return ldns_rdf2native_sockaddr_storage_port(
1085340022aSzrj 			rd, (port == 0 ? (uint16_t)LDNS_PORT : port), size);
1095340022aSzrj }
1105340022aSzrj 
1115340022aSzrj /** best effort to set nonblocking */
1125340022aSzrj static void
ldns_sock_nonblock(int sockfd)1135340022aSzrj ldns_sock_nonblock(int sockfd)
1145340022aSzrj {
1155340022aSzrj #ifdef HAVE_FCNTL
1165340022aSzrj 	int flag;
1175340022aSzrj 	if((flag = fcntl(sockfd, F_GETFL)) != -1) {
1185340022aSzrj 		flag |= O_NONBLOCK;
1195340022aSzrj 		if(fcntl(sockfd, F_SETFL, flag) == -1) {
1205340022aSzrj 			/* ignore error, continue blockingly */
1215340022aSzrj 		}
1225340022aSzrj 	}
1235340022aSzrj #elif defined(HAVE_IOCTLSOCKET)
1245340022aSzrj 	unsigned long on = 1;
1255340022aSzrj 	if(ioctlsocket(sockfd, FIONBIO, &on) != 0) {
1265340022aSzrj 		/* ignore error, continue blockingly */
1275340022aSzrj 	}
1285340022aSzrj #endif
1295340022aSzrj }
1305340022aSzrj 
1315340022aSzrj /** best effort to set blocking */
1325340022aSzrj static void
ldns_sock_block(int sockfd)1335340022aSzrj ldns_sock_block(int sockfd)
1345340022aSzrj {
1355340022aSzrj #ifdef HAVE_FCNTL
1365340022aSzrj 	int flag;
1375340022aSzrj 	if((flag = fcntl(sockfd, F_GETFL)) != -1) {
1385340022aSzrj 		flag &= ~O_NONBLOCK;
1395340022aSzrj 		if(fcntl(sockfd, F_SETFL, flag) == -1) {
1405340022aSzrj 			/* ignore error, continue */
1415340022aSzrj 		}
1425340022aSzrj 	}
1435340022aSzrj #elif defined(HAVE_IOCTLSOCKET)
1445340022aSzrj 	unsigned long off = 0;
1455340022aSzrj 	if(ioctlsocket(sockfd, FIONBIO, &off) != 0) {
1465340022aSzrj 		/* ignore error, continue */
1475340022aSzrj 	}
1485340022aSzrj #endif
1495340022aSzrj }
1505340022aSzrj 
1515340022aSzrj /** wait for a socket to become ready */
1525340022aSzrj static int
ldns_sock_wait(int sockfd,struct timeval timeout,int write)1535340022aSzrj ldns_sock_wait(int sockfd, struct timeval timeout, int write)
1545340022aSzrj {
1555340022aSzrj 	int ret;
1565340022aSzrj #ifndef HAVE_POLL
1575340022aSzrj #ifndef S_SPLINT_S
1585340022aSzrj 	fd_set fds;
1595340022aSzrj 	FD_ZERO(&fds);
1605340022aSzrj 	FD_SET(FD_SET_T sockfd, &fds);
1615340022aSzrj 	if(write)
1625340022aSzrj 		ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
1635340022aSzrj 	else
1645340022aSzrj 		ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
1655340022aSzrj #endif
1665340022aSzrj #else
1675340022aSzrj 	struct pollfd pfds[2];
1685340022aSzrj 
1695340022aSzrj 	memset(&pfds[0], 0, sizeof(pfds[0]) * 2);
1705340022aSzrj 
1715340022aSzrj 	pfds[0].fd = sockfd;
1725340022aSzrj 	pfds[0].events = POLLIN|POLLERR;
1735340022aSzrj 
1745340022aSzrj 	if (write) {
1755340022aSzrj 		pfds[0].events |= POLLOUT;
1765340022aSzrj 	}
1775340022aSzrj 
1785340022aSzrj 	ret = poll(pfds, 1, (int)(timeout.tv_sec * 1000
1795340022aSzrj 				+ timeout.tv_usec / 1000));
1805340022aSzrj #endif
1815340022aSzrj 	if(ret == 0)
1825340022aSzrj 		/* timeout expired */
1835340022aSzrj 		return 0;
1845340022aSzrj 	else if(ret == -1)
1855340022aSzrj 		/* error */
1865340022aSzrj 		return 0;
1875340022aSzrj 	return 1;
1885340022aSzrj }
1895340022aSzrj 
1905340022aSzrj 
1915340022aSzrj 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)1925340022aSzrj ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen,
1935340022aSzrj 	       	const struct sockaddr_storage *from, socklen_t fromlen,
1945340022aSzrj 		struct timeval timeout)
1955340022aSzrj {
1965340022aSzrj 	int sockfd;
1975340022aSzrj 
1985340022aSzrj #ifndef S_SPLINT_S
1995340022aSzrj 	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM,
2005340022aSzrj 					IPPROTO_TCP)) == SOCK_INVALID) {
201819dec71SDaniel Fojt 		return -1;
2025340022aSzrj 	}
2035340022aSzrj #endif
2045340022aSzrj 	if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == SOCK_INVALID){
205819dec71SDaniel Fojt 		close_socket(sockfd);
206819dec71SDaniel Fojt 		return -1;
2075340022aSzrj 	}
2085340022aSzrj 
2095340022aSzrj 	/* perform nonblocking connect, to be able to wait with select() */
2105340022aSzrj 	ldns_sock_nonblock(sockfd);
2115340022aSzrj 	if (connect(sockfd, (struct sockaddr*)to, tolen) == SOCK_INVALID) {
2125340022aSzrj #ifndef USE_WINSOCK
2135340022aSzrj #ifdef EINPROGRESS
2145340022aSzrj 		if(errno != EINPROGRESS) {
2155340022aSzrj #else
2165340022aSzrj 		if(1) {
2175340022aSzrj #endif
2185340022aSzrj 			close_socket(sockfd);
219819dec71SDaniel Fojt 			return -1;
2205340022aSzrj 		}
2215340022aSzrj #else /* USE_WINSOCK */
2225340022aSzrj 		if(WSAGetLastError() != WSAEINPROGRESS &&
2235340022aSzrj 			WSAGetLastError() != WSAEWOULDBLOCK) {
2245340022aSzrj 			close_socket(sockfd);
225819dec71SDaniel Fojt 			return -1;
2265340022aSzrj 		}
2275340022aSzrj #endif
2285340022aSzrj 		/* error was only telling us that it would block */
2295340022aSzrj 	}
2305340022aSzrj 
2315340022aSzrj 	/* wait(write) until connected or error */
2325340022aSzrj 	while(1) {
2335340022aSzrj 		int error = 0;
2345340022aSzrj 		socklen_t len = (socklen_t)sizeof(error);
2355340022aSzrj 
2365340022aSzrj 		if(!ldns_sock_wait(sockfd, timeout, 1)) {
2375340022aSzrj 			close_socket(sockfd);
238819dec71SDaniel Fojt 			return -1;
2395340022aSzrj 		}
2405340022aSzrj 
2415340022aSzrj 		/* check if there is a pending error for nonblocking connect */
2425340022aSzrj 		if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error,
2435340022aSzrj 			&len) < 0) {
2445340022aSzrj #ifndef USE_WINSOCK
2455340022aSzrj 			error = errno; /* on solaris errno is error */
2465340022aSzrj #else
2475340022aSzrj 			error = WSAGetLastError();
2485340022aSzrj #endif
2495340022aSzrj 		}
2505340022aSzrj #ifndef USE_WINSOCK
2515340022aSzrj #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
2525340022aSzrj 		if(error == EINPROGRESS || error == EWOULDBLOCK)
2535340022aSzrj 			continue; /* try again */
2545340022aSzrj #endif
2555340022aSzrj 		else if(error != 0) {
2565340022aSzrj 			close_socket(sockfd);
2575340022aSzrj 			/* error in errno for our user */
2585340022aSzrj 			errno = error;
259819dec71SDaniel Fojt 			return -1;
2605340022aSzrj 		}
2615340022aSzrj #else /* USE_WINSOCK */
2625340022aSzrj 		if(error == WSAEINPROGRESS)
2635340022aSzrj 			continue;
2645340022aSzrj 		else if(error == WSAEWOULDBLOCK)
2655340022aSzrj 			continue;
2665340022aSzrj 		else if(error != 0) {
2675340022aSzrj 			close_socket(sockfd);
2685340022aSzrj 			errno = error;
269819dec71SDaniel Fojt 			return -1;
2705340022aSzrj 		}
2715340022aSzrj #endif /* USE_WINSOCK */
2725340022aSzrj 		/* connected */
2735340022aSzrj 		break;
2745340022aSzrj 	}
2755340022aSzrj 
2765340022aSzrj 	/* set the socket blocking again */
2775340022aSzrj 	ldns_sock_block(sockfd);
2785340022aSzrj 
2795340022aSzrj 	return sockfd;
2805340022aSzrj }
2815340022aSzrj 
2825340022aSzrj int
2835340022aSzrj ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen,
2845340022aSzrj 		struct timeval timeout)
2855340022aSzrj {
286819dec71SDaniel Fojt 	int s = ldns_tcp_connect_from(to, tolen, NULL, 0, timeout);
287819dec71SDaniel Fojt 	return s > 0 ? s : 0;
288819dec71SDaniel Fojt }
289819dec71SDaniel Fojt 
290819dec71SDaniel Fojt int
291819dec71SDaniel Fojt ldns_tcp_connect2(const struct sockaddr_storage *to, socklen_t tolen,
292819dec71SDaniel Fojt 		struct timeval timeout)
293819dec71SDaniel Fojt {
2945340022aSzrj 	return ldns_tcp_connect_from(to, tolen, NULL, 0, timeout);
2955340022aSzrj }
2965340022aSzrj 
2975340022aSzrj static int
2985340022aSzrj ldns_tcp_bgsend_from(ldns_buffer *qbin,
2995340022aSzrj 		const struct sockaddr_storage *to, socklen_t tolen,
3005340022aSzrj 	       	const struct sockaddr_storage *from, socklen_t fromlen,
3015340022aSzrj 		struct timeval timeout)
3025340022aSzrj {
3035340022aSzrj 	int sockfd;
3045340022aSzrj 
3055340022aSzrj 	sockfd = ldns_tcp_connect_from(to, tolen, from, fromlen, timeout);
3065340022aSzrj 
307819dec71SDaniel Fojt 	if (sockfd >= 0 && ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
3085340022aSzrj 		close_socket(sockfd);
309819dec71SDaniel Fojt 		return -1;
3105340022aSzrj 	}
3115340022aSzrj 
3125340022aSzrj 	return sockfd;
3135340022aSzrj }
3145340022aSzrj 
3155340022aSzrj int
3165340022aSzrj ldns_tcp_bgsend(ldns_buffer *qbin,
3175340022aSzrj 		const struct sockaddr_storage *to, socklen_t tolen,
3185340022aSzrj 		struct timeval timeout)
3195340022aSzrj {
320819dec71SDaniel Fojt 	int s = ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
321819dec71SDaniel Fojt 	return s > 0 ? s : 0;
3225340022aSzrj }
3235340022aSzrj 
324819dec71SDaniel Fojt int
325819dec71SDaniel Fojt ldns_tcp_bgsend2(ldns_buffer *qbin,
326819dec71SDaniel Fojt 		const struct sockaddr_storage *to, socklen_t tolen,
327819dec71SDaniel Fojt 		struct timeval timeout)
328819dec71SDaniel Fojt {
329819dec71SDaniel Fojt 	return ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
330819dec71SDaniel Fojt }
3315340022aSzrj 
3325340022aSzrj /* keep in mind that in DNS tcp messages the first 2 bytes signal the
3335340022aSzrj  * amount data to expect
3345340022aSzrj  */
3355340022aSzrj static ldns_status
3365340022aSzrj ldns_tcp_send_from(uint8_t **result,  ldns_buffer *qbin,
3375340022aSzrj 	       	const struct sockaddr_storage *to, socklen_t tolen,
3385340022aSzrj 	       	const struct sockaddr_storage *from, socklen_t fromlen,
3395340022aSzrj 		struct timeval timeout, size_t *answer_size)
3405340022aSzrj {
3415340022aSzrj 	int sockfd;
3425340022aSzrj 	uint8_t *answer;
3435340022aSzrj 
3445340022aSzrj 	sockfd = ldns_tcp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
3455340022aSzrj 
346819dec71SDaniel Fojt 	if (sockfd == -1) {
3475340022aSzrj 		return LDNS_STATUS_ERR;
3485340022aSzrj 	}
3495340022aSzrj 
3505340022aSzrj 	answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
3515340022aSzrj 	close_socket(sockfd);
3525340022aSzrj 
353819dec71SDaniel Fojt 	if (!answer) {
3545340022aSzrj 		/* oops */
3555340022aSzrj 		return LDNS_STATUS_NETWORK_ERR;
3565340022aSzrj 	}
3575340022aSzrj 
358819dec71SDaniel Fojt 	*result = answer;
3595340022aSzrj 	return LDNS_STATUS_OK;
3605340022aSzrj }
3615340022aSzrj 
3625340022aSzrj ldns_status
3635340022aSzrj ldns_tcp_send(uint8_t **result,  ldns_buffer *qbin,
3645340022aSzrj 		const struct sockaddr_storage *to, socklen_t tolen,
3655340022aSzrj 		struct timeval timeout, size_t *answer_size)
3665340022aSzrj {
3675340022aSzrj 	return ldns_tcp_send_from(result, qbin,
3685340022aSzrj 			to, tolen, NULL, 0, timeout, answer_size);
3695340022aSzrj }
3705340022aSzrj 
3715340022aSzrj int
3725340022aSzrj ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
3735340022aSzrj {
3745340022aSzrj 	int sockfd;
3755340022aSzrj 
3765340022aSzrj #ifndef S_SPLINT_S
3775340022aSzrj 	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
3785340022aSzrj 					IPPROTO_UDP))
379819dec71SDaniel Fojt 			== SOCK_INVALID) {
3805340022aSzrj                 return 0;
3815340022aSzrj         }
3825340022aSzrj #endif
3835340022aSzrj 	return sockfd;
3845340022aSzrj }
3855340022aSzrj 
386819dec71SDaniel Fojt int
387819dec71SDaniel Fojt ldns_udp_connect2(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
388819dec71SDaniel Fojt {
389819dec71SDaniel Fojt 	int sockfd;
390819dec71SDaniel Fojt 
391819dec71SDaniel Fojt #ifndef S_SPLINT_S
392819dec71SDaniel Fojt 	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
393819dec71SDaniel Fojt 					IPPROTO_UDP))
394819dec71SDaniel Fojt 			== SOCK_INVALID) {
395819dec71SDaniel Fojt                 return -1;
396819dec71SDaniel Fojt         }
397819dec71SDaniel Fojt #endif
398819dec71SDaniel Fojt 	return sockfd;
399819dec71SDaniel Fojt }
400819dec71SDaniel Fojt 
4015340022aSzrj static int
4025340022aSzrj ldns_udp_bgsend_from(ldns_buffer *qbin,
4035340022aSzrj 		const struct sockaddr_storage *to  , socklen_t tolen,
4045340022aSzrj 		const struct sockaddr_storage *from, socklen_t fromlen,
4055340022aSzrj 		struct timeval timeout)
4065340022aSzrj {
4075340022aSzrj 	int sockfd;
4085340022aSzrj 
409819dec71SDaniel Fojt 	sockfd = ldns_udp_connect2(to, timeout);
4105340022aSzrj 
411819dec71SDaniel Fojt 	if (sockfd == -1) {
412819dec71SDaniel Fojt 		return -1;
4135340022aSzrj 	}
4145340022aSzrj 
4155340022aSzrj 	if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){
416819dec71SDaniel Fojt 		close_socket(sockfd);
417819dec71SDaniel Fojt 		return -1;
4185340022aSzrj 	}
4195340022aSzrj 
4205340022aSzrj 	if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
4215340022aSzrj 		close_socket(sockfd);
422819dec71SDaniel Fojt 		return -1;
4235340022aSzrj 	}
4245340022aSzrj 	return sockfd;
4255340022aSzrj }
4265340022aSzrj 
4275340022aSzrj int
4285340022aSzrj ldns_udp_bgsend(ldns_buffer *qbin,
4295340022aSzrj 		const struct sockaddr_storage *to  , socklen_t tolen,
4305340022aSzrj 		struct timeval timeout)
4315340022aSzrj {
432819dec71SDaniel Fojt 	int s = ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
433819dec71SDaniel Fojt 	return s > 0 ? s : 0;
434819dec71SDaniel Fojt }
435819dec71SDaniel Fojt 
436819dec71SDaniel Fojt int
437819dec71SDaniel Fojt ldns_udp_bgsend2(ldns_buffer *qbin,
438819dec71SDaniel Fojt 		const struct sockaddr_storage *to  , socklen_t tolen,
439819dec71SDaniel Fojt 		struct timeval timeout)
440819dec71SDaniel Fojt {
4415340022aSzrj 	return ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
4425340022aSzrj }
4435340022aSzrj 
4445340022aSzrj static ldns_status
4455340022aSzrj ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin,
4465340022aSzrj 		const struct sockaddr_storage *to  , socklen_t tolen,
4475340022aSzrj 		const struct sockaddr_storage *from, socklen_t fromlen,
4485340022aSzrj 		struct timeval timeout, size_t *answer_size)
4495340022aSzrj {
4505340022aSzrj 	int sockfd;
4515340022aSzrj 	uint8_t *answer;
4525340022aSzrj 
4535340022aSzrj 	sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
4545340022aSzrj 
455819dec71SDaniel Fojt 	if (sockfd == -1) {
4565340022aSzrj 		return LDNS_STATUS_SOCKET_ERROR;
4575340022aSzrj 	}
4585340022aSzrj 
4595340022aSzrj 	/* wait for an response*/
4605340022aSzrj 	if(!ldns_sock_wait(sockfd, timeout, 0)) {
4615340022aSzrj 		close_socket(sockfd);
4625340022aSzrj 		return LDNS_STATUS_NETWORK_ERR;
4635340022aSzrj 	}
4645340022aSzrj 
4655340022aSzrj         /* set to nonblocking, so if the checksum is bad, it becomes
466*ee791febSAntonio Huete Jimenez          * an EAGAIN error and the ldns_udp_send function does not block,
4675340022aSzrj          * but returns a 'NETWORK_ERROR' much like a timeout. */
4685340022aSzrj         ldns_sock_nonblock(sockfd);
4695340022aSzrj 
4705340022aSzrj 	answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
4715340022aSzrj 	close_socket(sockfd);
4725340022aSzrj 
473819dec71SDaniel Fojt 	if (!answer) {
4745340022aSzrj 		/* oops */
4755340022aSzrj 		return LDNS_STATUS_NETWORK_ERR;
4765340022aSzrj 	}
4775340022aSzrj 
4785340022aSzrj 	*result = answer;
4795340022aSzrj 	return LDNS_STATUS_OK;
4805340022aSzrj }
4815340022aSzrj 
4825340022aSzrj ldns_status
4835340022aSzrj ldns_udp_send(uint8_t **result, ldns_buffer *qbin,
4845340022aSzrj 		const struct sockaddr_storage *to  , socklen_t tolen,
4855340022aSzrj 		struct timeval timeout, size_t *answer_size)
4865340022aSzrj {
4875340022aSzrj 	return ldns_udp_send_from(result, qbin, to, tolen, NULL, 0,
4885340022aSzrj 			timeout, answer_size);
4895340022aSzrj }
4905340022aSzrj 
491825eb42bSJan Lentfer ldns_status
492825eb42bSJan Lentfer ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac)
493825eb42bSJan Lentfer {
494825eb42bSJan Lentfer 	uint8_t i;
495825eb42bSJan Lentfer 
4965340022aSzrj 	struct sockaddr_storage *src = NULL;
497819dec71SDaniel Fojt 	size_t src_len = 0;
498825eb42bSJan Lentfer 	struct sockaddr_storage *ns;
499825eb42bSJan Lentfer 	size_t ns_len;
500825eb42bSJan Lentfer 	struct timeval tv_s;
501825eb42bSJan Lentfer 	struct timeval tv_e;
502825eb42bSJan Lentfer 
503825eb42bSJan Lentfer 	ldns_rdf **ns_array;
504825eb42bSJan Lentfer 	size_t *rtt;
505825eb42bSJan Lentfer 	ldns_pkt *reply;
506825eb42bSJan Lentfer 	bool all_servers_rtt_inf;
507825eb42bSJan Lentfer 	uint8_t retries;
508825eb42bSJan Lentfer 
509825eb42bSJan Lentfer 	uint8_t *reply_bytes = NULL;
510825eb42bSJan Lentfer 	size_t reply_size = 0;
511825eb42bSJan Lentfer 	ldns_status status, send_status;
512825eb42bSJan Lentfer 
513825eb42bSJan Lentfer 	assert(r != NULL);
514825eb42bSJan Lentfer 
515825eb42bSJan Lentfer 	status = LDNS_STATUS_OK;
516825eb42bSJan Lentfer 	rtt = ldns_resolver_rtt(r);
517825eb42bSJan Lentfer 	ns_array = ldns_resolver_nameservers(r);
518825eb42bSJan Lentfer 	reply = NULL;
519825eb42bSJan Lentfer 	ns_len = 0;
520825eb42bSJan Lentfer 
521825eb42bSJan Lentfer 	all_servers_rtt_inf = true;
522825eb42bSJan Lentfer 
523825eb42bSJan Lentfer 	if (ldns_resolver_random(r)) {
524825eb42bSJan Lentfer 		ldns_resolver_nameservers_randomize(r);
525825eb42bSJan Lentfer 	}
526825eb42bSJan Lentfer 
5275340022aSzrj 	if(ldns_resolver_source(r)) {
5285340022aSzrj 		src = ldns_rdf2native_sockaddr_storage_port(
5295340022aSzrj 				ldns_resolver_source(r), 0, &src_len);
5305340022aSzrj 	}
5315340022aSzrj 
532825eb42bSJan Lentfer 	/* loop through all defined nameservers */
533825eb42bSJan Lentfer 	for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
534825eb42bSJan Lentfer 		if (rtt[i] == LDNS_RESOLV_RTT_INF) {
535825eb42bSJan Lentfer 			/* not reachable nameserver! */
536825eb42bSJan Lentfer 			continue;
537825eb42bSJan Lentfer 		}
538825eb42bSJan Lentfer 
539825eb42bSJan Lentfer 		/* maybe verbosity setting?
540825eb42bSJan Lentfer 		printf("Sending to ");
541825eb42bSJan Lentfer 		ldns_rdf_print(stdout, ns_array[i]);
542825eb42bSJan Lentfer 		printf("\n");
543825eb42bSJan Lentfer 		*/
544825eb42bSJan Lentfer 		ns = ldns_rdf2native_sockaddr_storage(ns_array[i],
545825eb42bSJan Lentfer 				ldns_resolver_port(r), &ns_len);
546825eb42bSJan Lentfer 
547d1b2b5caSJohn Marino 
548d1b2b5caSJohn Marino #ifndef S_SPLINT_S
549825eb42bSJan Lentfer 		if ((ns->ss_family == AF_INET) &&
550825eb42bSJan Lentfer 				(ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) {
551ac996e71SJan Lentfer 			/* not reachable */
552d1b2b5caSJohn Marino 			LDNS_FREE(ns);
553825eb42bSJan Lentfer 			continue;
554825eb42bSJan Lentfer 		}
555825eb42bSJan Lentfer 
556825eb42bSJan Lentfer 		if ((ns->ss_family == AF_INET6) &&
557825eb42bSJan Lentfer 				 (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) {
558ac996e71SJan Lentfer 			/* not reachable */
559d1b2b5caSJohn Marino 			LDNS_FREE(ns);
560825eb42bSJan Lentfer 			continue;
561825eb42bSJan Lentfer 		}
562d1b2b5caSJohn Marino #endif
563825eb42bSJan Lentfer 
564ac996e71SJan Lentfer 		all_servers_rtt_inf = false;
565ac996e71SJan Lentfer 
566825eb42bSJan Lentfer 		gettimeofday(&tv_s, NULL);
567825eb42bSJan Lentfer 
568825eb42bSJan Lentfer 		send_status = LDNS_STATUS_ERR;
569825eb42bSJan Lentfer 
570825eb42bSJan Lentfer 		/* reply_bytes implicitly handles our error */
5715340022aSzrj 		if (ldns_resolver_usevc(r)) {
572825eb42bSJan Lentfer 			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
573825eb42bSJan Lentfer 				send_status =
5745340022aSzrj 					ldns_tcp_send_from(&reply_bytes, qb,
5755340022aSzrj 						ns, (socklen_t)ns_len,
5765340022aSzrj 						src, (socklen_t)src_len,
5775340022aSzrj 						ldns_resolver_timeout(r),
578825eb42bSJan Lentfer 						&reply_size);
579825eb42bSJan Lentfer 				if (send_status == LDNS_STATUS_OK) {
580825eb42bSJan Lentfer 					break;
581825eb42bSJan Lentfer 				}
582825eb42bSJan Lentfer 			}
583825eb42bSJan Lentfer 		} else {
584825eb42bSJan Lentfer 			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
585825eb42bSJan Lentfer 				/* ldns_rdf_print(stdout, ns_array[i]); */
586825eb42bSJan Lentfer 				send_status =
5875340022aSzrj 					ldns_udp_send_from(&reply_bytes, qb,
5885340022aSzrj 						ns,  (socklen_t)ns_len,
5895340022aSzrj 						src, (socklen_t)src_len,
5905340022aSzrj 						ldns_resolver_timeout(r),
591825eb42bSJan Lentfer 						&reply_size);
592825eb42bSJan Lentfer 				if (send_status == LDNS_STATUS_OK) {
593825eb42bSJan Lentfer 					break;
594825eb42bSJan Lentfer 				}
595825eb42bSJan Lentfer 			}
596825eb42bSJan Lentfer 		}
597825eb42bSJan Lentfer 
598825eb42bSJan Lentfer 		if (send_status != LDNS_STATUS_OK) {
599825eb42bSJan Lentfer 			ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF);
600825eb42bSJan Lentfer 			status = send_status;
601825eb42bSJan Lentfer 		}
602825eb42bSJan Lentfer 
603825eb42bSJan Lentfer 		/* obey the fail directive */
604825eb42bSJan Lentfer 		if (!reply_bytes) {
605825eb42bSJan Lentfer 			/* the current nameserver seems to have a problem, blacklist it */
606825eb42bSJan Lentfer 			if (ldns_resolver_fail(r)) {
607819dec71SDaniel Fojt 				if(src) {
608819dec71SDaniel Fojt 					LDNS_FREE(src);
609819dec71SDaniel Fojt 				}
610825eb42bSJan Lentfer 				LDNS_FREE(ns);
611825eb42bSJan Lentfer 				return LDNS_STATUS_ERR;
612825eb42bSJan Lentfer 			} else {
613825eb42bSJan Lentfer 				LDNS_FREE(ns);
614825eb42bSJan Lentfer 				continue;
615825eb42bSJan Lentfer 			}
616825eb42bSJan Lentfer 		}
617825eb42bSJan Lentfer 
618825eb42bSJan Lentfer 		status = ldns_wire2pkt(&reply, reply_bytes, reply_size);
619825eb42bSJan Lentfer 		if (status != LDNS_STATUS_OK) {
620819dec71SDaniel Fojt 			if(src) LDNS_FREE(src);
621825eb42bSJan Lentfer 			LDNS_FREE(reply_bytes);
622825eb42bSJan Lentfer 			LDNS_FREE(ns);
623825eb42bSJan Lentfer 			return status;
624825eb42bSJan Lentfer 		}
625819dec71SDaniel Fojt 		assert(reply);
626825eb42bSJan Lentfer 
627825eb42bSJan Lentfer 		LDNS_FREE(ns);
628825eb42bSJan Lentfer 		gettimeofday(&tv_e, NULL);
629825eb42bSJan Lentfer 
630825eb42bSJan Lentfer 		if (reply) {
631825eb42bSJan Lentfer 			ldns_pkt_set_querytime(reply, (uint32_t)
632825eb42bSJan Lentfer 				((tv_e.tv_sec - tv_s.tv_sec) * 1000) +
633825eb42bSJan Lentfer 				(tv_e.tv_usec - tv_s.tv_usec) / 1000);
634d1b2b5caSJohn Marino 			ldns_pkt_set_answerfrom(reply,
635d1b2b5caSJohn Marino 					ldns_rdf_clone(ns_array[i]));
636825eb42bSJan Lentfer 			ldns_pkt_set_timestamp(reply, tv_s);
637825eb42bSJan Lentfer 			ldns_pkt_set_size(reply, reply_size);
638825eb42bSJan Lentfer 			break;
639825eb42bSJan Lentfer 		} else {
640825eb42bSJan Lentfer 			if (ldns_resolver_fail(r)) {
641825eb42bSJan Lentfer 				/* if fail is set bail out, after the first
642825eb42bSJan Lentfer 				 * one */
643825eb42bSJan Lentfer 				break;
644825eb42bSJan Lentfer 			}
645825eb42bSJan Lentfer 		}
646825eb42bSJan Lentfer 
647825eb42bSJan Lentfer 		/* wait retrans seconds... */
648825eb42bSJan Lentfer 		sleep((unsigned int) ldns_resolver_retrans(r));
649825eb42bSJan Lentfer 	}
650825eb42bSJan Lentfer 
6515340022aSzrj 	if(src) {
6525340022aSzrj 		LDNS_FREE(src);
6535340022aSzrj 	}
654825eb42bSJan Lentfer 	if (all_servers_rtt_inf) {
655825eb42bSJan Lentfer 		LDNS_FREE(reply_bytes);
656825eb42bSJan Lentfer 		return LDNS_STATUS_RES_NO_NS;
657825eb42bSJan Lentfer 	}
658825eb42bSJan Lentfer #ifdef HAVE_SSL
659d1b2b5caSJohn Marino 	if (tsig_mac && reply && reply_bytes) {
660825eb42bSJan Lentfer 		if (!ldns_pkt_tsig_verify(reply,
661825eb42bSJan Lentfer 		                          reply_bytes,
662825eb42bSJan Lentfer 					  reply_size,
663825eb42bSJan Lentfer 		                          ldns_resolver_tsig_keyname(r),
664825eb42bSJan Lentfer 		                          ldns_resolver_tsig_keydata(r), tsig_mac)) {
665825eb42bSJan Lentfer 			status = LDNS_STATUS_CRYPTO_TSIG_BOGUS;
666825eb42bSJan Lentfer 		}
667825eb42bSJan Lentfer 	}
668825eb42bSJan Lentfer #else
669825eb42bSJan Lentfer 	(void)tsig_mac;
670825eb42bSJan Lentfer #endif /* HAVE_SSL */
671825eb42bSJan Lentfer 
672825eb42bSJan Lentfer 	LDNS_FREE(reply_bytes);
673825eb42bSJan Lentfer 	if (result) {
674825eb42bSJan Lentfer 		*result = reply;
675825eb42bSJan Lentfer 	}
676825eb42bSJan Lentfer 
677825eb42bSJan Lentfer 	return status;
678825eb42bSJan Lentfer }
679825eb42bSJan Lentfer 
680825eb42bSJan Lentfer ssize_t
681825eb42bSJan Lentfer ldns_tcp_send_query(ldns_buffer *qbin, int sockfd,
682825eb42bSJan Lentfer                     const struct sockaddr_storage *to, socklen_t tolen)
683825eb42bSJan Lentfer {
684825eb42bSJan Lentfer 	uint8_t *sendbuf;
685825eb42bSJan Lentfer 	ssize_t bytes;
686825eb42bSJan Lentfer 
687825eb42bSJan Lentfer 	/* add length of packet */
688825eb42bSJan Lentfer 	sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2);
689ac996e71SJan Lentfer 	if(!sendbuf) return 0;
690825eb42bSJan Lentfer 	ldns_write_uint16(sendbuf, ldns_buffer_position(qbin));
691d1b2b5caSJohn Marino 	memcpy(sendbuf + 2, ldns_buffer_begin(qbin), ldns_buffer_position(qbin));
692825eb42bSJan Lentfer 
693825eb42bSJan Lentfer 	bytes = sendto(sockfd, (void*)sendbuf,
694825eb42bSJan Lentfer 			ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen);
695825eb42bSJan Lentfer 
696825eb42bSJan Lentfer         LDNS_FREE(sendbuf);
697825eb42bSJan Lentfer 
698825eb42bSJan Lentfer 	if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) {
699825eb42bSJan Lentfer 		return 0;
700825eb42bSJan Lentfer 	}
701825eb42bSJan Lentfer 	return bytes;
702825eb42bSJan Lentfer }
703825eb42bSJan Lentfer 
704825eb42bSJan Lentfer /* don't wait for an answer */
705825eb42bSJan Lentfer ssize_t
706825eb42bSJan Lentfer ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to,
707825eb42bSJan Lentfer 		socklen_t tolen)
708825eb42bSJan Lentfer {
709825eb42bSJan Lentfer 	ssize_t bytes;
710825eb42bSJan Lentfer 
711825eb42bSJan Lentfer 	bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin),
712825eb42bSJan Lentfer 			ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen);
713825eb42bSJan Lentfer 
714825eb42bSJan Lentfer 	if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) {
715825eb42bSJan Lentfer 		return 0;
716825eb42bSJan Lentfer 	}
717825eb42bSJan Lentfer 	return bytes;
718825eb42bSJan Lentfer }
719825eb42bSJan Lentfer 
720825eb42bSJan Lentfer uint8_t *
721825eb42bSJan Lentfer ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from,
722825eb42bSJan Lentfer 		socklen_t *fromlen)
723825eb42bSJan Lentfer {
724ac996e71SJan Lentfer 	uint8_t *wire, *wireout;
725825eb42bSJan Lentfer 	ssize_t wire_size;
726825eb42bSJan Lentfer 
727825eb42bSJan Lentfer 	wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
728825eb42bSJan Lentfer 	if (!wire) {
729825eb42bSJan Lentfer 		*size = 0;
730825eb42bSJan Lentfer 		return NULL;
731825eb42bSJan Lentfer 	}
732825eb42bSJan Lentfer 
733825eb42bSJan Lentfer 	wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0,
734825eb42bSJan Lentfer 			(struct sockaddr *)from, fromlen);
735825eb42bSJan Lentfer 
736825eb42bSJan Lentfer 	/* recvfrom can also return 0 */
737825eb42bSJan Lentfer 	if (wire_size == -1 || wire_size == 0) {
738825eb42bSJan Lentfer 		*size = 0;
739825eb42bSJan Lentfer 		LDNS_FREE(wire);
740825eb42bSJan Lentfer 		return NULL;
741825eb42bSJan Lentfer 	}
742825eb42bSJan Lentfer 
743825eb42bSJan Lentfer 	*size = (size_t)wire_size;
744ac996e71SJan Lentfer 	wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size);
745ac996e71SJan Lentfer 	if(!wireout) LDNS_FREE(wire);
746825eb42bSJan Lentfer 
747ac996e71SJan Lentfer 	return wireout;
748825eb42bSJan Lentfer }
749825eb42bSJan Lentfer 
750825eb42bSJan Lentfer uint8_t *
751825eb42bSJan Lentfer ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout)
752825eb42bSJan Lentfer {
753825eb42bSJan Lentfer 	uint8_t *wire;
754825eb42bSJan Lentfer 	uint16_t wire_size;
755ac996e71SJan Lentfer 	ssize_t bytes = 0, rc = 0;
756825eb42bSJan Lentfer 
757825eb42bSJan Lentfer 	wire = LDNS_XMALLOC(uint8_t, 2);
758825eb42bSJan Lentfer 	if (!wire) {
759825eb42bSJan Lentfer 		*size = 0;
760825eb42bSJan Lentfer 		return NULL;
761825eb42bSJan Lentfer 	}
762825eb42bSJan Lentfer 
763825eb42bSJan Lentfer 	while (bytes < 2) {
764825eb42bSJan Lentfer 		if(!ldns_sock_wait(sockfd, timeout, 0)) {
765825eb42bSJan Lentfer 			*size = 0;
766825eb42bSJan Lentfer 			LDNS_FREE(wire);
767825eb42bSJan Lentfer 			return NULL;
768825eb42bSJan Lentfer 		}
769ac996e71SJan Lentfer 		rc = recv(sockfd, (void*) (wire + bytes),
770ac996e71SJan Lentfer 				(size_t) (2 - bytes), 0);
771ac996e71SJan Lentfer 		if (rc == -1 || rc == 0) {
772825eb42bSJan Lentfer 			*size = 0;
773825eb42bSJan Lentfer 			LDNS_FREE(wire);
774825eb42bSJan Lentfer 			return NULL;
775825eb42bSJan Lentfer 		}
776ac996e71SJan Lentfer                 bytes += rc;
777825eb42bSJan Lentfer 	}
778825eb42bSJan Lentfer 
779825eb42bSJan Lentfer 	wire_size = ldns_read_uint16(wire);
780825eb42bSJan Lentfer 
781825eb42bSJan Lentfer 	LDNS_FREE(wire);
782825eb42bSJan Lentfer 	wire = LDNS_XMALLOC(uint8_t, wire_size);
783fd185f4dSJan Lentfer 	if (!wire) {
784fd185f4dSJan Lentfer 		*size = 0;
785fd185f4dSJan Lentfer 		return NULL;
786fd185f4dSJan Lentfer 	}
787825eb42bSJan Lentfer 	bytes = 0;
788825eb42bSJan Lentfer 
789825eb42bSJan Lentfer 	while (bytes < (ssize_t) wire_size) {
790825eb42bSJan Lentfer 		if(!ldns_sock_wait(sockfd, timeout, 0)) {
791825eb42bSJan Lentfer 			*size = 0;
792825eb42bSJan Lentfer 			LDNS_FREE(wire);
793825eb42bSJan Lentfer 			return NULL;
794825eb42bSJan Lentfer 		}
795ac996e71SJan Lentfer 		rc = recv(sockfd, (void*) (wire + bytes),
796825eb42bSJan Lentfer 				(size_t) (wire_size - bytes), 0);
797ac996e71SJan Lentfer 		if (rc == -1 || rc == 0) {
798825eb42bSJan Lentfer 			LDNS_FREE(wire);
799825eb42bSJan Lentfer 			*size = 0;
800825eb42bSJan Lentfer 			return NULL;
801825eb42bSJan Lentfer 		}
802ac996e71SJan Lentfer                 bytes += rc;
803825eb42bSJan Lentfer 	}
804825eb42bSJan Lentfer 
805825eb42bSJan Lentfer 	*size = (size_t) bytes;
806825eb42bSJan Lentfer 	return wire;
807825eb42bSJan Lentfer }
808825eb42bSJan Lentfer 
809825eb42bSJan Lentfer uint8_t *
810825eb42bSJan Lentfer ldns_tcp_read_wire(int sockfd, size_t *size)
811825eb42bSJan Lentfer {
812825eb42bSJan Lentfer 	uint8_t *wire;
813825eb42bSJan Lentfer 	uint16_t wire_size;
814ac996e71SJan Lentfer 	ssize_t bytes = 0, rc = 0;
815825eb42bSJan Lentfer 
816825eb42bSJan Lentfer 	wire = LDNS_XMALLOC(uint8_t, 2);
817825eb42bSJan Lentfer 	if (!wire) {
818825eb42bSJan Lentfer 		*size = 0;
819825eb42bSJan Lentfer 		return NULL;
820825eb42bSJan Lentfer 	}
821825eb42bSJan Lentfer 
822825eb42bSJan Lentfer 	while (bytes < 2) {
823ac996e71SJan Lentfer 		rc = recv(sockfd, (void*) (wire + bytes),
824ac996e71SJan Lentfer 				(size_t) (2 - bytes), 0);
825ac996e71SJan Lentfer 		if (rc == -1 || rc == 0) {
826825eb42bSJan Lentfer 			*size = 0;
827825eb42bSJan Lentfer 			LDNS_FREE(wire);
828825eb42bSJan Lentfer 			return NULL;
829825eb42bSJan Lentfer 		}
830ac996e71SJan Lentfer                 bytes += rc;
831825eb42bSJan Lentfer 	}
832825eb42bSJan Lentfer 
833825eb42bSJan Lentfer 	wire_size = ldns_read_uint16(wire);
834825eb42bSJan Lentfer 
835825eb42bSJan Lentfer 	LDNS_FREE(wire);
836825eb42bSJan Lentfer 	wire = LDNS_XMALLOC(uint8_t, wire_size);
837fd185f4dSJan Lentfer 	if (!wire) {
838fd185f4dSJan Lentfer 		*size = 0;
839fd185f4dSJan Lentfer 		return NULL;
840fd185f4dSJan Lentfer 	}
841825eb42bSJan Lentfer 	bytes = 0;
842825eb42bSJan Lentfer 
843825eb42bSJan Lentfer 	while (bytes < (ssize_t) wire_size) {
844ac996e71SJan Lentfer 		rc = recv(sockfd, (void*) (wire + bytes),
845825eb42bSJan Lentfer 				(size_t) (wire_size - bytes), 0);
846ac996e71SJan Lentfer 		if (rc == -1 || rc == 0) {
847825eb42bSJan Lentfer 			LDNS_FREE(wire);
848825eb42bSJan Lentfer 			*size = 0;
849825eb42bSJan Lentfer 			return NULL;
850825eb42bSJan Lentfer 		}
851ac996e71SJan Lentfer                 bytes += rc;
852825eb42bSJan Lentfer 	}
853825eb42bSJan Lentfer 
854825eb42bSJan Lentfer 	*size = (size_t) bytes;
855825eb42bSJan Lentfer 	return wire;
856825eb42bSJan Lentfer }
857825eb42bSJan Lentfer 
858d1b2b5caSJohn Marino #ifndef S_SPLINT_S
859825eb42bSJan Lentfer ldns_rdf *
8605340022aSzrj ldns_sockaddr_storage2rdf(const struct sockaddr_storage *sock, uint16_t *port)
861825eb42bSJan Lentfer {
862825eb42bSJan Lentfer         ldns_rdf *addr;
863825eb42bSJan Lentfer         struct sockaddr_in *data_in;
864825eb42bSJan Lentfer         struct sockaddr_in6 *data_in6;
865825eb42bSJan Lentfer 
866825eb42bSJan Lentfer         switch(sock->ss_family) {
867825eb42bSJan Lentfer                 case AF_INET:
868825eb42bSJan Lentfer                         data_in = (struct sockaddr_in*)sock;
869825eb42bSJan Lentfer                         if (port) {
870825eb42bSJan Lentfer                                 *port = ntohs((uint16_t)data_in->sin_port);
871825eb42bSJan Lentfer                         }
872825eb42bSJan Lentfer                         addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A,
873825eb42bSJan Lentfer                                         LDNS_IP4ADDRLEN, &data_in->sin_addr);
874825eb42bSJan Lentfer                         break;
875825eb42bSJan Lentfer                 case AF_INET6:
876825eb42bSJan Lentfer                         data_in6 = (struct sockaddr_in6*)sock;
877825eb42bSJan Lentfer                         if (port) {
878825eb42bSJan Lentfer                                 *port = ntohs((uint16_t)data_in6->sin6_port);
879825eb42bSJan Lentfer                         }
880825eb42bSJan Lentfer                         addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA,
881825eb42bSJan Lentfer                                         LDNS_IP6ADDRLEN, &data_in6->sin6_addr);
882825eb42bSJan Lentfer                         break;
883825eb42bSJan Lentfer                 default:
884825eb42bSJan Lentfer                         if (port) {
885825eb42bSJan Lentfer                                 *port = 0;
886825eb42bSJan Lentfer                         }
887825eb42bSJan Lentfer                         return NULL;
888825eb42bSJan Lentfer         }
889825eb42bSJan Lentfer         return addr;
890825eb42bSJan Lentfer }
891d1b2b5caSJohn Marino #endif
892825eb42bSJan Lentfer 
893825eb42bSJan Lentfer /* code from resolver.c */
894825eb42bSJan Lentfer ldns_status
8955340022aSzrj ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class class)
896825eb42bSJan Lentfer {
897825eb42bSJan Lentfer         ldns_pkt *query;
898825eb42bSJan Lentfer         ldns_buffer *query_wire;
899825eb42bSJan Lentfer 
9005340022aSzrj         struct sockaddr_storage *src = NULL;
9015340022aSzrj         size_t src_len = 0;
902825eb42bSJan Lentfer         struct sockaddr_storage *ns = NULL;
903825eb42bSJan Lentfer         size_t ns_len = 0;
904825eb42bSJan Lentfer         size_t ns_i;
905825eb42bSJan Lentfer         ldns_status status;
906825eb42bSJan Lentfer 
907825eb42bSJan Lentfer         if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) {
908825eb42bSJan Lentfer                 return LDNS_STATUS_ERR;
909825eb42bSJan Lentfer         }
910825eb42bSJan Lentfer 
911825eb42bSJan Lentfer         query = ldns_pkt_query_new(ldns_rdf_clone(domain), LDNS_RR_TYPE_AXFR, class, 0);
912825eb42bSJan Lentfer 
913825eb42bSJan Lentfer         if (!query) {
914825eb42bSJan Lentfer                 return LDNS_STATUS_ADDRESS_ERR;
915825eb42bSJan Lentfer         }
9165340022aSzrj 	if(ldns_resolver_source(resolver)) {
9175340022aSzrj 		src = ldns_rdf2native_sockaddr_storage_port(
9185340022aSzrj 				ldns_resolver_source(resolver), 0, &src_len);
9195340022aSzrj 	}
920825eb42bSJan Lentfer         /* For AXFR, we have to make the connection ourselves */
921825eb42bSJan Lentfer         /* try all nameservers (which usually would mean v4 fallback if
922825eb42bSJan Lentfer          * @hostname is used */
923825eb42bSJan Lentfer         for (ns_i = 0;
924825eb42bSJan Lentfer              ns_i < ldns_resolver_nameserver_count(resolver) &&
9255340022aSzrj              resolver->_socket == SOCK_INVALID;
926825eb42bSJan Lentfer              ns_i++) {
927d1b2b5caSJohn Marino 		if (ns != NULL) {
928d1b2b5caSJohn Marino 			LDNS_FREE(ns);
929d1b2b5caSJohn Marino 		}
930825eb42bSJan Lentfer 	        ns = ldns_rdf2native_sockaddr_storage(
931825eb42bSJan Lentfer 	        	resolver->_nameservers[ns_i],
932825eb42bSJan Lentfer 			ldns_resolver_port(resolver), &ns_len);
9335340022aSzrj #ifndef S_SPLINT_S
9345340022aSzrj 		if ((ns->ss_family == AF_INET) &&
9355340022aSzrj 			(ldns_resolver_ip6(resolver) == LDNS_RESOLV_INET6)) {
9365340022aSzrj 			/* not reachable */
9375340022aSzrj 			LDNS_FREE(ns);
9385340022aSzrj 			ns = NULL;
9395340022aSzrj 			continue;
9405340022aSzrj 		}
941825eb42bSJan Lentfer 
9425340022aSzrj 		if ((ns->ss_family == AF_INET6) &&
9435340022aSzrj 			 (ldns_resolver_ip6(resolver) == LDNS_RESOLV_INET)) {
9445340022aSzrj 			/* not reachable */
9455340022aSzrj 			LDNS_FREE(ns);
9465340022aSzrj 			ns = NULL;
9475340022aSzrj 			continue;
9485340022aSzrj 		}
9495340022aSzrj #endif
9505340022aSzrj 
9515340022aSzrj 		resolver->_socket = ldns_tcp_connect_from(
9525340022aSzrj 				ns, (socklen_t)ns_len,
9535340022aSzrj 				src, (socklen_t)src_len,
954825eb42bSJan Lentfer 				ldns_resolver_timeout(resolver));
955825eb42bSJan Lentfer 	}
956819dec71SDaniel Fojt 	if (src) {
957819dec71SDaniel Fojt 		LDNS_FREE(src);
958819dec71SDaniel Fojt 	}
959825eb42bSJan Lentfer 
9605340022aSzrj 	if (resolver->_socket == SOCK_INVALID) {
961825eb42bSJan Lentfer 		ldns_pkt_free(query);
962825eb42bSJan Lentfer 		LDNS_FREE(ns);
963825eb42bSJan Lentfer 		return LDNS_STATUS_NETWORK_ERR;
964825eb42bSJan Lentfer 	}
965825eb42bSJan Lentfer 
966825eb42bSJan Lentfer #ifdef HAVE_SSL
967825eb42bSJan Lentfer 	if (ldns_resolver_tsig_keyname(resolver) && ldns_resolver_tsig_keydata(resolver)) {
968825eb42bSJan Lentfer 		status = ldns_pkt_tsig_sign(query,
969825eb42bSJan Lentfer 		                            ldns_resolver_tsig_keyname(resolver),
970825eb42bSJan Lentfer 		                            ldns_resolver_tsig_keydata(resolver),
971825eb42bSJan Lentfer 		                            300, ldns_resolver_tsig_algorithm(resolver), NULL);
972825eb42bSJan Lentfer 		if (status != LDNS_STATUS_OK) {
9735340022aSzrj 			/* to prevent problems on subsequent calls to
9745340022aSzrj 			 * ldns_axfr_start we have to close the socket here! */
9755340022aSzrj 			close_socket(resolver->_socket);
976ac996e71SJan Lentfer 			resolver->_socket = 0;
977ac996e71SJan Lentfer 
978d1b2b5caSJohn Marino 			ldns_pkt_free(query);
979d1b2b5caSJohn Marino 			LDNS_FREE(ns);
980d1b2b5caSJohn Marino 
981825eb42bSJan Lentfer 			return LDNS_STATUS_CRYPTO_TSIG_ERR;
982825eb42bSJan Lentfer 		}
983825eb42bSJan Lentfer 	}
984825eb42bSJan Lentfer #endif /* HAVE_SSL */
985825eb42bSJan Lentfer 
986ac996e71SJan Lentfer         /* Convert the query to a buffer
987ac996e71SJan Lentfer          * Is this necessary?
988825eb42bSJan Lentfer          */
989825eb42bSJan Lentfer         query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN);
990fd185f4dSJan Lentfer         if(!query_wire) {
991fd185f4dSJan Lentfer                 ldns_pkt_free(query);
992fd185f4dSJan Lentfer                 LDNS_FREE(ns);
9935340022aSzrj 
9945340022aSzrj 		close_socket(resolver->_socket);
995fd185f4dSJan Lentfer 
996fd185f4dSJan Lentfer                 return LDNS_STATUS_MEM_ERR;
997fd185f4dSJan Lentfer         }
998825eb42bSJan Lentfer         status = ldns_pkt2buffer_wire(query_wire, query);
999825eb42bSJan Lentfer         if (status != LDNS_STATUS_OK) {
1000825eb42bSJan Lentfer                 ldns_pkt_free(query);
1001ac996e71SJan Lentfer 		ldns_buffer_free(query_wire);
1002825eb42bSJan Lentfer                 LDNS_FREE(ns);
1003ac996e71SJan Lentfer 
10045340022aSzrj 		/* to prevent problems on subsequent calls to ldns_axfr_start
10055340022aSzrj 		 * we have to close the socket here! */
10065340022aSzrj 		close_socket(resolver->_socket);
1007ac996e71SJan Lentfer 		resolver->_socket = 0;
1008ac996e71SJan Lentfer 
1009825eb42bSJan Lentfer                 return status;
1010825eb42bSJan Lentfer         }
1011825eb42bSJan Lentfer         /* Send the query */
1012825eb42bSJan Lentfer         if (ldns_tcp_send_query(query_wire, resolver->_socket, ns,
1013825eb42bSJan Lentfer 				(socklen_t)ns_len) == 0) {
1014825eb42bSJan Lentfer                 ldns_pkt_free(query);
1015825eb42bSJan Lentfer                 ldns_buffer_free(query_wire);
1016825eb42bSJan Lentfer                 LDNS_FREE(ns);
1017ac996e71SJan Lentfer 
10185340022aSzrj 		/* to prevent problems on subsequent calls to ldns_axfr_start
10195340022aSzrj 		 * we have to close the socket here! */
1020ac996e71SJan Lentfer 
10215340022aSzrj 
10225340022aSzrj 		close_socket(resolver->_socket);
1023ac996e71SJan Lentfer 
1024825eb42bSJan Lentfer                 return LDNS_STATUS_NETWORK_ERR;
1025825eb42bSJan Lentfer         }
1026825eb42bSJan Lentfer 
1027825eb42bSJan Lentfer         ldns_pkt_free(query);
1028825eb42bSJan Lentfer         ldns_buffer_free(query_wire);
1029825eb42bSJan Lentfer         LDNS_FREE(ns);
1030825eb42bSJan Lentfer 
1031825eb42bSJan Lentfer         /*
1032825eb42bSJan Lentfer          * The AXFR is done once the second SOA record is sent
1033825eb42bSJan Lentfer          */
1034825eb42bSJan Lentfer         resolver->_axfr_soa_count = 0;
1035825eb42bSJan Lentfer         return LDNS_STATUS_OK;
1036825eb42bSJan Lentfer }
1037