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