1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
|
/** \file masock_sa2name.c
* (C) Copyright 2001 - 2021 by Matthias Andree
* \author Matthias Andree
* \year 2001,2021
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* to expose nonstandard members in in.h structures to
* fix compilation in strict conformance mode on Linux
*/
#endif
#include "masock.h"
#include "critmem.h"
#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef __LCLINT__
#include <arpa/inet.h>
#endif /* not __LCLINT__ */
#include <netdb.h>
#include <string.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif
#include <errno.h>
/** Look up the host name belonging to the socket address. If compiled
* with IPv6 support, use IPv6 lookup unless the address is actually an
* IPv6-mapped IPv4 address.
*
* \return strdup'ed string containing the host name or NULL in case of
* trouble.
*
* \bug Linux [e]glibc has broken IN6_IS_ADDR_* macros that do not cast to
* const and that do not work in strict conformance mode because they
* access nonstandard members.
*/
char *
masock_sa2name(const struct sockaddr *sa
/** socket address to convert */ ,
/*@out@*/ int *h_e
/** variable to place h_errno into */ )
{
struct hostent *he;
char *ret;
switch (sa->sa_family) {
#ifdef HAVE_IPV6
case AF_INET6:
/* any warnings issued here are the fault of broken system
includes */
if (IN6_IS_ADDR_V4MAPPED(&((const struct sockaddr_in6 *)sa)->sin6_addr)) {
/* do IPv4 lookup on mapped addresses */
/* see RFC-2553 section 6.2 for "12" */
he = gethostbyaddr(12 + (const char *)
&((const struct sockaddr_in6 *)sa)
->sin6_addr, sizeof(struct in_addr), AF_INET);
} else {
/* real IPv6 */
he = gethostbyaddr((const char *)
&((const struct sockaddr_in6 *)sa)
->sin6_addr,
sizeof(struct in6_addr), sa->sa_family);
}
if (!he)
errno = 0, *h_e = h_errno;
break;
#endif
case AF_INET:
he = gethostbyaddr((const char *)
&((const struct sockaddr_in *)sa)
->sin_addr.s_addr,
sizeof(struct in_addr), sa->sa_family);
if (!he)
errno = 0, *h_e = h_errno;
break;
default:
errno = EAFNOSUPPORT;
*h_e = 0;
he = 0;
break;
}
ret = he && he->h_name ? critstrdup(he->h_name, "masock_sa2name") : 0;
endhostent();
return ret;
}
|