ares_conn.c (16260B)
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 29 void ares_conn_sock_state_cb_update(ares_conn_t *conn, 30 ares_conn_state_flags_t flags) 31 { 32 ares_channel_t *channel = conn->server->channel; 33 34 if ((conn->state_flags & ARES_CONN_STATE_CBFLAGS) != flags && 35 channel->sock_state_cb) { 36 channel->sock_state_cb(channel->sock_state_cb_data, conn->fd, 37 flags & ARES_CONN_STATE_READ ? 1 : 0, 38 flags & ARES_CONN_STATE_WRITE ? 1 : 0); 39 } 40 41 conn->state_flags &= ~((unsigned int)ARES_CONN_STATE_CBFLAGS); 42 conn->state_flags |= flags; 43 } 44 45 ares_conn_err_t ares_conn_read(ares_conn_t *conn, void *data, size_t len, 46 size_t *read_bytes) 47 { 48 ares_channel_t *channel = conn->server->channel; 49 ares_conn_err_t err; 50 51 if (!(conn->flags & ARES_CONN_FLAG_TCP)) { 52 struct sockaddr_storage sa_storage; 53 ares_socklen_t salen = sizeof(sa_storage); 54 55 memset(&sa_storage, 0, sizeof(sa_storage)); 56 57 err = 58 ares_socket_recvfrom(channel, conn->fd, ARES_FALSE, data, len, 0, 59 (struct sockaddr *)&sa_storage, &salen, read_bytes); 60 61 #ifdef HAVE_RECVFROM 62 if (err == ARES_CONN_ERR_SUCCESS && 63 !ares_sockaddr_addr_eq((struct sockaddr *)&sa_storage, 64 &conn->server->addr)) { 65 err = ARES_CONN_ERR_WOULDBLOCK; 66 } 67 #endif 68 } else { 69 err = ares_socket_recv(channel, conn->fd, ARES_TRUE, data, len, read_bytes); 70 } 71 72 /* Toggle connected state if needed */ 73 if (err == ARES_CONN_ERR_SUCCESS) { 74 conn->state_flags |= ARES_CONN_STATE_CONNECTED; 75 } 76 77 return err; 78 } 79 80 /* Use like: 81 * struct sockaddr_storage sa_storage; 82 * ares_socklen_t salen = sizeof(sa_storage); 83 * struct sockaddr *sa = (struct sockaddr *)&sa_storage; 84 * ares_conn_set_sockaddr(conn, sa, &salen); 85 */ 86 static ares_status_t ares_conn_set_sockaddr(const ares_conn_t *conn, 87 struct sockaddr *sa, 88 ares_socklen_t *salen) 89 { 90 const ares_server_t *server = conn->server; 91 unsigned short port = 92 conn->flags & ARES_CONN_FLAG_TCP ? server->tcp_port : server->udp_port; 93 struct sockaddr_in *sin; 94 struct sockaddr_in6 *sin6; 95 96 switch (server->addr.family) { 97 case AF_INET: 98 sin = (struct sockaddr_in *)(void *)sa; 99 if (*salen < (ares_socklen_t)sizeof(*sin)) { 100 return ARES_EFORMERR; 101 } 102 *salen = sizeof(*sin); 103 memset(sin, 0, sizeof(*sin)); 104 sin->sin_family = AF_INET; 105 sin->sin_port = htons(port); 106 memcpy(&sin->sin_addr, &server->addr.addr.addr4, sizeof(sin->sin_addr)); 107 return ARES_SUCCESS; 108 case AF_INET6: 109 sin6 = (struct sockaddr_in6 *)(void *)sa; 110 if (*salen < (ares_socklen_t)sizeof(*sin6)) { 111 return ARES_EFORMERR; 112 } 113 *salen = sizeof(*sin6); 114 memset(sin6, 0, sizeof(*sin6)); 115 sin6->sin6_family = AF_INET6; 116 sin6->sin6_port = htons(port); 117 memcpy(&sin6->sin6_addr, &server->addr.addr.addr6, 118 sizeof(sin6->sin6_addr)); 119 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 120 sin6->sin6_scope_id = server->ll_scope; 121 #endif 122 return ARES_SUCCESS; 123 default: 124 break; 125 } 126 127 return ARES_EBADFAMILY; 128 } 129 130 static ares_status_t ares_conn_set_self_ip(ares_conn_t *conn, ares_bool_t early) 131 { 132 ares_channel_t *channel = conn->server->channel; 133 struct sockaddr_storage sa_storage; 134 int rv; 135 ares_socklen_t len = sizeof(sa_storage); 136 137 /* We call this twice on TFO, if we already have the IP we can go ahead and 138 * skip processing */ 139 if (!early && conn->self_ip.family != AF_UNSPEC) { 140 return ARES_SUCCESS; 141 } 142 143 memset(&sa_storage, 0, sizeof(sa_storage)); 144 145 if (channel->sock_funcs.agetsockname == NULL) { 146 /* Not specified, we can still use cookies cooked with an empty self_ip */ 147 memset(&conn->self_ip, 0, sizeof(conn->self_ip)); 148 return ARES_SUCCESS; 149 } 150 rv = channel->sock_funcs.agetsockname(conn->fd, 151 (struct sockaddr *)(void *)&sa_storage, 152 &len, channel->sock_func_cb_data); 153 if (rv != 0) { 154 /* During TCP FastOpen, we can't get the IP this early since connect() 155 * may not be called. That's ok, we'll try again later */ 156 if (early && conn->flags & ARES_CONN_FLAG_TCP && 157 conn->flags & ARES_CONN_FLAG_TFO) { 158 memset(&conn->self_ip, 0, sizeof(conn->self_ip)); 159 return ARES_SUCCESS; 160 } 161 return ARES_ECONNREFUSED; 162 } 163 164 if (!ares_sockaddr_to_ares_addr(&conn->self_ip, NULL, 165 (struct sockaddr *)(void *)&sa_storage)) { 166 return ARES_ECONNREFUSED; 167 } 168 169 return ARES_SUCCESS; 170 } 171 172 ares_conn_err_t ares_conn_write(ares_conn_t *conn, const void *data, size_t len, 173 size_t *written) 174 { 175 ares_channel_t *channel = conn->server->channel; 176 ares_bool_t is_tfo = ARES_FALSE; 177 ares_conn_err_t err = ARES_CONN_ERR_SUCCESS; 178 struct sockaddr_storage sa_storage; 179 ares_socklen_t salen = 0; 180 struct sockaddr *sa = NULL; 181 182 *written = 0; 183 184 /* Don't try to write if not doing initial TFO and not connected */ 185 if (conn->flags & ARES_CONN_FLAG_TCP && 186 !(conn->state_flags & ARES_CONN_STATE_CONNECTED) && 187 !(conn->flags & ARES_CONN_FLAG_TFO_INITIAL)) { 188 return ARES_CONN_ERR_WOULDBLOCK; 189 } 190 191 /* On initial write during TFO we need to send an address */ 192 if (conn->flags & ARES_CONN_FLAG_TFO_INITIAL) { 193 salen = sizeof(sa_storage); 194 sa = (struct sockaddr *)&sa_storage; 195 196 conn->flags &= ~((unsigned int)ARES_CONN_FLAG_TFO_INITIAL); 197 is_tfo = ARES_TRUE; 198 199 if (ares_conn_set_sockaddr(conn, sa, &salen) != ARES_SUCCESS) { 200 return ARES_CONN_ERR_FAILURE; 201 } 202 } 203 204 err = ares_socket_write(channel, conn->fd, data, len, written, sa, salen); 205 if (err != ARES_CONN_ERR_SUCCESS) { 206 goto done; 207 } 208 209 if (is_tfo) { 210 /* If using TFO, we might not have been able to get an IP earlier, since 211 * we hadn't informed the OS of the destination. When using sendto() 212 * now we have so we should be able to fetch it */ 213 ares_conn_set_self_ip(conn, ARES_FALSE); 214 goto done; 215 } 216 217 done: 218 if (err == ARES_CONN_ERR_SUCCESS && len == *written) { 219 /* Wrote all data, make sure we're not listening for write events unless 220 * using TFO, in which case we'll need a write event to know when 221 * we're connected. */ 222 ares_conn_sock_state_cb_update( 223 conn, ARES_CONN_STATE_READ | 224 (is_tfo ? ARES_CONN_STATE_WRITE : ARES_CONN_STATE_NONE)); 225 } else if (err == ARES_CONN_ERR_WOULDBLOCK) { 226 /* Need to wait on more buffer space to write */ 227 ares_conn_sock_state_cb_update(conn, ARES_CONN_STATE_READ | 228 ARES_CONN_STATE_WRITE); 229 } 230 231 return err; 232 } 233 234 ares_status_t ares_conn_flush(ares_conn_t *conn) 235 { 236 const unsigned char *data; 237 size_t data_len; 238 size_t count; 239 ares_conn_err_t err; 240 ares_status_t status; 241 ares_bool_t tfo = ARES_FALSE; 242 243 if (conn == NULL) { 244 return ARES_EFORMERR; 245 } 246 247 if (conn->flags & ARES_CONN_FLAG_TFO_INITIAL) { 248 tfo = ARES_TRUE; 249 } 250 251 do { 252 if (ares_buf_len(conn->out_buf) == 0) { 253 status = ARES_SUCCESS; 254 goto done; 255 } 256 257 if (conn->flags & ARES_CONN_FLAG_TCP) { 258 data = ares_buf_peek(conn->out_buf, &data_len); 259 } else { 260 unsigned short msg_len; 261 262 /* Read length, then provide buffer without length */ 263 ares_buf_tag(conn->out_buf); 264 status = ares_buf_fetch_be16(conn->out_buf, &msg_len); 265 if (status != ARES_SUCCESS) { 266 return status; 267 } 268 ares_buf_tag_rollback(conn->out_buf); 269 270 data = ares_buf_peek(conn->out_buf, &data_len); 271 if (data_len < (size_t)(msg_len + 2)) { 272 status = ARES_EFORMERR; 273 goto done; 274 } 275 data += 2; 276 data_len = msg_len; 277 } 278 279 err = ares_conn_write(conn, data, data_len, &count); 280 if (err != ARES_CONN_ERR_SUCCESS) { 281 if (err != ARES_CONN_ERR_WOULDBLOCK) { 282 status = ARES_ECONNREFUSED; 283 goto done; 284 } 285 status = ARES_SUCCESS; 286 goto done; 287 } 288 289 /* UDP didn't send the length prefix so augment that here */ 290 if (!(conn->flags & ARES_CONN_FLAG_TCP)) { 291 count += 2; 292 } 293 294 /* Strip data written from the buffer */ 295 ares_buf_consume(conn->out_buf, count); 296 status = ARES_SUCCESS; 297 298 /* Loop only for UDP since we have to send per-packet. We already 299 * sent everything we could if using tcp */ 300 } while (!(conn->flags & ARES_CONN_FLAG_TCP)); 301 302 done: 303 if (status == ARES_SUCCESS) { 304 ares_conn_state_flags_t flags = ARES_CONN_STATE_READ; 305 306 /* When using TFO, the we need to enabling waiting on a write event to 307 * be notified of when a connection is actually established */ 308 if (tfo) { 309 flags |= ARES_CONN_STATE_WRITE; 310 } 311 312 /* If using TCP and not all data was written (partial write), that means 313 * we need to also wait on a write event */ 314 if (conn->flags & ARES_CONN_FLAG_TCP && ares_buf_len(conn->out_buf)) { 315 flags |= ARES_CONN_STATE_WRITE; 316 } 317 318 ares_conn_sock_state_cb_update(conn, flags); 319 } 320 321 return status; 322 } 323 324 static ares_status_t ares_conn_connect(ares_conn_t *conn, 325 const struct sockaddr *sa, 326 ares_socklen_t salen) 327 { 328 ares_conn_err_t err; 329 330 err = ares_socket_connect( 331 conn->server->channel, conn->fd, 332 (conn->flags & ARES_CONN_FLAG_TFO) ? ARES_TRUE : ARES_FALSE, sa, salen); 333 334 if (err != ARES_CONN_ERR_WOULDBLOCK && err != ARES_CONN_ERR_SUCCESS) { 335 return ARES_ECONNREFUSED; 336 } 337 return ARES_SUCCESS; 338 } 339 340 ares_status_t ares_open_connection(ares_conn_t **conn_out, 341 ares_channel_t *channel, 342 ares_server_t *server, ares_bool_t is_tcp) 343 { 344 ares_status_t status; 345 struct sockaddr_storage sa_storage; 346 ares_socklen_t salen = sizeof(sa_storage); 347 struct sockaddr *sa = (struct sockaddr *)&sa_storage; 348 ares_conn_t *conn; 349 ares_llist_node_t *node = NULL; 350 int stype = is_tcp ? SOCK_STREAM : SOCK_DGRAM; 351 ares_conn_state_flags_t state_flags; 352 353 *conn_out = NULL; 354 355 conn = ares_malloc(sizeof(*conn)); 356 if (conn == NULL) { 357 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 358 } 359 360 memset(conn, 0, sizeof(*conn)); 361 conn->fd = ARES_SOCKET_BAD; 362 conn->server = server; 363 conn->queries_to_conn = ares_llist_create(NULL); 364 conn->flags = is_tcp ? ARES_CONN_FLAG_TCP : ARES_CONN_FLAG_NONE; 365 conn->out_buf = ares_buf_create(); 366 conn->in_buf = ares_buf_create(); 367 368 if (conn->queries_to_conn == NULL || conn->out_buf == NULL || 369 conn->in_buf == NULL) { 370 /* LCOV_EXCL_START: OutOfMemory */ 371 status = ARES_ENOMEM; 372 goto done; 373 /* LCOV_EXCL_STOP */ 374 } 375 376 /* Try to enable TFO always if using TCP. it will fail later on if its 377 * really not supported when we try to enable it on the socket. */ 378 if (conn->flags & ARES_CONN_FLAG_TCP) { 379 conn->flags |= ARES_CONN_FLAG_TFO; 380 } 381 382 /* Convert into the struct sockaddr structure needed by the OS */ 383 status = ares_conn_set_sockaddr(conn, sa, &salen); 384 if (status != ARES_SUCCESS) { 385 goto done; 386 } 387 388 /* Acquire a socket. */ 389 if (ares_socket_open(&conn->fd, channel, server->addr.family, stype, 0) != 390 ARES_CONN_ERR_SUCCESS) { 391 status = ARES_ECONNREFUSED; 392 goto done; 393 } 394 395 /* Configure channel configured options */ 396 status = ares_socket_configure( 397 channel, server->addr.family, 398 (conn->flags & ARES_CONN_FLAG_TCP) ? ARES_TRUE : ARES_FALSE, conn->fd); 399 if (status != ARES_SUCCESS) { 400 goto done; 401 } 402 403 /* Enable TFO if possible */ 404 if (conn->flags & ARES_CONN_FLAG_TFO && 405 ares_socket_enable_tfo(channel, conn->fd) != ARES_CONN_ERR_SUCCESS) { 406 conn->flags &= ~((unsigned int)ARES_CONN_FLAG_TFO); 407 } 408 409 if (channel->sock_config_cb) { 410 int err = 411 channel->sock_config_cb(conn->fd, stype, channel->sock_config_cb_data); 412 if (err < 0) { 413 status = ARES_ECONNREFUSED; 414 goto done; 415 } 416 } 417 418 /* Connect */ 419 status = ares_conn_connect(conn, sa, salen); 420 if (status != ARES_SUCCESS) { 421 goto done; 422 } 423 424 if (channel->sock_create_cb) { 425 int err = 426 channel->sock_create_cb(conn->fd, stype, channel->sock_create_cb_data); 427 if (err < 0) { 428 status = ARES_ECONNREFUSED; 429 goto done; 430 } 431 } 432 433 /* Let the connection know we haven't written our first packet yet for TFO */ 434 if (conn->flags & ARES_CONN_FLAG_TFO) { 435 conn->flags |= ARES_CONN_FLAG_TFO_INITIAL; 436 } 437 438 /* Need to store our own ip for DNS cookie support */ 439 status = ares_conn_set_self_ip(conn, ARES_TRUE); 440 if (status != ARES_SUCCESS) { 441 goto done; /* LCOV_EXCL_LINE: UntestablePath */ 442 } 443 444 /* TCP connections are thrown to the end as we don't spawn multiple TCP 445 * connections. UDP connections are put on front where the newest connection 446 * can be quickly pulled */ 447 if (is_tcp) { 448 node = ares_llist_insert_last(server->connections, conn); 449 } else { 450 node = ares_llist_insert_first(server->connections, conn); 451 } 452 if (node == NULL) { 453 /* LCOV_EXCL_START: OutOfMemory */ 454 status = ARES_ENOMEM; 455 goto done; 456 /* LCOV_EXCL_STOP */ 457 } 458 459 /* Register globally to quickly map event on file descriptor to connection 460 * node object */ 461 if (!ares_htable_asvp_insert(channel->connnode_by_socket, conn->fd, node)) { 462 /* LCOV_EXCL_START: OutOfMemory */ 463 status = ARES_ENOMEM; 464 goto done; 465 /* LCOV_EXCL_STOP */ 466 } 467 468 state_flags = ARES_CONN_STATE_READ; 469 470 /* Get notified on connect if using TCP */ 471 if (conn->flags & ARES_CONN_FLAG_TCP) { 472 state_flags |= ARES_CONN_STATE_WRITE; 473 } 474 475 /* Dot no attempt to update sock state callbacks on TFO until *after* the 476 * initial write is performed. Due to the notification event, its possible 477 * an erroneous read can come in before the attempt to write the data which 478 * might be used to set the ip address */ 479 if (!(conn->flags & ARES_CONN_FLAG_TFO_INITIAL)) { 480 ares_conn_sock_state_cb_update(conn, state_flags); 481 } 482 483 if (is_tcp) { 484 server->tcp_conn = conn; 485 } 486 487 done: 488 if (status != ARES_SUCCESS) { 489 ares_llist_node_claim(node); 490 ares_llist_destroy(conn->queries_to_conn); 491 ares_socket_close(channel, conn->fd); 492 ares_buf_destroy(conn->out_buf); 493 ares_buf_destroy(conn->in_buf); 494 ares_free(conn); 495 } else { 496 *conn_out = conn; 497 } 498 return status; 499 } 500 501 ares_conn_t *ares_conn_from_fd(const ares_channel_t *channel, ares_socket_t fd) 502 { 503 ares_llist_node_t *node; 504 505 node = ares_htable_asvp_get_direct(channel->connnode_by_socket, fd); 506 if (node == NULL) { 507 return NULL; 508 } 509 510 return ares_llist_node_val(node); 511 }