⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 igmp.c

📁 igmp proxy 实现源码
💻 C
字号:
/***  igmpproxy - IGMP proxy based multicast router **  Copyright (C) 2005 Johnny Egeland <johnny@rlo.org>****  This program is free software; you can redistribute it and/or modify**  it under the terms of the GNU General Public License as published by**  the Free Software Foundation; either version 2 of the License, or**  (at your option) any later version.****  This program is distributed in the hope that it will be useful,**  but WITHOUT ANY WARRANTY; without even the implied warranty of**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the**  GNU General Public License for more details.****  You should have received a copy of the GNU General Public License**  along with this program; if not, write to the Free Software**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA****----------------------------------------------------------------------------****  This software is derived work from the following software. The original**  source code has been modified from it's original state by the author**  of igmpproxy.****  smcroute 0.92 - Copyright (C) 2001 Carsten Schill <carsten@cschill.de>**  - Licensed under the GNU General Public License, version 2**  **  mrouted 3.9-beta3 - COPYRIGHT 1989 by The Board of Trustees of **  Leland Stanford Junior University.**  - Original license can be found in the "doc/mrouted-LINCESE" file.***//***   igmp.h - Recieves IGMP requests, and handle them *            appropriately...*/#include "defs.h" // Globals                  uint32     allhosts_group;          /* All hosts addr in net order */uint32     allrouters_group;          /* All hosts addr in net order */              extern int MRouterFD;/* * Open and initialize the igmp socket, and fill in the non-changing * IP header fields in the output packet buffer. */void initIgmp() {    struct ip *ip;    recv_buf = malloc(RECV_BUF_SIZE);    send_buf = malloc(RECV_BUF_SIZE);    k_hdr_include(TRUE);    /* include IP header when sending */    k_set_rcvbuf(256*1024,48*1024); /* lots of input buffering        */    k_set_ttl(1);       /* restrict multicasts to one hop */    k_set_loop(FALSE);      /* disable multicast loopback     */    ip         = (struct ip *)send_buf;    bzero(ip, sizeof(struct ip));    /*     * Fields zeroed that aren't filled in later:     * - IP ID (let the kernel fill it in)     * - Offset (we don't send fragments)     * - Checksum (let the kernel fill it in)     */    ip->ip_v   = IPVERSION;    ip->ip_hl  = sizeof(struct ip) >> 2;    ip->ip_tos = 0xc0;      /* Internet Control */    ip->ip_ttl = MAXTTL;    /* applies to unicasts only */    ip->ip_p   = IPPROTO_IGMP;    allhosts_group   = htonl(INADDR_ALLHOSTS_GROUP);    allrouters_group = htonl(INADDR_ALLRTRS_GROUP);}/***   Finds the textual name of the supplied IGMP request.*/char *igmpPacketKind(u_int type, u_int code) {    static char unknown[20];    switch (type) {    case IGMP_MEMBERSHIP_QUERY:     return  "Membership query  ";    case IGMP_V1_MEMBERSHIP_REPORT:  return "V1 member report  ";    case IGMP_V2_MEMBERSHIP_REPORT:  return "V2 member report  ";    case IGMP_V2_LEAVE_GROUP:        return "Leave message     ";        default:        sprintf(unknown, "unk: 0x%02x/0x%02x    ", type, code);        return unknown;    }}/** * Process a newly received IGMP packet that is sitting in the input * packet buffer. */void acceptIgmp(int recvlen) {    register uint32 src, dst, group;    struct ip *ip;    struct igmp *igmp;    int ipdatalen, iphdrlen, igmpdatalen;    if (recvlen < sizeof(struct ip)) {        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;    //IF_DEBUG log(LOG_DEBUG, 0, "Got a IGMP request to process...");    /*      * 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) {            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) {                log(LOG_ERR, 0, "Upstream VIF was null.");                return;            }             else if(src == checkVIF->InAdr.s_addr) {                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)) {                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.            IF_DEBUG 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 = ntohs(ip->ip_len) - iphdrlen;    if (iphdrlen + ipdatalen != recvlen) {        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) {        log(LOG_WARNING, 0,            "received IP data field too short (%u bytes) for IGMP, from %s",            ipdatalen, inetFmt(src, s1));        return;    }    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:        //accept_membership_query(src, dst, group, igmp->igmp_code);        return;    */    default:        log(LOG_INFO, 0,            "ignoring unknown IGMP message type %x from %s to %s",            igmp->igmp_type, inetFmt(src, s1),            inetFmt(dst, s2));        return;    }}/* * Construct an IGMP message in the output packet buffer.  The caller may * have already placed data in that buffer, of length 'datalen'. */void buildIgmp(uint32 src, uint32 dst, int type, int code, uint32 group, int datalen) {    struct ip *ip;    struct igmp *igmp;    extern int curttl;    ip                      = (struct ip *)send_buf;    ip->ip_src.s_addr       = src;    ip->ip_dst.s_addr       = dst;    ip->ip_len              = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;    ip->ip_len              = htons(ip->ip_len);    if (IN_MULTICAST(ntohl(dst))) {        ip->ip_ttl = curttl;    } else {        ip->ip_ttl = MAXTTL;    }    igmp                    = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);    igmp->igmp_type         = type;    igmp->igmp_code         = code;    igmp->igmp_group.s_addr = group;    igmp->igmp_cksum        = 0;    igmp->igmp_cksum        = inetChksum((u_short *)igmp,                                         IGMP_MINLEN + datalen);}/*  * Call build_igmp() to build an IGMP message in the output packet buffer. * Then send the message from the interface with IP address 'src' to * destination 'dst'. */void sendIgmp(uint32 src, uint32 dst, int type, int code, uint32 group, int datalen) {    struct sockaddr_in sdst;    int setloop = 0, setigmpsource = 0;    buildIgmp(src, dst, type, code, group, datalen);    if (IN_MULTICAST(ntohl(dst))) {        k_set_if(src);        setigmpsource = 1;        if (type != IGMP_DVMRP || dst == allhosts_group) {            setloop = 1;            k_set_loop(TRUE);        }    }    bzero(&sdst, sizeof(sdst));    sdst.sin_family = AF_INET;#ifdef HAVE_SA_LEN    sdst.sin_len = sizeof(sdst);#endif    sdst.sin_addr.s_addr = dst;    if (sendto(MRouterFD, send_buf,               MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen, 0,               (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {        if (errno == ENETDOWN)            log(LOG_ERR, errno, "Sender VIF was down.");        else            log(LOG_INFO, errno,                "sendto to %s on %s",                inetFmt(dst, s1), inetFmt(src, s2));    }    if(setigmpsource) {        if (setloop) {            k_set_loop(FALSE);        }        // Restore original...        k_set_if(INADDR_ANY);    }    IF_DEBUG log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",        igmpPacketKind(type, code), src == INADDR_ANY ? "INADDR_ANY" :        inetFmt(src, s1), inetFmt(dst, s2));}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -