+
+sub firewall_chain_exists ($) {
+ my ($chain) = @_;
+
+ my $ret = &General::system("iptables", "--wait", "-n", "-L", "$chain");
+
+ return $ret;
+}
+
+sub ipset_get_sets () {
+ my @sets;
+
+ # Get all currently used ipset lists and store them in an array.
+ my @output = `$IPSET -n list`;
+
+ # Loop through the temporary array.
+ foreach my $set (@output) {
+ # Remove any newlines.
+ chomp($set);
+
+ # Add the set the array of used sets.
+ push(@sets, $set);
+ }
+
+ # Display used sets in debug mode.
+ if($DEBUG) {
+ print "Used ipset sets:\n";
+ print "@sets\n\n";
+ }
+
+ # Return the array of sets.
+ return @sets;
+}
+
+sub ipset_restore ($) {
+ my ($set) = @_;
+
+ # Empty variable to store the db file, which should be
+ # restored by ipset.
+ my $db_file;
+
+ # Check if the set already has been loaded.
+ if($ipset_loaded_sets{$set}) {
+ # It already has been loaded - so there is nothing to do.
+ return;
+ }
+
+ # Check if the given set name is a country code.
+ if($set ~~ @locations) {
+ # Libloc adds the IP type (v4 or v6) as part of the set and file name.
+ my $loc_set = "$set" . "v4";
+
+ # The bare filename equals the set name.
+ my $filename = $loc_set;
+
+ # Libloc uses "ipset" as file extension.
+ my $file_extension = "ipset";
+
+ # Generate full path and filename for the ipset db file.
+ my $db_file = "$Location::Functions::ipset_db_directory/$filename.$file_extension";
+
+ # Call function to restore/load the set.
+ &ipset_call_restore($db_file);
+
+ # Check if the set is already loaded (has been used before).
+ if ($set ~~ @ipset_used_sets) {
+ # The sets contains the IP type (v4 or v6) as part of the name.
+ # The firewall rules matches against sets without that extension. So we safely
+ # can swap or rename the sets to use the new ones.
+ run("$IPSET swap $loc_set $set");
+ } else {
+ # If the set is not loaded, we have to rename it to proper use it.
+ run("$IPSET rename $loc_set $set");
+ }
+
+ # Check if the given set name is a blocklist.
+ } elsif ($set ~~ @blocklists) {
+ # IPblocklist sets contains v4 as setname extension.
+ my $set_name = "$set" . "v4";
+
+ # Get the database file for the given blocklist.
+ my $db_file = &IPblocklist::get_ipset_db_file($set);
+
+ # Call function to restore/load the set.
+ &ipset_call_restore($db_file);
+
+ # Check if the set is already loaded (has been used before).
+ if ($set ~~ @ipset_used_sets) {
+ # Swap the sets.
+ run("$IPSET swap $set_name $set");
+ } else {
+ # Rename the set to proper use it.
+ run("$IPSET rename $set_name $set");
+ }
+ }
+
+ # Store the restored set to the hash to prevent from loading it again.
+ $ipset_loaded_sets{$set} = "1";
+}
+
+sub ipset_call_restore ($) {
+ my ($file) = @_;
+
+ # Check if the requested file exists.
+ if (-f $file) {
+ # Run ipset and restore the given set.
+ run("$IPSET restore -f $file");
+ }
+}
+
+sub ipset_cleanup () {
+ # Reload the array of used sets.
+ @ipset_used_sets = &ipset_get_sets();
+
+ # Loop through the array of used sets.
+ foreach my $set (@ipset_used_sets) {
+ # Check if this set is still in use.
+ #
+ # In this case an entry in the loaded sets hash exists.
+ unless($ipset_loaded_sets{$set}) {
+ # Entry does not exist, so this set is not longer
+ # used and can be destroyed.
+ run("$IPSET destroy $set");
+ }
+ }
+}