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: 39: 40: 41: 42: 43: 44: 45: 46:
47:
48: #include <sys/cdefs.h>
49: #if defined(LIBC_SCCS) && !defined(lint)
50: __RCSID("$NetBSD: getnameinfo.c,v 1.45 2006/10/15 16:14:46 christos Exp $");
51: #endif
52:
53: #ifdef T2EX
54: #include <t2ex/errno.h>
55: #include "port_before.h"
56: #endif
57:
58: #include "namespace.h"
59: #include <sys/types.h>
60: #include <sys/socket.h>
61: #include <net/if.h>
62: #include <net/if_dl.h>
63: #include <net/if_ieee1394.h>
64: #include <net/if_types.h>
65: #include <netinet/in.h>
66: #include <arpa/inet.h>
67: #include <arpa/nameser.h>
68: #include <assert.h>
69: #include <limits.h>
70: #include <netdb.h>
71: #include <resolv.h>
72: #include <stddef.h>
73: #include <string.h>
74:
75: #include "servent.h"
76:
77: #ifdef __weak_alias
78: __weak_alias(getnameinfo,_getnameinfo)
79: #endif
80:
81: static const struct afd {
82: int a_af;
83: socklen_t a_addrlen;
84: socklen_t a_socklen;
85: int a_off;
86: } afdl [] = {
87: #ifdef INET6
88: {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
89: offsetof(struct sockaddr_in6, sin6_addr)},
90: #endif
91: {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
92: offsetof(struct sockaddr_in, sin_addr)},
93: {0, 0, 0, 0},
94: };
95:
96: struct sockinet {
97: u_char si_len;
98: u_char si_family;
99: u_short si_port;
100: };
101:
102: static int getnameinfo_inet __P((const struct sockaddr *, socklen_t, char *,
103: socklen_t, char *, socklen_t, int));
104: #ifdef INET6
105: static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
106: socklen_t, int));
107: static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t,
108: int));
109: #endif
110: static int getnameinfo_link __P((const struct sockaddr *, socklen_t, char *,
111: socklen_t, char *, socklen_t, int));
112: static int hexname __P((const u_int8_t *, size_t, char *, socklen_t));
113:
114: 115: 116: 117:
118: int
119: getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
120: const struct sockaddr *sa;
121: socklen_t salen;
122: char *host, *serv;
123: socklen_t hostlen, servlen;
124: int flags;
125: {
126:
127: switch (sa->sa_family) {
128: case AF_INET:
129: case AF_INET6:
130: return getnameinfo_inet(sa, salen, host, hostlen,
131: serv, servlen, flags);
132: case AF_LINK:
133: return getnameinfo_link(sa, salen, host, hostlen,
134: serv, servlen, flags);
135: default:
136: return EAI_FAMILY;
137: }
138: }
139:
140:
141: 142: 143: 144:
145: static int
146: getnameinfo_inet(sa, salen, host, hostlen, serv, servlen, flags)
147: const struct sockaddr *sa;
148: socklen_t salen;
149: char *host;
150: socklen_t hostlen;
151: char *serv;
152: socklen_t servlen;
153: int flags;
154: {
155: const struct afd *afd;
156: struct servent *sp;
157: struct hostent *hp;
158: u_short port;
159: int family, i;
160: const char *addr;
161: u_int32_t v4a;
162: #ifndef T2EX
163: char numserv[512];
164: char numaddr[512];
165: #else
166: char numserv[8]; 167:
168: #if defined(INET6)
169: char numaddr[INET6_ADDRSTRLEN];
170: #elif defined(INET)
171: char numaddr[INET_ADDRSTRLEN];
172: #else
173: char numaddr[INET6_ADDRSTRLEN];
174: #endif
175: #endif
176:
177:
178:
179:
180:
181: if (sa == NULL)
182: return EAI_FAIL;
183:
184: #ifdef BSD4_4
185: if (sa->sa_len != salen)
186: return EAI_FAIL;
187: #endif
188:
189: family = sa->sa_family;
190: for (i = 0; afdl[i].a_af; i++)
191: if (afdl[i].a_af == family) {
192: afd = &afdl[i];
193: goto found;
194: }
195: return EAI_FAMILY;
196:
197: found:
198: if (salen != afd->a_socklen)
199: return EAI_FAIL;
200:
201:
202: port = ((const struct sockinet *)(const void *)sa)->si_port;
203: addr = (const char *)(const void *)sa + afd->a_off;
204:
205: if (serv == NULL || servlen == 0) {
206: 207: 208: 209: 210: 211:
212: } else {
213: #ifdef T2EX
214: struct servent_data svd;
215: struct servent sv;
216: (void)memset(&svd, 0, sizeof(svd));
217: #endif
218:
219: if (flags & NI_NUMERICSERV)
220: sp = NULL;
221: else {
222: #ifndef T2EX
223: struct servent_data svd;
224: struct servent sv;
225:
226: (void)memset(&svd, 0, sizeof(svd));
227: #endif
228: sp = getservbyport_r(port,
229: (flags & NI_DGRAM) ? "udp" : "tcp", &sv, &svd);
230: #ifndef T2EX
231: endservent_r(&svd);
232: #endif
233: }
234: if (sp) {
235: if (strlen(sp->s_name) + 1 > servlen)
236: return EAI_MEMORY;
237: strlcpy(serv, sp->s_name, servlen);
238: } else {
239: snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
240: if (strlen(numserv) + 1 > servlen)
241: return EAI_MEMORY;
242: strlcpy(serv, numserv, servlen);
243: }
244:
245: #ifdef T2EX
246: endservent_r(&svd);
247: #endif
248: }
249:
250: switch (sa->sa_family) {
251: case AF_INET:
252: v4a = (u_int32_t)
253: ntohl(((const struct sockaddr_in *)
254: (const void *)sa)->sin_addr.s_addr);
255: if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
256: flags |= NI_NUMERICHOST;
257: v4a >>= IN_CLASSA_NSHIFT;
258: if (v4a == 0)
259: flags |= NI_NUMERICHOST;
260: break;
261: #ifdef INET6
262: case AF_INET6:
263: {
264: const struct sockaddr_in6 *sin6;
265: sin6 = (const struct sockaddr_in6 *)(const void *)sa;
266: switch (sin6->sin6_addr.s6_addr[0]) {
267: case 0x00:
268: if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
269: ;
270: else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
271: ;
272: else
273: flags |= NI_NUMERICHOST;
274: break;
275: default:
276: if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
277: flags |= NI_NUMERICHOST;
278: }
279: else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
280: flags |= NI_NUMERICHOST;
281: break;
282: }
283: }
284: break;
285: #endif
286: }
287: if (host == NULL || hostlen == 0) {
288: 289: 290: 291: 292: 293:
294: } else if (flags & NI_NUMERICHOST) {
295: size_t numaddrlen;
296:
297:
298: if (flags & NI_NAMEREQD)
299: return EAI_NONAME;
300:
301: switch(afd->a_af) {
302: #ifdef INET6
303: case AF_INET6:
304: {
305: int error;
306:
307: if ((error = ip6_parsenumeric(sa, addr, host,
308: hostlen, flags)) != 0)
309: return(error);
310: break;
311: }
312: #endif
313: default:
314: if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
315: == NULL)
316: return EAI_SYSTEM;
317: numaddrlen = strlen(numaddr);
318: if (numaddrlen + 1 > hostlen)
319: return EAI_MEMORY;
320: strlcpy(host, numaddr, hostlen);
321: break;
322: }
323: } else {
324: hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
325:
326: if (hp) {
327: #if 0
328: 329: 330: 331:
332: if (flags & NI_NOFQDN) {
333: char *p;
334: p = strchr(hp->h_name, '.');
335: if (p)
336: *p = '\0';
337: }
338: #endif
339: if (strlen(hp->h_name) + 1 > hostlen) {
340: return EAI_MEMORY;
341: }
342: strlcpy(host, hp->h_name, hostlen);
343: } else {
344: if (flags & NI_NAMEREQD)
345: return EAI_NONAME;
346: switch(afd->a_af) {
347: #ifdef INET6
348: case AF_INET6:
349: {
350: int error;
351:
352: if ((error = ip6_parsenumeric(sa, addr, host,
353: hostlen,
354: flags)) != 0)
355: return(error);
356: break;
357: }
358: #endif
359: default:
360: if (inet_ntop(afd->a_af, addr, host,
361: hostlen) == NULL)
362: return EAI_SYSTEM;
363: break;
364: }
365: }
366: }
367: return(0);
368: }
369:
370: #ifdef INET6
371: static int
372: ip6_parsenumeric(sa, addr, host, hostlen, flags)
373: const struct sockaddr *sa;
374: const char *addr;
375: char *host;
376: socklen_t hostlen;
377: int flags;
378: {
379: size_t numaddrlen;
380: char numaddr[512];
381:
382: _DIAGASSERT(sa != NULL);
383: _DIAGASSERT(addr != NULL);
384: _DIAGASSERT(host != NULL);
385:
386: if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL)
387: return EAI_SYSTEM;
388:
389: numaddrlen = strlen(numaddr);
390: if (numaddrlen + 1 > hostlen)
391: return EAI_OVERFLOW;
392: strlcpy(host, numaddr, hostlen);
393:
394: if (((const struct sockaddr_in6 *)(const void *)sa)->sin6_scope_id) {
395: char zonebuf[MAXHOSTNAMELEN];
396: int zonelen;
397:
398: zonelen = ip6_sa2str(
399: (const struct sockaddr_in6 *)(const void *)sa,
400: zonebuf, sizeof(zonebuf), flags);
401: if (zonelen < 0)
402: return EAI_OVERFLOW;
403: if ((size_t) zonelen + 1 + numaddrlen + 1 > hostlen)
404: return EAI_OVERFLOW;
405:
406: memcpy(host + numaddrlen + 1, zonebuf,
407: (size_t)zonelen);
408: host[numaddrlen] = SCOPE_DELIMITER;
409: host[numaddrlen + 1 + zonelen] = '\0';
410: }
411:
412: return 0;
413: }
414:
415:
416: static int
417: ip6_sa2str(sa6, buf, bufsiz, flags)
418: const struct sockaddr_in6 *sa6;
419: char *buf;
420: size_t bufsiz;
421: int flags;
422: {
423: unsigned int ifindex;
424: const struct in6_addr *a6;
425: int n;
426:
427: _DIAGASSERT(sa6 != NULL);
428: _DIAGASSERT(buf != NULL);
429:
430: ifindex = (unsigned int)sa6->sin6_scope_id;
431: a6 = &sa6->sin6_addr;
432:
433: #ifdef NI_NUMERICSCOPE
434: if ((flags & NI_NUMERICSCOPE) != 0) {
435: n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
436: if (n < 0 || n >= bufsiz)
437: return -1;
438: else
439: return n;
440: }
441: #endif
442:
443:
444: if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
445: bufsiz >= IF_NAMESIZE) {
446: char *p = if_indextoname(ifindex, buf);
447: if (p) {
448: return(strlen(p));
449: }
450: }
451:
452:
453: n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
454: if (n < 0 || (size_t) n >= bufsiz)
455: return -1;
456: else
457: return n;
458: }
459: #endif
460:
461:
462: 463: 464: 465: 466:
467:
468: static int
469: getnameinfo_link(const struct sockaddr *sa, socklen_t salen,
470: char *host, socklen_t hostlen, char *serv, socklen_t servlen,
471: int flags)
472: {
473: const struct sockaddr_dl *sdl =
474: (const struct sockaddr_dl *)(const void *)sa;
475: const struct ieee1394_hwaddr *iha;
476: int n;
477:
478: if (serv != NULL && servlen > 0)
479: *serv = '\0';
480:
481: if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) {
482: n = snprintf(host, hostlen, "link#%u", sdl->sdl_index);
483: if (n < 0 || (socklen_t) n > hostlen) {
484: *host = '\0';
485: return EAI_MEMORY;
486: }
487: return 0;
488: }
489:
490: switch (sdl->sdl_type) {
491: #ifdef IFT_ECONET
492: case IFT_ECONET:
493: if (sdl->sdl_alen < 2)
494: return EAI_FAMILY;
495: if (CLLADDR(sdl)[1] == 0)
496: n = snprintf(host, hostlen, "%u", CLLADDR(sdl)[0]);
497: else
498: n = snprintf(host, hostlen, "%u.%u",
499: CLLADDR(sdl)[1], CLLADDR(sdl)[0]);
500: if (n < 0 || (socklen_t) n >= hostlen) {
501: *host = '\0';
502: return EAI_MEMORY;
503: } else
504: return 0;
505: #endif
506: case IFT_IEEE1394:
507: if (sdl->sdl_alen < sizeof(iha->iha_uid))
508: return EAI_FAMILY;
509: iha =
510: (const struct ieee1394_hwaddr *)(const void *)CLLADDR(sdl);
511: return hexname(iha->iha_uid, sizeof(iha->iha_uid),
512: host, hostlen);
513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524:
525: 526: 527: 528:
529: case IFT_ARCNET:
530: case IFT_ETHER:
531: case IFT_FDDI:
532: case IFT_HIPPI:
533: case IFT_ISO88025:
534: default:
535: return hexname((const u_int8_t *)CLLADDR(sdl),
536: (size_t)sdl->sdl_alen, host, hostlen);
537: }
538: }
539:
540: static int
541: hexname(cp, len, host, hostlen)
542: const u_int8_t *cp;
543: char *host;
544: size_t len;
545: socklen_t hostlen;
546: {
547: int n;
548: size_t i;
549: char *outp = host;
550:
551: *outp = '\0';
552: for (i = 0; i < len; i++) {
553: n = snprintf(outp, hostlen, "%s%02x",
554: i ? ":" : "", cp[i]);
555: if (n < 0 || (socklen_t) n >= hostlen) {
556: *host = '\0';
557: return EAI_MEMORY;
558: }
559: outp += n;
560: hostlen -= n;
561: }
562: return 0;
563: }