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>