Files
webmin/nftables/import_table.cgi
Ilia Ross 12eff54277 Add nftables apply-needed header action
* Note: Track saved nftables configuration changes with Apache-style config/apply timestamp flags, expose the standard restart.cgi header action for themes, and use it as the single apply endpoint. The button expands to “Apply Changes” when saved rules need applying, while the existing Apply Configuration action now routes through restart.cgi and clears the pending state after a successful apply.
2026-05-03 13:59:58 +02:00

106 lines
3.0 KiB
Perl
Executable File

#!/usr/bin/perl
# import_table.cgi
# Import an active nftables table as a Webmin-managed saved table
require './nftables-lib.pl'; ## no critic
use strict;
use warnings;
use Storable qw(dclone);
our (%in, %text);
ReadParse();
error_setup($text{'import_err'});
my ($active, $active_err) = get_active_nftables_save();
error(text('active_failed', $active_err)) if ($active_err);
my $source;
foreach my $t (@$active) {
if ($t->{'family'} eq $in{'family'} && $t->{'name'} eq $in{'name'}) {
$source = $t;
last;
}
}
$source || error($text{'import_esource'});
my @tables = get_nftables_save();
if (table_is_webmin_managed($source, \@tables)) {
error(text('import_emanaged', nft_table_spec($source)));
}
if ($in{'import'}) {
my $name = $in{'new_name'};
$name =~ /^\w[\w-]*$/ || error($text{'create_ename'});
foreach my $t (@tables) {
if ($t->{'family'} eq $source->{'family'} && $t->{'name'} eq $name) {
error($text{'create_edup'});
}
}
foreach my $t (@$active) {
if ($t->{'family'} eq $source->{'family'} && $t->{'name'} eq $name &&
table_is_externally_managed($t)) {
error(text('import_eexternal', nft_table_spec($t)));
}
}
my $import = dclone($source);
$import->{'name'} = $name;
delete($import->{'flags'});
push(@tables, $import);
write_configuration(@tables);
register_managed_table($import,
'source' => 'imported',
'imported_from' => nft_table_spec($source),
'imported_from_family' => $source->{'family'},
'imported_from_name' => $source->{'name'},
'imported_at' => time());
webmin_log("import", "table", $source->{'name'},
{ 'family' => $source->{'family'}, 'new' => $name });
redirect("index.cgi?table_family=".urlize($source->{'family'}).
"&table_name=".urlize($name));
return;
}
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'});
print ui_hidden("name", $source->{'name'});
print ui_hidden("import", 1);
print ui_table_start($text{'import_header'}, "width=100%", 2);
print ui_table_row($text{'import_source'}, html_escape(nft_table_spec($source)));
print ui_table_row($text{'import_flags'}, html_escape($source->{'flags'} || "-"));
print ui_table_row($text{'import_new_name'},
ui_textbox("new_name", unique_import_table_name($source, \@tables, $active), 30));
if (table_is_externally_managed($source)) {
print ui_table_row("", ui_note($text{'import_external_note'}),
undef, undef, undef, 1);
}
print ui_table_end();
print ui_form_end([ [ undef, $text{'import_ok'} ] ]);
ui_print_footer("active.cgi", $text{'active_return'});
sub unique_import_table_name
{
my ($source, $saved, $active_tables) = @_;
my $base = "imported_".$source->{'name'};
$base =~ s/[^\w-]/_/g;
$base = "imported_table" if ($base !~ /^\w/);
my %used;
foreach my $list ($saved, $active_tables) {
foreach my $t (@$list) {
next if ($t->{'family'} ne $source->{'family'});
$used{$t->{'name'}} = 1;
}
}
my $name = $base;
my $i = 1;
while ($used{$name}) {
$name = $base."_".$i++;
}
return $name;
}