Deleted Added
full compact
getnameinfo.c (92986) getnameinfo.c (99252)
1/* $KAME: getnameinfo.c,v 1.45 2000/09/25 22:43:56 itojun Exp $ */
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * Issues to be discussed:
34 * - Thread safe-ness must be checked
35 * - RFC2553 says that we should raise error on short buffer. X/Open says
36 * we need to truncate the result. We obey RFC2553 (and X/Open should be
37 * modified). ipngwg rough consensus seems to follow RFC2553.
38 * - What is "local" in NI_FQDN?
39 * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
1/* $KAME: getnameinfo.c,v 1.45 2000/09/25 22:43:56 itojun Exp $ */
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * Issues to be discussed:
34 * - Thread safe-ness must be checked
35 * - RFC2553 says that we should raise error on short buffer. X/Open says
36 * we need to truncate the result. We obey RFC2553 (and X/Open should be
37 * modified). ipngwg rough consensus seems to follow RFC2553.
38 * - What is "local" in NI_FQDN?
39 * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
40 * - (KAME extension) NI_WITHSCOPEID when called with global address,
41 * and sin6_scope_id filled
40 * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if
41 * sin6_scope_id is filled - standardization status?
42 * XXX breaks backward compat for code that expects no scopeid.
43 * beware on merge.
42 */
43
44#include <sys/cdefs.h>
44 */
45
46#include <sys/cdefs.h>
45__FBSDID("$FreeBSD: head/lib/libc/net/getnameinfo.c 92986 2002-03-22 21:53:29Z obrien $");
47__FBSDID("$FreeBSD: head/lib/libc/net/getnameinfo.c 99252 2002-07-02 11:05:31Z ume $");
46
47#include <sys/types.h>
48#include <sys/socket.h>
49#include <net/if.h>
50#include <netinet/in.h>
51#include <arpa/inet.h>
52#include <arpa/nameser.h>
53#include <netdb.h>
54#include <resolv.h>
55#include <string.h>
56#include <stddef.h>
57#include <errno.h>
58
59#define SUCCESS 0
60#define ANY 0
61#define YES 1
62#define NO 0
63
64static struct afd {
65 int a_af;
66 int a_addrlen;
67 int a_socklen;
68 int a_off;
69} afdl [] = {
70#ifdef INET6
71 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
72 offsetof(struct sockaddr_in6, sin6_addr)},
73#endif
74 {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
75 offsetof(struct sockaddr_in, sin_addr)},
76 {0, 0, 0},
77};
78
79struct sockinet {
80 u_char si_len;
81 u_char si_family;
82 u_short si_port;
83};
84
85#ifdef INET6
86static int ip6_parsenumeric(const struct sockaddr *, const char *, char *,
87 size_t, int);
88static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int);
89#endif
90
91/* 2553bis: use EAI_xx for getnameinfo */
92#define ENI_NOSOCKET EAI_FAIL /*XXX*/
93#define ENI_NOSERVNAME EAI_NONAME
94#define ENI_NOHOSTNAME EAI_NONAME
95#define ENI_MEMORY EAI_MEMORY
96#define ENI_SYSTEM EAI_SYSTEM
97#define ENI_FAMILY EAI_FAMILY
98#define ENI_SALEN EAI_FAMILY
99
100int
101getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
102 const struct sockaddr *sa;
103 socklen_t salen;
104 char *host;
105 size_t hostlen;
106 char *serv;
107 size_t servlen;
108 int flags;
109{
110 struct afd *afd;
111 struct servent *sp;
112 struct hostent *hp;
113 u_short port;
114 int family, i;
115 const char *addr;
116 u_int32_t v4a;
117 int h_error;
118 char numserv[512];
119 char numaddr[512];
120
121 if (sa == NULL)
122 return ENI_NOSOCKET;
123
124 if (sa->sa_len != salen)
125 return ENI_SALEN;
126
127 family = sa->sa_family;
128 for (i = 0; afdl[i].a_af; i++)
129 if (afdl[i].a_af == family) {
130 afd = &afdl[i];
131 goto found;
132 }
133 return ENI_FAMILY;
134
135 found:
136 if (salen != afd->a_socklen)
137 return ENI_SALEN;
138
139 /* network byte order */
140 port = ((const struct sockinet *)sa)->si_port;
141 addr = (const char *)sa + afd->a_off;
142
143 if (serv == NULL || servlen == 0) {
144 /*
145 * do nothing in this case.
146 * in case you are wondering if "&&" is more correct than
147 * "||" here: RFC2553 says that serv == NULL OR servlen == 0
148 * means that the caller does not want the result.
149 */
150 } else {
151 if (flags & NI_NUMERICSERV)
152 sp = NULL;
153 else {
154 sp = getservbyport(port,
155 (flags & NI_DGRAM) ? "udp" : "tcp");
156 }
157 if (sp) {
158 if (strlen(sp->s_name) + 1 > servlen)
159 return ENI_MEMORY;
160 strcpy(serv, sp->s_name);
161 } else {
162 snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
163 if (strlen(numserv) + 1 > servlen)
164 return ENI_MEMORY;
165 strcpy(serv, numserv);
166 }
167 }
168
169 switch (sa->sa_family) {
170 case AF_INET:
171 v4a = (u_int32_t)
172 ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
173 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
174 flags |= NI_NUMERICHOST;
175 v4a >>= IN_CLASSA_NSHIFT;
176 if (v4a == 0)
177 flags |= NI_NUMERICHOST;
178 break;
179#ifdef INET6
180 case AF_INET6:
181 {
182 const struct sockaddr_in6 *sin6;
183 sin6 = (const struct sockaddr_in6 *)sa;
184 switch (sin6->sin6_addr.s6_addr[0]) {
185 case 0x00:
186 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
187 ;
188 else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
189 ;
190 else
191 flags |= NI_NUMERICHOST;
192 break;
193 default:
194 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
195 flags |= NI_NUMERICHOST;
196 }
197 else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
198 flags |= NI_NUMERICHOST;
199 break;
200 }
201 }
202 break;
203#endif
204 }
205 if (host == NULL || hostlen == 0) {
206 /*
207 * do nothing in this case.
208 * in case you are wondering if "&&" is more correct than
209 * "||" here: RFC2553 says that host == NULL OR hostlen == 0
210 * means that the caller does not want the result.
211 */
212 } else if (flags & NI_NUMERICHOST) {
213 int numaddrlen;
214
215 /* NUMERICHOST and NAMEREQD conflicts with each other */
216 if (flags & NI_NAMEREQD)
217 return ENI_NOHOSTNAME;
218
219 switch(afd->a_af) {
220#ifdef INET6
221 case AF_INET6:
222 {
223 int error;
224
225 if ((error = ip6_parsenumeric(sa, addr, host,
226 hostlen, flags)) != 0)
227 return(error);
228 break;
229 }
230#endif
231 default:
232 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
233 == NULL)
234 return ENI_SYSTEM;
235 numaddrlen = strlen(numaddr);
236 if (numaddrlen + 1 > hostlen) /* don't forget terminator */
237 return ENI_MEMORY;
238 strcpy(host, numaddr);
239 break;
240 }
241 } else {
242 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
243
244 if (hp) {
245#if 0
246 /*
247 * commented out, since "for local host" is not
248 * implemented here - see RFC2553 p30
249 */
250 if (flags & NI_NOFQDN) {
251 char *p;
252 p = strchr(hp->h_name, '.');
253 if (p)
254 *p = '\0';
255 }
256#endif
257 if (strlen(hp->h_name) + 1 > hostlen) {
258 freehostent(hp);
259 return ENI_MEMORY;
260 }
261 strcpy(host, hp->h_name);
262 freehostent(hp);
263 } else {
264 if (flags & NI_NAMEREQD)
265 return ENI_NOHOSTNAME;
266 switch(afd->a_af) {
267#ifdef INET6
268 case AF_INET6:
269 {
270 int error;
271
272 if ((error = ip6_parsenumeric(sa, addr, host,
273 hostlen,
274 flags)) != 0)
275 return(error);
276 break;
277 }
278#endif
279 default:
280 if (inet_ntop(afd->a_af, addr, host,
281 hostlen) == NULL)
282 return ENI_SYSTEM;
283 break;
284 }
285 }
286 }
287 return SUCCESS;
288}
289
290#ifdef INET6
291static int
292ip6_parsenumeric(sa, addr, host, hostlen, flags)
293 const struct sockaddr *sa;
294 const char *addr;
295 char *host;
296 size_t hostlen;
297 int flags;
298{
299 int numaddrlen;
300 char numaddr[512];
301
302 if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr))
303 == NULL)
304 return ENI_SYSTEM;
305
306 numaddrlen = strlen(numaddr);
307 if (numaddrlen + 1 > hostlen) /* don't forget terminator */
308 return ENI_MEMORY;
309 strcpy(host, numaddr);
310
48
49#include <sys/types.h>
50#include <sys/socket.h>
51#include <net/if.h>
52#include <netinet/in.h>
53#include <arpa/inet.h>
54#include <arpa/nameser.h>
55#include <netdb.h>
56#include <resolv.h>
57#include <string.h>
58#include <stddef.h>
59#include <errno.h>
60
61#define SUCCESS 0
62#define ANY 0
63#define YES 1
64#define NO 0
65
66static struct afd {
67 int a_af;
68 int a_addrlen;
69 int a_socklen;
70 int a_off;
71} afdl [] = {
72#ifdef INET6
73 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
74 offsetof(struct sockaddr_in6, sin6_addr)},
75#endif
76 {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
77 offsetof(struct sockaddr_in, sin_addr)},
78 {0, 0, 0},
79};
80
81struct sockinet {
82 u_char si_len;
83 u_char si_family;
84 u_short si_port;
85};
86
87#ifdef INET6
88static int ip6_parsenumeric(const struct sockaddr *, const char *, char *,
89 size_t, int);
90static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int);
91#endif
92
93/* 2553bis: use EAI_xx for getnameinfo */
94#define ENI_NOSOCKET EAI_FAIL /*XXX*/
95#define ENI_NOSERVNAME EAI_NONAME
96#define ENI_NOHOSTNAME EAI_NONAME
97#define ENI_MEMORY EAI_MEMORY
98#define ENI_SYSTEM EAI_SYSTEM
99#define ENI_FAMILY EAI_FAMILY
100#define ENI_SALEN EAI_FAMILY
101
102int
103getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
104 const struct sockaddr *sa;
105 socklen_t salen;
106 char *host;
107 size_t hostlen;
108 char *serv;
109 size_t servlen;
110 int flags;
111{
112 struct afd *afd;
113 struct servent *sp;
114 struct hostent *hp;
115 u_short port;
116 int family, i;
117 const char *addr;
118 u_int32_t v4a;
119 int h_error;
120 char numserv[512];
121 char numaddr[512];
122
123 if (sa == NULL)
124 return ENI_NOSOCKET;
125
126 if (sa->sa_len != salen)
127 return ENI_SALEN;
128
129 family = sa->sa_family;
130 for (i = 0; afdl[i].a_af; i++)
131 if (afdl[i].a_af == family) {
132 afd = &afdl[i];
133 goto found;
134 }
135 return ENI_FAMILY;
136
137 found:
138 if (salen != afd->a_socklen)
139 return ENI_SALEN;
140
141 /* network byte order */
142 port = ((const struct sockinet *)sa)->si_port;
143 addr = (const char *)sa + afd->a_off;
144
145 if (serv == NULL || servlen == 0) {
146 /*
147 * do nothing in this case.
148 * in case you are wondering if "&&" is more correct than
149 * "||" here: RFC2553 says that serv == NULL OR servlen == 0
150 * means that the caller does not want the result.
151 */
152 } else {
153 if (flags & NI_NUMERICSERV)
154 sp = NULL;
155 else {
156 sp = getservbyport(port,
157 (flags & NI_DGRAM) ? "udp" : "tcp");
158 }
159 if (sp) {
160 if (strlen(sp->s_name) + 1 > servlen)
161 return ENI_MEMORY;
162 strcpy(serv, sp->s_name);
163 } else {
164 snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
165 if (strlen(numserv) + 1 > servlen)
166 return ENI_MEMORY;
167 strcpy(serv, numserv);
168 }
169 }
170
171 switch (sa->sa_family) {
172 case AF_INET:
173 v4a = (u_int32_t)
174 ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
175 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
176 flags |= NI_NUMERICHOST;
177 v4a >>= IN_CLASSA_NSHIFT;
178 if (v4a == 0)
179 flags |= NI_NUMERICHOST;
180 break;
181#ifdef INET6
182 case AF_INET6:
183 {
184 const struct sockaddr_in6 *sin6;
185 sin6 = (const struct sockaddr_in6 *)sa;
186 switch (sin6->sin6_addr.s6_addr[0]) {
187 case 0x00:
188 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
189 ;
190 else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
191 ;
192 else
193 flags |= NI_NUMERICHOST;
194 break;
195 default:
196 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
197 flags |= NI_NUMERICHOST;
198 }
199 else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
200 flags |= NI_NUMERICHOST;
201 break;
202 }
203 }
204 break;
205#endif
206 }
207 if (host == NULL || hostlen == 0) {
208 /*
209 * do nothing in this case.
210 * in case you are wondering if "&&" is more correct than
211 * "||" here: RFC2553 says that host == NULL OR hostlen == 0
212 * means that the caller does not want the result.
213 */
214 } else if (flags & NI_NUMERICHOST) {
215 int numaddrlen;
216
217 /* NUMERICHOST and NAMEREQD conflicts with each other */
218 if (flags & NI_NAMEREQD)
219 return ENI_NOHOSTNAME;
220
221 switch(afd->a_af) {
222#ifdef INET6
223 case AF_INET6:
224 {
225 int error;
226
227 if ((error = ip6_parsenumeric(sa, addr, host,
228 hostlen, flags)) != 0)
229 return(error);
230 break;
231 }
232#endif
233 default:
234 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
235 == NULL)
236 return ENI_SYSTEM;
237 numaddrlen = strlen(numaddr);
238 if (numaddrlen + 1 > hostlen) /* don't forget terminator */
239 return ENI_MEMORY;
240 strcpy(host, numaddr);
241 break;
242 }
243 } else {
244 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
245
246 if (hp) {
247#if 0
248 /*
249 * commented out, since "for local host" is not
250 * implemented here - see RFC2553 p30
251 */
252 if (flags & NI_NOFQDN) {
253 char *p;
254 p = strchr(hp->h_name, '.');
255 if (p)
256 *p = '\0';
257 }
258#endif
259 if (strlen(hp->h_name) + 1 > hostlen) {
260 freehostent(hp);
261 return ENI_MEMORY;
262 }
263 strcpy(host, hp->h_name);
264 freehostent(hp);
265 } else {
266 if (flags & NI_NAMEREQD)
267 return ENI_NOHOSTNAME;
268 switch(afd->a_af) {
269#ifdef INET6
270 case AF_INET6:
271 {
272 int error;
273
274 if ((error = ip6_parsenumeric(sa, addr, host,
275 hostlen,
276 flags)) != 0)
277 return(error);
278 break;
279 }
280#endif
281 default:
282 if (inet_ntop(afd->a_af, addr, host,
283 hostlen) == NULL)
284 return ENI_SYSTEM;
285 break;
286 }
287 }
288 }
289 return SUCCESS;
290}
291
292#ifdef INET6
293static int
294ip6_parsenumeric(sa, addr, host, hostlen, flags)
295 const struct sockaddr *sa;
296 const char *addr;
297 char *host;
298 size_t hostlen;
299 int flags;
300{
301 int numaddrlen;
302 char numaddr[512];
303
304 if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr))
305 == NULL)
306 return ENI_SYSTEM;
307
308 numaddrlen = strlen(numaddr);
309 if (numaddrlen + 1 > hostlen) /* don't forget terminator */
310 return ENI_MEMORY;
311 strcpy(host, numaddr);
312
311#ifdef NI_WITHSCOPEID
312 if (
313#ifdef DONT_OPAQUE_SCOPEID
314 (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
315 IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
316#endif
317 ((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
318#ifndef ALWAYS_WITHSCOPE
319 if (flags & NI_WITHSCOPEID)
320#endif /* !ALWAYS_WITHSCOPE */
321 {
322 char scopebuf[MAXHOSTNAMELEN];
323 int scopelen;
313 if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
314 char zonebuf[MAXHOSTNAMELEN];
315 int zonelen;
324
316
325 /* ip6_sa2str never fails */
326 scopelen = ip6_sa2str((const struct sockaddr_in6 *)sa,
327 scopebuf, sizeof(scopebuf),
328 flags);
329 if (scopelen + 1 + numaddrlen + 1 > hostlen)
330 return ENI_MEMORY;
331 /*
332 * construct <numeric-addr><delim><scopeid>
333 */
334 memcpy(host + numaddrlen + 1, scopebuf,
335 scopelen);
336 host[numaddrlen] = SCOPE_DELIMITER;
337 host[numaddrlen + 1 + scopelen] = '\0';
338 }
317 /* ip6_sa2str never fails */
318 zonelen = ip6_sa2str(
319 (const struct sockaddr_in6 *)(const void *)sa,
320 zonebuf, sizeof(zonebuf), flags);
321 if (zonelen < 0)
322 return EAI_MEMORY;
323 if (zonelen + 1 + numaddrlen + 1 > hostlen)
324 return ENI_MEMORY;
325 /* construct <numeric-addr><delim><scopeid> */
326 memcpy(host + numaddrlen + 1, zonebuf,
327 (size_t)zonelen);
328 host[numaddrlen] = SCOPE_DELIMITER;
329 host[numaddrlen + 1 + zonelen] = '\0';
339 }
330 }
340#endif /* NI_WITHSCOPEID */
341
342 return 0;
343}
344
345/* ARGSUSED */
346static int
347ip6_sa2str(sa6, buf, bufsiz, flags)
348 const struct sockaddr_in6 *sa6;
349 char *buf;
350 size_t bufsiz;
351 int flags;
352{
353 unsigned int ifindex = (unsigned int)sa6->sin6_scope_id;
354 const struct in6_addr *a6 = &sa6->sin6_addr;
355
356#ifdef NI_NUMERICSCOPE
357 if (flags & NI_NUMERICSCOPE) {
358 return(snprintf(buf, bufsiz, "%d", sa6->sin6_scope_id));
359 }
360#endif
361
362 /* if_indextoname() does not take buffer size. not a good api... */
363 if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
364 bufsiz >= IF_NAMESIZE) {
365 char *p = if_indextoname(ifindex, buf);
366 if (p) {
367 return(strlen(p));
368 }
369 }
370
371 /* last resort */
372 return(snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id));
373}
374#endif /* INET6 */
331
332 return 0;
333}
334
335/* ARGSUSED */
336static int
337ip6_sa2str(sa6, buf, bufsiz, flags)
338 const struct sockaddr_in6 *sa6;
339 char *buf;
340 size_t bufsiz;
341 int flags;
342{
343 unsigned int ifindex = (unsigned int)sa6->sin6_scope_id;
344 const struct in6_addr *a6 = &sa6->sin6_addr;
345
346#ifdef NI_NUMERICSCOPE
347 if (flags & NI_NUMERICSCOPE) {
348 return(snprintf(buf, bufsiz, "%d", sa6->sin6_scope_id));
349 }
350#endif
351
352 /* if_indextoname() does not take buffer size. not a good api... */
353 if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
354 bufsiz >= IF_NAMESIZE) {
355 char *p = if_indextoname(ifindex, buf);
356 if (p) {
357 return(strlen(p));
358 }
359 }
360
361 /* last resort */
362 return(snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id));
363}
364#endif /* INET6 */