1825eb42bSJan Lentfer /*
2825eb42bSJan Lentfer * net.c
3825eb42bSJan Lentfer *
4825eb42bSJan Lentfer * Network implementation
5825eb42bSJan Lentfer * All network related functions are grouped here
6825eb42bSJan Lentfer *
7825eb42bSJan Lentfer * a Net::DNS like library for C
8825eb42bSJan Lentfer *
9825eb42bSJan Lentfer * (c) NLnet Labs, 2004-2006
10825eb42bSJan Lentfer *
11825eb42bSJan Lentfer * See the file LICENSE for the license
12825eb42bSJan Lentfer */
13825eb42bSJan Lentfer
14825eb42bSJan Lentfer #include <ldns/config.h>
15825eb42bSJan Lentfer
16825eb42bSJan Lentfer #include <ldns/ldns.h>
17825eb42bSJan Lentfer
18825eb42bSJan Lentfer #ifdef HAVE_NETINET_IN_H
19825eb42bSJan Lentfer #include <netinet/in.h>
20825eb42bSJan Lentfer #endif
21825eb42bSJan Lentfer #ifdef HAVE_SYS_SOCKET_H
22825eb42bSJan Lentfer #include <sys/socket.h>
23825eb42bSJan Lentfer #endif
24825eb42bSJan Lentfer #ifdef HAVE_NETDB_H
25825eb42bSJan Lentfer #include <netdb.h>
26825eb42bSJan Lentfer #endif
27825eb42bSJan Lentfer #ifdef HAVE_ARPA_INET_H
28825eb42bSJan Lentfer #include <arpa/inet.h>
29825eb42bSJan Lentfer #endif
30825eb42bSJan Lentfer #include <sys/time.h>
31825eb42bSJan Lentfer #include <errno.h>
32825eb42bSJan Lentfer #include <fcntl.h>
335340022aSzrj #ifdef HAVE_POLL
345340022aSzrj #include <poll.h>
355340022aSzrj #endif
36825eb42bSJan Lentfer
37825eb42bSJan Lentfer ldns_status
ldns_send(ldns_pkt ** result_packet,ldns_resolver * r,const ldns_pkt * query_pkt)38825eb42bSJan Lentfer ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt)
39825eb42bSJan Lentfer {
40825eb42bSJan Lentfer ldns_buffer *qb;
41825eb42bSJan Lentfer ldns_status result;
42825eb42bSJan Lentfer ldns_rdf *tsig_mac = NULL;
43825eb42bSJan Lentfer
44825eb42bSJan Lentfer qb = ldns_buffer_new(LDNS_MIN_BUFLEN);
45825eb42bSJan Lentfer
46825eb42bSJan Lentfer if (query_pkt && ldns_pkt_tsig(query_pkt)) {
47825eb42bSJan Lentfer tsig_mac = ldns_rr_rdf(ldns_pkt_tsig(query_pkt), 3);
48825eb42bSJan Lentfer }
49825eb42bSJan Lentfer
50825eb42bSJan Lentfer if (!query_pkt ||
51825eb42bSJan Lentfer ldns_pkt2buffer_wire(qb, query_pkt) != LDNS_STATUS_OK) {
52825eb42bSJan Lentfer result = LDNS_STATUS_ERR;
53825eb42bSJan Lentfer } else {
54825eb42bSJan Lentfer result = ldns_send_buffer(result_packet, r, qb, tsig_mac);
55825eb42bSJan Lentfer }
56825eb42bSJan Lentfer
57825eb42bSJan Lentfer ldns_buffer_free(qb);
58825eb42bSJan Lentfer
59825eb42bSJan Lentfer return result;
60825eb42bSJan Lentfer }
61825eb42bSJan Lentfer
625340022aSzrj /* code from rdata.c */
635340022aSzrj static struct sockaddr_storage *
ldns_rdf2native_sockaddr_storage_port(const ldns_rdf * rd,uint16_t port,size_t * size)645340022aSzrj ldns_rdf2native_sockaddr_storage_port(
655340022aSzrj const ldns_rdf *rd, uint16_t port, size_t *size)
665340022aSzrj {
675340022aSzrj struct sockaddr_storage *data;
685340022aSzrj struct sockaddr_in *data_in;
695340022aSzrj struct sockaddr_in6 *data_in6;
705340022aSzrj
715340022aSzrj data = LDNS_MALLOC(struct sockaddr_storage);
725340022aSzrj if (!data) {
735340022aSzrj return NULL;
745340022aSzrj }
755340022aSzrj /* zero the structure for portability */
765340022aSzrj memset(data, 0, sizeof(struct sockaddr_storage));
775340022aSzrj
785340022aSzrj switch(ldns_rdf_get_type(rd)) {
795340022aSzrj case LDNS_RDF_TYPE_A:
805340022aSzrj #ifndef S_SPLINT_S
815340022aSzrj data->ss_family = AF_INET;
825340022aSzrj #endif
835340022aSzrj data_in = (struct sockaddr_in*) data;
845340022aSzrj data_in->sin_port = (in_port_t)htons(port);
855340022aSzrj memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd));
865340022aSzrj *size = sizeof(struct sockaddr_in);
875340022aSzrj return data;
885340022aSzrj case LDNS_RDF_TYPE_AAAA:
895340022aSzrj #ifndef S_SPLINT_S
905340022aSzrj data->ss_family = AF_INET6;
915340022aSzrj #endif
925340022aSzrj data_in6 = (struct sockaddr_in6*) data;
935340022aSzrj data_in6->sin6_port = (in_port_t)htons(port);
945340022aSzrj memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd));
955340022aSzrj *size = sizeof(struct sockaddr_in6);
965340022aSzrj return data;
975340022aSzrj default:
985340022aSzrj LDNS_FREE(data);
995340022aSzrj return NULL;
1005340022aSzrj }
1015340022aSzrj }
1025340022aSzrj
1035340022aSzrj struct sockaddr_storage *
ldns_rdf2native_sockaddr_storage(const ldns_rdf * rd,uint16_t port,size_t * size)1045340022aSzrj ldns_rdf2native_sockaddr_storage(
1055340022aSzrj const ldns_rdf *rd, uint16_t port, size_t *size)
1065340022aSzrj {
1075340022aSzrj return ldns_rdf2native_sockaddr_storage_port(
1085340022aSzrj rd, (port == 0 ? (uint16_t)LDNS_PORT : port), size);
1095340022aSzrj }
1105340022aSzrj
1115340022aSzrj /** best effort to set nonblocking */
1125340022aSzrj static void
ldns_sock_nonblock(int sockfd)1135340022aSzrj ldns_sock_nonblock(int sockfd)
1145340022aSzrj {
1155340022aSzrj #ifdef HAVE_FCNTL
1165340022aSzrj int flag;
1175340022aSzrj if((flag = fcntl(sockfd, F_GETFL)) != -1) {
1185340022aSzrj flag |= O_NONBLOCK;
1195340022aSzrj if(fcntl(sockfd, F_SETFL, flag) == -1) {
1205340022aSzrj /* ignore error, continue blockingly */
1215340022aSzrj }
1225340022aSzrj }
1235340022aSzrj #elif defined(HAVE_IOCTLSOCKET)
1245340022aSzrj unsigned long on = 1;
1255340022aSzrj if(ioctlsocket(sockfd, FIONBIO, &on) != 0) {
1265340022aSzrj /* ignore error, continue blockingly */
1275340022aSzrj }
1285340022aSzrj #endif
1295340022aSzrj }
1305340022aSzrj
1315340022aSzrj /** best effort to set blocking */
1325340022aSzrj static void
ldns_sock_block(int sockfd)1335340022aSzrj ldns_sock_block(int sockfd)
1345340022aSzrj {
1355340022aSzrj #ifdef HAVE_FCNTL
1365340022aSzrj int flag;
1375340022aSzrj if((flag = fcntl(sockfd, F_GETFL)) != -1) {
1385340022aSzrj flag &= ~O_NONBLOCK;
1395340022aSzrj if(fcntl(sockfd, F_SETFL, flag) == -1) {
1405340022aSzrj /* ignore error, continue */
1415340022aSzrj }
1425340022aSzrj }
1435340022aSzrj #elif defined(HAVE_IOCTLSOCKET)
1445340022aSzrj unsigned long off = 0;
1455340022aSzrj if(ioctlsocket(sockfd, FIONBIO, &off) != 0) {
1465340022aSzrj /* ignore error, continue */
1475340022aSzrj }
1485340022aSzrj #endif
1495340022aSzrj }
1505340022aSzrj
1515340022aSzrj /** wait for a socket to become ready */
1525340022aSzrj static int
ldns_sock_wait(int sockfd,struct timeval timeout,int write)1535340022aSzrj ldns_sock_wait(int sockfd, struct timeval timeout, int write)
1545340022aSzrj {
1555340022aSzrj int ret;
1565340022aSzrj #ifndef HAVE_POLL
1575340022aSzrj #ifndef S_SPLINT_S
1585340022aSzrj fd_set fds;
1595340022aSzrj FD_ZERO(&fds);
1605340022aSzrj FD_SET(FD_SET_T sockfd, &fds);
1615340022aSzrj if(write)
1625340022aSzrj ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
1635340022aSzrj else
1645340022aSzrj ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
1655340022aSzrj #endif
1665340022aSzrj #else
1675340022aSzrj struct pollfd pfds[2];
1685340022aSzrj
1695340022aSzrj memset(&pfds[0], 0, sizeof(pfds[0]) * 2);
1705340022aSzrj
1715340022aSzrj pfds[0].fd = sockfd;
1725340022aSzrj pfds[0].events = POLLIN|POLLERR;
1735340022aSzrj
1745340022aSzrj if (write) {
1755340022aSzrj pfds[0].events |= POLLOUT;
1765340022aSzrj }
1775340022aSzrj
1785340022aSzrj ret = poll(pfds, 1, (int)(timeout.tv_sec * 1000
1795340022aSzrj + timeout.tv_usec / 1000));
1805340022aSzrj #endif
1815340022aSzrj if(ret == 0)
1825340022aSzrj /* timeout expired */
1835340022aSzrj return 0;
1845340022aSzrj else if(ret == -1)
1855340022aSzrj /* error */
1865340022aSzrj return 0;
1875340022aSzrj return 1;
1885340022aSzrj }
1895340022aSzrj
1905340022aSzrj
1915340022aSzrj static int
ldns_tcp_connect_from(const struct sockaddr_storage * to,socklen_t tolen,const struct sockaddr_storage * from,socklen_t fromlen,struct timeval timeout)1925340022aSzrj ldns_tcp_connect_from(const struct sockaddr_storage *to, socklen_t tolen,
1935340022aSzrj const struct sockaddr_storage *from, socklen_t fromlen,
1945340022aSzrj struct timeval timeout)
1955340022aSzrj {
1965340022aSzrj int sockfd;
1975340022aSzrj
1985340022aSzrj #ifndef S_SPLINT_S
1995340022aSzrj if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM,
2005340022aSzrj IPPROTO_TCP)) == SOCK_INVALID) {
201819dec71SDaniel Fojt return -1;
2025340022aSzrj }
2035340022aSzrj #endif
2045340022aSzrj if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == SOCK_INVALID){
205819dec71SDaniel Fojt close_socket(sockfd);
206819dec71SDaniel Fojt return -1;
2075340022aSzrj }
2085340022aSzrj
2095340022aSzrj /* perform nonblocking connect, to be able to wait with select() */
2105340022aSzrj ldns_sock_nonblock(sockfd);
2115340022aSzrj if (connect(sockfd, (struct sockaddr*)to, tolen) == SOCK_INVALID) {
2125340022aSzrj #ifndef USE_WINSOCK
2135340022aSzrj #ifdef EINPROGRESS
2145340022aSzrj if(errno != EINPROGRESS) {
2155340022aSzrj #else
2165340022aSzrj if(1) {
2175340022aSzrj #endif
2185340022aSzrj close_socket(sockfd);
219819dec71SDaniel Fojt return -1;
2205340022aSzrj }
2215340022aSzrj #else /* USE_WINSOCK */
2225340022aSzrj if(WSAGetLastError() != WSAEINPROGRESS &&
2235340022aSzrj WSAGetLastError() != WSAEWOULDBLOCK) {
2245340022aSzrj close_socket(sockfd);
225819dec71SDaniel Fojt return -1;
2265340022aSzrj }
2275340022aSzrj #endif
2285340022aSzrj /* error was only telling us that it would block */
2295340022aSzrj }
2305340022aSzrj
2315340022aSzrj /* wait(write) until connected or error */
2325340022aSzrj while(1) {
2335340022aSzrj int error = 0;
2345340022aSzrj socklen_t len = (socklen_t)sizeof(error);
2355340022aSzrj
2365340022aSzrj if(!ldns_sock_wait(sockfd, timeout, 1)) {
2375340022aSzrj close_socket(sockfd);
238819dec71SDaniel Fojt return -1;
2395340022aSzrj }
2405340022aSzrj
2415340022aSzrj /* check if there is a pending error for nonblocking connect */
2425340022aSzrj if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error,
2435340022aSzrj &len) < 0) {
2445340022aSzrj #ifndef USE_WINSOCK
2455340022aSzrj error = errno; /* on solaris errno is error */
2465340022aSzrj #else
2475340022aSzrj error = WSAGetLastError();
2485340022aSzrj #endif
2495340022aSzrj }
2505340022aSzrj #ifndef USE_WINSOCK
2515340022aSzrj #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
2525340022aSzrj if(error == EINPROGRESS || error == EWOULDBLOCK)
2535340022aSzrj continue; /* try again */
2545340022aSzrj #endif
2555340022aSzrj else if(error != 0) {
2565340022aSzrj close_socket(sockfd);
2575340022aSzrj /* error in errno for our user */
2585340022aSzrj errno = error;
259819dec71SDaniel Fojt return -1;
2605340022aSzrj }
2615340022aSzrj #else /* USE_WINSOCK */
2625340022aSzrj if(error == WSAEINPROGRESS)
2635340022aSzrj continue;
2645340022aSzrj else if(error == WSAEWOULDBLOCK)
2655340022aSzrj continue;
2665340022aSzrj else if(error != 0) {
2675340022aSzrj close_socket(sockfd);
2685340022aSzrj errno = error;
269819dec71SDaniel Fojt return -1;
2705340022aSzrj }
2715340022aSzrj #endif /* USE_WINSOCK */
2725340022aSzrj /* connected */
2735340022aSzrj break;
2745340022aSzrj }
2755340022aSzrj
2765340022aSzrj /* set the socket blocking again */
2775340022aSzrj ldns_sock_block(sockfd);
2785340022aSzrj
2795340022aSzrj return sockfd;
2805340022aSzrj }
2815340022aSzrj
2825340022aSzrj int
2835340022aSzrj ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen,
2845340022aSzrj struct timeval timeout)
2855340022aSzrj {
286819dec71SDaniel Fojt int s = ldns_tcp_connect_from(to, tolen, NULL, 0, timeout);
287819dec71SDaniel Fojt return s > 0 ? s : 0;
288819dec71SDaniel Fojt }
289819dec71SDaniel Fojt
290819dec71SDaniel Fojt int
291819dec71SDaniel Fojt ldns_tcp_connect2(const struct sockaddr_storage *to, socklen_t tolen,
292819dec71SDaniel Fojt struct timeval timeout)
293819dec71SDaniel Fojt {
2945340022aSzrj return ldns_tcp_connect_from(to, tolen, NULL, 0, timeout);
2955340022aSzrj }
2965340022aSzrj
2975340022aSzrj static int
2985340022aSzrj ldns_tcp_bgsend_from(ldns_buffer *qbin,
2995340022aSzrj const struct sockaddr_storage *to, socklen_t tolen,
3005340022aSzrj const struct sockaddr_storage *from, socklen_t fromlen,
3015340022aSzrj struct timeval timeout)
3025340022aSzrj {
3035340022aSzrj int sockfd;
3045340022aSzrj
3055340022aSzrj sockfd = ldns_tcp_connect_from(to, tolen, from, fromlen, timeout);
3065340022aSzrj
307819dec71SDaniel Fojt if (sockfd >= 0 && ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) {
3085340022aSzrj close_socket(sockfd);
309819dec71SDaniel Fojt return -1;
3105340022aSzrj }
3115340022aSzrj
3125340022aSzrj return sockfd;
3135340022aSzrj }
3145340022aSzrj
3155340022aSzrj int
3165340022aSzrj ldns_tcp_bgsend(ldns_buffer *qbin,
3175340022aSzrj const struct sockaddr_storage *to, socklen_t tolen,
3185340022aSzrj struct timeval timeout)
3195340022aSzrj {
320819dec71SDaniel Fojt int s = ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
321819dec71SDaniel Fojt return s > 0 ? s : 0;
3225340022aSzrj }
3235340022aSzrj
324819dec71SDaniel Fojt int
325819dec71SDaniel Fojt ldns_tcp_bgsend2(ldns_buffer *qbin,
326819dec71SDaniel Fojt const struct sockaddr_storage *to, socklen_t tolen,
327819dec71SDaniel Fojt struct timeval timeout)
328819dec71SDaniel Fojt {
329819dec71SDaniel Fojt return ldns_tcp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
330819dec71SDaniel Fojt }
3315340022aSzrj
3325340022aSzrj /* keep in mind that in DNS tcp messages the first 2 bytes signal the
3335340022aSzrj * amount data to expect
3345340022aSzrj */
3355340022aSzrj static ldns_status
3365340022aSzrj ldns_tcp_send_from(uint8_t **result, ldns_buffer *qbin,
3375340022aSzrj const struct sockaddr_storage *to, socklen_t tolen,
3385340022aSzrj const struct sockaddr_storage *from, socklen_t fromlen,
3395340022aSzrj struct timeval timeout, size_t *answer_size)
3405340022aSzrj {
3415340022aSzrj int sockfd;
3425340022aSzrj uint8_t *answer;
3435340022aSzrj
3445340022aSzrj sockfd = ldns_tcp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
3455340022aSzrj
346819dec71SDaniel Fojt if (sockfd == -1) {
3475340022aSzrj return LDNS_STATUS_ERR;
3485340022aSzrj }
3495340022aSzrj
3505340022aSzrj answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout);
3515340022aSzrj close_socket(sockfd);
3525340022aSzrj
353819dec71SDaniel Fojt if (!answer) {
3545340022aSzrj /* oops */
3555340022aSzrj return LDNS_STATUS_NETWORK_ERR;
3565340022aSzrj }
3575340022aSzrj
358819dec71SDaniel Fojt *result = answer;
3595340022aSzrj return LDNS_STATUS_OK;
3605340022aSzrj }
3615340022aSzrj
3625340022aSzrj ldns_status
3635340022aSzrj ldns_tcp_send(uint8_t **result, ldns_buffer *qbin,
3645340022aSzrj const struct sockaddr_storage *to, socklen_t tolen,
3655340022aSzrj struct timeval timeout, size_t *answer_size)
3665340022aSzrj {
3675340022aSzrj return ldns_tcp_send_from(result, qbin,
3685340022aSzrj to, tolen, NULL, 0, timeout, answer_size);
3695340022aSzrj }
3705340022aSzrj
3715340022aSzrj int
3725340022aSzrj ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
3735340022aSzrj {
3745340022aSzrj int sockfd;
3755340022aSzrj
3765340022aSzrj #ifndef S_SPLINT_S
3775340022aSzrj if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
3785340022aSzrj IPPROTO_UDP))
379819dec71SDaniel Fojt == SOCK_INVALID) {
3805340022aSzrj return 0;
3815340022aSzrj }
3825340022aSzrj #endif
3835340022aSzrj return sockfd;
3845340022aSzrj }
3855340022aSzrj
386819dec71SDaniel Fojt int
387819dec71SDaniel Fojt ldns_udp_connect2(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout))
388819dec71SDaniel Fojt {
389819dec71SDaniel Fojt int sockfd;
390819dec71SDaniel Fojt
391819dec71SDaniel Fojt #ifndef S_SPLINT_S
392819dec71SDaniel Fojt if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM,
393819dec71SDaniel Fojt IPPROTO_UDP))
394819dec71SDaniel Fojt == SOCK_INVALID) {
395819dec71SDaniel Fojt return -1;
396819dec71SDaniel Fojt }
397819dec71SDaniel Fojt #endif
398819dec71SDaniel Fojt return sockfd;
399819dec71SDaniel Fojt }
400819dec71SDaniel Fojt
4015340022aSzrj static int
4025340022aSzrj ldns_udp_bgsend_from(ldns_buffer *qbin,
4035340022aSzrj const struct sockaddr_storage *to , socklen_t tolen,
4045340022aSzrj const struct sockaddr_storage *from, socklen_t fromlen,
4055340022aSzrj struct timeval timeout)
4065340022aSzrj {
4075340022aSzrj int sockfd;
4085340022aSzrj
409819dec71SDaniel Fojt sockfd = ldns_udp_connect2(to, timeout);
4105340022aSzrj
411819dec71SDaniel Fojt if (sockfd == -1) {
412819dec71SDaniel Fojt return -1;
4135340022aSzrj }
4145340022aSzrj
4155340022aSzrj if (from && bind(sockfd, (const struct sockaddr*)from, fromlen) == -1){
416819dec71SDaniel Fojt close_socket(sockfd);
417819dec71SDaniel Fojt return -1;
4185340022aSzrj }
4195340022aSzrj
4205340022aSzrj if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) {
4215340022aSzrj close_socket(sockfd);
422819dec71SDaniel Fojt return -1;
4235340022aSzrj }
4245340022aSzrj return sockfd;
4255340022aSzrj }
4265340022aSzrj
4275340022aSzrj int
4285340022aSzrj ldns_udp_bgsend(ldns_buffer *qbin,
4295340022aSzrj const struct sockaddr_storage *to , socklen_t tolen,
4305340022aSzrj struct timeval timeout)
4315340022aSzrj {
432819dec71SDaniel Fojt int s = ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
433819dec71SDaniel Fojt return s > 0 ? s : 0;
434819dec71SDaniel Fojt }
435819dec71SDaniel Fojt
436819dec71SDaniel Fojt int
437819dec71SDaniel Fojt ldns_udp_bgsend2(ldns_buffer *qbin,
438819dec71SDaniel Fojt const struct sockaddr_storage *to , socklen_t tolen,
439819dec71SDaniel Fojt struct timeval timeout)
440819dec71SDaniel Fojt {
4415340022aSzrj return ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
4425340022aSzrj }
4435340022aSzrj
4445340022aSzrj static ldns_status
4455340022aSzrj ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin,
4465340022aSzrj const struct sockaddr_storage *to , socklen_t tolen,
4475340022aSzrj const struct sockaddr_storage *from, socklen_t fromlen,
4485340022aSzrj struct timeval timeout, size_t *answer_size)
4495340022aSzrj {
4505340022aSzrj int sockfd;
4515340022aSzrj uint8_t *answer;
4525340022aSzrj
4535340022aSzrj sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
4545340022aSzrj
455819dec71SDaniel Fojt if (sockfd == -1) {
4565340022aSzrj return LDNS_STATUS_SOCKET_ERROR;
4575340022aSzrj }
4585340022aSzrj
4595340022aSzrj /* wait for an response*/
4605340022aSzrj if(!ldns_sock_wait(sockfd, timeout, 0)) {
4615340022aSzrj close_socket(sockfd);
4625340022aSzrj return LDNS_STATUS_NETWORK_ERR;
4635340022aSzrj }
4645340022aSzrj
4655340022aSzrj /* set to nonblocking, so if the checksum is bad, it becomes
466*ee791febSAntonio Huete Jimenez * an EAGAIN error and the ldns_udp_send function does not block,
4675340022aSzrj * but returns a 'NETWORK_ERROR' much like a timeout. */
4685340022aSzrj ldns_sock_nonblock(sockfd);
4695340022aSzrj
4705340022aSzrj answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
4715340022aSzrj close_socket(sockfd);
4725340022aSzrj
473819dec71SDaniel Fojt if (!answer) {
4745340022aSzrj /* oops */
4755340022aSzrj return LDNS_STATUS_NETWORK_ERR;
4765340022aSzrj }
4775340022aSzrj
4785340022aSzrj *result = answer;
4795340022aSzrj return LDNS_STATUS_OK;
4805340022aSzrj }
4815340022aSzrj
4825340022aSzrj ldns_status
4835340022aSzrj ldns_udp_send(uint8_t **result, ldns_buffer *qbin,
4845340022aSzrj const struct sockaddr_storage *to , socklen_t tolen,
4855340022aSzrj struct timeval timeout, size_t *answer_size)
4865340022aSzrj {
4875340022aSzrj return ldns_udp_send_from(result, qbin, to, tolen, NULL, 0,
4885340022aSzrj timeout, answer_size);
4895340022aSzrj }
4905340022aSzrj
491825eb42bSJan Lentfer ldns_status
492825eb42bSJan Lentfer ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac)
493825eb42bSJan Lentfer {
494825eb42bSJan Lentfer uint8_t i;
495825eb42bSJan Lentfer
4965340022aSzrj struct sockaddr_storage *src = NULL;
497819dec71SDaniel Fojt size_t src_len = 0;
498825eb42bSJan Lentfer struct sockaddr_storage *ns;
499825eb42bSJan Lentfer size_t ns_len;
500825eb42bSJan Lentfer struct timeval tv_s;
501825eb42bSJan Lentfer struct timeval tv_e;
502825eb42bSJan Lentfer
503825eb42bSJan Lentfer ldns_rdf **ns_array;
504825eb42bSJan Lentfer size_t *rtt;
505825eb42bSJan Lentfer ldns_pkt *reply;
506825eb42bSJan Lentfer bool all_servers_rtt_inf;
507825eb42bSJan Lentfer uint8_t retries;
508825eb42bSJan Lentfer
509825eb42bSJan Lentfer uint8_t *reply_bytes = NULL;
510825eb42bSJan Lentfer size_t reply_size = 0;
511825eb42bSJan Lentfer ldns_status status, send_status;
512825eb42bSJan Lentfer
513825eb42bSJan Lentfer assert(r != NULL);
514825eb42bSJan Lentfer
515825eb42bSJan Lentfer status = LDNS_STATUS_OK;
516825eb42bSJan Lentfer rtt = ldns_resolver_rtt(r);
517825eb42bSJan Lentfer ns_array = ldns_resolver_nameservers(r);
518825eb42bSJan Lentfer reply = NULL;
519825eb42bSJan Lentfer ns_len = 0;
520825eb42bSJan Lentfer
521825eb42bSJan Lentfer all_servers_rtt_inf = true;
522825eb42bSJan Lentfer
523825eb42bSJan Lentfer if (ldns_resolver_random(r)) {
524825eb42bSJan Lentfer ldns_resolver_nameservers_randomize(r);
525825eb42bSJan Lentfer }
526825eb42bSJan Lentfer
5275340022aSzrj if(ldns_resolver_source(r)) {
5285340022aSzrj src = ldns_rdf2native_sockaddr_storage_port(
5295340022aSzrj ldns_resolver_source(r), 0, &src_len);
5305340022aSzrj }
5315340022aSzrj
532825eb42bSJan Lentfer /* loop through all defined nameservers */
533825eb42bSJan Lentfer for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
534825eb42bSJan Lentfer if (rtt[i] == LDNS_RESOLV_RTT_INF) {
535825eb42bSJan Lentfer /* not reachable nameserver! */
536825eb42bSJan Lentfer continue;
537825eb42bSJan Lentfer }
538825eb42bSJan Lentfer
539825eb42bSJan Lentfer /* maybe verbosity setting?
540825eb42bSJan Lentfer printf("Sending to ");
541825eb42bSJan Lentfer ldns_rdf_print(stdout, ns_array[i]);
542825eb42bSJan Lentfer printf("\n");
543825eb42bSJan Lentfer */
544825eb42bSJan Lentfer ns = ldns_rdf2native_sockaddr_storage(ns_array[i],
545825eb42bSJan Lentfer ldns_resolver_port(r), &ns_len);
546825eb42bSJan Lentfer
547d1b2b5caSJohn Marino
548d1b2b5caSJohn Marino #ifndef S_SPLINT_S
549825eb42bSJan Lentfer if ((ns->ss_family == AF_INET) &&
550825eb42bSJan Lentfer (ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) {
551ac996e71SJan Lentfer /* not reachable */
552d1b2b5caSJohn Marino LDNS_FREE(ns);
553825eb42bSJan Lentfer continue;
554825eb42bSJan Lentfer }
555825eb42bSJan Lentfer
556825eb42bSJan Lentfer if ((ns->ss_family == AF_INET6) &&
557825eb42bSJan Lentfer (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) {
558ac996e71SJan Lentfer /* not reachable */
559d1b2b5caSJohn Marino LDNS_FREE(ns);
560825eb42bSJan Lentfer continue;
561825eb42bSJan Lentfer }
562d1b2b5caSJohn Marino #endif
563825eb42bSJan Lentfer
564ac996e71SJan Lentfer all_servers_rtt_inf = false;
565ac996e71SJan Lentfer
566825eb42bSJan Lentfer gettimeofday(&tv_s, NULL);
567825eb42bSJan Lentfer
568825eb42bSJan Lentfer send_status = LDNS_STATUS_ERR;
569825eb42bSJan Lentfer
570825eb42bSJan Lentfer /* reply_bytes implicitly handles our error */
5715340022aSzrj if (ldns_resolver_usevc(r)) {
572825eb42bSJan Lentfer for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
573825eb42bSJan Lentfer send_status =
5745340022aSzrj ldns_tcp_send_from(&reply_bytes, qb,
5755340022aSzrj ns, (socklen_t)ns_len,
5765340022aSzrj src, (socklen_t)src_len,
5775340022aSzrj ldns_resolver_timeout(r),
578825eb42bSJan Lentfer &reply_size);
579825eb42bSJan Lentfer if (send_status == LDNS_STATUS_OK) {
580825eb42bSJan Lentfer break;
581825eb42bSJan Lentfer }
582825eb42bSJan Lentfer }
583825eb42bSJan Lentfer } else {
584825eb42bSJan Lentfer for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
585825eb42bSJan Lentfer /* ldns_rdf_print(stdout, ns_array[i]); */
586825eb42bSJan Lentfer send_status =
5875340022aSzrj ldns_udp_send_from(&reply_bytes, qb,
5885340022aSzrj ns, (socklen_t)ns_len,
5895340022aSzrj src, (socklen_t)src_len,
5905340022aSzrj ldns_resolver_timeout(r),
591825eb42bSJan Lentfer &reply_size);
592825eb42bSJan Lentfer if (send_status == LDNS_STATUS_OK) {
593825eb42bSJan Lentfer break;
594825eb42bSJan Lentfer }
595825eb42bSJan Lentfer }
596825eb42bSJan Lentfer }
597825eb42bSJan Lentfer
598825eb42bSJan Lentfer if (send_status != LDNS_STATUS_OK) {
599825eb42bSJan Lentfer ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF);
600825eb42bSJan Lentfer status = send_status;
601825eb42bSJan Lentfer }
602825eb42bSJan Lentfer
603825eb42bSJan Lentfer /* obey the fail directive */
604825eb42bSJan Lentfer if (!reply_bytes) {
605825eb42bSJan Lentfer /* the current nameserver seems to have a problem, blacklist it */
606825eb42bSJan Lentfer if (ldns_resolver_fail(r)) {
607819dec71SDaniel Fojt if(src) {
608819dec71SDaniel Fojt LDNS_FREE(src);
609819dec71SDaniel Fojt }
610825eb42bSJan Lentfer LDNS_FREE(ns);
611825eb42bSJan Lentfer return LDNS_STATUS_ERR;
612825eb42bSJan Lentfer } else {
613825eb42bSJan Lentfer LDNS_FREE(ns);
614825eb42bSJan Lentfer continue;
615825eb42bSJan Lentfer }
616825eb42bSJan Lentfer }
617825eb42bSJan Lentfer
618825eb42bSJan Lentfer status = ldns_wire2pkt(&reply, reply_bytes, reply_size);
619825eb42bSJan Lentfer if (status != LDNS_STATUS_OK) {
620819dec71SDaniel Fojt if(src) LDNS_FREE(src);
621825eb42bSJan Lentfer LDNS_FREE(reply_bytes);
622825eb42bSJan Lentfer LDNS_FREE(ns);
623825eb42bSJan Lentfer return status;
624825eb42bSJan Lentfer }
625819dec71SDaniel Fojt assert(reply);
626825eb42bSJan Lentfer
627825eb42bSJan Lentfer LDNS_FREE(ns);
628825eb42bSJan Lentfer gettimeofday(&tv_e, NULL);
629825eb42bSJan Lentfer
630825eb42bSJan Lentfer if (reply) {
631825eb42bSJan Lentfer ldns_pkt_set_querytime(reply, (uint32_t)
632825eb42bSJan Lentfer ((tv_e.tv_sec - tv_s.tv_sec) * 1000) +
633825eb42bSJan Lentfer (tv_e.tv_usec - tv_s.tv_usec) / 1000);
634d1b2b5caSJohn Marino ldns_pkt_set_answerfrom(reply,
635d1b2b5caSJohn Marino ldns_rdf_clone(ns_array[i]));
636825eb42bSJan Lentfer ldns_pkt_set_timestamp(reply, tv_s);
637825eb42bSJan Lentfer ldns_pkt_set_size(reply, reply_size);
638825eb42bSJan Lentfer break;
639825eb42bSJan Lentfer } else {
640825eb42bSJan Lentfer if (ldns_resolver_fail(r)) {
641825eb42bSJan Lentfer /* if fail is set bail out, after the first
642825eb42bSJan Lentfer * one */
643825eb42bSJan Lentfer break;
644825eb42bSJan Lentfer }
645825eb42bSJan Lentfer }
646825eb42bSJan Lentfer
647825eb42bSJan Lentfer /* wait retrans seconds... */
648825eb42bSJan Lentfer sleep((unsigned int) ldns_resolver_retrans(r));
649825eb42bSJan Lentfer }
650825eb42bSJan Lentfer
6515340022aSzrj if(src) {
6525340022aSzrj LDNS_FREE(src);
6535340022aSzrj }
654825eb42bSJan Lentfer if (all_servers_rtt_inf) {
655825eb42bSJan Lentfer LDNS_FREE(reply_bytes);
656825eb42bSJan Lentfer return LDNS_STATUS_RES_NO_NS;
657825eb42bSJan Lentfer }
658825eb42bSJan Lentfer #ifdef HAVE_SSL
659d1b2b5caSJohn Marino if (tsig_mac && reply && reply_bytes) {
660825eb42bSJan Lentfer if (!ldns_pkt_tsig_verify(reply,
661825eb42bSJan Lentfer reply_bytes,
662825eb42bSJan Lentfer reply_size,
663825eb42bSJan Lentfer ldns_resolver_tsig_keyname(r),
664825eb42bSJan Lentfer ldns_resolver_tsig_keydata(r), tsig_mac)) {
665825eb42bSJan Lentfer status = LDNS_STATUS_CRYPTO_TSIG_BOGUS;
666825eb42bSJan Lentfer }
667825eb42bSJan Lentfer }
668825eb42bSJan Lentfer #else
669825eb42bSJan Lentfer (void)tsig_mac;
670825eb42bSJan Lentfer #endif /* HAVE_SSL */
671825eb42bSJan Lentfer
672825eb42bSJan Lentfer LDNS_FREE(reply_bytes);
673825eb42bSJan Lentfer if (result) {
674825eb42bSJan Lentfer *result = reply;
675825eb42bSJan Lentfer }
676825eb42bSJan Lentfer
677825eb42bSJan Lentfer return status;
678825eb42bSJan Lentfer }
679825eb42bSJan Lentfer
680825eb42bSJan Lentfer ssize_t
681825eb42bSJan Lentfer ldns_tcp_send_query(ldns_buffer *qbin, int sockfd,
682825eb42bSJan Lentfer const struct sockaddr_storage *to, socklen_t tolen)
683825eb42bSJan Lentfer {
684825eb42bSJan Lentfer uint8_t *sendbuf;
685825eb42bSJan Lentfer ssize_t bytes;
686825eb42bSJan Lentfer
687825eb42bSJan Lentfer /* add length of packet */
688825eb42bSJan Lentfer sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2);
689ac996e71SJan Lentfer if(!sendbuf) return 0;
690825eb42bSJan Lentfer ldns_write_uint16(sendbuf, ldns_buffer_position(qbin));
691d1b2b5caSJohn Marino memcpy(sendbuf + 2, ldns_buffer_begin(qbin), ldns_buffer_position(qbin));
692825eb42bSJan Lentfer
693825eb42bSJan Lentfer bytes = sendto(sockfd, (void*)sendbuf,
694825eb42bSJan Lentfer ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen);
695825eb42bSJan Lentfer
696825eb42bSJan Lentfer LDNS_FREE(sendbuf);
697825eb42bSJan Lentfer
698825eb42bSJan Lentfer if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) {
699825eb42bSJan Lentfer return 0;
700825eb42bSJan Lentfer }
701825eb42bSJan Lentfer return bytes;
702825eb42bSJan Lentfer }
703825eb42bSJan Lentfer
704825eb42bSJan Lentfer /* don't wait for an answer */
705825eb42bSJan Lentfer ssize_t
706825eb42bSJan Lentfer ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to,
707825eb42bSJan Lentfer socklen_t tolen)
708825eb42bSJan Lentfer {
709825eb42bSJan Lentfer ssize_t bytes;
710825eb42bSJan Lentfer
711825eb42bSJan Lentfer bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin),
712825eb42bSJan Lentfer ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen);
713825eb42bSJan Lentfer
714825eb42bSJan Lentfer if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) {
715825eb42bSJan Lentfer return 0;
716825eb42bSJan Lentfer }
717825eb42bSJan Lentfer return bytes;
718825eb42bSJan Lentfer }
719825eb42bSJan Lentfer
720825eb42bSJan Lentfer uint8_t *
721825eb42bSJan Lentfer ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from,
722825eb42bSJan Lentfer socklen_t *fromlen)
723825eb42bSJan Lentfer {
724ac996e71SJan Lentfer uint8_t *wire, *wireout;
725825eb42bSJan Lentfer ssize_t wire_size;
726825eb42bSJan Lentfer
727825eb42bSJan Lentfer wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN);
728825eb42bSJan Lentfer if (!wire) {
729825eb42bSJan Lentfer *size = 0;
730825eb42bSJan Lentfer return NULL;
731825eb42bSJan Lentfer }
732825eb42bSJan Lentfer
733825eb42bSJan Lentfer wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0,
734825eb42bSJan Lentfer (struct sockaddr *)from, fromlen);
735825eb42bSJan Lentfer
736825eb42bSJan Lentfer /* recvfrom can also return 0 */
737825eb42bSJan Lentfer if (wire_size == -1 || wire_size == 0) {
738825eb42bSJan Lentfer *size = 0;
739825eb42bSJan Lentfer LDNS_FREE(wire);
740825eb42bSJan Lentfer return NULL;
741825eb42bSJan Lentfer }
742825eb42bSJan Lentfer
743825eb42bSJan Lentfer *size = (size_t)wire_size;
744ac996e71SJan Lentfer wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size);
745ac996e71SJan Lentfer if(!wireout) LDNS_FREE(wire);
746825eb42bSJan Lentfer
747ac996e71SJan Lentfer return wireout;
748825eb42bSJan Lentfer }
749825eb42bSJan Lentfer
750825eb42bSJan Lentfer uint8_t *
751825eb42bSJan Lentfer ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout)
752825eb42bSJan Lentfer {
753825eb42bSJan Lentfer uint8_t *wire;
754825eb42bSJan Lentfer uint16_t wire_size;
755ac996e71SJan Lentfer ssize_t bytes = 0, rc = 0;
756825eb42bSJan Lentfer
757825eb42bSJan Lentfer wire = LDNS_XMALLOC(uint8_t, 2);
758825eb42bSJan Lentfer if (!wire) {
759825eb42bSJan Lentfer *size = 0;
760825eb42bSJan Lentfer return NULL;
761825eb42bSJan Lentfer }
762825eb42bSJan Lentfer
763825eb42bSJan Lentfer while (bytes < 2) {
764825eb42bSJan Lentfer if(!ldns_sock_wait(sockfd, timeout, 0)) {
765825eb42bSJan Lentfer *size = 0;
766825eb42bSJan Lentfer LDNS_FREE(wire);
767825eb42bSJan Lentfer return NULL;
768825eb42bSJan Lentfer }
769ac996e71SJan Lentfer rc = recv(sockfd, (void*) (wire + bytes),
770ac996e71SJan Lentfer (size_t) (2 - bytes), 0);
771ac996e71SJan Lentfer if (rc == -1 || rc == 0) {
772825eb42bSJan Lentfer *size = 0;
773825eb42bSJan Lentfer LDNS_FREE(wire);
774825eb42bSJan Lentfer return NULL;
775825eb42bSJan Lentfer }
776ac996e71SJan Lentfer bytes += rc;
777825eb42bSJan Lentfer }
778825eb42bSJan Lentfer
779825eb42bSJan Lentfer wire_size = ldns_read_uint16(wire);
780825eb42bSJan Lentfer
781825eb42bSJan Lentfer LDNS_FREE(wire);
782825eb42bSJan Lentfer wire = LDNS_XMALLOC(uint8_t, wire_size);
783fd185f4dSJan Lentfer if (!wire) {
784fd185f4dSJan Lentfer *size = 0;
785fd185f4dSJan Lentfer return NULL;
786fd185f4dSJan Lentfer }
787825eb42bSJan Lentfer bytes = 0;
788825eb42bSJan Lentfer
789825eb42bSJan Lentfer while (bytes < (ssize_t) wire_size) {
790825eb42bSJan Lentfer if(!ldns_sock_wait(sockfd, timeout, 0)) {
791825eb42bSJan Lentfer *size = 0;
792825eb42bSJan Lentfer LDNS_FREE(wire);
793825eb42bSJan Lentfer return NULL;
794825eb42bSJan Lentfer }
795ac996e71SJan Lentfer rc = recv(sockfd, (void*) (wire + bytes),
796825eb42bSJan Lentfer (size_t) (wire_size - bytes), 0);
797ac996e71SJan Lentfer if (rc == -1 || rc == 0) {
798825eb42bSJan Lentfer LDNS_FREE(wire);
799825eb42bSJan Lentfer *size = 0;
800825eb42bSJan Lentfer return NULL;
801825eb42bSJan Lentfer }
802ac996e71SJan Lentfer bytes += rc;
803825eb42bSJan Lentfer }
804825eb42bSJan Lentfer
805825eb42bSJan Lentfer *size = (size_t) bytes;
806825eb42bSJan Lentfer return wire;
807825eb42bSJan Lentfer }
808825eb42bSJan Lentfer
809825eb42bSJan Lentfer uint8_t *
810825eb42bSJan Lentfer ldns_tcp_read_wire(int sockfd, size_t *size)
811825eb42bSJan Lentfer {
812825eb42bSJan Lentfer uint8_t *wire;
813825eb42bSJan Lentfer uint16_t wire_size;
814ac996e71SJan Lentfer ssize_t bytes = 0, rc = 0;
815825eb42bSJan Lentfer
816825eb42bSJan Lentfer wire = LDNS_XMALLOC(uint8_t, 2);
817825eb42bSJan Lentfer if (!wire) {
818825eb42bSJan Lentfer *size = 0;
819825eb42bSJan Lentfer return NULL;
820825eb42bSJan Lentfer }
821825eb42bSJan Lentfer
822825eb42bSJan Lentfer while (bytes < 2) {
823ac996e71SJan Lentfer rc = recv(sockfd, (void*) (wire + bytes),
824ac996e71SJan Lentfer (size_t) (2 - bytes), 0);
825ac996e71SJan Lentfer if (rc == -1 || rc == 0) {
826825eb42bSJan Lentfer *size = 0;
827825eb42bSJan Lentfer LDNS_FREE(wire);
828825eb42bSJan Lentfer return NULL;
829825eb42bSJan Lentfer }
830ac996e71SJan Lentfer bytes += rc;
831825eb42bSJan Lentfer }
832825eb42bSJan Lentfer
833825eb42bSJan Lentfer wire_size = ldns_read_uint16(wire);
834825eb42bSJan Lentfer
835825eb42bSJan Lentfer LDNS_FREE(wire);
836825eb42bSJan Lentfer wire = LDNS_XMALLOC(uint8_t, wire_size);
837fd185f4dSJan Lentfer if (!wire) {
838fd185f4dSJan Lentfer *size = 0;
839fd185f4dSJan Lentfer return NULL;
840fd185f4dSJan Lentfer }
841825eb42bSJan Lentfer bytes = 0;
842825eb42bSJan Lentfer
843825eb42bSJan Lentfer while (bytes < (ssize_t) wire_size) {
844ac996e71SJan Lentfer rc = recv(sockfd, (void*) (wire + bytes),
845825eb42bSJan Lentfer (size_t) (wire_size - bytes), 0);
846ac996e71SJan Lentfer if (rc == -1 || rc == 0) {
847825eb42bSJan Lentfer LDNS_FREE(wire);
848825eb42bSJan Lentfer *size = 0;
849825eb42bSJan Lentfer return NULL;
850825eb42bSJan Lentfer }
851ac996e71SJan Lentfer bytes += rc;
852825eb42bSJan Lentfer }
853825eb42bSJan Lentfer
854825eb42bSJan Lentfer *size = (size_t) bytes;
855825eb42bSJan Lentfer return wire;
856825eb42bSJan Lentfer }
857825eb42bSJan Lentfer
858d1b2b5caSJohn Marino #ifndef S_SPLINT_S
859825eb42bSJan Lentfer ldns_rdf *
8605340022aSzrj ldns_sockaddr_storage2rdf(const struct sockaddr_storage *sock, uint16_t *port)
861825eb42bSJan Lentfer {
862825eb42bSJan Lentfer ldns_rdf *addr;
863825eb42bSJan Lentfer struct sockaddr_in *data_in;
864825eb42bSJan Lentfer struct sockaddr_in6 *data_in6;
865825eb42bSJan Lentfer
866825eb42bSJan Lentfer switch(sock->ss_family) {
867825eb42bSJan Lentfer case AF_INET:
868825eb42bSJan Lentfer data_in = (struct sockaddr_in*)sock;
869825eb42bSJan Lentfer if (port) {
870825eb42bSJan Lentfer *port = ntohs((uint16_t)data_in->sin_port);
871825eb42bSJan Lentfer }
872825eb42bSJan Lentfer addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A,
873825eb42bSJan Lentfer LDNS_IP4ADDRLEN, &data_in->sin_addr);
874825eb42bSJan Lentfer break;
875825eb42bSJan Lentfer case AF_INET6:
876825eb42bSJan Lentfer data_in6 = (struct sockaddr_in6*)sock;
877825eb42bSJan Lentfer if (port) {
878825eb42bSJan Lentfer *port = ntohs((uint16_t)data_in6->sin6_port);
879825eb42bSJan Lentfer }
880825eb42bSJan Lentfer addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA,
881825eb42bSJan Lentfer LDNS_IP6ADDRLEN, &data_in6->sin6_addr);
882825eb42bSJan Lentfer break;
883825eb42bSJan Lentfer default:
884825eb42bSJan Lentfer if (port) {
885825eb42bSJan Lentfer *port = 0;
886825eb42bSJan Lentfer }
887825eb42bSJan Lentfer return NULL;
888825eb42bSJan Lentfer }
889825eb42bSJan Lentfer return addr;
890825eb42bSJan Lentfer }
891d1b2b5caSJohn Marino #endif
892825eb42bSJan Lentfer
893825eb42bSJan Lentfer /* code from resolver.c */
894825eb42bSJan Lentfer ldns_status
8955340022aSzrj ldns_axfr_start(ldns_resolver *resolver, const ldns_rdf *domain, ldns_rr_class class)
896825eb42bSJan Lentfer {
897825eb42bSJan Lentfer ldns_pkt *query;
898825eb42bSJan Lentfer ldns_buffer *query_wire;
899825eb42bSJan Lentfer
9005340022aSzrj struct sockaddr_storage *src = NULL;
9015340022aSzrj size_t src_len = 0;
902825eb42bSJan Lentfer struct sockaddr_storage *ns = NULL;
903825eb42bSJan Lentfer size_t ns_len = 0;
904825eb42bSJan Lentfer size_t ns_i;
905825eb42bSJan Lentfer ldns_status status;
906825eb42bSJan Lentfer
907825eb42bSJan Lentfer if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) {
908825eb42bSJan Lentfer return LDNS_STATUS_ERR;
909825eb42bSJan Lentfer }
910825eb42bSJan Lentfer
911825eb42bSJan Lentfer query = ldns_pkt_query_new(ldns_rdf_clone(domain), LDNS_RR_TYPE_AXFR, class, 0);
912825eb42bSJan Lentfer
913825eb42bSJan Lentfer if (!query) {
914825eb42bSJan Lentfer return LDNS_STATUS_ADDRESS_ERR;
915825eb42bSJan Lentfer }
9165340022aSzrj if(ldns_resolver_source(resolver)) {
9175340022aSzrj src = ldns_rdf2native_sockaddr_storage_port(
9185340022aSzrj ldns_resolver_source(resolver), 0, &src_len);
9195340022aSzrj }
920825eb42bSJan Lentfer /* For AXFR, we have to make the connection ourselves */
921825eb42bSJan Lentfer /* try all nameservers (which usually would mean v4 fallback if
922825eb42bSJan Lentfer * @hostname is used */
923825eb42bSJan Lentfer for (ns_i = 0;
924825eb42bSJan Lentfer ns_i < ldns_resolver_nameserver_count(resolver) &&
9255340022aSzrj resolver->_socket == SOCK_INVALID;
926825eb42bSJan Lentfer ns_i++) {
927d1b2b5caSJohn Marino if (ns != NULL) {
928d1b2b5caSJohn Marino LDNS_FREE(ns);
929d1b2b5caSJohn Marino }
930825eb42bSJan Lentfer ns = ldns_rdf2native_sockaddr_storage(
931825eb42bSJan Lentfer resolver->_nameservers[ns_i],
932825eb42bSJan Lentfer ldns_resolver_port(resolver), &ns_len);
9335340022aSzrj #ifndef S_SPLINT_S
9345340022aSzrj if ((ns->ss_family == AF_INET) &&
9355340022aSzrj (ldns_resolver_ip6(resolver) == LDNS_RESOLV_INET6)) {
9365340022aSzrj /* not reachable */
9375340022aSzrj LDNS_FREE(ns);
9385340022aSzrj ns = NULL;
9395340022aSzrj continue;
9405340022aSzrj }
941825eb42bSJan Lentfer
9425340022aSzrj if ((ns->ss_family == AF_INET6) &&
9435340022aSzrj (ldns_resolver_ip6(resolver) == LDNS_RESOLV_INET)) {
9445340022aSzrj /* not reachable */
9455340022aSzrj LDNS_FREE(ns);
9465340022aSzrj ns = NULL;
9475340022aSzrj continue;
9485340022aSzrj }
9495340022aSzrj #endif
9505340022aSzrj
9515340022aSzrj resolver->_socket = ldns_tcp_connect_from(
9525340022aSzrj ns, (socklen_t)ns_len,
9535340022aSzrj src, (socklen_t)src_len,
954825eb42bSJan Lentfer ldns_resolver_timeout(resolver));
955825eb42bSJan Lentfer }
956819dec71SDaniel Fojt if (src) {
957819dec71SDaniel Fojt LDNS_FREE(src);
958819dec71SDaniel Fojt }
959825eb42bSJan Lentfer
9605340022aSzrj if (resolver->_socket == SOCK_INVALID) {
961825eb42bSJan Lentfer ldns_pkt_free(query);
962825eb42bSJan Lentfer LDNS_FREE(ns);
963825eb42bSJan Lentfer return LDNS_STATUS_NETWORK_ERR;
964825eb42bSJan Lentfer }
965825eb42bSJan Lentfer
966825eb42bSJan Lentfer #ifdef HAVE_SSL
967825eb42bSJan Lentfer if (ldns_resolver_tsig_keyname(resolver) && ldns_resolver_tsig_keydata(resolver)) {
968825eb42bSJan Lentfer status = ldns_pkt_tsig_sign(query,
969825eb42bSJan Lentfer ldns_resolver_tsig_keyname(resolver),
970825eb42bSJan Lentfer ldns_resolver_tsig_keydata(resolver),
971825eb42bSJan Lentfer 300, ldns_resolver_tsig_algorithm(resolver), NULL);
972825eb42bSJan Lentfer if (status != LDNS_STATUS_OK) {
9735340022aSzrj /* to prevent problems on subsequent calls to
9745340022aSzrj * ldns_axfr_start we have to close the socket here! */
9755340022aSzrj close_socket(resolver->_socket);
976ac996e71SJan Lentfer resolver->_socket = 0;
977ac996e71SJan Lentfer
978d1b2b5caSJohn Marino ldns_pkt_free(query);
979d1b2b5caSJohn Marino LDNS_FREE(ns);
980d1b2b5caSJohn Marino
981825eb42bSJan Lentfer return LDNS_STATUS_CRYPTO_TSIG_ERR;
982825eb42bSJan Lentfer }
983825eb42bSJan Lentfer }
984825eb42bSJan Lentfer #endif /* HAVE_SSL */
985825eb42bSJan Lentfer
986ac996e71SJan Lentfer /* Convert the query to a buffer
987ac996e71SJan Lentfer * Is this necessary?
988825eb42bSJan Lentfer */
989825eb42bSJan Lentfer query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN);
990fd185f4dSJan Lentfer if(!query_wire) {
991fd185f4dSJan Lentfer ldns_pkt_free(query);
992fd185f4dSJan Lentfer LDNS_FREE(ns);
9935340022aSzrj
9945340022aSzrj close_socket(resolver->_socket);
995fd185f4dSJan Lentfer
996fd185f4dSJan Lentfer return LDNS_STATUS_MEM_ERR;
997fd185f4dSJan Lentfer }
998825eb42bSJan Lentfer status = ldns_pkt2buffer_wire(query_wire, query);
999825eb42bSJan Lentfer if (status != LDNS_STATUS_OK) {
1000825eb42bSJan Lentfer ldns_pkt_free(query);
1001ac996e71SJan Lentfer ldns_buffer_free(query_wire);
1002825eb42bSJan Lentfer LDNS_FREE(ns);
1003ac996e71SJan Lentfer
10045340022aSzrj /* to prevent problems on subsequent calls to ldns_axfr_start
10055340022aSzrj * we have to close the socket here! */
10065340022aSzrj close_socket(resolver->_socket);
1007ac996e71SJan Lentfer resolver->_socket = 0;
1008ac996e71SJan Lentfer
1009825eb42bSJan Lentfer return status;
1010825eb42bSJan Lentfer }
1011825eb42bSJan Lentfer /* Send the query */
1012825eb42bSJan Lentfer if (ldns_tcp_send_query(query_wire, resolver->_socket, ns,
1013825eb42bSJan Lentfer (socklen_t)ns_len) == 0) {
1014825eb42bSJan Lentfer ldns_pkt_free(query);
1015825eb42bSJan Lentfer ldns_buffer_free(query_wire);
1016825eb42bSJan Lentfer LDNS_FREE(ns);
1017ac996e71SJan Lentfer
10185340022aSzrj /* to prevent problems on subsequent calls to ldns_axfr_start
10195340022aSzrj * we have to close the socket here! */
1020ac996e71SJan Lentfer
10215340022aSzrj
10225340022aSzrj close_socket(resolver->_socket);
1023ac996e71SJan Lentfer
1024825eb42bSJan Lentfer return LDNS_STATUS_NETWORK_ERR;
1025825eb42bSJan Lentfer }
1026825eb42bSJan Lentfer
1027825eb42bSJan Lentfer ldns_pkt_free(query);
1028825eb42bSJan Lentfer ldns_buffer_free(query_wire);
1029825eb42bSJan Lentfer LDNS_FREE(ns);
1030825eb42bSJan Lentfer
1031825eb42bSJan Lentfer /*
1032825eb42bSJan Lentfer * The AXFR is done once the second SOA record is sent
1033825eb42bSJan Lentfer */
1034825eb42bSJan Lentfer resolver->_axfr_soa_count = 0;
1035825eb42bSJan Lentfer return LDNS_STATUS_OK;
1036825eb42bSJan Lentfer }
1037