#!/usr/bin/perl use lib "/opt/vyatta/share/perl5/"; use Vyatta::Config; use Vyatta::IpTables::Rule; use Vyatta::IpTables::AddressFilter; exit 1 if ($#ARGV < 1); my $chain_name = $ARGV[0]; my $xsl_file = $ARGV[1]; my $rule_num = $ARGV[2]; # rule number to match (optional) if (! -e $xsl_file) { print "Invalid XSL file \"$xsl_file\"\n"; exit 1; } if (defined($rule_num) && (!($rule_num =~ /^\d+$/) || ($rule_num > 1025))) { print "Invalid rule number \"$rule_num\"\n"; exit 1; } sub numerically { $a <=> $b; } ### all interfaces firewall nodes #/ethernet/node.tag/pppoe/node.tag/firewall//name/node.def #/ethernet/node.tag/vif/node.tag/firewall//name/node.def #/ethernet/node.tag/firewall//name/node.def #/adsl/node.tag/pvc/node.tag/pppoa/node.tag/firewall//name/node.def #/adsl/node.tag/pvc/node.tag/pppoe/node.tag/firewall//name/node.def #/adsl/node.tag/pvc/node.tag/classical-ipoa/firewall//name/node.def #/tunnel/node.tag/firewall//name/node.def #/serial/node.tag/cisco-hdlc/vif/node.tag/firewall//name/node.def #/serial/node.tag/frame-relay/vif/node.tag/firewall//name/node.def #/serial/node.tag/ppp/vif/node.tag/firewall//name/node.def sub show_interfaces { my $chain = shift; my $cmd = "find /opt/vyatta/config/active/ " . "|grep -e '/firewall/[^/]\\+/name/node.val'" . "| xargs grep -l '^$chain\$'"; my $ifd; return if (!open($ifd, "$cmd |")); my @ints = <$ifd>; # e.g., #/opt/vyatta/config/active/interfaces/ethernet/eth1/firewall/in/name/node.val my $pfx = '/opt/vyatta/config/active/interfaces'; my $sfx = '/name/node.val'; my @int_strs = (); foreach (@ints) { my ($intf, $vif, $dir) = (undef, undef, undef); if (/^$pfx\/[^\/]+\/([^\/]+)(\/.*)?\/firewall\/([^\/]+)$sfx$/) { ($intf, $dir) = ($1, $3); $dir =~ y/a-z/A-Z/; } else { next; } if (/\/vif\/([^\/]+)\/firewall\//) { $vif = $1; push @int_strs, "($intf.$vif,$dir)"; } else { push @int_strs, "($intf,$dir)"; } } if (scalar(@int_strs) > 0) { print "\nActive on " . (join ' ', @int_strs) . "\n"; } else { print "\nInactive: Not applied to any interfaces.\n"; } } # mapping from config node to iptables/ip6tables table my %table_hash = ( 'name' => 'filter', 'ipv6-name' => 'filter', 'modify' => 'mangle', 'ipv6-modify' => 'mangle' ); # mapping from config node to iptables command. my %cmd_hash = ( 'name' => 'iptables', 'ipv6-name' => 'ip6tables', 'modify' => 'iptables', 'ipv6-modify' => 'ip6tables'); # mapping from config node to printable string describing it. my %description_hash = ( 'name' => 'IPv4', 'ipv6-name' => 'IPv6', 'modify' => 'IPv4 Modify', 'ipv6-modify' => 'IPv6 Modify'); sub show_chain($$$) { my ($chain, $fh, $tree) = @_; my $table = $table_hash{$tree}; my $iptables_cmd = $cmd_hash{$tree}; open my $iptables, "-|" or exec "sudo", "/sbin/$iptables_cmd", "-t", $table, "-L", $chain, "-vn" or exit 1; my @stats = (); while (<$iptables>) { if (!/^\s*(\d+[KMG]?)\s+(\d+[KMG]?)\s/) { next; } push @stats, ($1, $2); } close $iptables; print $fh "\n"; my $config = new Vyatta::Config; $config->setLevel("firewall $tree $chain rule"); my @rules = sort numerically $config->listOrigNodes(); foreach (@rules) { # just take the stats from the 1st iptables rule and remove unneeded stats # (if this rule corresponds to multiple iptables rules). note that # depending on how our rule is translated into multiple iptables rules, # this may actually need to be the sum of all corresponding iptables stats # instead of just taking the first pair. my $pkts = shift @stats; my $bytes = shift @stats; my $rule = new Vyatta::IpTables::Rule; $rule->setupOrig("firewall $tree $chain rule $_"); my $ipt_rules = $rule->get_num_ipt_rules(); splice(@stats, 0, (($ipt_rules - 1) * 2)); if (defined($rule_num) && $rule_num != $_) { next; } next if $rule->is_disabled(); print $fh " \n"; print $fh " $_\n"; print $fh " $pkts\n"; print $fh " $bytes\n"; $rule->outputXml($fh); print $fh " \n"; } if (!defined($rule_num)) { # dummy rule print $fh " \n"; print $fh " 1025\n"; my $pkts = shift @stats; my $bytes = shift @stats; print $fh " $pkts\n"; print $fh " $bytes\n"; my $rule = new Vyatta::IpTables::Rule; $rule->setupDummy(); $rule->outputXml($fh); print $fh " \n"; } print $fh "\n"; } my $tree; my $config = new Vyatta::Config; my @chains; if ($chain_name eq "-all") { # Print all rule sets in all four trees foreach $tree (keys %table_hash) { my $description = $description_hash{$tree}; $config->setLevel("firewall $tree"); @chains = $config->listOrigNodes(); foreach (@chains) { print "$description Firewall \"$_\":\n"; show_interfaces($_); open(RENDER, "| /opt/vyatta/sbin/render_xml $xsl_file") or exit 1; show_chain($_, *RENDER{IO}, $tree); close RENDER; print "-" x 80 . "\n"; } } exit 0 } else { # Look through all four trees trying to find the rule set name passed in foreach $tree (keys %table_hash) { $config->setLevel("firewall $tree"); @chains = $config->listOrigNodes(); if (scalar(grep(/^$chain_name$/, @chains)) > 0) { # Found it! my $description = $description_hash{$tree}; print "$description Firewall \"$chain_name\":\n"; show_interfaces($chain_name); open(RENDER, "| /opt/vyatta/sbin/render_xml $xsl_file") or exit 1; show_chain($chain_name, *RENDER{IO}, $tree); close RENDER; exit 0 } } # Didn't find matching rule print "Invalid firewall name \"$chain_name\"\n"; exit 1; } # Local Variables: # mode: perl # indent-tabs-mode: nil # perl-indent-level: 2 # End: