1#!/usr/bin/perl -w 2# 3# Written by Camiel Dobbelaar <cd@sentia.nl>, Aug-2000 4# ipfmeta is in the Public Domain. 5# 6 7use strict; 8use Getopt::Std; 9 10## PROCESS COMMANDLINE 11our($opt_v); $opt_v=1; 12getopts('v:') || die "usage: ipfmeta [-v verboselevel] [objfile]\n"; 13my $verbose = $opt_v + 0; 14my $objfile = shift || "ipf.objs"; 15my $MAXRECURSION = 10; 16 17## READ OBJECTS 18open(FH, "$objfile") || die "cannot open $objfile: $!\n"; 19my @tokens; 20while (<FH>) { 21 chomp; 22 s/#.*$//; # remove comments 23 s/^\s+//; # compress whitespace 24 s/\s+$//; 25 next if m/^$/; # skip empty lines 26 push (@tokens, split); 27} 28close(FH) || die "cannot close $objfile: $!\n"; 29# link objects with their values 30my $obj=""; 31my %objs; 32while (@tokens) { 33 my $token = shift(@tokens); 34 if ($token =~ m/^\[([^]]*)\]$/) { 35 # new object 36 $obj = $1; 37 } else { 38 # new value 39 push(@{$objs{$obj}}, $token) unless ($obj eq ""); 40 } 41} 42 43# sort objects: longest first 44my @objs = sort { length($b) <=> length($a) } keys %objs; 45 46## SUBSTITUTE OBJECTS WITH THEIR VALUES FROM STDIN 47foreach (<STDIN>) { 48 foreach (expand($_, 0)) { 49 print; 50 } 51} 52 53## END 54 55sub expand { 56 my $line = shift; 57 my $level = shift; 58 my @retlines = $line; 59 my $obj; 60 my $val; 61 62 # coarse protection 63 if ($level > $MAXRECURSION) { 64 print STDERR "ERR: recursion exceeds $MAXRECURSION levels\n"; 65 return; 66 } 67 68 foreach $obj (@objs) { 69 if ($line =~ m/$obj/) { 70 @retlines = ""; 71 if ($level < $verbose) { 72 # add metarule as a comment 73 push(@retlines, "# ".$line); 74 } 75 foreach $val (@{$objs{$obj}}) { 76 my $newline = $line; 77 $newline =~ s/$obj/$val/; 78 push(@retlines, expand($newline, $level+1)); 79 } 80 last; 81 } 82 } 83 84 return @retlines; 85} 86 87__END__ 88 89=head1 NAME 90 91B<ipfmeta> - use objects in IP filter files 92 93=head1 SYNOPSIS 94 95B<ipfmeta> [F<options>] [F<objfile>] 96 97=head1 DESCRIPTION 98 99B<ipfmeta> is used to simplify the maintenance of your IP filter 100ruleset. It does this through the use of 'objects'. A matching 101object gets replaced by its values at runtime. This is similar to 102what a macro processor like m4 does. 103 104B<ipfmeta> is specifically geared towards IP filter. It is line 105oriented, if an object has multiple values, the line with the object 106is duplicated and substituted for each value. It is also recursive, 107an object may have another object as a value. 108 109Rules to be processed are read from stdin, output goes to stdout. 110 111The verbose option allows for the inclusion of the metarules in the 112output as comments. 113 114Definition of the objects and their values is done in a separate 115file, the filename defaults to F<ipf.objs>. An object is delimited 116by square brackets. A value is delimited by whitespace. Comments 117start with '#' and end with a newline. Empty lines and extraneous 118whitespace are allowed. A value belongs to the first object that 119precedes it. 120 121It is recommended that you use all caps or another distinguishing 122feature for object names. You can use B<ipfmeta> for NAT rules also, 123for instance to keep them in sync with filter rules. Combine 124B<ipfmeta> with a Makefile to save typing. 125 126=head1 OPTIONS 127 128=over 4 129 130=item B<-v> I<verboselevel> 131 132Include metarules in output as comments. Default is 1, the top level 133metarules. Higher levels cause expanded metarules to be included. 134Level 0 does not add comments at all. 135 136=back 137 138=head1 BUGS 139 140A value can not have whitespace in it. 141 142=head1 EXAMPLE 143 144(this does not look good, formatted) 145 146I<ipf.objs> 147 148[PRIVATE] 10.0.0.0/8 127.0.0.0/8 172.16.0.0/12 192.168.0.0/16 149 150[MULTICAST] 224.0.0.0/4 151 152[UNWANTED] PRIVATE MULTICAST 153 154[NOC] xxx.yy.zz.1/32 xxx.yy.zz.2/32 155 156[WEBSERVERS] 192.168.1.1/32 192.168.1.2/32 157 158[MGMT-PORTS] 22 23 159 160I<ipf.metarules> 161 162block in from UNWANTED to any 163 164pass in from NOC to WEBSERVERS port = MGMT-PORTS 165 166pass out all 167 168I<Run> 169 170ipfmeta ipf.objs <ipf.metarules >ipf.rules 171 172I<Output> 173 174# block in from UNWANTED to any 175 176block in from 10.0.0.0/8 to any 177 178block in from 127.0.0.0/8 to any 179 180block in from 172.16.0.0/12 to any 181 182block in from 192.168.0.0/16 to any 183 184block in from 224.0.0.0/4 to any 185 186# pass in from NOC to WEBSERVERS port = MGMT-PORTS 187 188pass in from xxx.yy.zz.1/32 to 192.168.1.1/32 port = 22 189 190pass in from xxx.yy.zz.1/32 to 192.168.1.1/32 port = 23 191 192pass in from xxx.yy.zz.1/32 to 192.168.1.2/32 port = 22 193 194pass in from xxx.yy.zz.1/32 to 192.168.1.2/32 port = 23 195 196pass in from xxx.yy.zz.2/32 to 192.168.1.1/32 port = 22 197 198pass in from xxx.yy.zz.2/32 to 192.168.1.1/32 port = 23 199 200pass in from xxx.yy.zz.2/32 to 192.168.1.2/32 port = 22 201 202pass in from xxx.yy.zz.2/32 to 192.168.1.2/32 port = 23 203 204pass out all 205 206=head1 AUTHOR 207 208Camiel Dobbelaar <cd@sentia.nl>. B<ipfmeta> is in the Public Domain. 209 210=cut 211