Checking IP Against CIDR Netmask with T-SQL

By Anthony Mattas

I’ve been in the process of improving the functionality in ASLB, one of the improvements I have been working on adding is functionality for ASLB to be smart enough to understand geo-location in a large network.

However in doing so I went through many iterations on how to identify which network a user is in for picking the server priority. The result was to create a network table and a scalar function which returned a bit if the provided IP address was in the supplied sub network. Below is the function I used to accomplish this. With a little more work I may modify the function to accept the netmask in CIDR notation instead of two separate columns.

-- Author: Anthony Mattas 
-- Create date: 1-28-2012 
-- Description: This function takes an IP address, CIDR network, and CIDR netmask 
-- (i.e. 192.168.0.0/16) and checks to see if the IP address is in the 
-- network 
-- =================================================================
CREATE FUNCTION [dbo].[udf_CheckNetmask] ( 
     @Address VARCHAR(16), 
     @Network VARCHAR(16), 
     @Netmask INT 
) 
RETURNS BIT 
AS 
BEGIN 
     DECLARE @Octet1 INT 
     DECLARE @Octet2 INT 
     DECLARE @Octet3 INT 
     DECLARE @Octet4 INT 
     DECLARE @BAddress BINARY(4) 
     DECLARE @BNetwork BINARY(4) 
     DECLARE @Return BIT 
     SELECT @BAddress = 
          CAST( 
               CAST( 
                    PARSENAME( @Address, 4 ) AS INTEGER
               ) AS BINARY(1)
          ) + 
          CAST( 
               CAST( 
                    PARSENAME( @Address, 3 ) AS INTEGER
               ) AS BINARY(1)
          ) + 
          CAST( 
               CAST( 
                    PARSENAME( @Address, 2 ) AS INTEGER
               ) AS BINARY(1)
          ) + 
          CAST( 
               CAST( 
                    PARSENAME( @Address, 1 ) AS INTEGER
               ) AS BINARY(1)
          ) 
SELECT @BNetwork = 
          CAST( 
               CAST( 
                    PARSENAME( @Network, 4 ) AS INTEGER
               ) AS BINARY(1)
          ) + 
          CAST(
               CAST( 
                    PARSENAME( @Network, 3 ) AS INTEGER
               ) AS BINARY(1)
          ) + 
          CAST( 
               CAST( 
                    PARSENAME( @Network, 2 ) AS INTEGER
               ) AS BINARY(1)
          ) + 
          CAST( 
               CAST( 
                    PARSENAME( @Network, 1 ) AS INTEGER
               ) AS BINARY(1)
          ) 
SELECT @Return = 
     CASE 
          WHEN 0 = (
               cast(@BAddress as bigint) ^ 
               cast(@BNetwork as bigint)
          ) & 
          ~(
               power(
                    CAST(2 AS bigint), 
                    32 - @Netmask
               ) - 1
          ) THEN 1
          ELSE 0 
     END 
RETURN @Return 
END 
GO

Category: SQL Server