+---- Changes since 1.351 ----
+Corrected name to "Shoreline Firewall".
+Correctly determine Shorewall version for beta releases.
+Corrected zones file support on version 3 or greater when IPSECFILE=ipsec.
+Added bug compatibility with IPSECFILE on Shorewall 3.4.0-3.4.4.
+Added support for renaming firewall zone.
+Added support for editing of params & shorewall.conf.
---- Changes since 1.140 ----
Added buttons for adding rules or other table entries above or below an existing entry.
Added support for OpenVPN and generic tunnels.
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# Delete a bunch of table rows
require './shorewall-lib.pl';
&ReadParse();
&can_access($in{'table'}) || &error($text{'list_ecannot'});
-$pfunc = $in{'table'}."_parser";
-$pfunc = "standard_parser" if (!defined(&$pfunc));
+$pfunc = &get_parser_func(\%in);
&error_setup($text{'delete_err'});
@d = split(/\0/, $in{'d'});
scalar(@d) || &error($text{'delete_enone'});
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# down.cgi
# Move a row in a table down
require './shorewall-lib.pl';
&ReadParse();
&can_access($in{'table'}) || &error($text{'list_ecannot'});
-
-$pfunc = $in{'table'}."_parser";
-$pfunc = "standard_parser" if (!defined(&$pfunc));
+$pfunc = &get_parser_func(\%in);
&lock_table($in{'table'});
&swap_table_rows($in{'table'}, $pfunc, $in{'idx'}, $in{'idx'}+1);
&unlock_table($in{'table'});
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# edit.cgi
# Display a form for editing or creating a table entry
require './shorewall-lib.pl';
&ReadParse();
+&get_clean_table_name(\%in);
&can_access($in{'table'}) || &error($text{'list_ecannot'});
if ($in{'new'}) {
- &ui_print_header(undef, $text{$in{'table'}."_create"}, "");
+ &ui_print_header(undef, $text{$in{'tableclean'}."_create"}, "");
if ($in{'before'} ne '') {
$msg = &text('edit_before', $in{'before'}+1);
}
print "<center><font size=+1>$msg</font></center>\n" if ($msg);
}
else {
- &ui_print_header(undef, $text{$in{'table'}."_edit"}, "");
- $pfunc = $in{'table'}."_parser";
- $pfunc = "standard_parser" if (!defined(&$pfunc));
+ &ui_print_header(undef, $text{$in{'tableclean'}."_edit"}, "");
+ $pfunc = &get_parser_func(\%in);
@table = &read_table_file($in{'table'}, $pfunc);
$row = $table[$in{'idx'}];
}
print "<input type=hidden name=after value='$in{'after'}'>\n";
print "<table border width=100%>\n";
-print "<tr $tb> <td><b>",$text{$in{'table'}."_header"},"</b></td> </tr>\n";
+print "<tr $tb> <td><b>",$text{$in{'tableclean'}."_header"},"</b></td> </tr>\n";
print "<tr $cb> <td><table width=100%>\n";
-$ffunc = $in{'table'}."_form";
+$ffunc = $in{'tableclean'}."_form";
&$ffunc(@$row);
print "</table></td></tr></table>\n";
print "</form>\n";
-&ui_print_footer("list.cgi?table=$in{'table'}", $text{$in{'table'}."_return"});
+&ui_print_footer("list.cgi?table=$in{'table'}", $text{$in{'tableclean'}."_return"});
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# Display a form for editing or creating a comment
require './shorewall-lib.pl';
&ReadParse();
+&get_clean_table_name(\%in);
&can_access($in{'table'}) || &error($text{'list_ecannot'});
if ($in{'new'}) {
&ui_print_header(undef, $text{"comment_create"}, "");
}
else {
&ui_print_header(undef, $text{"comment_edit"}, "");
- $pfunc = $in{'table'}."_parser";
- $pfunc = "standard_parser" if (!defined(&$pfunc));
+ $pfunc = &get_parser_func(\%in);
@table = &read_table_file($in{'table'}, $pfunc);
$row = $table[$in{'idx'}];
}
[ "delete", $text{'delete'} ] ]);
}
-&ui_print_footer("list.cgi?table=$in{'table'}", $text{$in{'table'}."_return"});
+&ui_print_footer("list.cgi?table=$in{'table'}", $text{$in{'tableclean'}."_return"});
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# index.cgi
# Display icons for the various shorewall configuration files
&ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1, 0,
&help_search_link("shorewall", "doc", "google"),
- undef, undef, &text('index_version', $shorewall_version));
+ undef, undef, &text('index_version', &get_printable_version($shorewall_version)));
if (!-d $config{'config_dir'}) {
# Config dir not found!
else {
# Just show the file icons
@files = grep { &can_access($_) } @shorewall_files;
- @titles = map { $text{$_."_title"}."<br>($_)" } @files;
+ @titles = map { $text{&clean_name($_)."_title"}."<br>($_)" } @files;
@links = map { "list.cgi?table=".$_ } @files;
@icons = map { "images/".$_.".gif" } @files;
&icons_table(\@links, \@titles, \@icons, 4);
log_refresh=Refreshed firewall
log_restart=Restarted firewall
log_clear=Cleared firewall
+
+shorewall_conf_title=Master configuration file
+shorewall_conf_desc=This page allows you to configure the global configuration variables. NOTE: Changing the order of variables here is not recommended if you wish to preserve the relative position of comments in the configuration file.
+shorewall_conf_add=Add a new configuration variable.
+shorewall_conf_none=No shorewall configuration found.
+shorewall_conf_0=Variable
+shorewall_conf_1=Value
+shorewall_conf_return=configuration variables list
+shorewall_conf_edit=Edit configuration variable
+shorewall_conf_create=Create configuration variable
+shorewall_conf_header=Configuration variable details
+shorewall_conf_err=Failed to save configuration variable
+shorewall_conf_varname=Invalid variable name (must be a valid shell variable name)
+
+params_title=Custom parameters
+params_desc=This page allows you to configure Shorewall's custom parameters. NOTE: Changing the order of parameters here is not recommended if you wish to preserve the relative position of comments in the configuration file.
+params_add=Add a new custom parameter.
+params_none=No custom parameters found.
+params_0=Parameter
+params_1=Value
+params_return=custom parameters list
+params_edit=Edit custom parameter
+params_create=Create custom parameter
+params_header=Custom parameter details
+params_err=Failed to save custom parameter
+params_varname=Invalid parameter name (must be a valid shell variable name)
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# list.cgi
# Display the contents of some table
require './shorewall-lib.pl';
&ReadParse();
&can_access($in{'table'}) || &error($text{'list_ecannot'});
-&ui_print_header(undef, $text{$in{'table'}."_title"}, "");
+&get_clean_table_name(\%in);
+&ui_print_header(undef, $text{$in{'tableclean'}."_title"}, "");
-$desc = $text{$in{'table'}."_desc"};
+$desc = $text{$in{'tableclean'}."_desc"};
print "$desc<p>\n" if ($desc);
-$pfunc = $in{'table'}."_parser";
-$pfunc = "standard_parser" if (!defined(&$pfunc));
+$pfunc = &get_parser_func(\%in);
@table = &read_table_file($in{'table'}, $pfunc);
-$cfunc = $in{'table'}."_columns";
+$cfunc = $in{'tableclean'}."_columns";
$cols = &$cfunc() if (defined(&$cfunc));
-$nfunc = $in{'table'}."_colnames";
+$nfunc = $in{'tableclean'}."_colnames";
+#&debug_message("cfunc = $cfunc");
+#&debug_message("nfunc = $nfunc");
if (defined(&$nfunc)) {
@colnames = &$nfunc();
}
else {
@colnames = ( );
- for($j=0; defined($cols) ? ($j<$cols) : ($text{$in{'table'}."_".$j}); $j++) {
- push(@colnames, $text{$in{'table'}."_".$j});
+ for($j=0; defined($cols) ? ($j<$cols) : ($text{$in{'tableclean'}."_".$j}); $j++) {
+ push(@colnames, $text{$in{'tableclean'}."_".$j});
}
}
@links = ( &select_all_link("d"),
&select_invert_link("d"),
"<a href='edit.cgi?table=$in{'table'}&new=1'>".
- $text{$in{'table'}."_add"}."</a>" );
+ $text{$in{'tableclean'}."_add"}."</a>" );
if (&version_atleast(3, 3, 3) && &indexof($in{'table'}, @comment_tables) >= 0) {
push(@links, "<a href='editcmt.cgi?table=$in{'table'}&new=1'>".
$text{"comment_add"}."</a>");
$text{'list_add'}
], undef, 0, [ "width=5" ]);
- $rfunc = $in{'table'}."_row";
+ $rfunc = $in{'tableclean'}."_row";
for($i=0; $i<@table; $i++) {
@t = @{$table[$i]};
local @cols;
print &ui_columns_end();
}
else {
- print "<b>",$text{$in{'table'}."_none"},"</b><p>\n";
+ print "<b>",$text{$in{'tableclean'}."_none"},"</b><p>\n";
shift(@links); shift(@links);
}
print &ui_links_row(\@links);
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# Display the contents of a table file
require './shorewall-lib.pl';
&ReadParse();
+&get_clean_table_name(\%in);
&can_access($in{'table'}) || &error($text{'list_ecannot'});
-&ui_print_header(undef, $text{$in{'table'}."_title"}, "");
+&ui_print_header(undef, $text{$in{'tableclean'}."_title"}, "");
$file = "$config{'config_dir'}/$in{'table'}";
$in{'table'} =~ /\.\./ && &error($text{'manual_efile'});
print "<input type=reset value='$text{'manual_reset'}'>\n";
print "</form>\n";
-&ui_print_footer("list.cgi?table=$in{'table'}", $text{$in{'table'}."_return"});
+&ui_print_footer("list.cgi?table=$in{'table'}", $text{$in{'tableclean'}."_return"});
-name=Shorewall
-desc=Shorewall Firewall
+name=Shoreline
+desc=Shoreline Firewall
category=net
os_support=*-linux
depends=syslog
-longdesc=Lets you edit the most useful tables of the simple Shoreline Firewall
-desc_ca=Tallafocs Shorewall
-desc_es=Cortafuegos Shorewall
+longdesc=Lets you edit the most useful tables of the Shoreline Firewall
+desc_ca=Tallafocs Shoreline
+desc_es=Cortafuegos Shoreline
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# save.cgi
# Updated, modify or delete a table entry
require './shorewall-lib.pl';
&ReadParse();
+&get_clean_table_name(\%in);
&can_access($in{'table'}) || &error($text{'list_ecannot'});
-$pfunc = $in{'table'}."_parser";
-$pfunc = "standard_parser" if (!defined(&$pfunc));
-&error_setup($text{$in{'table'}."_err"});
+$pfunc = &get_parser_func(\%in);
+&error_setup($text{$in{'tableclean'}."_err"});
&lock_table($in{'table'});
if ($in{'delete'}) {
}
else {
# Validate inputs
- $vfunc = $in{'table'}."_validate";
+ $vfunc = $in{'tableclean'}."_validate";
@row = &$vfunc();
- $jfunc = $in{'table'}."_join";
+ $jfunc = $in{'tableclean'}."_join";
if (defined(&$jfunc)) {
$line = &$jfunc(@row);
}
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# Updated, modify or delete a comment
require './shorewall-lib.pl';
&ReadParse();
&can_access($in{'table'}) || &error($text{'list_ecannot'});
-$pfunc = $in{'table'}."_parser";
-$pfunc = "standard_parser" if (!defined(&$pfunc));
+$pfunc = &get_parser_func(\%in);
&error_setup($text{"comment_err"});
&lock_table($in{'table'});
# shorewall-lib.pl
# Common functions for the shorewall configuration files
-# XXX rule sections
+# FIXME:
+# - rule sections
+# - read_shorewall_config & standard_parser do not allow quoted comment characters
do '../web-lib.pl';
&init_config();
# Get the version
$shorewall_version = &get_shorewall_version(0);
+%shorewall_config = &read_shorewall_config();
+#&dump_shorewall_config();
# get access permissions
%access = &get_module_acl();
@shorewall_files = ( 'zones', 'interfaces', 'policy', 'rules', 'tos',
'masq', 'nat', 'proxyarp', 'routestopped',
'tunnels', 'hosts', 'blacklist',
- ( &version_atleast(2, 3) ? ( 'providers' ) : ( ) ) );
+ ( &version_atleast(2, 3) ? ( 'providers' ) : ( ) ),
+ 'params', 'shorewall.conf',
+);
@comment_tables = ( 'masq', 'nat', 'rules', 'tcrules' );
-# version_atleast(v1, v2, v3)
+sub debug_message
+{
+ print STDERR scalar(localtime).": shorewall-lib: @_\n";
+}
+
+# version_atleast(v1, v2, v3, ...)
+# - Check if the Shorewall version is greater than or equal to the one supplied.
sub version_atleast
{
local @vsp = split(/\./, $shorewall_version);
return 1; # same!
}
+sub read_shorewall_config
+{
+ local @ret;
+ open(SHOREWALL_CONF, "$config{'config_dir'}/shorewall.conf");
+ while (<SHOREWALL_CONF>) {
+ chomp;
+ s/\r//;
+ s/#.*$//;
+ @F = split( /=/, $_, 2 );
+ next if $#F != 1;
+ push @ret, ( $F[0], $F[1] );
+ }
+ close(SHOREWALL_CONF);
+ return @ret;
+}
+
+# dump_shorewall_config()
+# - Debugging code
+sub dump_shorewall_config
+{
+ for (sort keys %shorewall_config) {
+ print STDERR "$_=$shorewall_config{$_}\n";
+ }
+}
+
+# shorewall_config(var)
+sub shorewall_config
+{
+ if (exists $shorewall_config{$_[0]} && defined $shorewall_config{$_[0]}) {
+ return $shorewall_config{$_[0]};
+ }
+ return '';
+}
+
+# return true if new zones format is in use
+sub new_zones_format
+{
+ # Shorewall 3.4.0 - 3.4.4 have a bug that prevents the old format from being used.
+ if (&version_atleast(3, 4) && !&version_atleast(3, 4, 5)) {
+ return 1;
+ }
+ # Zones table is in new format in Shorewall 3, unless shorewall.conf has IPSECFILE=ipsec
+ if (!&version_atleast(3) || &shorewall_config('IPSECFILE') eq 'ipsec') {
+ return 0;
+ }
+ return 1;
+}
+
# read_table_file(table, &parserfunc)
sub read_table_file
{
&unlock_file("$config{'config_dir'}/$_[0]");
}
+# parser for whitespace-separated config files
sub standard_parser
{
local $l = $_[0];
return @sp ? \@sp : undef;
}
+# parser for shell-style config files
+sub config_parser
+{
+ local $l = $_[0];
+ $l =~ s/#.*$//;
+ local @sp = split(/=/, $l, 2);
+ return @sp ? \@sp : undef;
+}
+
+# determine which parser function to use
+sub get_parser_func
+{
+ local $hashref = $_[0];
+ &get_clean_table_name($hashref);
+ &debug_message("table = $hashref->{'table'}, pfunc = $pfunc");
+ local $pfunc = $hashref->{'tableclean'}."_parser";
+ if (!defined(&$pfunc)) {
+ if ($hashref->{'tableclean'} =~ /^(params|shorewall_conf)$/) {
+ $pfunc = "config_parser";
+ }
+ else {
+ $pfunc = "standard_parser";
+ }
+ }
+ &debug_message("table = $hashref->{'table'}, pfunc = $pfunc");
+ return $pfunc;
+}
+
+# ensure that the passed string contains only characters valid in shell variable identifiers
+sub clean_name
+{
+ local $str = $_[0];
+ $str =~ s/\W/_/g;
+ return $str;
+}
+
+# get a table name that is clean enough to use as a function prefix
+sub get_clean_table_name
+{
+ local $hashref = $_[0];
+ if (!exists hashref->{'tableclean'}) {
+ $hashref->{'tableclean'} = &clean_name($in{'table'});
+ &debug_message("table = " . $hashref->{'table'} . ", tableclean = " . $hashref->{'tableclean'});
+ }
+}
+
# zone_field(name, value, othermode, simplemode)
sub zone_field
{
$found = !$_[1] || $_[1] eq 'all' || &is_fw($_[1]);
}
foreach $z (@ztable) {
- if (&version_atleast(3)) {
+ if (&new_zones_format()) {
printf "<option value=%s %s>%s\n",
$z->[0], $_[1] eq $z->[0] ? "selected" : "", $z->[0];
}
# Given a zone name, returns a description
sub convert_zone
{
-if (&version_atleast(3)) {
+if (&new_zones_format()) {
# No descriptions in shorewall 3
return $_[0];
}
}
# is_fw(zone)
+# - Checks if the supplied zone is the firewall zone.
+# Now handles renaming of firewall zone in shorewall.conf.
sub is_fw
{
-return $_[0] eq '$FW' || $_[0] eq 'fw';
+ local $fw = &shorewall_config('FW');
+ $fw = 'fw' if ($fw eq '');
+ return $_[0] eq '$FW' || $_[0] eq $fw;
}
################################# zones #######################################
sub zones_parser
{
-if (&version_atleast(3)) {
- # Zones table is in new format in Shorewall 3
+if (&new_zones_format()) {
+ # New format
local $l = $_[0];
$l =~ s/#.*$//;
local @r = split(/\s+/, $l);
sub zones_columns
{
-return &version_atleast(3) ? 2 : 3;
+return &new_zones_format() ? 2 : 3;
}
sub zones_row
{
-if (&version_atleast(3)) {
+if (&new_zones_format()) {
return ( $_[0], $text{'zones_'.$_[1]} || $_[1] );
}
else {
sub zones_colnames
{
-if (&version_atleast(3)) {
+if (&new_zones_format()) {
return ( $text{'zones_0'}, $text{'zones_1new'} );
}
else {
sub zones_form
{
-if (&version_atleast(3)) {
+if (&new_zones_format()) {
# Shorewall 3 zones format
print "<tr> <td><b>$text{'zones_0'}</b></td>\n";
print "<td>",&ui_textbox("id", $_[0], 8),"</td>\n";
{
$in{'id'} =~ /^\S+$/ || &error($text{'zones_eid'});
&is_fw($in{'id'}) && &error($text{'zones_efwid'});
-if (&version_atleast(3)) {
+if (&new_zones_format()) {
# Parse new format
$in{'opts'} =~ /^\S*$/ || &error($text{'zones_eopts'});
$in{'opts_in'} =~ /^\S*$/ || &error($text{'zones_eopts_in'});
$in{'copy'} || "-" );
}
+################################ shorewall.conf ##################################
+
+sub conf_form
+{
+ local $msg1 = shift;
+ local $msg2 = shift;
+ local ($var, $val, $dummy) = @_;
+
+ &debug_message( "var = $var, val = $val");
+
+ $var =~ s/"/"/g;
+ print "<tr><td><b>$msg1</b></td>\n";
+ print "<td><input name=var size=50 value=\"$var\"></td></tr>\n";
+
+ $val =~ s/"/"/g;
+ print "<tr><td><b>$msg2</b></td>\n";
+ print "<td><input name=val size=50 value=\"$val\"></td></tr>\n";
+
+ print "</td></tr>\n";
+}
+
+sub shorewall_conf_columns
+{
+ return 2;
+}
+
+sub shorewall_conf_form
+{
+ &conf_form($text{'shorewall_conf_0'}, $text{'shorewall_conf_1'}, @_);
+}
+
+sub shorewall_conf_validate
+{
+ &debug_message("invar = $in{'var'}");
+ &error($text{'shorewall_conf_varname'}) unless $in{'var'} =~ /^\w+$/;
+ return ($in{'var'}.'='.$in{'val'});
+}
+
+################################ params ##################################
+
+sub params_columns
+{
+ return 2;
+}
+
+sub params_form
+{
+ &conf_form($text{'params_0'}, $text{'params_1'}, @_);
+}
+
+sub params_validate
+{
+ &debug_message("invar = $in{'var'}");
+ &error($text{'params_varname'}) unless $in{'var'} =~ /^\w+$/;
+ return ($in{'var'}.'='.$in{'val'});
+}
+
+
#############################################################################
# can_access(file)
return &unique(@rv);
}
+$BETA_STR = "-Beta";
+$BETA_NUM = "\.0000\.";
+
# get_shorewall_version(nocache)
sub get_shorewall_version
{
chop($version = <VERSION>);
close(VERSION);
}
-else {
+if (!$version) {
local $out = `$config{'shorewall'} version 2>&1`;
$out =~ s/\r//g;
+ $out =~ s/$BETA_STR/$BETA_NUM/i; # Convert beta string to version number.
if ($out =~ /(\n|^)([0-9\.]+)\n/) {
$version = $2;
}
return $version;
}
+sub get_printable_version($)
+{
+ local $out = $_[0];
+ $out =~ s/$BETA_NUM/$BETA_STR/i; # Convert version number back to string.
+ return $out;
+}
+
sub list_protocols
{
local @stdprotos = ( 'tcp', 'udp', 'icmp' );
print "</table>\n";
}
+&debug_message("shorewall-lib.pl loaded");
+
1;
-#!/usr/local/bin/perl
+#!/usr/bin/perl
# up.cgi
# Move a row in a table up
require './shorewall-lib.pl';
&ReadParse();
&can_access($in{'table'}) || &error($text{'list_ecannot'});
-
-$pfunc = $in{'table'}."_parser";
-$pfunc = "standard_parser" if (!defined(&$pfunc));
+$pfunc = &get_parser_func(\%in);
&lock_table($in{'table'});
&swap_table_rows($in{'table'}, $pfunc, $in{'idx'}, $in{'idx'}-1);
&unlock_table($in{'table'});