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
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
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);
}
}
}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
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); } }}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
| Step / line | What happens | State after step | Output 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.