211 lines
4.5 KiB
Perl
211 lines
4.5 KiB
Perl
|
#!/usr/bin/perl -w
|
||
|
#
|
||
|
# Written by Camiel Dobbelaar <cd@sentia.nl>, Aug-2000
|
||
|
# ipfmeta is in the Public Domain.
|
||
|
#
|
||
|
|
||
|
use strict;
|
||
|
use Getopt::Std;
|
||
|
|
||
|
## PROCESS COMMANDLINE
|
||
|
our($opt_v); $opt_v=1;
|
||
|
getopts('v:') || die "usage: ipfmeta [-v verboselevel] [objfile]\n";
|
||
|
my $verbose = $opt_v + 0;
|
||
|
my $objfile = shift || "ipf.objs";
|
||
|
my $MAXRECURSION = 10;
|
||
|
|
||
|
## READ OBJECTS
|
||
|
open(FH, "$objfile") || die "cannot open $objfile: $!\n";
|
||
|
my @tokens;
|
||
|
while (<FH>) {
|
||
|
chomp;
|
||
|
s/#.*$//; # remove comments
|
||
|
s/^\s+//; # compress whitespace
|
||
|
s/\s+$//;
|
||
|
next if m/^$/; # skip empty lines
|
||
|
push (@tokens, split);
|
||
|
}
|
||
|
close(FH) || die "cannot close $objfile: $!\n";
|
||
|
# link objects with their values
|
||
|
my $obj="";
|
||
|
my %objs;
|
||
|
while (@tokens) {
|
||
|
my $token = shift(@tokens);
|
||
|
if ($token =~ m/^\[([^]]*)\]$/) {
|
||
|
# new object
|
||
|
$obj = $1;
|
||
|
} else {
|
||
|
# new value
|
||
|
push(@{$objs{$obj}}, $token) unless ($obj eq "");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# sort objects: longest first
|
||
|
my @objs = sort { length($b) <=> length($a) } keys %objs;
|
||
|
|
||
|
## SUBSTITUTE OBJECTS WITH THEIR VALUES FROM STDIN
|
||
|
foreach (<STDIN>) {
|
||
|
foreach (expand($_, 0)) {
|
||
|
print;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
## END
|
||
|
|
||
|
sub expand {
|
||
|
my $line = shift;
|
||
|
my $level = shift;
|
||
|
my @retlines = $line;
|
||
|
my $obj;
|
||
|
my $val;
|
||
|
|
||
|
# coarse protection
|
||
|
if ($level > $MAXRECURSION) {
|
||
|
print STDERR "ERR: recursion exceeds $MAXRECURSION levels\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
foreach $obj (@objs) {
|
||
|
if ($line =~ m/$obj/) {
|
||
|
@retlines = "";
|
||
|
if ($level < $verbose) {
|
||
|
# add metarule as a comment
|
||
|
push(@retlines, "# ".$line);
|
||
|
}
|
||
|
foreach $val (@{$objs{$obj}}) {
|
||
|
my $newline = $line;
|
||
|
$newline =~ s/$obj/$val/;
|
||
|
push(@retlines, expand($newline, $level+1));
|
||
|
}
|
||
|
last;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return @retlines;
|
||
|
}
|
||
|
|
||
|
__END__
|
||
|
|
||
|
=head1 NAME
|
||
|
|
||
|
B<ipfmeta> - use objects in IP filter files
|
||
|
|
||
|
=head1 SYNOPSIS
|
||
|
|
||
|
B<ipfmeta> [F<options>] [F<objfile>]
|
||
|
|
||
|
=head1 DESCRIPTION
|
||
|
|
||
|
B<ipfmeta> is used to simplify the maintenance of your IP filter
|
||
|
ruleset. It does this through the use of 'objects'. A matching
|
||
|
object gets replaced by its values at runtime. This is similar to
|
||
|
what a macro processor like m4 does.
|
||
|
|
||
|
B<ipfmeta> is specifically geared towards IP filter. It is line
|
||
|
oriented, if an object has multiple values, the line with the object
|
||
|
is duplicated and substituted for each value. It is also recursive,
|
||
|
an object may have another object as a value.
|
||
|
|
||
|
Rules to be processed are read from stdin, output goes to stdout.
|
||
|
|
||
|
The verbose option allows for the inclusion of the metarules in the
|
||
|
output as comments.
|
||
|
|
||
|
Definition of the objects and their values is done in a separate
|
||
|
file, the filename defaults to F<ipf.objs>. An object is delimited
|
||
|
by square brackets. A value is delimited by whitespace. Comments
|
||
|
start with '#' and end with a newline. Empty lines and extraneous
|
||
|
whitespace are allowed. A value belongs to the first object that
|
||
|
precedes it.
|
||
|
|
||
|
It is recommended that you use all caps or another distinguishing
|
||
|
feature for object names. You can use B<ipfmeta> for NAT rules also,
|
||
|
for instance to keep them in sync with filter rules. Combine
|
||
|
B<ipfmeta> with a Makefile to save typing.
|
||
|
|
||
|
=head1 OPTIONS
|
||
|
|
||
|
=over 4
|
||
|
|
||
|
=item B<-v> I<verboselevel>
|
||
|
|
||
|
Include metarules in output as comments. Default is 1, the top level
|
||
|
metarules. Higher levels cause expanded metarules to be included.
|
||
|
Level 0 does not add comments at all.
|
||
|
|
||
|
=back
|
||
|
|
||
|
=head1 BUGS
|
||
|
|
||
|
A value can not have whitespace in it.
|
||
|
|
||
|
=head1 EXAMPLE
|
||
|
|
||
|
(this does not look good, formatted)
|
||
|
|
||
|
I<ipf.objs>
|
||
|
|
||
|
[PRIVATE] 10.0.0.0/8 127.0.0.0/8 172.16.0.0/12 192.168.0.0/16
|
||
|
|
||
|
[MULTICAST] 224.0.0.0/4
|
||
|
|
||
|
[UNWANTED] PRIVATE MULTICAST
|
||
|
|
||
|
[NOC] xxx.yy.zz.1/32 xxx.yy.zz.2/32
|
||
|
|
||
|
[WEBSERVERS] 192.168.1.1/32 192.168.1.2/32
|
||
|
|
||
|
[MGMT-PORTS] 22 23
|
||
|
|
||
|
I<ipf.metarules>
|
||
|
|
||
|
block in from UNWANTED to any
|
||
|
|
||
|
pass in from NOC to WEBSERVERS port = MGMT-PORTS
|
||
|
|
||
|
pass out all
|
||
|
|
||
|
I<Run>
|
||
|
|
||
|
ipfmeta ipf.objs <ipf.metarules >ipf.rules
|
||
|
|
||
|
I<Output>
|
||
|
|
||
|
# block in from UNWANTED to any
|
||
|
|
||
|
block in from 10.0.0.0/8 to any
|
||
|
|
||
|
block in from 127.0.0.0/8 to any
|
||
|
|
||
|
block in from 172.16.0.0/12 to any
|
||
|
|
||
|
block in from 192.168.0.0/16 to any
|
||
|
|
||
|
block in from 224.0.0.0/4 to any
|
||
|
|
||
|
# pass in from NOC to WEBSERVERS port = MGMT-PORTS
|
||
|
|
||
|
pass in from xxx.yy.zz.1/32 to 192.168.1.1/32 port = 22
|
||
|
|
||
|
pass in from xxx.yy.zz.1/32 to 192.168.1.1/32 port = 23
|
||
|
|
||
|
pass in from xxx.yy.zz.1/32 to 192.168.1.2/32 port = 22
|
||
|
|
||
|
pass in from xxx.yy.zz.1/32 to 192.168.1.2/32 port = 23
|
||
|
|
||
|
pass in from xxx.yy.zz.2/32 to 192.168.1.1/32 port = 22
|
||
|
|
||
|
pass in from xxx.yy.zz.2/32 to 192.168.1.1/32 port = 23
|
||
|
|
||
|
pass in from xxx.yy.zz.2/32 to 192.168.1.2/32 port = 22
|
||
|
|
||
|
pass in from xxx.yy.zz.2/32 to 192.168.1.2/32 port = 23
|
||
|
|
||
|
pass out all
|
||
|
|
||
|
=head1 AUTHOR
|
||
|
|
||
|
Camiel Dobbelaar <cd@sentia.nl>. B<ipfmeta> is in the Public Domain.
|
||
|
|
||
|
=cut
|