• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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