Annotation of embedaddon/igmpproxy/src/igmp.c, revision 1.1.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>