����JFIF��x�x����'
Server IP : 78.140.185.180 / Your IP : 18.119.0.207 Web Server : LiteSpeed System : Linux cpanel13.v.fozzy.com 4.18.0-513.11.1.lve.el8.x86_64 #1 SMP Thu Jan 18 16:21:02 UTC 2024 x86_64 User : builderbox ( 1072) PHP Version : 7.3.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /lib64/nagios/plugins/extra/ |
Upload File : |
#! /usr/bin/env perl use strict; use warnings; use Getopt::Long; use JSON::PP qw(decode_json); use IPC::Open3 qw(open3); use Symbol qw(gensym); use constant REFERENCE_FILE => '/etc/icinga2/plinc/fw_rules'; sub usage { print sprintf( <<"EOF", REFERENCE_FILE ); Usage: $0 --backend iptables|nft [-i 'rule1' -i 'rule2' -i 'rule3'] [--save] -b|--backend use the specified firewall -s|--save save current rules to %s -i|--ignore ignor firewall rule support usage placeholder %%word (eq (\\S+\\h*)+ regexp) Examples: $0 -b iptables -i 'iptables -t filter -A custom-out -s %%word -d %%word -j ACCEPT' -i 'ip6tables -t nat' $0 -b nft -i 'element inet filter tor %%word' -i 'set inet %%word tor' $0 -b nft -i 'element inet filter custom-out6 %%word' EOF exit 1; } my $type; my $is_save; my @criteria; GetOptions( 'backend=s' => \$type, 'save' => \$is_save, 'ignore=s' => \@criteria, ) or usage; usage unless ( defined $type ); my $get_rules = { 'iptables' => \&iptables_h, 'nft' => \&nftables_h, }->{$type}; my @rules = filter_rules( \@criteria, $get_rules->() ); if ($is_save) { save_rules(@rules); } else { compare( load_rules(), \@rules ); } sub compare { my ( $reference_rules, $actual_rules ) = @_; my %h; $h{$_}-- for @$reference_rules; $h{$_}++ for @$actual_rules; my @diff = sort map { $h{$_} > 0 ? "added : $_" : $h{$_} < 0 ? "deleted: $_" : () } keys %h; if (@diff) { print "[Critical]: Firewall has changed\n"; print "$_\n" for @diff; exit 2; } else { print "Checked rules: " . scalar keys %h; } } sub filter_rules { my ( $criteria, @rules ) = @_; return @rules unless @$criteria; my @regexps = map {s/\\\%word/(\\S+\\h*)+/gr} map {quotemeta} @$criteria; grep { my $rule = $_; my $is_match = sub { grep { return 1 if $rule =~ /^$_$/ } @regexps; } ->(); not $is_match; } @rules; } sub nftables_h { my @ruleset = @{ decode_json(`nft -js list ruleset`)->{nftables} }; my %raw_rules_cache; my @tables = map { parse_nft_table($_) } filter_nft( 'table', @ruleset ); my @sets = map { parse_nft_set_elements($_) } filter_nft( 'set', @ruleset ); my @chains = map { parse_nft_chain($_) } filter_nft( 'chain', @ruleset ); my @rules = map { my $rule_name = "$_->{family} $_->{table} $_->{chain}"; $raw_rules_cache{$rule_name} = join( "\n", @{ ( sec_run( 'nft', '-ats', "list chain $rule_name" ) )[0] } ) unless defined $raw_rules_cache{$rule_name}; parse_nft_rule( $_, $raw_rules_cache{$rule_name} ); } filter_nft( 'rule', @ruleset ); return ( @tables, @sets, @chains, @rules ); } sub filter_nft { my ( $key, @ruleset ) = @_; return map { $_->{$key} } grep { defined $_->{$key} } @ruleset; } sub parse_nft_table { return "table $_[0]->{family} $_[0]->{name}"; } sub parse_nft_rule { my ( $rule, $raw_rules ) = @_; my ($raw_rule) = $raw_rules =~ /\s*(.+) # handle $rule->{handle}\s+/; return "rule $rule->{family} $rule->{table} $rule->{chain} $raw_rule"; } sub parse_nft_chain { my ($chain) = @_; my @parsed_chain = map { my ( $key, $value ) = %{$_}; defined $chain->{$key} ? sprintf( $value, $chain->{$key} ) : (); } ( { family => '%s' }, { table => '%s' }, { name => '%s {' }, { type => 'type %s' }, { hook => 'hook %s' }, { prio => 'priority %s;' }, { policy => 'policy %s;' }, ); return "chain @parsed_chain }"; } sub parse_nft_set_elements { my %parser = ( prefix => sub {"$_[0]->{addr}/$_[0]->{len}"}, elem => sub { $_[0]->{val} }, range => sub { join '-', @{ $_[0] } }, _string => sub { $_[0] }, ); return map { my $set = $_; my $set_name = "$set->{family} $set->{table} $set->{name}"; my @elements = map { my ( $key, $value ) = ref $_ eq 'HASH' ? %$_ : ( _string => $_ ); "element $set_name " . $parser{$key}->($value); } @{ $set->{elem} }; ( "set $set_name", @elements ); } @_; } sub iptables_h { map { my $x = $_; open FH, '<', "/proc/net/${x}_tables_names" or die $!; my @tables = <FH>; chomp(@tables); close FH; map { my $table = $_; my ($ruleset) = sec_run( "${x}tables", '-t', $table, '-S' ); map { "${x}tables -t $table $_"; } @$ruleset; } @tables; } qw(ip ip6); } sub save_rules { my @rules = @_; open( my $fh, '>', REFERENCE_FILE ) or die $!; chomp @rules; print $fh "$_\n" for @rules; close $fh; } sub load_rules { open( my $fh, '<', REFERENCE_FILE ) or die $!; my @rules = <$fh>; close $fh; chomp @rules; return \@rules; } sub sec_run { my ( $cmd, @args ) = @_; my $pid = open3( undef, my $out, my $err = gensym, $cmd, @args ) or die "$!"; my @stdout = <$out>; my @stderr = <$err>; close $out; chomp @stdout; close $err; waitpid( $pid, 0 ); die "Failed run: $cmd @args\n@stderr" if $? >> 8 != 0; return ( \@stdout, \@stderr ); }