继这篇文章之后,我对搜索 IPv6 地址范围很感兴趣。
在 IPv4 下,我将能够确定 ISP 提供的开始和结束 IP 地址,并使用这些整数值作为范围边界快速搜索数据库以查看数据库中是否有任何条目落入该范围。
IPv6 将如何影响这一点?ISP 是否仍会像现在一样在范围内拥有 IPv6 地址?如果您将 IPv6 地址作为两个 bigint 存储在 SQL Server DB 中,您将如何有效地搜索这些范围?
在范围内使用 IP 地址(既不是 IPv4 也不是 IPv6)是不正确的。对 IP 地址的特定“范围”进行分组的正确方法是使用前缀(CIDR 表示法)或掩码(已过时,仅对 IPv4 有效,如果您尝试使用非连续掩码,则会出现精神错乱)。
有时您会看到有人(有时甚至是应用程序、家庭路由器等)使用 IPv4 范围,但这是错误的做法。
使用无类域间路由 (CIDR),您将有一个元组 <Address, Prefix>,其中 Address 是一个 128 位无符号整数,Prefix 是一个微小的 (0..128) 无符号整数。前缀告诉地址有多少个最高有效位代表网络地址,剩下的其他 128 个前缀最低有效位代表该网络中的特定主机。
因此,例如,2620:0:860:2::/64 (wikimedia.org) 的 IPv6“范围”表示从 2620:0:860:2:: 到 2620:0:860:2 的所有主机: FFFF:FFFF:FFFF:FFFF。
您不应该使用两个“bigint”将这样的值存储在数据库中,而应在单个列中使用任何本机表示,除非您想让您的开发人员生活成为一场噩梦。如果您的 DBMS 不支持这么大的整数,除了替换您的 DBMS 之外,我建议使用 16 字节长的固定大小的二进制数据列。
使用适当支持 IPv6 地址的 DBMS 并不是一个坏主意。以下是 PostgreSQL 版本 8.3 的示例:
mydb=> CREATE TABLE Networks (name TEXT, prefix INET);
CREATE TABLE
mydb=> INSERT INTO Networks VALUES ('Documentation', '2001:DB8::/32');
INSERT 0 1
mydb=> INSERT INTO Networks VALUES ('ULA', 'FC00::/7');
INSERT 0 1
mydb=> INSERT INTO Networks VALUES ('Orchid', '2001:10::/28');
INSERT 0 1
mydb=> SELECT * FROM Networks;
name | prefix
---------------+---------------
Documentation | 2001:db8::/32
ULA | fc00::/7
Orchid | 2001:10::/28
(3 rows)
mydb=> SELECT * FROM Networks WHERE '2001:DB8::dcaf:BAD' << prefix;
name | prefix
---------------+---------------
Documentation | 2001:db8::/32
(1 row)