* Fixed a tricky deep recursion bug in Network->is_local when the passed in host was an empty string. Also created a cache system where a host name that has been checked before is immediately returned, without needing to run through the logic in 'is_local', which gets called quite frequently.

* Updated the loop detection logic in Log->entry where processing large strings was triggering it when it shouldn't.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent 32bcdbe6d3
commit af6e2c076d
  1. 4
      Anvil/Tools.pm
  2. 26
      Anvil/Tools/Log.pm
  3. 50
      Anvil/Tools/Network.pm
  4. 1
      Anvil/Tools/Storage.pm
  5. 2
      share/words.xml
  6. 2
      tools/anvil-daemon
  7. 21
      tools/striker-parse-oui

@ -240,7 +240,7 @@ sub new
# If the local './tools.conf' file exists, read it in.
if (-r $anvil->data->{path}{configs}{'anvil.conf'})
{
$anvil->Storage->read_config({debug => $debug, file => $anvil->data->{path}{configs}{'anvil.conf'}});
$anvil->Storage->read_config({debug => 3, file => $anvil->data->{path}{configs}{'anvil.conf'}});
### TODO: Should anvil.conf override parameters?
# Let parameters override config file values.
@ -720,7 +720,7 @@ sub _host_name
else
{
# The environment variable isn't set. Call 'hostnamectl' on the command line.
($host_name, my $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static"});
($host_name, my $return_code) = $anvil->System->call({debug => 9999, shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static"});
}
return($host_name);

@ -248,11 +248,19 @@ sub entry
my $source = defined $parameter->{source} ? $parameter->{source} : "";
my $tag = defined $parameter->{tag} ? $parameter->{tag} : $anvil->data->{defaults}{'log'}{tag};
my $variables = defined $parameter->{variables} ? $parameter->{variables} : "";
$anvil->data->{loop}{count} = 0 if not defined $anvil->data->{loop}{count};
$anvil->data->{loop}{count}++;
print $THIS_FILE." ".__LINE__."; [ Debug ] - level: [".$level."], defaults::log::level: [".$anvil->data->{defaults}{'log'}{level}."], logging secure? [".$anvil->Log->secure."], loop::count: [".$anvil->data->{loop}{count}."]\n" if $test;
print $THIS_FILE." ".__LINE__."; [ Debug ] - level: [".$level."], defaults::log::level: [".$anvil->data->{defaults}{'log'}{level}."], logging secure? [".$anvil->Log->secure."], loop::count: [".$anvil->data->{loop}{count}."], source: [".$source."], line: [".$line."], key: [".$key."], variables: [".$variables."]\n" if $test;
if (($test) && (ref($variables) eq "HASH"))
{
foreach my $key (sort {$a cmp $b} keys %{$variables})
{
print $THIS_FILE." ".__LINE__."; - key: [".$key."] -> [".$variables->{$key}."]\n";
}
}
# The counter needs to be longer than any conceivable file line count we might read.
if ($anvil->data->{loop}{count} > 500000)
if ($anvil->data->{loop}{count} > 5000000)
{
if ($anvil->environment eq "html")
{
@ -292,10 +300,12 @@ sub entry
# Exit immediately if this isn't going to be logged
if ($level > $anvil->Log->level)
{
$anvil->data->{loop}{count}--;
return(1);
}
if (($secure) && (not $anvil->Log->secure))
{
$anvil->data->{loop}{count}--;
return(2);
}
@ -343,6 +353,7 @@ sub entry
$string .= "$line; ";
print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test;
}
print $THIS_FILE." ".__LINE__."; loop::count: [".$anvil->data->{loop}{count}."] " if $test;
# If I have a raw string, do no more processing.
print $THIS_FILE." ".__LINE__."; raw: [".$raw."], key: [".$key."]\n" if $test;
@ -386,6 +397,7 @@ sub entry
### TODO: Periodically check the log file size. If it's over a gigabyte, archive it
# Open the file?
$anvil->data->{HANDLE}{'log'}{main} = "" if not defined $anvil->data->{HANDLE}{'log'}{main};
print $THIS_FILE." ".__LINE__."; HANDLE::log::main: [".$anvil->data->{HANDLE}{'log'}{main}."]\n" if $test;
if (not $anvil->data->{HANDLE}{'log'}{main})
{
@ -420,7 +432,7 @@ sub entry
# The handle has to be wrapped in a block to make 'print' happy as it doesn't like non-scalars for file handles
print { $anvil->data->{HANDLE}{'log'}{main} } $string;
$anvil->data->{loop}{count} = 0;
$anvil->data->{loop}{count} = 0;
}
else
{
@ -432,6 +444,9 @@ sub entry
SYSLOG_FACILITY => $secure ? "authpriv" : $facility,
SYSLOG_IDENTIFIER => $tag,
);
# Reset the loop counter
$anvil->data->{loop}{count} = 0;
}
if ($print)
@ -439,6 +454,7 @@ sub entry
print $print_string."\n";
}
$anvil->data->{loop}{count}--;
return(0);
}
@ -679,7 +695,7 @@ sub variables
# Exit immediately if this isn't going to be logged
print $THIS_FILE." ".__LINE__."; debug: [".$debug."], level: [".$level."], Log->level: [".$anvil->Log->level."]\n" if $test;
die if $test;
#die if $test;
if (not defined $level)
{
die $THIS_FILE." ".__LINE__."; Log->variables() called without 'level': [".$level."] defined from: [$source : $line]\n";
@ -688,7 +704,7 @@ sub variables
{
die $THIS_FILE." ".__LINE__."; Log->variables() called without Log->level: [".$anvil->Log->level."] defined from: [$source : $line]\n";
}
#print "level: [$level], logging: [".$anvil->Log->level."], secure: [$secure], logging secure: [".$anvil->Log->secure."]\n";
print "level: [$level], logging: [".$anvil->Log->level."], secure: [$secure], logging secure: [".$anvil->Log->secure."]\n" if $test;
if ($level > $anvil->Log->level)
{
return(1);

@ -964,7 +964,8 @@ sub get_ips
my $in_iface = "";
my $shell_call = $anvil->data->{path}{exe}{ip}." addr list";
my $output = "";
if ($anvil->Network->is_local({host => $target}))
my $is_local = $anvil->Network->is_local({host => $target});
if ($is_local)
{
# Local call.
($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
@ -1058,7 +1059,7 @@ sub get_ips
# we'll read them all in.
$shell_call = $anvil->data->{path}{exe}{ls}." ".$anvil->data->{path}{directories}{ifcfg};
$output = "";
if ($anvil->Network->is_local({host => $target}))
if ($is_local)
{
# Local call.
($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
@ -1154,7 +1155,7 @@ sub get_ips
my $route_ip = "";
$shell_call = $anvil->data->{path}{exe}{ip}." route show";
$output = "";
if ($anvil->Network->is_local({host => $target}))
if ($is_local)
{
# Local call.
($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
@ -1222,7 +1223,7 @@ sub get_ips
my $dns_hash = {};
my $shell_call = $anvil->data->{path}{exe}{nmcli}." dev show";
my $output = "";
if ($anvil->Network->is_local({host => $target}))
if ($is_local)
{
# Local call.
($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
@ -1369,6 +1370,7 @@ Parameters;
This is the host name (or IP address) to check against the local system.
=cut
### NOTE: Do not log in here, it will cause a recursive loop!
sub is_local
{
my $self = shift;
@ -1376,45 +1378,49 @@ sub is_local
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
# To avoid deep recurssion, we set this on the first call so that anything below that re-calls us just gets a quick '1' and returns
$anvil->data->{env}{checking_local} = 0 if not defined $anvil->data->{env}{checking_local};
return(1) if $anvil->data->{env}{checking_local};
$anvil->data->{env}{checking_local} = 1;
my $host = $parameter->{host} ? $parameter->{host} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host }});
return(1) if not $host;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host => $host,
}});
# If we've checked this host before, return the cached answer
if (exists $anvil->data->{cache}{is_local}{$host})
{
return($anvil->data->{cache}{is_local}{$host});
}
my $is_local = 0;
$anvil->data->{cache}{is_local}{$host} = 0;
if (($host eq $anvil->_host_name) or
($host eq $anvil->_short_host_name) or
($host eq "localhost") or
($host eq "127.0.0.1"))
{
# It's local
$is_local = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }});
$anvil->data->{cache}{is_local}{$host} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cache::is_local::${host}" => $anvil->data->{cache}{is_local}{$host} }});
}
else
{
### NOTE: We use the undocumented 'is_local' parameter to avoid ->get_ips() calling us,
### causing a recursive loop.
# Get the list of current IPs and see if they match.
$anvil->Network->get_ips({debug => 3});
if (not exists $anvil->data->{network}{'local'}{interface})
{
$anvil->Network->get_ips({debug => 9999});
}
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "network::local::interface::${interface}::ip" => $anvil->data->{network}{'local'}{interface}{$interface}{ip} }});
#$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "network::local::interface::${interface}::ip" => $anvil->data->{network}{'local'}{interface}{$interface}{ip} }});
if ($host eq $anvil->data->{network}{'local'}{interface}{$interface}{ip})
{
$is_local = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }});
$anvil->data->{cache}{is_local}{$host} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cache::is_local::${host}" => $anvil->data->{cache}{is_local}{$host} }});
last;
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }});
delete $anvil->data->{env}{checking_local};
return($is_local);
#$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }});
return($anvil->data->{cache}{is_local}{$host});
}
# =head3

