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