xref: /third_party/node/deps/cares/src/lib/ares_query.c (revision 1cb0ef41)
1/* MIT License
2 *
3 * Copyright (c) 1998 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
28#include "ares_setup.h"
29
30#ifdef HAVE_NETINET_IN_H
31#  include <netinet/in.h>
32#endif
33
34#include "ares_nameser.h"
35
36#include "ares.h"
37#include "ares_dns.h"
38#include "ares_private.h"
39
40struct qquery {
41  ares_callback callback;
42  void         *arg;
43};
44
45static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf,
46                      int alen);
47
48ares_status_t ares_query_qid(ares_channel_t *channel, const char *name,
49                             int dnsclass, int type, ares_callback callback,
50                             void *arg, unsigned short *qid)
51{
52  struct qquery *qquery;
53  unsigned char *qbuf;
54  int            qlen;
55  int            rd;
56  ares_status_t  status;
57
58  /* Compose the query. */
59  rd     = !(channel->flags & ARES_FLAG_NORECURSE);
60  status = (ares_status_t)ares_create_query(
61    name, dnsclass, type, 0, rd, &qbuf, &qlen,
62    (channel->flags & ARES_FLAG_EDNS) ? (int)channel->ednspsz : 0);
63  if (status != ARES_SUCCESS) {
64    if (qbuf != NULL) {
65      ares_free(qbuf);
66    }
67    callback(arg, (int)status, 0, NULL, 0);
68    return status;
69  }
70
71  /* Allocate and fill in the query structure. */
72  qquery = ares_malloc(sizeof(struct qquery));
73  if (!qquery) {
74    ares_free_string(qbuf);
75    callback(arg, ARES_ENOMEM, 0, NULL, 0);
76    return ARES_ENOMEM;
77  }
78  qquery->callback = callback;
79  qquery->arg      = arg;
80
81  /* Send it off.  qcallback will be called when we get an answer. */
82  status = ares_send_ex(channel, qbuf, (size_t)qlen, qcallback, qquery, qid);
83  ares_free_string(qbuf);
84
85  return status;
86}
87
88void ares_query(ares_channel_t *channel, const char *name, int dnsclass,
89                int type, ares_callback callback, void *arg)
90{
91  if (channel == NULL) {
92    return;
93  }
94  ares__channel_lock(channel);
95  ares_query_qid(channel, name, dnsclass, type, callback, arg, NULL);
96  ares__channel_unlock(channel);
97}
98
99static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf,
100                      int alen)
101{
102  struct qquery *qquery = (struct qquery *)arg;
103  size_t         ancount;
104  int            rcode;
105
106  if (status != ARES_SUCCESS) {
107    qquery->callback(qquery->arg, status, timeouts, abuf, alen);
108  } else {
109    /* Pull the response code and answer count from the packet. */
110    rcode   = DNS_HEADER_RCODE(abuf);
111    ancount = DNS_HEADER_ANCOUNT(abuf);
112
113    /* Convert errors. */
114    switch (rcode) {
115      case NOERROR:
116        status = (ancount > 0) ? ARES_SUCCESS : ARES_ENODATA;
117        break;
118      case FORMERR:
119        status = ARES_EFORMERR;
120        break;
121      case SERVFAIL:
122        status = ARES_ESERVFAIL;
123        break;
124      case NXDOMAIN:
125        status = ARES_ENOTFOUND;
126        break;
127      case NOTIMP:
128        status = ARES_ENOTIMP;
129        break;
130      case REFUSED:
131        status = ARES_EREFUSED;
132        break;
133      default:
134        break;
135    }
136    qquery->callback(qquery->arg, status, timeouts, abuf, alen);
137  }
138  ares_free(qquery);
139}
140