From 5f9e84ea517a9aee52adda5372f77c8ef995f067 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 2 Oct 2014 07:55:08 -0600 Subject: [PATCH] Use inet_ntop() instead of inet_ntoa() and include a version for systems that are missing it. --- MANIFEST | 1 + config.h.in | 4 +- configure | 29 +++--- configure.ac | 17 ++-- lib/util/inet_ntop.c | 230 +++++++++++++++++++++++++++++++++++++++++++ src/net_ifs.c | 69 +++++++------ 6 files changed, 294 insertions(+), 56 deletions(-) create mode 100644 lib/util/inet_ntop.c diff --git a/MANIFEST b/MANIFEST index b6f42b7cb..244ae236d 100644 --- a/MANIFEST +++ b/MANIFEST @@ -94,6 +94,7 @@ lib/util/getline.c lib/util/getopt_long.c lib/util/gidlist.c lib/util/glob.c +lib/util/inet_ntop.c lib/util/inet_pton.c lib/util/isblank.c lib/util/key_val.c diff --git a/config.h.in b/config.h.in index 70e40fd9c..0acb6d1fe 100644 --- a/config.h.in +++ b/config.h.in @@ -259,8 +259,8 @@ /* Define to 1 if your Kerberos is Heimdal. */ #undef HAVE_HEIMDAL -/* Define to 1 if you have the `inet_ntoa' function. */ -#undef HAVE_INET_NTOA +/* Define to 1 if you have the `inet_ntop' function. */ +#undef HAVE_INET_NTOP /* Define to 1 if you have the `inet_pton' function. */ #undef HAVE_INET_PTON diff --git a/configure b/configure index 76b96fa4c..dd054a55b 100755 --- a/configure +++ b/configure @@ -19133,9 +19133,13 @@ fi LIBS="$OLIBS" OLIBS="$LIBS" LIBS="${LIBS} ${NET_LIBS}" -ac_fn_c_check_func "$LINENO" "inet_ntoa" "ac_cv_func_inet_ntoa" -if test "x$ac_cv_func_inet_ntoa" = xyes; then : - $as_echo "#define HAVE_INET_NTOA 1" >>confdefs.h +found=false +ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop" +if test "x$ac_cv_func_inet_ntop" = xyes; then : + + found=true + $as_echo "#define HAVE_INET_NTOP 1" >>confdefs.h + else @@ -19153,9 +19157,9 @@ else extralibs="`echo \"$libs\"|sed 's/^-l[^ ]*//'`" _sudo_check_lib_extras=`echo "$extralibs"|sed -e 's/ *//g' -e 's/-l/_/g'` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -l$lib${5+ }$extralibs" >&5 -$as_echo_n "checking for inet_ntoa in -l$lib${5+ }$extralibs... " >&6; } - if { as_var=sudo_cv_lib_$lib''_inet_ntoa$_sudo_check_lib_extras; eval \${$as_var+:} false; }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntop in -l$lib${5+ }$extralibs" >&5 +$as_echo_n "checking for inet_ntop in -l$lib${5+ }$extralibs... " >&6; } + if { as_var=sudo_cv_lib_$lib''_inet_ntop$_sudo_check_lib_extras; eval \${$as_var+:} false; }; then : $as_echo_n "(cached) " >&6 else @@ -19170,19 +19174,19 @@ else #ifdef __cplusplus extern "C" #endif -char inet_ntoa (); +char inet_ntop (); int main () { -return inet_ntoa (); +return inet_ntop (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - eval sudo_cv_lib_$lib''_inet_ntoa$_sudo_check_lib_extras=yes + eval sudo_cv_lib_$lib''_inet_ntop$_sudo_check_lib_extras=yes else - eval sudo_cv_lib_$lib''_inet_ntoa$_sudo_check_lib_extras=no + eval sudo_cv_lib_$lib''_inet_ntop$_sudo_check_lib_extras=no fi rm -f core conftest.err conftest.$ac_objext \ @@ -19191,11 +19195,12 @@ rm -f core conftest.err conftest.$ac_objext \ fi - if eval test \$sudo_cv_lib_$lib''_inet_ntoa$_sudo_check_lib_extras = "yes"; then + if eval test \$sudo_cv_lib_$lib''_inet_ntop$_sudo_check_lib_extras = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - $as_echo "#define HAVE_INET_NTOA 1" >>confdefs.h + found=true + $as_echo "#define HAVE_INET_NTOP 1" >>confdefs.h NET_LIBS="${NET_LIBS} $libs" break diff --git a/configure.ac b/configure.ac index c4a711418..120000cdb 100644 --- a/configure.ac +++ b/configure.ac @@ -2654,13 +2654,17 @@ AC_CHECK_FUNC(socket, [], [ ]) LIBS="$OLIBS" dnl -dnl If inet_ntoa(3) not in libc, check -lnsl and -linet +dnl If inet_ntop(3) not in libc, check -lnsl and -linet dnl May need to link with *both* -lnsl and -lsocket due to unresolved symbols -dnl Some systems may have inet_ntoa() in libresolv. +dnl Some systems may have inet_ntop() in libresolv. dnl OLIBS="$LIBS" LIBS="${LIBS} ${NET_LIBS}" -AC_CHECK_FUNC(inet_ntoa, [AC_DEFINE(HAVE_INET_NTOA)], [ +found=false +AC_CHECK_FUNC(inet_ntop, [ + found=true + AC_DEFINE(HAVE_INET_NTOP) +], [ for libs in "-lsocket" "-linet" "-lsocket -lnsl" "-lresolv"; do _libs= for lib in $libs; do @@ -2673,8 +2677,9 @@ AC_CHECK_FUNC(inet_ntoa, [AC_DEFINE(HAVE_INET_NTOA)], [ test -z "$libs" && continue lib="`echo \"$libs\"|sed -e 's/^-l//' -e 's/ .*$//'`" extralibs="`echo \"$libs\"|sed 's/^-l[[^ ]]*//'`" - SUDO_CHECK_LIB($lib, inet_ntoa, [ - AC_DEFINE(HAVE_INET_NTOA) + SUDO_CHECK_LIB($lib, inet_ntop, [ + found=true + AC_DEFINE(HAVE_INET_NTOP) NET_LIBS="${NET_LIBS} $libs" break ], [], [$extralibs]) @@ -4078,7 +4083,7 @@ AH_TEMPLATE(HAVE_GETSPNAM, [Define to 1 if you have the `getspnam' function (SVR AH_TEMPLATE(HAVE_GETSPWUID, [Define to 1 if you have the `getspwuid' function. (HP-UX <= 9.X shadow passwords).]) AH_TEMPLATE(HAVE_GSS_KRB5_CCACHE_NAME, [Define to 1 if you have the `gss_krb5_ccache_name' function.]) AH_TEMPLATE(HAVE_HEIMDAL, [Define to 1 if your Kerberos is Heimdal.]) -AH_TEMPLATE(HAVE_INET_NTOA, [Define to 1 if you have the `inet_ntoa' function.]) +AH_TEMPLATE(HAVE_INET_NTOP, [Define to 1 if you have the `inet_ntop' function.]) AH_TEMPLATE(HAVE_INET_PTON, [Define to 1 if you have the `inet_pton' function.]) AH_TEMPLATE(HAVE_ISCOMSEC, [Define to 1 if you have the `iscomsec' function. (HP-UX >= 10.x check for shadow enabled).]) AH_TEMPLATE(HAVE_ISSECURE, [Define to 1 if you have the `issecure' function. (SunOS 4.x check for shadow enabled).]) diff --git a/lib/util/inet_ntop.c b/lib/util/inet_ntop.c new file mode 100644 index 000000000..28b6a9eb7 --- /dev/null +++ b/lib/util/inet_ntop.c @@ -0,0 +1,230 @@ +/* $OpenBSD: inet_ntop.c,v 1.9 2014/02/05 14:20:43 millert Exp $ */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include + +#if !defined(HAVE_INET_NTOP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sudo_compat.h" + +#ifndef EAFNOSUPPORT +# define EAFNOSUPPORT EINVAL +#endif + +#ifndef NS_IN6ADDRSZ +# ifdef IN6ADDRSZ +# define NS_IN6ADDRSZ IN6ADDRSZ +# else +# define NS_IN6ADDRSZ 16 +# endif +#endif +#ifndef NS_INT16SZ +# ifdef INT16SZ +# define NS_INT16SZ INT16SZ +# else +# define NS_INT16SZ 2 +# endif +#endif +#ifndef INET6_ADDRSTRLEN +# define INET6_ADDRSTRLEN 46 +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a unsigned char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(const unsigned char *src, char *dst, socklen_t size) +{ + const char fmt[] = "%u.%u.%u.%u"; + int len; + + len = snprintf(dst, size, fmt, src[0], src[1], src[2], src[3]); + if (len <= 0 || len >= size) { + errno = ENOSPC; + return (NULL); + } + return (dst); +} + +#ifdef HAVE_STRUCT_IN6_ADDR +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(const unsigned char *src, char *dst, socklen_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char *cp, *ep; + struct { int base, len; } best, cur; + unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + int advance; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, 0, sizeof(words)); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + cp = dst; + ep = dst + size; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ) && cp < ep; i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) { + if (cp + 1 >= ep) { + errno = ENOSPC; + return (NULL); + } + *cp++ = ':'; + } + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) { + if (cp + 1 >= ep) { + errno = ENOSPC; + return (NULL); + } + *cp++ = ':'; + } + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src + 12, cp, (socklen_t)(ep - cp))) + return (NULL); + cp += strlen(cp); + break; + } + advance = snprintf(cp, (size_t)(ep - cp), "%x", words[i]); + if (advance <= 0 || advance >= ep - cp) { + errno = ENOSPC; + return (NULL); + } + cp += advance; + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && + (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) { + if (cp + 1 >= ep) { + errno = ENOSPC; + return (NULL); + } + *cp++ = ':'; + } + if (cp + 1 >= ep) { + errno = ENOSPC; + return (NULL); + } + *cp++ = '\0'; + + return (dst); +} +#endif /* HAVE_STRUCT_IN6_ADDR */ + +/* const char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +inet_ntop(int af, const void *src, char *dst, socklen_t size) +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); +#ifdef HAVE_STRUCT_IN6_ADDR + case AF_INET6: + return (inet_ntop6(src, dst, size)); +#endif + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +#endif /* !HAVE_INET_NTOP */ diff --git a/src/net_ifs.c b/src/net_ifs.c index 220d67912..3c941c6ca 100644 --- a/src/net_ifs.c +++ b/src/net_ifs.c @@ -98,6 +98,9 @@ struct rtentry; # define IFF_LOOPBACK 0 #endif +#ifndef INET_ADDRSTRLEN +# define INET_ADDRSTRLEN 16 +#endif #ifndef INET6_ADDRSTRLEN # define INET6_ADDRSTRLEN 46 #endif @@ -115,7 +118,9 @@ get_net_ifs(char **addrinfo) struct sockaddr_in *sin; #ifdef HAVE_STRUCT_IN6_ADDR struct sockaddr_in6 *sin6; - char addrbuf[INET6_ADDRSTRLEN]; + char addrstr[INET6_ADDRSTRLEN], maskstr[INET6_ADDRSTRLEN]; +#else + char addrstr[INET_ADDRSTRLEN], maskstr[INET_ADDRSTRLEN]; #endif int ailen, len, num_interfaces = 0; char *cp; @@ -155,18 +160,14 @@ get_net_ifs(char **addrinfo) switch (ifa->ifa_addr->sa_family) { case AF_INET: sin = (struct sockaddr_in *)ifa->ifa_addr; - len = snprintf(cp, ailen - (*addrinfo - cp), - "%s%s/", cp == *addrinfo ? "" : " ", - inet_ntoa(sin->sin_addr)); - if (len <= 0 || len >= ailen - (*addrinfo - cp)) { - sudo_warnx(U_("internal error, %s overflow"), __func__); - goto done; - } - cp += len; - + if (inet_ntop(AF_INET, &sin->sin_addr, addrstr, sizeof(addrstr)) == NULL) + continue; sin = (struct sockaddr_in *)ifa->ifa_netmask; + if (inet_ntop(AF_INET, &sin->sin_addr, maskstr, sizeof(maskstr)) == NULL) + continue; + len = snprintf(cp, ailen - (*addrinfo - cp), - "%s", inet_ntoa(sin->sin_addr)); + "%s%s/%s", cp == *addrinfo ? "" : " ", addrstr, maskstr); if (len <= 0 || len >= ailen - (*addrinfo - cp)) { sudo_warnx(U_("internal error, %s overflow"), __func__); goto done; @@ -176,18 +177,14 @@ get_net_ifs(char **addrinfo) #ifdef HAVE_STRUCT_IN6_ADDR case AF_INET6: sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; - inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf)); - len = snprintf(cp, ailen - (*addrinfo - cp), - "%s%s/", cp == *addrinfo ? "" : " ", addrbuf); - if (len <= 0 || len >= ailen - (*addrinfo - cp)) { - sudo_warnx(U_("internal error, %s overflow"), __func__); - goto done; - } - cp += len; - + if (inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr, sizeof(addrstr)) == NULL) + continue; sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask; - inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf)); - len = snprintf(cp, ailen - (*addrinfo - cp), "%s", addrbuf); + if (inet_ntop(AF_INET6, &sin6->sin6_addr, maskstr, sizeof(maskstr)) == NULL) + continue; + + len = snprintf(cp, ailen - (*addrinfo - cp), + "%s%s/%s", cp == *addrinfo ? "" : " ", addrstr, maskstr); if (len <= 0 || len >= ailen - (*addrinfo - cp)) { sudo_warnx(U_("internal error, %s overflow"), __func__); goto done; @@ -223,6 +220,7 @@ get_net_ifs(char **addrinfo) int ailen, i, len, n, sock, num_interfaces = 0; size_t buflen = sizeof(struct ifconf) + BUFSIZ; char *cp, *previfname = "", *ifconf_buf = NULL; + char addrstr[INET_ADDRSTRLEN], maskstr[INET_ADDRSTRLEN]; #ifdef _ISC struct strioctl strioctl; #endif /* _ISC */ @@ -299,19 +297,6 @@ get_net_ifs(char **addrinfo) ISSET(ifr_tmp->ifr_flags, IFF_LOOPBACK)) continue; - sin = (struct sockaddr_in *) &ifr->ifr_addr; - len = snprintf(cp, ailen - (*addrinfo - cp), - "%s%s/", cp == *addrinfo ? "" : " ", - inet_ntoa(sin->sin_addr)); - if (len <= 0 || len >= ailen - (*addrinfo - cp)) { - sudo_warnx(U_("internal error, %s overflow"), __func__); - goto done; - } - cp += len; - - /* Stash the name of the interface we saved. */ - previfname = ifr->ifr_name; - /* Get the netmask. */ memset(ifr_tmp, 0, sizeof(*ifr_tmp)); strncpy(ifr_tmp->ifr_name, ifr->ifr_name, sizeof(ifr_tmp->ifr_name) - 1); @@ -323,13 +308,25 @@ get_net_ifs(char **addrinfo) if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) ifr_tmp) < 0) #endif /* _ISC */ sin->sin_addr.s_addr = htonl(IN_CLASSC_NET); + + /* Convert the addr and mask to string form. */ + sin = (struct sockaddr_in *) &ifr->ifr_addr; + if (inet_ntop(AF_INET, &sin->sin_addr, addrstr, sizeof(addrstr)) == NULL) + continue; + sin = (struct sockaddr_in *) &ifr_tmp->ifr_addr; + if (inet_ntop(AF_INET, &sin->sin_addr, maskstr, sizeof(maskstr)) == NULL) + continue; + len = snprintf(cp, ailen - (*addrinfo - cp), - "%s", inet_ntoa(sin->sin_addr)); + "%s%s/%s", cp == *addrinfo ? "" : " ", addrstr, maskstr); if (len <= 0 || len >= ailen - (*addrinfo - cp)) { sudo_warnx(U_("internal error, %s overflow"), __func__); goto done; } cp += len; + + /* Stash the name of the interface we saved. */ + previfname = ifr->ifr_name; num_interfaces++; } -- 2.40.0