Server IP : 195.201.23.43 / Your IP : 18.219.89.186 Web Server : Apache System : Linux webserver2.vercom.be 5.4.0-192-generic #212-Ubuntu SMP Fri Jul 5 09:47:39 UTC 2024 x86_64 User : kdecoratie ( 1041) PHP Version : 7.1.33-63+ubuntu20.04.1+deb.sury.org+1 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals, MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /usr/share/webmin/firewall6/ |
Upload 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;Private