从整数范围创建按位匹配的集合
Create collection of bitwise matches from an integer range
... 以下列格式描述填充规则:
Range matches can be expressed as a collection of bitwise matches. For
example, suppose that the goal is to match TCP source ports 1000 to
1999, inclusive. The binary representations of 1000 and 1999 are:
01111101000
11111001111
The following series of bitwise matches will match 1000 and 1999 and
all the values in between:
01111101xxx
0111111xxxx
10xxxxxxxxx
110xxxxxxxx
1110xxxxxxx
11110xxxxxx
1111100xxxx
which can be written as the following matches:
tcp,tp_src=0x03e8/0xfff8
tcp,tp_src=0x03f0/0xfff0
tcp,tp_src=0x0400/0xfe00
tcp,tp_src=0x0600/0xff00
tcp,tp_src=0x0700/0xff80
tcp,tp_src=0x0780/0xffc0
tcp,tp_src=0x07c0/0xfff0
我正在尝试根据 perl 中的最小和最大整数值确定生成这些匹配项的正确方法。我查看了模块 Bit::Vector ,但我无法弄清楚如何为此目的有效地使用它。
假设我们正在尝试解决十进制的等价问题。
假设你想要567(含)到1203(不含)。
- 放大阶段
- 你递增 1,直到你有 10 的倍数,否则你会超出范围。
- ⇒598(创造 597-597)
- ⇒599(创造 598-598)
- ⇒600(创造599-599)
- 你递增 10,直到你有 100 的倍数,否则你会超出范围。
- 你增加 100,直到你有 1000 的倍数,否则你会超出范围。
- ⇒700(创造 600-699)
- ⇒800(创造 700-799)
- ⇒900(创造800-899)
- ⇒1000(创造 900-999)
- 你增加 1000,直到你有 10000 的倍数,否则你会超出范围。
- [会超出限制]
- 收缩阶段
- 您递增 100,直到超出范围。
- ⇒1100(创造1000-1099)
- ⇒1200(创造1100-1199)
- 您递增 10,直到超出范围。
- 您递增 1,直到超出范围。
- ⇒1201(创造1200-1200)
- ⇒1202(创造1201-1201)
- ⇒1203(创造1202-1202)
二进制相同,但使用 2 的幂而不是 10 的幂。
my $start = 1000;
my $end = 1999 + 1;
my @ranges;
my $this = $start;
my $this_power = 1;
OUTER: while (1) {
my $next_power = $this_power * 2;
while ($this % $next_power) {
my $next = $this + $this_power;
last OUTER if $next > $end;
my $mask = ~($this_power - 1) & 0xFFFF;
push @ranges, sprintf("0x%04x/0x%x", $this, $mask);
$this = $next;
}
$this_power = $next_power;
}
while ($this_power > 1) {
$this_power /= 2;
while (1) {
my $next = $this + $this_power;
last if $next > $end;
my $mask = ~($this_power - 1) & 0xFFFF;
push @ranges, sprintf("0x%04x/0x%x", $this, $mask);
$this = $next;
}
}
say for @ranges;
我们可以利用我们正在处理二进制文件这一事实对其进行优化。
my $start = 1000;
my $end = 1999 + 1;
my @ranges;
my $this = $start;
my $power = 1;
my $mask = 0xFFFF;
while ($start & $mask) {
if ($this & $power) {
push @ranges, sprintf("0x%04x/0x%x", $this, $mask);
$this += $power;
}
$mask &= ~$power;
$power <<= 1;
}
while ($end & ~$mask) {
$power >>= 1;
$mask |= $power;
if ($end & $power) {
push @ranges, sprintf("0x%04x/0x%x", $this, $mask);
$this |= $power;
}
}
say for @ranges;
输出:
0x03e8/0xfff8
0x03f0/0xfff0
0x0400/0xfe00
0x0600/0xff00
0x0700/0xff80
0x0780/0xffc0
0x07c0/0xfff0
我尝试使用@ikegami 提供的非常优雅的解决方案,但发现有一些边缘情况导致端口超出范围或缺少端口(例如 1-6、1000-4000、1000-10000)。这种替代方法似乎可以避免这些问题。
my $LIMIT = 65535;
sub maxPort {
my ($port, $mask) = @_;
my $xid = $LIMIT - $mask;
my $nid = $port & $mask;
return $nid + $xid;
}
sub portMask {
my ($port, $end) = @_;
my $mask = $LIMIT;
my $test_mask = $LIMIT;
my $bit = 1;
my $net = $port & $LIMIT;
my $max_port = maxPort($net, $LIMIT);
while ($net && ($max_port <= $end)) {
$net = $port & $test_mask;
if ($net < $port) {
last;
}
$max_port = maxPort($net, $test_mask);
if ($max_port <= $end) {
$mask = $test_mask;
}
$test_mask -= $bit;
$bit <<= 1;
}
return $mask;
}
sub maskRange {
my ($start, $end) = @_;
my @portMasks;
if (($end <= $start) || ($end > $LIMIT)) {
exit 1;
}
my $mask = $LIMIT;
my $port = $start;
while ($port <= $end) {
$mask = portMask($port, $end);
push @portMasks, sprintf("0x%04x/0x%x", $port, $mask);
$port = maxPort($port, $mask) + 1;
}
return @portMasks;
}
my @ranges = maskRange(1000, 1999);
for (@ranges) {
print("$_", "\n");
}
输出:
0x03e8/0xfff8
0x03f0/0xfff0
0x0400/0xfe00
0x0600/0xff00
0x0700/0xff80
0x0780/0xffc0
0x07c0/0xfff0
... 以下列格式描述填充规则:
Range matches can be expressed as a collection of bitwise matches. For example, suppose that the goal is to match TCP source ports 1000 to 1999, inclusive. The binary representations of 1000 and 1999 are:
01111101000
11111001111
The following series of bitwise matches will match 1000 and 1999 and all the values in between:
01111101xxx
0111111xxxx
10xxxxxxxxx
110xxxxxxxx
1110xxxxxxx
11110xxxxxx
1111100xxxx
which can be written as the following matches:
tcp,tp_src=0x03e8/0xfff8
tcp,tp_src=0x03f0/0xfff0
tcp,tp_src=0x0400/0xfe00
tcp,tp_src=0x0600/0xff00
tcp,tp_src=0x0700/0xff80
tcp,tp_src=0x0780/0xffc0
tcp,tp_src=0x07c0/0xfff0
我正在尝试根据 perl 中的最小和最大整数值确定生成这些匹配项的正确方法。我查看了模块 Bit::Vector ,但我无法弄清楚如何为此目的有效地使用它。
假设我们正在尝试解决十进制的等价问题。
假设你想要567(含)到1203(不含)。
- 放大阶段
- 你递增 1,直到你有 10 的倍数,否则你会超出范围。
- ⇒598(创造 597-597)
- ⇒599(创造 598-598)
- ⇒600(创造599-599)
- 你递增 10,直到你有 100 的倍数,否则你会超出范围。
- 你增加 100,直到你有 1000 的倍数,否则你会超出范围。
- ⇒700(创造 600-699)
- ⇒800(创造 700-799)
- ⇒900(创造800-899)
- ⇒1000(创造 900-999)
- 你增加 1000,直到你有 10000 的倍数,否则你会超出范围。
- [会超出限制]
- 你递增 1,直到你有 10 的倍数,否则你会超出范围。
- 收缩阶段
- 您递增 100,直到超出范围。
- ⇒1100(创造1000-1099)
- ⇒1200(创造1100-1199)
- 您递增 10,直到超出范围。
- 您递增 1,直到超出范围。
- ⇒1201(创造1200-1200)
- ⇒1202(创造1201-1201)
- ⇒1203(创造1202-1202)
- 您递增 100,直到超出范围。
二进制相同,但使用 2 的幂而不是 10 的幂。
my $start = 1000;
my $end = 1999 + 1;
my @ranges;
my $this = $start;
my $this_power = 1;
OUTER: while (1) {
my $next_power = $this_power * 2;
while ($this % $next_power) {
my $next = $this + $this_power;
last OUTER if $next > $end;
my $mask = ~($this_power - 1) & 0xFFFF;
push @ranges, sprintf("0x%04x/0x%x", $this, $mask);
$this = $next;
}
$this_power = $next_power;
}
while ($this_power > 1) {
$this_power /= 2;
while (1) {
my $next = $this + $this_power;
last if $next > $end;
my $mask = ~($this_power - 1) & 0xFFFF;
push @ranges, sprintf("0x%04x/0x%x", $this, $mask);
$this = $next;
}
}
say for @ranges;
我们可以利用我们正在处理二进制文件这一事实对其进行优化。
my $start = 1000;
my $end = 1999 + 1;
my @ranges;
my $this = $start;
my $power = 1;
my $mask = 0xFFFF;
while ($start & $mask) {
if ($this & $power) {
push @ranges, sprintf("0x%04x/0x%x", $this, $mask);
$this += $power;
}
$mask &= ~$power;
$power <<= 1;
}
while ($end & ~$mask) {
$power >>= 1;
$mask |= $power;
if ($end & $power) {
push @ranges, sprintf("0x%04x/0x%x", $this, $mask);
$this |= $power;
}
}
say for @ranges;
输出:
0x03e8/0xfff8
0x03f0/0xfff0
0x0400/0xfe00
0x0600/0xff00
0x0700/0xff80
0x0780/0xffc0
0x07c0/0xfff0
我尝试使用@ikegami 提供的非常优雅的解决方案,但发现有一些边缘情况导致端口超出范围或缺少端口(例如 1-6、1000-4000、1000-10000)。这种替代方法似乎可以避免这些问题。
my $LIMIT = 65535;
sub maxPort {
my ($port, $mask) = @_;
my $xid = $LIMIT - $mask;
my $nid = $port & $mask;
return $nid + $xid;
}
sub portMask {
my ($port, $end) = @_;
my $mask = $LIMIT;
my $test_mask = $LIMIT;
my $bit = 1;
my $net = $port & $LIMIT;
my $max_port = maxPort($net, $LIMIT);
while ($net && ($max_port <= $end)) {
$net = $port & $test_mask;
if ($net < $port) {
last;
}
$max_port = maxPort($net, $test_mask);
if ($max_port <= $end) {
$mask = $test_mask;
}
$test_mask -= $bit;
$bit <<= 1;
}
return $mask;
}
sub maskRange {
my ($start, $end) = @_;
my @portMasks;
if (($end <= $start) || ($end > $LIMIT)) {
exit 1;
}
my $mask = $LIMIT;
my $port = $start;
while ($port <= $end) {
$mask = portMask($port, $end);
push @portMasks, sprintf("0x%04x/0x%x", $port, $mask);
$port = maxPort($port, $mask) + 1;
}
return @portMasks;
}
my @ranges = maskRange(1000, 1999);
for (@ranges) {
print("$_", "\n");
}
输出:
0x03e8/0xfff8
0x03f0/0xfff0
0x0400/0xfe00
0x0600/0xff00
0x0700/0xff80
0x0780/0xffc0
0x07c0/0xfff0