From d55b9e14c14011577354b69cc569d2652d5e31fd Mon Sep 17 00:00:00 2001 From: zsdc Date: Mon, 12 Sep 2022 18:07:01 +0300 Subject: ipset: T2189: optimized firewall groups performance This commit optimizes the speed of interaction with the ipset. * removed extra `sudo` from `ipset` commands, because scripts that run `ipset` commands already run under `sudo`. This gives approximately 4x performance improvement. * replaced logic in the `member_exists` function for port groups. Instead of calling `ipset -T` for each port now the whole list is received in one command and a search process is done inside Perl. This significantly improves speed for port groups with long port ranges inside. * delete ip address and port ranges using a single command instead deleting each element individually. * added the same ranges validation for address-group as for port-group. --- scripts/firewall/vyatta-ipset.pl | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'scripts/firewall') diff --git a/scripts/firewall/vyatta-ipset.pl b/scripts/firewall/vyatta-ipset.pl index a5375dc..43322f3 100755 --- a/scripts/firewall/vyatta-ipset.pl +++ b/scripts/firewall/vyatta-ipset.pl @@ -33,6 +33,7 @@ use Vyatta::Misc; use Vyatta::IpTables::IpSet; use Sort::Versions; use IO::Prompt; +use NetAddr::IP; use warnings; use strict; @@ -403,23 +404,51 @@ sub check_duplicates { # check if this is a port range if ($item =~ /([\d]+)-([\d]+)/) { foreach my $port ($1..$2) { - return "Port $port exist in more than one item\n" if (exists $portlist{$port}); + return "Port $port exists in more than one configuration enrty\n" if (exists $portlist{$port}); $portlist{$port} = undef; } # check if this is an alphabetic port name } elsif ($item =~ /^\D+/) { my $port = getservbyname($item, ""); - return "Port $port exist in more than one item\n" if (exists $portlist{$port}); + return "Port $port exists in more than one configuration enrty\n" if (exists $portlist{$port}); $portlist{$port} = undef; # process simple numeric ports } else { - return "Port $item exist in more than one item\n" if (exists $portlist{$item}); + return "Port $item exists in more than one configuration enrty\n" if (exists $portlist{$item}); $portlist{$item} = undef; } } } + # check duplicates in address-group + if ($set_type eq "address") { + # define hash with addresses as keys + my %addresslist; + + for my $item (@vals) { + # check if this is an address range + if ($item =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})-(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/) { + my $first_ip = new NetAddr::IP("$1/0"); + my $last_ip = new NetAddr::IP("$2/0"); + + for (; $first_ip <= $last_ip; $first_ip++) { + my $current_addr = $first_ip->addr(); + # check if an address already listed + if (exists $addresslist{$current_addr}) { + return "Address $current_addr exists in more than one configuration enrty\n"; + } + # add an address to a list + $addresslist{$current_addr} = undef; + } + # process single addresses + } else { + return "Address $item exists in more than one configuration enrty\n" if (exists $addresslist{$item}); + # add an address to a list + $addresslist{$item} = undef; + } + } + } # do not return anything if there are no duplicates return; -- cgit v1.2.3