![]() ![]() |
sedlo |
Subversion Repositories: |
Compare with Previous - Blame - Download
#!/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 5minutuse strict;use LWP::UserAgent;use Fcntl qw(:DEFAULT :flock);use Getopt::Long;use Pod::Usage;use Storable;# Main config filesmy($sedlo_config) = "/etc/sedlo.conf";my($sedlo_spool_dir) = "/var/cache/sedlo/";my($sedlo_spool_config) = "sedlo.conf";# iproute2 config filesmy($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 loggingmy($debug_level) = 0;############################################################## DON'T MODIFY BELOW ################################################################## define versionuse constant VERSION => "0.0.3";# define error codesuse constant E_MISSING_CMD => -1; # missing commanduse constant E_MISSING_CFG => -2; # missing configuration fileuse constant E_MISSING_MCNF => -3; # missing mcnf stanza in main config. fileuse constant E_NONET => -4; # Problems with network communicationuse constant E_CREATSPOOL => -5; # Problems creating spool directoryuse constant E_INVSTANZA => -6; # Invalid stanza in config. fileuse constant E_MISC => -7; # Other kind of erroruse constant E_OK => 0; # Everything is OKuse constant TRUE => 1; # All's OKuse constant FALSE => 0; # Baaad# Commandsmy($IP_CMD) = get_command("ip");# Check config filescheck_configs($sedlo_config, $rttables_config);# Where is main cfg file?my($main_cfg_url) = get_main_cfg_url($sedlo_config);# Parse command linemy($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 directorycreate_spool_dir($sedlo_spool_dir);if(not $opt_no_get_cfg){# Download main config. fileget_main_config();}# Merge main config with local configmerge_main_and_local_config();# Remove duplicates from spool config fileremove_dups_from_config();# Create routing tablescreate_tables();# Fill routing tablesfill_tables();# Fill routing rulesfill_rules();################### Util Functions ########################### Name: fill_rules()# Desc: Fills routing tables with rules# Param: nonesub 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 entrieswhile($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: nonesub 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 = <SEDLO_SPOOL_CONFIG>){chomp($line);if($line =~ m/^ip\s+/){my(@iGWs) = split(/\s/, $line);# Remove ^ipshift(@iGWs);# Store IP addressmy($IP) = $iGWs[0];# Remove IP addressshift(@iGWs);# Remove name of subnetshift(@iGWs);$IPs{$IP} = Storable::freeze(\@iGWs);}}close(SEDLO_SPOOL_CONFIG);return %IPs;}# Name: fill_tables()# Desc: Fills routing tables# Param: nonesub 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: nonesub 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, intsub 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 = <RTTABLES_CONFIG>){chomp($line);# Costif($type == 1){if($line =~ /^$entry\s+\w+/){return TRUE;}}# Name of tableelsif($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: nonesub 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 = <SEDLO_SPOOL_CONFIG>){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: nonesub 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 = <SEDLO_SPOOL_CONFIG>){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: nonesub 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: nonesub 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 = <RTTABLES>){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: nonesub show_help(){pod2usage(1);}# Name: create_spool_dir()# Desc: Creates spool dir if not present# Param: stringsub 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: stringsub 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.mainopen(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: nonesub 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 = <DATA>){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: nonesub remove_dups_from_config(){# Now lets dump duplicate entries in $SEDLO_SPOOL_CONFIGopen(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 = <SEDLO_SPOOL_CONFIG>){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: stringsub 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 = <SEDLO_CFG>){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, stringsub 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: stringsub 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 NAMEsedlo - Program na nastavovani default routy podle danych pravidel=head1 SYNOPSISsedlo [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 DESCRIPTIOnB<Sedlo> stahne hlavni seznam a spolecne s lokalnim seznamem pravidel nastavi default routypro jednotlive podsite tak, jak jsou zaznamenany v konfiguracnim souboru. Jeho hlavni vyuzitije v prostredi, kde je vice ISP a pouziva se dynamicke routovani (OSPF).(This documentation is crap ;-) If you feel adventurous send patches :-)=cut