| #!/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 |