• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

c-ares / c-ares / 14332039557

08 Apr 2025 11:11AM UTC coverage: 92.274% (-0.01%) from 92.287%
14332039557

push

github

bradh352
Windows build fix

1 of 1 new or added line in 1 file covered. (100.0%)

4 existing lines in 2 files now uncovered.

21009 of 22768 relevant lines covered (92.27%)

99252.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.88
/src/lib/ares_process.c
1
/* MIT License
2
 *
3
 * Copyright (c) 1998 Massachusetts Institute of Technology
4
 * Copyright (c) 2010 Daniel Stenberg
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

28
#include "ares_private.h"
29

30
#ifdef HAVE_STRINGS_H
31
#  include <strings.h>
32
#endif
33
#ifdef HAVE_SYS_IOCTL_H
34
#  include <sys/ioctl.h>
35
#endif
36
#ifdef NETWARE
37
#  include <sys/filio.h>
38
#endif
39
#ifdef HAVE_STDINT_H
40
#  include <stdint.h>
41
#endif
42

43
#include <assert.h>
44
#include <fcntl.h>
45
#include <limits.h>
46

47

48
static void          timeadd(ares_timeval_t *now, size_t millisecs);
49
static void          write_tcp_data(ares_channel_t *channel, fd_set *write_fds,
50
                                    ares_socket_t write_fd);
51
static void          read_packets(ares_channel_t *channel, fd_set *read_fds,
52
                                  ares_socket_t read_fd, const ares_timeval_t *now);
53
static void          process_timeouts(ares_channel_t       *channel,
54
                                      const ares_timeval_t *now);
55
static ares_status_t process_answer(ares_channel_t      *channel,
56
                                    const unsigned char *abuf, size_t alen,
57
                                    ares_conn_t *conn, ares_bool_t tcp,
58
                                    const ares_timeval_t *now,
59
                                    ares__array_t        **requeue);
60
static void handle_conn_error(ares_conn_t *conn, ares_bool_t critical_failure,
61
                              ares_status_t failure_status);
62

63
static ares_bool_t same_questions(const ares_query_t      *query,
64
                                  const ares_dns_record_t *arec);
65
static ares_bool_t same_address(const struct sockaddr  *sa,
66
                                const struct ares_addr *aa);
67
static void        end_query(ares_channel_t *channel, ares_server_t *server,
68
                             ares_query_t *query, ares_status_t status,
69
                             const ares_dns_record_t *dnsrec);
70

71
static void        ares__query_disassociate_from_conn(ares_query_t *query)
6,479✔
72
{
73
  /* If its not part of a connection, it can't be tracked for timeouts either */
74
  ares__slist_node_destroy(query->node_queries_by_timeout);
6,479✔
75
  ares__llist_node_destroy(query->node_queries_to_conn);
6,479✔
76
  query->node_queries_by_timeout = NULL;
6,479✔
77
  query->node_queries_to_conn    = NULL;
6,479✔
78
  query->conn                    = NULL;
6,479✔
79
}
6,479✔
80

81
/* Invoke the server state callback after a success or failure */
82
static void invoke_server_state_cb(const ares_server_t *server,
2,704✔
83
                                   ares_bool_t success, int flags)
84
{
85
  const ares_channel_t *channel = server->channel;
2,704✔
86
  ares__buf_t          *buf;
87
  ares_status_t         status;
88
  char                 *server_string;
89

90
  if (channel->server_state_cb == NULL) {
2,704✔
91
    return;
2,680✔
92
  }
93

94
  buf = ares__buf_create();
24✔
95
  if (buf == NULL) {
24✔
96
    return; /* LCOV_EXCL_LINE: OutOfMemory */
97
  }
98

99
  status = ares_get_server_addr(server, buf);
24✔
100
  if (status != ARES_SUCCESS) {
24✔
101
    ares__buf_destroy(buf); /* LCOV_EXCL_LINE: OutOfMemory */
102
    return;                 /* LCOV_EXCL_LINE: OutOfMemory */
103
  }
104

105
  server_string = ares__buf_finish_str(buf, NULL);
24✔
106
  buf           = NULL;
24✔
107
  if (server_string == NULL) {
24✔
108
    return; /* LCOV_EXCL_LINE: OutOfMemory */
109
  }
110

111
  channel->server_state_cb(server_string, success, flags,
24✔
112
                           channel->server_state_cb_data);
24✔
113
  ares_free(server_string);
24✔
114
}
115

116
static void server_increment_failures(ares_server_t *server,
754✔
117
                                      ares_bool_t    used_tcp)
118
{
119
  ares__slist_node_t   *node;
120
  const ares_channel_t *channel = server->channel;
754✔
121
  ares_timeval_t        next_retry_time;
122

123
  node = ares__slist_node_find(channel->servers, server);
754✔
124
  if (node == NULL) {
754✔
125
    return; /* LCOV_EXCL_LINE: DefensiveCoding */
126
  }
127

128
  server->consec_failures++;
754✔
129
  ares__slist_node_reinsert(node);
754✔
130

131
  ares__tvnow(&next_retry_time);
754✔
132
  timeadd(&next_retry_time, channel->server_retry_delay);
754✔
133
  server->next_retry_time = next_retry_time;
754✔
134

135
  invoke_server_state_cb(server, ARES_FALSE,
754✔
136
                         used_tcp == ARES_TRUE ? ARES_SERV_STATE_TCP
137
                                               : ARES_SERV_STATE_UDP);
138
}
139

140
static void server_set_good(ares_server_t *server, ares_bool_t used_tcp)
1,950✔
141
{
142
  ares__slist_node_t   *node;
143
  const ares_channel_t *channel = server->channel;
1,950✔
144

145
  node = ares__slist_node_find(channel->servers, server);
1,950✔
146
  if (node == NULL) {
1,950✔
147
    return; /* LCOV_EXCL_LINE: DefensiveCoding */
148
  }
149

150
  if (server->consec_failures > 0) {
1,950✔
151
    server->consec_failures = 0;
176✔
152
    ares__slist_node_reinsert(node);
176✔
153
  }
154

155
  server->next_retry_time.sec  = 0;
1,950✔
156
  server->next_retry_time.usec = 0;
1,950✔
157

158
  invoke_server_state_cb(server, ARES_TRUE,
1,950✔
159
                         used_tcp == ARES_TRUE ? ARES_SERV_STATE_TCP
160
                                               : ARES_SERV_STATE_UDP);
161
}
162

163
/* return true if now is exactly check time or later */
164
ares_bool_t ares__timedout(const ares_timeval_t *now,
5,121,426✔
165
                           const ares_timeval_t *check)
166
{
167
  ares_int64_t secs = (now->sec - check->sec);
5,121,426✔
168

169
  if (secs > 0) {
5,121,426✔
170
    return ARES_TRUE; /* yes, timed out */
5✔
171
  }
172
  if (secs < 0) {
5,121,421✔
173
    return ARES_FALSE; /* nope, not timed out */
467,435✔
174
  }
175

176
  /* if the full seconds were identical, check the sub second parts */
177
  return ((ares_int64_t)now->usec - (ares_int64_t)check->usec) >= 0
4,653,986✔
178
           ? ARES_TRUE
179
           : ARES_FALSE;
4,653,986✔
180
}
181

