C# · Course navigation

C#: IPv4 subnets with IPAddress and bit masks

Compute the network and broadcast addresses for a CIDR block and test whether addresses belong to it.

On this page
Before you start

C# bitwise operators and System.Net.

  • Compute the network and broadcast addresses for a CIDR block and test whether addresses belong to it.
  • Predict the sample output and explain the state changes.
  • Complete the practice task and check the boundary cases.

The concept

An IPv4 address is 32 bits. In CIDR notation 192.168.10.77/26, the first 26 bits are the network part. The subnet mask has ones in those bits and zeros elsewhere. ANDing an address with the mask gives the network address, and setting all host bits to one gives the broadcast address.

IPAddress.GetAddressBytes returns the four bytes in network order, which are combined into one unsigned integer. An address belongs to the subnet when its masked value equals the network address. The block has 2^(32 − 26) = 64 addresses, and 62 of them are usable hosts.

Code example

C#
using System;
using System.Net;

class Program {
  static uint ToNumber(string text) {
    byte[] b = IPAddress.Parse(text).GetAddressBytes();
    return ((uint)b[0] << 24) | ((uint)b[1] << 16) | ((uint)b[2] << 8) | b[3];
  }

  static string ToText(uint v) {
    return new IPAddress(new[] { (byte)(v >> 24), (byte)(v >> 16), (byte)(v >> 8), (byte)v }).ToString();
  }

  static void Main() {
    int prefix = 26;
    uint mask = prefix == 0 ? 0 : uint.MaxValue << (32 - prefix);
    uint network = ToNumber("192.168.10.77") & mask;
    uint broadcast = network | ~mask;
    Console.WriteLine("network   " + ToText(network));
    Console.WriteLine("broadcast " + ToText(broadcast));
    Console.WriteLine("hosts     " + ((1L << (32 - prefix)) - 2));
    foreach (string candidate in new[] { "192.168.10.100", "192.168.10.130" }) {
      bool inside = (ToNumber(candidate) & mask) == network;
      Console.WriteLine(candidate + " in subnet: " + inside);
    }
  }
}
Output
network   192.168.10.64
broadcast 192.168.10.127
hosts     62
192.168.10.100 in subnet: True
192.168.10.130 in subnet: False

Follow the code

Open the walkthrough to inspect the example one step at a time.

Show guided walkthrough
Guided walkthroughReady
1using System;
2using System.Net;
3
4class Program {
5 static uint ToNumber(string text) {
6 byte[] b = IPAddress.Parse(text).GetAddressBytes();
7 return ((uint)b[0] << 24) | ((uint)b[1] << 16) | ((uint)b[2] << 8) | b[3];
8 }
9
10 static string ToText(uint v) {
11 return new IPAddress(new[] { (byte)(v >> 24), (byte)(v >> 16), (byte)(v >> 8), (byte)v }).ToString();
12 }
13
14 static void Main() {
15 int prefix = 26;
16 uint mask = prefix == 0 ? 0 : uint.MaxValue << (32 - prefix);
17 uint network = ToNumber("192.168.10.77") & mask;
18 uint broadcast = network | ~mask;
19 Console.WriteLine("network " + ToText(network));
20 Console.WriteLine("broadcast " + ToText(broadcast));
21 Console.WriteLine("hosts " + ((1L << (32 - prefix)) - 2));
22 foreach (string candidate in new[] { "192.168.10.100", "192.168.10.130" }) {
23 bool inside = (ToNumber(candidate) & mask) == network;
24 Console.WriteLine(candidate + " in subnet: " + inside);
25 }
26 }
27}

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
26 ones then 6 zeros: 255.255.255.192.mask = 255.255.255.192
—
AND with the mask clears the host bits: 77 falls in the block starting at 64.network = 192.168.10.64
—
64 addresses minus the network and broadcast addresses.network = 192.168.10.64
network   192.168.10.64
broadcast 192.168.10.127
hosts     62
100 lies within 64–127 but 130 does not.network = 192.168.10.64
network   192.168.10.64
broadcast 192.168.10.127
hosts     62
192.168.10.100 in subnet: True
192.168.10.130 in subnet: False

Behind the scenes

How C# processes this code

C# compiles to code for the .NET runtime, which invokes the program entry point.

Cost and common mistakes

O(1): a fixed number of bit operations.

  • Shifting a 32-bit value by 32 is not the same as shifting it out entirely, since C# uses only the low five bits of the shift count. That is why prefix 0 is a special case.
  • Casting each byte to uint before shifting avoids the sign problems of int arithmetic.
  • IPv6 addresses have 128 bits and need a different approach, for example System.Numerics.BigInteger.

Try it yourself

How many usable hosts are in a /24?

Reveal answer and reasoning

2^8 − 2 = 254 usable host addresses.

Further reading