• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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