mirror of
https://github.com/webmin/webmin.git
synced 2025-07-21 23:40:34 +00:00
696 lines
17 KiB
Perl
Executable File
696 lines
17 KiB
Perl
Executable File
# firewall-lib.pl
|
|
# Unified functions for firewall4-lib and firewall6-lib
|
|
# has to be included from every perl and cgi script
|
|
# cgi scripts has also to include firewall4/6-lib based on result of get_ipvx_version()
|
|
|
|
BEGIN { push(@INC, ".."); };
|
|
use WebminCore;
|
|
&init_config();
|
|
|
|
$config{'perpage'} ||= 50; # a value of 0 can cause problems
|
|
|
|
# provide default values if only firewall-lib is included, e.g. foreign_require(firewall, firewall-lib.pl) calls
|
|
set_ipvx_version(get_ipvx_version());
|
|
|
|
# set_ipvx_version(version)
|
|
# version can be ipv6 or ipv4,
|
|
sub set_ipvx_version
|
|
{
|
|
$ipvx_save=$iptables_save_file;
|
|
$ipvx_lib='firewall4-lib.pl';
|
|
$ipv4_link='../firewall/';
|
|
$ipv6_link='../firewall6/';
|
|
$ipvx_icmp="";
|
|
$ipvx_arg="inet4";
|
|
|
|
if ($_[0] =~ /6$/i) {
|
|
$ipvx='6';
|
|
$ipvx_save=$ip6tables_save_file;
|
|
$ipvx_lib='firewall6-lib.pl';
|
|
$ipvx_icmp="v6";
|
|
$ipvx_arg="inet6";
|
|
}
|
|
}
|
|
|
|
# get_ipvx_version
|
|
# get iptables version used from environment
|
|
# if script runs in firewall6 or version=inet6, 6 is returned, else 4
|
|
sub get_ipvx_version
|
|
{
|
|
return $in{'version'} =~ /6$/ || $module_name =~ /6$/ ? 6 : 4;
|
|
}
|
|
|
|
|
|
# get_iptables_save([file|"direct"])
|
|
# Parse the iptables save file into a list of tables
|
|
# format seems to be:
|
|
# *table
|
|
# :chain defaultpolicy
|
|
# -A chain options
|
|
# -N chain
|
|
# COMMIT
|
|
sub get_iptables_save
|
|
{
|
|
local ($file) = @_;
|
|
local (@rv, $table, %got);
|
|
local $lnum = 0;
|
|
|
|
local $direct = "ip${ipvx}tables-save 2>/dev/null |";
|
|
if (!$file) {
|
|
# Use default file
|
|
$file = $config{"direct${ipvx}"} ? $direct : "<".$ipvx_save;
|
|
}
|
|
elsif ($file eq "direct") {
|
|
# Read active rules
|
|
$file = $direct;
|
|
}
|
|
open(FILE, $file);
|
|
local $cmt;
|
|
LINE:
|
|
while(<FILE>) {
|
|
local $read_comment;
|
|
s/\r|\n//g;
|
|
# regex to filter out chains not managed by firewall, i.e. fail2ban
|
|
if ($config{"direct${ipvx}"} && $config{'filter_chain'}) {
|
|
foreach $filter (split(',', $config{'filter_chain'})) {
|
|
# NOTE: keep ":chain ..." as reference to avoid error when rebuild active config
|
|
# -A|-I chain ... -j chain -> skip line if machtes filter_chain
|
|
if (/^.?-(A|I)\s+(\S+).*\s+-j\s+(.*)/) {
|
|
next LINE if($2 =~ /^$filter$/);
|
|
}
|
|
}
|
|
}
|
|
if (s/#\s*(.*)$//) {
|
|
$cmt .= " " if ($cmt);
|
|
$cmt .= $1;
|
|
$read_comment=1;
|
|
}
|
|
if (/^\*(\S+)/) {
|
|
# Start of a new table
|
|
$got{$1}++;
|
|
push(@rv, $table = { 'line' => $lnum,
|
|
'eline' => $lnum,
|
|
'name' => $1,
|
|
'rules' => [ ],
|
|
'defaults' => { } });
|
|
}
|
|
elsif (/^:(\S+)\s+(\S+)/) {
|
|
# Default policy definition
|
|
$table->{'defaults'}->{$1} = $2;
|
|
}
|
|
elsif (/^(\[[^\]]*\]\s+)?-N\s+(\S+)(.*)/) {
|
|
# New chain definition
|
|
$table->{'defaults'}->{$2} = '-';
|
|
}
|
|
elsif (/^(\[[^\]]*\]\s+)?-(A|I)\s+(\S+)(.*)/) {
|
|
# Rule definition
|
|
local $rule = { 'line' => $lnum,
|
|
'eline' => $lnum,
|
|
'index' => scalar(@{$table->{'rules'}}),
|
|
'cmt' => $cmt,
|
|
'chain' => $3,
|
|
'args' => $4 };
|
|
if ($2 eq "I") {
|
|
unshift(@{$table->{'rules'}}, $rule);
|
|
}
|
|
else {
|
|
push(@{$table->{'rules'}}, $rule);
|
|
}
|
|
|
|
# Parse arguments
|
|
foreach $a (@known_args) {
|
|
local @vl;
|
|
while($rule->{'args'} =~
|
|
s/\s+(!?)\s*($a)\s+(!?)\s*("[^"]*")(\s+|$)/ / ||
|
|
$rule->{'args'} =~
|
|
s/\s+(!?)\s*($a)\s+(!?)\s*('[^']*')(\s+|$)/ / ||
|
|
$rule->{'args'} =~
|
|
s/\s+(!?)\s*($a)\s+(!?)\s*(([^ \-!]\S*(\s+|$))+)/ / ||
|
|
$rule->{'args'} =~
|
|
s/\s+(!?)\s*($a)()(\s+|$)/ /) {
|
|
push(@vl, [ $1 || $3, &split_quoted_string($4) ]);
|
|
}
|
|
local ($aa = $a); $aa =~ s/^-+//;
|
|
if ($a eq '-m') {
|
|
$rule->{$aa} = \@vl if (@vl);
|
|
}
|
|
else {
|
|
$rule->{$aa} = $vl[0];
|
|
}
|
|
}
|
|
}
|
|
elsif (/^COMMIT/) {
|
|
# Marks end of a table
|
|
$table->{'eline'} = $lnum;
|
|
}
|
|
elsif (/\S/) {
|
|
&error(&text('eiptables', "<tt>$_</tt>"));
|
|
}
|
|
$lnum++;
|
|
if (! defined($read_comment)) { $cmt=undef; }
|
|
}
|
|
close(FILE);
|
|
@rv = sort { $a->{'name'} cmp $b->{'name'} } @rv;
|
|
local $i;
|
|
map { $_->{'index'} = $i++ } @rv;
|
|
return @rv;
|
|
}
|
|
|
|
# save_table(&table)
|
|
# Updates an existing IPtable in the save file
|
|
sub save_table
|
|
{
|
|
local $lref;
|
|
if ($config{"direct${ipvx}"}) {
|
|
# Read in the current iptables-save output
|
|
$lref = &read_file_lines("ip${ipvx}tables-save 2>/dev/null |", 1);
|
|
}
|
|
else {
|
|
# Updating the save file
|
|
$lref = &read_file_lines($ipvx_save);
|
|
}
|
|
local @lines = ( "*$_[0]->{'name'}" );
|
|
local ($d, $r);
|
|
foreach $d (keys %{$_[0]->{'defaults'}}) {
|
|
push(@lines, ":$d $_[0]->{'defaults'}->{$d} [0:0]");
|
|
}
|
|
foreach $r (@{$_[0]->{'rules'}}) {
|
|
local $line = "";
|
|
$line = "# $r->{'cmt'}\n" if ($r->{'cmt'});
|
|
$line .= &make_rule_command($r);
|
|
push(@lines, $line);
|
|
}
|
|
push(@lines, "COMMIT");
|
|
if (defined($_[0]->{'line'})) {
|
|
# Update in file
|
|
splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1,
|
|
@lines);
|
|
}
|
|
else {
|
|
# Append new table to file
|
|
push(@$lref, "# Generated by webmin", @lines, "# Completed");
|
|
}
|
|
if ($config{"direct${ipvx}"}) {
|
|
# Pass new lines to iptables-restore
|
|
open(SAVE, "| ip${ipvx}tables-restore");
|
|
print SAVE map { $_."\n" } @$lref;
|
|
close(SAVE);
|
|
}
|
|
else {
|
|
# Just save the file
|
|
&flush_file_lines();
|
|
}
|
|
}
|
|
|
|
# make_rule_command(&rule)
|
|
# Returns the flags needed to create a rule
|
|
sub make_rule_command
|
|
{
|
|
my ($r) = @_;
|
|
my $line = "-A $r->{'chain'}";
|
|
foreach my $a (@known_args) {
|
|
my $aa = $a;
|
|
$aa =~ s/^-+//;
|
|
if ($r->{$aa}) {
|
|
my @al = ref($r->{$aa}->[0]) ? @{$r->{$aa}} : ( $r->{$aa} );
|
|
foreach my $ag (@al) {
|
|
my $n = shift(@$ag);
|
|
my @w = ( $n ? ( $n ) : (), $a, @$ag );
|
|
@w = map { $_ =~ /'/ ? "\"$_\"" :
|
|
$_ =~ /"/ ? "'".$_."'" :
|
|
$_ =~ /\s/ ? "\"$_\"" : $_ } @w;
|
|
$line .= " ".join(" ", @w);
|
|
}
|
|
}
|
|
}
|
|
$line .= " $r->{'args'}" if ($r->{'args'} =~ /\S/);
|
|
return $line;
|
|
}
|
|
|
|
# get_ipsets_active()
|
|
# return a list of active ipsets
|
|
sub get_ipsets_active
|
|
{
|
|
my (@rv, $name, $set);
|
|
open(FILE, "ipset list -t 2>/dev/null |");
|
|
while(<FILE>) {
|
|
# remove newlines, get arg and value
|
|
s/\r|\n//g;
|
|
my ($n, $v) = split(/: /, $_);
|
|
$n =~ s/^(\S+).*/$1/;
|
|
if ($n eq "Name") {
|
|
$set = { };
|
|
push(@rv, $set);
|
|
}
|
|
$set->{$n} = $v;
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
|
|
# describe_rule(&rule)
|
|
# Returns a human-readable description of some rule conditions
|
|
sub describe_rule
|
|
{
|
|
my ($rule) = @_;
|
|
my (@c, $d);
|
|
foreach $d ('p', 's', 'd', 'i', 'o', 'f', 'dport',
|
|
'sport', 'tcp-flags', 'tcp-option',
|
|
'icmp-type', 'icmpv6-type', 'mac-source', 'limit', 'limit-burst',
|
|
'ports', 'uid-owner', 'gid-owner',
|
|
'pid-owner', 'sid-owner', 'ctstate', 'state', 'tos',
|
|
'dports', 'sports', 'physdev-in', 'physdev-out', 'match-set',
|
|
'args') {
|
|
if ($rule->{$d}) {
|
|
# get name and values
|
|
my ($n, @v) = @{$rule->{$d}};
|
|
# with additional args
|
|
if ($d eq 'args') {
|
|
# get args
|
|
@v = grep {/\S/} split(/ / , $rule->{$d});
|
|
# first arg is name, next are values
|
|
$n=shift(@v);
|
|
# translate src and dest parameter for ipset
|
|
push(@v, &text("desc_".pop(@v)))
|
|
if ($n eq "--match-set");
|
|
}
|
|
# uppercase for p
|
|
@v = map { uc($_) } @v if ($d eq 'p');
|
|
# merge all in one for s and d
|
|
@v = map { join(", ", split(/,/, $_)) } @v
|
|
if ($d eq 's' || $d eq 'd' );
|
|
# compose desc_$n$d to get myized message, provide values
|
|
# as $1, ..., $n
|
|
if ($d eq 'match-set') {
|
|
$v[1] = $text{'desc_'.$d.'_'.$v[1]} || $v[1];
|
|
}
|
|
my $txt = &text("desc_$d$n", map { "<b>$_</b>" } @v);
|
|
push(@c, $txt) if ($txt);
|
|
}
|
|
}
|
|
my $rv;
|
|
if (@c) {
|
|
$rv = &text('desc_conds', join(" $text{'desc_and'} ", @c));
|
|
}
|
|
else {
|
|
$rv = $text{'desc_always'};
|
|
}
|
|
return $rv;
|
|
}
|
|
|
|
# create_firewall_init()
|
|
# Do whatever is needed to have the firewall started at boot time
|
|
sub create_firewall_init
|
|
{
|
|
if (defined(&enable_at_boot)) {
|
|
# Use distro's function
|
|
&enable_at_boot();
|
|
}
|
|
else {
|
|
# May need to create init script
|
|
&create_webmin_init();
|
|
}
|
|
}
|
|
|
|
# create_webmin_init()
|
|
# Create (if necessary) the Webmin iptables init script
|
|
sub create_webmin_init
|
|
{
|
|
local $res = &iptables_restore_command();
|
|
local $ipt = &has_command("ip${ipvx}tables");
|
|
local $out = &backquote_command("$res -h 2>&1 </dev/null");
|
|
if ($out =~ /\s+-w\s+/) {
|
|
# Supports the wait flag, in case two instances are run at once
|
|
$res .= " -w";
|
|
$ipt .= " -w";
|
|
}
|
|
local $start = "$res <$ipvx_save";
|
|
local $stop = "$ipt -t filter -F\n".
|
|
"$ipt -t nat -F\n".
|
|
"$ipt -t mangle -F\n".
|
|
"$ipt -t filter -P INPUT ACCEPT\n".
|
|
"$ipt -t filter -P OUTPUT ACCEPT\n".
|
|
"$ipt -t filter -P FORWARD ACCEPT\n".
|
|
"$ipt -t nat -P PREROUTING ACCEPT\n".
|
|
"$ipt -t nat -P POSTROUTING ACCEPT\n".
|
|
"$ipt -t nat -P OUTPUT ACCEPT\n".
|
|
"$ipt -t mangle -P PREROUTING ACCEPT\n".
|
|
"$ipt -t mangle -P OUTPUT ACCEPT";
|
|
&foreign_require("init", "init-lib.pl");
|
|
&init::enable_at_boot("webmin-ip${ipvx}tables",
|
|
"Load ip${ipvx}tables save file",
|
|
$start, $stop, undef, { 'exit' => 1 });
|
|
}
|
|
|
|
# interface_choice(name, value)
|
|
sub interface_choice
|
|
{
|
|
local ($name, $value) = @_;
|
|
local @ifaces;
|
|
if (&foreign_check("net")) {
|
|
&foreign_require("net", "net-lib.pl");
|
|
return &net::interface_choice($name, $value, undef, 0, 1);
|
|
}
|
|
else {
|
|
return &ui_textbox($name, $value, 6);
|
|
}
|
|
}
|
|
|
|
sub check_previous
|
|
{
|
|
my (@p,$max,$n)=@_;
|
|
for ($i=0;$i<$max;$i++)
|
|
{
|
|
if ($n eq $p[$i]){return 1}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
sub by_string_for_iptables
|
|
{
|
|
my @p=("PREROUTING","INPUT","FORWARD","OUTPUT","POSTROUTING");
|
|
|
|
for ($i=0;$i<@p;$i++)
|
|
{
|
|
if ($a eq $p[$i]){
|
|
if (&check_previous(@p,$i,$b)){return -1;}
|
|
else{ return 1;}}
|
|
if ($b eq $p[$i]){
|
|
if (&check_previous(@p,$i,$b)){return 1;}
|
|
else{ return -1;}}
|
|
}
|
|
|
|
return $a cmp $b;
|
|
}
|
|
|
|
sub missing_firewall_commands
|
|
{
|
|
local $c;
|
|
foreach $c ("ip${ipvx}tables", "ip${ipvx}tables-restore", "ip${ipvx}tables-save") {
|
|
return $c if (!&has_command($c));
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub iptables_restore_command
|
|
{
|
|
return &has_command("ip${ipvx}tables-restore") ||
|
|
&has_command("ip${ipvx}tables-legacy-restore");
|
|
}
|
|
|
|
# iptables_restore()
|
|
# Activates the current firewall rules, and returns any error
|
|
sub iptables_restore
|
|
{
|
|
local $rcmd = &iptables_restore_command();
|
|
local $out = &backquote_logged("cd / && $rcmd <$ipvx_save 2>&1");
|
|
return $? ? "<pre>$out</pre>" : undef;
|
|
}
|
|
|
|
sub iptables_save_command
|
|
{
|
|
return &has_command("ip${ipvx}tables-save") ||
|
|
&has_command("ip${ipvx}tables-legacy-save");
|
|
}
|
|
|
|
# iptables_save()
|
|
# Saves the active firewall rules, and returns any error
|
|
sub iptables_save
|
|
{
|
|
local $scmd = &iptables_save_command();
|
|
local $out = &backquote_logged("cd / && $scmd >$ipvx_save 2>&1");
|
|
return $? ? "<pre>$out</pre>" : undef;
|
|
}
|
|
|
|
# can_edit_table(name)
|
|
sub can_edit_table
|
|
{
|
|
return $access{$_[0]};
|
|
}
|
|
|
|
# can_jump(jump|&rule)
|
|
sub can_jump
|
|
{
|
|
return 1 if (!$access{'jumps'});
|
|
if (!%can_jumps_cache) {
|
|
%can_jumps_cache = map { lc($_), 1 } split(/\s+/, $access{'jumps'});
|
|
}
|
|
local $j = ref($_[0]) ? $_[0]->{'j'}->[1] : $_[0];
|
|
return 1 if (!$j); # always allow 'do nothing'
|
|
return $can_jumps_cache{lc($j)};
|
|
}
|
|
|
|
# run_before_command()
|
|
# Runs the before-saving command, if any
|
|
sub run_before_command
|
|
{
|
|
if ($config{'before_cmd'}) {
|
|
&system_logged("($config{'before_cmd'}) </dev/null >/dev/null 2>&1");
|
|
}
|
|
}
|
|
|
|
# run_after_command()
|
|
# Runs the after-saving command, if any
|
|
sub run_after_command
|
|
{
|
|
if ($config{'after_cmd'}) {
|
|
&system_logged("($config{'after_cmd'}) </dev/null >/dev/null 2>&1");
|
|
}
|
|
}
|
|
|
|
# run_before_apply_command()
|
|
# Runs the before-applying command, if any. If it fails, returns the error
|
|
# message output
|
|
sub run_before_apply_command
|
|
{
|
|
if ($config{'before_apply_cmd'}) {
|
|
local $out = &backquote_logged("($config{'before_apply_cmd'}) </dev/null 2>&1");
|
|
return $out if ($?);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
# run_after_apply_command()
|
|
# Runs the after-applying command, if any
|
|
sub run_after_apply_command
|
|
{
|
|
if ($config{'after_apply_cmd'}) {
|
|
&system_logged("($config{'after_apply_cmd'}) </dev/null >/dev/null 2>&1");
|
|
}
|
|
}
|
|
|
|
# apply_configuration()
|
|
# Calls all the appropriate apply functions and programs, and returns an error
|
|
# message if anything fails
|
|
sub apply_configuration
|
|
{
|
|
local $err = &run_before_apply_command();
|
|
return $err if ($err);
|
|
local @oldlive = &get_iptables_save("direct");
|
|
if (defined(&apply_iptables)) {
|
|
# Call distro's apply command
|
|
$err = &apply_iptables();
|
|
}
|
|
else {
|
|
# Manually run iptables-restore
|
|
$err = &iptables_restore();
|
|
}
|
|
return $err if ($err);
|
|
if (!$config{"direct${ipvx}"}) {
|
|
# Put back fail2ban rules
|
|
local @newlive = &get_iptables_save("direct");
|
|
&merge_fail2ban_rules(\@oldlive, \@newlive);
|
|
}
|
|
&run_after_apply_command();
|
|
return undef;
|
|
}
|
|
|
|
# merge_fail2ban_rules(&old-live, &new-live)
|
|
# If there were fail2ban rules before applying but not after, re-create them
|
|
sub merge_fail2ban_rules
|
|
{
|
|
local ($oldlive, $newlive) = @_;
|
|
|
|
# Get old and new filter table
|
|
local ($oldfilter) = grep { $_->{'name'} eq 'filter' } @$oldlive;
|
|
local ($newfilter) = grep { $_->{'name'} eq 'filter' } @$newlive;
|
|
return if (!$oldfilter || !$newfilter);
|
|
local $oldrules = $oldfilter->{'rules'};
|
|
local $newrules = $newfilter->{'rules'};
|
|
|
|
# Get all old fail2ban chain rules and inputs that jump to them
|
|
local @oldrules = grep { $_->{'chain'} =~ /^f2b-/ } @$oldrules;
|
|
return if (!@oldrules);
|
|
local @oldjumps = grep { $_->{'chain'} eq 'INPUT' &&
|
|
$_->{'j'}->[1] =~ /^f2b-/ } @$oldrules;
|
|
|
|
# Get all new fail2ban chain rules and inputs that jump to them
|
|
local @newrules = grep { $_->{'chain'} =~ /^f2b-/ } @$newrules;
|
|
local @newjumps = grep { $_->{'chain'} eq 'INPUT' &&
|
|
$_->{'j'}->[1] =~ /^f2b-/ } @newrules;
|
|
|
|
# Re-create the chains
|
|
my @oldchains = &unique(map { $_->{'chain'} } @oldrules);
|
|
foreach my $c (@oldchains) {
|
|
&system_logged("ip${ipvx}tables -t filter -N $c 2>&1");
|
|
}
|
|
|
|
# Re-create any missing old rules
|
|
foreach my $r (@oldrules) {
|
|
&create_active_rule($newfilter, $r, 0);
|
|
}
|
|
foreach my $j (@oldjumps) {
|
|
my ($nj) = grep { $_->{'j'}->[1] eq $j->{'j'}->[1] } @newjumps;
|
|
if (!$nj) {
|
|
&create_active_rule($newfilter, $j, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
# list_cluster_servers()
|
|
# Returns a list of servers on which the firewall is managed
|
|
sub list_cluster_servers
|
|
{
|
|
&foreign_require("servers", "servers-lib.pl");
|
|
local %ids = map { $_, 1 } split(/\s+/, $config{'servers'});
|
|
return grep { $ids{$_->{'id'}} } &servers::list_servers();
|
|
}
|
|
|
|
# add_cluster_server(&server)
|
|
sub add_cluster_server
|
|
{
|
|
local @sids = split(/\s+/, $config{'servers'});
|
|
$config{'servers'} = join(" ", @sids, $_[0]->{'id'});
|
|
&save_module_config();
|
|
}
|
|
|
|
# delete_cluster_server(&server)
|
|
sub delete_cluster_server
|
|
{
|
|
local @sids = split(/\s+/, $config{'servers'});
|
|
$config{'servers'} = join(" ", grep { $_ != $_[0]->{'id'} } @sids);
|
|
&save_module_config();
|
|
}
|
|
|
|
# server_name(&server)
|
|
sub server_name
|
|
{
|
|
return $_[0]->{'desc'} ? $_[0]->{'desc'} : $_[0]->{'host'};
|
|
}
|
|
|
|
# copy_to_cluster([force])
|
|
# Copy all firewall rules from this server to those in the cluster
|
|
sub copy_to_cluster
|
|
{
|
|
return if (!$config{'servers'}); # no servers defined
|
|
return if (!$_[0] && $config{'cluster_mode'}); # only push out when applying
|
|
local $s;
|
|
local $ltemp;
|
|
if ($config{"direct${ipvx}"}) {
|
|
# Dump current configuration
|
|
$ltemp = &transname();
|
|
system("ip${ipvx}tables-save >$ltemp 2>/dev/null");
|
|
}
|
|
foreach $s (&list_cluster_servers()) {
|
|
&remote_foreign_require($s, $module_name);
|
|
if ($config{"direct${ipvx}"}) {
|
|
# Directly activate on remote server!
|
|
local $rtemp = &remote_write($s, $ltemp);
|
|
unlink($ltemp);
|
|
local $err = &remote_eval($s, $module_name,
|
|
"\$out = `ip${ipvx}tables-restore <$rtemp 2>&1`; [ \$out, \$? ]");
|
|
&remote_foreign_call($s, $module_name, "unlink_file", $rtemp);
|
|
&error(&text('apply_remote', $s->{'host'}, $err->[0]))
|
|
if ($err->[1]);
|
|
}
|
|
else {
|
|
# Can just copy across save file
|
|
local $rfile = &remote_eval($s, $module_name,
|
|
"\$ip${ipvx}tables_save_file");
|
|
&remote_write($s, $ipvx_save, $rfile);
|
|
}
|
|
}
|
|
}
|
|
|
|
# apply_cluster_configuration()
|
|
# Activate the current configuration on all servers in the cluster
|
|
sub apply_cluster_configuration
|
|
{
|
|
return undef if (!$config{'servers'});
|
|
if ($config{'cluster_mode'}) {
|
|
©_to_cluster(1);
|
|
}
|
|
local $s;
|
|
foreach $s (&list_cluster_servers()) {
|
|
&remote_foreign_require($s->{'host'}, $module_name);
|
|
local $err = &remote_foreign_call(
|
|
$s->{'host'}, $module_name, "apply_configuration");
|
|
if ($err) {
|
|
return &text('apply_remote', $s->{'host'}, $err);
|
|
}
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
# validate_iptables_config()
|
|
# Tests that the rules file can be parsed
|
|
sub validate_iptables_config
|
|
{
|
|
my $out = &backquote_command(
|
|
"ip${ipvx}tables-restore --test <$ipvx_save 2>&1");
|
|
return undef if (!$?);
|
|
$out =~ s/Try\s.*more\s+information.*//;
|
|
return $out;
|
|
}
|
|
|
|
sub supports_conntrack
|
|
{
|
|
if (!defined($supports_conntrack_cache)) {
|
|
my $out = &backquote_command("uname -r 2>/dev/null");
|
|
$supports_conntrack_cache = $out =~ /^[3-9]\./ ? 1 : 0;
|
|
}
|
|
return $supports_conntrack_cache;
|
|
}
|
|
|
|
# create_active_rule(&table, &rule, insert?)
|
|
# Execute the commands to create one rule
|
|
sub create_active_rule
|
|
{
|
|
my ($table, $rule, $insert) = @_;
|
|
my $flags = &make_rule_command($rule);
|
|
$flags =~ s/^-A /-I / if ($insert);
|
|
my $cmd = "ip${ipvx}tables -t ".$table->{'name'}." ".$flags;
|
|
my $out = &backquote_logged("$cmd 2>&1 </dev/null");
|
|
return $? ? $out : undef;
|
|
}
|
|
|
|
# external_firewall_list(&tables)
|
|
# Returns a list of all external firewalls detected
|
|
sub external_firewall_list
|
|
{
|
|
my ($tables) = @_;
|
|
my @fwname;
|
|
my ($filter) = grep { $_->{'name'} eq 'filter' } @$tables;
|
|
if ($filter->{'defaults'}->{'shorewall'}) {
|
|
push(@fwname, 'shorewall');
|
|
}
|
|
if ($filter->{'defaults'}->{'INPUT_ZONES'}) {
|
|
push(@fwname, 'firewalld');
|
|
}
|
|
if ($filter->{'defaults'} =~ /^f2b-|^fail2ban-/ && !$config{'filter_chain'} ) {
|
|
push(@fwname, 'fail2ban');
|
|
}
|
|
if (&indexof('firewalld', @fwname) < 0 &&
|
|
&foreign_installed("firewalld", 1) == 2) {
|
|
push(@fwname, 'firewalld');
|
|
}
|
|
if (&indexof('shorewall', @fwname) < 0 &&
|
|
&foreign_installed("shorewall", 1) == 2) {
|
|
push(@fwname, 'shorewall');
|
|
}
|
|
return &unique(@fwname);
|
|
}
|
|
|
|
1;
|
|
|