diff options
-rwxr-xr-x | lib/Vyatta/IpTables/IpSet.pm | 37 | ||||
-rwxr-xr-x | scripts/firewall/vyatta-ipset.pl | 72 | ||||
-rw-r--r-- | templates/firewall/group/address-group/node.def | 11 | ||||
-rw-r--r-- | templates/firewall/group/address-group/node.tag/address/node.def | 93 | ||||
-rw-r--r-- | templates/firewall/group/network-group/node.def | 10 | ||||
-rw-r--r-- | templates/firewall/group/network-group/node.tag/network/node.def | 18 | ||||
-rw-r--r-- | templates/firewall/group/port-group/node.def | 11 | ||||
-rw-r--r-- | templates/firewall/group/port-group/node.tag/port/node.def | 87 | ||||
-rw-r--r-- | templates/firewall/modify/node.def | 1 | ||||
-rw-r--r-- | templates/firewall/name/node.def | 1 | ||||
-rw-r--r-- | templates/firewall/node.def | 2 |
11 files changed, 100 insertions, 243 deletions
diff --git a/lib/Vyatta/IpTables/IpSet.pm b/lib/Vyatta/IpTables/IpSet.pm index 703a3ac..607333c 100755 --- a/lib/Vyatta/IpTables/IpSet.pm +++ b/lib/Vyatta/IpTables/IpSet.pm @@ -40,7 +40,7 @@ my %fields = ( _debug => undef, ); -my %grouptype_hash = ( +our %grouptype_hash = ( 'address' => 'hash:ip', 'network' => 'hash:net', 'port' => 'bitmap:port' @@ -175,8 +175,8 @@ sub create { 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(); - + 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; @@ -203,6 +203,14 @@ sub references { 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 delete { my ($self) = @_; @@ -210,7 +218,15 @@ sub delete { 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; + 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); @@ -391,25 +407,28 @@ sub get_description { } sub get_firewall_references { - my ($self) = @_; - + 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', 'modify') { my $path = "firewall $tree "; $config->setLevel($path); - my @names = $config->listOrigNodes(); + my @names = $config->$lfunc(); foreach my $name (@names) { my $name_path = "$path $name rule "; $config->setLevel($name_path); - my @rules = $config->listOrigNodes(); + 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->returnOrigValue($group_type); + 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"; diff --git a/scripts/firewall/vyatta-ipset.pl b/scripts/firewall/vyatta-ipset.pl index 18bd270..7ee7bdc 100755 --- a/scripts/firewall/vyatta-ipset.pl +++ b/scripts/firewall/vyatta-ipset.pl @@ -31,6 +31,7 @@ use Vyatta::Config; use Vyatta::TypeChecker; use Vyatta::Misc; use Vyatta::IpTables::IpSet; +use Sort::Versions; use warnings; use strict; @@ -82,13 +83,9 @@ sub ipset_check_set_type { die "Error: undefined set_name\n" if ! defined $set_name; die "Error: undefined set_type\n" if ! defined $set_type; - my $group = new Vyatta::IpTables::IpSet($set_name); - return "Group [$set_name] has not been defined\n" if ! $group->exists(); - my $type = $group->get_type(); - $type = 'undefined' if ! defined $type; - if ($type ne $set_type) { - return "Error: group [$set_name] is of type [$type] not [$set_type]\n"; - } + my $cfg = new Vyatta::Config; + return "Group [$set_name] has not been defined\n" + if (!$cfg->exists("firewall group $set_type-group $set_name")); return; } @@ -127,12 +124,16 @@ sub ipset_is_set_empty { sub ipset_show_sets { my @lines = `ipset -L`; + my @sets = (); foreach my $line (@lines) { if ($line =~ /^Name:\s+(\S+)$/ ) { - ipset_show_members($1); - print "\n"; + push @sets, $1; } } + foreach my $set (sort { versioncmp($b, $a) } (@sets)) { + ipset_show_members($set); + print "\n"; + } return; } @@ -199,6 +200,56 @@ sub ipset_is_group_used { exit 1; } +sub update_set { + my ($set_name, $set_type) = @_; + my $cfg = new Vyatta::Config; + my $rc; + my $cpath = "firewall group $set_type-group $set_name"; + if ($cfg->existsOrig($cpath)) { + if (!$cfg->exists($cpath)) { + # deleted + return $rc if (($rc = ipset_delete($set_name))); + return; + } + } else { + if ($cfg->exists($cpath)) { + # added + return $rc if (($rc = ipset_create($set_name, $set_type))); + } else { + # doesn't exist! should not happen + return "Updating non-existent group [$set_name]"; + } + + } + # added or potentially changed => iterate members + my @ovals = $cfg->returnOrigValues("$cpath $set_type"); + my @nvals = $cfg->returnValues("$cpath $set_type"); + my %vals = $cfg->compareValueLists(\@ovals, \@nvals); + for my $d (@{$vals{deleted}}) { + return $rc if (($rc = ipset_delete_member($set_name, $d))); + } + for my $a (@{$vals{added}}) { + return $rc if (($rc = ipset_add_member($set_name, $a))); + } + exit 0; +} + +sub prune_deleted_sets { + my $cfg = new Vyatta::Config; + my @set_types = keys(%Vyatta::IpTables::IpSet::grouptype_hash); + foreach my $set_type (@set_types) { + $cfg->setLevel("firewall group $set_type-group"); + my %groups = $cfg->listNodeStatus(); + next if (scalar(keys(%groups)) < 1); + foreach my $g (keys(%groups)) { + next if ($groups{$g} ne 'deleted'); + next if ($cfg->isEffective($g)); # don't prune if delete failed + my $rc; + return $rc if (($rc = ipset_delete($g))); + } + } + exit 0; +} # # main @@ -242,6 +293,9 @@ $rc = ipset_is_group_deleted($set_name, $set_type) $rc = ipset_is_group_used($set_name, $set_type) if $action eq 'is-group-used'; +$rc = update_set($set_name, $set_type) if $action eq 'update-set'; +$rc = prune_deleted_sets() if $action eq 'prune-deleted-sets'; + if (defined $rc) { print $rc; exit 1; diff --git a/templates/firewall/group/address-group/node.def b/templates/firewall/group/address-group/node.def index 40462fa..5b2e510 100644 --- a/templates/firewall/group/address-group/node.def +++ b/templates/firewall/group/address-group/node.def @@ -15,12 +15,5 @@ syntax:expression: pattern $VAR(@) "^[^!]" ; \ syntax:expression: pattern $VAR(@) "^[^|;&$<>]*$" ; \ "Firewall group name cannot contain shell punctuation" -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(@)" +end: sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=update-set \ + --set-name="$VAR(@)" --set-type=address diff --git a/templates/firewall/group/address-group/node.tag/address/node.def b/templates/firewall/group/address-group/node.tag/address/node.def index a04dd5b..2629b9d 100644 --- a/templates/firewall/group/address-group/node.tag/address/node.def +++ b/templates/firewall/group/address-group/node.tag/address/node.def @@ -10,96 +10,3 @@ syntax:expression: exec "sudo /opt/vyatta/sbin/vyatta-ipset.pl \ --set-type=address \ --member=\"$VAR(@)\"; " -create: tmpgrp=$VAR(../@)-$PPID - len=${#tmpgrp} - if [ "$len" -gt 31 ]; then - tmpgrp=${tmpgrp: -31}; - if [[ "$tmpgrp" =~ ^- ]]; then - tmpgrp=${tmpgrp/-/Z}; - fi - fi - tmpfile="/tmp/$tmpgrp"; - - # echo create $VAR(@) $tmpgrp $COMMIT_SIBLING_POSITION - - if [ "$COMMIT_SIBLING_POSITION" = "FIRST" ] || \ - [ "$COMMIT_SIBLING_POSITION" = "FIRSTLAST" ] ; then - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=is-set-empty \ - --set-name=$VAR(../@) - if [ $? != 0 ]; then - # echo create $tmpfile; - touch $tmpfile; - fi; - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=copy-set \ - --set-name=$VAR(../@) --set-type=address --set-copy=$tmpgrp - # echo create $tmpgrp - fi; - - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=add-member \ - --set-name="$tmpgrp" --member="$VAR(@)" --alias=$VAR(../@) - if [ $? != 0 ]; then - # echo error adding, destroy $tmpgrp - sudo ipset --destroy $tmpgrp; - if [ -e $tmpfile ]; then - # echo destroy $VAR(../@) - sudo ipset --destroy $VAR(../@); - rm $tmpfile; - fi; - exit 1; - fi; - - if [ "$COMMIT_SIBLING_POSITION" = "LAST" ] || \ - [ "$COMMIT_SIBLING_POSITION" = "FIRSTLAST" ] ; then - # echo swap and destroy $tmpgrp - sudo ipset --swap $tmpgrp "$VAR(../@)"; - sudo ipset --destroy $tmpgrp; - rm -f $tmpfile; - fi; - -delete: tmpgrp=$VAR(../@)-$PPID - len=${#tmpgrp} - if [ "$len" -gt 31 ]; then - tmpgrp=${tmpgrp: -31}; - if [[ "$tmpgrp" =~ ^- ]]; then - tmpgrp=${tmpgrp/-/Z}; - fi - fi - tmpfile="/tmp/$tmpgrp"; - - # echo delete $VAR(@) $tmpgrp $COMMIT_SIBLING_POSITION - - if [ "$COMMIT_SIBLING_POSITION" = "FIRST" ] || \ - [ "$COMMIT_SIBLING_POSITION" = "FIRSTLAST" ] ; then - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=is-set-empty \ - --set-name=$VAR(../@) - if [ $? != 0 ]; then - # echo create $tmpfile; - touch $tmpfile; - fi; - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=copy-set \ - --set-name=$VAR(../@) --set-type=address --set-copy=$tmpgrp - # echo create $tmpgrp - fi; - - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=is-group-deleted \ - --set-name=$VAR(../@) --set-type=address; - if [ $? == 0 ] ; then - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=is-group-used \ - --set-name=$VAR(../@) --set-type=address - if [ $? == 0 ] ; then - echo "Error: group [$VAR(../@)] still in use." - exit 1; - fi - fi - - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=delete-member \ - --set-name=$tmpgrp \ - --member="$VAR(@)" - - if [ "$COMMIT_SIBLING_POSITION" = "LAST" ] || \ - [ "$COMMIT_SIBLING_POSITION" = "FIRSTLAST" ] ; then - # echo swap and destroy $tmpgrp - sudo ipset --swap $tmpgrp "$VAR(../@)"; - sudo ipset --destroy $tmpgrp; - rm -f $tmpfile; - fi; diff --git a/templates/firewall/group/network-group/node.def b/templates/firewall/group/network-group/node.def index e20b536..8e50b7d 100644 --- a/templates/firewall/group/network-group/node.def +++ b/templates/firewall/group/network-group/node.def @@ -15,12 +15,6 @@ syntax:expression: pattern $VAR(@) "^[^!]" ; \ syntax:expression: pattern $VAR(@) "^[^|;&$<>]*$" ; \ "Firewall group name cannot contain shell punctuation" -create: sudo /opt/vyatta/sbin/vyatta-ipset.pl \ - --action=create-set \ - --set-type=network \ - --set-name="$VAR(@)" +end: sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=update-set \ + --set-name="$VAR(@)" --set-type=network - -delete: sudo /opt/vyatta/sbin/vyatta-ipset.pl \ - --action=delete-set \ - --set-name="$VAR(@)" diff --git a/templates/firewall/group/network-group/node.tag/network/node.def b/templates/firewall/group/network-group/node.tag/network/node.def index 4db4d49..7388561 100644 --- a/templates/firewall/group/network-group/node.tag/network/node.def +++ b/templates/firewall/group/network-group/node.tag/network/node.def @@ -12,21 +12,3 @@ syntax:expression: exec "sudo /opt/vyatta/sbin/vyatta-ipset.pl \ 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=is-group-deleted \ - --set-name=$VAR(../@) --set-type=network; - if [ $? == 0 ] ; then - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=is-group-used \ - --set-name=$VAR(../@) --set-type=network - if [ $? == 0 ] ; then - echo "Error: group [$VAR(../@)] still in use." - exit 1; - fi - fi - - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=delete-member \ - --set-name=$VAR(../@) \ - --member="$VAR(@)" diff --git a/templates/firewall/group/port-group/node.def b/templates/firewall/group/port-group/node.def index 76fef9e..949403e 100644 --- a/templates/firewall/group/port-group/node.def +++ b/templates/firewall/group/port-group/node.def @@ -15,12 +15,5 @@ syntax:expression: pattern $VAR(@) "^[^!]" ; \ syntax:expression: pattern $VAR(@) "^[^|;&$<>]*$" ; \ "Firewall group name cannot contain shell punctuation" -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(@)" +end: sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=update-set \ + --set-name="$VAR(@)" --set-type=port diff --git a/templates/firewall/group/port-group/node.tag/port/node.def b/templates/firewall/group/port-group/node.tag/port/node.def index 6e657c4..7a9b867 100644 --- a/templates/firewall/group/port-group/node.tag/port/node.def +++ b/templates/firewall/group/port-group/node.tag/port/node.def @@ -11,90 +11,3 @@ syntax:expression: exec "sudo /opt/vyatta/sbin/vyatta-ipset.pl \ --set-name=$VAR(../@) \ --set-type=port \ --member=\"$VAR(@)\"; " - -create: tmpgrp=$VAR(../@)-$PPID - len=${#tmpgrp} - if [ "$len" -gt 31 ]; then - tmpgrp=${tmpgrp: -31}; - if [[ "$tmpgrp" =~ ^- ]]; then - tmpgrp=${tmpgrp/-/Z}; - fi - fi - tmpfile="/tmp/$tmpgrp"; - - if [ "$COMMIT_SIBLING_POSITION" = "FIRST" ] || \ - [ "$COMMIT_SIBLING_POSITION" = "FIRSTLAST" ] ; then - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=is-set-empty \ - --set-name=$VAR(../@) - if [ $? != 0 ]; then - touch $tmpfile; - fi; - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=copy-set \ - --set-name=$VAR(../@) --set-type=port --set-copy=$tmpgrp - fi; - - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=add-member \ - --set-name="$tmpgrp" --member="$VAR(@)" --alias=$VAR(../@) - if [ $? != 0 ]; then - sudo ipset --destroy $tmpgrp; - if [ -e $tmpfile ]; then - sudo ipset --destroy $VAR(../@); - rm $tmpfile; - fi; - exit 1; - fi; - - if [ "$COMMIT_SIBLING_POSITION" = "LAST" ] || \ - [ "$COMMIT_SIBLING_POSITION" = "FIRSTLAST" ] ; then - sudo ipset --swap $tmpgrp "$VAR(../@)"; - sudo ipset --destroy $tmpgrp; - rm -f $tmpfile; - fi; - -delete: tmpgrp=$VAR(../@)-$PPID - len=${#tmpgrp} - if [ "$len" -gt 31 ]; then - tmpgrp=${tmpgrp: -31}; - if [[ "$tmpgrp" =~ ^- ]]; then - tmpgrp=${tmpgrp/-/Z}; - fi - fi - tmpfile="/tmp/$tmpgrp"; - - # echo delete $VAR(@) $tmpgrp $COMMIT_SIBLING_POSITION - - if [ "$COMMIT_SIBLING_POSITION" = "FIRST" ] || \ - [ "$COMMIT_SIBLING_POSITION" = "FIRSTLAST" ] ; then - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=is-set-empty \ - --set-name=$VAR(../@) - if [ $? != 0 ]; then - # echo create $tmpfile; - touch $tmpfile; - fi; - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=copy-set \ - --set-name=$VAR(../@) --set-type=port --set-copy=$tmpgrp - # echo create $tmpgrp - fi; - - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=is-group-deleted \ - --set-name=$VAR(../@) --set-type=port; - if [ $? == 0 ] ; then - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=is-group-used \ - --set-name=$VAR(../@) --set-type=port - if [ $? == 0 ] ; then - echo "Error: group [$VAR(../@)] still in use." - exit 1; - fi - fi - - sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=delete-member \ - --set-name=$tmpgrp \ - --member="$VAR(@)" - - if [ "$COMMIT_SIBLING_POSITION" = "LAST" ] || \ - [ "$COMMIT_SIBLING_POSITION" = "FIRSTLAST" ] ; then - # echo swap and destroy $tmpgrp - sudo ipset --swap $tmpgrp "$VAR(../@)"; - sudo ipset --destroy $tmpgrp; - rm -f $tmpfile; - fi; diff --git a/templates/firewall/modify/node.def b/templates/firewall/modify/node.def index e1f82f3..640a89c 100644 --- a/templates/firewall/modify/node.def +++ b/templates/firewall/modify/node.def @@ -24,6 +24,7 @@ end: if sudo /opt/vyatta/sbin/vyatta-firewall.pl --update-rules modify "$VAR(@)" else exit 1; fi + sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=prune-deleted-sets create: sudo /opt/vyatta/sbin/vyatta-firewall.pl --setup iptables modify diff --git a/templates/firewall/name/node.def b/templates/firewall/name/node.def index 7e9bc44..e8be1cd 100644 --- a/templates/firewall/name/node.def +++ b/templates/firewall/name/node.def @@ -24,6 +24,7 @@ end: if sudo /opt/vyatta/sbin/vyatta-firewall.pl --update-rules name "$VAR(@)" ; else exit 1; fi + sudo /opt/vyatta/sbin/vyatta-ipset.pl --action=prune-deleted-sets create: sudo /opt/vyatta/sbin/vyatta-firewall.pl --setup iptables name diff --git a/templates/firewall/node.def b/templates/firewall/node.def index 30b5330..6ee0386 100644 --- a/templates/firewall/node.def +++ b/templates/firewall/node.def @@ -1,4 +1,4 @@ -priority: 215 +priority: 199 help: Firewall delete: # set conntrack table size to standard 16384 entries if fw disabled |