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