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_private.h"
29
30 #ifdef HAVE_NETINET_IN_H
31 # include <netinet/in.h>
32 #endif
33
34 typedef struct {
35 ares_callback_dnsrec callback;
36 void *arg;
37 } ares_query_dnsrec_arg_t;
38
ares_query_dnsrec_cb(void * arg,ares_status_t status,size_t timeouts,const ares_dns_record_t * dnsrec)39 static void ares_query_dnsrec_cb(void *arg, ares_status_t status,
40 size_t timeouts,
41 const ares_dns_record_t *dnsrec)
42 {
43 ares_query_dnsrec_arg_t *qquery = arg;
44
45 if (status != ARES_SUCCESS) {
46 qquery->callback(qquery->arg, status, timeouts, dnsrec);
47 } else {
48 size_t ancount;
49 ares_dns_rcode_t rcode;
50 /* Pull the response code and answer count from the packet and convert any
51 * errors.
52 */
53 rcode = ares_dns_record_get_rcode(dnsrec);
54 ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER);
55 status = ares_dns_query_reply_tostatus(rcode, ancount);
56 qquery->callback(qquery->arg, status, timeouts, dnsrec);
57 }
58 ares_free(qquery);
59 }
60
ares_query_nolock(ares_channel_t * channel,const char * name,ares_dns_class_t dnsclass,ares_dns_rec_type_t type,ares_callback_dnsrec callback,void * arg,unsigned short * qid)61 ares_status_t ares_query_nolock(ares_channel_t *channel, const char *name,
62 ares_dns_class_t dnsclass,
63 ares_dns_rec_type_t type,
64 ares_callback_dnsrec callback, void *arg,
65 unsigned short *qid)
66 {
67 ares_status_t status;
68 ares_dns_record_t *dnsrec = NULL;
69 ares_dns_flags_t flags = 0;
70 ares_query_dnsrec_arg_t *qquery = NULL;
71
72 if (channel == NULL || name == NULL || callback == NULL) {
73 /* LCOV_EXCL_START: DefensiveCoding */
74 status = ARES_EFORMERR;
75 if (callback != NULL) {
76 callback(arg, status, 0, NULL);
77 }
78 return status;
79 /* LCOV_EXCL_STOP */
80 }
81
82 if (!(channel->flags & ARES_FLAG_NORECURSE)) {
83 flags |= ARES_FLAG_RD;
84 }
85
86 status = ares_dns_record_create_query(
87 &dnsrec, name, dnsclass, type, 0, flags,
88 (size_t)(channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : 0);
89 if (status != ARES_SUCCESS) {
90 callback(arg, status, 0, NULL); /* LCOV_EXCL_LINE: OutOfMemory */
91 return status; /* LCOV_EXCL_LINE: OutOfMemory */
92 }
93
94 qquery = ares_malloc(sizeof(*qquery));
95 if (qquery == NULL) {
96 /* LCOV_EXCL_START: OutOfMemory */
97 status = ARES_ENOMEM;
98 callback(arg, status, 0, NULL);
99 ares_dns_record_destroy(dnsrec);
100 return status;
101 /* LCOV_EXCL_STOP */
102 }
103
104 qquery->callback = callback;
105 qquery->arg = arg;
106
107 /* Send it off. qcallback will be called when we get an answer. */
108 status = ares_send_nolock(channel, NULL, 0, dnsrec, ares_query_dnsrec_cb,
109 qquery, qid);
110
111 ares_dns_record_destroy(dnsrec);
112 return status;
113 }
114
ares_query_dnsrec(ares_channel_t * channel,const char * name,ares_dns_class_t dnsclass,ares_dns_rec_type_t type,ares_callback_dnsrec callback,void * arg,unsigned short * qid)115 ares_status_t ares_query_dnsrec(ares_channel_t *channel, const char *name,
116 ares_dns_class_t dnsclass,
117 ares_dns_rec_type_t type,
118 ares_callback_dnsrec callback, void *arg,
119 unsigned short *qid)
120 {
121 ares_status_t status;
122
123 if (channel == NULL) {
124 return ARES_EFORMERR;
125 }
126
127 ares_channel_lock(channel);
128 status = ares_query_nolock(channel, name, dnsclass, type, callback, arg, qid);
129 ares_channel_unlock(channel);
130 return status;
131 }
132
ares_query(ares_channel_t * channel,const char * name,int dnsclass,int type,ares_callback callback,void * arg)133 void ares_query(ares_channel_t *channel, const char *name, int dnsclass,
134 int type, ares_callback callback, void *arg)
135 {
136 void *carg = NULL;
137
138 if (channel == NULL) {
139 return;
140 }
141
142 carg = ares_dnsrec_convert_arg(callback, arg);
143 if (carg == NULL) {
144 callback(arg, ARES_ENOMEM, 0, NULL, 0); /* LCOV_EXCL_LINE: OutOfMemory */
145 return; /* LCOV_EXCL_LINE: OutOfMemory */
146 }
147
148 ares_query_dnsrec(channel, name, (ares_dns_class_t)dnsclass,
149 (ares_dns_rec_type_t)type, ares_dnsrec_convert_cb, carg,
150 NULL);
151 }
152