182
/* add the specific number of milliseconds to the time in the first argument */
183
static void timeadd(ares_timeval_t *now, size_t millisecs)
6,529✔
184
{
185
  now->sec  += (ares_int64_t)millisecs / 1000;
6,529✔
186
  now->usec += (unsigned int)((millisecs % 1000) * 1000);
6,529✔
187

188
  if (now->usec >= 1000000) {
6,529✔
189
    now->sec  += now->usec / 1000000;
1,065✔
190
    now->usec %= 1000000;
1,065✔
191
  }
192
}
6,529✔
193

194
/*
195
 * generic process function
196
 */
197
static void processfds(ares_channel_t *channel, fd_set *read_fds,
5,123,697✔
198
                       ares_socket_t read_fd, fd_set *write_fds,
199
                       ares_socket_t write_fd)
200
{
201
  ares_timeval_t now;
202

203
  if (channel == NULL) {
5,123,697✔
204
    return; /* LCOV_EXCL_LINE: DefensiveCoding */
205
  }
206

207
  ares__channel_lock(channel);
5,123,697✔
208

209
  ares__tvnow(&now);
5,123,697✔
210
  read_packets(channel, read_fds, read_fd, &now);
5,123,697✔
211
  process_timeouts(channel, &now);
5,123,697✔
212
  /* Write last as the other 2 operations might have triggered writes */
213
  write_tcp_data(channel, write_fds, write_fd);
5,123,697✔
214

215
  /* See if any connections should be cleaned up */
216
  ares__check_cleanup_conns(channel);
5,123,697✔
217
  ares__channel_unlock(channel);
5,123,697✔
218
}
219

220
/* Something interesting happened on the wire, or there was a timeout.
221
 * See what's up and respond accordingly.
222
 */
223
void ares_process(ares_channel_t *channel, fd_set *read_fds, fd_set *write_fds)
9,561✔
224
{
225
  processfds(channel, read_fds, ARES_SOCKET_BAD, write_fds, ARES_SOCKET_BAD);
9,561✔
226
}
9,561✔
227

228
/* Something interesting happened on the wire, or there was a timeout.
229
 * See what's up and respond accordingly.
230
 */
231
void ares_process_fd(ares_channel_t *channel,
5,114,136✔
232
                     ares_socket_t   read_fd, /* use ARES_SOCKET_BAD or valid
233
                                                 file descriptors */
234
                     ares_socket_t   write_fd)
235
{
236
  processfds(channel, NULL, read_fd, NULL, write_fd);
5,114,136✔
237
}
5,114,136✔
238

239
/* If any TCP sockets select true for writing, write out queued data
240
 * we have for them.
241
 */
242
static void write_tcp_data(ares_channel_t *channel, fd_set *write_fds,
5,123,697✔
243
                           ares_socket_t write_fd)
244
{
245
  ares__slist_node_t *node;
246

247
  if (!write_fds && (write_fd == ARES_SOCKET_BAD)) {
5,123,697✔
248
    /* no possible action */
249
    return;
2,559,190✔
250
  }
251

252
  for (node = ares__slist_node_first(channel->servers); node != NULL;
10,223,406✔
253
       node = ares__slist_node_next(node)) {
7,658,899✔
254
    ares_server_t       *server = ares__slist_node_val(node);
7,658,899✔
255
    const unsigned char *data;
256
    size_t               data_len;
257
    ares_ssize_t         count;
258

259
    /* Make sure server has data to send and is selected in write_fds or
260
       write_fd. */
261
    if (ares__buf_len(server->tcp_send) == 0 || server->tcp_conn == NULL) {
7,658,899✔
262
      continue;
7,658,572✔
263
    }
264

265
    if (write_fds) {
437✔
266
      if (!FD_ISSET(server->tcp_conn->fd, write_fds)) {
244✔
267
        continue;
106✔
268
      }
269
    } else {
270
      if (server->tcp_conn->fd != write_fd) {
193✔
UNCOV
271
        continue;
×
272
      }
273
    }
274

275
    if (write_fds) {
331✔
276
      /* If there's an error and we close this socket, then open
277
       * another with the same fd to talk to another server, then we
278
       * don't want to think that it was the new socket that was
279
       * ready. This is not disastrous, but is likely to result in
280
       * extra system calls and confusion. */
281
      FD_CLR(server->tcp_conn->fd, write_fds);
138✔
282
    }
283

284
    data  = ares__buf_peek(server->tcp_send, &data_len);
331✔
285
    count = ares__conn_write(server->tcp_conn, data, data_len);
331✔
286
    if (count <= 0) {
331✔
287
      if (!ares__socket_try_again(SOCKERRNO)) {
4✔
288
        handle_conn_error(server->tcp_conn, ARES_TRUE, ARES_ECONNREFUSED);
4✔
289
      }
290
      continue;
4✔
291
    }
292

293
    /* Strip data written from the buffer */
294
    ares__buf_consume(server->tcp_send, (size_t)count);
327✔
295

296
    /* Notify state callback all data is written */
297
    if (ares__buf_len(server->tcp_send) == 0) {
327✔
298
      SOCK_STATE_CALLBACK(channel, server->tcp_conn->fd, 1, 0);
327✔
299
    }
300
  }
301
}
302

303
/* Simple data structure to store a query that needs to be requeued with
304
 * optional server */
305
typedef struct {
306
  unsigned short qid;
307
  ares_server_t *server; /* optional */
308
} ares_requeue_t;
309

310
static ares_status_t ares_append_requeue(ares__array_t **requeue,
420✔
311
                                         ares_query_t *query,
312
                                         ares_server_t *server)
313
{
314
  ares_requeue_t entry;
315

316
  if (*requeue == NULL) {
420✔
317
    *requeue = ares__array_create(sizeof(ares_requeue_t), NULL);
420✔
318
    if (*requeue == NULL) {
420✔
319
      return ARES_ENOMEM;
×
320
    }
321
  }
322

323
  ares__query_disassociate_from_conn(query);
420✔
324

325
  entry.qid    = query->qid;
420✔
326
  entry.server = server;
420✔
327
  return ares__array_insertdata_last(*requeue, &entry);
420✔
328
}
329

330

331
/* If any TCP socket selects true for reading, read some data,
332
 * allocate a buffer if we finish reading the length word, and process
333
 * a packet if we finish reading one.
334
 */
335
static void read_tcp_data(ares_channel_t *channel, ares_conn_t *conn,
1,073✔
336
                          const ares_timeval_t *now)
