summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore18
-rw-r--r--AUTHORS1
-rw-r--r--COPYING26
-rw-r--r--Makefile.am21
-rw-r--r--NEWS1
-rw-r--r--README1
-rw-r--r--configure.ac29
-rw-r--r--debian/README6
-rwxr-xr-xdebian/autogen.sh37
-rw-r--r--debian/changelog5
-rw-r--r--debian/compat1
-rw-r--r--debian/control14
-rw-r--r--debian/copyright34
-rw-r--r--debian/docs2
-rw-r--r--debian/linda1
-rw-r--r--debian/lintian2
-rwxr-xr-xdebian/rules102
-rw-r--r--scripts/VyattaNatRule.pm532
-rwxr-xr-xscripts/vyatta-show-nat.pl64
-rwxr-xr-xscripts/vyatta-update-nat.pl164
-rw-r--r--templates-cfg/service/nat/node.def2
-rw-r--r--templates-cfg/service/nat/rule/node.def4
-rw-r--r--templates-cfg/service/nat/rule/node.tag/destination/address/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/destination/network/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/destination/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/destination/port-name/node.def10
-rw-r--r--templates-cfg/service/nat/rule/node.tag/destination/port-number/node.def4
-rw-r--r--templates-cfg/service/nat/rule/node.tag/destination/port-range/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/destination/port-range/start/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/destination/port-range/stop/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inbound-interface/node.def5
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inside-address/address/node.def2
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inside-address/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inside-address/port-number/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inside-address/port-range/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inside-address/port-range/start/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inside-address/port-range/stop/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inside-address/range/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inside-address/range/start/node.def2
-rw-r--r--templates-cfg/service/nat/rule/node.tag/inside-address/range/stop/node.def2
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outbound-interface/node.def5
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outside-address/address/node.def2
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outside-address/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outside-address/port-number/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outside-address/port-range/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outside-address/port-range/start/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outside-address/port-range/stop/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outside-address/range/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outside-address/range/start/node.def2
-rw-r--r--templates-cfg/service/nat/rule/node.tag/outside-address/range/stop/node.def2
-rw-r--r--templates-cfg/service/nat/rule/node.tag/protocols/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/source/address/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/source/network/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/source/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/source/port-name/node.def10
-rw-r--r--templates-cfg/service/nat/rule/node.tag/source/port-number/node.def4
-rw-r--r--templates-cfg/service/nat/rule/node.tag/source/port-range/node.def1
-rw-r--r--templates-cfg/service/nat/rule/node.tag/source/port-range/start/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/source/port-range/stop/node.def3
-rw-r--r--templates-cfg/service/nat/rule/node.tag/type/node.def4
-rw-r--r--templates-op/clear/nat/counters/node.def2
-rw-r--r--templates-op/clear/nat/node.def1
-rw-r--r--templates-op/clear/nat/translations/node.def2
-rw-r--r--templates-op/show/nat/node.def1
-rw-r--r--templates-op/show/nat/rules/node.def3
-rw-r--r--templates-op/show/nat/statistics/node.def3
-rw-r--r--xsl/show_nat_rules.xsl309
-rw-r--r--xsl/show_nat_statistics.xsl107
68 files changed, 1604 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..139f1b1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+*~
+.*.swp
+/aclocal.m4
+/autom4te.cache
+/build-stamp
+/ChangeLog
+/config
+/config.log
+/config.guess
+/config.status
+/config.sub
+/configure
+/debian/files
+/debian/vyatta-nat
+/INSTALL
+/Makefile.in
+/Makefile
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..ee635b2
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+eng@vyatta.com
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..2134a08
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,26 @@
+/*
+ * Package: vyatt-nat
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) "YEAR" Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: An-Cheng Huang
+ * Date: 2007
+ * Description: Vyatta configuration/operational commands for NAT
+ *
+ * **** End License ****
+ */
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..850d7c9
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,21 @@
+cfgdir = $(datadir)/vyatta-cfg/templates
+opdir = $(datadir)/vyatta-op/templates
+xsldir = $(datadir)/xsl
+share_perl5dir = $(datadir)/perl5
+bin_sudo_usersdir = $(bindir)/sudo-users
+
+sbin_SCRIPTS = scripts/vyatta-update-nat.pl
+bin_sudo_users_SCRIPTS = scripts/vyatta-show-nat.pl
+
+share_perl5_DATA = scripts/VyattaNatRule.pm
+
+cpiop = find . ! -regex '\(.*~\|.*\.bak\|.*\.swp\|.*\#.*\#\)' -print0 | \
+ cpio -0pd
+
+install-exec-hook:
+ mkdir -p $(DESTDIR)$(cfgdir)
+ cd templates-cfg; $(cpiop) $(DESTDIR)$(cfgdir)
+ mkdir -p $(DESTDIR)$(opdir)
+ cd templates-op; $(cpiop) $(DESTDIR)$(opdir)
+ mkdir -p $(DESTDIR)$(xsldir)
+ cd xsl; $(cpiop) $(DESTDIR)$(xsldir)
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..78fdaa6
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+see http://www.vyatta.com/news/
diff --git a/README b/README
new file mode 100644
index 0000000..27ef63d
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+This package has the Vyatta configuration and operational templates and scripts for NAT.
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..15fd8e9
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,29 @@
+# Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.59)
+
+m4_define([VERSION_ID], [m4_esyscmd([
+ if test -f .version ; then
+ head -n 1 .version | tr -d \\n
+ else
+ echo -n 2.4
+ fi])])
+AC_INIT([vyatta-nat], VERSION_ID, [vyatta-support@vyatta.com])
+
+test -n "$VYATTA_VERSION" || VYATTA_VERSION=$PACKAGE_VERSION
+
+AC_CONFIG_AUX_DIR([config])
+AM_INIT_AUTOMAKE([gnu no-dist-gzip dist-bzip2 subdir-objects])
+AC_PREFIX_DEFAULT([/opt/vyatta])
+
+AC_ARG_ENABLE([nostrip],
+ AC_HELP_STRING([--enable-nostrip],
+ [include -nostrip option during packaging]),
+ [NOSTRIP=-nostrip], [NOSTRIP=])
+
+AC_CONFIG_FILES(
+ [Makefile])
+
+AC_SUBST(NOSTRIP)
+
+AC_OUTPUT
+
diff --git a/debian/README b/debian/README
new file mode 100644
index 0000000..30b3107
--- /dev/null
+++ b/debian/README
@@ -0,0 +1,6 @@
+The Debian Package vyatta-nat
+----------------------------
+
+This package has the Vyatta configuration and operational templates and scripts for NAT.
+
+ -- An-Cheng Huang <ancheng@vyatta.com> Tue, 18 Dec 2007 11:59:49 -0700
diff --git a/debian/autogen.sh b/debian/autogen.sh
new file mode 100755
index 0000000..ff125d1
--- /dev/null
+++ b/debian/autogen.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+
+if [ -d .git ] ; then
+# generate GNU/Debian format ChangeLog from git log
+
+ rm -f ChangeLog
+
+ if which git2cl >/dev/null ; then
+ git-log --pretty --numstat --summary | git2cl >> ChangeLog
+ else
+ git-log --pretty=short >> ChangeLog
+ fi
+
+# append repository reference
+
+ url=` git repo-config --get remote.origin.url`
+ test "x$url" = "x" && url=`pwd`
+
+ branch=`git-branch --no-color | sed '/^\* /!d; s/^\* //'`
+ test "x$branch" = "x" && branch=master
+
+ sha=`git log --pretty=oneline --no-color -n 1 | cut -c-8`
+ test "x$sha" = "x" && sha=00000000
+
+ echo "$url#$branch-$sha" >> ChangeLog
+
+fi
+
+rm -rf config
+rm -f aclocal.m4 config.guess config.statusconfig.sub configure INSTALL
+
+autoreconf --force --install
+
+rm -f config.sub config.guess
+ln -s /usr/share/misc/config.sub .
+ln -s /usr/share/misc/config.guess .
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..b558752
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+vyatta-nat (0.1) unstable; urgency=low
+
+ * Initial Release.
+
+ -- An-Cheng Huang <ancheng@vyatta.com> Tue, 18 Dec 2007 11:59:49 -0700
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..f1359be
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,14 @@
+Source: vyatta-nat
+Section: contrib/net
+Priority: extra
+Maintainer: An-Cheng Huang <ancheng@vyatta.com>
+Build-Depends: debhelper (>= 5), autotools-dev
+Standards-Version: 3.7.2
+
+Package: vyatta-nat
+Architecture: all
+Depends: vyatta-cfg,
+ vyatta-op,
+ iptables
+Description: Vyatta configuration/operational commands for NAT
+ Vyatta configuration and operational templates and scripts for NAT
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..f7600be
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,34 @@
+This package was debianized by An-Cheng Huang <ancheng@vyatta.com> on
+Tue, 18 Dec 2007 11:59:49 -0700.
+
+It's original content from the GIT repository <http://vyatt.com/git/vyatta-nat>
+
+Upstream Author:
+
+ <eng@vyatta.com>
+
+Copyright:
+
+ Copyright (C) 2007 Vyatta, Inc.
+ All Rights Reserved.
+
+License:
+
+ The contents of this package are subject to the Vyatta Public License
+ Version 1.0 ("License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.vyatta.com/vpl
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ This code was originally developed by Vyatta, Inc.
+ Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
+
+The Debian packaging is (C) 2007, Tom Grennan <tgrennan@vyatta.com> and
+is licensed under the GPL, see above.
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..50bd824
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,2 @@
+NEWS
+README
diff --git a/debian/linda b/debian/linda
new file mode 100644
index 0000000..0381d9d
--- /dev/null
+++ b/debian/linda
@@ -0,0 +1 @@
+Tag: file-in-opt
diff --git a/debian/lintian b/debian/lintian
new file mode 100644
index 0000000..3bcedc4
--- /dev/null
+++ b/debian/lintian
@@ -0,0 +1,2 @@
+vyatta-nat: file-in-unusual-dir
+vyatta-nat: dir-or-file-in-opt
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..e98fe01
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,102 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+PACKAGE=vyatta-nat
+PKGDIR=$(CURDIR)/debian/$(PACKAGE)
+
+CFLAGS = -Wall -g
+
+configure = ./configure
+configure += --host=$(DEB_HOST_GNU_TYPE)
+configure += --build=$(DEB_BUILD_GNU_TYPE)
+configure += --prefix=/opt/vyatta
+configure += --mandir=\$${prefix}/share/man
+configure += --infodir=\$${prefix}/share/info
+configure += CFLAGS="$(CFLAGS)"
+configure += LDFLAGS="-Wl,-z,defs"
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -O0
+else
+ CFLAGS += -O2
+endif
+
+configure: configure.ac Makefile.am
+ chmod +x debian/autogen.sh
+ debian/autogen.sh
+
+config.status: configure
+ dh_testdir
+ rm -f config.cache
+ $(configure)
+
+build: build-stamp
+
+build-stamp: config.status
+ dh_testdir
+ $(MAKE)
+ touch $@
+
+clean: clean-patched
+
+# Clean everything up, including everything auto-generated
+# at build time that needs not to be kept around in the Debian diff
+clean-patched:
+ dh_testdir
+ dh_testroot
+ if test -f Makefile ; then $(MAKE) clean distclean ; fi
+ rm -f build-stamp
+ rm -f config.status config.sub config.guess config.log
+ rm -f aclocal.m4 configure Makefile.in Makefile INSTALL
+ rm -f etc/default/vyatta
+ rm -rf config
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ $(MAKE) DESTDIR=$(PKGDIR) install
+
+ install -D --mode=0644 debian/lintian $(PKGDIR)/usr/share/lintian/overrides/$(PACKAGE)
+ install -D --mode=0644 debian/linda $(PKGDIR)/usr/share/linda/overrides/$(PACKAGE)
+
+# Build architecture-independent files here.
+binary-indep: build install
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs ChangeLog
+ dh_installdocs
+ dh_install
+ dh_installdebconf
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+# Build architecture-dependent files here.
+binary-arch: build install
+# This is an architecture independent package
+# so; we have nothing to do by default.
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/scripts/VyattaNatRule.pm b/scripts/VyattaNatRule.pm
new file mode 100644
index 0000000..5bcfac6
--- /dev/null
+++ b/scripts/VyattaNatRule.pm
@@ -0,0 +1,532 @@
+package VyattaNatRule;
+
+use strict;
+use lib "/opt/vyatta/share/perl5/";
+use VyattaConfig;
+
+my %fields = (
+ _type => undef,
+ _orig_type => undef,
+ _inbound_if => undef,
+ _outbound_if => undef,
+ _proto => undef,
+ _source => {
+ _addr => undef,
+ _net => undef,
+ _port_num => undef,
+ _port_name => undef,
+ _port_range => {
+ _start => undef,
+ _stop => undef,
+ },
+ },
+ _destination => {
+ _addr => undef,
+ _net => undef,
+ _port_num => undef,
+ _port_name => undef,
+ _port_range => {
+ _start => undef,
+ _stop => undef,
+ },
+ },
+ _inside_addr => {
+ _addr => undef,
+ _range => {
+ _start => undef,
+ _stop => undef,
+ },
+ _port_num => undef,
+ _port_range => {
+ _start => undef,
+ _stop => undef,
+ },
+ },
+ _outside_addr => {
+ _addr => undef,
+ _range => {
+ _start => undef,
+ _stop => undef,
+ },
+ _port_num => undef,
+ _port_range => {
+ _start => undef,
+ _stop => undef,
+ },
+ },
+);
+
+sub new {
+ my $that = shift;
+ my $class = ref ($that) || $that;
+ my $self = {
+ %fields,
+ };
+
+ bless $self, $class;
+ return $self;
+}
+
+sub setup {
+ my ( $self, $level ) = @_;
+ my $config = new VyattaConfig;
+
+ $config->setLevel("$level");
+
+ $self->{_type} = $config->returnValue("type");
+ $self->{_orig_type} = $config->returnOrigValue("type");
+ $self->{_inbound_if} = $config->returnValue("inbound-interface");
+ $self->{_outbound_if} = $config->returnValue("outbound-interface");
+ $self->{_proto} = $config->returnValue("protocols");
+
+ $self->{_source}->{_addr} = $config->returnValue("source address");
+ $self->{_source}->{_net} = $config->returnValue("source network");
+ my @tmp = $config->returnValues("source port-number");
+ $self->{_source}->{_port_num} = [ @tmp ];
+ @tmp = $config->returnValues("source port-name");
+ $self->{_source}->{_port_name} = [ @tmp ];
+ $self->{_source}->{_port_range}->{_start}
+ = $config->returnValue("source port-range start");
+ $self->{_source}->{_port_range}->{_stop}
+ = $config->returnValue("source port-range stop");
+
+ $self->{_destination}->{_addr} = $config->returnValue("destination address");
+ $self->{_destination}->{_net} = $config->returnValue("destination network");
+ @tmp = $config->returnValues("destination port-number");
+ $self->{_destination}->{_port_num} = [ @tmp ];
+ @tmp = $config->returnValues("destination port-name");
+ $self->{_destination}->{_port_name} = [ @tmp ];
+ $self->{_destination}->{_port_range}->{_start}
+ = $config->returnValue("destination port-range start");
+ $self->{_destination}->{_port_range}->{_stop}
+ = $config->returnValue("destination port-range stop");
+
+ $self->{_inside_addr}->{_addr}
+ = $config->returnValue("inside-address address");
+ $self->{_inside_addr}->{_range}->{_start}
+ = $config->returnValue("inside-address range start");
+ $self->{_inside_addr}->{_range}->{_stop}
+ = $config->returnValue("inside-address range stop");
+ $self->{_inside_addr}->{_port_num}
+ = $config->returnValue("inside-address port-number");
+ $self->{_inside_addr}->{_port_range}->{_start}
+ = $config->returnValue("inside-address port-range start");
+ $self->{_inside_addr}->{_port_range}->{_stop}
+ = $config->returnValue("inside-address port-range stop");
+
+ $self->{_outside_addr}->{_addr}
+ = $config->returnValue("outside-address address");
+ $self->{_outside_addr}->{_range}->{_start}
+ = $config->returnValue("outside-address range start");
+ $self->{_outside_addr}->{_range}->{_stop}
+ = $config->returnValue("outside-address range stop");
+ $self->{_outside_addr}->{_port_num}
+ = $config->returnValue("outside-address port-number");
+ $self->{_outside_addr}->{_port_range}->{_start}
+ = $config->returnValue("outside-address port-range start");
+ $self->{_outside_addr}->{_port_range}->{_stop}
+ = $config->returnValue("outside-address port-range stop");
+
+ return 0;
+}
+
+sub setupOrig {
+ my ( $self, $level ) = @_;
+ my $config = new VyattaConfig;
+
+ $config->setLevel("$level");
+
+ $self->{_type} = $config->returnOrigValue("type");
+ $self->{_orig_type} = $config->returnOrigValue("type");
+ $self->{_inbound_if} = $config->returnOrigValue("inbound-interface");
+ $self->{_outbound_if} = $config->returnOrigValue("outbound-interface");
+ $self->{_proto} = $config->returnOrigValue("protocols");
+
+ $self->{_source}->{_addr} = $config->returnOrigValue("source address");
+ $self->{_source}->{_net} = $config->returnOrigValue("source network");
+ my @tmp = $config->returnOrigValues("source port-number");
+ $self->{_source}->{_port_num} = [ @tmp ];
+ @tmp = $config->returnOrigValues("source port-name");
+ $self->{_source}->{_port_name} = [ @tmp ];
+ $self->{_source}->{_port_range}->{_start}
+ = $config->returnOrigValue("source port-range start");
+ $self->{_source}->{_port_range}->{_stop}
+ = $config->returnOrigValue("source port-range stop");
+
+ $self->{_destination}->{_addr}
+ = $config->returnOrigValue("destination address");
+ $self->{_destination}->{_net}
+ = $config->returnOrigValue("destination network");
+ @tmp = $config->returnOrigValues("destination port-number");
+ $self->{_destination}->{_port_num} = [ @tmp ];
+ @tmp = $config->returnOrigValues("destination port-name");
+ $self->{_destination}->{_port_name} = [ @tmp ];
+ $self->{_destination}->{_port_range}->{_start}
+ = $config->returnOrigValue("destination port-range start");
+ $self->{_destination}->{_port_range}->{_stop}
+ = $config->returnOrigValue("destination port-range stop");
+
+ $self->{_inside_addr}->{_addr}
+ = $config->returnOrigValue("inside-address address");
+ $self->{_inside_addr}->{_range}->{_start}
+ = $config->returnOrigValue("inside-address range start");
+ $self->{_inside_addr}->{_range}->{_stop}
+ = $config->returnOrigValue("inside-address range stop");
+ $self->{_inside_addr}->{_port_num}
+ = $config->returnOrigValue("inside-address port-number");
+ $self->{_inside_addr}->{_port_range}->{_start}
+ = $config->returnOrigValue("inside-address port-range start");
+ $self->{_inside_addr}->{_port_range}->{_stop}
+ = $config->returnOrigValue("inside-address port-range stop");
+
+ $self->{_outside_addr}->{_addr}
+ = $config->returnOrigValue("outside-address address");
+ $self->{_outside_addr}->{_range}->{_start}
+ = $config->returnOrigValue("outside-address range start");
+ $self->{_outside_addr}->{_range}->{_stop}
+ = $config->returnOrigValue("outside-address range stop");
+ $self->{_outside_addr}->{_port_num}
+ = $config->returnOrigValue("outside-address port-number");
+ $self->{_outside_addr}->{_port_range}->{_start}
+ = $config->returnOrigValue("outside-address port-range start");
+ $self->{_outside_addr}->{_port_range}->{_stop}
+ = $config->returnOrigValue("outside-address port-range stop");
+
+ return 0;
+}
+
+sub handle_ports {
+ my $num_ref = shift;
+ my $name_ref = shift;
+ my $pstart = shift;
+ my $pstop = shift;
+ my $can_use_port = shift;
+ my $prefix = shift;
+ my $proto = shift;
+
+ my $rule_str = "";
+ my ($ports, $prange) = (0, 0);
+ my @pnums = @{$num_ref};
+ my @pnames = @{$name_ref};
+ $ports = ($#pnums + 1) + ($#pnames + 1);
+
+ if (defined($pstart) && defined($pstop)) {
+ if ($pstop < $pstart) {
+ return (undef, "invalid port range $pstart-$pstop");
+ }
+ $ports += ($pstop - $pstart + 1);
+ $prange = ($pstop - $pstart - 1);
+ }
+ if (($ports > 0) && (!$can_use_port)) {
+ return (undef, "ports can only be specified when protocol is \"tcp\" "
+ . "or \"udp\" (currently \"$proto\")");
+ }
+ if (($ports - $prange) > 15) {
+ return (undef, "source/destination port specification only supports "
+ . "up to 15 ports (port range counts as 2)");
+ }
+ if ($ports > 1) {
+ $rule_str .= " -m multiport --${prefix}ports ";
+ my $first = 1;
+ if ($#pnums >= 0) {
+ my $pstr = join(',', @pnums);
+ $rule_str .= "$pstr";
+ $first = 0;
+ }
+ if ($#pnames >= 0) {
+ if ($first == 0) {
+ $rule_str .= ",";
+ }
+ my $pstr = join(',', @pnames);
+ $rule_str .= "$pstr";
+ $first = 0;
+ }
+ if (defined($pstart) && defined($pstop)) {
+ if ($first == 0) {
+ $rule_str .= ",";
+ }
+ if ($pstart == $pstop) {
+ $rule_str .= "$pstart";
+ } else {
+ $rule_str .= "$pstart:$pstop";
+ }
+ $first = 0;
+ }
+ } elsif ($ports > 0) {
+ $rule_str .= " --${prefix}port ";
+ if ($#pnums >= 0) {
+ $rule_str .= "$pnums[0]";
+ } elsif ($#pnames >= 0) {
+ $rule_str .= "$pnames[0]";
+ } else {
+ # no number, no name, range of 1
+ $rule_str .= "$pstart";
+ }
+ }
+
+ return ($rule_str, undef);
+}
+
+# returns (rule, error)
+sub rule_str {
+ my ($self) = @_;
+ my $rule_str = "";
+ my $can_use_port = 1;
+
+ if (!defined($self->{_proto}) ||
+ (($self->{_proto} ne "tcp") && ($self->{_proto} ne "6")
+ && ($self->{_proto} ne "udp") && ($self->{_proto} ne "17"))) {
+ $can_use_port = 0;
+ }
+ if (($self->{_type} eq "source") || ($self->{_type} eq "masquerade")) {
+ if ($self->{_type} eq "masquerade") {
+ $rule_str .= "-j MASQUERADE";
+ } else {
+ $rule_str .= "-j SNAT";
+ }
+ if (defined($self->{_outbound_if})) {
+ $rule_str .= " -o $self->{_outbound_if}";
+ } else {
+ # "masquerade" requires outbound_if.
+ # also make this a requirement for "source" to prevent users from
+ # inadvertently NATing loopback traffic.
+ return (undef, "outbound-interface not specified");
+ }
+
+ if (defined($self->{_proto})) {
+ my $str = $self->{_proto};
+ $str =~ s/^\!(.*)$/! $1/;
+ $rule_str .= " -p $str";
+ }
+
+ #my $to_src = " --to-source ";
+ my $to_src = "";
+ if (defined($self->{_outside_addr}->{_addr})) {
+ $to_src .= "$self->{_outside_addr}->{_addr}";
+ } elsif (defined($self->{_outside_addr}->{_range}->{_start})
+ && defined($self->{_outside_addr}->{_range}->{_stop})) {
+ $to_src .= "$self->{_outside_addr}->{_range}->{_start}";
+ $to_src .= "-$self->{_outside_addr}->{_range}->{_stop}";
+ }
+
+ if (($to_src ne "") && ($self->{_type} eq "masquerade")) {
+ return (undef, "cannot specify outside IP address with \"masquerade\"");
+ }
+
+ if (defined($self->{_outside_addr}->{_port_num})) {
+ if (!$can_use_port) {
+ return (undef, "ports can only be specified when protocol is \"tcp\" "
+ . "or \"udp\" (currently \"$self->{_proto}\")");
+ }
+ if ($self->{_type} ne "masquerade") {
+ $to_src .= ":";
+ }
+ $to_src .= "$self->{_outside_addr}->{_port_num}";
+ } elsif (defined($self->{_outside_addr}->{_port_range}->{_start})
+ && defined($self->{_outside_addr}->{_port_range}->{_stop})) {
+ if (!$can_use_port) {
+ return (undef, "ports can only be specified when protocol is \"tcp\" "
+ . "or \"udp\" (currently \"$self->{_proto}\")");
+ }
+ if ($self->{_type} ne "masquerade") {
+ $to_src .= ":";
+ }
+ $to_src .= "$self->{_outside_addr}->{_port_range}->{_start}";
+ $to_src .= "-$self->{_outside_addr}->{_port_range}->{_stop}";
+ }
+
+ if ($to_src ne "") {
+ if ($self->{_type} eq "masquerade") {
+ $rule_str .= " --to-ports $to_src";
+ } else {
+ $rule_str .= " --to-source $to_src";
+ }
+ } elsif ($self->{_type} ne "masquerade") {
+ return (undef, "outside-address not specified");
+ }
+ } else {
+ # type is destination
+ $rule_str .= "-j DNAT";
+
+ if (defined($self->{_inbound_if})) {
+ $rule_str .= " -i $self->{_inbound_if}";
+ } else {
+ # make this a requirement to prevent users from
+ # inadvertently NATing loopback traffic.
+ return (undef, "inbound-interface not specified");
+ }
+
+ if (defined($self->{_proto})) {
+ $rule_str .= " -p $self->{_proto}";
+ }
+
+ my $to_dst = " --to-destination ";
+ if (defined($self->{_inside_addr}->{_addr})) {
+ $to_dst .= "$self->{_inside_addr}->{_addr}";
+ } elsif (defined($self->{_inside_addr}->{_range}->{_start})
+ && defined($self->{_inside_addr}->{_range}->{_stop})) {
+ $to_dst .= "$self->{_inside_addr}->{_range}->{_start}";
+ $to_dst .= "-$self->{_inside_addr}->{_range}->{_stop}";
+ }
+ if (defined($self->{_inside_addr}->{_port_num})) {
+ if (!$can_use_port) {
+ return (undef, "ports can only be specified when protocol is \"tcp\" "
+ . "or \"udp\" (currently \"$self->{_proto}\")");
+ }
+ $to_dst .= ":$self->{_inside_addr}->{_port_num}";
+ } elsif (defined($self->{_inside_addr}->{_port_range}->{_start})
+ && defined($self->{_inside_addr}->{_port_range}->{_stop})) {
+ if (!$can_use_port) {
+ return (undef, "ports can only be specified when protocol is \"tcp\" "
+ . "or \"udp\" (currently \"$self->{_proto}\")");
+ }
+ $to_dst .= ":$self->{_inside_addr}->{_port_range}->{_start}";
+ $to_dst .= "-$self->{_inside_addr}->{_port_range}->{_stop}";
+ }
+ if ($to_dst ne " --to-destination ") {
+ $rule_str .= $to_dst;
+ } else {
+ return (undef, "inside-address not specified");
+ }
+ }
+
+ # source port(s)
+ my ($port_str, $port_err)
+ = handle_ports($self->{_source}->{_port_num},
+ $self->{_source}->{_port_name},
+ $self->{_source}->{_port_range}->{_start},
+ $self->{_source}->{_port_range}->{_stop},
+ $can_use_port, "s", $self->{_proto});
+ return (undef, $port_err) if (!defined($port_str));
+ $rule_str .= $port_str;
+
+ # destination port(s)
+ ($port_str, $port_err)
+ = handle_ports($self->{_destination}->{_port_num},
+ $self->{_destination}->{_port_name},
+ $self->{_destination}->{_port_range}->{_start},
+ $self->{_destination}->{_port_range}->{_stop},
+ $can_use_port, "d", $self->{_proto});
+ return (undef, $port_err) if (!defined($port_str));
+ $rule_str .= $port_str;
+
+ if (defined($self->{_source}->{_addr})) {
+ my $str = $self->{_source}->{_addr};
+ $str =~ s/^\!(.*)$/! $1/;
+ $rule_str .= " -s $str";
+ } elsif (defined($self->{_source}->{_net})) {
+ my $str = $self->{_source}->{_net};
+ $str =~ s/^\!(.*)$/! $1/;
+ $rule_str .= " -s $str";
+ }
+
+ if (defined($self->{_destination}->{_addr})) {
+ my $str = $self->{_destination}->{_addr};
+ $str =~ s/^\!(.*)$/! $1/;
+ $rule_str .= " -d $str";
+ } elsif (defined($self->{_destination}->{_net})) {
+ my $str = $self->{_destination}->{_net};
+ $str =~ s/^\!(.*)$/! $1/;
+ $rule_str .= " -d $str";
+ }
+
+ return ($rule_str, "");
+}
+
+sub orig_type {
+ my ($self) = @_;
+ return "source" if ($self->{_orig_type} eq "masquerade");
+ return $self->{_orig_type};
+}
+
+sub new_type {
+ my ($self) = @_;
+ return "source" if ($self->{_type} eq "masquerade");
+ return $self->{_type};
+}
+
+sub print_str {
+ my ($self) = @_;
+ my $str =
+ "type[$self->{_type}] " .
+ "in_if[$self->{_inbound_if}] out_if[$self->{_outbound_if}] " .
+ "proto[$self->{_proto}] saddr[$self->{_source}->{_addr}] ".
+ "snet[$self->{_source}->{_net}] spnum[@{$self->{_source}->{_port_num}}] ".
+ "spname[@{$self->{_source}->{_port_name}}] " .
+ "sprange[$self->{_source}->{_port_range}->{_start}" .
+ "-$self->{_source}->{_port_range}->{_stop}] " .
+ "daddr[$self->{_destination}->{_addr}] " .
+ "dnet[$self->{_destination}->{_net}] " .
+ "dpnum[@{$self->{_destination}->{_port_num}}] " .
+ "dpname[@{$self->{_destination}->{_port_name}}] " .
+ "dprange[$self->{_destination}->{_port_range}->{_start}-" .
+ "$self->{_destination}->{_port_range}->{_stop}] " .
+ "inaddr[$self->{_inside_addr}->{_addr}] " .
+ "inrange[$self->{_inside_addr}->{_range}->{_start}-" .
+ "$self->{_inside_addr}->{_range}->{_stop}] " .
+ "inp[$self->{_inside_addr}->{_port_num}] " .
+ "inprange[$self->{_inside_addr}->{_port_range}->{_start}-" .
+ "$self->{_inside_addr}->{_port_range}->{_stop}] " .
+ "outaddr[$self->{_outside_addr}->{_addr}] " .
+ "outrange[$self->{_outside_addr}->{_range}->{_start}-" .
+ "$self->{_outside_addr}->{_range}->{_stop}]";
+ "outp[$self->{_outside_addr}->{_port_num}] " .
+ "outprange[$self->{_outside_addr}->{_port_range}->{_start}-" .
+ "$self->{_outside_addr}->{_port_range}->{_stop}] " .
+
+ return $str;
+}
+
+sub outputXmlElem {
+ my ($name, $value, $fh) = @_;
+ print $fh " <$name>$value</$name>\n";
+}
+
+sub outputXml {
+ my ($self, $fh) = @_;
+ outputXmlElem("type", $self->{_type}, $fh);
+ outputXmlElem("in_interface", $self->{_inbound_if}, $fh);
+ outputXmlElem("out_interface", $self->{_outbound_if}, $fh);
+ outputXmlElem("src_addr", $self->{_source}->{_addr}, $fh);
+ outputXmlElem("src_network", $self->{_source}->{_net}, $fh);
+ outputXmlElem("src_ports", join(',', @{$self->{_source}->{_port_num}}), $fh);
+ outputXmlElem("src_ports_apps", join(',', @{$self->{_source}->{_port_name}}),
+ $fh);
+ outputXmlElem("src_port_start", $self->{_source}->{_port_range}->{_start},
+ $fh);
+ outputXmlElem("src_port_stop", $self->{_source}->{_port_range}->{_stop},
+ $fh);
+ outputXmlElem("dst_addr", $self->{_destination}->{_addr}, $fh);
+ outputXmlElem("dst_network", $self->{_destination}->{_net}, $fh);
+ outputXmlElem("dst_ports", join(',', @{$self->{_destination}->{_port_num}}),
+ $fh);
+ outputXmlElem("dst_ports_apps",
+ join(',', @{$self->{_destination}->{_port_name}}), $fh);
+ outputXmlElem("dst_port_start",
+ $self->{_destination}->{_port_range}->{_start}, $fh);
+ outputXmlElem("dst_port_stop",
+ $self->{_destination}->{_port_range}->{_stop}, $fh);
+ outputXmlElem("in_addr", $self->{_inside_addr}->{_addr}, $fh);
+ outputXmlElem("in_addr_start", $self->{_inside_addr}->{_range}->{_start},
+ $fh);
+ outputXmlElem("in_addr_stop", $self->{_inside_addr}->{_range}->{_stop},
+ $fh);
+ outputXmlElem("in_port", $self->{_inside_addr}->{_port_num}, $fh);
+ outputXmlElem("in_port_start",
+ $self->{_inside_addr}->{_port_range}->{_start}, $fh);
+ outputXmlElem("in_port_stop",
+ $self->{_inside_addr}->{_port_range}->{_stop}, $fh);
+ outputXmlElem("out_addr", $self->{_outside_addr}->{_addr}, $fh);
+ outputXmlElem("out_addr_start", $self->{_outside_addr}->{_range}->{_start},
+ $fh);
+ outputXmlElem("out_addr_stop", $self->{_outside_addr}->{_range}->{_stop},
+ $fh);
+ outputXmlElem("out_port", $self->{_outside_addr}->{_port_num}, $fh);
+ outputXmlElem("out_port_start",
+ $self->{_outside_addr}->{_port_range}->{_start}, $fh);
+ outputXmlElem("out_port_stop",
+ $self->{_outside_addr}->{_port_range}->{_stop}, $fh);
+
+ # no proto? ($self->{_proto})
+}
+
diff --git a/scripts/vyatta-show-nat.pl b/scripts/vyatta-show-nat.pl
new file mode 100755
index 0000000..5ae67b8
--- /dev/null
+++ b/scripts/vyatta-show-nat.pl
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+
+use strict;
+use lib "/opt/vyatta/share/perl5/";
+use VyattaConfig;
+use VyattaNatRule;
+
+sub numerically { $a <=> $b; }
+
+exit 1 if ($#ARGV != 0);
+my $xsl_file = $ARGV[0];
+
+my %stats = (
+ source => [ ],
+ destination => [ ],
+ );
+open(STATS, "iptables -t nat -L -vn |") or exit 1;
+my $skey = "";
+while (<STATS>) {
+ if (m/^Chain PREROUTING/) {
+ $skey = "destination";
+ } elsif (m/^Chain POSTROUTING/) {
+ $skey = "source";
+ } elsif (m/^Chain /) {
+ $skey = "";
+ }
+
+ if ($skey ne "" && (m/SNAT/ || m/DNAT/ || m/MASQUERADE/)) {
+ m/^\s*(\d+)\s+(\d+)\s/;
+ push @{$stats{$skey}}, ($1, $2);
+ }
+}
+close STATS;
+
+open(RENDER, "| /opt/vyatta/libexec/xorp/render_xml $xsl_file") or exit 1;
+
+# begin
+print RENDER "<opcommand name='natrules'><format type='row'>\n";
+
+my $config = new VyattaConfig;
+$config->setLevel("service nat rule");
+my @rules_pre = $config->listOrigNodes();
+my $rule;
+my @rules = sort numerically @rules_pre;
+for $rule (@rules) {
+ my $nrule = new VyattaNatRule;
+ $nrule->setupOrig("service nat rule $rule");
+ my $ntype = $nrule->orig_type();
+ print RENDER " <row>\n";
+ print RENDER " <rule_num>$rule</rule_num>\n";
+ my $pkts = shift @{$stats{$ntype}};
+ my $bytes = shift @{$stats{$ntype}};
+ print RENDER " <pkts>$pkts</pkts>\n";
+ print RENDER " <bytes>$bytes</bytes>\n";
+ $nrule->outputXml(*RENDER{IO});
+ print RENDER " </row>\n";
+}
+
+# end
+print RENDER "</format></opcommand>\n";
+
+close RENDER;
+exit 0;
+
diff --git a/scripts/vyatta-update-nat.pl b/scripts/vyatta-update-nat.pl
new file mode 100755
index 0000000..19255ed
--- /dev/null
+++ b/scripts/vyatta-update-nat.pl
@@ -0,0 +1,164 @@
+#!/usr/bin/perl
+
+use strict;
+use lib "/opt/vyatta/share/perl5/";
+use VyattaConfig;
+use VyattaNatRule;
+
+sub numerically { $a <=> $b; }
+
+sub raw_cleanup {
+ # remove the conntrack setup.
+ my @lines
+ = `iptables -t raw -L PREROUTING -vn --line-numbers | egrep ^[0-9]`;
+ foreach (@lines) {
+ my ($num, $ignore, $ignore, $chain, $ignore, $ignore, $in, $out,
+ $ignore, $ignore) = split /\s+/;
+ if ($chain eq "NAT_CONNTRACK") {
+ system("iptables -t raw -D PREROUTING $num");
+ system("iptables -t raw -D OUTPUT $num");
+ system("iptables -t raw -F NAT_CONNTRACK");
+ system("iptables -t raw -X NAT_CONNTRACK");
+ last;
+ }
+ }
+}
+
+# for "clear nat translations"
+if ($ARGV[0] eq "clearnattranslations") {
+ system("iptables-save -t nat | iptables-restore");
+ exit 0;
+}
+
+my $config = new VyattaConfig;
+$config->setLevel("service nat rule");
+my %rules = $config->listNodeStatus();
+my $rule;
+open(OUT, ">>/dev/null") or exit 1;
+my %ipt_rulenum = (
+ source => 1,
+ destination => 1,
+ );
+my %chain_name = (
+ source => "POSTROUTING",
+ destination => "PREROUTING",
+ );
+print OUT "========= nat list =========\n";
+my @rule_keys = sort numerically keys %rules;
+if ($#rule_keys < 0) {
+ # no rules (everything is deleted) => flush the nat table & return
+ print OUT "iptables -t nat -F\n";
+ if (system("iptables -t nat -F")) {
+ exit 1;
+ }
+
+ raw_cleanup();
+
+ exit 0;
+}
+
+## it seems that "multiport" does not like port range (p1:p2) if nobody has
+## touched the nat table yet after reboot!?
+system("iptables -t nat -L -n >& /dev/null");
+
+# we have some nat rule(s). make sure conntrack is enabled.
+system("iptables -t raw -L NAT_CONNTRACK -n >& /dev/null");
+if ($? >> 8) {
+ # NAT_CONNTRACK chain does not exist yet. set up conntrack.
+ system("iptables -t raw -N NAT_CONNTRACK");
+ # this enables conntrack for all packets. potentially we can add more rules
+ # to the NAT_CONNTRACK chain for finer-grained control over which packets
+ # are tracked.
+ system("iptables -t raw -A NAT_CONNTRACK -j ACCEPT");
+ system("iptables -t raw -I PREROUTING 1 -j NAT_CONNTRACK");
+ system("iptables -t raw -I OUTPUT 1 -j NAT_CONNTRACK");
+}
+
+my $all_deleted = 1;
+for $rule (@rule_keys) {
+ print OUT "$rule: $rules{$rule}\n";
+ my $nrule = new VyattaNatRule;
+ $nrule->setup("service nat rule $rule");
+ my $otype = $nrule->orig_type();
+ my $ntype = $nrule->new_type();
+ if ((defined($otype) && $otype ne "source" && $otype ne "destination")
+ || (defined($ntype) && $ntype ne "source" && $ntype ne "destination")) {
+ exit 2;
+ }
+
+ if ($rules{$rule} ne "deleted") {
+ $all_deleted = 0;
+ }
+
+ my $cmd;
+ if ($rules{$rule} eq "static") {
+ # $otype and $ntype should be the same
+ if (!defined($ntype)) {
+ exit 3;
+ }
+ $ipt_rulenum{$ntype} += 1;
+ next;
+ } elsif ($rules{$rule} eq "deleted") {
+ # $ntype should be empty
+ if (!defined($otype)) {
+ exit 4;
+ }
+ $cmd = "iptables -t nat -D $chain_name{$otype} $ipt_rulenum{$otype}";
+ print OUT "$cmd\n";
+ if (system($cmd)) {
+ exit 1;
+ }
+ next;
+ }
+
+ my ($str, $err) = $nrule->rule_str();
+ if (!defined($str)) {
+ # rule check failed => return error
+ print OUT "ERROR: $err\n";
+ print STDERR "ERROR: $err\n";
+ exit 5;
+ }
+
+ if ($rules{$rule} eq "added") {
+ # $otype should be empty
+ if (!defined($ntype)) {
+ exit 6;
+ }
+ $cmd = "iptables -t nat -I $chain_name{$ntype} $ipt_rulenum{$ntype} " .
+ "$str";
+ print OUT "$cmd\n";
+ if (system($cmd)) {
+ exit 1;
+ }
+ $ipt_rulenum{$ntype} += 1;
+ } elsif ($rules{$rule} eq "changed") {
+ # $otype and $ntype may not be the same
+ if (!defined($otype) || !defined($ntype)) {
+ exit 7;
+ }
+ $cmd = "iptables -t nat -I $chain_name{$ntype} $ipt_rulenum{$ntype} " .
+ "$str";
+ print OUT "$cmd\n";
+ if (system($cmd)) {
+ exit 1;
+ }
+ my $idx = $ipt_rulenum{$otype};
+ if ($otype eq $ntype) {
+ $idx += 1;
+ }
+ $cmd = "iptables -t nat -D $chain_name{$otype} $idx";
+ print OUT "$cmd\n";
+ if (system($cmd)) {
+ exit 1;
+ }
+ $ipt_rulenum{$ntype} += 1;
+ }
+}
+
+if ($all_deleted) {
+ raw_cleanup();
+}
+
+close OUT;
+exit 0;
+
diff --git a/templates-cfg/service/nat/node.def b/templates-cfg/service/nat/node.def
new file mode 100644
index 0000000..a06299a
--- /dev/null
+++ b/templates-cfg/service/nat/node.def
@@ -0,0 +1,2 @@
+help: "NAT configuration"
+end: "sudo /opt/vyatta/sbin/vyatta-update-nat.pl"
diff --git a/templates-cfg/service/nat/rule/node.def b/templates-cfg/service/nat/rule/node.def
new file mode 100644
index 0000000..8de4c74
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.def
@@ -0,0 +1,4 @@
+tag:
+type: u32
+help: "Rule number for NAT"
+syntax: ($(@) > 0 && $(@) < 1025) ; "rule number must be between 1 and 1024"
diff --git a/templates-cfg/service/nat/rule/node.tag/destination/address/node.def b/templates-cfg/service/nat/rule/node.tag/destination/address/node.def
new file mode 100644
index 0000000..21aa728
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/destination/address/node.def
@@ -0,0 +1,3 @@
+type: txt
+help: "Destination address"
+syntax: exec "/opt/vyatta/sbin/vyatta-validate-type.pl ipv4_negate '$(@)'" ; "invalid destination address \"$(@)\""
diff --git a/templates-cfg/service/nat/rule/node.tag/destination/network/node.def b/templates-cfg/service/nat/rule/node.tag/destination/network/node.def
new file mode 100644
index 0000000..90c0571
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/destination/network/node.def
@@ -0,0 +1,3 @@
+type: txt
+help: "Destination network"
+syntax: exec "/opt/vyatta/sbin/vyatta-validate-type.pl ipv4net_negate '$(@)'" ; "invalid destination network \"$(@)\""
diff --git a/templates-cfg/service/nat/rule/node.tag/destination/node.def b/templates-cfg/service/nat/rule/node.tag/destination/node.def
new file mode 100644
index 0000000..54f73b4
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/destination/node.def
@@ -0,0 +1 @@
+help: "NAT destination parameters"
diff --git a/templates-cfg/service/nat/rule/node.tag/destination/port-name/node.def b/templates-cfg/service/nat/rule/node.tag/destination/port-name/node.def
new file mode 100644
index 0000000..ddd9de5
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/destination/port-name/node.def
@@ -0,0 +1,10 @@
+multi:
+type: txt
+help: "Named destination port (e.g., http)"
+syntax: exec "sh -c 'if grep -q '\\''^$(@)[ \t]'\\'' /etc/services; \
+then exit 0; else \
+ if grep -q \
+ '\\''^[^ \t]\\+[ \t]\\+[^ \t]\\+[^#]*[ \t]$(@)\\([ \t]\\|\\$\\)'\\'' \
+ /etc/services; then exit 0; else exit 1; \
+ fi; \
+fi' " ; "invalid port name $(@)"
diff --git a/templates-cfg/service/nat/rule/node.tag/destination/port-number/node.def b/templates-cfg/service/nat/rule/node.tag/destination/port-number/node.def
new file mode 100644
index 0000000..5a1c509
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/destination/port-number/node.def
@@ -0,0 +1,4 @@
+multi:
+type: u32
+help: "Numbered destination port (ex. 80)"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/destination/port-range/node.def b/templates-cfg/service/nat/rule/node.tag/destination/port-range/node.def
new file mode 100644
index 0000000..62f0ac8
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/destination/port-range/node.def
@@ -0,0 +1 @@
+help: "Range of destination ports (ex. 80-110)"
diff --git a/templates-cfg/service/nat/rule/node.tag/destination/port-range/start/node.def b/templates-cfg/service/nat/rule/node.tag/destination/port-range/start/node.def
new file mode 100644
index 0000000..59ade24
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/destination/port-range/start/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Starting destination port range"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/destination/port-range/stop/node.def b/templates-cfg/service/nat/rule/node.tag/destination/port-range/stop/node.def
new file mode 100644
index 0000000..d745455
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/destination/port-range/stop/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Ending destination port range"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/inbound-interface/node.def b/templates-cfg/service/nat/rule/node.tag/inbound-interface/node.def
new file mode 100644
index 0000000..c87d281
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inbound-interface/node.def
@@ -0,0 +1,5 @@
+type: txt
+help: "Inbound interface of NAT traffic"
+## iptables allow any interface names.
+#syntax: exec "sh -c 'if grep -q '\\''^ \\+$(@):'\\'' /proc/net/dev; \
+#then exit 0; else exit 1; fi' " ; "invalid interface $(@)"
diff --git a/templates-cfg/service/nat/rule/node.tag/inside-address/address/node.def b/templates-cfg/service/nat/rule/node.tag/inside-address/address/node.def
new file mode 100644
index 0000000..8ff9c72
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inside-address/address/node.def
@@ -0,0 +1,2 @@
+type: ipv4
+help: "Inside address to NAT"
diff --git a/templates-cfg/service/nat/rule/node.tag/inside-address/node.def b/templates-cfg/service/nat/rule/node.tag/inside-address/node.def
new file mode 100644
index 0000000..113c11a
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inside-address/node.def
@@ -0,0 +1 @@
+help: "Inside NAT IP (used by destination NAT only)"
diff --git a/templates-cfg/service/nat/rule/node.tag/inside-address/port-number/node.def b/templates-cfg/service/nat/rule/node.tag/inside-address/port-number/node.def
new file mode 100644
index 0000000..0ff1b43
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inside-address/port-number/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Inside port to NAT"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/inside-address/port-range/node.def b/templates-cfg/service/nat/rule/node.tag/inside-address/port-range/node.def
new file mode 100644
index 0000000..4dbd32c
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inside-address/port-range/node.def
@@ -0,0 +1 @@
+help: "Inside port range to NAT"
diff --git a/templates-cfg/service/nat/rule/node.tag/inside-address/port-range/start/node.def b/templates-cfg/service/nat/rule/node.tag/inside-address/port-range/start/node.def
new file mode 100644
index 0000000..8658b46
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inside-address/port-range/start/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Inside port range start"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/inside-address/port-range/stop/node.def b/templates-cfg/service/nat/rule/node.tag/inside-address/port-range/stop/node.def
new file mode 100644
index 0000000..182a362
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inside-address/port-range/stop/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Inside port range stop"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/inside-address/range/node.def b/templates-cfg/service/nat/rule/node.tag/inside-address/range/node.def
new file mode 100644
index 0000000..f8ef0ea
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inside-address/range/node.def
@@ -0,0 +1 @@
+help: "Inside address range"
diff --git a/templates-cfg/service/nat/rule/node.tag/inside-address/range/start/node.def b/templates-cfg/service/nat/rule/node.tag/inside-address/range/start/node.def
new file mode 100644
index 0000000..473d565
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inside-address/range/start/node.def
@@ -0,0 +1,2 @@
+type: ipv4
+help: "Inside address range start"
diff --git a/templates-cfg/service/nat/rule/node.tag/inside-address/range/stop/node.def b/templates-cfg/service/nat/rule/node.tag/inside-address/range/stop/node.def
new file mode 100644
index 0000000..4c3ebb0
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/inside-address/range/stop/node.def
@@ -0,0 +1,2 @@
+type: ipv4
+help: "Inside address range stop"
diff --git a/templates-cfg/service/nat/rule/node.tag/outbound-interface/node.def b/templates-cfg/service/nat/rule/node.tag/outbound-interface/node.def
new file mode 100644
index 0000000..bf3e8a2
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outbound-interface/node.def
@@ -0,0 +1,5 @@
+type: txt
+help: "Outbound interface for NAT traffic"
+## iptables allow any interface names.
+#syntax: exec "sh -c 'if grep -q '\\''^ \\+$(@):'\\'' /proc/net/dev; \
+#then exit 0; else exit 1; fi' " ; "invalid interface $(@)"
diff --git a/templates-cfg/service/nat/rule/node.tag/outside-address/address/node.def b/templates-cfg/service/nat/rule/node.tag/outside-address/address/node.def
new file mode 100644
index 0000000..d6ee617
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outside-address/address/node.def
@@ -0,0 +1,2 @@
+type: ipv4
+help: "Outside address to NAT"
diff --git a/templates-cfg/service/nat/rule/node.tag/outside-address/node.def b/templates-cfg/service/nat/rule/node.tag/outside-address/node.def
new file mode 100644
index 0000000..466af5c
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outside-address/node.def
@@ -0,0 +1 @@
+help: "Outside NAT IP (used by source NAT only)"
diff --git a/templates-cfg/service/nat/rule/node.tag/outside-address/port-number/node.def b/templates-cfg/service/nat/rule/node.tag/outside-address/port-number/node.def
new file mode 100644
index 0000000..d30ea94
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outside-address/port-number/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Outside port to NAT"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/outside-address/port-range/node.def b/templates-cfg/service/nat/rule/node.tag/outside-address/port-range/node.def
new file mode 100644
index 0000000..aa13b4a
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outside-address/port-range/node.def
@@ -0,0 +1 @@
+help: "Outside port range to NAT"
diff --git a/templates-cfg/service/nat/rule/node.tag/outside-address/port-range/start/node.def b/templates-cfg/service/nat/rule/node.tag/outside-address/port-range/start/node.def
new file mode 100644
index 0000000..09a987a
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outside-address/port-range/start/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Outside port range start"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/outside-address/port-range/stop/node.def b/templates-cfg/service/nat/rule/node.tag/outside-address/port-range/stop/node.def
new file mode 100644
index 0000000..3ce8342
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outside-address/port-range/stop/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Outside port range stop"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/outside-address/range/node.def b/templates-cfg/service/nat/rule/node.tag/outside-address/range/node.def
new file mode 100644
index 0000000..b28186e
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outside-address/range/node.def
@@ -0,0 +1 @@
+help: "Outside address range"
diff --git a/templates-cfg/service/nat/rule/node.tag/outside-address/range/start/node.def b/templates-cfg/service/nat/rule/node.tag/outside-address/range/start/node.def
new file mode 100644
index 0000000..27395f1
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outside-address/range/start/node.def
@@ -0,0 +1,2 @@
+type: ipv4
+help: "Outside address range start"
diff --git a/templates-cfg/service/nat/rule/node.tag/outside-address/range/stop/node.def b/templates-cfg/service/nat/rule/node.tag/outside-address/range/stop/node.def
new file mode 100644
index 0000000..f441522
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/outside-address/range/stop/node.def
@@ -0,0 +1,2 @@
+type: ipv4
+help: "Outside address range stop"
diff --git a/templates-cfg/service/nat/rule/node.tag/protocols/node.def b/templates-cfg/service/nat/rule/node.tag/protocols/node.def
new file mode 100644
index 0000000..75ccb86
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/protocols/node.def
@@ -0,0 +1,3 @@
+type: txt
+help: "Protocol to NAT (this can be a protocol name in /etc/protocols, a protocol number, or \"all\")"
+syntax: exec "/opt/vyatta/sbin/vyatta-validate-type.pl protocol_negate '$(@)'" ; "invalid protocol \"$(@)\""
diff --git a/templates-cfg/service/nat/rule/node.tag/source/address/node.def b/templates-cfg/service/nat/rule/node.tag/source/address/node.def
new file mode 100644
index 0000000..6b88193
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/source/address/node.def
@@ -0,0 +1,3 @@
+type: txt
+help: "Source address"
+syntax: exec "/opt/vyatta/sbin/vyatta-validate-type.pl ipv4_negate '$(@)'" ; "invalid source address \"$(@)\""
diff --git a/templates-cfg/service/nat/rule/node.tag/source/network/node.def b/templates-cfg/service/nat/rule/node.tag/source/network/node.def
new file mode 100644
index 0000000..9306c53
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/source/network/node.def
@@ -0,0 +1,3 @@
+type: txt
+help: "Inside network"
+syntax: exec "/opt/vyatta/sbin/vyatta-validate-type.pl ipv4net_negate '$(@)'" ; "invalid source network \"$(@)\""
diff --git a/templates-cfg/service/nat/rule/node.tag/source/node.def b/templates-cfg/service/nat/rule/node.tag/source/node.def
new file mode 100644
index 0000000..3aad309
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/source/node.def
@@ -0,0 +1 @@
+help: "NAT source parameters"
diff --git a/templates-cfg/service/nat/rule/node.tag/source/port-name/node.def b/templates-cfg/service/nat/rule/node.tag/source/port-name/node.def
new file mode 100644
index 0000000..1ead23b
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/source/port-name/node.def
@@ -0,0 +1,10 @@
+multi:
+type: txt
+help: "Named source port (e.g., http)"
+syntax: exec "sh -c 'if grep -q '\\''^$(@)[ \t]'\\'' /etc/services; \
+then exit 0; else \
+ if grep -q \
+ '\\''^[^ \t]\\+[ \t]\\+[^ \t]\\+[^#]*[ \t]$(@)\\([ \t]\\|\\$\\)'\\'' \
+ /etc/services; then exit 0; else exit 1; \
+ fi; \
+fi' " ; "invalid port name $(@)"
diff --git a/templates-cfg/service/nat/rule/node.tag/source/port-number/node.def b/templates-cfg/service/nat/rule/node.tag/source/port-number/node.def
new file mode 100644
index 0000000..8b8be63
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/source/port-number/node.def
@@ -0,0 +1,4 @@
+multi:
+type: u32
+help: "Numbered source port (ex. 80)"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/source/port-range/node.def b/templates-cfg/service/nat/rule/node.tag/source/port-range/node.def
new file mode 100644
index 0000000..b21d6e8
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/source/port-range/node.def
@@ -0,0 +1 @@
+help: "Range of source ports (ex. 80-110)"
diff --git a/templates-cfg/service/nat/rule/node.tag/source/port-range/start/node.def b/templates-cfg/service/nat/rule/node.tag/source/port-range/start/node.def
new file mode 100644
index 0000000..4ad95f4
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/source/port-range/start/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Starting source port range"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/source/port-range/stop/node.def b/templates-cfg/service/nat/rule/node.tag/source/port-range/stop/node.def
new file mode 100644
index 0000000..74a308b
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/source/port-range/stop/node.def
@@ -0,0 +1,3 @@
+type: u32
+help: "Ending source port range"
+syntax: ($(@) > 0 && $(@) < 65536) ; "port must be between 1 and 65535"
diff --git a/templates-cfg/service/nat/rule/node.tag/type/node.def b/templates-cfg/service/nat/rule/node.tag/type/node.def
new file mode 100644
index 0000000..9df10a9
--- /dev/null
+++ b/templates-cfg/service/nat/rule/node.tag/type/node.def
@@ -0,0 +1,4 @@
+type: txt
+help: "Source, destination, or masquerade NAT"
+syntax: ($(@) == "source" || $(@) == "destination" || $(@) == "masquerade") ; \
+"invalid type $(@)"
diff --git a/templates-op/clear/nat/counters/node.def b/templates-op/clear/nat/counters/node.def
new file mode 100644
index 0000000..39a6ed5
--- /dev/null
+++ b/templates-op/clear/nat/counters/node.def
@@ -0,0 +1,2 @@
+help: Clear NAT counters
+run: sudo iptables -Z -t nat
diff --git a/templates-op/clear/nat/node.def b/templates-op/clear/nat/node.def
new file mode 100644
index 0000000..aae6adc
--- /dev/null
+++ b/templates-op/clear/nat/node.def
@@ -0,0 +1 @@
+help: Clear Network Address Translation tables
diff --git a/templates-op/clear/nat/translations/node.def b/templates-op/clear/nat/translations/node.def
new file mode 100644
index 0000000..0727cbd
--- /dev/null
+++ b/templates-op/clear/nat/translations/node.def
@@ -0,0 +1,2 @@
+help: Clear NAT translations
+run: sudo ${vyatta_sbindir}/vyatta-update-nat.pl clearnattranslations
diff --git a/templates-op/show/nat/node.def b/templates-op/show/nat/node.def
new file mode 100644
index 0000000..20ecd4d
--- /dev/null
+++ b/templates-op/show/nat/node.def
@@ -0,0 +1 @@
+help: Show Network Address Translation information
diff --git a/templates-op/show/nat/rules/node.def b/templates-op/show/nat/rules/node.def
new file mode 100644
index 0000000..772e1b0
--- /dev/null
+++ b/templates-op/show/nat/rules/node.def
@@ -0,0 +1,3 @@
+help: Show configured NAT rule set
+run: sudo ${vyatta_bindir}/sudo-users/vyatta-show-nat.pl \
+ ${vyatta_datadir}/xsl/show_nat_rules.xsl
diff --git a/templates-op/show/nat/statistics/node.def b/templates-op/show/nat/statistics/node.def
new file mode 100644
index 0000000..b4fe23f
--- /dev/null
+++ b/templates-op/show/nat/statistics/node.def
@@ -0,0 +1,3 @@
+help: Show statistics for configured NAT rules
+run: sudo ${vyatta_bindir}/sudo-users/vyatta-show-nat.pl \
+ ${vyatta_datadir}/xsl/show_nat_statistics.xsl
diff --git a/xsl/show_nat_rules.xsl b/xsl/show_nat_rules.xsl
new file mode 100644
index 0000000..e9fdbc9
--- /dev/null
+++ b/xsl/show_nat_rules.xsl
@@ -0,0 +1,309 @@
+<?xml version="1.0"?>
+<!DOCTYPE stylesheet [
+<!ENTITY newln "&#10;">
+]>
+
+<!-- /*
+ * Copyright 2006, Vyatta, Inc.
+ *
+ * GNU General Public 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Module: show_nat_rules.xsl
+ *
+ * Author: Mike Horn
+ * Date: 2006
+ *
+ */ -->
+
+<!--XSL Template for formatting the "show nat rules" command-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:include href="url-decode.xsl" />
+
+<xsl:variable name="pad6" select="' '"/>
+<xsl:variable name="pad6_len" select="string-length($pad6)"/>
+<xsl:variable name="pad7" select="' '"/>
+<xsl:variable name="pad7_len" select="string-length($pad7)"/>
+<xsl:variable name="pad11" select="' '"/>
+<xsl:variable name="pad11_len" select="string-length($pad11)"/>
+<xsl:variable name="pad13" select="' '"/>
+<xsl:variable name="pad13_len" select="string-length($pad13)"/>
+<xsl:variable name="pad20" select="' '"/>
+<xsl:variable name="pad20_len" select="string-length($pad20)"/>
+
+
+<xsl:template match="opcommand">
+<xsl:text>&newln;</xsl:text>
+<xsl:text>&newln;</xsl:text>
+<xsl:text>Type Codes: SRC - source, DST - destination, MASQ - masquerade&newln;</xsl:text>
+<xsl:text>&newln;</xsl:text>
+<xsl:text>rule type IN OUT source destination translation</xsl:text>
+<xsl:text>&newln;</xsl:text>
+<xsl:text>---- ---- --------- --------- ------ ----------- -----------</xsl:text>
+<xsl:text>&newln;</xsl:text>
+
+<xsl:for-each select="format/row">
+
+<xsl:value-of select="rule_num"/>
+<xsl:value-of select="substring($pad6,1,$pad6_len - string-length(rule_num))"/>
+
+ <xsl:choose>
+ <xsl:when test="type='source'">
+ <xsl:text>SRC </xsl:text>
+ </xsl:when>
+
+ <xsl:when test="type='destination'">
+ <xsl:text>DST </xsl:text>
+ </xsl:when>
+
+ <xsl:when test="type='masquerade'">
+ <xsl:text>MASQ </xsl:text>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="in_interface=''">
+ <xsl:text> - </xsl:text>
+ </xsl:when>
+
+ <xsl:when test="in_interface!=''">
+ <xsl:value-of select="in_interface"/>
+ <xsl:value-of select="substring($pad11,1,$pad11_len - string-length(in_interface))"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="out_interface=''">
+ <xsl:text> - </xsl:text>
+ </xsl:when>
+
+ <xsl:when test="out_interface!=''">
+ <xsl:value-of select="out_interface"/>
+ <xsl:value-of select="substring($pad11,1,$pad11_len - string-length(out_interface))"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="src_addr=''">
+ <xsl:value-of select="src_network"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(src_network))"/>
+ </xsl:when>
+
+ <xsl:when test="src_addr!='0.0.0.0'">
+ <xsl:value-of select="src_addr"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(src_addr))"/>
+ </xsl:when>
+
+ <xsl:when test="src_addr='0.0.0.0'">
+ <xsl:value-of select="src_network"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(src_network))"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="dst_addr=''">
+ <xsl:value-of select="dst_network"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(dst_network))"/>
+ </xsl:when>
+
+ <xsl:when test="dst_addr!='0.0.0.0'">
+ <xsl:value-of select="dst_addr"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(dst_addr))"/>
+ </xsl:when>
+
+ <xsl:when test="dst_addr='0.0.0.0'">
+ <xsl:value-of select="dst_network"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(dst_network))"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:if test="type='destination'">
+ <xsl:choose>
+ <xsl:when test="in_addr=''">
+ <xsl:value-of select="in_network"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(in_network))"/>
+ </xsl:when>
+
+ <xsl:when test="in_addr!='0.0.0.0'">
+ <xsl:value-of select="in_addr"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(in_addr))"/>
+ </xsl:when>
+
+ <xsl:when test="in_addr='0.0.0.0'">
+ <xsl:value-of select="in_network"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(in_network))"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:if test="type!='destination'">
+ <xsl:choose>
+ <xsl:when test="out_addr=''">
+ <xsl:value-of select="out_network"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(out_network))"/>
+ </xsl:when>
+
+ <xsl:when test="out_addr!='0.0.0.0'">
+ <xsl:value-of select="out_addr"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(out_addr))"/>
+ </xsl:when>
+
+ <xsl:when test="out_addr='0.0.0.0'">
+ <xsl:value-of select="out_network"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(out_network))"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:text>&newln;</xsl:text>
+
+
+ <xsl:if test="src_ports!='' or dst_ports!=''">
+ <xsl:variable name="src_ports_d">
+ <xsl:call-template name="decode">
+ <xsl:with-param name="encoded" select="src_ports"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="dst_ports_d">
+ <xsl:call-template name="decode">
+ <xsl:with-param name="encoded" select="dst_ports"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad11"/>
+ <xsl:value-of select="$pad11"/>
+
+ <xsl:choose>
+ <xsl:when test="$src_ports_d=''">
+ <xsl:value-of select="$pad20"/>
+ </xsl:when>
+ <xsl:when test="$src_ports_d!=''">
+ <xsl:value-of select="$src_ports_d"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length($src_ports_d))"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="$dst_ports_d!=''">
+ <xsl:value-of select="$dst_ports_d"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length($dst_ports_d))"/>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:text>&newln;</xsl:text>
+ </xsl:if>
+
+
+ <xsl:if test="src_ports_apps!='' or dst_ports_apps!=''">
+ <xsl:variable name="src_ports_apps_d">
+ <xsl:call-template name="decode">
+ <xsl:with-param name="encoded" select="src_ports_apps"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="dst_ports_apps_d">
+ <xsl:call-template name="decode">
+ <xsl:with-param name="encoded" select="dst_ports_apps"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad11"/>
+ <xsl:value-of select="$pad11"/>
+
+ <xsl:choose>
+ <xsl:when test="$src_ports_apps_d=''">
+ <xsl:value-of select="$pad20"/>
+ </xsl:when>
+ <xsl:when test="$src_ports_apps_d!=''">
+ <xsl:value-of select="$src_ports_apps_d"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length($src_ports_apps_d))"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="$dst_ports_apps_d!=''">
+ <xsl:value-of select="$dst_ports_apps_d"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length($dst_ports_apps_d))"/>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:text>&newln;</xsl:text>
+ </xsl:if>
+
+ <xsl:if test="src_port_start!='' or dst_port_start!=''">
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad11"/>
+ <xsl:value-of select="$pad11"/>
+
+ <xsl:choose>
+ <xsl:when test="src_port_start=''">
+ <xsl:value-of select="$pad20"/>
+ </xsl:when>
+ <xsl:when test="src_port_start!=''">
+ <xsl:value-of select="src_port_start"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(src_port_start))"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="dst_port_start!=''">
+ <xsl:value-of select="dst_port_start"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(dst_port_start))"/>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:text>&newln;</xsl:text>
+ </xsl:if>
+
+ <xsl:if test="src_port_stop!='' or dst_port_stop!=''">
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad6"/>
+ <xsl:value-of select="$pad11"/>
+ <xsl:value-of select="$pad11"/>
+
+ <xsl:choose>
+ <xsl:when test="src_port_stop=''">
+ <xsl:value-of select="$pad20"/>
+ </xsl:when>
+ <xsl:when test="src_port_stop!=''">
+ <xsl:value-of select="src_port_stop"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(src_port_stop))"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="dst_port_stop!=''">
+ <xsl:value-of select="dst_port_stop"/>
+ <xsl:value-of select="substring($pad20,1,$pad20_len - string-length(dst_port_stop))"/>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:text>&newln;</xsl:text>
+ </xsl:if>
+
+</xsl:for-each>
+</xsl:template>
+
+</xsl:stylesheet>
+
diff --git a/xsl/show_nat_statistics.xsl b/xsl/show_nat_statistics.xsl
new file mode 100644
index 0000000..140f98c
--- /dev/null
+++ b/xsl/show_nat_statistics.xsl
@@ -0,0 +1,107 @@
+<?xml version="1.0"?>
+<!DOCTYPE stylesheet [
+<!ENTITY newln "&#10;">
+]>
+
+<!-- /*
+ * Copyright 2006, Vyatta, Inc.
+ *
+ * GNU General Public 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Module: show_nat_statistics.xsl
+ *
+ * Author: Mike Horn
+ * Date: 2006
+ *
+ */ -->
+
+<!--XSL Template for formatting the "show nat statistics" command-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:variable name="pad6" select="' '"/>
+<xsl:variable name="pad6_len" select="string-length($pad6)"/>
+<xsl:variable name="pad10" select="' '"/>
+<xsl:variable name="pad10_len" select="string-length($pad10)"/>
+<xsl:variable name="pad11" select="' '"/>
+<xsl:variable name="pad11_len" select="string-length($pad11)"/>
+<xsl:variable name="pad12" select="' '"/>
+<xsl:variable name="pad12_len" select="string-length($pad12)"/>
+
+<xsl:template match="opcommand">
+
+<xsl:text>&newln;</xsl:text>
+<xsl:text>&newln;</xsl:text>
+<xsl:text>Type Codes: SRC - source, DST - destination, MASQ - masquerade&newln;</xsl:text>
+<xsl:text>&newln;</xsl:text>
+<xsl:text>rule packets bytes type IN OUT</xsl:text>
+<xsl:text>&newln;</xsl:text>
+<xsl:text>---- ------- ----- ---- --------- ---------</xsl:text>
+<xsl:text>&newln;</xsl:text>
+
+<xsl:for-each select="format/row">
+
+<xsl:value-of select="rule_num"/>
+<xsl:value-of select="substring($pad6,1,$pad6_len - string-length(rule_num))"/>
+
+<xsl:value-of select="pkts"/>
+<xsl:value-of select="substring($pad10,1,$pad10_len - string-length(pkts))"/>
+
+<xsl:value-of select="bytes"/>
+<xsl:value-of select="substring($pad10,1,$pad10_len - string-length(bytes))"/>
+
+ <xsl:choose>
+ <xsl:when test="type='source'">
+ <xsl:text>SRC </xsl:text>
+ </xsl:when>
+
+ <xsl:when test="type='destination'">
+ <xsl:text>DST </xsl:text>
+ </xsl:when>
+
+ <xsl:when test="type='masquerade'">
+ <xsl:text>MASQ </xsl:text>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="in_interface=''">
+ <xsl:text> - </xsl:text>
+ </xsl:when>
+
+ <xsl:when test="in_interface!=''">
+ <xsl:value-of select="in_interface"/>
+ <xsl:value-of select="substring($pad11,1,$pad11_len - string-length(in_interface))"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="out_interface=''">
+ <xsl:text> - </xsl:text>
+ </xsl:when>
+
+ <xsl:when test="out_interface!=''">
+ <xsl:value-of select="out_interface"/>
+ </xsl:when>
+ </xsl:choose>
+
+<xsl:text>&newln;</xsl:text>
+
+</xsl:for-each>
+</xsl:template>
+
+</xsl:stylesheet>