From 65af96e0907ba9367aab9c1534b11c7f674c1e6a Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 19 Apr 2022 13:29:07 +0300 Subject: [PATCH 2/6] mreceive: join IGMP group by interface mreceive uses the old-style struct ip_mreq for IP_ADD_MEMBERSHIP, which takes the source address of the interface wishing to join. Since the IPV6_ADD_MEMBERSHIP variant only takes a struct ipv6_mreq which contains the ifindex and not the source address, we need to add support for that. In preparation for IPv6 support, add logic to join an IGMP group either by source address or by interface name, whichever is specified. Signed-off-by: Vladimir Oltean --- mreceive.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) --- a/mreceive.c +++ b/mreceive.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -61,7 +62,7 @@ Usage: mreceive [-g GROUP] [-p PORT] [-i -h Print the command usage.\n\n", VERSION); } -static void igmp_join(int s, in_addr_t multiaddr, in_addr_t interface) +static void igmp_join_by_saddr(int s, in_addr_t multiaddr, in_addr_t interface) { struct ip_mreq mreq; int ret; @@ -77,10 +78,34 @@ static void igmp_join(int s, in_addr_t m } } +static void igmp_join_by_if_name(int s, in_addr_t multicast, + const char *if_name) +{ + struct ip_mreqn mreq = {}; + int if_index; + int ret; + + if_index = if_nametoindex(if_name); + if (!if_index) { + perror("if_nametoindex"); + exit(1); + } + + mreq.imr_multiaddr.s_addr = multicast; + mreq.imr_ifindex = if_index; + + ret = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + if (ret) { + perror("setsockopt() IP_ADD_MEMBERSHIP"); + exit(1); + } +} + int main(int argc, char *argv[]) { struct sockaddr_in stLocal, stFrom; unsigned char achIn[BUFSIZE]; + const char *if_name; int s, i; int iTmp, iRet; int ipnum = 0; @@ -131,6 +156,17 @@ int main(int argc, char *argv[]) ii++; ipnum++; } + } else if (strcmp(argv[ii], "-I") == 0) { + ii++; + if (ii < argc) { + if (if_name) { + printf("Single interface expected\n"); + exit(1); + } + + if_name = argv[ii]; + ii++; + } } else if (strcmp(argv[ii], "-n") == 0) { ii++; NUM = 1; @@ -167,11 +203,16 @@ int main(int argc, char *argv[]) } /* join the multicast group. */ - if (!ipnum) { /* single interface */ - igmp_join(s, inet_addr(TEST_ADDR), INADDR_ANY); + if (if_name) { + igmp_join_by_if_name(s, inet_addr(TEST_ADDR), if_name); } else { - for (i = 0; i < ipnum; i++) { - igmp_join(s, inet_addr(TEST_ADDR), IP[i]); + if (!ipnum) { /* single interface */ + igmp_join_by_saddr(s, inet_addr(TEST_ADDR), INADDR_ANY); + } else { + for (i = 0; i < ipnum; i++) { + igmp_join_by_saddr(s, inet_addr(TEST_ADDR), + IP[i]); + } } }