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#include "defs.h" 35#include <linux/sockios.h> 36#ifdef USE_ATH_HEADER 37#include <sys/ioctl.h> 38#include <fcntl.h> 39#include <unistd.h> 40#endif 41 42 43struct IfDesc IfDescVc[ MAX_IF ], *IfDescEp = IfDescVc; 44 45/* 46** Builds up a vector with the interface of the machine. Calls to the other functions of 47** the module will fail if they are called before the vector is build. 48** 49*/ 50void buildIfVc() { 51 struct ifreq IfVc[ sizeof( IfDescVc ) / sizeof( IfDescVc[ 0 ] ) ]; 52 struct ifreq *IfEp; 53 54 int Sock; 55 56 if ( (Sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) 57 igmp_syslog( LOG_ERR, errno, "RAW socket open" ); 58 59 /* get If vector 60 */ 61 { 62 struct ifconf IoCtlReq; 63 64 IoCtlReq.ifc_buf = (void *)IfVc; 65 IoCtlReq.ifc_len = sizeof( IfVc ); 66 67 if ( ioctl( Sock, SIOCGIFCONF, &IoCtlReq ) < 0 ) 68 igmp_syslog( LOG_ERR, errno, "ioctl SIOCGIFCONF" ); 69 70 IfEp = (void *)((char *)IfVc + IoCtlReq.ifc_len); 71 } 72 73 /* loop over interfaces and copy interface info to IfDescVc 74 */ 75 { 76 struct ifreq *IfPt; 77 //struct IfDesc *IfDp; 78 79 // Temp keepers of interface params... 80 uint32 addr, subnet, mask; 81 82 for ( IfPt = IfVc; IfPt < IfEp; IfPt++ ) { 83 struct ifreq IfReq; 84 char FmtBu[ 32 ]; 85 86 strncpy( IfDescEp->Name, IfPt->ifr_name, sizeof( IfDescEp->Name ) ); 87 88 // Currently don't set any allowed nets... 89 //IfDescEp->allowednets = NULL; 90 91 // Set the index to -1 by default. 92 IfDescEp->index = -1; 93 94 /* don't retrieve more info for non-IP interfaces 95 */ 96 if ( IfPt->ifr_addr.sa_family != AF_INET ) { 97 IfDescEp->InAdr.s_addr = 0; /* mark as non-IP interface */ 98 IfDescEp++; 99 continue; 100 } 101 102 // Get the interface adress... 103 IfDescEp->InAdr = ((struct sockaddr_in *)&IfPt->ifr_addr)->sin_addr; 104 addr = IfDescEp->InAdr.s_addr; 105 106 memcpy( IfReq.ifr_name, IfDescEp->Name, sizeof( IfReq.ifr_name ) ); 107 108 // Get the subnet mask... 109 if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0) 110 igmp_syslog(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name); 111 mask = ((struct sockaddr_in *)&IfReq.ifr_addr)->sin_addr.s_addr; 112 subnet = addr & mask; 113 114 // Get the physical index of the Interface 115 if (ioctl(Sock, SIOCGIFINDEX, &IfReq ) < 0) 116 igmp_syslog(LOG_ERR, errno, "ioctl SIOCGIFINDEX for %s", IfReq.ifr_name); 117 118 igmp_syslog(LOG_DEBUG, 0, "Physical Index value of IF '%s' is %d", 119 IfDescEp->Name, IfReq.ifr_ifindex); 120 121 122 /* get if flags 123 ** 124 ** typical flags: 125 ** lo 0x0049 -> Running, Loopback, Up 126 ** ethx 0x1043 -> Multicast, Running, Broadcast, Up 127 ** ipppx 0x0091 -> NoArp, PointToPoint, Up 128 ** grex 0x00C1 -> NoArp, Running, Up 129 ** ipipx 0x00C1 -> NoArp, Running, Up 130 */ 131 if ( ioctl( Sock, SIOCGIFFLAGS, &IfReq ) < 0 ) 132 igmp_syslog( LOG_ERR, errno, "ioctl SIOCGIFFLAGS" ); 133 134 IfDescEp->Flags = IfReq.ifr_flags; 135 136 // Insert the verified subnet as an allowed net... 137 IfDescEp->allowednets = (struct SubnetList *)malloc(sizeof(struct SubnetList)); 138 if(IfDescEp->allowednets == NULL) igmp_syslog(LOG_ERR, 0, "Out of memory !"); 139 140 // Create the network address for the IF.. 141 IfDescEp->allowednets->next = NULL; 142 IfDescEp->allowednets->subnet_mask = mask; 143 IfDescEp->allowednets->subnet_addr = subnet; 144 145 // Set the default params for the IF... 146 IfDescEp->state = IF_STATE_DOWNSTREAM; 147 IfDescEp->robustness = DEFAULT_ROBUSTNESS; 148 IfDescEp->threshold = DEFAULT_THRESHOLD; /* ttl limit */ 149 IfDescEp->ratelimit = DEFAULT_RATELIMIT; 150 151 152 // Debug igmp_syslog the result... 153 IF_DEBUG igmp_syslog( LOG_DEBUG, 0, "buildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s", 154 IfDescEp->Name, 155 fmtInAdr( FmtBu, IfDescEp->InAdr ), 156 IfDescEp->Flags, 157 inetFmts(subnet,mask, s1)); 158 159 IfDescEp++; 160 } 161 } 162 163 close( Sock ); 164} 165 166#ifdef USE_ATH_HEADER 167int 168initSnoopBr() 169{ 170 unsigned Ix; 171 struct IfDesc *Dp; 172 173 // Join the all routers group on downstream vifs... 174 for (Ix = 0; (Dp = getIfByIx(Ix)); Ix++) { 175 // If this is a downstream vif, we should join the All routers group... 176 if ((Dp->state == IF_STATE_DOWNSTREAM) 177 && Dp->InAdr.s_addr && !(Dp->Flags & IFF_LOOPBACK)){ 178 179 addVIF(Dp); 180 181#if 0 182 joinMcGroup(confFD /*getMcGroupSock()*/, Dp, allrouters_group); 183 IF_DEBUG log(LOG_DEBUG, 0, "Joining all-routers group %s on vif %s", 184 inetFmt(allrouters_group, s1), 185 inetFmt(Dp->InAdr.s_addr, s2)); 186#endif 187 188 } 189 } 190 191 return 0; 192} 193 194int 195clearSnoopBr() 196{ 197 unsigned Ix; 198 struct IfDesc *Dp; 199 200 // Join the all routers group on downstream vifs... 201 for (Ix = 0; (Dp = getIfByIx(Ix)); Ix++) { 202 // If this is a downstream vif, we should join the All routers group... 203 if ((Dp->state == IF_STATE_DOWNSTREAM) 204 && Dp->InAdr.s_addr && !(Dp->Flags & IFF_LOOPBACK)){ 205 206 //delVIF(Dp); 207 Dp->state = IF_STATE_DISABLED; 208 209#if 0 210 leaveMcGroup(confFD /*getMcGroupSock()*/, Dp, allrouters_group); 211 IF_DEBUG log(LOG_DEBUG, 0, "Leaving all-routers group %s on vif %s", 212 inetFmt(allrouters_group, s1), 213 inetFmt(Dp->InAdr.s_addr, s2)); 214#endif 215 216 } 217 } 218 219 return 0; 220} 221#endif 222 223/* 224** Returns a pointer to the IfDesc of the interface 'IfName' 225** 226** returns: - pointer to the IfDesc of the requested interface 227** - NULL if no interface 'IfName' exists 228** 229*/ 230struct IfDesc *getIfByName( const char *IfName ) { 231 struct IfDesc *Dp; 232 233 for ( Dp = IfDescVc; Dp < IfDescEp; Dp++ ) 234 if ( ! strcmp( IfName, Dp->Name ) ) 235 return Dp; 236 237 return NULL; 238} 239 240/* 241** Returns a pointer to the IfDesc of the interface 'Ix' 242** 243** returns: - pointer to the IfDesc of the requested interface 244** - NULL if no interface 'Ix' exists 245** 246*/ 247struct IfDesc *getIfByIx( unsigned Ix ) { 248 struct IfDesc *Dp = &IfDescVc[ Ix ]; 249 return Dp < IfDescEp ? Dp : NULL; 250} 251 252/** 253* Returns a pointer to the IfDesc whose subnet matches 254* the supplied IP adress. The IP must match a interfaces 255* subnet, or any configured allowed subnet on a interface. 256*/ 257struct IfDesc *getIfByAddress( uint32 ipaddr ) { 258 259 struct IfDesc *Dp; 260 struct SubnetList *currsubnet; 261 262 for ( Dp = IfDescVc; Dp < IfDescEp; Dp++ ) { 263 // Loop through all registered allowed nets of the VIF... 264 for(currsubnet = Dp->allowednets; currsubnet != NULL; currsubnet = currsubnet->next) { 265 // Check if the ip falls in under the subnet.... 266 if((ipaddr & currsubnet->subnet_mask) == currsubnet->subnet_addr) { 267 return Dp; 268 } 269 } 270 } 271 return NULL; 272} 273 274 275/** 276* Returns a pointer to the IfDesc whose subnet matches 277* the supplied IP adress. The IP must match a interfaces 278* subnet, or any configured allowed subnet on a interface. 279*/ 280struct IfDesc *getIfByVifIndex( unsigned vifindex ) { 281 struct IfDesc *Dp; 282 if(vifindex>0) { 283 for ( Dp = IfDescVc; Dp < IfDescEp; Dp++ ) { 284 if(Dp->index == vifindex) { 285 return Dp; 286 } 287 } 288 } 289 return NULL; 290} 291 292 293/** 294* Function that checks if a given ipaddress is a valid 295* address for the supplied VIF. 296*/ 297int isAdressValidForIf( struct IfDesc* intrface, uint32 ipaddr ) { 298 struct SubnetList *currsubnet; 299 300 if(intrface == NULL) { 301 return 0; 302 } 303 // Loop through all registered allowed nets of the VIF... 304 for(currsubnet = intrface->allowednets; currsubnet != NULL; currsubnet = currsubnet->next) { 305 306 /* 307 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Testing %s for subnet %s, mask %s: Result net: %s", 308 inetFmt(ipaddr, s1), 309 inetFmt(currsubnet->subnet_addr, s2), 310 inetFmt(currsubnet->subnet_mask, s3), 311 inetFmt((ipaddr & currsubnet->subnet_mask), s4) 312 ); 313 */ 314 315 // Check if the ip falls in under the subnet.... 316 if((ipaddr & currsubnet->subnet_mask) == currsubnet->subnet_addr) { 317 return 1; 318 } 319 } 320 return 0; 321} 322 323 324