]> git.ipfire.org Git - thirdparty/glibc.git/blame - inet/getnameinfo.c
* include/stdlib.h: Use libc_hidden_proto for wctomb.
[thirdparty/glibc.git] / inet / getnameinfo.c
CommitLineData
1fb05e3d
UD
1/* The Inner Net License, Version 2.00
2
3 The author(s) grant permission for redistribution and use in source and
4binary forms, with or without modification, of the software and documentation
5provided that the following conditions are met:
6
70. If you receive a version of the software that is specifically labelled
8 as not being for redistribution (check the version message and/or README),
9 you are not permitted to redistribute that version of the software in any
10 way or form.
111. All terms of the all other applicable copyrights and licenses must be
12 followed.
132. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
153. Redistributions in binary form must reproduce the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
aeb25823 184. [The copyright holder has authorized the removal of this clause.]
1fb05e3d
UD
195. Neither the name(s) of the author(s) nor the names of its contributors
20 may be used to endorse or promote products derived from this software
21 without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
24EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
27DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34 If these license terms cause you a real problem, contact the author. */
35
36/* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
37
c0bc5f7b 38#include <alloca.h>
1fb05e3d 39#include <errno.h>
c0bc5f7b 40#include <netdb.h>
1fb05e3d 41#include <stdio.h>
c0bc5f7b 42#include <string.h>
1fb05e3d 43#include <unistd.h>
5a97622d 44#include <arpa/inet.h>
c0bc5f7b
UD
45#include <net/if.h>
46#include <netinet/in.h>
47#include <sys/param.h>
48#include <sys/socket.h>
49#include <sys/types.h>
50#include <sys/un.h>
51#include <sys/utsname.h>
52#include <bits/libc-lock.h>
1fb05e3d 53
1fb05e3d 54#ifndef min
cd6ede75 55# define min(x,y) (((x) > (y)) ? (y) : (x))
1fb05e3d
UD
56#endif /* min */
57
1fb05e3d 58
40a55d20 59static char *
dfd2257a 60internal_function
cd6ede75 61nrl_domainname (void)
1fb05e3d 62{
390500b1
UD
63 static char *domain;
64 static int not_first;
1fb05e3d 65
3a07823a 66 if (! not_first)
cd6ede75
UD
67 {
68 __libc_lock_define_initialized (static, lock);
69 __libc_lock_lock (lock);
70
3a07823a 71 if (! not_first)
cd6ede75
UD
72 {
73 char *c;
74 struct hostent *h, th;
40a55d20 75 size_t tmpbuflen = 1024;
cd6ede75
UD
76 char *tmpbuf = alloca (tmpbuflen);
77 int herror;
78
390500b1 79 not_first = 1;
cd6ede75
UD
80
81 while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
82 &herror))
83 {
84 if (herror == NETDB_INTERNAL && errno == ERANGE)
85 {
86 tmpbuflen *= 2;
87 tmpbuf = alloca (tmpbuflen);
88 }
89 else
90 break;
91 }
5a97622d 92
cd6ede75
UD
93 if (h && (c = strchr (h->h_name, '.')))
94 domain = __strdup (++c);
95 else
96 {
97 /* The name contains no domain information. Use the name
98 now to get more information. */
50304ef0 99 while (__gethostname (tmpbuf, tmpbuflen))
cd6ede75
UD
100 {
101 tmpbuflen *= 2;
102 tmpbuf = alloca (tmpbuflen);
103 }
5a97622d 104
cd6ede75
UD
105 if ((c = strchr (tmpbuf, '.')))
106 domain = __strdup (++c);
107 else
108 {
109 /* We need to preserve the hostname. */
110 const char *hstname = strdupa (tmpbuf);
111
112 while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
113 &h, &herror))
114 {
115 if (herror == NETDB_INTERNAL && errno == ERANGE)
116 {
117 tmpbuflen *= 2;
118 tmpbuf = alloca (tmpbuflen);
119 }
120 else
121 break;
122 }
123
124 if (h && (c = strchr(h->h_name, '.')))
125 domain = __strdup (++c);
126 else
127 {
128 struct in_addr in_addr;
129
062a2a18 130 in_addr.s_addr = htonl (INADDR_LOOPBACK);
cd6ede75
UD
131
132 while (__gethostbyaddr_r ((const char *) &in_addr,
133 sizeof (struct in_addr),
134 AF_INET, &th, tmpbuf,
135 tmpbuflen, &h, &herror))
136 {
137 if (herror == NETDB_INTERNAL && errno == ERANGE)
138 {
139 tmpbuflen *= 2;
140 tmpbuf = alloca (tmpbuflen);
141 }
142 else
143 break;
144 }
145
146 if (h && (c = strchr (h->h_name, '.')))
147 domain = __strdup (++c);
148 }
149 }
5a97622d 150 }
5a97622d 151 }
1fb05e3d 152
cd6ede75 153 __libc_lock_unlock (lock);
1fb05e3d
UD
154 }
155
1fb05e3d
UD
156 return domain;
157};
158
cd6ede75
UD
159
160int
c7614ee9 161getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
ccd4b479
UD
162 socklen_t hostlen, char *serv, socklen_t servlen,
163 unsigned int flags)
1fb05e3d
UD
164{
165 int serrno = errno;
5a97622d
UD
166 int tmpbuflen = 1024;
167 int herrno;
cd6ede75 168 char *tmpbuf = alloca (tmpbuflen);
5a97622d 169 struct hostent th;
c0bc5f7b 170 int ok = 0;
1fb05e3d 171
85599e53
UD
172 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
173 return EAI_BADFLAGS;
174
922809a2 175 if (sa == NULL || addrlen < sizeof (sa_family_t))
85599e53 176 return EAI_FAMILY;
922809a2
UD
177
178 switch (sa->sa_family)
179 {
180 case AF_LOCAL:
4fcddf8e 181 if (addrlen < (socklen_t) (((struct sockaddr_un *) NULL)->sun_path))
85599e53 182 return EAI_FAMILY;
4fcddf8e
UD
183 break;
184 case AF_INET:
185 if (addrlen < sizeof (struct sockaddr_in))
85599e53 186 return EAI_FAMILY;
4fcddf8e
UD
187 break;
188 case AF_INET6:
189 if (addrlen < sizeof (struct sockaddr_in6))
85599e53 190 return EAI_FAMILY;
922809a2
UD
191 break;
192 default:
85599e53 193 return EAI_FAMILY;
922809a2 194 }
1fb05e3d 195
cd6ede75 196 if (host != NULL && hostlen > 0)
4fcddf8e 197 switch (sa->sa_family)
cd6ede75 198 {
1fb05e3d 199 case AF_INET:
1fb05e3d 200 case AF_INET6:
cd6ede75
UD
201 if (!(flags & NI_NUMERICHOST))
202 {
203 struct hostent *h = NULL;
cd6ede75
UD
204 if (h == NULL)
205 {
cd6ede75
UD
206 if (sa->sa_family == AF_INET6)
207 {
c3301189 208 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
cd6ede75
UD
209 sizeof(struct in6_addr),
210 AF_INET6, &th, tmpbuf, tmpbuflen,
211 &h, &herrno))
212 {
213 if (herrno == NETDB_INTERNAL)
214 {
215 if (errno == ERANGE)
216 {
217 tmpbuflen *= 2;
218 tmpbuf = alloca (tmpbuflen);
219 }
220 else
221 {
222 __set_h_errno (herrno);
40a55d20 223 __set_errno (serrno);
85599e53 224 return EAI_SYSTEM;
cd6ede75
UD
225 }
226 }
227 else
228 {
229 break;
230 }
231 }
5a97622d 232 }
cd6ede75
UD
233 else
234 {
c3301189 235 while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
cd6ede75
UD
236 sizeof(struct in_addr), AF_INET,
237 &th, tmpbuf, tmpbuflen,
238 &h, &herrno))
239 {
240 if (errno == ERANGE)
241 {
242 tmpbuflen *= 2;
243 tmpbuf = alloca (tmpbuflen);
244 }
245 else
246 {
247 break;
248 }
249 }
250 }
5a97622d 251 }
1fb05e3d 252
cd6ede75
UD
253 if (h)
254 {
85599e53 255 char *c;
104d0bd3 256 if ((flags & NI_NOFQDN)
85599e53
UD
257 && (c = nrl_domainname ())
258 && (c = strstr (h->h_name, c))
259 && (c != h->h_name) && (*(--c) == '.'))
cd6ede75 260 {
85599e53
UD
261 strncpy (host, h->h_name,
262 min(hostlen, (size_t) (c - h->h_name)));
263 host[min(hostlen - 1, (size_t) (c - h->h_name))]
264 = '\0';
265 ok = 1;
266 }
267 else
268 {
269 strncpy (host, h->h_name, hostlen);
270 ok = 1;
cd6ede75 271 }
cd6ede75
UD
272 }
273 }
1fb05e3d 274
c0bc5f7b 275 if (!ok)
40a55d20 276 {
c0bc5f7b 277 if (flags & NI_NAMEREQD)
40a55d20
UD
278 {
279 __set_errno (serrno);
85599e53 280 return EAI_NONAME;
40a55d20 281 }
c0bc5f7b
UD
282 else
283 {
284 const char *c;
285 if (sa->sa_family == AF_INET6)
286 {
c3301189 287 const struct sockaddr_in6 *sin6p;
c0bc5f7b
UD
288 uint32_t scopeid;
289
c3301189
UD
290 sin6p = (const struct sockaddr_in6 *) sa;
291
c0bc5f7b 292 c = inet_ntop (AF_INET6,
c3301189 293 (const void *) &sin6p->sin6_addr, host, hostlen);
85599e53
UD
294 scopeid = sin6p->sin6_scope_id;
295 if (scopeid != 0)
c0bc5f7b
UD
296 {
297 /* Buffer is >= IFNAMSIZ+1. */
4fcddf8e 298 char scopebuf[IFNAMSIZ + 1];
85599e53 299 char *scopeptr;
c0bc5f7b 300 int ni_numericscope = 0;
85599e53
UD
301 size_t real_hostlen = __strnlen (host, hostlen);
302 size_t scopelen = 0;
303
304 scopebuf[0] = SCOPE_DELIMITER;
305 scopebuf[1] = '\0';
306 scopeptr = &scopebuf[1];
c0bc5f7b
UD
307
308 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
309 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
310 {
5804f16c 311 if (if_indextoname (scopeid, scopeptr) == NULL)
c0bc5f7b 312 ++ni_numericscope;
85599e53
UD
313 else
314 scopelen = strlen (scopebuf);
c0bc5f7b
UD
315 }
316 else
317 ++ni_numericscope;
318
319 if (ni_numericscope)
85599e53
UD
320 scopelen = 1 + __snprintf (scopeptr,
321 (scopebuf
322 + sizeof scopebuf
323 - scopeptr),
324 "%u", scopeid);
325
326 if (real_hostlen + scopelen + 1 > hostlen)
327 /* XXX We should not fail here. Simply enlarge
328 the buffer or return with out of memory. */
329 return EAI_SYSTEM;
330 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
c0bc5f7b
UD
331 }
332 }
333 else
334 c = inet_ntop (AF_INET,
c3301189 335 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
c0bc5f7b
UD
336 host, hostlen);
337 if (c == NULL)
338 {
339 __set_errno (serrno);
85599e53 340 return EAI_SYSTEM;
c0bc5f7b
UD
341 }
342 }
343 ok = 1;
cd6ede75 344 }
1fb05e3d 345 break;
cd6ede75 346
1fb05e3d 347 case AF_LOCAL:
cd6ede75
UD
348 if (!(flags & NI_NUMERICHOST))
349 {
350 struct utsname utsname;
1fb05e3d 351
cd6ede75
UD
352 if (!uname (&utsname))
353 {
354 strncpy (host, utsname.nodename, hostlen);
355 break;
356 };
1fb05e3d 357 };
1fb05e3d
UD
358
359 if (flags & NI_NAMEREQD)
40a55d20
UD
360 {
361 __set_errno (serrno);
85599e53 362 return EAI_NONAME;
40a55d20 363 }
1fb05e3d 364
cd6ede75 365 strncpy (host, "localhost", hostlen);
1fb05e3d 366 break;
cd6ede75 367
1fb05e3d 368 default:
85599e53 369 return EAI_FAMILY;
cd6ede75 370 }
1fb05e3d
UD
371
372 if (serv && (servlen > 0))
4fcddf8e 373 switch (sa->sa_family)
cd6ede75 374 {
1fb05e3d 375 case AF_INET:
1fb05e3d 376 case AF_INET6:
cd6ede75
UD
377 if (!(flags & NI_NUMERICSERV))
378 {
379 struct servent *s, ts;
c3301189 380 while (__getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
cd6ede75
UD
381 ((flags & NI_DGRAM) ? "udp" : "tcp"),
382 &ts, tmpbuf, tmpbuflen, &s))
383 {
384 if (herrno == NETDB_INTERNAL)
385 {
386 if (errno == ERANGE)
387 {
388 tmpbuflen *= 2;
40a55d20 389 tmpbuf = __alloca (tmpbuflen);
cd6ede75
UD
390 }
391 else
40a55d20
UD
392 {
393 __set_errno (serrno);
85599e53 394 return EAI_SYSTEM;
40a55d20 395 }
cd6ede75
UD
396 }
397 else
398 {
399 break;
400 }
401 }
402 if (s)
403 {
40a55d20 404 strncpy (serv, s->s_name, servlen);
cd6ede75 405 break;
5a97622d 406 }
5a97622d 407 }
50304ef0 408 __snprintf (serv, servlen, "%d",
c3301189 409 ntohs (((const struct sockaddr_in *) sa)->sin_port));
1fb05e3d 410 break;
cd6ede75 411
1fb05e3d 412 case AF_LOCAL:
c3301189 413 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1fb05e3d 414 break;
cd6ede75
UD
415 }
416
1fb05e3d
UD
417 if (host && (hostlen > 0))
418 host[hostlen-1] = 0;
419 if (serv && (servlen > 0))
420 serv[servlen-1] = 0;
421 errno = serrno;
422 return 0;
40a55d20 423}