]>
The Tcpdump Group git mirrors - tcpdump/blob - missing/getnameinfo.c
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
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.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * Issues to be discussed:
32 * - Thread safe-ness must be checked
33 * - Return values. There seems to be no standard for return value (RFC2553)
34 * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
35 * - RFC2553 says that we should raise error on short buffer. X/Open says
36 * we need to truncate the result. We obey RFC2553 (and X/Open should be
45 static const char rcsid
[] =
46 "@(#) $Header: /tcpdump/master/tcpdump/missing/getnameinfo.c,v 1.5 2000-01-19 04:42:21 itojun Exp $";
49 #include <sys/types.h>
50 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <arpa/nameser.h>
61 #ifndef HAVE_PORTABLE_PROTOTYPE
62 #include "cdecl_ext.h"
81 {PF_INET6
, sizeof(struct in6_addr
), sizeof(struct sockaddr_in6
),
82 offsetof(struct sockaddr_in6
, sin6_addr
)},
84 {PF_INET
, sizeof(struct in_addr
), sizeof(struct sockaddr_in
),
85 offsetof(struct sockaddr_in
, sin_addr
)},
95 #define ENI_NOSOCKET 0
96 #define ENI_NOSERVNAME 1
97 #define ENI_NOHOSTNAME 2
104 getnameinfo(sa
, salen
, host
, hostlen
, serv
, servlen
, flags
)
105 const struct sockaddr
*sa
;
127 #ifdef HAVE_SA_LEN /*XXX*/
128 if (sa
->sa_len
!= salen
)
132 family
= sa
->sa_family
;
133 for (i
= 0; afdl
[i
].a_af
; i
++)
134 if (afdl
[i
].a_af
== family
) {
141 if (salen
!= afd
->a_socklen
)
144 port
= ((struct sockinet
*)sa
)->si_port
; /* network byte order */
145 addr
= (char *)sa
+ afd
->a_off
;
147 if (serv
== NULL
|| servlen
== 0) {
149 * do nothing in this case.
150 * in case you are wondering if "&&" is more correct than
151 * "||" here: RFC2553 says that serv == NULL OR servlen == 0
152 * means that the caller does not want the result.
155 if (flags
& NI_NUMERICSERV
)
158 sp
= getservbyport(port
,
159 (flags
& NI_DGRAM
) ? "udp" : "tcp");
162 if (strlen(sp
->s_name
) > servlen
)
164 strcpy(serv
, sp
->s_name
);
166 snprintf(numserv
, sizeof(numserv
), "%d", ntohs(port
));
167 if (strlen(numserv
) > servlen
)
169 strcpy(serv
, numserv
);
173 switch (sa
->sa_family
) {
176 ntohl(((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
);
177 if (IN_MULTICAST(v4a
) || IN_EXPERIMENTAL(v4a
))
178 flags
|= NI_NUMERICHOST
;
179 v4a
>>= IN_CLASSA_NSHIFT
;
181 flags
|= NI_NUMERICHOST
;
186 struct sockaddr_in6
*sin6
;
187 sin6
= (struct sockaddr_in6
*)sa
;
188 switch (sin6
->sin6_addr
.s6_addr
[0]) {
190 if (IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
))
192 else if (IN6_IS_ADDR_LOOPBACK(&sin6
->sin6_addr
))
195 flags
|= NI_NUMERICHOST
;
198 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
)) {
199 flags
|= NI_NUMERICHOST
;
201 else if (IN6_IS_ADDR_MULTICAST(&sin6
->sin6_addr
))
202 flags
|= NI_NUMERICHOST
;
209 if (host
== NULL
|| hostlen
== 0) {
211 * do nothing in this case.
212 * in case you are wondering if "&&" is more correct than
213 * "||" here: RFC2553 says that host == NULL OR hostlen == 0
214 * means that the caller does not want the result.
216 } else if (flags
& NI_NUMERICHOST
) {
217 /* NUMERICHOST and NAMEREQD conflicts with each other */
218 if (flags
& NI_NAMEREQD
)
219 return ENI_NOHOSTNAME
;
220 if (inet_ntop(afd
->a_af
, addr
, numaddr
, sizeof(numaddr
))
223 if (strlen(numaddr
) > hostlen
)
225 strcpy(host
, numaddr
);
226 #if defined(INET6) && defined(NI_WITHSCOPEID)
227 if (afd
->a_af
== AF_INET6
&&
228 (IN6_IS_ADDR_LINKLOCAL((struct in6_addr
*)addr
) ||
229 IN6_IS_ADDR_MULTICAST((struct in6_addr
*)addr
)) &&
230 ((struct sockaddr_in6
*)sa
)->sin6_scope_id
) {
231 #ifndef ALWAYS_WITHSCOPE
232 if (flags
& NI_WITHSCOPEID
)
233 #endif /* !ALWAYS_WITHSCOPE */
235 char *ep
= strchr(host
, '\0');
236 unsigned int ifindex
=
237 ((struct sockaddr_in6
*)sa
)->sin6_scope_id
;
239 *ep
= SCOPE_DELIMITER
;
240 if ((if_indextoname(ifindex
, ep
+ 1)) == NULL
)
241 /* XXX what should we do? */
242 strncpy(ep
+ 1, "???", 3);
247 #ifdef USE_GETIPNODEBY
248 hp
= getipnodebyaddr(addr
, afd
->a_addrlen
, afd
->a_af
, &h_error
);
250 hp
= gethostbyaddr(addr
, afd
->a_addrlen
, afd
->a_af
);
259 if (flags
& NI_NOFQDN
) {
260 p
= strchr(hp
->h_name
, '.');
263 if (strlen(hp
->h_name
) > hostlen
) {
264 #ifdef USE_GETIPNODEBY
269 strcpy(host
, hp
->h_name
);
270 #ifdef USE_GETIPNODEBY
274 if (flags
& NI_NAMEREQD
)
275 return ENI_NOHOSTNAME
;
276 if (inet_ntop(afd
->a_af
, addr
, numaddr
, sizeof(numaddr
))
278 return ENI_NOHOSTNAME
;
279 if (strlen(numaddr
) > hostlen
)
281 strcpy(host
, numaddr
);