mirror of
https://github.com/webmin/webmin.git
synced 2026-03-20 16:50:24 +00:00
Merge pull request #1624 from webmin/dev/fail2ban-jails-status-and-actions
Add jails status and actions 1/2 #1623
This commit is contained in:
BIN
fail2ban/images/status.gif
Normal file
BIN
fail2ban/images/status.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
@@ -28,14 +28,14 @@ if ($err) {
|
||||
|
||||
# Show category icons
|
||||
my @links = ( "list_filters.cgi", "list_actions.cgi",
|
||||
"list_jails.cgi", "edit_config.cgi",
|
||||
"edit_manual.cgi", );
|
||||
"list_jails.cgi", "list_status.cgi",
|
||||
"edit_config.cgi", "edit_manual.cgi", );
|
||||
my @titles = ( $text{'filters_title'}, $text{'actions_title'},
|
||||
$text{'jails_title'}, $text{'config_title'},
|
||||
$text{'manual_title'}, );
|
||||
$text{'jails_title'}, $text{'status_title'},
|
||||
$text{'config_title'}, $text{'manual_title'}, );
|
||||
my @icons = ( "images/filters.gif", "images/actions.gif",
|
||||
"images/jails.gif", "images/config.gif",
|
||||
"images/manual.gif", );
|
||||
"images/jails.gif", "images/status.gif",
|
||||
"images/config.gif", "images/manual.gif", );
|
||||
&icons_table(\@links, \@titles, \@icons, 5);
|
||||
|
||||
# Show start / stop buttons
|
||||
|
||||
102
fail2ban/list_status.cgi
Executable file
102
fail2ban/list_status.cgi
Executable file
@@ -0,0 +1,102 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Show a list of all defined actions
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './fail2ban-lib.pl';
|
||||
our (%in, %text, %config);
|
||||
|
||||
&ui_print_header(undef, $text{'status_title2'}, "");
|
||||
|
||||
# Check if firewalld is used
|
||||
&foreign_require('firewalld', 'install_check.pl');
|
||||
my $is_firewalld = &firewalld::is_installed();
|
||||
|
||||
my $out = &backquote_logged("$config{'client_cmd'} status 2>&1 </dev/null");
|
||||
my ($jail_list) = $out =~ /jail\s+list:\s*(.*)/im;
|
||||
my @jails = split(/,\s*/, $jail_list);
|
||||
if (@jails) {
|
||||
my $tdc = "style=\"text-align: center\"";
|
||||
my @links = ( &select_all_link("jail"),
|
||||
&select_invert_link("jail") );
|
||||
my $head;
|
||||
my @jipsall;
|
||||
foreach my $jail (@jails) {
|
||||
my $fh = 'cmdjail';
|
||||
my $cmd = "$config{'client_cmd'} status ".quotemeta($jail);
|
||||
my $jcmd = "$cmd 2>&1 </dev/null";
|
||||
my @head = (undef, $text{"status_head_jail_name"});
|
||||
my @body = (&ui_link("edit_jail.cgi?name=".urlize($jail), " ".&html_escape($jail)));
|
||||
my $br = '<br>';
|
||||
my $nbsp = ' ';
|
||||
my $ipslimit = sub {
|
||||
my ($ips, $limit) = @_;
|
||||
$limit ||= 15;
|
||||
# Limit sanity check
|
||||
$limit = 1 if ($limit < 1);
|
||||
my $ipscount = () = $ips =~ /$br/g;
|
||||
if ($ipscount > $limit) {
|
||||
my @ips = split($br, $ips);
|
||||
@ips = @ips[0 .. $limit];
|
||||
$ips = join($br, @ips);
|
||||
$ips .= "<small>$br$nbsp".&text('list_rules_plus_more', $ipscount-$limit)."</small>";
|
||||
}
|
||||
return $ips;
|
||||
};
|
||||
my $jips;
|
||||
my $noval;
|
||||
&open_execute_command($fh, $jcmd, 1);
|
||||
while(<$fh>) {
|
||||
if (/-\s+(.*):\s*(.*)/) {
|
||||
my $col = $1;
|
||||
my $val = $2;
|
||||
$col = lc($col);
|
||||
$col =~ s/\s/_/g;
|
||||
if ($col !~ /journal_matches/) {
|
||||
push(@head, "<div $tdc>".$text{"status_head_$col"}."</div>");
|
||||
if ($col =~ /banned_ip_list/) {
|
||||
$jips = $val;
|
||||
my @ips = split(/\s+/, $val);
|
||||
@ips = map { "<label style=\"white-space: nowrap\">" .
|
||||
&ui_link("unblock_jail.cgi?unblock=1&jips-@{[&urlize($jail)]}=@{[&urlize($_)]}&jail=@{[&urlize($jail)]}", $_, undef,
|
||||
"title=\"@{[&text('status_jail_unblock_ip', "e_escape($_))]}\" onmouseover=\"this.style.textDecoration='line-through'\" onmouseout=\"this.style.textDecoration='none'\""
|
||||
) .
|
||||
($is_firewalld ? " " .
|
||||
&ui_link("unblock_jail.cgi?permblock=1&jips-@{[&urlize($jail)]}=@{[&urlize($_)]}&jail=@{[&urlize($jail)]}", "∅", undef,
|
||||
"title=\"@{[&text('status_jail_permblock_ip', "e_escape($_))]}\" onmouseover=\"this.style.opacity='1';this.style.filter='grayscale(0)'\" onmouseout=\"this.style.opacity='0.25';this.style.filter='grayscale(100%)'\" style=\"font-size: 125%; margin-right:10px; filter: grayscale(100%); opacity: .25\""
|
||||
) : undef) . "</label>" } @ips;
|
||||
$val = "<br>" if ($val);
|
||||
$val .= join('<br>', @ips);
|
||||
$val = &$ipslimit($val);
|
||||
$val .= "<br><br>" if ($val);
|
||||
$val .= "–", $noval++ if (!$val);
|
||||
}
|
||||
push(@body, $val);
|
||||
}
|
||||
}
|
||||
}
|
||||
close($fh);
|
||||
if (!$head++) {
|
||||
print &ui_form_start("unblock_jail.cgi", "post");
|
||||
print &ui_links_row(\@links);
|
||||
print &ui_columns_start(\@head);
|
||||
}
|
||||
print &ui_checked_columns_row(\@body, [ 'width=5', undef, $tdc, $tdc, $tdc, $tdc, $noval ? $tdc : undef ], "jail", $jail);
|
||||
push(@jipsall, ["$jail" => $jips]);
|
||||
}
|
||||
if ($head) {
|
||||
print &ui_columns_end();
|
||||
print &ui_links_row(\@links);
|
||||
foreach my $j (@jipsall) {
|
||||
print &ui_hidden("jips-$j->[0]", "$j->[1]");
|
||||
}
|
||||
print &ui_form_end([ [ 'unblock', $text{'status_jail_unblock'} ],
|
||||
$is_firewalld ?
|
||||
[ 'permblock', $text{'status_jail_block'} ] : undef ]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
print $text{'status_jail_noactive'};
|
||||
}
|
||||
|
||||
&ui_print_footer("", $text{'index_return'});
|
||||
54
fail2ban/unblock_jail.cgi
Executable file
54
fail2ban/unblock_jail.cgi
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Create, update or delete a action
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './fail2ban-lib.pl';
|
||||
our (%in, %text, %config);
|
||||
&ReadParse();
|
||||
&error_setup($text{'status_err_set'});
|
||||
|
||||
my @jails = split(/\0/, $in{'jail'});
|
||||
my $action = $in{'permblock'} ? 'block' : $in{'unblock'} ? 'unblock' : undef;
|
||||
|
||||
# Error checks
|
||||
!$action || $in{'jail'} || &error($text{'status_err_nojail'});
|
||||
|
||||
# Unblock given IP in given jail
|
||||
my $unblock_jailed_ip = sub {
|
||||
my ($jail, $ip) = @_;
|
||||
my $cmd = "$config{'client_cmd'} set ".quotemeta($jail)." unbanip ".quotemeta($ip)." 2>&1 </dev/null";
|
||||
my $out = &backquote_logged($cmd);
|
||||
if ($?) {
|
||||
&error(&text('status_err_unban', &html_escape($ip)) . " : $out");
|
||||
}
|
||||
};
|
||||
|
||||
# Processes jails actions
|
||||
foreach my $jail (@jails) {
|
||||
my @jailips = split(/\s+/, $in{"jips-$jail"});
|
||||
if (@jailips) {
|
||||
foreach my $ip (@jailips) {
|
||||
# Blocking permanently IP from given jail
|
||||
if ($action eq 'block') {
|
||||
# Add permanent block first
|
||||
&foreign_require('firewalld');
|
||||
my $out = &firewalld::add_ip_ban($ip);
|
||||
if ($out) {
|
||||
&error(&text('status_err_ban', &html_escape($ip)) . " : $out");
|
||||
}
|
||||
# Remove from fail2ban now
|
||||
&$unblock_jailed_ip($jail, $ip);
|
||||
}
|
||||
# Unblocking IP from given jail
|
||||
elsif ($action eq 'unblock') {
|
||||
# Just unblock
|
||||
&$unblock_jailed_ip($jail, $ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Log and redirect
|
||||
&webmin_log('update', 'jail', join(", ", @jails));
|
||||
&redirect("list_status.cgi");
|
||||
@@ -230,8 +230,9 @@ return ($w{'port'}, $w{'proto'}, $w{'toport'}, $w{'toaddr'});
|
||||
# Make the current saved config active
|
||||
sub apply_firewalld
|
||||
{
|
||||
my $out = &backquote_logged("$config{'firewall_cmd'} --reload 2>&1");
|
||||
return $? ? $out : undef;
|
||||
&foreign_require("init");
|
||||
my ($ok, $err) = &init::restart_action($config{'init_name'});
|
||||
return $ok ? undef : $err;
|
||||
}
|
||||
|
||||
# stop_firewalld()
|
||||
@@ -353,4 +354,147 @@ else {
|
||||
}
|
||||
}
|
||||
|
||||
# get_default_zone
|
||||
# Returns default zone
|
||||
sub get_default_zone
|
||||
{
|
||||
my @zones = &list_firewalld_zones();
|
||||
my ($zone) = grep { $_->{'default'} } @zones;
|
||||
return $zone;
|
||||
}
|
||||
|
||||
# add_ip_ban(ip, [zone])
|
||||
# Ban given IP address in given or default zone
|
||||
sub add_ip_ban
|
||||
{
|
||||
my ($ip, $zone) = @_;
|
||||
return create_rich_rule('add', $ip, $zone);
|
||||
}
|
||||
|
||||
# remove_ip_ban(ip, [zone])
|
||||
# Un-ban given IP address in given or default zone
|
||||
sub remove_ip_ban
|
||||
{
|
||||
my ($ip, $zone) = @_;
|
||||
return create_rich_rule('remove', $ip, $zone);
|
||||
}
|
||||
|
||||
# create_rich_rule(action, ip, [\zone], [opts])
|
||||
# Add or remove rich rule for given IP in given or default zone
|
||||
sub create_rich_rule
|
||||
{
|
||||
my ($action, $ip, $zone, $opts) = @_;
|
||||
my $ip_validate = sub {
|
||||
return &check_ipaddress($_[0]) || &check_ip6address($_[0]);
|
||||
};
|
||||
|
||||
# Default action for permanent ban is 'drop'
|
||||
my $action_type = "drop";
|
||||
|
||||
# Override defaults
|
||||
if (ref($opts)) {
|
||||
|
||||
# Override default action
|
||||
$action_type = lc($opts->{'action'})
|
||||
if ($opts->{'action'} &&
|
||||
$opts->{'action'} =~ /^accept|reject|drop|mark$/);
|
||||
}
|
||||
|
||||
# Zone name
|
||||
if (!$zone) {
|
||||
($zone) = get_default_zone();
|
||||
}
|
||||
$zone = &sanitize_zone_name($zone->{'name'});
|
||||
|
||||
# Validate action
|
||||
$action eq 'add' || $action eq 'remove' || &error($text{'list_rule_actionerr'});
|
||||
|
||||
# Validate IP
|
||||
&$ip_validate($ip) || &error($text{'list_rule_iperr'});
|
||||
|
||||
# Set family
|
||||
my $family = $ip =~ /:/ ? 'ipv6' : 'ipv4';
|
||||
|
||||
# Apply block
|
||||
# (quotemeta doesn't work for params)
|
||||
my $get_cmd = sub {
|
||||
my ($rtype) = @_;
|
||||
my $type;
|
||||
$type = " --permanent" if ($rtype eq 'permanent');
|
||||
return "$config{'firewall_cmd'} --zone=".$zone."$type --$action-rich-rule=\"rule family='$family' source address='$ip' $action_type\"";
|
||||
};
|
||||
my $out = &backquote_logged(&$get_cmd()." 2>&1 </dev/null");
|
||||
return $out if ($?);
|
||||
$out = &backquote_logged(&$get_cmd('permanent')." 2>&1 </dev/null");
|
||||
return $? ? $out : undef;
|
||||
}
|
||||
|
||||
# remove_rich_rule(rule, [\zone])
|
||||
# Remove rich rule in given or default zone
|
||||
sub remove_rich_rule
|
||||
{
|
||||
my ($rule, $zone) = @_;
|
||||
|
||||
# Zone name
|
||||
if (!$zone) {
|
||||
($zone) = get_default_zone();
|
||||
}
|
||||
$zone = &sanitize_zone_name($zone->{'name'});
|
||||
|
||||
# Sanitize rule
|
||||
$rule = &sanitize_rule_name($rule);
|
||||
|
||||
# Remove rule command
|
||||
# (quotemeta doesn't work for params)
|
||||
my $get_cmd = sub {
|
||||
my ($rtype) = @_;
|
||||
my $type;
|
||||
$type = " --permanent" if ($rtype eq 'permanent');
|
||||
return "$config{'firewall_cmd'} --zone=${zone}${type} --remove-rich-rule '${rule}'";
|
||||
};
|
||||
|
||||
my $out = &backquote_logged(&$get_cmd()." 2>&1 </dev/null");
|
||||
return $out if ($?);
|
||||
$out = &backquote_logged(&$get_cmd('permanent')." 2>&1 </dev/null");
|
||||
return $? ? $out : undef;
|
||||
}
|
||||
|
||||
# remove_direct_rule(rule)
|
||||
# Remove given direct rule
|
||||
sub remove_direct_rule
|
||||
{
|
||||
my ($rule) = @_;
|
||||
|
||||
# Sanitize rule
|
||||
$rule = &sanitize_rule_name($rule);
|
||||
|
||||
# Remove rule command
|
||||
# (quotemeta doesn't work for params)
|
||||
my $get_cmd = sub {
|
||||
my ($rtype) = @_;
|
||||
my $type;
|
||||
$type = " --permanent" if ($rtype eq 'permanent');
|
||||
return "$config{'firewall_cmd'}${type} --direct --remove-rule $rule";
|
||||
};
|
||||
|
||||
my $out = &backquote_logged(&$get_cmd()." 2>&1 </dev/null");
|
||||
return $out if ($?);
|
||||
$out = &backquote_logged(&$get_cmd('permanent')." 2>&1 </dev/null");
|
||||
return $? ? $out : undef;
|
||||
}
|
||||
|
||||
sub sanitize_zone_name
|
||||
{
|
||||
my ($zone) = @_;
|
||||
$zone =~ tr/A-Za-z0-9\-\_//cd;
|
||||
return $zone;
|
||||
}
|
||||
|
||||
sub sanitize_rule_name
|
||||
{
|
||||
my ($rule) = @_;
|
||||
$rule =~ tr/A-Za-z0-9\-\_\=\"\:\.\,\/ //cd;
|
||||
return $rule;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -30,129 +30,140 @@ if ($err) {
|
||||
return;
|
||||
}
|
||||
|
||||
# Get rules and zones
|
||||
my @zones = &list_firewalld_zones();
|
||||
@zones || &error($text{'index_ezones'});
|
||||
my @zones;
|
||||
my $zone;
|
||||
if ($in{'zone'}) {
|
||||
($zone) = grep { $_->{'name'} eq $in{'zone'} } @zones;
|
||||
}
|
||||
else {
|
||||
($zone) = grep { $_->{'default'} } @zones;
|
||||
}
|
||||
$zone ||= $zones[0];
|
||||
my ($azone);
|
||||
eval {
|
||||
local $main::error_must_die = 1;
|
||||
my @azones = &list_firewalld_zones(1);
|
||||
($azone) = grep { $_->{'name'} eq $zone->{'name'} } @azones;
|
||||
};
|
||||
|
||||
# Show zone selector
|
||||
print &ui_form_start("index.cgi");
|
||||
print "$text{'index_zone'} ",
|
||||
&ui_select("zone", $zone->{'name'},
|
||||
[ map { [ $_->{'name'},
|
||||
$_->{'name'}.($_->{'default'} ? ' (default)' : '') ]}
|
||||
@zones ], 1, 0, 0, 0,
|
||||
"onChange='form.submit()'")," ",
|
||||
&ui_submit($text{'index_zonedef'}, "defzone")," ",
|
||||
&ui_submit($text{'index_zonedel'}, "delzone")," ",
|
||||
&ui_submit($text{'index_zoneadd'}, "addzone")," ",
|
||||
"<p>\n";
|
||||
print &ui_form_end();
|
||||
|
||||
# Show allowed ports and services in this zone
|
||||
my @links = ( &ui_link("edit_port.cgi?new=1&zone=".&urlize($zone->{'name'}),
|
||||
$text{'index_padd'}),
|
||||
&ui_link("edit_serv.cgi?new=1&zone=".&urlize($zone->{'name'}),
|
||||
$text{'index_sadd'}),
|
||||
&ui_link("edit_forward.cgi?new=1&zone=".&urlize($zone->{'name'}),
|
||||
$text{'index_fadd'}),
|
||||
);
|
||||
if (@{$zone->{'services'}} || @{$zone->{'ports'}}) {
|
||||
my @tds = ( "width=5" );
|
||||
unshift(@links, &select_all_link("d", 1),
|
||||
&select_invert_link("d", 1));
|
||||
print &ui_form_start("delete_rules.cgi", "post");
|
||||
print &ui_hidden("zone", $zone->{'name'});
|
||||
print &ui_links_row(\@links);
|
||||
print &ui_columns_start([ "", $text{'index_type'}, $text{'index_port'},
|
||||
$text{'index_proto'} ], 100, 0, \@tds);
|
||||
foreach my $s (@{$zone->{'services'}}) {
|
||||
my $url = "edit_serv.cgi?id=".&urlize($s).
|
||||
"&zone=".&urlize($zone->{'name'});
|
||||
my $sportsprotos = &list_firewalld_service_desc($s);
|
||||
my $sport = $sportsprotos->{'ports'};
|
||||
my $sprotocols = $sportsprotos->{'protocols'};
|
||||
$sport = " ($sport)" if ($sport);
|
||||
print &ui_checked_columns_row([
|
||||
&ui_link($url, $text{'index_tservice'}),
|
||||
&ui_link($url, "$s$sport"),
|
||||
$sprotocols || "",
|
||||
], \@tds, "d", "service/".$s);
|
||||
}
|
||||
foreach my $p (@{$zone->{'ports'}}) {
|
||||
my $url = "edit_port.cgi?id=".&urlize($p).
|
||||
"&zone=".&urlize($zone->{'name'});
|
||||
my ($port, $proto) = split(/\//, $p);
|
||||
print &ui_checked_columns_row([
|
||||
&ui_link($url, $text{'index_tport'}),
|
||||
&ui_link($url, $port),
|
||||
uc($proto),
|
||||
], \@tds, "d", "port/".$p);
|
||||
}
|
||||
foreach my $f (@{$zone->{'forward-ports'}}) {
|
||||
my ($port, $proto, $dstport, $dstaddr) =
|
||||
&parse_firewalld_forward($f);
|
||||
my $p = join("/", $port, $proto, $dstport, $dstaddr);
|
||||
my $url = "edit_forward.cgi?id=".&urlize($p).
|
||||
"&zone=".&urlize($zone->{'name'});
|
||||
print &ui_checked_columns_row([
|
||||
&ui_link($url, $text{'index_tforward'}),
|
||||
&ui_link($url, $port),
|
||||
&ui_link($url, uc($proto)),
|
||||
], \@tds, "d", "forward/".$p);
|
||||
}
|
||||
print &ui_columns_end();
|
||||
print &ui_links_row(\@links);
|
||||
print &ui_form_end([ [ undef, $text{'index_delete'} ] ]);
|
||||
}
|
||||
else {
|
||||
print "$text{'index_none'}<p>\n";
|
||||
print &ui_links_row(\@links);
|
||||
}
|
||||
|
||||
if ($azone) {
|
||||
# Show interfaces for this zone
|
||||
print &ui_form_start("save_ifaces.cgi");
|
||||
print &ui_hidden("zone", $zone->{'name'});
|
||||
print "<br>$text{'index_ifaces'} \n";
|
||||
my %zifcs = map { $_, 1 } &unique(@{$azone->{'interfaces'}},
|
||||
@{$zone->{'interfaces'}});
|
||||
print &ui_radio("iface_def", %zifcs ? 0 : 1,
|
||||
[ [ 1, $text{'index_ifaces_def'} ],
|
||||
[ 0, $text{'index_ifaces_sel'} ] ]),"\n";
|
||||
foreach my $i (&list_system_interfaces()) {
|
||||
print &ui_checkbox("iface", $i, $i, $zifcs{$i}),"\n";
|
||||
}
|
||||
print &ui_submit($text{'save'});
|
||||
print &ui_form_end();
|
||||
}
|
||||
|
||||
# Show start/apply buttons
|
||||
print &ui_hr();
|
||||
print &ui_buttons_start();
|
||||
# Is FirewallD running if not, show start button
|
||||
my $ok = &is_firewalld_running();
|
||||
if ($ok) {
|
||||
print &ui_buttons_row("restart.cgi", $text{'index_restart'},
|
||||
$text{'index_restartdesc'},
|
||||
# Get rules and zones
|
||||
@zones = &list_firewalld_zones();
|
||||
@zones || &error($text{'index_ezones'});
|
||||
if ($in{'zone'}) {
|
||||
($zone) = grep { $_->{'name'} eq $in{'zone'} } @zones;
|
||||
}
|
||||
else {
|
||||
($zone) = grep { $_->{'default'} } @zones;
|
||||
}
|
||||
$zone ||= $zones[0];
|
||||
my ($azone);
|
||||
eval {
|
||||
local $main::error_must_die = 1;
|
||||
my @azones = &list_firewalld_zones(1);
|
||||
($azone) = grep { $_->{'name'} eq $zone->{'name'} } @azones;
|
||||
};
|
||||
|
||||
# Show zone selector
|
||||
print &ui_form_start("index.cgi");
|
||||
print "$text{'index_zone'} ",
|
||||
&ui_select("zone", $zone->{'name'},
|
||||
[ map { [ $_->{'name'},
|
||||
$_->{'name'}.($_->{'default'} ? ' (default)' : '') ]}
|
||||
@zones ], 1, 0, 0, 0,
|
||||
"onChange='form.submit()'")," ",
|
||||
&ui_submit($text{'index_zonedef'}, "defzone")," ",
|
||||
&ui_submit($text{'index_zonedel'}, "delzone")," ",
|
||||
&ui_submit($text{'index_zoneadd'}, "addzone")," ",
|
||||
"<p>\n";
|
||||
print &ui_form_end();
|
||||
|
||||
# Show allowed ports and services in this zone
|
||||
my @links = ( &ui_link("edit_port.cgi?new=1&zone=".&urlize($zone->{'name'}),
|
||||
$text{'index_padd'}),
|
||||
&ui_link("edit_serv.cgi?new=1&zone=".&urlize($zone->{'name'}),
|
||||
$text{'index_sadd'}),
|
||||
&ui_link("edit_forward.cgi?new=1&zone=".&urlize($zone->{'name'}),
|
||||
$text{'index_fadd'}),
|
||||
);
|
||||
if (@{$zone->{'services'}} || @{$zone->{'ports'}}) {
|
||||
my @tds = ( "width=5" );
|
||||
unshift(@links, &select_all_link("d", 1),
|
||||
&select_invert_link("d", 1));
|
||||
print &ui_form_start("delete_rules.cgi", "post");
|
||||
print &ui_hidden("zone", $zone->{'name'});
|
||||
print &ui_links_row(\@links);
|
||||
print &ui_columns_start([ "", $text{'index_type'}, $text{'index_port'},
|
||||
$text{'index_proto'} ], 100, 0, \@tds);
|
||||
foreach my $s (@{$zone->{'services'}}) {
|
||||
my $url = "edit_serv.cgi?id=".&urlize($s).
|
||||
"&zone=".&urlize($zone->{'name'});
|
||||
my $sportsprotos = &list_firewalld_service_desc($s);
|
||||
my $sport = $sportsprotos->{'ports'};
|
||||
my $sprotocols = $sportsprotos->{'protocols'};
|
||||
$sport = " ($sport)" if ($sport);
|
||||
print &ui_checked_columns_row([
|
||||
&ui_link($url, $text{'index_tservice'}),
|
||||
&ui_link($url, "$s$sport"),
|
||||
$sprotocols || "",
|
||||
], \@tds, "d", "service/".$s);
|
||||
}
|
||||
foreach my $p (@{$zone->{'ports'}}) {
|
||||
my $url = "edit_port.cgi?id=".&urlize($p).
|
||||
"&zone=".&urlize($zone->{'name'});
|
||||
my ($port, $proto) = split(/\//, $p);
|
||||
print &ui_checked_columns_row([
|
||||
&ui_link($url, $text{'index_tport'}),
|
||||
&ui_link($url, $port),
|
||||
uc($proto),
|
||||
], \@tds, "d", "port/".$p);
|
||||
}
|
||||
foreach my $f (@{$zone->{'forward-ports'}}) {
|
||||
my ($port, $proto, $dstport, $dstaddr) =
|
||||
&parse_firewalld_forward($f);
|
||||
my $p = join("/", $port, $proto, $dstport, $dstaddr);
|
||||
my $url = "edit_forward.cgi?id=".&urlize($p).
|
||||
"&zone=".&urlize($zone->{'name'});
|
||||
print &ui_checked_columns_row([
|
||||
&ui_link($url, $text{'index_tforward'}),
|
||||
&ui_link($url, $port),
|
||||
&ui_link($url, uc($proto)),
|
||||
], \@tds, "d", "forward/".$p);
|
||||
}
|
||||
print &ui_columns_end();
|
||||
print &ui_links_row(\@links);
|
||||
print &ui_form_end([ [ undef, $text{'index_delete'} ] ]);
|
||||
}
|
||||
else {
|
||||
print "$text{'index_none'}<p>\n";
|
||||
print &ui_links_row(\@links);
|
||||
}
|
||||
|
||||
if ($azone) {
|
||||
# Show interfaces for this zone
|
||||
print &ui_form_start("save_ifaces.cgi");
|
||||
print &ui_hidden("zone", $zone->{'name'});
|
||||
print "<br>$text{'index_ifaces'} \n";
|
||||
my %zifcs = map { $_, 1 } &unique(@{$azone->{'interfaces'}},
|
||||
@{$zone->{'interfaces'}});
|
||||
print &ui_radio("iface_def", %zifcs ? 0 : 1,
|
||||
[ [ 1, $text{'index_ifaces_def'} ],
|
||||
[ 0, $text{'index_ifaces_sel'} ] ]),"\n";
|
||||
foreach my $i (&list_system_interfaces()) {
|
||||
print &ui_checkbox("iface", $i, $i, $zifcs{$i}),"\n";
|
||||
}
|
||||
print &ui_submit($text{'index_ifaces_apply'});
|
||||
print &ui_form_end();
|
||||
}
|
||||
|
||||
print &ui_hr();
|
||||
|
||||
# Show start/apply buttons
|
||||
print &ui_buttons_start();
|
||||
print &ui_buttons_row("list_rules.cgi", $text{'index_listrules'},
|
||||
&text("index_listrules_restartdesc",
|
||||
"<tt>".$zone->{'name'}."</tt>"),
|
||||
[ [ "zone", $zone->{'name'} ] ]);
|
||||
print &ui_buttons_row("restart.cgi", $text{'index_restart_firewalld'},
|
||||
$text{'index_restart_firewallddesc'},
|
||||
[ [ "zone", $zone->{'name'} ] ]);
|
||||
print &ui_buttons_row("stop.cgi", $text{'index_stop'},
|
||||
$text{'index_stopdesc'},
|
||||
[ [ "zone", $zone->{'name'} ] ]);
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
# Show Start and disable/enabled at boot button
|
||||
if (!$ok) {
|
||||
print &ui_buttons_start();
|
||||
print &ui_buttons_row("start.cgi", $text{'index_start'},
|
||||
$text{'index_startdesc'},
|
||||
[ [ "zone", $zone->{'name'} ] ]);
|
||||
|
||||
182
firewalld/list_rules.cgi
Executable file
182
firewalld/list_rules.cgi
Executable file
@@ -0,0 +1,182 @@
|
||||
#!/usr/local/bin/perl
|
||||
# List FirewallD rich and direct rules
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './firewalld-lib.pl';
|
||||
our (%in, %text, %config);
|
||||
&ReadParse();
|
||||
my $dzone = $in{'zone'};
|
||||
if (!$dzone) {
|
||||
my $zone = &get_default_zone();
|
||||
$dzone = $zone->{'name'};
|
||||
}
|
||||
&ui_print_header(&text('list_rules_title_sub', "<tt>".&html_escape($dzone)."</tt>"), $text{'list_rules_title'}, "");
|
||||
|
||||
my $head;
|
||||
my @head = (undef, $text{'list_rules_type'});
|
||||
my $tdc = "style=\"text-align: center\"";
|
||||
my @links = ( &select_all_link("rules"),
|
||||
&select_invert_link("rules") );
|
||||
|
||||
# Check rich rules first
|
||||
my $fh = 'rrules';
|
||||
my $rcmd = "$config{'firewall_cmd'} --list-rich-rules --zone=$dzone";
|
||||
&open_execute_command($fh, "$rcmd 2>&1 </dev/null", 1);
|
||||
while(<$fh>) {
|
||||
my @body;
|
||||
if ($_ =~ /\S+/) {
|
||||
push(@body, $text{'list_rules_type_rich'});
|
||||
|
||||
# Get protocol
|
||||
if (/family=["'](ipv\d)["']/) {
|
||||
push(@head, $text{'list_rules_protocol'});
|
||||
push(@body, $1 =~ /ipv6/i ? "IPv6" : "IPv4");
|
||||
}
|
||||
|
||||
# Get address
|
||||
if (/address=["'](.*?)["']/) {
|
||||
push(@head, $text{'list_rules_ip'});
|
||||
push(@body, "$1 ");
|
||||
}
|
||||
|
||||
# Get origin
|
||||
if (/\s+(source|destination)\s+/) {
|
||||
push(@head, $text{'list_rules_origin'});
|
||||
push(@body, $1 eq 'source' ? 'Input' : 'Output');
|
||||
}
|
||||
|
||||
# Get action
|
||||
if (/(accept|reject|drop|mark$)/i) {
|
||||
push(@head, $text{'list_rules_action'});
|
||||
push(@body, ucfirst($1));
|
||||
}
|
||||
|
||||
# Add full rule
|
||||
push(@head, $text{'list_rules_rule'});
|
||||
push(@body, "<tt>$_</tt>");
|
||||
|
||||
# Print start
|
||||
if (!$head++) {
|
||||
print &ui_form_start("save_rules.cgi", "post");
|
||||
print &ui_hidden("zone", $dzone);
|
||||
print &ui_links_row(\@links);
|
||||
print &ui_columns_start(\@head);
|
||||
}
|
||||
print &ui_checked_columns_row(\@body, [ 'width=5', $tdc, $tdc, undef, $tdc, $tdc, undef ], "rules", $_);
|
||||
}
|
||||
}
|
||||
close($fh);
|
||||
|
||||
# Check direct rules
|
||||
my $fh2 = 'drules';
|
||||
my $dcmd = "$config{'firewall_cmd'} --direct --get-all-rules";
|
||||
&open_execute_command($fh2, "$dcmd 2>&1 </dev/null", 1);
|
||||
while(<$fh2>) {
|
||||
my @body;
|
||||
if ($_ =~ /\S+/) {
|
||||
my $ndash = "–";
|
||||
my $br = "<br>";
|
||||
my $nbsp = " ";
|
||||
my $ips = $ndash;
|
||||
my $candelete = 1;
|
||||
my $ipslimit = sub {
|
||||
my ($ips, $limit) = @_;
|
||||
$limit ||= 15;
|
||||
# Limit sanity check and adjustment
|
||||
$limit = 1 if ($limit < 1);
|
||||
$limit -= 1;
|
||||
my $ipscount = () = $ips =~ /$br/g;
|
||||
if ($ipscount > $limit) {
|
||||
my @ips = split($br, $ips);
|
||||
@ips = @ips[0 .. $limit];
|
||||
$ips = join($br, @ips);
|
||||
$ips .= "<small>$br$nbsp".&text('list_rules_plus_more', $ipscount-$limit)."</small>";
|
||||
}
|
||||
return $ips;
|
||||
};
|
||||
# Extract IPs from match sets
|
||||
if (/set\s+\-\-match-set\s+(.*?)\s+/) {
|
||||
my $ipset_name = $1;
|
||||
my $ipset_cmd = &has_command($config{'firewall_ipset'} || 'ipset');
|
||||
my $ipset_cmd_out = &backquote_logged("$ipset_cmd list ".quotemeta($ipset_name)." 2>&1 </dev/null");
|
||||
if (!$?) {
|
||||
if ($ipset_cmd_out =~ /number\s+of\s+entries:\s+(\d)+/i) {
|
||||
if ($1 > 0) {
|
||||
my @ipset_cmd_out_lines = split(/\n/, $ipset_cmd_out);
|
||||
my @ips = map { $_ =~ /^([0-9\.\:a-f\/]+)/i } @ipset_cmd_out_lines;
|
||||
$ips = join("$nbsp$nbsp$br", @ips);
|
||||
}
|
||||
}
|
||||
}
|
||||
# Rules with match sets must not be controlled here
|
||||
$candelete = 0;
|
||||
}
|
||||
|
||||
# Standard direct rules
|
||||
else {
|
||||
# Extract IPs from the rule,
|
||||
# considering comma separated
|
||||
my @ips = ($_ =~ /-[sd]\s+([0-9\.\:a-f,\/]+)/gi);
|
||||
$ips = join("$nbsp$nbsp$br", @ips);
|
||||
$ips =~ s/\s*,\s*/$nbsp$nbsp$br/g;
|
||||
$ips ||= $ndash;
|
||||
}
|
||||
|
||||
# Trim the number of IPs to allow at max 10
|
||||
$ips = &$ipslimit($ips);
|
||||
|
||||
# Add type name
|
||||
push(@body, $text{'list_rules_type_direct'});
|
||||
|
||||
# Get protocol
|
||||
if (/(ipv\d)/) {
|
||||
push(@head, $text{'list_rules_protocol'});
|
||||
push(@body, $1 =~ /ipv6/i ? "IPv6" : "IPv4");
|
||||
}
|
||||
|
||||
# Get address
|
||||
if (/address=["'](.*?)["']/) {
|
||||
}
|
||||
push(@head, $text{'list_rules_ip'});
|
||||
push(@body, $ips);
|
||||
|
||||
# Get origin
|
||||
if (/(INPUT|OUTPUT)/) {
|
||||
push(@head, $text{'list_rules_origin'});
|
||||
push(@body, ucfirst(lc($1)));
|
||||
}
|
||||
|
||||
# Get action
|
||||
if (/(ACCEPT|REJECT|DROP|MARK$)/) {
|
||||
push(@head, $text{'list_rules_action'});
|
||||
push(@body, ucfirst(lc($1)));
|
||||
}
|
||||
|
||||
# Add full rule
|
||||
push(@head, $text{'list_rules_rule'});
|
||||
push(@body, "<tt>$_</tt>");
|
||||
|
||||
# Print start
|
||||
if (!$head++) {
|
||||
print &ui_form_start("save_rules.cgi", "post");
|
||||
print &ui_hidden("zone", $dzone);
|
||||
print &ui_links_row(\@links);
|
||||
print &ui_columns_start(\@head);
|
||||
}
|
||||
print &ui_checked_columns_row(\@body, [ 'width=5', $tdc, $tdc, undef, $tdc, $tdc, undef ], "rules", $_, undef, !$candelete);
|
||||
}
|
||||
}
|
||||
close($fh2);
|
||||
|
||||
|
||||
if ($head) {
|
||||
print &ui_columns_end();
|
||||
print &ui_links_row(\@links);
|
||||
print &ui_form_end([ [ 'remove', $text{'list_rules_delete'} ] ] );
|
||||
}
|
||||
else {
|
||||
print "There are no existing direct or rich firewall rules to display."
|
||||
}
|
||||
|
||||
&ui_print_footer("index.cgi?zone=".&urlize($dzone), $text{'index_return'});
|
||||
26
firewalld/save_rules.cgi
Executable file
26
firewalld/save_rules.cgi
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Delete multiple ports or services
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './firewalld-lib.pl';
|
||||
our (%in, %text);
|
||||
&error_setup($text{'delete_err'});
|
||||
&ReadParse();
|
||||
my @rules = split(/\0/, $in{'rules'});
|
||||
@rules || &error($text{'delete_enone'});
|
||||
|
||||
my @zones = &list_firewalld_zones();
|
||||
my ($zone) = grep { $_->{'name'} eq $in{'zone'} } @zones;
|
||||
$zone || &error($text{'port_ezone'});
|
||||
|
||||
if ($in{'remove'}) {
|
||||
foreach my $rule (@rules) {
|
||||
my $rrfunc = \&{"remove_" . ($rule =~ /^(ipv4|ipv6|eb)/ ? 'direct' : 'rich') . "_rule"};
|
||||
my $rmerr = &$rrfunc($rule, $zone);
|
||||
&error(&text('delete_edel', $rule, $rmerr)) if ($rmerr);
|
||||
}
|
||||
}
|
||||
|
||||
&webmin_log("save", "rules", scalar(@rules));
|
||||
&redirect("list_rules.cgi?zone=".&urlize($zone->{'name'}));
|
||||
Reference in New Issue
Block a user