diff options
17 files changed, 308 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am index 70f85c2..63966e0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,7 +8,8 @@ curverdir = $(sysconfdir)/config-migrate/current sbin_SCRIPTS = scripts/vyatta-update-nat.pl sbin_SCRIPTS += scripts/vyatta-show-nat.pl -bin_sudo_users_SCRIPTS = scripts/vyatta-clear-nat +bin_sudo_users_SCRIPTS = scripts/vyatta-clear-nat +bin_sudo_users_SCRIPTS += scripts/vyatta-nat-translations.pl share_perl5_DATA = scripts/VyattaNatRule.pm curver_DATA = cfg-version/nat@2 diff --git a/debian/control b/debian/control index 31a487e..d82a8fe 100644 --- a/debian/control +++ b/debian/control @@ -11,6 +11,7 @@ Depends: vyatta-cfg, vyatta-bash | bash (>= 3.1), vyatta-op, vyatta-op-xml, - iptables + iptables, + conntrack Description: Vyatta configuration/operational commands for NAT Vyatta configuration and operational templates and scripts for NAT diff --git a/scripts/vyatta-nat-translations.pl b/scripts/vyatta-nat-translations.pl new file mode 100755 index 0000000..e5e9e64 --- /dev/null +++ b/scripts/vyatta-nat-translations.pl @@ -0,0 +1,254 @@ +#!/usr/bin/perl +# +# Module: vyatta-nat-translate.pl +# +# **** License **** +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# This code was originally developed by Vyatta, Inc. +# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc. +# All Rights Reserved. +# +# Author: Stig Thormodsrud +# Date: July 2008 +# Description: Script to display nat translations +# +# **** End License **** +# + +use Getopt::Long; +use XML::Simple; +use Data::Dumper; +use POSIX; + +use warnings; +use strict; + +my $dump = 0; +my ($xml_file, $verbose, $proto, $stats, $ipaddr, $pipe); +my $mode='both'; +my $verbose_format = "%-20s %-18s %-20s %-18s\n"; +my $format = "%-20s %-20s %-4s %-4s %-8s"; + + +sub add_xml_root { + my $xml = shift; + + $xml = '<data>' . $xml . '</data>'; + return $xml; +} + +sub read_xml_file { + my $file = shift; + + local($/, *FD); # slurp mode + open FD, "<", $file or die "Couldn't open $file\n"; + my $xml = <FD>; + close FD; + $xml = add_xml_root($xml); + return $xml; +} + +sub print_xml { + my $data = shift; + print Dumper($data); +} + +sub nat_print_xml { + my ($data, $mode) = @_; + + my $flow = 0; + + my %flowh; + while (1) { + my $meta = 0; + last if ! defined $data->{flow}[$flow]; + my $flow_ref = $data->{flow}[$flow]; + my $flow_type = $flow_ref->{type}; + my (%src, %dst, %sport, %dport, %proto); + my (%packets, %bytes); + my $timeout = undef; + my $uses = undef; + while (1) { + my $meta_ref = $flow_ref->{meta}[$meta]; + last if ! defined $meta_ref; + my $dir = $meta_ref->{direction}; + if ($dir eq 'original' or $dir eq 'reply') { + my $l3_ref = $meta_ref->{layer3}[0]; + my $l4_ref = $meta_ref->{layer4}[0]; + my $count_ref = $meta_ref->{counters}[0]; + if (defined $l3_ref) { + $src{$dir} = $l3_ref->{src}[0]; + $dst{$dir} = $l3_ref->{dst}[0]; + if (defined $l4_ref) { + $sport{$dir} = $l4_ref->{sport}[0]; + $dport{$dir} = $l4_ref->{dport}[0]; + $proto{$dir} = $l4_ref->{protoname}; + } + } + if (defined $stats and defined $count_ref) { + $packets{$dir} = $count_ref->{packets}[0]; + $bytes{$dir} = $count_ref->{bytes}[0]; + } + } elsif ($dir eq 'independent') { + $timeout = $meta_ref->{timeout}[0]; + $uses = $meta_ref->{'use'}[0]; + } + $meta++; + } + my ($proto, $in_src, $in_dst, $out_src, $out_dst); + $proto = $proto{original}; + $in_src = "$src{original}"; + $in_src .= ":$sport{original}" if defined $sport{original}; + $in_dst = "$dst{original}"; + $in_dst .= ":$dport{original}" if defined $dport{original}; + $out_src = "$dst{reply}"; + $out_src .= ":$dport{reply}" if defined $dport{reply}; + $out_dst = "$src{reply}"; + $out_dst .= ":$sport{reply}" if defined $sport{reply}; + if (defined $verbose) { + printf($verbose_format, $in_src, $in_dst, $out_src, $out_dst); + } + if (defined $mode) { + my ($from, $to); + if ($mode eq 'snat') { + $from = "$src{original}"; + $to = "$dst{reply}"; + if (defined $sport{original} and defined $dport{reply}) { + if ($sport{original} ne $dport{reply}) { + $from .= ":$sport{original}"; + $to .= ":$dport{reply}"; + } + } + } else { + $from = "$dst{original}"; + $to = "$src{reply}"; + if (defined $dport{original} and defined $sport{reply}) { + if ($dport{original} ne $sport{reply}) { + $from .= ":$dport{original}"; + $to .= ":$sport{reply}"; + } + } + } + if (defined $verbose) { + print " $proto: $mode: $from ==> $to"; + } else { + my $timeout2 = ""; + if (defined $timeout) { + $timeout2 = $timeout; + } + printf($format, $from, $to, $mode, $proto, $timeout2); + print " $flow_type" if defined $flow_type; + print "\n"; + } + } + if (defined $verbose) { + print " timeout: $timeout" if defined $timeout; + print " use: $uses " if defined $uses; + print " type: $flow_type" if defined $flow_type; + print "\n"; + } + if (defined $stats) { + foreach my $dir ('original', 'reply') { + if (defined $packets{$dir}) { + printf(" %-8s: packets %s, bytes %s\n", + $dir, $packets{$dir}, $bytes{$dir}); + } + } + } + $flow++; + } + return $flow; +} + + +# +# main +# +GetOptions("verbose" => \$verbose, + "proto=s" => \$proto, + "file=s" => \$xml_file, + "stats" => \$stats, + "mode=s" => \$mode, + "ipaddr=s" => \$ipaddr, + "pipe" => \$pipe, +); + +my $conntrack = '/usr/sbin/conntrack'; +if (! -f $conntrack) { + die "Package [conntrack] not installed"; +} + +my $xs = XML::Simple->new(ForceArray => 1, KeepRoot => 0); +my ($xml, $data); + +if (defined $xml_file) { + $xml = read_xml_file($xml_file); + $data = $xs->XMLin($xml); + if ($dump) { + print_xml($data); + exit; + } + if (defined $verbose) { + printf($verbose_format, 'Inside src', 'Inside dst', + 'Outside src', 'Outside dst'); + } else { + printf($format, 'Pre-NAT', 'Post-NAT', 'Type', 'Prot', 'Timeout'); + print "\n"; + } + nat_print_xml($data, 'snat'); + +} elsif (defined $pipe) { + # flush stdout after every write + $| = 1; + printf($format, 'Pre-NAT', 'Post-NAT', 'Type', 'Prot', 'Timeout'); + print " Type\n"; + while ($xml = <STDIN>) { + $xml = add_xml_root($xml); + $data = $xs->XMLin($xml); + nat_print_xml($data, $mode); + } +} else { + + if (defined $proto) { + $proto = "-p $proto" + } else { + $proto = ""; + } + if (defined $verbose) { + printf($verbose_format, 'Inside src', 'Inside dst', + 'Outside src', 'Outside dst'); + } else { + printf($format, 'Pre-NAT', 'Post-NAT', 'Type', 'Prot', 'Timeout'); + print "\n"; + } + if ($mode eq 'both' or $mode eq 'snat') { + my $ipopt = ""; + if (defined $ipaddr) { + $ipopt = "--orig-src $ipaddr"; + } + $xml = `sudo $conntrack -L -n $ipopt -o xml $proto`; + my $snat_xml = add_xml_root($xml); + $data = $xs->XMLin($snat_xml); + nat_print_xml($data, 'snat'); + } + if ($mode eq 'both' or $mode eq 'dnat') { + my $ipopt = ""; + if (defined $ipaddr) { + $ipopt = "--orig-dst $ipaddr"; + } + $xml = `sudo $conntrack -L -g $ipopt -o xml $proto`; + my $dnat_xml = add_xml_root($xml); + $data = $xs->XMLin($dnat_xml); + nat_print_xml($data, 'dnat'); + } +} + +# end of file diff --git a/templates-op/show/nat/translations/destination/address/node.def b/templates-op/show/nat/translations/destination/address/node.def new file mode 100644 index 0000000..f103fe4 --- /dev/null +++ b/templates-op/show/nat/translations/destination/address/node.def @@ -0,0 +1 @@ +help: Show active NAT destination translations for an IP address diff --git a/templates-op/show/nat/translations/destination/address/node.tag/node.def b/templates-op/show/nat/translations/destination/address/node.tag/node.def new file mode 100644 index 0000000..0ae5846 --- /dev/null +++ b/templates-op/show/nat/translations/destination/address/node.tag/node.def @@ -0,0 +1,11 @@ +help: Show active NAT destination translations for an IP address +allowed: echo -n '<x.x.x.x>' +run: if /opt/vyatta/sbin/vyatta-validate-type.pl -q ipv4 $6 + then + sudo ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl \ + --mode=dnat \ + --verbose \ + --ipaddr="$6" + else + echo "Invalid IP address" + fi diff --git a/templates-op/show/nat/translations/destination/detail/node.def b/templates-op/show/nat/translations/destination/detail/node.def new file mode 100644 index 0000000..90990f2 --- /dev/null +++ b/templates-op/show/nat/translations/destination/detail/node.def @@ -0,0 +1,3 @@ +help: Show active NAT destination translations detail +run: sudo ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl --mode=dnat \ + --verbose diff --git a/templates-op/show/nat/translations/destination/monitor/detail/node.def b/templates-op/show/nat/translations/destination/monitor/detail/node.def new file mode 100644 index 0000000..f1d196f --- /dev/null +++ b/templates-op/show/nat/translations/destination/monitor/detail/node.def @@ -0,0 +1,3 @@ +help: Show active NAT destination translations events detail +run: echo Type control-C to quit + sudo /usr/sbin/conntrack -E -g -o xml | ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl --mode=dnat --pipe --verbose | ${VYATTA_PAGER:-cat} diff --git a/templates-op/show/nat/translations/destination/monitor/node.def b/templates-op/show/nat/translations/destination/monitor/node.def new file mode 100644 index 0000000..99cf715 --- /dev/null +++ b/templates-op/show/nat/translations/destination/monitor/node.def @@ -0,0 +1,3 @@ +help: Show active NAT destination translations events +run: echo Type control-C to quit + sudo /usr/sbin/conntrack -E -g -o xml | ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl --mode=dnat --pipe | ${VYATTA_PAGER:-cat} diff --git a/templates-op/show/nat/translations/destination/node.def b/templates-op/show/nat/translations/destination/node.def new file mode 100644 index 0000000..347b034 --- /dev/null +++ b/templates-op/show/nat/translations/destination/node.def @@ -0,0 +1,2 @@ +help: Show active NAT destination translations +run: sudo ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl --mode=dnat diff --git a/templates-op/show/nat/translations/detail/node.def b/templates-op/show/nat/translations/detail/node.def new file mode 100644 index 0000000..0635e6d --- /dev/null +++ b/templates-op/show/nat/translations/detail/node.def @@ -0,0 +1,2 @@ +help: Show active NAT translations detail +run: sudo ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl --verbose diff --git a/templates-op/show/nat/translations/node.def b/templates-op/show/nat/translations/node.def new file mode 100644 index 0000000..f71c365 --- /dev/null +++ b/templates-op/show/nat/translations/node.def @@ -0,0 +1,2 @@ +help: Show active NAT translations +run: sudo ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl diff --git a/templates-op/show/nat/translations/source/address/node.def b/templates-op/show/nat/translations/source/address/node.def new file mode 100644 index 0000000..42bfbba --- /dev/null +++ b/templates-op/show/nat/translations/source/address/node.def @@ -0,0 +1 @@ +help: Show active NAT source translations for a IP address diff --git a/templates-op/show/nat/translations/source/address/node.tag/node.def b/templates-op/show/nat/translations/source/address/node.tag/node.def new file mode 100644 index 0000000..0271dd1 --- /dev/null +++ b/templates-op/show/nat/translations/source/address/node.tag/node.def @@ -0,0 +1,11 @@ +help: Show active NAT source translations for an IP address +allowed: echo -n '<x.x.x.x>' +run: if /opt/vyatta/sbin/vyatta-validate-type.pl -q ipv4 $6 + then + sudo ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl \ + --mode=snat \ + --verbose \ + --ipaddr="$6" + else + echo "Invalid IP address" + fi diff --git a/templates-op/show/nat/translations/source/detail/node.def b/templates-op/show/nat/translations/source/detail/node.def new file mode 100644 index 0000000..5f8af5b --- /dev/null +++ b/templates-op/show/nat/translations/source/detail/node.def @@ -0,0 +1,3 @@ +help: Show active NAT source translations detail +run: sudo ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl --mode=snat \ + --verbose diff --git a/templates-op/show/nat/translations/source/monitor/detail/node.def b/templates-op/show/nat/translations/source/monitor/detail/node.def new file mode 100644 index 0000000..cadd4bf --- /dev/null +++ b/templates-op/show/nat/translations/source/monitor/detail/node.def @@ -0,0 +1,3 @@ +help: Show active NAT source translations events +run: echo Type control-C to quit + sudo /usr/sbin/conntrack -E -n -o xml | ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl --mode=snat --pipe --verbose | ${VYATTA_PAGER:-cat}
\ No newline at end of file diff --git a/templates-op/show/nat/translations/source/monitor/node.def b/templates-op/show/nat/translations/source/monitor/node.def new file mode 100644 index 0000000..b1fced2 --- /dev/null +++ b/templates-op/show/nat/translations/source/monitor/node.def @@ -0,0 +1,3 @@ +help: Show active NAT source translations events +run: echo Type control-C to quit + sudo /usr/sbin/conntrack -E -n -o xml | ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl --mode=snat --pipe | ${VYATTA_PAGER:-cat} diff --git a/templates-op/show/nat/translations/source/node.def b/templates-op/show/nat/translations/source/node.def new file mode 100644 index 0000000..c14c955 --- /dev/null +++ b/templates-op/show/nat/translations/source/node.def @@ -0,0 +1,2 @@ +help: Show active NAT source translations +run: sudo ${vyatta_bindir}/sudo-users/vyatta-nat-translations.pl --mode=snat |