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 -><- 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 () {
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
=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