* Created Network->get_company_from_mac() that converts a MAC address to the company name that owns it.

* Added recording the last-change order for network interfaces in System->generate_state_json() so that the most recently unplugged and plugged back in interfaces can be tracked.
* Worked out a faster way to ping scan subnets with nmap in striker-scan-network. Dropped average scan time from 35 minutes to 4~5 minutes for a /16 subnet.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent e3a8c1a01d
commit b2ff4c4c53
  1. 129
      Anvil/Tools/Network.pm
  2. 3
      Anvil/Tools/System.pm
  3. 2
      html/skins/alteeve/main.css
  4. 2
      html/skins/alteeve/striker.html
  5. 5
      share/words.xml
  6. 31
      tools/striker-scan-network

@ -16,6 +16,7 @@ my $THIS_FILE = "Network.pm";
# check_internet # check_internet
# download # download
# find_matches # find_matches
# get_company_from_mac
# get_ips # get_ips
# get_network # get_network
# is_local # is_local
@ -973,6 +974,7 @@ ORDER BY
results => $results, results => $results,
count => $count, count => $count,
}}); }});
my $changed_order = 1;
foreach my $row (@{$results}) foreach my $row (@{$results})
{ {
my $network_interface_uuid = defined $row->[0] ? $row->[0] : ""; my $network_interface_uuid = defined $row->[0] ? $row->[0] : "";
@ -1019,38 +1021,42 @@ ORDER BY
network_interface_bond_uuid => $network_interface_bond_uuid, network_interface_bond_uuid => $network_interface_bond_uuid,
network_interface_bridge_uuid => $network_interface_bridge_uuid, network_interface_bridge_uuid => $network_interface_bridge_uuid,
bond_name => $bond_name, bond_name => $bond_name,
changed_order => $changed_order,
}}); }});
# We'll initially load empty strings for what would be the IP information. Any interface with IPs will be populated when we call # We'll initially load empty strings for what would be the IP information. Any interface with IPs will be populated when we call
$anvil->data->{network}{$host}{interface}{$network_interface_name}{uuid} = $network_interface_uuid; $anvil->data->{network}{$host}{interface}{$network_interface_name}{uuid} = $network_interface_uuid;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{mac_address} = $network_interface_mac_address; $anvil->data->{network}{$host}{interface}{$network_interface_name}{mac_address} = $network_interface_mac_address;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{speed} = $network_interface_speed; $anvil->data->{network}{$host}{interface}{$network_interface_name}{speed} = $network_interface_speed;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{mtu} = $network_interface_mtu; $anvil->data->{network}{$host}{interface}{$network_interface_name}{mtu} = $network_interface_mtu;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{link_state} = $network_interface_link_state; $anvil->data->{network}{$host}{interface}{$network_interface_name}{link_state} = $network_interface_link_state;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{operational} = $network_interface_operational; $anvil->data->{network}{$host}{interface}{$network_interface_name}{operational} = $network_interface_operational;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{duplex} = $network_interface_duplex; $anvil->data->{network}{$host}{interface}{$network_interface_name}{duplex} = $network_interface_duplex;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{medium} = $network_interface_medium; $anvil->data->{network}{$host}{interface}{$network_interface_name}{medium} = $network_interface_medium;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{bond_uuid} = $network_interface_bond_uuid; $anvil->data->{network}{$host}{interface}{$network_interface_name}{bond_uuid} = $network_interface_bond_uuid;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{bond_name} = $bond_name; $anvil->data->{network}{$host}{interface}{$network_interface_name}{bond_name} = $bond_name;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{bridge_uuid} = $network_interface_bridge_uuid; $anvil->data->{network}{$host}{interface}{$network_interface_name}{bridge_uuid} = $network_interface_bridge_uuid;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{bridge_name} = $bridge_name; $anvil->data->{network}{$host}{interface}{$network_interface_name}{bridge_name} = $bridge_name;
$anvil->data->{network}{$host}{interface}{$network_interface_name}{type} = "interface"; $anvil->data->{network}{$host}{interface}{$network_interface_name}{type} = "interface";
$anvil->data->{network}{$host}{interface}{$network_interface_name}{changed_order} = $changed_order;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"network::${host}::interface::${network_interface_name}::uuid" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{uuid}, "network::${host}::interface::${network_interface_name}::uuid" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{uuid},
"network::${host}::interface::${network_interface_name}::mac_address" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{mac_address}, "network::${host}::interface::${network_interface_name}::mac_address" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{mac_address},
"network::${host}::interface::${network_interface_name}::speed" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{speed}, "network::${host}::interface::${network_interface_name}::speed" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{speed},
"network::${host}::interface::${network_interface_name}::mtu" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{mtu}, "network::${host}::interface::${network_interface_name}::mtu" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{mtu},
"network::${host}::interface::${network_interface_name}::link_state" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{link_state}, "network::${host}::interface::${network_interface_name}::link_state" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{link_state},
"network::${host}::interface::${network_interface_name}::operational" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{operational}, "network::${host}::interface::${network_interface_name}::operational" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{operational},
"network::${host}::interface::${network_interface_name}::duplex" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{duplex}, "network::${host}::interface::${network_interface_name}::duplex" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{duplex},
"network::${host}::interface::${network_interface_name}::medium" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{medium}, "network::${host}::interface::${network_interface_name}::medium" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{medium},
"network::${host}::interface::${network_interface_name}::bond_uuid" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{bond_uuid}, "network::${host}::interface::${network_interface_name}::bond_uuid" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{bond_uuid},
"network::${host}::interface::${network_interface_name}::bond_name" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{bond_name}, "network::${host}::interface::${network_interface_name}::bond_name" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{bond_name},
"network::${host}::interface::${network_interface_name}::bridge_uuid" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{bridge_uuid}, "network::${host}::interface::${network_interface_name}::bridge_uuid" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{bridge_uuid},
"network::${host}::interface::${network_interface_name}::bridge_name" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{bridge_name}, "network::${host}::interface::${network_interface_name}::bridge_name" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{bridge_name},
"network::${host}::interface::${network_interface_name}::type" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{type}, "network::${host}::interface::${network_interface_name}::type" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{type},
"network::${host}::interface::${network_interface_name}::changed_order" => $anvil->data->{network}{$host}{interface}{$network_interface_name}{changed_order},
}}); }});
$changed_order++;
} }
# Load the IPs # Load the IPs
@ -1305,6 +1311,77 @@ WHERE
return(0); return(0);
} }
=head2 get_company_from_mac
This takes a MAC address (or the first six bytes) and returns the company that owns the OUI. If the company name is not found, an expty string is returned.
Parameters;
=head3 mac (required)
This is the first six bytes of the mac address, C<< xx:xx:xx >> format, being searched for.
=cut
sub get_company_from_mac
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->get_company_from_mac()" }});
my $mac = defined $parameter->{mac} ? lc($parameter->{mac}) : "";
my $company = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
mac => $mac,
}});
if (not $mac)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->get_company_from_mac()", parameter => "mac_prefix" }});
return("");
}
# Have I already looked this one up?
if ($anvil->data->{cache}{mac_to_oui}{$mac})
{
# Yup, no need to process.
return($anvil->data->{cache}{mac_to_oui}{$mac});
}
my $valid_mac = $anvil->Validate->is_mac({mac => $mac});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mac => $mac }});
if ($valid_mac)
{
# Strip the first six bytes.
$mac = ($mac =~ /^([0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2})/i)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mac => $mac }});
}
elsif ($mac !~ /[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}/i)
{
# Bad format
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0104", variables => { mac => $mac }});
return("");
}
my $query = "SELECT oui_company_name FROM oui WHERE oui_mac_prefix = ".$anvil->Database->quote(lc($mac)).";";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0124", variables => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
if ($count)
{
$company = $results->[0]->[0];
$anvil->data->{cache}{mac_to_oui}{$mac} = $company;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { company => $company }});
}
return($company);
}
=head2 get_ips =head2 get_ips
This method checks the local system for interfaces and stores them in: This method checks the local system for interfaces and stores them in:

