views:

261

answers:

5

Ok, it's friday afternoon, and i've had a long week so would appreciate some help! Currently, i have a list of IP ranges, as follows:

List<IPRange> ipRanges = new List<IPRange>();

ipRanges.Add(new IPRange { From = "145.36.0.0", To = "145.36.255.255" });
ipRanges.Add(new IPRange { From = "194.183.227.184", To = "194.183.227.191" });
ipRanges.Add(new IPRange { From = "193.131.192.0", To = "193.131.223.255" });

After getting the IP of the client, if it falls anywhere between these sets of ranges, they need to be redirected elsewhere.

For example,

If someone visited the site with the IP 192.168.0.1, they would be allowed access. If they visited with 145.36.1.0, they would not be allowed access because it falls between the first range in that list.

I could split each IP by the period, and work out where the range starts to change, then do a comparison, but that would be heavy on the server.

I know IP's are basically just decimal numbers, but am not really sure how that works.

Has anyone come across this before?

Cheers, Sean.

+6  A: 

Convert Each IP-address to number, and then check if the user ip address is between those numbers.

public double Dot2LongIP(string DottedIP)
{
    int i;
    string [] arrDec;
    double num = 0;
    if (DottedIP == "")
    {
       return 0;
    }
    else
    {
       arrDec = DottedIP.Split('.');
       for(i = arrDec.Length - 1; i >= 0 ; i --)
       {
          num += ((int.Parse(arrDec[i])%256) * Math.Pow(256 ,(3 - i )));
       }
       return num;
    }
}
Espo
spot on - works a treat!
seanxe
+7  A: 

I would convert the IP addresses to 32-bit numbers and then do a simple >= From and <= To check to see if it's in range.

For example, 192.168.1.1 -> 192 * 256^3 + 168 * 256^2 + 1 * 256 + 1.

Working with your values, 145.36.0.0 -> 2435055616 and 145.36.0.0 -> 2435121151. So 145.36.200.30 -> 2435106846, and falls in that range, so it's valid. But 145.35.255.255 -> 2435055615 is not in the range (just barely), so it fails.

Kaleb Brasee
A: 

I read about this a few days ago.

You can get your IP ranges converted and compare.

IF exists (SELECT * from dbo.sysobjects 
    WHERE id = object_id(N'[dbo].[IsPrivateIP]') 
    AND OBJECTPROPERTY(id, N'IsScalarFunction') = 1)
DROP FUNCTION [dbo].[IsPrivateIP]
GO


CREATE FUNCTION dbo.IsPrivateIP( @vcIPAddress varchar(15))
/**************************************************************************
DESCRIPTION: Returns Numeric IP if not private, otherwise returns null

PARAMETERS:
     @vcIPAddress - The string containing a valid IP

RETURNS:    IP converted to bigint or null if a private IP

USAGE:   SELECT dbo.IsPrivateIP( '207.158.26.10')

DEPENDANCIES:    dbo.IPStringToNumber() function 

AUTHOR: Karen Gayda

DATE:   06/11/2003

MODIFICATION HISTORY:
    WHO  DATE  DESCRIPTION
    ---  ---------- ---------------------------------------------------

***************************************************************************/

    RETURNS bigint
AS
BEGIN
    DECLARE @biClassALo bigint ,
     @biClassAHi bigint ,
     @biClassBLo bigint ,
     @biClassBHi bigint ,
     @biClassCLo bigint ,
     @biClassCHi bigint ,
     @biIP     bigint,
     @bTemp  int 

    SET @biClassALo = 167772160
    SET @biClassAHi = 169549375
    SET @biClassBLo = 2885681152
    SET @biClassBHi = 2887778303
    SET @biClassCLo = 3232235520
    SET @biClassCHi = 3232301055


    SET @biIP = dbo.IPStringToNumber(@vcIPAddress)
    IF @biIP BETWEEN @biClassALo AND @biClassAHi OR @biIP BETWEEN @biClassBLo AND @biClassBHi 
     OR @biIP BETWEEN @biClassCLo AND @biClassCHi 
     SET @biIP = NULL

    RETURN @biIP
