insertRules
changeset 0 26a429d60aae
child 3 5b59ba9c9113
equal deleted inserted replaced
-1:000000000000 0:26a429d60aae
       
     1 #! /usr/bin/perl
       
     2 # $Id$
       
     3 # $URL$
       
     4 # © 2008 Heiko Schlittermann <hs@schlittermann.de>
       
     5 use constant USAGE => <<'#';
       
     6 {{ME}} [-n] [-v]
       
     7 #
       
     8 
       
     9 use strict;
       
    10 use warnings;
       
    11 use File::Basename;
       
    12 use AppConfig;
       
    13 
       
    14 use constant ME => basename $0;
       
    15 
       
    16 #use constant FI => { chain => "ipac~fi", parent => "FORWARD", iface => "--out" };
       
    17 #use constant FO => { chain => "ipac~fo", parent => "FORWARD", iface =>"--in" };
       
    18 #use constant I  => { chain => "ipac~i", parent => "OUTPUT", iface => "--in" };
       
    19 #use constant O  => { chain => "ipac~o", parent => "INPUT", iface => "--out" };
       
    20 
       
    21 my %TARGETS = (
       
    22     "ipac~fi" => { chain => "ipac~fi", parent => "FORWARD", iface => "--in-interface" },
       
    23     "ipac~fo" => { chain => "ipac~fo", parent => "FORWARD", iface => "--out-interface" },
       
    24     "ipac~i" => { chain => "ipac~i", parent => "OUTPUT", iface => "--out-interface" },
       
    25     "ipac~o" => { chain => "ipac~o", parent => "INPUT", iface => "--in-interface" },
       
    26 );
       
    27 
       
    28 use constant FILE => $ENV{IPAC_RULES} ? $ENV{IPAC_RULES} : "/etc/ipac-ng/rules.conf";
       
    29 
       
    30 use constant CONFIG => (
       
    31     { CASE => 1 },
       
    32     nothing => { ARGS => "!", DEFAULT => 0 },
       
    33     verbose => { ARGS => "!", DEFAULT => 0 },
       
    34 );
       
    35 
       
    36 my $Cf = new AppConfig CONFIG or die;
       
    37    $Cf->getopt or die;
       
    38 
       
    39 sub checkTarget($);
       
    40 sub insertTarget($);
       
    41 sub cleanTarget($);
       
    42 sub parseConfig($);
       
    43 sub expand($);
       
    44 
       
    45 MAIN: {
       
    46     my @cmds; 
       
    47 
       
    48     # Check, if our rules exist
       
    49     foreach (keys %TARGETS) {
       
    50 	checkTarget($TARGETS{$_})
       
    51 	    or push @cmds, insertTarget($TARGETS{$_});
       
    52 
       
    53 	push @cmds, cleanTarget($TARGETS{$_});
       
    54     }
       
    55     
       
    56     
       
    57     my ($iptables, $rules) = parseConfig(FILE);
       
    58     push @cmds, @$iptables;
       
    59 
       
    60 
       
    61     foreach (@cmds) {
       
    62 	print "@$_\n" if $Cf->verbose or $Cf->nothing;
       
    63 	next if $Cf->nothing;
       
    64 	system @$_ and do {
       
    65 	    warn "FAILED: @$_\n" if not $Cf->verbose;
       
    66 	};
       
    67     }
       
    68 
       
    69     if (!$Cf->nothing) {
       
    70 	open(RUNFILE, $_ = ">/var/run/ipac.rules") or die "Can't open $_: $!\n";
       
    71 	print RUNFILE join "\n", @$rules;
       
    72 	close(RUNFILE);
       
    73     }
       
    74 }
       
    75 
       
    76 {
       
    77     my $dump;
       
    78 sub checkTarget($) {
       
    79     my $target = shift;
       
    80 
       
    81     if (!$dump) {
       
    82 	open(X, "iptables-save|") or die "Can't open iptables-save: $!\n";
       
    83 	$dump = join "", grep /^:/, <X>;
       
    84 	close(X);
       
    85     }
       
    86 
       
    87     return $dump =~ /^:$target->{chain}/m
       
    88 
       
    89 } }
       
    90 
       
    91 sub insertTarget($) {
       
    92     my $target = shift;
       
    93 
       
    94     return (
       
    95 	["iptables", "--new-chain" => $target->{chain}],
       
    96 	["iptables", 
       
    97 	    "--insert" => $target->{parent}, 
       
    98 	    "--jump" => $target->{chain}]
       
    99 	);
       
   100 }
       
   101 
       
   102 sub cleanTarget($) {
       
   103     my $target = shift;
       
   104     return ["iptables",
       
   105 	"--flush" => $target->{chain}];
       
   106 }
       
   107 
       
   108 sub parseConfig($) {
       
   109     my (@iptables, @rules);
       
   110     my $file = shift;
       
   111     local(@ARGV) = ($file);
       
   112 
       
   113     die ME.": Can't open $file: $!\n" if not -r $file;
       
   114 
       
   115     @ARGV = ($file);
       
   116 
       
   117     # Read the config file and create the iptables statements
       
   118     while (<>) {
       
   119 	s/#.*//;
       
   120 	s/^\s*$//;
       
   121 	next unless $_;
       
   122 
       
   123 	chomp;
       
   124 
       
   125 
       
   126 	my (%src, %dst);
       
   127 	(my ($name, $target, $iface, $proto), $src{ip}, $dst{ip}) 
       
   128 		= split /\s*\|\s*/, $_;
       
   129 
       
   130 	# $src / $dst
       
   131 	foreach (\%src, \%dst) {
       
   132 	    @{$_}{qw/ip port/} = split /[:\s]/, $_->{ip};
       
   133 	}
       
   134 
       
   135 
       
   136 	my @cmd = ("iptables", 
       
   137 	    "--append" => $target, 
       
   138 	    $TARGETS{$target}->{iface} => $iface,
       
   139 	    "--src" => expand($src{ip}),
       
   140 	    "--dst" => expand($dst{ip}),
       
   141 	    "--proto" => expand($proto),
       
   142 	    $src{port} ? ("--sport" => $src{port}) : (),
       
   143 	    $dst{port} ? ("--dport" => $dst{port}) : (),
       
   144 	);
       
   145 
       
   146 	push @iptables, \@cmd;
       
   147 	push @rules, "$target|$name";
       
   148     }
       
   149 
       
   150     return \@iptables, \@rules;
       
   151 }
       
   152 
       
   153 sub expand($) {
       
   154     local $_ = shift;
       
   155     return ($_) if not /^!/;
       
   156     return ("!", substr($_, 1));
       
   157 }
       
   158 
       
   159 # vim:sts=4 sw=4 aw ai sm: