miércoles, 7 de diciembre de 2011

Función SQL para Comparar un rango de direcciones IP

Esta función nos sirve para comparar si una dirección IP se encuentre entre un rango de direcciones IP desde-hasta.

Recibe como parámetros la dirección IP a comparar, el rango IP "desde" y el rango IP "hasta", como salida devuelve  1 (bit)  si la IP a comparar se encuentra entre dicho rango, de lo contrario devuelve 0.

En muchos casos las direcciones IP son guardadas en la base como caracteres, para poder comparar un rango IP primero se debe convertir a un BINARY(4) que  es lo que realmente representa a una dirección IP y permite  comprar rangos.

La función es la siguiente:
CREATE FUNCTION dbo.RangoIPv4(@ip AS VARCHAR(15),@ipDesde AS VARCHAR(15),@ipHasta AS VARCHAR(15)) RETURNS BIT
AS
BEGIN
    DECLARE @binIP AS BINARY(4)
    DECLARE @binDesde AS BINARY(4)
    DECLARE @binHasta AS BINARY(4)
    DECLARE @bit as bit

    SELECT @binIP =
CAST( CAST( PARSENAME ( @ip, 4 ) AS INTEGER) AS BINARY(1))
                + CAST( CAST( PARSENAME( @ip, 3 ) AS INTEGER) AS BINARY(1))
                + CAST( CAST( PARSENAME( @ip, 2 ) AS INTEGER) AS BINARY(1))
                + CAST( CAST( PARSENAME( @ip, 1 ) AS INTEGER) AS BINARY(1))

    SELECT @binDesde =
CAST( CAST( PARSENAME( @ipDesde, 4 ) AS INTEGER) AS BINARY(1))
                + CAST( CAST( PARSENAME( @ipDesde, 3 ) AS INTEGER) AS BINARY(1))
                + CAST( CAST( PARSENAME( @ipDesde, 2 ) AS INTEGER) AS BINARY(1))
                + CAST( CAST( PARSENAME( @ipDesde, 1 ) AS INTEGER) AS BINARY(1))

    SELECT @binHasta =
CAST( CAST( PARSENAME( @ipHasta, 4 ) AS INTEGER) AS BINARY(1))
                + CAST( CAST( PARSENAME( @ipHasta, 3 ) AS INTEGER) AS BINARY(1))
                + CAST( CAST( PARSENAME( @ipHasta, 2 ) AS INTEGER) AS BINARY(1))
                + CAST( CAST( PARSENAME( @ipHasta, 1 ) AS INTEGER) AS BINARY(1))

set @bit= Case when @binIP between @binDesde and @binHasta then 'TRUE' else 'FALSE' end
 
    RETURN @bit
END
go

Un par de ejemplos de los resultados:

select dbo.RangoIPv4('192.168.10.8','192.168.10.1','192.168.10.255')

Resultado:

-----
1

select dbo.RangoIPv4('192.168.10.8','192.168.10.1','192.168.10.7')

Resultado:

-----
0

Fuente, adaptación del artículo: http://stackoverflow.com/questions/1385552/datatype-for-storing-ip-address-in-sql-server