337
{
338
  ares_ssize_t    count;
339
  ares_server_t  *server = conn->server;
1,073✔
340
  ares_status_t   status;
341
  ares__array_t  *requeue = NULL;
1,073✔
342

343
  /* Fetch buffer to store data we are reading */
344
  size_t         ptr_len = 65535;
1,073✔
345
  unsigned char *ptr;
346

347
  ptr = ares__buf_append_start(server->tcp_parser, &ptr_len);
1,073✔
348

349
  if (ptr == NULL) {
1,073✔
350
    handle_conn_error(conn, ARES_FALSE /* not critical to connection */,
×
351
                      ARES_SUCCESS);
352
    return; /* bail out on malloc failure. TODO: make this
8✔
353
               function return error codes */
354
  }
355

356
  /* Read from socket */
357
  count = ares__socket_recv(channel, conn->fd, ptr, ptr_len);
1,073✔
358
  if (count <= 0) {
1,073✔
359
    ares__buf_append_finish(server->tcp_parser, 0);
8✔
360
    if (!(count == -1 && ares__socket_try_again(SOCKERRNO))) {
8✔
361
      handle_conn_error(conn, ARES_TRUE, ARES_ECONNREFUSED);
8✔
362
    }
363
    return;
8✔
364
  }
365

366
  /* Record amount of data read */
367
  ares__buf_append_finish(server->tcp_parser, (size_t)count);
1,065✔
368

369
  /* Process all queued answers */
370
  while (1) {
1,123✔
371
    unsigned short       dns_len  = 0;
2,188✔
372
    const unsigned char *data     = NULL;
2,188✔
373
    size_t               data_len = 0;
2,188✔
374

375
    /* Tag so we can roll back */
376
    ares__buf_tag(server->tcp_parser);
2,188✔
377

378
    /* Read length indicator */
379
    if (ares__buf_fetch_be16(server->tcp_parser, &dns_len) != ARES_SUCCESS) {
2,188✔
380
      ares__buf_tag_rollback(server->tcp_parser);
1,035✔
381
      break;
1,035✔
382
    }
383

384
    /* Not enough data for a full response yet */
385
    if (ares__buf_consume(server->tcp_parser, dns_len) != ARES_SUCCESS) {
1,153✔
386
      ares__buf_tag_rollback(server->tcp_parser);
×
387
      break;
×
388
    }
389

390
    /* Can't fail except for misuse */
391
    data = ares__buf_tag_fetch(server->tcp_parser, &data_len);
1,153✔
392
    if (data == NULL || data_len < 2) {
1,153✔
393
      ares__buf_tag_clear(server->tcp_parser);
×
394
      break;
×
395
    }
396

397
    /* Strip off 2 bytes length */
398
    data     += 2;
1,153✔
399
    data_len -= 2;
1,153✔
400

401
    /* We finished reading this answer; process it */
402
    status = process_answer(channel, data, data_len, conn, ARES_TRUE, now,
1,153✔
403
                            &requeue);
404
    if (status != ARES_SUCCESS) {
1,153✔
405
      handle_conn_error(conn, ARES_TRUE, status);
30✔
406
      goto cleanup;
30✔
407
    }
408

409
    /* Since we processed the answer, clear the tag so space can be reclaimed */
410
    ares__buf_tag_clear(server->tcp_parser);
1,123✔
411
  }
412

413
cleanup:
1,065✔
414

415
  /* Flush requeue */
416
  while (ares__array_len(requeue) > 0) {
1,293✔
417
    ares_query_t  *query;
418
    ares_requeue_t entry;
419
    ares_status_t  internal_status;
420

421
    internal_status = ares__array_claim_at(&entry, sizeof(entry), requeue, 0);
228✔
422
    if (internal_status != ARES_SUCCESS) {
228✔
423
      break;
×
424
    }
425

426
    /* Query disappeared */
427
    query = ares__htable_szvp_get_direct(channel->queries_by_qid, entry.qid);
228✔
428
    if (query == NULL) {
228✔
429
      continue;
×
430
    }
431

432
    ares__send_query(query, now);
228✔
433
  }
434
  ares__array_destroy(requeue);
1,065✔
435
}
436

437
static ares_socket_t *channel_socket_list(const ares_channel_t *channel,
9,561✔
438
                                          size_t               *num)
439
{
440
  ares__slist_node_t *snode;
441
  ares__array_t      *arr = ares__array_create(sizeof(ares_socket_t), NULL);
9,561✔
442

443
  *num = 0;
9,561✔
444

445
  if (arr == NULL) {
9,561✔
446
    return NULL; /* LCOV_EXCL_LINE: OutOfMemory */
447
  }
448

449
  for (snode = ares__slist_node_first(channel->servers); snode != NULL;
20,042✔
450
       snode = ares__slist_node_next(snode)) {
10,481✔
451
    ares_server_t      *server = ares__slist_node_val(snode);
10,481✔
452
    ares__llist_node_t *node;
453

454
    for (node = ares__llist_node_first(server->connections); node != NULL;
20,144✔
455
         node = ares__llist_node_next(node)) {
9,663✔
456
      const ares_conn_t *conn = ares__llist_node_val(node);
9,663✔
457
      ares_socket_t     *sptr;
458
      ares_status_t      status;
459

460
      if (conn->fd == ARES_SOCKET_BAD) {
9,663✔
461
        continue;
×
462
      }
463

464
      status = ares__array_insert_last((void **)&sptr, arr);
9,663✔
465
      if (status != ARES_SUCCESS) {
9,663✔
466
        ares__array_destroy(arr); /* LCOV_EXCL_LINE: OutOfMemory */
467
        return NULL;              /* LCOV_EXCL_LINE: OutOfMemory */
468
      }
469
      *sptr = conn->fd;
9,663✔
470
    }
471
  }
472

473
  return ares__array_finish(arr, num);
9,561✔
474
}
475

476
/* If any UDP sockets select true for reading, process them. */
477
static void read_udp_packets_fd(ares_channel_t *channel, ares_conn_t *conn,
1,283✔
478
                                const ares_timeval_t *now)
479
{
480
  ares_ssize_t   read_len;
481
  unsigned char  buf[MAXENDSSZ + 1];
482
  ares__array_t *requeue = NULL;
1,283✔
483

484
#ifdef HAVE_RECVFROM
485
  ares_socklen_t fromlen;
486

487
  union {
488
    struct sockaddr     sa;
489
    struct sockaddr_in  sa4;
490
    struct sockaddr_in6 sa6;
491
  } from;
492

493
  memset(&from, 0, sizeof(from));
1,283✔
494
#endif
495

496
  /* To reduce event loop overhead, read and process as many
497
   * packets as we can. */
498
  do {
499
    if (conn->fd == ARES_SOCKET_BAD) {
2,561✔
500
      read_len = -1;
×
501
    } else {
502
      if (conn->server->addr.family == AF_INET) {
2,561✔
503
        fromlen = sizeof(from.sa4);
1,314✔
504
      } else {
505
        fromlen = sizeof(from.sa6);
1,247✔
506
      }
507
      read_len = ares__socket_recvfrom(channel, conn->fd, (void *)buf,
2,561✔
508
                                       sizeof(buf), 0, &from.sa, &fromlen);
509
    }
510

511
    if (read_len == 0) {
2,561✔
512
      /* UDP is connectionless, so result code of 0 is a 0-length UDP
513
       * packet, and not an indication the connection is closed like on
514
       * tcp */
515
      continue;
×
516
    } else if (read_len < 0) {
2,561✔
517
      if (ares__socket_try_again(SOCKERRNO)) {
1,244✔
518
        break;
1,244✔
519
      }
520

521
      handle_conn_error(conn, ARES_TRUE, ARES_ECONNREFUSED);
×
522
      goto cleanup;
×
523
#ifdef HAVE_RECVFROM
524
    } else if (!same_address(&from.sa, &conn->server->addr)) {
1,317✔
525
      /* The address the response comes from does not match the address we
526
       * sent the request to. Someone may be attempting to perform a cache
527
       * poisoning attack. */
528
      continue;
×
529
#endif
530

531
    } else {
532
      process_answer(channel, buf, (size_t)read_len, conn, ARES_FALSE, now,
1,317✔
533
                     &requeue);
534
    }
535

536
    /* Try to read again only if *we* set up the socket, otherwise it may be
537
     * a blocking socket and would cause recvfrom to hang. */
538
  } while (read_len >= 0 && channel->sock_funcs == NULL);
1,317✔
539

540
cleanup:
39✔
541

542
  /* Flush requeue */
543
  while (ares__array_len(requeue) > 0) {
1,475✔
544
    ares_query_t  *query;
545
    ares_requeue_t entry;
546
    ares_status_t  internal_status;
547

548
    internal_status = ares__array_claim_at(&entry, sizeof(entry), requeue, 0);
192✔
549
    if (internal_status != ARES_SUCCESS) {
192✔
550
      break;
×
551
    }
552

553
    /* Query disappeared */
554
    query = ares__htable_szvp_get_direct(channel->queries_by_qid, entry.qid);
192✔
555
    if (query == NULL) {
192✔
556
      continue;
×
557
    }
558

559
    internal_status = ares__send_query(query, now);
192✔
560
  }
561
  ares__array_destroy(requeue);
1,283✔
562
}
1,283✔
563

