summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorBob Gilligan <gilligan@sydney.vyatta.com>2007-12-10 17:40:27 -0800
committerBob Gilligan <gilligan@sydney.vyatta.com>2007-12-10 17:40:27 -0800
commita6d5039dd4936734b0a28d04a1e497280a342491 (patch)
tree880fc1a49a87850129c1b8be50f97646cf79cd86 /scripts
downloadvyatta-cfg-firewall-a6d5039dd4936734b0a28d04a1e497280a342491.tar.gz
vyatta-cfg-firewall-a6d5039dd4936734b0a28d04a1e497280a342491.zip
Initial setup of vyatta-cfg-firewall package.
Diffstat (limited to 'scripts')
-rw-r--r--scripts/firewall/VyattaIpTablesAddressFilter.pm250
-rw-r--r--scripts/firewall/VyattaIpTablesRule.pm262
-rwxr-xr-xscripts/firewall/firewall.init45
-rw-r--r--scripts/firewall/firewall.tp557
-rwxr-xr-xscripts/firewall/vyatta-firewall.pl374
-rwxr-xr-xscripts/firewall/vyatta-show-firewall.pl90
6 files changed, 1578 insertions, 0 deletions
diff --git a/scripts/firewall/VyattaIpTablesAddressFilter.pm b/scripts/firewall/VyattaIpTablesAddressFilter.pm
new file mode 100644
index 0000000..4747e5e
--- /dev/null
+++ b/scripts/firewall/VyattaIpTablesAddressFilter.pm
@@ -0,0 +1,250 @@
+package VyattaIpTablesAddressFilter;
+
+use VyattaConfig;
+
+my %_protocolswithports = (
+ tcp => 1,
+ udp => 1,
+ 6 => 1,
+ 17 => 1,
+);
+
+my %fields = (
+ _srcdst => undef,
+ _range_start => undef,
+ _range_stop => undef,
+ _network => undef,
+ _address => undef,
+ _portname => undef,
+ _portrange_start => undef,
+ _portrange_stop => undef,
+ _portnumber => undef,
+ _protocol => undef,
+ _src_mac => 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");
+
+ # setup needed parent nodes
+ $self->{_srcdst} = $config->returnParent("..");
+ $self->{_protocol} = $config->returnValue(".. protocol");
+
+ # setup address filter nodes
+ $self->{_range_start} = $config->returnValue("range start");
+ $self->{_range_stop} = $config->returnValue("range stop");
+ $self->{_network} = $config->returnValue("network");
+ $self->{_address} = $config->returnValue("address");
+ my @tmp = $config->returnValues("port-number");
+ $self->{_portnumber} = [ @tmp ];
+ @tmp = $config->returnValues("port-name");
+ $self->{_portname} = [ @tmp ];
+ $self->{_portrange_start} = $config->returnValue("port-range start");
+ $self->{_portrange_stop} = $config->returnValue("port-range stop");
+
+ $self->{_src_mac} = $config->returnValue("mac-address");
+
+ return 0;
+}
+
+sub setupOrig {
+ my ($self, $level) = @_;
+ my $config = new VyattaConfig;
+
+ $config->setLevel("$level");
+
+ # setup needed parent nodes
+ $self->{_srcdst} = $config->returnParent("..");
+ $self->{_protocol} = $config->returnOrigValue(".. protocol");
+
+ # setup address filter nodes
+ $self->{_range_start} = $config->returnOrigValue("range start");
+ $self->{_range_stop} = $config->returnOrigValue("range stop");
+ $self->{_network} = $config->returnOrigValue("network");
+ $self->{_address} = $config->returnOrigValue("address");
+ my @tmp = $config->returnOrigValues("port-number");
+ $self->{_portnumber} = [ @tmp ];
+ @tmp = $config->returnOrigValues("port-name");
+ $self->{_portname} = [ @tmp ];
+ $self->{_portrange_start} = $config->returnOrigValue("port-range start");
+ $self->{_portrange_stop} = $config->returnOrigValue("port-range stop");
+
+ $self->{_src_mac} = $config->returnValue("mac-address");
+
+ return 0;
+}
+
+sub print {
+ my ($self) = @_;
+
+ print "srcdst: $self->{_srcdst}\n" if defined $self->{_srcdst};
+ print "range start: $self->{_range_start}\n" if defined $self->{_range_start};
+ print "range stop: $self->{_range_stop}\n" if defined $self->{_range_stop};
+ print "network: $self->{_network}\n" if defined $self->{_network};
+ print "address: $self->{_address}\n" if defined $self->{_address};
+ print "port-name: " . (join ',', $self->{_portname}) . "\n"
+ if defined $self->{_portname};
+ print "port-range start: $self->{_portrange_start}\n" if defined $self->{_portrange_start};
+ print "port-range stop: $self->{_portrange_stop}\n" if defined $self->{_portrange_stop};
+ print "port-number: " . (join ',', $self->{_portnumber}) . "\n"
+ if defined $self->{_portnumber};
+ print "protocol: $self->{_protocol}\n" if defined $self->{_protocol};
+ print "src-mac: $self->{_src_mac}\n" if defined $self->{_src_mac};
+
+ 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);
+}
+
+sub rule {
+ my ($self) = @_;
+ my $rule = "";
+ my $can_use_port = 1;
+
+ if (!defined($self->{_protocol})
+ || !defined($_protocolswithports{$self->{_protocol}})) {
+ $can_use_port = 0;
+ }
+
+ if (($self->{_srcdst} eq "source") && (defined($self->{_src_mac}))) {
+ # handle src mac
+ my $str = $self->{_src_mac};
+ $str =~ s/^\!(.*)$/! $1/;
+ $rule .= "-m mac --mac-source $str ";
+ }
+
+ # set the address filter parameters
+ if (defined($self->{_network})) {
+ my $str = $self->{_network};
+ $str =~ s/^\!(.*)$/! $1/;
+ $rule .= "--$self->{_srcdst} $str ";
+ } elsif (defined($self->{_address})) {
+ my $str = $self->{_address};
+ $str =~ s/^\!(.*)$/! $1/;
+ $rule .= "--$self->{_srcdst} $str ";
+ } elsif ((defined $self->{_range_start}) && (defined $self->{_range_stop})) {
+ if ("$self->{_srcdst}" eq "source") {
+ $rule .= ("-m iprange "
+ . "--src-range $self->{_range_start}-$self->{_range_stop} ");
+ }
+ elsif ("$self->{_srcdst}" eq "destination") {
+ $rule .= ("-m iprange "
+ . "--dst-range $self->{_range_start}-$self->{_range_stop} ");
+ }
+ }
+
+ my ($port_str, $port_err)
+ = handle_ports($self->{_portnumber},
+ $self->{_portname},
+ $self->{_portrange_start},
+ $self->{_portrange_stop},
+ $can_use_port,
+ ($self->{_srcdst} eq "source") ? "s" : "d",
+ $self->{_protocol});
+ return (undef, $port_err) if (!defined($port_str));
+ $rule .= $port_str;
+ return ($rule, undef);
+}
+
+sub outputXmlElem {
+ my ($name, $value, $fh) = @_;
+ print $fh " <$name>$value</$name>\n";
+}
+
+sub outputXml {
+ my ($self, $prefix, $fh) = @_;
+ outputXmlElem("${prefix}_addr", $self->{_address}, $fh);
+ outputXmlElem("${prefix}_net", $self->{_network}, $fh);
+ outputXmlElem("${prefix}_addr_start", $self->{_range_start}, $fh);
+ outputXmlElem("${prefix}_addr_stop", $self->{_range_stop}, $fh);
+ outputXmlElem("${prefix}_port_num",
+ (join ',', @{$self->{_portnumber}}), $fh);
+ outputXmlElem("${prefix}_port_name",
+ (join ',', @{$self->{_portname}}), $fh);
+ outputXmlElem("${prefix}_port_start", $self->{_portrange_start}, $fh);
+ outputXmlElem("${prefix}_port_stop", $self->{_portrange_stop}, $fh);
+}
+
diff --git a/scripts/firewall/VyattaIpTablesRule.pm b/scripts/firewall/VyattaIpTablesRule.pm
new file mode 100644
index 0000000..c2174c4
--- /dev/null
+++ b/scripts/firewall/VyattaIpTablesRule.pm
@@ -0,0 +1,262 @@
+package VyattaIpTablesRule;
+
+use VyattaConfig;
+use VyattaIpTablesAddressFilter;
+
+my $src = new VyattaIpTablesAddressFilter;
+my $dst = new VyattaIpTablesAddressFilter;
+
+my %fields = (
+ _name => undef,
+ _rule_number => undef,
+ _protocol => undef,
+ _state => {
+ _established => undef,
+ _new => undef,
+ _related => undef,
+ _invalid => undef,
+ },
+ _action => undef,
+ _log => undef,
+ _icmp_code => undef,
+ _icmp_type => undef,
+);
+
+my %dummy_rule = (
+ _rule_number => 1025,
+ _protocol => "all",
+ _state => {
+ _established => undef,
+ _new => undef,
+ _related => undef,
+ _invalid => undef,
+ },
+ _action => "DROP",
+ _log => undef,
+ _icmp_code => undef,
+ _icmp_type => undef,
+);
+
+sub new {
+ my $that = shift;
+ my $class = ref ($that) || $that;
+ my $self = {
+ %fields,
+ };
+
+ bless $self, $class;
+ return $self;
+}
+
+sub setupDummy {
+ my $self = shift;
+ %{$self} = %dummy_rule;
+ $src = new VyattaIpTablesAddressFilter;
+ $dst = new VyattaIpTablesAddressFilter;
+}
+
+sub setup {
+ my ( $self, $level ) = @_;
+ my $config = new VyattaConfig;
+
+ $config->setLevel("$level");
+
+ # for documentation sake. nodes returns an array so must transform
+ # and ".. .. .." means go up three levels in the current hierarchy
+ $self->{_name} = $config->returnParent(".. .. ..");
+ $self->{_rule_number} = $config->returnParent("..");
+
+ $self->{_protocol} = $config->returnValue("protocol");
+ $self->{_state}->{_established} = $config->returnValue("state established");
+ $self->{_state}->{_new} = $config->returnValue("state new");
+ $self->{_state}->{_related} = $config->returnValue("state related");
+ $self->{_state}->{_invalid} = $config->returnValue("state invalid");
+ $self->{_action} = $config->returnValue("action");
+ $self->{_log} = $config->returnValue("log");
+ $self->{_icmp_code} = $config->returnValue("icmp code");
+ $self->{_icmp_type} = $config->returnValue("icmp type");
+
+ # TODO: need $config->exists("$level source") in VyattaConfig.pm
+ $src->setup("$level source");
+ $dst->setup("$level destination");
+
+ return 0;
+}
+
+sub setupOrig {
+ my ( $self, $level ) = @_;
+ my $config = new VyattaConfig;
+
+ $config->setLevel("$level");
+
+ # for documentation sake. nodes returns an array so must transform
+ # and ".. .. .." means go up three levels in the current hierarchy
+ $self->{_name} = $config->returnParent(".. .. ..");
+ $self->{_rule_number} = $config->returnParent("..");
+
+ $self->{_protocol} = $config->returnOrigValue("protocol");
+ $self->{_state}->{_established}
+ = $config->returnOrigValue("state established");
+ $self->{_state}->{_new} = $config->returnOrigValue("state new");
+ $self->{_state}->{_related} = $config->returnOrigValue("state related");
+ $self->{_state}->{_invalid} = $config->returnOrigValue("state invalid");
+ $self->{_action} = $config->returnOrigValue("action");
+ $self->{_log} = $config->returnOrigValue("log");
+ $self->{_icmp_code} = $config->returnOrigValue("icmp code");
+ $self->{_icmp_type} = $config->returnOrigValue("icmp type");
+
+ # TODO: need $config->exists("$level source") in VyattaConfig.pm
+ $src->setupOrig("$level source");
+ $dst->setupOrig("$level destination");
+
+ return 0;
+}
+
+sub print {
+ my ( $self ) = @_;
+
+ print "name: $self->{_name}\n" if defined $self->{_name};
+ print "rulenum: $self->{_rule_number}\n" if defined $self->{_rule_number};
+ print "protocol: $self->{_protocol}\n" if defined $self->{_protocol};
+ print "state: $self->{_state}\n" if defined $self->{_state};
+ print "action: $self->{_action}\n" if defined $self->{_action};
+ print "log: $self->{_log}\n" if defined $self->{_log};
+ print "icmp code: $self->{_icmp_code}\n" if defined $self->{_icmp_code};
+ print "icmp type: $self->{_icmp_type}\n" if defined $self->{_icmp_type};
+
+ $src->print();
+ $dst->print();
+
+}
+
+sub is_stateful {
+ my $self = shift;
+ my @states = qw(established new related invalid);
+ foreach (@states) {
+ if (defined($self->{_state}->{"_$_"})
+ && $self->{_state}->{"_$_"} eq "enable") {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub get_state_str {
+ my $self = shift;
+ my @states = qw(established new related invalid);
+ my @add_states = ();
+ foreach (@states) {
+ if (defined($self->{_state}->{"_$_"})
+ && $self->{_state}->{"_$_"} eq "enable") {
+ push @add_states, $_;
+ }
+ }
+ if ($#add_states >= 0) {
+ my $str = join ',', @add_states;
+ return $str;
+ } else {
+ return "";
+ }
+}
+
+sub get_num_ipt_rules {
+ my $self = shift;
+ my $ipt_rules = 1;
+ if (("$self->{_log}" eq "enable") && (("$self->{_action}" eq "drop")
+ || ("$self->{_action}" eq "accept")
+ || ("$self->{_action}" eq "reject"))) {
+ $ipt_rules += 1;
+ }
+ return $ipt_rules;
+}
+
+sub rule {
+ my ( $self ) = @_;
+ my $rule = undef;
+ my $srcrule = $dstrule = undef;
+ my $err_str = undef;
+
+ # set the protocol
+ if (defined($self->{_protocol})) {
+ my $str = $self->{_protocol};
+ $str =~ s/^\!(.*)$/! $1/;
+ $rule .= "--protocol $str ";
+ }
+
+ # set the session state if protocol tcp
+ my $state_str = uc (get_state_str($self));
+ if ($state_str ne "") {
+ $rule .= "-m state --state $state_str ";
+ }
+
+ # set the icmp code and type if applicable
+ if (($self->{_protocol} eq "icmp") || ($self->{_protocol} eq "1")) {
+ if (defined $self->{_icmp_type}) {
+ $rule .= "--icmp-type $self->{_icmp_type}";
+ if (defined $self->{_icmp_code}) {
+ $rule .= "/$self->{_icmp_code}";
+ }
+ $rule .= " ";
+ } elsif (defined $self->{_icmp_code}) {
+ return ("ICMP code can only be defined if ICMP type is defined", );
+
+ }
+ } elsif (defined($self->{_icmp_type}) || defined($self->{_icmp_code})) {
+ return ("ICMP type/code can only be defined if protocol is ICMP", );
+ }
+
+ # add the source and destination rules
+ ($srcrule, $err_str) = $src->rule();
+ return ($err_str, ) if (!defined($srcrule));
+ ($dstrule, $err_str) = $dst->rule();
+ return ($err_str, ) if (!defined($dstrule));
+ $rule .= " $srcrule $dstrule ";
+
+ my $chain = $self->{_name};
+ my $rule_num = $self->{_rule_number};
+ my $rule2 = undef;
+ # set the jump target. Depends on action and log
+ if ("$self->{_log}" eq "enable") {
+ $rule2 = $rule;
+ $rule2 .= "-j LOG --log-prefix '[$chain $rule_num $self->{_action}] ' ";
+ }
+ if ("$self->{_action}" eq "drop") {
+ $rule .= "-j DROP ";
+ } elsif ("$self->{_action}" eq "accept") {
+ $rule .= "-j RETURN ";
+ } elsif ("$self->{_action}" eq "reject") {
+ $rule .= "-j REJECT ";
+ } else {
+ return ("\"action\" must be defined", );
+ }
+ if (defined($rule2)) {
+ my $tmp = $rule2;
+ $rule2 = $rule;
+ $rule = $tmp;
+ }
+ return (undef, $rule, $rule2, );
+}
+
+sub outputXmlElem {
+ my ($name, $value, $fh) = @_;
+ print $fh " <$name>$value</$name>\n";
+}
+
+sub outputXml {
+ my ($self, $fh) = @_;
+ outputXmlElem("protocol", $self->{_protocol}, $fh);
+ my $state_str = get_state_str($self);
+ if ($state_str ne "") {
+ $state_str =~ s/,/%2C/g;
+ $state_str .= "+";
+ }
+ outputXmlElem("state", $state_str, $fh);
+ outputXmlElem("action", uc($self->{_action}), $fh);
+ outputXmlElem("log", $self->{_log}, $fh);
+ outputXmlElem("icmp_type", $self->{_icmp_type}, $fh);
+ outputXmlElem("icmp_code", $self->{_icmp_code}, $fh);
+
+ $src->outputXml("src", $fh);
+ $dst->outputXml("dst", $fh);
+}
+
diff --git a/scripts/firewall/firewall.init b/scripts/firewall/firewall.init
new file mode 100755
index 0000000..b58d4d5
--- /dev/null
+++ b/scripts/firewall/firewall.init
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# source the shared functions
+. /etc/init.d/vyatta-functions
+
+ACTION=$1
+
+start() {
+ echo -n "Initializing firewall: "
+ # progress_indicator "start" $INIT_PID
+
+ OUTPUT=`/opt/vyatta/sbin/vyatta-firewall.pl --setup 2>&1`;
+ # progress_indicator "stop" $INIT_PID
+
+ echo "OK"
+}
+
+stop() {
+ echo -n "Reseting firewall: "
+ # progress_indicator "start" $INIT_PID
+ OUTPUT=`/opt/vyatta/sbin/vyatta-firewall.pl --setup 2>&1`;
+
+ # progress_indicator "stop" $INIT_PID
+ echo "OK"
+}
+
+case "$ACTION" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart)
+ stop
+ start
+ ;;
+ *)
+ echo "usage: $0 {start|stop|restart}"
+ exit 1
+ ;;
+esac
+
+exit 0
+
diff --git a/scripts/firewall/firewall.tp b/scripts/firewall/firewall.tp
new file mode 100644
index 0000000..08d2cbe
--- /dev/null
+++ b/scripts/firewall/firewall.tp
@@ -0,0 +1,557 @@
+/*
+ * Module: firewall.tp
+ *
+ * **** 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 setd by Vyatta are Copyright (C) 2005, 2006, 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2005
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+firewall {
+ targetname: txt = "rl_firewall";
+/* disable: toggle = true;*/
+
+ log-martians: txt = "enable";
+ send-redirects: txt = "disable";
+ receive-redirects:txt = "disable";
+ ip-src-route: txt = "disable";
+ broadcast-ping: txt = "disable";
+ syn-cookies: txt = "enable";
+
+ name @: txt {
+ description: txt;
+ rule @: u32 {
+ protocol: txt = "all";
+ icmp {
+ type: txt;
+ code: txt;
+ }
+
+ state {
+ established: txt;
+ new: txt;
+ related: txt;
+ invalid: txt;
+ }
+
+ action: txt;
+ log: txt = "disable";
+
+ source {
+ address: ipv4;
+ network: ipv4net;
+ range {
+ start: ipv4;
+ stop: ipv4;
+ }
+
+ port-number: u32;
+ port-name: txt;
+ port-range {
+ start: u32;
+ stop: u32;
+ }
+
+ }
+ destination {
+ address: ipv4;
+ network: ipv4net;
+ range {
+ start: ipv4;
+ stop: ipv4;
+ }
+
+ port-number: u32;
+ port-name: txt;
+ port-range {
+ start: u32;
+ stop: u32;
+ }
+ }
+ }
+ }
+}
+
+interfaces {
+ ethernet @: txt {
+ firewall {
+
+ in {
+ name: txt;
+ }
+ out {
+ name: txt;
+ }
+ local {
+ name: txt;
+ }
+ }
+
+ vif @: txt {
+ firewall {
+ in {
+ name: txt;
+ }
+ out {
+ name: txt;
+ }
+ local {
+ name: txt;
+ }
+ }
+ }
+ }
+}
+
+firewall {
+ %help: short "Firewall configuration";
+ %modinfo: provides firewall;
+
+ %modinfo: path "libexec/xorp/xorp_rl_firewall";
+ %modinfo: default_targetname "rl_firewall";
+ %modinfo: start_commit program "/opt/vyatta/sbin/xorp_tmpl_tool cleanup";
+ %modinfo: end_commit program "/opt/vyatta/sbin/xorp_tmpl_tool commit";
+ %modinfo: status_method xrl "$(firewall.targetname)/common/0.1/get_status->status:u32&reason:txt";
+ /*
+ %modinfo: shutdown_method xrl "$(firewall.targetname)/rl_firewall/0.1/shutdown_firewall";
+ */
+ %modinfo: shutdown_method program "/opt/vyatta/sbin/xorp_tmpl_tool cleanup && /opt/vyatta/sbin/xorp_tmpl_tool delete firewall && /opt/vyatta/sbin/xorp_tmpl_tool commit && /opt/vyatta/sbin/xorp_tmpl_tool rtrmgr_indirect_cleanup";
+
+ /*
+ %delete: xrl "$(firewall.targetname)/rl_firewall/0.1/delete_rl_firewall";
+ */
+ %delete: ;
+
+ targetname {
+ %user-hidden: "XRL target name";
+ %help: short "Set the target name";
+ }
+
+ log-martians {
+ %help: short "Configure log martians";
+ %allow: $(@) "enable" %help: "Enable log martians";
+ %allow: $(@) "disable" %help: "Disable log martians";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall log-martians $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall log-martians";
+ }
+
+ send-redirects {
+ %help: short "Configure send redirects";
+ %allow: $(@) "enable" %help: "Enable send redirects";
+ %allow: $(@) "disable" %help: "Disable send redirects";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall send-redirects $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall send-redirects";
+ }
+
+ receive-redirects {
+ %help: short "Configure receive redirects";
+ %allow: $(@) "enable" %help: "Enable receive redirects";
+ %allow: $(@) "disable" %help: "Disable receive redirects";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall receive-redirects $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall receive-redirects";
+ }
+
+ ip-src-route {
+ %help: short "Configure IP source route";
+ %allow: $(@) "enable" %help: "Enable IP source route";
+ %allow: $(@) "disable" %help: "Disable IP source route";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall ip-src-route $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall ip-src-route";
+ }
+
+ broadcast-ping {
+ %help: short "Configure broadcast ping";
+ %allow: $(@) "enable" %help: "Enable broadcast ping";
+ %allow: $(@) "disable" %help: "Disable broadcast ping";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall broadcast-ping $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall broadcast-ping";
+ }
+
+ syn-cookies {
+ %help: short "Configure SYN cookies";
+ %allow: $(@) "enable" %help: "Enable SYN cookies";
+ %allow: $(@) "disable" %help: "Disable SYN cookies";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall syn-cookies $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall syn-cookies";
+ }
+ name @: txt {
+ %help: short "Configure firewall rule set name";
+
+ %create: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name '$(@)'";
+ %update: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name '$(@)'";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name '$(@)'";
+
+ description {
+ %help: short "Firewall description";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) description '$(@)'";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) description";
+
+ }
+
+ rule @: u32 {
+ %help: short "Firewall rule number in range from 1 to 1024";
+ %order: sorted-numeric;
+ %allow-range: $(@) "1" "1024" %help: "Firewall rule number";
+
+ %create: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(@)";
+ %update: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(@)";
+
+ protocol {
+ %help: short "Configure Protocol";
+ %allow: $(@) "all" %help: "";
+ %allow: $(@) "tcp" %help: "";
+ %allow: $(@) "udp" %help: "";
+ %allow: $(@) "icmp" %help: "";
+ %allow: $(@) "igmp" %help: "";
+ %allow: $(@) "ipencap" %help: "";
+ %allow: $(@) "gre" %help: "";
+ %allow: $(@) "esp" %help: "";
+ %allow: $(@) "ah" %help: "";
+ %allow: $(@) "ospf" %help: "";
+ %allow: $(@) "pim" %help: "";
+ %allow: $(@) "vrrp" %help: "";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) protocol $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) protocol";
+ }
+
+ icmp {
+ %help: short "ICMP type and code settings";
+ %mandatory: $(@.type);
+
+ type {
+ %help: short "ICMP type";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) icmp type $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) icmp type";
+ }
+
+ code {
+ %help: short "ICMP code";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) icmp code $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) icmp code";
+ }
+ }
+
+ state {
+ %help: short "Rule state";
+
+ established {
+ %help: short "Configure established state";
+ %allow: $(@) "enable" %help: "Enable established state";
+ %allow: $(@) "disable" %help: "Disable established state";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) state established $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) state established";
+ }
+
+ new {
+ %help: short "Configure new state";
+ %allow: $(@) "enable" %help: "Enable new state";
+ %allow: $(@) "disable" %help: "Disable new state";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) state new $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) state new";
+ }
+
+ related {
+ %help: short "Configure related state";
+ %allow: $(@) "enable" %help: "Enable related state";
+ %allow: $(@) "disable" %help: "Disable related state";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) state related $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) state related";
+ }
+
+ invalid {
+ %help: short "Configure invalid state";
+ %allow: $(@) "enable" %help: "Enable invalid state";
+ %allow: $(@) "disable" %help: "Disable invalid state";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) state invalid $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) state invalid";
+ }
+ }
+
+ action {
+ %help: short "Configure rule action";
+ %allow: $(@) "accept" %help: "Accept packet";
+ %allow: $(@) "drop" %help: "Silently drop packet";
+ %allow: $(@) "reject" %help: "Reject packet with TCP reset";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) action $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) action";
+ }
+
+ log {
+ %help: short "Configure firewall logging";
+ %allow: $(@) "enable" %help: "Enable firewall logging";
+ %allow: $(@) "disable" %help: "Disable firewall logging";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) log $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) log";
+ }
+
+ source {
+ %help: short "Firewall source parameters";
+
+ address {
+ %help: short "Source address";
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source address $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source address";
+ }
+
+ network {
+ %help: short "Source network";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source network $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source network";
+ }
+ range {
+ %mandatory: $(@.start);
+ %mandatory: $(@.stop);
+ %help: short "Source range start and stop";
+
+ start {
+ %help: short "Source range start";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source range start $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source range start";
+ }
+ stop {
+ %help: short "Source range stop";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source range stop $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source range stop";
+ }
+ }
+
+ port-number {
+ %help: short "Source port number";
+ %allow-range: $(@) "1" "65535" %help: "";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source port-number $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source port-number";
+ }
+
+ port-name {
+ %help: short "Source port name";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source port-name $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source port-name";
+ }
+
+ port-range {
+ %help: short "Source port range start and stop";
+ %mandatory: $(@.start);
+ %mandatory: $(@.stop);
+
+ start {
+ %help: short "Source port range start";
+ %allow-range: $(@) "1" "65535" %help: "";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source port-range start $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source port-range start";
+
+ }
+ stop {
+ %help: short "Source port range stop";
+ %allow-range: $(@) "1" "65535" %help: "";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) source port-range stop $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) source port-range stop";
+ }
+ }
+ }
+ destination {
+ %help: short "Firewall destination parameters";
+
+ address {
+ %help: short "Destination address";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination address $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination address";
+ }
+
+ network {
+ %help: short "Destination network";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination network $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination network";
+ }
+
+ range {
+ %help: short "Destination range start and stop";
+ %mandatory: $(@.start);
+ %mandatory: $(@.stop);
+
+ start {
+ %help: short "Destination range start";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination range start $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination range start";
+ }
+
+ stop {
+ %help: short "Destination range stop";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination range stop $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination range stop";
+ }
+ }
+
+ port-number {
+ %help: short "Destination port number";
+ %allow-range: $(@) "1" "65535" %help: "";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination port-number $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination port-number";
+ }
+
+ port-name {
+ %help: short "Destination port name";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination port-name $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination port-name";
+ }
+
+ port-range {
+ %help: short "Port range start and stop";
+ %mandatory: $(@.start);
+ %mandatory: $(@.stop);
+
+ start {
+ %help: short "Destination port range start";
+ %allow-range: $(@) "1" "65535" %help: "";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination port-range start $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination port-range start";
+ }
+ stop {
+ %help: short "Destination port range stop";
+ %allow-range: $(@) "1" "65535" %help: "";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set firewall name $(name.@) rule $(rule.@) destination port-range stop $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete firewall name $(name.@) rule $(rule.@) destination port-range stop";
+ }
+ }
+ }
+ }
+ }
+}
+
+interfaces {
+ ethernet @: txt {
+ firewall {
+ %help: short "Configure firewall options";
+
+ in {
+ %mandatory: $(@.name);
+ %help: short "Filter forwarded packets on inbound interface";
+
+ name {
+ %help: short "Inbound interface filter name";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) firewall in name $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) firewall in name";
+ }
+
+ }
+
+ out {
+ %mandatory: $(@.name);
+ %help: short "Filter forwarded packets on outbound interface";
+
+ name {
+ %help: short "Outbound interface filter name";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) firewall out name $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) firewall out name";
+ }
+
+ }
+
+ local {
+ %mandatory: $(@.name);
+ %help: short "Filter packets destined for this router";
+
+ name {
+ %help: short "Local filter name";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) firewall local name $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) firewall local name";
+ }
+
+ }
+ }
+
+ vif @: txt {
+ firewall {
+ %help: short "Configure firewall options";
+
+ in {
+ %mandatory: $(@.name);
+ %help: short "Filter forwarded packets on inbound interface";
+
+ name {
+ %help: short "Inbound interface filter name";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) vif $(vif.@) firewall in name $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) vif $(vif.@) firewall in name";
+ }
+ }
+
+ out {
+ %mandatory: $(@.name);
+ %help: short "Filter forwarded packets on outbound interface";
+
+ name {
+ %help: short "Outbound interface filter name";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) vif $(vif.@) firewall out name $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) vif $(vif.@) firewall out name";
+ }
+ }
+
+ local {
+ %mandatory: $(@.name);
+ %help: short "Filter packets destined for this router";
+
+ name {
+ %help: short "Local filter name";
+
+ %set: program "/opt/vyatta/sbin/xorp_tmpl_tool set interfaces ethernet $(ethernet.@) vif $(vif.@) firewall local name $(@)";
+ %delete: program "/opt/vyatta/sbin/xorp_tmpl_tool delete interfaces ethernet $(ethernet.@) vif $(vif.@) firewall local name";
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/scripts/firewall/vyatta-firewall.pl b/scripts/firewall/vyatta-firewall.pl
new file mode 100755
index 0000000..93cbd09
--- /dev/null
+++ b/scripts/firewall/vyatta-firewall.pl
@@ -0,0 +1,374 @@
+#!/usr/bin/perl
+
+use lib "/opt/vyatta/share/perl5/";
+use VyattaConfig;
+use VyattaIpTablesRule;
+use VyattaIpTablesAddressFilter;
+use Getopt::Long;
+
+my @updateints = ();
+GetOptions("setup" => \$setup,
+ "teardown" => \$teardown,
+ "update-rules" => \$updaterules,
+ "update-interfaces=s{4}" => \@updateints,
+);
+
+if (defined $setup) {
+ setup_iptables();
+ exit 0;
+}
+
+if (defined $updaterules) {
+ update_rules();
+ exit 0;
+}
+
+if ($#updateints == 3) {
+ update_ints(@updateints);
+ exit 0;
+}
+
+if (defined $teardown) {
+ teardown_iptables();
+ exit 0;
+}
+
+help();
+exit 1;
+
+sub help() {
+ print "usage: vyatta-firewall.pl\n";
+ print "\t--setup setup Vyatta specific iptables settings\n";
+ print "\t--update-rules update iptables with the current firewall rules\n";
+ print "\t--update-interfaces update the rules applpied to interfaces\n";
+ print "\t (<action> <interface> <direction> <chain name>)\n";
+ print "\t--teardown teardown all user rules and iptables settings\n";
+ print "\n";
+}
+
+sub update_rules() {
+ my $config = new VyattaConfig;
+ my $name = undef;
+ my %nodes = ();
+
+ $config->setLevel("firewall name");
+
+ %nodes = $config->listNodeStatus();
+ if ((scalar (keys %nodes)) == 0) {
+ # no names. teardown the user chains and return.
+ teardown_iptables();
+ return;
+ }
+
+ # by default, nothing needs to be tracked.
+ my $stateful = 0;
+
+ for $name (keys %nodes) {
+ if ($nodes{$name} eq "static") {
+ # not changed. check if stateful.
+ $config->setLevel("firewall name $name rule");
+ my @rules = $config->listOrigNodes();
+ foreach (sort numerically @rules) {
+ my $node = new VyattaIpTablesRule;
+ $node->setupOrig("firewall name $name rule $_");
+ if ($node->is_stateful()) {
+ $stateful = 1;
+ last;
+ }
+ }
+ next;
+ } elsif ($nodes{$name} eq "added") {
+ # create the chain
+ print "creating chain $name\n";
+ setup_chain("$name");
+ # handle the rules below.
+ } elsif ($nodes{$name} eq "deleted") {
+ # delete the chain
+ print "deleting chain $name\n";
+ delete_chain("$name");
+ next;
+ } elsif ($nodes{$name} eq "changed") {
+ # handle the rules below.
+ }
+
+ print "firewall name $name\n";
+ #print "-----------------------------------------------\n";
+
+ # set our config level to rule and get the rule numbers
+ $config->setLevel("firewall name $name rule");
+
+ # Let's find the status of the rule nodes
+ my %rulehash = ();
+ %rulehash = $config->listNodeStatus();
+ if ((scalar (keys %rulehash)) == 0) {
+ # no rules. flush the user rules.
+ # note that this clears the counters on the default DROP rule.
+ # we could delete rule one by one if those are important.
+ system("iptables -F $name");
+ system("iptables -A $name -j DROP");
+ next;
+ }
+
+ my $iptablesrule = 1;
+ foreach $rule (sort numerically keys %rulehash) {
+ #print "rule: $rule\t\t$rulehash{$rule}\n";
+
+ if ("$rulehash{$rule}" eq "static") {
+ my $node = new VyattaIpTablesRule;
+ $node->setupOrig("firewall name $name rule $rule");
+ if ($node->is_stateful()) {
+ $stateful = 1;
+ }
+ my $ipt_rules = $node->get_num_ipt_rules();
+ $iptablesrule += $ipt_rules;
+ } elsif ("$rulehash{$rule}" eq "added") {
+ # create a new iptables object of the current rule
+ my $node = new VyattaIpTablesRule;
+ $node->setup("firewall name $name rule $rule");
+ if ($node->is_stateful()) {
+ $stateful = 1;
+ }
+
+ #print "node print:\n";
+ #$node->print();
+ my ($err_str, @rule_strs) = $node->rule();
+ if (defined($err_str)) {
+ print STDERR "Firewall config error: $err_str\n";
+ exit 1;
+ }
+ foreach (@rule_strs) {
+ if (!defined) {
+ last;
+ }
+ print "iptables --insert $name $iptablesrule $_\n";
+ system ("iptables --insert $name $iptablesrule $_") == 0
+ || die "iptables error: $? - $_\n";
+ $iptablesrule++;
+ }
+ } elsif ("$rulehash{$rule}" eq "changed") {
+ # create a new iptables object of the current rule
+ my $oldnode = new VyattaIpTablesRule;
+ $oldnode->setupOrig("firewall name $name rule $rule");
+ my $node = new VyattaIpTablesRule;
+ $node->setup("firewall name $name rule $rule");
+ if ($node->is_stateful()) {
+ $stateful = 1;
+ }
+
+ my ($err_str, @rule_strs) = $node->rule();
+ if (defined($err_str)) {
+ print STDERR "Firewall config error: $err_str\n";
+ exit 1;
+ }
+
+ my $ipt_rules = $oldnode->get_num_ipt_rules();
+ for (1 .. $ipt_rules) {
+ print "iptables --delete $name $iptablesrule\n";
+ system ("iptables --delete $name $iptablesrule") == 0
+ || die "iptables error: $? - $rule\n";
+ }
+
+ foreach (@rule_strs) {
+ if (!defined) {
+ last;
+ }
+ print "iptables --insert $name $iptablesrule $_\n";
+ system ("iptables --insert $name $iptablesrule $_") == 0
+ || die "iptables error: $? - $rule_str\n";
+ $iptablesrule++;
+ }
+ } elsif ("$rulehash{$rule}" eq "deleted") {
+ my $node = new VyattaIpTablesRule;
+ $node->setupOrig("firewall name $name rule $rule");
+
+ my $ipt_rules = $node->get_num_ipt_rules();
+ for (1 .. $ipt_rules) {
+ print "iptables --delete $name $iptablesrule\n";
+ system ("iptables --delete $name $iptablesrule") == 0
+ || die "iptables error: $? - $rule\n";
+ }
+ }
+ }
+ }
+ if ($stateful) {
+ enable_fw_conntrack();
+ } else {
+ disable_fw_conntrack();
+ }
+}
+
+sub chain_configured($) {
+ my $chain = shift;
+
+ my $config = new VyattaConfig;
+ my %chains = ();
+ $config->setLevel("firewall name");
+ %chains = $config->listNodeStatus();
+
+ if (grep(/^$chain$/, (keys %chains))) {
+ if ($chains{$chain} ne "deleted") {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub update_ints() {
+ my ($action, $int_name, $direction, $chain) = @_;
+ my $interface = undef;
+
+ if (! defined $action || ! defined $int_name || ! defined $direction || ! defined $chain) {
+ return -1;
+ }
+
+ if ($action eq "update") {
+ # make sure chain exists
+ setup_chain($chain);
+ }
+
+ $_ = $direction;
+ my $dir_str = $direction;
+
+ CASE: {
+ /^in/ && do {
+ $direction = "FORWARD";
+ $interface = "--in-interface $int_name";
+ last CASE;
+ };
+
+ /^out/ && do {
+ $direction = "FORWARD";
+ $interface = "--out-interface $int_name";
+ last CASE;
+ };
+
+ /^local/ && do {
+ $direction = "INPUT";
+ $interface = "--in-interface $int_name";
+ last CASE;
+ };
+ }
+
+ my $grep = "| grep $int_name";
+ my $line = `iptables -L $direction -n -v --line-numbers | egrep ^[0-9] $grep`;
+ my ($num, $ignore, $ignore, $oldchain, $ignore, $ignore, $in, $out, $ignore, $ignore) = split /\s+/, $line;
+
+ if ("$action" eq "update") {
+ if (($num =~ /.+/) && (($dir_str eq "in" && $in eq $int_name)
+ || ($dir_str eq "out" && $out eq $int_name)
+ || ($dir_str eq "local"))) {
+ $action = "replace";
+ $rule = "--replace $direction $num $interface --jump $chain";
+ } else {
+ $rule = "--append $direction $interface --jump $chain";
+ }
+ }
+ else {
+ $rule = "--$action $direction $num";
+ }
+
+ print "iptables $rule\n";
+ $ret = system("iptables $rule");
+ if ($ret >> 8) {
+ exit 1;
+ }
+ if ($action eq "replace" || $action eq "delete") {
+ if (!chain_configured($oldchain)) {
+ if (!chain_referenced($oldchain)) {
+ delete_chain($oldchain);
+ }
+ }
+ }
+ return 0;
+}
+
+sub enable_fw_conntrack {
+ # potentially we can add rules in the FW_CONNTRACK chain to provide
+ # finer-grained control over which packets are tracked.
+ system("iptables -t raw -R FW_CONNTRACK 1 -j ACCEPT");
+}
+
+sub disable_fw_conntrack {
+ system("iptables -t raw -R FW_CONNTRACK 1 -j RETURN");
+}
+
+sub teardown_iptables() {
+ my @chains = `iptables -L -n`;
+ my $chain;
+
+ # $chain is going to look like this...
+ # Chain inbound (0 references)
+ foreach $chain (@chains) {
+ # chains start with Chain
+ if ($chain =~ s/^Chain//) {
+ # all we need to do is make sure this is a user chain
+ # by looking at the references keyword and then
+ if ($chain =~ /references/) {
+ ($chain) = split /\(/, $chain;
+ $chain =~ s/\s//g;
+ delete_chain("$chain");
+ }
+ }
+ }
+
+ # 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 "FW_CONNTRACK") {
+ system("iptables -t raw -D PREROUTING $num");
+ system("iptables -t raw -D OUTPUT $num");
+ system("iptables -t raw -F FW_CONNTRACK");
+ system("iptables -t raw -X FW_CONNTRACK");
+ last;
+ }
+ }
+}
+
+sub setup_iptables() {
+ teardown_iptables();
+ # by default, nothing is tracked (the last rule in raw/PREROUTING).
+ system("iptables -t raw -N FW_CONNTRACK");
+ system("iptables -t raw -A FW_CONNTRACK -j RETURN");
+ system("iptables -t raw -I PREROUTING 1 -j FW_CONNTRACK");
+ system("iptables -t raw -I OUTPUT 1 -j FW_CONNTRACK");
+ return 0;
+}
+
+sub setup_chain($) {
+ my $chain = shift;
+ my $configured = `iptables -n -L $chain 2>&1 | head -1`;
+
+ $_ = $configured;
+ if (!/^Chain $chain/) {
+ system("iptables --new-chain $chain") == 0 || die "iptables error: $chain --new-chain: $?\n";
+ system("iptables -A $chain -j DROP");
+ }
+}
+
+sub chain_referenced($) {
+ my $chain = shift;
+ my $line = `iptables -n -L $chain |head -n1`;
+ if ($line =~ m/^Chain $chain \((\d+) references\)$/) {
+ if ($1 > 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub delete_chain($) {
+ my $chain = shift;
+ my $configured = `iptables -n -L $chain 2>&1 | head -1`;
+
+ if ($configured =~ /^Chain $chain/) {
+ system("iptables --flush $chain") == 0 || die "iptables error: $chain --flush: $?\n";
+ if (!chain_referenced($chain)) {
+ system("iptables --delete-chain $chain") == 0 || die "iptables error: $chain --delete-chain: $?\n";
+ }
+ }
+}
+
+sub numerically { $a <=> $b; }
diff --git a/scripts/firewall/vyatta-show-firewall.pl b/scripts/firewall/vyatta-show-firewall.pl
new file mode 100755
index 0000000..241a03a
--- /dev/null
+++ b/scripts/firewall/vyatta-show-firewall.pl
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+
+use lib "/opt/vyatta/share/perl5/";
+use VyattaConfig;
+use VyattaIpTablesRule;
+use VyattaIpTablesAddressFilter;
+
+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)
+
+sub numerically { $a <=> $b; }
+
+sub show_chain {
+ my $chain = shift;
+ my $fh = shift;
+
+ open(STATS, "iptables -L $chain -vn |") or exit 1;
+ my @stats = ();
+ while (<STATS>) {
+ if (!/^\s*(\d+[KMG]?)\s+(\d+[KMG]?)\s/) {
+ next;
+ }
+ push @stats, ($1, $2);
+ }
+ close STATS;
+
+ print $fh "<opcommand name='firewallrules'><format type='row'>\n";
+ my $config = new VyattaConfig;
+ $config->setLevel("firewall name $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 VyattaIpTablesRule;
+ $rule->setupOrig("firewall name $chain rule $_");
+ my $ipt_rules = $rule->get_num_ipt_rules();
+ splice(@stats, 0, (($ipt_rules - 1) * 2));
+
+ if (defined($rule_num) && $rule_num != $_) {
+ next;
+ }
+ print $fh " <row>\n";
+ print $fh " <rule_number>$_</rule_number>\n";
+ print $fh " <pkts>$pkts</pkts>\n";
+ print $fh " <bytes>$bytes</bytes>\n";
+ $rule->outputXml($fh);
+ print $fh " </row>\n";
+ }
+ if (!defined($rule_num)) {
+ # dummy rule
+ print $fh " <row>\n";
+ print $fh " <rule_number>1025</rule_number>\n";
+ my $pkts = shift @stats;
+ my $bytes = shift @stats;
+ print $fh " <pkts>$pkts</pkts>\n";
+ print $fh " <bytes>$bytes</bytes>\n";
+ my $rule = new VyattaIpTablesRule;
+ $rule->setupDummy();
+ $rule->outputXml($fh);
+ print $fh " </row>\n";
+ }
+ print $fh "</format></opcommand>\n";
+}
+
+if ($chain_name eq "-all") {
+ my $config = new VyattaConfig;
+ $config->setLevel("firewall name");
+ my @chains = $config->listOrigNodes();
+ foreach (@chains) {
+ print "Firewall \"$_\":\n";
+ open(RENDER, "| /opt/vyatta/libexec/xorp/render_xml $xsl_file") or exit 1;
+ show_chain($_, *RENDER{IO});
+ close RENDER;
+ print "-" x 80 . "\n";
+ }
+} else {
+ open(RENDER, "| /opt/vyatta/libexec/xorp/render_xml $xsl_file") or exit 1;
+ show_chain($chain_name, *RENDER{IO});
+ close RENDER;
+}
+
+exit 0;
+