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