564
static void read_packets(ares_channel_t *channel, fd_set *read_fds,
5,123,697✔
565
                         ares_socket_t read_fd, const ares_timeval_t *now)
566
{
567
  size_t              i;
568
  ares_socket_t      *socketlist  = NULL;
5,123,697✔
569
  size_t              num_sockets = 0;
5,123,697✔
570
  ares_conn_t        *conn        = NULL;
5,123,697✔
571
  ares__llist_node_t *node        = NULL;
5,123,697✔
572

573
  if (!read_fds && (read_fd == ARES_SOCKET_BAD)) {
5,123,697✔
574
    /* no possible action */
575
    return;
5,114,136✔
576
  }
577

578
  /* Single socket specified */
579
  if (!read_fds) {
10,994✔
580
    node = ares__htable_asvp_get_direct(channel->connnode_by_socket, read_fd);
1,433✔
581
    if (node == NULL) {
1,433✔
582
      return;
27✔
583
    }
584

585
    conn = ares__llist_node_val(node);
1,406✔
586

587
    if (conn->flags & ARES_CONN_FLAG_TCP) {
1,406✔
588
      read_tcp_data(channel, conn, now);
732✔
589
    } else {
590
      read_udp_packets_fd(channel, conn, now);
674✔
591
    }
592

593
    return;
1,406✔
594
  }
595

596
  /* There is no good way to iterate across an fd_set, instead we must pull a
597
   * list of all known fds, and iterate across that checking against the fd_set.
598
   */
599
  socketlist = channel_socket_list(channel, &num_sockets);
9,561✔
600

601
  for (i = 0; i < num_sockets; i++) {
19,224✔
602
    if (!FD_ISSET(socketlist[i], read_fds)) {
9,663✔
603
      continue;
8,713✔
604
    }
605

606
    /* If there's an error and we close this socket, then open
607
     * another with the same fd to talk to another server, then we
608
     * don't want to think that it was the new socket that was
609
     * ready. This is not disastrous, but is likely to result in
610
     * extra system calls and confusion. */
611
    FD_CLR(socketlist[i], read_fds);
950✔
612

613
    node =
614
      ares__htable_asvp_get_direct(channel->connnode_by_socket, socketlist[i]);
950✔
615
    if (node == NULL) {
950✔
616
      return;
×
617
    }
618

619
    conn = ares__llist_node_val(node);
950✔
620

621
    if (conn->flags & ARES_CONN_FLAG_TCP) {
950✔
622
      read_tcp_data(channel, conn, now);
341✔
623
    } else {
624
      read_udp_packets_fd(channel, conn, now);
609✔
625
    }
626
  }
627

628
  ares_free(socketlist);
9,561✔
629
}
630

631
/* If any queries have timed out, note the timeout and move them on. */
632
static void process_timeouts(ares_channel_t *channel, const ares_timeval_t *now)
5,123,697✔
633
{
634
  ares__slist_node_t *node;
635

636
  /* Just keep popping off the first as this list will re-sort as things come
637
   * and go.  We don't want to try to rely on 'next' as some operation might
638
   * cause a cleanup of that pointer and would become invalid */
639
  while ((node = ares__slist_node_first(channel->queries_by_timeout)) != NULL) {
5,123,825✔
640
    ares_query_t *query = ares__slist_node_val(node);
5,120,993✔
641
    ares_conn_t  *conn;
642

643
    /* Since this is sorted, as soon as we hit a query that isn't timed out,
644
     * break */
645
    if (!ares__timedout(now, &query->timeout)) {
5,120,993✔
646
      break;
5,120,865✔
647
    }
648

649
    query->timeouts++;
128✔
650

651
    conn = query->conn;
128✔
652
    server_increment_failures(conn->server, query->using_tcp);
128✔
653
    ares__requeue_query(query, now, ARES_ETIMEOUT, ARES_TRUE, NULL, NULL);
128✔
654
  }
655
}
5,123,697✔
656

657
static ares_status_t rewrite_without_edns(ares_query_t *query)
26✔
658
{
659
  ares_status_t status = ARES_SUCCESS;
26✔
660
  size_t        i;
661
  ares_bool_t   found_opt_rr = ARES_FALSE;
26✔
662

663
  /* Find and remove the OPT RR record */
664
  for (i = 0; i < ares_dns_record_rr_cnt(query->query, ARES_SECTION_ADDITIONAL);
26✔
665
       i++) {
×
666
    const ares_dns_rr_t *rr;
667
    rr = ares_dns_record_rr_get(query->query, ARES_SECTION_ADDITIONAL, i);
26✔
668
    if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_OPT) {
26✔
669
      ares_dns_record_rr_del(query->query, ARES_SECTION_ADDITIONAL, i);
26✔
670
      found_opt_rr = ARES_TRUE;
26✔
671
      break;
26✔
672
    }
673
  }
674

675
  if (!found_opt_rr) {
26✔
676
    status = ARES_EFORMERR;
×
677
    goto done;
×
678
  }
679

680
done:
26✔
681
  return status;
26✔
682
}
683

684
static ares_bool_t issue_might_be_edns(const ares_dns_record_t *req,
2,412✔
685
                                       const ares_dns_record_t *rsp)
686
{
687
  const ares_dns_rr_t *rr;
688

689
  /* If we use EDNS and server answers with FORMERR without an OPT RR, the
690
   * protocol extension is not understood by the responder. We must retry the
691
   * query without EDNS enabled. */
692
  if (ares_dns_record_get_rcode(rsp) != ARES_RCODE_FORMERR) {
2,412✔
693
    return ARES_FALSE;
2,376✔
694
  }
695

696
  rr = ares_dns_get_opt_rr_const(req);
36✔
697
  if (rr == NULL) {
36✔
698
    /* We didn't send EDNS */
699
    return ARES_FALSE;
10✔
700
  }
701

702
  if (ares_dns_get_opt_rr_const(rsp) == NULL) {
26✔
703
    /* Spec says EDNS won't be echo'd back on non-supporting servers, so
704
     * retry without EDNS */
705
    return ARES_TRUE;
24✔
706
  }
707

708
  /* As per issue #911 some non-compliant servers that do indeed support EDNS
709
   * but don't support unrecognized option codes exist.  At this point we
710
   * expect them to have also returned an EDNS opt record, but we may remove
711
   * that check in the future. Lets detect this situation if we're sending
712
   * option codes */
713
  if (ares_dns_rr_get_opt_cnt(rr, ARES_RR_OPT_OPTIONS) == 0) {
2✔
714
    /* We didn't send any option codes */
715
    return ARES_FALSE;
×
716
  }
717

718
  if (ares_dns_get_opt_rr_const(rsp) != NULL) {
2✔
719
    /* At this time we're requiring the server to respond with EDNS opt
720
     * records since that's what has been observed in the field.  We might
721
     * find in the future we have to remove this, who knows. Lets go
722
     * ahead and force a retry without EDNS*/
723
    return ARES_TRUE;
2✔
724
  }
725

726
  return ARES_FALSE;
×
727
}
728

729
/* Handle an answer from a server. This must NEVER cleanup the
730
 * server connection! Return something other than ARES_SUCCESS to cause
731
 * the connection to be terminated after this call. */
732
static ares_status_t process_answer(ares_channel_t      *channel,
2,470✔
733
                                    const unsigned char *abuf, size_t alen,
734
                                    ares_conn_t *conn, ares_bool_t tcp,
735
                                    const ares_timeval_t *now,
736
                                    ares__array_t        **requeue)
737
{
738
  ares_query_t      *query;
739
  /* Cache these as once ares__send_query() gets called, it may end up
740
   * invalidating the connection all-together */
741
  ares_server_t     *server  = conn->server;
2,470✔
742
  ares_dns_record_t *rdnsrec = NULL;
2,470✔
743
  ares_status_t      status;
744
  ares_bool_t        is_cached = ARES_FALSE;
2,470✔
745

746
  /* Parse the response */
747
  status = ares_dns_parse(abuf, alen, 0, &rdnsrec);
2,470✔
748
  if (status != ARES_SUCCESS) {
2,470✔
749
    /* Malformations are never accepted */
750
    status = ARES_EBADRESP;
30✔
751
    goto cleanup;
30✔
752
  }
753

754
  /* Find the query corresponding to this packet. The queries are
755
   * hashed/bucketed by query id, so this lookup should be quick.
756
   */
757
  query = ares__htable_szvp_get_direct(channel->queries_by_qid,
2,440✔
758
                                       ares_dns_record_get_id(rdnsrec));
2,440✔
759
  if (!query) {
2,440✔
760
    /* We may have stopped listening for this query, that's ok */
761
    status = ARES_SUCCESS;
8✔
762
    goto cleanup;
8✔
763
  }
764

765
  /* Both the query id and the questions must be the same. We will drop any
766
   * replies that aren't for the same query as this is considered invalid. */
767
  if (!same_questions(query, rdnsrec)) {
2,432✔
768
    /* Possible qid conflict due to delayed response, that's ok */
769
    status = ARES_SUCCESS;
6✔
770
    goto cleanup;
6✔
771
  }
772

773
  /* Validate DNS cookie in response. This function may need to requeue the
774
   * query. */
775
  if (ares_cookie_validate(query, rdnsrec, conn, now, requeue)
2,426✔
776
      != ARES_SUCCESS) {
777
    /* Drop response and return */
778
    status = ARES_SUCCESS;
14✔
779
    goto cleanup;
14✔
780
  }
781

782
  /* At this point we know we've received an answer for this query, so we should
783
   * remove it from the connection's queue so we can possibly invalidate the
784
   * connection. Delay cleaning up the connection though as we may enqueue
785
   * something new.  */
786
  ares__llist_node_destroy(query->node_queries_to_conn);
2,412✔
787
  query->node_queries_to_conn = NULL;
2,412✔
788

789
  /* There are old servers that don't understand EDNS at all, then some servers
790
   * that have non-compliant implementations.  Lets try to detect this sort
791
   * of thing. */
792
  if (issue_might_be_edns(query->query, rdnsrec)) {
2,412✔
793
    status = rewrite_without_edns(query);
26✔
794
    if (status != ARES_SUCCESS) {
26✔
795
      end_query(channel, server, query, status, NULL);
×
796
      goto cleanup;
×
797
    }
798

799
    /* Requeue to same server */
800
    status = ares_append_requeue(requeue, query, server);
26✔
801
    goto cleanup;
26✔
802
  }
803

804
  /* If we got a truncated UDP packet and are not ignoring truncation,
805
   * don't accept the packet, and switch the query to TCP if we hadn't
806
   * done so already.
807
   */
808
  if (ares_dns_record_get_flags(rdnsrec) & ARES_FLAG_TC && !tcp &&
2,386✔
809
      !(channel->flags & ARES_FLAG_IGNTC)) {
10✔
810
    query->using_tcp = ARES_TRUE;
10✔
811
    status = ares_append_requeue(requeue, query, NULL);
10✔
812
    /* Status will reflect success except on memory error, which is good since
813
     * requeuing to TCP is ok */
814
    goto cleanup;
10✔
815
  }
816

817
  /* If we aren't passing through all error packets, discard packets
818
   * with SERVFAIL, NOTIMP, or REFUSED response codes.
819
   */
820
  if (!(channel->flags & ARES_FLAG_NOCHECKRESP)) {
2,376✔
821
    ares_dns_rcode_t rcode = ares_dns_record_get_rcode(rdnsrec);
2,316✔
822
    if (rcode == ARES_RCODE_SERVFAIL || rcode == ARES_RCODE_NOTIMP ||
2,316✔
823
        rcode == ARES_RCODE_REFUSED) {
824
      switch (rcode) {
426✔
825
        case ARES_RCODE_SERVFAIL:
262✔
826
          status = ARES_ESERVFAIL;
262✔
827
          break;
262✔
828
        case ARES_RCODE_NOTIMP:
110✔
829
          status = ARES_ENOTIMP;
110✔
830
          break;
110✔
831
        case ARES_RCODE_REFUSED:
54✔
832
          status = ARES_EREFUSED;
54✔
833
          break;
54✔
834
        default:
×
835
          break;
×
836
      }
837

838
      server_increment_failures(server, query->using_tcp);
426✔
839
      status = ares__requeue_query(query, now, status, ARES_TRUE, rdnsrec,
426✔
840
                                   requeue);
841

842
      if (status != ARES_ENOMEM) {
426✔
843
        /* Should any of these cause a connection termination?
844
         * Maybe SERVER_FAILURE? */
845
        status = ARES_SUCCESS;
426✔
846
      }
847
      goto cleanup;
426✔
848
    }
849
  }
850

851
  /* If cache insertion was successful, it took ownership.  We ignore
852
   * other cache insertion failures. */
853
  if (ares_qcache_insert(channel, now, query, rdnsrec) == ARES_SUCCESS) {
1,950✔
854
    is_cached = ARES_TRUE;
48✔
855
  }
856

857
  server_set_good(server, query->using_tcp);
1,950✔
858
  end_query(channel, server, query, ARES_SUCCESS, rdnsrec);
1,950✔
859

860
  status = ARES_SUCCESS;
1,950✔
861

862
cleanup:
2,470✔
863
  /* Don't cleanup the cached pointer to the dns response */
864
  if (!is_cached) {
2,470✔
865
    ares_dns_record_destroy(rdnsrec);
2,422✔
866
  }
867

868
  return status;
2,470✔
869
}
870

871
static void handle_conn_error(ares_conn_t *conn, ares_bool_t critical_failure,
140✔
872
                              ares_status_t failure_status)
873
{
874
  ares_server_t *server = conn->server;
140✔
875

876
  /* Increment failures first before requeue so it is unlikely to requeue
877
   * to the same server */
878
  if (critical_failure) {
140✔
879
    server_increment_failures(
140✔
880
      server, (conn->flags & ARES_CONN_FLAG_TCP) ? ARES_TRUE : ARES_FALSE);
140✔
881
  }
882

883
  /* This will requeue any connections automatically */
884
  ares__close_connection(conn, failure_status);
140✔
885
}
140✔
886

887
ares_status_t ares__requeue_query(ares_query_t            *query,
860✔
888
                                  const ares_timeval_t    *now,
889
                                  ares_status_t            status,
890
                                  ares_bool_t              inc_try_count,
891
                                  const ares_dns_record_t *dnsrec,
892
                                  ares__array_t           **requeue)
