Calculate IP range by subnet mask
Asked Answered
S

5

8

If I have a subnet mask e.g. 255.255.255.0 and an ip address 192.168.1.5, is there an easy way to determine all the possible ip addresses within this subnet?

In this case:

192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
...
...
192.168.1.252
192.168.1.253
192.168.1.254
192.168.1.255

All I found until now are heavy overloaded .net libraries. Isn't there any native way to solve this with the default namespaces?

Shortening answered 14/1, 2013 at 21:28 Comment(8)
There's no built in way. You either do the math/bitshifting yourself or use 3rd party I'm afraid.Brace
Sure. For that you need to know what is a subnet mask and basic binary operators of C#. Have you made any research on that?Fetlock
AND and bitshift, enough said.Heckelphone
You want to actually list them all, or just determine if a specific address is in the subnet? For instance, a 255.0.0.0 subnet mask would contain 16,777,216 addresses.Behm
@Fetlock I hoped for a built in way first, but it looks like I have to do it by myself. :/Shortening
actually, it's not about being lazy. For a language like c#, it's usually more advantageous to use "built in" ways than to write your own. This is to optimize for performance and code size. Of course, this will open up a holy war. I am sorry.Rhinal
@Rhinal If you want performance and small code size you would certainly write the 2-3 lines of code yourself. If you want a library you will certainly pay costs in both performance and code size. Your objectives are mutually contradictory.Algolagnia
you're missing the point. built-in ways with (c#) .net are usually distributed with the OS and most likely implemented natively. this is always better than writing 2-3 lines of code in c# because the 2-3 lines of code will be carried in your program (i.e. larger code size) and executed by the runtime or compiled by the JIT compiler (i.e. slower).Rhinal
D
9

To determine the adress range follow these steps :

1) Take your subnet mask (here 255.255.255.0) and convert it in binary :

11111111.11111111.11111111.00000000

 (  8    +    8   +   8    +    0    = 24 ->  So you can write your ip adresse like this : 192.168.1.x/24 because you are in a /24 network)

2) You have in a /24 network 256-2=254 usable ip adresses for host (one is for the network adress (the first in your range) and the other one is for the broadcast adress (the last in your range)).

3) To get your range simply get your network adress (the first ip adress according to your subnet mask) and get the next 255 ip addresses and you'll have your range.

Your network adress:

In binary the last octet has to be null :

xxxxxxxx.xxxxxxxx.xxxxxxxx.00000000

Your broadcast adress:

In binary the last octet has to be equal to 1:

xxxxxxxx.xxxxxxxx.xxxxxxxx.11111111

Here your ip adress is 192.168.1.5. In binary we get:

11000000.10101000.00000000.00000101
  1. Your network address: 11000000.10101000.00000000.00000000 <-> 192.168.1.0
  2. Your broadcast address: 11000000.10101000.000000000.11111111 <-> 192.168.1.255
  3. First usable ip address: 192.168.1.1

  4. Last usable ip address : 192.168.1.254

Hope you enjoyed reading bad english. Tell me if you have any question, Loris

Dais answered 14/1, 2013 at 21:52 Comment(1)
In case anyone wants the code for step 1: var bytes = subnetMask.GetAddressBytes(); var binarySubnetMask = String.Join(".", bytes.Select(b => Convert.ToString(b, 2).PadLeft(8, '0'))); int mask = binarySubnetMask.Count(b => b == '1');Foreordain
S
13

10 minutes of coding, and NOT fully tested:

class IPSegment {

    private UInt32 _ip;
    private UInt32 _mask;

    public IPSegment(string ip, string mask) {
        _ip = ip.ParseIp();
        _mask = mask.ParseIp();
    }

    public UInt32 NumberOfHosts {
        get { return ~_mask+1; }
    }

    public UInt32 NetworkAddress {
        get { return _ip & _mask; }
    }

    public UInt32 BroadcastAddress {
        get { return NetworkAddress + ~_mask; }
    }

