From fe8545703d5489ebc3496e82956ca5ccb05a0275 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Fri, 25 Jul 2025 02:05:50 +0300 Subject: [PATCH] Add support for timeouts in temporary rules in FirewallD https://forum.virtualmin.com/t/fantastic-new-addition-to-firewall-module/134328/10?u=ilia --- firewalld/config | 1 + firewalld/config.info | 1 + firewalld/config_info.pl | 48 ++++++++++++++++++++++++++++++++++++++ firewalld/firewalld-lib.pl | 11 ++++++++- firewalld/lang/en | 15 ++++++++++++ firewalld/manage_ip.cgi | 6 +++-- 6 files changed, 79 insertions(+), 3 deletions(-) create mode 100755 firewalld/config_info.pl diff --git a/firewalld/config b/firewalld/config index 41f25fb31..7f597097e 100644 --- a/firewalld/config +++ b/firewalld/config @@ -2,3 +2,4 @@ firewall_cmd=firewall-cmd init_name=firewalld config_dir=/etc/firewalld packet_handling=0 +timeout=0 diff --git a/firewalld/config.info b/firewalld/config.info index 0b77490d9..6f4b52724 100644 --- a/firewalld/config.info +++ b/firewalld/config.info @@ -2,3 +2,4 @@ firewall_cmd=Full path to firewall-cmd program,0 init_name=FirewallD init script name,0 config_dir=FirewallD configuration directory,0 packet_handling=Default packet handling action,1,0-drop,1-reject +timeout=Timeout for temporary rules,15,timeout_data diff --git a/firewalld/config_info.pl b/firewalld/config_info.pl new file mode 100755 index 000000000..5e88a08a5 --- /dev/null +++ b/firewalld/config_info.pl @@ -0,0 +1,48 @@ +require './firewalld-lib.pl'; + +# show_timeout_data(value, config-option-name) +# Returns a radio button and a select box for timeout values +sub show_timeout_data +{ +my ($value, $name) = @_; +$name = &format_option_name($name); +my $radio = &ui_radio( + "${name}_def", !$value ? 1 : 0, + [ [ 1, $text{'config_timeout_none'} ], + [ 0, ' ' ] ] ); +my @list = &get_timeouts(); +my @opts = map { [ $_, $text{"config_timeout_$_"} ] } @list; +my $select = &ui_select($name, !$value ? $list[3] : $value, \@opts); +return $radio . ' ' . $select; +} + +# parse_timeout_data(old-value, config-option-name) +# Parses the timeout value from the form input +sub parse_timeout_data +{ +my ($oldval, $name) = @_; +$name = &format_option_name($name); +my $val = $in{$name} // ''; +return 0 if ($in{"${name}_def"}); +my %valid = map { $_ => 1 } &get_timeouts(); +&error(&text('config_timeout_err', $val)) unless($valid{$val}); +return $val; +} + +# get_timeouts +# Returns a list of valid timeout values for the select box +sub get_timeouts +{ +return qw(1m 5m 15m 30m 1h 3h 6h 12h 1d 3d 7d 30d); +} + +# format_option_name(name) +# Formats the option name for use in HTML element names +sub format_option_name +{ +my ($name) = @_; +$name =~ s/\s+/_/g; +$name =~ s/[^\x00-\x7F]/_/g; +$name = lc($name); +return $name; +} diff --git a/firewalld/firewalld-lib.pl b/firewalld/firewalld-lib.pl index 420ccc21c..9f69786ac 100644 --- a/firewalld/firewalld-lib.pl +++ b/firewalld/firewalld-lib.pl @@ -540,6 +540,14 @@ if (!$zone) { $zone = $zone->{'name'}; } +# Timeout +my $timeout = $opts->{'timeout'}; +if ($timeout) { + # Validate timeout format + &error(&text('config_timeout_err', $timeout)) + if ($timeout !~ /^(\d+)([smhd]?)$/); + } + # Permanent rule my $permanent = $opts->{'permanent'}; @@ -548,7 +556,8 @@ my $get_cmd = sub { my ($rtype) = @_; my $type = $rtype ? " --permanent" : ""; return "$config{'firewall_cmd'} --zone=\"".quotemeta($zone)."\"". - "$type --".quotemeta($action)."-rich-rule='$opts->{'rule'}'"; + "$type --".quotemeta($action)."-rich-rule='$opts->{'rule'}'". + ($timeout ? " --timeout=".quotemeta($timeout) : ""); }; for my $type (0..1) { diff --git a/firewalld/lang/en b/firewalld/lang/en index 732b4f453..44510e017 100644 --- a/firewalld/lang/en +++ b/firewalld/lang/en @@ -50,6 +50,21 @@ index_dependent=Failed to restart $1 dependent service index_manual=Edit Config Files. index_downrules=FirewallD rules cannot be created or edited and are not enforced unless the server is running. +config_timeout_none=None +config_timeout_1m=1 minute +config_timeout_5m=5 minutes +config_timeout_15m=15 minutes +config_timeout_30m=30 minutes +config_timeout_1h=1 hour +config_timeout_3h=3 hours +config_timeout_6h=6 hours +config_timeout_12h=12 hours +config_timeout_1d=1 day +config_timeout_3d=3 days +config_timeout_7d=7 days +config_timeout_30d=30 days +config_timeout_err=Invalid timeout value $1 + manual_title=Edit Config Files manual_editsel=Edit FirewallD configuration file manual_err=Failed to save config file diff --git a/firewalld/manage_ip.cgi b/firewalld/manage_ip.cgi index cb831da33..6cecbcb4e 100755 --- a/firewalld/manage_ip.cgi +++ b/firewalld/manage_ip.cgi @@ -6,7 +6,7 @@ use warnings; no warnings 'redefine'; no warnings 'uninitialized'; require './firewalld-lib.pl'; -our (%in, %text); +our (%in, %text, %config); &ReadParse(); # Setup error messages @@ -31,6 +31,7 @@ $ip =~ s/\Q$mask\E// if ($mask); # Block the IP my $perm = $in{'permanent'} ? 'perm' : ''; +my $timeout = $config{'timeout'} unless ($perm && $config{'timeout'}); my ($out, $rs) = &rich_rule('add', { 'rule' => &construct_rich_rule( @@ -38,7 +39,8 @@ my ($out, $rs) = &rich_rule('add', 'action' => $allow ? 'accept' : undef, 'priority' => $allow ? -32767 : -32766, ), - 'zone' => $zone->{'name'}, 'permanent' => $perm }); + 'zone' => $zone->{'name'}, 'permanent' => $perm, + 'timeout' => $timeout }); &error($out) if ($rs); &apply_firewalld() if ($perm);