insertRules
changeset 0 26a429d60aae
child 3 5b59ba9c9113
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/insertRules	Sat Oct 11 20:18:44 2008 +0000
@@ -0,0 +1,159 @@
+#! /usr/bin/perl
+# $Id$
+# $URL$
+# © 2008 Heiko Schlittermann <hs@schlittermann.de>
+use constant USAGE => <<'#';
+{{ME}} [-n] [-v]
+#
+
+use strict;
+use warnings;
+use File::Basename;
+use AppConfig;
+
+use constant ME => basename $0;
+
+#use constant FI => { chain => "ipac~fi", parent => "FORWARD", iface => "--out" };
+#use constant FO => { chain => "ipac~fo", parent => "FORWARD", iface =>"--in" };
+#use constant I  => { chain => "ipac~i", parent => "OUTPUT", iface => "--in" };
+#use constant O  => { chain => "ipac~o", parent => "INPUT", iface => "--out" };
+
+my %TARGETS = (
+    "ipac~fi" => { chain => "ipac~fi", parent => "FORWARD", iface => "--in-interface" },
+    "ipac~fo" => { chain => "ipac~fo", parent => "FORWARD", iface => "--out-interface" },
+    "ipac~i" => { chain => "ipac~i", parent => "OUTPUT", iface => "--out-interface" },
+    "ipac~o" => { chain => "ipac~o", parent => "INPUT", iface => "--in-interface" },
+);
+
+use constant FILE => $ENV{IPAC_RULES} ? $ENV{IPAC_RULES} : "/etc/ipac-ng/rules.conf";
+
+use constant CONFIG => (
+    { CASE => 1 },
+    nothing => { ARGS => "!", DEFAULT => 0 },
+    verbose => { ARGS => "!", DEFAULT => 0 },
+);
+
+my $Cf = new AppConfig CONFIG or die;
+   $Cf->getopt or die;
+
+sub checkTarget($);
+sub insertTarget($);
+sub cleanTarget($);
+sub parseConfig($);
+sub expand($);
+
+MAIN: {
+    my @cmds; 
+
+    # Check, if our rules exist
+    foreach (keys %TARGETS) {
+	checkTarget($TARGETS{$_})
+	    or push @cmds, insertTarget($TARGETS{$_});
+
+	push @cmds, cleanTarget($TARGETS{$_});
+    }
+    
+    
+    my ($iptables, $rules) = parseConfig(FILE);
+    push @cmds, @$iptables;
+
+
+    foreach (@cmds) {
+	print "@$_\n" if $Cf->verbose or $Cf->nothing;
+	next if $Cf->nothing;
+	system @$_ and do {
+	    warn "FAILED: @$_\n" if not $Cf->verbose;
+	};
+    }
+
+    if (!$Cf->nothing) {
+	open(RUNFILE, $_ = ">/var/run/ipac.rules") or die "Can't open $_: $!\n";
+	print RUNFILE join "\n", @$rules;
+	close(RUNFILE);
+    }
+}
+
+{
+    my $dump;
+sub checkTarget($) {
+    my $target = shift;
+
+    if (!$dump) {
+	open(X, "iptables-save|") or die "Can't open iptables-save: $!\n";
+	$dump = join "", grep /^:/, <X>;
+	close(X);
+    }
+
+    return $dump =~ /^:$target->{chain}/m
+
+} }
+
+sub insertTarget($) {
+    my $target = shift;
+
+    return (
+	["iptables", "--new-chain" => $target->{chain}],
+	["iptables", 
+	    "--insert" => $target->{parent}, 
+	    "--jump" => $target->{chain}]
+	);
+}
+
+sub cleanTarget($) {
+    my $target = shift;
+    return ["iptables",
+	"--flush" => $target->{chain}];
+}
+
+sub parseConfig($) {
+    my (@iptables, @rules);
+    my $file = shift;
+    local(@ARGV) = ($file);
+
+    die ME.": Can't open $file: $!\n" if not -r $file;
+
+    @ARGV = ($file);
+
+    # Read the config file and create the iptables statements
+    while (<>) {
+	s/#.*//;
+	s/^\s*$//;
+	next unless $_;
+
+	chomp;
+
+
+	my (%src, %dst);
+	(my ($name, $target, $iface, $proto), $src{ip}, $dst{ip}) 
+		= split /\s*\|\s*/, $_;
+
+	# $src / $dst
+	foreach (\%src, \%dst) {
+	    @{$_}{qw/ip port/} = split /[:\s]/, $_->{ip};
+	}
+
+
+	my @cmd = ("iptables", 
+	    "--append" => $target, 
+	    $TARGETS{$target}->{iface} => $iface,
+	    "--src" => expand($src{ip}),
+	    "--dst" => expand($dst{ip}),
+	    "--proto" => expand($proto),
+	    $src{port} ? ("--sport" => $src{port}) : (),
+	    $dst{port} ? ("--dport" => $dst{port}) : (),
+	);
+
+	push @iptables, \@cmd;
+	push @rules, "$target|$name";
+    }
+
+    return \@iptables, \@rules;
+}
+
+sub expand($) {
+    local $_ = shift;
+    return ($_) if not /^!/;
+    return ("!", substr($_, 1));
+}
+
+# vim:sts=4 sw=4 aw ai sm: