[5/5] ids-functions.pl: Use libarchive to extract archives

Message ID 20240330113530.1710702-5-stefan.schantl@ipfire.org
State Accepted
Commit ee16b227a55aa2ee61a906342ca322de3c0fcf67
Headers
Series [1/5] perl-Capture-Tiny: New package |

Commit Message

Stefan Schantl March 30, 2024, 11:35 a.m. UTC
  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>
---
 config/cfgroot/ids-functions.pl | 56 +++++++++++----------------------
 1 file changed, 18 insertions(+), 38 deletions(-)
  

Patch

diff --git a/config/cfgroot/ids-functions.pl b/config/cfgroot/ids-functions.pl
index c29a5151f..3eb883aa9 100644
--- a/config/cfgroot/ids-functions.pl
+++ b/config/cfgroot/ids-functions.pl
@@ -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);
-
-		# Get the filelist inside the tarball.
-		my @packed_files = $tar->list_files;
+		my $tar = Archive::Peek::Libarchive->new(filename => $tarball);
 
-		# 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 "$_";
-				}
+				# Open filehandle to append the content to the existing file.
+				open(FILE, ">>", "$destination") or die "Could not open $destination. $!\n";
+			}
 
-				# Close the file handles.
-				close(TMPFILE);
-				close(DESTFILE);
+			# Write the extracted file content to the filehandle.
+			print FILE "$content" if ($content);
 
-				# Remove the temporary file.
-				unlink("$tmpfile");
-			}
-		}
+			# Close the file handle.
+			close(FILE);
+		});
 	}
 }