From 92f0bdb15f8e539eccf5cf8726b413b0b2429da2 Mon Sep 17 00:00:00 2001 From: zocker007 Date: Mon, 23 Jan 2023 14:49:41 +0100 Subject: [PATCH 1/7] implemented igmpv3 query sending on downstream interfaces --- src/igmp.c | 12 ++++++++---- src/igmpv3.h | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/igmp.c b/src/igmp.c index a80c4e58..129260c1 100644 --- a/src/igmp.c +++ b/src/igmp.c @@ -262,13 +262,14 @@ void acceptIgmp(int recvlen) { */ static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) { struct ip *ip; - struct igmp *igmp; + struct igmpv3 *igmp; + struct Config *conf = getCommonConfig(); extern int curttl; ip = (struct ip *)send_buf; ip->ip_src.s_addr = src; ip->ip_dst.s_addr = dst; - ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen); + ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMPV3_MINLEN + datalen); if (IN_MULTICAST(ntohl(dst))) { ip->ip_ttl = curttl; @@ -282,13 +283,16 @@ static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t g ((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[2] = 0x00; ((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[3] = 0x00; - igmp = (struct igmp *)(send_buf + IP_HEADER_RAOPT_LEN); + igmp = (struct igmpv3 *)(send_buf + IP_HEADER_RAOPT_LEN); igmp->igmp_type = type; igmp->igmp_code = code; igmp->igmp_group.s_addr = group; igmp->igmp_cksum = 0; igmp->igmp_cksum = inetChksum((unsigned short *)igmp, IP_HEADER_RAOPT_LEN + datalen); + igmp->igmp_misc = conf->robustnessValue & 0x7; + igmp->igmp_qqi = conf->queryInterval; + igmp->igmp_numsrc = 0; } @@ -321,7 +325,7 @@ void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, in #endif sdst.sin_addr.s_addr = dst; if (sendto(MRouterFD, send_buf, - IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen, 0, + IP_HEADER_RAOPT_LEN + IGMPV3_MINLEN + datalen, 0, (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { if (errno == ENETDOWN) my_log(LOG_ERR, errno, "Sender VIF was down."); diff --git a/src/igmpv3.h b/src/igmpv3.h index f8658237..5d1d96ae 100644 --- a/src/igmpv3.h +++ b/src/igmpv3.h @@ -21,6 +21,21 @@ * igmpv3.h - Header file for common IGMPv3 includes. */ +/* + * IGMP v3 query format. + */ +struct igmpv3 { + u_int8_t igmp_type; /* version & type of IGMP message */ + u_int8_t igmp_code; /* subtype for routing msgs */ + u_int16_t igmp_cksum; /* IP-style checksum */ + struct in_addr igmp_group; /* group address being reported */ + /* (zero for queries) */ + u_int8_t igmp_misc; /* reserved/suppress/robustness */ + u_int8_t igmp_qqi; /* querier's query interval */ + u_int16_t igmp_numsrc; /* number of sources */ + /*struct in_addr igmp_sources[1];*/ /* source addresses */ +}; + struct igmpv3_grec { u_int8_t grec_type; u_int8_t grec_auxwords; From e1a0f55f3f1529240d7bdd8aba5b242823212c01 Mon Sep 17 00:00:00 2001 From: Zocker007 Date: Mon, 4 May 2020 00:42:15 +0200 Subject: [PATCH 2/7] fixed checksum calculation --- src/igmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/igmp.c b/src/igmp.c index 129260c1..429b2801 100644 --- a/src/igmp.c +++ b/src/igmp.c @@ -288,11 +288,11 @@ static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t g igmp->igmp_code = code; igmp->igmp_group.s_addr = group; igmp->igmp_cksum = 0; - igmp->igmp_cksum = inetChksum((unsigned short *)igmp, - IP_HEADER_RAOPT_LEN + datalen); igmp->igmp_misc = conf->robustnessValue & 0x7; igmp->igmp_qqi = conf->queryInterval; igmp->igmp_numsrc = 0; + igmp->igmp_cksum = inetChksum((unsigned short *)igmp, + IGMP_V3_QUERY_MINLEN + datalen); } From 846eebf316187842b9213a03898aa545a61e6e71 Mon Sep 17 00:00:00 2001 From: zocker007 Date: Mon, 23 Jan 2023 14:49:48 +0100 Subject: [PATCH 3/7] use define IGMP_V3_QUERY_MINLEN instead of IGMPV3_MINLEN --- src/igmp.c | 4 ++-- src/os-linux.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/igmp.c b/src/igmp.c index 429b2801..0d868322 100644 --- a/src/igmp.c +++ b/src/igmp.c @@ -269,7 +269,7 @@ static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t g ip = (struct ip *)send_buf; ip->ip_src.s_addr = src; ip->ip_dst.s_addr = dst; - ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMPV3_MINLEN + datalen); + ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMP_V3_QUERY_MINLEN + datalen); if (IN_MULTICAST(ntohl(dst))) { ip->ip_ttl = curttl; @@ -325,7 +325,7 @@ void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, in #endif sdst.sin_addr.s_addr = dst; if (sendto(MRouterFD, send_buf, - IP_HEADER_RAOPT_LEN + IGMPV3_MINLEN + datalen, 0, + IP_HEADER_RAOPT_LEN + IGMP_V3_QUERY_MINLEN + datalen, 0, (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { if (errno == ENETDOWN) my_log(LOG_ERR, errno, "Sender VIF was down."); diff --git a/src/os-linux.h b/src/os-linux.h index e0a271d4..bdfbe234 100644 --- a/src/os-linux.h +++ b/src/os-linux.h @@ -8,6 +8,7 @@ #include #define IGMP_V3_MEMBERSHIP_REPORT 0x22 +#define IGMP_V3_QUERY_MINLEN IGMPV3_MINLEN #define INADDR_ALLIGMPV3_GROUP ((in_addr_t) 0xe0000016) From deda7926964d850024e4091d3b233f266d8260ed Mon Sep 17 00:00:00 2001 From: Zocker007 Date: Fri, 18 Feb 2022 22:57:07 +0100 Subject: [PATCH 4/7] add config option to enable IGMPv3 queries --- doc/igmpproxy.conf.5.in | 12 ++++++++++++ src/config.c | 12 ++++++++++++ src/igmpproxy.h | 2 ++ 3 files changed, 26 insertions(+) diff --git a/doc/igmpproxy.conf.5.in b/doc/igmpproxy.conf.5.in index 74378417..076278f9 100644 --- a/doc/igmpproxy.conf.5.in +++ b/doc/igmpproxy.conf.5.in @@ -78,6 +78,15 @@ the risk of bandwidth saturation. .RE +.B igmpv3 +.RS +Enables IGMPv3 queries. On default settings, IGMPv1/2 queries are send out. +With this setting, you can enable IGMPv3 frames for sending queries. This is needed +for IGMPv3 capable hosts to send IGMPv3 reports. When a IGMPv3 capable host receives +a IGMPv1/2 query, it answers with a IGMPv1/2 report. +.RE + + .B phyint .I interface .I role @@ -187,6 +196,9 @@ explicitly whitelisted multicast groups will be ignored. ## Enable quickleave quickleave .br +## Enable IGMPv3 queries instead of IGMPv1/2 +igmpv3 +.br ## Define settings for eth0 (upstream) .br phyint eth0 upstream diff --git a/src/config.c b/src/config.c index eef7f1af..854c2dc7 100644 --- a/src/config.c +++ b/src/config.c @@ -84,6 +84,9 @@ static void initCommonConfig(void) { // If 1, a leave message is sent upstream on leave messages from downstream. commonConfig.fastUpstreamLeave = 0; + // If 1, IGMPv3 queries are send instead of IGMPv1/2 + commonConfig.useIgmpv3 = 0; + // Default size of hash table is 32 bytes (= 256 bits) and can store // up to the 256 non-collision hosts, approximately half of /24 subnet commonConfig.downstreamHostsHashTableSize = 32; @@ -221,6 +224,15 @@ int loadConfig(char *configFile) { my_log(LOG_DEBUG, 0, "Config: user set to %s", commonConfig.user); token = nextConfigToken(); continue; + } + else if(strcmp("igmpv3", token)==0) { + // got an igmpv3 token + my_log(LOG_DEBUG, 0, "Config: IGMPv3 mode enabled."); + commonConfig.useIgmpv3 = 1; + + // Read next token... + token = nextConfigToken(); + continue; } else { // Unparsable token... Exit... closeConfigFile(); diff --git a/src/igmpproxy.h b/src/igmpproxy.h index b8f46a35..96c1eb18 100644 --- a/src/igmpproxy.h +++ b/src/igmpproxy.h @@ -175,6 +175,8 @@ struct Config { unsigned int lastMemberQueryCount; // Set if upstream leave messages should be sent instantly.. unsigned short fastUpstreamLeave; + // Set if IGMPv3 should be used for IGMP queries + unsigned short useIgmpv3; // Size in bytes of hash table of downstream hosts used for fast leave unsigned int downstreamHostsHashTableSize; //~ aimwang added From a2b5c183da887c2321d44a4aa4bda94dc754af6b Mon Sep 17 00:00:00 2001 From: Zocker007 Date: Sat, 19 Feb 2022 00:33:02 +0100 Subject: [PATCH 5/7] send igmpv3 queries only when activated --- src/igmp.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/igmp.c b/src/igmp.c index 0d868322..75d81317 100644 --- a/src/igmp.c +++ b/src/igmp.c @@ -260,16 +260,22 @@ void acceptIgmp(int recvlen) { * Construct an IGMP message in the output packet buffer. The caller may * have already placed data in that buffer, of length 'datalen'. */ -static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) { +static int buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) { struct ip *ip; struct igmpv3 *igmp; struct Config *conf = getCommonConfig(); extern int curttl; + int query_minlen = IGMP_MINLEN; ip = (struct ip *)send_buf; ip->ip_src.s_addr = src; ip->ip_dst.s_addr = dst; - ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMP_V3_QUERY_MINLEN + datalen); + + if(conf->useIgmpv3) { + query_minlen = IGMP_V3_QUERY_MINLEN; + } + + ip_set_len(ip, IP_HEADER_RAOPT_LEN + query_minlen + datalen); if (IN_MULTICAST(ntohl(dst))) { ip->ip_ttl = curttl; @@ -288,12 +294,19 @@ static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t g igmp->igmp_code = code; igmp->igmp_group.s_addr = group; igmp->igmp_cksum = 0; - igmp->igmp_misc = conf->robustnessValue & 0x7; - igmp->igmp_qqi = conf->queryInterval; - igmp->igmp_numsrc = 0; - igmp->igmp_cksum = inetChksum((unsigned short *)igmp, - IGMP_V3_QUERY_MINLEN + datalen); + if(conf->useIgmpv3) { + igmp->igmp_misc = conf->robustnessValue & 0x7; + igmp->igmp_qqi = conf->queryInterval; + igmp->igmp_numsrc = 0; + igmp->igmp_cksum = inetChksum((unsigned short *)igmp, + IGMP_V3_QUERY_MINLEN + datalen); + } else { + igmp->igmp_cksum = inetChksum((unsigned short *)igmp, + IP_HEADER_RAOPT_LEN + datalen); + } + + return IP_HEADER_RAOPT_LEN + query_minlen + datalen; } /* @@ -305,9 +318,9 @@ static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t g */ void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen, int ifidx) { struct sockaddr_in sdst; - int setloop = 0, setigmpsource = 0; + int setloop = 0, setigmpsource = 0, sendlen = 0; - buildIgmp(src, dst, type, code, group, datalen); + sendlen = buildIgmp(src, dst, type, code, group, datalen); if (IN_MULTICAST(ntohl(dst))) { k_set_if(src, ifidx); @@ -324,8 +337,7 @@ void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, in sdst.sin_len = sizeof(sdst); #endif sdst.sin_addr.s_addr = dst; - if (sendto(MRouterFD, send_buf, - IP_HEADER_RAOPT_LEN + IGMP_V3_QUERY_MINLEN + datalen, 0, + if (sendto(MRouterFD, send_buf, sendlen, 0, (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { if (errno == ENETDOWN) my_log(LOG_ERR, errno, "Sender VIF was down."); From 8ecda1895a21bd68ea0ac5450f9adf8f62a4514c Mon Sep 17 00:00:00 2001 From: zocker007 Date: Mon, 23 Jan 2023 14:49:53 +0100 Subject: [PATCH 6/7] changed config option for igmp version selection new 'proto' key for selection of either IGMPv1/v2 or IGMPv3 --- doc/igmpproxy.conf.5.in | 12 +++++++----- src/config.c | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/doc/igmpproxy.conf.5.in b/doc/igmpproxy.conf.5.in index 076278f9..6154b412 100644 --- a/doc/igmpproxy.conf.5.in +++ b/doc/igmpproxy.conf.5.in @@ -78,12 +78,14 @@ the risk of bandwidth saturation. .RE -.B igmpv3 +.B proto +.I protover .RS -Enables IGMPv3 queries. On default settings, IGMPv1/2 queries are send out. -With this setting, you can enable IGMPv3 frames for sending queries. This is needed -for IGMPv3 capable hosts to send IGMPv3 reports. When a IGMPv3 capable host receives -a IGMPv1/2 query, it answers with a IGMPv1/2 report. +Specifies IGMP protocol version. On default or whith 'proto igmpv2', IGMPv1/2 +queries are send out. With 'proto igmpv3', you can enable IGMPv3 frames for +sending queries. This is needed for IGMPv3 capable hosts to send IGMPv3 reports. +When a IGMPv3 capable host receives a IGMPv1/2 query, it answers with a IGMPv1/2 +report. .RE diff --git a/src/config.c b/src/config.c index 854c2dc7..c8a50714 100644 --- a/src/config.c +++ b/src/config.c @@ -225,10 +225,18 @@ int loadConfig(char *configFile) { token = nextConfigToken(); continue; } - else if(strcmp("igmpv3", token)==0) { - // got an igmpv3 token - my_log(LOG_DEBUG, 0, "Config: IGMPv3 mode enabled."); - commonConfig.useIgmpv3 = 1; + else if(strcmp("proto", token)==0) { + // IGMP protocol version to use is in next token + token = nextConfigToken(); + + if (strcmp("igmpv3", token) == 0) { + my_log(LOG_DEBUG, 0, "Config: IGMPv3 mode enabled."); + commonConfig.useIgmpv3 = 1; + } + else if (strcmp("igmpv2", token) == 0) { + my_log(LOG_DEBUG, 0, "Config: IGMPv2 mode enabled."); + commonConfig.useIgmpv3 = 0; + } // Read next token... token = nextConfigToken(); From db55eecd7267cf129feddaa7394117ef1f0eebe7 Mon Sep 17 00:00:00 2001 From: zocker007 Date: Mon, 23 Jan 2023 14:49:59 +0100 Subject: [PATCH 7/7] rename igmpv3 query struct and fix incompl struct --- src/igmp.c | 4 ++-- src/igmpv3.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/igmp.c b/src/igmp.c index 75d81317..7400bd56 100644 --- a/src/igmp.c +++ b/src/igmp.c @@ -262,7 +262,7 @@ void acceptIgmp(int recvlen) { */ static int buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) { struct ip *ip; - struct igmpv3 *igmp; + struct igmpv3_query *igmp; struct Config *conf = getCommonConfig(); extern int curttl; int query_minlen = IGMP_MINLEN; @@ -289,7 +289,7 @@ static int buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t gr ((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[2] = 0x00; ((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[3] = 0x00; - igmp = (struct igmpv3 *)(send_buf + IP_HEADER_RAOPT_LEN); + igmp = (struct igmpv3_query *)(send_buf + IP_HEADER_RAOPT_LEN); igmp->igmp_type = type; igmp->igmp_code = code; igmp->igmp_group.s_addr = group; diff --git a/src/igmpv3.h b/src/igmpv3.h index 5d1d96ae..986b870d 100644 --- a/src/igmpv3.h +++ b/src/igmpv3.h @@ -24,7 +24,7 @@ /* * IGMP v3 query format. */ -struct igmpv3 { +struct igmpv3_query { u_int8_t igmp_type; /* version & type of IGMP message */ u_int8_t igmp_code; /* subtype for routing msgs */ u_int16_t igmp_cksum; /* IP-style checksum */ @@ -33,7 +33,7 @@ struct igmpv3 { u_int8_t igmp_misc; /* reserved/suppress/robustness */ u_int8_t igmp_qqi; /* querier's query interval */ u_int16_t igmp_numsrc; /* number of sources */ - /*struct in_addr igmp_sources[1];*/ /* source addresses */ + struct in_addr igmp_sources[0]; /* source addresses */ }; struct igmpv3_grec {