Coverage Report

Created: 2024-10-08 17:38

/src/c-ares/src/lib/ares_gethostbyaddr.c
Line
Count
Source (jump to first uncovered line)
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
#ifdef HAVE_NETDB_H
34
#  include <netdb.h>
35
#endif
36
#ifdef HAVE_ARPA_INET_H
37
#  include <arpa/inet.h>
38
#endif
39
40
#include "ares_nameser.h"
41
#include "ares_inet_net_pton.h"
42
43
struct addr_query {
44
  /* Arguments passed to ares_gethostbyaddr() */
45
  ares_channel_t    *channel;
46
  struct ares_addr   addr;
47
  ares_host_callback callback;
48
  void              *arg;
49
  char       *lookups; /* duplicate memory from channel for ares_reinit() */
50
  const char *remaining_lookups;
51
  size_t      timeouts;
52
};
53
54
static void next_lookup(struct addr_query *aquery);
55
static void addr_callback(void *arg, ares_status_t status, size_t timeouts,
56
                          const ares_dns_record_t *dnsrec);
57
static void end_aquery(struct addr_query *aquery, ares_status_t status,
58
                       struct hostent *host);
59
static ares_status_t file_lookup(ares_channel_t         *channel,
60
                                 const struct ares_addr *addr,
61
                                 struct hostent        **host);
62
63
void ares_gethostbyaddr_nolock(ares_channel_t *channel, const void *addr,
64
                               int addrlen, int family,
65
                               ares_host_callback callback, void *arg)
66
0
{
67
0
  struct addr_query *aquery;
68
69
0
  if (family != AF_INET && family != AF_INET6) {
70
0
    callback(arg, ARES_ENOTIMP, 0, NULL);
71
0
    return;
72
0
  }
73
74
0
  if ((family == AF_INET && addrlen != sizeof(aquery->addr.addr.addr4)) ||
75
0
      (family == AF_INET6 && addrlen != sizeof(aquery->addr.addr.addr6))) {
76
0
    callback(arg, ARES_ENOTIMP, 0, NULL);
77
0
    return;
78
0
  }
79
80
0
  aquery = ares_malloc(sizeof(struct addr_query));
81
0
  if (!aquery) {
82
0
    callback(arg, ARES_ENOMEM, 0, NULL);
83
0
    return;
84
0
  }
85
0
  aquery->lookups = ares_strdup(channel->lookups);
86
0
  if (aquery->lookups == NULL) {
87
    /* LCOV_EXCL_START: OutOfMemory */
88
0
    ares_free(aquery);
89
0
    callback(arg, ARES_ENOMEM, 0, NULL);
90
0
    return;
91
    /* LCOV_EXCL_STOP */
92
0
  }
93
0
  aquery->channel = channel;
94
0
  if (family == AF_INET) {
95
0
    memcpy(&aquery->addr.addr.addr4, addr, sizeof(aquery->addr.addr.addr4));
96
0
  } else {
97
0
    memcpy(&aquery->addr.addr.addr6, addr, sizeof(aquery->addr.addr.addr6));
98
0
  }
99
0
  aquery->addr.family       = family;
100
0
  aquery->callback          = callback;
101
0
  aquery->arg               = arg;
102
0
  aquery->remaining_lookups = aquery->lookups;
103
0
  aquery->timeouts          = 0;
104
105
0
  next_lookup(aquery);
106
0
}
107
108
void ares_gethostbyaddr(ares_channel_t *channel, const void *addr, int addrlen,
109
                        int family, ares_host_callback callback, void *arg)
