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
40 struct qquery {
41 ares_callback callback;
42 void *arg;
43 };
44
45 static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf,
46 int alen);
47
ares_query_qid(ares_channel_t * channel,const char * name,int dnsclass,int type,ares_callback callback,void * arg,unsigned short * qid)48 ares_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
ares_query(ares_channel_t * channel,const char * name,int dnsclass,int type,ares_callback callback,void * arg)88 void 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
qcallback(void * arg,int status,int timeouts,unsigned char * abuf,int alen)99 static 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