    public IEnumerable<UInt32> Hosts(){
        for (var host = NetworkAddress+1; host < BroadcastAddress; host++) {
            yield return  host;
        }
    }

}

public static class IpHelpers {
    public static string ToIpString(this UInt32 value) {
        var bitmask = 0xff000000;
        var parts = new string[4];
        for (var i = 0; i < 4; i++) {
            var masked = (value & bitmask) >> ((3-i)*8);
            bitmask >>= 8;
            parts[i] = masked.ToString(CultureInfo.InvariantCulture);
        }
        return String.Join(".", parts);
    }

    public static UInt32 ParseIp(this string ipAddress) {
        var splitted = ipAddress.Split('.');
        UInt32 ip = 0;
        for (var i = 0; i < 4; i++) {
            ip = (ip << 8) + UInt32.Parse(splitted[i]);
        }
        return ip;
    }
}

Usage:

    static void Main(string[] args) {

        IPSegment ip = new IPSegment("192.168.1.1","255.255.255.248");

        Console.WriteLine(ip.NumberOfHosts);
        Console.WriteLine(ip.NetworkAddress.ToIpString());
        Console.WriteLine(ip.BroadcastAddress.ToIpString());

        Console.WriteLine("===");
        foreach (var host in ip.Hosts()) {
            Console.WriteLine(host.ToIpString());
        }
        Console.ReadLine();

    }
Spindling answered 14/1, 2013 at 22:38 Comment(0)
D
9

To determine the adress range follow these steps :

1) Take your subnet mask (here 255.255.255.0) and convert it in binary :

11111111.11111111.11111111.00000000

 (  8    +    8   +   8    +    0    = 24 ->  So you can write your ip adresse like this : 192.168.1.x/24 because you are in a /24 network)

2) You have in a /24 network 256-2=254 usable ip adresses for host (one is for the network adress (the first in your range) and the other one is for the broadcast adress (the last in your range)).

3) To get your range simply get your network adress (the first ip adress according to your subnet mask) and get the next 255 ip addresses and you'll have your range.

Your network adress:

In binary the last octet has to be null :

xxxxxxxx.xxxxxxxx.xxxxxxxx.00000000

Your broadcast adress:

In binary the last octet has to be equal to 1:

xxxxxxxx.xxxxxxxx.xxxxxxxx.11111111

Here your ip adress is 192.168.1.5. In binary we get:

11000000.10101000.00000000.00000101
  1. Your network address: 11000000.10101000.00000000.00000000 <-> 192.168.1.0
  2. Your broadcast address: 11000000.10101000.000000000.11111111 <-> 192.168.1.255
  3. First usable ip address: 192.168.1.1

  4. Last usable ip address : 192.168.1.254

Hope you enjoyed reading bad english. Tell me if you have any question, Loris

Dais answered 14/1, 2013 at 21:52 Comment(1)
In case anyone wants the code for step 1: var bytes = subnetMask.GetAddressBytes(); var binarySubnetMask = String.Join(".", bytes.Select(b => Convert.ToString(b, 2).PadLeft(8, '0'))); int mask = binarySubnetMask.Count(b => b == '1');Foreordain
R
1

yup, convert everything to 32-bit representation (assuming IPv4). if your mask is M and ip is IP, then your ip range is (M&IP)+1,(M&IP)+2,...,(M&IP)+(~M)-1. where & is bitwise AND and ~ is bitwise not.

to convert things to 32-bit representation, each spot in the ip a.b.c.d is an 8-bit number.

Rhinal answered 14/1, 2013 at 21:33 Comment(0)
S
1

To use just do:

