与子网列表匹配
matching against a list of subnets
有一个以网络地址/掩码形式的子网列表,例如12.34.45.0/24 192.168.0.0/16 45.0.0.0/10…
想知道判断给定IP地址是否在任何子网中的最佳方法是什么。
以下是匹配的一些背景:对于IP地址x,我们将其转换为一个整数。例如,11.12.13.14被转换为0x0b0c0d0e。对于掩码m,我们将其转换为整数,其前导(32-m)位为1,其余为0。
要检查IP x是否在子网A/m中,
我们只需要检查(x&m) == (A&m)
想知道是什么数据结构或功能可以快速匹配一系列子网。当然,我们可以循环通过子网,但这并不有效。
制作一个树,其中每个级别代表IP地址的n位。在每个级别上存储子网,以便掩码位数在n * level
和n * (level +1)
之间。例如,当n=4时,每个节点有16个子节点。因此,如果你正在针对11.12.13.14
(==0x0b0c0d0e
)进行测试,你可以这样走树:
0 -> b -> 0 -> c -> 0 -> d -> 0 -> e
在节点上,您可以跟踪具有相应大小的子网。我的意思是:级别0应该有子网/1到/4(包括),级别1应该有子网络/5到/8,依此类推,直到/29到/32。请注意,/0匹配所有内容,因此在数据结构中使用它是无用的。
要在树中进行搜索,请将IP分组为n位(在我的示例4中)。下降到与前n位匹配的第一个级别,并测试该级别上的所有子网。如果未找到,则下降到与接下来的n个比特匹配的下一级别。
通过这种方式,您必须测试每个2^n个子网的32/n级别(最大值)。对于n=4,您必须测试8个级别,每个级别最多有16个子网。这很快就能完成。
说明:节点是一个子网,例如(十六进制中,一位是一个半字节,即4位):0a.A.00.00/16。此节点的父节点将是包含此子网的子网:例如:0a.50.00.00/12。指向子节点的边可以解释为:"包含",如:"此(父)子网包含由子节点表示的子网"。为了使此树包含您想要的所有子网,您可能必须插入节点,这些节点表示不在列表中的子网。因此,将这些节点标记为辅助节点,这样您就可以知道,在搜索此树时,您知道在它下面有更多特定的子网,但节点本身不在要检查的子网列表中。您只需要添加这些直接在列表中的节点,以及所有父节点,就可以在树结构中访问这些节点。
以下是我如何看待它的struct
:
struct subnet_tree_node
{
uint_32 ip; // 32 bit IP address
subnet_tree_node *children;
uint_8 number_of_children;
uint_8 mask; // number of bits for this subnet
uint_8 valid; // wether this node is valid or auxiliary
}
所以您已经确定性能是个问题。
- 将每个网络掩码/地址对视为一对IP地址:第一个有效,最后一个有效
- 让我们假设最后一个有效值总是奇数(不确定/32网络是否真的是这样,但这真的很奇怪)
- 构造这些IP地址的排序向量。(如果网络重叠或有什么愚蠢的事情,就抱怨。)
- 用某种二进制斩波器搜索你的目标IP地址
- 如果IP地址在矢量中,则为a)wierd;b) 在其中一个子网中
- 如果IP地址不在矢量中,并且下面的值是偶数,则它在子网中。如果下面的值是奇数,则它不在子网中
您有任何证据表明性能是个问题吗?只有2^24个子网(好吧,你可以有/28个子网,但它们通常是组织内部的,所以即使组织有a类网络,它们仍然只有2^2 4个子网)。
做1600万个and
和比较将不需要时间。
保持简单(直到你真的必须做得更好)。
感谢这里的讨论,他们给了我这个解决方案的灵感。
首先,在失去一般性的情况下,我们假设没有一个子网覆盖另一个子网(或者我们只是删除较小的一个子网)。
每个子网都被视为一个区间[subnet_min,subnet_max]。
我们只需要将所有子网组织成一个二叉树,每个节点都是一对(subnet_min,subnet_max)。当搜索IP时,它像只基于子网_min的常规二进制搜索一样遍历树,目的是在<=给定IP。找到该节点后,我们检查该节点的subnet_max是否大于给定的IP。如果是这样,则给定的IP被子网覆盖,否则,我们可以说该IP不被该节点中的子网覆盖。
最后一点是通过假设两个子网中没有一个子网包含彼此来保证的。
- 从网链套接字请求连接设备的列表
- std::bind() 参数列表中函子的执行顺序(可能与函数参数的求值顺序无关)
- 用初始化列表和超类构造函数声明子类构造函数的正确方式
- Node中的子节点列表在C++中的BFS遍历过程中丢失
- 如何从 getifaddr 读取子网掩码
- 获取位于特定区间的已排序值列表的子列表的最短方法
- C++ 链表合并排序的实现在连接 1 个以上节点的子列表时失败
- C++将静态多态类自添加到子类的 constexpr 列表中
- 使用GCC的C makefile - 从子文件夹列表中生成源文件列表
- C++类型列表创建子列表
- 子类对象列表重新解释为基类对象列表?(C++11).
- 查找子网中的所有IP
- 正在计算组成给定IP范围的子网列表
- Icmp子网地址请求
- 与子网列表匹配
- 将递增数量的列表子列表存储在vector中
- 正在验证IPv6子网掩码前缀
- 使用boost::asio查找子网中所有可访问的ip
- 如何知道从子网掩码中搜索哪些IP地址
- 查找和跨子网通信