%PDF- %PDF-
| Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/cares/src/lib/ |
| Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/cares/src/lib/ares_gethostbyaddr.c |
/* MIT License
*
* Copyright (c) 1998 Massachusetts Institute of Technology
* Copyright (c) The c-ares project and its contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* SPDX-License-Identifier: MIT
*/
#include "ares_setup.h"
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#include "ares_nameser.h"
#include "ares.h"
#include "ares_inet_net_pton.h"
#include "ares_platform.h"
#include "ares_private.h"
#ifdef WATT32
# undef WIN32
#endif
struct addr_query {
/* Arguments passed to ares_gethostbyaddr() */
ares_channel_t *channel;
struct ares_addr addr;
ares_host_callback callback;
void *arg;
char *lookups; /* duplicate memory from channel for ares_reinit() */
const char *remaining_lookups;
size_t timeouts;
};
static void next_lookup(struct addr_query *aquery);
static void addr_callback(void *arg, int status, int timeouts,
unsigned char *abuf, int alen);
static void end_aquery(struct addr_query *aquery, ares_status_t status,
struct hostent *host);
static ares_status_t file_lookup(ares_channel_t *channel,
const struct ares_addr *addr,
struct hostent **host);
static void ares_gethostbyaddr_int(ares_channel_t *channel, const void *addr,
int addrlen, int family,
ares_host_callback callback, void *arg)
{
struct addr_query *aquery;
if (family != AF_INET && family != AF_INET6) {
callback(arg, ARES_ENOTIMP, 0, NULL);
return;
}
if ((family == AF_INET && addrlen != sizeof(aquery->addr.addr.addr4)) ||
(family == AF_INET6 && addrlen != sizeof(aquery->addr.addr.addr6))) {
callback(arg, ARES_ENOTIMP, 0, NULL);
return;
}
aquery = ares_malloc(sizeof(struct addr_query));
if (!aquery) {
callback(arg, ARES_ENOMEM, 0, NULL);
return;
}
aquery->lookups = ares_strdup(channel->lookups);
if (aquery->lookups == NULL) {
ares_free(aquery);
callback(arg, ARES_ENOMEM, 0, NULL);
return;
}
aquery->channel = channel;
if (family == AF_INET) {
memcpy(&aquery->addr.addr.addr4, addr, sizeof(aquery->addr.addr.addr4));
} else {
memcpy(&aquery->addr.addr.addr6, addr, sizeof(aquery->addr.addr.addr6));
}
aquery->addr.family = family;
aquery->callback = callback;
aquery->arg = arg;
aquery->remaining_lookups = aquery->lookups;
aquery->timeouts = 0;
next_lookup(aquery);
}
void ares_gethostbyaddr(ares_channel_t *channel, const void *addr, int addrlen,
int family, ares_host_callback callback, void *arg)
{
if (channel == NULL) {
return;
}
ares__channel_lock(channel);
ares_gethostbyaddr_int(channel, addr, addrlen, family, callback, arg);
ares__channel_unlock(channel);
}
static void next_lookup(struct addr_query *aquery)
{
const char *p;
ares_status_t status;
struct hostent *host;
char *name;
for (p = aquery->remaining_lookups; *p; p++) {
switch (*p) {
case 'b':
name = ares_dns_addr_to_ptr(&aquery->addr);
if (name == NULL) {
end_aquery(aquery, ARES_ENOMEM, NULL);
return;
}
aquery->remaining_lookups = p + 1;
ares_query(aquery->channel, name, C_IN, T_PTR, addr_callback, aquery);
ares_free(name);
return;
case 'f':
status = file_lookup(aquery->channel, &aquery->addr, &host);
/* this status check below previously checked for !ARES_ENOTFOUND,
but we should not assume that this single error code is the one
that can occur, as that is in fact no longer the case */
if (status == ARES_SUCCESS) {
end_aquery(aquery, status, host);
return;
}
break;
default:
break;
}
}
end_aquery(aquery, ARES_ENOTFOUND, NULL);
}
static void addr_callback(void *arg, int status, int timeouts,
unsigned char *abuf, int alen)
{
struct addr_query *aquery = (struct addr_query *)arg;
struct hostent *host;
size_t addrlen;
aquery->timeouts += (size_t)timeouts;
if (status == ARES_SUCCESS) {
if (aquery->addr.family == AF_INET) {
addrlen = sizeof(aquery->addr.addr.addr4);
status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addr.addr4,
(int)addrlen, AF_INET, &host);
} else {
addrlen = sizeof(aquery->addr.addr.addr6);
status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addr.addr6,
(int)addrlen, AF_INET6, &host);
}
end_aquery(aquery, (ares_status_t)status, host);
} else if (status == ARES_EDESTRUCTION || status == ARES_ECANCELLED) {
end_aquery(aquery, (ares_status_t)status, NULL);
} else {
next_lookup(aquery);
}
}
static void end_aquery(struct addr_query *aquery, ares_status_t status,
struct hostent *host)
{
aquery->callback(aquery->arg, (int)status, (int)aquery->timeouts, host);
if (host) {
ares_free_hostent(host);
}
ares_free(aquery->lookups);
ares_free(aquery);
}
static ares_status_t file_lookup(ares_channel_t *channel,
const struct ares_addr *addr,
struct hostent **host)
{
char ipaddr[INET6_ADDRSTRLEN];
const void *ptr = NULL;
const ares_hosts_entry_t *entry;
ares_status_t status;
if (addr->family == AF_INET) {
ptr = &addr->addr.addr4;
} else if (addr->family == AF_INET6) {
ptr = &addr->addr.addr6;
}
if (ptr == NULL) {
return ARES_ENOTFOUND;
}
if (!ares_inet_ntop(addr->family, ptr, ipaddr, sizeof(ipaddr))) {
return ARES_ENOTFOUND;
}
status = ares__hosts_search_ipaddr(channel, ARES_FALSE, ipaddr, &entry);
if (status != ARES_SUCCESS) {
return status;
}
status = ares__hosts_entry_to_hostent(entry, addr->family, host);
if (status != ARES_SUCCESS) {
return status;
}
return ARES_SUCCESS;
}