1 /* $NetBSD: getnameinfo.c,v 1.3 2014/12/10 04:37:56 christos Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Issues to be discussed:
34 * - Thread safe-ness must be checked
35 * - Return values. There seems to be no standard for return value (RFC2553)
36 * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <arpa/nameser.h>
63 {PF_INET6
, sizeof(struct in6_addr
), sizeof(struct sockaddr_in6
),
64 offsetof(struct sockaddr_in6
, sin6_addr
)},
66 {PF_INET
, sizeof(struct in_addr
), sizeof(struct sockaddr_in
),
67 offsetof(struct sockaddr_in
, sin_addr
)},
77 #define ENI_NOSOCKET 0
78 #define ENI_NOSERVNAME 1
79 #define ENI_NOHOSTNAME 2
86 getnameinfo(sa
, salen
, host
, hostlen
, serv
, servlen
, flags
)
87 const struct sockaddr
*sa
;
111 if (len
!= salen
) return ENI_SALEN
;
116 family
= sa
->sa_family
;
117 for (i
= 0; afdl
[i
].a_af
; i
++)
118 if (afdl
[i
].a_af
== family
) {
125 if (len
!= afd
->a_socklen
) return ENI_SALEN
;
127 port
= ((struct sockinet
*)sa
)->si_port
; /* network byte order */
128 addr
= (char *)sa
+ afd
->a_off
;
130 if (serv
== NULL
|| servlen
== 0) {
131 /* what we should do? */
132 } else if (flags
& NI_NUMERICSERV
) {
133 snprintf(numserv
, sizeof(numserv
), "%d", ntohs(port
));
134 if (strlen(numserv
) > servlen
)
136 strcpy(serv
, numserv
);
138 sp
= getservbyport(port
, (flags
& NI_DGRAM
) ? "udp" : "tcp");
140 if (strlen(sp
->s_name
) > servlen
)
142 strcpy(serv
, sp
->s_name
);
144 return ENI_NOSERVNAME
;
147 switch (sa
->sa_family
) {
149 v4a
= ntohl(((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
);
150 if (IN_MULTICAST(v4a
) || IN_EXPERIMENTAL(v4a
))
151 flags
|= NI_NUMERICHOST
;
152 v4a
>>= IN_CLASSA_NSHIFT
;
153 if (v4a
== 0 || v4a
== IN_LOOPBACKNET
)
154 flags
|= NI_NUMERICHOST
;
159 struct sockaddr_in6
*sin6
;
160 sin6
= (struct sockaddr_in6
*)sa
;
161 switch (sin6
->sin6_addr
.s6_addr
[0]) {
163 if (IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
))
165 else if (IN6_IS_ADDR_LOOPBACK(&sin6
->sin6_addr
))
168 flags
|= NI_NUMERICHOST
;
171 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
))
172 flags
|= NI_NUMERICHOST
;
173 else if (IN6_IS_ADDR_MULTICAST(&sin6
->sin6_addr
))
174 flags
|= NI_NUMERICHOST
;
181 if (host
== NULL
|| hostlen
== 0) {
182 /* what should we do? */
183 } else if (flags
& NI_NUMERICHOST
) {
184 /* NUMERICHOST and NAMEREQD conflicts with each other */
185 if (flags
& NI_NAMEREQD
)
186 return ENI_NOHOSTNAME
;
187 if (inet_ntop(afd
->a_af
, addr
, numaddr
, sizeof(numaddr
))
190 if (strlen(numaddr
) > hostlen
)
192 strcpy(host
, numaddr
);
194 #ifdef USE_GETIPNODEBY
195 hp
= getipnodebyaddr(addr
, afd
->a_addrlen
, afd
->a_af
, &h_error
);
197 hp
= gethostbyaddr(addr
, afd
->a_addrlen
, afd
->a_af
);
202 if (flags
& NI_NOFQDN
) {
203 p
= strchr(hp
->h_name
, '.');
206 if (strlen(hp
->h_name
) > hostlen
) {
207 #ifdef USE_GETIPNODEBY
212 strcpy(host
, hp
->h_name
);
213 #ifdef USE_GETIPNODEBY
217 if (flags
& NI_NAMEREQD
)
218 return ENI_NOHOSTNAME
;
219 if (inet_ntop(afd
->a_af
, addr
, numaddr
, sizeof(numaddr
))
221 return ENI_NOHOSTNAME
;
222 if (strlen(numaddr
) > hostlen
)
224 strcpy(host
, numaddr
);