7

Ok I can't seem to figure this out: given the following:

IP address = 192.168.1.0
Subnetmask = 255.255.255.240

Using c#, how do I calculate the CIDR notation 192.168.1.0/28 ? Is there an easy way to achieve this? Am I missing something?

Thanks!

Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
RoelF
  • 7,483
  • 5
  • 44
  • 67

7 Answers7

7

256 - 240 = 16 = 2**4, 32 - 4 = 28

It is not really a C# question.

To get a net address from an IP and mask you can apply bytewise and to the IP and mask. You can get bytes from a string using IPAddress.Parse() and IPAddress.GetAddressBytes().

wRAR
  • 25,009
  • 4
  • 84
  • 97
  • Thanks for the info. I know I can manipulate string to ip address and bytes with the IPAddress class. I also understand the logic behind the subnet/broadcast/cidr calculations etc... I'm just having trouble putting this into a simple c# method which gives me `26` when I input `255.255.255.192` – RoelF Mar 24 '10 at 13:42
  • I know. That was not the question. Nevermind I figured it out. – RoelF Mar 24 '10 at 14:13
7

I had to do the same thing, no new info but this snippet may come in handy for the next person looking for a way to do this in C#. note that this method only counts the number of consecutive 1s, and leaves you the work of appending it to the IP.

public class IPAddressHelper
{
    public static UInt32 SubnetToCIDR(string subnetStr)
    {
        IPAddress subnetAddress = IPAddress.Parse(subnetStr);
        byte[] ipParts = subnetAddress.GetAddressBytes();
        UInt32 subnet = 16777216 * Convert.ToUInt32(ipParts[0]) + 65536 * Convert.ToUInt32(ipParts[1]) + 256 * Convert.ToUInt32(ipParts[2]) + Convert.ToUInt32(ipParts[3]);
        UInt32 mask = 0x80000000;
        UInt32 subnetConsecutiveOnes = 0;
        for (int i = 0; i < 32; i++)
        {
            if (!(mask & subnet).Equals(mask)) break;

            subnetConsecutiveOnes++;
            mask = mask >> 1;
        }
        return subnetConsecutiveOnes;
    }
}
Yonatan Karni
  • 977
  • 2
  • 13
  • 32
3

Keep it simple!

This works for IPv4 only, but since IPv6 does only support CIDR like /64 in fe80::1ff:fe23:4567:890a/64 calculations like that are unnecessary there.

All you need for an IPv4 network mask:

int cidr = Convert.ToString(mask.Address, 2).Count( o => o == '1'); 

Explanation based on the given example:

IPAddress mask = new IPAddress(new byte[] { 255, 255, 255, 240 });

// maskBinAsString = 11110000111101001111111111111111
string maskBinAsString = Convert.ToString(mask.Address, 2); 

// cidr = 28
int cidr = Convert.ToString(mask.Address, 2).Count( o=> o == '1'); 
marsh-wiggle
  • 2,508
  • 3
  • 35
  • 52
1

I don't have it as C# code but here is the answer in VB. Should not be to hard to convert.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim someIP As Net.IPAddress = Net.IPAddress.Parse("192.168.1.10")
    Dim someMASK As Net.IPAddress = Net.IPAddress.Parse("255.255.255.240")

    Dim ipL As Long = IPtoLong(someIP)
    Dim maskL As Long = IPtoLong(someMASK)

    'Convert  Mask to CIDR(1-30)
    Dim oneBit As Long = &H80000000L
    Dim CIDR As Integer = 0

    For x As Integer = 31 To 0 Step -1
        If (maskL And oneBit) = oneBit Then CIDR += 1 Else Exit For
        oneBit = oneBit >> 1
    Next

    Dim answer As String = LongToIp(ipL And maskL) & " /" & CIDR.ToString

End Sub

Public Function IPtoLong(ByVal theIP As Net.IPAddress) As Long 'convert IP to number

    Dim IPb() As Byte = theIP.GetAddressBytes 'get the octets
    Dim addr As Long 'accumulator for address

    For x As Integer = 0 To 3
        addr = addr Or (CLng(IPb(x)) << (3 - x) * 8)
    Next
    Return addr

End Function

Public Function LongToIp(ByVal theIP As Long) As String 'convert number back to IP

    Dim IPb(3) As Byte '4 octets
    Dim addr As String = "" 'accumulator for address

    Dim mask8 As Long = MaskFromCidr(8) 'create eight bit mask

    For x = 0 To 3 'get the octets
        IPb(x) = CByte((theIP And mask8) >> ((3 - x) * 8))
        mask8 = mask8 >> 8
        addr &= IPb(x).ToString & "." 'add current octet to string
    Next
    Return addr.TrimEnd("."c)

End Function

Private Function MaskFromCidr(ByVal CIDR As Integer) As Long
    MaskFromCidr = CLng(2 ^ ((32 - CIDR)) - 1) Xor 4294967295L
End Function
dbasnett
  • 11,334
  • 2
  • 25
  • 33
0

my solution, first parse to IPAddress:

var Subnetmask = "255.255.255.240";
IPAddress ip = IPAddress.Parse(Subnetmask);

then, check count of set bits in the mask ip:

var intAddress = (int)IPAddress.Address;
Console.WriteLine(NumberOfSetBits(intAddress)); //28

the function (from https://stackoverflow.com/a/12175897/1271037):

int NumberOfSetBits(int i)
{
    i = i - ((i >> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
    return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
Community
  • 1
  • 1
dovid
  • 6,354
  • 3
  • 33
  • 73
0

I know it's a little late, but I took a swing converting dbasnett's answer VB.NET code above to C# (thanks to Telerik Code Converter) and put it up in a .NET Fiddle here and included my conversion below:

public static void Main()
{
    System.Net.IPAddress someIP = System.Net.IPAddress.Parse("192.168.1.23");
    System.Net.IPAddress someMASK = System.Net.IPAddress.Parse("255.255.255.128");

    long ipL = IPtoLong(someIP);
    long maskL = IPtoLong(someMASK);

    // Convert  Mask to CIDR(1-30)
    long oneBit = 0x80000000L;
    int CIDR = 0;

    for (int x = 31; x >= 0; x += -1)
    {
        if ((maskL & oneBit) == oneBit)
            CIDR += 1;
        else
            break;
        oneBit = oneBit >> 1;
    }

    string answer = LongToIp(ipL & maskL) + "/" + CIDR.ToString();

    Console.Out.WriteLine("woah woah we woah " + answer);
}

public static long IPtoLong(System.Net.IPAddress theIP) // convert IP to number
{
    byte[] IPb = theIP.GetAddressBytes(); // get the octets
    long addr = 0; // accumulator for address

    for (int x = 0; x <= 3; x++) {
        addr |=  (System.Convert.ToInt64(IPb[x]) << (3 - x) * 8);
    }
    return addr;
}

public static string LongToIp(long theIP) // convert number back to IP
{
    byte[] IPb = new byte[4]; // 4 octets
    string addr = ""; // accumulator for address

    long mask8 = MaskFromCidr(8); // create eight bit mask

    for (var x = 0; x <= 3; x++) // get the octets
    {
        IPb[x] = System.Convert.ToByte((theIP & mask8) >> ((3 - x) * 8));
        mask8 = mask8 >> 8;
        addr += IPb[x].ToString() + "."; // add current octet to string
    }
    return addr.TrimEnd('.');
}

private static long MaskFromCidr(int CIDR)
{
    return  System.Convert.ToInt64(Math.Pow(2, ((32 - CIDR))) - 1) ^ 4294967295L;
}
Matt Plank
  • 333
  • 6
  • 12
  • This solution doesn't check the validity of the subnet mask. For example 255.255.255.253 will produce a result. Once we've found a zero in the subnet mask, we need to check that all remaining bits are also 0. – Andrew McLachlan Mar 28 '19 at 19:59
-1

See Get CIDR from netmask

Usage:

var cidrnetmask = MaskToCIDR(IPAddress.Parse("255.0.0.0").GetAddressBytes());

This works for IPv4. To support IPv6, one could expand the number of bytes but hopefully nobody will try and use old-style netmasks for IPv6 :o)

Method:

static int MaskToCIDR(byte[] bytes)
{

        var b0 = bytes[0];
        var b1 = bytes[1];
        var b2 = bytes[2];
        var b3 = bytes[3];

        return
            b3 != 0 ? (
                (b3 & 0x01) != 0 ? 32 :
                (b3 & 0x02) != 0 ? 31 :
                (b3 & 0x04) != 0 ? 30 :
                (b3 & 0x08) != 0 ? 29 :
                (b3 & 0x10) != 0 ? 28 :
                (b3 & 0x20) != 0 ? 27 :
                (b3 & 0x40) != 0 ? 26 :
                                   25 ) :
            b2 != 0 ? (
                (b2 & 0x01) != 0 ? 24 :
                (b2 & 0x02) != 0 ? 23 :
                (b2 & 0x04) != 0 ? 22 :
                (b2 & 0x08) != 0 ? 21 :
                (b2 & 0x10) != 0 ? 20 :
                (b2 & 0x20) != 0 ? 19 :
                (b2 & 0x40) != 0 ? 18 :
                                   17 ) :
            b1 != 0 ? (
                (b1 & 0x01) != 0 ? 16 :
                (b1 & 0x02) != 0 ? 15 :
                (b1 & 0x04) != 0 ? 14 :
                (b1 & 0x08) != 0 ? 13 :
                (b1 & 0x10) != 0 ? 12 :
                (b1 & 0x20) != 0 ? 11 :
                (b1 & 0x40) != 0 ? 10 :
                                   9  ) :
            b0 != 0 ? (
                (b0 & 0x01) != 0 ? 8 :
                (b0 & 0x02) != 0 ? 7 :
                (b0 & 0x04) != 0 ? 6 :
                (b0 & 0x08) != 0 ? 5 :
                (b0 & 0x10) != 0 ? 4 :
                (b0 & 0x20) != 0 ? 3 :
                (b0 & 0x40) != 0 ? 2 :
                                   1 ) :
                               0;
}
Community
  • 1
  • 1
Robert Cutajar
  • 3,181
  • 1
  • 30
  • 42