END
GO

Here is the IPStringToNumber function that it needs:

IF exists (SELECT * from dbo.sysobjects 
    WHERE id = object_id(N'[dbo].[IPStringToNumber]') 
    AND OBJECTPROPERTY(id, N'IsScalarFunction') = 1)
DROP FUNCTION [dbo].[IPStringToNumber]
GO

CREATE FUNCTION dbo.IPStringToNumber( @vcIPAddress varchar(15))
/**************************************************************************
DESCRIPTION: Returns Numeric IP, otherwise returns null

PARAMETERS:
     @vcIPAddress - The string containing a valid IP

RETURNS:    IP converted to bigint or null if not a valid IP

USAGE:         SELECT  dbo.IPStringToNumber( '10.255.255.255')



AUTHOR: Karen Gayda

DATE:   06/11/2003

MODIFICATION HISTORY:
    WHO  DATE  DESCRIPTION
    ---  ---------- ---------------------------------------------------

***************************************************************************/

    RETURNS bigint
AS
BEGIN
    DECLARE 
     @biOctetA  bigint,
     @biOctetB bigint,
     @biOctetC bigint,
     @biOctetD bigint,
     @biIP      bigint

    DECLARE @tblArray TABLE 
       (
     OctetID  smallint,    --Array index
        Octet  bigint      --Array element contents
       )

    --split the IP string and insert each octet into a table row
    INSERT INTO @tblArray
    SELECT ElementID, Convert(bigint,Element) FROM dbo.Split(@vcIPAddress, '.')

    --check that there are four octets and that they are within valid ranges
    IF (SELECT COUNT(*) FROM @tblArray WHERE Octet BETWEEN 0 AND 255) = 4
    BEGIN
     SET @biOctetA = (SELECT (Octet * 256 * 256 * 256) FROM @tblArray WHERE OctetID = 1)
     SET @biOctetB = (SELECT (Octet * 256 * 256 ) FROM @tblArray WHERE OctetID = 2)
     SET @biOctetC = (SELECT (Octet * 256 ) FROM @tblArray WHERE OctetID = 3)
     SET @biOctetD = (SELECT (Octet) FROM @tblArray WHERE OctetID = 4)
     SET @biIP = @biOctetA + @biOctetB + @biOctetC + @biOctetD
    END

    RETURN(@biIP)
END

References:

http://www.sqlservercentral.com/scripts/Miscellaneous/31036/

http://www.sqlservercentral.com/Authors/Scripts/kgayda/17134/

Raj More
copy/paste the good parts for those of us who aren't or don't want to register?
rally25rs
+1  A: 

I would write my IPRange class so that the getter/setters internally convert the IP string to a number:

new IPRange { From = "145.36.0.0", To = "145.36.255.255" }

Would internally set:

int from = 145036000000;
int to = 145036255255;

Then add a .IsInRange(string ip) method that converts the incoming IP to the name int form and does a plain comparison.

public bool IsInRange(string ipStr)
{
    int ip = ConvertIPStringToInt(ipStr);
    return (from <= ip && ip <= to);
}

That way you dont have to split the IPs in the range by periods each time its checked.

rally25rs
and you can replace my "ConvertIPStringToInt()" with Espo's "Dot2LongIP()", since I was too lazy to write the conversion method :)
rally25rs
yeah, once i get the fundamentals working i'll streamline it :)
seanxe
+1  A: 

Just for fun (and some semblance of completeness) - the other way obvious to do this is to ensure that you always use 3 digits for each segment of the IP address when stored as a string i.e. 145.36.0.0 should be 145.036.000.000 - that way the strings would be directly comparable.

And the Less obvious would be to have an explicit IP Address class and a roll your own set of comparison logic (I'm rashly assuming that there isn't already something like this buried in the depths of the .NET framework...)

Murph