diff options
Diffstat (limited to 'inet')
-rw-r--r-- | inet/getnameinfo.c | 107 | ||||
-rw-r--r-- | inet/netinet/in.h | 3 |
2 files changed, 80 insertions, 30 deletions
diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c index 9a07092..6ee3d4d 100644 --- a/inet/getnameinfo.c +++ b/inet/getnameinfo.c @@ -42,20 +42,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */ -#include <sys/types.h> -#include <sys/socket.h> - -#include <netinet/in.h> -#include <sys/un.h> -#include <sys/utsname.h> -#include <netdb.h> +#include <alloca.h> #include <errno.h> -#include <string.h> +#include <netdb.h> #include <stdio.h> +#include <string.h> #include <unistd.h> -#include <alloca.h> -#include <bits/libc-lock.h> #include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#include <sys/utsname.h> +#include <bits/libc-lock.h> #ifndef min # define min(x,y) (((x) > (y)) ? (y) : (x)) @@ -173,6 +174,7 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host, char *tmpbuf = alloca (tmpbuflen); struct hostent th; socklen_t min_addrlen = 0; + int ok = 0; if (sa == NULL || addrlen < sizeof (sa_family_t)) return -1; @@ -257,36 +259,83 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host, min(hostlen, (size_t) (c - h->h_name))); host[min(hostlen - 1, (size_t) (c - h->h_name))] = '\0'; - break; + ok = 1; + } + else + { + strncpy (host, h->h_name, hostlen); + ok = 1; } } strncpy (host, h->h_name, hostlen); - break; + ok = 1; } } - if (flags & NI_NAMEREQD) + if (!ok) { - __set_errno (serrno); - return -1; - } - else - { - const char *c; - if (sa->sa_family == AF_INET6) - c = inet_ntop (AF_INET6, - (void *) &(((struct sockaddr_in6 *) sa)->sin6_addr), - host, hostlen); - else - c = inet_ntop (AF_INET, - (void *) &(((struct sockaddr_in *) sa)->sin_addr), - host, hostlen); - - if (c == NULL) + if (flags & NI_NAMEREQD) { __set_errno (serrno); return -1; } + else + { + const char *c; + if (sa->sa_family == AF_INET6) + { + struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) sa; + uint32_t scopeid; + + c = inet_ntop (AF_INET6, + (void *) &sin6p->sin6_addr, host, hostlen); + if (addrlen > sizeof (struct sockaddr_in6) + && (scopeid = sin6p->sin6_scope_id)) + { + /* Buffer is >= IFNAMSIZ+1. */ + char scopebuf[MAXHOSTNAMELEN + 1]; + int ni_numericscope = 0; + + if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr) + || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr)) + { + if (if_indextoname (scopeid, scopebuf) == NULL) + ++ni_numericscope; + } + else + ++ni_numericscope; + + if (ni_numericscope) + { + char *scopeptr = &scopebuf[1]; + size_t real_hostlen; + size_t scopelen; + + scopebuf[0] = SCOPE_DELIMITER; + scopelen = 1 + snprintf (scopeptr, + (scopebuf + + sizeof scopebuf + - scopeptr), + "%u", scopeid); + + real_hostlen = __strnlen (host, hostlen); + if (real_hostlen + scopelen + 1 > hostlen) + return -1; + memcpy (host + real_hostlen, scopebuf, scopelen); + } + } + } + else + c = inet_ntop (AF_INET, + (void *) &(((struct sockaddr_in *) sa)->sin_addr), + host, hostlen); + if (c == NULL) + { + __set_errno (serrno); + return -1; + } + } + ok = 1; } break; diff --git a/inet/netinet/in.h b/inet/netinet/in.h index 13c2767..fb668a2 100644 --- a/inet/netinet/in.h +++ b/inet/netinet/in.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc. +/* Copyright (C) 1991-1999, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -209,6 +209,7 @@ struct sockaddr_in6 uint16_t sin6_port; /* Transport layer port # */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ + uint32_t sin6_scope_id; /* IPv6 scope-id */ }; /* IPv6 multicast request. */ |