Handle hostnames with upper-case letters
[webmin.git] / ipfw / edit_rule.cgi
1 #!/usr/local/bin/perl
2 # Display a form for editing or creating a firewall rule
3
4 require './ipfw-lib.pl';
5 &ReadParse();
6 $rules = &get_config();
7
8 if ($in{'delsel'}) {
9         # Special case - deleting selected rules
10         %nums = map { $_, 1 } split(/\0/, $in{'d'});
11         @$rules = grep { !$nums{$_->{'num'}} } @$rules;
12         &lock_file($ipfw_file);
13         &save_config($rules);
14         &unlock_file($ipfw_file);
15         &webmin_log("delsel", undef, undef,
16                     { 'count' => scalar(keys %nums) });
17         &redirect("");
18         exit;
19         }
20
21 if ($in{'new'}) {
22         &ui_print_header(undef, $text{'edit_title1'}, "");
23         $rule = { 'action' => 'allow',
24                   'from' => 'any',
25                   'to' => 'any' };
26         }
27 else {
28         $rule = $rules->[$in{'idx'}];
29         &ui_print_header(undef, &text('edit_title2', $rule->{'num'}), "");
30         }
31
32 print &ui_form_start("save_rule.cgi", "post");
33 print &ui_hidden("new", $in{'new'}),"\n";
34 print &ui_hidden("idx", $in{'idx'}),"\n";
35 print &ui_hidden("before", $in{'before'}),"\n";
36 print &ui_hidden("after", $in{'after'}),"\n";
37 @tds = ( "width=20%", undef );
38
39 print &ui_table_start($text{'edit_header1'}, "width=100%", 2);
40
41 # Comment
42 print &ui_table_row($text{'edit_cmt'},
43                     $rule->{'cmt'} =~ /\n/ ? 
44                         &ui_textarea("cmt", $rule->{'cmt'}, 3, 50) :
45                         &ui_textbox("cmt", $rule->{'cmt'}, 50),
46                     undef, \@tds);
47
48 # Number for new rules
49 if ($in{'new'} && !$in{'before'} && !$in{'after'}) {
50         print &ui_table_row($text{'edit_num'},
51                 &ui_opt_textbox("num", undef, 6, $text{'default'}));
52         }
53
54 # Rule action and argument
55 $ra = &real_action($rule->{'action'});
56 push(@action, $ra) if ($ra && &indexof($ra, @actions) < 0);
57 $acts = "<table cellpadding=1 cellspacing=1>\n";
58 $i = 0;
59 foreach $a (@actions) {
60         $acts .= "<tr>\n" if ($i%2 == 0);
61         $acts .= "<td nowrap>";
62         local $ma = $rule->{'action'} eq $a;
63         $acts .= &ui_oneradio("action", $a,
64                         $text{"laction_".$a} || $text{"action_".$a} || uc($a),
65                         $ma);
66         if ($a eq "skipto") {
67                 $acts .= &ui_textbox("action_skipto",
68                                      $ma ? $rule->{'aarg'} : "", 8);
69                 }
70         elsif ($a eq "fwd") {
71                 local ($ip, $port) = split(/,/, $rule->{'aarg'});
72                 $acts .= &ui_textbox("action_fwdip", $ma ? $ip : "", 15).":".
73                          &ui_textbox("action_fwdport", $ma ? $port : "", 5);
74                 }
75         elsif ($a eq "divert" || $a eq "pipe" || $a eq "queue" || $a eq "tee") {
76                 $acts .= &ui_textbox("action_port",
77                                      $ma ? $rule->{'aarg'} : "", 5);
78                 }
79         elsif ($a eq "unreach") {
80                 $acts .= &ui_select("action_unreach", $ma ? $rule->{'aarg'} :"",
81                                     [ map { [ $_, $_ ] } @unreaches ]);
82                 }
83         $acts .= "</td>";
84         $acts .= "</tr>\n" if ($i++%2 == 1);
85         }
86 $acts .= "</table>\n";
87 print &ui_table_row($text{'edit_action'}, $acts,
88                     undef, \@tds);
89
90 # Logging field
91 print &ui_table_row($text{'edit_log'},
92                    &ui_oneradio("log", 0, $text{'no'},
93                                 !$rule->{'log'})." ".
94                    &ui_oneradio("log", 1,
95                                 &text('edit_logyes',
96                                   &ui_textbox("logamount",
97                                                 $rule->{'logamount'}, 5)),
98                                 $rule->{'log'}));
99
100 # State-keeping rule
101 print &ui_table_row($text{'edit_keep-state'},
102                     &yes_no_ignored_input("keep-state"), 1, \@tds);
103
104 print &ui_table_end();
105 print "<p>\n";
106
107 # Condition section
108 print "$text{'edit_desc'}<br>\n";
109 print &ui_table_start($text{'edit_header3'}, "width=100%", 4);
110
111 # Protocol field
112 if (ref($rule->{'proto'})) {
113         # Multiple or-block values!
114         print &ui_table_row($text{'edit_proto'},
115                             &orblock_input("proto", $rule->{'proto'}));
116         }
117 else {
118         local @protos = &list_protocols();
119         $rule->{'proto'} = "all" if ($rule->{'proto'} eq "ip");
120         print &ui_table_row($text{'edit_proto'},
121                             &ui_select("proto", $rule->{'proto'},
122                                        [ [ "all", $text{'edit_any'} ],
123                                          map { [ $_, uc($_) ] } @protos ]),
124                             undef, \@tds);
125         }
126
127 # Incoming / outgoing
128 $iomode = $rule->{'in'} || $rule->{'out'} && $rule->{'out_not'} ? 1 :
129           $rule->{'out'} || $rule->{'in'} && $rule->{'in_not'} ? 2 : 0;
130 print &ui_table_row($text{'edit_inout'},
131                     &ui_select("inout", $iomode,
132                               [ [ 0, "<$text{'edit_ignored'}>" ],
133                                 [ 1, $text{'edit_inout1'} ],
134                                 [ 2, $text{'edit_inout2'} ] ]), 1, \@tds);
135
136 # Via interface
137 print &ui_table_row($text{'edit_via'},
138                     &interface_choice("via", $rule->{'via'}), 1, \@tds);
139
140 print &ui_table_end();
141 print "<p>\n";
142
143 # Source and destination sections
144 foreach $s ("from", "to") {
145         print &ui_table_start($text{'edit_header'.$s}, "width=100%", 2);
146
147         # IP address
148         if (ref($rule->{$s})) {
149                 print &ui_table_row($text{'edit_'.$s},
150                                     &orblock_input($s, $rule->{$s}));
151                 }
152         else {
153                 local $mode = $rule->{$s} eq "any" ? 0 :
154                               $rule->{$s} eq "me" ? 1 : 2;
155                 print &ui_table_row($text{'edit_'.$s},
156                       &ui_oneradio($s."_mode", 0, $text{'edit_sany'},
157                                    $mode == 0)."<br>".
158                       &ui_oneradio($s."_mode", 1, $text{'edit_sme'},
159                                    $mode == 1)."<br>".
160                       &ui_oneradio($s."_mode", 2, $text{'edit_saddr'},
161                                    $mode == 2)." ".
162                       &ui_textbox($s, $mode == 2 ? $rule->{$s} : "", 40),
163                       undef, \@tds);
164                 print &ui_table_row("",
165                       &ui_checkbox($s."_not", 1, $text{'edit_snot'},
166                                    $rule->{$s."_not"}),
167                       undef, \@tds);
168                 }
169         #print &ui_table_hr();
170
171         # Ports within IPs
172         if (ref($rule->{$s."_ports"})) {
173                 print &ui_table_row($text{'edit_port'.$s},
174                     &orblock_input($s."_ports", $rule->{$s."_ports"}));
175                 }
176         else {
177                 local $mode = defined($rule->{$s."_ports"}) ? 1 : 0;
178                 print &ui_table_row($text{'edit_port'.$s},
179                       &ui_oneradio($s."_ports_mode", 0, $text{'edit_pany'},
180                                    $mode == 0)."<br>".
181                       &ui_oneradio($s."_ports_mode", 1, $text{'edit_ports'},
182                                    $mode == 1)." ".
183                       &ui_textbox($s."_ports", $mode == 1 ? $rule->{$s."_ports"}
184                                                  : "", 40),
185                       undef, \@tds);
186                 if ($ipfw_version >= 2) {
187                         print &ui_table_row("",
188                               &ui_checkbox($s."_ports_not", 1, $text{'edit_pnot'},
189                                            $rule->{$s."_ports_not"}),
190                               undef, \@tds);
191                         }
192                 }
193
194         # Received interface
195         local $rs = $s eq "from" ? "recv" : "xmit";
196         print &ui_table_row($text{'edit_'.$rs},
197                             &interface_choice($rs, $rule->{$rs}), 1, \@tds);
198
199         print &ui_table_end();
200         print "<p>\n";
201         }
202
203 # Options section
204 @tds = ( "", "nowrap" );
205 # XXX or-block support
206 print &ui_table_start($text{'edit_header2'}, "width=100%", 4);
207
208 # Established traffic
209 print &ui_table_row($text{'edit_established'},
210                     &yes_no_ignored_input("established"), 1, \@tds);
211
212 # TCP setup packets
213 print &ui_table_row($text{'edit_setup'},
214                     &yes_no_ignored_input("setup"), 1, \@tds);
215
216 # Bridged packets
217 print &ui_table_row($text{'edit_bridged'},
218                     &yes_no_ignored_input("bridged"), 1, \@tds);
219
220 # Fragmented packets
221 print &ui_table_row($text{'edit_frag'},
222                     &yes_no_ignored_input("frag"), 1, \@tds);
223
224 # MAC addresses (if supported)
225 if ($ipfw_version >= 2) {
226         local ($md, $ms) = $rule->{'mac'} ? @{$rule->{'mac'}} : ( "any", "any" );
227         print &ui_table_row($text{'edit_mac1'},
228                     &ui_radio("mac1_def", $ms eq "any" ? 1 : 0,
229                               [ [ 1, $text{'edit_ignored'} ],
230                                 [ 0, $text{'edit_macaddr'} ] ] )." ".
231                     &ui_textbox("mac1", $ms eq "any" ? "" : $ms, 20), 3, \@tds);
232         print &ui_table_row($text{'edit_mac2'},
233                     &ui_radio("mac2_def", $md eq "any" ? 1 : 0,
234                               [ [ 1, $text{'edit_ignored'} ],
235                                 [ 0, $text{'edit_macaddr'} ] ] )." ".
236                     &ui_textbox("mac2", $md eq "any" ? "" : $md, 20), 3, \@tds);
237         }
238
239 # UID and GID
240 if (defined($rule->{'uid'})) {
241         $user = getpwuid($rule->{'uid'});
242         $user = "#".$rule->{'uid'} if (!defined($user));
243         }
244 print &ui_table_row($text{'edit_uid'},
245                     &ui_radio("uid_def", $user ? 0 : 1,
246                               [ [ 1, $text{'edit_ignored'} ],
247                                 [ 0, $text{'edit_user'} ] ] )." ".
248                     &ui_user_textbox("uid", $user), 3, \@tds);
249 if (defined($rule->{'gid'})) {
250         $group = getgrgid($rule->{'gid'});
251         $group = "#".$rule->{'gid'} if (!defined($group));
252         }
253 print &ui_table_row($text{'edit_gid'},
254                     &ui_radio("gid_def", $group ? 0 : 1,
255                               [ [ 1, $text{'edit_ignored'} ],
256                                 [ 0, $text{'edit_group'} ] ] )." ".
257                     &ui_group_textbox("gid", $group), 3, \@tds);
258
259 # ICMP types
260 %gottypes = map { $_, 1 }
261                 map { $_ =~ /^(\d+)\-(\d+)$/ ? ( $1 .. $2 ) : ( $_ ) }
262                         split(/,/, $rule->{'icmptypes'});
263 $icmptypes = "<select name=icmptypes size=5 multiple>\n";
264 for($i=0; $i<@icmptypes; $i++) {
265         if ($icmptypes[$i] || $gottypes{$i}) {
266                 $icmptypes .= sprintf "<option value=%d %s>%s\n",
267                         $i, $gottypes{$i} ? "selected" : "",
268                         $icmptypes[$i] || "Type $i";
269                 }
270         }
271 $icmptypes .= "</select>\n";
272 print &ui_table_row($text{'edit_icmptypes'}, $icmptypes, 1, \@tds);
273
274 # TCP flags
275 %gotflags = map { $_, 1 } split(/,/, $rule->{'tcpflags'});
276 $tcpflags = "<select name=tcpflags size=5 multiple>\n";
277 foreach $i (@tcpflags) {
278         $tcpflags .= sprintf "<option value=%s %s>%s\n",
279                 $i, $gotflags{$i} ? "selected" : "", $i;
280         }
281 foreach $i (@tcpflags) {
282         $tcpflags .= sprintf "<option value=!%s %s>%s\n",
283                 $i, $gotflags{"!$i"} ? "selected" : "", &text('edit_not', $i);
284         }
285 $tcpflags .= "</select>\n";
286 print &ui_table_row($text{'edit_tcpflags'}, $tcpflags, 1, \@tds);
287
288 # Limit directive
289 print &ui_table_row($text{'edit_limit'},
290               &ui_select("limit", $rule->{'limit'} ? $rule->{'limit'}->[0] : "",
291                          [ [ "", "<$text{'edit_unlimited'}>" ],
292                            [ "src-addr", $text{'edit_src-addr'} ],
293                            [ "src-port", $text{'edit_src-port'} ],
294                            [ "dst-addr", $text{'edit_dst-addr'} ],
295                            [ "dst-port", $text{'edit_dst-port'} ] ])." ".
296               &ui_textbox("limit2", $rule->{'limit'} ? $rule->{'limit'}->[1]
297                                                      : "", 6),
298               3, \@tds);
299
300 # Destination ports directive
301 print &ui_table_row($text{'edit_dstport'},
302     &ui_opt_textbox("dstport",
303         $rule->{'dst-port'} ? join(" ", @{$rule->{'dst-port'}}) : undef,
304         30, $text{'edit_pany'}), 3, \@tds);
305
306 # Source ports directive
307 print &ui_table_row($text{'edit_srcport'},
308     &ui_opt_textbox("srcport",
309         $rule->{'src-port'} ? join(" ", @{$rule->{'src-port'}}) : undef,
310         30, $text{'edit_pany'}), 3, \@tds);
311
312 print &ui_table_end();
313
314 if ($in{'new'}) {
315         print &ui_form_end([ [ 'create', $text{'create'} ] ], "100%");
316         }
317 else {
318         print &ui_form_end([ [ 'save', $text{'save'} ],
319                              [ 'delete', $text{'delete'} ] ], "100%");
320         }
321
322 &ui_print_footer("", $text{'index_return'});
323
324 # orblock_input(name, &orblock)
325 sub orblock_input
326 {
327 return $text{'edit_orblock'}." ".
328        &ui_textbox($_[0], join(" ", @{$_[1]}), 50).
329        &ui_hidden($_[0]."_orblock", 1);
330 }
331
332 # yes_no_ignored_input(name)
333 sub yes_no_ignored_input
334 {
335 local $mode = $rule->{$_[0]} && $rule->{$_[0]."_not"} ? 2 :
336               $rule->{$_[0]} ? 1 : 0;
337 return &ui_radio($_[0], $mode,
338                  [ [ 1, $text{'yes'} ],
339                    [ 0, $text{'no'} ] ]);
340 }
341