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_private.h"
28 #ifdef HAVE_SYS_UIO_H
29 # include <sys/uio.h>
30 #endif
31 #ifdef HAVE_NETINET_IN_H
32 # include <netinet/in.h>
33 #endif
34 #ifdef HAVE_NETINET_TCP_H
35 # include <netinet/tcp.h>
36 #endif
37 #ifdef HAVE_NETDB_H
38 # include <netdb.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 # include <arpa/inet.h>
42 #endif
43
44 #ifdef HAVE_STRINGS_H
45 # include <strings.h>
46 #endif
47 #ifdef HAVE_SYS_IOCTL_H
48 # include <sys/ioctl.h>
49 #endif
50 #ifdef NETWARE
51 # include <sys/filio.h>
52 #endif
53
54 #include <assert.h>
55 #include <fcntl.h>
56 #include <limits.h>
57
ares_socket_deref_error(int err)58 static ares_conn_err_t ares_socket_deref_error(int err)
59 {
60 switch (err) {
61 #if defined(EWOULDBLOCK)
62 case EWOULDBLOCK:
63 return ARES_CONN_ERR_WOULDBLOCK;
64 #endif
65 #if defined(EAGAIN) && (!defined(EWOULDBLOCK) || EAGAIN != EWOULDBLOCK)
66 case EAGAIN:
67 return ARES_CONN_ERR_WOULDBLOCK;
68 #endif
69 case EINPROGRESS:
70 return ARES_CONN_ERR_WOULDBLOCK;
71 case ENETDOWN:
72 return ARES_CONN_ERR_NETDOWN;
73 case ENETUNREACH:
74 return ARES_CONN_ERR_NETUNREACH;
75 case ECONNABORTED:
76 return ARES_CONN_ERR_CONNABORTED;
77 case ECONNRESET:
78 return ARES_CONN_ERR_CONNRESET;
79 case ECONNREFUSED:
80 return ARES_CONN_ERR_CONNREFUSED;
81 case ETIMEDOUT:
82 return ARES_CONN_ERR_CONNTIMEDOUT;
83 case EHOSTDOWN:
84 return ARES_CONN_ERR_HOSTDOWN;
85 case EHOSTUNREACH:
86 return ARES_CONN_ERR_HOSTUNREACH;
87 case EINTR:
88 return ARES_CONN_ERR_INTERRUPT;
89 case EAFNOSUPPORT:
90 return ARES_CONN_ERR_AFNOSUPPORT;
91 case EADDRNOTAVAIL:
92 return ARES_CONN_ERR_BADADDR;
93 default:
94 break;
95 }
96
97 return ARES_CONN_ERR_FAILURE;
98 }
99
ares_sockaddr_addr_eq(const struct sockaddr * sa,const struct ares_addr * aa)100 ares_bool_t ares_sockaddr_addr_eq(const struct sockaddr *sa,
101 const struct ares_addr *aa)
102 {
103 const void *addr1;
104 const void *addr2;
105
106 if (sa->sa_family == aa->family) {
107 switch (aa->family) {
108 case AF_INET:
109 addr1 = &aa->addr.addr4;
110 addr2 = &(CARES_INADDR_CAST(const struct sockaddr_in *, sa))->sin_addr;
111 if (memcmp(addr1, addr2, sizeof(aa->addr.addr4)) == 0) {
112 return ARES_TRUE; /* match */
113 }
114 break;
115 case AF_INET6:
116 addr1 = &aa->addr.addr6;
117 addr2 =
118 &(CARES_INADDR_CAST(const struct sockaddr_in6 *, sa))->sin6_addr;
119 if (memcmp(addr1, addr2, sizeof(aa->addr.addr6)) == 0) {
120 return ARES_TRUE; /* match */
121 }
122 break;
123 default:
124 break; /* LCOV_EXCL_LINE */
125 }
126 }
127 return ARES_FALSE; /* different */
128 }
129
ares_socket_write(ares_channel_t * channel,ares_socket_t fd,const void * data,size_t len,size_t * written,const struct sockaddr * sa,ares_socklen_t salen)130 ares_conn_err_t ares_socket_write(ares_channel_t *channel, ares_socket_t fd,
131 const void *data, size_t len, size_t *written,
132 const struct sockaddr *sa,
133 ares_socklen_t salen)
134 {
135 int flags = 0;
136 ares_ssize_t rv;
137 ares_conn_err_t err = ARES_CONN_ERR_SUCCESS;
138
139 #ifdef HAVE_MSG_NOSIGNAL
140 flags |= MSG_NOSIGNAL;
141 #endif
142
143 rv = channel->sock_funcs.asendto(fd, data, len, flags, sa, salen,
144 channel->sock_func_cb_data);
145 if (rv <= 0) {
146 err = ares_socket_deref_error(SOCKERRNO);
147 } else {
148 *written = (size_t)rv;
149 }
150 return err;
151 }
152
ares_socket_recv(ares_channel_t * channel,ares_socket_t s,ares_bool_t is_tcp,void * data,size_t data_len,size_t * read_bytes)153 ares_conn_err_t ares_socket_recv(ares_channel_t *channel, ares_socket_t s,
154 ares_bool_t is_tcp, void *data,
155 size_t data_len, size_t *read_bytes)
156 {
157 ares_ssize_t rv;
158
159 *read_bytes = 0;
160
161 rv = channel->sock_funcs.arecvfrom(s, data, data_len, 0, NULL, 0,
162 channel->sock_func_cb_data);
163
164 if (rv > 0) {
165 *read_bytes = (size_t)rv;
166 return ARES_CONN_ERR_SUCCESS;
167 }
168
169 if (rv == 0) {
170 /* UDP allows 0-byte packets and is connectionless, so this is success */
171 if (!is_tcp) {
172 return ARES_CONN_ERR_SUCCESS;
173 } else {
174 return ARES_CONN_ERR_CONNCLOSED;
175 }
176 }
177
178 /* If we're here, rv<0 */
179 return ares_socket_deref_error(SOCKERRNO);
180 }
181
ares_socket_recvfrom(ares_channel_t * channel,ares_socket_t s,ares_bool_t is_tcp,void * data,size_t data_len,int flags,struct sockaddr * from,ares_socklen_t * from_len,size_t * read_bytes)182 ares_conn_err_t ares_socket_recvfrom(ares_channel_t *channel, ares_socket_t s,
183 ares_bool_t is_tcp, void *data,
184 size_t data_len, int flags,
185 struct sockaddr *from,
186 ares_socklen_t *from_len,
187 size_t *read_bytes)
188 {
189 ares_ssize_t rv;
190
191 rv = channel->sock_funcs.arecvfrom(s, data, data_len, flags, from, from_len,
192 channel->sock_func_cb_data);
193
194 if (rv > 0) {
195 *read_bytes = (size_t)rv;
196 return ARES_CONN_ERR_SUCCESS;
197 }
198
199 if (rv == 0) {
200 /* UDP allows 0-byte packets and is connectionless, so this is success */
201 if (!is_tcp) {
202 return ARES_CONN_ERR_SUCCESS;
203 } else {
204 return ARES_CONN_ERR_CONNCLOSED;
205 }
206 }
207
208 /* If we're here, rv<0 */
209 return ares_socket_deref_error(SOCKERRNO);
210 }
211
ares_socket_enable_tfo(const ares_channel_t * channel,ares_socket_t fd)212 ares_conn_err_t ares_socket_enable_tfo(const ares_channel_t *channel,
213 ares_socket_t fd)
214 {
215 ares_bool_t opt = ARES_TRUE;
216
217 if (channel->sock_funcs.asetsockopt(fd, ARES_SOCKET_OPT_TCP_FASTOPEN,
218 (void *)&opt, sizeof(opt),
219 channel->sock_func_cb_data) != 0) {
220 return ARES_CONN_ERR_NOTIMP;
221 }
222
223 return ARES_CONN_ERR_SUCCESS;
224 }
225
ares_socket_configure(ares_channel_t * channel,int family,ares_bool_t is_tcp,ares_socket_t fd)226 ares_status_t ares_socket_configure(ares_channel_t *channel, int family,
227 ares_bool_t is_tcp, ares_socket_t fd)
228 {
229 union {
230 struct sockaddr sa;
231 struct sockaddr_in sa4;
232 struct sockaddr_in6 sa6;
233 } local;
234
235 ares_socklen_t bindlen = 0;
236 int rv;
237 unsigned int bind_flags = 0;
238
239 /* Set the socket's send and receive buffer sizes. */
240 if (channel->socket_send_buffer_size > 0) {
241 rv = channel->sock_funcs.asetsockopt(
242 fd, ARES_SOCKET_OPT_SENDBUF_SIZE,
243 (void *)&channel->socket_send_buffer_size,
244 sizeof(channel->socket_send_buffer_size), channel->sock_func_cb_data);
245 if (rv != 0 && SOCKERRNO != ENOSYS) {
246 return ARES_ECONNREFUSED; /* LCOV_EXCL_LINE: UntestablePath */
247 }
248 }
249
250 if (channel->socket_receive_buffer_size > 0) {
251 rv = channel->sock_funcs.asetsockopt(
252 fd, ARES_SOCKET_OPT_RECVBUF_SIZE,
253 (void *)&channel->socket_receive_buffer_size,
254 sizeof(channel->socket_receive_buffer_size), channel->sock_func_cb_data);
255 if (rv != 0 && SOCKERRNO != ENOSYS) {
256 return ARES_ECONNREFUSED; /* LCOV_EXCL_LINE: UntestablePath */
257 }
258 }
259
260 /* Bind to network interface if configured */
261 if (ares_strlen(channel->local_dev_name)) {
262 /* Prior versions silently ignored failure, so we need to maintain that
263 * compatibility */
264 (void)channel->sock_funcs.asetsockopt(
265 fd, ARES_SOCKET_OPT_BIND_DEVICE, channel->local_dev_name,
266 (ares_socklen_t)ares_strlen(channel->local_dev_name),
267 channel->sock_func_cb_data);
268 }
269
270 /* Bind to ip address if configured */
271 if (family == AF_INET && channel->local_ip4) {
272 memset(&local.sa4, 0, sizeof(local.sa4));
273 local.sa4.sin_family = AF_INET;
274 local.sa4.sin_addr.s_addr = htonl(channel->local_ip4);
275 bindlen = sizeof(local.sa4);
276 } else if (family == AF_INET6 &&
277 memcmp(channel->local_ip6, ares_in6addr_any._S6_un._S6_u8,
278 sizeof(channel->local_ip6)) != 0) {
279 /* Only if not link-local and an ip other than "::" is specified */
280 memset(&local.sa6, 0, sizeof(local.sa6));
281 local.sa6.sin6_family = AF_INET6;
282 memcpy(&local.sa6.sin6_addr, channel->local_ip6,
283 sizeof(channel->local_ip6));
284 bindlen = sizeof(local.sa6);
285 }
286
287
288 if (bindlen && channel->sock_funcs.abind != NULL) {
289 bind_flags |= ARES_SOCKET_BIND_CLIENT;
290 if (is_tcp) {
291 bind_flags |= ARES_SOCKET_BIND_TCP;
292 }
293 if (channel->sock_funcs.abind(fd, bind_flags, &local.sa, bindlen,
294 channel->sock_func_cb_data) != 0) {
295 return ARES_ECONNREFUSED;
296 }
297 }
298
299 return ARES_SUCCESS;
300 }
301
ares_sockaddr_to_ares_addr(struct ares_addr * ares_addr,unsigned short * port,const struct sockaddr * sockaddr)302 ares_bool_t ares_sockaddr_to_ares_addr(struct ares_addr *ares_addr,
303 unsigned short *port,
304 const struct sockaddr *sockaddr)
305 {
306 if (sockaddr->sa_family == AF_INET) {
307 /* NOTE: memcpy sockaddr_in due to alignment issues found by UBSAN due to
308 * dnsinfo packing on MacOS */
309 struct sockaddr_in sockaddr_in;
310 memcpy(&sockaddr_in, sockaddr, sizeof(sockaddr_in));
311
312 ares_addr->family = AF_INET;
313 memcpy(&ares_addr->addr.addr4, &(sockaddr_in.sin_addr),
314 sizeof(ares_addr->addr.addr4));
315
316 if (port) {
317 *port = ntohs(sockaddr_in.sin_port);
318 }
319 return ARES_TRUE;
320 }
321
322 if (sockaddr->sa_family == AF_INET6) {
323 /* NOTE: memcpy sockaddr_in6 due to alignment issues found by UBSAN due to
324 * dnsinfo packing on MacOS */
325 struct sockaddr_in6 sockaddr_in6;
326 memcpy(&sockaddr_in6, sockaddr, sizeof(sockaddr_in6));
327
328 ares_addr->family = AF_INET6;
329 memcpy(&ares_addr->addr.addr6, &(sockaddr_in6.sin6_addr),
330 sizeof(ares_addr->addr.addr6));
331 if (port) {
332 *port = ntohs(sockaddr_in6.sin6_port);
333 }
334 return ARES_TRUE;
335 }
336
337 return ARES_FALSE;
338 }
339
ares_socket_open(ares_socket_t * sock,ares_channel_t * channel,int af,int type,int protocol)340 ares_conn_err_t ares_socket_open(ares_socket_t *sock, ares_channel_t *channel,
341 int af, int type, int protocol)
342 {
343 ares_socket_t s;
344
345 *sock = ARES_SOCKET_BAD;
346
347 s =
348 channel->sock_funcs.asocket(af, type, protocol, channel->sock_func_cb_data);
349
350 if (s == ARES_SOCKET_BAD) {
351 return ares_socket_deref_error(SOCKERRNO);
352 }
353
354 *sock = s;
355
356 return ARES_CONN_ERR_SUCCESS;
357 }
358
ares_socket_connect(ares_channel_t * channel,ares_socket_t sockfd,ares_bool_t is_tfo,const struct sockaddr * addr,ares_socklen_t addrlen)359 ares_conn_err_t ares_socket_connect(ares_channel_t *channel,
360 ares_socket_t sockfd, ares_bool_t is_tfo,
361 const struct sockaddr *addr,
362 ares_socklen_t addrlen)
363 {
364 ares_conn_err_t err = ARES_CONN_ERR_SUCCESS;
365 unsigned int flags = 0;
366
367 if (is_tfo) {
368 flags |= ARES_SOCKET_CONN_TCP_FASTOPEN;
369 }
370
371 do {
372 int rv;
373
374 rv = channel->sock_funcs.aconnect(sockfd, addr, addrlen, flags,
375 channel->sock_func_cb_data);
376
377 if (rv < 0) {
378 err = ares_socket_deref_error(SOCKERRNO);
379 } else {
380 err = ARES_CONN_ERR_SUCCESS;
381 }
382 } while (err == ARES_CONN_ERR_INTERRUPT);
383
384 return err;
385 }
386
ares_socket_close(ares_channel_t * channel,ares_socket_t s)387 void ares_socket_close(ares_channel_t *channel, ares_socket_t s)
388 {
389 if (channel == NULL || s == ARES_SOCKET_BAD) {
390 return;
391 }
392
393 channel->sock_funcs.aclose(s, channel->sock_func_cb_data);
394 }
395
ares_set_socket_callback(ares_channel_t * channel,ares_sock_create_callback cb,void * data)396 void ares_set_socket_callback(ares_channel_t *channel,
397 ares_sock_create_callback cb, void *data)
398 {
399 if (channel == NULL) {
400 return;
401 }
402 channel->sock_create_cb = cb;
403 channel->sock_create_cb_data = data;
404 }
405
ares_set_socket_configure_callback(ares_channel_t * channel,ares_sock_config_callback cb,void * data)406 void ares_set_socket_configure_callback(ares_channel_t *channel,
407 ares_sock_config_callback cb,
408 void *data)
409 {
410 if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
411 return;
412 }
413 channel->sock_config_cb = cb;
414 channel->sock_config_cb_data = data;
415 }
416
ares_set_pending_write_cb(ares_channel_t * channel,ares_pending_write_cb callback,void * user_data)417 void ares_set_pending_write_cb(ares_channel_t *channel,
418 ares_pending_write_cb callback, void *user_data)
419 {
420 if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
421 return;
422 }
423 channel->notify_pending_write_cb = callback;
424 channel->notify_pending_write_cb_data = user_data;
425 }
426