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* config.c - Contains functions to load and parse config 35* file, and functions to configure the daemon. 36*/ 37 38#include "defs.h" 39 40// Structure to keep configuration for VIFs... 41struct vifconfig { 42 char* name; 43 short state; 44 int ratelimit; 45 int threshold; 46 47 // Keep allowed nets for VIF. 48 struct SubnetList* allowednets; 49 50 // Next config in list... 51 struct vifconfig* next; 52}; 53 54// Structure to keep vif configuration 55struct vifconfig* vifconf; 56 57// Keeps common settings... 58#ifdef USE_ATH_HEADER 59struct Config commonConfig; 60#else 61static struct Config commonConfig; 62#endif 63 64// Prototypes... 65struct vifconfig *parsePhyintToken(); 66struct SubnetList *parseSubnetAddress(char *addrstr); 67 68 69/** 70* Initializes common config.. 71*/ 72void initCommonConfig() { 73#ifdef USE_ATH_HEADER 74 commonConfig.mode = 1; 75#endif 76 commonConfig.robustnessValue = DEFAULT_ROBUSTNESS; 77 commonConfig.queryInterval = INTERVAL_QUERY; 78 commonConfig.queryResponseInterval = INTERVAL_QUERY_RESPONSE; 79 80 // The defaults are calculated from other settings. 81 commonConfig.startupQueryInterval = INTERVAL_QUERY;//(unsigned int)(INTERVAL_QUERY / 4); 82 commonConfig.startupQueryCount = DEFAULT_ROBUSTNESS; 83 84 // Default values for leave intervals... 85 commonConfig.lastMemberQueryInterval = INTERVAL_QUERY_RESPONSE; 86 commonConfig.lastMemberQueryCount = DEFAULT_ROBUSTNESS; 87 88 // If 1, a leave message is sent upstream on leave messages from downstream. 89 commonConfig.fastUpstreamLeave = 0; 90 91} 92 93/** 94* Returns a pointer to the common config... 95*/ 96struct Config *getCommonConfig() { 97 return &commonConfig; 98} 99 100/** 101* Loads the configuration from file, and stores the config in 102* respective holders... 103*/ 104int loadConfig(char *configFile) { 105 struct vifconfig *tmpPtr; 106 struct vifconfig **currPtr = &vifconf; 107 char *token; 108 109 // Initialize common config 110 initCommonConfig(); 111 112 // Test config file reader... 113 if(!openConfigFile(configFile)) { 114 igmp_syslog(LOG_ERR, 0, "Unable to open configfile from %s", configFile); 115 } 116 117 // Get first token... 118 token = nextConfigToken(); 119 if(token == NULL) { 120 igmp_syslog(LOG_ERR, 0, "Config file was empty."); 121 } 122 123 // Loop until all configuration is read. 124 while ( token != NULL ) { 125 // Check token... 126 if(strcmp("phyint", token)==0) { 127 // Got a phyint token... Call phyint parser 128 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: Got a phyint token."); 129 tmpPtr = parsePhyintToken(); 130 if(tmpPtr == NULL) { 131 // Unparsable token... Exit... 132 closeConfigFile(); 133 igmp_syslog(LOG_WARNING, 0, "Unknown token '%s' in configfile", token); 134 return 0; 135 } else { 136 137 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "IF name : %s", tmpPtr->name); 138 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Next ptr : %x", tmpPtr->next); 139 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Ratelimit : %d", tmpPtr->ratelimit); 140 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Threshold : %d", tmpPtr->threshold); 141 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "State : %d", tmpPtr->state); 142 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Allowednet ptr : %x", tmpPtr->allowednets); 143 144 // Insert config, and move temppointer to next location... 145 *currPtr = tmpPtr; 146 currPtr = &tmpPtr->next; 147 } 148 } 149 else if(strcmp("quickleave", token)==0) { 150 // Got a quickleave token.... 151 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: Quick leave mode enabled."); 152 commonConfig.fastUpstreamLeave = 1; 153 154 // Read next token... 155 token = nextConfigToken(); 156 continue; 157#ifdef USE_ATH_HEADER 158 }else if(strcmp("mode", token)==0) { 159 // Got a mode token... 160 token = nextConfigToken(); 161 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: set mode to '%s'.", token); 162 commonConfig.mode = atoi( token ); 163 164 // Read next token... 165 token = nextConfigToken(); 166 continue; 167#endif 168 } else { 169 // Unparsable token... Exit... 170 closeConfigFile(); 171 igmp_syslog(LOG_WARNING, 0, "Unknown token '%s' in configfile", token); 172 return 0; 173 } 174 // Get token that was not recognized by phyint parser. 175 token = getCurrentConfigToken(); 176 } 177 178 // Close the configfile... 179 closeConfigFile(); 180 181 return 1; 182} 183 184/** 185* Appends extra VIF configuration from config file. 186*/ 187void configureVifs() { 188 unsigned Ix; 189 struct IfDesc *Dp; 190 struct vifconfig *confPtr; 191 192 // If no config is availible, just return... 193 if(vifconf == NULL) { 194 return; 195 } 196 197 // Loop through all VIFs... 198 for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) { 199 if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) { 200 201 // Now try to find a matching config... 202 for( confPtr = vifconf; confPtr; confPtr = confPtr->next) { 203 204 // I the VIF names match... 205 if(strcmp(Dp->Name, confPtr->name)==0) { 206 struct SubnetList *vifLast; 207 208 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Found config for %s", Dp->Name); 209 210 211 // Set the VIF state 212 Dp->state = confPtr->state; 213 214 Dp->threshold = confPtr->threshold; 215 Dp->ratelimit = confPtr->ratelimit; 216 217 // Go to last allowed net on VIF... 218 for(vifLast = Dp->allowednets; vifLast->next; vifLast = vifLast->next); 219 220 // Insert the configured nets... 221 vifLast->next = confPtr->allowednets; 222 223 break; 224 } 225 } 226 } 227 } 228} 229 230 231/** 232* Internal function to parse phyint config 233*/ 234struct vifconfig *parsePhyintToken() { 235 struct vifconfig *tmpPtr; 236 struct SubnetList **anetPtr; 237 char *token; 238 short parseError = 0; 239 240 // First token should be the interface name.... 241 token = nextConfigToken(); 242 243 // Sanitycheck the name... 244 if(token == NULL) return NULL; 245 if(strlen(token) >= sizeof( ((struct ifreq *)NULL)->ifr_name) ) return NULL; 246 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: IF: Config for interface %s.", token); 247 248 // Allocate memory for configuration... 249 tmpPtr = (struct vifconfig*)malloc(sizeof(struct vifconfig)); 250 if(tmpPtr == NULL) { 251 igmp_syslog(LOG_ERR, 0, "Out of memory."); 252 } 253 254 // Set default values... 255 tmpPtr->next = NULL; // Important to avoid seg fault... 256 tmpPtr->ratelimit = 0; 257 tmpPtr->threshold = 1; 258 tmpPtr->state = IF_STATE_DOWNSTREAM; 259 tmpPtr->allowednets = NULL; 260 261 // Make a copy of the token to store the IF name 262 tmpPtr->name = (char *)malloc( sizeof(char) * strlen(token) ); 263 if(tmpPtr->name == NULL) { 264 igmp_syslog(LOG_ERR, 0, "Out of memory."); 265 } 266 strcpy(tmpPtr->name, token); 267 268 // Set the altnet pointer to the allowednets pointer. 269 anetPtr = &tmpPtr->allowednets; 270 271 // Parse the rest of the config.. 272 token = nextConfigToken(); 273 while(token != NULL) { 274 if(strcmp("altnet", token)==0) { 275 // Altnet... 276 //struct in_addr networkAddr; /* moved this avoid warning */ 277 278 token = nextConfigToken(); 279 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: IF: Got altnet token %s.",token); 280 281 *anetPtr = parseSubnetAddress(token); 282 if(*anetPtr == NULL) { 283 parseError = 1; 284 igmp_syslog(LOG_WARNING, 0, "Unable to parse subnet address."); 285 break; 286 } else { 287 anetPtr = &(*anetPtr)->next; 288 } 289 } 290 else if(strcmp("upstream", token)==0) { 291 // Upstream 292 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: IF: Got upstream token."); 293 tmpPtr->state = IF_STATE_UPSTREAM; 294 } 295 else if(strcmp("downstream", token)==0) { 296 // Downstream 297 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: IF: Got downstream token."); 298 tmpPtr->state = IF_STATE_DOWNSTREAM; 299 } 300 else if(strcmp("disabled", token)==0) { 301 // Disabled 302 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: IF: Got disabled token."); 303 tmpPtr->state = IF_STATE_DISABLED; 304 } 305 else if(strcmp("ratelimit", token)==0) { 306 // Ratelimit 307 token = nextConfigToken(); 308 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: IF: Got ratelimit token '%s'.", token); 309 tmpPtr->ratelimit = atoi( token ); 310 if(tmpPtr->ratelimit < 0) { 311 igmp_syslog(LOG_WARNING, 0, "Ratelimit must be 0 or more."); 312 parseError = 1; 313 break; 314 } 315 } 316 else if(strcmp("threshold", token)==0) { 317 // Threshold 318 token = nextConfigToken(); 319 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: IF: Got threshold token '%s'.", token); 320 tmpPtr->threshold = atoi( token ); 321 if(tmpPtr->threshold <= 0 || tmpPtr->threshold > 255) { 322 igmp_syslog(LOG_WARNING, 0, "Threshold must be between 1 and 255."); 323 parseError = 1; 324 break; 325 } 326 } 327 else { 328 // Unknown token. Break... 329 break; 330 } 331 token = nextConfigToken(); 332 } 333 334 // Clean up after a parseerror... 335 if(parseError) { 336 free(tmpPtr); 337 tmpPtr = NULL; 338 } 339 340 return tmpPtr; 341} 342 343/** 344* Parses a subnet address string on the format 345* a.b.c.d/n into a SubnetList entry. 346*/ 347struct SubnetList *parseSubnetAddress(char *addrstr) { 348 struct SubnetList *tmpSubnet; 349 char *tmpStr; 350 uint32 addr = 0x00000000; 351 uint32 mask = 0xFFFFFFFF; 352 353 // First get the network part of the address... 354 tmpStr = strtok(addrstr, "/"); 355 addr = inet_addr(tmpStr); 356 357 tmpStr = strtok(NULL, "/"); 358 if(tmpStr != NULL) { 359 int bitcnt = atoi(tmpStr); 360 if(bitcnt <= 0 || bitcnt > 32) { 361 igmp_syslog(LOG_WARNING, 0, "The bits part of the address is invalid : %d.",tmpStr); 362 return NULL; 363 } 364 365 mask <<= (32 - bitcnt); 366 } 367 368 if(addr == -1 || addr == 0) { 369 igmp_syslog(LOG_WARNING, 0, "Unable to parse address token '%s'.", addrstr); 370 return NULL; 371 } 372 373 tmpSubnet = (struct SubnetList*) malloc(sizeof(struct SubnetList)); 374 tmpSubnet->subnet_addr = addr; 375 tmpSubnet->subnet_mask = ntohl(mask); 376 tmpSubnet->next = NULL; 377 378 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "Config: IF: Altnet: Parsed altnet to %s.", 379 inetFmts(tmpSubnet->subnet_addr, tmpSubnet->subnet_mask,s1)); 380 381 return tmpSubnet; 382} 383 384