1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38: #include <alloca.h>
39: #include <errno.h>
40: #include <netdb.h>
41: #include <stddef.h>
42: #include <stdlib.h>
43: #include <stdio.h>
44: #include <string.h>
45: #include <unistd.h>
46: #include <arpa/inet.h>
47: #include <net/if.h>
48: #include <netinet/in.h>
49: #include <sys/param.h>
50: #include <sys/socket.h>
51: #include <sys/types.h>
52: #include <sys/un.h>
53: #include <sys/utsname.h>
54: #include <bits/libc-lock.h>
55:
56: #ifdef HAVE_LIBIDN
57: # include <libidn/idna.h>
58: extern int __idna_to_unicode_lzlz (const char *input, char **output,
59: int flags);
60: #endif
61:
62: #ifndef min
63: # define min(x,y) (((x) > (y)) ? (y) : (x))
64: #endif
65:
66: libc_freeres_ptr (static char *domain);
67:
68:
69: static char *
70: internal_function
71: nrl_domainname (void)
72: {
73: static int not_first;
74:
75: if (! not_first)
76: {
77: __libc_lock_define_initialized (static, lock);
78: __libc_lock_lock (lock);
79:
80: if (! not_first)
81: {
82: char *c;
83: struct hostent *h, th;
84: size_t tmpbuflen = 1024;
85: char *tmpbuf = alloca (tmpbuflen);
86: int herror;
87:
88: not_first = 1;
89:
90: while (__gethostbyname_r ("localhost", &th, tmpbuf, tmpbuflen, &h,
91: &herror))
92: {
93: if (herror == NETDB_INTERNAL && errno == ERANGE)
94: tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
95: else
96: break;
97: }
98:
99: if (h && (c = strchr (h->h_name, '.')))
100: domain = __strdup (++c);
101: else
102: {
103:
104:
105: while (__gethostname (tmpbuf, tmpbuflen))
106: tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
107:
108: if ((c = strchr (tmpbuf, '.')))
109: domain = __strdup (++c);
110: else
111: {
112:
113: const char *hstname = strdupa (tmpbuf);
114:
115: while (__gethostbyname_r (hstname, &th, tmpbuf, tmpbuflen,
116: &h, &herror))
117: {
118: if (herror == NETDB_INTERNAL && errno == ERANGE)
119: tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
120: 2 * tmpbuflen);
121: else
122: break;
123: }
124:
125: if (h && (c = strchr(h->h_name, '.')))
126: domain = __strdup (++c);
127: else
128: {
129: struct in_addr in_addr;
130:
131: in_addr.s_addr = htonl (INADDR_LOOPBACK);
132:
133: while (__gethostbyaddr_r ((const char *) &in_addr,
134: sizeof (struct in_addr),
135: AF_INET, &th, tmpbuf,
136: tmpbuflen, &h, &herror))
137: {
138: if (herror == NETDB_INTERNAL && errno == ERANGE)
139: tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
140: 2 * tmpbuflen);
141: else
142: break;
143: }
144:
145: if (h && (c = strchr (h->h_name, '.')))
146: domain = __strdup (++c);
147: }
148: }
149: }
150: }
151:
152: __libc_lock_unlock (lock);
153: }
154:
155: return domain;
156: };
157:
158:
159: int
160: getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
161: socklen_t hostlen, char *serv, socklen_t servlen,
162: unsigned int flags)
163: {
164: int serrno = errno;
165: int tmpbuflen = 1024;
166: int herrno;
167: char *tmpbuf = alloca (tmpbuflen);
168: struct hostent th;
169: int ok = 0;
170:
171: if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
172: #ifdef HAVE_LIBIDN
173: |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
174: #endif
175: ))
176: return EAI_BADFLAGS;
177:
178: if (sa == NULL || addrlen < sizeof (sa_family_t))
179: return EAI_FAMILY;
180:
181: switch (sa->sa_family)
182: {
183: case AF_LOCAL:
184: if (addrlen < (socklen_t) offsetof (struct sockaddr_un, sun_path))
185: return EAI_FAMILY;
186: break;
187: case AF_INET:
188: if (addrlen < sizeof (struct sockaddr_in))
189: return EAI_FAMILY;
190: break;
191: case AF_INET6:
192: if (addrlen < sizeof (struct sockaddr_in6))
193: return EAI_FAMILY;
194: break;
195: default:
196: return EAI_FAMILY;
197: }
198:
199: if (host != NULL && hostlen > 0)
200: switch (sa->sa_family)
201: {
202: case AF_INET:
203: case AF_INET6:
204: if (!(flags & NI_NUMERICHOST))
205: {
206: struct hostent *h = NULL;
207: if (sa->sa_family == AF_INET6)
208: {
209: while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
210: sizeof(struct in6_addr),
211: AF_INET6, &th, tmpbuf, tmpbuflen,
212: &h, &herrno))
213: if (herrno == NETDB_INTERNAL && errno == ERANGE)
214: tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
215: else
216: break;
217: }
218: else
219: {
220: while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
221: sizeof(struct in_addr), AF_INET,
222: &th, tmpbuf, tmpbuflen,
223: &h, &herrno))
224: if (herrno == NETDB_INTERNAL && errno == ERANGE)
225: tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
226: else
227: break;
228: }
229:
230: if (h == NULL)
231: {
232: if (herrno == NETDB_INTERNAL)
233: {
234: __set_h_errno (herrno);
235: return EAI_SYSTEM;
236: }
237: if (herrno == TRY_AGAIN)
238: {
239: __set_h_errno (herrno);
240: return EAI_AGAIN;
241: }
242: }
243:
244: if (h)
245: {
246: char *c;
247: if ((flags & NI_NOFQDN)
248: && (c = nrl_domainname ())
249: && (c = strstr (h->h_name, c))
250: && (c != h->h_name) && (*(--c) == '.'))
251:
252: *c = '\0';
253:
254: #ifdef HAVE_LIBIDN
255:
256: if (flags & NI_IDN)
257: {
258: int idn_flags = 0;
259: if (flags & NI_IDN_ALLOW_UNASSIGNED)
260: idn_flags |= IDNA_ALLOW_UNASSIGNED;
261: if (flags & NI_IDN_USE_STD3_ASCII_RULES)
262: idn_flags |= IDNA_USE_STD3_ASCII_RULES;
263:
264: char *out;
265: int rc = __idna_to_unicode_lzlz (h->h_name, &out,
266: idn_flags);
267: if (rc != IDNA_SUCCESS)
268: {
269: if (rc == IDNA_MALLOC_ERROR)
270: return EAI_MEMORY;
271: if (rc == IDNA_DLOPEN_ERROR)
272: return EAI_SYSTEM;
273: return EAI_IDN_ENCODE;
274: }
275:
276: if (out != h->h_name)
277: {
278: h->h_name = strdupa (out);
279: free (out);
280: }
281: }
282: #endif
283:
284: size_t len = strlen (h->h_name) + 1;
285: if (len > hostlen)
286: return EAI_OVERFLOW;
287:
288: memcpy (host, h->h_name, len);
289:
290: ok = 1;
291: }
292: }
293:
294: if (!ok)
295: {
296: if (flags & NI_NAMEREQD)
297: {
298: __set_errno (serrno);
299: return EAI_NONAME;
300: }
301: else
302: {
303: const char *c;
304: if (sa->sa_family == AF_INET6)
305: {
306: const struct sockaddr_in6 *sin6p;
307: uint32_t scopeid;
308:
309: sin6p = (const struct sockaddr_in6 *) sa;
310:
311: c = inet_ntop (AF_INET6,
312: (const void *) &sin6p->sin6_addr, host, hostlen);
313: scopeid = sin6p->sin6_scope_id;
314: if (scopeid != 0)
315: {
316:
317: char scopebuf[IFNAMSIZ + 1];
318: char *scopeptr;
319: int ni_numericscope = 0;
320: size_t real_hostlen = __strnlen (host, hostlen);
321: size_t scopelen = 0;
322:
323: scopebuf[0] = SCOPE_DELIMITER;
324: scopebuf[1] = '\0';
325: scopeptr = &scopebuf[1];
326:
327: if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
328: || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
329: {
330: if (if_indextoname (scopeid, scopeptr) == NULL)
331: ++ni_numericscope;
332: else
333: scopelen = strlen (scopebuf);
334: }
335: else
336: ++ni_numericscope;
337:
338: if (ni_numericscope)
339: scopelen = 1 + __snprintf (scopeptr,
340: (scopebuf
341: + sizeof scopebuf
342: - scopeptr),
343: "%u", scopeid);
344:
345: if (real_hostlen + scopelen + 1 > hostlen)
346:
347:
348: return EAI_SYSTEM;
349: memcpy (host + real_hostlen, scopebuf, scopelen + 1);
350: }
351: }
352: else
353: c = inet_ntop (AF_INET,
354: (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
355: host, hostlen);
356: if (c == NULL)
357: return EAI_SYSTEM;
358: }
359: ok = 1;
360: }
361: break;
362:
363: case AF_LOCAL:
364: if (!(flags & NI_NUMERICHOST))
365: {
366: struct utsname utsname;
367:
368: if (!uname (&utsname))
369: {
370: strncpy (host, utsname.nodename, hostlen);
371: break;
372: };
373: };
374:
375: if (flags & NI_NAMEREQD)
376: {
377: __set_errno (serrno);
378: return EAI_NONAME;
379: }
380:
381: strncpy (host, "localhost", hostlen);
382: break;
383:
384: default:
385: return EAI_FAMILY;
386: }
387:
388: if (serv && (servlen > 0))
389: switch (sa->sa_family)
390: {
391: case AF_INET:
392: case AF_INET6:
393: if (!(flags & NI_NUMERICSERV))
394: {
395: struct servent *s, ts;
396: int e;
397: while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
398: ((flags & NI_DGRAM)
399: ? "udp" : "tcp"),
400: &ts, tmpbuf, tmpbuflen, &s)))
401: {
402: if (e == ERANGE)
403: tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
404: else
405: break;
406: }
407: if (s)
408: {
409: strncpy (serv, s->s_name, servlen);
410: break;
411: }
412: }
413:
414: if (__snprintf (serv, servlen, "%d",
415: ntohs (((const struct sockaddr_in *) sa)->sin_port))
416: + 1 > servlen)
417: return EAI_OVERFLOW;
418:
419: break;
420:
421: case AF_LOCAL:
422: strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
423: break;
424: }
425:
426: if (host && (hostlen > 0))
427: host[hostlen-1] = 0;
428: if (serv && (servlen > 0))
429: serv[servlen-1] = 0;
430: errno = serrno;
431: return 0;
432: }
433: libc_hidden_def (getnameinfo)