diff --git a/edit_rule.cgi b/edit_rule.cgi
index 17b41dca9..142ace248 100755
--- a/edit_rule.cgi
+++ b/edit_rule.cgi
@@ -17,6 +17,23 @@ my $proto_sel;
my $icmp_type;
my $log_enabled;
my $raw_extra = "";
+my $ct_state_sel;
+my $tcp_flags_sel;
+my $advanced_open;
+
+sub split_multi_value
+{
+ my ($v) = @_;
+ return undef if (!defined($v) || $v eq '');
+ $v =~ s/^\s*\{//;
+ $v =~ s/\}\s*$//;
+ $v =~ s/^\s+//;
+ $v =~ s/\s+$//;
+ return undef if ($v eq '');
+ my @vals = split(/\s*,\s*/, $v);
+ @vals = grep { $_ ne '' } @vals;
+ return \@vals;
+}
if ($in{'new'}) {
&ui_print_header(undef, $text{'edit_title_new'}, "", "intro", 1, 1);
@@ -53,8 +70,50 @@ if ($rule) {
}
$proto_sel ||= 'tcp' if ($in{'new'});
$icmp_type = $rule->{'icmp_type'} || $rule->{'icmpv6_type'};
+ $ct_state_sel = &split_multi_value($rule->{'ct_state'});
+ $tcp_flags_sel = &split_multi_value($rule->{'tcp_flags'});
$log_enabled = $rule->{'log'} || $rule->{'log_prefix'} || $rule->{'log_level'};
}
+$advanced_open = 1 if ($action_sel && ($action_sel eq 'jump' || $action_sel eq 'goto'));
+$advanced_open = 1 if ($rule && (
+ $rule->{'jump'} || $rule->{'goto'} ||
+ $rule->{'iif'} || $rule->{'oif'} ||
+ $icmp_type ||
+ $rule->{'ct_state'} ||
+ $rule->{'tcp_flags'} || $rule->{'tcp_flags_mask'} ||
+ $rule->{'limit_rate'} || $rule->{'limit_burst'} ||
+ $log_enabled ||
+ $rule->{'counter'}
+));
+
+my @icmp_types = qw(
+ echo-reply destination-unreachable source-quench redirect echo-request
+ router-advertisement router-solicitation time-exceeded parameter-problem
+ timestamp-request timestamp-reply info-request info-reply
+ address-mask-request address-mask-reply
+);
+my @icmpv6_types = qw(
+ destination-unreachable packet-too-big time-exceeded parameter-problem
+ echo-request echo-reply mld-listener-query mld-listener-report
+ mld-listener-done mld-listener-reduction nd-router-solicit
+ nd-router-advert nd-neighbor-solicit nd-neighbor-advert nd-redirect
+ router-renumbering ind-neighbor-solicit ind-neighbor-advert
+ mld2-listener-report
+);
+my %icmp_seen;
+my @icmp_type_opts = ( [ "", $text{'edit_proto_any'} ] );
+foreach my $t (@icmp_types, @icmpv6_types) {
+ next if ($icmp_seen{$t}++);
+ push(@icmp_type_opts, [ $t, $t ]);
+}
+my @ct_state_opts = (
+ [ "", $text{'edit_proto_any'} ],
+ map { [ $_, $_ ] } qw(invalid new established related untracked),
+);
+my @tcp_flags_opts = (
+ [ "", $text{'edit_proto_any'} ],
+ map { [ $_, $_ ] } qw(fin syn rst psh ack urg ecn cwr),
+);
print &ui_form_start("save_rule.cgi");
print &ui_hidden("table", $in{'table'});
@@ -66,11 +125,11 @@ print &ui_hidden("raw_extra", $raw_extra);
print &ui_table_start($text{'edit_header'}, "width=100%", 2);
# Rule comment
-print &ui_table_row($text{'edit_comment'},
+print &ui_table_row(hlink($text{'edit_comment'}, "comment"),
&ui_textbox("comment", $rule->{'comment'}, 50));
# Action
-print &ui_table_row($text{'edit_action'},
+print &ui_table_row(hlink($text{'edit_action'}, "action"),
&ui_select("action", $action_sel,
[
[ "accept", $text{'index_accept'} ],
@@ -81,39 +140,14 @@ print &ui_table_row($text{'edit_action'},
[ "goto", $text{'edit_goto_action'} ],
]));
-# Jump/Goto target chain
-print &ui_table_row($text{'edit_jump'},
- &ui_textbox("jump", $rule->{'jump'}, 20));
-print &ui_table_row($text{'edit_goto'},
- &ui_textbox("goto", $rule->{'goto'}, 20));
-
-# Interfaces
-if ($chain_hook && $chain_hook eq 'input') {
- # Incoming interface
- print &ui_table_row($text{'edit_iif'},
- &interface_choice("iif", $rule->{'iif'}, $text{'edit_if_any'}));
-}
-elsif ($chain_hook && $chain_hook eq 'output') {
- # Outgoing interface
- print &ui_table_row($text{'edit_oif'},
- &interface_choice("oif", $rule->{'oif'}, $text{'edit_if_any'}));
-}
-else {
- # Forward or unknown chain - allow both
- print &ui_table_row($text{'edit_iif'},
- &interface_choice("iif", $rule->{'iif'}, $text{'edit_if_any'}));
- print &ui_table_row($text{'edit_oif'},
- &interface_choice("oif", $rule->{'oif'}, $text{'edit_if_any'}));
-}
-
# Addresses
-print &ui_table_row($text{'edit_saddr'},
+print &ui_table_row(hlink($text{'edit_saddr'}, "saddr"),
&ui_textbox("saddr", $rule->{'saddr'}, 30));
-print &ui_table_row($text{'edit_daddr'},
+print &ui_table_row(hlink($text{'edit_daddr'}, "daddr"),
&ui_textbox("daddr", $rule->{'daddr'}, 30));
# Protocol
-print &ui_table_row($text{'edit_proto'},
+print &ui_table_row(hlink($text{'edit_proto'}, "proto"),
&ui_select("proto", $proto_sel,
[
[ "", $text{'edit_proto_any'} ],
@@ -124,46 +158,81 @@ print &ui_table_row($text{'edit_proto'},
]));
# Ports
-print &ui_table_row($text{'edit_sport'},
+print &ui_table_row(hlink($text{'edit_sport'}, "sport"),
&ui_textbox("sport", $rule->{'sport'}, 10));
-print &ui_table_row($text{'edit_dport'},
+print &ui_table_row(hlink($text{'edit_dport'}, "dport"),
&ui_textbox("dport", $rule->{'dport'}, 10));
+print &ui_table_end();
+
+print &ui_hidden_table_start($text{'edit_advanced'}, "width=100%", 2,
+ "advanced", $advanced_open ? 1 : 0);
+
+# Jump/Goto target chain
+print &ui_table_row(hlink($text{'edit_jump'}, "jump"),
+ &ui_textbox("jump", $rule->{'jump'}, 20));
+print &ui_table_row(hlink($text{'edit_goto'}, "goto"),
+ &ui_textbox("goto", $rule->{'goto'}, 20));
+
+# Interfaces
+if ($chain_hook && $chain_hook eq 'input') {
+ # Incoming interface
+ print &ui_table_row(hlink($text{'edit_iif'}, "iif"),
+ &interface_choice("iif", $rule->{'iif'}, $text{'edit_if_any'}));
+}
+elsif ($chain_hook && $chain_hook eq 'output') {
+ # Outgoing interface
+ print &ui_table_row(hlink($text{'edit_oif'}, "oif"),
+ &interface_choice("oif", $rule->{'oif'}, $text{'edit_if_any'}));
+}
+else {
+ # Forward or unknown chain - allow both
+ print &ui_table_row(hlink($text{'edit_iif'}, "iif"),
+ &interface_choice("iif", $rule->{'iif'}, $text{'edit_if_any'}));
+ print &ui_table_row(hlink($text{'edit_oif'}, "oif"),
+ &interface_choice("oif", $rule->{'oif'}, $text{'edit_if_any'}));
+}
+
# ICMP type
-print &ui_table_row($text{'edit_icmp_type'},
- &ui_textbox("icmp_type", $icmp_type, 20));
+print &ui_table_row(hlink($text{'edit_icmp_type'}, "icmp_type"),
+ &ui_select("icmp_type", $icmp_type, \@icmp_type_opts, 1, 0, 1));
# Conntrack state
-print &ui_table_row($text{'edit_ct_state'},
- &ui_textbox("ct_state", $rule->{'ct_state'}, 30));
+print &ui_table_row(hlink($text{'edit_ct_state'}, "ct_state"),
+ &ui_select("ct_state", $ct_state_sel, \@ct_state_opts, 5, 1, 1));
# TCP flags
-print &ui_table_row($text{'edit_tcp_flags'},
- &ui_textbox("tcp_flags", $rule->{'tcp_flags'}, 20));
-print &ui_table_row($text{'edit_tcp_flags_mask'},
+print &ui_table_row(hlink($text{'edit_tcp_flags'}, "tcp_flags"),
+ &ui_select("tcp_flags", $tcp_flags_sel, \@tcp_flags_opts, 8, 1, 1));
+print &ui_table_row(hlink($text{'edit_tcp_flags_mask'}, "tcp_flags_mask"),
&ui_textbox("tcp_flags_mask", $rule->{'tcp_flags_mask'}, 20));
# Limit
-print &ui_table_row($text{'edit_limit_rate'},
+print &ui_table_row(hlink($text{'edit_limit_rate'}, "limit_rate"),
&ui_textbox("limit_rate", $rule->{'limit_rate'}, 20));
-print &ui_table_row($text{'edit_limit_burst'},
+print &ui_table_row(hlink($text{'edit_limit_burst'}, "limit_burst"),
&ui_textbox("limit_burst", $rule->{'limit_burst'}, 10));
# Log
-my $log_row = &ui_checkbox("log", 1, $text{'edit_log_enable'}, $log_enabled);
+my $log_row = &ui_checkbox("log", 1, hlink($text{'edit_log_enable'}, "log_enable"), $log_enabled);
$log_row .= "
".&text('edit_log_prefix', &ui_textbox("log_prefix", $rule->{'log_prefix'}, 20));
$log_row .= " ".&text('edit_log_level', &ui_textbox("log_level", $rule->{'log_level'}, 10));
print &ui_table_row($text{'edit_log'}, $log_row);
# Counter
-print &ui_table_row($text{'edit_counter'},
+print &ui_table_row(hlink($text{'edit_counter'}, "counter"),
&ui_checkbox("counter", 1, $text{'edit_counter_enable'}, $rule->{'counter'}));
+print &ui_hidden_table_end("advanced");
+
+print &ui_table_start($text{'edit_rule'}, "width=100%", 2);
+
# Raw rule (read-only unless edit direct is checked)
my $raw_controls = &ui_checkbox("edit_direct", 1, $text{'edit_raw_rule_direct'}, 0);
my $raw_area = &ui_textarea("raw_rule", $rule->{'text'}, 4, 60, undef, undef,
"readonly='true'");
-print &ui_table_row($text{'edit_raw_rule'}, $raw_controls."
".$raw_area);
+print &ui_table_row(hlink($text{'edit_raw_rule'}, "raw_rule"), $raw_controls."
".$raw_area,
+ undef, undef, ["data-column-span='all' data-column-locked='1'"]);
print &ui_table_end();
my @buttons;
@@ -175,9 +244,29 @@ if ($in{'new'}) {
}
print &ui_form_end(\@buttons);
+sub js_array
+{
+ my (@vals) = @_;
+ return "[".join(",", map {
+ my $v = $_;
+ $v =~ s/\\/\\\\/g;
+ $v =~ s/"/\\"/g;
+ "\"$v\"";
+ } @vals)."]";
+}
+
+my $icmp_js = &js_array(@icmp_types);
+my $icmpv6_js = &js_array(@icmpv6_types);
+my $icmp_any = $text{'edit_proto_any'};
+$icmp_any =~ s/\\/\\\\/g;
+$icmp_any =~ s/"/\\"/g;
+
+print "