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