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 40static 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 51ares_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 153void 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 167size_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