summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--debian/control3
-rwxr-xr-xlib/Vyatta/IpTables/AddressFilter.pm46
-rwxr-xr-xlib/Vyatta/IpTables/IpSet.pm225
-rwxr-xr-xscripts/firewall/vyatta-ipset.pl112
-rw-r--r--templates/firewall/group/address-group/node.def24
-rw-r--r--templates/firewall/group/address-group/node.tag/address/node.def17
-rw-r--r--templates/firewall/group/address-group/node.tag/description/node.def2
-rw-r--r--templates/firewall/group/network-group/node.def24
-rw-r--r--templates/firewall/group/network-group/node.tag/description/node.def2
-rw-r--r--templates/firewall/group/network-group/node.tag/network/node.def20
-rw-r--r--templates/firewall/group/node.def3
-rw-r--r--templates/firewall/group/port-group/node.def24
-rw-r--r--templates/firewall/group/port-group/node.tag/description/node.def2
-rw-r--r--templates/firewall/group/port-group/node.tag/port/node.def17
-rw-r--r--templates/firewall/name/node.tag/rule/node.tag/destination/group/address-group/node.def2
-rw-r--r--templates/firewall/name/node.tag/rule/node.tag/destination/group/network-group/node.def2
-rw-r--r--templates/firewall/name/node.tag/rule/node.tag/destination/group/node.def1
-rw-r--r--templates/firewall/name/node.tag/rule/node.tag/destination/group/port-group/node.def2
-rw-r--r--templates/firewall/name/node.tag/rule/node.tag/source/group/address-group/node.def2
-rw-r--r--templates/firewall/name/node.tag/rule/node.tag/source/group/network-group/node.def2
-rw-r--r--templates/firewall/name/node.tag/rule/node.tag/source/group/node.def1
-rw-r--r--templates/firewall/name/node.tag/rule/node.tag/source/group/port-group/node.def2
23 files changed, 532 insertions, 7 deletions
diff --git a/Makefile.am b/Makefile.am
index 62150f4..c771b11 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,9 +8,11 @@ curver_DATA = cfg-version/firewall@3
sbin_SCRIPTS += scripts/firewall/vyatta-firewall.pl
sbin_SCRIPTS += scripts/firewall/firewall.init
+sbin_SCRIPTS += scripts/firewall/vyatta-ipset.pl
-share_perl5_DATA = lib/Vyatta/IpTables/Rule.pm
+share_perl5_DATA = lib/Vyatta/IpTables/Rule.pm
share_perl5_DATA += lib/Vyatta/IpTables/AddressFilter.pm
+share_perl5_DATA += lib/Vyatta/IpTables/IpSet.pm
cpiop = find . ! -regex '\(.*~\|.*\.bak\|.*\.swp\|.*\#.*\#\)' -print0 | \
cpio -0pd
diff --git a/debian/control b/debian/control
index c1d3152..2de8ed1 100644
--- a/debian/control
+++ b/debian/control
@@ -20,7 +20,8 @@ Depends: sed (>= 4.1.5),
busybox,
whois,
sudo,
- snmpd
+ snmpd,
+ ipset
Suggests: util-linux (>= 2.13-5),
net-tools,
ethtool,
diff --git a/lib/Vyatta/IpTables/AddressFilter.pm b/lib/Vyatta/IpTables/AddressFilter.pm
index fe17c09..dacba1a 100755
--- a/lib/Vyatta/IpTables/AddressFilter.pm
+++ b/lib/Vyatta/IpTables/AddressFilter.pm
@@ -15,13 +15,14 @@
# General Public License for more details.
#
# This code was originally developed by Vyatta, Inc.
-# Portions created by Vyatta are Copyright (C) 2006, 2007, 2008 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;
@@ -45,6 +46,9 @@ my %fields = (
_protocol => undef,
_src_mac => undef,
_ip_version => undef,
+ _address_group => undef,
+ _network_group => undef,
+ _port_group => undef,
);
sub new {
@@ -93,8 +97,12 @@ sub setup {
}
}
- $self->{_port} = $config->returnValue("port");
- $self->{_src_mac} = $config->returnValue("mac-address");
+ $self->{_port} = $config->returnValue("port");
+ $self->{_src_mac} = $config->returnValue("mac-address");
+
+ $self->{_address_group} = $config->returnValue("group address-group");
+ $self->{_network_group} = $config->returnValue("group network-group");
+ $self->{_port_group} = $config->returnValue("group port-group");
return 0;
}
@@ -128,8 +136,12 @@ sub setupOrig {
}
}
- $self->{_port} = $config->returnOrigValue("port");
- $self->{_src_mac} = $config->returnValue("mac-address");
+ $self->{_port} = $config->returnOrigValue("port");
+ $self->{_src_mac} = $config->returnValue("mac-address");
+
+ $self->{_address_group} = $config->returnOrigValue("group address-group");
+ $self->{_network_group} = $config->returnOrigValue("group network-group");
+ $self->{_port_group} = $config->returnOrigValue("group port-group");
return 0;
}
@@ -223,6 +235,30 @@ sub rule {
$rule .= ("-m iprange $negate--dst-range $start-$self->{_range_stop} ");
}
}
+ # so far ipset only supports IPv4
+ if ($self->{_ip_version} eq "ipv4") {
+ if (defined($self->{_address_group})) {
+ my $name = $self->{_address_group};
+ my $group = new Vyatta::IpTables::IpSet($name, 'address');
+ my ($set_rule, $err_str) = $group->rule($self->{_srcdst});
+ return ($err_str, ) if ! defined $set_rule;
+ $rule .= $set_rule;
+ }
+ if (defined($self->{_network_group})) {
+ my $name = $self->{_network_group};
+ my $group = new Vyatta::IpTables::IpSet($name, 'network');
+ my ($set_rule, $err_str) = $group->rule($self->{_srcdst});
+ return ($err_str, ) if ! defined $set_rule;
+ $rule .= $set_rule;
+ }
+ if (defined($self->{_port_group})) {
+ my $name = $self->{_port_group};
+ my $group = new Vyatta::IpTables::IpSet($name, 'port');
+ my ($set_rule, $err_str) = $group->rule($self->{_srcdst});
+ return ($err_str, ) if ! defined $set_rule;
+ $rule .= $set_rule;
+ }
+ }
my ($port_str, $port_err)
= getPortRuleString($self->{_port}, $can_use_port,
diff --git a/lib/Vyatta/IpTables/IpSet.pm b/lib/Vyatta/IpTables/IpSet.pm
new file mode 100755
index 0000000..c8508c6
--- /dev/null
+++ b/lib/Vyatta/IpTables/IpSet.pm
@@ -0,0 +1,225 @@
+#!/usr/bin/perl
+#
+# 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 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,
+ _debug => undef,
+);
+
+my $logger = 'logger -t IpSet.pm -p local0.warn --';
+
+sub new {
+ my ($that, $name, $type) = @_;
+
+ my $class = ref ($that) || $that;
+ my $self = {
+ %fields,
+ };
+ $self->{_name} = $name;
+ $self->{_type} = $type;
+
+ bless $self, $class;
+ return $self;
+}
+
+sub debug {
+ my ($self, $onoff) = @_;
+
+ $self->{_debug} = undef;
+ $self->{_debug} = 1 if $onoff eq "on";
+}
+
+sub exists {
+ my ($self) = @_;
+
+ return 0 if ! defined $self->{_name};
+ my $func = (caller(0))[3];
+ my $cmd = "ipset -L $self->{_name}";
+ my $rc = system("sudo $cmd > /dev/null &>2");
+ system("$logger [$func] [$cmd] = [$rc]") if defined $self->{_debug};
+ return $rc ? 0 : 1;
+}
+
+sub create {
+ my ($self) = @_;
+
+ return "Error: undefined group name" if ! defined $self->{_name};
+ return "Error: undefined group type" if ! defined $self->{_type};
+ return "Error: group [$self->{_name}] already exists" if $self->exists();
+
+ my $ipset_param;
+ if ($self->{_type} eq 'address') {
+ $ipset_param = 'iphash';
+ } elsif ($self->{_type} eq 'network') {
+ $ipset_param = 'nethash';
+ } elsif ($self->{_type} eq 'port') {
+ $ipset_param = 'portmap --from 1 --to 65535';
+ } else {
+ return "Error: invalid group type";
+ }
+
+ my $func = (caller(0))[3];
+ my $cmd = "ipset -N $self->{_name} $ipset_param";
+ my $rc = system("sudo $cmd");
+ system("$logger [$func] [$cmd] = [$rc]") if defined $self->{_debug};
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return undef;
+}
+
+sub references {
+ my ($self) = @_;
+
+ return 0 if ! $self->exists();
+ my @lines = `sudo ipset -L $self->{_name}`;
+ foreach my $line (@lines) {
+ if ($line =~ /^References:\s+(\d+)$/) {
+ return $1;
+ }
+ }
+ return 0;
+}
+
+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();
+ return "Error: group [$self->{_name}] still in use.\n" if $refs != 0;
+
+ my $func = (caller(0))[3];
+ my $cmd = "ipset -X $self->{_name}";
+ my $rc = system("sudo $cmd");
+ system("$logger [$func] [$cmd] = [$rc]") if defined $self->{_debug};
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return undef;
+}
+
+sub check_member {
+ my ($self, $member) = @_;
+
+ return "Error: undefined group name" if ! defined $self->{_name};
+ return "Error: undefined group type" if ! defined $self->{_type};
+
+ if ($self->{_type} eq 'address') {
+ if (!Vyatta::TypeChecker::validateType('ipv4', $member, 1)) {
+ return "Error: [$member] isn't valid IPv4 address\n";
+ }
+ } elsif ($self->{_type} eq 'network') {
+ if (!Vyatta::TypeChecker::validateType('ipv4net', $member, 1)) {
+ return "Error: [$member] isn't valid IPv4 network\n";
+ }
+ } elsif ($self->{_type} eq 'port') {
+ if ($member =~ /^\d/) {
+ my ($success, $err) = Vyatta::Misc::isValidPortNumber($member);
+ if (!defined $success) {
+ return "Error: [$member] isn't valid port number\n";
+ }
+ } else {
+ my ($success, $err) = Vyatta::Misc::isValidPortName($member);
+ if (!defined $success) {
+ return "Error: [$member] isn't valid port name\n";
+ }
+ }
+ } else {
+ return "Error: invalid set type [$self->{_type}]";
+ }
+ return undef;
+}
+
+sub member_exists {
+ my ($self, $member) = @_;
+
+ my $func = (caller(0))[3];
+ my $cmd = "ipset -T $self->{_name} $member -q";
+ my $rc = system("sudo $cmd");
+ system("$logger [$func] [$cmd] = [$rc]") if defined $self->{_debug};
+ return $rc ? 0 : 1;
+}
+
+sub add_member {
+ my ($self, $member) = @_;
+
+ 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)) {
+ return "Error: member [$member] already exists in [$self->{_name}]\n";
+ }
+ my $func = (caller(0))[3];
+ my $cmd = "ipset -A $self->{_name} $member";
+ my $rc = system("sudo $cmd");
+ system("$logger [$func] [$cmd] = [$rc]") if defined $self->{_debug};
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return undef;
+}
+
+sub delete_member {
+ my ($self, $member) = @_;
+
+ 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)) {
+ return "Error: member [$member] doesn't exists in [$self->{_name}]\n";
+ }
+ my $func = (caller(0))[3];
+ my $cmd = "ipset -D $self->{_name} $member";
+ my $rc = system("sudo $cmd");
+ system("$logger [$func] [$cmd] = [$rc]") if defined $self->{_debug};
+ return "Error: call to ipset failed [$rc]" if $rc;
+ return undef;
+}
+
+sub rule {
+ my ($self, $direction) = @_;
+
+ if (! $self->exists()) {
+ my $rc = $self->create();
+ return (undef, $rc) if $rc;
+ }
+
+ 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;
+ return ("-m set --set $grp $srcdst ", );
+}
+
+1;
diff --git a/scripts/firewall/vyatta-ipset.pl b/scripts/firewall/vyatta-ipset.pl
new file mode 100755
index 0000000..0c0ee86
--- /dev/null
+++ b/scripts/firewall/vyatta-ipset.pl
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+#
+# Module: vyatta-ipset.pl
+#
+# **** License ****
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2009 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: Stig Thormodsrud
+# Date: January 2009
+# Description: Script to configure ipset to support firewall groups
+#
+# **** End License ****
+#
+
+use Getopt::Long;
+use POSIX;
+
+use lib "/opt/vyatta/share/perl5";
+use Vyatta::Config;
+use Vyatta::TypeChecker;
+use Vyatta::Misc;
+use Vyatta::IpTables::IpSet;
+
+use warnings;
+use strict;
+
+
+sub ipset_create {
+ my ($set_name, $set_type) = @_;
+
+ my $group = new Vyatta::IpTables::IpSet($set_name, $set_type);
+
+ return $group->create();
+
+}
+
+sub ipset_delete {
+ my $set_name = shift;
+
+ my $group = new Vyatta::IpTables::IpSet($set_name);
+ return $group->delete();
+}
+
+sub ipset_check_member {
+ my ($set_name, $set_type, $member) = @_;
+
+ die "undefined type or member" if ! defined $set_type or ! defined $member;
+
+ my $group = new Vyatta::IpTables::IpSet($set_name, $set_type);
+ return $group->check_member($member);
+}
+
+sub ipset_add_member {
+ my ($set_name, $member) = @_;
+
+ die "Error: undefined member" if ! defined $member;
+ my $group = new Vyatta::IpTables::IpSet($set_name);
+ return $group->add_member($member);
+}
+
+sub ipset_delete_member {
+ my ($set_name, $member) = @_;
+
+ die "Error: undefined member" if ! defined $member;
+ my $group = new Vyatta::IpTables::IpSet($set_name);
+ return $group->delete_member($member);
+}
+
+
+#
+# main
+#
+my ($action, $set_name, $set_type, $member);
+
+GetOptions("action=s" => \$action,
+ "set-name=s" => \$set_name,
+ "set-type=s" => \$set_type,
+ "member=s" => \$member,
+);
+
+die "undefined action" if ! defined $action;
+
+my $rc;
+$rc = ipset_create($set_name, $set_type) if $action eq 'create-set';
+
+$rc = ipset_delete($set_name) if $action eq 'delete-set';
+
+$rc = ipset_check_member($set_name, $set_type, $member)
+ if $action eq 'check-member';
+
+$rc = ipset_add_member($set_name, $member) if $action eq 'add-member';
+
+$rc = ipset_delete_member($set_name, $member) if $action eq 'delete-member';
+
+if (defined $rc) {
+ print $rc;
+ exit 1;
+}
+exit 0;
+
+# end of file
diff --git a/templates/firewall/group/address-group/node.def b/templates/firewall/group/address-group/node.def
new file mode 100644
index 0000000..bc4fb68
--- /dev/null
+++ b/templates/firewall/group/address-group/node.def
@@ -0,0 +1,24 @@
+tag:
+type: txt
+help: Set a firewall address-group
+
+syntax:expression: exec " \
+ if [ `echo $VAR(@) | wc -c` -gt 31 ]; then \
+ echo group name must be 31 characters or less;\
+ exit 1 ; \
+ fi ; "
+
+syntax:expression: pattern $VAR(@) "^[^-]" ; \
+ "Firewall group name cannot start with \"-\""
+
+create: sudo /opt/vyatta/sbin/vyatta-ipset.pl \
+ --action=create-set \
+ --set-type=address \
+ --set-name="$VAR(@)"
+
+
+delete: sudo /opt/vyatta/sbin/vyatta-ipset.pl \
+ --action=delete-set \
+ --set-name="$VAR(@)"
+
+comp_help: Enter the name of the firewall address-group
diff --git a/templates/firewall/group/address-group/node.tag/address/node.def b/templates/firewall/group/address-group/node.tag/address/node.def
new file mode 100644
index 0000000..e0f8026
--- /dev/null
+++ b/templates/firewall/group/address-group/node.tag/address/node.def
@@ -0,0 +1,17 @@
+multi:
+type: ipv4
+help: Set a address-group member
+
+syntax:expression: exec "/opt/vyatta/sbin/vyatta-ipset.pl \
+ --action=check-member \
+ --set-name=$VAR(../@) \
+ --set-type=address \
+ --member=\"$VAR(@)\"; "
+
+create: sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=add-member \
+ --set-name=$VAR(../@) \
+ --member="$VAR(@) "
+
+delete: sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=delete-member \
+ --set-name=$VAR(../@) \
+ --member="$VAR(@) "
diff --git a/templates/firewall/group/address-group/node.tag/description/node.def b/templates/firewall/group/address-group/node.tag/description/node.def
new file mode 100644
index 0000000..05f7e51
--- /dev/null
+++ b/templates/firewall/group/address-group/node.tag/description/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: Set address-group description
diff --git a/templates/firewall/group/network-group/node.def b/templates/firewall/group/network-group/node.def
new file mode 100644
index 0000000..2d8bf60
--- /dev/null
+++ b/templates/firewall/group/network-group/node.def
@@ -0,0 +1,24 @@
+tag:
+type: txt
+help: Set a firewall network-group
+
+syntax:expression: exec " \
+ if [ `echo $VAR(@) | wc -c` -gt 31 ]; then \
+ echo group name must be 31 characters or less;\
+ exit 1 ; \
+ fi ; "
+
+syntax:expression: pattern $VAR(@) "^[^-]" ; \
+ "Firewall group name cannot start with \"-\""
+
+create: sudo /opt/vyatta/sbin/vyatta-ipset.pl \
+ --action=create-set \
+ --set-type=network \
+ --set-name="$VAR(@)"
+
+
+delete: sudo /opt/vyatta/sbin/vyatta-ipset.pl \
+ --action=delete-set \
+ --set-name="$VAR(@)"
+
+comp_help: Enter the name of the firewall network-group
diff --git a/templates/firewall/group/network-group/node.tag/description/node.def b/templates/firewall/group/network-group/node.tag/description/node.def
new file mode 100644
index 0000000..3c50208
--- /dev/null
+++ b/templates/firewall/group/network-group/node.tag/description/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: Set network-group description
diff --git a/templates/firewall/group/network-group/node.tag/network/node.def b/templates/firewall/group/network-group/node.tag/network/node.def
new file mode 100644
index 0000000..1f33ba9
--- /dev/null
+++ b/templates/firewall/group/network-group/node.tag/network/node.def
@@ -0,0 +1,20 @@
+multi:
+type: ipv4net
+help: Set a network-group member
+
+syntax:expression: exec "/opt/vyatta/sbin/vyatta-ipset.pl \
+ --action=check-member \
+ --set-name=$VAR(../@) \
+ --set-type=network \
+ --member=\"$VAR(@)\"; "
+
+syntax:expression: exec " \
+ /opt/vyatta/sbin/check_prefix_boundary $VAR(@)" \
+
+create: sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=add-member \
+ --set-name=$VAR(../@) \
+ --member="$VAR(@) "
+
+delete: sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=delete-member \
+ --set-name=$VAR(../@) \
+ --member="$VAR(@) "
diff --git a/templates/firewall/group/node.def b/templates/firewall/group/node.def
new file mode 100644
index 0000000..d45d3d9
--- /dev/null
+++ b/templates/firewall/group/node.def
@@ -0,0 +1,3 @@
+help: Set a firewall group
+
+comp_help: Enter the name of the firewall group
diff --git a/templates/firewall/group/port-group/node.def b/templates/firewall/group/port-group/node.def
new file mode 100644
index 0000000..0ec803f
--- /dev/null
+++ b/templates/firewall/group/port-group/node.def
@@ -0,0 +1,24 @@
+tag:
+type: txt
+help: Set a firewall port-group
+
+syntax:expression: exec " \
+ if [ `echo $VAR(@) | wc -c` -gt 31 ]; then \
+ echo group name must be 31 characters or less;\
+ exit 1 ; \
+ fi ; "
+
+syntax:expression: pattern $VAR(@) "^[^-]" ; \
+ "Firewall group name cannot start with \"-\""
+
+create: sudo /opt/vyatta/sbin/vyatta-ipset.pl \
+ --action=create-set \
+ --set-type=port \
+ --set-name="$VAR(@)"
+
+
+delete: sudo /opt/vyatta/sbin/vyatta-ipset.pl \
+ --action=delete-set \
+ --set-name="$VAR(@)"
+
+comp_help: Enter the name of the firewall port-group
diff --git a/templates/firewall/group/port-group/node.tag/description/node.def b/templates/firewall/group/port-group/node.tag/description/node.def
new file mode 100644
index 0000000..90124a9
--- /dev/null
+++ b/templates/firewall/group/port-group/node.tag/description/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: Set port-group description
diff --git a/templates/firewall/group/port-group/node.tag/port/node.def b/templates/firewall/group/port-group/node.tag/port/node.def
new file mode 100644
index 0000000..3f9c530
--- /dev/null
+++ b/templates/firewall/group/port-group/node.tag/port/node.def
@@ -0,0 +1,17 @@
+multi:
+type: txt
+help: Set a port-group member
+
+syntax:expression: exec "/opt/vyatta/sbin/vyatta-ipset.pl \
+ --action=check-member \
+ --set-name=$VAR(../@) \
+ --set-type=port \
+ --member=\"$VAR(@)\"; "
+
+create: sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=add-member \
+ --set-name=$VAR(../@) \
+ --member="$VAR(@) "
+
+delete: sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=delete-member \
+ --set-name=$VAR(../@) \
+ --member="$VAR(@) "
diff --git a/templates/firewall/name/node.tag/rule/node.tag/destination/group/address-group/node.def b/templates/firewall/name/node.tag/rule/node.tag/destination/group/address-group/node.def
new file mode 100644
index 0000000..51953bb
--- /dev/null
+++ b/templates/firewall/name/node.tag/rule/node.tag/destination/group/address-group/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: Set group of addresses
diff --git a/templates/firewall/name/node.tag/rule/node.tag/destination/group/network-group/node.def b/templates/firewall/name/node.tag/rule/node.tag/destination/group/network-group/node.def
new file mode 100644
index 0000000..cd91233
--- /dev/null
+++ b/templates/firewall/name/node.tag/rule/node.tag/destination/group/network-group/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: Set group of networks
diff --git a/templates/firewall/name/node.tag/rule/node.tag/destination/group/node.def b/templates/firewall/name/node.tag/rule/node.tag/destination/group/node.def
new file mode 100644
index 0000000..f3d9347
--- /dev/null
+++ b/templates/firewall/name/node.tag/rule/node.tag/destination/group/node.def
@@ -0,0 +1 @@
+help: Set group to match
diff --git a/templates/firewall/name/node.tag/rule/node.tag/destination/group/port-group/node.def b/templates/firewall/name/node.tag/rule/node.tag/destination/group/port-group/node.def
new file mode 100644
index 0000000..c9ec6ac
--- /dev/null
+++ b/templates/firewall/name/node.tag/rule/node.tag/destination/group/port-group/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: Set group of ports
diff --git a/templates/firewall/name/node.tag/rule/node.tag/source/group/address-group/node.def b/templates/firewall/name/node.tag/rule/node.tag/source/group/address-group/node.def
new file mode 100644
index 0000000..51953bb
--- /dev/null
+++ b/templates/firewall/name/node.tag/rule/node.tag/source/group/address-group/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: Set group of addresses
diff --git a/templates/firewall/name/node.tag/rule/node.tag/source/group/network-group/node.def b/templates/firewall/name/node.tag/rule/node.tag/source/group/network-group/node.def
new file mode 100644
index 0000000..cd91233
--- /dev/null
+++ b/templates/firewall/name/node.tag/rule/node.tag/source/group/network-group/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: Set group of networks
diff --git a/templates/firewall/name/node.tag/rule/node.tag/source/group/node.def b/templates/firewall/name/node.tag/rule/node.tag/source/group/node.def
new file mode 100644
index 0000000..f3d9347
--- /dev/null
+++ b/templates/firewall/name/node.tag/rule/node.tag/source/group/node.def
@@ -0,0 +1 @@
+help: Set group to match
diff --git a/templates/firewall/name/node.tag/rule/node.tag/source/group/port-group/node.def b/templates/firewall/name/node.tag/rule/node.tag/source/group/port-group/node.def
new file mode 100644
index 0000000..c9ec6ac
--- /dev/null
+++ b/templates/firewall/name/node.tag/rule/node.tag/source/group/port-group/node.def
@@ -0,0 +1,2 @@
+type: txt
+help: Set group of ports