Annotation of embedaddon/igmpproxy/src/igmp.c, revision 1.1

1.1     ! misho       1: /*
        !             2: **  igmpproxy - IGMP proxy based multicast router 
        !             3: **  Copyright (C) 2005 Johnny Egeland <johnny@rlo.org>
        !             4: **
        !             5: **  This program is free software; you can redistribute it and/or modify
        !             6: **  it under the terms of the GNU General Public License as published by
        !             7: **  the Free Software Foundation; either version 2 of the License, or
        !             8: **  (at your option) any later version.
        !             9: **
        !            10: **  This program is distributed in the hope that it will be useful,
        !            11: **  but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            12: **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            13: **  GNU General Public License for more details.
        !            14: **
        !            15: **  You should have received a copy of the GNU General Public License
        !            16: **  along with this program; if not, write to the Free Software
        !            17: **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
        !            18: **
        !            19: **----------------------------------------------------------------------------
        !            20: **
        !            21: **  This software is derived work from the following software. The original
        !            22: **  source code has been modified from it's original state by the author
        !            23: **  of igmpproxy.
        !            24: **
        !            25: **  smcroute 0.92 - Copyright (C) 2001 Carsten Schill <carsten@cschill.de>
        !            26: **  - Licensed under the GNU General Public License, version 2
        !            27: **  
        !            28: **  mrouted 3.9-beta3 - COPYRIGHT 1989 by The Board of Trustees of 
        !            29: **  Leland Stanford Junior University.
        !            30: **  - Original license can be found in the Stanford.txt file.
        !            31: **
        !            32: */
        !            33: /**
        !            34: *   igmp.h - Recieves IGMP requests, and handle them 
        !            35: *            appropriately...
        !            36: */
        !            37: 
        !            38: #include "igmpproxy.h"
        !            39:  
        !            40: // Globals                  
        !            41: uint32_t     allhosts_group;          /* All hosts addr in net order */
        !            42: uint32_t     allrouters_group;          /* All hosts addr in net order */
        !            43:               
        !            44: extern int MRouterFD;
        !            45: 
        !            46: /*
        !            47:  * Open and initialize the igmp socket, and fill in the non-changing
        !            48:  * IP header fields in the output packet buffer.
        !            49:  */
        !            50: void initIgmp() {
        !            51:     struct ip *ip;
        !            52: 
        !            53:     recv_buf = malloc(RECV_BUF_SIZE);
        !            54:     send_buf = malloc(RECV_BUF_SIZE);
        !            55: 
        !            56:     k_hdr_include(true);    /* include IP header when sending */
        !            57:     k_set_rcvbuf(256*1024,48*1024); /* lots of input buffering        */
        !            58:     k_set_ttl(1);       /* restrict multicasts to one hop */
        !            59:     k_set_loop(false);      /* disable multicast loopback     */
        !            60: 
        !            61:     ip         = (struct ip *)send_buf;
        !            62:     memset(ip, 0, sizeof(struct ip));
        !            63:     /*
        !            64:      * Fields zeroed that aren't filled in later:
        !            65:      * - IP ID (let the kernel fill it in)
        !            66:      * - Offset (we don't send fragments)
        !            67:      * - Checksum (let the kernel fill it in)
        !            68:      */
        !            69:     ip->ip_v   = IPVERSION;
        !            70:     ip->ip_hl  = sizeof(struct ip) >> 2;
        !            71:     ip->ip_tos = 0xc0;      /* Internet Control */
        !            72:     ip->ip_ttl = MAXTTL;    /* applies to unicasts only */
        !            73:     ip->ip_p   = IPPROTO_IGMP;
        !            74: 
        !            75:     allhosts_group   = htonl(INADDR_ALLHOSTS_GROUP);
        !            76:     allrouters_group = htonl(INADDR_ALLRTRS_GROUP);
        !            77: }
        !            78: 
        !            79: /**
        !            80: *   Finds the textual name of the supplied IGMP request.
        !            81: */
        !            82: char *igmpPacketKind(u_int type, u_int code) {
        !            83:     static char unknown[20];
        !            84: 
        !            85:     switch (type) {
        !            86:     case IGMP_MEMBERSHIP_QUERY:     return  "Membership query  ";
        !            87:     case IGMP_V1_MEMBERSHIP_REPORT:  return "V1 member report  ";
        !            88:     case IGMP_V2_MEMBERSHIP_REPORT:  return "V2 member report  ";
        !            89:     case IGMP_V2_LEAVE_GROUP:        return "Leave message     ";
        !            90:     
        !            91:     default:
        !            92:         sprintf(unknown, "unk: 0x%02x/0x%02x    ", type, code);
        !            93:         return unknown;
        !            94:     }
        !            95: }
        !            96: 
        !            97: 
        !            98: /**
        !            99:  * Process a newly received IGMP packet that is sitting in the input
        !           100:  * packet buffer.
        !           101:  */
        !           102: void acceptIgmp(int recvlen) {
        !           103:     register uint32_t src, dst, group;
        !           104:     struct ip *ip;
        !           105:     struct igmp *igmp;
        !           106:     int ipdatalen, iphdrlen, igmpdatalen;
        !           107: 
        !           108:     if (recvlen < sizeof(struct ip)) {
        !           109:         my_log(LOG_WARNING, 0,
        !           110:             "received packet too short (%u bytes) for IP header", recvlen);
        !           111:         return;
        !           112:     }
        !           113: 
        !           114:     ip        = (struct ip *)recv_buf;
        !           115:     src       = ip->ip_src.s_addr;
        !           116:     dst       = ip->ip_dst.s_addr;
        !           117: 
        !           118:     /* 
        !           119:      * this is most likely a message from the kernel indicating that
        !           120:      * a new src grp pair message has arrived and so, it would be 
        !           121:      * necessary to install a route into the kernel for this.
        !           122:      */
        !           123:     if (ip->ip_p == 0) {
        !           124:         if (src == 0 || dst == 0) {
        !           125:             my_log(LOG_WARNING, 0, "kernel request not accurate");
        !           126:         }
        !           127:         else {
        !           128:             struct IfDesc *checkVIF;
        !           129:             
        !           130:             // Check if the source address matches a valid address on upstream vif.
        !           131:             checkVIF = getIfByIx( upStreamVif );
        !           132:             if(checkVIF == 0) {
        !           133:                 my_log(LOG_ERR, 0, "Upstream VIF was null.");
        !           134:                 return;
        !           135:             } 
        !           136:             else if(src == checkVIF->InAdr.s_addr) {
        !           137:                 my_log(LOG_NOTICE, 0, "Route activation request from %s for %s is from myself. Ignoring.",
        !           138:                     inetFmt(src, s1), inetFmt(dst, s2));
        !           139:                 return;
        !           140:             }
        !           141:             else if(!isAdressValidForIf(checkVIF, src)) {
        !           142:                 my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.",
        !           143:                     inetFmt(src, s1), inetFmt(dst, s2));
        !           144:                 return;
        !           145:             }
        !           146:             
        !           147:             // Activate the route.
        !           148:             my_log(LOG_DEBUG, 0, "Route activate request from %s to %s",
        !           149:                    inetFmt(src,s1), inetFmt(dst,s2));
        !           150:             activateRoute(dst, src);
        !           151:             
        !           152: 
        !           153:         }
        !           154:         return;
        !           155:     }
        !           156: 
        !           157:     iphdrlen  = ip->ip_hl << 2;
        !           158:     ipdatalen = ip_data_len(ip);
        !           159: 
        !           160:     if (iphdrlen + ipdatalen != recvlen) {
        !           161:         my_log(LOG_WARNING, 0,
        !           162:             "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
        !           163:             inetFmt(src, s1), recvlen, iphdrlen, ipdatalen);
        !           164:         return;
        !           165:     }
        !           166: 
        !           167:     igmp        = (struct igmp *)(recv_buf + iphdrlen);
        !           168:     group       = igmp->igmp_group.s_addr;
        !           169:     igmpdatalen = ipdatalen - IGMP_MINLEN;
        !           170:     if (igmpdatalen < 0) {
        !           171:         my_log(LOG_WARNING, 0,
        !           172:             "received IP data field too short (%u bytes) for IGMP, from %s",
        !           173:             ipdatalen, inetFmt(src, s1));
        !           174:         return;
        !           175:     }
        !           176: 
        !           177:     my_log(LOG_NOTICE, 0, "RECV %s from %-15s to %s",
        !           178:         igmpPacketKind(igmp->igmp_type, igmp->igmp_code),
        !           179:         inetFmt(src, s1), inetFmt(dst, s2) );
        !           180: 
        !           181:     switch (igmp->igmp_type) {
        !           182:     case IGMP_V1_MEMBERSHIP_REPORT:
        !           183:     case IGMP_V2_MEMBERSHIP_REPORT:
        !           184:         acceptGroupReport(src, group, igmp->igmp_type);
        !           185:         return;
        !           186:     
        !           187:     case IGMP_V2_LEAVE_GROUP:
        !           188:         acceptLeaveMessage(src, group);
        !           189:         return;
        !           190:     
        !           191:     case IGMP_MEMBERSHIP_QUERY:
        !           192:         return;
        !           193: 
        !           194:     default:
        !           195:         my_log(LOG_INFO, 0,
        !           196:             "ignoring unknown IGMP message type %x from %s to %s",
        !           197:             igmp->igmp_type, inetFmt(src, s1),
        !           198:             inetFmt(dst, s2));
        !           199:         return;
        !           200:     }
        !           201: }
        !           202: 
        !           203: 
        !           204: /*
        !           205:  * Construct an IGMP message in the output packet buffer.  The caller may
        !           206:  * have already placed data in that buffer, of length 'datalen'.
        !           207:  */
        !           208: void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
        !           209:     struct ip *ip;
        !           210:     struct igmp *igmp;
        !           211:     extern int curttl;
        !           212: 
        !           213:     ip                      = (struct ip *)send_buf;
        !           214:     ip->ip_src.s_addr       = src;
        !           215:     ip->ip_dst.s_addr       = dst;
        !           216:     ip_set_len(ip, MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen);
        !           217: 
        !           218:     if (IN_MULTICAST(ntohl(dst))) {
        !           219:         ip->ip_ttl = curttl;
        !           220:     } else {
        !           221:         ip->ip_ttl = MAXTTL;
        !           222:     }
        !           223: 
        !           224:     igmp                    = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
        !           225:     igmp->igmp_type         = type;
        !           226:     igmp->igmp_code         = code;
        !           227:     igmp->igmp_group.s_addr = group;
        !           228:     igmp->igmp_cksum        = 0;
        !           229:     igmp->igmp_cksum        = inetChksum((u_short *)igmp,
        !           230:                                          IGMP_MINLEN + datalen);
        !           231: }
        !           232: 
        !           233: /* 
        !           234:  * Call build_igmp() to build an IGMP message in the output packet buffer.
        !           235:  * Then send the message from the interface with IP address 'src' to
        !           236:  * destination 'dst'.
        !           237:  */
        !           238: void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
        !           239:     struct sockaddr_in sdst;
        !           240:     int setloop = 0, setigmpsource = 0;
        !           241: 
        !           242:     buildIgmp(src, dst, type, code, group, datalen);
        !           243: 
        !           244:     if (IN_MULTICAST(ntohl(dst))) {
        !           245:         k_set_if(src);
        !           246:         setigmpsource = 1;
        !           247:         if (type != IGMP_DVMRP || dst == allhosts_group) {
        !           248:             setloop = 1;
        !           249:             k_set_loop(true);
        !           250:         }
        !           251:     }
        !           252: 
        !           253:     memset(&sdst, 0, sizeof(sdst));
        !           254:     sdst.sin_family = AF_INET;
        !           255: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        !           256:     sdst.sin_len = sizeof(sdst);
        !           257: #endif
        !           258:     sdst.sin_addr.s_addr = dst;
        !           259:     if (sendto(MRouterFD, send_buf,
        !           260:                MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen, 0,
        !           261:                (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
        !           262:         if (errno == ENETDOWN)
        !           263:             my_log(LOG_ERR, errno, "Sender VIF was down.");
        !           264:         else
        !           265:             my_log(LOG_INFO, errno,
        !           266:                 "sendto to %s on %s",
        !           267:                 inetFmt(dst, s1), inetFmt(src, s2));
        !           268:     }
        !           269: 
        !           270:     if(setigmpsource) {
        !           271:         if (setloop) {
        !           272:             k_set_loop(false);
        !           273:         }
        !           274:         // Restore original...
        !           275:         k_set_if(INADDR_ANY);
        !           276:     }
        !           277: 
        !           278:     my_log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
        !           279:            igmpPacketKind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
        !           280:            inetFmt(src, s1), inetFmt(dst, s2));
        !           281: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>