893
{
894
  ares_channel_t *channel = query->channel;
860✔
895
  size_t max_tries        = ares__slist_len(channel->servers) * channel->tries;
860✔
896

897
  ares__query_disassociate_from_conn(query);
860✔
898

899
  if (status != ARES_SUCCESS) {
860✔
900
    query->error_status = status;
848✔
901
  }
902

903
  if (inc_try_count) {
860✔
904
    query->try_count++;
852✔
905
  }
906

907
  if (query->try_count < max_tries && !query->no_retries) {
860✔
908
    if (requeue != NULL) {
698✔
909
      return ares_append_requeue(requeue, query, NULL);
384✔
910
    }
911
    return ares__send_query(query, now);
314✔
912
  }
913

914
  /* If we are here, all attempts to perform query failed. */
915
  if (query->error_status == ARES_SUCCESS) {
162✔
916
    query->error_status = ARES_ETIMEOUT;
×
917
  }
918

919
  end_query(channel, NULL, query, query->error_status, dnsrec);
162✔
920
  return ARES_ETIMEOUT;
162✔
921
}
922

923
/* Pick a random server from the list, we first get a random number in the
924
 * range of the number of servers, then scan until we find that server in
925
 * the list */
926
static ares_server_t *ares__random_server(ares_channel_t *channel)
×
927
{
928
  unsigned char       c;
929
  size_t              cnt;
930
  size_t              idx;
931
  ares__slist_node_t *node;
932
  size_t              num_servers = ares__slist_len(channel->servers);
×
933

934
  /* Silence coverity, not possible */
935
  if (num_servers == 0) {
×
936
    return NULL;
×
937
  }
938

939
  ares__rand_bytes(channel->rand_state, &c, 1);
×
940

941
  cnt = c;
×
942
  idx = cnt % num_servers;
×
943

944
  cnt = 0;
×
945
  for (node = ares__slist_node_first(channel->servers); node != NULL;
×
946
       node = ares__slist_node_next(node)) {
×
947
    if (cnt == idx) {
×
948
      return ares__slist_node_val(node);
×
949
    }
950

951
    cnt++;
×
952
  }
953

954
  return NULL;
×
955
}
956

957
/* Pick a server from the list with failover behavior.
958
 *
959
 * We default to using the first server in the sorted list of servers. That is
960
 * the server with the lowest number of consecutive failures and then the
961
 * highest priority server (by idx) if there is a draw.
962
 *
963
 * However, if a server temporarily goes down and hits some failures, then that
964
 * server will never be retried until all other servers hit the same number of
965
 * failures. This may prevent the server from being retried for a long time.
966
 *
967
 * To resolve this, with some probability we select a failed server to retry
968
 * instead.
969
 */
970
static ares_server_t *ares__failover_server(ares_channel_t *channel)
5,933✔
971
{
972
  ares_server_t       *first_server = ares__slist_first_val(channel->servers);
5,933✔
973
  const ares_server_t *last_server  = ares__slist_last_val(channel->servers);
5,933✔
974
  unsigned short       r;
975

976
  /* Defensive code against no servers being available on the channel. */
977
  if (first_server == NULL) {
5,933✔
978
    return NULL; /* LCOV_EXCL_LINE: DefensiveCoding */
979
  }
980

981
  /* If no servers have failures, then prefer the first server in the list. */
982
  if (last_server != NULL && last_server->consec_failures == 0) {
5,933✔
983
    return first_server;
5,049✔
984
  }
985

986
  /* If we are not configured with a server retry chance then return the first
987
   * server.
988
   */
989
  if (channel->server_retry_chance == 0) {
884✔
990
    return first_server;
×
991
  }
992

993
  /* Generate a random value to decide whether to retry a failed server. The
994
   * probability to use is 1/channel->server_retry_chance, rounded up to a
995
   * precision of 1/2^B where B is the number of bits in the random value.
996
   * We use an unsigned short for the random value for increased precision.
997
   */
998
  ares__rand_bytes(channel->rand_state, (unsigned char *)&r, sizeof(r));
884✔
999
  if (r % channel->server_retry_chance == 0) {
884✔
1000
    /* Select a suitable failed server to retry. */
1001
    ares_timeval_t      now;
1002
    ares__slist_node_t *node;
1003

1004
    ares__tvnow(&now);
267✔
1005
    for (node = ares__slist_node_first(channel->servers); node != NULL;
880✔
1006
         node = ares__slist_node_next(node)) {
613✔
1007
      ares_server_t *node_val = ares__slist_node_val(node);
677✔
1008
      if (node_val != NULL && node_val->consec_failures > 0 &&
1,110✔
1009
          ares__timedout(&now, &node_val->next_retry_time)) {
433✔
1010
        return node_val;
64✔
1011
      }
1012
    }
1013
  }
1014

1015
  /* If we have not returned yet, then return the first server. */
1016
  return first_server;
820✔
1017
}
1018

1019
static size_t ares__calc_query_timeout(const ares_query_t   *query,
5,775✔
1020
                                       const ares_server_t  *server,
1021
                                       const ares_timeval_t *now)
1022
{
1023
  const ares_channel_t *channel  = query->channel;
5,775✔
1024
  size_t                timeout  = ares_metrics_server_timeout(server, now);
5,775✔
1025
  size_t                timeplus = timeout;
5,775✔
1026
  size_t                rounds;
1027
  size_t                num_servers = ares__slist_len(channel->servers);
5,775✔
1028

1029
  if (num_servers == 0) {
5,775✔
1030
    return 0; /* LCOV_EXCL_LINE: DefensiveCoding */
1031
  }
1032

1033
  /* For each trip through the entire server list, we want to double the
1034
   * retry from the last retry */
1035
  rounds = (query->try_count / num_servers);
5,775✔
1036
  if (rounds > 0) {
5,775✔
1037
    timeplus <<= rounds;
314✔
1038
  }
1039

1040
  if (channel->maxtimeout && timeplus > channel->maxtimeout) {
5,775✔
1041
    timeplus = channel->maxtimeout;
×
1042
  }
1043

1044
  /* Add some jitter to the retry timeout.
1045
   *
1046
   * Jitter is needed in situation when resolve requests are performed
1047
   * simultaneously from multiple hosts and DNS server throttle these requests.
1048
   * Adding randomness allows to avoid synchronisation of retries.
1049
   *
1050
   * Value of timeplus adjusted randomly to the range [0.5 * timeplus,
1051
   * timeplus].
1052
   */
1053
  if (rounds > 0) {
5,775✔
1054
    unsigned short r;
1055
    float          delta_multiplier;
1056

1057
    ares__rand_bytes(channel->rand_state, (unsigned char *)&r, sizeof(r));
314✔
1058
    delta_multiplier  = ((float)r / USHRT_MAX) * 0.5f;
314✔
1059
    timeplus         -= (size_t)((float)timeplus * delta_multiplier);
314✔
1060
  }
1061

1062
  /* We want explicitly guarantee that timeplus is greater or equal to timeout
1063
   * specified in channel options. */
1064
  if (timeplus < timeout) {
5,775✔
1065
    timeplus = timeout;
×
1066
  }
1067

1068
  return timeplus;
5,775✔
1069
}
1070

1071
static ares_conn_t *ares__fetch_connection(const ares_channel_t *channel,
5,933✔
1072
                                           ares_server_t        *server,
1073
                                           const ares_query_t   *query)
