#!/usr/bin/perl # # dump bridge tables for a list of switches # # $Id: btdump,v 1.17 2002/04/11 13:45:01 trockij Exp $ # # Copyright (C) 1998 Jim Trocki # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # use A3Com::BridgeTable; use A3Com::ARP; use A3Com::EtherDetail; use Getopt::Std; use Socket; use strict; sub lookup; sub usage; my $SWITCH_LIST = "/home/mis/net/switch-config/switch-list"; my $HIST_BT = 0; my %GLOBALPARMS; my @SWITCHLIST; my %opt; my $TO_FIND; my %HOSTHASH; my $GLOBALCACHE = 1; getopts ("a:p:cdfgmnos", \%opt) || usage ("argument error"); if (@ARGV) { @SWITCHLIST = @ARGV; } else { open (I, $SWITCH_LIST) || die "couldn't get switch list: $!\n"; while () { next if (/^\s*#/ || /^\s*$/); chomp; push @SWITCHLIST, $_; } close (I); } die "no switches given\n" if (@SWITCHLIST == 0); if (defined $opt{"p"}) { $GLOBALPARMS{"GLOBALCACHEDIR"} = $opt{"p"}; } if ($opt{"a"}) { if ($opt{"a"} =~ /:/) { $TO_FIND = $opt{"a"}; } elsif ($opt{"a"} =~ /^\d+\.\d+\.\d+\.\d+$/) { $TO_FIND = $opt{"a"}; } elsif ($opt{"a"} =~ /^[a-z][a-z0-9-]*$/i) { die "could not resolve host $opt{a}\n" if (!defined ($TO_FIND = gethostbyname ($opt{"a"}))); $TO_FIND = inet_ntoa ($TO_FIND); } else { die "unidentified address type\n"; } } # # get ARP stuff # my $arp = new A3Com::ARP ( SWITCH => "helium", GLOBALCACHE => 0, CACHE => 0, %GLOBALPARMS, ); die "couldn't get arp cache\n" if (!defined $arp); my $arphist; $arphist = $arp->load_history (); die "couldn't load history: " . $arp->error . "\n" if ($arp->error ne ""); if ($opt{"a"} && $TO_FIND =~ /\d+\./) { if (defined $arphist->{$TO_FIND}) { $TO_FIND = $arphist->{$TO_FIND}->{"current"}; } else { die "IP address not found in ARP tables\n"; } } if ($opt{"d"}) { print "#\n# switch port portState actualPortMode autoNegMode addrs\n#\n"; } else { print "#\n# switch port addrs\n#\n"; } # # walk through switches and display bridge tables (with IP addresses) # foreach my $switch (@SWITCHLIST) { my $sw = new A3Com::BridgeTable ( SWITCH => $switch, GLOBALCACHE => 1, %GLOBALPARMS, ); $sw->cache (0) if ($opt{"f"}); $sw->globalcache (0) if ($opt{"g"}); $sw->cachetime (time) if ($opt{"c"}); my $swdetail; if ($opt{"d"}) { $swdetail = new A3Com::EtherDetail ( SWITCH => $switch, %GLOBALPARMS, ); $sw->globalcache (0) if ($opt{"g"}); $swdetail->cache (0) if ($opt{"s"}); $swdetail->cachetime (time) if ($opt{"c"}); } my (@ports, %hist); if ($HIST_BT) { %hist = $sw->load_history; if ($sw->error ne "") { print STDERR "could not load history for $switch: " . $sw->error . "\n"; next; } @ports = keys %hist; } else { @ports = $sw->ports; die "error for $switch: " . $sw->error . "\n" if (@ports == 0); } foreach my $port (sort { $a <=> $b} @ports) { my $detail; if ($opt{"d"}) { $detail = $swdetail->port_val ($port, "portState") . " " . $swdetail->port_val ($port, "actualPortMode") . " " . $swdetail->port_val ($port, "autoNegMode"); } my @macs; if ($HIST_BT) { @macs = (); } else { @macs = $sw->port ($port); } next if (@macs > 1 && $opt{"o"}); if (@macs == ()) { if ($opt{"d"}) { print "$switch $port $detail\n"; } else { print "$switch $port\n"; } next; } if ($opt{"m"} && ! $opt{"a"}) { if ($opt{"d"}) { print "$switch $port $detail @macs\n"; } else { print "$switch $port @macs\n"; } next; } my @addrs = (); foreach my $mac (@macs) { next if ($opt{"a"} && $mac ne $TO_FIND); if ($opt{"m"}) { push @addrs, $mac; next; } # look at all of $arphist for IPs that resolve to $mac my @ips = $arp->lookup_mac_history ($arphist, $mac); push @addrs, @ips; } next if ($opt{"a"} && @addrs == ()); if (!$opt{"n"}) { for (@addrs) { $_ = lookup ($_) unless (/:/); } } if ($opt{"d"}) { print "$switch $port $detail @addrs\n"; } else { print "$switch $port @addrs\n"; } } } sub lookup { my $ip = shift; return $HOSTHASH{$ip} if (defined $HOSTHASH{$ip}); my $IP = gethostbyaddr (inet_aton ($ip), AF_INET); if (!defined $IP) { $HOSTHASH{$ip} = $ip; return $ip; } $IP =~ s/^([^.]+)\..*$/$1/; $HOSTHASH{$ip} = $IP; } sub usage { print STDERR "$0: @_\n" if @_; die <