@ -1002,6 +1002,7 @@ sub generate_state_json
my $medium = $anvil->data->{network}{$host}{interface}{$interface}{medium}; my $medium = $anvil->data->{network}{$host}{interface}{$interface}{medium};
my $bond_name = $anvil->data->{network}{$host}{interface}{$interface}{bond_name} ? $anvil->data->{network}{$host}{interface}{$interface}{bond_name} : $anvil->Words->string({key => "unit_0005"}); my $bond_name = $anvil->data->{network}{$host}{interface}{$interface}{bond_name} ? $anvil->data->{network}{$host}{interface}{$interface}{bond_name} : $anvil->Words->string({key => "unit_0005"});
my $bridge_name = $anvil->data->{network}{$host}{interface}{$interface}{bridge_name} ? $anvil->data->{network}{$host}{interface}{$interface}{bridge_name} : $anvil->Words->string({key => "unit_0005"}); my $bridge_name = $anvil->data->{network}{$host}{interface}{$interface}{bridge_name} ? $anvil->data->{network}{$host}{interface}{$interface}{bridge_name} : $anvil->Words->string({key => "unit_0005"});
my $changed_order = $anvil->data->{network}{$host}{interface}{$interface}{changed_order};
my $say_link_state = $link_state; my $say_link_state = $link_state;
my $say_operational = $operational; my $say_operational = $operational;
my $say_medium = $medium; my $say_medium = $medium;
@ -1047,6 +1048,7 @@ sub generate_state_json
medium => $medium, medium => $medium,
bond_name => $bond_name, bond_name => $bond_name,
bridge_name => $bridge_name, bridge_name => $bridge_name,
changed_order => $changed_order,
}}); }});
$iface_hash->{speed} = $speed; $iface_hash->{speed} = $speed;
@ -1060,6 +1062,7 @@ sub generate_state_json
$iface_hash->{medium} = $medium; $iface_hash->{medium} = $medium;
$iface_hash->{bond_name} = $bond_name; $iface_hash->{bond_name} = $bond_name;
$iface_hash->{bridge_name} = $bridge_name; $iface_hash->{bridge_name} = $bridge_name;
$iface_hash->{changed_order} = $changed_order;
}; };
push @{$ifaces_array}, $iface_hash; push @{$ifaces_array}, $iface_hash;
} }

