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