Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何在SQL中计算IPv6 CIDR路由前缀?_Sql Server_Tsql_Sql Server 2012_Network Programming_Ipv6 - Fatal编程技术网

Sql server 如何在SQL中计算IPv6 CIDR路由前缀?

Sql server 如何在SQL中计算IPv6 CIDR路由前缀?,sql-server,tsql,sql-server-2012,network-programming,ipv6,Sql Server,Tsql,Sql Server 2012,Network Programming,Ipv6,我一直致力于使用SQL Server 2012实例上运行的T-SQL从IPv4和IPv6地址范围生成CIDR。通常,我们的应用程序(数据库之外)负责计算CIDR,但我目前需要在数据库中进行CIDR计算。由于IPv6太大,无法存储在bigint数据类型中,我们将IP地址存储为binary(4)或binary(16) 计算IPv4范围的路由前缀相对简单,如果有点难看: declare @ipv4_begin binary(4) ,@ipv4_end binary(4) set @ip

我一直致力于使用SQL Server 2012实例上运行的T-SQL从IPv4和IPv6地址范围生成CIDR。通常,我们的应用程序(数据库之外)负责计算CIDR,但我目前需要在数据库中进行CIDR计算。由于IPv6太大,无法存储在
bigint
数据类型中,我们将IP地址存储为
binary(4)
binary(16)

计算IPv4范围的路由前缀相对简单,如果有点难看:

declare @ipv4_begin binary(4)
       ,@ipv4_end binary(4)

set @ipv4_begin = 0xC0A80000 -- '192.168.000.000'
set @ipv4_end = 0xC0A8FFFF   -- '192.168.255.255'

select 32 - LOG(
                Cast(@ipv4_end As bigint)
                - Cast(@ipv4_begin As bigint) + 1, 2
               ) as ipv4_route_prefix
遗憾的是,为IPv6修改的同一查询不起作用。它不起作用的原因是IPv6地址大于
bigint
数据类型中可以存储的内容(我们使用
binary(4)
binary(16)
进行存储的原因):

除了不可靠的按位操作(最终不起作用),我还没有在数据库中找到任何可以进行这种计算的方法


IPv6 CIDR的路由前缀可以从T-SQL中的IPv6地址范围计算出来吗?

好吧,您已经有了一个针对IPv4的巧妙技巧——只需将该值切分为我们可以处理的最大部分,然后重复该技巧

SELECT ISNULL(MIN(32 - B + N), 128) 
FROM (VALUES
    (LOG(
        CONVERT(BIGINT, SUBSTRING(@ip_end,    1, 4)) - 
        CONVERT(BIGINT, SUBSTRING(@ip_begin,  1, 4)
        ) + 1, 2),  0),
    (LOG(
        CONVERT(BIGINT, SUBSTRING(@ip_end,    5, 4)) - 
        CONVERT(BIGINT, SUBSTRING(@ip_begin,  5, 4)
        ) + 1, 2), 32),
    (LOG(
        CONVERT(BIGINT, SUBSTRING(@ip_end,    9, 4)) - 
        CONVERT(BIGINT, SUBSTRING(@ip_begin,  9, 4)
        ) + 1, 2), 64),
    (LOG(
        CONVERT(BIGINT, SUBSTRING(@ip_end,   13, 4)) - 
        CONVERT(BIGINT, SUBSTRING(@ip_begin, 13, 4)
        ) + 1, 2), 96)
) AS Bits(B, N)
WHERE B <> 0;
样本用途:

-- 192.168.100.0 - 192.168.103.255
SELECT * FROM dbo.CidrPrefixFromRange(0xc0a86400, 0xc0a867ff) -- /22

-- 192.168.0.0 - 192.168.255.255
SELECT * FROM dbo.CidrPrefixFromRange(0xC0A80000, 0xC0A8FFFF) -- /16

-- fc00:: - fc00::ffff:ffff:ffff:ffff
SELECT * FROM dbo.CidrPrefixFromRange(
    0xFC000000000000000000000000000000,
    0xFC00000000000000FFFFFFFFFFFFFFFF
) -- /64

-- 127.0.0.1 - 127.0.0.1
SELECT * FROM dbo.CidrPrefixFromRange(0x7f000001, 0x7f000001) -- /32
没有关于这有多高效的承诺。。。如果您希望提高效率,这不是您希望在T-SQL中做的事情。:-)


