ares_set_socket_functions.c (17541B)
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }