2015-08-20 5 views
1

Я не знаю, как точно объяснить, но есть проблема с выбором и сопоставлением подсети IP-запроса. Например, есть список для IP-адреса, и у меня есть другой список маски CIDR/подсети (X.X.X.0/24 и т. Д.). Как узнать, что каждый IP-адрес в первом списке находится в списке маски CIDR/подсети через T-SQL?IP-контроль подсети (или CIDR) на T-SQL

Например:

IP: 172.28.112.23 -> ложный

IP: 172.28.111.33 -> истинный

Список IP Вывод:

IP List

SubNe т Выход:

enter image description here

ответ

3

Вы хотите сделать именно то, что компьютер будет делать, чтобы определить, является ли IP-адрес в subnet- а именно:

1) преобразуют сетевой адрес, маску подсети и тестовый адрес в двоичный файл.

2) Проверьте (Network Address & Subnet Mask) = (Тест Адрес маски & Subnet)
(& представляет побитовое И)
Если это сравнение верно тест-адрес в подсети

The ключ к пониманию этого заключается в том, чтобы понять, что IP-адреса (и маски подсети) - это всего лишь 32-разрядные номера.
Побитовое и между 2 32-битными номерами создает новое 32-битное число с 1 в позиции, где было 1 в обоих из двух сравниваемых чисел, и 0 в противном случае.

EG: 1010 & 1100 = 1000, потому что первая цифра равна 1 в обоих числах (в результате получается 1 в результате для первой цифры), но 2-я и 4-я цифры не являются (так что дайте 0 в результате для 2-я и 4-я цифры).

К сожалению, SQL Server не может выполнять побитовое и между двумя двоичными числами, но отлично работает между десятичными представлениями (т.е. при преобразовании в тип данных BIGINT).

Поэтому я предлагаю вам создать функцию, которая преобразует IP-адреса в BIGINT тип данных, во-первых

CREATE FUNCTION dbo.fnIPtoBigInt 
(
    @Ipaddress NVARCHAR(15) -- should be in the form '123.123.123.123' 
) 
RETURNS BIGINT 
AS 
BEGIN 
DECLARE @part1 AS NVARCHAR(3) 
DECLARE @part2 AS NVARCHAR(3) 
DECLARE @part3 AS NVARCHAR(3) 
DECLARE @part4 AS NVARCHAR(3) 

SELECT @part1 = LEFT(@Ipaddress, CHARINDEX('.',@Ipaddress) - 1) 
SELECT @Ipaddress = SUBSTRING(@Ipaddress, LEN(@part1) + 2, 15) 
SELECT @part2 = LEFT(@Ipaddress, CHARINDEX('.',@Ipaddress) - 1) 
SELECT @Ipaddress = SUBSTRING(@Ipaddress, LEN(@part2) + 2, 15) 
SELECT @part3 = LEFT(@Ipaddress, CHARINDEX('.',@Ipaddress) - 1) 
SELECT @part4 = SUBSTRING(@Ipaddress, LEN(@part3) + 2, 15) 

DECLARE @ipAsBigInt AS BIGINT 
SELECT @ipAsBigInt = 
    (16777216 * (CAST(@part1 AS BIGINT))) 
    + (65536 * (CAST(@part2 AS BIGINT))) 
    + (256 * (CAST(@part3 AS BIGINT))) 
    + (CAST(@part4 AS BIGINT)) 

RETURN @ipAsBigInt 

END 

GO 

Затем вы можете легко реализовать функцию, чтобы проверить, если адрес находится в подсети:

CREATE FUNCTION dbo.fnIsIpaddressInSubnet 
(
    @networkAddress NVARCHAR(15), -- 'eg: '192.168.0.0' 
    @subnetMask NVARCHAR(15), -- 'eg: '255.255.255.0' for '/24' 
    @testAddress NVARCHAR(15) -- 'eg: '192.168.0.1' 
) 
RETURNS BIT AS 
BEGIN 
    RETURN CASE WHEN (dbo.fnIPtoBigInt(@networkAddress) & dbo.fnIPtoBigInt(@subnetMask)) 
     = (dbo.fnIPtoBigInt(@testAddress) & dbo.fnIPtoBigInt(@subnetMask)) 
    THEN 1 ELSE 0 END 
END 

Чтобы сделать это немного легче для вас, вам, вероятно, понадобится функция, которая может конвертировать '/ 24' в BigInt.
'/ 24' - сокращенный способ написания 255.255.255.0 - то есть 32-битный номер с первым 24бит, установленным в 1 (а остальные 8 бит установлен в 0)

CREATE FUNCTION dbo.fnSubnetBitstoBigInt 
(
    @SubnetBits TINYINT -- max = 32 
) 
RETURNS BIGINT 
AS 
BEGIN 

DECLARE @multiplier AS BIGINT = 2147483648 
DECLARE @ipAsBigInt AS BIGINT = 0 
DECLARE @bitIndex TINYINT = 1 
WHILE @bitIndex <= @SubnetBits 
BEGIN 
    SELECT @ipAsBigInt = @ipAsBigInt + @multiplier 
    SELECT @multiplier = @multiplier/2 
    SELECT @bitIndex = @bitIndex + 1 
END 

RETURN @ipAsBigInt 

END 

GO 

Если вы создаете следующую дополнительную функцию преобразования становится легко

CREATE FUNCTION dbo.fnIsIpaddressInSubnetShortHand 
(
    @network NVARCHAR(18), -- 'eg: '192.168.0.0/24' 
    @testAddress NVARCHAR(15) -- 'eg: '192.168.0.1' 
) 
RETURNS BIT AS 
BEGIN 
    DECLARE @networkAddress NVARCHAR(15) 
    DECLARE @subnetBits TINYINT 

    SELECT @networkAddress = LEFT(@network, CHARINDEX('/', @network) - 1) 
    SELECT @subnetBits = CAST(SUBSTRING(@network, LEN(@networkAddress) + 2, 2) AS TINYINT) 

    RETURN CASE WHEN (dbo.fnIPtoBigInt(@networkAddress) & dbo.fnSubnetBitstoBigInt(@subnetBits)) 
     = (dbo.fnIPtoBigInt(@testAddress) & dbo.fnSubnetBitstoBigInt(@subnetBits)) 
    THEN 1 ELSE 0 END 
END 

т.е.

SELECT dbo.fnIsIpaddressInSubnetShorthand('192.168.2.0/24','192.168.3.91') -- returns 0 
SELECT dbo.fnIsIpaddressInSubnetShorthand('192.168.2.0/24','192.168.2.91') -- returns 1 
+0

Большое спасибо @ james-s. Это очень полезно и полезно для меня. – juniorDev

+0

добро пожаловать @juniorDev –