Use newer IP_MULTICAST_IF API

Use newer API for IP_MULTICAST_IF which allows one to specify
interface by index, not by address. Introduced in Linux 3.5, it IMHO should
be available on all systems that declare struct ip_mreqn.

This fixes operation failure when a system has multiple interfaces
with same address, but only on of them is desired. Example:

> grep interface /usr/local/etc/minidlna.conf
network_interface=igb0
> ifconfig igb0
igb0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        ether 0c:c4:7a:xx:xx:xx
        inet 10.1.10.3 netmask 0xffffff00 broadcast 10.1.10.255
        media: Ethernet autoselect (1000baseT <full-duplex>)
        status: active
> ifconfig ng0
ng0: flags=88d1<UP,POINTOPOINT,RUNNING,NOARP,SIMPLEX,MULTICAST> metric 0 mtu 1454
        inet 10.1.10.3 --> 10.1.10.2 netmask 0xffffffff

In such configuration, ng0 would be chosen before this fix.
This commit is contained in:
Gleb Smirnoff 2018-12-19 19:06:26 -08:00 committed by Justin Maggard
parent 256d271201
commit 36b9136d2b

View File

@ -145,7 +145,11 @@ OpenAndConfSSDPNotifySocket(struct lan_addr_s *iface)
int s; int s;
unsigned char loopchar = 0; unsigned char loopchar = 0;
uint8_t ttl = 4; uint8_t ttl = 4;
#ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn imr;
#else
struct in_addr mc_if; struct in_addr mc_if;
#endif
struct sockaddr_in sockname; struct sockaddr_in sockname;
s = socket(PF_INET, SOCK_DGRAM, 0); s = socket(PF_INET, SOCK_DGRAM, 0);
@ -155,8 +159,6 @@ OpenAndConfSSDPNotifySocket(struct lan_addr_s *iface)
return -1; return -1;
} }
mc_if.s_addr = iface->addr.s_addr;
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0) if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0)
{ {
DPRINTF(E_ERROR, L_SSDP, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %s\n", strerror(errno)); DPRINTF(E_ERROR, L_SSDP, "setsockopt(udp_notify, IP_MULTICAST_LOOP): %s\n", strerror(errno));
@ -164,7 +166,14 @@ OpenAndConfSSDPNotifySocket(struct lan_addr_s *iface)
return -1; return -1;
} }
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&mc_if, sizeof(mc_if)) < 0) #ifdef HAVE_STRUCT_IP_MREQN
imr.imr_address = iface->addr;
imr.imr_ifindex = iface->ifindex;
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &imr, sizeof(imr)) < 0)
#else
mc_if = iface->addr;
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &mc_if, sizeof(mc_if)) < 0)
#endif
{ {
DPRINTF(E_ERROR, L_SSDP, "setsockopt(udp_notify, IP_MULTICAST_IF): %s\n", strerror(errno)); DPRINTF(E_ERROR, L_SSDP, "setsockopt(udp_notify, IP_MULTICAST_IF): %s\n", strerror(errno));
close(s); close(s);