git: d80d73493767 - main - arp(8): use getifaddrs(3) instead of ioctl(SIOCGIFCONF)
Date: Tue, 05 Jul 2022 03:56:58 UTC
The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=d80d73493767111b7569e831a93061014c682274 commit d80d73493767111b7569e831a93061014c682274 Author: KUROSAWA Takahiro <takahiro.kurosawa@gmail.com> AuthorDate: 2022-07-05 03:56:29 +0000 Commit: Gleb Smirnoff <glebius@FreeBSD.org> CommitDate: 2022-07-05 03:56:29 +0000 arp(8): use getifaddrs(3) instead of ioctl(SIOCGIFCONF) The original code had used a fixed-size buffer for ioctl(SIOCGIFCONF), that might cause the target ifreq spilled from the buffer. Use the handy getifaddrs(3) to fix the problem. Reviewed by: glebius Differential revision: https://reviews.freebsd.org/D35536 --- usr.sbin/arp/arp.c | 71 ++++++++++++++++++++---------------------------------- 1 file changed, 26 insertions(+), 45 deletions(-) diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c index f018baa2679e..e7c18b0f323f 100644 --- a/usr.sbin/arp/arp.c +++ b/usr.sbin/arp/arp.c @@ -79,6 +79,7 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <strings.h> #include <unistd.h> +#include <ifaddrs.h> #include <libxo/xo.h> typedef void (action_fn)(struct sockaddr_dl *sdl, struct sockaddr_in *s_in, @@ -794,90 +795,70 @@ doit: * get_ether_addr - get the hardware address of an interface on the * the same subnet as ipaddr. */ -#define MAX_IFS 32 - static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr) { - struct ifreq *ifr, *ifend, *ifp; + struct ifaddrs *ifa, *ifd, *ifas = NULL; in_addr_t ina, mask; struct sockaddr_dl *dla; - struct ifreq ifreq; - struct ifconf ifc; - struct ifreq ifs[MAX_IFS]; - int sock; int retval = 0; - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - xo_err(1, "socket"); - - ifc.ifc_len = sizeof(ifs); - ifc.ifc_req = ifs; - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { - xo_warnx("ioctl(SIOCGIFCONF)"); - goto done; - } - -#define NEXTIFR(i) \ - ((struct ifreq *)((char *)&(i)->ifr_addr \ - + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) ) - /* * Scan through looking for an interface with an Internet * address on the same subnet as `ipaddr'. */ - ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len); - for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr) ) { - if (ifr->ifr_addr.sa_family != AF_INET) + if (getifaddrs(&ifas) < 0) { + xo_warnx("getifaddrs"); + goto done; + } + + for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL) + continue; + if (ifa->ifa_addr->sa_family != AF_INET) continue; - strncpy(ifreq.ifr_name, ifr->ifr_name, - sizeof(ifreq.ifr_name)); - ifreq.ifr_addr = ifr->ifr_addr; /* * Check that the interface is up, * and not point-to-point or loopback. */ - if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) - continue; - if ((ifreq.ifr_flags & + if ((ifa->ifa_flags & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST)) continue; /* Get its netmask and check that it's on the right subnet. */ - if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0) - continue; mask = ((struct sockaddr_in *) - &ifreq.ifr_addr)->sin_addr.s_addr; + ifa->ifa_netmask)->sin_addr.s_addr; ina = ((struct sockaddr_in *) - &ifr->ifr_addr)->sin_addr.s_addr; + ifa->ifa_addr)->sin_addr.s_addr; if ((ipaddr & mask) == (ina & mask)) break; /* ok, we got it! */ } - - if (ifr >= ifend) + if (ifa == NULL) goto done; /* * Now scan through again looking for a link-level address * for this interface. */ - ifp = ifr; - for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr)) - if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 && - ifr->ifr_addr.sa_family == AF_LINK) + for (ifd = ifas; ifd != NULL; ifd = ifd->ifa_next) { + if (ifd->ifa_addr == NULL) + continue; + if (strcmp(ifa->ifa_name, ifd->ifa_name) == 0 && + ifd->ifa_addr->sa_family == AF_LINK) break; - if (ifr >= ifend) + } + if (ifd == NULL) goto done; /* * Found the link-level address - copy it out */ - dla = (struct sockaddr_dl *) &ifr->ifr_addr; + dla = (struct sockaddr_dl *)ifd->ifa_addr; memcpy(hwaddr, LLADDR(dla), dla->sdl_alen); - printf("using interface %s for proxy with address %s\n", ifp->ifr_name, + printf("using interface %s for proxy with address %s\n", ifa->ifa_name, ether_ntoa(hwaddr)); retval = dla->sdl_alen; done: - close(sock); + if (ifas != NULL) + freeifaddrs(ifas); return (retval); }