Use SIOCGSIZIFCONF or SIOCGIFNUM where available.

Still falls back to a loop if not but now maxes out at 2048
interfaces instead of potentially looping forever.
This commit is contained in:
Todd C. Miller
2021-03-24 08:57:40 -06:00
parent cf8feb2876
commit 45ca46d735

View File

@@ -143,8 +143,7 @@ get_net_ifs(char **addrinfo)
if ((cp = malloc(ailen)) == NULL) { if ((cp = malloc(ailen)) == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to allocate memory"); "unable to allocate memory");
num_interfaces = -1; goto bad;
goto done;
} }
*addrinfo = cp; *addrinfo = cp;
@@ -203,12 +202,15 @@ get_net_ifs(char **addrinfo)
cp == *addrinfo ? "" : " ", addrstr, maskstr); cp == *addrinfo ? "" : " ", addrstr, maskstr);
if (len < 0 || (size_t)len >= ailen) { if (len < 0 || (size_t)len >= ailen) {
sudo_warnx(U_("internal error, %s overflow"), __func__); sudo_warnx(U_("internal error, %s overflow"), __func__);
goto done; goto bad;
} }
cp += len; cp += len;
ailen -= len; ailen -= len;
} }
goto done;
bad:
num_interfaces = -1;
done: done:
# ifdef HAVE_FREEIFADDRS # ifdef HAVE_FREEIFADDRS
freeifaddrs(ifaddrs); freeifaddrs(ifaddrs);
@@ -236,8 +238,8 @@ get_net_ifs(char **addrinfo)
# endif # endif
char addrstr[INET6_ADDRSTRLEN], maskstr[INET6_ADDRSTRLEN]; char addrstr[INET6_ADDRSTRLEN], maskstr[INET6_ADDRSTRLEN];
int i, n, sock, sock4, sock6 = -1; int i, n, sock, sock4, sock6 = -1;
int num_interfaces = -1; int num_interfaces = 0;
size_t ailen, buflen; size_t ailen;
char *cp; char *cp;
debug_decl(get_net_ifs, SUDO_DEBUG_NETIF); debug_decl(get_net_ifs, SUDO_DEBUG_NETIF);
@@ -272,27 +274,27 @@ get_net_ifs(char **addrinfo)
if (lifconf.lifc_buf == NULL) { if (lifconf.lifc_buf == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to allocate memory"); "unable to allocate memory");
goto done; goto bad;
} }
if (ioctl(sock, SIOCGLIFCONF, &lifconf) < 0) { if (ioctl(sock, SIOCGLIFCONF, &lifconf) < 0) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"unable to get interface list (SIOCGLIFCONF)"); "unable to get interface list (SIOCGLIFCONF)");
goto done; goto bad;
} }
/* Allocate space for the maximum number of interfaces that could exist. */ /* Allocate space for the maximum number of interfaces that could exist. */
if ((n = lifconf.lifc_len / sizeof(struct lifreq)) > 0) { n = lifconf.lifc_len / sizeof(struct lifreq);
ailen = n * 2 * INET6_ADDRSTRLEN; if (n == 0)
if ((cp = malloc(ailen)) == NULL) { goto done;
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, ailen = n * 2 * INET6_ADDRSTRLEN;
"unable to allocate memory"); if ((cp = malloc(ailen)) == NULL) {
goto done; sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
} "unable to allocate memory");
*addrinfo = cp; goto bad;
} }
*addrinfo = cp;
/* For each interface, store the ip address and netmask. */ /* For each interface, store the ip address and netmask. */
num_interfaces = 0;
for (i = 0; i < lifconf.lifc_len; ) { for (i = 0; i < lifconf.lifc_len; ) {
/* Get a pointer to the current interface. */ /* Get a pointer to the current interface. */
lifr = (struct lifreq *)&lifconf.lifc_buf[i]; lifr = (struct lifreq *)&lifconf.lifc_buf[i];
@@ -389,14 +391,17 @@ get_net_ifs(char **addrinfo)
cp == *addrinfo ? "" : " ", addrstr, maskstr); cp == *addrinfo ? "" : " ", addrstr, maskstr);
if (n < 0 || (size_t)n >= ailen) { if (n < 0 || (size_t)n >= ailen) {
sudo_warnx(U_("internal error, %s overflow"), __func__); sudo_warnx(U_("internal error, %s overflow"), __func__);
goto done; goto bad;
} }
cp += n; cp += n;
ailen -= n; ailen -= n;
num_interfaces++; num_interfaces++;
} }
goto done;
bad:
num_interfaces = -1;
done: done:
free(lifconf.lifc_buf); free(lifconf.lifc_buf);
if (sock4 != -1) if (sock4 != -1)
@@ -424,8 +429,9 @@ get_net_ifs(char **addrinfo)
struct sockaddr_in6 *sin6; struct sockaddr_in6 *sin6;
# endif # endif
char addrstr[INET6_ADDRSTRLEN], maskstr[INET6_ADDRSTRLEN]; char addrstr[INET6_ADDRSTRLEN], maskstr[INET6_ADDRSTRLEN];
int i, n, sock, sock4, sock6 = -1, num_interfaces = 0; int i, n, sock, sock4, sock6 = -1;
size_t ailen; int num_interfaces = 0;
size_t ailen, buflen;
char *cp, *ifconf_buf = NULL; char *cp, *ifconf_buf = NULL;
debug_decl(get_net_ifs, SUDO_DEBUG_NETIF); debug_decl(get_net_ifs, SUDO_DEBUG_NETIF);
@@ -442,31 +448,43 @@ get_net_ifs(char **addrinfo)
/* Use INET6 socket with SIOCGIFCONF if possible (may not matter). */ /* Use INET6 socket with SIOCGIFCONF if possible (may not matter). */
sock = sock6 != -1 ? sock6 : sock4; sock = sock6 != -1 ? sock6 : sock4;
/* Get the size of the interface buffer (if possible). */ /*
memset(&ifconf, 0, sizeof(ifconf)); * Get the size of the interface buffer (if possible).
* We over-allocate a bit in case interfaces come afterward.
*/
# if defined(SIOCGSIZIFCONF) # if defined(SIOCGSIZIFCONF)
if (ioctl(sock, SIOCGSIZIFCONF, &i) != -1) { if (ioctl(sock, SIOCGSIZIFCONF, &i) != -1) {
ifconf.ifc_len = i; buflen = i + (sizeof(struct ifreq) * 4);
} } else
# elif defined(SIOCGIFNUM) # elif defined(SIOCGIFNUM)
if (ioctl(sock, SIOCGIFNUM, &i) != -1) { if (ioctl(sock, SIOCGIFNUM, &i) != -1) {
ifconf.ifc_len = sizeof(struct ifreq) * (i + 4); buflen = (i + 4) * sizeof(struct ifreq);
} } else
# endif # endif
if (ifconf.ifc_len = 0) {
ifconf.ifc_len = sizeof(struct ifreq) * 512; buflen = 256 * sizeof(struct ifreq);
/* Allocate and fill in the interface buffer. */
ifconf.ifc_buf = malloc(ifconf.ifc_len);
if (ifconf.ifc_buf == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to allocate memory");
num_interfaces = -1;
goto done;
} }
if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0) {
num_interfaces = -1; /* Get interface configuration. */
goto done; memset(&ifconf, 0, sizeof(ifconf));
for (i = 0; i < 4; i++) {
ifconf.ifc_len = buflen;
ifconf.ifc_buf = malloc(buflen);
if (ifconf.ifc_buf == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to allocate memory");
goto bad;
}
/* Note that some kernels return EINVAL if the buffer is too small */
if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0 && errno != EINVAL)
goto bad;
/* Break out of loop if we have a big enough buffer. */
if (ifconf.ifc_len + sizeof(struct ifreq) < buflen)
break;
buflen *= 2;
free(ifconf.ifc_buf);
} }
/* /*
@@ -488,8 +506,7 @@ get_net_ifs(char **addrinfo)
if ((cp = malloc(ailen)) == NULL) { if ((cp = malloc(ailen)) == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to allocate memory"); "unable to allocate memory");
num_interfaces = -1; goto bad;
goto done;
} }
*addrinfo = cp; *addrinfo = cp;
@@ -589,14 +606,17 @@ get_net_ifs(char **addrinfo)
cp == *addrinfo ? "" : " ", addrstr, maskstr); cp == *addrinfo ? "" : " ", addrstr, maskstr);
if (n < 0 || (size_t)n >= ailen) { if (n < 0 || (size_t)n >= ailen) {
sudo_warnx(U_("internal error, %s overflow"), __func__); sudo_warnx(U_("internal error, %s overflow"), __func__);
goto done; goto bad;
} }
cp += n; cp += n;
ailen -= n; ailen -= n;
num_interfaces++; num_interfaces++;
} }
goto done;
bad:
num_interfaces = -1;
done: done:
free(ifconf_buf); free(ifconf_buf);
if (sock4 != -1) if (sock4 != -1)