Home | History | Annotate | Line # | Download | only in perl
ipfmeta.pl revision 1.1.1.1.2.2
      1 #!/usr/bin/perl -w
      2 #
      3 # Written by Camiel Dobbelaar <cd (at] sentia.nl>, Aug-2000
      4 # ipfmeta is in the Public Domain.
      5 #
      6 
      7 use strict;
      8 use Getopt::Std;
      9 
     10 ## PROCESS COMMANDLINE
     11 our($opt_v); $opt_v=1;
     12 getopts('v:') || die "usage: ipfmeta [-v verboselevel] [objfile]\n";
     13 my $verbose = $opt_v + 0;
     14 my $objfile = shift || "ipf.objs";
     15 my $MAXRECURSION = 10;
     16 
     17 ## READ OBJECTS
     18 open(FH, "$objfile") || die "cannot open $objfile: $!\n";
     19 my @tokens;
     20 while (<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 }
     28 close(FH) || die "cannot close $objfile: $!\n";
     29 # link objects with their values
     30 my $obj="";
     31 my %objs;
     32 while (@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
     44 my @objs = sort { length($b) <=> length($a) } keys %objs;
     45 
     46 ## SUBSTITUTE OBJECTS WITH THEIR VALUES FROM STDIN
     47 foreach (<STDIN>) {
     48 	foreach (expand($_, 0)) {
     49 		print;
     50 	}
     51 }
     52 
     53 ## END
     54 
     55 sub 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 
     91 B<ipfmeta> - use objects in IP filter files
     92 
     93 =head1 SYNOPSIS
     94 
     95 B<ipfmeta> [F<options>] [F<objfile>]
     96 
     97 =head1 DESCRIPTION
     98 
     99 B<ipfmeta> is used to simplify the maintenance of your IP filter
    100 ruleset. It does this through the use of 'objects'.  A matching
    101 object gets replaced by its values at runtime.  This is similar to
    102 what a macro processor like m4 does.
    103 
    104 B<ipfmeta> is specifically geared towards IP filter. It is line
    105 oriented, if an object has multiple values, the line with the object
    106 is duplicated and substituted for each value. It is also recursive,
    107 an object may have another object as a value.
    108 
    109 Rules to be processed are read from stdin, output goes to stdout.
    110 
    111 The verbose option allows for the inclusion of the metarules in the
    112 output as comments.
    113 
    114 Definition of the objects and their values is done in a separate
    115 file, the filename defaults to F<ipf.objs>.  An object is delimited
    116 by square brackets. A value is delimited by whitespace.  Comments
    117 start with '#' and end with a newline. Empty lines and extraneous
    118 whitespace are allowed.  A value belongs to the first object that
    119 precedes it.
    120 
    121 It is recommended that you use all caps or another distinguishing
    122 feature for object names. You can use B<ipfmeta> for NAT rules also,
    123 for instance to keep them in sync with filter rules.  Combine
    124 B<ipfmeta> with a Makefile to save typing.
    125 
    126 =head1 OPTIONS
    127 
    128 =over 4
    129 
    130 =item B<-v> I<verboselevel>
    131 
    132 Include metarules in output as comments. Default is 1, the top level
    133 metarules. Higher levels cause expanded metarules to be included.
    134 Level 0 does not add comments at all.
    135 
    136 =back
    137 
    138 =head1 BUGS
    139 
    140 A value can not have whitespace in it.
    141 
    142 =head1 EXAMPLE
    143 
    144 (this does not look good, formatted)
    145 
    146 I<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 
    160 I<ipf.metarules>
    161 
    162 block in from UNWANTED to any
    163 
    164 pass  in from NOC to WEBSERVERS port = MGMT-PORTS
    165 
    166 pass  out all
    167 
    168 I<Run>
    169 
    170 ipfmeta ipf.objs <ipf.metarules >ipf.rules
    171 
    172 I<Output>
    173 
    174 # block in from UNWANTED to any
    175 
    176 block in from 10.0.0.0/8 to any
    177 
    178 block in from 127.0.0.0/8 to any
    179 
    180 block in from 172.16.0.0/12 to any
    181 
    182 block in from 192.168.0.0/16 to any
    183 
    184 block in from 224.0.0.0/4 to any
    185 
    186 # pass  in from NOC to WEBSERVERS port = MGMT-PORTS
    187 
    188 pass  in from xxx.yy.zz.1/32 to 192.168.1.1/32 port = 22
    189 
    190 pass  in from xxx.yy.zz.1/32 to 192.168.1.1/32 port = 23
    191 
    192 pass  in from xxx.yy.zz.1/32 to 192.168.1.2/32 port = 22
    193 
    194 pass  in from xxx.yy.zz.1/32 to 192.168.1.2/32 port = 23
    195 
    196 pass  in from xxx.yy.zz.2/32 to 192.168.1.1/32 port = 22
    197 
    198 pass  in from xxx.yy.zz.2/32 to 192.168.1.1/32 port = 23
    199 
    200 pass  in from xxx.yy.zz.2/32 to 192.168.1.2/32 port = 22
    201 
    202 pass  in from xxx.yy.zz.2/32 to 192.168.1.2/32 port = 23
    203 
    204 pass  out all
    205 
    206 =head1 AUTHOR
    207 
    208 Camiel Dobbelaar <cd@sentia.nl>. B<ipfmeta> is in the Public Domain.
    209 
    210 =cut
    211