1074
{
1075
  ares__llist_node_t *node;
1076
  ares_conn_t        *conn;
1077

1078
  if (query->using_tcp) {
5,933✔
1079
    return server->tcp_conn;
2,771✔
1080
  }
1081

1082
  /* Fetch existing UDP connection */
1083
  node = ares__llist_node_first(server->connections);
3,162✔
1084
  if (node == NULL) {
3,162✔
1085
    return NULL;
920✔
1086
  }
1087

1088
  conn = ares__llist_node_val(node);
2,242✔
1089
  /* Not UDP, skip */
1090
  if (conn->flags & ARES_CONN_FLAG_TCP) {
2,242✔
1091
    return NULL;
×
1092
  }
1093

1094
  /* Used too many times */
1095
  if (channel->udp_max_queries > 0 &&
2,242✔
1096
      conn->total_queries >= channel->udp_max_queries) {
248✔
1097
    return NULL;
24✔
1098
  }
1099

1100
  return conn;
2,218✔
1101
}
1102

1103
static ares_status_t ares__conn_query_write(ares_conn_t          *conn,
5,873✔
1104
                                            ares_query_t         *query,
1105
                                            const ares_timeval_t *now)
1106
{
1107
  unsigned char  *qbuf     = NULL;
5,873✔
1108
  size_t          qbuf_len = 0;
5,873✔
1109
  ares_ssize_t    len;
1110
  ares_server_t  *server  = conn->server;
5,873✔
1111
  ares_channel_t *channel = server->channel;
5,873✔
1112
  ares_status_t   status;
1113

1114
  status = ares_cookie_apply(query->query, conn, now);
5,873✔
1115
  if (status != ARES_SUCCESS) {
5,873✔
1116
    return status;
×
1117
  }
1118

1119
  if (conn->flags & ARES_CONN_FLAG_TCP) {
5,873✔
1120
    size_t prior_len = ares__buf_len(server->tcp_send);
2,741✔
1121

1122
    status = ares_dns_write_buf_tcp(query->query, server->tcp_send);
2,741✔
1123
    if (status != ARES_SUCCESS) {
2,741✔
1124
      return status;
×
1125
    }
1126

1127
    if (conn->flags & ARES_CONN_FLAG_TFO_INITIAL) {
2,741✔
1128
      /* When using TFO, we need to put it on the wire immediately. */
1129
      size_t               data_len;
1130
      const unsigned char *data = NULL;
715✔
1131

1132
      data = ares__buf_peek(server->tcp_send, &data_len);
715✔
1133
      len  = ares__conn_write(conn, data, data_len);
715✔
1134
      if (len <= 0) {
715✔
1135
        if (ares__socket_try_again(SOCKERRNO)) {
×
1136
          /* This means we must not have qualified for TFO, keep the data
1137
           * buffered, wait on write signal. */
1138
          return ARES_SUCCESS;
×
1139
        }
1140

1141
        /* TCP TFO might delay failure.  Reflect that here */
1142
        return ARES_ECONNREFUSED;
×
1143
      }
1144

1145
      /* Consume what was written */
1146
      ares__buf_consume(server->tcp_send, (size_t)len);
715✔
1147
      return ARES_SUCCESS;
715✔
1148
    }
1149

1150
    if (prior_len == 0) {
2,026✔
1151
      SOCK_STATE_CALLBACK(channel, conn->fd, 1, 1);
342✔
1152
    }
1153

1154
    return ARES_SUCCESS;
2,026✔
1155
  }
1156

1157
  /* UDP Here */
1158
  status = ares_dns_write(query->query, &qbuf, &qbuf_len);
3,132✔
1159
  if (status != ARES_SUCCESS) {
3,132✔
1160
    return status;
×
1161
  }
1162

1163
  len = ares__conn_write(conn, qbuf, qbuf_len);
3,132✔
1164
  ares_free(qbuf);
3,132✔
1165

1166
  if (len == -1) {
3,132✔
1167
    if (ares__socket_try_again(SOCKERRNO)) {
98✔
1168
      return ARES_ESERVFAIL;
×
1169
    }
1170
    /* UDP is connection-less, but we might receive an ICMP unreachable which
1171
     * means we can't talk to the remote host at all and that will be
1172
     * reflected here */
1173
    return ARES_ECONNREFUSED;
98✔
1174
  }
1175

1176
  return ARES_SUCCESS;
3,034✔
1177
}
1178

1179
ares_status_t ares__send_query(ares_query_t *query, const ares_timeval_t *now)
5,933✔
1180
{
1181
  ares_channel_t *channel = query->channel;
5,933✔
1182
  ares_server_t  *server;
1183
  ares_conn_t    *conn;
1184
  size_t          timeplus;
1185
  ares_status_t   status;
1186

1187
  /* Choose the server to send the query to */
1188
  if (channel->rotate) {
5,933✔
1189
    /* Pull random server */
1190
    server = ares__random_server(channel);
×
1191
  } else {
1192
    /* Pull server with failover behavior */
1193
    server = ares__failover_server(channel);
5,933✔
1194
  }
1195

1196
  if (server == NULL) {
5,933✔
1197
    end_query(channel, server, query, ARES_ENOSERVER /* ? */, NULL);
×
1198
    return ARES_ENOSERVER;
×
1199
  }
1200

1201
  conn = ares__fetch_connection(channel, server, query);
5,933✔
1202
  if (conn == NULL) {
5,933✔
1203
    status = ares__open_connection(&conn, channel, server, query->using_tcp);
1,697✔
1204
    switch (status) {
1,697✔
1205
      /* Good result, continue on */
1206
      case ARES_SUCCESS:
1,637✔
1207
        break;
1,637✔
1208

1209
      /* These conditions are retryable as they are server-specific
1210
       * error codes */
1211
      case ARES_ECONNREFUSED:
60✔
1212
      case ARES_EBADFAMILY:
1213
        server_increment_failures(server, query->using_tcp);
60✔
1214
        return ares__requeue_query(query, now, status, ARES_TRUE, NULL, NULL);
60✔
1215

1216
      /* Anything else is not retryable, likely ENOMEM */
1217
      default:
×
1218
        end_query(channel, server, query, status, NULL);
×
1219
        return status;
×
1220
    }
1221
  }
1222

1223
  /* Write the query */
1224
  status = ares__conn_query_write(conn, query, now);
5,873✔
1225
  switch (status) {
5,873✔
1226
    /* Good result, continue on */
1227
    case ARES_SUCCESS:
5,775✔
1228
      break;
5,775✔
1229

1230
    case ARES_ENOMEM:
×
1231
      /* Not retryable */
1232
      end_query(channel, server, query, status, NULL);
×
1233
      return status;
×
1234

1235
    /* These conditions are retryable as they are server-specific
1236
     * error codes */
1237
    case ARES_ECONNREFUSED:
98✔
1238
    case ARES_EBADFAMILY:
1239
      handle_conn_error(conn, ARES_TRUE, status);
98✔
1240
      status = ares__requeue_query(query, now, status, ARES_TRUE, NULL, NULL);
98✔
1241
      if (status == ARES_ETIMEOUT) {
98✔
1242
        status = ARES_ECONNREFUSED;
30✔
1243
      }
1244
      return status;
98✔
1245

1246
    /* FIXME: Handle EAGAIN here since it likely can happen. Right now we
1247
     * just requeue to a different server/connection. */
1248
    default:
×
1249
      server_increment_failures(server, query->using_tcp);
×
1250
      status = ares__requeue_query(query, now, status, ARES_TRUE, NULL, NULL);
×
1251
      return status;
×
1252
  }
1253

1254
  timeplus = ares__calc_query_timeout(query, server, now);
5,775✔
1255
  /* Keep track of queries bucketed by timeout, so we can process
1256
   * timeout events quickly.
1257
   */
1258
  ares__slist_node_destroy(query->node_queries_by_timeout);
5,775✔
1259
  query->ts      = *now;
5,775✔
1260
  query->timeout = *now;
5,775✔
1261
  timeadd(&query->timeout, timeplus);
5,775✔
1262
  query->node_queries_by_timeout =
5,775✔
1263
    ares__slist_insert(channel->queries_by_timeout, query);
5,775✔
1264
  if (!query->node_queries_by_timeout) {
5,775✔
1265
    /* LCOV_EXCL_START: OutOfMemory */
1266
    end_query(channel, server, query, ARES_ENOMEM, NULL);
1267
    return ARES_ENOMEM;
1268
    /* LCOV_EXCL_STOP */
1269
  }
1270

1271
  /* Keep track of queries bucketed by connection, so we can process errors
1272
   * quickly. */
1273
  ares__llist_node_destroy(query->node_queries_to_conn);
5,775✔
1274
  query->node_queries_to_conn =
5,775✔
1275
    ares__llist_insert_last(conn->queries_to_conn, query);
5,775✔
1276

1277
  if (query->node_queries_to_conn == NULL) {
5,775✔
1278
    /* LCOV_EXCL_START: OutOfMemory */
1279
    end_query(channel, server, query, ARES_ENOMEM, NULL);
1280
    return ARES_ENOMEM;
1281
    /* LCOV_EXCL_STOP */
1282
  }
1283

1284
  query->conn = conn;
5,775✔
1285
  conn->total_queries++;
5,775✔
1286
  return ARES_SUCCESS;
5,775✔
1287
}
1288

