summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsarthurdev <965089+sarthurdev@users.noreply.github.com>2022-01-06 15:16:55 +0100
committersarthurdev <965089+sarthurdev@users.noreply.github.com>2022-01-06 16:17:34 +0100
commit6fc263b9cb71ca24dce60aec63aa453ef2b0000b (patch)
tree0835036feacf1322c1e47b72e928dfb4cf3a55ae
parent4df0cd1e64a33a7a0b47d226e983da4cd1c2a089 (diff)
downloadvyatta-conntrack-6fc263b9cb71ca24dce60aec63aa453ef2b0000b.tar.gz
vyatta-conntrack-6fc263b9cb71ca24dce60aec63aa453ef2b0000b.zip
conntrack: T4145: Remove `vyatta-cfg-firewall` dependency
-rw-r--r--Makefile.am6
-rw-r--r--debian/control1
-rw-r--r--lib/Vyatta/Conntrack/ConntrackUtil.pm4
-rw-r--r--lib/Vyatta/IpTables/AddressFilter.pm289
-rw-r--r--lib/Vyatta/IpTables/IpSet.pm554
-rw-r--r--lib/Vyatta/IpTables/Mgr.pm341
-rw-r--r--lib/Vyatta/IpTables/Rule.pm818
-rw-r--r--scripts/vyatta-conntrack-ignore.pl13
-rw-r--r--scripts/vyatta-conntrack-timeouts.pl14
-rw-r--r--scripts/vyatta-show-ignore.pl2
10 files changed, 2025 insertions, 17 deletions
diff --git a/Makefile.am b/Makefile.am
index d35ad8e..f0bbd54 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,7 @@
cfgdir = $(datadir)/vyatta-cfg/templates
opdir = $(datadir)/vyatta-op/templates
share_perl5dir = $(datarootdir)/perl5/Vyatta/Conntrack
+ipt_share_perl5dir = $(datarootdir)/perl5/Vyatta/IpTables
modprobedir = /etc/modprobe.d
vprefix = /opt/vyatta
@@ -18,6 +19,11 @@ share_perl5_DATA += lib/Vyatta/Conntrack/ConntrackUtil.pm
share_perl5_DATA += lib/Vyatta/Conntrack/RuleCT.pm
share_perl5_DATA += lib/Vyatta/Conntrack/RuleIgnore.pm
+ipt_share_perl5_DATA = lib/Vyatta/IpTables/Rule.pm
+ipt_share_perl5_DATA += lib/Vyatta/IpTables/AddressFilter.pm
+ipt_share_perl5_DATA += lib/Vyatta/IpTables/IpSet.pm
+ipt_share_perl5_DATA += lib/Vyatta/IpTables/Mgr.pm
+
sbin_SCRIPTS = scripts/vyatta-update-conntrack-log.pl
bin_sudo_usersdir = $(bindir)/sudo-users
bin_sudo_users_SCRIPTS = scripts/vyatta-show-conntrack.pl
diff --git a/debian/control b/debian/control
index 27d56f1..86f79b9 100644
--- a/debian/control
+++ b/debian/control
@@ -12,6 +12,7 @@ Depends: vyatta-cfg-system,
vyatta-op,
conntrack,
conntrackd,
+ libswitch-perl,
libxml-namespacesupport-perl,
libxml-sax-base-perl,
libxml-sax-perl,
diff --git a/lib/Vyatta/Conntrack/ConntrackUtil.pm b/lib/Vyatta/Conntrack/ConntrackUtil.pm
index 0ded3ef..daed392 100644
--- a/lib/Vyatta/Conntrack/ConntrackUtil.pm
+++ b/lib/Vyatta/Conntrack/ConntrackUtil.pm
@@ -50,7 +50,7 @@ our @EXPORT = qw(check_for_conntrack_hooks, process_protocols, check_and_add_hel
#returns one if any hook is present
sub check_for_conntrack_hooks {
- my @output = `sudo iptables -L -t raw`;
+ my @output = `sudo iptables-nft -L -t raw`;
foreach(@output) {
if (($_ =~ m/WEBPROXY_CONNTRACK/)) {
return 1;
@@ -68,7 +68,7 @@ sub check_for_conntrack_hooks {
sub
check_ct_helper_rules {
my $index;
- my $cthelper_chain = "VYATTA_CT_HELPER";
+ my $cthelper_chain = "VYOS_CT_HELPER";
foreach my $label ('PREROUTING', 'OUTPUT') {
$index = ipt_find_chain_rule($iptables_cmd, 'raw', $label, $cthelper_chain);
if (!defined($index)) {
diff --git a/lib/Vyatta/IpTables/AddressFilter.pm b/lib/Vyatta/IpTables/AddressFilter.pm
new file mode 100644
index 0000000..9b3be53
--- /dev/null
+++ b/lib/Vyatta/IpTables/AddressFilter.pm
@@ -0,0 +1,289 @@
+# Author: Vyatta <eng@vyatta.com>
+# Date: 2007
+# Description: IP tables address filter
+
+# **** License ****
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2006-2009 Vyatta, Inc.
+# All Rights Reserved.
+# **** End License ****
+
+package Vyatta::IpTables::AddressFilter;
+
+require Vyatta::Config;
+require Vyatta::IpTables::IpSet;
+use Vyatta::Misc qw(getPortRuleString);
+use Vyatta::TypeChecker;
+
+use strict;
+use warnings;
+
+my %_protocolswithports = (
+ tcp_udp => 1,
+
+ # 'tcp_udp' is to be allowed for nat and firewall rules only.
+ # features should have syntax checks for allowing or forbiding
+ # the use of 'tcp_udp' as protocol. to allow tcp_udp see syntax check
+ # in protocol/node.def for NAT rules and to forbid tcp_udp see syntax
+ # check in protocol/node.def for load-balancing rules
+ # when allowed : tcp_udp creates 2 iptable rules - one for tcp, other for udp
+ tcp => 1,
+ udp => 1,
+ 6 => 1,
+ 17 => 1,
+);
+
+my %fields = (
+ _srcdst => undef,
+ _range_start => undef,
+ _range_stop => undef,
+ _network => undef,
+ _address => undef,
+ _port => undef,
+ _protocol => undef,
+ _src_mac => undef,
+ _ip_version => undef,
+ _address_group => undef,
+ _network_group => undef,
+ _port_group => undef,
+);
+
+sub new {
+ my $that = shift;
+ my $class = ref($that) || $that;
+ my $self = {%fields,};
+
+ bless $self, $class;
+ return $self;
+}
+
+sub set_ip_version {
+ my ($self, $ip_version) = @_;
+
+ $self->{_ip_version} = $ip_version;
+}
+
+sub setup_base {
+ my ($self, $level, $func) = @_;
+ my $config = new Vyatta::Config;
+
+ $config->setLevel("$level");
+
+ # Default to IPv4.
+ $self->{_ip_version} = "ipv4";
+
+ # setup needed parent nodes
+ $self->{_srcdst} = $config->returnParent("..");
+ $self->{_protocol} = $config->$func(".. protocol");
+
+ # setup address filter nodes
+ $self->{_address} = $config->$func("address");
+ $self->{_network} = undef;
+ $self->{_range_start} = undef;
+ $self->{_range_stop} = undef;
+ if (defined($self->{_address})) {
+ if ($self->{_address} =~ /\//) {
+ $self->{_network} = $self->{_address};
+ $self->{_address} = undef;
+ } elsif ($self->{_address} =~ /^([^-]+)-([^-]+)$/) {
+ $self->{_range_start} = $1;
+ $self->{_range_stop} = $2;
+ $self->{_address} = undef;
+ }
+ }
+
+ $self->{_port} = $config->$func("port");
+ $self->{_src_mac} = $config->$func("mac-address");
+ $self->{_address_group} = $config->$func("group address-group");
+ $self->{_network_group} = $config->$func("group network-group");
+ $self->{_port_group} = $config->$func("group port-group");
+
+ return 0;
+}
+
+sub setup {
+ my ($self, $level) = @_;
+
+ $self->setup_base($level, 'returnValue');
+ return 0;
+}
+
+sub setupOrig {
+ my ($self, $level) = @_;
+
+ $self->setup_base($level, 'returnOrigValue');
+ 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: $self->{_port}\n" if defined $self->{_port};
+ print "protocol: $self->{_protocol}\n" if defined $self->{_protocol};
+ print "src-mac: $self->{_src_mac}\n" if defined $self->{_src_mac};
+
+ return 0;
+}
+
+sub rule {
+ my ($self) = @_;
+ my $rule = "";
+ my $can_use_port = 1;
+
+ my $addr_checker;
+ my $prefix_checker;
+ my $pure_addr_checker;
+ my $ip_term;
+ my $prefix_term;
+
+ if ($self->{_ip_version} eq "ipv4") {
+ # This is an IPv4 rule
+ $addr_checker = 'ipv4_negate';
+ $prefix_checker = 'ipv4net_negate';
+ $pure_addr_checker = 'ipv4';
+ $ip_term = "IPv4";
+ $prefix_term = "subnet";
+ } elsif ($self->{_ip_version} eq "ipv6") {
+ # This is an IPv6 rule
+ $addr_checker = 'ipv6_negate';
+ $prefix_checker = 'ipv6net_negate';
+ $pure_addr_checker = 'ipv6';
+ $ip_term = "IPv6";
+ $prefix_term = "prefix";
+ } else {
+ return (undef, "Invalid IP version: $self->{_ip_version}");
+ }
+
+ 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};
+ my $negate = '';
+ if ($str =~ /^\!(.*)$/) {
+ $str = $1;
+ $negate = '! ';
+ }
+ $rule .= "-m mac $negate --mac-source $str ";
+ }
+
+ my %group_ok;
+ foreach my $group_type ('address', 'network', 'port') {
+ $group_ok{$group_type} = 1;
+ }
+
+ # set the address filter parameters
+ if (defined($self->{_network})) {
+ my $str = $self->{_network};
+ return (undef, "\"$str\" is not a valid $ip_term $prefix_term")
+ if (!Vyatta::TypeChecker::validateType($prefix_checker, $str, 1));
+ my $negate = '';
+ if ($str =~ /^\!(.*)$/) {
+ $str = $1;
+ $negate = '! ';
+ }
+ $rule .= "$negate --$self->{_srcdst} $str ";
+ $group_ok{network} = 0;
+ } elsif (defined($self->{_address})) {
+ my $str = $self->{_address};
+ return (undef, "\"$str\" is not a valid $ip_term address")
+ if (!Vyatta::TypeChecker::validateType($addr_checker, $str, 1));
+ my $negate = '';
+ if ($str =~ /^\!(.*)$/) {
+ $str = $1;
+ $negate = '! ';
+ }
+ $rule .= "$negate --$self->{_srcdst} $str ";
+ $group_ok{address} = 0;
+ } elsif ((defined $self->{_range_start}) && (defined $self->{_range_stop})) {
+ my $start = $self->{_range_start};
+ my $stop = $self->{_range_stop};
+ return (undef, "\"$start-$stop\" is not a valid IP range")
+ if ( !Vyatta::TypeChecker::validateType($addr_checker, $start, 1)
+ || !Vyatta::TypeChecker::validateType($pure_addr_checker, $stop, 1));
+ my $negate = '';
+ if ($self->{_range_start} =~ /^!(.*)$/) {
+ $start = $1;
+ $negate = '! ';
+ }
+ if ("$self->{_srcdst}" eq "source") {
+ $rule .= ("-m iprange $negate --src-range $start-$self->{_range_stop} ");
+ }elsif ("$self->{_srcdst}" eq "destination") {
+ $rule .= ("-m iprange $negate --dst-range $start-$self->{_range_stop} ");
+ }
+ $group_ok{address} = 0;
+ $group_ok{network} = 0;
+ }
+
+ $group_ok{port} = 0 if defined $self->{_port};
+ my ($port_str, $port_err)= getPortRuleString($self->{_port}, $can_use_port,($self->{_srcdst} eq "source") ? "s" : "d",$self->{_protocol});
+ return (undef, $port_err) if (!defined($port_str));
+ $rule .= $port_str;
+ # Handle groups last so we can check $group_ok
+ my %group_used = ('address' => 0, 'network' => 0);
+ foreach my $group_type ('address', 'network', 'port') {
+ my $var_name = '_' . $group_type . '_group';
+ if (defined($self->{$var_name})) {
+ $group_used{$group_type} = 1;
+ my $name = $self->{$var_name};
+ if (!$group_ok{$group_type}) {
+ return (undef, "Can't mix $self->{_srcdst} $group_type group [$name] and $group_type");
+ }
+ my $group = new Vyatta::IpTables::IpSet($name, $group_type);
+ my ($set_rule, $err_str) = $group->rule($self->{_srcdst});
+ return ($err_str,) if !defined $set_rule;
+ $rule .= $set_rule;
+ }
+ }
+ if ($group_used{address} and $group_used{network}) {
+ return (undef,"Can't combine network and address group for $self->{_srcdst}\n");
+ }
+ return ($rule, undef);
+}
+
+sub outputXmlElem {
+ my ($name, $value, $fh) = @_;
+ return if !defined $value;
+ print $fh " <$name>$value</$name>\n";
+}
+
+sub outputXml {
+ my ($self, $prefix, $fh) = @_;
+ if ( !defined($self->{_address})
+ && !defined($self->{_network})
+ && !defined($self->{_range_start})
+ && !defined($self->{_range_stop}))
+ {
+ if (($self->{_ip_version} eq "ipv4")) {
+ $self->{_address} = "0.0.0.0/0";
+ } else {
+ $self->{_address} = "::/0";
+ }
+ }
+ 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", $self->{_port}, $fh);
+}
+
+1;
diff --git a/lib/Vyatta/IpTables/IpSet.pm b/lib/Vyatta/IpTables/IpSet.pm
new file mode 100644
index 0000000..d7a014a
--- /dev/null
+++ b/lib/Vyatta/IpTables/IpSet.pm
@@ -0,0 +1,554 @@
+#
+# Module: IpSet.pm
+#
+# **** License ****
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2009-2010 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: Stig Thormodsrud
+# Date: January 2009
+# Description: vyatta interface to ipset
+#
+# **** End License ****
+#
+
+package Vyatta::IpTables::IpSet;
+
+use Vyatta::Config;
+use Vyatta::TypeChecker;
+use Vyatta::Misc;
+use NetAddr::IP;
+
+use strict;
+use warnings;
+
+my %fields = (
+ _name => undef,
+ _type => undef, # vyatta group type, not ipset type
+ _family => undef,
+ _exists => undef,
+ _negate => undef,
+ _debug => undef,
+);
+
+our %grouptype_hash = (
+ 'address' => 'hash:ip',
+ 'network' => 'hash:net',
+ 'port' => 'bitmap:port'
+);
+
+my $logger = 'logger -t IpSet.pm -p local0.warn --';
+
+# Currently we restrict an address range to a /24 even
+# though ipset would support a /16. The main reason is
+# due to the long time it takes to make that many calls
+# to add each individual member to the set.
+my $addr_range_mask = 24;
+my $lockfile = "/opt/vyatta/config/.lock";
+
+# remove lock file to avoid commit blockade on interrupt
+# like CTRL+C.
+sub INT_handler {
+ my $rc = system("sudo rm -f $lockfile >>/dev/null");
+ exit(0);
+}
+
+$SIG{'INT'} = 'INT_handler';
+
+sub new {
+ my ($that, $name, $type, $family) = @_;
+
+ my $class = ref($that) || $that;
+ my $self = {%fields,};
+ if ($name =~ m/^!/) {
+ $self->{_negate} = 1;
+ $name =~ s/^!(.*)$/$1/;
+ }
+ $self->{_name} = $name;
+ $self->{_type} = $type;
+ $self->{_family} = $family;
+
+ bless $self, $class;
+ return $self;
+}
+
+sub debug {
+ my ($self, $onoff) = @_;
+
+ $self->{_debug} = undef;
+ $self->{_debug} = 1 if $onoff eq "on";
+}
+
+sub run_cmd {
+ my ($self, $cmd) = @_;
+
+ my $rc = system("sudo $cmd");
+ if (defined $self->{_debug}) {
+ my $func = (caller(1))[3];
+ system("$logger [$func] [$cmd] = [$rc]");
+ }
+ return $rc;
+}
+
+sub exists {
+ my ($self) = @_;
+
+ return 1 if defined $self->{_exists};
+ return 0 if !defined $self->{_name};
+ my $cmd = "ipset -L $self->{_name} > /dev/null 2>&1";
+ my $rc = $self->run_cmd($cmd);
+ if ($rc eq 0) {
+ $self->{_exists} = 1;
+ $self->get_type() if !defined $self->{_type};
+ }
+ return $rc ? 0 : 1;
+}
+
+sub get_type {
+ my ($self) = @_;
+
+ return $self->{_type} if defined $self->{_type};
+ return if !$self->exists();
+ my @lines = `ipset -L $self->{_name}`;
+ my $type;
+ foreach my $line (@lines) {
+ if ($line =~ /^Type:\s+([\w:]+)$/) {
+ $type = $1;
+ last;
+ }
+ }
+ return if !defined $type;
+ foreach my $vtype (keys(%grouptype_hash)) {
+ if ($grouptype_hash{$vtype} eq $type) {
+ $self->{_type} = $vtype;
+ last;
+ }
+ }
+ return $self->{_type};
+}
+
+sub get_family {
+ my ($self) = @_;
+ return $self->{_family} if defined $self->{_family};
+ return if !$self->exists();
+ my @lines = `ipset -L $self->{_name}`;
+ my $family;
+ foreach my $line (@lines) {
+ if ($line =~ /^Header: family (\w+) hashsize/) {
+ $family = $1;
+ $self->{_family} = $family;
+ last;
+ } elsif ($line =~ /^Type: bitmap:port$/){
+ $self->{_family} = "inet";
+ last;
+ }
+ }
+ return $self->{_family};
+}
+
+sub alphanum_split {
+ my ($str) = @_;
+ my @list = split m/(?=(?<=\D)\d|(?<=\d)\D)/, $str;
+ return @list;
+}
+
+sub natural_order {
+ my ($a, $b) = @_;
+ my @a = alphanum_split($a);
+ my @b = alphanum_split($b);
+
+ while (@a && @b) {
+ my $a_seg = shift @a;
+ my $b_seg = shift @b;
+ my $val;
+ if (($a_seg =~ /\d/) && ($b_seg =~ /\d/)) {
+ $val = $a_seg <=> $b_seg;
+ } else {
+ $val = $a_seg cmp $b_seg;
+ }
+ if ($val != 0) {
+ return $val;
+ }
+ }
+ return @a <=> @b;
+}
+
+sub get_members {
+ my ($self) = @_;
+
+ my @members = ();
+ return @members if !$self->exists();
+
+ my @lines = `ipset -L $self->{_name} -s`;
+ foreach my $line (@lines) {
+ push @members, $line if $line =~ /^\d/;
+ }
+ if ($self->{_type} ne 'port') {
+ @members = sort {natural_order($a,$b)} @members;
+ }
+ return @members;
+}
+
+sub create {
+ my ($self) = @_;
+
+ return "Error: undefined group name" if !defined $self->{_name};
+ return "Error: undefined group type" if !defined $self->{_type};
+ return if $self->exists(); # treat as nop if already exists
+
+ my $ipset_param = $grouptype_hash{$self->{_type}};
+ return "Error: invalid group type\n" if !defined $ipset_param;
+
+ my $cmd = "ipset -N $self->{_name} $ipset_param family $self->{_family}";
+
+ if ($self->{_type} eq 'port') {
+ $ipset_param .= ' --from 1 --to 65535';
+ $cmd = "ipset -N $self->{_name} $ipset_param";
+ }
+
+ my $rc = $self->run_cmd($cmd);
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return; # undef
+}
+
+sub references {
+ my ($self) = @_;
+
+ return 0 if !$self->exists();
+ my @lines = `ipset -L $self->{_name}`;
+ foreach my $line (@lines) {
+ if ($line =~ /^References:\s+(\d+)$/) {
+ return $1;
+ }
+ }
+ return 0;
+}
+
+sub flush {
+ my ($self) = @_;
+ my $cmd = "ipset flush $self->{_name}";
+ my $rc = $self->run_cmd($cmd);
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return;
+}
+
+sub rebuild_ipset() {
+ my ($self) = @_;
+ my $name = $self->{_name};
+ my $type = $self->{_type};
+ my $config = new Vyatta::Config;
+
+ my @members = $config->returnOrigValues("firewall group $type-group $name $type");
+
+ # go through the firewall group config with this name,
+ my $member;
+ foreach $member (@members) {
+ $self->add_member($member, $name);
+ }
+}
+
+sub reset_ipset_named {
+ my ($self) = @_;
+ my $name = $self->{_name};
+
+ # flush the ipset group first, then re-build the group from configuration
+ $self->flush();
+
+ $self->rebuild_ipset();
+}
+
+sub reset_ipset_all {
+ my $config = new Vyatta::Config;
+ my @pgroups = $config->listOrigNodes("firewall group port-group");
+ my @adgroups = $config->listOrigNodes("firewall group address-group");
+ my @nwgroups = $config->listOrigNodes("firewall group network-group");
+ my $group;
+
+ foreach $group (@pgroups) {
+ my $grp = new Vyatta::IpTables::IpSet($group, "port");
+ $grp->reset_ipset_named();
+ }
+ foreach $group (@adgroups) {
+ my $grp = new Vyatta::IpTables::IpSet($group, "address");
+ $grp->reset_ipset_named();
+ }
+ foreach $group (@nwgroups) {
+ my $grp = new Vyatta::IpTables::IpSet($group, "network");
+ $grp->reset_ipset_named();
+ }
+}
+
+sub reset_ipset {
+
+ # main function to do the reset operation
+ my ($self) = @_;
+ my $name = $self->{_name};
+
+ my $lockcmd = "touch $lockfile";
+ my $unlockcmd = "rm -f $lockfile";
+ $self->run_cmd($lockcmd);
+
+ # reset one rule or all?
+ if ($name eq 'all') {
+ $self->reset_ipset_all();
+ } else {
+ $self->reset_ipset_named();
+ }
+ my $rc = $self->run_cmd($unlockcmd);
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return; # undef
+}
+
+sub delete {
+ my ($self) = @_;
+
+ return "Error: undefined group name" if !defined $self->{_name};
+ return "Error: group [$self->{_name}] doesn't exists\n" if !$self->exists();
+
+ my $refs = $self->references();
+ if ($refs > 0) {
+
+ # still in use
+ if (scalar($self->get_firewall_references(1)) > 0) {
+
+ # still referenced by config
+ return "Error: group [$self->{_name}] still in use.\n";
+ }
+
+ # not referenced by config => simultaneous deletes. just do flush.
+ return $self->flush();
+ }
+
+ my $cmd = "ipset -X $self->{_name}";
+ my $rc = $self->run_cmd($cmd);
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return; # undef
+}
+
+sub check_member_address {
+ my $member = shift;
+
+ if (!Vyatta::TypeChecker::validateType('ipv4', $member, 1)) {
+ return "Error: [$member] isn't valid IPv4 address\n";
+ }
+ if ($member eq '0.0.0.0') {
+ return "Error: zero IP address not valid in address-group\n";
+ }
+ return;
+}
+
+sub check_member {
+ my ($self, $member) = @_;
+
+ return "Error: undefined group name" if !defined $self->{_name};
+ return "Error: undefined group type" if !defined $self->{_type};
+
+ # We can't call $self->member_exists() here since this is a
+ # syntax check and the group may not have been created yet
+ # if there hasn't been a commit yet on this group. Move the
+ # exists check to $self->add_member().
+
+ if ($self->{_type} eq 'address') {
+ if ($member =~ /^([^-]+)-([^-]+)$/) {
+ foreach my $address ($1, $2) {
+ my $rc = check_member_address($address);
+ return $rc if defined $rc;
+ }
+ my $start_ip = new NetAddr::IP($1);
+ my $stop_ip = new NetAddr::IP($2);
+ if ($stop_ip <= $start_ip) {
+ return "Error: $1 must be less than $2\n";
+ }
+ my $start_net = new NetAddr::IP("$1/$addr_range_mask");
+ if (!$start_net->contains($stop_ip)) {
+ return "Error: address range must be within /$addr_range_mask\n";
+ }
+
+ } else {
+ my $rc = check_member_address($member);
+ return $rc if defined $rc;
+ }
+ } elsif ($self->{_type} eq 'network') {
+ if (!Vyatta::TypeChecker::validateType('ipv4net', $member, 1)) {
+ return "Error: [$member] isn't a valid IPv4 network\n";
+ }
+ if ($member =~ /([\d.]+)\/(\d+)/) {
+ my ($net, $mask) = ($1, $2);
+ return "Error: 0.0.0.0/0 invalid in network-group\n"
+ if (($net eq '0.0.0.0') and ($mask == 0));
+ return "Error: invalid mask [$mask] - must be between 1-31\n"
+ if (($mask < 1) or ($mask > 31));
+ } else {
+ return "Error: Invalid network group [$member]\n";
+ }
+ } elsif ($self->{_type} eq 'port') {
+ my ($success, $err) = (undef, "invalid port [$member]");
+ if ($member =~ /^(\d+)-(\d+)$/) {
+ ($success, $err) = Vyatta::Misc::isValidPortRange($member, '-');
+ } elsif ($member =~ /^\d/) {
+ ($success, $err) = Vyatta::Misc::isValidPortNumber($member);
+ } else {
+ ($success, $err) = Vyatta::Misc::isValidPortName($member);
+ }
+ return "Error: $err\n" if defined $err;
+ } else {
+ return "Error: invalid set type [$self->{_type}]";
+ }
+ return; #undef
+}
+
+sub member_exists {
+ my ($self, $member) = @_;
+
+ # check if a member is a port range and roll through all members it is
+ if ($member =~ /([\d]+)-([\d]+)/) {
+ foreach my $port ($1..$2) {
+ # test port with ipset
+ my $cmd = "ipset -T $self->{_name} $port -q";
+ my $rc = $self->run_cmd($cmd);
+ # return true if port was found
+ return 1 if !$rc;
+ }
+ # return false if ports was not found in set
+ return 0;
+ } else {
+ my $cmd = "ipset -T $self->{_name} $member -q";
+ my $rc = $self->run_cmd($cmd);
+ return $rc ? 0 : 1;
+ }
+}
+
+
+sub add_member {
+ my ($self, $member, $alias, $hyphenated_port) = @_;
+
+ return "Error: undefined group name" if !defined $self->{_name};
+ return "Error: group [$self->{_name}] doesn't exists\n" if !$self->exists();
+
+ if ($self->member_exists($member)) {
+ my $set_name = $alias;
+ $set_name = $self->{_name} if !defined $set_name;
+ return "Error: member [$member] already exists in [$set_name]\n";
+ }
+ my $cmd = "ipset -A $self->{_name} $member";
+ my $rc = $self->run_cmd($cmd);
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return; # undef
+}
+
+sub delete_member_range {
+ my ($self, $start, $stop) = @_;
+
+ if ($self->{_type} eq 'port') {
+ foreach my $member ($start .. $stop) {
+ my $rc = $self->delete_member($member);
+ return $rc if defined $rc;
+ }
+ } elsif ($self->{_type} eq 'address') {
+ my $start_ip = new NetAddr::IP("$start/$addr_range_mask");
+ my $stop_ip = new NetAddr::IP("$stop/$addr_range_mask");
+ for (; $start_ip <= $stop_ip; $start_ip++) {
+ my $rc = $self->delete_member($start_ip->addr());
+ return $rc if defined $rc;
+ last if $start_ip->cidr() eq $start_ip->broadcast();
+ }
+ }
+ return;
+}
+
+sub delete_member {
+ my ($self, $member, $hyphenated_port) = @_;
+
+ return "Error: undefined group name" if !defined $self->{_name};
+ return "Error: group [$self->{_name}] doesn't exists\n" if !$self->exists();
+
+ # service name or port name may contain a hyphen, which needs to be escaped
+ # using square brackets in ipset, to avoid confusion with port ranges
+ if (($member =~ /^([^-]+)-([^-]+)$/) and ((defined($hyphenated_port)) and ($hyphenated_port eq 'false'))) {
+ return $self->delete_member_range($1, $2);
+ }
+
+ if (!$self->member_exists($member)) {
+ return "Error: member [$member] doesn't exists in [$self->{_name}]\n";
+ }
+ my $cmd = "ipset -D $self->{_name} $member";
+ my $rc = $self->run_cmd($cmd);
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return; # undef
+}
+
+sub get_description {
+ my ($self) = @_;
+
+ return if !$self->exists();
+ my $config = new Vyatta::Config;
+ my $group_type = "$self->{_type}-group";
+ $config->setLevel("firewall group $group_type $self->{_name}");
+ return $config->returnOrigValue('description');
+}
+
+sub get_firewall_references {
+ my ($self, $working) = @_;
+ my ($lfunc, $vfunc) = qw(listOrigNodes returnOrigValue);
+ if ($working) {
+ ($lfunc, $vfunc) = qw(listNodes returnValue);
+ }
+ my @fw_refs = ();
+ return @fw_refs if !$self->exists();
+ my $config = new Vyatta::Config;
+ foreach my $tree ('name', 'ipv6-name', 'modify') {
+ my $path = "firewall $tree ";
+ $config->setLevel($path);
+ my @names = $config->$lfunc();
+ foreach my $name (@names) {
+ my $name_path = "$path $name rule ";
+ $config->setLevel($name_path);
+ my @rules = $config->$lfunc();
+ foreach my $rule (@rules) {
+ foreach my $dir ('source', 'destination') {
+ my $rule_path = "$name_path $rule $dir group";
+ $config->setLevel($rule_path);
+ my $group_type = "$self->{_type}-group";
+ my $value = $config->$vfunc($group_type);
+ $value =~ s/^!(.*)$/$1/ if defined $value;
+ if (defined $value and $self->{_name} eq $value) {
+ push @fw_refs, "$name-$rule-$dir";
+ }
+ } # foreach $dir
+ } # foreach $rule
+ } # foreach $name
+ } # foreach $tree
+ return @fw_refs;
+}
+
+sub rule {
+ my ($self, $direction) = @_;
+
+ if (!$self->exists()) {
+ my $name = $self->{_name};
+ $name = 'undefined' if !defined $name;
+ return (undef, "Undefined group [$name]");
+ }
+
+ my $srcdst;
+ my $grp = $self->{_name};
+ $srcdst = 'src' if $direction eq 'source';
+ $srcdst = 'dst' if $direction eq 'destination';
+
+ return (undef, "Invalid direction [$direction]") if !defined $srcdst;
+ my $opt = '';
+ $opt = '!' if $self->{_negate};
+ return (" -m set $opt --match-set $grp $srcdst ",);
+}
+
+1;
diff --git a/lib/Vyatta/IpTables/Mgr.pm b/lib/Vyatta/IpTables/Mgr.pm
new file mode 100644
index 0000000..39a03f1
--- /dev/null
+++ b/lib/Vyatta/IpTables/Mgr.pm
@@ -0,0 +1,341 @@
+#
+# Module: Vyatta::IpTables::Mgr.pm
+#
+# **** License ****
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2010 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: Stig Thormodsrud
+# Date: June 2010
+# Description: common iptables routines
+#
+# **** End License ****
+#
+
+package Vyatta::IpTables::Mgr;
+
+use strict;
+use warnings;
+
+use base 'Exporter';
+our @EXPORT = qw(ipt_find_chain_rule ipt_enable_conntrack
+ ipt_disable_conntrack count_iptables_rules
+ chain_referenced ipt_get_queue_target
+ run_ipt_cmd create_ipt_chain delete_ipt_chain
+ flush_ipt_chain insert_ipt_rule append_ipt_rule
+ delete_ipt_rule delete_ipt_rulenum ipt_find_comment_rule);
+
+## TODO - in future, we could use perl's libiptc module instead of
+## running system commands in the following function for iptables.
+## However, that would need integrating the libiptc module into the system
+## and also adding other functionality to it, including IPv6 support.
+sub run_ipt_cmd {
+ my ($cmd) = shift;
+ my $error = system("$cmd");
+
+ my $debug = "false";
+ my $syslog = "false";
+ my $logger = "sudo logger -t Vyatta::IPTables::Mgr -p local0.warn --";
+
+ if ($syslog eq "true") {
+ my $func = (caller(1))[3];
+ system("$logger [$func] [$cmd] = [$error]");
+ }
+ if ($debug eq "true") {
+ my $func = (caller(1))[3];
+ print "\n[$func] [$cmd] = [$error]";
+ }
+ return $error;
+}
+
+sub create_ipt_chain {
+ my ($ipt_cmd, $table, $chain) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -N $chain";
+ $error = run_ipt_cmd($cmd);
+ return "create_ipt_chain [$ipt_cmd -t $table -N $chain] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+sub flush_ipt_chain {
+ my ($ipt_cmd, $table, $chain) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -F $chain";
+ $error = run_ipt_cmd($cmd);
+ return "flush_ipt_chain [$ipt_cmd -t $table -F $chain] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+sub delete_ipt_chain {
+ my ($ipt_cmd, $table, $chain) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -X $chain";
+ $error = run_ipt_cmd($cmd);
+ return "delete_ipt_chain [$ipt_cmd -t $table -X $chain] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+sub insert_ipt_rule {
+ my ($ipt_cmd, $table, $chain, $jump_target, $insert_num, $append_options) = @_;
+ my ($cmd, $error);
+
+ $insert_num = 1 if (!defined $insert_num);
+ $cmd = "sudo $ipt_cmd -t $table -I $chain $insert_num -j $jump_target ";
+ $cmd .= $append_options if defined $append_options;
+ $error = run_ipt_cmd($cmd);
+ return "insert_ipt_rule [$ipt_cmd -t $table -I $chain $insert_num -j $jump_target] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+sub append_ipt_rule {
+ my ($ipt_cmd, $table, $chain, $jump_target, $append_options) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -A $chain -j $jump_target ";
+ $cmd .= $append_options if defined $append_options;
+ $error = run_ipt_cmd($cmd);
+ return "append_ipt_rule [$ipt_cmd -t $table -A $chain -j $jump_target] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+# delete rule based on jump target. should only be used if jump_target is unique in that chain
+sub delete_ipt_rule {
+ my ($ipt_cmd, $table, $chain, $jump_target) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -D $chain -j $jump_target";
+ $error = run_ipt_cmd($cmd);
+ return "delete_ipt_rule [$ipt_cmd -t $table -D $chain -j $jump_target] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+# delete rule based on rule number
+sub delete_ipt_rulenum {
+ my ($ipt_cmd, $table, $chain, $delete_num) = @_;
+ my ($cmd, $error);
+
+ $cmd = "sudo $ipt_cmd -t $table -D $chain $delete_num";
+ $error = run_ipt_cmd($cmd);
+ return "delete_ipt_rulenum [$ipt_cmd -t $table -D $chain $delete_num] failed: [error code - $error]" if $error;
+
+ return;
+}
+
+# searches and returns first found rule based on jump target
+sub ipt_find_chain_rule {
+ my ($iptables_cmd, $table, $chain, $search) = @_;
+
+ my ($num, $chain2) = (undef, undef);
+ my $cmd = "$iptables_cmd -t $table -L $chain -vn --line";
+ my @lines = `sudo $cmd 2> /dev/null | egrep ^[0-9]`;
+ if (scalar(@lines) < 1) {
+ return;
+ }
+ foreach my $line (@lines) {
+ ($num, undef, undef, $chain2) = split /\s+/, $line;
+ last if $chain2 eq $search;
+ ($num, $chain2) = (undef, undef);
+ }
+
+ return $num if defined $num;
+ return;
+}
+
+# searches and returns first found rule based on matching text in rule comment
+sub ipt_find_comment_rule {
+ my ($iptables_cmd, $table, $chain, $search) = @_;
+
+ my $cmd = "$iptables_cmd -t $table -L $chain -vn --line";
+ my @lines = `sudo $cmd 2> /dev/null | egrep ^[0-9]`;
+ if (scalar(@lines) < 1) {
+ return;
+ }
+
+ my ($num, $rule_txt, $comment) = (undef, undef);
+ foreach my $line (@lines) {
+ ($rule_txt, $comment) = split /\/\*/, $line;
+
+ #print "rule_txt : $rule_txt, comment : $comment\n";
+ if (defined $comment && $comment =~ m/$search/) {
+
+ #print "found $search in $comment \n";
+ ($num) = split /\s+/, $rule_txt if defined $rule_txt;
+ return $num;
+ }
+ ($rule_txt, $comment) = (undef, undef);
+ }
+ return;
+}
+my %conntrack_hook_hash =(
+ 'PREROUTING' => 'VYATTA_CT_PREROUTING_HOOK',
+ 'OUTPUT' => 'VYATTA_CT_OUTPUT_HOOK',
+);
+
+sub ipt_enable_conntrack {
+ my ($iptables_cmd, $chain) = @_;
+ my $hookCtHelper = 'false';
+
+ if (($chain eq 'FW_CONNTRACK') or ($chain eq 'NAT_CONNTRACK')) {
+ $hookCtHelper = 'true';
+ }
+
+ system("sudo $iptables_cmd -t raw -L $chain -n >& /dev/null");
+ if ($? >> 8) {
+
+ # chain does not exist yet. set up conntrack.
+ system("sudo $iptables_cmd -t raw -N $chain");
+ system("sudo $iptables_cmd -t raw -A $chain -j ACCEPT");
+
+ foreach my $label ('PREROUTING', 'OUTPUT') {
+ my $index;
+ my $conntrack_hook = $conntrack_hook_hash{$label};
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, $conntrack_hook);
+ if (!defined($index)) {
+ print "Error: unable to find [$label] [$conntrack_hook]\n";
+ return 1;
+ }
+ $index++;
+ system("sudo $iptables_cmd -t raw -I $label $index -j $chain");
+
+ if ($hookCtHelper eq 'true') {
+
+ # we want helper hook only for Firewall / NAT.
+ $conntrack_hook = "VYATTA_CT_HELPER";
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, $conntrack_hook);
+ if (!defined($index)) {
+
+ # this index does not change now but maybe later we change it, so being defensive.
+ my $cttimeout_index = ipt_find_chain_rule($iptables_cmd, 'raw', $label, "VYATTA_CT_TIMEOUT");
+ if (defined($cttimeout_index)) {
+
+ # $cttimeout_index++; fixing 8173
+ # currently we have cttimeout at 1 index, it might change in future.
+ # helper chain should be before timeout chain
+ system("sudo $iptables_cmd -t raw -I $label $cttimeout_index -j VYATTA_CT_HELPER");
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+sub remove_cthelper_hook {
+ my ($iptables_cmd, $label, $chain) =@_;
+
+ #label is PREROUTING / OUTPUT, chain is FW_CONNTRACK/NAT_CONNTRACK etc.
+ my $index;
+
+ # find if we need to remove VYATTA_CT_HELPER
+ my $cthelper_index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, 'VYATTA_CT_HELPER');
+ if(!defined($cthelper_index)) {
+
+ # not an error: this hook is only for FW / NAT
+ return 0;
+ }
+
+ # if this chain is FW_CONNTRACK, look if NAT is using it, else remove
+ if ($chain eq 'FW_CONNTRACK') {
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, 'NAT_CONNTRACK');
+ if (!defined($index)) {
+
+ # NAT, only other user of helpers, not enabled, can remove VYATTA_CT_HELPER
+ system("sudo $iptables_cmd -t raw -D $label $cthelper_index");
+ return 0;
+ }
+ } elsif ($chain eq 'NAT_CONNTRACK') {
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, 'FW_CONNTRACK');
+ if (!defined($index)) {
+
+ # Firewall, only other user of helpers, not enabled, can remove VYATTA_CT_HELPER
+ system("sudo $iptables_cmd -t raw -D $label $cthelper_index");
+ return 0;
+ }
+ }
+}
+
+sub ipt_disable_conntrack {
+ my ($iptables_cmd, $chain) = @_;
+
+ my $debug = 0;
+ my @lines;
+ foreach my $label ('PREROUTING', 'OUTPUT') {
+ my $index;
+ my $conntrack_hook = $conntrack_hook_hash{$label};
+ $index = ipt_find_chain_rule($iptables_cmd, 'raw',$label, $chain);
+ if (!defined($index)) {
+ if ($debug > 0) {
+ print "Error: ipt_disable_conntrack failed to find ". "[$label][$chain]\n";
+ }
+ return 1;
+ }
+ system("sudo $iptables_cmd -t raw -D $label $index");
+
+ remove_cthelper_hook($iptables_cmd, $label, $chain);
+ }
+
+ system("sudo $iptables_cmd -t raw -F $chain >& /dev/null");
+ system("sudo $iptables_cmd -t raw -X $chain >& /dev/null");
+
+ return 0;
+}
+
+my %queue_target_hash =(
+ 'SNORT' => 'NFQUEUE',
+ 'VG_HTTPS' => 'NFQUEUE --queue-num 1',
+);
+
+sub ipt_get_queue_target {
+ my ($app) = @_;
+
+ my $target = $queue_target_hash{$app};
+ return $target;
+}
+
+sub count_iptables_rules {
+ my ($iptables_cmd, $table, $chain) = @_;
+
+ my $cmd = "$iptables_cmd -t $table -L $chain -n --line";
+ my @lines = `sudo $cmd 2> /dev/null`;
+ my $cnt = 0;
+ foreach my $line (@lines) {
+ $cnt++ if $line =~ /^\d/;
+ }
+ return $cnt;
+}
+
+sub chain_referenced {
+ my ($table, $chain, $iptables_cmd) = @_;
+
+ my $cmd = "$iptables_cmd -t $table -n -L $chain";
+ my $line = `sudo $cmd 2>/dev/null |head -n1`;
+ chomp $line;
+ my $found = 0;
+ if ($line =~ m/^Chain $chain \((\d+) references\)$/) {
+ if ($1 > 0) {
+ $found = 1;
+ }
+ }
+ return $found;
+}
+
+1;
diff --git a/lib/Vyatta/IpTables/Rule.pm b/lib/Vyatta/IpTables/Rule.pm
new file mode 100644
index 0000000..5f1e0a4
--- /dev/null
+++ b/lib/Vyatta/IpTables/Rule.pm
@@ -0,0 +1,818 @@
+package Vyatta::IpTables::Rule;
+
+use strict;
+use Vyatta::Config;
+use Vyatta::IpTables::Mgr;
+require Vyatta::IpTables::AddressFilter;
+
+my $src = new Vyatta::IpTables::AddressFilter;
+my $dst = new Vyatta::IpTables::AddressFilter;
+
+my %fields = (
+ _name => undef,
+ _rule_number => undef,
+ _protocol => undef,
+ _state => {
+ _established => undef,
+ _new => undef,
+ _related => undef,
+ _invalid => undef,
+ },
+ _action => undef,
+ _log => undef,
+ _tcp_flags => undef,
+ _icmp_code => undef,
+ _icmp_type => undef,
+ _icmp_name => undef,
+ _icmpv6_type => undef,
+ _mod_mark => undef,
+ _mod_table => undef,
+ _mod_dscp => undef,
+ _mod_tcpmss => undef,
+ _ipsec => undef,
+ _non_ipsec => undef,
+ _frag => undef,
+ _non_frag => undef,
+ _recent_time => undef,
+ _recent_cnt => undef,
+ _p2p => {
+ _all => undef,
+ _apple => undef,
+ _bit => undef,
+ _dc => undef,
+ _edk => undef,
+ _gnu => undef,
+ _kazaa => undef,
+ },
+ _time => {
+ _startdate => undef,
+ _stopdate => undef,
+ _starttime => undef,
+ _stoptime => undef,
+ _monthdays => undef,
+ _weekdays => undef,
+ _utc => undef,
+ },
+ _limit => {
+ _rate => undef,
+ _burst => undef,
+ },
+ _disable => undef,
+ _ip_version => undef,
+ _comment => undef,
+ _hop_limit => {
+ _eq => undef,
+ _lt => undef,
+ _gt => undef,
+ }
+);
+
+my %dummy_rule = (
+ _rule_number => 10000,
+ _protocol => "all",
+ _state => {
+ _established => undef,
+ _new => undef,
+ _related => undef,
+ _invalid => undef,
+ },
+ _action => "DROP",
+ _log => undef,
+ _tcp_flags => undef,
+ _icmp_code => undef,
+ _icmp_type => undef,
+ _icmp_name => undef,
+ _icmpv6_type => undef,
+ _mod_mark => undef,
+ _mod_table => undef,
+ _mod_dscp => undef,
+ _mod_tcpmss => undef,
+ _ipsec => undef,
+ _non_ipsec => undef,
+ _frag => undef,
+ _non_frag => undef,
+ _recent_time => undef,
+ _recent_cnt => undef,
+ _p2p => {
+ _all => undef,
+ _apple => undef,
+ _bit => undef,
+ _dc => undef,
+ _edk => undef,
+ _gnu => undef,
+ _kazaa => undef,
+ },
+ _time => {
+ _startdate => undef,
+ _stopdate => undef,
+ _starttime => undef,
+ _stoptime => undef,
+ _monthdays => undef,
+ _weekdays => undef,
+ _utc => undef,
+ },
+ _limit => {
+ _rate => undef,
+ _burst => undef,
+ },
+ _disable => undef,
+ _ip_version => undef,
+ _comment => undef,
+ _hop_limit => {
+ _eq => undef,
+ _lt => undef,
+ _gt => undef,
+ }
+);
+
+my $DEBUG = 'false';
+
+sub new {
+ my $that = shift;
+ my $class = ref($that) || $that;
+ my $self = {%fields,};
+
+ bless $self, $class;
+ return $self;
+}
+
+sub setupDummy {
+ my ($self, $level) = @_;
+
+ %{$self} = %dummy_rule;
+ $src = new Vyatta::IpTables::AddressFilter;
+ $dst = new Vyatta::IpTables::AddressFilter;
+
+ # set the default policy
+ my $config = new Vyatta::Config;
+ $config->setLevel("$level");
+ my $policy = $config->returnOrigValue('default-action');
+ $policy = 'drop' if !defined $policy;
+ $self->{_action} = $policy;
+ my $log = $config->existsOrig('enable-default-log');
+ $log = 'enable' if defined $log;
+ $self->{_log} = $log;
+}
+
+sub setup_base {
+ my ($self, $level, $val_func, $exists_func, $addr_setup) = @_;
+ my $config = new Vyatta::Config;
+
+ $self->{_comment} = $level;
+ $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->$val_func("protocol");
+
+ $self->{_state}->{_established} = $config->$val_func("state established");
+ $self->{_state}->{_new} = $config->$val_func("state new");
+ $self->{_state}->{_related} = $config->$val_func("state related");
+ $self->{_state}->{_invalid} = $config->$val_func("state invalid");
+
+ $self->{_action} = $config->$val_func("action");
+ $self->{_log} = $config->$val_func("log");
+ $self->{_tcp_flags} = $config->$val_func("tcp flags");
+ $self->{_icmp_code} = $config->$val_func("icmp code");
+ $self->{_icmp_type} = $config->$val_func("icmp type");
+ $self->{_icmp_name} = $config->$val_func("icmp type-name");
+ $self->{_icmpv6_type} = $config->$val_func("icmpv6 type");
+ $self->{_mod_mark} = $config->$val_func("set mark");
+ $self->{_mod_table} = $config->$val_func("set table");
+
+ if ($self->{_mod_table} eq 'main') {
+ $self->{_mod_table} = 254;
+ }
+ $self->{_mod_dscp} = $config->$val_func("set dscp");
+ $self->{_mod_tcpmss} = $config->$val_func("set tcp-mss");
+ $self->{_ipsec} = $config->$exists_func("ipsec match-ipsec");
+ $self->{_non_ipsec} = $config->$exists_func("ipsec match-none");
+ $self->{_frag} = $config->$exists_func("fragment match-frag");
+ $self->{_non_frag} = $config->$exists_func("fragment match-non-frag");
+ $self->{_recent_time} = $config->$val_func('recent time');
+ $self->{_recent_cnt} = $config->$val_func('recent count');
+
+ $self->{_p2p}->{_all} = $config->$exists_func("p2p all");
+ $self->{_p2p}->{_apple} = $config->$exists_func("p2p applejuice");
+ $self->{_p2p}->{_bit} = $config->$exists_func("p2p bittorrent");
+ $self->{_p2p}->{_dc} = $config->$exists_func("p2p directconnect");
+ $self->{_p2p}->{_edk} = $config->$exists_func("p2p edonkey");
+ $self->{_p2p}->{_gnu} = $config->$exists_func("p2p gnutella");
+ $self->{_p2p}->{_kazaa} = $config->$exists_func("p2p kazaa");
+
+ $self->{_time}->{_startdate} = $config->$val_func("time startdate");
+ $self->{_time}->{_stopdate} = $config->$val_func("time stopdate");
+ $self->{_time}->{_starttime} = $config->$val_func("time starttime");
+ $self->{_time}->{_stoptime} = $config->$val_func("time stoptime");
+ $self->{_time}->{_monthdays} = $config->$val_func("time monthdays");
+ $self->{_time}->{_weekdays} = $config->$val_func("time weekdays");
+ $self->{_time}->{_utc} = $config->$exists_func("time utc");
+
+ $self->{_limit}->{_rate} = $config->$val_func("limit rate");
+ $self->{_limit}->{_burst} = $config->$val_func("limit burst");
+
+ $self->{_disable} = $config->$exists_func("disable");
+
+ $self->{_hop_limit}->{_eq} = $config->$val_func("hop-limit eq");
+ $self->{_hop_limit}->{_lt} = $config->$val_func("hop-limit lt");
+ $self->{_hop_limit}->{_gt} = $config->$val_func("hop-limit gt");
+
+ # TODO: need $config->exists("$level source") in Vyatta::Config.pm
+ $src->$addr_setup("$level source");
+ $dst->$addr_setup("$level destination");
+
+ # Default to IPv4
+ $self->{_ip_version} = "ipv4";
+ return 0;
+}
+
+sub setup {
+ my ($self, $level) = @_;
+
+ $self->setup_base($level, 'returnValue', 'exists', 'setup');
+ return 0;
+}
+
+sub setupOrig {
+ my ($self, $level) = @_;
+
+ $self->setup_base($level, 'returnOrigValue', 'existsOrig', 'setupOrig');
+
+ $self->{_ip_version} = "ipv4";
+ return 0;
+}
+
+sub set_ip_version {
+ my ($self, $ip_version) = @_;
+
+ $self->{_ip_version} = $ip_version;
+ $src->set_ip_version($ip_version);
+ $dst->set_ip_version($ip_version);
+}
+
+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};
+ print "icmpv6 type: $self->{_icmpv6_type}\n" if defined $self->{_icmpv6_type};
+ print "mod mark: $self->{_mod_mark}\n" if defined $self->{_mod_mark};
+ print "mod table: $self->{_mod_table}\n" if defined $self->{_mod_table};
+ print "mod dscp: $self->{_mod_dscp}\n" if defined $self->{_mod_dscp};
+ print "mod tcp-mss: $self->{_mod_tcpmss}\n" if defined $self->{_mod_tcpmss};
+ print "hop-limit: $self->{_hop_limit}\n" if defined $self->{_hop_limit};
+
+ $src->print();
+ $dst->print();
+
+}
+
+sub is_stateful {
+ my $self = shift;
+ return 0 if defined $self->{_disable};
+ my @states = qw(established new related invalid);
+ foreach (@states) {
+ if ( defined($self->{_state}->{"_$_"})
+ && $self->{_state}->{"_$_"} eq "enable") {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub is_disabled {
+ my $self = shift;
+ return 1 if defined $self->{_disable};
+ return 0;
+}
+
+sub is_route_table {
+ my $self = shift;
+ return $self->{_mod_table};
+}
+
+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_log_prefix {
+ my ($chain, $rule_num, $action) = @_;
+
+ # In iptables it allows a 29 character log_prefix, but we ideally
+ # want to include "[$chain-$rule_num-$action] " but that would require
+ # 1 29 1 4 1 1 11 = 39
+ # so truncate the chain name so that it'll all fit.
+ my $action_char = uc(substr($action, 0, 1));
+ if (length($chain) > 19) {
+ $chain = substr($chain, 0, 19);
+ printf STDERR "Firewall config warning: rule $rule_num logging prefix will be truncated to [$chain-$rule_num-$action_char]\n";
+ }
+ my $log_prefix = "[$chain-$rule_num-$action_char] ";
+ return $log_prefix;
+}
+
+sub get_num_ipt_rules {
+ my $self = shift;
+ my $ipt_rules = 1;
+ return 0 if defined $self->{_disable};
+ my $protocol_tcpudp = 0;
+ if (defined $self->{_protocol} && $self->{_protocol} eq 'tcp_udp') {
+ $ipt_rules++;
+ $protocol_tcpudp = 1;
+ }
+
+ if (( "$self->{_log}" eq "enable")
+ && ( ("$self->{_action}" eq "drop")
+ ||("$self->{_action}" eq "accept")
+ ||("$self->{_action}" eq "reject")
+ ||("$self->{_action}" eq "inspect")
+ ||("$self->{_action}" eq "modify"))){
+ $ipt_rules += 1;
+ $ipt_rules++ if $protocol_tcpudp == 1;
+ }
+ if (defined($self->{_recent_time}) || defined($self->{_recent_cnt})) {
+ $ipt_rules += 1;
+ $ipt_rules++ if $protocol_tcpudp == 1;
+ }
+ return $ipt_rules;
+}
+
+sub rule {
+ my ($self) = @_;
+ my ($rule, $srcrule, $dstrule, $err_str);
+ my $tcp_and_udp = 0;
+
+ # set CLI rule num as comment
+ my @level_nodes = split(' ', $self->{_comment});
+ $rule .= "-m comment --comment \"$level_nodes[2]-$level_nodes[4]\" ";
+
+ # set the protocol
+ if (defined($self->{_protocol})) {
+ my $str = $self->{_protocol};
+ my $negate = '';
+ if ($str =~ /^\!(.*)$/) {
+ $str = $1;
+ $negate = '! ';
+ }
+ if ($str eq 'tcp_udp') {
+ $tcp_and_udp = 1;
+ $rule .= " $negate -p tcp "; # we'll add the '-p udp' to 2nd rule later
+ } else {
+ $rule .= " $negate -p $str ";
+ }
+ }
+
+ my $state_str = uc(get_state_str($self));
+ if ($state_str ne "") {
+ $rule .= "-m state --state $state_str ";
+ }
+
+ # set tcp flags if applicable
+ my $tcp_flags = undef;
+ if (defined $self->{_tcp_flags}) {
+ if (($self->{_protocol} eq "tcp") || ($self->{_protocol} eq "6")) {
+ $tcp_flags = get_tcp_flags_string($self->{_tcp_flags});
+ } else {
+ return ("TCP flags can only be set if protocol is set to TCP",);
+ }
+ }
+ if (defined($tcp_flags)) {
+ $rule .= " -m tcp --tcp-flags $tcp_flags ";
+ }
+
+ # set the icmp code and type if applicable
+ if (($self->{_protocol} eq "icmp") || ($self->{_protocol} eq "1")) {
+ if (defined $self->{_icmp_name}) {
+ if (defined($self->{_icmp_type}) || defined($self->{_icmp_code})){
+ return ("Cannot use ICMP type/code with ICMP type-name",);
+ }
+ $rule .= "--icmp-type $self->{_icmp_name} ";
+ } elsif (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})
+ || defined($self->{_icmp_name}))
+ {
+ return ("ICMP type/code or type-name can only be defined if protocol is ICMP",);
+ }
+
+ # Setup ICMPv6 rule if configured
+ # ICMPv6 parameters are only valid if the rule is matching on the
+ # ICMPv6 protocol ID.
+ #
+ if ( ($self->{_protocol} eq "icmpv6")
+ ||($self->{_protocol} eq "ipv6-icmp")
+ ||($self->{_protocol} eq "58")) {
+ if (defined($self->{_icmpv6_type})) {
+ $rule .= "-m icmpv6 --icmpv6-type $self->{_icmpv6_type}";
+ }
+ }
+
+ # Setup HL rule if configured
+ #
+ if ( defined($self->{_hop_limit}->{_eq}) ) {
+ $rule .= " -m hl --hl-eq $self->{_hop_limit}->{_eq}";
+ } elsif ( defined($self->{_hop_limit}->{_lt}) ) {
+ $rule .= " -m hl --hl-lt $self->{_hop_limit}->{_lt}";
+ } elsif ( defined($self->{_hop_limit}->{_gt}) ) {
+ $rule .= " -m hl --hl-gt $self->{_hop_limit}->{_gt}";
+ }
+
+ # 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));
+
+ # make sure multiport is always behind single port option
+ if ((grep /multiport/, $srcrule)) {
+ $rule .= " $dstrule $srcrule ";
+ } elsif ((grep /multiport/, $dstrule)) {
+ $rule .= " $srcrule $dstrule ";
+ } else {
+ $rule .= " $srcrule $dstrule ";
+ }
+
+ return ('Cannot specify both "match-frag" and "match-non-frag"',)
+ if (defined($self->{_frag}) && defined($self->{_non_frag}));
+ if (defined($self->{_frag})) {
+ $rule .= ' -f ';
+ } elsif (defined($self->{_non_frag})) {
+ $rule .= ' ! -f ';
+ }
+
+ # note: "out" is not valid in the INPUT chain.
+ return ('Cannot specify both "match-ipsec" and "match-none"',)
+ if (defined($self->{_ipsec}) && defined($self->{_non_ipsec}));
+ if (defined($self->{_ipsec})) {
+ $rule .= ' -m policy --pol ipsec --dir in ';
+ } elsif (defined($self->{_non_ipsec})) {
+ $rule .= ' -m policy --pol none --dir in ';
+ }
+
+ my $p2p = undef;
+ if (defined($self->{_p2p}->{_all})) {
+ $p2p = '--apple --bit --dc --edk --gnu --kazaa ';
+ } else {
+ my @apps = qw(apple bit dc edk gnu kazaa);
+ foreach (@apps) {
+ if (defined($self->{_p2p}->{"_$_"})) {
+ $p2p .= "--$_ ";
+ }
+ }
+ }
+ if (defined($p2p)) {
+ $rule .= " -m ipp2p $p2p ";
+ }
+
+ my $time = undef;
+ if (defined($self->{_time}->{_utc})) {
+ $time .= " --utc ";
+ }
+ if (defined($self->{_time}->{_startdate})) {
+ my $check_date = validate_date($self->{_time}->{_startdate}, "startdate");
+ if (!($check_date eq "")) {
+ return ($check_date,);
+ }
+ $time .= " --datestart $self->{_time}->{_startdate} ";
+ }
+ if (defined($self->{_time}->{_stopdate})) {
+ my $check_date = validate_date($self->{_time}->{_stopdate}, "stopdate");
+ if (!($check_date eq "")) {
+ return ($check_date,);
+ }
+ $time .= " --datestop $self->{_time}->{_stopdate} ";
+ }
+ if (defined($self->{_time}->{_starttime})) {
+ return ("Invalid starttime $self->{_time}->{_starttime}. Time should use 24 hour notation hh:mm:ss and lie in between 00:00:00 and 23:59:59", )
+ if (!validate_timevalues($self->{_time}->{_starttime}, "time"));
+ $time .= " --timestart $self->{_time}->{_starttime} ";
+ }
+ if (defined($self->{_time}->{_stoptime})) {
+ return ("Invalid stoptime $self->{_time}->{_stoptime}. Time should use 24 hour notation hh:mm:ss and lie in between 00:00:00 and 23:59:59", )
+ if (!validate_timevalues($self->{_time}->{_stoptime}, "time"));
+ $time .= " --timestop $self->{_time}->{_stoptime} ";
+ }
+ if (defined($self->{_time}->{_monthdays})) {
+ my $negate = " ";
+ if ($self->{_time}->{_monthdays} =~ m/^!/) {
+ $negate = "! ";
+ $self->{_time}->{_monthdays} = substr $self->{_time}->{_monthdays}, 1;
+ }
+ return ("Invalid monthdays value $self->{_time}->{_monthdays}. Monthdays should have values between 1 and 31 with multiple days separated by commas eg. 2,12,21 For negation, add ! in front eg. !2,12,21", )
+ if (!validate_timevalues($self->{_time}->{_monthdays}, "monthdays"));
+ $time .= " $negate --monthdays $self->{_time}->{_monthdays} ";
+ }
+ if (defined($self->{_time}->{_weekdays})) {
+ my $negate = " ";
+ if ($self->{_time}->{_weekdays} =~ m/^!/) {
+ $negate = "! ";
+ $self->{_time}->{_weekdays} = substr $self->{_time}->{_weekdays}, 1;
+ }
+ return ("Invalid weekdays value $self->{_time}->{_weekdays}. Weekdays should be specified using the first three characters of the day with the
+first character capitalized eg. Mon,Thu,Sat For negation, add ! in front eg. !Mon,Thu,Sat", )
+ if (!validate_timevalues($self->{_time}->{_weekdays}, "weekdays"));
+ $time .= " $negate --weekdays $self->{_time}->{_weekdays} ";
+ }
+ if (defined($time)) {
+ $rule .= " -m time $time ";
+ }
+
+ my $limit = undef;
+ if (defined $self->{_limit}->{_rate}) {
+ my $rate_integer = $self->{_limit}->{_rate};
+ $rate_integer =~ s/\/(second|minute|hour|day)//;
+ if ($rate_integer < 1) {
+ return ("integer value in rate cannot be less than 1",);
+ }
+ $limit = "--limit $self->{_limit}->{_rate} --limit-burst $self->{_limit}->{_burst}";
+ }
+ $rule .= " -m limit $limit " if defined $limit;
+
+ # recent match condition SHOULD BE DONE IN THE LAST so
+ # all options in $rule are copied to $recent_rule below
+ my $recent_rule = undef;
+ if (defined($self->{_recent_time}) || defined($self->{_recent_cnt})) {
+ my $recent_rule1 = undef;
+ my $recent_rule2 = undef;
+ $recent_rule1 .= ' -m recent --update ';
+ $recent_rule2 .= ' -m recent --set ';
+ if (defined($self->{_recent_time})) {
+ $recent_rule1 .= " --seconds $self->{_recent_time} ";
+ }
+ if (defined($self->{_recent_cnt})) {
+ $recent_rule1 .= " --hitcount $self->{_recent_cnt} ";
+ }
+
+ $recent_rule1 .= " --name $self->{_name}-$self->{_rule_number} ";
+ $recent_rule2 .= " --name $self->{_name}-$self->{_rule_number} ";
+
+ $recent_rule = $rule;
+
+ if ($rule =~ m/\-m\s+set\s+\-\-match\-set/) {
+
+ # firewall group being used in this rule. iptables complains if recent
+ # match condition is placed after group match conditions [see bug 5744]
+ # so instead of appending recent match place it before group match
+ my @split_rules = ();
+
+ @split_rules = split(/(\-m\s+set\s+\-\-match\-set)/, $rule, 2);
+ $rule = $split_rules[0] . $recent_rule1 .$split_rules[1] . $split_rules[2];
+
+ @split_rules = split(/(\-m\s+set\s+\-\-match\-set)/, $recent_rule, 2);
+ $recent_rule = $split_rules[0] . $recent_rule2 .$split_rules[1] . $split_rules[2];
+ } else {
+
+ # append recent match conditions to the two rules needed for recent match
+ $rule .= $recent_rule1;
+ $recent_rule .= $recent_rule2;
+ }
+ }
+
+ 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;
+ my $log_prefix = get_log_prefix($chain, $rule_num, $self->{_action});
+ $rule2 .= "-j LOG --log-prefix \"$log_prefix\" ";
+ }
+ if ("$self->{_action}" eq "drop") {
+ $rule .= "-j DROP ";
+ } elsif ("$self->{_action}" eq "accept") {
+ $rule .= "-j RETURN ";
+ } elsif ("$self->{_action}" eq "reject") {
+ $rule .= "-j REJECT ";
+ } elsif ("$self->{_action}" eq 'inspect') {
+ my $target = ipt_get_queue_target('SNORT');
+ return ('Undefined target for inspect',) if !defined $target;
+ $rule .= "-j $target ";
+ } elsif ($self->{_comment} =~ m/^policy/) {
+
+ # mangle actions
+ my $count = 0;
+ if (defined($self->{_mod_mark})) {
+ # MARK
+ $rule .= "-j MARK --set-mark $self->{_mod_mark} ";
+ $count++;
+ }
+ if (defined($self->{_mod_table})) {
+ # Route table
+ $rule .= "-j VYATTA_PBR_$self->{_mod_table} ";
+ $count++;
+ }
+ if (defined($self->{_mod_dscp})) {
+ # DSCP
+ $rule .= "-j DSCP --set-dscp $self->{_mod_dscp} ";
+ $count++;
+ }
+ if (defined($self->{_mod_tcpmss})) {
+ # TCP-MSS
+ # check for SYN flag
+ if ( !defined $self->{_tcp_flags}
+ ||!(($self->{_tcp_flags} =~ m/SYN/) && !($self->{_tcp_flags} =~ m/!SYN/)))
+ {
+ return ('need to set TCP SYN flag to modify TCP MSS',);
+ }
+
+ if ($self->{_mod_tcpmss} =~ m/\d/) {
+ $rule .= "-j TCPMSS --set-mss $self->{_mod_tcpmss} ";
+ } else {
+ $rule .= "-j TCPMSS --clamp-mss-to-pmtu ";
+ }
+ $count++;
+ }
+
+ # others
+ if ($count == 0) {
+ return ('Policy route requires "action drop" or "set" parameters be defined.');
+ } elsif ($count > 1) {
+ return ('Can not define more than one "set" parameter per policy route');
+ }
+ } else {
+ return ("\"action\" must be defined in rule $rule_num",);
+ }
+ if (defined($rule2)) {
+ my $tmp = $rule2;
+ $rule2 = $rule;
+ $rule = $tmp;
+ } elsif (defined($recent_rule)) {
+ $rule2 = $recent_rule;
+ $recent_rule = undef;
+ }
+
+ return (undef, undef) if defined $self->{_disable};
+
+ my ($udp_rule, $udp_rule2, $udp_recent_rule) = (undef, undef, undef);
+ if ($tcp_and_udp == 1) {
+
+ # create udp rules
+ $udp_rule = $rule;
+ $udp_rule2 = $rule2 if defined $rule2;
+ $udp_recent_rule = $recent_rule if defined $recent_rule;
+ foreach my $each_udprule ($udp_rule, $udp_rule2, $udp_recent_rule) {
+ $each_udprule =~ s/ \-p tcp / -p udp / if defined $each_udprule;
+ }
+ }
+
+ if ($DEBUG eq 'true') {
+
+ # print all potential iptables rules that could be formed for
+ # a single CLI rule. see get_num_ipt_rules to see exact count
+ print "rule :\n$rule\n" if defined $rule;
+ print "rule2 :\n$rule2\n" if defined $rule2;
+ print "recent rule :\n$recent_rule\n" if defined $recent_rule;
+ print "udp rule :\n$udp_rule\n" if defined $udp_rule;
+ print "udp rule2 :\n$udp_rule2\n" if defined $udp_rule2;
+ print "udp recent rule :\n$udp_recent_rule\n" if defined $udp_recent_rule;
+ }
+
+ return (undef, $rule, $rule2, $recent_rule, $udp_rule, $udp_rule2, $udp_recent_rule);
+}
+
+sub outputXmlElem {
+ my ($name, $value, $fh) = @_;
+ print $fh " <$name>$value</$name>\n";
+}
+
+sub outputXml {
+ my ($self, $fh) = @_;
+ if (!defined($self->{_protocol})) {
+ $self->{_protocol} = "all";
+ }
+ 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);
+}
+
+sub validate_timevalues {
+ my ($string, $type) = @_;
+ use Switch;
+ use Time::Local;
+ switch ($type) {
+ case "date" {
+ $string =~ s/-//g;
+ my ($year, $month, $day) = unpack "A4 A2 A2", $string;
+ eval {
+ timelocal(0,0,0,$day, $month-1, $year);
+ 1;
+ } or return 0;
+ }
+
+ case "time" {
+ $string =~ s/://g;
+ my ($hour, $min, $sec) = unpack "A2 A2 A2", $string;
+ eval {
+ timelocal($sec,$min,$hour, 1, 0, 1970);
+ 1;
+ } or return 0;
+ }
+
+ case "monthdays" {
+ while($string =~ m/(\d+)/g) {
+ if ($1 < 1 || $1 > 31) {
+ return 0;
+ }
+ }
+ }
+
+ case "weekdays" {
+ my @weekdays = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun");
+ while($string =~ m/(\w+)/g) {
+ if (!grep(/$1/,@weekdays)) {
+ return 0;
+ }
+ }
+ }
+
+ else {
+ print"Invalid type '$type' passed to sub validate_timevalues()\n";
+ return 0;
+ }
+ }
+ return 1;
+}
+
+sub validate_date {
+
+ my ($date, $string) = @_;
+ if ($date =~ m/T/) {
+ my $actualdate = substr $date, 0, 10;
+ my $datetime = substr $date, 11;
+ return ("Invalid $string $actualdate. Date should use yyyy-mm-dd format and lie in between 1970-01-01 and 2038-01-19")
+ if (!validate_timevalues($actualdate, "date"));
+ return ("Invalid time $datetime for $string $actualdate. Time should use 24 hour notation hh:mm:ss and lie in between 00:00:00 and 23:59:59")
+ if (!validate_timevalues($datetime, "time"));
+ } else {
+ return ("Invalid $string $date. Date should use yyyy-mm-dd format and lie in between 1970-01-01 and 2038-01-19")
+ if (!validate_timevalues($date, "date"));
+ }
+ return ("");
+}
+
+sub get_tcp_flags_string {
+
+ my $string = shift;
+ my @list_of_flags = (); # list of tcp flags to be examined
+ my @list_of_set_flags = (); # list of flags which must be set
+
+ my @string_list = split(/,/, $string);
+ while(@string_list) {
+ if (!grep(/!/,$string_list[0])) {
+ push @list_of_flags, $string_list[0];
+ push @list_of_set_flags, $string_list[0];
+ } else {
+ $string_list[0] =~ s/!//g;
+ push @list_of_flags, $string_list[0];
+ }
+ shift(@string_list);
+ }
+
+ push @list_of_set_flags, 'NONE' if @list_of_set_flags == ();
+ return join(",",@list_of_flags) . " " . join(",",@list_of_set_flags);
+}
+
+1;
diff --git a/scripts/vyatta-conntrack-ignore.pl b/scripts/vyatta-conntrack-ignore.pl
index 7d07604..a103173 100644
--- a/scripts/vyatta-conntrack-ignore.pl
+++ b/scripts/vyatta-conntrack-ignore.pl
@@ -10,12 +10,11 @@ use Vyatta::Conntrack::RuleIgnore;
use Vyatta::IpTables::AddressFilter;
use Vyatta::Conntrack::ConntrackUtil;
use Getopt::Long;
-use Vyatta::Zone;
use Sys::Syslog qw(:standard :macros);
#for future use when v6 ignore s need to be set
-my %cmd_hash = ( 'ipv4' => 'iptables',
- 'ipv6' => 'ip6tables');
+my %cmd_hash = ( 'ipv4' => 'iptables-nft',
+ 'ipv6' => 'ip6tables-nft');
# Enable printing debug output to stdout.
my $debug_flag = 0;
@@ -35,8 +34,8 @@ openlog("vyatta-conntrack", "pid", "local0");
sub remove_ignore_policy {
my ($rule_string) = @_;
- my $iptables_cmd1 = "iptables -D VYATTA_CT_IGNORE -t raw $rule_string -j CT --notrack";
- my $iptables_cmd2 = "iptables -D VYATTA_CT_IGNORE -t raw $rule_string -j RETURN";
+ my $iptables_cmd1 = "iptables-nft -D VYOS_CT_IGNORE -t raw $rule_string -j CT --notrack";
+ my $iptables_cmd2 = "iptables-nft -D VYOS_CT_IGNORE -t raw $rule_string -j RETURN";
run_cmd($iptables_cmd2);
if ($? >> 8) {
print "$CTERROR failed to run $iptables_cmd2\n";
@@ -51,9 +50,9 @@ sub remove_ignore_policy {
sub apply_ignore_policy {
my ($rule_string, $rule, $num_rules) = @_;
# insert at num_rules + 1 as there are so many rules already.
- my $iptables_cmd1 = "iptables -I VYATTA_CT_IGNORE $num_rules -t raw $rule_string -j CT --notrack";
+ my $iptables_cmd1 = "iptables-nft -I VYOS_CT_IGNORE $num_rules -t raw $rule_string -j CT --notrack";
$num_rules +=1;
- my $iptables_cmd2 = "iptables -I VYATTA_CT_IGNORE $num_rules -t raw $rule_string -j RETURN";
+ my $iptables_cmd2 = "iptables-nft -I VYOS_CT_IGNORE $num_rules -t raw $rule_string -j RETURN";
run_cmd($iptables_cmd1);
if ($? >> 8) {
print "$CTERROR failed to run $iptables_cmd1\n";
diff --git a/scripts/vyatta-conntrack-timeouts.pl b/scripts/vyatta-conntrack-timeouts.pl
index 557f4eb..7394945 100644
--- a/scripts/vyatta-conntrack-timeouts.pl
+++ b/scripts/vyatta-conntrack-timeouts.pl
@@ -13,8 +13,8 @@ use Vyatta::Zone;
use Sys::Syslog qw(:standard :macros);
#for future use when v6 timeouts need to be set
-my %cmd_hash = ( 'ipv4' => 'iptables',
- 'ipv6' => 'ip6tables');
+my %cmd_hash = ( 'ipv4' => 'iptables-nft',
+ 'ipv6' => 'ip6tables-nft');
# Enable printing debug output to stdout.
my $debug_flag = 0;
@@ -36,8 +36,8 @@ sub remove_timeout_policy {
my ($rule_string, $timeout_policy) = @_;
my @tokens = split (' ', $timeout_policy);
# First remove the iptables rules before removing policy.
- my $iptables_cmd1 = "iptables -D VYATTA_CT_TIMEOUT -t raw $rule_string -j CT --timeout $tokens[0]";
- my $iptables_cmd2 = "iptables -D VYATTA_CT_TIMEOUT -t raw $rule_string -j RETURN";
+ my $iptables_cmd1 = "iptables-nft -D VYOS_CT_TIMEOUT -t raw $rule_string -j CT --timeout $tokens[0]";
+ my $iptables_cmd2 = "iptables-nft -D VYOS_CT_TIMEOUT -t raw $rule_string -j RETURN";
my $nfct_timeout_cmd = "$nfct timeout delete $timeout_policy";
run_cmd($iptables_cmd2);
if ($? >> 8) {
@@ -66,9 +66,9 @@ sub apply_timeout_policy {
my $nfct_timeout_cmd = "$nfct timeout add $timeout_policy";
my @tokens = split (' ', $timeout_policy);
# insert at num_rules + 1 as there are so many rules already.
- my $iptables_cmd1 = "iptables -I VYATTA_CT_TIMEOUT $num_rules -t raw $rule_string -j CT --timeout $tokens[0]";
+ my $iptables_cmd1 = "iptables-nft -I VYATTA_CT_TIMEOUT $num_rules -t raw $rule_string -j CT --timeout $tokens[0]";
$num_rules +=1;
- my $iptables_cmd2 = "iptables -I VYATTA_CT_TIMEOUT $num_rules -t raw $rule_string -j RETURN";
+ my $iptables_cmd2 = "iptables-nft -I VYATTA_CT_TIMEOUT $num_rules -t raw $rule_string -j RETURN";
run_cmd($nfct_timeout_cmd);
if ($? >> 8) {
print "$CTERROR failed to run $nfct_timeout_cmd\n";
@@ -84,7 +84,7 @@ sub apply_timeout_policy {
run_cmd($iptables_cmd2);
if ($? >> 8) {
run_cmd("nfct timeout delete policy_timeout_$rule");
- run_cmd("iptables -D PREROUTING -t raw $rule_string -j CT --timeout $tokens[0]");
+ run_cmd("iptables-nft -D PREROUTING -t raw $rule_string -j CT --timeout $tokens[0]");
print "$CTERROR failed to run $iptables_cmd2\n";
exit 1;
}
diff --git a/scripts/vyatta-show-ignore.pl b/scripts/vyatta-show-ignore.pl
index 40efa8f..e650bf1 100644
--- a/scripts/vyatta-show-ignore.pl
+++ b/scripts/vyatta-show-ignore.pl
@@ -43,7 +43,7 @@ sub print_ignore_rules {
$config->setLevel("system conntrack ignore rule");
my @rules = sort numerically $config->listOrigNodes();
- my @rules_in_chain = `sudo iptables -L VYATTA_CT_IGNORE -t raw -nv`;
+ my @rules_in_chain = `sudo iptables-nft -L VYOS_CT_IGNORE -t raw -nv`;
if (!(@rules_in_chain)){
die "Error: no ignore rules configured\n";
}