ares_socket.c (12838B)
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }