#!/usr/local/bin/perl # edit_rule.cgi # Display the details of one firewall rule, or allow the adding of a new one require './firewall-lib.pl'; &ReadParse(); @tables = &get_iptables_save(); $table = $tables[$in{'table'}]; &can_edit_table($table->{'name'}) || &error($text{'etable'}); if ($in{'clone'} ne '') { &ui_print_header(undef, $text{'edit_title3'}, ""); %clone = %{$table->{'rules'}->[$in{'clone'}]}; $rule = \%clone; } elsif ($in{'new'}) { &ui_print_header(undef, $text{'edit_title1'}, ""); $rule = { 'chain' => $in{'chain'}, 'j' => &can_jump('DROP') ? 'DROP' : "" }; } else { &ui_print_header(undef, $text{'edit_title2'}, ""); $rule = $table->{'rules'}->[$in{'idx'}]; &can_jump($rule) || &error($text{'ejump'}); } print "
\n"; foreach $f ('table', 'idx', 'new', 'chain', 'before', 'after') { print &ui_hidden($f, $in{$f}); } # Display action section print "\n"; print "\n"; print "
$text{'edit_header1'}
\n"; print "\n"; print "\n"; print "\n"; if ($config{'comment_mod'} || $rule->{'comment'}) { # Get comment from --comment option printf "\n", &html_escape($rule->{'comment'}->[1]); } else { # Get comment from # at end of line printf "\n", &html_escape($rule->{'cmt'}); } print "\n"; if (&indexof('REJECT', @jumps) >= 0 && &can_jump("REJECT")) { # Show input for REJECT icmp type if ($rule->{'j'}->[1] eq 'REJECT') { $rwith = $rule->{'reject-with'}->[1]; } print "\n"; printf "\n"; } if (($table->{'name'} eq 'nat' && $rule->{'chain'} ne 'POSTROUTING') && &can_jump("REDIRECT")) { # Show inputs for redirect host and port if ($rule->{'j'}->[1] eq 'REDIRECT') { ($rtofrom, $rtoto) = split(/\-/, $rule->{'to-ports'}->[1]); } print "\n"; printf "\n"; } if (($table->{'name'} eq 'nat' && $rule->{'chain'} ne 'PREROUTING' && $rule->{'chain'} ne 'OUTPUT') && &can_jump("MASQUERADE")) { # Show inputs for masquerading ports if ($rule->{'j'}->[1] eq 'MASQUERADE') { ($mtofrom, $mtoto) = split(/\-/, $rule->{'to-ports'}->[1]); } print "\n"; printf "\n"; } if (($table->{'name'} eq 'nat' && $rule->{'chain'} ne 'POSTROUTING') && &can_jump("DNAT")) { if ($rule->{'j'}->[1] eq 'DNAT') { if ($rule->{'to-destination'}->[1] =~ /^([0-9\.]+)(\-([0-9\.]+))?(:(\d+)(\-(\d+))?)?$/) { $dipfrom = $1; $dipto = $3; $dpfrom = $5; $dpto = $7; } } print "\n"; printf "\n"; } if (($table->{'name'} eq 'nat' && $rule->{'chain'} ne 'PREROUTING' && $rule->{'chain'} ne 'OUTPUT') && &can_jump("SNAT")) { if ($rule->{'j'}->[1] eq 'SNAT') { if ($rule->{'to-source'}->[1] =~ /^([0-9\.]+)(\-([0-9\.]+))?(:(\d+)(\-(\d+))?)?$/) { $sipfrom = $1; $sipto = $3; $spfrom = $5; $spto = $7; } } print "\n"; printf "\n"; } print "
$text{'edit_chain'}",$text{"index_chain_".lc($rule->{'chain'})} || &text('index_chain', "$rule->{'chain'}"),"
$text{'edit_cmt'}
$text{'edit_jump'} \n"; if ($table->{'name'} eq 'nat') { @jumps = ( undef, 'ACCEPT', 'DROP' ); if ($rule->{'chain'} eq 'POSTROUTING') { push(@jumps, 'MASQUERADE', 'SNAT'); } elsif ($rule->{'chain'} eq 'PREROUTING' || $rule->{'chain'} eq 'OUTPUT') { push(@jumps, 'REDIRECT', 'DNAT'); } else { push(@jumps, 'MASQUERADE', 'SNAT', 'REDIRECT', 'DNAT'); } } else { @jumps = ( undef, 'ACCEPT', 'DROP', 'REJECT', 'QUEUE', 'RETURN', 'LOG' ); } print "\n"; $i = 0; foreach $j (grep { &can_jump($_) } @jumps) { print "\n" if ($i%5 == 0); printf "\n", $j, $rule->{'j'}->[1] eq $j ? "checked" : "", $text{"index_jump_".lc($j)}; $found++ if ($rule->{'j'}->[1] eq $j); $i++; print "\n" if ($i%5 == 0); } print "\n", $found ? "" : $rule->{'j'}->[1]; print "
 %s
