diff --git a/nftables/active.cgi b/nftables/active.cgi index e8472dc68..ed728396b 100755 --- a/nftables/active.cgi +++ b/nftables/active.cgi @@ -7,7 +7,8 @@ use strict; use warnings; our (%text); -ui_print_header(undef, $text{'active_title'}, "", "intro", 1, 1); +ui_print_header(undef, $text{'active_title'}, "", "intro", 1, 1, + undef, restart_button()); my ($tables, $err) = get_active_nftables_save(); if ($err) { diff --git a/nftables/active_table.cgi b/nftables/active_table.cgi index 082aada68..5065161fa 100755 --- a/nftables/active_table.cgi +++ b/nftables/active_table.cgi @@ -24,7 +24,8 @@ my @saved_tables = get_nftables_save(); my $status_key = active_table_status($table, \@saved_tables); my $is_saved = table_is_webmin_managed($table, \@saved_tables); -ui_print_header(undef, $text{'active_table_title'}, "", "intro", 1, 1); +ui_print_header(undef, $text{'active_table_title'}, "", "intro", 1, 1, + undef, restart_button()); print ui_table_start($text{'active_table_summary'}, "width=100%", 2); print ui_table_row($text{'active_table'}, html_escape(nft_table_spec($table))); diff --git a/nftables/clear_table.cgi b/nftables/clear_table.cgi index cff049737..76957e6a4 100755 --- a/nftables/clear_table.cgi +++ b/nftables/clear_table.cgi @@ -30,7 +30,8 @@ if ($in{'confirm'}) { return; } -ui_print_header(undef, $text{'clear_title'}, "", "intro", 1, 1); +ui_print_header(undef, $text{'clear_title'}, "", "intro", 1, 1, + undef, restart_button()); print "
\n"; print ui_form_start("clear_table.cgi"); print ui_hidden("family", $table->{'family'}); diff --git a/nftables/create_table.cgi b/nftables/create_table.cgi index 0456cc481..5a7122d9c 100755 --- a/nftables/create_table.cgi +++ b/nftables/create_table.cgi @@ -50,7 +50,8 @@ if ($in{'create'}) { return; } -ui_print_header(undef, $text{'create_title'}, "", "intro", 1, 1); +ui_print_header(undef, $text{'create_title'}, "", "intro", 1, 1, + undef, restart_button()); print ui_form_start("create_table.cgi"); print ui_hidden("create", 1); diff --git a/nftables/delete_table.cgi b/nftables/delete_table.cgi index a0470d69e..70a56435b 100755 --- a/nftables/delete_table.cgi +++ b/nftables/delete_table.cgi @@ -29,18 +29,21 @@ else { $table || error($text{'delete_notable'}); if ($in{'confirm'}) { + my $needs_apply = needs_config_restart(); splice(@tables, $table_idx, 1); my $err = delete_table_configuration($table, @tables); error(text('delete_failed', $err)) if ($err); $err = delete_active_table($table); error(text('delete_failed', $err)) if ($err); + restart_last_restart_time() if (!$needs_apply); webmin_log("delete", "table", $table->{'name'}, { 'family' => $table->{'family'} }); redirect("index.cgi"); return; } -ui_print_header(undef, $text{'delete_title'}, "", "intro", 1, 1); +ui_print_header(undef, $text{'delete_title'}, "", "intro", 1, 1, + undef, restart_button()); print "
\n"; print ui_form_start("delete_table.cgi"); print ui_hidden("table", $table_idx); diff --git a/nftables/edit_chain.cgi b/nftables/edit_chain.cgi index f7580b69e..41fde4db6 100644 --- a/nftables/edit_chain.cgi +++ b/nftables/edit_chain.cgi @@ -17,12 +17,14 @@ my $chain_name = ""; my $is_new = $in{'new'} ? 1 : 0; if ($is_new) { - ui_print_header(undef, $text{'chain_title_new'}, "", "intro", 1, 1); + ui_print_header(undef, $text{'chain_title_new'}, "", "intro", 1, 1, + undef, restart_button()); } else { $chain_name = $in{'chain'}; $chain = $table->{'chains'}->{$chain_name}; $chain || error($text{'chain_nochain'}); - ui_print_header(undef, $text{'chain_title_edit'}, "", "intro", 1, 1); + ui_print_header(undef, $text{'chain_title_edit'}, "", "intro", 1, 1, + undef, restart_button()); } my @type_opts = ( @@ -84,4 +86,3 @@ if (window.addEventListener) { EOF ui_print_footer("index.cgi?table=$in{'table'}", $text{'index_return'}); - diff --git a/nftables/edit_rule.cgi b/nftables/edit_rule.cgi index f531a2964..fc849b55b 100755 --- a/nftables/edit_rule.cgi +++ b/nftables/edit_rule.cgi @@ -47,10 +47,12 @@ sub split_multi_value } if ($in{'new'}) { - ui_print_header(undef, $text{'edit_title_new'}, "", "intro", 1, 1); + ui_print_header(undef, $text{'edit_title_new'}, "", "intro", 1, 1, + undef, restart_button()); $rule = { 'chain' => $in{'chain'} }; } else { - ui_print_header(undef, $text{'edit_title_edit'}, "", "intro", 1, 1); + ui_print_header(undef, $text{'edit_title_edit'}, "", "intro", 1, 1, + undef, restart_button()); $rule = $table->{'rules'}->[$in{'idx'}]; } if ($table && $rule->{'chain'}) { diff --git a/nftables/edit_set.cgi b/nftables/edit_set.cgi index bccd95787..c34caff5b 100755 --- a/nftables/edit_set.cgi +++ b/nftables/edit_set.cgi @@ -17,13 +17,15 @@ my $set_name = ""; my $is_new = $in{'new'} ? 1 : 0; if ($is_new) { - ui_print_header(undef, $text{'set_title_new'}, "", "intro", 1, 1); + ui_print_header(undef, $text{'set_title_new'}, "", "intro", 1, 1, + undef, restart_button()); } else { $set_name = $in{'set'}; $set = $table->{'sets'}->{$set_name}; $set || error($text{'set_noset'}); - ui_print_header(undef, $text{'set_title_edit'}, "", "intro", 1, 1); + ui_print_header(undef, $text{'set_title_edit'}, "", "intro", 1, 1, + undef, restart_button()); } my $elements_text = set_elements_text($set); diff --git a/nftables/import_table.cgi b/nftables/import_table.cgi index 99d012d36..3dc5a3d26 100755 --- a/nftables/import_table.cgi +++ b/nftables/import_table.cgi @@ -60,7 +60,8 @@ if ($in{'import'}) { return; } -ui_print_header(undef, $text{'import_title'}, "", "intro", 1, 1); +ui_print_header(undef, $text{'import_title'}, "", "intro", 1, 1, + undef, restart_button()); print ui_form_start("import_table.cgi"); print ui_hidden("family", $source->{'family'}); diff --git a/nftables/index.cgi b/nftables/index.cgi index 0bdae9aab..36f36ab56 100755 --- a/nftables/index.cgi +++ b/nftables/index.cgi @@ -9,7 +9,8 @@ our (%in, %text, %config); ReadParse(); my $partial = $in{'partial'}; if (!$partial) { - ui_print_header(undef, $text{'index_title'}, "", "intro", 1, 1); + ui_print_header(undef, $text{'index_title'}, "", "intro", 1, 1, + undef, restart_button()); } # Check for nft command @@ -279,7 +280,7 @@ print $rules_html; if (@tables) { print ui_hr(); print ui_buttons_start(); - print ui_buttons_row("apply.cgi", $text{'index_apply'}, $text{'index_applydesc'}); + print ui_buttons_row("restart.cgi", $text{'index_apply'}, $text{'index_applydesc'}); print ui_buttons_row("active.cgi", $text{'index_active'}, $text{'index_activedesc'}); print ui_buttons_row("setup.cgi", $text{'index_setup'}, $text{'index_setupdesc'}); print ui_buttons_end(); diff --git a/nftables/lang/en b/nftables/lang/en index 5e99a4e03..4b837c2f1 100644 --- a/nftables/lang/en +++ b/nftables/lang/en @@ -50,6 +50,7 @@ index_cdeletesel=Delete Selected Chains index_cmovesel=Move Selected index_radd=Add Rule index_apply=Apply Configuration +index_apply_changes=Apply Changes index_applydesc=Click this button to replace the saved Webmin-managed tables in the active nftables ruleset. index_active=View Active Ruleset index_activedesc=View active nftables tables and import copies into Webmin's saved configuration. diff --git a/nftables/nftables-lib.pl b/nftables/nftables-lib.pl index fcd2b56e0..d64428852 100644 --- a/nftables/nftables-lib.pl +++ b/nftables/nftables-lib.pl @@ -5,8 +5,63 @@ BEGIN { push(@INC, ".."); }; ## no critic use WebminCore; use strict; use warnings; -our (%config, $module_config_directory); +our (%config, $module_config_directory, $module_var_directory); +our ($last_config_change_flag, $last_restart_time_flag); init_config(); +$last_config_change_flag = $module_var_directory."/config-flag"; +$last_restart_time_flag = $module_var_directory."/restart-flag"; + +# restart_button() +# Returns HTML for the header apply button +sub restart_button +{ +my @tables = get_nftables_save(); +return "" if (!@tables); +my $args = "redir=".urlize(this_url()); +my $needs = needs_config_restart(); +my $apply = text('index_apply_changes'); +my $label = $needs ? "$apply" : $apply; +my $url = "restart.cgi?$args"; +$url .= "&newconfig=1" if ($needs); +return ui_link($url, $label); +} + +# this_url() +# Returns the URL in the nftables module for the current script +sub this_url +{ +my $url = $ENV{'SCRIPT_NAME'} || ""; +my $query = $ENV{'QUERY_STRING'} || ""; +$url .= "?$query" if ($query ne ""); +return $url; +} + +# update_last_config_change() +# Updates the flag file indicating when the saved config was changed +sub update_last_config_change +{ +open_tempfile(my $fh, ">$last_config_change_flag", 0, 1); +close_tempfile($fh); +} + +# restart_last_restart_time() +# Updates the flag file indicating when the saved config was applied +sub restart_last_restart_time +{ +open_tempfile(my $fh, ">$last_restart_time_flag", 0, 1); +close_tempfile($fh); +} + +# needs_config_restart() +# Returns 1 if saved config changes still need to be applied +sub needs_config_restart +{ +my @cst = stat($last_config_change_flag); +my @rst = stat($last_restart_time_flag); +return 0 if (!@cst); +return 1 if (!@rst); +return $cst[9] > $rst[9] ? 1 : 0; +} # get_nft_command() # Returns the configured nft command path, or finds it in PATH @@ -1198,6 +1253,7 @@ open_tempfile(my $fh, ">$file"); print_tempfile($fh, $out); close_tempfile($fh); sync_managed_metadata(@tables); +update_last_config_change(); return; } @@ -1294,6 +1350,7 @@ unlink_file($tmp); if ($?) { return "
$out
"; } +restart_last_restart_time(); return; } diff --git a/nftables/rename_chain.cgi b/nftables/rename_chain.cgi index 4c82e21c3..13ef7fe26 100644 --- a/nftables/rename_chain.cgi +++ b/nftables/rename_chain.cgi @@ -15,7 +15,8 @@ $table || error($text{'chain_notable'}); my $chain = $table->{'chains'}->{$in{'chain'}}; $chain || error($text{'chain_nochain'}); -ui_print_header(undef, $text{'rename_chain_title'}, "", "intro", 1, 1); +ui_print_header(undef, $text{'rename_chain_title'}, "", "intro", 1, 1, + undef, restart_button()); print ui_form_start("save_chain.cgi"); print ui_hidden("table", $in{'table'}); print ui_hidden("rename", 1); @@ -30,4 +31,3 @@ print ui_table_end(); print ui_form_end([ [ undef, $text{'rename_chain_ok'} ] ]); ui_print_footer("index.cgi?table=$in{'table'}", $text{'index_return'}); - diff --git a/nftables/apply.cgi b/nftables/restart.cgi similarity index 60% rename from nftables/apply.cgi rename to nftables/restart.cgi index 4fa246ec1..0ae1f1886 100755 --- a/nftables/apply.cgi +++ b/nftables/restart.cgi @@ -1,6 +1,6 @@ #!/usr/bin/perl -# apply.cgi -# Apply the current configuration +# restart.cgi +# Apply saved nftables configuration from the header action require './nftables-lib.pl'; ## no critic use strict; @@ -12,4 +12,5 @@ error_setup($text{'apply_err'}); my $err = apply_restore(); error($err) if ($err); -redirect("index.cgi"); +webmin_log("apply"); +redirect($in{'redir'} || "index.cgi"); diff --git a/nftables/setup.cgi b/nftables/setup.cgi index 0b0f287ab..8c6867361 100644 --- a/nftables/setup.cgi +++ b/nftables/setup.cgi @@ -47,7 +47,8 @@ if ($in{'action'} eq 'create') { return; } -ui_print_header(undef, $text{'setup_title'}, "", "intro", 1, 1); +ui_print_header(undef, $text{'setup_title'}, "", "intro", 1, 1, + undef, restart_button()); print ui_form_start("setup.cgi"); print ui_hidden("action", "create");