mysql - 在地址范围内查找未使用的 IPv6

标签 mysql

如何在 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/

相关文章:

javascript - 如何返回一个对象而不是数组? (mysql 与 Node ,js)

php - PDO 捕获 PDOException 错误

mysql - 连续几天的特定状态

mysql - 如何使用 RAND() 别名来使用 HAVING 子句

php - 我可以根据 ID 限制 PHP 中结果集的显示吗?

php - 显示奇数和偶数数据

PHP 使用密码加密方案的安全登录系统

php - 不执行 Codeigniter Mysql 查询

mysql - 优化MySQL结构和查询

mysql - 谁能告诉我在 mysql 中如何显示姓名不以字母 A 开头的员工姓名?