From: Stefan Schantl <stefan.schantl@ipfire.org>
To: development@lists.ipfire.org
Cc: Stefan Schantl <stefan.schantl@ipfire.org>
Subject: [PATCH 3/3] ids-functions.pl: Use new general downloader function.
Date: Sat, 22 Mar 2025 15:57:24 +0100 [thread overview]
Message-ID: <20250322145724.4593-3-stefan.schantl@ipfire.org> (raw)
In-Reply-To: <20250322145724.4593-1-stefan.schantl@ipfire.org>
Signed-off-by: Stefan Schantl <stefan.schantl@ipfire.org>
---
config/cfgroot/ids-functions.pl | 196 +++-----------------------------
1 file changed, 17 insertions(+), 179 deletions(-)
diff --git a/config/cfgroot/ids-functions.pl b/config/cfgroot/ids-functions.pl
index 399f5cbf8..9f548e2e7 100644
--- a/config/cfgroot/ids-functions.pl
+++ b/config/cfgroot/ids-functions.pl
@@ -130,9 +130,6 @@ my $suricatactrl = "/usr/local/bin/suricatactrl";
# Prefix for each downloaded ruleset.
my $dl_rulesfile_prefix = "idsrules";
-# Temporary directory to download the rules files.
-my $tmp_dl_directory = "/var/tmp";
-
# Temporary directory where the rulesets will be extracted.
my $tmp_directory = "/tmp/ids_tmp";
@@ -299,61 +296,13 @@ sub checkdiskspace () {
#
## This function is responsible for downloading the ruleset for a given provider.
##
-## * At first it initialize the downloader and sets an upstream proxy if configured.
-## * The next step will be to generate the final download url, by obtaining the URL for the desired
-## ruleset and add the settings for the upstream proxy.
-## * Finally the function will grab the rule file or tarball from the server.
-## It tries to reduce the amount of download by using the "If-Modified-Since" HTTP header.
-#
-## Return codes:
-##
-## * "no url" - If no download URL could be gathered for the provider.
-## * "not modified" - In case the already stored rules file is up to date.
-## * "incomplete download" - When the remote file size differs from the downloaded file size.
-## * "$error" - The error message generated from the LWP::User Agent module.
+## It uses the LWP-based downloader function from the general-functions.pl to
+## download the ruleset for a requested provider.
#
sub downloadruleset ($) {
my ($provider) = @_;
- # The amount of download attempts before giving up and
- # logging an error.
- my $max_dl_attempts = 3;
-
- # Read proxysettings.
- my %proxysettings=();
- &General::readhash("${General::swroot}/proxy/settings", \%proxysettings);
-
- # Init the download module.
- #
- # Request SSL hostname verification and specify path
- # to the CA file.
- my $downloader = LWP::UserAgent->new(
- ssl_opts => {
- SSL_ca_file => '/etc/ssl/cert.pem',
- verify_hostname => 1,
- }
- );
-
- # Set timeout to 10 seconds.
- $downloader->timeout(10);
-
- # Check if an upstream proxy is configured.
- if ($proxysettings{'UPSTREAM_PROXY'}) {
- my $proxy_url;
-
- $proxy_url = "http://";
-
- # Check if the proxy requires authentication.
- if (($proxysettings{'UPSTREAM_USER'}) && ($proxysettings{'UPSTREAM_PASSWORD'})) {
- $proxy_url .= "$proxysettings{'UPSTREAM_USER'}\:$proxysettings{'UPSTREAM_PASSWORD'}\@";
- }
-
- # Add proxy server address and port.
- $proxy_url .= $proxysettings{'UPSTREAM_PROXY'};
-
- # Setup proxy settings.
- $downloader->proxy(['http', 'https'], $proxy_url);
- }
+ my %settings = ();
# Grab the download url for the provider.
my $url = $IDS::Ruleset::Providers{$provider}{'dl_url'};
@@ -371,141 +320,30 @@ sub downloadruleset ($) {
# Abort and return "no url", if no url could be determined for the provider.
return "no url" unless ($url);
- # Pass the requested URL to the downloader.
- my $request = HTTP::Request->new(GET => $url);
-
- # Generate temporary file name, located in the tempoary download directory and with a suffix of ".tmp".
- # The downloaded file will be stored there until some sanity checks are performed.
- my $tmp = File::Temp->new( SUFFIX => ".tmp", DIR => "$tmp_dl_directory/", UNLINK => 0 );
- my $tmpfile = $tmp->filename();
+ # Pass the requested URL to the settings hash.
+ $settings{'URL'} = $url;
# Call function to get the final path and filename for the downloaded file.
my $dl_rulesfile = &_get_dl_rulesfile($provider);
- # Check if the rulesfile already exits, because it has been downloaded in the past.
- #
- # In this case we are requesting the server if the remote file has been changed or not.
- # This will be done by sending the modification time in a special HTTP header.
- if (-f $dl_rulesfile) {
- # Call stat on the file.
- my $stat = stat($dl_rulesfile);
-
- # Omit the mtime of the existing file.
- my $mtime = $stat->mtime;
-
- # Convert the timestamp into right format.
- my $http_date = time2str($mtime);
+ # Add the file information to the settings hash.
+ $settings{'FILE'} = $dl_rulesfile;
- # Add the If-Modified-Since header to the request to ask the server if the
- # file has been modified.
- $request->header( 'If-Modified-Since' => "$http_date" );
- }
-
- # Read-in Etags file for known Etags if the file is present.
- my %etags = ();
- &General::readhash("$etags_file", \%etags) if (-f $etags_file);
+ # Add Etag details to the settings hash.
+ $settings{'ETAGSFILE'} = $etags_file;
+ $settings{'ETAGPREFIX'} = $provider;
- # Check if an Etag for the current provider is stored.
- if ($etags{$provider}) {
- # Grab the stored tag.
- my $etag = $etags{$provider};
+ # Call the downloader and pass the settings hash.
+ my $response = &General::downloader(%settings);
- # Add an "If-None-Match header to the request to ask the server if the
- # file has been modified.
- $request->header( 'If-None-Match' => $etag );
+ # Return the response message if the downloader provided one.
+ if ($response) {
+ return $response;
}
- my $dl_attempt = 1;
- my $response;
-
- # Download and retry on failure.
- while ($dl_attempt <= $max_dl_attempts) {
- # Perform the request and save the output into the tmpfile.
- $response = $downloader->request($request, $tmpfile);
-
- # Check if the download was successfull.
- if($response->is_success) {
- # Break loop.
- last;
-
- # Check if the server responds with 304 (Not Modified).
- } elsif ($response->code == 304) {
- # Remove temporary file, if one exists.
- unlink("$tmpfile") if (-e "$tmpfile");
-
- # Return "not modified".
- return "not modified";
-
- # Check if we ran out of download re-tries.
- } elsif ($dl_attempt eq $max_dl_attempts) {
- # Obtain error.
- my $error = $response->content;
-
- # Remove temporary file, if one exists.
- unlink("$tmpfile") if (-e "$tmpfile");
-
- # Return the error message from response..
- return "$error";
- }
-
- # Remove temporary file, if one exists.
- unlink("$tmpfile") if (-e "$tmpfile");
-
- # Increase download attempt counter.
- $dl_attempt++;
- }
-
- # Obtain the connection headers.
- my $headers = $response->headers;
-
- # Get the timestamp from header, when the file has been modified the
- # last time.
- my $last_modified = $headers->last_modified;
-
- # Get the remote size of the downloaded file.
- my $remote_filesize = $headers->content_length;
-
- # Grab the Etag from response it the server provides one.
- if ($response->header('Etag')) {
- # Add the Etag to the etags hash.
- $etags{$provider} = $response->header('Etag');
-
- # Write the etags file.
- &General::writehash($etags_file, \%etags);
- }
-
- # Perform stat on the tmpfile.
- my $stat = stat($tmpfile);
-
- # Grab the local filesize of the downloaded tarball.
- my $local_filesize = $stat->size;
-
- # Check if both file sizes match.
- if (($remote_filesize) && ($remote_filesize ne $local_filesize)) {
- # Delete temporary file.
- unlink("$tmpfile");
-
- # Return "1" - false.
- return "incomplete download";
- }
-
- # Overwrite the may existing rulefile or tarball with the downloaded one.
- move("$tmpfile", "$dl_rulesfile");
-
- # Check if we got a last-modified value from the server.
- if ($last_modified) {
- # Assign the last-modified timestamp as mtime to the
- # rules file.
- utime(time(), "$last_modified", "$dl_rulesfile");
- }
-
- # Delete temporary file.
- unlink("$tmpfile");
-
- # Set correct ownership for the tarball.
- set_ownership("$dl_rulesfile");
+ # Set correct ownership for the downloaded rules file.
+ &set_ownership("$dl_rulesfile");
- # If we got here, everything worked fine. Return nothing.
return;
}
--
2.47.2
next prev parent reply other threads:[~2025-03-22 15:07 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-22 14:57 [PATCH 1/3] general-functions.pl: Add LWP-based flexible " Stefan Schantl
2025-03-22 14:57 ` [PATCH 2/3] general-functions.pl: Use new downloader for FetchPublicIp function Stefan Schantl
2025-03-23 12:08 ` Michael Tremer
2025-03-22 14:57 ` Stefan Schantl [this message]
2025-03-23 12:08 ` [PATCH 1/3] general-functions.pl: Add LWP-based flexible downloader function Michael Tremer
2025-03-23 19:00 ` Stefan Schantl
2025-03-24 10:02 ` Michael Tremer
2025-03-26 12:47 ` Stefan Schantl
2025-03-26 16:18 ` Michael Tremer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250322145724.4593-3-stefan.schantl@ipfire.org \
--to=stefan.schantl@ipfire.org \
--cc=development@lists.ipfire.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox