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 40struct qquery { 41 ares_callback callback; 42 void *arg; 43}; 44 45static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, 46 int alen); 47 48ares_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 88void 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 99static 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