\n"; printf " %s ", $found ? "" : "checked", $text{'edit_jump_other'}; printf "
$text{'edit_rwith'} %s\n", $rwith eq "" ? "checked" : "", $text{'default'}; printf "\n", $rwith eq "" ? "" : "checked"; local @rtypes = ( "icmp-net-unreachable", "icmp-host-unreachable", "icmp-port-unreachable", "icmp-proto-unreachable", "icmp-net-prohibited", "icmp-host-prohibited", "echo-reply", "tcp-reset" ); print &text('edit_rwithtype', &icmptype_input("rwithtype", $rwith, \@rtypes)), "
$text{'edit_rtoports'} %s\n", $rtofrom eq "" ? "checked" : "", $text{'default'}; printf "\n", $rtofrom eq "" ? "" : "checked"; print &text('edit_prange', "", ""),"
$text{'edit_mtoports'} %s\n", $mtofrom eq "" ? "checked" : "", $text{'edit_any'}; printf "\n", $mtofrom eq "" ? "" : "checked"; print &text('edit_prange', "", ""),"
$text{'edit_dnat'} %s\n", $dipfrom eq "" ? "checked" : "", $text{'default'}; printf "\n", $dipfrom eq "" ? "" : "checked"; print &text('edit_dnatip', "", ""),"\n"; print &text('edit_prange', "", ""),"
$text{'edit_snat'} %s\n", $sipfrom eq "" ? "checked" : "", $text{'default'}; printf "\n", $sipfrom eq "" ? "" : "checked"; print &text('edit_dnatip', "", ""),"\n"; print &text('edit_prange', "", ""),"

