2 * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: head/lib/libutil/realhostname.c 185277 2008-11-25 02:15:09Z avatar $
29 #include <sys/param.h>
30 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
47 realhostname(char *host
, size_t hsize
, const struct in_addr
*ip
)
49 char trimmed
[MAXHOSTNAMELEN
];
53 result
= HOSTNAME_INVALIDADDR
;
54 hp
= gethostbyaddr((const char *)ip
, sizeof(*ip
), AF_INET
);
57 strlcpy(trimmed
, hp
->h_name
, sizeof(trimmed
));
58 trimdomain(trimmed
, strlen(trimmed
));
59 if (strlen(trimmed
) <= hsize
) {
60 char lookup
[MAXHOSTNAMELEN
];
62 strlcpy(lookup
, hp
->h_name
, sizeof(lookup
));
63 hp
= gethostbyname(lookup
);
65 result
= HOSTNAME_INVALIDNAME
;
66 else for (; ; hp
->h_addr_list
++) {
67 if (*hp
->h_addr_list
== NULL
) {
68 result
= HOSTNAME_INCORRECTNAME
;
71 if (!memcmp(*hp
->h_addr_list
, ip
, sizeof(*ip
))) {
72 strncpy(host
, trimmed
, hsize
);
73 return HOSTNAME_FOUND
;
79 strncpy(host
, inet_ntoa(*ip
), hsize
);
85 * struct sockaddr has very lax alignment requirements, since all its
86 * members are char or equivalent. This is a problem when trying to
87 * dereference a struct sockaddr_in6 * that was passed in as a struct
88 * sockaddr *. Although we know (or trust) that the passed-in struct was
89 * properly aligned, the compiler doesn't, and (rightly) complains. These
90 * macros perform the cast in a way that the compiler will accept.
92 #define SOCKADDR_IN6(p) ((struct sockaddr_in6 *)(void *)(p))
93 #define SOCKADDR_IN(p) ((struct sockaddr_in *)(void *)(p))
94 #define SOCKINET(p) ((struct sockinet *)(void *)(p))
97 realhostname_sa(char *host
, size_t hsize
, struct sockaddr
*addr
, int addrlen
)
100 char buf
[NI_MAXHOST
];
102 struct sockaddr_in lsin
;
105 result
= HOSTNAME_INVALIDADDR
;
108 /* IPv4 mapped IPv6 addr consideraton, specified in rfc2373. */
109 if (addr
->sa_family
== AF_INET6
&&
110 addrlen
== sizeof(struct sockaddr_in6
) &&
111 IN6_IS_ADDR_V4MAPPED(&SOCKADDR_IN6(addr
)->sin6_addr
)) {
112 struct sockaddr_in6
*sin6
;
114 sin6
= SOCKADDR_IN6(addr
);
116 memset(&lsin
, 0, sizeof(lsin
));
117 lsin
.sin_len
= sizeof(struct sockaddr_in
);
118 lsin
.sin_family
= AF_INET
;
119 lsin
.sin_port
= sin6
->sin6_port
;
120 memcpy(&lsin
.sin_addr
, &sin6
->sin6_addr
.s6_addr
[12],
121 sizeof(struct in_addr
));
122 addr
= (struct sockaddr
*)&lsin
;
123 addrlen
= lsin
.sin_len
;
127 error
= getnameinfo(addr
, addrlen
, buf
, sizeof(buf
), NULL
, 0,
130 struct addrinfo hints
, *res
, *ores
;
133 memset(&hints
, 0, sizeof(struct addrinfo
));
134 hints
.ai_family
= addr
->sa_family
;
135 hints
.ai_flags
= AI_CANONNAME
| AI_PASSIVE
;
136 hints
.ai_socktype
= SOCK_STREAM
;
138 error
= getaddrinfo(buf
, NULL
, &hints
, &res
);
140 result
= HOSTNAME_INVALIDNAME
;
143 for (ores
= res
; ; res
= res
->ai_next
) {
146 result
= HOSTNAME_INCORRECTNAME
;
152 result
= HOSTNAME_INCORRECTNAME
;
155 if (sa
->sa_len
== addrlen
&&
156 sa
->sa_family
== addr
->sa_family
) {
157 SOCKINET(sa
)->si_port
= SOCKINET(addr
)->si_port
;
160 * XXX: sin6_socpe_id may not been
163 if (sa
->sa_family
== AF_INET6
&&
164 SOCKADDR_IN6(sa
)->sin6_scope_id
== 0)
165 SOCKADDR_IN6(sa
)->sin6_scope_id
=
166 SOCKADDR_IN6(addr
)->sin6_scope_id
;
168 if (!memcmp(sa
, addr
, sa
->sa_len
)) {
169 result
= HOSTNAME_FOUND
;
170 if (ores
->ai_canonname
== NULL
) {
174 strlcpy(buf
, ores
->ai_canonname
,
176 trimdomain(buf
, hsize
);
177 if (strlen(buf
) > hsize
&&
178 addr
->sa_family
== AF_INET
) {
182 strncpy(host
, buf
, hsize
);
190 if (getnameinfo(addr
, addrlen
, buf
, sizeof(buf
), NULL
, 0,
191 NI_NUMERICHOST
) == 0)
192 strncpy(host
, buf
, hsize
);