]> The Tcpdump Group git mirrors - tcpdump/blob - missing/getnameinfo.c
regen
[tcpdump] / missing / getnameinfo.c
1 /*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
16 *
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
27 * SUCH DAMAGE.
28 */
29
30 /*
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 */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #ifndef lint
42 static const char rcsid[] =
43 "@(#) $Header: /tcpdump/master/tcpdump/missing/getnameinfo.c,v 1.4 2000-01-09 21:35:44 fenner Exp $";
44 #endif
45
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <net/if.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <arpa/nameser.h>
52 #include <netdb.h>
53 #include <resolv.h>
54 #include <string.h>
55 #include <stddef.h>
56 #include <errno.h>
57
58 #ifndef HAVE_PORTABLE_PROTOTYPE
59 #include "cdecl_ext.h"
60 #endif
61
62 #include "addrinfo.h"
63
64 #define SUCCESS 0
65 #define ANY 0
66 #define YES 1
67 #define NO 0
68
69 static struct afd {
70 int a_af;
71 int a_addrlen;
72 int a_socklen;
73 int a_off;
74 } afdl [] = {
75 #ifdef INET6
76 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
77 offsetof(struct sockaddr_in6, sin6_addr)},
78 #endif
79 {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
80 offsetof(struct sockaddr_in, sin_addr)},
81 {0, 0, 0},
82 };
83
84 struct sockinet {
85 u_char si_len;
86 u_char si_family;
87 u_short si_port;
88 };
89
90 #define ENI_NOSOCKET 0
91 #define ENI_NOSERVNAME 1
92 #define ENI_NOHOSTNAME 2
93 #define ENI_MEMORY 3
94 #define ENI_SYSTEM 4
95 #define ENI_FAMILY 5
96 #define ENI_SALEN 6
97
98 int
99 getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
100 const struct sockaddr *sa;
101 size_t salen;
102 char *host;
103 size_t hostlen;
104 char *serv;
105 size_t servlen;
106 int flags;
107 {
108 struct afd *afd;
109 struct servent *sp;
110 struct hostent *hp;
111 u_short port;
112 int family, i;
113 char *addr, *p;
114 u_long v4a;
115 int h_error;
116 char numserv[512];
117 char numaddr[512];
118
119 if (sa == NULL)
120 return ENI_NOSOCKET;
121
122 #ifdef HAVE_SA_LEN /*XXX*/
123 if (sa->sa_len != salen)
124 return ENI_SALEN;
125 #endif
126
127 family = sa->sa_family;
128 for (i = 0; afdl[i].a_af; i++)
129 if (afdl[i].a_af == family) {
130 afd = &afdl[i];
131 goto found;
132 }
133 return ENI_FAMILY;
134
135 found:
136 if (salen != afd->a_socklen)
137 return ENI_SALEN;
138
139 port = ((struct sockinet *)sa)->si_port; /* network byte order */
140 addr = (char *)sa + afd->a_off;
141
142 if (serv == NULL || servlen == 0) {
143 /* what we should do? */
144 } else {
145 if (flags & NI_NUMERICSERV)
146 sp = NULL;
147 else {
148 sp = getservbyport(port,
149 (flags & NI_DGRAM) ? "udp" : "tcp");
150 }
151 if (sp) {
152 if (strlen(sp->s_name) > servlen)
153 return ENI_MEMORY;
154 strcpy(serv, sp->s_name);
155 } else {
156 sprintf(numserv, "%d", ntohs(port));
157 if (strlen(numserv) > servlen)
158 return ENI_MEMORY;
159 strcpy(serv, numserv);
160 }
161 }
162
163 switch (sa->sa_family) {
164 case AF_INET:
165 v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
166 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
167 flags |= NI_NUMERICHOST;
168 v4a >>= IN_CLASSA_NSHIFT;
169 if (v4a == 0 || v4a == IN_LOOPBACKNET)
170 flags |= NI_NUMERICHOST;
171 break;
172 #ifdef INET6
173 case AF_INET6:
174 {
175 struct sockaddr_in6 *sin6;
176 sin6 = (struct sockaddr_in6 *)sa;
177 switch (sin6->sin6_addr.s6_addr[0]) {
178 case 0x00:
179 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
180 ;
181 else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
182 ;
183 else
184 flags |= NI_NUMERICHOST;
185 break;
186 default:
187 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
188 flags |= NI_NUMERICHOST;
189 }
190 else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
191 flags |= NI_NUMERICHOST;
192 break;
193 }
194 }
195 break;
196 #endif
197 }
198 if (host == NULL || hostlen == 0) {
199 /* what should we do? */
200 } else if (flags & NI_NUMERICHOST) {
201 /* NUMERICHOST and NAMEREQD conflicts with each other */
202 if (flags & NI_NAMEREQD)
203 return ENI_NOHOSTNAME;
204 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
205 == NULL)
206 return ENI_SYSTEM;
207 if (strlen(numaddr) > hostlen)
208 return ENI_MEMORY;
209 strcpy(host, numaddr);
210 #ifdef INET6
211 if (afd->a_af == AF_INET6 &&
212 (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
213 IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
214 ((struct sockaddr_in6 *)sa)->sin6_scope_id) {
215 #ifndef ALWAYS_WITHSCOPE
216 if (flags & NI_WITHSCOPEID)
217 #endif /* !ALWAYS_WITHSCOPE */
218 {
219 char *ep = strchr(host, '\0');
220 unsigned int ifindex =
221 ((struct sockaddr_in6 *)sa)->sin6_scope_id;
222
223 *ep = SCOPE_DELIMITER;
224 if ((if_indextoname(ifindex, ep + 1)) == NULL)
225 /* XXX what should we do? */
226 strncpy(ep + 1, "???", 3);
227 }
228 }
229 #endif /* INET6 */
230 } else {
231 #ifdef USE_GETIPNODEBY
232 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
233 #else
234 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
235 #ifdef HAVE_H_ERRNO
236 h_error = h_errno;
237 #else
238 h_error = EINVAL;
239 #endif
240 #endif
241
242 if (hp) {
243 if (flags & NI_NOFQDN) {
244 p = strchr(hp->h_name, '.');
245 if (p) *p = '\0';
246 }
247 if (strlen(hp->h_name) > hostlen) {
248 #ifdef USE_GETIPNODEBY
249 freehostent(hp);
250 #endif
251 return ENI_MEMORY;
252 }
253 strcpy(host, hp->h_name);
254 #ifdef USE_GETIPNODEBY
255 freehostent(hp);
256 #endif
257 } else {
258 if (flags & NI_NAMEREQD)
259 return ENI_NOHOSTNAME;
260 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
261 == NULL)
262 return ENI_NOHOSTNAME;
263 if (strlen(numaddr) > hostlen)
264 return ENI_MEMORY;
265 strcpy(host, numaddr);
266 }
267 }
268 return SUCCESS;
269 }