@ -136,7 +136,7 @@ body {
.job_output { .job_output {
font: 0.8em 'Dejavu Sans Mono', Courier; font: 0.8em 'Dejavu Sans Mono', Courier;
color: #d2e2d2; color: #d2e2d2;
white-space: nowrap; /*white-space: nowrap;*/
} }
.job_status { .job_status {

@ -384,7 +384,7 @@
</tr> </tr>
<tr> <tr>
<td colspan="3" style="padding-left: 4px;"> <td colspan="3" style="padding-left: 4px;">
<span class="column_row_name">#!variable!description!#</span> <span class="column_row_value">#!variable!description!#</span>
</td> </td>
</tr> </tr>
<tr> <tr>

@ -776,8 +776,8 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a
#!variable!section!# #!variable!section!#
==== ====
</key> </key>
<key name="log_0445"><![CDATA[[ Note ] - We're about to do a ping scan of: [#!variable!range!#]. This could take a long time, please be patient!<br />If you think this process is hung, please run 'pgrep nmap' on the host. If a process is returned, this is still running. We go slow to avoid upsetting network security devices or admin.]]></key> <key name="log_0445"><![CDATA[[ Note ] - We're about to do a ping scan of: [#!variable!range!#]. This could take a long time, please be patient! If you think this process is hung, please run 'pgrep nmap' on the host. If a process is returned, this is still running. We go slow to avoid upsetting network security devices or admin.]]></key>
<key name="log_0446">Found the network device: [#!variable!mac!#] usingt the IP address: [#!variable!ip!#].</key> <key name="log_0446">Found the network device: [#!variable!mac!#] (owned by #!variable!company!#) using the IP address: [#!variable!ip!#].</key>
<key name="log_0447">About to download: [#!variable!url!#] and save it to: [#!variable!file!#].</key> <key name="log_0447">About to download: [#!variable!url!#] and save it to: [#!variable!file!#].</key>
<key name="log_0448">Ready to parse: [#!variable!file!#].</key> <key name="log_0448">Ready to parse: [#!variable!file!#].</key>
<key name="log_0449">Parsed: [#!variable!records!#], adding/updating them to the database now.</key> <key name="log_0449">Parsed: [#!variable!records!#], adding/updating them to the database now.</key>
@ -1253,6 +1253,7 @@ Failed to generate an RSA public key for the user: [#!variable!user!#]. The outp
<key name="error_0101">Compression appears to have failed. The output file: [#!variable!out_file!#] was not found.</key> <key name="error_0101">Compression appears to have failed. The output file: [#!variable!out_file!#] was not found.</key>
<key name="error_0102">Failed to check the existence and size of the file: [#!variable!file!#] on the target: [#!variable!target!#] as: [#!variable!remote_user!#]. The error (if any) was: [#!variable!error!#] and the output (if any) was: [#!variable!output!#].</key> <key name="error_0102">Failed to check the existence and size of the file: [#!variable!file!#] on the target: [#!variable!target!#] as: [#!variable!remote_user!#]. The error (if any) was: [#!variable!error!#] and the output (if any) was: [#!variable!output!#].</key>
<key name="error_0103">The file: [#!variable!file!#] wasn't found.</key> <key name="error_0103">The file: [#!variable!file!#] wasn't found.</key>
<key name="error_0104">The parameter get_company_from_oui->mac must be a valid MAC address or be in the format 'xx:xx:xx'. Received: [#!variable!mac!#].</key>
<!-- These are units, words and so on used when displaying information. --> <!-- These are units, words and so on used when displaying information. -->
<key name="unit_0001">Yes</key> <key name="unit_0001">Yes</key>

@ -346,17 +346,19 @@ sub call_nmap
$anvil->data->{progress} += 10; $anvil->data->{progress} += 10;
update_progress($anvil, $anvil->data->{progress}, "log_0445,!!range!".$address."!!"); update_progress($anvil, $anvil->data->{progress}, "log_0445,!!range!".$address."!!");
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "log_0445", variables => { range => $address }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "log_0445", variables => { range => $address }});
my ($nmap_data, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{nmap}." -sn -n ".$address });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
nmap_data => $nmap_data,
return_code => $return_code,
}});
my $this_ip = ""; # Make the call directly, instead of using 'System->call', so that we can show output as it's found.
my $this_mac = ""; my $this_ip = "";
my $section = ""; my $this_mac = "";
foreach my $line (split/\n/, $nmap_data) my $section = "";
my $shell_call = $anvil->data->{path}{exe}{nmap}." -sP -T4 --min-parallelism 100 --max-parallelism 256 ".$address;
open (my $file_handle, $shell_call." 2>&1 |") or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, priority => "err", key => "log_0014", variables => { shell_call => $shell_call, error => $! }});
while(<$file_handle>)
{ {
chomp;
my $line = $_;
$line =~ s/\n$//;
$line =~ s/\r$//;
$line = $anvil->Words->clean_spaces({'string' => $line}); $line = $anvil->Words->clean_spaces({'string' => $line});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
@ -393,10 +395,14 @@ sub call_nmap
{ {
$anvil->data->{progress} += 1; $anvil->data->{progress} += 1;
$anvil->data->{progress} = 95 if $anvil->data->{progress} > 95; $anvil->data->{progress} = 95 if $anvil->data->{progress} > 95;
update_progress($anvil, $anvil->data->{progress}, "log_0446,!!ip!".$this_ip."!!,!!mac!".$this_mac."!!"); my $company = $anvil->Network->get_company_from_mac({debug => 2, mac => $this_mac });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { company => $company }});
update_progress($anvil, $anvil->data->{progress}, "log_0446,!!ip!".$this_ip."!!,!!mac!".$this_mac."!!,!!company!".$company."!!");
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "log_0446", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "log_0446", variables => {
ip => $this_ip, ip => $this_ip,
mac => $this_mac, mac => $this_mac,
company => $company,
}}); }});
my ($mac_to_ip_uuid) = $anvil->Database->insert_or_update_mac_to_ip({ my ($mac_to_ip_uuid) = $anvil->Database->insert_or_update_mac_to_ip({
debug => 3, debug => 3,
@ -423,6 +429,7 @@ sub call_nmap
$section = ""; $section = "";
} }
} }
close $file_handle;
return(0); return(0);
} }

Loading…
Cancel
Save