\n"; # Display conditions section print "$text{'edit_desc'}
\n"; print "\n"; print "\n"; print "
$text{'edit_header2'}
\n"; print "\n"; print "\n", $rule->{'s'}->[1]; print "\n"; print "\n", $rule->{'d'}->[1]; print "\n"; print "\n"; print "\n"; print "\n"; $f = !$rule->{'f'} ? 0 : $rule->{'f'}->[0] eq "!" ? 2 : 1; print "\n"; printf "\n", $f == 2 ? "checked" : "", $text{'edit_fragnot'}; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n", $rule->{'ports'}->[1]; print "\n"; print "\n"; print "\n"; print "\n", $rule->{'tcp-option'}->[1]; print "\n"; print "\n"; print "\n"; print "\n"; print "\n", $rule->{'mac-source'}->[1]; print "\n"; print "\n"; print "\n"; print "\n"; print "\n", $rule->{'limit-burst'}->[1]; if ($rule->{'chain'} eq 'OUTPUT') { print "\n"; print "\n"; print "\n", $rule->{'uid-owner'}->[1], &user_chooser_button("uidowner"); print "\n"; print "\n", $rule->{'gid-owner'}->[1], &group_chooser_button("gidowner"); print "\n"; print "\n", $rule->{'pid-owner'}->[1]; print "\n"; print "\n", $rule->{'sid-owner'}->[1]; } print "\n"; # Connection states print "\n"; print "\n"; # Type of service print "\n"; print "\n"; print "\n"; # Input physical device print "\n"; print "\n"; # Output physical device print "\n"; print "\n"; # Physdev match modes print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; # Show unknown modules @mods = grep { !/^(tcp|udp|icmp|multiport|mac|limit|owner|state|tos|comment|physdev)$/ } map { $_->[1] } @{$rule->{'m'}}; print "\n"; printf "\n", join(" ", @mods); # Show unknown parameters $rule->{'args'} =~ s/^\s+//; $rule->{'args'} =~ s/\s+$//; print "\n"; printf "\n", $rule->{'args'}; print "
$text{'edit_source'}",&print_mode("source", $rule->{'s'}),"\n"; printf "
$text{'edit_dest'}",&print_mode("dest", $rule->{'d'}),"\n"; printf "
$text{'edit_in'}",&print_mode("in", $rule->{'i'}),"\n"; print &interface_choice("in", $rule->{'i'}->[1]),"
$text{'edit_out'}",&print_mode("out", $rule->{'o'}),"\n"; print &interface_choice("out", $rule->{'o'}->[1]),"
$text{'edit_frag'} %s\n", $f == 0 ? "checked" : "", $text{'edit_ignore'}; printf " %s\n", $f == 1 ? "checked" : "", $text{'edit_fragis'}; printf " %s
$text{'edit_proto'}",&print_mode("proto", $rule->{'p'}),"\n"; print &protocol_input("proto", $rule->{'p'}->[1]),"

$text{'edit_sport'}",&print_mode("sport", $rule->{'sports'} || $rule->{'sport'}),"\n"; print &port_input("sport", $rule->{'sports'}->[1] || $rule->{'sport'}->[1]), "
$text{'edit_dport'}",&print_mode("dport", $rule->{'dports'} || $rule->{'dport'}),"\n"; print &port_input("dport", $rule->{'dports'}->[1] || $rule->{'dport'}->[1]), "
$text{'edit_ports'}",&print_mode("ports", $rule->{'ports'}),"\n"; printf "
$text{'edit_tcpflags'}
",&print_mode("tcpflags", $rule->{'tcp-flags'}),"\n"; print " ",&text('edit_flags', &tcpflag_input("tcpflags0", $rule->{'tcp-flags'}->[1]), &tcpflag_input("tcpflags1", $rule->{'tcp-flags'}->[2])), "
$text{'edit_tcpoption'}",&print_mode("tcpoption", $rule->{'tcp-option'}),"\n"; printf "

$text{'edit_icmptype'}",&print_mode("icmptype", $rule->{'icmp-type'}),"\n"; print &icmptype_input("icmptype", $rule->{'icmp-type'}->[1]),"
$text{'edit_mac'}",&print_mode("macsource", $rule->{'mac-source'}),"\n"; printf "

$text{'edit_limit'}",&print_mode("limit", $rule->{'limit'}, $text{'edit_below'}, $text{'edit_above'}, 1),"\n"; ($n, $u) = $rule->{'limit'}->[1] =~ /^(\d+)\/(\S+)$/ ? ($1, $2) : (); print "\n"; print "/
$text{'edit_limitburst'}",&print_mode("limitburst", $rule->{'limit-burst'}, $text{'edit_below'}, $text{'edit_above'}, 1),"\n"; printf "

$text{'edit_uidowner'}",&print_mode("uidowner", $rule->{'uid-owner'}),"\n"; printf " %s
$text{'edit_gidowner'}",&print_mode("gidowner", $rule->{'gid-owner'}),"\n"; printf " %s
$text{'edit_pidowner'}",&print_mode("pidowner", $rule->{'pid-owner'}),"\n"; printf "
$text{'edit_sidowner'}",&print_mode("sidowner", $rule->{'sid-owner'}),"\n"; printf "

$text{'edit_state'}\n"; print "
", &print_mode("state", $rule->{'state'})," 
$text{'edit_tos'}",&print_mode("tos", $rule->{'tos'}),"\n"; print &tos_input("tos", $rule->{'tos'}->[1]),"

