From bfbe42d3920e1311027cf88535c4a491d1273d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 30 Dec 2020 13:51:24 +0100 Subject: [PATCH] miniupnpc: Fix usage of IP_MULTICAST_IF with struct ip_mreqn When struct ip_mreqn is passed to IP_MULTICAST_IF setsockopt option it is always required to set also ipv4 source address. Otherwise Linux kernel will choose default system multicast ipv4 address which does not have to belong to chosen interface specified in struct ip_mreqn. Therefore on system with more multicast interfaces and more ipv4 addresses, it may happen that interface chosen by upnpc -m option would use ipv4 address which does not belong to this interface. This change is fixing above issue and ensure that if interface is chosen by upnpc -m option then source address which belongs to this interface would be used. Without this change upnpc -m eth1 can send multicast traffic over interface eth1 but with source ipv4 address of interface eth0, which obviously would be rejected by upnp gateway. --- miniupnpc/minissdpc.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/miniupnpc/minissdpc.c b/miniupnpc/minissdpc.c index ff4d8c1..7cc9deb 100644 --- a/miniupnpc/minissdpc.c +++ b/miniupnpc/minissdpc.c @@ -66,7 +66,7 @@ struct sockaddr_un { #define HAS_IP_MREQN #endif -#if !defined(HAS_IP_MREQN) && !defined(_WIN32) +#ifndef _WIN32 #include #if defined(__sun) || defined(__HAIKU__) #include @@ -735,10 +735,24 @@ ssdpDiscoverDevices(const char * const deviceTypes[], PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); } } else { -#ifdef HAS_IP_MREQN /* was not an ip address, try with an interface name */ +#ifndef _WIN32 +#ifdef HAS_IP_MREQN struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ +#endif + struct ifreq ifr; + int ifrlen = sizeof(ifr); + strncpy(ifr.ifr_name, multicastif, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0) + { + PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)"); + goto error; + } + mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; +#ifdef HAS_IP_MREQN memset(&reqn, 0, sizeof(struct ip_mreqn)); + reqn.imr_address.s_addr = mc_if.s_addr; reqn.imr_ifindex = if_nametoindex(multicastif); if(reqn.imr_ifindex == 0) { @@ -751,20 +765,12 @@ ssdpDiscoverDevices(const char * const deviceTypes[], { PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); } -#elif !defined(_WIN32) - struct ifreq ifr; - int ifrlen = sizeof(ifr); - strncpy(ifr.ifr_name, multicastif, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = '\0'; - if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0) - { - PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)"); - } - mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; +#else if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); } +#endif #else /* _WIN32 */ #ifdef DEBUG printf("Setting of multicast interface not supported with interface name.\n");