ids-functions.pl: Use libarchive to extract archives

This gives us a lot of benefits:

* Speed up the extraction process
* More supported archive types due the power of libarchive
* Support of passphrase protected archives

It also fixes a problem with non extracted files next to a zero sized
file inside an archive.

Fixes #13632.

Signed-off-by: Stefan Schantl <stefan.schantl@ipfire.org>
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
This commit is contained in:
Stefan Schantl 2024-03-30 12:35:30 +01:00 committed by Michael Tremer
parent 2ef62acc01
commit ee16b227a5
1 changed files with 19 additions and 39 deletions

View File

@ -30,7 +30,7 @@ require "${General::swroot}/network-functions.pl";
require "${General::swroot}/suricata/ruleset-sources";
# Load perl module to deal with Archives.
use Archive::Tar;
use Archive::Peek::Libarchive;
# Load perl module to deal with files and path.
use File::Basename;
@ -515,9 +515,6 @@ sub downloadruleset ($) {
sub extractruleset ($) {
my ($provider) = @_;
# Disable chown functionality when uncompressing files.
$Archive::Tar::CHOWN = "0";
# Get full path and downloaded rulesfile for the given provider.
my $tarball = &_get_dl_rulesfile($provider);
@ -547,13 +544,11 @@ sub extractruleset ($) {
} elsif ( $type eq "archive") {
# Initialize the tar module.
my $tar = Archive::Tar->new($tarball);
my $tar = Archive::Peek::Libarchive->new(filename => $tarball);
# Get the filelist inside the tarball.
my @packed_files = $tar->list_files;
# Loop through the filelist.
foreach my $packed_file (@packed_files) {
# Loop through the archive
$tar->iterate( sub {
my ($packed_file, $content) = @_;
my $destination;
# Splitt the packed file into chunks.
@ -572,13 +567,13 @@ sub extractruleset ($) {
# Handle rules files.
} elsif ($file =~ m/\.rules$/) {
# Skip rule files which are not located in the rules directory or archive root.
next unless(($packed_file =~ /^rules\//) || ($packed_file =~ /^$provider-rules\//) || ($packed_file !~ /\//));
return unless(($packed_file =~ /^rules\//) || ($packed_file =~ /^$provider-rules\//) || ($packed_file !~ /\//));
# Skip deleted.rules.
#
# Mostly they have been taken out for correctness or performance reasons and therfore
# it is not a great idea to enable any of them.
next if($file =~ m/deleted.rules$/);
return if($file =~ m/deleted.rules$/);
my $rulesfilename;
@ -615,39 +610,24 @@ sub extractruleset ($) {
$destination = "$tmp_rules_directory/$rulesfilename";
} else {
# Skip all other files.
next;
return;
}
# Check if the destination file exists.
unless(-e "$destination") {
# Extract the file to the temporary directory.
$tar->extract_file("$packed_file", "$destination");
# Open filehandle to write the content to a new file.
open(FILE, ">", "$destination") or die "Could not open $destination. $!\n";
} else {
# Generate temporary file name, located in the temporary rules directory and a suffix of ".tmp".
my $tmp = File::Temp->new( SUFFIX => ".tmp", DIR => "$tmp_rules_directory", UNLINK => 0 );
my $tmpfile = $tmp->filename();
# Extract the file to the new temporary file name.
$tar->extract_file("$packed_file", "$tmpfile");
# Open the the existing file.
open(DESTFILE, ">>", "$destination") or die "Could not open $destination. $!\n";
open(TMPFILE, "<", "$tmpfile") or die "Could not open $tmpfile. $!\n";
# Loop through the content of the temporary file.
while (<TMPFILE>) {
# Append the content line by line to the destination file.
print DESTFILE "$_";
}
# Close the file handles.
close(TMPFILE);
close(DESTFILE);
# Remove the temporary file.
unlink("$tmpfile");
# Open filehandle to append the content to the existing file.
open(FILE, ">>", "$destination") or die "Could not open $destination. $!\n";
}
}
# Write the extracted file content to the filehandle.
print FILE "$content" if ($content);
# Close the file handle.
close(FILE);
});
}
}