net.c revision 238104
1/*
2 * net.c
3 *
4 * Network implementation
5 * All network related functions are grouped here
6 *
7 * a Net::DNS like library for C
8 *
9 * (c) NLnet Labs, 2004-2006
10 *
11 * See the file LICENSE for the license
12 */
13
14#include <ldns/config.h>
15
16#include <ldns/ldns.h>
17
18#ifdef HAVE_NETINET_IN_H
19#include <netinet/in.h>
20#endif
21#ifdef HAVE_SYS_SOCKET_H
22#include <sys/socket.h>
23#endif
24#ifdef HAVE_NETDB_H
25#include <netdb.h>
26#endif
27#ifdef HAVE_ARPA_INET_H
28#include <arpa/inet.h>
29#endif
30#include <sys/time.h>
31#include <errno.h>
32#include <fcntl.h>
33
34ldns_status
35ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt)
36{
37	ldns_buffer *qb;
38	ldns_status result;
39	ldns_rdf *tsig_mac = NULL;
40
41	qb = ldns_buffer_new(LDNS_MIN_BUFLEN);
42
43	if (query_pkt && ldns_pkt_tsig(query_pkt)) {
44		tsig_mac = ldns_rr_rdf(ldns_pkt_tsig(query_pkt), 3);
45	}
46
47	if (!query_pkt ||
48	    ldns_pkt2buffer_wire(qb, query_pkt) != LDNS_STATUS_OK) {
49		result = LDNS_STATUS_ERR;
50	} else {
51        	result = ldns_send_buffer(result_packet, r, qb, tsig_mac);
52	}
53
54	ldns_buffer_free(qb);
55
56	return result;
57}
58
59ldns_status
60ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac)
61{
62	uint8_t i;
63
64	struct sockaddr_storage *ns;
65	size_t ns_len;
66	struct timeval tv_s;
67	struct timeval tv_e;
68
69	ldns_rdf **ns_array;
70	size_t *rtt;
71	ldns_pkt *reply;
72	bool all_servers_rtt_inf;
73	uint8_t retries;
74
75	uint8_t *reply_bytes = NULL;
76	size_t reply_size = 0;
77	ldns_status status, send_status;
78
79	assert(r != NULL);
80
81	status = LDNS_STATUS_OK;
82	rtt = ldns_resolver_rtt(r);
83	ns_array = ldns_resolver_nameservers(r);
84	reply = NULL;
85	ns_len = 0;
86
87	all_servers_rtt_inf = true;
88
89	if (ldns_resolver_random(r)) {
90		ldns_resolver_nameservers_randomize(r);
91	}
92
93	/* loop through all defined nameservers */
94	for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
95		if (rtt[i] == LDNS_RESOLV_RTT_INF) {
96			/* not reachable nameserver! */
97			continue;
98		}
99
100		/* maybe verbosity setting?
101		printf("Sending to ");
102		ldns_rdf_print(stdout, ns_array[i]);
103		printf("\n");
104		*/
105		ns = ldns_rdf2native_sockaddr_storage(ns_array[i],
106				ldns_resolver_port(r), &ns_len);
107
108
109#ifndef S_SPLINT_S
110		if ((ns->ss_family == AF_INET) &&
111				(ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) {
112			/* not reachable */
113			continue;
114		}
115
116		if ((ns->ss_family == AF_INET6) &&
117				 (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) {
118			/* not reachable */
119			continue;
120		}
121#endif
122
123		all_servers_rtt_inf = false;
124
125		gettimeofday(&tv_s, NULL);
126
127		send_status = LDNS_STATUS_ERR;
128
129		/* reply_bytes implicitly handles our error */
130		if (1 == ldns_resolver_usevc(r)) {
131			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
132				send_status =
133					ldns_tcp_send(&reply_bytes, qb, ns,
134					(socklen_t)ns_len, ldns_resolver_timeout(r),
135					&reply_size);
136				if (send_status == LDNS_STATUS_OK) {
137					break;
138				}
139			}
140		} else {
141			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
142				/* ldns_rdf_print(stdout, ns_array[i]); */
143				send_status =
144					ldns_udp_send(&reply_bytes, qb, ns,
145							(socklen_t)ns_len, ldns_resolver_timeout(r),
146							&reply_size);
147
148				if (send_status == LDNS_STATUS_OK) {
149					break;
150				}
151			}
152		}
153
154		if (send_status != LDNS_STATUS_OK) {
155			ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF);
156			status = send_status;
157		}
158
159		/* obey the fail directive */
160		if (!reply_bytes) {
161			/* the current nameserver seems to have a problem, blacklist it */
162			if (ldns_resolver_fail(r)) {
163				LDNS_FREE(ns);
164				return LDNS_STATUS_ERR;
165			} else {
166				LDNS_FREE(ns);
167				continue;
168			}
169		}
170
171		status = ldns_wire2pkt(&reply, reply_bytes, reply_size);
172		if (status != LDNS_STATUS_OK) {
173			LDNS_FREE(reply_bytes);
174			LDNS_FREE(ns);
175			return status;
176		}
177
178		LDNS_FREE(ns);
179		gettimeofday(&tv_e, NULL);
180
181		if (reply) {
182			ldns_pkt_set_querytime(reply, (uint32_t)
183				((tv_e.tv_sec - tv_s.tv_sec) * 1000) +
184				(tv_e.tv_usec - tv_s.tv_usec) / 1000);
185			ldns_pkt_set_answerfrom(reply, ns_array[i]);
186			ldns_pkt_set_timestamp(reply, tv_s);
187			ldns_pkt_set_size(reply, reply_size);
188			break;
189		} else {
190			if (ldns_resolver_fail(r)) {
191				/* if fail is set bail out, after the first
192				 * one */
193				break;
194			}
195		}
196
197		/* wait retrans seconds... */
198		sleep((unsigned int) ldns_resolver_retrans(r));
199	}
200
201	if (all_servers_rtt_inf) {
202		LDNS_FREE(reply_bytes);
203		return LDNS_STATUS_RES_NO_NS;
204	}
205#ifdef HAVE_SSL
206	if (tsig_mac && reply_bytes) {
207		if (!ldns_pkt_tsig_verify(reply,
208		                          reply_bytes,
209					  reply_size,
210		                          ldns_resolver_tsig_keyname(r),
211		                          ldns_resolver_tsig_keydata(r), tsig_mac)) {
212			status = LDNS_STATUS_CRYPTO_TSIG_BOGUS;
213		}
214	}
215#else
216	(void)tsig_mac;
217#endif /* HAVE_SSL */
218
219	LDNS_FREE(reply_bytes);
220	if (result) {
221		*result = reply;
222	}
223
224	return status;
225}
226
227/** best effort to set nonblocking */
228static void
229ldns_sock_nonblock(int sockfd)
230{
231#ifdef HAVE_FCNTL
232	int flag;
233	if((flag = fcntl(sockfd, F_GETFL)) != -1) {
234		flag |= O_NONBLOCK;
235		if(fcntl(sockfd, F_SETFL, flag) == -1) {
236			/* ignore error, continue blockingly */
237		}
238	}
239#elif defined(HAVE_IOCTLSOCKET)
240	unsigned long on = 1;
241	if(ioctlsocket(sockfd, FIONBIO, &on) != 0) {
242		/* ignore error, continue blockingly */
243	}
244#endif
245}
246
247/** best effort to set blocking */
248static void
249ldns_sock_block(int sockfd)
250{
251#ifdef HAVE_FCNTL
252	int flag;
253	if((flag = fcntl(sockfd, F_GETFL)) != -1) {
254		flag &= ~O_NONBLOCK;
255		if(fcntl(sockfd, F_SETFL, flag) == -1) {
256			/* ignore error, continue */
257		}
258	}
259#elif defined(HAVE_IOCTLSOCKET)
260	unsigned long off = 0;
261	if(ioctlsocket(sockfd, FIONBIO, &off) != 0) {
262		/* ignore error, continue */
263	}
264#endif
265}
266
267/** wait for a socket to become ready */
268static int
269ldns_sock_wait(int sockfd, struct timeval timeout, int write)
270{
271	int ret;
272#ifndef S_SPLINT_S
273	fd_set fds;
274	FD_ZERO(&fds);
275	FD_SET(FD_SET_T sockfd, &fds);
276	if(write)
277		ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
278	else
279		ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
280#endif
281	if(ret == 0)
282		/* timeout expired */
283		return 0;
284	else if(ret == -1)
285		/* error */
286		return 0;
287	return 1;
288}
289
290ldns_status
291ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to,
292		socklen_t tolen, struct timeval timeout, size_t *answer_size)
293{
294	int sockfd;
295	uint8_t *answer;
296
297	sockfd = ldns_udp_bgsend(qbin, to, tolen, timeout);
298
299	if (sockfd == 0) {
300		return LDNS_STATUS_SOCKET_ERROR;
301	}
302
303	/* wait for an response*/
304	if(!ldns_sock_wait(sockfd, timeout, 0)) {
305#ifndef USE_WINSOCK
306		close(sockfd);
307#else
308                closesocket(sockfd);
309#endif
310		return LDNS_STATUS_NETWORK_ERR;
311	}
312
313        /* set to nonblocking, so if the checksum is bad, it becomes
314         * an EGAIN error and the ldns_udp_send function does not block,
315         * but returns a 'NETWORK_ERROR' much like a timeout. */
316        ldns_sock_nonblock(sockfd);
317
318	answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
319#ifndef USE_WINSOCK
320	close(sockfd);
321#else
322        closesocket(sockfd);
323#endif
324
325	if (*answer_size == 0) {
326		/* oops */
327		return LDNS_STATUS_NETWORK_ERR;
328	}
329
330	*result = answer;
331	return LDNS_STATUS_OK;
332}
333
334int
335ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen,
336		struct timeval timeout)
337{
338	int sockfd;
339
340	sockfd = ldns_udp_connect(to, timeout);
341
342	if (sockfd == 0) {
343		return 0;
344	}
345
346	if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
347#ifndef USE_WINSOCK
348		close(sockfd);
349#else
350		closesocket(sockfd);
351#endif
352		return 0;
353	}
354	return sockfd;
355}
356
357int
358ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
359{
360	int sockfd;
361
362#ifndef S_SPLINT_S
363	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
364					IPPROTO_UDP))
365			== -1) {
366                return 0;
367        }
368#endif
369	return sockfd;
370}
371
372int
373ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen,
374		struct timeval timeout)
375{
376	int sockfd;
377
378#ifndef S_SPLINT_S
379	if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM,
380					IPPROTO_TCP)) == -1) {
381		return 0;
382	}
383#endif
384
385	/* perform nonblocking connect, to be able to wait with select() */
386	ldns_sock_nonblock(sockfd);
387	if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) {
388#ifndef USE_WINSOCK
389#ifdef EINPROGRESS
390		if(errno != EINPROGRESS) {
391#else
392		if(1) {
393#endif
394			close(sockfd);
395			return 0;
396		}
397#else /* USE_WINSOCK */
398		if(WSAGetLastError() != WSAEINPROGRESS &&
399			WSAGetLastError() != WSAEWOULDBLOCK) {
400			closesocket(sockfd);
401			return 0;
402		}
403#endif
404		/* error was only telling us that it would block */
405	}
406
407	/* wait(write) until connected or error */
408	while(1) {
409		int error = 0;
410		socklen_t len = (socklen_t)sizeof(error);
411
412		if(!ldns_sock_wait(sockfd, timeout, 1)) {
413#ifndef USE_WINSOCK
414			close(sockfd);
415#else
416			closesocket(sockfd);
417#endif
418			return 0;
419		}
420
421		/* check if there is a pending error for nonblocking connect */
422		if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error,
423			&len) < 0) {
424#ifndef USE_WINSOCK
425			error = errno; /* on solaris errno is error */
426#else
427			error = WSAGetLastError();
428#endif
429		}
430#ifndef USE_WINSOCK
431#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
432		if(error == EINPROGRESS || error == EWOULDBLOCK)
433			continue; /* try again */
434#endif
435		else if(error != 0) {
436			close(sockfd);
437			/* error in errno for our user */
438			errno = error;
439			return 0;
440		}
441#else /* USE_WINSOCK */
442		if(error == WSAEINPROGRESS)
443			continue;
444		else if(error == WSAEWOULDBLOCK)
445			continue;
446		else if(error != 0) {
447			closesocket(sockfd);
448			errno = error;
449			return 0;
450		}
451#endif /* USE_WINSOCK */
452		/* connected */
453		break;
454	}
455
456	/* set the socket blocking again */
457	ldns_sock_block(sockfd);
458
459	return sockfd;
460}
461
462ssize_t
463ldns_tcp_send_query(ldns_buffer *qbin, int sockfd,
464                    const struct sockaddr_storage *to, socklen_t tolen)
465{
466	uint8_t *sendbuf;
467	ssize_t bytes;
468
469	/* add length of packet */
470	sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2);
471	if(!sendbuf) return 0;
472	ldns_write_uint16(sendbuf, ldns_buffer_position(qbin));
473	memcpy(sendbuf + 2, ldns_buffer_export(qbin), ldns_buffer_position(qbin));
474
475	bytes = sendto(sockfd, (void*)sendbuf,
476			ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen);
477
478        LDNS_FREE(sendbuf);
479
480	if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) {
481		return 0;
482	}
483	return bytes;
484}
485
486/* don't wait for an answer */
487ssize_t
488ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to,
489		socklen_t tolen)
490{
491	ssize_t bytes;
492
493	bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin),
494			ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen);
495
496	if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) {
497		return 0;
498	}
499	if ((size_t) bytes != ldns_buffer_position(qbin)) {
500		return 0;
501	}
502	return bytes;
503}
504
505uint8_t *
506ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from,
507		socklen_t *fromlen)
508{
509	uint8_t *wire, *wireout;
510	ssize_t wire_size;
511
512	wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
513	if (!wire) {
514		*size = 0;
515		return NULL;
516	}
517
518	wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0,
519			(struct sockaddr *)from, fromlen);
520
521	/* recvfrom can also return 0 */
522	if (wire_size == -1 || wire_size == 0) {
523		*size = 0;
524		LDNS_FREE(wire);
525		return NULL;
526	}
527
528	*size = (size_t)wire_size;
529	wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size);
530	if(!wireout) LDNS_FREE(wire);
531
532	return wireout;
533}
534
535uint8_t *
536ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout)
537{
538	uint8_t *wire;
539	uint16_t wire_size;
540	ssize_t bytes = 0, rc = 0;
541
542	wire = LDNS_XMALLOC(uint8_t, 2);
543	if (!wire) {
544		*size = 0;
545		return NULL;
546	}
547
548	while (bytes < 2) {
549		if(!ldns_sock_wait(sockfd, timeout, 0)) {
550			*size = 0;
551			LDNS_FREE(wire);
552			return NULL;
553		}
554		rc = recv(sockfd, (void*) (wire + bytes),
555				(size_t) (2 - bytes), 0);
556		if (rc == -1 || rc == 0) {
557			*size = 0;
558			LDNS_FREE(wire);
559			return NULL;
560		}
561                bytes += rc;
562	}
563
564	wire_size = ldns_read_uint16(wire);
565
566	LDNS_FREE(wire);
567	wire = LDNS_XMALLOC(uint8_t, wire_size);
568	if (!wire) {
569		*size = 0;
570		return NULL;
571	}
572	bytes = 0;
573
574	while (bytes < (ssize_t) wire_size) {
575		if(!ldns_sock_wait(sockfd, timeout, 0)) {
576			*size = 0;
577			LDNS_FREE(wire);
578			return NULL;
579		}
580		rc = recv(sockfd, (void*) (wire + bytes),
581				(size_t) (wire_size - bytes), 0);
582		if (rc == -1 || rc == 0) {
583			LDNS_FREE(wire);
584			*size = 0;
585			return NULL;
586		}
587                bytes += rc;
588	}
589
590	*size = (size_t) bytes;
591	return wire;
592}
593
594uint8_t *
595ldns_tcp_read_wire(int sockfd, size_t *size)
596{
597	uint8_t *wire;
598	uint16_t wire_size;
599	ssize_t bytes = 0, rc = 0;
600
601	wire = LDNS_XMALLOC(uint8_t, 2);
602	if (!wire) {
603		*size = 0;
604		return NULL;
605	}
606
607	while (bytes < 2) {
608		rc = recv(sockfd, (void*) (wire + bytes),
609				(size_t) (2 - bytes), 0);
610		if (rc == -1 || rc == 0) {
611			*size = 0;
612			LDNS_FREE(wire);
613			return NULL;
614		}
615                bytes += rc;
616	}
617
618	wire_size = ldns_read_uint16(wire);
619
620	LDNS_FREE(wire);
621	wire = LDNS_XMALLOC(uint8_t, wire_size);
622	if (!wire) {
623		*size = 0;
624		return NULL;
625	}
626	bytes = 0;
627
628	while (bytes < (ssize_t) wire_size) {
629		rc = recv(sockfd, (void*) (wire + bytes),
630				(size_t) (wire_size - bytes), 0);
631		if (rc == -1 || rc == 0) {
632			LDNS_FREE(wire);
633			*size = 0;
634			return NULL;
635		}
636                bytes += rc;
637	}
638
639	*size = (size_t) bytes;
640	return wire;
641}
642
643/* keep in mind that in DNS tcp messages the first 2 bytes signal the
644 * amount data to expect
645 */
646ldns_status
647ldns_tcp_send(uint8_t **result,  ldns_buffer *qbin, const struct sockaddr_storage *to,
648		socklen_t tolen, struct timeval timeout, size_t *answer_size)
649{
650	int sockfd;
651	uint8_t *answer;
652
653	sockfd = ldns_tcp_bgsend(qbin, to, tolen, timeout);
654
655	if (sockfd == 0) {
656		return LDNS_STATUS_ERR;
657	}
658
659	answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
660#ifndef USE_WINSOCK
661	close(sockfd);
662#else
663	closesocket(sockfd);
664#endif
665
666	if (*answer_size == 0) {
667		/* oops */
668		return LDNS_STATUS_NETWORK_ERR;
669	}
670
671	/* resize accordingly */
672	*result = (uint8_t*)LDNS_XREALLOC(answer, uint8_t *, (size_t)*answer_size);
673        if(!*result) {
674                LDNS_FREE(answer);
675                return LDNS_STATUS_MEM_ERR;
676        }
677	return LDNS_STATUS_OK;
678}
679
680int
681ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen,
682		struct timeval timeout)
683{
684	int sockfd;
685
686	sockfd = ldns_tcp_connect(to, tolen, timeout);
687
688	if (sockfd == 0) {
689		return 0;
690	}
691
692	if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
693#ifndef USE_WINSOCK
694		close(sockfd);
695#else
696		closesocket(sockfd);
697#endif
698		return 0;
699	}
700
701	return sockfd;
702}
703
704/* code from rdata.c */
705struct sockaddr_storage *
706ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, uint16_t port, size_t *size)
707{
708        struct sockaddr_storage *data;
709        struct sockaddr_in  *data_in;
710        struct sockaddr_in6 *data_in6;
711
712        data = LDNS_MALLOC(struct sockaddr_storage);
713        if (!data) {
714                return NULL;
715        }
716		/* zero the structure for portability */
717		memset(data, 0, sizeof(struct sockaddr_storage));
718        if (port == 0) {
719                port =  LDNS_PORT;
720        }
721
722        switch(ldns_rdf_get_type(rd)) {
723                case LDNS_RDF_TYPE_A:
724#ifndef S_SPLINT_S
725                        data->ss_family = AF_INET;
726#endif
727                        data_in = (struct sockaddr_in*) data;
728                        data_in->sin_port = (in_port_t)htons(port);
729                        memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd));
730                        *size = sizeof(struct sockaddr_in);
731                        return data;
732                case LDNS_RDF_TYPE_AAAA:
733#ifndef S_SPLINT_S
734                        data->ss_family = AF_INET6;
735#endif
736                        data_in6 = (struct sockaddr_in6*) data;
737                        data_in6->sin6_port = (in_port_t)htons(port);
738                        memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd));
739                        *size = sizeof(struct sockaddr_in6);
740                        return data;
741                default:
742                        LDNS_FREE(data);
743                        return NULL;
744        }
745}
746
747#ifndef S_SPLINT_S
748ldns_rdf *
749ldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port)
750{
751        ldns_rdf *addr;
752        struct sockaddr_in *data_in;
753        struct sockaddr_in6 *data_in6;
754
755        switch(sock->ss_family) {
756                case AF_INET:
757                        data_in = (struct sockaddr_in*)sock;
758                        if (port) {
759                                *port = ntohs((uint16_t)data_in->sin_port);
760                        }
761                        addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A,
762                                        LDNS_IP4ADDRLEN, &data_in->sin_addr);
763                        break;
764                case AF_INET6:
765                        data_in6 = (struct sockaddr_in6*)sock;
766                        if (port) {
767                                *port = ntohs((uint16_t)data_in6->sin6_port);
768                        }
769                        addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA,
770                                        LDNS_IP6ADDRLEN, &data_in6->sin6_addr);
771                        break;
772                default:
773                        if (port) {
774                                *port = 0;
775                        }
776                        return NULL;
777        }
778        return addr;
779}
780#endif
781
782/* code from resolver.c */
783ldns_status
784ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class)
785{
786        ldns_pkt *query;
787        ldns_buffer *query_wire;
788
789        struct sockaddr_storage *ns = NULL;
790        size_t ns_len = 0;
791        size_t ns_i;
792        ldns_status status;
793
794        if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) {
795                return LDNS_STATUS_ERR;
796        }
797
798        query = ldns_pkt_query_new(ldns_rdf_clone(domain), LDNS_RR_TYPE_AXFR, class, 0);
799
800        if (!query) {
801                return LDNS_STATUS_ADDRESS_ERR;
802        }
803        /* For AXFR, we have to make the connection ourselves */
804        /* try all nameservers (which usually would mean v4 fallback if
805         * @hostname is used */
806        for (ns_i = 0;
807             ns_i < ldns_resolver_nameserver_count(resolver) &&
808             resolver->_socket == 0;
809             ns_i++) {
810	        ns = ldns_rdf2native_sockaddr_storage(
811	        	resolver->_nameservers[ns_i],
812			ldns_resolver_port(resolver), &ns_len);
813
814		resolver->_socket = ldns_tcp_connect(ns, (socklen_t)ns_len,
815				ldns_resolver_timeout(resolver));
816	}
817
818	if (resolver->_socket == 0) {
819		ldns_pkt_free(query);
820		LDNS_FREE(ns);
821		return LDNS_STATUS_NETWORK_ERR;
822	}
823
824#ifdef HAVE_SSL
825	if (ldns_resolver_tsig_keyname(resolver) && ldns_resolver_tsig_keydata(resolver)) {
826		status = ldns_pkt_tsig_sign(query,
827		                            ldns_resolver_tsig_keyname(resolver),
828		                            ldns_resolver_tsig_keydata(resolver),
829		                            300, ldns_resolver_tsig_algorithm(resolver), NULL);
830		if (status != LDNS_STATUS_OK) {
831			/* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
832			   we have to close the socket here! */
833#ifndef USE_WINSOCK
834			close(resolver->_socket);
835#else
836			closesocket(resolver->_socket);
837#endif
838			resolver->_socket = 0;
839
840			return LDNS_STATUS_CRYPTO_TSIG_ERR;
841		}
842	}
843#endif /* HAVE_SSL */
844
845        /* Convert the query to a buffer
846         * Is this necessary?
847         */
848        query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN);
849        if(!query_wire) {
850                ldns_pkt_free(query);
851                LDNS_FREE(ns);
852#ifndef USE_WINSOCK
853		close(resolver->_socket);
854#else
855		closesocket(resolver->_socket);
856#endif
857		resolver->_socket = 0;
858
859                return LDNS_STATUS_MEM_ERR;
860        }
861        status = ldns_pkt2buffer_wire(query_wire, query);
862        if (status != LDNS_STATUS_OK) {
863                ldns_pkt_free(query);
864		ldns_buffer_free(query_wire);
865                LDNS_FREE(ns);
866
867		/* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
868		    we have to close the socket here! */
869#ifndef USE_WINSOCK
870		close(resolver->_socket);
871#else
872		closesocket(resolver->_socket);
873#endif
874		resolver->_socket = 0;
875
876                return status;
877        }
878        /* Send the query */
879        if (ldns_tcp_send_query(query_wire, resolver->_socket, ns,
880				(socklen_t)ns_len) == 0) {
881                ldns_pkt_free(query);
882                ldns_buffer_free(query_wire);
883                LDNS_FREE(ns);
884
885		/* RoRi: to prevent problems on subsequent calls to ldns_axfr_start
886		         we have to close the socket here! */
887
888#ifndef USE_WINSOCK
889		close(resolver->_socket);
890#else
891		closesocket(resolver->_socket);
892#endif
893		resolver->_socket = 0;
894
895                return LDNS_STATUS_NETWORK_ERR;
896        }
897
898        ldns_pkt_free(query);
899        ldns_buffer_free(query_wire);
900        LDNS_FREE(ns);
901
902        /*
903         * The AXFR is done once the second SOA record is sent
904         */
905        resolver->_axfr_soa_count = 0;
906        return LDNS_STATUS_OK;
907}
908