110
0
{
111
0
  if (channel == NULL) {
112
0
    return;
113
0
  }
114
0
  ares_channel_lock(channel);
115
0
  ares_gethostbyaddr_nolock(channel, addr, addrlen, family, callback, arg);
116
0
  ares_channel_unlock(channel);
117
0
}
118
119
static void next_lookup(struct addr_query *aquery)
120
0
{
121
0
  const char     *p;
122
0
  ares_status_t   status;
123
0
  struct hostent *host;
124
0
  char           *name;
125
126
0
  for (p = aquery->remaining_lookups; *p; p++) {
127
0
    switch (*p) {
128
0
      case 'b':
129
0
        name = ares_dns_addr_to_ptr(&aquery->addr);
130
0
        if (name == NULL) {
131
0
          end_aquery(aquery, ARES_ENOMEM,
132
0
                     NULL); /* LCOV_EXCL_LINE: OutOfMemory */
133
0
          return;           /* LCOV_EXCL_LINE: OutOfMemory */
134
0
        }
135
0
        aquery->remaining_lookups = p + 1;
136
0
        ares_query_nolock(aquery->channel, name, ARES_CLASS_IN,
137
0
                          ARES_REC_TYPE_PTR, addr_callback, aquery, NULL);
138
0
        ares_free(name);
139
0
        return;
140
0
      case 'f':
141
0
        status = file_lookup(aquery->channel, &aquery->addr, &host);
142
143
        /* this status check below previously checked for !ARES_ENOTFOUND,
144
           but we should not assume that this single error code is the one
145
           that can occur, as that is in fact no longer the case */
146
0
        if (status == ARES_SUCCESS) {
147
0
          end_aquery(aquery, status, host);
148
0
          return;
149
0
        }
150
0
        break;
151
0
      default:
152
0
        break;
153
0
    }
154
0
  }
155
0
  end_aquery(aquery, ARES_ENOTFOUND, NULL);
156
0
}
157
158
static void addr_callback(void *arg, ares_status_t status, size_t timeouts,
159
                          const ares_dns_record_t *dnsrec)
160
0
{
161
0
  struct addr_query *aquery = (struct addr_query *)arg;
162
0
  struct hostent    *host;
163
0
  size_t             addrlen;
164
165
0
  aquery->timeouts += timeouts;
166
0
  if (status == ARES_SUCCESS) {
167
0
    if (aquery->addr.family == AF_INET) {
168
0
      addrlen = sizeof(aquery->addr.addr.addr4);
169
0
      status  = ares_parse_ptr_reply_dnsrec(dnsrec, &aquery->addr.addr.addr4,
170
0
                                            (int)addrlen, AF_INET, &host);
171
0
    } else {
172
0
      addrlen = sizeof(aquery->addr.addr.addr6);
173
0
      status  = ares_parse_ptr_reply_dnsrec(dnsrec, &aquery->addr.addr.addr6,
174
0
                                            (int)addrlen, AF_INET6, &host);
175
0
    }
176
0
    end_aquery(aquery, status, host);
177
0
  } else if (status == ARES_EDESTRUCTION || status == ARES_ECANCELLED) {
178
0
    end_aquery(aquery, status, NULL);
179
0
  } else {
180
0
    next_lookup(aquery);
181
0
  }
182
0
}
183
184
static void end_aquery(struct addr_query *aquery, ares_status_t status,
185
                       struct hostent *host)
186
0
{
187
0
  aquery->callback(aquery->arg, (int)status, (int)aquery->timeouts, host);
188
0
  if (host) {
189
0
    ares_free_hostent(host);
190
0
  }
191
0
  ares_free(aquery->lookups);
192
0
  ares_free(aquery);
193
0
}
194
195
static ares_status_t file_lookup(ares_channel_t         *channel,
196
                                 const struct ares_addr *addr,
197
                                 struct hostent        **host)
198
0
{
199
0
  char                      ipaddr[INET6_ADDRSTRLEN];
200
0
  const void               *ptr = NULL;
201
0
  const ares_hosts_entry_t *entry;
202
0
  ares_status_t             status;
203
204
0
  if (addr->family == AF_INET) {
205
0
    ptr = &addr->addr.addr4;
206
0
  } else if (addr->family == AF_INET6) {
207
0
    ptr = &addr->addr.addr6;
208
0
  }
209
210
0
  if (ptr == NULL) {
211
0
    return ARES_ENOTFOUND;
212
0
  }
213
214
0
  if (!ares_inet_ntop(addr->family, ptr, ipaddr, sizeof(ipaddr))) {
215
0
    return ARES_ENOTFOUND;
216
0
  }
217
218
0
  status = ares_hosts_search_ipaddr(channel, ARES_FALSE, ipaddr, &entry);
219
0
  if (status != ARES_SUCCESS) {
220
0
    return status;
221
0
  }
222
223
0
  status = ares_hosts_entry_to_hostent(entry, addr->family, host);
224
0
  if (status != ARES_SUCCESS) {
225
0
    return status; /* LCOV_EXCL_LINE: OutOfMemory */
226
0
  }
227
228
0
  return ARES_SUCCESS;
229
0
}