@ -1651,7 +1651,6 @@ sub read_file
return("!!error!!");
}
### NOTE: This is called by 'is_local', so it pre-sets 'is_local' to avoid a deep recursion.
# Reading locally or remote?
if ($anvil->Network->is_local({host => $target}))
{

@ -781,7 +781,7 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a
<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_0449">Parsed: [#!variable!records!#], adding/updating them to the database now.</key>
<key name="log_0450">Skipping the network scan. The next scheduled scan will be done in: [#!variable!next_scan!#] second(s). Override with '--force'.</key>
<key name="log_0450">Skipping the network scan. The next scheduled scan will be done in: [#!variable!next_scan!#]. Override with '--force'.</key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>

@ -1085,7 +1085,7 @@ sub prep_database
if ($host_type eq "dashboard")
{
my ($database_output, $return_code) = $anvil->System->call({
debug => 2,
debug => 3,
shell_call => $anvil->data->{path}{exe}{'striker-prep-database'},
source => $THIS_FILE,
line => __LINE__,

@ -53,16 +53,21 @@ my $process = 0;
if (-e $oui_file)
{
# How long ago did we download it?
my $mtime = (stat($oui_file))[9];
my $size = (stat($oui_file))[7];
my $age = time - $mtime;
my $refresh_time = 259200;
my $modified_time = (stat($oui_file))[9];
my $size = (stat($oui_file))[7];
my $age = time - $modified_time;
my $download_after = $refresh_time - $age;
$download_after = 0 if $download_after < 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:oui_file' => $oui_file,
's2:mtime' => $mtime." (".$anvil->Get->date_and_time({use_time => $mtime}).")",
's3:age' => $anvil->Convert->add_commas({number => $age})." (".$anvil->Convert->time({'time' => $age, translate => 1}).")",
's4:size' => $anvil->Convert->add_commas({number => $size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $size}).")",
's1:oui_file' => $oui_file,
's2:modified_time' => $modified_time." (".$anvil->Get->date_and_time({use_time => $modified_time}).")",
's3:age' => $anvil->Convert->add_commas({number => $age})." (".$anvil->Convert->time({'time' => $age, translate => 1}).")",
's4:refresh_time' => $anvil->Convert->add_commas({number => $refresh_time})." (".$anvil->Convert->time({'time' => $refresh_time, translate => 1}).")",
's5:download_after' => $anvil->Convert->add_commas({number => $download_after})." (".$anvil->Convert->time({'time' => $download_after, translate => 1}).")",
's6:size' => $anvil->Convert->add_commas({number => $size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $size}).")",
}});
if (($age < 259200) && ($size > 0))
if (($download_after) && ($size > 0))
{
# It's less than three days old, don't download. Do parse though (for now at least)
$download = 0;

Loading…
Cancel
Save