• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MIT License
2  *
3  * Copyright (c) 2024 Brad House
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * SPDX-License-Identifier: MIT
25  */
26 #include "ares_private.h"
27 #ifdef HAVE_SYS_UIO_H
28 #  include <sys/uio.h>
29 #endif
30 #ifdef HAVE_NETINET_IN_H
31 #  include <netinet/in.h>
32 #endif
33 #ifdef HAVE_NETINET_TCP_H
34 #  include <netinet/tcp.h>
35 #endif
36 #ifdef HAVE_NETDB_H
37 #  include <netdb.h>
38 #endif
39 #ifdef HAVE_ARPA_INET_H
40 #  include <arpa/inet.h>
41 #endif
42 
43 #ifdef HAVE_STRINGS_H
44 #  include <strings.h>
45 #endif
46 #ifdef HAVE_SYS_IOCTL_H
47 #  include <sys/ioctl.h>
48 #endif
49 #ifdef NETWARE
50 #  include <sys/filio.h>
51 #endif
52 
53 #include <assert.h>
54 #include <fcntl.h>
55 #include <limits.h>
56 
57 
58 #if defined(__linux__) && defined(TCP_FASTOPEN_CONNECT)
59 #  define TFO_SUPPORTED      1
60 #  define TFO_SKIP_CONNECT   0
61 #  define TFO_USE_SENDTO     0
62 #  define TFO_USE_CONNECTX   0
63 #  define TFO_CLIENT_SOCKOPT TCP_FASTOPEN_CONNECT
64 #elif defined(__FreeBSD__) && defined(TCP_FASTOPEN)
65 #  define TFO_SUPPORTED      1
66 #  define TFO_SKIP_CONNECT   1
67 #  define TFO_USE_SENDTO     1
68 #  define TFO_USE_CONNECTX   0
69 #  define TFO_CLIENT_SOCKOPT TCP_FASTOPEN
70 #elif defined(__APPLE__) && defined(HAVE_CONNECTX)
71 #  define TFO_SUPPORTED    1
72 #  define TFO_SKIP_CONNECT 0
73 #  define TFO_USE_SENDTO   0
74 #  define TFO_USE_CONNECTX 1
75 #  undef TFO_CLIENT_SOCKOPT
76 #else
77 #  define TFO_SUPPORTED 0
78 #endif
79 
80 #ifndef HAVE_WRITEV
81 /* Structure for scatter/gather I/O. */
82 struct iovec {
83   void  *iov_base; /* Pointer to data. */
84   size_t iov_len;  /* Length of data.  */
85 };
86 #endif
87 
88 ares_status_t
ares_set_socket_functions_ex(ares_channel_t * channel,const struct ares_socket_functions_ex * funcs,void * user_data)89   ares_set_socket_functions_ex(ares_channel_t                        *channel,
90                                const struct ares_socket_functions_ex *funcs,
91                                void                                  *user_data)
92 {
93   unsigned int known_versions[] = { 1 };
94   size_t       i;
95 
96   if (channel == NULL || funcs == NULL) {
97     return ARES_EFORMERR;
98   }
99 
100   /* Check to see if we know the version referenced */
101   for (i = 0; i < sizeof(known_versions) / sizeof(*known_versions); i++) {
102     if (funcs->version == known_versions[i]) {
103       break;
104     }
105   }
106   if (i == sizeof(known_versions) / sizeof(*known_versions)) {
107     return ARES_EFORMERR;
108   }
109 
110   memset(&channel->sock_funcs, 0, sizeof(channel->sock_funcs));
111 
112   /* Copy individually for ABI compliance.  memcpy() with a sizeof would do
113    * invalid reads */
114   if (funcs->version >= 1) {
115     if (funcs->asocket == NULL || funcs->aclose == NULL ||
116         funcs->asetsockopt == NULL || funcs->aconnect == NULL ||
117         funcs->arecvfrom == NULL || funcs->asendto == NULL) {
118       return ARES_EFORMERR;
119     }
120     channel->sock_funcs.version      = funcs->version;
121     channel->sock_funcs.flags        = funcs->flags;
122     channel->sock_funcs.asocket      = funcs->asocket;
123     channel->sock_funcs.aclose       = funcs->aclose;
124     channel->sock_funcs.asetsockopt  = funcs->asetsockopt;
125     channel->sock_funcs.aconnect     = funcs->aconnect;
126     channel->sock_funcs.arecvfrom    = funcs->arecvfrom;
127     channel->sock_funcs.asendto      = funcs->asendto;
128     channel->sock_funcs.agetsockname = funcs->agetsockname;
129     channel->sock_funcs.abind        = funcs->abind;
130   }
131 
132   /* Implement newer versions here ...*/
133 
134 
135   channel->sock_func_cb_data = user_data;
136 
137   return ARES_SUCCESS;
138 }
139 
setsocknonblock(ares_socket_t sockfd,int nonblock)140 static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
141                            int           nonblock /* TRUE or FALSE */)
142 {
143 #if defined(HAVE_FCNTL_O_NONBLOCK)
144 
145   /* most recent unix versions */
146   int flags;
147   flags = fcntl(sockfd, F_GETFL, 0);
148   if (nonblock) {
149     return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
150   } else {
151     return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); /* LCOV_EXCL_LINE */
152   }
153 
154 #elif defined(HAVE_IOCTL_FIONBIO)
155 
156   /* older unix versions */
157   int flags = nonblock ? 1 : 0;
158   return ioctl(sockfd, FIONBIO, &flags);
159 
160 #elif defined(HAVE_IOCTLSOCKET_FIONBIO)
161 
162 #  ifdef WATT32
163   char flags = nonblock ? 1 : 0;
164 #  else
165   /* Windows */
166   unsigned long flags = nonblock ? 1UL : 0UL;
167 #  endif
168   return ioctlsocket(sockfd, (long)FIONBIO, &flags);
169 
170 #elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
171 
172   /* Amiga */
173   long flags = nonblock ? 1L : 0L;
174   return IoctlSocket(sockfd, FIONBIO, flags);
175 
176 #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
177 
178   /* BeOS */
179   long b = nonblock ? 1L : 0L;
180   return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
181 
182 #else
183 #  error "no non-blocking method was found/used/set"
184 #endif
185 }
186 
default_aclose(ares_socket_t sock,void * user_data)187 static int default_aclose(ares_socket_t sock, void *user_data)
188 {
189   (void)user_data;
190 
191 #if defined(HAVE_CLOSESOCKET)
192   return closesocket(sock);
193 #elif defined(HAVE_CLOSESOCKET_CAMEL)
194   return CloseSocket(sock);
195 #elif defined(HAVE_CLOSE_S)
196   return close_s(sock);
197 #else
198   return close(sock);
199 #endif
200 }
201 
default_asocket(int domain,int type,int protocol,void * user_data)202 static ares_socket_t default_asocket(int domain, int type, int protocol,
203                                      void *user_data)
204 {
205   ares_socket_t s;
206   (void)user_data;
207 
208   s = socket(domain, type, protocol);
209   if (s == ARES_SOCKET_BAD) {
210     return s;
211   }
212 
213   if (setsocknonblock(s, 1) != 0) {
214     goto fail; /* LCOV_EXCL_LINE */
215   }
216 
217 #if defined(FD_CLOEXEC) && !defined(MSDOS)
218   /* Configure the socket fd as close-on-exec. */
219   if (fcntl(s, F_SETFD, FD_CLOEXEC) != 0) {
220     goto fail; /* LCOV_EXCL_LINE */
221   }
222 #endif
223 
224   /* No need to emit SIGPIPE on socket errors */
225 #if defined(SO_NOSIGPIPE)
226   {
227     int opt = 1;
228     (void)setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, sizeof(opt));
229   }
230 #endif
231 
232 
233   if (type == SOCK_STREAM) {
234     int opt = 1;
235 
236 #ifdef TCP_NODELAY
237     /*
238      * Disable the Nagle algorithm (only relevant for TCP sockets, and thus not
239      * in configure_socket). In general, in DNS lookups we're pretty much
240      * interested in firing off a single request and then waiting for a reply,
241      * so batching isn't very interesting.
242      */
243     if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) !=
244         0) {
245       goto fail;
246     }
247 #endif
248   }
249 
250 #if defined(IPV6_V6ONLY) && defined(USE_WINSOCK)
251   /* Support for IPv4-mapped IPv6 addresses.
252    * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
253    * Windows Vista and later: default is on;
254    * DragonFly BSD: acts like off, and dummy setting;
255    * OpenBSD and earlier Windows: unsupported.
256    * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
257    */
258   if (domain == PF_INET6) {
259     int on = 0;
260     (void)setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
261   }
262 #endif
263 
264   return s;
265 
266 fail:
267   default_aclose(s, user_data);
268   return ARES_SOCKET_BAD;
269 }
270 
default_asetsockopt(ares_socket_t sock,ares_socket_opt_t opt,const void * val,ares_socklen_t val_size,void * user_data)271 static int default_asetsockopt(ares_socket_t sock, ares_socket_opt_t opt,
272                                const void *val, ares_socklen_t val_size,
273                                void *user_data)
274 {
275   switch (opt) {
276     case ARES_SOCKET_OPT_SENDBUF_SIZE:
277       if (val_size != sizeof(int)) {
278         SET_SOCKERRNO(EINVAL);
279         return -1;
280       }
281       return setsockopt(sock, SOL_SOCKET, SO_SNDBUF, val, val_size);
282 
283     case ARES_SOCKET_OPT_RECVBUF_SIZE:
284       if (val_size != sizeof(int)) {
285         SET_SOCKERRNO(EINVAL);
286         return -1;
287       }
288       return setsockopt(sock, SOL_SOCKET, SO_RCVBUF, val, val_size);
289 
290     case ARES_SOCKET_OPT_BIND_DEVICE:
291       /* Count the number of characters before NULL terminator then
292        * validate those are all printable */
293       if (!ares_str_isprint(val, ares_strnlen(val, (size_t)val_size))) {
294         SET_SOCKERRNO(EINVAL);
295         return -1;
296       }
297 #ifdef SO_BINDTODEVICE
298       return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, val, val_size);
299 #else
300       SET_SOCKERRNO(ENOSYS);
301       return -1;
302 #endif
303 
304     case ARES_SOCKET_OPT_TCP_FASTOPEN:
305       if (val_size != sizeof(ares_bool_t)) {
306         SET_SOCKERRNO(EINVAL);
307         return -1;
308       }
309 #if defined(TFO_CLIENT_SOCKOPT)
310       {
311         int                oval;
312         const ares_bool_t *pval = val;
313         oval                    = (int)*pval;
314         return setsockopt(sock, IPPROTO_TCP, TFO_CLIENT_SOCKOPT, (void *)&oval,
315                           sizeof(oval));
316       }
317 #elif TFO_SUPPORTED
318       return 0;
319 #else
320       SET_SOCKERRNO(ENOSYS);
321       return -1;
322 #endif
323   }
324 
325   (void)user_data;
326   SET_SOCKERRNO(ENOSYS);
327   return -1;
328 }
329 
default_aconnect(ares_socket_t sock,const struct sockaddr * address,ares_socklen_t address_len,unsigned int flags,void * user_data)330 static int default_aconnect(ares_socket_t sock, const struct sockaddr *address,
331                             ares_socklen_t address_len, unsigned int flags,
332                             void *user_data)
333 {
334   (void)user_data;
335 
336 #if defined(TFO_SKIP_CONNECT) && TFO_SKIP_CONNECT
337   if (flags & ARES_SOCKET_CONN_TCP_FASTOPEN) {
338     return 0;
339   }
340   return connect(sock, address, address_len);
341 #elif defined(TFO_USE_CONNECTX) && TFO_USE_CONNECTX
342   if (flags & ARES_SOCKET_CONN_TCP_FASTOPEN) {
343     sa_endpoints_t endpoints;
344 
345     memset(&endpoints, 0, sizeof(endpoints));
346     endpoints.sae_dstaddr    = address;
347     endpoints.sae_dstaddrlen = address_len;
348 
349     return connectx(sock, &endpoints, SAE_ASSOCID_ANY,
350                     CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE,
351                     NULL, 0, NULL, NULL);
352   } else {
353     return connect(sock, address, address_len);
354   }
355 #else
356   (void)flags;
357   return connect(sock, address, address_len);
358 #endif
359 }
360 
default_arecvfrom(ares_socket_t sock,void * buffer,size_t length,int flags,struct sockaddr * address,ares_socklen_t * address_len,void * user_data)361 static ares_ssize_t default_arecvfrom(ares_socket_t sock, void *buffer,
362                                       size_t length, int flags,
363                                       struct sockaddr *address,
364                                       ares_socklen_t  *address_len,
365                                       void            *user_data)
366 {
367   (void)user_data;
368 
369 #ifdef HAVE_RECVFROM
370   return (ares_ssize_t)recvfrom(sock, buffer, (RECVFROM_TYPE_ARG3)length, flags,
371                                 address, address_len);
372 #else
373   if (address != NULL && address_len != NULL) {
374     memset(address, 0, (size_t)*address_len);
375     address->sa_family = AF_UNSPEC;
376   }
377   return (ares_ssize_t)recv(sock, buffer, (RECVFROM_TYPE_ARG3)length, flags);
378 #endif
379 }
380 
default_asendto(ares_socket_t sock,const void * buffer,size_t length,int flags,const struct sockaddr * address,ares_socklen_t address_len,void * user_data)381 static ares_ssize_t default_asendto(ares_socket_t sock, const void *buffer,
382                                     size_t length, int flags,
383                                     const struct sockaddr *address,
384                                     ares_socklen_t address_len, void *user_data)
385 {
386   (void)user_data;
387 
388   if (address != NULL) {
389 #ifdef HAVE_SENDTO
390     return (ares_ssize_t)sendto((SEND_TYPE_ARG1)sock, (SEND_TYPE_ARG2)buffer,
391                                 (SEND_TYPE_ARG3)length, (SEND_TYPE_ARG4)flags,
392                                 address, address_len);
393 #else
394     (void)address_len;
395 #endif
396   }
397 
398   return (ares_ssize_t)send((SEND_TYPE_ARG1)sock, (SEND_TYPE_ARG2)buffer,
399                             (SEND_TYPE_ARG3)length, (SEND_TYPE_ARG4)flags);
400 }
401 
default_agetsockname(ares_socket_t sock,struct sockaddr * address,ares_socklen_t * address_len,void * user_data)402 static int default_agetsockname(ares_socket_t sock, struct sockaddr *address,
403                                 ares_socklen_t *address_len, void *user_data)
404 {
405   (void)user_data;
406   return getsockname(sock, address, address_len);
407 }
408 
default_abind(ares_socket_t sock,unsigned int flags,const struct sockaddr * address,socklen_t address_len,void * user_data)409 static int default_abind(ares_socket_t sock, unsigned int flags,
410                          const struct sockaddr *address, socklen_t address_len,
411                          void *user_data)
412 {
413   (void)user_data;
414 
415 #ifdef IP_BIND_ADDRESS_NO_PORT
416   if (flags & ARES_SOCKET_BIND_TCP && flags & ARES_SOCKET_BIND_CLIENT) {
417     int opt = 1;
418     (void)setsockopt(sock, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &opt, sizeof(opt));
419   }
420 #else
421   (void)flags;
422 #endif
423 
424   return bind(sock, address, address_len);
425 }
426 
default_aif_nametoindex(const char * ifname,void * user_data)427 static unsigned int default_aif_nametoindex(const char *ifname, void *user_data)
428 {
429   (void)user_data;
430   return ares_os_if_nametoindex(ifname);
431 }
432 
default_aif_indextoname(unsigned int ifindex,char * ifname_buf,size_t ifname_buf_len,void * user_data)433 static const char *default_aif_indextoname(unsigned int ifindex,
434                                            char        *ifname_buf,
435                                            size_t       ifname_buf_len,
436                                            void        *user_data)
437 {
438   (void)user_data;
439   return ares_os_if_indextoname(ifindex, ifname_buf, ifname_buf_len);
440 }
441 
442 static const struct ares_socket_functions_ex default_socket_functions = {
443   1,
444   ARES_SOCKFUNC_FLAG_NONBLOCKING,
445   default_asocket,
446   default_aclose,
447   default_asetsockopt,
448   default_aconnect,
449   default_arecvfrom,
450   default_asendto,
451   default_agetsockname,
452   default_abind,
453   default_aif_nametoindex,
454   default_aif_indextoname
455 };
456 
ares_set_socket_functions_def(ares_channel_t * channel)457 void ares_set_socket_functions_def(ares_channel_t *channel)
458 {
459   ares_set_socket_functions_ex(channel, &default_socket_functions, NULL);
460 }
461 
legacycb_aclose(ares_socket_t sock,void * user_data)462 static int legacycb_aclose(ares_socket_t sock, void *user_data)
463 {
464   ares_channel_t *channel = user_data;
465 
466   if (channel->legacy_sock_funcs != NULL &&
467       channel->legacy_sock_funcs->aclose != NULL) {
468     return channel->legacy_sock_funcs->aclose(
469       sock, channel->legacy_sock_funcs_cb_data);
470   }
471 
472   return default_aclose(sock, NULL);
473 }
474 
legacycb_asocket(int domain,int type,int protocol,void * user_data)475 static ares_socket_t legacycb_asocket(int domain, int type, int protocol,
476                                       void *user_data)
477 {
478   ares_channel_t *channel = user_data;
479 
480   if (channel->legacy_sock_funcs != NULL &&
481       channel->legacy_sock_funcs->asocket != NULL) {
482     return channel->legacy_sock_funcs->asocket(
483       domain, type, protocol, channel->legacy_sock_funcs_cb_data);
484   }
485 
486   return default_asocket(domain, type, protocol, NULL);
487 }
488 
legacycb_asetsockopt(ares_socket_t sock,ares_socket_opt_t opt,const void * val,ares_socklen_t val_size,void * user_data)489 static int legacycb_asetsockopt(ares_socket_t sock, ares_socket_opt_t opt,
490                                 const void *val, ares_socklen_t val_size,
491                                 void *user_data)
492 {
493   (void)sock;
494   (void)opt;
495   (void)val;
496   (void)val_size;
497   (void)user_data;
498   SET_SOCKERRNO(ENOSYS);
499   return -1;
500 }
501 
legacycb_aconnect(ares_socket_t sock,const struct sockaddr * address,ares_socklen_t address_len,unsigned int flags,void * user_data)502 static int legacycb_aconnect(ares_socket_t sock, const struct sockaddr *address,
503                              ares_socklen_t address_len, unsigned int flags,
504                              void *user_data)
505 {
506   ares_channel_t *channel = user_data;
507 
508   if (channel->legacy_sock_funcs != NULL &&
509       channel->legacy_sock_funcs->aconnect != NULL) {
510     return channel->legacy_sock_funcs->aconnect(
511       sock, address, address_len, channel->legacy_sock_funcs_cb_data);
512   }
513 
514   return default_aconnect(sock, address, address_len, flags, NULL);
515 }
516 
legacycb_arecvfrom(ares_socket_t sock,void * buffer,size_t length,int flags,struct sockaddr * address,ares_socklen_t * address_len,void * user_data)517 static ares_ssize_t legacycb_arecvfrom(ares_socket_t sock, void *buffer,
518                                        size_t length, int flags,
519                                        struct sockaddr *address,
520                                        ares_socklen_t  *address_len,
521                                        void            *user_data)
522 {
523   ares_channel_t *channel = user_data;
524 
525   if (channel->legacy_sock_funcs != NULL &&
526       channel->legacy_sock_funcs->arecvfrom != NULL) {
527     if (address != NULL && address_len != NULL) {
528       memset(address, 0, (size_t)*address_len);
529       address->sa_family = AF_UNSPEC;
530     }
531     return channel->legacy_sock_funcs->arecvfrom(
532       sock, buffer, length, flags, address, address_len,
533       channel->legacy_sock_funcs_cb_data);
534   }
535 
536   return default_arecvfrom(sock, buffer, length, flags, address, address_len,
537                            NULL);
538 }
539 
legacycb_asendto(ares_socket_t sock,const void * buffer,size_t length,int flags,const struct sockaddr * address,ares_socklen_t address_len,void * user_data)540 static ares_ssize_t legacycb_asendto(ares_socket_t sock, const void *buffer,
541                                      size_t length, int flags,
542                                      const struct sockaddr *address,
543                                      ares_socklen_t         address_len,
544                                      void                  *user_data)
545 {
546   ares_channel_t *channel = user_data;
547 
548   if (channel->legacy_sock_funcs != NULL &&
549       channel->legacy_sock_funcs->asendv != NULL) {
550     struct iovec vec;
551     vec.iov_base = (void *)((size_t)buffer); /* Cast off const */
552     vec.iov_len  = length;
553     return channel->legacy_sock_funcs->asendv(
554       sock, &vec, 1, channel->legacy_sock_funcs_cb_data);
555   }
556 
557   return default_asendto(sock, buffer, length, flags, address, address_len,
558                          NULL);
559 }
560 
561 
562 static const struct ares_socket_functions_ex legacy_socket_functions = {
563   1,
564   0,
565   legacycb_asocket,
566   legacycb_aclose,
567   legacycb_asetsockopt,
568   legacycb_aconnect,
569   legacycb_arecvfrom,
570   legacycb_asendto,
571   NULL, /* agetsockname */
572   NULL, /* abind */
573   NULL, /* aif_nametoindex */
574   NULL  /* aif_indextoname */
575 };
576 
ares_set_socket_functions(ares_channel_t * channel,const struct ares_socket_functions * funcs,void * data)577 void ares_set_socket_functions(ares_channel_t                     *channel,
578                                const struct ares_socket_functions *funcs,
579                                void                               *data)
580 {
581   if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
582     return;
583   }
584 
585   channel->legacy_sock_funcs         = funcs;
586   channel->legacy_sock_funcs_cb_data = data;
587   ares_set_socket_functions_ex(channel, &legacy_socket_functions, channel);
588 }
589