Fix possible SIGSEGV in bpf.c

This commit is contained in:
Simon Kelley
2025-02-08 22:58:42 +00:00
parent bceab45dbe
commit 535be2f5d3

164
src/bpf.c
View File

@@ -126,108 +126,106 @@ int iface_enumerate(int family, void *parm, callback_t callback)
for (addrs = head; addrs; addrs = addrs->ifa_next) for (addrs = head; addrs; addrs = addrs->ifa_next)
{ {
if (addrs->ifa_addr->sa_family == family) int iface_index = if_nametoindex(addrs->ifa_name);
if (iface_index == 0 || !addrs->ifa_addr ||
addrs->ifa_addr->sa_family != family ||
(!addrs->ifa_netmask && family != AF_LINK))
continue;
if (family == AF_INET)
{ {
int iface_index = if_nametoindex(addrs->ifa_name); struct in_addr addr, netmask, broadcast;
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
if (iface_index == 0 || !addrs->ifa_addr || #ifdef HAVE_BSD_NETWORK
(!addrs->ifa_netmask && family != AF_LINK)) if (del_family == AF_INET && del_addr.addr4.s_addr == addr.s_addr)
continue; continue;
if (family == AF_INET)
{
struct in_addr addr, netmask, broadcast;
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
#ifdef HAVE_BSD_NETWORK
if (del_family == AF_INET && del_addr.addr4.s_addr == addr.s_addr)
continue;
#endif #endif
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr; netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
if (addrs->ifa_broadaddr) if (addrs->ifa_broadaddr)
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr; broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
else else
broadcast.s_addr = 0; broadcast.s_addr = 0;
if (!callback.af_inet(addr, iface_index, NULL, netmask, broadcast, parm)) if (!callback.af_inet(addr, iface_index, NULL, netmask, broadcast, parm))
goto err; goto err;
} }
else if (family == AF_INET6) else if (family == AF_INET6)
{ {
struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr; struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr; unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id; int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
int i, j, prefix = 0; int i, j, prefix = 0;
u32 valid = 0xffffffff, preferred = 0xffffffff; u32 valid = 0xffffffff, preferred = 0xffffffff;
int flags = 0; int flags = 0;
#ifdef HAVE_BSD_NETWORK #ifdef HAVE_BSD_NETWORK
if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr6, addr)) if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr6, addr))
continue; continue;
#endif #endif
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
struct in6_ifreq ifr6; struct in6_ifreq ifr6;
memset(&ifr6, 0, sizeof(ifr6)); memset(&ifr6, 0, sizeof(ifr6));
safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name)); safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr); ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1) if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
{ {
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE) if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
flags |= IFACE_TENTATIVE; flags |= IFACE_TENTATIVE;
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED) if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
flags |= IFACE_DEPRECATED; flags |= IFACE_DEPRECATED;
#ifdef IN6_IFF_TEMPORARY #ifdef IN6_IFF_TEMPORARY
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY))) if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
flags |= IFACE_PERMANENT; flags |= IFACE_PERMANENT;
#endif #endif
#ifdef IN6_IFF_PRIVACY #ifdef IN6_IFF_PRIVACY
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY))) if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
flags |= IFACE_PERMANENT; flags |= IFACE_PERMANENT;
#endif #endif
}
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
{
valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
}
#endif
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
if (netmask[i] != 0xff)
break;
if (i != IN6ADDRSZ && netmask[i])
for (j = 7; j > 0; j--, prefix++)
if ((netmask[i] & (1 << j)) == 0)
break;
/* voodoo to clear interface field in address */
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
{
addr->s6_addr[2] = 0;
addr->s6_addr[3] = 0;
}
if (!callback.af_inet6(addr, prefix, scope_id, iface_index, flags,
(unsigned int) preferred, (unsigned int)valid, parm))
goto err;
} }
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
{
valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
}
#endif
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
if (netmask[i] != 0xff)
break;
if (i != IN6ADDRSZ && netmask[i])
for (j = 7; j > 0; j--, prefix++)
if ((netmask[i] & (1 << j)) == 0)
break;
/* voodoo to clear interface field in address */
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
{
addr->s6_addr[2] = 0;
addr->s6_addr[3] = 0;
}
if (!callback.af_inet6(addr, prefix, scope_id, iface_index, flags,
(unsigned int) preferred, (unsigned int)valid, parm))
goto err;
}
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else if (family == AF_LINK) else if (family == AF_LINK)
{ {
/* Assume ethernet again here */ /* Assume ethernet again here */
struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr; struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
if (sdl->sdl_alen != 0 && if (sdl->sdl_alen != 0 &&
!callback.af_local(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)) !callback.af_local(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm))
goto err; goto err;
}
#endif
} }
#endif
} }
ret = 1; ret = 1;