1*03645a16Schristos /* $NetBSD: getnameinfo.c,v 1.60 2023/09/08 18:17:41 christos Exp $ */
2a931ac82Sitojun /* $KAME: getnameinfo.c,v 1.45 2000/09/25 22:43:56 itojun Exp $ */
34620b004Sitojun
437e81591Sitojun /*
5b1297979Sbjh21 * Copyright (c) 2000 Ben Harris.
637e81591Sitojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
737e81591Sitojun * All rights reserved.
837e81591Sitojun *
937e81591Sitojun * Redistribution and use in source and binary forms, with or without
1037e81591Sitojun * modification, are permitted provided that the following conditions
1137e81591Sitojun * are met:
1237e81591Sitojun * 1. Redistributions of source code must retain the above copyright
1337e81591Sitojun * notice, this list of conditions and the following disclaimer.
1437e81591Sitojun * 2. Redistributions in binary form must reproduce the above copyright
1537e81591Sitojun * notice, this list of conditions and the following disclaimer in the
1637e81591Sitojun * documentation and/or other materials provided with the distribution.
1737e81591Sitojun * 3. Neither the name of the project nor the names of its contributors
1837e81591Sitojun * may be used to endorse or promote products derived from this software
1937e81591Sitojun * without specific prior written permission.
2037e81591Sitojun *
2137e81591Sitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2237e81591Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2337e81591Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2437e81591Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2537e81591Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2637e81591Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2737e81591Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2837e81591Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2937e81591Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3037e81591Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3137e81591Sitojun * SUCH DAMAGE.
3237e81591Sitojun */
3337e81591Sitojun
3437e81591Sitojun /*
3537e81591Sitojun * Issues to be discussed:
3637e81591Sitojun * - Thread safe-ness must be checked
371501f618Sitojun * - RFC2553 says that we should raise error on short buffer. X/Open says
381501f618Sitojun * we need to truncate the result. We obey RFC2553 (and X/Open should be
396acd1fa3Sitojun * modified). ipngwg rough consensus seems to follow RFC2553.
403fc57d3fSitojun * - What is "local" in NI_FQDN?
413fc57d3fSitojun * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
426c9440f3Sitojun * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if
436c9440f3Sitojun * sin6_scope_id is filled - standardization status?
446c9440f3Sitojun * XXX breaks backward compat for code that expects no scopeid.
456c9440f3Sitojun * beware on merge.
4637e81591Sitojun */
4737e81591Sitojun
4872eddcacSitojun #include <sys/cdefs.h>
4972eddcacSitojun #if defined(LIBC_SCCS) && !defined(lint)
50*03645a16Schristos __RCSID("$NetBSD: getnameinfo.c,v 1.60 2023/09/08 18:17:41 christos Exp $");
5172eddcacSitojun #endif /* LIBC_SCCS and not lint */
5272eddcacSitojun
536011d36bSozaki-r #ifndef RUMP_ACTION
54c6bf4b09Sitojun #include "namespace.h"
556011d36bSozaki-r #endif
5637e81591Sitojun #include <sys/types.h>
5737e81591Sitojun #include <sys/socket.h>
58911623fbSchristos #include <sys/un.h>
591501f618Sitojun #include <net/if.h>
60b1297979Sbjh21 #include <net/if_dl.h>
61b1297979Sbjh21 #include <net/if_ieee1394.h>
62b1297979Sbjh21 #include <net/if_types.h>
63000fbf6bSis #include <netatalk/at.h>
6437e81591Sitojun #include <netinet/in.h>
6537e81591Sitojun #include <arpa/inet.h>
6637e81591Sitojun #include <arpa/nameser.h>
67a976c8e3Slukem #include <assert.h>
68b1297979Sbjh21 #include <limits.h>
6937e81591Sitojun #include <netdb.h>
7037e81591Sitojun #include <resolv.h>
7137e81591Sitojun #include <stddef.h>
72a976c8e3Slukem #include <string.h>
7337e81591Sitojun
741463de6aSchristos #include "servent.h"
7502dd2447Schristos #include "hostent.h"
761463de6aSchristos
775d88ea0bSjoerg #ifndef RUMP_ACTION
78c6bf4b09Sitojun #ifdef __weak_alias
79c6bf4b09Sitojun __weak_alias(getnameinfo,_getnameinfo)
80c6bf4b09Sitojun #endif
815d88ea0bSjoerg #endif
82c6bf4b09Sitojun
83ca797c3cSjdolecek static const struct afd {
8437e81591Sitojun int a_af;
85a51e2828Skleink socklen_t a_addrlen;
86a51e2828Skleink socklen_t a_socklen;
8737e81591Sitojun int a_off;
8837e81591Sitojun } afdl [] = {
8937e81591Sitojun #ifdef INET6
9037e81591Sitojun {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
9137e81591Sitojun offsetof(struct sockaddr_in6, sin6_addr)},
9237e81591Sitojun #endif
9337e81591Sitojun {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
9437e81591Sitojun offsetof(struct sockaddr_in, sin_addr)},
95ce2c90c7Schristos {0, 0, 0, 0},
9637e81591Sitojun };
9737e81591Sitojun
9837e81591Sitojun struct sockinet {
9937e81591Sitojun u_char si_len;
10037e81591Sitojun u_char si_family;
10137e81591Sitojun u_short si_port;
10237e81591Sitojun };
10337e81591Sitojun
104504f8671Smatt static int getnameinfo_inet(const struct sockaddr *, socklen_t, char *,
105504f8671Smatt socklen_t, char *, socklen_t, int);
10634a6354bSitojun #ifdef INET6
107504f8671Smatt static int ip6_parsenumeric(const struct sockaddr *, const char *, char *,
108504f8671Smatt socklen_t, int);
109504f8671Smatt static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int);
11034a6354bSitojun #endif
111504f8671Smatt static int getnameinfo_atalk(const struct sockaddr *, socklen_t, char *,
112504f8671Smatt socklen_t, char *, socklen_t, int);
113911623fbSchristos static int getnameinfo_local(const struct sockaddr *, socklen_t, char *,
114911623fbSchristos socklen_t, char *, socklen_t, int);
115000fbf6bSis
116504f8671Smatt static int getnameinfo_link(const struct sockaddr *, socklen_t, char *,
117504f8671Smatt socklen_t, char *, socklen_t, int);
118504f8671Smatt static int hexname(const uint8_t *, size_t, char *, socklen_t);
11934a6354bSitojun
120b1297979Sbjh21 /*
121b1297979Sbjh21 * Top-level getnameinfo() code. Look at the address family, and pick an
122b1297979Sbjh21 * appropriate function to call.
123b1297979Sbjh21 */
12437e81591Sitojun int
getnameinfo(const struct sockaddr * sa,socklen_t salen,char * host,socklen_t hostlen,char * serv,socklen_t servlen,int flags)125504f8671Smatt getnameinfo(const struct sockaddr *sa, socklen_t salen,
126504f8671Smatt char *host, socklen_t hostlen,
127504f8671Smatt char *serv, socklen_t servlen,
128504f8671Smatt int flags)
129b1297979Sbjh21 {
130b1297979Sbjh21
131*03645a16Schristos /*
132*03645a16Schristos * getnameinfo() accepts an salen of sizeof(struct sockaddr_storage)
133*03645a16Schristos * at maximum as shown in RFC 4038 Sec.6.2.3.
134*03645a16Schristos */
135*03645a16Schristos if (salen > sizeof(struct sockaddr_storage))
136*03645a16Schristos return EAI_FAMILY;
137*03645a16Schristos
138b1297979Sbjh21 switch (sa->sa_family) {
139000fbf6bSis case AF_APPLETALK:
140000fbf6bSis return getnameinfo_atalk(sa, salen, host, hostlen,
141000fbf6bSis serv, servlen, flags);
142b1297979Sbjh21 case AF_INET:
143b1297979Sbjh21 case AF_INET6:
144b1297979Sbjh21 return getnameinfo_inet(sa, salen, host, hostlen,
145b1297979Sbjh21 serv, servlen, flags);
146b1297979Sbjh21 case AF_LINK:
147b1297979Sbjh21 return getnameinfo_link(sa, salen, host, hostlen,
148b1297979Sbjh21 serv, servlen, flags);
149911623fbSchristos case AF_LOCAL:
150911623fbSchristos return getnameinfo_local(sa, salen, host, hostlen,
151911623fbSchristos serv, servlen, flags);
152b1297979Sbjh21 default:
153b1297979Sbjh21 return EAI_FAMILY;
154b1297979Sbjh21 }
155b1297979Sbjh21 }
156b1297979Sbjh21
157000fbf6bSis /*
158000fbf6bSis * getnameinfo_atalk():
159000fbf6bSis * Format an AppleTalk address into a printable format.
160000fbf6bSis */
161000fbf6bSis /* ARGSUSED */
162000fbf6bSis static int
getnameinfo_atalk(const struct sockaddr * sa,socklen_t salen,char * host,socklen_t hostlen,char * serv,socklen_t servlen,int flags)163000fbf6bSis getnameinfo_atalk(const struct sockaddr *sa, socklen_t salen,
164000fbf6bSis char *host, socklen_t hostlen, char *serv, socklen_t servlen,
165000fbf6bSis int flags)
166000fbf6bSis {
167000fbf6bSis char numserv[8];
16845845cf0Sis int n, m=0;
169000fbf6bSis
170000fbf6bSis const struct sockaddr_at *sat =
171000fbf6bSis (const struct sockaddr_at *)(const void *)sa;
172000fbf6bSis
173000fbf6bSis if (serv != NULL && servlen > 0) {
174000fbf6bSis snprintf(numserv, sizeof(numserv), "%u", sat->sat_port);
175000fbf6bSis if (strlen(numserv) + 1 > servlen)
176000fbf6bSis return EAI_MEMORY;
177000fbf6bSis strlcpy(serv, numserv, servlen);
178000fbf6bSis }
179000fbf6bSis
180000fbf6bSis n = snprintf(host, hostlen, "%u.%u",
181000fbf6bSis ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
18245845cf0Sis
18345845cf0Sis if (n < 0 || (socklen_t)(m+n) >= hostlen)
18445845cf0Sis goto errout;
18545845cf0Sis
18645845cf0Sis m += n;
18745845cf0Sis
18845845cf0Sis if (sat->sat_range.r_netrange.nr_phase) {
18945845cf0Sis n = snprintf(host+m, hostlen-m, " phase %u",
19045845cf0Sis sat->sat_range.r_netrange.nr_phase);
19145845cf0Sis
19245845cf0Sis if (n < 0 || (socklen_t)(m+n) >= hostlen)
19345845cf0Sis goto errout;
19445845cf0Sis
19545845cf0Sis m += n;
19645845cf0Sis }
19745845cf0Sis if (sat->sat_range.r_netrange.nr_firstnet) {
19845845cf0Sis n = snprintf(host+m, hostlen-m, " range %u - %u",
19945845cf0Sis ntohs(sat->sat_range.r_netrange.nr_firstnet),
20045845cf0Sis ntohs(sat->sat_range.r_netrange.nr_lastnet ));
20145845cf0Sis
20245845cf0Sis if (n < 0 || (socklen_t)(m+n) >= hostlen)
20345845cf0Sis goto errout;
20445845cf0Sis
20545845cf0Sis m += n;
206000fbf6bSis }
207000fbf6bSis
208000fbf6bSis return 0;
20945845cf0Sis
21045845cf0Sis errout:
21145845cf0Sis if (host && hostlen>0)
21245845cf0Sis host[m] = '\0'; /* XXX ??? */
21345845cf0Sis
21445845cf0Sis return EAI_MEMORY;
215000fbf6bSis }
216b1297979Sbjh21
217b1297979Sbjh21 /*
218911623fbSchristos * getnameinfo_local():
219911623fbSchristos * Format an local address into a printable format.
220911623fbSchristos */
221911623fbSchristos /* ARGSUSED */
222911623fbSchristos static int
getnameinfo_local(const struct sockaddr * sa,socklen_t salen,char * host,socklen_t hostlen,char * serv,socklen_t servlen,int flags)223911623fbSchristos getnameinfo_local(const struct sockaddr *sa, socklen_t salen,
224911623fbSchristos char *host, socklen_t hostlen, char *serv, socklen_t servlen,
225911623fbSchristos int flags)
226911623fbSchristos {
227911623fbSchristos const struct sockaddr_un *sun =
228911623fbSchristos (const struct sockaddr_un *)(const void *)sa;
229911623fbSchristos
230*03645a16Schristos if (salen <= sizeof(*sun) - sizeof(sun->sun_path))
231*03645a16Schristos return EAI_FAMILY;
232*03645a16Schristos
233911623fbSchristos if (serv != NULL && servlen > 0)
234911623fbSchristos serv[0] = '\0';
235911623fbSchristos
236911623fbSchristos if (host && hostlen > 0)
237911623fbSchristos strlcpy(host, sun->sun_path,
238911623fbSchristos MIN(sizeof(sun->sun_path) + 1, hostlen));
239911623fbSchristos
240911623fbSchristos return 0;
241911623fbSchristos }
242911623fbSchristos
243911623fbSchristos /*
244b1297979Sbjh21 * getnameinfo_inet():
245b1297979Sbjh21 * Format an IPv4 or IPv6 sockaddr into a printable string.
246b1297979Sbjh21 */
247b1297979Sbjh21 static int
getnameinfo_inet(const struct sockaddr * sa,socklen_t salen,char * host,socklen_t hostlen,char * serv,socklen_t servlen,int flags)248504f8671Smatt getnameinfo_inet(const struct sockaddr *sa, socklen_t salen,
249504f8671Smatt char *host, socklen_t hostlen,
250504f8671Smatt char *serv, socklen_t servlen,
251504f8671Smatt int flags)
25237e81591Sitojun {
253ca797c3cSjdolecek const struct afd *afd;
25437e81591Sitojun struct servent *sp;
25537e81591Sitojun struct hostent *hp;
25637e81591Sitojun u_short port;
2571501f618Sitojun int family, i;
2583fc57d3fSitojun const char *addr;
259504f8671Smatt uint32_t v4a;
26037e81591Sitojun char numserv[512];
26137e81591Sitojun char numaddr[512];
26237e81591Sitojun
263a976c8e3Slukem /* sa is checked below */
264a976c8e3Slukem /* host may be NULL */
265a976c8e3Slukem /* serv may be NULL */
266a976c8e3Slukem
26737e81591Sitojun if (sa == NULL)
26872a8edddSitojun return EAI_FAIL;
26937e81591Sitojun
27037e81591Sitojun family = sa->sa_family;
27137e81591Sitojun for (i = 0; afdl[i].a_af; i++)
27237e81591Sitojun if (afdl[i].a_af == family) {
27337e81591Sitojun afd = &afdl[i];
27437e81591Sitojun goto found;
27537e81591Sitojun }
27672a8edddSitojun return EAI_FAMILY;
27737e81591Sitojun
27837e81591Sitojun found:
279*03645a16Schristos if (salen < afd->a_socklen)
280*03645a16Schristos return EAI_FAMILY;
28137e81591Sitojun
2823fc57d3fSitojun /* network byte order */
2837bc5ea81Schristos port = ((const struct sockinet *)(const void *)sa)->si_port;
2847bc5ea81Schristos addr = (const char *)(const void *)sa + afd->a_off;
28537e81591Sitojun
28637e81591Sitojun if (serv == NULL || servlen == 0) {
2871501f618Sitojun /*
2881501f618Sitojun * do nothing in this case.
2891501f618Sitojun * in case you are wondering if "&&" is more correct than
29072a8edddSitojun * "||" here: rfc2553bis-03 says that serv == NULL OR
29172a8edddSitojun * servlen == 0 means that the caller does not want the result.
2921501f618Sitojun */
29337e81591Sitojun } else {
2941463de6aSchristos struct servent_data svd;
2951463de6aSchristos struct servent sv;
2961463de6aSchristos
297612dfc4dSseanb if (flags & NI_NUMERICSERV)
298612dfc4dSseanb sp = NULL;
299612dfc4dSseanb else {
3001463de6aSchristos (void)memset(&svd, 0, sizeof(svd));
3011463de6aSchristos sp = getservbyport_r(port,
3021463de6aSchristos (flags & NI_DGRAM) ? "udp" : "tcp", &sv, &svd);
3031501f618Sitojun }
30437e81591Sitojun if (sp) {
305612dfc4dSseanb if (strlen(sp->s_name) + 1 > servlen) {
306612dfc4dSseanb endservent_r(&svd);
30772a8edddSitojun return EAI_MEMORY;
308612dfc4dSseanb }
309b617695bSitojun strlcpy(serv, sp->s_name, servlen);
310612dfc4dSseanb endservent_r(&svd);
3111501f618Sitojun } else {
3120c63dd3cSitojun snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
313a931ac82Sitojun if (strlen(numserv) + 1 > servlen)
31472a8edddSitojun return EAI_MEMORY;
315b617695bSitojun strlcpy(serv, numserv, servlen);
3161501f618Sitojun }
31737e81591Sitojun }
31837e81591Sitojun
31937e81591Sitojun switch (sa->sa_family) {
32037e81591Sitojun case AF_INET:
321504f8671Smatt v4a = (uint32_t)
3227bc5ea81Schristos ntohl(((const struct sockaddr_in *)
3237bc5ea81Schristos (const void *)sa)->sin_addr.s_addr);
32437e81591Sitojun if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
32537e81591Sitojun flags |= NI_NUMERICHOST;
32637e81591Sitojun v4a >>= IN_CLASSA_NSHIFT;
3272cd2ee94Sitojun if (v4a == 0)
32837e81591Sitojun flags |= NI_NUMERICHOST;
32937e81591Sitojun break;
33037e81591Sitojun #ifdef INET6
33137e81591Sitojun case AF_INET6:
332bc3bad7aSitojun {
3333fc57d3fSitojun const struct sockaddr_in6 *sin6;
3347bc5ea81Schristos sin6 = (const struct sockaddr_in6 *)(const void *)sa;
3351501f618Sitojun switch (sin6->sin6_addr.s6_addr[0]) {
336bc3bad7aSitojun case 0x00:
337bc3bad7aSitojun if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
338bc3bad7aSitojun ;
339bc3bad7aSitojun else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
340bc3bad7aSitojun ;
341bc3bad7aSitojun else
34237e81591Sitojun flags |= NI_NUMERICHOST;
34337e81591Sitojun break;
344bc3bad7aSitojun default:
3451501f618Sitojun if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
346bc3bad7aSitojun flags |= NI_NUMERICHOST;
3471501f618Sitojun }
348bc3bad7aSitojun else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
349bc3bad7aSitojun flags |= NI_NUMERICHOST;
350bc3bad7aSitojun break;
351bc3bad7aSitojun }
352bc3bad7aSitojun }
353bc3bad7aSitojun break;
35437e81591Sitojun #endif
35537e81591Sitojun }
35637e81591Sitojun if (host == NULL || hostlen == 0) {
3571501f618Sitojun /*
3581501f618Sitojun * do nothing in this case.
3591501f618Sitojun * in case you are wondering if "&&" is more correct than
36072a8edddSitojun * "||" here: rfc2553bis-03 says that host == NULL or
36172a8edddSitojun * hostlen == 0 means that the caller does not want the result.
3621501f618Sitojun */
36337e81591Sitojun } else if (flags & NI_NUMERICHOST) {
364585ad39aSthorpej size_t numaddrlen;
36534a6354bSitojun
366bc3bad7aSitojun /* NUMERICHOST and NAMEREQD conflicts with each other */
367bc3bad7aSitojun if (flags & NI_NAMEREQD)
36872a8edddSitojun return EAI_NONAME;
3693fc57d3fSitojun
3703fc57d3fSitojun switch(afd->a_af) {
3713fc57d3fSitojun #ifdef INET6
3723fc57d3fSitojun case AF_INET6:
3733fc57d3fSitojun {
3743fc57d3fSitojun int error;
3753fc57d3fSitojun
3763fc57d3fSitojun if ((error = ip6_parsenumeric(sa, addr, host,
3773fc57d3fSitojun hostlen, flags)) != 0)
3783fc57d3fSitojun return(error);
3793fc57d3fSitojun break;
3803fc57d3fSitojun }
3813fc57d3fSitojun #endif
3823fc57d3fSitojun default:
383c5e820caSchristos if (inet_ntop(afd->a_af, addr, numaddr,
384c5e820caSchristos (socklen_t)sizeof(numaddr)) == NULL)
38572a8edddSitojun return EAI_SYSTEM;
38634a6354bSitojun numaddrlen = strlen(numaddr);
38734a6354bSitojun if (numaddrlen + 1 > hostlen) /* don't forget terminator */
38872a8edddSitojun return EAI_MEMORY;
389b617695bSitojun strlcpy(host, numaddr, hostlen);
3903fc57d3fSitojun break;
3911501f618Sitojun }
39237e81591Sitojun } else {
39302dd2447Schristos struct hostent hent;
39402dd2447Schristos char hbuf[4096];
39502dd2447Schristos int he;
39602dd2447Schristos hp = gethostbyaddr_r(addr, afd->a_addrlen, afd->a_af, &hent,
39702dd2447Schristos hbuf, sizeof(hbuf), &he);
39837e81591Sitojun
39937e81591Sitojun if (hp) {
4003fc57d3fSitojun #if 0
4013fc57d3fSitojun /*
4023fc57d3fSitojun * commented out, since "for local host" is not
4033fc57d3fSitojun * implemented here - see RFC2553 p30
4043fc57d3fSitojun */
40537e81591Sitojun if (flags & NI_NOFQDN) {
4063fc57d3fSitojun char *p;
40737e81591Sitojun p = strchr(hp->h_name, '.');
4083fc57d3fSitojun if (p)
4093fc57d3fSitojun *p = '\0';
41037e81591Sitojun }
4113fc57d3fSitojun #endif
412a931ac82Sitojun if (strlen(hp->h_name) + 1 > hostlen) {
41372a8edddSitojun return EAI_MEMORY;
41437e81591Sitojun }
415b617695bSitojun strlcpy(host, hp->h_name, hostlen);
41637e81591Sitojun } else {
417b350f7a4Schristos switch (he) {
418b350f7a4Schristos case NO_DATA:
419b350f7a4Schristos case HOST_NOT_FOUND:
42037e81591Sitojun if (flags & NI_NAMEREQD)
42172a8edddSitojun return EAI_NONAME;
422b350f7a4Schristos break;
423b350f7a4Schristos case TRY_AGAIN:
424b350f7a4Schristos return EAI_AGAIN;
425b350f7a4Schristos case NETDB_SUCCESS:
426525756d3Schristos case NETDB_INTERNAL:
427525756d3Schristos case NO_RECOVERY:
428b350f7a4Schristos /*FALLTHROUGH*/
429b350f7a4Schristos default:
430525756d3Schristos return EAI_SYSTEM;
431b350f7a4Schristos }
4323fc57d3fSitojun switch(afd->a_af) {
4333fc57d3fSitojun #ifdef INET6
4343fc57d3fSitojun case AF_INET6:
4353fc57d3fSitojun {
4363fc57d3fSitojun int error;
4373fc57d3fSitojun
4383fc57d3fSitojun if ((error = ip6_parsenumeric(sa, addr, host,
4393fc57d3fSitojun hostlen,
4403fc57d3fSitojun flags)) != 0)
4413fc57d3fSitojun return(error);
4423fc57d3fSitojun break;
4433fc57d3fSitojun }
4443fc57d3fSitojun #endif
4453fc57d3fSitojun default:
4463fc57d3fSitojun if (inet_ntop(afd->a_af, addr, host,
4473fc57d3fSitojun hostlen) == NULL)
44872a8edddSitojun return EAI_SYSTEM;
4493fc57d3fSitojun break;
4503fc57d3fSitojun }
45137e81591Sitojun }
45237e81591Sitojun }
45372a8edddSitojun return(0);
45437e81591Sitojun }
45534a6354bSitojun
45634a6354bSitojun #ifdef INET6
4573fc57d3fSitojun static int
ip6_parsenumeric(const struct sockaddr * sa,const char * addr,char * host,socklen_t hostlen,int flags)458504f8671Smatt ip6_parsenumeric(const struct sockaddr *sa, const char *addr, char *host,
459504f8671Smatt socklen_t hostlen, int flags)
4603fc57d3fSitojun {
461585ad39aSthorpej size_t numaddrlen;
4623fc57d3fSitojun char numaddr[512];
4633fc57d3fSitojun
464a976c8e3Slukem _DIAGASSERT(sa != NULL);
465a976c8e3Slukem _DIAGASSERT(addr != NULL);
466a976c8e3Slukem _DIAGASSERT(host != NULL);
467a976c8e3Slukem
468c5e820caSchristos if (inet_ntop(AF_INET6, addr, numaddr, (socklen_t)sizeof(numaddr))
469c5e820caSchristos == NULL)
47072a8edddSitojun return EAI_SYSTEM;
4713fc57d3fSitojun
4723fc57d3fSitojun numaddrlen = strlen(numaddr);
4733fc57d3fSitojun if (numaddrlen + 1 > hostlen) /* don't forget terminator */
47480194aa8Sginsbach return EAI_OVERFLOW;
475b617695bSitojun strlcpy(host, numaddr, hostlen);
4763fc57d3fSitojun
4777bc5ea81Schristos if (((const struct sockaddr_in6 *)(const void *)sa)->sin6_scope_id) {
4786c9440f3Sitojun char zonebuf[MAXHOSTNAMELEN];
4796c9440f3Sitojun int zonelen;
4803fc57d3fSitojun
4816c9440f3Sitojun zonelen = ip6_sa2str(
4827bc5ea81Schristos (const struct sockaddr_in6 *)(const void *)sa,
4836c9440f3Sitojun zonebuf, sizeof(zonebuf), flags);
4846c9440f3Sitojun if (zonelen < 0)
48580194aa8Sginsbach return EAI_OVERFLOW;
486585ad39aSthorpej if ((size_t) zonelen + 1 + numaddrlen + 1 > hostlen)
48780194aa8Sginsbach return EAI_OVERFLOW;
4886c9440f3Sitojun /* construct <numeric-addr><delim><zoneid> */
4896c9440f3Sitojun memcpy(host + numaddrlen + 1, zonebuf,
4906c9440f3Sitojun (size_t)zonelen);
4913fc57d3fSitojun host[numaddrlen] = SCOPE_DELIMITER;
4926c9440f3Sitojun host[numaddrlen + 1 + zonelen] = '\0';
4933fc57d3fSitojun }
4943fc57d3fSitojun
4953fc57d3fSitojun return 0;
4963fc57d3fSitojun }
4973fc57d3fSitojun
49834a6354bSitojun /* ARGSUSED */
4993fc57d3fSitojun static int
ip6_sa2str(const struct sockaddr_in6 * sa6,char * buf,size_t bufsiz,int flags)500504f8671Smatt ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, size_t bufsiz, int flags)
50134a6354bSitojun {
502a976c8e3Slukem unsigned int ifindex;
503a976c8e3Slukem const struct in6_addr *a6;
504511e898dSitojun int n;
505a976c8e3Slukem
506a976c8e3Slukem _DIAGASSERT(sa6 != NULL);
507a976c8e3Slukem _DIAGASSERT(buf != NULL);
508a976c8e3Slukem
509a976c8e3Slukem ifindex = (unsigned int)sa6->sin6_scope_id;
510a976c8e3Slukem a6 = &sa6->sin6_addr;
51134a6354bSitojun
512511e898dSitojun #ifdef NI_NUMERICSCOPE
513511e898dSitojun if ((flags & NI_NUMERICSCOPE) != 0) {
514511e898dSitojun n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
515da77f10aSlukem if (n < 0 || (size_t)n >= bufsiz)
516511e898dSitojun return -1;
517511e898dSitojun else
518511e898dSitojun return n;
51934a6354bSitojun }
52034a6354bSitojun #endif
52134a6354bSitojun
5223fc57d3fSitojun /* if_indextoname() does not take buffer size. not a good api... */
5233fc57d3fSitojun if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
5243fc57d3fSitojun bufsiz >= IF_NAMESIZE) {
5253fc57d3fSitojun char *p = if_indextoname(ifindex, buf);
5263fc57d3fSitojun if (p) {
527c5e820caSchristos return (int)strlen(p);
52834a6354bSitojun }
5293fc57d3fSitojun }
5303fc57d3fSitojun
5313fc57d3fSitojun /* last resort */
532511e898dSitojun n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
533585ad39aSthorpej if (n < 0 || (size_t) n >= bufsiz)
534511e898dSitojun return -1;
535511e898dSitojun else
536511e898dSitojun return n;
5373fc57d3fSitojun }
5383fc57d3fSitojun #endif /* INET6 */
539b1297979Sbjh21
540b1297979Sbjh21
541b1297979Sbjh21 /*
542b1297979Sbjh21 * getnameinfo_link():
543b1297979Sbjh21 * Format a link-layer address into a printable format, paying attention to
544b1297979Sbjh21 * the interface type.
545b1297979Sbjh21 */
546b1297979Sbjh21 /* ARGSUSED */
547b1297979Sbjh21 static int
getnameinfo_link(const struct sockaddr * sa,socklen_t salen,char * host,socklen_t hostlen,char * serv,socklen_t servlen,int flags)548b1297979Sbjh21 getnameinfo_link(const struct sockaddr *sa, socklen_t salen,
5494b77e72eSkleink char *host, socklen_t hostlen, char *serv, socklen_t servlen,
550a24f74d0Skleink int flags)
551b1297979Sbjh21 {
552b1297979Sbjh21 const struct sockaddr_dl *sdl =
553b1297979Sbjh21 (const struct sockaddr_dl *)(const void *)sa;
554b1297979Sbjh21 const struct ieee1394_hwaddr *iha;
555b1297979Sbjh21 int n;
556b1297979Sbjh21
557*03645a16Schristos if (salen <= sizeof(*sdl) - sizeof(sdl->sdl_data))
558*03645a16Schristos return EAI_FAMILY;
559*03645a16Schristos
560b1297979Sbjh21 if (serv != NULL && servlen > 0)
561b1297979Sbjh21 *serv = '\0';
562b1297979Sbjh21
563b1297979Sbjh21 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) {
5640c63dd3cSitojun n = snprintf(host, hostlen, "link#%u", sdl->sdl_index);
56533eb4d86Schristos goto out;
566b1297979Sbjh21 }
567b1297979Sbjh21
568b1297979Sbjh21 switch (sdl->sdl_type) {
569b1297979Sbjh21 #ifdef IFT_ECONET
570b1297979Sbjh21 case IFT_ECONET:
571b1297979Sbjh21 if (sdl->sdl_alen < 2)
572b1297979Sbjh21 return EAI_FAMILY;
57303256c6eSchristos if (CLLADDR(sdl)[1] == 0)
57403256c6eSchristos n = snprintf(host, hostlen, "%u", CLLADDR(sdl)[0]);
575b1297979Sbjh21 else
5760c63dd3cSitojun n = snprintf(host, hostlen, "%u.%u",
57703256c6eSchristos CLLADDR(sdl)[1], CLLADDR(sdl)[0]);
57833eb4d86Schristos goto out;
579b1297979Sbjh21 #endif
580b1297979Sbjh21 case IFT_IEEE1394:
581b1297979Sbjh21 if (sdl->sdl_alen < sizeof(iha->iha_uid))
582b1297979Sbjh21 return EAI_FAMILY;
583b1297979Sbjh21 iha =
58403256c6eSchristos (const struct ieee1394_hwaddr *)(const void *)CLLADDR(sdl);
585b1297979Sbjh21 return hexname(iha->iha_uid, sizeof(iha->iha_uid),
586b1297979Sbjh21 host, hostlen);
587b1297979Sbjh21 /*
588b1297979Sbjh21 * The following have zero-length addresses.
589b1297979Sbjh21 * IFT_ATM (net/if_atmsubr.c)
590b1297979Sbjh21 * IFT_FAITH (net/if_faith.c)
591b1297979Sbjh21 * IFT_GIF (net/if_gif.c)
592b1297979Sbjh21 * IFT_LOOP (net/if_loop.c)
593b1297979Sbjh21 * IFT_PPP (net/if_ppp.c, net/if_spppsubr.c)
594b1297979Sbjh21 * IFT_SLIP (net/if_sl.c, net/if_strip.c)
595b1297979Sbjh21 * IFT_STF (net/if_stf.c)
596b1297979Sbjh21 * IFT_L2VLAN (net/if_vlan.c)
597b1297979Sbjh21 * IFT_PROPVIRTUAL (net/if_bridge.h>
598b1297979Sbjh21 */
599b1297979Sbjh21 /*
600b1297979Sbjh21 * The following use IPv4 addresses as link-layer addresses:
601b1297979Sbjh21 * IFT_OTHER (net/if_gre.c)
602b1297979Sbjh21 */
603b1297979Sbjh21 case IFT_ARCNET: /* default below is believed correct for all these. */
604b1297979Sbjh21 case IFT_ETHER:
605b1297979Sbjh21 case IFT_FDDI:
606b1297979Sbjh21 case IFT_HIPPI:
607b1297979Sbjh21 case IFT_ISO88025:
608b1297979Sbjh21 default:
609504f8671Smatt return hexname((const uint8_t *)CLLADDR(sdl),
61003256c6eSchristos (size_t)sdl->sdl_alen, host, hostlen);
611b1297979Sbjh21 }
61233eb4d86Schristos out:
61333eb4d86Schristos if (n < 0 || (socklen_t) n >= hostlen) {
61433eb4d86Schristos *host = '\0';
61533eb4d86Schristos return EAI_MEMORY;
61633eb4d86Schristos }
61733eb4d86Schristos return 0;
618b1297979Sbjh21 }
619b1297979Sbjh21
620b1297979Sbjh21 static int
hexname(const uint8_t * cp,size_t len,char * host,socklen_t hostlen)621504f8671Smatt hexname(const uint8_t *cp, size_t len, char *host, socklen_t hostlen)
622b1297979Sbjh21 {
623585ad39aSthorpej int n;
624585ad39aSthorpej size_t i;
625b1297979Sbjh21 char *outp = host;
626b1297979Sbjh21
627b1297979Sbjh21 *outp = '\0';
628b1297979Sbjh21 for (i = 0; i < len; i++) {
629b1297979Sbjh21 n = snprintf(outp, hostlen, "%s%02x",
630b1297979Sbjh21 i ? ":" : "", cp[i]);
631585ad39aSthorpej if (n < 0 || (socklen_t) n >= hostlen) {
632b1297979Sbjh21 *host = '\0';
633b1297979Sbjh21 return EAI_MEMORY;
634b1297979Sbjh21 }
635b1297979Sbjh21 outp += n;
636b1297979Sbjh21 hostlen -= n;
637b1297979Sbjh21 }
638b1297979Sbjh21 return 0;
639b1297979Sbjh21 }
640