On Wed, Jan 10, 2007 at 02:18:57PM +0100, Johan Segern?s wrote:
> Today it looks like (very stripped down)
> pass in on $FOO_NET inet from $FOO_IPS to any keep state
> pass in on $BAR_NET inet from $BAR_IPS to any keep state
>
> Instead I would like to do it like
> for i in FOO BAR; do
> pass in on ${i}_NET inet from ${i}_IPS to any keep state
> done> Or something. Is this possible within pf.conf or would I have to make a > shell loop creating this little extra pf config file and include in > pf.conf? You could also do it with dfd_keeper, available off my web site. It's a framework for writing pf rules using python. There used to be a static version, but I think it didn't present enough utility to continue to maintain static-only as a seperate library. You could do it as a shell script, or any kind of preprocessor. I don't really like the way m4 syntax looks, or how it re-reads expanded macros as input again. The cpp would be fine if it wasn't specific to C, so I wrote a little script that mimics cpp (but offers much more flexibility) and I've attached it for your convenience. -- ``Unthinking respect for authority is the greatest enemy of truth.'' -- Albert Einstein -><- <URL:http://www.subspacefield.org/~travis/>
#! /usr/local/bin/perl -w
# $Id: preprocess 11947 2007-01-12 04:01:15Z user $
$main::command="#"; # semicolon is the default command indicator
$main::ignore_header = 1; # ignore interpreter line and leading #commands
$main::quiet = 0; # give error messages for invalid commands
$main::leading_spaces = 1;
$main::fi_match = 0;
$main::empty_fi = 1; # Empty commands are fi commands by default.
use Getopt::Long;
GetOptions("command=s", \$main::command,
"define=s%", \%main::preprocess,
"quiet!", \$main::quiet,
"ignore!", \$main::ignore_header,
"leading-spaces!", \$main::leading_spaces,
"fi-match!", \$main::fi_match,
"empty!", \$main::empty_fi);
@main::regions = ( [ 1, ""] ); # The root-level region is a printing region.
# Force user-defined variables into preprocess namespace.
while (($key, $val) = each (%main::preprocess)) {
eval "\$preprocess::$key = $val";
}
$main::skip_spaces = ($main::leading_spaces ? '\s*' : '');
# We found a command line, so do something.
sub process_command {
my ($command) = @_;
$_ = $command;
# Get rid of leading/trailing white space.
s/^\s*//;
s/\s*$//;
# Do we want to allow trailing comments? Other comments?
# Empty commands are fi commands by default.
$_ = "fi" if ($main::empty_fi and $_ eq "");
# Process any end-of-region markers.
if (/^(endif|fi)(\s+(.*))?$/) {
die "Unexpected end of region at line $.\n" unless $#main::regions;
my ($truth, $expr) = @{pop @main::regions};
if (defined($3) and $main::fi_match and $expr ne $3) {
die "Unmatched fi at line $. (\"$expr\" ne \"$3\")\n";
}
return;
}
# NB: We do not ignore if commands inside conditional regions that are
# false because we allow nested if statements. We need to see the
# if statement so we can skip the next end-of-region marker.
if (/^(unless|if)\s+(.*)$/) {
my $expr = $2;
package preprocess;
my $condition = eval $expr;
# Undefined expressions are false.
$condition = 0 unless defined($condition);
package main;
my $cond_truth = ($1 eq "if") ? $condition : !$condition;
# NB: If we are in a false region, all nested regions are false.
push(@main::regions, [ $cond_truth && $main::current_truth, $expr ]);
return;
}
# Ignore anything else if we are in a conditional region that is false.
return unless $main::current_truth;
if (/([^=]+)\s*=\s*([^=]+)/) {
package preprocess;
eval "$1=$2";
return;
}
die "Invalid command $_ at line $.\n" unless $main::quiet;
}
while (<STDIN>) {
chomp;
# NB: Easier to short-circuit the header if we are ignoring it.
if (/^#/ and $main::ignore_header) { print "$_\n"; next; }
$main::ignore_header = 0;
# Is the current region true?
$main::current_truth = $main::regions[-1]->[0];
if ($_ =~ /^$main::skip_spaces$main::command(.*)$/) {
process_command($1);
next;
}
print "$_\n" if $main::current_truth;
}
if ($#main::regions) { die "Not enough fi statements.\n"; }
exit 0;
__END__
=head1 NAME
preprocess - Preprocess arbitrary files.
=head1 SYNPOSIS
preprocess --command=';' --quiet <whatever.in > whatever
=head1 DESCRIPTION
This program is used for conditionally printing various regions of a file.
It is much like the C preprocessor, except that it is meant for any text
file, not just C code. Its command language is a restricted subset of Perl.
=item --command delimiter
Specify that you may introduce commands to preprocess by beginning the line
with the specified delimiter.
=item --define var=val
Define a variable. Must be in perl syntax (e.g. '$foo = bar').
=item --quiet
Ignore lines that start with the command delimiter, but are not valid commands.
=item --ignore
Don't treat any leading lines beginning with hash (#) as commands, even if the
command delimiter is hash.
=item --leading-spaces
Allow leading spaces before the command character.
=item --fi-match
Allow expressions to follow fi statements to match them to if statements.
This is to catch errors such as forgetting a fi statement.
=head2 COMMANDS
The commands in the file may be one of the following:
=item if [expr]
The following lines are printed if the Perl expression is true.
=item unless [expr]
The following lines are printed unless the expression is true.
=item fi [expr]
Ends an if or unless block.
If --fi-match is enabled, you may optionally add an expression which
must match the corresponding if/unless expression.
=item var=expr
Set the value of a variable.
=head2 EXAMPLES
#! /bin/sh
; if $foo
$foo is defined
; endif
=head2 AUTHOR
The author is [EMAIL PROTECTED]
=cut
pgpqY52wiL4Zm.pgp
Description: PGP signature
