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 "doc/mrouted-LINCESE" file. 31** 32*/ 33/** 34* mroute-api.c 35* 36* This module contains the interface routines to the Linux mrouted API 37*/ 38 39 40#define USE_LINUX_IN_H 41#include "defs.h" 42#ifdef USE_ATH_HEADER 43#include <unistd.h> 44#endif 45 46 47// MAX_MC_VIFS from mclab.h must have same value as MAXVIFS from mroute.h 48#if MAX_MC_VIFS != MAXVIFS 49# error "constants don't match, correct mclab.h" 50#endif 51 52// need an IGMP socket as interface for the mrouted API 53// - receives the IGMP messages 54int MRouterFD; /* socket for all network I/O */ 55char *recv_buf; /* input packet buffer */ 56char *send_buf; /* output packet buffer */ 57int recv_len; 58 59 60// my internal virtual interfaces descriptor vector 61static struct VifDesc { 62 struct IfDesc *IfDp; 63} VifDescVc[ MAXVIFS ]; 64 65 66 67/* 68** Initialises the mrouted API and locks it by this exclusively. 69** 70** returns: - 0 if the functions succeeds 71** - the errno value for non-fatal failure condition 72*/ 73int enableMRouter() 74{ 75 int Va = 1; 76 77 if ( (MRouterFD = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0 ) 78 igmp_syslog( LOG_ERR, errno, "IGMP socket open" ); 79 80 if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_INIT, 81 (void *)&Va, sizeof( Va ) ) ) 82 return errno; 83 84 return 0; 85} 86 87/* 88** Diables the mrouted API and relases by this the lock. 89** 90*/ 91void disableMRouter() 92{ 93 if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_DONE, NULL, 0 ) 94 || close( MRouterFD ) 95 ) { 96 MRouterFD = 0; 97 igmp_syslog( LOG_ERR, errno, "MRT_DONE/close" ); 98 } 99 100 MRouterFD = 0; 101} 102 103/* 104** Adds the interface '*IfDp' as virtual interface to the mrouted API 105** 106*/ 107void addVIF( struct IfDesc *IfDp ) 108{ 109 struct vifctl VifCtl; 110 struct VifDesc *VifDp; 111 112 /* search free VifDesc 113 */ 114 for ( VifDp = VifDescVc; VifDp < VCEP( VifDescVc ); VifDp++ ) { 115 if ( ! VifDp->IfDp ) 116 break; 117 } 118 119 /* no more space 120 */ 121 if ( VifDp >= VCEP( VifDescVc ) ) 122 igmp_syslog( LOG_ERR, ENOMEM, "addVIF, out of VIF space" ); 123 124 VifDp->IfDp = IfDp; 125 126 VifCtl.vifc_vifi = VifDp - VifDescVc; 127 VifCtl.vifc_flags = 0; /* no tunnel, no source routing, register ? */ 128 VifCtl.vifc_threshold = VifDp->IfDp->threshold; // Packet TTL must be at least 1 to pass them 129 VifCtl.vifc_rate_limit = VifDp->IfDp->ratelimit; // Ratelimit 130 131 VifCtl.vifc_lcl_addr.s_addr = VifDp->IfDp->InAdr.s_addr; 132 VifCtl.vifc_rmt_addr.s_addr = INADDR_ANY; 133 134 // Set the index... 135 VifDp->IfDp->index = VifCtl.vifc_vifi; 136 137 igmp_syslog( LOG_NOTICE, 0, "adding VIF, Ix %d Fl 0x%x IP 0x%08x %s, Threshold: %d, Ratelimit: %d", 138 VifCtl.vifc_vifi, VifCtl.vifc_flags, VifCtl.vifc_lcl_addr.s_addr, VifDp->IfDp->Name, 139 VifCtl.vifc_threshold, VifCtl.vifc_rate_limit); 140 141 IF_DEBUG { 142 struct SubnetList *currSubnet; 143 for(currSubnet = IfDp->allowednets; currSubnet; currSubnet = currSubnet->next) { 144 igmp_syslog(LOG_DEBUG, 0, " Network for [%s] : %s", 145 IfDp->Name, 146 inetFmts(currSubnet->subnet_addr, currSubnet->subnet_mask, s1)); 147 } 148 } 149 150 if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_ADD_VIF, 151 (char *)&VifCtl, sizeof( VifCtl ) ) ) 152 igmp_syslog( LOG_ERR, errno, "MRT_ADD_VIF" ); 153 154} 155 156/* 157** Adds the multicast routed '*Dp' to the kernel routes 158** 159** returns: - 0 if the function succeeds 160** - the errno value for non-fatal failure condition 161*/ 162int addMRoute( struct MRouteDesc *Dp ) 163{ 164 struct mfcctl CtlReq; 165 166 CtlReq.mfcc_origin = Dp->OriginAdr; 167 CtlReq.mfcc_mcastgrp = Dp->McAdr; 168 CtlReq.mfcc_parent = Dp->InVif; 169 170 /* copy the TTL vector 171 */ 172 if ( sizeof( CtlReq.mfcc_ttls ) != sizeof( Dp->TtlVc ) 173 || VCMC( CtlReq.mfcc_ttls ) != VCMC( Dp->TtlVc ) 174 ) 175 igmp_syslog( LOG_ERR, 0, "data types doesn't match in " __FILE__ ", source adaption needed !" ); 176 177 memcpy( CtlReq.mfcc_ttls, Dp->TtlVc, sizeof( CtlReq.mfcc_ttls ) ); 178 179 { 180 char FmtBuO[ 32 ], FmtBuM[ 32 ]; 181 182 igmp_syslog( LOG_NOTICE, 0, "Adding MFC: %s -> %s, InpVIf: %d", 183 fmtInAdr( FmtBuO, CtlReq.mfcc_origin ), 184 fmtInAdr( FmtBuM, CtlReq.mfcc_mcastgrp ), 185 CtlReq.mfcc_parent == ALL_VIFS ? -1 : CtlReq.mfcc_parent 186 ); 187 } 188 189 if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_ADD_MFC, 190 (void *)&CtlReq, sizeof( CtlReq ) ) ) 191 igmp_syslog( LOG_WARNING, errno, "MRT_ADD_MFC" ); 192 193 return 0; 194} 195 196/* 197** Removes the multicast routed '*Dp' from the kernel routes 198** 199** returns: - 0 if the function succeeds 200** - the errno value for non-fatal failure condition 201*/ 202int delMRoute( struct MRouteDesc *Dp ) 203{ 204 struct mfcctl CtlReq; 205 206 CtlReq.mfcc_origin = Dp->OriginAdr; 207 CtlReq.mfcc_mcastgrp = Dp->McAdr; 208 CtlReq.mfcc_parent = Dp->InVif; 209 210 /* clear the TTL vector 211 */ 212 memset( CtlReq.mfcc_ttls, 0, sizeof( CtlReq.mfcc_ttls ) ); 213 214 { 215 char FmtBuO[ 32 ], FmtBuM[ 32 ]; 216 217 igmp_syslog( LOG_NOTICE, 0, "Removing MFC: %s -> %s, InpVIf: %d", 218 fmtInAdr( FmtBuO, CtlReq.mfcc_origin ), 219 fmtInAdr( FmtBuM, CtlReq.mfcc_mcastgrp ), 220 CtlReq.mfcc_parent == ALL_VIFS ? -1 : CtlReq.mfcc_parent 221 ); 222 } 223 224 if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_DEL_MFC, 225 (void *)&CtlReq, sizeof( CtlReq ) ) ) 226 igmp_syslog( LOG_WARNING, errno, "MRT_DEL_MFC" ); 227 return 0; 228} 229 230/* 231** Returns for the virtual interface index for '*IfDp' 232** 233** returns: - the vitrual interface index if the interface is registered 234** - -1 if no virtual interface exists for the interface 235** 236*/ 237int getVifIx( struct IfDesc *IfDp ) 238{ 239 struct VifDesc *Dp; 240 241 for ( Dp = VifDescVc; Dp < VCEP( VifDescVc ); Dp++ ) 242 if ( Dp->IfDp == IfDp ) 243 return Dp - VifDescVc; 244 245 return -1; 246} 247 248#if (DNI_MULTI_LAN_SUPPORT) 249int add_source_list(uint32 mgroup, uint32 src_ip) 250{ 251 struct ip_data 252 { 253 unsigned short family; 254 unsigned long ip; 255 } group, src; 256 union 257 { 258 struct group_req gr; 259 struct group_source_req gsr; 260 } opt; 261 int ret = 0, optlen; 262 263 memset(&opt, 0, sizeof(opt)); 264 group.family = src.family = AF_INET; 265 group.ip = mgroup; 266 src.ip = src_ip; 267 memcpy(&opt.gsr.gsr_source, &src, 8); 268 memcpy(&opt.gsr.gsr_group, &group, 8); 269 optlen = sizeof(opt.gsr); 270 if ((ret =setsockopt(getMcGroupSock(), IPPROTO_IP, MCAST_JOIN_SOURCE_GROUP, (void *)&opt, optlen)) < 0) 271 { 272 DPRINTF("%s :: setsockopt : MCAST_JOIN_SOURCE_GROUP error [%d]\n", __FUNCTION__, ret); 273 ret = 1; 274 } 275 return ret; 276} 277 278int set_source_list(struct RouteTable *croute) 279{ 280 struct ip_msfilter *imsfp = NULL; 281 int i, ret = 0, num = croute->source.num; 282 struct IfDesc *vif; 283 284 imsfp = (struct ip_msfilter *)malloc(IP_MSFILTER_SIZE(num)); 285 if (!imsfp) 286 { 287 DPRINTF("%s :: out of memory...\n", __FUNCTION__); 288 return 1; 289 } 290 memset (imsfp, 0, IP_MSFILTER_SIZE(num)); 291 imsfp->imsf_fmode = (croute->mode == st_is_in)?1:0; 292 imsfp->imsf_numsrc = num; 293 imsfp->imsf_multiaddr = croute->group; 294 for (i = 0; i < num; i++) 295 imsfp->imsf_slist[i] = croute->source.list[i]; 296 297 vif = getIfByIx( upStreamVif ); 298 imsfp->imsf_interface = htonl(vif->InAdr.s_addr); 299 i = IP_MSFILTER_SIZE(num); 300 if ((ret = setsockopt(getMcGroupSock(), IPPROTO_IP, IP_MSFILTER, imsfp,i)) < 0 ) 301 { 302 DPRINTF("%s :: setsockopt : IP_MSFILTER error [%d]\n", __FUNCTION__, ret); 303 ret = 1; 304 } 305 free(imsfp); 306 return ret; 307} 308#endif 309 310