Handle hostnames with upper-case letters
[webmin.git] / firewall / index.cgi
1 #!/usr/local/bin/perl
2 # index.cgi
3 # Display current iptables firewall configuration from save file
4
5 require './firewall-lib.pl';
6 &ReadParse();
7 if ($iptables_save_file) {
8         $desc = &text('index_editing', "<tt>$iptables_save_file</tt>");
9         }
10 &ui_print_header(undef, $text{'index_title'}, undef, "intro", 1, 1, 0,
11         &help_search_link("iptables", "man", "doc"), undef, undef, $desc);
12
13 # Check for iptables and iptables-restore commands
14 if ($c = &missing_firewall_commands()) {
15         print "<p>",&text('index_ecommand', "<tt>$c</tt>"),"<p>\n";
16         &ui_print_footer("/", $text{'index'});
17         exit;
18         }
19
20 # Check if the kernel supports iptables
21 $out = `iptables -n -t filter -L OUTPUT 2>&1`;
22 if ($?) {
23         print "<p>",&text('index_ekernel', "<pre>$out</pre>"),"<p>\n";
24         &ui_print_footer("/", $text{'index'});
25         exit;
26         }
27
28 # Check if the distro supports iptables
29 if (!$config{'direct'} && defined(&check_iptables) &&
30     ($err = &check_iptables())) {
31         print "<p>$err</p>\n";
32         &ui_print_footer("/", $text{'index'});
33         exit;
34         }
35
36 # Check if firewall is being started at boot
37 if (!$config{'direct'} && &foreign_check("init")) {
38         $init_support++;
39         if (defined(&started_at_boot)) {
40                 $atboot = &started_at_boot();
41                 }
42         else {
43                 &foreign_require("init", "init-lib.pl");
44                 $atboot = &init::action_status("webmin-iptables") == 2;
45                 }
46         }
47
48 # Check if the save file exists. If not, check for any existing firewall
49 # rules, and offer to create a save file from them
50 @livetables = &get_iptables_save("iptables-save 2>/dev/null |");
51 &shorewall_message(\@livetables);
52 if (!$config{'direct'} &&
53     (!-s $iptables_save_file || $in{'reset'}) && $access{'setup'}) {
54         @tables = @livetables;
55         foreach $t (@tables) {
56                 $rules++ if (@{$t->{'rules'}});
57                 foreach $c (keys %{$t->{'defaults'}}) {
58                         $chains++ if ($t->{'defaults'}->{$c} ne 'ACCEPT');
59                         }
60                 $hastable{$t->{'name'}}++;
61                 }
62         foreach $t (@known_tables) {
63                 system("iptables -t $t -n -L >/dev/null") if (!$hastable{$t});
64                 }
65         if (!$in{'reset'} && ($rules || $chains)) {
66                 # Offer to save the current rules
67                 print &text('index_existing', $rules,
68                             "<tt>$iptables_save_file</tt>"),"<p>\n";
69                 print "<form action=convert.cgi>\n";
70                 print "<center><input type=submit ",
71                       "value='$text{'index_saveex'}'><p>\n";
72                 if ($init_support && !$atboot) {
73                         print "<input type=checkbox name=atboot value=1> ",
74                               "$text{'index_atboot'}\n";
75                         }
76                 print "</center></form><p>\n";
77
78                 print "<table border width=100%>\n";
79                 print "<tr $tb><td><b>$text{'index_headerex'}</b></td></tr>\n";
80                 print "<tr $cb> <td><pre>";
81                 open(OUT, "iptables-save 2>/dev/null |");
82                 while(<OUT>) {
83                         print &html_escape($_);
84                         }
85                 close(OUT);
86                 print "</pre></td> </tr></table>\n";
87                 }
88         else {
89                 # Offer to set up a firewall
90                 print &text($in{'reset'} ? 'index_rsetup' : 'index_setup',
91                             "<tt>$iptables_save_file</tt>"),"<p>\n";
92                 print "<form action=setup.cgi>\n";
93                 print &ui_hidden("reset", $in{'reset'});
94                 print "<center><table><tr><td>\n";
95                 print "<input type=radio name=auto value=0 checked> ",
96                       "$text{'index_auto0'}<p>\n";
97                 foreach $a (1 .. 5) {
98                         print "<input type=radio name=auto value=$a> ",
99                               "$text{'index_auto'.$a} ",
100                               &interface_choice("iface".$a),"<p>\n";
101                         }
102                 print "</td></tr></table>\n";
103                 print "<input type=submit value='$text{'index_auto'}'><p>\n";
104                 if ($init_support && !$atboot) {
105                         print "<input type=checkbox name=atboot value=1> ",
106                               "$text{'index_atboot'}\n";
107                         }
108                 print "</center></form>\n";
109                 }
110         }
111 else {
112         $form = 0;
113         @tables = &get_iptables_save();
114         if (!$config{'direct'}) {
115                 # Verify that all known tables exist, and if not add them to the
116                 # save file
117                 foreach $t (@tables) {
118                         $hastable{$t->{'name'}}++;
119                         }
120                 foreach $t (@known_tables) {
121                         if (!$hastable{$t}) {
122                                 local ($missing) = &get_iptables_save(
123                                     "iptables-save --table $t 2>/dev/null |");
124                                 if ($missing) {
125                                         delete($missing->{'line'});
126                                         &save_table($missing);
127                                         }
128                                 $need_reload++;
129                                 }
130                         }
131                 @tables = &get_iptables_save() if ($need_reload);
132                 }
133
134         # Work out the default table
135         if (!defined($in{'table'})) {
136                 foreach $t (@tables) {
137                         if (@{$t->{'rules'}} && &can_edit_table($t->{'name'})) {
138                                 $in{'table'} = $t->{'index'};
139                                 last;
140                                 }
141                         }
142                 }
143         if (!defined($in{'table'})) {
144                 foreach $t (@tables) {
145                         if (&can_edit_table($t->{'name'})) {
146                                 $in{'table'} = $t->{'index'};
147                                 last;
148                                 }
149                         }
150                 }
151         $table = $tables[$in{'table'}];
152
153         # Allow selection of a table
154         print "<table width=100%><tr>\n";
155         print "<form action=index.cgi>\n";
156         print "<td><input type=submit value='$text{'index_change'}'>\n";
157         print "<select name=table onChange='form.submit()'>\n";
158         foreach $t (@tables) {
159                 if (&can_edit_table($t->{'name'})) {
160                         printf "<option value=%s %s>%s\n",
161                             $t->{'index'}, $t eq $table ? "selected" : "",
162                             &text('index_table_'.$t->{'name'}) || $t->{'name'};
163                         }
164                 }
165         print "</select></td></form>\n";
166         $form++;
167
168         if ($access{'newchain'}) {
169                 # Show form to create a chain
170                 print "<form action=newchain.cgi>\n";
171                 print "<td align=right>",&ui_hidden("table", $in{'table'});
172                 print "<input type=submit value='$text{'index_cadd'}'>\n";
173                 print "<input name=chain size=20></td></form>\n";
174                 print "</tr></table>\n";
175                 $form++;
176                 }
177
178         # Display a table of rules for each chain
179         foreach $c (sort by_string_for_iptables keys %{$table->{'defaults'}}) {
180                 print &ui_hr();
181                 @rules = grep { lc($_->{'chain'}) eq lc($c) }
182                               @{$table->{'rules'}};
183                 print "<b>",$text{"index_chain_".lc($c)} ||
184                             &text('index_chain', "<tt>$c</tt>"),"</b><br>\n";
185                 print "<form action=save_policy.cgi>\n";
186                 print &ui_hidden("table", $in{'table'});
187                 print &ui_hidden("chain", $c);
188                 if (@rules) {
189                         @links = ( &select_all_link("d", $form),
190                                    &select_invert_link("d", $form) );
191                         print &ui_links_row(\@links);
192
193                         # Generate the header
194                         local (@hcols, @tds);
195                         push(@hcols, "", $text{'index_action'});
196                         push(@tds, "width=5", "width=10% nowrap");
197                         if ($config{'view_condition'}) {
198                                 push(@hcols, $text{'index_desc'});
199                                 push(@tds, "");
200                                 }
201                         if ($config{'view_comment'}) {
202                                 push(@hcols, $text{'index_comm'});
203                                 push(@tds, "");
204                                 }
205                         push(@hcols, $text{'index_move'}, $text{'index_add'});
206                         push(@tds, "width=32", "width=32");
207                         print &ui_columns_start(\@hcols, 100, 0, \@tds);
208
209                         # Generate a row for each rule
210                         foreach $r (@rules) {
211                                 $edit = &can_jump($r);
212                                 local @cols;
213                                 local $act =
214                                   $text{"index_jump_".lc($r->{'j'}->[1])} ||
215                                   &text('index_jump', $r->{'j'}->[1]);
216                                 if ($edit) {
217                                         push(@cols, "<a href='edit_rule.cgi?table=".&urlize($in{'table'})."&idx=$r->{'index'}'>$act</a>");
218                                         }
219                                 else {
220                                         push(@cols, $act);
221                                         }
222                                 if ($config{'view_condition'}) {
223                                         push(@cols, &describe_rule($r));
224                                         }
225                                 if ($config{'view_comment'}) {
226                                         $cmt = $config{'comment_mod'} ||
227                                                $r->{'comment'} ?
228                                             $r->{'comment'}->[1] : $r->{'cmt'};
229                                         push(@cols, $cmt);
230                                         }
231
232                                 # Up/down mover
233                                 local $mover;
234                                 if ($r eq $rules[@rules-1]) {
235                                         $mover .= "<img src=images/gap.gif>";
236                                         }
237                                 else {
238                                         $mover .= "<a href='move.cgi?table=".
239                                               &urlize($in{'table'}).
240                                               "&idx=$r->{'index'}&".
241                                               "down=1'><img src=".
242                                               "images/down.gif border=0></a>";
243                                         }
244                                 if ($r eq $rules[0]) {
245                                         $mover .= "<img src=images/gap.gif>";
246                                         }
247                                 else {
248                                         $mover .= "<a href='move.cgi?table=".
249                                               &urlize($in{'table'}).
250                                               "&idx=$r->{'index'}&".
251                                               "up=1'><img src=images/up.gif ".
252                                               "border=0></a>";
253                                         }
254                                 push(@cols, $mover);
255
256                                 # Before / after adder
257                                 local $adder;
258                                 $adder .= "<a href='edit_rule.cgi?table=".
259                                       &urlize($in{'table'}).
260                                       "&chain=".&urlize($c)."&new=1&".
261                                       "after=$r->{'index'}'><img src=".
262                                       "images/after.gif border=0></a>";
263                                 $adder .= "<a href='edit_rule.cgi?table=".
264                                       &urlize($in{'table'}).
265                                       "&chain=".&urlize($c)."&new=1&".
266                                       "before=$r->{'index'}'><img src=".
267                                       "images/before.gif border=0></a>";
268                                 push(@cols, $adder);
269
270                                 if ($edit) {
271                                         print &ui_checked_columns_row(
272                                             \@cols, \@tds, "d", $r->{'index'});
273                                         }
274                                 else {
275                                         print &ui_columns_row(\@cols, \@tds);
276                                         }
277                                 }
278                         print &ui_columns_end();
279                         print &ui_links_row(\@links);
280                         }
281                 else {
282                         print "<b>$text{'index_none'}</b><br>\n";
283                         }
284
285                 # Show policy changing button for chains that support it,
286                 # and rule-adding button
287                 print "<table width=100%><tr>\n";
288                 local $d = $table->{'defaults'}->{$c};
289                 if ($d ne '-') {
290                         # Built-in chain
291                         if ($access{'policy'}) {
292                                 # Change default button
293                                 print "<td width=33% nowrap>",
294                                       &ui_submit($text{'index_policy'}),"\n";
295                                 print "<select name=policy>\n";
296                                 foreach $t ('ACCEPT','DROP','QUEUE','RETURN') {
297                                         printf "<option value=%s %s>%s\n",
298                                                 $t, $d eq $t ? "selected" : "",
299                                                 $text{"index_policy_".lc($t)};
300                                         }
301                                 print "</select></td>\n";
302                                 }
303                         else {
304                                 print "<td width=33%></td>\n";
305                                 }
306                         print "<td align=center width=33%>\n";
307                         if (@rules) {
308                                 # Delete selected button
309                                 print &ui_submit($text{'index_cdeletesel'},
310                                                  "delsel"),"\n";
311
312                                 # Move selected button
313                                 print &ui_submit($text{'index_cmovesel'},
314                                                  "movesel"),"\n";
315                                 }
316                         print "</td>\n";
317                         }
318                 else {
319                         # Custom chain
320                         if ($access{'delchain'}) {
321                                 # Delete and rename chain buttons
322                                 print "<td width=33%>",
323                                    &ui_submit($text{'index_cdelete'}, "delete"),
324                                    "\n",
325                                    &ui_submit($text{'index_crename'}, "rename"),
326                                    "</td>\n";
327                                 }
328                         print "<td align=center width=33%>\n";
329                         if (@rules) {
330                                 # Clear chain button
331                                 if ($access{'delchain'}) {
332                                         print &ui_submit($text{'index_cclear'},
333                                                          "clear"),"\n";
334                                         }
335
336                                 # Delete rules button
337                                 print &ui_submit($text{'index_cdeletesel'},
338                                                  "delsel"),"\n";
339
340                                 # Move selected button
341                                 print &ui_submit($text{'index_cmovesel'},
342                                                  "movesel"),"\n";
343                                 }
344                         print "</td>\n";
345                         }
346                 print "<td align=right width=33%>",
347                       &ui_submit($text{'index_radd'}, "add"),"</td>\n";
348                 print "</tr></table></form>\n";
349                 $form++;
350                 }
351
352         # Display buttons for applying and un-applying the configuration,
353         # and for creating an init script if possible
354         print &ui_hr();
355         print "<table width=100%>\n";
356
357         if (!$config{'direct'}) {
358                 if (&foreign_check("servers")) {
359                         @servers = &list_cluster_servers();
360                         }
361                 if ($access{'apply'}) {
362                         print "<tr><form action=apply.cgi>\n";
363                         print &ui_hidden("table", $in{'table'});
364                         print "<td><input type=submit ",
365                               "value='$text{'index_apply'}'></td>\n";
366                         if (@servers) {
367                                 print "<td>$text{'index_applydesc2'}</td>\n";
368                                 }
369                         else {
370                                 print "<td>$text{'index_applydesc'}</td>\n";
371                                 }
372                         print "</form></tr>\n";
373                         }
374
375                 if ($access{'unapply'}) {
376                         print "<tr><form action=unapply.cgi>\n";
377                         print &ui_hidden("table", $in{'table'});
378                         print "<td><input type=submit ",
379                               "value='$text{'index_unapply'}'></td>\n";
380                         print "<td>$text{'index_unapplydesc'}</td>\n";
381                         print "</form></tr>\n";
382                         }
383
384                 if ($init_support && $access{'bootup'}) {
385                         print "<tr><form action=bootup.cgi>\n";
386                         print &ui_hidden("table", $in{'table'});
387                         print "<td nowrap><input type=submit ",
388                               "value='$text{'index_bootup'}'>\n";
389                         printf "<input type=radio name=boot value=1 %s> %s\n",
390                                 $atboot ? "checked" : "", $text{'yes'};
391                         printf "<input type=radio name=boot value=0 %s> %s\n",
392                                 $atboot ? "" : "checked", $text{'no'};
393                         print "</td> <td>$text{'index_bootupdesc'}</td>\n";
394                         print "</form></tr>\n";
395                         }
396
397                 if ($access{'setup'}) {
398                         print "<tr><form action=index.cgi>\n";
399                         print "<input type=hidden name=reset value=1>\n";
400                         print "<td><input type=submit ",
401                               "value='$text{'index_reset'}'></td>\n";
402                         print "<td>$text{'index_resetdesc'}</td>\n";
403                         print "</form></tr>\n";
404                         }
405                 }
406
407         # Show button for cluster page
408         if (&foreign_check("servers")) {
409                 &foreign_require("servers", "servers-lib.pl");
410                 @allservers = grep { $_->{'user'} }
411                                 &servers::list_servers();
412                 }
413         if ($access{'cluster'} && @allservers) {
414                 print "<tr><form action=cluster.cgi>\n";
415                 print "<td><input type=submit ",
416                       "value='$text{'index_cluster'}'></td>\n";
417                 print "<td>$text{'index_clusterdesc'}</td>\n";
418                 print "</form></tr>\n";
419                 }
420
421         print "</table>\n";
422         }
423
424 &ui_print_footer("/", $text{'index'});
425
426 sub shorewall_message
427 {
428 local ($filter) = grep { $_->{'name'} eq 'filter' } @{$_[0]};
429 if ($filter->{'defaults'}->{'shorewall'}) {
430         print "<b><center>",
431               &text('index_shorewall', "$gconfig{'webprefix'}/shorewall/"),
432               "</b></center><p>\n";
433         }
434 }
435