• 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 
generate_unique_qid(ares_channel_t * channel)40 static unsigned short generate_unique_qid(ares_channel_t *channel)
41 {
42   unsigned short id;
43 
44   do {
45     id = ares__generate_new_id(channel->rand_state);
46   } while (ares__htable_szvp_get(channel->queries_by_qid, id, NULL));
47 
48   return id;
49 }
50 
ares_send_ex(ares_channel_t * channel,const unsigned char * qbuf,size_t qlen,ares_callback callback,void * arg,unsigned short * qid)51 ares_status_t ares_send_ex(ares_channel_t *channel, const unsigned char *qbuf,
52                            size_t qlen, ares_callback callback, void *arg,
53                            unsigned short *qid)
54 {
55   struct query  *query;
56   size_t         packetsz;
57   struct timeval now = ares__tvnow();
58   ares_status_t  status;
59   unsigned short id   = generate_unique_qid(channel);
60   unsigned char *abuf = NULL;
61   size_t         alen = 0;
62 
63   /* Verify that the query is at least long enough to hold the header. */
64   if (qlen < HFIXEDSZ || qlen >= (1 << 16)) {
65     callback(arg, ARES_EBADQUERY, 0, NULL, 0);
66     return ARES_EBADQUERY;
67   }
68   if (ares__slist_len(channel->servers) == 0) {
69     callback(arg, ARES_ENOSERVER, 0, NULL, 0);
70     return ARES_ENOSERVER;
71   }
72 
73   /* Check query cache */
74   status = ares_qcache_fetch(channel, &now, qbuf, qlen, &abuf, &alen);
75   if (status != ARES_ENOTFOUND) {
76     /* ARES_SUCCESS means we retrieved the cache, anything else is a critical
77      * failure, all result in termination */
78     callback(arg, (int)status, 0, abuf, (int)alen);
79     ares_free(abuf);
80     return status;
81   }
82 
83   /* Allocate space for query and allocated fields. */
84   query = ares_malloc(sizeof(struct query));
85   if (!query) {
86     callback(arg, ARES_ENOMEM, 0, NULL, 0);
87     return ARES_ENOMEM;
88   }
89   memset(query, 0, sizeof(*query));
90 
91   query->channel = channel;
92   query->qbuf    = ares_malloc(qlen);
93   if (!query->qbuf) {
94     ares_free(query);
95     callback(arg, ARES_ENOMEM, 0, NULL, 0);
96     return ARES_ENOMEM;
97   }
98 
99   query->qid             = id;
100   query->timeout.tv_sec  = 0;
101   query->timeout.tv_usec = 0;
102 
103   /* Ignore first 2 bytes, assign our own query id */
104   query->qbuf[0] = (unsigned char)((id >> 8) & 0xFF);
105   query->qbuf[1] = (unsigned char)(id & 0xFF);
106   memcpy(query->qbuf + 2, qbuf + 2, qlen - 2);
107   query->qlen = qlen;
108 
109   /* Fill in query arguments. */
110   query->callback = callback;
111   query->arg      = arg;
112 
113   /* Initialize query status. */
114   query->try_count = 0;
115 
116   packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ;
117   query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > packetsz;
118 
119   query->error_status = ARES_SUCCESS;
120   query->timeouts     = 0;
121 
122   /* Initialize our list nodes. */
123   query->node_queries_by_timeout = NULL;
124   query->node_queries_to_conn    = NULL;
125 
126   /* Chain the query into the list of all queries. */
127   query->node_all_queries =
128     ares__llist_insert_last(channel->all_queries, query);
129   if (query->node_all_queries == NULL) {
130     callback(arg, ARES_ENOMEM, 0, NULL, 0);
131     ares__free_query(query);
132     return ARES_ENOMEM;
133   }
134 
135   /* Keep track of queries bucketed by qid, so we can process DNS
136    * responses quickly.
137    */
138   if (!ares__htable_szvp_insert(channel->queries_by_qid, query->qid, query)) {
139     callback(arg, ARES_ENOMEM, 0, NULL, 0);
140     ares__free_query(query);
141     return ARES_ENOMEM;
142   }
143 
144   /* Perform the first query action. */
145 
146   status = ares__send_query(query, &now);
147   if (status == ARES_SUCCESS && qid) {
148     *qid = id;
149   }
150   return status;
151 }
152 
ares_send(ares_channel_t * channel,const unsigned char * qbuf,int qlen,ares_callback callback,void * arg)153 void ares_send(ares_channel_t *channel, const unsigned char *qbuf, int qlen,
154                ares_callback callback, void *arg)
155 {
156   if (channel == NULL) {
157     return;
158   }
159 
160   ares__channel_lock(channel);
161 
162   ares_send_ex(channel, qbuf, (size_t)qlen, callback, arg, NULL);
163 
164   ares__channel_unlock(channel);
165 }
166 
ares_queue_active_queries(ares_channel_t * channel)167 size_t ares_queue_active_queries(ares_channel_t *channel)
168 {
169   size_t len;
170 
171   if (channel == NULL) {
172     return 0;
173   }
174 
175   ares__channel_lock(channel);
176 
177   len = ares__llist_len(channel->all_queries);
178 
179   ares__channel_unlock(channel);
180 
181   return len;
182 }
183