ares_getnameinfo.c
Go to the documentation of this file.
1 
2 /* Copyright 2005 by Dominick Meglio
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 #include "ares_setup.h"
17 
18 #ifdef HAVE_GETSERVBYPORT_R
19 # if !defined(GETSERVBYPORT_R_ARGS) || \
20  (GETSERVBYPORT_R_ARGS < 4) || (GETSERVBYPORT_R_ARGS > 6)
21 # error "you MUST specifiy a valid number of arguments for getservbyport_r"
22 # endif
23 #endif
24 
25 #ifdef HAVE_NETINET_IN_H
26 # include <netinet/in.h>
27 #endif
28 #ifdef HAVE_NETDB_H
29 # include <netdb.h>
30 #endif
31 #ifdef HAVE_ARPA_INET_H
32 # include <arpa/inet.h>
33 #endif
34 
35 #include "ares_nameser.h"
36 
37 #ifdef HAVE_NET_IF_H
38 #include <net/if.h>
39 #endif
40 
41 #include "ares.h"
42 #include "ares_ipv6.h"
43 #include "ares_nowarn.h"
44 #include "ares_private.h"
45 
48  void *arg;
49  union {
50  struct sockaddr_in addr4;
52  } addr;
53  int family;
54  int flags;
55  int timeouts;
56 };
57 
58 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
59 #define IPBUFSIZ \
60  (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") + IF_NAMESIZE)
61 #else
62 #define IPBUFSIZ \
63  (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"))
64 #endif
65 
66 static void nameinfo_callback(void *arg, int status, int timeouts,
67  struct hostent *host);
68 static char *lookup_service(unsigned short port, int flags,
69  char *buf, size_t buflen);
70 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
71 static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int scopeid,
72  char *buf, size_t buflen);
73 #endif
74 STATIC_TESTABLE char *ares_striendstr(const char *s1, const char *s2);
75 
76 void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa,
77  ares_socklen_t salen,
79 {
80  struct sockaddr_in *addr = NULL;
81  struct sockaddr_in6 *addr6 = NULL;
82  struct nameinfo_query *niquery;
83  unsigned int port = 0;
84 
85  /* Validate socket address family and length */
86  if ((sa->sa_family == AF_INET) &&
87  (salen == sizeof(struct sockaddr_in)))
88  {
89  addr = CARES_INADDR_CAST(struct sockaddr_in *, sa);
90  port = addr->sin_port;
91  }
92  else if ((sa->sa_family == AF_INET6) &&
93  (salen == sizeof(struct sockaddr_in6)))
94  {
95  addr6 = CARES_INADDR_CAST(struct sockaddr_in6 *, sa);
96  port = addr6->sin6_port;
97  }
98  else
99  {
100  callback(arg, ARES_ENOTIMP, 0, NULL, NULL);
101  return;
102  }
103 
104  /* If neither, assume they want a host */
107 
108  /* All they want is a service, no need for DNS */
110  {
111  char buf[33], *service;
112 
113  service = lookup_service((unsigned short)(port & 0xffff),
114  flags, buf, sizeof(buf));
115  callback(arg, ARES_SUCCESS, 0, NULL, service);
116  return;
117  }
118 
119  /* They want a host lookup */
120  if ((flags & ARES_NI_LOOKUPHOST))
121  {
122  /* A numeric host can be handled without DNS */
123  if ((flags & ARES_NI_NUMERICHOST))
124  {
125  char ipbuf[IPBUFSIZ];
126  char srvbuf[33];
127  char *service = NULL;
128  ipbuf[0] = 0;
129 
130  /* Specifying not to lookup a host, but then saying a host
131  * is required has to be illegal.
132  */
133  if (flags & ARES_NI_NAMEREQD)
134  {
135  callback(arg, ARES_EBADFLAGS, 0, NULL, NULL);
136  return;
137  }
138  if (salen == sizeof(struct sockaddr_in6))
139  {
141  /* If the system supports scope IDs, use it */
142 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
143  append_scopeid(addr6, flags, ipbuf, sizeof(ipbuf));
144 #endif
145  }
146  else
147  {
148  ares_inet_ntop(AF_INET, &addr->sin_addr, ipbuf, IPBUFSIZ);
149  }
150  /* They also want a service */
152  service = lookup_service((unsigned short)(port & 0xffff),
153  flags, srvbuf, sizeof(srvbuf));
154  callback(arg, ARES_SUCCESS, 0, ipbuf, service);
155  return;
156  }
157  /* This is where a DNS lookup becomes necessary */
158  else
159  {
160  niquery = ares_malloc(sizeof(struct nameinfo_query));
161  if (!niquery)
162  {
163  callback(arg, ARES_ENOMEM, 0, NULL, NULL);
164  return;
165  }
166  niquery->callback = callback;
167  niquery->arg = arg;
168  niquery->flags = flags;
169  niquery->timeouts = 0;
170  if (sa->sa_family == AF_INET)
171  {
172  niquery->family = AF_INET;
173  memcpy(&niquery->addr.addr4, addr, sizeof(niquery->addr.addr4));
174  ares_gethostbyaddr(channel, &addr->sin_addr,
175  sizeof(struct in_addr), AF_INET,
176  nameinfo_callback, niquery);
177  }
178  else
179  {
180  niquery->family = AF_INET6;
181  memcpy(&niquery->addr.addr6, addr6, sizeof(niquery->addr.addr6));
183  sizeof(struct ares_in6_addr), AF_INET6,
184  nameinfo_callback, niquery);
185  }
186  }
187  }
188 }
189 
190 static void nameinfo_callback(void *arg, int status, int timeouts,
191  struct hostent *host)
192 {
193  struct nameinfo_query *niquery = (struct nameinfo_query *) arg;
194  char srvbuf[33];
195  char *service = NULL;
196 
197  niquery->timeouts += timeouts;
198  if (status == ARES_SUCCESS)
199  {
200  /* They want a service too */
201  if (niquery->flags & ARES_NI_LOOKUPSERVICE)
202  {
203  if (niquery->family == AF_INET)
204  service = lookup_service(niquery->addr.addr4.sin_port,
205  niquery->flags, srvbuf, sizeof(srvbuf));
206  else
208  niquery->flags, srvbuf, sizeof(srvbuf));
209  }
210  /* NOFQDN means we have to strip off the domain name portion. We do
211  this by determining our own domain name, then searching the string
212  for this domain name and removing it.
213  */
214 #ifdef HAVE_GETHOSTNAME
215  if (niquery->flags & ARES_NI_NOFQDN)
216  {
217  char buf[255];
218  char *domain;
219  gethostname(buf, 255);
220  if ((domain = strchr(buf, '.')) != NULL)
221  {
222  char *end = ares_striendstr(host->h_name, domain);
223  if (end)
224  *end = 0;
225  }
226  }
227 #endif
228  niquery->callback(niquery->arg, ARES_SUCCESS, niquery->timeouts,
229  (char *)(host->h_name),
230  service);
231  ares_free(niquery);
232  return;
233  }
234  /* We couldn't find the host, but it's OK, we can use the IP */
235  else if (status == ARES_ENOTFOUND && !(niquery->flags & ARES_NI_NAMEREQD))
236  {
237  char ipbuf[IPBUFSIZ];
238  if (niquery->family == AF_INET)
239  ares_inet_ntop(AF_INET, &niquery->addr.addr4.sin_addr, ipbuf,
240  IPBUFSIZ);
241  else
242  {
243  ares_inet_ntop(AF_INET6, &niquery->addr.addr6.sin6_addr, ipbuf,
244  IPBUFSIZ);
245 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
246  append_scopeid(&niquery->addr.addr6, niquery->flags, ipbuf,
247  sizeof(ipbuf));
248 #endif
249  }
250  /* They want a service too */
251  if (niquery->flags & ARES_NI_LOOKUPSERVICE)
252  {
253  if (niquery->family == AF_INET)
254  service = lookup_service(niquery->addr.addr4.sin_port,
255  niquery->flags, srvbuf, sizeof(srvbuf));
256  else
258  niquery->flags, srvbuf, sizeof(srvbuf));
259  }
260  niquery->callback(niquery->arg, ARES_SUCCESS, niquery->timeouts, ipbuf,
261  service);
262  ares_free(niquery);
263  return;
264  }
265  niquery->callback(niquery->arg, status, niquery->timeouts, NULL, NULL);
266  ares_free(niquery);
267 }
268 
269 static char *lookup_service(unsigned short port, int flags,
270  char *buf, size_t buflen)
271 {
272  const char *proto;
273  struct servent *sep;
274 #ifdef HAVE_GETSERVBYPORT_R
275  struct servent se;
276 #endif
277  char tmpbuf[4096];
278  char *name;
279  size_t name_len;
280 
281  if (port)
282  {
284  sep = NULL;
285  else
286  {
287  if (flags & ARES_NI_UDP)
288  proto = "udp";
289  else if (flags & ARES_NI_SCTP)
290  proto = "sctp";
291  else if (flags & ARES_NI_DCCP)
292  proto = "dccp";
293  else
294  proto = "tcp";
295 #ifdef HAVE_GETSERVBYPORT_R
296  memset(&se, 0, sizeof(se));
297  sep = &se;
298  memset(tmpbuf, 0, sizeof(tmpbuf));
299 #if GETSERVBYPORT_R_ARGS == 6
300  if (getservbyport_r(port, proto, &se, (void *)tmpbuf,
301  sizeof(tmpbuf), &sep) != 0)
302  sep = NULL; /* LCOV_EXCL_LINE: buffer large so this never fails */
303 #elif GETSERVBYPORT_R_ARGS == 5
304  sep = getservbyport_r(port, proto, &se, (void *)tmpbuf,
305  sizeof(tmpbuf));
306 #elif GETSERVBYPORT_R_ARGS == 4
307  if (getservbyport_r(port, proto, &se, (void *)tmpbuf) != 0)
308  sep = NULL;
309 #else
310  /* Lets just hope the OS uses TLS! */
311  sep = getservbyport(port, proto);
312 #endif
313 #else
314  /* Lets just hope the OS uses TLS! */
315 #if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
316  sep = getservbyport(port, (char*)proto);
317 #else
318  sep = getservbyport(port, proto);
319 #endif
320 #endif
321  }
322  if (sep && sep->s_name)
323  {
324  /* get service name */
325  name = sep->s_name;
326  }
327  else
328  {
329  /* get port as a string */
330  sprintf(tmpbuf, "%u", (unsigned int)ntohs(port));
331  name = tmpbuf;
332  }
333  name_len = strlen(name);
334  if (name_len < buflen)
335  /* return it if buffer big enough */
336  memcpy(buf, name, name_len + 1);
337  else
338  /* avoid reusing previous one */
339  buf[0] = '\0'; /* LCOV_EXCL_LINE: no real service names are too big */
340  return buf;
341  }
342  buf[0] = '\0';
343  return NULL;
344 }
345 
346 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
347 static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int flags,
348  char *buf, size_t buflen)
349 {
350 #ifdef HAVE_IF_INDEXTONAME
351  int is_ll, is_mcll;
352 #endif
353  char tmpbuf[IF_NAMESIZE + 2];
354  size_t bufl;
355  int is_scope_long = sizeof(addr6->sin6_scope_id) > sizeof(unsigned int);
356 
357  tmpbuf[0] = '%';
358 
359 #ifdef HAVE_IF_INDEXTONAME
360  is_ll = IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr);
361  is_mcll = IN6_IS_ADDR_MC_LINKLOCAL(&addr6->sin6_addr);
362  if ((flags & ARES_NI_NUMERICSCOPE) ||
363  (!is_ll && !is_mcll))
364  {
365  if (is_scope_long)
366  {
367  sprintf(&tmpbuf[1], "%lu", (unsigned long)addr6->sin6_scope_id);
368  }
369  else
370  {
371  sprintf(&tmpbuf[1], "%u", (unsigned int)addr6->sin6_scope_id);
372  }
373  }
374  else
375  {
376  if (if_indextoname(addr6->sin6_scope_id, &tmpbuf[1]) == NULL)
377  {
378  if (is_scope_long)
379  {
380  sprintf(&tmpbuf[1], "%lu", (unsigned long)addr6->sin6_scope_id);
381  }
382  else
383  {
384  sprintf(&tmpbuf[1], "%u", (unsigned int)addr6->sin6_scope_id);
385  }
386  }
387  }
388 #else
389  if (is_scope_long)
390  {
391  sprintf(&tmpbuf[1], "%lu", (unsigned long)addr6->sin6_scope_id);
392  }
393  else
394  {
395  sprintf(&tmpbuf[1], "%u", (unsigned int)addr6->sin6_scope_id);
396  }
397  (void) flags;
398 #endif
399  tmpbuf[IF_NAMESIZE + 1] = '\0';
400  bufl = strlen(buf);
401 
402  if(bufl + strlen(tmpbuf) < buflen)
403  /* only append the scopeid string if it fits in the target buffer */
404  strcpy(&buf[bufl], tmpbuf);
405 }
406 #endif
407 
408 /* Determines if s1 ends with the string in s2 (case-insensitive) */
409 STATIC_TESTABLE char *ares_striendstr(const char *s1, const char *s2)
410 {
411  const char *c1, *c2, *c1_begin;
412  int lo1, lo2;
413  size_t s1_len = strlen(s1), s2_len = strlen(s2);
414 
415  /* If the substr is longer than the full str, it can't match */
416  if (s2_len > s1_len)
417  return NULL;
418 
419  /* Jump to the end of s1 minus the length of s2 */
420  c1_begin = s1+s1_len-s2_len;
421  c1 = (const char *)c1_begin;
422  c2 = s2;
423  while (c2 < s2+s2_len)
424  {
425  lo1 = TOLOWER(*c1);
426  lo2 = TOLOWER(*c2);
427  if (lo1 != lo2)
428  return NULL;
429  else
430  {
431  c1++;
432  c2++;
433  }
434  }
435  return (char *)c1_begin;
436 }
437 
438 int ares__is_onion_domain(const char *name)
439 {
440  if (ares_striendstr(name, ".onion"))
441  return 1;
442 
443  if (ares_striendstr(name, ".onion."))
444  return 1;
445 
446  return 0;
447 }
ARES_NI_LOOKUPHOST
#define ARES_NI_LOOKUPHOST
Definition: ares.h:183
ares_inet_ntop
const CARES_EXTERN char * ares_inet_ntop(int af, const void *src, char *dst, ares_socklen_t size)
Definition: inet_ntop.c:56
ARES_ENOMEM
#define ARES_ENOMEM
Definition: ares.h:117
ARES_NI_SCTP
#define ARES_NI_SCTP
Definition: ares.h:180
AF_INET6
#define AF_INET6
Definition: ares_setup.h:208
memset
return memset(p, 0, total)
nameinfo_query::family
int family
Definition: ares_getnameinfo.c:53
ares.h
nameinfo_query::flags
int flags
Definition: ares_getnameinfo.c:54
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
ARES_NI_NUMERICSERV
#define ARES_NI_NUMERICSERV
Definition: ares.h:176
status
absl::Status status
Definition: rls.cc:251
setup.name
name
Definition: setup.py:542
ares__is_onion_domain
int ares__is_onion_domain(const char *name)
Definition: ares_getnameinfo.c:438
ares_striendstr
STATIC_TESTABLE char * ares_striendstr(const char *s1, const char *s2)
Definition: ares_getnameinfo.c:409
nameinfo_query::addr4
struct sockaddr_in addr4
Definition: ares_getnameinfo.c:50
nameinfo_query
Definition: ares_getnameinfo.c:46
ares_nameinfo_callback
void(* ares_nameinfo_callback)(void *arg, int status, int timeouts, char *node, char *service)
Definition: ares.h:301
ARES_NI_NUMERICHOST
#define ARES_NI_NUMERICHOST
Definition: ares.h:174
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
nameinfo_query::addr
union nameinfo_query::@385 addr
ARES_ENOTFOUND
#define ARES_ENOTFOUND
Definition: ares.h:104
channel
wrapped_grpc_channel * channel
Definition: src/php/ext/grpc/call.h:33
ares_malloc
void *(* ares_malloc)(size_t size)=default_malloc
Definition: ares_library_init.c:58
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
sockaddr_in6
Definition: ares_ipv6.h:25
CARES_INADDR_CAST
#define CARES_INADDR_CAST(type, var)
Definition: ares_private.h:56
nameinfo_query::callback
ares_nameinfo_callback callback
Definition: ares_getnameinfo.c:47
sockaddr_in6::sin6_port
unsigned short sin6_port
Definition: ares_ipv6.h:28
text_format_test_wrapper.sep
sep
Definition: text_format_test_wrapper.py:34
nameinfo_query::timeouts
int timeouts
Definition: ares_getnameinfo.c:55
nameinfo_query::arg
void * arg
Definition: ares_getnameinfo.c:48
TOLOWER
#define TOLOWER(x)
Definition: setup_once.h:289
addr6
static struct sockaddr_in6 addr6
Definition: test-getnameinfo.c:34
arg
Definition: cmdline.cc:40
nameinfo_query::addr6
struct sockaddr_in6 addr6
Definition: ares_getnameinfo.c:51
callback
static void callback(void *arg, int status, int timeouts, struct hostent *host)
Definition: acountry.c:224
ares_getnameinfo
void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, ares_socklen_t salen, int flags, ares_nameinfo_callback callback, void *arg)
Definition: ares_getnameinfo.c:76
ARES_SUCCESS
#define ARES_SUCCESS
Definition: ares.h:98
ARES_NI_DCCP
#define ARES_NI_DCCP
Definition: ares.h:181
ares_setup.h
tests.unit._exit_scenarios.port
port
Definition: _exit_scenarios.py:179
absl::hash_internal::c1
static const uint32_t c1
Definition: abseil-cpp/absl/hash/internal/city.cc:58
ares_channeldata
Definition: ares_private.h:266
ares_ipv6.h
STATIC_TESTABLE
#define STATIC_TESTABLE
Definition: ares_private.h:50
absl::flags_internal
Definition: abseil-cpp/absl/flags/commandlineflag.h:40
ares_in6_addr
Definition: ares.h:514
ARES_NI_LOOKUPSERVICE
#define ARES_NI_LOOKUPSERVICE
Definition: ares.h:184
ares_free
void(* ares_free)(void *ptr)=default_free
Definition: ares_library_init.c:60
arg
struct arg arg
ARES_NI_NUMERICSCOPE
#define ARES_NI_NUMERICSCOPE
Definition: ares.h:182
ares_private.h
ARES_NI_NOFQDN
#define ARES_NI_NOFQDN
Definition: ares.h:173
ares_gethostbyaddr
CARES_EXTERN void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen, int family, ares_host_callback callback, void *arg)
Definition: ares_gethostbyaddr.c:58
sockaddr_in6::sin6_addr
struct ares_in6_addr sin6_addr
Definition: ares_ipv6.h:30
flags
uint32_t flags
Definition: retry_filter.cc:632
service
__attribute__((deprecated("Please use GRPCProtoMethod."))) @interface ProtoMethod NSString * service
Definition: ProtoMethod.h:25
ARES_NI_NAMEREQD
#define ARES_NI_NAMEREQD
Definition: ares.h:175
lookup_service
static char * lookup_service(unsigned short port, int flags, char *buf, size_t buflen)
Definition: ares_getnameinfo.c:269
ares_nameser.h
ARES_NI_UDP
#define ARES_NI_UDP
Definition: ares.h:179
ARES_ENOTIMP
#define ARES_ENOTIMP
Definition: ares.h:105
nameinfo_callback
static void nameinfo_callback(void *arg, int status, int timeouts, struct hostent *host)
Definition: ares_getnameinfo.c:190
ares_nowarn.h
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
ARES_EBADFLAGS
#define ARES_EBADFLAGS
Definition: ares.h:122
sockaddr_in6::sin6_scope_id
unsigned int sin6_scope_id
Definition: ares_ipv6.h:31
IF_NAMESIZE
#define IF_NAMESIZE
Definition: ares_ipv6.h:77
IPBUFSIZ
#define IPBUFSIZ
Definition: ares_getnameinfo.c:62
absl::hash_internal::c2
static const uint32_t c2
Definition: abseil-cpp/absl/hash/internal/city.cc:59


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:43