ares_query.c (5128B)
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_private.h" 29 30 #ifdef HAVE_NETINET_IN_H 31 # include <netinet/in.h> 32 #endif 33 34 typedef struct { 35 ares_callback_dnsrec callback; 36 void *arg; 37 } ares_query_dnsrec_arg_t; 38 39 static void ares_query_dnsrec_cb(void *arg, ares_status_t status, 40 size_t timeouts, 41 const ares_dns_record_t *dnsrec) 42 { 43 ares_query_dnsrec_arg_t *qquery = arg; 44 45 if (status != ARES_SUCCESS) { 46 qquery->callback(qquery->arg, status, timeouts, dnsrec); 47 } else { 48 size_t ancount; 49 ares_dns_rcode_t rcode; 50 /* Pull the response code and answer count from the packet and convert any 51 * errors. 52 */ 53 rcode = ares_dns_record_get_rcode(dnsrec); 54 ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); 55 status = ares_dns_query_reply_tostatus(rcode, ancount); 56 qquery->callback(qquery->arg, status, timeouts, dnsrec); 57 } 58 ares_free(qquery); 59 } 60 61 ares_status_t ares_query_nolock(ares_channel_t *channel, const char *name, 62 ares_dns_class_t dnsclass, 63 ares_dns_rec_type_t type, 64 ares_callback_dnsrec callback, void *arg, 65 unsigned short *qid) 66 { 67 ares_status_t status; 68 ares_dns_record_t *dnsrec = NULL; 69 ares_dns_flags_t flags = 0; 70 ares_query_dnsrec_arg_t *qquery = NULL; 71 72 if (channel == NULL || name == NULL || callback == NULL) { 73 /* LCOV_EXCL_START: DefensiveCoding */ 74 status = ARES_EFORMERR; 75 if (callback != NULL) { 76 callback(arg, status, 0, NULL); 77 } 78 return status; 79 /* LCOV_EXCL_STOP */ 80 } 81 82 if (!(channel->flags & ARES_FLAG_NORECURSE)) { 83 flags |= ARES_FLAG_RD; 84 } 85 86 status = ares_dns_record_create_query( 87 &dnsrec, name, dnsclass, type, 0, flags, 88 (size_t)(channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : 0); 89 if (status != ARES_SUCCESS) { 90 callback(arg, status, 0, NULL); /* LCOV_EXCL_LINE: OutOfMemory */ 91 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 92 } 93 94 qquery = ares_malloc(sizeof(*qquery)); 95 if (qquery == NULL) { 96 /* LCOV_EXCL_START: OutOfMemory */ 97 status = ARES_ENOMEM; 98 callback(arg, status, 0, NULL); 99 ares_dns_record_destroy(dnsrec); 100 return status; 101 /* LCOV_EXCL_STOP */ 102 } 103 104 qquery->callback = callback; 105 qquery->arg = arg; 106 107 /* Send it off. qcallback will be called when we get an answer. */ 108 status = ares_send_nolock(channel, NULL, 0, dnsrec, ares_query_dnsrec_cb, 109 qquery, qid); 110 111 ares_dns_record_destroy(dnsrec); 112 return status; 113 } 114 115 ares_status_t ares_query_dnsrec(ares_channel_t *channel, const char *name, 116 ares_dns_class_t dnsclass, 117 ares_dns_rec_type_t type, 118 ares_callback_dnsrec callback, void *arg, 119 unsigned short *qid) 120 { 121 ares_status_t status; 122 123 if (channel == NULL) { 124 return ARES_EFORMERR; 125 } 126 127 ares_channel_lock(channel); 128 status = ares_query_nolock(channel, name, dnsclass, type, callback, arg, qid); 129 ares_channel_unlock(channel); 130 return status; 131 } 132 133 void ares_query(ares_channel_t *channel, const char *name, int dnsclass, 134 int type, ares_callback callback, void *arg) 135 { 136 void *carg = NULL; 137 138 if (channel == NULL) { 139 return; 140 } 141 142 carg = ares_dnsrec_convert_arg(callback, arg); 143 if (carg == NULL) { 144 callback(arg, ARES_ENOMEM, 0, NULL, 0); /* LCOV_EXCL_LINE: OutOfMemory */ 145 return; /* LCOV_EXCL_LINE: OutOfMemory */ 146 } 147 148 ares_query_dnsrec(channel, name, (ares_dns_class_t)dnsclass, 149 (ares_dns_rec_type_t)type, ares_dnsrec_convert_cb, carg, 150 NULL); 151 }