#!/opt/vdops/bin/perl # This script identifies ports in switches configured in SPAN mode. Uses # SMON-MIB support # V Who When What # --------------------------------------------------------------------------- # 1.0.2 skendric 2010-01-26 Upgrade to perl 5.10.1 # 1.0.1 skendric 12-21-2007 Fiddle with report # 1.0.0 skendric 09-11-2007 First Version # # Author: Stuart Kendrick, sbk {put at sign here} skendric {put dot here} com # # Source: http://www.skendric.com/device # # This software is available under the GNU GENERAL PUBLIC LICENSE, see # http://www.fsf.org/licenses/gpl.html # # # This script takes the following approach: # -Parses the hosts table for a list of targets (or accepts a command- # line list) # -Identifies ports configured in SPAN mode # -Produces a report # # # Requirements: # -Devices must support SMON-MIB # # -PERL modules: the FHCRC::Netops collection # # # Assumptions: # # # Tested on: # -perl-5.10.1 # -net-snmp-5.5 # # # Instructions: # -Customize the script for your site: find the 'user-configurable # variables' section and modify as appropriate # -Try it out # # # # Caveats: # # # Known Bugs: # # # To do: # -In the report, specify which modules contain afflicted ports # -Add support for SNMPv3 # # Begin script # Load modules use strict; use warnings; use feature 'say'; use feature 'switch'; use Carp qw(carp cluck croak confess); use Data::Dumper; use English qw( -no_match_vars ); use Getopt::Std; use FHCRC::Netops::CiscoTools 1.3.1; use FHCRC::Netops::HostTools 1.0.3; use FHCRC::Netops::NetopsTools 2.0.7; use FHCRC::Netops::NetopsData 1.3.0; use FHCRC::Netops::PingTools 1.1.5; use FHCRC::Netops::SNMPTools 1.3.9; use FHCRC::Netops::Utilities 1.3.9; # Declare global variables my %span; # Hash of arrays (keyed by switch name), each # element of which consists of a hash, keyed # by destination ifName, pointing to a two # element array: the 0th element is the ifAlias # of the destination port, the 1st element is # an array of source ifNames # Define global variables $debug = 0; # 10 = Logging # 9 = Database SELECT operations # 8 = Per IP/MAC/Port processing # 7 = Database INSERT/UPDATE/DELETE # 6 = Dump SNMP var # 5 = Dump snmp_packets # 4 = Grody: print big var # 3 = Verbose: print mid var # 2 = Simple: print small var # 1 = Basic: subroutine trace # 0 = Disable debugging $program_name = 'find-span-ports'; $usage = 'Usage: find-span-ports -s {yes|no} [-d {integer}] [-r] [-a | -e {expr} | -f {filename} | target1 target2 target3 ...]'; $version = '1.0.2'; # Binaries $grab_hosts = '/bin/cat /etc/hosts'; # Pause parameters $long = 30; $mid = 10; $short = 5; # Ping Stuff $ping_count = 3; $ping_timeout = 1; # Report stuff $institution = 'Widgets International'; $report_file = '/home/netops/rpts/find-span-ports.txt'; $report_queries = 'bsmith@widgets.com'; $report_recipients = 'ksamuels@fhcrc.org mclemens@fhcrc.org skendric@fhcrc.org jroberts@fhcrc.org'; $report_subject = 'SPAN Port Report'; # SNMP Stuff # Optimize performance by sorting your community strings and SNMP version # list, most frequently used to the left, least frequently used to the right @mib_dir = qw(/opt/vdops/share/snmp/mibs); @mib_file = qw/ALL/; @snmp_read_list = qw/public/; @snmp_version_list = qw/2/; $snmp_port = 161; $snmp_retries = 3; $snmp_timeout = 2000000; # Syslog stuff $syslog_facility = 'local5'; $syslog_host = 'localhost'; $syslog_port = 514; $syslog_priority = 'info'; $syslog_socket = 'unix'; # Other possibilites include 'udp' and # 'stream'; depending on the flavor of Unix, # I've employed each of these # Target details @skip_name = qw/swamp/; @suffixes = qw/-esx -rtr/; # Grab arguments getopts('ad:e:f:rs:', \%option); @target = @ARGV; # Set mode if ($option{r}) { $mode = 'report' } elsif (-t STDIN) { $mode = 'interactive' } else { $mode = 'batch' } ### Begin Main Program ############################################### { check_args(); # Check arguments compile_mibs(); # Compile MIB files build_target(); # Populate @target target_check(); # Look for errors in @target basic_info(); # Gather information do_the_work(); # Do the work print_report(); # Print report } ##### End Main Program ############################################### ######################################################################## # Do the work: find SPAN ports ######################################################################## sub do_the_work { # Debug trace trace_location('begin') if $debug; # Notify operator print_it('Acquiring SPAN info...'); # Loop through targets for my $target (@target) { my (%arg, %if_name, $span_port_ref); # Look for span ports say 'Walking portCopyStatus' if $debug > 3; %arg = ( host => $target, oid => '.1.3.6.1.2.1.16.22.1.3.1.1.5' ); $span_port_ref = snmpWalk(\%arg); # Pull out SPAN ports PORT: for my $varbind (@$span_port_ref) { my (%arg, $dst, $dst_alias, $dst_name, $src, $src_name, $status); $status = $varbind->{val}; next PORT unless defined $status; next PORT unless $status ne $EMPTY_STR; next PORT unless $status eq 'active'; ($src, $dst) = split /\./, $varbind->{iid}; # Find src IF name say "Getting ifName.$src" if $debug > 3; %arg = (host => $target, oid => ".1.3.6.1.2.1.31.1.1.1.1.$src" ); $src_name = snmpGet(\%arg); # Find dst IF name say "Getting ifName.$dst" if $debug > 3; %arg = (host => $target, oid => ".1.3.6.1.2.1.31.1.1.1.1.$dst" ); $dst_name = snmpGet(\%arg); # Find dst IF alias say "Getting ifAlias.$dst" if $debug > 3; %arg = (host => $target, oid => ".1.3.6.1.2.1.31.1.1.1.18.$dst"); $dst_alias = snmpGet(\%arg); # Build data structure $if_name{$dst_name}->[0] = $dst_alias; push @{$if_name{$dst_name}->[1]}, $src_name; $shit_happens++; } # Save results $span{$target} = \%if_name if keys %if_name > 0; # Entertain operator print $BANG if $mode eq 'interactive'; } # Make things look pretty say "\n" if $mode eq 'interactive'; # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Tell the operator what I discovered ######################################################################## sub print_report { my @fields; my $handle; my $total = @target; my $now = get_now(); # Debug trace trace_location('begin') if $debug; # If we are running in test mode, skip this routine unless ($dome) { print_it("Running in test mode, cannot print a meaningful report\n"); return 1; } # Direct output to screen or to file if ($mode eq 'interactive') { $handle = *STDOUT; } else { open $handle, '>', $report_file or die "Cannot open $report_file: $!\n"; } print {$handle} <{$dst}->[1]}; my $dst_alias = $span_ref->{$dst}->[0]; printf {$handle} "%-16s %-28.28s %-6s %-24.24s\n", $target, $src_list, $dst, $dst_alias; } } unless ($handle =~ /STDOUT/) { close $handle or warn "Cannot close $report_file: $!\n"; } # Make things look pretty print_it("\n\nEnding $PROGRAM_NAME"); # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Output help ######################################################################## sub HELP_MESSAGE { print <