/** * Process a newly received IGMP packet that is sitting in the input * packet buffer. */ void acceptIgmp(int recvlen) { register uint32_t src, dst, group; struct ip *ip; struct igmp *igmp; struct igmpv3_report *igmpv3; struct igmpv3_grec *grec; int ipdatalen, iphdrlen, ngrec, nsrcs; if (recvlen < sizeof(struct ip)) { my_log(LOG_WARNING, 0, "received packet too short (%u bytes) for IP header", recvlen); return; } ip = (struct ip *)recv_buf; src = ip->ip_src.s_addr; dst = ip->ip_dst.s_addr; /* filter local multicast 239.255.255.250 */ if (dst == htonl(0xEFFFFFFA)) { my_log(LOG_NOTICE, 0, "The IGMP message was local multicast. Ignoring."); return; } /* * this is most likely a message from the kernel indicating that * a new src grp pair message has arrived and so, it would be * necessary to install a route into the kernel for this. */ if (ip->ip_p == 0) { if (src == 0 || dst == 0) { my_log(LOG_WARNING, 0, "kernel request not accurate"); } else { struct IfDesc *checkVIF; // Check if the source address matches a valid address on upstream vif. checkVIF = getIfByIx( upStreamVif ); if(checkVIF == 0) { my_log(LOG_ERR, 0, "Upstream VIF was null."); return; } else if(src == checkVIF->InAdr.s_addr) { my_log(LOG_NOTICE, 0, "Route activation request from %s for %s is from myself. Ignoring.", inetFmt(src, s1), inetFmt(dst, s2)); return; } else if(!isAdressValidForIf(checkVIF, src)) { my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.", inetFmt(src, s1), inetFmt(dst, s2)); return; } // Activate the route. my_log(LOG_DEBUG, 0, "Route activate request from %s to %s", inetFmt(src,s1), inetFmt(dst,s2)); activateRoute(dst, src); } return; } iphdrlen = ip->ip_hl << 2; ipdatalen = ip_data_len(ip); if (iphdrlen + ipdatalen != recvlen) { my_log(LOG_WARNING, 0, "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)", inetFmt(src, s1), recvlen, iphdrlen, ipdatalen); return; } igmp = (struct igmp *)(recv_buf + iphdrlen); if ((ipdatalen < IGMP_MINLEN) || (igmp->igmp_type == IGMP_V3_MEMBERSHIP_REPORT && ipdatalen <= IGMPV3_MINLEN)) { my_log(LOG_WARNING, 0, "received IP data field too short (%u bytes) for IGMP, from %s", ipdatalen, inetFmt(src, s1)); return; } my_log(LOG_NOTICE, 0, "RECV %s from %-15s to %s", igmpPacketKind(igmp->igmp_type, igmp->igmp_code), inetFmt(src, s1), inetFmt(dst, s2) ); switch (igmp->igmp_type) { case IGMP_V1_MEMBERSHIP_REPORT: case IGMP_V2_MEMBERSHIP_REPORT: group = igmp->igmp_group.s_addr; acceptGroupReport(src, group, igmp->igmp_type); return; case IGMP_V3_MEMBERSHIP_REPORT: igmpv3 = (struct igmpv3_report *)(recv_buf + iphdrlen); grec = &igmpv3->igmp_grec[0]; ngrec = ntohs(igmpv3->igmp_ngrec); while (ngrec--) { if ((uint8_t *)igmpv3 + ipdatalen < (uint8_t *)grec + sizeof(*grec)) break; group = grec->grec_mca.s_addr; nsrcs = ntohs(grec->grec_nsrcs); switch (grec->grec_type) { case IGMPV3_MODE_IS_INCLUDE: case IGMPV3_CHANGE_TO_INCLUDE: if (nsrcs == 0) { acceptLeaveMessage(src, group); break; } /* else fall through */ case IGMPV3_MODE_IS_EXCLUDE: case IGMPV3_CHANGE_TO_EXCLUDE: case IGMPV3_ALLOW_NEW_SOURCES: acceptGroupReport(src, group, IGMP_V2_MEMBERSHIP_REPORT); break; case IGMPV3_BLOCK_OLD_SOURCES: break; default: my_log(LOG_INFO, 0, "ignoring unknown IGMPv3 group record type %x from %s to %s for %s", grec->grec_type, inetFmt(src, s1), inetFmt(dst, s2), inetFmt(group, s3)); break; } grec = (struct igmpv3_grec *) (&grec->grec_src[nsrcs] + grec->grec_auxwords * 4); } return; case IGMP_V2_LEAVE_GROUP: group = igmp->igmp_group.s_addr; acceptLeaveMessage(src, group); return; case IGMP_MEMBERSHIP_QUERY: return; default: my_log(LOG_INFO, 0, "ignoring unknown IGMP message type %x from %s to %s", igmp->igmp_type, inetFmt(src, s1), inetFmt(dst, s2)); return; } }
/** * Process a newly received IGMP packet that is sitting in the input * packet buffer. */ void acceptIgmp(int recvlen) { register uint32_t src, dst, group; struct ip *ip; struct igmp *igmp; int ipdatalen, iphdrlen, igmpdatalen; if (recvlen < sizeof(struct ip)) { my_log(LOG_WARNING, 0, "received packet too short (%u bytes) for IP header", recvlen); return; } ip = (struct ip *)recv_buf; src = ip->ip_src.s_addr; dst = ip->ip_dst.s_addr; /* * this is most likely a message from the kernel indicating that * a new src grp pair message has arrived and so, it would be * necessary to install a route into the kernel for this. */ if (ip->ip_p == 0) { if (src == 0 || dst == 0) { my_log(LOG_WARNING, 0, "kernel request not accurate"); } else { struct IfDesc *checkVIF; // Check if the source address matches a valid address on upstream vif. checkVIF = getIfByIx( upStreamVif ); if(checkVIF == 0) { my_log(LOG_ERR, 0, "Upstream VIF was null."); return; } else if(src == checkVIF->InAdr.s_addr) { my_log(LOG_NOTICE, 0, "Route activation request from %s for %s is from myself. Ignoring.", inetFmt(src, s1), inetFmt(dst, s2)); return; } /* else if(!isAdressValidForIf(checkVIF, src)) { my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.", inetFmt(src, s1), inetFmt(dst, s2)); return; }*/ // Activate the route. my_log(LOG_DEBUG, 0, "Route activate request from %s to %s", inetFmt(src,s1), inetFmt(dst,s2)); activateRoute(dst, src); } return; } iphdrlen = ip->ip_hl << 2; ipdatalen = ip_data_len(ip); if (iphdrlen + ipdatalen != recvlen) { my_log(LOG_WARNING, 0, "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)", inetFmt(src, s1), recvlen, iphdrlen, ipdatalen); return; } igmp = (struct igmp *)(recv_buf + iphdrlen); group = igmp->igmp_group.s_addr; igmpdatalen = ipdatalen - IGMP_MINLEN; if (igmpdatalen < 0) { my_log(LOG_WARNING, 0, "received IP data field too short (%u bytes) for IGMP, from %s", ipdatalen, inetFmt(src, s1)); return; } my_log(LOG_NOTICE, 0, "RECV %s from %-15s to %s", igmpPacketKind(igmp->igmp_type, igmp->igmp_code), inetFmt(src, s1), inetFmt(dst, s2) ); switch (igmp->igmp_type) { case IGMP_V1_MEMBERSHIP_REPORT: case IGMP_V2_MEMBERSHIP_REPORT: acceptGroupReport(src, group, igmp->igmp_type); return; case IGMP_V2_LEAVE_GROUP: acceptLeaveMessage(src, group); return; case IGMP_MEMBERSHIP_QUERY: return; default: my_log(LOG_INFO, 0, "ignoring unknown IGMP message type %x from %s to %s", igmp->igmp_type, inetFmt(src, s1), inetFmt(dst, s2)); return; } }