diff options
Diffstat (limited to 'lib/Vyatta/IpTables/IpSet.pm')
-rwxr-xr-x | lib/Vyatta/IpTables/IpSet.pm | 412 |
1 files changed, 208 insertions, 204 deletions
diff --git a/lib/Vyatta/IpTables/IpSet.pm b/lib/Vyatta/IpTables/IpSet.pm index 5222edc..37bbb37 100755 --- a/lib/Vyatta/IpTables/IpSet.pm +++ b/lib/Vyatta/IpTables/IpSet.pm @@ -1,24 +1,24 @@ # # 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 **** # @@ -48,7 +48,7 @@ our %grouptype_hash = ( my $logger = 'logger -t IpSet.pm -p local0.warn --'; -# Currently we restrict an address range to a /24 even +# 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. @@ -67,17 +67,15 @@ $SIG{'INT'} = 'INT_handler'; sub new { my ($that, $name, $type) = @_; - my $class = ref ($that) || $that; - my $self = { - %fields, - }; + my $class = ref($that) || $that; + my $self = {%fields,}; if ($name =~ m/^!/) { - $self->{_negate} = 1; - $name =~ s/^!(.*)$/$1/; + $self->{_negate} = 1; + $name =~ s/^!(.*)$/$1/; } $self->{_name} = $name; $self->{_type} = $type; - + bless $self, $class; return $self; } @@ -94,8 +92,8 @@ sub run_cmd { my $rc = system("sudo $cmd"); if (defined $self->{_debug}) { - my $func = (caller(1))[3]; - system("$logger [$func] [$cmd] = [$rc]"); + my $func = (caller(1))[3]; + system("$logger [$func] [$cmd] = [$rc]"); } return $rc; } @@ -104,12 +102,12 @@ sub exists { my ($self) = @_; return 1 if defined $self->{_exists}; - return 0 if ! defined $self->{_name}; + 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}; + $self->{_exists} = 1; + $self->get_type() if !defined $self->{_type}; } return $rc ? 0 : 1; } @@ -118,21 +116,21 @@ sub get_type { my ($self) = @_; return $self->{_type} if defined $self->{_type}; - return if ! $self->exists(); + return if !$self->exists(); my @lines = `ipset -L $self->{_name}`; my $type; foreach my $line (@lines) { - if ($line =~ /^Type:\s+([\w:]+)$/) { - $type = $1; - last; - } + if ($line =~ /^Type:\s+([\w:]+)$/) { + $type = $1; + last; + } } - return if ! defined $type; + return if !defined $type; foreach my $vtype (keys(%grouptype_hash)) { - if ($grouptype_hash{$vtype} eq $type) { - $self->{_type} = $vtype; - last; - } + if ($grouptype_hash{$vtype} eq $type) { + $self->{_type} = $vtype; + last; + } } return $self->{_type}; } @@ -147,54 +145,54 @@ 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; - } + 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(); + return @members if !$self->exists(); my @lines = `ipset -L $self->{_name} -s`; foreach my $line (@lines) { - push @members, $line if $line =~ /^\d/; + push @members, $line if $line =~ /^\d/; } if ($self->{_type} ne 'port') { - @members = sort { natural_order($a,$b) } @members; + @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 "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; + return "Error: invalid group type\n" if !defined $ipset_param; if ($self->{_type} eq 'port') { - $ipset_param .= ' --from 1 --to 65535'; - } + $ipset_param .= ' --from 1 --to 65535'; + } - my $cmd = "ipset -N $self->{_name} $ipset_param"; + my $cmd = "ipset -N $self->{_name} $ipset_param"; my $rc = $self->run_cmd($cmd); return "Error: call to ipset failed [$rc]" if $rc; return; # undef @@ -203,45 +201,47 @@ sub create { sub references { my ($self) = @_; - return 0 if ! $self->exists(); + return 0 if !$self->exists(); my @lines = `ipset -L $self->{_name}`; foreach my $line (@lines) { - if ($line =~ /^References:\s+(\d+)$/) { - return $1; - } + 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; + 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); - } + 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(); + 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 { @@ -249,57 +249,61 @@ sub reset_ipset_all { 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; + my $group; foreach $group (@pgroups) { - my $grp = new Vyatta::IpTables::IpSet($group, "port"); - $grp->reset_ipset_named(); + 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(); + 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(); + 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 + + # 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: 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(); + + # 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}"; @@ -312,10 +316,10 @@ sub check_member_address { my $member = shift; if (!Vyatta::TypeChecker::validateType('ipv4', $member, 1)) { - return "Error: [$member] isn't valid IPv4 address\n"; + 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 "Error: zero IP address not valid in address-group\n"; } return; } @@ -323,8 +327,8 @@ sub check_member_address { sub check_member { my ($self, $member) = @_; - return "Error: undefined group name" if ! defined $self->{_name}; - return "Error: undefined group type" if ! defined $self->{_type}; + 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 @@ -332,72 +336,72 @@ sub check_member { # 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; - } + 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: zero net invalid in network-group\n" - if $net eq '0.0.0.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"; - } + 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: zero net invalid in network-group\n" + if $net eq '0.0.0.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; + 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 "Error: invalid set type [$self->{_type}]"; } - return; #undef + return; #undef } sub member_exists { my ($self, $member) = @_; - + my $cmd = "ipset -T $self->{_name} $member -q"; my $rc = $self->run_cmd($cmd); - return $rc ? 0 : 1; + return $rc ? 0 : 1; } sub add_member { my ($self, $member, $alias, $hyphenated_port) = @_; - return "Error: undefined group name" if ! defined $self->{_name}; + 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"; + $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); @@ -406,21 +410,21 @@ sub add_member { } sub delete_member_range { - my ($self, $start, $stop) = @_; - + 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; - } + 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; + 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; } @@ -428,17 +432,17 @@ sub delete_member_range { sub delete_member { my ($self, $member, $hyphenated_port) = @_; - return "Error: undefined group name" if ! defined $self->{_name}; + 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); + return $self->delete_member_range($1, $2); } if (!$self->member_exists($member)) { - return "Error: member [$member] doesn't exists in [$self->{_name}]\n"; + return "Error: member [$member] doesn't exists in [$self->{_name}]\n"; } my $cmd = "ipset -D $self->{_name} $member"; my $rc = $self->run_cmd($cmd); @@ -449,10 +453,10 @@ sub delete_member { sub get_description { my ($self) = @_; - return if ! $self->exists(); + return if !$self->exists(); my $config = new Vyatta::Config; my $group_type = "$self->{_type}-group"; - $config->setLevel("firewall group $group_type $self->{_name}"); + $config->setLevel("firewall group $group_type $self->{_name}"); return $config->returnOrigValue('description'); } @@ -463,29 +467,29 @@ sub get_firewall_references { ($lfunc, $vfunc) = qw(listNodes returnValue); } my @fw_refs = (); - return @fw_refs if ! $self->exists(); + 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->$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 + 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; } @@ -493,10 +497,10 @@ sub get_firewall_references { sub rule { my ($self, $direction) = @_; - if (! $self->exists()) { - my $name = $self->{_name}; - $name = 'undefined' if ! defined $name; - return (undef, "Undefined group [$name]"); + if (!$self->exists()) { + my $name = $self->{_name}; + $name = 'undefined' if !defined $name; + return (undef, "Undefined group [$name]"); } my $srcdst; @@ -504,10 +508,10 @@ sub rule { $srcdst = 'src' if $direction eq 'source'; $srcdst = 'dst' if $direction eq 'destination'; - return (undef, "Invalid direction [$direction]") if ! defined $srcdst; + return (undef, "Invalid direction [$direction]") if !defined $srcdst; my $opt = ''; $opt = '!' if $self->{_negate}; - return (" -m set $opt --match-set $grp $srcdst ", ); + return (" -m set $opt --match-set $grp $srcdst ",); } 1; |