#!/usr/bin/perl use strict; # iptables viewer # Copyright (C) 2005-2006 Daniel De Graaf # # Released under the GNU GPL (http://www.gnu.org/licenses/gpl.txt) # # $Id: ipt-view 662 2006-06-01 04:01:16Z daniel $ open I, shift || ($> ? '-' : 'iptables-save|'); #well, get the real table if we're root! my %equiv = ( match => 'm', protocol => 'p', src => 's', source => 's', dst => 'd', destination => 'd', jump => 'j', 'in-interface' => 'i', 'out-interface' => 'o', dports => 'dport', #don't care about the difference... ); my %ar; while () { print if s/^\*//; print " $1: $2\n" if /^:(\S+)\s+([^-]\S*)\s+\[/; # print "\n" if /^COMMIT/; next unless s/^\s*-A\s+(\S+)\s+//; #drop comments too my $ch = $1; s| -[sd] ::/0 | |g; #remove ip6tables-save extras s/ ! -/ -!/g; #and move the !'s to the items they negate my @v = split /\s+/; my %l; while (@v) { $_ = shift @v; s/^-+// or die "problem.... $_"; $l{$_} = ''; $l{$_} .= ' '.shift @v until $v[0] =~ /^-/ or !@v; $l{$_} =~ s/^ //; } # # %l is a hash of option -> value (or '' if there is no value) # Everything else is a check for a specific option/value pair # # $c is "category" - source/destination address/interface or '*' for none # $p is "port" - either a numeric port or a description of the target; again '*' = none # $ptag is appended to the port, used for TCP/UDP/ICMP tag # $e is the expression that goes on the right # # The end result is '$ar{$c}{$p.$ptag} = $e', except for some formatting modifications # for (keys %equiv) { next unless exists $l{$_}; die "help! There's a rule with -$_ and -$equiv{$_} in it!" if exists $l{$equiv{$_}}; $l{$equiv{$_}} = $l{$_}; delete $l{$_}; } my ($c,$e,$p,$ptag) = ('*',"\e[37m$ch\e[32m/", $l{dport} || $l{'icmp-type'} || '*',''); if (exists $l{p} and $l{p} ne 'tcp' and $l{p} ne 'udp' and $l{p} ne 'icmp') { $c = $l{p}; delete $l{p}; } elsif (exists $l{s}) { $c = $l{s}; $c .= '-'.$l{d} if exists $l{d}; delete $l{s}; delete $l{d}; } elsif (exists $l{d}) { $c = '>'.$l{d}; delete $l{d}; } elsif (exists $l{i}) { $c = '>'.$l{i}; delete $l{i}; } elsif (exists $l{o}) { $c = '<'.$l{o}; delete $l{o}; } elsif (exists $l{'physdev-in'}) { $c = '>phys-'.$l{'physdev-in'}; delete $l{'physdev-in'}; } elsif (exists $l{'physdev-out'}) { $c = ' 0 ? sprintf '%6d',$_ : $_).$ptag} .= $e.' ' for split /,/, $p; } close I; my @s = split /\e\[37m/, $ar{'*'}{'*'}; print " \e[1m$_\e[m\n" for @s; delete $ar{'*'}{'*'}; for my $e (values %ar) { for my $p (keys %$e) { $_ = $p; s/ T$/ ~/ and exists $$e{$_} and $$e{$p} eq $$e{$_} and do { delete $$e{$_}; s/ ~/ %/; $$e{$_} = $$e{$p}; delete $$e{$p}; }; } } for my $c (sort keys %ar) { printf "\e[1;33m%-21s \%s\e[m\n", "$c:", $ar{$c}{'*'} || '' unless $c eq '*'; delete $ar{$c}{'*'}; for my $p (sort keys %{$ar{$c}}) { my ($q,$l) = ($p,'%-20s'); $q =~ s/ I/ \e[31mI/ and $l = '%-25s'; printf "\e[1;32m $l \%s\e[m\n",$q,$ar{$c}{$p}; } }