我试图让端口范围1-65535允许用户从中排除某些范围的端口
输入将是逗号分隔的单个或范围的端口号,例如:
1-2,3-4,4-5,5-6,7-8,9-10,1-100
输出应为:
101-65535
我编写的代码涵盖了很多情况,但由于某些原因,我目前所拥有的代码并没有处理上一次排除1-100
,因为9
是当前的最小端口号
这是我的代码:
my @ranges;
push @ranges, '1-65535';
my $bFound = 0;
do {
$bFound = 0;
foreach my $ptrExclusion (@exclusions) {
my %exclusion = %{$ptrExclusion};
print STDERR "handling exclusion @ 7964: ".Dumper(\%exclusion);
my $currentPos = 0;
foreach my $range (@ranges) {
$currentPos++;
if ($range =~ /([0-9]+)-([0-9]+)/) {
my $firstPortInRange = $1;
my $secondPortInRange = $2;
if ($secondPortInRange == $exclusion{first} and
$exclusion{second} == $exclusion{first}) {
$bFound = 1;
my @newranges;
if ($exclusion{first} - 1 > 0) {
push @newranges, "$firstPortInRange-".(sprintf("%d", $exclusion{first} - 1));
} else { # Handle port "1"
### Don't put anything, we are excluded from adding this
}
if ($currentPos > 1) {
unshift @newranges, $ranges[1..($currentPos-1)];
}
if ($currentPos + 1 < scalar(@ranges)) {
push @newranges, $ranges[($currentPos+1) .. scalar(@ranges)];
}
print STDERR "newranges @ 7985: ".Dumper(\@newranges);
@ranges = @newranges;
last;
}
if ($firstPortInRange == $exclusion{first} and
$exclusion{second} == $exclusion{first}) {
$bFound = 1;
my @newranges;
if ($exclusion{second} + 1 <= 65535) {
push @newranges, (sprintf("%d", $exclusion{second} + 1))."-$secondPortInRange";
} else { # Handle port 65535
#### Don't put anything, we are excluded from adding this
}
if ($currentPos > 1) {
unshift @newranges, $ranges[1..($currentPos-1)];
}
if ($currentPos + 1 < scalar(@ranges)) {
push @newranges, $ranges[($currentPos+1) .. scalar(@ranges)];
}
print STDERR "newranges @ 8005: ".Dumper(\@newranges);
@ranges = @newranges;
last;
}
if ($firstPortInRange < $exclusion{first} and
$secondPortInRange > $exclusion{second} # An exclusion is between the ranges we currently have, this doesn't include "hits" on the exact port number, i.e. excluding port 1 and port 65535
) {
print STDERR "exclusion matched @ 8022\n";
$bFound = 1;
#printf (STDERR "currentPos @ 7973: %d\n", $currentPos);
my @newranges;
push @newranges, "$firstPortInRange-".(sprintf("%d", $exclusion{first} - 1));
push @newranges, (sprintf("%d", $exclusion{second} + 1))."-$secondPortInRange";
if ($currentPos > 1) {
unshift @newranges, $ranges[1..($currentPos-1)];
}
if ($currentPos + 1 < scalar(@ranges)) {
push @newranges, $ranges[($currentPos+1) .. scalar(@ranges)];
}
print STDERR "newranges @ 8026: ".Dumper(\@newranges);
@ranges = @newranges;
last;
}
if ($firstPortInRange >= $exclusion{first} and
$firstPortInRange < $exclusion{second} and
$secondPortInRange <= $exclusion{second} and
$secondPortInRange > $exclusion{first} # An exclusion is holding our range inside it
) {
print STDERR "exclusion matched @ 8045\n";
$bFound = 1;
splice(@ranges, $currentPos-1, 1); # -1 as our index starts from 1, while @ranges index starts at 0
print STDERR "ranges @ 8051: ".Dumper(\@ranges);
last;
}
}
}
if ($bFound) {
last;
}
}
} while ($bFound);
print STDERR "ranges @ 7980: ".join(", ", @ranges). "\n";
@exclusions
下面有哈希元素,其中包含first
和second
值,指定端口A和端口B(较低范围和最高范围),如果排除它们的值可以匹配是1端口。
答案 0 :(得分:3)
有许多模块可以使用套装,让您的生活更轻松。我建议Set::IntSpan::Fast:
use strict;
use warnings;
use 5.010;
use Set::IntSpan::Fast;
my $ports = Set::IntSpan::Fast->new('1-65535');
my $exclude = Set::IntSpan::Fast->new('1-2,3-4,4-5,5-6,7-8,9-10,1-100');
say $ports->diff($exclude)->as_string;
101-65535
答案 1 :(得分:3)
Range::Object
模块集非常全面,Range::Object::Serial
完全符合您的要求
这个简短的程序演示了
use strict;
use warnings;
use v5.10;
use Range::Object::Serial;
my $range = Range::Object::Serial->new('1-65535');
say scalar $range->collapsed;
$range->remove('1-2,3-4,4-5,5-6,7-8,9-10,1-100');
say scalar $range->collapsed;
1-65535
101-65535
答案 2 :(得分:0)
这是一次尝试,不使用库,而只是使用数组(因为它不是很大)。
#!/usr/bin/env perl
use warnings;
use strict;
my @port_range = ( 1, 65535 );
my @ports = map { 1 } ( 0 .. $port_range[1] );
my $exclusions = '1-2,3-4,4-5,5-6,7-8,9-10,1-100';
for my $exclusion ( split /,/, $exclusions ) {
if ($exclusion =~ m|\-|) {
# Range
my ($start, $stop) = split /-/, $exclusion;
$ports[$_] = 0 for ($start..$stop);
} else {
# Single port
$ports[$exclusion] = 0;
}
}
my @good_ports = grep { $ports[$_] > 0 } ( $port_range[0] .. $port_range[1] );
my $last_good = 0;
for my $i ( 1 .. $#good_ports ) {
if ($good_ports[$i] - $good_ports[$i-1] > 1) {
# gap
print join '-', $good_ports[$last_good], $good_ports[$i-1] . "\n";
$last_good = $i;
}
}
print join '-', $good_ports[$last_good], $good_ports[$#good_ports] . "\n";
<强>输出强>
101-65535
答案 3 :(得分:0)
在范围尽可能小的情况下,您可以保留每个端口的列表并设置打开的标记。关闭,并打印出结果。
#!/usr/bin/perl
use warnings;
use strict;
# print a list of open ports, given a string of closed ports
my @ports = map { 1 } 1..65535; # start with all ports flagged as open
while (<DATA>) { # get the string of closed port numbers & ranges
chomp;
/\d/ or next; # ensure we have at least one number to work with
my @exclusions = split /,/;
for (@exclusions) {
# each exclusion is a number, optionally followed
# by a dash and another number
/^(\d+)(?:-(\d+))?$/ or next;
# set the flag to 0 for a single port or a range of ports
if ($1 and ! $2) {
$ports[$1-1] = 0; # single port
}
elsif ($1 and $2) {
@ports[$1-1..$2-1] = map {0} $1..$2; # range of ports
}
}
}
# get a list of all ports which are open
my @open_ports = map {$_ + 1} grep {$ports[$_] == 1} 0..$#ports;
# the final list of open port ranges, to be displayed
my @ranges = ();
# build up the list of open ranges
for (@open_ports) {
my $one_less = $_ - 1;
# either add this open port to the previous range,
# or start a new range with this port
#
(@ranges and $ranges[-1] =~ s/-$one_less$/-$_/)
or push @ranges, "$_-$_";
}
# fix single-number ranges for display
for (@ranges) {
s/^(\d+)-\1$/$1/;
}
# display the result
print join ',', @ranges;
__DATA__
1-2,3-4,4-5,5-6,7-8,9-10,1-100
输出:
101-65535