diff options
Diffstat (limited to 'lib/libc/net/getnameinfo.c')
-rw-r--r-- | lib/libc/net/getnameinfo.c | 185 |
1 files changed, 112 insertions, 73 deletions
diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c index c174b8a7ea6..33e628c6238 100644 --- a/lib/libc/net/getnameinfo.c +++ b/lib/libc/net/getnameinfo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getnameinfo.c,v 1.12 2000/03/13 02:22:12 itojun Exp $ */ +/* $OpenBSD: getnameinfo.c,v 1.13 2000/04/26 14:46:47 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -37,9 +37,15 @@ * - RFC2553 says that we should raise error on short buffer. X/Open says * we need to truncate the result. We obey RFC2553 (and X/Open should be * modified). + * - What is "local" in NI_FQDN? + * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other. + * - (KAME extension) NI_WITHSCOPEID when called with global address, + * and sin6_scope_id filled */ +#ifndef INET6 #define INET6 +#endif #include <sys/types.h> #include <sys/socket.h> @@ -79,7 +85,9 @@ struct sockinet { }; #ifdef INET6 -static char *ip6_sa2str __P((struct sockaddr_in6 *, char *, int)); +static int ip6_parsenumeric __P((const struct sockaddr *, char *, char *, + int, int)); +static int ip6_sa2str __P((struct sockaddr_in6 *, char *, size_t, int)); #endif #define ENI_NOSOCKET 0 @@ -207,69 +215,40 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) /* NUMERICHOST and NAMEREQD conflicts with each other */ if (flags & NI_NAMEREQD) return ENI_NOHOSTNAME; - if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) - == NULL) - return ENI_SYSTEM; - numaddrlen = strlen(numaddr); - if (numaddrlen + 1 > hostlen) /* don't forget terminator */ - return ENI_MEMORY; - strcpy(host, numaddr); -#if defined(INET6) && defined(NI_WITHSCOPEID) - if (afd->a_af == AF_INET6 && - (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) || - IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) && - ((struct sockaddr_in6 *)sa)->sin6_scope_id) { -#ifndef ALWAYS_WITHSCOPE - if (flags & NI_WITHSCOPEID) -#endif /* !ALWAYS_WITHSCOPE */ - { - char scopebuf[MAXHOSTNAMELEN], *s; - int scopelen; - - if ((s = ip6_sa2str((struct sockaddr_in6 *)sa, - scopebuf, 0)) == NULL) - /* XXX what should we do? */ - strcpy(scopebuf, "0"); - scopelen = strlen(scopebuf); - if (scopelen + 1 + numaddrlen + 1 > hostlen) - return ENI_MEMORY; + switch(afd->a_af) { +#ifdef INET6 + case AF_INET6: + { + int error; -#if 0 - /* - * construct <scopeid><delim><numeric-addr> - */ - /* - * Shift the host string to allocate - * space for the scope ID part. - */ - memmove(host + scopelen + 1, host, - numaddrlen); - /* copy the scope ID and the delimiter */ - memcpy(host, scopebuf, scopelen); - host[scopelen] = SCOPE_DELIMITER; - host[scopelen + 1 + numaddrlen] = '\0'; -#else - /* - * construct <numeric-addr><delim><scopeid> - */ - memcpy(host + numaddrlen + 1, scopebuf, - scopelen); - host[numaddrlen] = SCOPE_DELIMITER; - host[numaddrlen + 1 + scopelen] = '\0'; + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, flags)) != 0) + return(error); + break; + } #endif - } + default: + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_SYSTEM; + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > hostlen) /* don't forget terminator */ + return ENI_MEMORY; + strcpy(host, numaddr); + break; } -#endif /* INET6 */ } else { hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); h_error = h_errno; if (hp) { #if 0 + /* + * commented out, since "for local host" is not + * implemented here - see RFC2553 p30 + */ if (flags & NI_NOFQDN) { - char *p; - p = strchr(hp->h_name, '.'); if (p) *p = '\0'; @@ -282,23 +261,82 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) } else { if (flags & NI_NAMEREQD) return ENI_NOHOSTNAME; - if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) - == NULL) - return ENI_NOHOSTNAME; - if (strlen(numaddr) > hostlen) - return ENI_MEMORY; - strcpy(host, numaddr); + switch(afd->a_af) { +#ifdef INET6 + case AF_INET6: + { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, + flags)) != 0) + return(error); + break; + } +#endif + default: + if (inet_ntop(afd->a_af, addr, host, + hostlen) == NULL) + return ENI_SYSTEM; + break; + } } } return SUCCESS; } #ifdef INET6 +static int +ip6_parsenumeric(sa, addr, host, hostlen, flags) + const struct sockaddr *sa; + char *addr, *host; + int flags, hostlen; +{ + int numaddrlen; + char numaddr[512]; + + if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_SYSTEM; + + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > hostlen) /* don't forget terminator */ + return ENI_MEMORY; + strcpy(host, numaddr); + +#ifdef NI_WITHSCOPEID + if (((struct sockaddr_in6 *)sa)->sin6_scope_id) { + if (flags & NI_WITHSCOPEID) + { + char scopebuf[MAXHOSTNAMELEN]; + int scopelen; + + /* ip6_sa2str never fails */ + scopelen = ip6_sa2str((struct sockaddr_in6 *)sa, + scopebuf, sizeof(scopebuf), + 0); + if (scopelen + 1 + numaddrlen + 1 > hostlen) + return ENI_MEMORY; + /* + * construct <numeric-addr><delim><scopeid> + */ + memcpy(host + numaddrlen + 1, scopebuf, + scopelen); + host[numaddrlen] = SCOPE_DELIMITER; + host[numaddrlen + 1 + scopelen] = '\0'; + } + } +#endif /* NI_WITHSCOPEID */ + + return 0; +} + /* ARGSUSED */ -static char * -ip6_sa2str(sa6, buf, flags) +static int +ip6_sa2str(sa6, buf, bufsiz, flags) struct sockaddr_in6 *sa6; char *buf; + size_t bufsiz; int flags; { unsigned int ifindex = (unsigned int)sa6->sin6_scope_id; @@ -306,19 +344,20 @@ ip6_sa2str(sa6, buf, flags) #ifdef notyet if (flags & NI_NUMERICSCOPE) { - sprintf(buf, "%d", sa6->sin6_scope_id); - return(buf); + return(snprintf(buf, bufsiz, "%d", sa6->sin6_scope_id)); } #endif - if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) - return(if_indextoname(ifindex, buf)); - - if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) - return(NULL); /* XXX */ - if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) - return(NULL); /* XXX */ + /* if_indextoname() does not take buffer size. not a good api... */ + if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) && + bufsiz >= IF_NAMESIZE) { + char *p = if_indextoname(ifindex, buf); + if (p) { + return(strlen(p)); + } + } - return(NULL); /* XXX */ + /* last resort */ + return(snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id)); } -#endif +#endif /* INET6 */ |