$text{'edit_physdevin'}",&print_mode("physdevin", $rule->{'physdev-in'}),"\n"; print &interface_choice("physdevin", $rule->{'physdev-in'}->[1]); print "
$text{'edit_physdevout'}",&print_mode("physdevout", $rule->{'physdev-out'}),"\n"; print &interface_choice("physdevout", $rule->{'physdev-out'}->[1]); print "
$text{'edit_physdevisin'}",&print_mode("physdevisin", $rule->{'physdev-is-in'}, $text{'yes'}, $text{'no'}),"
$text{'edit_physdevisout'}",&print_mode("physdevisout", $rule->{'physdev-is-out'}, $text{'yes'}, $text{'no'}),"
$text{'edit_physdevisbridged'}",&print_mode("physdevisbridged", $rule->{'physdev-is-bridged'}, $text{'yes'}, $text{'no'}),"

$text{'edit_mods'}
$text{'edit_args'}
\n"; print "\n"; if ($in{'new'}) { print "\n"; } else { print "\n"; print "\n"; print "\n"; } print "
\n"; &ui_print_footer("index.cgi?table=$in{'table'}", $text{'index_return'}); # print_mode(name, &value, [yes-option, no-option], [no-no-option]) sub print_mode { local $m = !$_[1] ? 0 : $_[1]->[0] eq "!" ? 2 : 1; local $rv = "\n"; return $rv; } # port_input(name, value) sub port_input { local ($s, $e, $p); if ($_[1] =~ /^(\d*):(\d*)$/) { $s = $1; $e = $2; } else { $p = $_[1] || ""; } local $rv = sprintf " %s\n", defined($p) ? "checked" : "", $text{'edit_port0'}; $rv .= "\n"; $rv .= sprintf "\n", defined($p) ? "" : "checked"; $rv .= &text('edit_port1', "", ""); return $rv; } # tcpflag_input(name, value) sub tcpflag_input { local %flags = map { $_, 1 } split(/,/, $_[1]); local $f; local $rv = "\n"; foreach $f ('SYN', 'ACK', 'FIN', 'RST', 'URG', 'PSH') { $rv .= sprintf " %s\n", $f, $flags{$f} || $flags{'ALL'} ? "checked" : "", "$f"; } $rv .= "\n"; return $rv; } # icmptype_input(name, value, [&types]) sub icmptype_input { local ($started, @types, $major, $minor); $major = -1; if ($_[2]) { @types = @{$_[2]}; } else { open(IPTABLES, "iptables -p icmp -h 2>/dev/null |"); while() { if (/valid\s+icmp\s+types:/i) { $started = 1; } elsif (!/\S/) { $started = 0; } elsif ($started && /^\s*(\S+)/) { push(@types, $1); } } close(IPTABLES); } if (@types && $_[1] !~ /^\d+$/ && $_[1] !~ /^\d+\/\d+$/) { local $rv = "\n"; return $rv; } else { return ""; } } # protocol_input(name, value) sub protocol_input { local @stdprotos = ( 'tcp', 'udp', 'icmp', undef ); local @otherprotos; open(PROTOS, "/etc/protocols"); while() { s/\r|\n//g; s/#.*$//; push(@otherprotos, $1) if (/^(\S+)\s+(\d+)/); } close(PROTOS); @otherprotos = sort { lc($a) cmp lc($b) } @otherprotos; local $p; local $rv = "\n"; $rv .= &ui_textbox($_[0]."_other", $found ? undef : $rule->{'p'}->[1], 5); return $rv; } # tos_input(name, value) sub tos_input { local ($started, @opts); open(IPTABLES, "iptables -m tos -h 2>/dev/null |"); while() { if (/TOS.*options:/i) { $started = 1; } elsif ($started && /^\s+(\S+)\s+(\d+)\s+\((0x[0-9a-f]+)\)/i) { push(@opts, [ $1, $3 ]); } } close(IPTABLES); if (@opts) { local $rv = "\n"; return $rv; } else { return "\n"; } }