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