1*b636d99dSDavid van Moolenbroek /*
2*b636d99dSDavid van Moolenbroek * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3*b636d99dSDavid van Moolenbroek * All rights reserved.
4*b636d99dSDavid van Moolenbroek *
5*b636d99dSDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
6*b636d99dSDavid van Moolenbroek * modification, are permitted provided that the following conditions
7*b636d99dSDavid van Moolenbroek * are met:
8*b636d99dSDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
9*b636d99dSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
10*b636d99dSDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
11*b636d99dSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
12*b636d99dSDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
13*b636d99dSDavid van Moolenbroek * 3. Neither the name of the project nor the names of its contributors
14*b636d99dSDavid van Moolenbroek * may be used to endorse or promote products derived from this software
15*b636d99dSDavid van Moolenbroek * without specific prior written permission.
16*b636d99dSDavid van Moolenbroek *
17*b636d99dSDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18*b636d99dSDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*b636d99dSDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*b636d99dSDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21*b636d99dSDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*b636d99dSDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*b636d99dSDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*b636d99dSDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*b636d99dSDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*b636d99dSDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*b636d99dSDavid van Moolenbroek * SUCH DAMAGE.
28*b636d99dSDavid van Moolenbroek */
29*b636d99dSDavid van Moolenbroek
30*b636d99dSDavid van Moolenbroek /*
31*b636d99dSDavid van Moolenbroek * Issues to be discussed:
32*b636d99dSDavid van Moolenbroek * - Thread safe-ness must be checked
33*b636d99dSDavid van Moolenbroek * - Return values. There seems to be no standard for return value (RFC2553)
34*b636d99dSDavid van Moolenbroek * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
35*b636d99dSDavid van Moolenbroek * - RFC2553 says that we should raise error on short buffer. X/Open says
36*b636d99dSDavid van Moolenbroek * we need to truncate the result. We obey RFC2553 (and X/Open should be
37*b636d99dSDavid van Moolenbroek * modified).
38*b636d99dSDavid van Moolenbroek */
39*b636d99dSDavid van Moolenbroek
40*b636d99dSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
41*b636d99dSDavid van Moolenbroek #include <config.h>
42*b636d99dSDavid van Moolenbroek #endif
43*b636d99dSDavid van Moolenbroek
44*b636d99dSDavid van Moolenbroek #include <sys/types.h>
45*b636d99dSDavid van Moolenbroek #include <sys/socket.h>
46*b636d99dSDavid van Moolenbroek #include <net/if.h>
47*b636d99dSDavid van Moolenbroek #include <netinet/in.h>
48*b636d99dSDavid van Moolenbroek #include <arpa/inet.h>
49*b636d99dSDavid van Moolenbroek #include <arpa/nameser.h>
50*b636d99dSDavid van Moolenbroek #include <netdb.h>
51*b636d99dSDavid van Moolenbroek #include <resolv.h>
52*b636d99dSDavid van Moolenbroek #include <string.h>
53*b636d99dSDavid van Moolenbroek #include <stddef.h>
54*b636d99dSDavid van Moolenbroek #include <errno.h>
55*b636d99dSDavid van Moolenbroek
56*b636d99dSDavid van Moolenbroek #ifdef NEED_ADDRINFO_H
57*b636d99dSDavid van Moolenbroek #include "addrinfo.h"
58*b636d99dSDavid van Moolenbroek #endif
59*b636d99dSDavid van Moolenbroek
60*b636d99dSDavid van Moolenbroek #define SUCCESS 0
61*b636d99dSDavid van Moolenbroek #define ANY 0
62*b636d99dSDavid van Moolenbroek #define YES 1
63*b636d99dSDavid van Moolenbroek #define NO 0
64*b636d99dSDavid van Moolenbroek
65*b636d99dSDavid van Moolenbroek static struct afd {
66*b636d99dSDavid van Moolenbroek int a_af;
67*b636d99dSDavid van Moolenbroek int a_addrlen;
68*b636d99dSDavid van Moolenbroek int a_socklen;
69*b636d99dSDavid van Moolenbroek int a_off;
70*b636d99dSDavid van Moolenbroek } afdl [] = {
71*b636d99dSDavid van Moolenbroek #ifdef INET6
72*b636d99dSDavid van Moolenbroek {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
73*b636d99dSDavid van Moolenbroek offsetof(struct sockaddr_in6, sin6_addr)},
74*b636d99dSDavid van Moolenbroek #endif
75*b636d99dSDavid van Moolenbroek {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
76*b636d99dSDavid van Moolenbroek offsetof(struct sockaddr_in, sin_addr)},
77*b636d99dSDavid van Moolenbroek {0, 0, 0},
78*b636d99dSDavid van Moolenbroek };
79*b636d99dSDavid van Moolenbroek
80*b636d99dSDavid van Moolenbroek struct sockinet {
81*b636d99dSDavid van Moolenbroek u_char si_len;
82*b636d99dSDavid van Moolenbroek u_char si_family;
83*b636d99dSDavid van Moolenbroek u_short si_port;
84*b636d99dSDavid van Moolenbroek };
85*b636d99dSDavid van Moolenbroek
86*b636d99dSDavid van Moolenbroek #define ENI_NOSOCKET 0
87*b636d99dSDavid van Moolenbroek #define ENI_NOSERVNAME 1
88*b636d99dSDavid van Moolenbroek #define ENI_NOHOSTNAME 2
89*b636d99dSDavid van Moolenbroek #define ENI_MEMORY 3
90*b636d99dSDavid van Moolenbroek #define ENI_SYSTEM 4
91*b636d99dSDavid van Moolenbroek #define ENI_FAMILY 5
92*b636d99dSDavid van Moolenbroek #define ENI_SALEN 6
93*b636d99dSDavid van Moolenbroek
94*b636d99dSDavid van Moolenbroek int
getnameinfo(sa,salen,host,hostlen,serv,servlen,flags)95*b636d99dSDavid van Moolenbroek getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
96*b636d99dSDavid van Moolenbroek const struct sockaddr *sa;
97*b636d99dSDavid van Moolenbroek size_t salen;
98*b636d99dSDavid van Moolenbroek char *host;
99*b636d99dSDavid van Moolenbroek size_t hostlen;
100*b636d99dSDavid van Moolenbroek char *serv;
101*b636d99dSDavid van Moolenbroek size_t servlen;
102*b636d99dSDavid van Moolenbroek int flags;
103*b636d99dSDavid van Moolenbroek {
104*b636d99dSDavid van Moolenbroek struct afd *afd;
105*b636d99dSDavid van Moolenbroek struct servent *sp;
106*b636d99dSDavid van Moolenbroek struct hostent *hp;
107*b636d99dSDavid van Moolenbroek u_short port;
108*b636d99dSDavid van Moolenbroek int family, i;
109*b636d99dSDavid van Moolenbroek char *addr, *p;
110*b636d99dSDavid van Moolenbroek uint32_t v4a;
111*b636d99dSDavid van Moolenbroek int h_error;
112*b636d99dSDavid van Moolenbroek char numserv[512];
113*b636d99dSDavid van Moolenbroek char numaddr[512];
114*b636d99dSDavid van Moolenbroek
115*b636d99dSDavid van Moolenbroek if (sa == NULL)
116*b636d99dSDavid van Moolenbroek return ENI_NOSOCKET;
117*b636d99dSDavid van Moolenbroek
118*b636d99dSDavid van Moolenbroek #ifdef HAVE_SA_LEN /*XXX*/
119*b636d99dSDavid van Moolenbroek if (sa->sa_len != salen)
120*b636d99dSDavid van Moolenbroek return ENI_SALEN;
121*b636d99dSDavid van Moolenbroek #endif
122*b636d99dSDavid van Moolenbroek
123*b636d99dSDavid van Moolenbroek family = sa->sa_family;
124*b636d99dSDavid van Moolenbroek for (i = 0; afdl[i].a_af; i++)
125*b636d99dSDavid van Moolenbroek if (afdl[i].a_af == family) {
126*b636d99dSDavid van Moolenbroek afd = &afdl[i];
127*b636d99dSDavid van Moolenbroek goto found;
128*b636d99dSDavid van Moolenbroek }
129*b636d99dSDavid van Moolenbroek return ENI_FAMILY;
130*b636d99dSDavid van Moolenbroek
131*b636d99dSDavid van Moolenbroek found:
132*b636d99dSDavid van Moolenbroek if (salen != afd->a_socklen)
133*b636d99dSDavid van Moolenbroek return ENI_SALEN;
134*b636d99dSDavid van Moolenbroek
135*b636d99dSDavid van Moolenbroek port = ((struct sockinet *)sa)->si_port; /* network byte order */
136*b636d99dSDavid van Moolenbroek addr = (char *)sa + afd->a_off;
137*b636d99dSDavid van Moolenbroek
138*b636d99dSDavid van Moolenbroek if (serv == NULL || servlen == 0) {
139*b636d99dSDavid van Moolenbroek /*
140*b636d99dSDavid van Moolenbroek * do nothing in this case.
141*b636d99dSDavid van Moolenbroek * in case you are wondering if "&&" is more correct than
142*b636d99dSDavid van Moolenbroek * "||" here: RFC2553 says that serv == NULL OR servlen == 0
143*b636d99dSDavid van Moolenbroek * means that the caller does not want the result.
144*b636d99dSDavid van Moolenbroek */
145*b636d99dSDavid van Moolenbroek } else {
146*b636d99dSDavid van Moolenbroek if (flags & NI_NUMERICSERV)
147*b636d99dSDavid van Moolenbroek sp = NULL;
148*b636d99dSDavid van Moolenbroek else {
149*b636d99dSDavid van Moolenbroek sp = getservbyport(port,
150*b636d99dSDavid van Moolenbroek (flags & NI_DGRAM) ? "udp" : "tcp");
151*b636d99dSDavid van Moolenbroek }
152*b636d99dSDavid van Moolenbroek if (sp) {
153*b636d99dSDavid van Moolenbroek if (strlen(sp->s_name) + 1 > servlen)
154*b636d99dSDavid van Moolenbroek return ENI_MEMORY;
155*b636d99dSDavid van Moolenbroek strcpy(serv, sp->s_name);
156*b636d99dSDavid van Moolenbroek } else {
157*b636d99dSDavid van Moolenbroek snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
158*b636d99dSDavid van Moolenbroek if (strlen(numserv) + 1 > servlen)
159*b636d99dSDavid van Moolenbroek return ENI_MEMORY;
160*b636d99dSDavid van Moolenbroek strcpy(serv, numserv);
161*b636d99dSDavid van Moolenbroek }
162*b636d99dSDavid van Moolenbroek }
163*b636d99dSDavid van Moolenbroek
164*b636d99dSDavid van Moolenbroek switch (sa->sa_family) {
165*b636d99dSDavid van Moolenbroek case AF_INET:
166*b636d99dSDavid van Moolenbroek v4a = (uint32_t)
167*b636d99dSDavid van Moolenbroek ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
168*b636d99dSDavid van Moolenbroek if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
169*b636d99dSDavid van Moolenbroek flags |= NI_NUMERICHOST;
170*b636d99dSDavid van Moolenbroek v4a >>= IN_CLASSA_NSHIFT;
171*b636d99dSDavid van Moolenbroek if (v4a == 0)
172*b636d99dSDavid van Moolenbroek flags |= NI_NUMERICHOST;
173*b636d99dSDavid van Moolenbroek break;
174*b636d99dSDavid van Moolenbroek #ifdef INET6
175*b636d99dSDavid van Moolenbroek case AF_INET6:
176*b636d99dSDavid van Moolenbroek {
177*b636d99dSDavid van Moolenbroek struct sockaddr_in6 *sin6;
178*b636d99dSDavid van Moolenbroek sin6 = (struct sockaddr_in6 *)sa;
179*b636d99dSDavid van Moolenbroek switch (sin6->sin6_addr.s6_addr[0]) {
180*b636d99dSDavid van Moolenbroek case 0x00:
181*b636d99dSDavid van Moolenbroek if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
182*b636d99dSDavid van Moolenbroek ;
183*b636d99dSDavid van Moolenbroek else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
184*b636d99dSDavid van Moolenbroek ;
185*b636d99dSDavid van Moolenbroek else
186*b636d99dSDavid van Moolenbroek flags |= NI_NUMERICHOST;
187*b636d99dSDavid van Moolenbroek break;
188*b636d99dSDavid van Moolenbroek default:
189*b636d99dSDavid van Moolenbroek if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
190*b636d99dSDavid van Moolenbroek flags |= NI_NUMERICHOST;
191*b636d99dSDavid van Moolenbroek }
192*b636d99dSDavid van Moolenbroek else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
193*b636d99dSDavid van Moolenbroek flags |= NI_NUMERICHOST;
194*b636d99dSDavid van Moolenbroek break;
195*b636d99dSDavid van Moolenbroek }
196*b636d99dSDavid van Moolenbroek }
197*b636d99dSDavid van Moolenbroek break;
198*b636d99dSDavid van Moolenbroek #endif
199*b636d99dSDavid van Moolenbroek }
200*b636d99dSDavid van Moolenbroek if (host == NULL || hostlen == 0) {
201*b636d99dSDavid van Moolenbroek /*
202*b636d99dSDavid van Moolenbroek * do nothing in this case.
203*b636d99dSDavid van Moolenbroek * in case you are wondering if "&&" is more correct than
204*b636d99dSDavid van Moolenbroek * "||" here: RFC2553 says that host == NULL OR hostlen == 0
205*b636d99dSDavid van Moolenbroek * means that the caller does not want the result.
206*b636d99dSDavid van Moolenbroek */
207*b636d99dSDavid van Moolenbroek } else if (flags & NI_NUMERICHOST) {
208*b636d99dSDavid van Moolenbroek /* NUMERICHOST and NAMEREQD conflicts with each other */
209*b636d99dSDavid van Moolenbroek if (flags & NI_NAMEREQD)
210*b636d99dSDavid van Moolenbroek return ENI_NOHOSTNAME;
211*b636d99dSDavid van Moolenbroek if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
212*b636d99dSDavid van Moolenbroek == NULL)
213*b636d99dSDavid van Moolenbroek return ENI_SYSTEM;
214*b636d99dSDavid van Moolenbroek if (strlen(numaddr) + 1 > hostlen)
215*b636d99dSDavid van Moolenbroek return ENI_MEMORY;
216*b636d99dSDavid van Moolenbroek strcpy(host, numaddr);
217*b636d99dSDavid van Moolenbroek #if defined(INET6) && defined(NI_WITHSCOPEID)
218*b636d99dSDavid van Moolenbroek if (afd->a_af == AF_INET6 &&
219*b636d99dSDavid van Moolenbroek (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
220*b636d99dSDavid van Moolenbroek IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
221*b636d99dSDavid van Moolenbroek ((struct sockaddr_in6 *)sa)->sin6_scope_id) {
222*b636d99dSDavid van Moolenbroek #ifndef ALWAYS_WITHSCOPE
223*b636d99dSDavid van Moolenbroek if (flags & NI_WITHSCOPEID)
224*b636d99dSDavid van Moolenbroek #endif /* !ALWAYS_WITHSCOPE */
225*b636d99dSDavid van Moolenbroek {
226*b636d99dSDavid van Moolenbroek char *ep = strchr(host, '\0');
227*b636d99dSDavid van Moolenbroek unsigned int ifindex =
228*b636d99dSDavid van Moolenbroek ((struct sockaddr_in6 *)sa)->sin6_scope_id;
229*b636d99dSDavid van Moolenbroek
230*b636d99dSDavid van Moolenbroek *ep = SCOPE_DELIMITER;
231*b636d99dSDavid van Moolenbroek if ((if_indextoname(ifindex, ep + 1)) == NULL)
232*b636d99dSDavid van Moolenbroek /* XXX what should we do? */
233*b636d99dSDavid van Moolenbroek strncpy(ep + 1, "???", 3);
234*b636d99dSDavid van Moolenbroek }
235*b636d99dSDavid van Moolenbroek }
236*b636d99dSDavid van Moolenbroek #endif /* INET6 */
237*b636d99dSDavid van Moolenbroek } else {
238*b636d99dSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
239*b636d99dSDavid van Moolenbroek hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
240*b636d99dSDavid van Moolenbroek #else
241*b636d99dSDavid van Moolenbroek hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
242*b636d99dSDavid van Moolenbroek #ifdef HAVE_H_ERRNO
243*b636d99dSDavid van Moolenbroek h_error = h_errno;
244*b636d99dSDavid van Moolenbroek #else
245*b636d99dSDavid van Moolenbroek h_error = EINVAL;
246*b636d99dSDavid van Moolenbroek #endif
247*b636d99dSDavid van Moolenbroek #endif
248*b636d99dSDavid van Moolenbroek
249*b636d99dSDavid van Moolenbroek if (hp) {
250*b636d99dSDavid van Moolenbroek if (flags & NI_NOFQDN) {
251*b636d99dSDavid van Moolenbroek p = strchr(hp->h_name, '.');
252*b636d99dSDavid van Moolenbroek if (p) *p = '\0';
253*b636d99dSDavid van Moolenbroek }
254*b636d99dSDavid van Moolenbroek if (strlen(hp->h_name) + 1 > hostlen) {
255*b636d99dSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
256*b636d99dSDavid van Moolenbroek freehostent(hp);
257*b636d99dSDavid van Moolenbroek #endif
258*b636d99dSDavid van Moolenbroek return ENI_MEMORY;
259*b636d99dSDavid van Moolenbroek }
260*b636d99dSDavid van Moolenbroek strcpy(host, hp->h_name);
261*b636d99dSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
262*b636d99dSDavid van Moolenbroek freehostent(hp);
263*b636d99dSDavid van Moolenbroek #endif
264*b636d99dSDavid van Moolenbroek } else {
265*b636d99dSDavid van Moolenbroek if (flags & NI_NAMEREQD)
266*b636d99dSDavid van Moolenbroek return ENI_NOHOSTNAME;
267*b636d99dSDavid van Moolenbroek if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
268*b636d99dSDavid van Moolenbroek == NULL)
269*b636d99dSDavid van Moolenbroek return ENI_NOHOSTNAME;
270*b636d99dSDavid van Moolenbroek if (strlen(numaddr) + 1 > hostlen)
271*b636d99dSDavid van Moolenbroek return ENI_MEMORY;
272*b636d99dSDavid van Moolenbroek strcpy(host, numaddr);
273*b636d99dSDavid van Moolenbroek }
274*b636d99dSDavid van Moolenbroek }
275*b636d99dSDavid van Moolenbroek return SUCCESS;
276*b636d99dSDavid van Moolenbroek }
277