附录:我之所以使用表值函数而不是更简单的标量值函数(毕竟,我们只返回一个值),是因为标量值函数。内联表值函数可以有效地交叉应用于表。出于这个原因,我习惯性地将每个函数作为内联TVF编写,即使我没有预见到这样的用途——任何东西都比标量值函数好。

虽然上面的示例都是简单的select语句,但我对SQL server函数、公共表表达式、按位操作、,或者任何其他有效的解决方案。也许您可以检查一些C#解决方案(和),并尝试使用CLR函数在SQL Server中实现它们?@gotqn我正在使用共享DB Server实例。因此,我的DBA对添加CLR类型犹豫不决(这是理所当然的)。也就是说,虽然有帮助(我以前使用过),但它不支持IPv6。它的值为0x00000000000000000000000000-0x01000000000000000000000000000000000000000000000000000,我认为应该返回8。()上限可能会解决这个问题,但一旦我遇到比SQL更复杂的东西,我就必须对它进行测试fiddle@rheone:我假设结束范围都以1位结束,因为否则没有前缀。在您的示例中,0x00000000000000000000-0x00ffffffffffffffffffffffffffff。否则,是的,您将遇到舍入问题,因为我们不再处理2的整数幂。使函数处理错误输入需要比
天花板
多一点工作,但这是可以做到的。我有一个替代实现,将输入切碎成字节,并使用
异或
,顺便说一句,它总是返回整数结果,但是如果你的范围不能用前缀来描述,它仍然不能给出正确的结果。(而且,这也不是很明显。)你完全正确。我想起了阿斯蒂尔正在研究的问题。高位地址始终只遵循2^(n)-1填充到128位的模式(如果以十六进制编码,则0、1、3、7、f后跟f)。作为一种辅助,高电平和低电平之间的异或操作将产生位掩码。这个位掩码可以用高或再反,用低和来纠正不适合正确cidr格式的错误高/低地址,正如我上面所描述的。但这在我们的情况下是不必要的,因为输入是干净的。干得好,有时这是最简单的解决方案,是最好的,也是最难以捉摸的。
CREATE FUNCTION dbo.CidrPrefixFromRange(@ip_begin VARBINARY(16), @ip_end VARBINARY(16)) 
RETURNS TABLE AS
RETURN
    SELECT ISNULL(MIN(32 - B + N), DATALENGTH(@ip_begin) * 8) AS Prefix
    FROM (VALUES
        (LOG(
            CONVERT(BIGINT, SUBSTRING(@ip_end,    1, 4)) - 
            CONVERT(BIGINT, SUBSTRING(@ip_begin,  1, 4)
            ) + 1, 2),  0),
        (LOG(
            CONVERT(BIGINT, SUBSTRING(@ip_end,    5, 4)) - 
            CONVERT(BIGINT, SUBSTRING(@ip_begin,  5, 4)
            ) + 1, 2), 32),
        (LOG(
            CONVERT(BIGINT, SUBSTRING(@ip_end,    9, 4)) - 
            CONVERT(BIGINT, SUBSTRING(@ip_begin,  9, 4)
            ) + 1, 2), 64),
        (LOG(
            CONVERT(BIGINT, SUBSTRING(@ip_end,   13, 4)) - 
            CONVERT(BIGINT, SUBSTRING(@ip_begin, 13, 4)
            ) + 1, 2), 96)
    ) AS Bits(B, N)
    WHERE B <> 0;
-- 192.168.100.0 - 192.168.103.255
SELECT * FROM dbo.CidrPrefixFromRange(0xc0a86400, 0xc0a867ff) -- /22

-- 192.168.0.0 - 192.168.255.255
SELECT * FROM dbo.CidrPrefixFromRange(0xC0A80000, 0xC0A8FFFF) -- /16

-- fc00:: - fc00::ffff:ffff:ffff:ffff
SELECT * FROM dbo.CidrPrefixFromRange(
    0xFC000000000000000000000000000000,
    0xFC00000000000000FFFFFFFFFFFFFFFF
) -- /64

-- 127.0.0.1 - 127.0.0.1
SELECT * FROM dbo.CidrPrefixFromRange(0x7f000001, 0x7f000001) -- /32