string[] range GetIpRange("100.68.18.218", "255.255.255.252",true)`;

The last parameter true is to filter the first and last IP
To get the full answer set it to false

It will return the first and last usable IPs.

All code with Explanation bellow:


/// <summary>
/// IPAddress to UInteger 
/// </summary>
/// <param name="ipAddress"></param>
/// <returns></returns>
public static uint IPToUInt(this string ipAddress)
{
    if (string.IsNullOrEmpty(ipAddress))
        return 0;

    if (IPAddress.TryParse(ipAddress, out IPAddress ip))
    {
        var bytes = ip.GetAddressBytes();
        Array.Reverse(bytes);
        return BitConverter.ToUInt32(bytes, 0);
    }
    else
        return 0;

}

/// <summary>
/// IP in Uinteger to string
/// </summary>
/// <param name="ipUInt"></param>
/// <returns></returns>
public static string IPToString(this uint ipUInt)
{
    return ToIPAddress(ipUInt).ToString();
}


/// <summary>
/// IP in Uinteger to IPAddress
/// </summary>
/// <param name="ipUInt"></param>
/// <returns></returns>
public static IPAddress ToIPAddress(this uint ipUInt)
{
    var bytes = BitConverter.GetBytes(ipUInt);
    Array.Reverse(bytes);
    return new IPAddress(bytes);
}

/// <summary>
/// First and Last IPv4 from IP + Mask
/// </summary>
/// <param name="ipv4"></param>
/// <param name="mask">Accepts CIDR or IP. Example 255.255.255.0 or 24</param>
/// <param name="filterUsable">Removes not usable IPs from Range</param>
/// <returns></returns>
/// <remarks>
/// If ´filterUsable=false´ first IP is not usable and last is reserved for broadcast.
/// </remarks>
public static string[] GetIpRange(string ipv4, string mask, bool filterUsable)
{
    uint[] uiIpRange = GetIpUintRange(ipv4, mask, filterUsable);

    return Array.ConvertAll(uiIpRange, x => IPToString(x));
}

/// <summary>
/// First and Last IPv4 + Mask. 
/// </summary>
/// <param name="ipv4"></param>
/// <param name="mask">Accepts CIDR or IP. Example 255.255.255.0 or 24</param>
/// <param name="filterUsable">Removes not usable IPs from Range</param>
/// <returns></returns>
/// <remarks>
/// First IP is not usable and last is reserverd for broadcast.
/// Can use all IPs in between
/// </remarks>
public static uint[] GetIpUintRange(string ipv4, string mask, bool filterUsable)
{
    uint sub;
    //check if mask is CIDR Notation
    if (mask.Contains(".")) {
        sub = IPToUInt(mask);
    }
    else
    {
        sub = ~(0xffffffff >> Convert.ToInt32(mask));
    }

    uint ip2 = IPToUInt(ipv4);
 

    uint first = ip2 & sub;
    uint last = first | (0xffffffff & ~sub);

    if (filterUsable)
    {
        first += 1;
        last -= 1; 
    }

    return new uint[] { first, last };
}

Senega answered 24/9, 2021 at 16:10 Comment(0)
M
-1

Good call. Don't use extra libraries for that. It's quite simple. This is how I do it:

public static uint[] GetIpRange(string ip, IPAddress subnet)
{
    uint ip2 = Utils.IPv4ToUInt(ip);
    uint sub = Utils.IPv4ToUInt(subnet);

    uint first = ip2 & sub;
    uint last = first | (0xffffffff & ~sub);

    return new uint[] { first, last };
}

Note:
You'll need to do some more work converting IPs to uint and back (should be easy enough). Then you can iterate all IPs with a simple for-loop between first and last.

Something like this (not tested):

byte[] bytes = subnet.GetAddressBytes();
uint sub = (uint)((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);

IPAddress ip1 = IPAddress.Parse(ip);
bytes = ip1.GetAddressBytes();
uint ip2 = (uint)((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
Mochun answered 21/9, 2016 at 8:59 Comment(1)
can you provide a simple ip2/sub ipAddress with the uint equivalent to evaluate our work?Consort

© 2022 - 2024 — McMap. All rights reserved.