• 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_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