1238104Sdes/*
2238104Sdes * net.c
3238104Sdes *
4238104Sdes * Network implementation
5238104Sdes * All network related functions are grouped here
6238104Sdes *
7238104Sdes * a Net::DNS like library for C
8238104Sdes *
9238104Sdes * (c) NLnet Labs, 2004-2006
10238104Sdes *
11238104Sdes * See the file LICENSE for the license
12238104Sdes */
13238104Sdes
14238104Sdes#include <ldns/config.h>
15238104Sdes
16238104Sdes#include <ldns/ldns.h>
17238104Sdes
18238104Sdes#ifdef HAVE_NETINET_IN_H
19238104Sdes#include <netinet/in.h>
20238104Sdes#endif
21238104Sdes#ifdef HAVE_SYS_SOCKET_H
22238104Sdes#include <sys/socket.h>
23238104Sdes#endif
24238104Sdes#ifdef HAVE_NETDB_H
25238104Sdes#include <netdb.h>
26238104Sdes#endif
27238104Sdes#ifdef HAVE_ARPA_INET_H
28238104Sdes#include <arpa/inet.h>
29238104Sdes#endif
30238104Sdes#include <sys/time.h>
31238104Sdes#include <errno.h>
32238104Sdes#include <fcntl.h>
33238104Sdes
34238104Sdesldns_status
35238104Sdesldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt)
36238104Sdes{
37238104Sdes	ldns_buffer *qb;
38238104Sdes	ldns_status result;
39238104Sdes	ldns_rdf *tsig_mac = NULL;
40238104Sdes
41238104Sdes	qb = ldns_buffer_new(LDNS_MIN_BUFLEN);
42238104Sdes
43238104Sdes	if (query_pkt && ldns_pkt_tsig(query_pkt)) {
44238104Sdes		tsig_mac = ldns_rr_rdf(ldns_pkt_tsig(query_pkt), 3);
45238104Sdes	}
46238104Sdes
47238104Sdes	if (!query_pkt ||
48238104Sdes	    ldns_pkt2buffer_wire(qb, query_pkt) != LDNS_STATUS_OK) {
49238104Sdes		result = LDNS_STATUS_ERR;
50238104Sdes	} else {
51238104Sdes        	result = ldns_send_buffer(result_packet, r, qb, tsig_mac);
52238104Sdes	}
53238104Sdes
54238104Sdes	ldns_buffer_free(qb);
55238104Sdes
56238104Sdes	return result;
57238104Sdes}
58238104Sdes
59269257Sdes/* code from rdata.c */
60269257Sdesstatic struct sockaddr_storage *
61269257Sdesldns_rdf2native_sockaddr_storage_port(
62269257Sdes		const ldns_rdf *rd, uint16_t port, size_t *size)
63269257Sdes{
64269257Sdes        struct sockaddr_storage *data;
65269257Sdes        struct sockaddr_in  *data_in;
66269257Sdes        struct sockaddr_in6 *data_in6;
67269257Sdes
68269257Sdes        data = LDNS_MALLOC(struct sockaddr_storage);
69269257Sdes        if (!data) {
70269257Sdes                return NULL;
71269257Sdes        }
72269257Sdes	/* zero the structure for portability */
73269257Sdes	memset(data, 0, sizeof(struct sockaddr_storage));
74269257Sdes
75269257Sdes        switch(ldns_rdf_get_type(rd)) {
76269257Sdes                case LDNS_RDF_TYPE_A:
77269257Sdes#ifndef S_SPLINT_S
78269257Sdes                        data->ss_family = AF_INET;
79269257Sdes#endif
80269257Sdes                        data_in = (struct sockaddr_in*) data;
81269257Sdes                        data_in->sin_port = (in_port_t)htons(port);
82269257Sdes                        memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd));
83269257Sdes                        *size = sizeof(struct sockaddr_in);
84269257Sdes                        return data;
85269257Sdes                case LDNS_RDF_TYPE_AAAA:
86269257Sdes#ifndef S_SPLINT_S
87269257Sdes                        data->ss_family = AF_INET6;
88269257Sdes#endif
89269257Sdes                        data_in6 = (struct sockaddr_in6*) data;
90269257Sdes                        data_in6->sin6_port = (in_port_t)htons(port);
91269257Sdes                        memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd));
92269257Sdes                        *size = sizeof(struct sockaddr_in6);
93269257Sdes                        return data;
94269257Sdes                default:
95269257Sdes                        LDNS_FREE(data);
96269257Sdes                        return NULL;
97269257Sdes        }
98269257Sdes}
99269257Sdes
100269257Sdesstruct sockaddr_storage *
101269257Sdesldns_rdf2native_sockaddr_storage(
102269257Sdes		const ldns_rdf *rd, uint16_t port, size_t *size)
103269257Sdes{
104269257Sdes	return ldns_rdf2native_sockaddr_storage_port(
105269257Sdes			rd, (port == 0 ? (uint16_t)LDNS_PORT : port), size);
106269257Sdes}
107269257Sdes
108269257Sdes/** best effort to set nonblocking */
109269257Sdesstatic void
110269257Sdesldns_sock_nonblock(int sockfd)
111269257Sdes{
112269257Sdes#ifdef HAVE_FCNTL
113269257Sdes	int flag;
114269257Sdes	if((flag = fcntl(sockfd, F_GETFL)) != -1) {
115269257Sdes		flag |= O_NONBLOCK;
116269257Sdes		if(fcntl(sockfd, F_SETFL, flag) == -1) {
117269257Sdes			/* ignore error, continue blockingly */
118269257Sdes		}
119269257Sdes	}
120269257Sdes#elif defined(HAVE_IOCTLSOCKET)
121269257Sdes	unsigned long on = 1;
122269257Sdes	if(ioctlsocket(sockfd, FIONBIO, &on) != 0) {
123269257Sdes		/* ignore error, continue blockingly */
124269257Sdes	}
125269257Sdes#endif
126269257Sdes}
127269257Sdes
128269257Sdes/** best effort to set blocking */
129269257Sdesstatic void
130269257Sdesldns_sock_block(int sockfd)
131269257Sdes{
132269257Sdes#ifdef HAVE_FCNTL
133269257Sdes	int flag;
134269257Sdes	if((flag = fcntl(sockfd, F_GETFL)) != -1) {
135269257Sdes		flag &= ~O_NONBLOCK;
136269257Sdes		if(fcntl(sockfd, F_SETFL, flag) == -1) {
137269257Sdes			/* ignore error, continue */
138269257Sdes		}
139269257Sdes	}
140269257Sdes#elif defined(HAVE_IOCTLSOCKET)
141269257Sdes	unsigned long off = 0;
142269257Sdes	if(ioctlsocket(sockfd, FIONBIO, &off) != 0) {
143269257Sdes		/* ignore error, continue */
144269257Sdes	}
145269257Sdes#endif
146269257Sdes}
147269257Sdes
148269257Sdes/** wait for a socket to become ready */
149269257Sdesstatic int
150269257Sdesldns_sock_wait(int sockfd, struct timeval timeout, int write)
151269257Sdes{
152269257Sdes	int ret;
153269257Sdes#ifndef S_SPLINT_S
154269257Sdes	fd_set fds;
155269257Sdes	FD_ZERO(&fds);
156269257Sdes	FD_SET(FD_SET_T sockfd, &fds);
157269257Sdes	if(write)
158269257Sdes		ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
159269257Sdes	else
160269257Sdes		ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
161269257Sdes#endif
162269257Sdes	if(ret == 0)
163269257Sdes		/* timeout expired */
164269257Sdes		return 0;
165269257Sdes	else if(ret == -1)
166269257Sdes		/* error */
167269257Sdes		return 0;
168269257Sdes	return 1;
169269257Sdes}
170269257Sdes
171269257Sdes
172269257Sdesstatic int
173269257Sdesldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen,
174269257Sdes	       	const struct sockaddr_storage *from, socklen_t fromlen,
175269257Sdes		struct timeval timeout)
176269257Sdes{
177269257Sdes	int sockfd;
178269257Sdes
179269257Sdes#ifndef S_SPLINT_S
180269257Sdes	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM,
181269257Sdes					IPPROTO_TCP)) == -1) {
182269257Sdes		return 0;
183269257Sdes	}
184269257Sdes#endif
185269257Sdes	if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){
186269257Sdes		return 0;
187269257Sdes	}
188269257Sdes
189269257Sdes	/* perform nonblocking connect, to be able to wait with select() */
190269257Sdes	ldns_sock_nonblock(sockfd);
191269257Sdes	if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) {
192269257Sdes#ifndef USE_WINSOCK
193269257Sdes#ifdef EINPROGRESS
194269257Sdes		if(errno != EINPROGRESS) {
195269257Sdes#else
196269257Sdes		if(1) {
197269257Sdes#endif
198269257Sdes			close(sockfd);
199269257Sdes			return 0;
200269257Sdes		}
201269257Sdes#else /* USE_WINSOCK */
202269257Sdes		if(WSAGetLastError() != WSAEINPROGRESS &&
203269257Sdes			WSAGetLastError() != WSAEWOULDBLOCK) {
204269257Sdes			closesocket(sockfd);
205269257Sdes			return 0;
206269257Sdes		}
207269257Sdes#endif
208269257Sdes		/* error was only telling us that it would block */
209269257Sdes	}
210269257Sdes
211269257Sdes	/* wait(write) until connected or error */
212269257Sdes	while(1) {
213269257Sdes		int error = 0;
214269257Sdes		socklen_t len = (socklen_t)sizeof(error);
215269257Sdes
216269257Sdes		if(!ldns_sock_wait(sockfd, timeout, 1)) {
217269257Sdes#ifndef USE_WINSOCK
218269257Sdes			close(sockfd);
219269257Sdes#else
220269257Sdes			closesocket(sockfd);
221269257Sdes#endif
222269257Sdes			return 0;
223269257Sdes		}
224269257Sdes
225269257Sdes		/* check if there is a pending error for nonblocking connect */
226269257Sdes		if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error,
227269257Sdes			&len) < 0) {
228269257Sdes#ifndef USE_WINSOCK
229269257Sdes			error = errno; /* on solaris errno is error */
230269257Sdes#else
231269257Sdes			error = WSAGetLastError();
232269257Sdes#endif
233269257Sdes		}
234269257Sdes#ifndef USE_WINSOCK
235269257Sdes#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
236269257Sdes		if(error == EINPROGRESS || error == EWOULDBLOCK)
237269257Sdes			continue; /* try again */
238269257Sdes#endif
239269257Sdes		else if(error != 0) {
240269257Sdes			close(sockfd);
241269257Sdes			/* error in errno for our user */
242269257Sdes			errno = error;
243269257Sdes			return 0;
244269257Sdes		}
245269257Sdes#else /* USE_WINSOCK */
246269257Sdes		if(error == WSAEINPROGRESS)
247269257Sdes			continue;
248269257Sdes		else if(error == WSAEWOULDBLOCK)
249269257Sdes			continue;
250269257Sdes		else if(error != 0) {
251269257Sdes			closesocket(sockfd);
252269257Sdes			errno = error;
253269257Sdes			return 0;
254269257Sdes		}
255269257Sdes#endif /* USE_WINSOCK */
256269257Sdes		/* connected */
257269257Sdes		break;
258269257Sdes	}
259269257Sdes
260269257Sdes	/* set the socket blocking again */
261269257Sdes	ldns_sock_block(sockfd);
262269257Sdes
263269257Sdes	return sockfd;
264269257Sdes}
265269257Sdes
266269257Sdesint
267269257Sdesldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen,
268269257Sdes		struct timeval timeout)
269269257Sdes{
270269257Sdes	return ldns_tcp_connect_from(to, tolen, NULL, 0, timeout);
271269257Sdes}
272269257Sdes
273269257Sdesstatic int
274269257Sdesldns_tcp_bgsend_from(ldns_buffer *qbin,
275269257Sdes		const struct sockaddr_storage *to, socklen_t tolen,
276269257Sdes	       	const struct sockaddr_storage *from, socklen_t fromlen,
277269257Sdes		struct timeval timeout)
278269257Sdes{
279269257Sdes	int sockfd;
280269257Sdes
281269257Sdes	sockfd = ldns_tcp_connect_from(to, tolen, from, fromlen, timeout);
282269257Sdes
283269257Sdes	if (sockfd == 0) {
284269257Sdes		return 0;
285269257Sdes	}
286269257Sdes
287269257Sdes	if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
288269257Sdes#ifndef USE_WINSOCK
289269257Sdes		close(sockfd);
290269257Sdes#else
291269257Sdes		closesocket(sockfd);
292269257Sdes#endif
293269257Sdes		return 0;
294269257Sdes	}
295269257Sdes
296269257Sdes	return sockfd;
297269257Sdes}
298269257Sdes
299269257Sdesint
300269257Sdesldns_tcp_bgsend(ldns_buffer *qbin,
301269257Sdes		const struct sockaddr_storage *to, socklen_t tolen,
302269257Sdes		struct timeval timeout)
303269257Sdes{
304269257Sdes	return ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
305269257Sdes}
306269257Sdes
307269257Sdes
308269257Sdes/* keep in mind that in DNS tcp messages the first 2 bytes signal the
309269257Sdes * amount data to expect
310269257Sdes */
311269257Sdesstatic ldns_status
312269257Sdesldns_tcp_send_from(uint8_t **result,  ldns_buffer *qbin,
313269257Sdes	       	const struct sockaddr_storage *to, socklen_t tolen,
314269257Sdes	       	const struct sockaddr_storage *from, socklen_t fromlen,
315269257Sdes		struct timeval timeout, size_t *answer_size)
316269257Sdes{
317269257Sdes	int sockfd;
318269257Sdes	uint8_t *answer;
319269257Sdes
320269257Sdes	sockfd = ldns_tcp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
321269257Sdes
322269257Sdes	if (sockfd == 0) {
323269257Sdes		return LDNS_STATUS_ERR;
324269257Sdes	}
325269257Sdes
326269257Sdes	answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
327269257Sdes#ifndef USE_WINSOCK
328269257Sdes	close(sockfd);
329269257Sdes#else
330269257Sdes	closesocket(sockfd);
331269257Sdes#endif
332269257Sdes
333269257Sdes	if (*answer_size == 0) {
334269257Sdes		/* oops */
335269257Sdes		return LDNS_STATUS_NETWORK_ERR;
336269257Sdes	}
337269257Sdes
338269257Sdes	/* resize accordingly */
339269257Sdes	*result = LDNS_XREALLOC(answer, uint8_t, (size_t)*answer_size);
340269257Sdes        if(!*result) {
341269257Sdes                LDNS_FREE(answer);
342269257Sdes                return LDNS_STATUS_MEM_ERR;
343269257Sdes        }
344269257Sdes	return LDNS_STATUS_OK;
345269257Sdes}
346269257Sdes
347238104Sdesldns_status
348269257Sdesldns_tcp_send(uint8_t **result,  ldns_buffer *qbin,
349269257Sdes		const struct sockaddr_storage *to, socklen_t tolen,
350269257Sdes		struct timeval timeout, size_t *answer_size)
351269257Sdes{
352269257Sdes	return ldns_tcp_send_from(result, qbin,
353269257Sdes			to, tolen, NULL, 0, timeout, answer_size);
354269257Sdes}
355269257Sdes
356269257Sdesint
357269257Sdesldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
358269257Sdes{
359269257Sdes	int sockfd;
360269257Sdes
361269257Sdes#ifndef S_SPLINT_S
362269257Sdes	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
363269257Sdes					IPPROTO_UDP))
364269257Sdes			== -1) {
365269257Sdes                return 0;
366269257Sdes        }
367269257Sdes#endif
368269257Sdes	return sockfd;
369269257Sdes}
370269257Sdes
371269257Sdesstatic int
372269257Sdesldns_udp_bgsend_from(ldns_buffer *qbin,
373269257Sdes		const struct sockaddr_storage *to  , socklen_t tolen,
374269257Sdes		const struct sockaddr_storage *from, socklen_t fromlen,
375269257Sdes		struct timeval timeout)
376269257Sdes{
377269257Sdes	int sockfd;
378269257Sdes
379269257Sdes	sockfd = ldns_udp_connect(to, timeout);
380269257Sdes
381269257Sdes	if (sockfd == 0) {
382269257Sdes		return 0;
383269257Sdes	}
384269257Sdes
385269257Sdes	if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){
386269257Sdes		return 0;
387269257Sdes	}
388269257Sdes
389269257Sdes	if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
390269257Sdes#ifndef USE_WINSOCK
391269257Sdes		close(sockfd);
392269257Sdes#else
393269257Sdes		closesocket(sockfd);
394269257Sdes#endif
395269257Sdes		return 0;
396269257Sdes	}
397269257Sdes	return sockfd;
398269257Sdes}
399269257Sdes
400269257Sdesint
401269257Sdesldns_udp_bgsend(ldns_buffer *qbin,
402269257Sdes		const struct sockaddr_storage *to  , socklen_t tolen,
403269257Sdes		struct timeval timeout)
404269257Sdes{
405269257Sdes	return ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
406269257Sdes}
407269257Sdes
408269257Sdesstatic ldns_status
409269257Sdesldns_udp_send_from(uint8_t **result, ldns_buffer *qbin,
410269257Sdes		const struct sockaddr_storage *to  , socklen_t tolen,
411269257Sdes		const struct sockaddr_storage *from, socklen_t fromlen,
412269257Sdes		struct timeval timeout, size_t *answer_size)
413269257Sdes{
414269257Sdes	int sockfd;
415269257Sdes	uint8_t *answer;
416269257Sdes
417269257Sdes	sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
418269257Sdes
419269257Sdes	if (sockfd == 0) {
420269257Sdes		return LDNS_STATUS_SOCKET_ERROR;
421269257Sdes	}
422269257Sdes
423269257Sdes	/* wait for an response*/
424269257Sdes	if(!ldns_sock_wait(sockfd, timeout, 0)) {
425269257Sdes#ifndef USE_WINSOCK
426269257Sdes		close(sockfd);
427269257Sdes#else
428269257Sdes                closesocket(sockfd);
429269257Sdes#endif
430269257Sdes		return LDNS_STATUS_NETWORK_ERR;
431269257Sdes	}
432269257Sdes
433269257Sdes        /* set to nonblocking, so if the checksum is bad, it becomes
434269257Sdes         * an EGAIN error and the ldns_udp_send function does not block,
435269257Sdes         * but returns a 'NETWORK_ERROR' much like a timeout. */
436269257Sdes        ldns_sock_nonblock(sockfd);
437269257Sdes
438269257Sdes	answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
439269257Sdes#ifndef USE_WINSOCK
440269257Sdes	close(sockfd);
441269257Sdes#else
442269257Sdes        closesocket(sockfd);
443269257Sdes#endif
444269257Sdes
445269257Sdes	if (*answer_size == 0) {
446269257Sdes		/* oops */
447269257Sdes		return LDNS_STATUS_NETWORK_ERR;
448269257Sdes	}
449269257Sdes
450269257Sdes	*result = answer;
451269257Sdes	return LDNS_STATUS_OK;
452269257Sdes}
453269257Sdes
454269257Sdesldns_status
455269257Sdesldns_udp_send(uint8_t **result, ldns_buffer *qbin,
456269257Sdes		const struct sockaddr_storage *to  , socklen_t tolen,
457269257Sdes		struct timeval timeout, size_t *answer_size)
458269257Sdes{
459269257Sdes	return ldns_udp_send_from(result, qbin, to, tolen, NULL, 0,
460269257Sdes			timeout, answer_size);
461269257Sdes}
462269257Sdes
463269257Sdesldns_status
464238104Sdesldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac)
465238104Sdes{
466238104Sdes	uint8_t i;
467269257Sdes
468269257Sdes	struct sockaddr_storage *src = NULL;
469269257Sdes	size_t src_len;
470238104Sdes	struct sockaddr_storage *ns;
471238104Sdes	size_t ns_len;
472238104Sdes	struct timeval tv_s;
473238104Sdes	struct timeval tv_e;
474238104Sdes
475238104Sdes	ldns_rdf **ns_array;
476238104Sdes	size_t *rtt;
477238104Sdes	ldns_pkt *reply;
478238104Sdes	bool all_servers_rtt_inf;
479238104Sdes	uint8_t retries;
480238104Sdes
481238104Sdes	uint8_t *reply_bytes = NULL;
482238104Sdes	size_t reply_size = 0;
483238104Sdes	ldns_status status, send_status;
484238104Sdes
485238104Sdes	assert(r != NULL);
486238104Sdes
487238104Sdes	status = LDNS_STATUS_OK;
488238104Sdes	rtt = ldns_resolver_rtt(r);
489238104Sdes	ns_array = ldns_resolver_nameservers(r);
490238104Sdes	reply = NULL;
491238104Sdes	ns_len = 0;
492238104Sdes
493238104Sdes	all_servers_rtt_inf = true;
494238104Sdes
495238104Sdes	if (ldns_resolver_random(r)) {
496238104Sdes		ldns_resolver_nameservers_randomize(r);
497238104Sdes	}
498238104Sdes
499269257Sdes	if(ldns_resolver_source(r)) {
500269257Sdes		src = ldns_rdf2native_sockaddr_storage_port(
501269257Sdes				ldns_resolver_source(r), 0, &src_len);
502269257Sdes	}
503269257Sdes
504238104Sdes	/* loop through all defined nameservers */
505238104Sdes	for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
506238104Sdes		if (rtt[i] == LDNS_RESOLV_RTT_INF) {
507238104Sdes			/* not reachable nameserver! */
508238104Sdes			continue;
509238104Sdes		}
510238104Sdes
511238104Sdes		/* maybe verbosity setting?
512238104Sdes		printf("Sending to ");
513238104Sdes		ldns_rdf_print(stdout, ns_array[i]);
514238104Sdes		printf("\n");
515238104Sdes		*/
516238104Sdes		ns = ldns_rdf2native_sockaddr_storage(ns_array[i],
517238104Sdes				ldns_resolver_port(r), &ns_len);
518238104Sdes
519238104Sdes
520238104Sdes#ifndef S_SPLINT_S
521238104Sdes		if ((ns->ss_family == AF_INET) &&
522238104Sdes				(ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) {
523238104Sdes			/* not reachable */
524246854Sdes			LDNS_FREE(ns);
525238104Sdes			continue;
526238104Sdes		}
527238104Sdes
528238104Sdes		if ((ns->ss_family == AF_INET6) &&
529238104Sdes				 (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) {
530238104Sdes			/* not reachable */
531246854Sdes			LDNS_FREE(ns);
532238104Sdes			continue;
533238104Sdes		}
534238104Sdes#endif
535238104Sdes
536238104Sdes		all_servers_rtt_inf = false;
537238104Sdes
538238104Sdes		gettimeofday(&tv_s, NULL);
539238104Sdes
540238104Sdes		send_status = LDNS_STATUS_ERR;
541238104Sdes
542238104Sdes		/* reply_bytes implicitly handles our error */
543269257Sdes		if (ldns_resolver_usevc(r)) {
544238104Sdes			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
545238104Sdes				send_status =
546269257Sdes					ldns_tcp_send_from(&reply_bytes, qb,
547269257Sdes						ns, (socklen_t)ns_len,
548269257Sdes						src, (socklen_t)src_len,
549269257Sdes						ldns_resolver_timeout(r),
550269257Sdes						&reply_size);
551238104Sdes				if (send_status == LDNS_STATUS_OK) {
552238104Sdes					break;
553238104Sdes				}
554238104Sdes			}
555238104Sdes		} else {
556238104Sdes			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
557238104Sdes				/* ldns_rdf_print(stdout, ns_array[i]); */
558238104Sdes				send_status =
559269257Sdes					ldns_udp_send_from(&reply_bytes, qb,
560269257Sdes						ns,  (socklen_t)ns_len,
561269257Sdes						src, (socklen_t)src_len,
562269257Sdes						ldns_resolver_timeout(r),
563269257Sdes						&reply_size);
564238104Sdes				if (send_status == LDNS_STATUS_OK) {
565238104Sdes					break;
566238104Sdes				}
567238104Sdes			}
568238104Sdes		}
569238104Sdes
570238104Sdes		if (send_status != LDNS_STATUS_OK) {
571238104Sdes			ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF);
572238104Sdes			status = send_status;
573238104Sdes		}
574238104Sdes
575238104Sdes		/* obey the fail directive */
576238104Sdes		if (!reply_bytes) {
577238104Sdes			/* the current nameserver seems to have a problem, blacklist it */
578238104Sdes			if (ldns_resolver_fail(r)) {
579238104Sdes				LDNS_FREE(ns);
580238104Sdes				return LDNS_STATUS_ERR;
581238104Sdes			} else {
582238104Sdes				LDNS_FREE(ns);
583238104Sdes				continue;
584238104Sdes			}
585238104Sdes		}
586238104Sdes
587238104Sdes		status = ldns_wire2pkt(&reply, reply_bytes, reply_size);
588238104Sdes		if (status != LDNS_STATUS_OK) {
589238104Sdes			LDNS_FREE(reply_bytes);
590238104Sdes			LDNS_FREE(ns);
591238104Sdes			return status;
592238104Sdes		}
593238104Sdes
594238104Sdes		LDNS_FREE(ns);
595238104Sdes		gettimeofday(&tv_e, NULL);
596238104Sdes
597238104Sdes		if (reply) {
598238104Sdes			ldns_pkt_set_querytime(reply, (uint32_t)
599238104Sdes				((tv_e.tv_sec - tv_s.tv_sec) * 1000) +
600238104Sdes				(tv_e.tv_usec - tv_s.tv_usec) / 1000);
601246854Sdes			ldns_pkt_set_answerfrom(reply,
602246854Sdes					ldns_rdf_clone(ns_array[i]));
603238104Sdes			ldns_pkt_set_timestamp(reply, tv_s);
604238104Sdes			ldns_pkt_set_size(reply, reply_size);
605238104Sdes			break;
606238104Sdes		} else {
607238104Sdes			if (ldns_resolver_fail(r)) {
608238104Sdes				/* if fail is set bail out, after the first
609238104Sdes				 * one */
610238104Sdes				break;
611238104Sdes			}
612238104Sdes		}
613238104Sdes
614238104Sdes		/* wait retrans seconds... */
615238104Sdes		sleep((unsigned int) ldns_resolver_retrans(r));
616238104Sdes	}
617238104Sdes
618269257Sdes	if(src) {
619269257Sdes		LDNS_FREE(src);
620269257Sdes	}
621238104Sdes	if (all_servers_rtt_inf) {
622238104Sdes		LDNS_FREE(reply_bytes);
623238104Sdes		return LDNS_STATUS_RES_NO_NS;
624238104Sdes	}
625238104Sdes#ifdef HAVE_SSL
626246854Sdes	if (tsig_mac && reply && reply_bytes) {
627238104Sdes		if (!ldns_pkt_tsig_verify(reply,
628238104Sdes		                          reply_bytes,
629238104Sdes					  reply_size,
630238104Sdes		                          ldns_resolver_tsig_keyname(r),
631238104Sdes		                          ldns_resolver_tsig_keydata(r), tsig_mac)) {
632238104Sdes			status = LDNS_STATUS_CRYPTO_TSIG_BOGUS;
633238104Sdes		}
634238104Sdes	}
635238104Sdes#else
636238104Sdes	(void)tsig_mac;
637238104Sdes#endif /* HAVE_SSL */
638238104Sdes
639238104Sdes	LDNS_FREE(reply_bytes);
640238104Sdes	if (result) {
641238104Sdes		*result = reply;
642238104Sdes	}
643238104Sdes
644238104Sdes	return status;
645238104Sdes}
646238104Sdes
647238104Sdesssize_t
648238104Sdesldns_tcp_send_query(ldns_buffer *qbin, int sockfd,
649238104Sdes                    const struct sockaddr_storage *to, socklen_t tolen)
650238104Sdes{
651238104Sdes	uint8_t *sendbuf;
652238104Sdes	ssize_t bytes;
653238104Sdes
654238104Sdes	/* add length of packet */
655238104Sdes	sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2);
656238104Sdes	if(!sendbuf) return 0;
657238104Sdes	ldns_write_uint16(sendbuf, ldns_buffer_position(qbin));
658246854Sdes	memcpy(sendbuf + 2, ldns_buffer_begin(qbin), ldns_buffer_position(qbin));
659238104Sdes
660238104Sdes	bytes = sendto(sockfd, (void*)sendbuf,
661238104Sdes			ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen);
662238104Sdes
663238104Sdes        LDNS_FREE(sendbuf);
664238104Sdes
665238104Sdes	if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) {
666238104Sdes		return 0;
667238104Sdes	}
668238104Sdes	return bytes;
669238104Sdes}
670238104Sdes
671238104Sdes/* don't wait for an answer */
672238104Sdesssize_t
673238104Sdesldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to,
674238104Sdes		socklen_t tolen)
675238104Sdes{
676238104Sdes	ssize_t bytes;
677238104Sdes
678238104Sdes	bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin),
679238104Sdes			ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen);
680238104Sdes
681238104Sdes	if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) {
682238104Sdes		return 0;
683238104Sdes	}
684238104Sdes	if ((size_t) bytes != ldns_buffer_position(qbin)) {
685238104Sdes		return 0;
686238104Sdes	}
687238104Sdes	return bytes;
688238104Sdes}
689238104Sdes
690238104Sdesuint8_t *
691238104Sdesldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from,
692238104Sdes		socklen_t *fromlen)
693238104Sdes{
694238104Sdes	uint8_t *wire, *wireout;
695238104Sdes	ssize_t wire_size;
696238104Sdes
697238104Sdes	wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
698238104Sdes	if (!wire) {
699238104Sdes		*size = 0;
700238104Sdes		return NULL;
701238104Sdes	}
702238104Sdes
703238104Sdes	wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0,
704238104Sdes			(struct sockaddr *)from, fromlen);
705238104Sdes
706238104Sdes	/* recvfrom can also return 0 */
707238104Sdes	if (wire_size == -1 || wire_size == 0) {
708238104Sdes		*size = 0;
709238104Sdes		LDNS_FREE(wire);
710238104Sdes		return NULL;
711238104Sdes	}
712238104Sdes
713238104Sdes	*size = (size_t)wire_size;
714238104Sdes	wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size);
715238104Sdes	if(!wireout) LDNS_FREE(wire);
716238104Sdes
717238104Sdes	return wireout;
718238104Sdes}
719238104Sdes
720238104Sdesuint8_t *
721238104Sdesldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout)
722238104Sdes{
723238104Sdes	uint8_t *wire;
724238104Sdes	uint16_t wire_size;
725238104Sdes	ssize_t bytes = 0, rc = 0;
726238104Sdes
727238104Sdes	wire = LDNS_XMALLOC(uint8_t, 2);
728238104Sdes	if (!wire) {
729238104Sdes		*size = 0;
730238104Sdes		return NULL;
731238104Sdes	}
732238104Sdes
733238104Sdes	while (bytes < 2) {
734238104Sdes		if(!ldns_sock_wait(sockfd, timeout, 0)) {
735238104Sdes			*size = 0;
736238104Sdes			LDNS_FREE(wire);
737238104Sdes			return NULL;
738238104Sdes		}
739238104Sdes		rc = recv(sockfd, (void*) (wire + bytes),
740238104Sdes				(size_t) (2 - bytes), 0);
741238104Sdes		if (rc == -1 || rc == 0) {
742238104Sdes			*size = 0;
743238104Sdes			LDNS_FREE(wire);
744238104Sdes			return NULL;
745238104Sdes		}
746238104Sdes                bytes += rc;
747238104Sdes	}
748238104Sdes
749238104Sdes	wire_size = ldns_read_uint16(wire);
750238104Sdes
751238104Sdes	LDNS_FREE(wire);
752238104Sdes	wire = LDNS_XMALLOC(uint8_t, wire_size);
753238104Sdes	if (!wire) {
754238104Sdes		*size = 0;
755238104Sdes		return NULL;
756238104Sdes	}
757238104Sdes	bytes = 0;
758238104Sdes
759238104Sdes	while (bytes < (ssize_t) wire_size) {
760238104Sdes		if(!ldns_sock_wait(sockfd, timeout, 0)) {
761238104Sdes			*size = 0;
762238104Sdes			LDNS_FREE(wire);
763238104Sdes			return NULL;
764238104Sdes		}
765238104Sdes		rc = recv(sockfd, (void*) (wire + bytes),
766238104Sdes				(size_t) (wire_size - bytes), 0);
767238104Sdes		if (rc == -1 || rc == 0) {
768238104Sdes			LDNS_FREE(wire);
769238104Sdes			*size = 0;
770238104Sdes			return NULL;
771238104Sdes		}
772238104Sdes                bytes += rc;
773238104Sdes	}
774238104Sdes
775238104Sdes	*size = (size_t) bytes;
776238104Sdes	return wire;
777238104Sdes}
778238104Sdes
779238104Sdesuint8_t *
780238104Sdesldns_tcp_read_wire(int sockfd, size_t *size)
781238104Sdes{
782238104Sdes	uint8_t *wire;
783238104Sdes	uint16_t wire_size;
784238104Sdes	ssize_t bytes = 0, rc = 0;
785238104Sdes
786238104Sdes	wire = LDNS_XMALLOC(uint8_t, 2);
787238104Sdes	if (!wire) {
788238104Sdes		*size = 0;
789238104Sdes		return NULL;
790238104Sdes	}
791238104Sdes
792238104Sdes	while (bytes < 2) {
793238104Sdes		rc = recv(sockfd, (void*) (wire + bytes),
794238104Sdes				(size_t) (2 - bytes), 0);
795238104Sdes		if (rc == -1 || rc == 0) {
796238104Sdes			*size = 0;
797238104Sdes			LDNS_FREE(wire);
798238104Sdes			return NULL;
799238104Sdes		}
800238104Sdes                bytes += rc;
801238104Sdes	}
802238104Sdes
803238104Sdes	wire_size = ldns_read_uint16(wire);
804238104Sdes
805238104Sdes	LDNS_FREE(wire);
806238104Sdes	wire = LDNS_XMALLOC(uint8_t, wire_size);
807238104Sdes	if (!wire) {
808238104Sdes		*size = 0;
809238104Sdes		return NULL;
810238104Sdes	}
811238104Sdes	bytes = 0;
812238104Sdes
813238104Sdes	while (bytes < (ssize_t) wire_size) {
814238104Sdes		rc = recv(sockfd, (void*) (wire + bytes),
815238104Sdes				(size_t) (wire_size - bytes), 0);
816238104Sdes		if (rc == -1 || rc == 0) {
817238104Sdes			LDNS_FREE(wire);
818238104Sdes			*size = 0;
819238104Sdes			return NULL;
820238104Sdes		}
821238104Sdes                bytes += rc;
822238104Sdes	}
823238104Sdes
824238104Sdes	*size = (size_t) bytes;
825238104Sdes	return wire;
826238104Sdes}
827238104Sdes
828238104Sdes#ifndef S_SPLINT_S
829238104Sdesldns_rdf *
830238104Sdesldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port)
831238104Sdes{
832238104Sdes        ldns_rdf *addr;
833238104Sdes        struct sockaddr_in *data_in;
834238104Sdes        struct sockaddr_in6 *data_in6;
835238104Sdes
836238104Sdes        switch(sock->ss_family) {
837238104Sdes                case AF_INET:
838238104Sdes                        data_in = (struct sockaddr_in*)sock;
839238104Sdes                        if (port) {
840238104Sdes                                *port = ntohs((uint16_t)data_in->sin_port);
841238104Sdes                        }
842238104Sdes                        addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A,
843238104Sdes                                        LDNS_IP4ADDRLEN, &data_in->sin_addr);
844238104Sdes                        break;
845238104Sdes                case AF_INET6:
846238104Sdes                        data_in6 = (struct sockaddr_in6*)sock;
847238104Sdes                        if (port) {
848238104Sdes                                *port = ntohs((uint16_t)data_in6->sin6_port);
849238104Sdes                        }
850238104Sdes                        addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA,
851238104Sdes                                        LDNS_IP6ADDRLEN, &data_in6->sin6_addr);
852238104Sdes                        break;
853238104Sdes                default:
854238104Sdes                        if (port) {
855238104Sdes                                *port = 0;
856238104Sdes                        }
857238104Sdes                        return NULL;
858238104Sdes        }
859238104Sdes        return addr;
860238104Sdes}
861238104Sdes#endif
862238104Sdes
863238104Sdes/* code from resolver.c */
864238104Sdesldns_status
865238104Sdesldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class)
866238104Sdes{
867238104Sdes        ldns_pkt *query;
868238104Sdes        ldns_buffer *query_wire;
869238104Sdes
870269257Sdes        struct sockaddr_storage *src = NULL;
871269257Sdes        size_t src_len = 0;
872238104Sdes        struct sockaddr_storage *ns = NULL;
873238104Sdes        size_t ns_len = 0;
874238104Sdes        size_t ns_i;
875238104Sdes        ldns_status status;
876238104Sdes
877238104Sdes        if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) {
878238104Sdes                return LDNS_STATUS_ERR;
879238104Sdes        }
880238104Sdes
881238104Sdes        query = ldns_pkt_query_new(ldns_rdf_clone(domain), LDNS_RR_TYPE_AXFR, class, 0);
882238104Sdes
883238104Sdes        if (!query) {
884238104Sdes                return LDNS_STATUS_ADDRESS_ERR;
885238104Sdes        }
886269257Sdes	if(ldns_resolver_source(resolver)) {
887269257Sdes		src = ldns_rdf2native_sockaddr_storage_port(
888269257Sdes				ldns_resolver_source(resolver), 0, &src_len);
889269257Sdes	}
890238104Sdes        /* For AXFR, we have to make the connection ourselves */
891238104Sdes        /* try all nameservers (which usually would mean v4 fallback if
892238104Sdes         * @hostname is used */
893238104Sdes        for (ns_i = 0;
894238104Sdes             ns_i < ldns_resolver_nameserver_count(resolver) &&
895238104Sdes             resolver->_socket == 0;
896238104Sdes             ns_i++) {
897246854Sdes		if (ns != NULL) {
898246854Sdes			LDNS_FREE(ns);
899246854Sdes		}
900238104Sdes	        ns = ldns_rdf2native_sockaddr_storage(
901238104Sdes	        	resolver->_nameservers[ns_i],
902238104Sdes			ldns_resolver_port(resolver), &ns_len);
903238104Sdes
904269257Sdes		resolver->_socket = ldns_tcp_connect_from(
905269257Sdes				ns, (socklen_t)ns_len,
906269257Sdes				src, (socklen_t)src_len,
907238104Sdes				ldns_resolver_timeout(resolver));
908238104Sdes	}
909238104Sdes
910238104Sdes	if (resolver->_socket == 0) {
911238104Sdes		ldns_pkt_free(query);
912238104Sdes		LDNS_FREE(ns);
913238104Sdes		return LDNS_STATUS_NETWORK_ERR;
914238104Sdes	}
915238104Sdes
916238104Sdes#ifdef HAVE_SSL
917238104Sdes	if (ldns_resolver_tsig_keyname(resolver) && ldns_resolver_tsig_keydata(resolver)) {
918238104Sdes		status = ldns_pkt_tsig_sign(query,
919238104Sdes		                            ldns_resolver_tsig_keyname(resolver),
920238104Sdes		                            ldns_resolver_tsig_keydata(resolver),
921238104Sdes		                            300, ldns_resolver_tsig_algorithm(resolver), NULL);
922238104Sdes		if (status != LDNS_STATUS_OK) {
923269257Sdes			/* to prevent problems on subsequent calls to
924269257Sdes			 * ldns_axfr_start we have to close the socket here! */
925238104Sdes#ifndef USE_WINSOCK
926238104Sdes			close(resolver->_socket);
927238104Sdes#else
928238104Sdes			closesocket(resolver->_socket);
929238104Sdes#endif
930238104Sdes			resolver->_socket = 0;
931238104Sdes
932246854Sdes			ldns_pkt_free(query);
933246854Sdes			LDNS_FREE(ns);
934246854Sdes
935238104Sdes			return LDNS_STATUS_CRYPTO_TSIG_ERR;
936238104Sdes		}
937238104Sdes	}
938238104Sdes#endif /* HAVE_SSL */
939238104Sdes
940238104Sdes        /* Convert the query to a buffer
941238104Sdes         * Is this necessary?
942238104Sdes         */
943238104Sdes        query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN);
944238104Sdes        if(!query_wire) {
945238104Sdes                ldns_pkt_free(query);
946238104Sdes                LDNS_FREE(ns);
947238104Sdes#ifndef USE_WINSOCK
948238104Sdes		close(resolver->_socket);
949238104Sdes#else
950238104Sdes		closesocket(resolver->_socket);
951238104Sdes#endif
952238104Sdes		resolver->_socket = 0;
953238104Sdes
954238104Sdes                return LDNS_STATUS_MEM_ERR;
955238104Sdes        }
956238104Sdes        status = ldns_pkt2buffer_wire(query_wire, query);
957238104Sdes        if (status != LDNS_STATUS_OK) {
958238104Sdes                ldns_pkt_free(query);
959238104Sdes		ldns_buffer_free(query_wire);
960238104Sdes                LDNS_FREE(ns);
961238104Sdes
962269257Sdes		/* to prevent problems on subsequent calls to ldns_axfr_start
963269257Sdes		 * we have to close the socket here! */
964238104Sdes#ifndef USE_WINSOCK
965238104Sdes		close(resolver->_socket);
966238104Sdes#else
967238104Sdes		closesocket(resolver->_socket);
968238104Sdes#endif
969238104Sdes		resolver->_socket = 0;
970238104Sdes
971238104Sdes                return status;
972238104Sdes        }
973238104Sdes        /* Send the query */
974238104Sdes        if (ldns_tcp_send_query(query_wire, resolver->_socket, ns,
975238104Sdes				(socklen_t)ns_len) == 0) {
976238104Sdes                ldns_pkt_free(query);
977238104Sdes                ldns_buffer_free(query_wire);
978238104Sdes                LDNS_FREE(ns);
979238104Sdes
980269257Sdes		/* to prevent problems on subsequent calls to ldns_axfr_start
981269257Sdes		 * we have to close the socket here! */
982238104Sdes
983238104Sdes#ifndef USE_WINSOCK
984238104Sdes		close(resolver->_socket);
985238104Sdes#else
986238104Sdes		closesocket(resolver->_socket);
987238104Sdes#endif
988238104Sdes		resolver->_socket = 0;
989238104Sdes
990238104Sdes                return LDNS_STATUS_NETWORK_ERR;
991238104Sdes        }
992238104Sdes
993238104Sdes        ldns_pkt_free(query);
994238104Sdes        ldns_buffer_free(query_wire);
995238104Sdes        LDNS_FREE(ns);
996238104Sdes
997238104Sdes        /*
998238104Sdes         * The AXFR is done once the second SOA record is sent
999238104Sdes         */
1000238104Sdes        resolver->_axfr_soa_count = 0;
1001238104Sdes        return LDNS_STATUS_OK;
1002238104Sdes}
1003