Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions doc/igmpproxy.conf.5.in
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ the risk of bandwidth saturation.
.RE


.B proto
.I protover
.RS
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


.B phyint
.I interface
.I role
Expand Down Expand Up @@ -187,6 +198,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
Expand Down
20 changes: 20 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -221,6 +224,23 @@ int loadConfig(char *configFile) {
my_log(LOG_DEBUG, 0, "Config: user set to %s", commonConfig.user);
token = nextConfigToken();
continue;
}
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();
continue;
} else {
// Unparsable token... Exit...
closeConfigFile();
Expand Down
36 changes: 26 additions & 10 deletions src/igmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,15 +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 igmp *igmp;
struct igmpv3_query *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_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;
Expand All @@ -282,14 +289,24 @@ 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_query *)(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);

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);
}
Comment on lines +302 to +307
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have stored query length in the query_minlen variable. So you can move inetChksum code outside of the if and call it based on the query_minlen.


return IP_HEADER_RAOPT_LEN + query_minlen + datalen;
}

/*
Expand All @@ -301,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);
Expand All @@ -320,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_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.");
Expand Down
2 changes: 2 additions & 0 deletions src/igmpproxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions src/igmpv3.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@
* igmpv3.h - Header file for common IGMPv3 includes.
*/

/*
* IGMP v3 query format.
*/
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 */
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[0]; /* source addresses */
};

struct igmpv3_grec {
u_int8_t grec_type;
u_int8_t grec_auxwords;
Expand Down
1 change: 1 addition & 0 deletions src/os-linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <linux/mroute.h>

#define IGMP_V3_MEMBERSHIP_REPORT 0x22
#define IGMP_V3_QUERY_MINLEN IGMPV3_MINLEN

#define INADDR_ALLIGMPV3_GROUP ((in_addr_t) 0xe0000016)

Expand Down