lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame^] | 1 | |
| 2 | /* Copyright 1998 by the Massachusetts Institute of Technology. |
| 3 | * |
| 4 | * Permission to use, copy, modify, and distribute this |
| 5 | * software and its documentation for any purpose and without |
| 6 | * fee is hereby granted, provided that the above copyright |
| 7 | * notice appear in all copies and that both that copyright |
| 8 | * notice and this permission notice appear in supporting |
| 9 | * documentation, and that the name of M.I.T. not be used in |
| 10 | * advertising or publicity pertaining to distribution of the |
| 11 | * software without specific, written prior permission. |
| 12 | * M.I.T. makes no representations about the suitability of |
| 13 | * this software for any purpose. It is provided "as is" |
| 14 | * without express or implied warranty. |
| 15 | */ |
| 16 | |
| 17 | #include "ares_setup.h" |
| 18 | |
| 19 | #ifdef HAVE_NETINET_IN_H |
| 20 | # include <netinet/in.h> |
| 21 | #endif |
| 22 | #ifdef HAVE_ARPA_NAMESER_H |
| 23 | # include <arpa/nameser.h> |
| 24 | #else |
| 25 | # include "nameser.h" |
| 26 | #endif |
| 27 | #ifdef HAVE_ARPA_NAMESER_COMPAT_H |
| 28 | # include <arpa/nameser_compat.h> |
| 29 | #endif |
| 30 | |
| 31 | #include "ares.h" |
| 32 | #include "ares_dns.h" |
| 33 | #include "ares_private.h" |
| 34 | |
| 35 | void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen, |
| 36 | ares_callback callback, void *arg) |
| 37 | { |
| 38 | struct query *query; |
| 39 | int i, packetsz; |
| 40 | struct timeval now; |
| 41 | |
| 42 | /* Verify that the query is at least long enough to hold the header. */ |
| 43 | if (qlen < HFIXEDSZ || qlen >= (1 << 16)) |
| 44 | { |
| 45 | callback(arg, ARES_EBADQUERY, 0, NULL, 0); |
| 46 | return; |
| 47 | } |
| 48 | |
| 49 | /* Allocate space for query and allocated fields. */ |
| 50 | query = ares_malloc(sizeof(struct query)); |
| 51 | if (!query) |
| 52 | { |
| 53 | callback(arg, ARES_ENOMEM, 0, NULL, 0); |
| 54 | return; |
| 55 | } |
| 56 | query->tcpbuf = ares_malloc(qlen + 2); |
| 57 | if (!query->tcpbuf) |
| 58 | { |
| 59 | ares_free(query); |
| 60 | callback(arg, ARES_ENOMEM, 0, NULL, 0); |
| 61 | return; |
| 62 | } |
| 63 | query->server_info = ares_malloc(channel->nservers * |
| 64 | sizeof(query->server_info[0])); |
| 65 | if (!query->server_info) |
| 66 | { |
| 67 | ares_free(query->tcpbuf); |
| 68 | ares_free(query); |
| 69 | callback(arg, ARES_ENOMEM, 0, NULL, 0); |
| 70 | return; |
| 71 | } |
| 72 | |
| 73 | /* Compute the query ID. Start with no timeout. */ |
| 74 | query->qid = DNS_HEADER_QID(qbuf); |
| 75 | query->timeout.tv_sec = 0; |
| 76 | query->timeout.tv_usec = 0; |
| 77 | |
| 78 | /* Form the TCP query buffer by prepending qlen (as two |
| 79 | * network-order bytes) to qbuf. |
| 80 | */ |
| 81 | query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff); |
| 82 | query->tcpbuf[1] = (unsigned char)(qlen & 0xff); |
| 83 | memcpy(query->tcpbuf + 2, qbuf, qlen); |
| 84 | query->tcplen = qlen + 2; |
| 85 | |
| 86 | /* Fill in query arguments. */ |
| 87 | query->qbuf = query->tcpbuf + 2; |
| 88 | query->qlen = qlen; |
| 89 | query->callback = callback; |
| 90 | query->arg = arg; |
| 91 | |
| 92 | /* Initialize query status. */ |
| 93 | query->try_count = 0; |
| 94 | |
| 95 | /* Choose the server to send the query to. If rotation is enabled, keep track |
| 96 | * of the next server we want to use. */ |
| 97 | query->server = channel->last_server; |
| 98 | if (channel->rotate == 1) |
| 99 | channel->last_server = (channel->last_server + 1) % channel->nservers; |
| 100 | |
| 101 | for (i = 0; i < channel->nservers; i++) |
| 102 | { |
| 103 | query->server_info[i].skip_server = 0; |
| 104 | query->server_info[i].tcp_connection_generation = 0; |
| 105 | } |
| 106 | |
| 107 | packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ; |
| 108 | query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > packetsz; |
| 109 | |
| 110 | query->error_status = ARES_ECONNREFUSED; |
| 111 | query->timeouts = 0; |
| 112 | |
| 113 | /* Initialize our list nodes. */ |
| 114 | ares__init_list_node(&(query->queries_by_qid), query); |
| 115 | ares__init_list_node(&(query->queries_by_timeout), query); |
| 116 | ares__init_list_node(&(query->queries_to_server), query); |
| 117 | ares__init_list_node(&(query->all_queries), query); |
| 118 | |
| 119 | /* Chain the query into the list of all queries. */ |
| 120 | ares__insert_in_list(&(query->all_queries), &(channel->all_queries)); |
| 121 | /* Keep track of queries bucketed by qid, so we can process DNS |
| 122 | * responses quickly. |
| 123 | */ |
| 124 | ares__insert_in_list( |
| 125 | &(query->queries_by_qid), |
| 126 | &(channel->queries_by_qid[query->qid % ARES_QID_TABLE_SIZE])); |
| 127 | |
| 128 | /* Perform the first query action. */ |
| 129 | now = ares__tvnow(); |
| 130 | ares__send_query(channel, query, &now); |
| 131 | } |