--- /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: