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
ares_conn_sock_state_cb_update(ares_conn_t * conn,ares_conn_state_flags_t flags)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
ares_conn_read(ares_conn_t * conn,void * data,size_t len,size_t * read_bytes)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 */
ares_conn_set_sockaddr(const ares_conn_t * conn,struct sockaddr * sa,ares_socklen_t * salen)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
ares_conn_set_self_ip(ares_conn_t * conn,ares_bool_t early)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
ares_conn_write(ares_conn_t * conn,const void * data,size_t len,size_t * written)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
ares_conn_flush(ares_conn_t * conn)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
ares_conn_connect(ares_conn_t * conn,const struct sockaddr * sa,ares_socklen_t salen)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
ares_open_connection(ares_conn_t ** conn_out,ares_channel_t * channel,ares_server_t * server,ares_bool_t is_tcp)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
ares_conn_from_fd(const ares_channel_t * channel,ares_socket_t fd)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 }
512