Subnet / CIDR Calculator — C# source
Compute IPv4 subnet details from a CIDR block - network, broadcast, host range, netmask, wildcard, host count, IP class, and private-range detection. Split a block into smaller subnets, all in your browser.
This is the C# implementation — the same logic the interactive tool runs, in a shareable, citable form.
// subnet-cidr — C# port: IPv4 subnet/CIDR math (dotted-quad ⇄ uint32, subnet details, CIDR splitting). (.NET 7+.) Port of src/lib/subnet-cidr.ts — same logic as this dir's python.py / go.go; invalid input yields null rather than throwing.
using System;
using System.Collections.Generic;
using System.Linq;
namespace SubnetCidr;
public static class SubnetCidr
{
// The TS /^\d+$/ check — rejects signs, hex, whitespace, and the empty string.
private static bool AllDigits(string s) => s.Length > 0 && s.All(char.IsAsciiDigit);
// "a.b.c.d" → uint. null for a wrong octet count, junk octets, or an octet > 255.
public static uint? IpToInt(string ip)
{
string[] parts = ip.Split('.');
if (parts.Length != 4) return null;
uint result = 0;
foreach (string part in parts)
{
if (!AllDigits(part) || part.Length > 3) return null;
uint octet = uint.Parse(part);
if (octet > 255) return null;
result = result * 256 + octet;
}
return result;
}
public static string IntToIp(uint v) => $"{v >> 24}.{(v >> 16) & 255}.{(v >> 8) & 255}.{v & 255}";
private static uint MaskFromPrefix(int p) => p == 0 ? 0 : 0xFFFFFFFFu << (32 - p);
// "ip/prefix" → (canonical ip, prefix). A second slash or a prefix > 32 is invalid.
private static (string ip, int prefix)? ParseCidr(string cidr)
{
string[] halves = cidr.Split('/', 2);
if (halves.Length != 2 || !AllDigits(halves[1]) || halves[1].Length > 2) return null;
if (!int.TryParse(halves[1], out int prefix) || prefix > 32) return null;
return IpToInt(halves[0]) is { } n ? (IntToIp(n), prefix) : null;
}
public sealed record SubnetInfo(string Network, string Broadcast, string FirstHost, string LastHost,
ulong HostCount, int Prefix, char IpClass, bool IsPrivate);
public static SubnetInfo SubnetDetails(string cidr) // "ip/prefix" → full block info
{
var parsed = ParseCidr(cidr);
if (parsed is null) return null;
uint mask = MaskFromPrefix(parsed.Value.prefix);
uint network = IpToInt(parsed.Value.ip)!.Value & mask, broadcast = network | ~mask;
// /31 (point-to-point) and /32 (single host) have no host/broadcast split.
uint first = parsed.Value.prefix >= 31 ? network : network + 1;
uint last = parsed.Value.prefix >= 31 ? broadcast : broadcast - 1;
ulong hosts = parsed.Value.prefix switch { >= 32 => 1, 31 => 2, var p => (1ul << (32 - p)) - 2 };
uint o1 = network >> 24, o2 = (network >> 16) & 255;
char klass = o1 < 128 ? 'A' : o1 < 192 ? 'B' : o1 < 224 ? 'C' : '-'; // D/E → '-'
bool priv = o1 == 10 || (o1 == 172 && o2 is >= 16 and <= 31) || (o1 == 192 && o2 == 168);
return new SubnetInfo(IntToIp(network), IntToIp(broadcast), IntToIp(first), IntToIp(last),
hosts, parsed.Value.prefix, klass, priv);
}
// Split into 2^(newPrefix-prefix) children; empty list for invalid input or range.
public static List<string> SplitSubnet(string cidr, int newPrefix)
{
var parsed = ParseCidr(cidr);
if (parsed is null || newPrefix < parsed.Value.prefix || newPrefix > 32) return new();
uint network = IpToInt(parsed.Value.ip)!.Value & MaskFromPrefix(parsed.Value.prefix);
uint block = 1u << (32 - newPrefix);
return Enumerable.Range(0, 1 << (newPrefix - parsed.Value.prefix))
.Select(i => $"{IntToIp(network + (uint)i * block)}/{newPrefix}").ToList();
}
public static void Main()
{
SubnetInfo d = SubnetDetails("192.168.1.100/24");
Console.WriteLine($"192.168.1.100/24 net={d.Network} bcast={d.Broadcast} first={d.FirstHost} " +
$"last={d.LastHost} hosts={d.HostCount} class={d.IpClass} private={d.IsPrivate}");
foreach (string kid in SplitSubnet("192.168.1.0/24", 26)) Console.WriteLine($" split /26 → {kid}");
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →