xref: /freebsd-src/contrib/ldns/net.c (revision 5afab0e5e56fe90a378fb57249600e7924e1cab2)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * net.c
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * Network implementation
57b5038d7SDag-Erling Smørgrav  * All network related functions are grouped here
67b5038d7SDag-Erling Smørgrav  *
77b5038d7SDag-Erling Smørgrav  * a Net::DNS like library for C
87b5038d7SDag-Erling Smørgrav  *
97b5038d7SDag-Erling Smørgrav  * (c) NLnet Labs, 2004-2006
107b5038d7SDag-Erling Smørgrav  *
117b5038d7SDag-Erling Smørgrav  * See the file LICENSE for the license
127b5038d7SDag-Erling Smørgrav  */
137b5038d7SDag-Erling Smørgrav 
147b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
157b5038d7SDag-Erling Smørgrav 
167b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
177b5038d7SDag-Erling Smørgrav 
187b5038d7SDag-Erling Smørgrav #ifdef HAVE_NETINET_IN_H
197b5038d7SDag-Erling Smørgrav #include <netinet/in.h>
207b5038d7SDag-Erling Smørgrav #endif
217b5038d7SDag-Erling Smørgrav #ifdef HAVE_SYS_SOCKET_H
227b5038d7SDag-Erling Smørgrav #include <sys/socket.h>
237b5038d7SDag-Erling Smørgrav #endif
247b5038d7SDag-Erling Smørgrav #ifdef HAVE_NETDB_H
257b5038d7SDag-Erling Smørgrav #include <netdb.h>
267b5038d7SDag-Erling Smørgrav #endif
277b5038d7SDag-Erling Smørgrav #ifdef HAVE_ARPA_INET_H
287b5038d7SDag-Erling Smørgrav #include <arpa/inet.h>
297b5038d7SDag-Erling Smørgrav #endif
307b5038d7SDag-Erling Smørgrav #include <sys/time.h>
317b5038d7SDag-Erling Smørgrav #include <errno.h>
327b5038d7SDag-Erling Smørgrav #include <fcntl.h>
33986ba33cSDag-Erling Smørgrav #ifdef HAVE_POLL
34986ba33cSDag-Erling Smørgrav #include <poll.h>
35986ba33cSDag-Erling Smørgrav #endif
367b5038d7SDag-Erling Smørgrav 
377b5038d7SDag-Erling Smørgrav ldns_status
ldns_send(ldns_pkt ** result_packet,ldns_resolver * r,const ldns_pkt * query_pkt)387b5038d7SDag-Erling Smørgrav ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt)
397b5038d7SDag-Erling Smørgrav {
407b5038d7SDag-Erling Smørgrav 	ldns_buffer *qb;
417b5038d7SDag-Erling Smørgrav 	ldns_status result;
427b5038d7SDag-Erling Smørgrav 	ldns_rdf *tsig_mac = NULL;
437b5038d7SDag-Erling Smørgrav 
447b5038d7SDag-Erling Smørgrav 	qb = ldns_buffer_new(LDNS_MIN_BUFLEN);
457b5038d7SDag-Erling Smørgrav 
467b5038d7SDag-Erling Smørgrav 	if (query_pkt && ldns_pkt_tsig(query_pkt)) {
477b5038d7SDag-Erling Smørgrav 		tsig_mac = ldns_rr_rdf(ldns_pkt_tsig(query_pkt), 3);
487b5038d7SDag-Erling Smørgrav 	}
497b5038d7SDag-Erling Smørgrav 
507b5038d7SDag-Erling Smørgrav 	if (!query_pkt ||
517b5038d7SDag-Erling Smørgrav 	    ldns_pkt2buffer_wire(qb, query_pkt) != LDNS_STATUS_OK) {
527b5038d7SDag-Erling Smørgrav 		result = LDNS_STATUS_ERR;
537b5038d7SDag-Erling Smørgrav 	} else {
547b5038d7SDag-Erling Smørgrav         	result = ldns_send_buffer(result_packet, r, qb, tsig_mac);
557b5038d7SDag-Erling Smørgrav 	}
567b5038d7SDag-Erling Smørgrav 
577b5038d7SDag-Erling Smørgrav 	ldns_buffer_free(qb);
587b5038d7SDag-Erling Smørgrav 
597b5038d7SDag-Erling Smørgrav 	return result;
607b5038d7SDag-Erling Smørgrav }
617b5038d7SDag-Erling Smørgrav 
6217d15b25SDag-Erling Smørgrav /* code from rdata.c */
6317d15b25SDag-Erling Smørgrav static struct sockaddr_storage *
ldns_rdf2native_sockaddr_storage_port(const ldns_rdf * rd,uint16_t port,size_t * size)6417d15b25SDag-Erling Smørgrav ldns_rdf2native_sockaddr_storage_port(
6517d15b25SDag-Erling Smørgrav 		const ldns_rdf *rd, uint16_t port, size_t *size)
667b5038d7SDag-Erling Smørgrav {
6717d15b25SDag-Erling Smørgrav         struct sockaddr_storage *data;
6817d15b25SDag-Erling Smørgrav         struct sockaddr_in  *data_in;
6917d15b25SDag-Erling Smørgrav         struct sockaddr_in6 *data_in6;
707b5038d7SDag-Erling Smørgrav 
7117d15b25SDag-Erling Smørgrav         data = LDNS_MALLOC(struct sockaddr_storage);
7217d15b25SDag-Erling Smørgrav         if (!data) {
7317d15b25SDag-Erling Smørgrav                 return NULL;
747b5038d7SDag-Erling Smørgrav         }
7517d15b25SDag-Erling Smørgrav 	/* zero the structure for portability */
7617d15b25SDag-Erling Smørgrav 	memset(data, 0, sizeof(struct sockaddr_storage));
777b5038d7SDag-Erling Smørgrav 
7817d15b25SDag-Erling Smørgrav         switch(ldns_rdf_get_type(rd)) {
7917d15b25SDag-Erling Smørgrav                 case LDNS_RDF_TYPE_A:
807b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S
8117d15b25SDag-Erling Smørgrav                         data->ss_family = AF_INET;
827b5038d7SDag-Erling Smørgrav #endif
8317d15b25SDag-Erling Smørgrav                         data_in = (struct sockaddr_in*) data;
8417d15b25SDag-Erling Smørgrav                         data_in->sin_port = (in_port_t)htons(port);
8517d15b25SDag-Erling Smørgrav                         memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd));
8617d15b25SDag-Erling Smørgrav                         *size = sizeof(struct sockaddr_in);
8717d15b25SDag-Erling Smørgrav                         return data;
8817d15b25SDag-Erling Smørgrav                 case LDNS_RDF_TYPE_AAAA:
8917d15b25SDag-Erling Smørgrav #ifndef S_SPLINT_S
9017d15b25SDag-Erling Smørgrav                         data->ss_family = AF_INET6;
9117d15b25SDag-Erling Smørgrav #endif
9217d15b25SDag-Erling Smørgrav                         data_in6 = (struct sockaddr_in6*) data;
9317d15b25SDag-Erling Smørgrav                         data_in6->sin6_port = (in_port_t)htons(port);
9417d15b25SDag-Erling Smørgrav                         memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd));
9517d15b25SDag-Erling Smørgrav                         *size = sizeof(struct sockaddr_in6);
9617d15b25SDag-Erling Smørgrav                         return data;
9717d15b25SDag-Erling Smørgrav                 default:
9817d15b25SDag-Erling Smørgrav                         LDNS_FREE(data);
9917d15b25SDag-Erling Smørgrav                         return NULL;
1007b5038d7SDag-Erling Smørgrav         }
1017b5038d7SDag-Erling Smørgrav }
1027b5038d7SDag-Erling Smørgrav 
10317d15b25SDag-Erling Smørgrav struct sockaddr_storage *
ldns_rdf2native_sockaddr_storage(const ldns_rdf * rd,uint16_t port,size_t * size)10417d15b25SDag-Erling Smørgrav ldns_rdf2native_sockaddr_storage(
10517d15b25SDag-Erling Smørgrav 		const ldns_rdf *rd, uint16_t port, size_t *size)
10617d15b25SDag-Erling Smørgrav {
10717d15b25SDag-Erling Smørgrav 	return ldns_rdf2native_sockaddr_storage_port(
10817d15b25SDag-Erling Smørgrav 			rd, (port == 0 ? (uint16_t)LDNS_PORT : port), size);
1097b5038d7SDag-Erling Smørgrav }
1107b5038d7SDag-Erling Smørgrav 
1117b5038d7SDag-Erling Smørgrav /** best effort to set nonblocking */
1127b5038d7SDag-Erling Smørgrav static void
ldns_sock_nonblock(int sockfd)1137b5038d7SDag-Erling Smørgrav ldns_sock_nonblock(int sockfd)
1147b5038d7SDag-Erling Smørgrav {
1157b5038d7SDag-Erling Smørgrav #ifdef HAVE_FCNTL
1167b5038d7SDag-Erling Smørgrav 	int flag;
1177b5038d7SDag-Erling Smørgrav 	if((flag = fcntl(sockfd, F_GETFL)) != -1) {
1187b5038d7SDag-Erling Smørgrav 		flag |= O_NONBLOCK;
1197b5038d7SDag-Erling Smørgrav 		if(fcntl(sockfd, F_SETFL, flag) == -1) {
1207b5038d7SDag-Erling Smørgrav 			/* ignore error, continue blockingly */
1217b5038d7SDag-Erling Smørgrav 		}
1227b5038d7SDag-Erling Smørgrav 	}
1237b5038d7SDag-Erling Smørgrav #elif defined(HAVE_IOCTLSOCKET)
1247b5038d7SDag-Erling Smørgrav 	unsigned long on = 1;
1257b5038d7SDag-Erling Smørgrav 	if(ioctlsocket(sockfd, FIONBIO, &on) != 0) {
1267b5038d7SDag-Erling Smørgrav 		/* ignore error, continue blockingly */
1277b5038d7SDag-Erling Smørgrav 	}
1287b5038d7SDag-Erling Smørgrav #endif
1297b5038d7SDag-Erling Smørgrav }
1307b5038d7SDag-Erling Smørgrav 
1317b5038d7SDag-Erling Smørgrav /** best effort to set blocking */
1327b5038d7SDag-Erling Smørgrav static void
ldns_sock_block(int sockfd)1337b5038d7SDag-Erling Smørgrav ldns_sock_block(int sockfd)
1347b5038d7SDag-Erling Smørgrav {
1357b5038d7SDag-Erling Smørgrav #ifdef HAVE_FCNTL
1367b5038d7SDag-Erling Smørgrav 	int flag;
1377b5038d7SDag-Erling Smørgrav 	if((flag = fcntl(sockfd, F_GETFL)) != -1) {
1387b5038d7SDag-Erling Smørgrav 		flag &= ~O_NONBLOCK;
1397b5038d7SDag-Erling Smørgrav 		if(fcntl(sockfd, F_SETFL, flag) == -1) {
1407b5038d7SDag-Erling Smørgrav 			/* ignore error, continue */
1417b5038d7SDag-Erling Smørgrav 		}
1427b5038d7SDag-Erling Smørgrav 	}
1437b5038d7SDag-Erling Smørgrav #elif defined(HAVE_IOCTLSOCKET)
1447b5038d7SDag-Erling Smørgrav 	unsigned long off = 0;
1457b5038d7SDag-Erling Smørgrav 	if(ioctlsocket(sockfd, FIONBIO, &off) != 0) {
1467b5038d7SDag-Erling Smørgrav 		/* ignore error, continue */
1477b5038d7SDag-Erling Smørgrav 	}
1487b5038d7SDag-Erling Smørgrav #endif
1497b5038d7SDag-Erling Smørgrav }
1507b5038d7SDag-Erling Smørgrav 
1517b5038d7SDag-Erling Smørgrav /** wait for a socket to become ready */
1527b5038d7SDag-Erling Smørgrav static int
ldns_sock_wait(int sockfd,struct timeval timeout,int write)1537b5038d7SDag-Erling Smørgrav ldns_sock_wait(int sockfd, struct timeval timeout, int write)
1547b5038d7SDag-Erling Smørgrav {
1557b5038d7SDag-Erling Smørgrav 	int ret;
156986ba33cSDag-Erling Smørgrav #ifndef HAVE_POLL
1577b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S
1587b5038d7SDag-Erling Smørgrav 	fd_set fds;
1597b5038d7SDag-Erling Smørgrav 	FD_ZERO(&fds);
1607b5038d7SDag-Erling Smørgrav 	FD_SET(FD_SET_T sockfd, &fds);
1617b5038d7SDag-Erling Smørgrav 	if(write)
1627b5038d7SDag-Erling Smørgrav 		ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
1637b5038d7SDag-Erling Smørgrav 	else
1647b5038d7SDag-Erling Smørgrav 		ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
1657b5038d7SDag-Erling Smørgrav #endif
166986ba33cSDag-Erling Smørgrav #else
167986ba33cSDag-Erling Smørgrav 	struct pollfd pfds[2];
168986ba33cSDag-Erling Smørgrav 
169986ba33cSDag-Erling Smørgrav 	memset(&pfds[0], 0, sizeof(pfds[0]) * 2);
170986ba33cSDag-Erling Smørgrav 
171986ba33cSDag-Erling Smørgrav 	pfds[0].fd = sockfd;
172986ba33cSDag-Erling Smørgrav 	pfds[0].events = POLLIN|POLLERR;
173986ba33cSDag-Erling Smørgrav 
174986ba33cSDag-Erling Smørgrav 	if (write) {
175986ba33cSDag-Erling Smørgrav 		pfds[0].events |= POLLOUT;
176986ba33cSDag-Erling Smørgrav 	}
177986ba33cSDag-Erling Smørgrav 
178986ba33cSDag-Erling Smørgrav 	ret = poll(pfds, 1, (int)(timeout.tv_sec * 1000
179986ba33cSDag-Erling Smørgrav 				+ timeout.tv_usec / 1000));
180986ba33cSDag-Erling Smørgrav #endif
1817b5038d7SDag-Erling Smørgrav 	if(ret == 0)
1827b5038d7SDag-Erling Smørgrav 		/* timeout expired */
1837b5038d7SDag-Erling Smørgrav 		return 0;
1847b5038d7SDag-Erling Smørgrav 	else if(ret == -1)
1857b5038d7SDag-Erling Smørgrav 		/* error */
1867b5038d7SDag-Erling Smørgrav 		return 0;
1877b5038d7SDag-Erling Smørgrav 	return 1;
1887b5038d7SDag-Erling Smørgrav }
1897b5038d7SDag-Erling Smørgrav 
1907b5038d7SDag-Erling Smørgrav 
19117d15b25SDag-Erling Smørgrav 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)19217d15b25SDag-Erling Smørgrav ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen,
19317d15b25SDag-Erling Smørgrav 	       	const struct sockaddr_storage *from, socklen_t fromlen,
1947b5038d7SDag-Erling Smørgrav 		struct timeval timeout)
1957b5038d7SDag-Erling Smørgrav {
1967b5038d7SDag-Erling Smørgrav 	int sockfd;
1977b5038d7SDag-Erling Smørgrav 
1987b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S
1997b5038d7SDag-Erling Smørgrav 	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM,
200986ba33cSDag-Erling Smørgrav 					IPPROTO_TCP)) == SOCK_INVALID) {
201*5afab0e5SDag-Erling Smørgrav 		return -1;
2027b5038d7SDag-Erling Smørgrav 	}
2037b5038d7SDag-Erling Smørgrav #endif
204986ba33cSDag-Erling Smørgrav 	if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == SOCK_INVALID){
205*5afab0e5SDag-Erling Smørgrav 		close_socket(sockfd);
206*5afab0e5SDag-Erling Smørgrav 		return -1;
20717d15b25SDag-Erling Smørgrav 	}
2087b5038d7SDag-Erling Smørgrav 
2097b5038d7SDag-Erling Smørgrav 	/* perform nonblocking connect, to be able to wait with select() */
2107b5038d7SDag-Erling Smørgrav 	ldns_sock_nonblock(sockfd);
211986ba33cSDag-Erling Smørgrav 	if (connect(sockfd, (struct sockaddr*)to, tolen) == SOCK_INVALID) {
2127b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK
2137b5038d7SDag-Erling Smørgrav #ifdef EINPROGRESS
2147b5038d7SDag-Erling Smørgrav 		if(errno != EINPROGRESS) {
2157b5038d7SDag-Erling Smørgrav #else
2167b5038d7SDag-Erling Smørgrav 		if(1) {
2177b5038d7SDag-Erling Smørgrav #endif
218986ba33cSDag-Erling Smørgrav 			close_socket(sockfd);
219*5afab0e5SDag-Erling Smørgrav 			return -1;
2207b5038d7SDag-Erling Smørgrav 		}
2217b5038d7SDag-Erling Smørgrav #else /* USE_WINSOCK */
2227b5038d7SDag-Erling Smørgrav 		if(WSAGetLastError() != WSAEINPROGRESS &&
2237b5038d7SDag-Erling Smørgrav 			WSAGetLastError() != WSAEWOULDBLOCK) {
224986ba33cSDag-Erling Smørgrav 			close_socket(sockfd);
225*5afab0e5SDag-Erling Smørgrav 			return -1;
2267b5038d7SDag-Erling Smørgrav 		}
2277b5038d7SDag-Erling Smørgrav #endif
2287b5038d7SDag-Erling Smørgrav 		/* error was only telling us that it would block */
2297b5038d7SDag-Erling Smørgrav 	}
2307b5038d7SDag-Erling Smørgrav 
2317b5038d7SDag-Erling Smørgrav 	/* wait(write) until connected or error */
2327b5038d7SDag-Erling Smørgrav 	while(1) {
2337b5038d7SDag-Erling Smørgrav 		int error = 0;
2347b5038d7SDag-Erling Smørgrav 		socklen_t len = (socklen_t)sizeof(error);
2357b5038d7SDag-Erling Smørgrav 
2367b5038d7SDag-Erling Smørgrav 		if(!ldns_sock_wait(sockfd, timeout, 1)) {
237986ba33cSDag-Erling Smørgrav 			close_socket(sockfd);
238*5afab0e5SDag-Erling Smørgrav 			return -1;
2397b5038d7SDag-Erling Smørgrav 		}
2407b5038d7SDag-Erling Smørgrav 
2417b5038d7SDag-Erling Smørgrav 		/* check if there is a pending error for nonblocking connect */
2427b5038d7SDag-Erling Smørgrav 		if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error,
2437b5038d7SDag-Erling Smørgrav 			&len) < 0) {
2447b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK
2457b5038d7SDag-Erling Smørgrav 			error = errno; /* on solaris errno is error */
2467b5038d7SDag-Erling Smørgrav #else
2477b5038d7SDag-Erling Smørgrav 			error = WSAGetLastError();
2487b5038d7SDag-Erling Smørgrav #endif
2497b5038d7SDag-Erling Smørgrav 		}
2507b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK
2517b5038d7SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
2527b5038d7SDag-Erling Smørgrav 		if(error == EINPROGRESS || error == EWOULDBLOCK)
2537b5038d7SDag-Erling Smørgrav 			continue; /* try again */
2547b5038d7SDag-Erling Smørgrav #endif
2557b5038d7SDag-Erling Smørgrav 		else if(error != 0) {
256986ba33cSDag-Erling Smørgrav 			close_socket(sockfd);
2577b5038d7SDag-Erling Smørgrav 			/* error in errno for our user */
2587b5038d7SDag-Erling Smørgrav 			errno = error;
259*5afab0e5SDag-Erling Smørgrav 			return -1;
2607b5038d7SDag-Erling Smørgrav 		}
2617b5038d7SDag-Erling Smørgrav #else /* USE_WINSOCK */
2627b5038d7SDag-Erling Smørgrav 		if(error == WSAEINPROGRESS)
2637b5038d7SDag-Erling Smørgrav 			continue;
2647b5038d7SDag-Erling Smørgrav 		else if(error == WSAEWOULDBLOCK)
2657b5038d7SDag-Erling Smørgrav 			continue;
2667b5038d7SDag-Erling Smørgrav 		else if(error != 0) {
267986ba33cSDag-Erling Smørgrav 			close_socket(sockfd);
2687b5038d7SDag-Erling Smørgrav 			errno = error;
269*5afab0e5SDag-Erling Smørgrav 			return -1;
2707b5038d7SDag-Erling Smørgrav 		}
2717b5038d7SDag-Erling Smørgrav #endif /* USE_WINSOCK */
2727b5038d7SDag-Erling Smørgrav 		/* connected */
2737b5038d7SDag-Erling Smørgrav 		break;
2747b5038d7SDag-Erling Smørgrav 	}
2757b5038d7SDag-Erling Smørgrav 
2767b5038d7SDag-Erling Smørgrav 	/* set the socket blocking again */
2777b5038d7SDag-Erling Smørgrav 	ldns_sock_block(sockfd);
2787b5038d7SDag-Erling Smørgrav 
2797b5038d7SDag-Erling Smørgrav 	return sockfd;
2807b5038d7SDag-Erling Smørgrav }
2817b5038d7SDag-Erling Smørgrav 
28217d15b25SDag-Erling Smørgrav int
28317d15b25SDag-Erling Smørgrav ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen,
28417d15b25SDag-Erling Smørgrav 		struct timeval timeout)
28517d15b25SDag-Erling Smørgrav {
286*5afab0e5SDag-Erling Smørgrav 	int s = ldns_tcp_connect_from(to, tolen, NULL, 0, timeout);
287*5afab0e5SDag-Erling Smørgrav 	return s > 0 ? s : 0;
288*5afab0e5SDag-Erling Smørgrav }
289*5afab0e5SDag-Erling Smørgrav 
290*5afab0e5SDag-Erling Smørgrav int
291*5afab0e5SDag-Erling Smørgrav ldns_tcp_connect2(const struct sockaddr_storage *to, socklen_t tolen,
292*5afab0e5SDag-Erling Smørgrav 		struct timeval timeout)
293*5afab0e5SDag-Erling Smørgrav {
29417d15b25SDag-Erling Smørgrav 	return ldns_tcp_connect_from(to, tolen, NULL, 0, timeout);
29517d15b25SDag-Erling Smørgrav }
29617d15b25SDag-Erling Smørgrav 
29717d15b25SDag-Erling Smørgrav static int
29817d15b25SDag-Erling Smørgrav ldns_tcp_bgsend_from(ldns_buffer *qbin,
29917d15b25SDag-Erling Smørgrav 		const struct sockaddr_storage *to, socklen_t tolen,
30017d15b25SDag-Erling Smørgrav 	       	const struct sockaddr_storage *from, socklen_t fromlen,
30117d15b25SDag-Erling Smørgrav 		struct timeval timeout)
30217d15b25SDag-Erling Smørgrav {
30317d15b25SDag-Erling Smørgrav 	int sockfd;
30417d15b25SDag-Erling Smørgrav 
30517d15b25SDag-Erling Smørgrav 	sockfd = ldns_tcp_connect_from(to, tolen, from, fromlen, timeout);
30617d15b25SDag-Erling Smørgrav 
307*5afab0e5SDag-Erling Smørgrav 	if (sockfd >= 0 && ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
308986ba33cSDag-Erling Smørgrav 		close_socket(sockfd);
309*5afab0e5SDag-Erling Smørgrav 		return -1;
31017d15b25SDag-Erling Smørgrav 	}
31117d15b25SDag-Erling Smørgrav 
31217d15b25SDag-Erling Smørgrav 	return sockfd;
31317d15b25SDag-Erling Smørgrav }
31417d15b25SDag-Erling Smørgrav 
31517d15b25SDag-Erling Smørgrav int
31617d15b25SDag-Erling Smørgrav ldns_tcp_bgsend(ldns_buffer *qbin,
31717d15b25SDag-Erling Smørgrav 		const struct sockaddr_storage *to, socklen_t tolen,
31817d15b25SDag-Erling Smørgrav 		struct timeval timeout)
31917d15b25SDag-Erling Smørgrav {
320*5afab0e5SDag-Erling Smørgrav 	int s = ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
321*5afab0e5SDag-Erling Smørgrav 	return s > 0 ? s : 0;
32217d15b25SDag-Erling Smørgrav }
32317d15b25SDag-Erling Smørgrav 
324*5afab0e5SDag-Erling Smørgrav int
325*5afab0e5SDag-Erling Smørgrav ldns_tcp_bgsend2(ldns_buffer *qbin,
326*5afab0e5SDag-Erling Smørgrav 		const struct sockaddr_storage *to, socklen_t tolen,
327*5afab0e5SDag-Erling Smørgrav 		struct timeval timeout)
328*5afab0e5SDag-Erling Smørgrav {
329*5afab0e5SDag-Erling Smørgrav 	return ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
330*5afab0e5SDag-Erling Smørgrav }
33117d15b25SDag-Erling Smørgrav 
33217d15b25SDag-Erling Smørgrav /* keep in mind that in DNS tcp messages the first 2 bytes signal the
33317d15b25SDag-Erling Smørgrav  * amount data to expect
33417d15b25SDag-Erling Smørgrav  */
33517d15b25SDag-Erling Smørgrav static ldns_status
33617d15b25SDag-Erling Smørgrav ldns_tcp_send_from(uint8_t **result,  ldns_buffer *qbin,
33717d15b25SDag-Erling Smørgrav 	       	const struct sockaddr_storage *to, socklen_t tolen,
33817d15b25SDag-Erling Smørgrav 	       	const struct sockaddr_storage *from, socklen_t fromlen,
33917d15b25SDag-Erling Smørgrav 		struct timeval timeout, size_t *answer_size)
34017d15b25SDag-Erling Smørgrav {
34117d15b25SDag-Erling Smørgrav 	int sockfd;
34217d15b25SDag-Erling Smørgrav 	uint8_t *answer;
34317d15b25SDag-Erling Smørgrav 
34417d15b25SDag-Erling Smørgrav 	sockfd = ldns_tcp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
34517d15b25SDag-Erling Smørgrav 
346*5afab0e5SDag-Erling Smørgrav 	if (sockfd == -1) {
34717d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_ERR;
34817d15b25SDag-Erling Smørgrav 	}
34917d15b25SDag-Erling Smørgrav 
35017d15b25SDag-Erling Smørgrav 	answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
351986ba33cSDag-Erling Smørgrav 	close_socket(sockfd);
35217d15b25SDag-Erling Smørgrav 
353*5afab0e5SDag-Erling Smørgrav 	if (!answer) {
35417d15b25SDag-Erling Smørgrav 		/* oops */
35517d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_NETWORK_ERR;
35617d15b25SDag-Erling Smørgrav 	}
35717d15b25SDag-Erling Smørgrav 
358*5afab0e5SDag-Erling Smørgrav 	*result = answer;
35917d15b25SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
36017d15b25SDag-Erling Smørgrav }
36117d15b25SDag-Erling Smørgrav 
36217d15b25SDag-Erling Smørgrav ldns_status
36317d15b25SDag-Erling Smørgrav ldns_tcp_send(uint8_t **result,  ldns_buffer *qbin,
36417d15b25SDag-Erling Smørgrav 		const struct sockaddr_storage *to, socklen_t tolen,
36517d15b25SDag-Erling Smørgrav 		struct timeval timeout, size_t *answer_size)
36617d15b25SDag-Erling Smørgrav {
36717d15b25SDag-Erling Smørgrav 	return ldns_tcp_send_from(result, qbin,
36817d15b25SDag-Erling Smørgrav 			to, tolen, NULL, 0, timeout, answer_size);
36917d15b25SDag-Erling Smørgrav }
37017d15b25SDag-Erling Smørgrav 
37117d15b25SDag-Erling Smørgrav int
37217d15b25SDag-Erling Smørgrav ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
37317d15b25SDag-Erling Smørgrav {
37417d15b25SDag-Erling Smørgrav 	int sockfd;
37517d15b25SDag-Erling Smørgrav 
37617d15b25SDag-Erling Smørgrav #ifndef S_SPLINT_S
37717d15b25SDag-Erling Smørgrav 	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
37817d15b25SDag-Erling Smørgrav 					IPPROTO_UDP))
379*5afab0e5SDag-Erling Smørgrav 			== SOCK_INVALID) {
38017d15b25SDag-Erling Smørgrav                 return 0;
38117d15b25SDag-Erling Smørgrav         }
38217d15b25SDag-Erling Smørgrav #endif
38317d15b25SDag-Erling Smørgrav 	return sockfd;
38417d15b25SDag-Erling Smørgrav }
38517d15b25SDag-Erling Smørgrav 
386*5afab0e5SDag-Erling Smørgrav int
387*5afab0e5SDag-Erling Smørgrav ldns_udp_connect2(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
388*5afab0e5SDag-Erling Smørgrav {
389*5afab0e5SDag-Erling Smørgrav 	int sockfd;
390*5afab0e5SDag-Erling Smørgrav 
391*5afab0e5SDag-Erling Smørgrav #ifndef S_SPLINT_S
392*5afab0e5SDag-Erling Smørgrav 	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
393*5afab0e5SDag-Erling Smørgrav 					IPPROTO_UDP))
394*5afab0e5SDag-Erling Smørgrav 			== SOCK_INVALID) {
395*5afab0e5SDag-Erling Smørgrav                 return -1;
396*5afab0e5SDag-Erling Smørgrav         }
397*5afab0e5SDag-Erling Smørgrav #endif
398*5afab0e5SDag-Erling Smørgrav 	return sockfd;
399*5afab0e5SDag-Erling Smørgrav }
400*5afab0e5SDag-Erling Smørgrav 
40117d15b25SDag-Erling Smørgrav static int
40217d15b25SDag-Erling Smørgrav ldns_udp_bgsend_from(ldns_buffer *qbin,
40317d15b25SDag-Erling Smørgrav 		const struct sockaddr_storage *to  , socklen_t tolen,
40417d15b25SDag-Erling Smørgrav 		const struct sockaddr_storage *from, socklen_t fromlen,
40517d15b25SDag-Erling Smørgrav 		struct timeval timeout)
40617d15b25SDag-Erling Smørgrav {
40717d15b25SDag-Erling Smørgrav 	int sockfd;
40817d15b25SDag-Erling Smørgrav 
409*5afab0e5SDag-Erling Smørgrav 	sockfd = ldns_udp_connect2(to, timeout);
41017d15b25SDag-Erling Smørgrav 
411*5afab0e5SDag-Erling Smørgrav 	if (sockfd == -1) {
412*5afab0e5SDag-Erling Smørgrav 		return -1;
41317d15b25SDag-Erling Smørgrav 	}
41417d15b25SDag-Erling Smørgrav 
41517d15b25SDag-Erling Smørgrav 	if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){
416*5afab0e5SDag-Erling Smørgrav 		close_socket(sockfd);
417*5afab0e5SDag-Erling Smørgrav 		return -1;
41817d15b25SDag-Erling Smørgrav 	}
41917d15b25SDag-Erling Smørgrav 
42017d15b25SDag-Erling Smørgrav 	if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
421986ba33cSDag-Erling Smørgrav 		close_socket(sockfd);
422*5afab0e5SDag-Erling Smørgrav 		return -1;
42317d15b25SDag-Erling Smørgrav 	}
42417d15b25SDag-Erling Smørgrav 	return sockfd;
42517d15b25SDag-Erling Smørgrav }
42617d15b25SDag-Erling Smørgrav 
42717d15b25SDag-Erling Smørgrav int
42817d15b25SDag-Erling Smørgrav ldns_udp_bgsend(ldns_buffer *qbin,
42917d15b25SDag-Erling Smørgrav 		const struct sockaddr_storage *to  , socklen_t tolen,
43017d15b25SDag-Erling Smørgrav 		struct timeval timeout)
43117d15b25SDag-Erling Smørgrav {
432*5afab0e5SDag-Erling Smørgrav 	int s = ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
433*5afab0e5SDag-Erling Smørgrav 	return s > 0 ? s : 0;
434*5afab0e5SDag-Erling Smørgrav }
435*5afab0e5SDag-Erling Smørgrav 
436*5afab0e5SDag-Erling Smørgrav int
437*5afab0e5SDag-Erling Smørgrav ldns_udp_bgsend2(ldns_buffer *qbin,
438*5afab0e5SDag-Erling Smørgrav 		const struct sockaddr_storage *to  , socklen_t tolen,
439*5afab0e5SDag-Erling Smørgrav 		struct timeval timeout)
440*5afab0e5SDag-Erling Smørgrav {
44117d15b25SDag-Erling Smørgrav 	return ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
44217d15b25SDag-Erling Smørgrav }
44317d15b25SDag-Erling Smørgrav 
44417d15b25SDag-Erling Smørgrav static ldns_status
44517d15b25SDag-Erling Smørgrav ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin,
44617d15b25SDag-Erling Smørgrav 		const struct sockaddr_storage *to  , socklen_t tolen,
44717d15b25SDag-Erling Smørgrav 		const struct sockaddr_storage *from, socklen_t fromlen,
44817d15b25SDag-Erling Smørgrav 		struct timeval timeout, size_t *answer_size)
44917d15b25SDag-Erling Smørgrav {
45017d15b25SDag-Erling Smørgrav 	int sockfd;
45117d15b25SDag-Erling Smørgrav 	uint8_t *answer;
45217d15b25SDag-Erling Smørgrav 
45317d15b25SDag-Erling Smørgrav 	sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
45417d15b25SDag-Erling Smørgrav 
455*5afab0e5SDag-Erling Smørgrav 	if (sockfd == -1) {
45617d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_SOCKET_ERROR;
45717d15b25SDag-Erling Smørgrav 	}
45817d15b25SDag-Erling Smørgrav 
45917d15b25SDag-Erling Smørgrav 	/* wait for an response*/
46017d15b25SDag-Erling Smørgrav 	if(!ldns_sock_wait(sockfd, timeout, 0)) {
461986ba33cSDag-Erling Smørgrav 		close_socket(sockfd);
46217d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_NETWORK_ERR;
46317d15b25SDag-Erling Smørgrav 	}
46417d15b25SDag-Erling Smørgrav 
46517d15b25SDag-Erling Smørgrav         /* set to nonblocking, so if the checksum is bad, it becomes
466*5afab0e5SDag-Erling Smørgrav          * an EAGAIN error and the ldns_udp_send function does not block,
46717d15b25SDag-Erling Smørgrav          * but returns a 'NETWORK_ERROR' much like a timeout. */
46817d15b25SDag-Erling Smørgrav         ldns_sock_nonblock(sockfd);
46917d15b25SDag-Erling Smørgrav 
47017d15b25SDag-Erling Smørgrav 	answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
471986ba33cSDag-Erling Smørgrav 	close_socket(sockfd);
47217d15b25SDag-Erling Smørgrav 
473*5afab0e5SDag-Erling Smørgrav 	if (!answer) {
47417d15b25SDag-Erling Smørgrav 		/* oops */
47517d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_NETWORK_ERR;
47617d15b25SDag-Erling Smørgrav 	}
47717d15b25SDag-Erling Smørgrav 
47817d15b25SDag-Erling Smørgrav 	*result = answer;
47917d15b25SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
48017d15b25SDag-Erling Smørgrav }
48117d15b25SDag-Erling Smørgrav 
48217d15b25SDag-Erling Smørgrav ldns_status
48317d15b25SDag-Erling Smørgrav ldns_udp_send(uint8_t **result, ldns_buffer *qbin,
48417d15b25SDag-Erling Smørgrav 		const struct sockaddr_storage *to  , socklen_t tolen,
48517d15b25SDag-Erling Smørgrav 		struct timeval timeout, size_t *answer_size)
48617d15b25SDag-Erling Smørgrav {
48717d15b25SDag-Erling Smørgrav 	return ldns_udp_send_from(result, qbin, to, tolen, NULL, 0,
48817d15b25SDag-Erling Smørgrav 			timeout, answer_size);
48917d15b25SDag-Erling Smørgrav }
49017d15b25SDag-Erling Smørgrav 
49117d15b25SDag-Erling Smørgrav ldns_status
49217d15b25SDag-Erling Smørgrav ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac)
49317d15b25SDag-Erling Smørgrav {
49417d15b25SDag-Erling Smørgrav 	uint8_t i;
49517d15b25SDag-Erling Smørgrav 
49617d15b25SDag-Erling Smørgrav 	struct sockaddr_storage *src = NULL;
497*5afab0e5SDag-Erling Smørgrav 	size_t src_len = 0;
49817d15b25SDag-Erling Smørgrav 	struct sockaddr_storage *ns;
49917d15b25SDag-Erling Smørgrav 	size_t ns_len;
50017d15b25SDag-Erling Smørgrav 	struct timeval tv_s;
50117d15b25SDag-Erling Smørgrav 	struct timeval tv_e;
50217d15b25SDag-Erling Smørgrav 
50317d15b25SDag-Erling Smørgrav 	ldns_rdf **ns_array;
50417d15b25SDag-Erling Smørgrav 	size_t *rtt;
50517d15b25SDag-Erling Smørgrav 	ldns_pkt *reply;
50617d15b25SDag-Erling Smørgrav 	bool all_servers_rtt_inf;
50717d15b25SDag-Erling Smørgrav 	uint8_t retries;
50817d15b25SDag-Erling Smørgrav 
50917d15b25SDag-Erling Smørgrav 	uint8_t *reply_bytes = NULL;
51017d15b25SDag-Erling Smørgrav 	size_t reply_size = 0;
51117d15b25SDag-Erling Smørgrav 	ldns_status status, send_status;
51217d15b25SDag-Erling Smørgrav 
51317d15b25SDag-Erling Smørgrav 	assert(r != NULL);
51417d15b25SDag-Erling Smørgrav 
51517d15b25SDag-Erling Smørgrav 	status = LDNS_STATUS_OK;
51617d15b25SDag-Erling Smørgrav 	rtt = ldns_resolver_rtt(r);
51717d15b25SDag-Erling Smørgrav 	ns_array = ldns_resolver_nameservers(r);
51817d15b25SDag-Erling Smørgrav 	reply = NULL;
51917d15b25SDag-Erling Smørgrav 	ns_len = 0;
52017d15b25SDag-Erling Smørgrav 
52117d15b25SDag-Erling Smørgrav 	all_servers_rtt_inf = true;
52217d15b25SDag-Erling Smørgrav 
52317d15b25SDag-Erling Smørgrav 	if (ldns_resolver_random(r)) {
52417d15b25SDag-Erling Smørgrav 		ldns_resolver_nameservers_randomize(r);
52517d15b25SDag-Erling Smørgrav 	}
52617d15b25SDag-Erling Smørgrav 
52717d15b25SDag-Erling Smørgrav 	if(ldns_resolver_source(r)) {
52817d15b25SDag-Erling Smørgrav 		src = ldns_rdf2native_sockaddr_storage_port(
52917d15b25SDag-Erling Smørgrav 				ldns_resolver_source(r), 0, &src_len);
53017d15b25SDag-Erling Smørgrav 	}
53117d15b25SDag-Erling Smørgrav 
53217d15b25SDag-Erling Smørgrav 	/* loop through all defined nameservers */
53317d15b25SDag-Erling Smørgrav 	for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
53417d15b25SDag-Erling Smørgrav 		if (rtt[i] == LDNS_RESOLV_RTT_INF) {
53517d15b25SDag-Erling Smørgrav 			/* not reachable nameserver! */
53617d15b25SDag-Erling Smørgrav 			continue;
53717d15b25SDag-Erling Smørgrav 		}
53817d15b25SDag-Erling Smørgrav 
53917d15b25SDag-Erling Smørgrav 		/* maybe verbosity setting?
54017d15b25SDag-Erling Smørgrav 		printf("Sending to ");
54117d15b25SDag-Erling Smørgrav 		ldns_rdf_print(stdout, ns_array[i]);
54217d15b25SDag-Erling Smørgrav 		printf("\n");
54317d15b25SDag-Erling Smørgrav 		*/
54417d15b25SDag-Erling Smørgrav 		ns = ldns_rdf2native_sockaddr_storage(ns_array[i],
54517d15b25SDag-Erling Smørgrav 				ldns_resolver_port(r), &ns_len);
54617d15b25SDag-Erling Smørgrav 
54717d15b25SDag-Erling Smørgrav 
54817d15b25SDag-Erling Smørgrav #ifndef S_SPLINT_S
54917d15b25SDag-Erling Smørgrav 		if ((ns->ss_family == AF_INET) &&
55017d15b25SDag-Erling Smørgrav 				(ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) {
55117d15b25SDag-Erling Smørgrav 			/* not reachable */
55217d15b25SDag-Erling Smørgrav 			LDNS_FREE(ns);
55317d15b25SDag-Erling Smørgrav 			continue;
55417d15b25SDag-Erling Smørgrav 		}
55517d15b25SDag-Erling Smørgrav 
55617d15b25SDag-Erling Smørgrav 		if ((ns->ss_family == AF_INET6) &&
55717d15b25SDag-Erling Smørgrav 				 (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) {
55817d15b25SDag-Erling Smørgrav 			/* not reachable */
55917d15b25SDag-Erling Smørgrav 			LDNS_FREE(ns);
56017d15b25SDag-Erling Smørgrav 			continue;
56117d15b25SDag-Erling Smørgrav 		}
56217d15b25SDag-Erling Smørgrav #endif
56317d15b25SDag-Erling Smørgrav 
56417d15b25SDag-Erling Smørgrav 		all_servers_rtt_inf = false;
56517d15b25SDag-Erling Smørgrav 
56617d15b25SDag-Erling Smørgrav 		gettimeofday(&tv_s, NULL);
56717d15b25SDag-Erling Smørgrav 
56817d15b25SDag-Erling Smørgrav 		send_status = LDNS_STATUS_ERR;
56917d15b25SDag-Erling Smørgrav 
57017d15b25SDag-Erling Smørgrav 		/* reply_bytes implicitly handles our error */
57117d15b25SDag-Erling Smørgrav 		if (ldns_resolver_usevc(r)) {
57217d15b25SDag-Erling Smørgrav 			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
57317d15b25SDag-Erling Smørgrav 				send_status =
57417d15b25SDag-Erling Smørgrav 					ldns_tcp_send_from(&reply_bytes, qb,
57517d15b25SDag-Erling Smørgrav 						ns, (socklen_t)ns_len,
57617d15b25SDag-Erling Smørgrav 						src, (socklen_t)src_len,
57717d15b25SDag-Erling Smørgrav 						ldns_resolver_timeout(r),
57817d15b25SDag-Erling Smørgrav 						&reply_size);
57917d15b25SDag-Erling Smørgrav 				if (send_status == LDNS_STATUS_OK) {
58017d15b25SDag-Erling Smørgrav 					break;
58117d15b25SDag-Erling Smørgrav 				}
58217d15b25SDag-Erling Smørgrav 			}
58317d15b25SDag-Erling Smørgrav 		} else {
58417d15b25SDag-Erling Smørgrav 			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
58517d15b25SDag-Erling Smørgrav 				/* ldns_rdf_print(stdout, ns_array[i]); */
58617d15b25SDag-Erling Smørgrav 				send_status =
58717d15b25SDag-Erling Smørgrav 					ldns_udp_send_from(&reply_bytes, qb,
58817d15b25SDag-Erling Smørgrav 						ns,  (socklen_t)ns_len,
58917d15b25SDag-Erling Smørgrav 						src, (socklen_t)src_len,
59017d15b25SDag-Erling Smørgrav 						ldns_resolver_timeout(r),
59117d15b25SDag-Erling Smørgrav 						&reply_size);
59217d15b25SDag-Erling Smørgrav 				if (send_status == LDNS_STATUS_OK) {
59317d15b25SDag-Erling Smørgrav 					break;
59417d15b25SDag-Erling Smørgrav 				}
59517d15b25SDag-Erling Smørgrav 			}
59617d15b25SDag-Erling Smørgrav 		}
59717d15b25SDag-Erling Smørgrav 
59817d15b25SDag-Erling Smørgrav 		if (send_status != LDNS_STATUS_OK) {
59917d15b25SDag-Erling Smørgrav 			ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF);
60017d15b25SDag-Erling Smørgrav 			status = send_status;
60117d15b25SDag-Erling Smørgrav 		}
60217d15b25SDag-Erling Smørgrav 
60317d15b25SDag-Erling Smørgrav 		/* obey the fail directive */
60417d15b25SDag-Erling Smørgrav 		if (!reply_bytes) {
60517d15b25SDag-Erling Smørgrav 			/* the current nameserver seems to have a problem, blacklist it */
60617d15b25SDag-Erling Smørgrav 			if (ldns_resolver_fail(r)) {
607*5afab0e5SDag-Erling Smørgrav 				if(src) {
608*5afab0e5SDag-Erling Smørgrav 					LDNS_FREE(src);
609*5afab0e5SDag-Erling Smørgrav 				}
61017d15b25SDag-Erling Smørgrav 				LDNS_FREE(ns);
61117d15b25SDag-Erling Smørgrav 				return LDNS_STATUS_ERR;
61217d15b25SDag-Erling Smørgrav 			} else {
61317d15b25SDag-Erling Smørgrav 				LDNS_FREE(ns);
61417d15b25SDag-Erling Smørgrav 				continue;
61517d15b25SDag-Erling Smørgrav 			}
61617d15b25SDag-Erling Smørgrav 		}
61717d15b25SDag-Erling Smørgrav 
61817d15b25SDag-Erling Smørgrav 		status = ldns_wire2pkt(&reply, reply_bytes, reply_size);
61917d15b25SDag-Erling Smørgrav 		if (status != LDNS_STATUS_OK) {
620*5afab0e5SDag-Erling Smørgrav 			if(src) LDNS_FREE(src);
62117d15b25SDag-Erling Smørgrav 			LDNS_FREE(reply_bytes);
62217d15b25SDag-Erling Smørgrav 			LDNS_FREE(ns);
62317d15b25SDag-Erling Smørgrav 			return status;
62417d15b25SDag-Erling Smørgrav 		}
625*5afab0e5SDag-Erling Smørgrav 		assert(reply);
62617d15b25SDag-Erling Smørgrav 
62717d15b25SDag-Erling Smørgrav 		LDNS_FREE(ns);
62817d15b25SDag-Erling Smørgrav 		gettimeofday(&tv_e, NULL);
62917d15b25SDag-Erling Smørgrav 
63017d15b25SDag-Erling Smørgrav 		if (reply) {
63117d15b25SDag-Erling Smørgrav 			ldns_pkt_set_querytime(reply, (uint32_t)
63217d15b25SDag-Erling Smørgrav 				((tv_e.tv_sec - tv_s.tv_sec) * 1000) +
63317d15b25SDag-Erling Smørgrav 				(tv_e.tv_usec - tv_s.tv_usec) / 1000);
63417d15b25SDag-Erling Smørgrav 			ldns_pkt_set_answerfrom(reply,
63517d15b25SDag-Erling Smørgrav 					ldns_rdf_clone(ns_array[i]));
63617d15b25SDag-Erling Smørgrav 			ldns_pkt_set_timestamp(reply, tv_s);
63717d15b25SDag-Erling Smørgrav 			ldns_pkt_set_size(reply, reply_size);
63817d15b25SDag-Erling Smørgrav 			break;
63917d15b25SDag-Erling Smørgrav 		} else {
64017d15b25SDag-Erling Smørgrav 			if (ldns_resolver_fail(r)) {
64117d15b25SDag-Erling Smørgrav 				/* if fail is set bail out, after the first
64217d15b25SDag-Erling Smørgrav 				 * one */
64317d15b25SDag-Erling Smørgrav 				break;
64417d15b25SDag-Erling Smørgrav 			}
64517d15b25SDag-Erling Smørgrav 		}
64617d15b25SDag-Erling Smørgrav 
64717d15b25SDag-Erling Smørgrav 		/* wait retrans seconds... */
64817d15b25SDag-Erling Smørgrav 		sleep((unsigned int) ldns_resolver_retrans(r));
64917d15b25SDag-Erling Smørgrav 	}
65017d15b25SDag-Erling Smørgrav 
65117d15b25SDag-Erling Smørgrav 	if(src) {
65217d15b25SDag-Erling Smørgrav 		LDNS_FREE(src);
65317d15b25SDag-Erling Smørgrav 	}
65417d15b25SDag-Erling Smørgrav 	if (all_servers_rtt_inf) {
65517d15b25SDag-Erling Smørgrav 		LDNS_FREE(reply_bytes);
65617d15b25SDag-Erling Smørgrav 		return LDNS_STATUS_RES_NO_NS;
65717d15b25SDag-Erling Smørgrav 	}
65817d15b25SDag-Erling Smørgrav #ifdef HAVE_SSL
65917d15b25SDag-Erling Smørgrav 	if (tsig_mac && reply && reply_bytes) {
66017d15b25SDag-Erling Smørgrav 		if (!ldns_pkt_tsig_verify(reply,
66117d15b25SDag-Erling Smørgrav 		                          reply_bytes,
66217d15b25SDag-Erling Smørgrav 					  reply_size,
66317d15b25SDag-Erling Smørgrav 		                          ldns_resolver_tsig_keyname(r),
66417d15b25SDag-Erling Smørgrav 		                          ldns_resolver_tsig_keydata(r), tsig_mac)) {
66517d15b25SDag-Erling Smørgrav 			status = LDNS_STATUS_CRYPTO_TSIG_BOGUS;
66617d15b25SDag-Erling Smørgrav 		}
66717d15b25SDag-Erling Smørgrav 	}
66817d15b25SDag-Erling Smørgrav #else
66917d15b25SDag-Erling Smørgrav 	(void)tsig_mac;
67017d15b25SDag-Erling Smørgrav #endif /* HAVE_SSL */
67117d15b25SDag-Erling Smørgrav 
67217d15b25SDag-Erling Smørgrav 	LDNS_FREE(reply_bytes);
67317d15b25SDag-Erling Smørgrav 	if (result) {
67417d15b25SDag-Erling Smørgrav 		*result = reply;
67517d15b25SDag-Erling Smørgrav 	}
67617d15b25SDag-Erling Smørgrav 
67717d15b25SDag-Erling Smørgrav 	return status;
67817d15b25SDag-Erling Smørgrav }
67917d15b25SDag-Erling Smørgrav 
6807b5038d7SDag-Erling Smørgrav ssize_t
6817b5038d7SDag-Erling Smørgrav ldns_tcp_send_query(ldns_buffer *qbin, int sockfd,
6827b5038d7SDag-Erling Smørgrav                     const struct sockaddr_storage *to, socklen_t tolen)
6837b5038d7SDag-Erling Smørgrav {
6847b5038d7SDag-Erling Smørgrav 	uint8_t *sendbuf;
6857b5038d7SDag-Erling Smørgrav 	ssize_t bytes;
6867b5038d7SDag-Erling Smørgrav 
6877b5038d7SDag-Erling Smørgrav 	/* add length of packet */
6887b5038d7SDag-Erling Smørgrav 	sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2);
6897b5038d7SDag-Erling Smørgrav 	if(!sendbuf) return 0;
6907b5038d7SDag-Erling Smørgrav 	ldns_write_uint16(sendbuf, ldns_buffer_position(qbin));
6912787e39aSDag-Erling Smørgrav 	memcpy(sendbuf + 2, ldns_buffer_begin(qbin), ldns_buffer_position(qbin));
6927b5038d7SDag-Erling Smørgrav 
6937b5038d7SDag-Erling Smørgrav 	bytes = sendto(sockfd, (void*)sendbuf,
6947b5038d7SDag-Erling Smørgrav 			ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen);
6957b5038d7SDag-Erling Smørgrav 
6967b5038d7SDag-Erling Smørgrav         LDNS_FREE(sendbuf);
6977b5038d7SDag-Erling Smørgrav 
6987b5038d7SDag-Erling Smørgrav 	if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) {
6997b5038d7SDag-Erling Smørgrav 		return 0;
7007b5038d7SDag-Erling Smørgrav 	}
7017b5038d7SDag-Erling Smørgrav 	return bytes;
7027b5038d7SDag-Erling Smørgrav }
7037b5038d7SDag-Erling Smørgrav 
7047b5038d7SDag-Erling Smørgrav /* don't wait for an answer */
7057b5038d7SDag-Erling Smørgrav ssize_t
7067b5038d7SDag-Erling Smørgrav ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to,
7077b5038d7SDag-Erling Smørgrav 		socklen_t tolen)
7087b5038d7SDag-Erling Smørgrav {
7097b5038d7SDag-Erling Smørgrav 	ssize_t bytes;
7107b5038d7SDag-Erling Smørgrav 
7117b5038d7SDag-Erling Smørgrav 	bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin),
7127b5038d7SDag-Erling Smørgrav 			ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen);
7137b5038d7SDag-Erling Smørgrav 
7147b5038d7SDag-Erling Smørgrav 	if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) {
7157b5038d7SDag-Erling Smørgrav 		return 0;
7167b5038d7SDag-Erling Smørgrav 	}
7177b5038d7SDag-Erling Smørgrav 	return bytes;
7187b5038d7SDag-Erling Smørgrav }
7197b5038d7SDag-Erling Smørgrav 
7207b5038d7SDag-Erling Smørgrav uint8_t *
7217b5038d7SDag-Erling Smørgrav ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from,
7227b5038d7SDag-Erling Smørgrav 		socklen_t *fromlen)
7237b5038d7SDag-Erling Smørgrav {
7247b5038d7SDag-Erling Smørgrav 	uint8_t *wire, *wireout;
7257b5038d7SDag-Erling Smørgrav 	ssize_t wire_size;
7267b5038d7SDag-Erling Smørgrav 
7277b5038d7SDag-Erling Smørgrav 	wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
7287b5038d7SDag-Erling Smørgrav 	if (!wire) {
7297b5038d7SDag-Erling Smørgrav 		*size = 0;
7307b5038d7SDag-Erling Smørgrav 		return NULL;
7317b5038d7SDag-Erling Smørgrav 	}
7327b5038d7SDag-Erling Smørgrav 
7337b5038d7SDag-Erling Smørgrav 	wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0,
7347b5038d7SDag-Erling Smørgrav 			(struct sockaddr *)from, fromlen);
7357b5038d7SDag-Erling Smørgrav 
7367b5038d7SDag-Erling Smørgrav 	/* recvfrom can also return 0 */
7377b5038d7SDag-Erling Smørgrav 	if (wire_size == -1 || wire_size == 0) {
7387b5038d7SDag-Erling Smørgrav 		*size = 0;
7397b5038d7SDag-Erling Smørgrav 		LDNS_FREE(wire);
7407b5038d7SDag-Erling Smørgrav 		return NULL;
7417b5038d7SDag-Erling Smørgrav 	}
7427b5038d7SDag-Erling Smørgrav 
7437b5038d7SDag-Erling Smørgrav 	*size = (size_t)wire_size;
7447b5038d7SDag-Erling Smørgrav 	wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size);
7457b5038d7SDag-Erling Smørgrav 	if(!wireout) LDNS_FREE(wire);
7467b5038d7SDag-Erling Smørgrav 
7477b5038d7SDag-Erling Smørgrav 	return wireout;
7487b5038d7SDag-Erling Smørgrav }
7497b5038d7SDag-Erling Smørgrav 
7507b5038d7SDag-Erling Smørgrav uint8_t *
7517b5038d7SDag-Erling Smørgrav ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout)
7527b5038d7SDag-Erling Smørgrav {
7537b5038d7SDag-Erling Smørgrav 	uint8_t *wire;
7547b5038d7SDag-Erling Smørgrav 	uint16_t wire_size;
7557b5038d7SDag-Erling Smørgrav 	ssize_t bytes = 0, rc = 0;
7567b5038d7SDag-Erling Smørgrav 
7577b5038d7SDag-Erling Smørgrav 	wire = LDNS_XMALLOC(uint8_t, 2);
7587b5038d7SDag-Erling Smørgrav 	if (!wire) {
7597b5038d7SDag-Erling Smørgrav 		*size = 0;
7607b5038d7SDag-Erling Smørgrav 		return NULL;
7617b5038d7SDag-Erling Smørgrav 	}
7627b5038d7SDag-Erling Smørgrav 
7637b5038d7SDag-Erling Smørgrav 	while (bytes < 2) {
7647b5038d7SDag-Erling Smørgrav 		if(!ldns_sock_wait(sockfd, timeout, 0)) {
7657b5038d7SDag-Erling Smørgrav 			*size = 0;
7667b5038d7SDag-Erling Smørgrav 			LDNS_FREE(wire);
7677b5038d7SDag-Erling Smørgrav 			return NULL;
7687b5038d7SDag-Erling Smørgrav 		}
7697b5038d7SDag-Erling Smørgrav 		rc = recv(sockfd, (void*) (wire + bytes),
7707b5038d7SDag-Erling Smørgrav 				(size_t) (2 - bytes), 0);
7717b5038d7SDag-Erling Smørgrav 		if (rc == -1 || rc == 0) {
7727b5038d7SDag-Erling Smørgrav 			*size = 0;
7737b5038d7SDag-Erling Smørgrav 			LDNS_FREE(wire);
7747b5038d7SDag-Erling Smørgrav 			return NULL;
7757b5038d7SDag-Erling Smørgrav 		}
7767b5038d7SDag-Erling Smørgrav                 bytes += rc;
7777b5038d7SDag-Erling Smørgrav 	}
7787b5038d7SDag-Erling Smørgrav 
7797b5038d7SDag-Erling Smørgrav 	wire_size = ldns_read_uint16(wire);
7807b5038d7SDag-Erling Smørgrav 
7817b5038d7SDag-Erling Smørgrav 	LDNS_FREE(wire);
7827b5038d7SDag-Erling Smørgrav 	wire = LDNS_XMALLOC(uint8_t, wire_size);
7837b5038d7SDag-Erling Smørgrav 	if (!wire) {
7847b5038d7SDag-Erling Smørgrav 		*size = 0;
7857b5038d7SDag-Erling Smørgrav 		return NULL;
7867b5038d7SDag-Erling Smørgrav 	}
7877b5038d7SDag-Erling Smørgrav 	bytes = 0;
7887b5038d7SDag-Erling Smørgrav 
7897b5038d7SDag-Erling Smørgrav 	while (bytes < (ssize_t) wire_size) {
7907b5038d7SDag-Erling Smørgrav 		if(!ldns_sock_wait(sockfd, timeout, 0)) {
7917b5038d7SDag-Erling Smørgrav 			*size = 0;
7927b5038d7SDag-Erling Smørgrav 			LDNS_FREE(wire);
7937b5038d7SDag-Erling Smørgrav 			return NULL;
7947b5038d7SDag-Erling Smørgrav 		}
7957b5038d7SDag-Erling Smørgrav 		rc = recv(sockfd, (void*) (wire + bytes),
7967b5038d7SDag-Erling Smørgrav 				(size_t) (wire_size - bytes), 0);
7977b5038d7SDag-Erling Smørgrav 		if (rc == -1 || rc == 0) {
7987b5038d7SDag-Erling Smørgrav 			LDNS_FREE(wire);
7997b5038d7SDag-Erling Smørgrav 			*size = 0;
8007b5038d7SDag-Erling Smørgrav 			return NULL;
8017b5038d7SDag-Erling Smørgrav 		}
8027b5038d7SDag-Erling Smørgrav                 bytes += rc;
8037b5038d7SDag-Erling Smørgrav 	}
8047b5038d7SDag-Erling Smørgrav 
8057b5038d7SDag-Erling Smørgrav 	*size = (size_t) bytes;
8067b5038d7SDag-Erling Smørgrav 	return wire;
8077b5038d7SDag-Erling Smørgrav }
8087b5038d7SDag-Erling Smørgrav 
8097b5038d7SDag-Erling Smørgrav uint8_t *
8107b5038d7SDag-Erling Smørgrav ldns_tcp_read_wire(int sockfd, size_t *size)
8117b5038d7SDag-Erling Smørgrav {
8127b5038d7SDag-Erling Smørgrav 	uint8_t *wire;
8137b5038d7SDag-Erling Smørgrav 	uint16_t wire_size;
8147b5038d7SDag-Erling Smørgrav 	ssize_t bytes = 0, rc = 0;
8157b5038d7SDag-Erling Smørgrav 
8167b5038d7SDag-Erling Smørgrav 	wire = LDNS_XMALLOC(uint8_t, 2);
8177b5038d7SDag-Erling Smørgrav 	if (!wire) {
8187b5038d7SDag-Erling Smørgrav 		*size = 0;
8197b5038d7SDag-Erling Smørgrav 		return NULL;
8207b5038d7SDag-Erling Smørgrav 	}
8217b5038d7SDag-Erling Smørgrav 
8227b5038d7SDag-Erling Smørgrav 	while (bytes < 2) {
8237b5038d7SDag-Erling Smørgrav 		rc = recv(sockfd, (void*) (wire + bytes),
8247b5038d7SDag-Erling Smørgrav 				(size_t) (2 - bytes), 0);
8257b5038d7SDag-Erling Smørgrav 		if (rc == -1 || rc == 0) {
8267b5038d7SDag-Erling Smørgrav 			*size = 0;
8277b5038d7SDag-Erling Smørgrav 			LDNS_FREE(wire);
8287b5038d7SDag-Erling Smørgrav 			return NULL;
8297b5038d7SDag-Erling Smørgrav 		}
8307b5038d7SDag-Erling Smørgrav                 bytes += rc;
8317b5038d7SDag-Erling Smørgrav 	}
8327b5038d7SDag-Erling Smørgrav 
8337b5038d7SDag-Erling Smørgrav 	wire_size = ldns_read_uint16(wire);
8347b5038d7SDag-Erling Smørgrav 
8357b5038d7SDag-Erling Smørgrav 	LDNS_FREE(wire);
8367b5038d7SDag-Erling Smørgrav 	wire = LDNS_XMALLOC(uint8_t, wire_size);
8377b5038d7SDag-Erling Smørgrav 	if (!wire) {
8387b5038d7SDag-Erling Smørgrav 		*size = 0;
8397b5038d7SDag-Erling Smørgrav 		return NULL;
8407b5038d7SDag-Erling Smørgrav 	}
8417b5038d7SDag-Erling Smørgrav 	bytes = 0;
8427b5038d7SDag-Erling Smørgrav 
8437b5038d7SDag-Erling Smørgrav 	while (bytes < (ssize_t) wire_size) {
8447b5038d7SDag-Erling Smørgrav 		rc = recv(sockfd, (void*) (wire + bytes),
8457b5038d7SDag-Erling Smørgrav 				(size_t) (wire_size - bytes), 0);
8467b5038d7SDag-Erling Smørgrav 		if (rc == -1 || rc == 0) {
8477b5038d7SDag-Erling Smørgrav 			LDNS_FREE(wire);
8487b5038d7SDag-Erling Smørgrav 			*size = 0;
8497b5038d7SDag-Erling Smørgrav 			return NULL;
8507b5038d7SDag-Erling Smørgrav 		}
8517b5038d7SDag-Erling Smørgrav                 bytes += rc;
8527b5038d7SDag-Erling Smørgrav 	}
8537b5038d7SDag-Erling Smørgrav 
8547b5038d7SDag-Erling Smørgrav 	*size = (size_t) bytes;
8557b5038d7SDag-Erling Smørgrav 	return wire;
8567b5038d7SDag-Erling Smørgrav }
8577b5038d7SDag-Erling Smørgrav 
8587b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S
8597b5038d7SDag-Erling Smørgrav ldns_rdf *
860986ba33cSDag-Erling Smørgrav ldns_sockaddr_storage2rdf(const struct sockaddr_storage *sock, uint16_t *port)
8617b5038d7SDag-Erling Smørgrav {
8627b5038d7SDag-Erling Smørgrav         ldns_rdf *addr;
8637b5038d7SDag-Erling Smørgrav         struct sockaddr_in *data_in;
8647b5038d7SDag-Erling Smørgrav         struct sockaddr_in6 *data_in6;
8657b5038d7SDag-Erling Smørgrav 
8667b5038d7SDag-Erling Smørgrav         switch(sock->ss_family) {
8677b5038d7SDag-Erling Smørgrav                 case AF_INET:
8687b5038d7SDag-Erling Smørgrav                         data_in = (struct sockaddr_in*)sock;
8697b5038d7SDag-Erling Smørgrav                         if (port) {
8707b5038d7SDag-Erling Smørgrav                                 *port = ntohs((uint16_t)data_in->sin_port);
8717b5038d7SDag-Erling Smørgrav                         }
8727b5038d7SDag-Erling Smørgrav                         addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A,
8737b5038d7SDag-Erling Smørgrav                                         LDNS_IP4ADDRLEN, &data_in->sin_addr);
8747b5038d7SDag-Erling Smørgrav                         break;
8757b5038d7SDag-Erling Smørgrav                 case AF_INET6:
8767b5038d7SDag-Erling Smørgrav                         data_in6 = (struct sockaddr_in6*)sock;
8777b5038d7SDag-Erling Smørgrav                         if (port) {
8787b5038d7SDag-Erling Smørgrav                                 *port = ntohs((uint16_t)data_in6->sin6_port);
8797b5038d7SDag-Erling Smørgrav                         }
8807b5038d7SDag-Erling Smørgrav                         addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA,
8817b5038d7SDag-Erling Smørgrav                                         LDNS_IP6ADDRLEN, &data_in6->sin6_addr);
8827b5038d7SDag-Erling Smørgrav                         break;
8837b5038d7SDag-Erling Smørgrav                 default:
8847b5038d7SDag-Erling Smørgrav                         if (port) {
8857b5038d7SDag-Erling Smørgrav                                 *port = 0;
8867b5038d7SDag-Erling Smørgrav                         }
8877b5038d7SDag-Erling Smørgrav                         return NULL;
8887b5038d7SDag-Erling Smørgrav         }
8897b5038d7SDag-Erling Smørgrav         return addr;
8907b5038d7SDag-Erling Smørgrav }
8917b5038d7SDag-Erling Smørgrav #endif
8927b5038d7SDag-Erling Smørgrav 
8937b5038d7SDag-Erling Smørgrav /* code from resolver.c */
8947b5038d7SDag-Erling Smørgrav ldns_status
895986ba33cSDag-Erling Smørgrav ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class class)
8967b5038d7SDag-Erling Smørgrav {
8977b5038d7SDag-Erling Smørgrav         ldns_pkt *query;
8987b5038d7SDag-Erling Smørgrav         ldns_buffer *query_wire;
8997b5038d7SDag-Erling Smørgrav 
90017d15b25SDag-Erling Smørgrav         struct sockaddr_storage *src = NULL;
90117d15b25SDag-Erling Smørgrav         size_t src_len = 0;
9027b5038d7SDag-Erling Smørgrav         struct sockaddr_storage *ns = NULL;
9037b5038d7SDag-Erling Smørgrav         size_t ns_len = 0;
9047b5038d7SDag-Erling Smørgrav         size_t ns_i;
9057b5038d7SDag-Erling Smørgrav         ldns_status status;
9067b5038d7SDag-Erling Smørgrav 
9077b5038d7SDag-Erling Smørgrav         if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) {
9087b5038d7SDag-Erling Smørgrav                 return LDNS_STATUS_ERR;
9097b5038d7SDag-Erling Smørgrav         }
9107b5038d7SDag-Erling Smørgrav 
9117b5038d7SDag-Erling Smørgrav         query = ldns_pkt_query_new(ldns_rdf_clone(domain), LDNS_RR_TYPE_AXFR, class, 0);
9127b5038d7SDag-Erling Smørgrav 
9137b5038d7SDag-Erling Smørgrav         if (!query) {
9147b5038d7SDag-Erling Smørgrav                 return LDNS_STATUS_ADDRESS_ERR;
9157b5038d7SDag-Erling Smørgrav         }
91617d15b25SDag-Erling Smørgrav 	if(ldns_resolver_source(resolver)) {
91717d15b25SDag-Erling Smørgrav 		src = ldns_rdf2native_sockaddr_storage_port(
91817d15b25SDag-Erling Smørgrav 				ldns_resolver_source(resolver), 0, &src_len);
91917d15b25SDag-Erling Smørgrav 	}
9207b5038d7SDag-Erling Smørgrav         /* For AXFR, we have to make the connection ourselves */
9217b5038d7SDag-Erling Smørgrav         /* try all nameservers (which usually would mean v4 fallback if
9227b5038d7SDag-Erling Smørgrav          * @hostname is used */
9237b5038d7SDag-Erling Smørgrav         for (ns_i = 0;
9247b5038d7SDag-Erling Smørgrav              ns_i < ldns_resolver_nameserver_count(resolver) &&
925986ba33cSDag-Erling Smørgrav              resolver->_socket == SOCK_INVALID;
9267b5038d7SDag-Erling Smørgrav              ns_i++) {
9272787e39aSDag-Erling Smørgrav 		if (ns != NULL) {
9282787e39aSDag-Erling Smørgrav 			LDNS_FREE(ns);
9292787e39aSDag-Erling Smørgrav 		}
9307b5038d7SDag-Erling Smørgrav 	        ns = ldns_rdf2native_sockaddr_storage(
9317b5038d7SDag-Erling Smørgrav 	        	resolver->_nameservers[ns_i],
9327b5038d7SDag-Erling Smørgrav 			ldns_resolver_port(resolver), &ns_len);
933986ba33cSDag-Erling Smørgrav #ifndef S_SPLINT_S
934986ba33cSDag-Erling Smørgrav 		if ((ns->ss_family == AF_INET) &&
935986ba33cSDag-Erling Smørgrav 			(ldns_resolver_ip6(resolver) == LDNS_RESOLV_INET6)) {
936986ba33cSDag-Erling Smørgrav 			/* not reachable */
937986ba33cSDag-Erling Smørgrav 			LDNS_FREE(ns);
938986ba33cSDag-Erling Smørgrav 			ns = NULL;
939986ba33cSDag-Erling Smørgrav 			continue;
940986ba33cSDag-Erling Smørgrav 		}
941986ba33cSDag-Erling Smørgrav 
942986ba33cSDag-Erling Smørgrav 		if ((ns->ss_family == AF_INET6) &&
943986ba33cSDag-Erling Smørgrav 			 (ldns_resolver_ip6(resolver) == LDNS_RESOLV_INET)) {
944986ba33cSDag-Erling Smørgrav 			/* not reachable */
945986ba33cSDag-Erling Smørgrav 			LDNS_FREE(ns);
946986ba33cSDag-Erling Smørgrav 			ns = NULL;
947986ba33cSDag-Erling Smørgrav 			continue;
948986ba33cSDag-Erling Smørgrav 		}
949986ba33cSDag-Erling Smørgrav #endif
9507b5038d7SDag-Erling Smørgrav 
95117d15b25SDag-Erling Smørgrav 		resolver->_socket = ldns_tcp_connect_from(
95217d15b25SDag-Erling Smørgrav 				ns, (socklen_t)ns_len,
95317d15b25SDag-Erling Smørgrav 				src, (socklen_t)src_len,
9547b5038d7SDag-Erling Smørgrav 				ldns_resolver_timeout(resolver));
9557b5038d7SDag-Erling Smørgrav 	}
956*5afab0e5SDag-Erling Smørgrav 	if (src) {
957*5afab0e5SDag-Erling Smørgrav 		LDNS_FREE(src);
958*5afab0e5SDag-Erling Smørgrav 	}
9597b5038d7SDag-Erling Smørgrav 
960986ba33cSDag-Erling Smørgrav 	if (resolver->_socket == SOCK_INVALID) {
9617b5038d7SDag-Erling Smørgrav 		ldns_pkt_free(query);
9627b5038d7SDag-Erling Smørgrav 		LDNS_FREE(ns);
9637b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_NETWORK_ERR;
9647b5038d7SDag-Erling Smørgrav 	}
9657b5038d7SDag-Erling Smørgrav 
9667b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL
9677b5038d7SDag-Erling Smørgrav 	if (ldns_resolver_tsig_keyname(resolver) && ldns_resolver_tsig_keydata(resolver)) {
9687b5038d7SDag-Erling Smørgrav 		status = ldns_pkt_tsig_sign(query,
9697b5038d7SDag-Erling Smørgrav 		                            ldns_resolver_tsig_keyname(resolver),
9707b5038d7SDag-Erling Smørgrav 		                            ldns_resolver_tsig_keydata(resolver),
9717b5038d7SDag-Erling Smørgrav 		                            300, ldns_resolver_tsig_algorithm(resolver), NULL);
9727b5038d7SDag-Erling Smørgrav 		if (status != LDNS_STATUS_OK) {
97317d15b25SDag-Erling Smørgrav 			/* to prevent problems on subsequent calls to
97417d15b25SDag-Erling Smørgrav 			 * ldns_axfr_start we have to close the socket here! */
975986ba33cSDag-Erling Smørgrav 			close_socket(resolver->_socket);
9767b5038d7SDag-Erling Smørgrav 			resolver->_socket = 0;
9777b5038d7SDag-Erling Smørgrav 
9782787e39aSDag-Erling Smørgrav 			ldns_pkt_free(query);
9792787e39aSDag-Erling Smørgrav 			LDNS_FREE(ns);
9802787e39aSDag-Erling Smørgrav 
9817b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_CRYPTO_TSIG_ERR;
9827b5038d7SDag-Erling Smørgrav 		}
9837b5038d7SDag-Erling Smørgrav 	}
9847b5038d7SDag-Erling Smørgrav #endif /* HAVE_SSL */
9857b5038d7SDag-Erling Smørgrav 
9867b5038d7SDag-Erling Smørgrav         /* Convert the query to a buffer
9877b5038d7SDag-Erling Smørgrav          * Is this necessary?
9887b5038d7SDag-Erling Smørgrav          */
9897b5038d7SDag-Erling Smørgrav         query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN);
9907b5038d7SDag-Erling Smørgrav         if(!query_wire) {
9917b5038d7SDag-Erling Smørgrav                 ldns_pkt_free(query);
9927b5038d7SDag-Erling Smørgrav                 LDNS_FREE(ns);
993986ba33cSDag-Erling Smørgrav 
994986ba33cSDag-Erling Smørgrav 		close_socket(resolver->_socket);
9957b5038d7SDag-Erling Smørgrav 
9967b5038d7SDag-Erling Smørgrav                 return LDNS_STATUS_MEM_ERR;
9977b5038d7SDag-Erling Smørgrav         }
9987b5038d7SDag-Erling Smørgrav         status = ldns_pkt2buffer_wire(query_wire, query);
9997b5038d7SDag-Erling Smørgrav         if (status != LDNS_STATUS_OK) {
10007b5038d7SDag-Erling Smørgrav                 ldns_pkt_free(query);
10017b5038d7SDag-Erling Smørgrav 		ldns_buffer_free(query_wire);
10027b5038d7SDag-Erling Smørgrav                 LDNS_FREE(ns);
10037b5038d7SDag-Erling Smørgrav 
100417d15b25SDag-Erling Smørgrav 		/* to prevent problems on subsequent calls to ldns_axfr_start
100517d15b25SDag-Erling Smørgrav 		 * we have to close the socket here! */
1006986ba33cSDag-Erling Smørgrav 		close_socket(resolver->_socket);
10077b5038d7SDag-Erling Smørgrav 		resolver->_socket = 0;
10087b5038d7SDag-Erling Smørgrav 
10097b5038d7SDag-Erling Smørgrav                 return status;
10107b5038d7SDag-Erling Smørgrav         }
10117b5038d7SDag-Erling Smørgrav         /* Send the query */
10127b5038d7SDag-Erling Smørgrav         if (ldns_tcp_send_query(query_wire, resolver->_socket, ns,
10137b5038d7SDag-Erling Smørgrav 				(socklen_t)ns_len) == 0) {
10147b5038d7SDag-Erling Smørgrav                 ldns_pkt_free(query);
10157b5038d7SDag-Erling Smørgrav                 ldns_buffer_free(query_wire);
10167b5038d7SDag-Erling Smørgrav                 LDNS_FREE(ns);
10177b5038d7SDag-Erling Smørgrav 
101817d15b25SDag-Erling Smørgrav 		/* to prevent problems on subsequent calls to ldns_axfr_start
101917d15b25SDag-Erling Smørgrav 		 * we have to close the socket here! */
10207b5038d7SDag-Erling Smørgrav 
1021986ba33cSDag-Erling Smørgrav 
1022986ba33cSDag-Erling Smørgrav 		close_socket(resolver->_socket);
10237b5038d7SDag-Erling Smørgrav 
10247b5038d7SDag-Erling Smørgrav                 return LDNS_STATUS_NETWORK_ERR;
10257b5038d7SDag-Erling Smørgrav         }
10267b5038d7SDag-Erling Smørgrav 
10277b5038d7SDag-Erling Smørgrav         ldns_pkt_free(query);
10287b5038d7SDag-Erling Smørgrav         ldns_buffer_free(query_wire);
10297b5038d7SDag-Erling Smørgrav         LDNS_FREE(ns);
10307b5038d7SDag-Erling Smørgrav 
10317b5038d7SDag-Erling Smørgrav         /*
10327b5038d7SDag-Erling Smørgrav          * The AXFR is done once the second SOA record is sent
10337b5038d7SDag-Erling Smørgrav          */
10347b5038d7SDag-Erling Smørgrav         resolver->_axfr_soa_count = 0;
10357b5038d7SDag-Erling Smørgrav         return LDNS_STATUS_OK;
10367b5038d7SDag-Erling Smørgrav }
1037