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