Re: Making 'loops' in pf.conf

2007-01-11 Thread Travis H.
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 

Re: Making 'loops' in pf.conf

2007-01-10 Thread Max Laier

Am Mi, 10.01.2007, 14:18, schrieb Johan Segernäs:
> I have several networks in different IP nets and different incoming
> interfaces. I would like to make this a loop or something instead of, as
> it is now, different blocks.
>
> 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?

"pfctl -f-" is your friend.  There are a million tools our there that are
simply made to do stuff like this, just feed the output to pfctl.  Also
take a look at:
http://blog.xbsd.org/2006/11/04/freebsdpf-include-command-hack/

-- 
/"\  Best regards,  | [EMAIL PROTECTED]
\ /  Max Laier  | ICQ #67774661
 X   http://pf4freebsd.love2party.net/  | [EMAIL PROTECTED]
/ \  ASCII Ribbon Campaign  | Against HTML Mail and News