]> git.proxmox.com Git - pve-firewall.git/commitdiff
api: Add optional parameters `since` and `until` for timestamp filter
authorChristian Ebner <c.ebner@proxmox.com>
Thu, 19 Jan 2023 10:25:04 +0000 (11:25 +0100)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Fri, 27 Jan 2023 09:49:55 +0000 (10:49 +0100)
The optional unix epoch timestamps parameters `since` and `until` are introduced
in order to filter firewall logs files. If one of these flags is set, also
rotated logfiles are included. This is handled in the `dump_fw_logfile` helper
function. Filtering is now performed based on a callback function passed to
`dump_fw_logfile`.

This patch depends on the corresponding patch in the pve-common repository.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
[w.bumiller@proxmox.com: fixup 'continue' -> 'next']
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
src/PVE/API2/Firewall/Host.pm
src/PVE/API2/Firewall/VM.pm
src/PVE/Firewall/Helpers.pm

index dfeccd08ef664e15264f87274fa3e0dc2c445633..0432de2224b7713ef787ff52ac996beebbaa2837 100644 (file)
@@ -172,6 +172,18 @@ __PACKAGE__->register_method({
                minimum => 0,
                optional => 1,
            },
+           since => {
+               type => 'integer',
+               minimum => 0,
+               description => "Display log since this UNIX epoch.",
+               optional => 1,
+           },
+           until => {
+               type => 'integer',
+               minimum => 0,
+               description => "Display log until this UNIX epoch.",
+               optional => 1,
+           },
        },
     },
     returns => {
@@ -196,8 +208,10 @@ __PACKAGE__->register_method({
        my $rpcenv = PVE::RPCEnvironment::get();
        my $user = $rpcenv->get_user();
        my $node = $param->{node};
+       my $filename = "/var/log/pve-firewall.log";
 
-       my ($count, $lines) = PVE::Tools::dump_logfile("/var/log/pve-firewall.log", $param->{start}, $param->{limit});
+       my ($count, $lines) = PVE::Firewall::Helpers::dump_fw_logfile(
+           $filename, $param, undef);
 
        $rpcenv->set_result_attrib('total', $count);
 
index 48b8c5fe2a974a02a0bb37d54fd4317b3d9f8cf6..fb255e0ccb6baeaee270610a1e6f9f34446ec34a 100644 (file)
@@ -176,6 +176,18 @@ sub register_handlers {
                    minimum => 0,
                    optional => 1,
                },
+               since => {
+                   type => 'integer',
+                   minimum => 0,
+                   description => "Display log since this UNIX epoch.",
+                   optional => 1,
+               },
+               until => {
+                   type => 'integer',
+                   minimum => 0,
+                   description => "Display log until this UNIX epoch.",
+                   optional => 1,
+               },
            },
        },
        returns => {
@@ -199,11 +211,17 @@ sub register_handlers {
 
            my $rpcenv = PVE::RPCEnvironment::get();
            my $user = $rpcenv->get_user();
-           my $vmid = $param->{vmid};
+           my $filename = "/var/log/pve-firewall.log";
+           my $vmid = $param->{'vmid'};
+
+           my $callback = sub {
+               my ($line) = @_;
+               my $reg = "^$vmid ";
+               return $line =~ m/$reg/;
+           };
 
-           my ($count, $lines) = PVE::Tools::dump_logfile("/var/log/pve-firewall.log",
-                                                          $param->{start}, $param->{limit},
-                                                          "^$vmid ");
+           my ($count, $lines) = PVE::Firewall::Helpers::dump_fw_logfile(
+               $filename, $param, $callback);
 
            $rpcenv->set_result_attrib('total', $count);
 
index 154fca5381723aaac9246783266018e9ef8160a2..a8e18e2b5e22593303d967126d4ffe32da6fe351 100644 (file)
@@ -3,6 +3,10 @@ package PVE::Firewall::Helpers;
 use strict;
 use warnings;
 
+use Date::Parse qw(str2time);
+use Errno qw(ENOENT);
+use File::Basename qw(fileparse);
+use IO::Zlib;
 use PVE::Cluster;
 use PVE::Tools qw(file_get_contents file_set_contents);
 
@@ -52,4 +56,78 @@ sub clone_vmfw_conf {
     });
 }
 
+sub dump_fw_logfile {
+    my ($filename, $param, $callback) = @_;
+    my ($start, $limit, $since, $until) = $param->@{qw(start limit since until)};
+
+    my $filter = sub {
+       my ($line) = @_;
+
+       if (defined($callback)) {
+           return undef if !$callback->($line);
+       }
+
+       if ($since || $until) {
+           my @words = split / /, $line;
+           my $timestamp = str2time($words[3], $words[4]);
+           return undef if $since && $timestamp < $since;
+           return undef if $until && $timestamp > $until;
+       }
+
+       return $line;
+    };
+
+    if (!defined($since) && !defined($until)) {
+       return PVE::Tools::dump_logfile($filename, $start, $limit, $filter);
+    }
+
+    my %state = (
+       'count' => 0,
+       'lines' => [],
+       'start' => $start,
+       'limit' => $limit,
+    );
+
+    # Take into consideration also rotated logs
+    my ($basename, $logdir, $type) = fileparse($filename);
+    my $regex = qr/^\Q$basename\E(\.[\d]+(\.gz)?)?$/;
+    my @files = ();
+
+    PVE::Tools::dir_glob_foreach($logdir, $regex, sub {
+       my ($file) = @_;
+       push @files,  $file;
+    });
+
+    @files = reverse sort @files;
+
+    my $filecount = 0;
+    for my $filename (@files) {
+       $state{'final'} = $filecount == $#files;
+       $filecount++;
+
+       my $fh;
+       if ($filename =~ /\.gz$/) {
+           $fh = IO::Zlib->new($logdir.$filename, "r");
+       } else {
+           $fh = IO::File->new($logdir.$filename, "r");
+       }
+
+       if (!$fh) {
+           # If file vanished since reading dir entries, ignore
+           next if $!{ENOENT};
+
+           my $lines = $state{'lines'};
+           my $count = ++$state{'count'};
+           push @$lines, ($count, { n => $count, t => "unable to open file - $!"});
+           last;
+       }
+
+       PVE::Tools::dump_logfile_by_filehandle($fh, $filter, \%state);
+
+       close($fh);
+    }
+
+    return ($state{'count'}, $state{'lines'});
+}
+
 1;