如何在 2001:48a8::1 到 2001:48a8::ffff
范围内找到最小未使用的 IPv6 地址,而不是在特定的 MySQL 已用 ips 表中?
我一直遇到的问题是无法对 varbinary(16)
我的整个想法是这样的:
SELECT MIN(IpAddress)+1
FROM IpAddresses t1
WHERE NOT EXISTS (SELECT *
FROM IpAddresses AS t2
WHERE t2.IPAddress = t1.IPAddress+1
AND t2.AddressRangeID = ?)
但这只有在我真的可以使用 varbinary(16)
进行数学计算时才有效。
最佳答案
通常使用位掩码检查 IP 地址范围。
2001:48a8::5 & FFFF:FFFF::0 = 2001:48a8::0 # in range
2002:48a8::5 & FFFF:FFFF::0 == 2002:48a8::0 # out of range
不幸的是 bitwise operators在 MySQL 中处理二进制类型时,它们通过转换为 64 位大整数来实现,而不是 IPv6 地址所需的 128 位。
幸运的是,我们可以在 VARBINARY 数据上使用字符串函数。 LEFT()
执行与位掩码相同的功能。
LEFT(2001:48a8::5, 4) = 200148a8 # in range
LEFT(2002:48a8::5, 4) = 200248a8 # out of range
它是 LEFT(x, 4)
而不是 LEFT(x, 8)
因为每个十六进制字符代表 16 位,所以其中两个组成一个 32 位字符。
像这样把它们放在一起。
SELECT HEX(IpAddress), HEX(LEFT(IpAddress, 4))
FROM IpAddresses
WHERE LEFT(IpAddress, 4) = UNHEX("200148A8");
您要求的最小 IP 不在该范围内。由于您不能对 varbinary 进行数学运算,我建议您简单地获取范围内的最大值并在 SQL 之外进行数学运算。
SELECT HEX(MAX(IpAddress))
FROM IpAddresses
WHERE LEFT(IpAddress, 4) = UNHEX("200148A8");
如果您真的想要这样做,请按以下步骤操作。
您不能处理完整地址,但可以只处理最低的 64 位。您可以使用 RIGHT(IpAddress, 8)
获取它。然后需要将它从二进制转换为十六进制再转换为整数。然后你可以在上面做数学运算。
CONV(HEX(RIGHT(IpAddress, 8)), 16, 10) + 1
完成后,必须将其与左侧一起放回原处。为此,必须将其转换回十六进制表示形式并填充为 16 位数字。
B -> 0000000000000000000000000000000B
LPAD( HEX(CONV(HEX(RIGHT(IpAddress, 8)), 16, 10) + 1), 32, '0' )
最后,与左侧连接。
CONCAT(
HEX(LEFT(IpAddress, 8)),
LPAD(
HEX(CONV(HEX(RIGHT(IpAddress, 8)), 16, 10) + 1),
32, '0'
)
)
在这两个地方将 IpAddress
更改为 MAX(IpAddress)
,您将获得下一个 IP 地址。
为了保持每个人的理智,我建议将所有这些都放入一个存储过程中。
我把它留作处理 NULL 结果的练习(提示:使用 CASE)。
关于mysql - 在地址范围内查找未使用的 IPv6,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35587205/