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