1 /* MIT License
2 *
3 * Copyright (c) Massachusetts Institute of Technology
4 * Copyright (c) The c-ares project and its contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * SPDX-License-Identifier: MIT
26 */
27 #include "ares_setup.h"
28
29 #ifdef HAVE_SYS_UIO_H
30 # include <sys/uio.h>
31 #endif
32 #ifdef HAVE_NETINET_IN_H
33 # include <netinet/in.h>
34 #endif
35 #ifdef HAVE_NETINET_TCP_H
36 # include <netinet/tcp.h>
37 #endif
38 #ifdef HAVE_NETDB_H
39 # include <netdb.h>
40 #endif
41 #ifdef HAVE_ARPA_INET_H
42 # include <arpa/inet.h>
43 #endif
44
45 #ifdef HAVE_STRINGS_H
46 # include <strings.h>
47 #endif
48 #ifdef HAVE_SYS_IOCTL_H
49 # include <sys/ioctl.h>
50 #endif
51 #ifdef NETWARE
52 # include <sys/filio.h>
53 #endif
54
55 #include <assert.h>
56 #include <fcntl.h>
57 #include <limits.h>
58
59 #include "ares.h"
60 #include "ares_private.h"
61
ares__socket_recvfrom(ares_channel_t * channel,ares_socket_t s,void * data,size_t data_len,int flags,struct sockaddr * from,ares_socklen_t * from_len)62 ares_ssize_t ares__socket_recvfrom(ares_channel_t *channel, ares_socket_t s,
63 void *data, size_t data_len, int flags,
64 struct sockaddr *from,
65 ares_socklen_t *from_len)
66 {
67 if (channel->sock_funcs && channel->sock_funcs->arecvfrom) {
68 return channel->sock_funcs->arecvfrom(s, data, data_len, flags, from,
69 from_len, channel->sock_func_cb_data);
70 }
71
72 #ifdef HAVE_RECVFROM
73 return (ares_ssize_t)recvfrom(s, data, (RECVFROM_TYPE_ARG3)data_len, flags,
74 from, from_len);
75 #else
76 return sread(s, data, data_len);
77 #endif
78 }
79
ares__socket_recv(ares_channel_t * channel,ares_socket_t s,void * data,size_t data_len)80 ares_ssize_t ares__socket_recv(ares_channel_t *channel, ares_socket_t s,
81 void *data, size_t data_len)
82 {
83 if (channel->sock_funcs && channel->sock_funcs->arecvfrom) {
84 return channel->sock_funcs->arecvfrom(s, data, data_len, 0, 0, 0,
85 channel->sock_func_cb_data);
86 }
87
88 /* sread() is a wrapper for read() or recv() depending on the system */
89 return sread(s, data, data_len);
90 }
91
92 /*
93 * setsocknonblock sets the given socket to either blocking or non-blocking
94 * mode based on the 'nonblock' boolean argument. This function is highly
95 * portable.
96 */
setsocknonblock(ares_socket_t sockfd,int nonblock)97 static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
98 int nonblock /* TRUE or FALSE */)
99 {
100 #if defined(USE_BLOCKING_SOCKETS)
101
102 return 0; /* returns success */
103
104 #elif defined(HAVE_FCNTL_O_NONBLOCK)
105
106 /* most recent unix versions */
107 int flags;
108 flags = fcntl(sockfd, F_GETFL, 0);
109 if (nonblock) {
110 return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
111 } else {
112 return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); /* LCOV_EXCL_LINE */
113 }
114
115 #elif defined(HAVE_IOCTL_FIONBIO)
116
117 /* older unix versions */
118 int flags = nonblock ? 1 : 0;
119 return ioctl(sockfd, FIONBIO, &flags);
120
121 #elif defined(HAVE_IOCTLSOCKET_FIONBIO)
122
123 # ifdef WATT32
124 char flags = nonblock ? 1 : 0;
125 # else
126 /* Windows */
127 unsigned long flags = nonblock ? 1UL : 0UL;
128 # endif
129 return ioctlsocket(sockfd, (long)FIONBIO, &flags);
130
131 #elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
132
133 /* Amiga */
134 long flags = nonblock ? 1L : 0L;
135 return IoctlSocket(sockfd, FIONBIO, flags);
136
137 #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
138
139 /* BeOS */
140 long b = nonblock ? 1L : 0L;
141 return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
142
143 #else
144 # error "no non-blocking method was found/used/set"
145 #endif
146 }
147
148 #if defined(IPV6_V6ONLY) && defined(WIN32)
149 /* It makes support for IPv4-mapped IPv6 addresses.
150 * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
151 * Windows Vista and later: default is on;
152 * DragonFly BSD: acts like off, and dummy setting;
153 * OpenBSD and earlier Windows: unsupported.
154 * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
155 */
set_ipv6_v6only(ares_socket_t sockfd,int on)156 static void set_ipv6_v6only(ares_socket_t sockfd, int on)
157 {
158 (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
159 }
160 #else
161 # define set_ipv6_v6only(s, v)
162 #endif
163
configure_socket(ares_socket_t s,struct server_state * server)164 static int configure_socket(ares_socket_t s, struct server_state *server)
165 {
166 union {
167 struct sockaddr sa;
168 struct sockaddr_in sa4;
169 struct sockaddr_in6 sa6;
170 } local;
171
172 ares_socklen_t bindlen = 0;
173 ares_channel_t *channel = server->channel;
174
175 /* do not set options for user-managed sockets */
176 if (channel->sock_funcs && channel->sock_funcs->asocket) {
177 return 0;
178 }
179
180 (void)setsocknonblock(s, 1);
181
182 #if defined(FD_CLOEXEC) && !defined(MSDOS)
183 /* Configure the socket fd as close-on-exec. */
184 if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
185 return -1; /* LCOV_EXCL_LINE */
186 }
187 #endif
188
189 /* Set the socket's send and receive buffer sizes. */
190 if ((channel->socket_send_buffer_size > 0) &&
191 setsockopt(s, SOL_SOCKET, SO_SNDBUF,
192 (void *)&channel->socket_send_buffer_size,
193 sizeof(channel->socket_send_buffer_size)) == -1) {
194 return -1;
195 }
196
197 if ((channel->socket_receive_buffer_size > 0) &&
198 setsockopt(s, SOL_SOCKET, SO_RCVBUF,
199 (void *)&channel->socket_receive_buffer_size,
200 sizeof(channel->socket_receive_buffer_size)) == -1) {
201 return -1;
202 }
203
204 #ifdef SO_BINDTODEVICE
205 if (channel->local_dev_name[0] &&
206 setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, channel->local_dev_name,
207 sizeof(channel->local_dev_name))) {
208 /* Only root can do this, and usually not fatal if it doesn't work, so */
209 /* just continue on. */
210 }
211 #endif
212
213 if (server->addr.family == AF_INET && channel->local_ip4) {
214 memset(&local.sa4, 0, sizeof(local.sa4));
215 local.sa4.sin_family = AF_INET;
216 local.sa4.sin_addr.s_addr = htonl(channel->local_ip4);
217 bindlen = sizeof(local.sa4);
218 } else if (server->addr.family == AF_INET6 && server->ll_scope == 0 &&
219 memcmp(channel->local_ip6, ares_in6addr_any._S6_un._S6_u8,
220 sizeof(channel->local_ip6)) != 0) {
221 /* Only if not link-local and an ip other than "::" is specified */
222 memset(&local.sa6, 0, sizeof(local.sa6));
223 local.sa6.sin6_family = AF_INET6;
224 memcpy(&local.sa6.sin6_addr, channel->local_ip6,
225 sizeof(channel->local_ip6));
226 bindlen = sizeof(local.sa6);
227 }
228
229 if (bindlen && bind(s, &local.sa, bindlen) < 0) {
230 return -1;
231 }
232
233 if (server->addr.family == AF_INET6) {
234 set_ipv6_v6only(s, 0);
235 }
236
237 return 0;
238 }
239
ares__open_connection(ares_channel_t * channel,struct server_state * server,ares_bool_t is_tcp)240 ares_status_t ares__open_connection(ares_channel_t *channel,
241 struct server_state *server,
242 ares_bool_t is_tcp)
243 {
244 ares_socket_t s;
245 int opt;
246 ares_socklen_t salen;
247
248 union {
249 struct sockaddr_in sa4;
250 struct sockaddr_in6 sa6;
251 } saddr;
252 struct sockaddr *sa;
253 struct server_connection *conn;
254 ares__llist_node_t *node;
255 int type = is_tcp ? SOCK_STREAM : SOCK_DGRAM;
256 #ifdef __OpenBSD__
257 if ((is_tcp && server->tcp_port == 53) ||
258 (!is_tcp && server->udp_port == 53)) {
259 type |= SOCK_DNS;
260 }
261 #endif
262
263 switch (server->addr.family) {
264 case AF_INET:
265 sa = (void *)&saddr.sa4;
266 salen = sizeof(saddr.sa4);
267 memset(sa, 0, (size_t)salen);
268 saddr.sa4.sin_family = AF_INET;
269 saddr.sa4.sin_port = htons(is_tcp ? server->tcp_port : server->udp_port);
270 memcpy(&saddr.sa4.sin_addr, &server->addr.addr.addr4,
271 sizeof(saddr.sa4.sin_addr));
272 break;
273 case AF_INET6:
274 sa = (void *)&saddr.sa6;
275 salen = sizeof(saddr.sa6);
276 memset(sa, 0, (size_t)salen);
277 saddr.sa6.sin6_family = AF_INET6;
278 saddr.sa6.sin6_port = htons(is_tcp ? server->tcp_port : server->udp_port);
279 memcpy(&saddr.sa6.sin6_addr, &server->addr.addr.addr6,
280 sizeof(saddr.sa6.sin6_addr));
281 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
282 saddr.sa6.sin6_scope_id = server->ll_scope;
283 #endif
284 break;
285 default:
286 return ARES_EBADFAMILY; /* LCOV_EXCL_LINE */
287 }
288
289 /* Acquire a socket. */
290 s = ares__open_socket(channel, server->addr.family, type, 0);
291 if (s == ARES_SOCKET_BAD) {
292 return ARES_ECONNREFUSED;
293 }
294
295 /* Configure it. */
296 if (configure_socket(s, server) < 0) {
297 ares__close_socket(channel, s);
298 return ARES_ECONNREFUSED;
299 }
300
301 #ifdef TCP_NODELAY
302 if (is_tcp) {
303 /*
304 * Disable the Nagle algorithm (only relevant for TCP sockets, and thus not
305 * in configure_socket). In general, in DNS lookups we're pretty much
306 * interested in firing off a single request and then waiting for a reply,
307 * so batching isn't very interesting.
308 */
309 opt = 1;
310 if ((!channel->sock_funcs || !channel->sock_funcs->asocket) &&
311 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) ==
312 -1) {
313 ares__close_socket(channel, s);
314 return ARES_ECONNREFUSED;
315 }
316 }
317 #endif
318
319 if (channel->sock_config_cb) {
320 int err = channel->sock_config_cb(s, type, channel->sock_config_cb_data);
321 if (err < 0) {
322 ares__close_socket(channel, s);
323 return ARES_ECONNREFUSED;
324 }
325 }
326
327 /* Connect to the server. */
328 if (ares__connect_socket(channel, s, sa, salen) == -1) {
329 int err = SOCKERRNO;
330
331 if (err != EINPROGRESS && err != EWOULDBLOCK) {
332 ares__close_socket(channel, s);
333 return ARES_ECONNREFUSED;
334 }
335 }
336
337 if (channel->sock_create_cb) {
338 int err = channel->sock_create_cb(s, type, channel->sock_create_cb_data);
339 if (err < 0) {
340 ares__close_socket(channel, s);
341 return ARES_ECONNREFUSED;
342 }
343 }
344
345 conn = ares_malloc(sizeof(*conn));
346 if (conn == NULL) {
347 ares__close_socket(channel, s);
348 return ARES_ENOMEM;
349 }
350 memset(conn, 0, sizeof(*conn));
351 conn->fd = s;
352 conn->server = server;
353 conn->queries_to_conn = ares__llist_create(NULL);
354 conn->is_tcp = is_tcp;
355 if (conn->queries_to_conn == NULL) {
356 ares__close_socket(channel, s);
357 ares_free(conn);
358 return ARES_ENOMEM;
359 }
360
361 /* TCP connections are thrown to the end as we don't spawn multiple TCP
362 * connections. UDP connections are put on front where the newest connection
363 * can be quickly pulled */
364 if (is_tcp) {
365 node = ares__llist_insert_last(server->connections, conn);
366 } else {
367 node = ares__llist_insert_first(server->connections, conn);
368 }
369 if (node == NULL) {
370 ares__close_socket(channel, s);
371 ares__llist_destroy(conn->queries_to_conn);
372 ares_free(conn);
373 return ARES_ENOMEM;
374 }
375
376 /* Register globally to quickly map event on file descriptor to connection
377 * node object */
378 if (!ares__htable_asvp_insert(channel->connnode_by_socket, s, node)) {
379 ares__close_socket(channel, s);
380 ares__llist_destroy(conn->queries_to_conn);
381 ares__llist_node_claim(node);
382 ares_free(conn);
383 return ARES_ENOMEM;
384 }
385
386 SOCK_STATE_CALLBACK(channel, s, 1, 0);
387
388 if (is_tcp) {
389 server->tcp_conn = conn;
390 }
391
392 return ARES_SUCCESS;
393 }
394
ares__open_socket(ares_channel_t * channel,int af,int type,int protocol)395 ares_socket_t ares__open_socket(ares_channel_t *channel, int af, int type,
396 int protocol)
397 {
398 if (channel->sock_funcs && channel->sock_funcs->asocket) {
399 return channel->sock_funcs->asocket(af, type, protocol,
400 channel->sock_func_cb_data);
401 }
402
403 return socket(af, type, protocol);
404 }
405
ares__connect_socket(ares_channel_t * channel,ares_socket_t sockfd,const struct sockaddr * addr,ares_socklen_t addrlen)406 int ares__connect_socket(ares_channel_t *channel, ares_socket_t sockfd,
407 const struct sockaddr *addr, ares_socklen_t addrlen)
408 {
409 if (channel->sock_funcs && channel->sock_funcs->aconnect) {
410 return channel->sock_funcs->aconnect(sockfd, addr, addrlen,
411 channel->sock_func_cb_data);
412 }
413
414 return connect(sockfd, addr, addrlen);
415 }
416
ares__close_socket(ares_channel_t * channel,ares_socket_t s)417 void ares__close_socket(ares_channel_t *channel, ares_socket_t s)
418 {
419 if (s == ARES_SOCKET_BAD) {
420 return;
421 }
422
423 if (channel->sock_funcs && channel->sock_funcs->aclose) {
424 channel->sock_funcs->aclose(s, channel->sock_func_cb_data);
425 } else {
426 sclose(s);
427 }
428 }
429
430 #ifndef HAVE_WRITEV
431 /* Structure for scatter/gather I/O. */
432 struct iovec {
433 void *iov_base; /* Pointer to data. */
434 size_t iov_len; /* Length of data. */
435 };
436 #endif
437
ares__socket_write(ares_channel_t * channel,ares_socket_t s,const void * data,size_t len)438 ares_ssize_t ares__socket_write(ares_channel_t *channel, ares_socket_t s,
439 const void *data, size_t len)
440 {
441 if (channel->sock_funcs && channel->sock_funcs->asendv) {
442 struct iovec vec;
443 vec.iov_base = (void *)((size_t)data); /* Cast off const */
444 vec.iov_len = len;
445 return channel->sock_funcs->asendv(s, &vec, 1, channel->sock_func_cb_data);
446 }
447 return swrite(s, data, len);
448 }
449
ares_set_socket_callback(ares_channel_t * channel,ares_sock_create_callback cb,void * data)450 void ares_set_socket_callback(ares_channel_t *channel,
451 ares_sock_create_callback cb, void *data)
452 {
453 if (channel == NULL) {
454 return;
455 }
456 channel->sock_create_cb = cb;
457 channel->sock_create_cb_data = data;
458 }
459
ares_set_socket_configure_callback(ares_channel_t * channel,ares_sock_config_callback cb,void * data)460 void ares_set_socket_configure_callback(ares_channel_t *channel,
461 ares_sock_config_callback cb,
462 void *data)
463 {
464 if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
465 return;
466 }
467 channel->sock_config_cb = cb;
468 channel->sock_config_cb_data = data;
469 }
470
ares_set_socket_functions(ares_channel_t * channel,const struct ares_socket_functions * funcs,void * data)471 void ares_set_socket_functions(ares_channel_t *channel,
472 const struct ares_socket_functions *funcs,
473 void *data)
474 {
475 if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
476 return;
477 }
478 channel->sock_funcs = funcs;
479 channel->sock_func_cb_data = data;
480 }
481