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
62ares_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
80ares_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 */
97static 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 */
156static 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
164static 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
240ares_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
395ares_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
406int 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
417void 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. */
432struct iovec {
433  void  *iov_base; /* Pointer to data. */
434  size_t iov_len;  /* Length of data.  */
435};
436#endif
437
438ares_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
450void 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
460void 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
471void 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