在地址范围中查找未使用的IPv6

时间:2016-02-23 20:10:09

标签: mysql

如何找到2001:48a8::1 to 2001:48a8::ffff范围内的最小未使用IPv6地址,而不是在使用的ips的特定MySQL表中?

我一直遇到的问题是无法在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)进行数学运算时才有效。

1 个答案:

答案 0 :(得分:1)

通常使用位掩码检查IP地址范围。

2001:48a8::5 & FFFF:FFFF::0 = 2001:48a8::0  # in range
2002:48a8::5 & FFFF:FFFF::0 == 2002:48a8::0  # out of range

不幸的是,MySQL中的bitwise operators处理二进制类型,它们通过转换为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)。