1289
static ares_bool_t same_questions(const ares_query_t      *query,
2,432✔
1290
                                  const ares_dns_record_t *arec)
1291
{
1292
  size_t                   i;
1293
  ares_bool_t              rv      = ARES_FALSE;
2,432✔
1294
  const ares_dns_record_t *qrec    = query->query;
2,432✔
1295
  const ares_channel_t    *channel = query->channel;
2,432✔
1296

1297

1298
  if (ares_dns_record_query_cnt(qrec) != ares_dns_record_query_cnt(arec)) {
2,432✔
1299
    goto done;
×
1300
  }
1301

1302
  for (i = 0; i < ares_dns_record_query_cnt(qrec); i++) {
4,858✔
1303
    const char         *qname = NULL;
2,432✔
1304
    const char         *aname = NULL;
2,432✔
1305
    ares_dns_rec_type_t qtype;
1306
    ares_dns_rec_type_t atype;
1307
    ares_dns_class_t    qclass;
1308
    ares_dns_class_t    aclass;
1309

1310
    if (ares_dns_record_query_get(qrec, i, &qname, &qtype, &qclass) !=
2,432✔
1311
          ARES_SUCCESS ||
2,432✔
1312
        qname == NULL) {
2,432✔
1313
      goto done;
6✔
1314
    }
1315

1316
    if (ares_dns_record_query_get(arec, i, &aname, &atype, &aclass) !=
2,432✔
1317
          ARES_SUCCESS ||
2,432✔
1318
        aname == NULL) {
2,432✔
1319
      goto done;
×
1320
    }
1321

1322
    if (qtype != atype || qclass != aclass) {
2,432✔
1323
      goto done;
×
1324
    }
1325

1326
    if (channel->flags & ARES_FLAG_DNS0x20 && !query->using_tcp) {
2,432✔
1327
      /* NOTE: for DNS 0x20, part of the protection is to use a case-sensitive
1328
       *       comparison of the DNS query name.  This expects the upstream DNS
1329
       *       server to preserve the case of the name in the response packet.
1330
       *       https://datatracker.ietf.org/doc/html/draft-vixie-dnsext-dns0x20-00
1331
       */
1332
      if (strcmp(qname, aname) != 0) {
1,024✔
1333
        goto done;
6✔
1334
      }
1335
    } else {
1336
      /* without DNS0x20 use case-insensitive matching */
1337
      if (strcasecmp(qname, aname) != 0) {
1,408✔
1338
        goto done;
×
1339
      }
1340
    }
1341
  }
1342

1343
  rv = ARES_TRUE;
2,426✔
1344

1345
done:
2,432✔
1346
  return rv;
2,432✔
1347
}
1348

1349
static ares_bool_t same_address(const struct sockaddr  *sa,
1,317✔
1350
                                const struct ares_addr *aa)
1351
{
1352
  const void *addr1;
1353
  const void *addr2;
1354

1355
  if (sa->sa_family == aa->family) {
1,317✔
1356
    switch (aa->family) {
1,317✔
1357
      case AF_INET:
679✔
1358
        addr1 = &aa->addr.addr4;
679✔
1359
        addr2 = &(CARES_INADDR_CAST(const struct sockaddr_in *, sa))->sin_addr;
679✔
1360
        if (memcmp(addr1, addr2, sizeof(aa->addr.addr4)) == 0) {
679✔
1361
          return ARES_TRUE; /* match */
679✔
1362
        }
1363
        break;
×
1364
      case AF_INET6:
638✔
1365
        addr1 = &aa->addr.addr6;
638✔
1366
        addr2 =
638✔
1367
          &(CARES_INADDR_CAST(const struct sockaddr_in6 *, sa))->sin6_addr;
1368
        if (memcmp(addr1, addr2, sizeof(aa->addr.addr6)) == 0) {
638✔
1369
          return ARES_TRUE; /* match */
638✔
1370
        }
1371
        break;
×
1372
      default:
×
1373
        break; /* LCOV_EXCL_LINE */
1374
    }
1375
  }
1376
  return ARES_FALSE; /* different */
×
1377
}
1378

1379
static void ares_detach_query(ares_query_t *query)
5,199✔
1380
{
1381
  /* Remove the query from all the lists in which it is linked */
1382
  ares__query_disassociate_from_conn(query);
5,199✔
1383
  ares__htable_szvp_remove(query->channel->queries_by_qid, query->qid);
5,199✔
1384
  ares__llist_node_destroy(query->node_all_queries);
5,199✔
1385
  query->node_all_queries = NULL;
5,199✔
1386
}
5,199✔
1387

1388
static void end_query(ares_channel_t *channel, ares_server_t *server,
2,112✔
1389
                      ares_query_t *query, ares_status_t status,
1390
                      const ares_dns_record_t *dnsrec)
1391
{
1392
  ares_metrics_record(query, server, status, dnsrec);
2,112✔
1393

1394
  /* Invoke the callback. */
1395
  query->callback(query->arg, status, query->timeouts, dnsrec);
2,112✔
1396
  ares__free_query(query);
2,112✔
1397

1398
  /* Check and notify if no other queries are enqueued on the channel.  This
1399
   * must come after the callback and freeing the query for 2 reasons.
1400
   *  1) The callback itself may enqueue a new query
1401
   *  2) Technically the current query isn't detached until it is free()'d.
1402
   */
1403
  ares_queue_notify_empty(channel);
2,112✔
1404
}
2,112✔
1405

1406
void ares__free_query(ares_query_t *query)
5,199✔
1407
{
1408
  ares_detach_query(query);
5,199✔
1409
  /* Zero out some important stuff, to help catch bugs */
1410
  query->callback = NULL;
5,199✔
1411
  query->arg      = NULL;
5,199✔
1412
  /* Deallocate the memory associated with the query */
1413
  ares_dns_record_destroy(query->query);
5,199✔
1414

1415
  ares_free(query);
5,199✔
1416
}
5,199✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc