Line 15... |
Line 15... |
15 |
# As new entries become available, they are added. A time stamp
|
15 |
# As new entries become available, they are added. A time stamp
|
16 |
# records the last time an entry was "seen"
|
16 |
# records the last time an entry was "seen"
|
17 |
|
17 |
|
18 |
# Data is stored in the hash %switchports with the following structure
|
18 |
# Data is stored in the hash %switchports with the following structure
|
19 |
# %switchports =
|
19 |
# %switchports =
|
20 |
# {switch} (from %switches key)
|
20 |
# {switch} (from $config{'switches'} key)
|
21 |
# {name} (scalar, from snmp)
|
21 |
# {name} (scalar, from snmp)
|
22 |
# {location} (scalar, from snmp)
|
22 |
# {location} (scalar, from snmp)
|
23 |
# {'ports'} (constant key for sub hash)
|
23 |
# {'ports'} (constant key for sub hash)
|
24 |
# {port number} (from snmp)
|
24 |
# {port number} (from snmp)
|
25 |
# {connection} (uniqe id from snmp, basically the MAC)
|
25 |
# {connection} (uniqe id from snmp, basically the MAC)
|
26 |
# {mac} (from snmp walk of switch)
|
26 |
# {mac} (from snmp walk of switch)
|
27 |
# {ip} (from snmp walk of router)
|
27 |
# {ip} (from snmp walk of router)
|
28 |
# {hostname} (from reverse dns query)
|
28 |
# {hostname} (from reverse dns query)
|
29 |
# {lastseen} (last time this was active as unix timestamp)
|
29 |
# {lastseen} (last time this was active as unix timestamp)
|
30 |
|
30 |
|
- |
|
31 |
# 20190407 RWR
|
- |
|
32 |
# converted to use external config file in YAML format
|
- |
|
33 |
# added the ability to ignore ports on the switches
|
- |
|
34 |
|
31 |
use strict;
|
35 |
use strict;
|
32 |
use warnings;
|
36 |
use warnings;
|
33 |
#use Data::Dumper; # only used for debugging
|
37 |
use Data::Dumper; # only used for debugging
|
34 |
use Socket; # for reverse dns entries
|
38 |
use Socket; # for reverse dns entries
|
35 |
use YAML::Tiny; # apt-get libyaml-tiny-perl under debian
|
39 |
use YAML::Tiny; # apt-get libyaml-tiny-perl under debian
|
36 |
use File::Spec; # find location of script so we can put storage in same directory
|
40 |
use File::Spec; # find location of script so we can put storage in same directory
|
37 |
use File::Basename;
|
41 |
use File::Basename;
|
38 |
|
42 |
|
39 |
# one or more switches and their corresponding
|
- |
|
40 |
# community name. Use v1 snmp only
|
- |
|
41 |
my %switches = (
|
- |
|
42 |
'dns name or ip' => 'snmp v1 community name',
|
- |
|
43 |
#'dns name or ip' => 'snmp v1 community name'
|
- |
|
44 |
);
|
- |
|
45 |
|
- |
|
46 |
# You must include at least one router.
|
- |
|
47 |
# this will be queried to resolve IP's to MAC
|
- |
|
48 |
# using its arp table
|
- |
|
49 |
# put IP and community name into the hash
|
- |
|
50 |
my %routers = (
|
43 |
my %config;
|
51 |
'dns name or ip' => 'snmp v1 read/only community name',
|
- |
|
52 |
#'dns name or ip' => 'snmp v1 read/only community name',
|
- |
|
53 |
);
|
- |
|
54 |
|
44 |
|
55 |
# where the script is located
|
45 |
# where the script is located
|
56 |
my $scriptDir = dirname( File::Spec->rel2abs( __FILE__ ) );
|
46 |
my $scriptDir = dirname( File::Spec->rel2abs( __FILE__ ) );
|
57 |
# put the statefile in there
|
47 |
# put the statefile in there
|
58 |
my $STATEFILE = $scriptDir . '/mapSwitches.yaml';
|
48 |
my $STATEFILE = $scriptDir . '/mapSwitches.yaml';
|
- |
|
49 |
my $CONFIGFILE = $scriptDir . '/mapSwitches.config.yaml';
|
59 |
# main hash that holds the data we collect
|
50 |
# main hash that holds the data we collect
|
60 |
my %switchports;
|
51 |
my %switchports;
|
61 |
# some OIDS we need for the program
|
52 |
# some OIDS we need for the program
|
62 |
my $SWITCHPORTMIB = 'iso.3.6.1.2.1.17.4.3.1.2';
|
53 |
my $SWITCHPORTMIB = 'iso.3.6.1.2.1.17.4.3.1.2';
|
63 |
my $SWITCHMACMIB = 'iso.3.6.1.2.1.17.4.3.1.1';
|
54 |
my $SWITCHMACMIB = 'iso.3.6.1.2.1.17.4.3.1.1';
|
Line 115... |
Line 106... |
115 |
} # for connection
|
106 |
} # for connection
|
116 |
} # for port
|
107 |
} # for port
|
117 |
} # for switch
|
108 |
} # for switch
|
118 |
} # updateIP
|
109 |
} # updateIP
|
119 |
|
110 |
|
- |
|
111 |
if ( -e $CONFIGFILE ) {
|
- |
|
112 |
my $yaml = YAML::Tiny->read( $CONFIGFILE );
|
- |
|
113 |
%config = %{ $yaml->[0] };
|
- |
|
114 |
} else {
|
- |
|
115 |
die "could not locate config file $CONFIGFILE\n";
|
- |
|
116 |
}
|
- |
|
117 |
|
120 |
# read the saved state into memory if it exists
|
118 |
# read the saved state into memory if it exists
|
121 |
if ( -e $STATEFILE ) {
|
119 |
if ( -e $STATEFILE ) {
|
122 |
my $yaml = YAML::Tiny->read( $STATEFILE );
|
120 |
my $yaml = YAML::Tiny->read( $STATEFILE );
|
123 |
%switchports = %{ $yaml->[0] };
|
121 |
%switchports = %{ $yaml->[0] };
|
124 |
}
|
122 |
}
|
125 |
|
123 |
|
126 |
# first, get all of the MAC/Port assignments from the switches
|
124 |
# first, get all of the MAC/Port assignments from the switches
|
127 |
foreach my $switch ( keys %switches ) {
|
125 |
foreach my $switch ( keys %{$config{'switches'}} ) {
|
128 |
&initialize( \%switchports, $switch, 'name','location' );
|
126 |
&initialize( \%switchports, $switch, 'name','location' );
|
129 |
&updateValue(
|
127 |
&updateValue(
|
130 |
\$switchports{$switch}{'name'},
|
128 |
\$switchports{$switch}{'name'},
|
131 |
&getOneSNMPValue( $DEVICENAMEMIB,$switches{$switch},$switch, '= STRING: "?([^"]*)"?' )
|
129 |
&getOneSNMPValue( $DEVICENAMEMIB,$config{'switches'}{$switch}{'community'},$switch, '= STRING: "?([^"]*)"?' )
|
132 |
);
|
130 |
);
|
133 |
|
131 |
|
134 |
&updateValue(
|
132 |
&updateValue(
|
135 |
\$switchports{$switch}{'location'},
|
133 |
\$switchports{$switch}{'location'},
|
136 |
&getOneSNMPValue( $DEVICELOCMIB,$switches{$switch},$switch, '= STRING: "?([^"]*)"?' )
|
134 |
&getOneSNMPValue( $DEVICELOCMIB,$config{'switches'}{$switch}{'community'},$switch, '= STRING: "?([^"]*)"?' )
|
137 |
);
|
135 |
);
|
138 |
|
136 |
|
139 |
my $values = `snmpwalk -v1 -c $switches{$switch} $switch $SWITCHPORTMIB`;
|
137 |
my $values = `snmpwalk -v1 -c $config{switches}{$switch}{'community'} $switch $SWITCHPORTMIB`;
|
140 |
my @lines = split( "\n", $values );
|
138 |
my @lines = split( "\n", $values );
|
141 |
foreach my $line ( @lines ) {
|
139 |
foreach my $line ( @lines ) {
|
142 |
$line =~ m/$SWITCHPORTMIB\.([0-9.]+)\s=\sINTEGER:\s+(\d+)/;
|
140 |
$line =~ m/$SWITCHPORTMIB\.([0-9.]+)\s=\sINTEGER:\s+(\d+)/;
|
- |
|
141 |
my $uuid = $1; # this is the ID string of this MAC; normally the MAC itself in decimal form
|
- |
|
142 |
my $port = $2; # this is the port number
|
143 |
next unless $2; # skip port 0, or any port which has nothing
|
143 |
next unless $port; # skip port 0, or any port which has nothing
|
- |
|
144 |
next if $config{'switches'}{$switch}{'portsToIgnore'} && grep( /^$port$/, @{$config{'switches'}{$switch}{'portsToIgnore'}} );
|
144 |
$switchports{$switch}{'ports'}{$2}{$1}{'mac'} = &makeMAC( $1 );
|
145 |
$switchports{$switch}{'ports'}{$port}{$uuid}{'mac'} = &makeMAC( $1 );
|
145 |
}
|
146 |
}
|
146 |
}
|
147 |
}
|
147 |
|
148 |
|
148 |
# die Dumper( \%switchports );
|
149 |
# die Dumper( \%switchports );
|
149 |
|
150 |
|
150 |
|
151 |
|
151 |
# Now, try to match up the MAC address. Read the ARP table from the router(s)
|
152 |
# Now, try to match up the MAC address. Read the ARP table from the router(s)
|
152 |
foreach my $router ( keys %routers ) {
|
153 |
foreach my $router ( keys %{$config{'routers'}} ) {
|
153 |
my $values = `snmpwalk -v1 -c $routers{$router} $router $ROUTERIPMACMIB`;
|
154 |
my $values = `snmpwalk -v1 -c $config{routers}{$router}{community} $router $ROUTERIPMACMIB`;
|
154 |
my @lines = split( "\n", $values );
|
155 |
my @lines = split( "\n", $values );
|
155 |
foreach my $line ( @lines ) {
|
156 |
foreach my $line ( @lines ) {
|
156 |
$line =~ m/$ROUTERIPMACMIB\.([0-9]+)\.([0-9.]+)\s=\sHex-STRING:\s([0-9a-z ]+)/i;
|
157 |
$line =~ m/$ROUTERIPMACMIB\.([0-9]+)\.([0-9.]+)\s=\sHex-STRING:\s([0-9a-z ]+)/i;
|
157 |
my $interface = $1;
|
158 |
my $interface = $1;
|
158 |
my $ip = $2;
|
159 |
my $ip = $2;
|