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 */
|