#!/usr/bin/perl use strict; use warnings; use Getopt::Long qw(:config no_ignore_case bundling); use Net::Telnet::Cisco; use FileHandle; use Term::ReadKey; use Config::Tiny; $|=1; #! #! my $version="0.07"; my $version_date="07/22/03"; #! #! #Get command line options my $ln_group=""; my $ln_router=""; my $user_name=""; my $password=""; my $input_file=""; my $output_file=""; my $flag_help=0; my $flag_version=0; my $command=""; GetOptions( 'r=s'=>\$ln_router, 'router=s'=>\$ln_router, 'g=s'=>\$ln_group, 'group=s'=>\$ln_group, 'u=s'=>\$user_name, 'username=s'=>\$user_name, 'p=s'=>\$password, 'password=s'=>\$password, 'i=s'=>\$input_file, 'input=s'=>\$input_file, 'o=s'=>\$output_file, 'output=s'=>\$output_file, 'c=s'=>\$command, 'command=s'=>\$command, 'h'=>\$flag_help, 'help'=>\$flag_help, 'v'=>\$flag_version, 'version'=>\$flag_version, ); #Validate command line options #my @commands=(); #if ($command ne "") #{ # $commands[0]="first array"; # push (@commands,$command); # my $line=""; # foreach $line (@commands) # { # print $line . "\n"; # } #} #exit 0; if ($flag_help) { #List Options print STDOUT "Batch Router - the batch router configurator\n"; print STDOUT "\n"; print STDOUT "List of options and their functions:\n"; print STDOUT "-r --router \t Specify a single router name from the config file, overides -g/--group.\n"; print STDOUT "-g --group \t Specify a single group of routers from the config file.\n"; print STDOUT "-u --username \t Specifies username to use for TACACS logins. If not supplied then script will prompt for name. Cannot be blank\n"; print STDOUT "-p --password \t Specifies password to use for TACACS logins. If not supplied then script will prompt for password. Cannot be blank\n"; print STDOUT "-c --command \t Specifies single command to run. Command must be surround with double qoutes, if there are spaces.\n"; print STDOUT "-i --input \t Specifies name and path to file which has the commands that will be ran on each router. If not supplied then script will prompt for path/name. Cannot be blank\n"; print STDOUT "-o --output \t Specifies name and path where to send output from routers. If not supplied output will be sent to STDOUT\n"; print STDOUT "-h --help \t This help screen. Displays a list of options.\n"; print STDOUT "-v --version \t Display version information for this script.\n"; exit 0; } if ($flag_version) { #Show Version print STDOUT "Batch Router - the batch router configurator\n"; print STDOUT "Version number $version\n"; print STDOUT "Latest revision on $version_date\n"; exit 0; } #Load Config file my %routers=(); my $conf = Config::Tiny->read('batch_router.cnf'); my $conf_routers = $conf->{routers}; # Hash ref with routers information my $conf_groups = $conf->{groups}; # Hash ref with group information my $validation=0; if ($ln_router ne "") { #Check for Single Host #Validate router with config file $validation = &Check_routers($conf_routers, $ln_router); if (!$validation) { print STDOUT "Router \'$ln_router\' is not in routers list.\n"; exit 1; } $routers{$ln_router}=$conf_routers->{$ln_router}; } elsif ($ln_group ne "") { #Check for group of hosts #Validate group with config file $validation = &Check_groups($conf_groups, $ln_group); if (!$validation) { print STDOUT "Group \'$ln_group\' is not in group list.\n"; exit 1; } #Pull each router name from $conf_group and put into a list my @router_list=&Group_to_routers($conf_groups->{$ln_group}); #Validate each router name in group my $line = ""; foreach $line (@router_list) { #Reset Validation to false $validation=0; $validation = &Check_routers($conf_routers, $line); if (!$validation) { print STDOUT "Router \'$line\' in group \'$ln_group\' is not in routers list.\n"; exit 1; } $routers{$line}=$conf_routers->{$line}; } } else { #Make sure single or group of hosts selected print STDOUT "You must select a router or group to run this script.\n"; exit 0; } #Prompt for user name if not provided if ($user_name eq "") { print STDOUT "Please enter your user name: "; ReadMode('normal'); $user_name = ReadLine(0); chomp $user_name; ReadMode('restore'); if ($user_name eq "") { print STDOUT "User name cannot be blank.\n"; exit 1; } } #prompt for password if not provided if ($password eq "") { print STDOUT "Please enter your password: "; ReadMode('noecho'); $password = ReadLine(0); chomp $password; ReadMode('restore'); if ($password eq "") { print STDOUT "Password cannot be blank.\n"; exit 1; } print "\n"; } if ($input_file eq "" && $command eq "") { print STDOUT "Please enter \'input' filename, with path if needed: "; ReadMode('normal'); $input_file = ReadLine(0); chomp $input_file; ReadMode('restore'); if ($input_file eq "") { print STDOUT "Input filename can not be blank name cannot be blank.\n"; exit 1; } } #Get list of commands from Input file or from the command line my @commands=(); if ($command ne "") { push (@commands,$command); } elsif ($input_file ne "") { print STDOUT "*Reading in commands from Input File..."; @commands= &Open_input_file($input_file); #Check for returned error if (scalar(@commands) <= 0) { print STDOUT "\nInput file '$input_file' does not exist, is unreadable, or is empty.\n"; exit 1; } print STDOUT "Done\n"; } #Set $out_fh(refernce to output file handle) to STDOUT or output file print STDOUT "*Setting up output file, if any..."; my $out_FH = &Set_output_FH($output_file); if (!$out_FH) { print STDOUT "\nOutput file '$output_file' can not be created or opened.\n"; exit 1; } print STDOUT "Done\n"; print STDOUT "*Logging into Routers.\n"; if ($output_file eq "") {print "\n";} my $host=""; my %Result=(); foreach $host (keys %routers) { print STDOUT "*Logging into router $host($routers{$host}).\n"; if ($output_file ne "") { print $out_FH "Router $host($routers{$host}).\n"; } %Result= &Router($user_name,$password, $routers{$host}, @commands); my $line = ""; foreach $line (@commands) { print $out_FH "-" . $line . "\n"; my $output_list=""; foreach $output_list ($Result{$line}) { my $output_line=""; foreach $output_line (@$output_list) { chomp ($output_line); print $out_FH "\t" . $output_line . "\n"; } } } print $out_FH "\n"; print $out_FH "----------------------------------------------------\n"; if ($output_file eq "") {print STDOUT "\n";} } if ($output_file eq "") {print STDOUT "\n";} print STDOUT "*Closing output file, if any..."; if (!$output_file eq "") { close ($out_FH); } print STDOUT "Done\n"; ## Start of subfunctions sub Check_routers { #Check router Hash reference for router string my ($conf_routers, $ln_router)=@_; if (!defined($conf_routers->{$ln_router})) { return 0; } return 1; } sub Check_groups { #Check group Hash refernce for group string my ($conf_groups, $ln_group)=@_; if (!defined($conf_groups->{$ln_group})) { return 0; } return 1; } sub Group_to_routers { #Convert group router string into list of router names my ($group)=@_; chomp $group; $group =~ s/[ \[\]]//g; my @router_list = split/,/,$group; return @router_list; } sub Open_input_file { #Open config file ($input_file)=@_; my @list = (); #Check if file exists and size > 0, else return error if (-s $input_file) { #Open Input file, else return Error unless (open IP_FH, "<$input_file") { close IP_FH; return (); } @list = ; chomp(@list); } else { close IP_FH; return (); } close IP_FH; return @list; } sub Set_output_FH { #Set output file handle, default to STDOUT ($output_file)=@_; my $out_FH=""; if ($output_file eq "") { $out_FH = \*STDOUT; } else { unless (open OUT_FH,">$output_file") { return 0; } $out_FH=\*OUT_FH; } return $out_FH; } sub Router { #Log into single router. Return command output in hash (with nested list) my ($user_name,$password, $host, @commands)=@_; my $t = Net::Telnet::Cisco->new(Host => $host, Dump_log=> "telnetlog$host.txt"); #Log in With Username and Password $t->login($user_name,$password); my @level = $t->cmd("show privilege"); #Check if at level 15, if not then enable if (!($level[0] =~ /15/)) { # if user level not 15 then enable $t->enable($password); } my $command=""; $t->cmd("terminal length 0"); my %Result=(); foreach $command (@commands) { @{$Result{$command}} = $t->cmd($command); } $t->close; return %Result; } #### ## Router Identification [routers] any-core_12016 = 192.168.1.1 any-edge_12012 = 192.168.1.2 ##Group of routers [groups] network = [any-core_12016, any-edge_12012]