#!/usr/bin/perl -w use strict; use IPTables 'load'; # iptables patcher # Copyright (C) 2006 Daniel De Graaf # # Released under the GNU GPL (http://www.gnu.org/licenses/gpl.txt) # # $Id: ipt-patch 662 2006-06-01 04:01:16Z daniel $ my($old_f,$new_f,$opt) = ('iptables-save|','-',''); my($fn1,$fn2); $opt = shift if @ARGV && $ARGV[0] =~ /^-/; $old_f = shift if @ARGV > 1; $new_f = shift if @ARGV; if ($opt =~ /h/) { print "$0 [options] [[old] new]\nProvides a script to patch in a new iptables-save file\n"; exit 0; } sub out_wipe { my ($table,$t) = @_; print "# Wipe $table table\n"; for (keys %$t) { my $p = $t->{$_}[0]{_POLICY}; print "iptables -t $table -P $_ ACCEPT\n" unless $p eq 'ACCEPT' || $p eq '-'; } print "iptables -t $table -F\n"; print "iptables -t $table -X\n"; } sub out_new_ch { my ($table,$chain,$c) = @_; my $pol = shift @$c; $pol = $$pol{_POLICY}; if ($pol eq '-') { print "iptables -t $table -N $chain\n"; } else { print "iptables -t $table -P $chain $pol\n" unless $pol eq 'ACCEPT'; } print "iptables -t $table -A $chain $$_{_RULE}\n" for @$c; } sub diffout { my ($table,$chain,$o,$n) = @_; open F, '>', $fn1; print F "$$_{_RULE}\n" for @$o; close F; open F, '>', $fn2; print F "$$_{_RULE}\n" for @$n; close F; open D, "diff -d -U -1 $fn1 $fn2 |" or die; $_ = ; $_ = ; $_ = ; my $rct = 1; while () { /^(.)(.+)/ or next; if ($1 eq ' ') { $rct++; } elsif ($1 eq '-') { print "#$2\n"; print "iptables -t $table -D $chain $rct\n"; } elsif ($1 eq '+') { print "iptables -t $table -I $chain $rct $2\n"; $rct++; } else { warn "bad output line from diff: $_"; } } unlink $fn1,$fn2; } my ($old,$new); if ($opt =~ /c/) { open my $fh, $new_f or die; $old = load $fh; $new = load $fh; } else { open my $newfh, $new_f or die; $new = load $newfh; open my $oldfh, $old_f or die; $old = load $oldfh; } normalize $new; normalize $old; chomp($fn1 = `mktemp`) or die; chomp($fn2 = `mktemp`) or die; for my $tbl (keys %$new) { if (exists $$old{$tbl}) { for (keys %{$$old{$tbl}}) { next if exists $$new{$tbl}{$_}; print "iptables -t $tbl -F $_\niptables -t $tbl -X $_\n"; } for my $chn (keys %{$$new{$tbl}}) { if (exists $$old{$tbl}{$chn}) { my $o = $$old{$tbl}{$chn}; my $n = $$new{$tbl}{$chn}; my $policy_o = shift @$o; my $policy_n = shift @$n; print "iptables -t $tbl -P $chn $$policy_n{_POLICY}\n" unless $$policy_o{_POLICY} eq $$policy_n{_POLICY}; diffout $tbl, $chn, $o, $n; } else { out_new_ch $tbl, $chn, $$new{$tbl}{$chn}; } } } else { out_new_ch $tbl,$_, $$new{$tbl}{$_} for keys %{$$new{$tbl}}; } } exists $new->{$_} or out_wipe $_, $old->{$_} for keys %$old;