#!/usr/bin/perl # author : Petr Simandl www.simandl.cz # rewrite to Perl: Jan Spitalnik www.spitalnik.net # release date : 29/08/2004 # name : sedlo # description : dynamic side routing tables tool # license : GPL # TODO: # 2) add logging :-) create some convenience fnc that can store either to STDOUT or file # 3) pridat podporu pro deamonize - default time je 5minut use strict; use LWP::UserAgent; use Fcntl qw(:DEFAULT :flock); use Getopt::Long; use Pod::Usage; use Storable; # Main config files my($sedlo_config) = "/etc/sedlo.conf"; my($sedlo_spool_dir) = "/var/cache/sedlo/"; my($sedlo_spool_config) = "sedlo.conf"; # iproute2 config files my($rttables_config) = "/etc/iproute2/rt_tables"; my($rttables_min) = 110; my($rttables_max) = 200; my($ip_nodef) = "10.0.0.0/8"; # Logging # 0 = no logging, 1 = basic logging, 2 = extensive logging my($debug_level) = 0; ################################################# ############# DON'T MODIFY BELOW ################ ################################################# # define version use constant VERSION => "0.0.3"; # define error codes use constant E_MISSING_CMD => -1; # missing command use constant E_MISSING_CFG => -2; # missing configuration file use constant E_MISSING_MCNF => -3; # missing mcnf stanza in main config. file use constant E_NONET => -4; # Problems with network communication use constant E_CREATSPOOL => -5; # Problems creating spool directory use constant E_INVSTANZA => -6; # Invalid stanza in config. file use constant E_MISC => -7; # Other kind of error use constant E_OK => 0; # Everything is OK use constant TRUE => 1; # All's OK use constant FALSE => 0; # Baaad # Commands my($IP_CMD) = get_command("ip"); # Check config files check_configs($sedlo_config, $rttables_config); # Where is main cfg file? my($main_cfg_url) = get_main_cfg_url($sedlo_config); # Parse command line my($opt_show_version) = 0; my($opt_show_help) = 0; my($opt_show_report) = 0; my($opt_no_get_cfg) = 0; my($opt_info1) = 0; my($opt_info2) = 0; Getopt::Long::Configure("bundling"); GetOptions('version|v' => \$opt_show_version, 'help|h' => \$opt_show_help, 'report|r' => \$opt_show_report, 'nogetcfg|n' => \$opt_no_get_cfg, 'info1|1' => \$opt_info1, 'info2|2' => \$opt_info2); parse_cmd_line(); # create spool directory create_spool_dir($sedlo_spool_dir); if(not $opt_no_get_cfg) { # Download main config. file get_main_config(); } # Merge main config with local config merge_main_and_local_config(); # Remove duplicates from spool config file remove_dups_from_config(); # Create routing tables create_tables(); # Fill routing tables fill_tables(); # Fill routing rules fill_rules(); ################### Util Functions ########################## # Name: fill_rules() # Desc: Fills routing tables with rules # Param: none sub fill_rules() { my(%IPs) = ret_IPs(); my(@iGW_array); my(@cmd_out); my($IP); my($iGW); foreach $IP (keys(%IPs)) { @iGW_array = @{ Storable::thaw($IPs{$IP}) }; my($we_added_this_entry) = FALSE; foreach $iGW (@iGW_array) { if($iGW =~ /^$/) { next; } # Check for existing entries @cmd_out = `$IP_CMD route ls table $iGW 2>&1`; if($! == 0 && $we_added_this_entry == FALSE) { my($has_entry) = TRUE; # Remove any existing entries while($has_entry) { @cmd_out = `$IP_CMD rule ls 2>&1`; my($tmp_line); $has_entry = FALSE; foreach $tmp_line (@cmd_out) { if($tmp_line =~ /$IP/) { $has_entry = TRUE; } } if($has_entry) { if($debug_level > 1) { print "Info: Removing old rules for $IP.\n"; } @cmd_out = `$IP_CMD rule del from $IP 2>&1`; @cmd_out = `$IP_CMD rule del from $IP to $ip_nodef 2>&1`; } } if ($debug_level > 1) { print "Info: Creating new rules to send $IP to table $iGW.\n"; } # Add new rules @cmd_out = `$IP_CMD rule add from $IP lookup $iGW 2>&1`; @cmd_out = `$IP_CMD rule add from $IP to $ip_nodef lookup main 2>&1`; $we_added_this_entry = TRUE; } else { if($debug_level > 1) { if($we_added_this_entry) { print "Info: iGW '$iGW' with lower priority!\n"; } else { print "Info: Non-existant table!\n"; } } } } } } # Name: ret_IPs() # Desc: Returns hash of IP containing array of iGWs as value. # Param: none sub ret_IPs() { open(SEDLO_SPOOL_CONFIG, "< $sedlo_spool_dir$sedlo_spool_config") or die("Error: Can't open $sedlo_spool_dir$sedlo_spool_config!\n"); flock(SEDLO_SPOOL_CONFIG, LOCK_SH); my($line); my(%IPs); while($line = ) { chomp($line); if($line =~ m/^ip\s+/) { my(@iGWs) = split(/\s/, $line); # Remove ^ip shift(@iGWs); # Store IP address my($IP) = $iGWs[0]; # Remove IP address shift(@iGWs); # Remove name of subnet shift(@iGWs); $IPs{$IP} = Storable::freeze(\@iGWs); } } close(SEDLO_SPOOL_CONFIG); return %IPs; } # Name: fill_tables() # Desc: Fills routing tables # Param: none sub fill_tables() { my(%iGWs) = get_iGWs_with_IPs(); my($iGW); my($iGW_IP); my($iGW_name); my($iGW_via); my(@cmd_tmp); foreach $iGW (keys %iGWs) { $iGW_IP = $iGW; $iGW_name = $iGWs{$iGW}; @cmd_tmp = `$IP_CMD route ls 2>&1`; my($line); foreach $line (@cmd_tmp) { if($line =~ /$iGW_IP\s+via\s+(\w+)/) { $iGW_via = $1; } } @cmd_tmp = `$IP_CMD route ls table $iGW_name 2>&1`; if($! != 0) { @cmd_tmp=`$IP_CMD route flush table $iGW_name 2>&1`; } if(not defined $iGW_via) { if($debug_level > 1) { print "Info: Route not found for iGW $iGW_name - leaving table empty.\n"; } } else { @cmd_tmp=`$IP_CMD route add 0.0.0.0/1 via $iGW_via table $iGW_name 2>&1`; @cmd_tmp=`$IP_CMD route add 128.0.0.0/1 via $iGW_via table $iGW_name 2>&1`; if($debug_level > 1) { print "Info: Table filled for iGW $iGW_name.\n"; } } } } # Name: create_tables() # Desc: Creates routing tables # Parm: none sub create_tables() { my(@iGWs) = get_iGWs(); my($iGW); foreach $iGW (@iGWs) { if(not ret_rttb_config_entry($iGW, 2)) { my($count) = $rttables_max; while($count != $rttables_min) { if(not ret_rttb_config_entry($count, 1)) { open(RTTABLES_CONFIG, ">> $rttables_config") or die("Error: Can't open $rttables_config!\n"); flock(RTTABLES_CONFIG, LOCK_SH); print RTTABLES_CONFIG "$count\t$iGW\n"; close(RTTABLES_CONFIG); $count = $rttables_min; next; } $count--; } } else { if($debug_level > 1) { print "Table found for $iGW, no action taken.\n"; } } } } # Name: ret_rttb_config_entry() # Desc: Returns true/false if found routing table config entry for given IP/Hostname # Second parameter says whether you want to match against cost (1) or against # name of the table (2) # Parm: string, int sub ret_rttb_config_entry() { my($entry, $type) = @_; open(RTTABLES_CONFIG, "< $rttables_config") or die("Error: Can't open $rttables_config!\n"); flock(RTTABLES_CONFIG, LOCK_SH); my($line); while($line = ) { chomp($line); # Cost if($type == 1) { if($line =~ /^$entry\s+\w+/) { return TRUE; } } # Name of table elsif($type == 2) { if($line =~ /^\w+\s+$entry/) { return TRUE; } } else { print "Error: Invalid argument to ret_rttb_config_entry()!\n"; exit(E_MISC); } } close(RTTABLES_CONFIG); return FALSE; } # Name: get_iGWs() # Desc: Returns iGWs from config. file # Parm: none sub get_iGWs() { my(@iGWs); open(SEDLO_SPOOL_CONFIG, "< $sedlo_spool_dir$sedlo_spool_config") or die("Error: Can't open $sedlo_spool_dir$sedlo_spool_config!\n"); flock(SEDLO_SPOOL_CONFIG, LOCK_SH); my($line); while($line = ) { chomp($line); if($line =~ /^igw\s+(.*)\s+(.*)/) { push(@iGWs, $2); } } close(SEDLO_SPOOL_CONFIG); return @iGWs; } # Name: get_iGWs_with_IPs() # Desc: Returns iGWs with IPs from config. file # Parm: none sub get_iGWs_with_IPs() { my(%iGWs); open(SEDLO_SPOOL_CONFIG, "< $sedlo_spool_dir$sedlo_spool_config") or die("Error: Can't open $sedlo_spool_dir$sedlo_spool_config!\n"); flock(SEDLO_SPOOL_CONFIG, LOCK_SH); my($line); while($line = ) { chomp($line); if($line =~ /^igw\s+(.*)\s+(.*)/) { $iGWs{$1} = $2; } } close(SEDLO_SPOOL_CONFIG); return %iGWs; } # Name: parse_cmd_line() # Desc: Parses command line options # Param: none sub parse_cmd_line() { if($opt_show_version) { print "$0 ".VERSION."\n"; exit(E_OK); } elsif($opt_show_help) { show_help(); exit(E_OK); } elsif($opt_show_report) { show_report(); exit(E_OK); } elsif($opt_info1) { $debug_level = 1; } elsif($opt_info2) { $debug_level = 2; } } # Name: show_report() # Desc: Prints routing tables and rules # Param: none sub show_report() { print "##### SEDLO #####\n"; print "Version:".VERSION."\n"; print "local config: $sedlo_config\n"; print "main config: $main_cfg_url\n"; print "##### TABLES #####\n"; open(RTTABLES, "< $rttables_config") or die("Can't open $rttables_config!\n"); flock(RTTABLES, LOCK_SH); my($line); while($line = ) { print $line; } close(RTTABLES); print "##### RULES #####\n"; my(@cmd_out) = `$IP_CMD rule ls 2>&1`; foreach $line (@cmd_out) { print $line; } } # Name: show_help() # Desc: Prints help screen # Param: none sub show_help() { pod2usage(1); } # Name: create_spool_dir() # Desc: Creates spool dir if not present # Param: string sub create_spool_dir() { my($spool_dir) = @_; if(not -e $spool_dir) { if(not mkdir($spool_dir)) { print "Error: Can't create spool dir in $spool_dir!\n"; exit(E_CREATSPOOL); } } } # Name: get_main_config() # Desc: Downloads configuration file # Param: string sub get_main_config() { my($user_agent) = LWP::UserAgent->new; my($request); my($response); $user_agent->agent("Sedlo/".VERSION); $request = HTTP::Request->new(GET => $main_cfg_url); $response = $user_agent->request($request); if($response->is_error) { print "Error: Can't download $main_cfg_url!\n"; exit(E_NONET); } # sedlo.config.main open(SEDLO_CONFIG_MAIN, ">$sedlo_spool_dir$sedlo_spool_config.main") or die("Error: Can't open $sedlo_spool_dir$sedlo_spool_config.main"); flock(SEDLO_CONFIG_MAIN, LOCK_EX); print SEDLO_CONFIG_MAIN $response->content; close(SEDLO_CONFIG_MAIN); } # Name: merge_main_and_local_config() # Desc: Merges main and local configuration files # Param: none sub merge_main_and_local_config() { my($file); my(@config_files) = ($sedlo_config, $sedlo_spool_dir.$sedlo_spool_config.".main"); open(SEDLO_SPOOL_CONFIG, ">>$sedlo_spool_dir$sedlo_spool_config") or die("Error: Can't open $sedlo_spool_dir$sedlo_spool_config!\n"); flock(SEDLO_SPOOL_CONFIG, LOCK_EX); foreach $file (@config_files) { open(DATA, "< $file") or die("Error: Can't open $file!\n"); flock(DATA, LOCK_SH); my($line); while($line = ) { if($line =~ /^mcnf\s+/) { print SEDLO_SPOOL_CONFIG "$line"; } elsif($line =~ /^igw\s+/) { print SEDLO_SPOOL_CONFIG "$line"; } elsif($line =~ /^ip\s+/) { print SEDLO_SPOOL_CONFIG "$line"; } elsif($line =~ /^\#/ or $line =~ /^\s+$/ or $line =~ /^$/) { next; } else { print "Error: Invalid stanza in $file!\n"; print "Trace -->$line<--\n"; exit(E_INVSTANZA); } } close(DATA); } close(SEDLO_SPOOL_CONFIG); } # Name: remove_dups_from_config # Desc: Removes duplicate lines from spool config # Param: none sub remove_dups_from_config() { # Now lets dump duplicate entries in $SEDLO_SPOOL_CONFIG open(SEDLO_SPOOL_CONFIG, "< $sedlo_spool_dir$sedlo_spool_config") or die("Error: Can't open $sedlo_spool_dir$sedlo_spool_config!\n"); flock(SEDLO_SPOOL_CONFIG, LOCK_SH); my($line); my(%uniq); while($line = ) { if($line !~ /^\#/) { $uniq{$line} = TRUE; } } close(SEDLO_SPOOL_CONFIG); open(SEDLO_SPOOL_CONFIG, "> $sedlo_spool_dir$sedlo_spool_config") or die("Error: Can't open $sedlo_spool_dir$sedlo_spool_config!\n"); flock(SEDLO_SPOOL_CONFIG, LOCK_SH); print SEDLO_SPOOL_CONFIG "# generated file\n"; print SEDLO_SPOOL_CONFIG keys(%uniq); close(SEDLO_SPOOL_CONFIG); } # Name: get_main_cfg_url() # Desc: Returns URL of main config file # Param: string sub get_main_cfg_url() { my($sedlo_conf) = @_; my($line); my($cfg_file); open(SEDLO_CFG, "< $sedlo_conf") or die("Error: Can't open $sedlo_conf!\n"); while($line = ) { if($line =~ /^mcnf\s+(.*)/) { $cfg_file = $1; } } if (not defined $cfg_file) { print "Error: Can't find 'mcnf' stanza in config file!\n"; exit(E_MISSING_MCNF); } else { return $cfg_file; } } # Name: check_configs() # Desc: Check for existance of configuration files # Param: string, string sub check_configs() { my($sedlo_config, $rttables_config) = @_; if (not -e $sedlo_config) { print "Error: Missing configuration file '$sedlo_config'!\n"; exit(E_MISSING_CFG); } if (not -e $rttables_config) { print "Error: Missing configuration file '$rttables_config'!\n"; exit(E_MISSING_CFG); } } # Name: get_command() # Desc: Returns path for specified command # Param: string sub get_command() { my($command) = @_; my($path) = "PATH=/bin:/sbin:/usr/bin:/usr/sbin:usr/local/bin:/usr/local/sbin"; my($cmd_path) = `$path which $command`; chomp($cmd_path); if ($cmd_path =~ /not found/) { print "Error: can't find '$command' in \$PATH!\n"; exit(E_MISSING_CMD); } return $cmd_path; } __END__ =head1 NAME sedlo - Program na nastavovani default routy podle danych pravidel =head1 SYNOPSIS sedlo [options] =head1 OPTIONS =over 8 =item B<--version, -v> Vypise verzi programu =item B<--help, -h> Vypise tuto napovedu =item B<--report, -r> Vypise prehled pravidel a tabulek =item B<--nogetcfg, -n> Zajisti ze se nedude znovu nacitat konfigurace a pouzije se predchozi z cache =item B<--info1, -1> Nastavi upovidanost na 1 (malo). =item B<--info2, -2> Nastavi upovidanost na 2 (hodne). =back =head1 DESCRIPTIOn B stahne hlavni seznam a spolecne s lokalnim seznamem pravidel nastavi default routy pro jednotlive podsite tak, jak jsou zaznamenany v konfiguracnim souboru. Jeho hlavni vyuziti je v prostredi, kde je vice ISP a pouziva se dynamicke routovani (OSPF). (This documentation is crap ;-) If you feel adventurous send patches :-) =cut WebSVN - sedlo - Blame - Rev 5 - /branches/sedlo.pl
  jablonka.czprosek.czf

sedlo

Subversion Repositories:
[/] [branches/] [sedlo.pl] - Blame information for rev 5

 

Line No. Rev Author Line

Powered by WebSVN 2.2.1