ZetCode

C# IPAddress and IPNetwork

last modified October 17, 2026

In this article we show how to work with IP addresses, networks, and endpoints in C#.

An IP address identifies a network interface on an IP network. IPv4 addresses have 32 bits and are written as four decimal numbers, such as 192.168.0.10. IPv6 addresses have 128 bits and are written as eight groups of hexadecimal digits, such as 2001:db8::1; the :: stands for a run of zero groups.

The System.Net namespace contains the IPAddress class for addresses, the IPNetwork structure for address ranges in CIDR notation, and the IPEndPoint class for an address combined with a port.

C# IPAddress parse

The IPAddress.Parse method converts a string into an address and throws a FormatException if the string is invalid. The TryParse method returns false instead.

Program.cs
using System.Net;

string[] inputs = ["192.168.0.10", "2001:db8::1", "::1", "10.0.0.256", "localhost", "fe80::1%2"];

foreach (var input in inputs)
{
    if (IPAddress.TryParse(input, out IPAddress? ip))
    {
        Console.WriteLine($"{input,-14} {ip.AddressFamily,-15} loopback: {IPAddress.IsLoopback(ip)}");
    }
    else
    {
        Console.WriteLine($"{input,-14} not an IP address");
    }
}

We try to parse several strings.

Console.WriteLine($"{input,-14} {ip.AddressFamily,-15} loopback: {IPAddress.IsLoopback(ip)}");

The AddressFamily property tells IPv4 (InterNetwork) and IPv6 (InterNetworkV6) addresses apart. The IsLoopback method checks for the loopback addresses 127.0.0.0/8 and ::1.

$ dotnet run
192.168.0.10   InterNetwork    loopback: False
2001:db8::1    InterNetworkV6  loopback: False
::1            InterNetworkV6  loopback: True
10.0.0.256     not an IP address
localhost      not an IP address
fe80::1%2      InterNetworkV6  loopback: False

The number 256 is out of range for an IPv4 address. A host name such as localhost is not an address; it must be resolved with the Dns class. The %2 suffix is the scope id of a link-local IPv6 address.

C# IPAddress properties

In the next example, we look at the bytes of an address, convert between IPv4 and IPv6, and use the predefined addresses.

Program.cs
using System.Net;

IPAddress ip = IPAddress.Parse("192.168.0.10");

byte[] bytes = ip.GetAddressBytes();
Console.WriteLine(string.Join(".", bytes));
Console.WriteLine(Convert.ToHexString(bytes));

var fromBytes = new IPAddress([10, 0, 0, 1]);
Console.WriteLine(fromBytes);

IPAddress mapped = ip.MapToIPv6();
Console.WriteLine(mapped);
Console.WriteLine(mapped.IsIPv4MappedToIPv6);
Console.WriteLine(mapped.MapToIPv4());

IPAddress v6 = IPAddress.Parse("2001:0db8:0000:0000:0000:0000:0000:0001");
Console.WriteLine(v6);

IPAddress link = IPAddress.Parse("fe80::1c3b:5e0c:5371:bddc%2");
Console.WriteLine($"{link.IsIPv6LinkLocal} scope {link.ScopeId}");

Console.WriteLine(IPAddress.Any);
Console.WriteLine(IPAddress.IPv6Any);
Console.WriteLine(IPAddress.Broadcast);

We work with IPv4 and IPv6 addresses.

byte[] bytes = ip.GetAddressBytes();
Console.WriteLine(string.Join(".", bytes));
Console.WriteLine(Convert.ToHexString(bytes));

var fromBytes = new IPAddress([10, 0, 0, 1]);

The GetAddressBytes method returns the address in network byte order; four bytes for IPv4 and sixteen for IPv6. An address can be created from bytes as well.

IPAddress mapped = ip.MapToIPv6();
Console.WriteLine(mapped);
Console.WriteLine(mapped.IsIPv4MappedToIPv6);
Console.WriteLine(mapped.MapToIPv4());

An IPv4 address can be represented as an IPv4-mapped IPv6 address. Dual-mode sockets, which accept both IPv4 and IPv6 connections, report IPv4 clients in this form, for instance ::ffff:192.168.0.10. The MapToIPv4 method converts it back.

IPAddress v6 = IPAddress.Parse("2001:0db8:0000:0000:0000:0000:0000:0001");
Console.WriteLine(v6);

IPv6 addresses are printed in the shortest form: leading zeros are dropped and the longest run of zero groups is replaced with ::.

Console.WriteLine(IPAddress.Any);
Console.WriteLine(IPAddress.IPv6Any);
Console.WriteLine(IPAddress.Broadcast);

The Any addresses are used by servers to listen on all network interfaces.

$ dotnet run
192.168.0.10
C0A8000A
10.0.0.1
::ffff:192.168.0.10
True
192.168.0.10
2001:db8::1
True scope 2
0.0.0.0
::
255.255.255.255

C# IPNetwork

The IPNetwork structure, added in .NET 8, represents a range of addresses in CIDR notation, for instance 192.168.0.0/16. The number after the slash is the prefix length: the number of leading bits that are the same for all addresses of the network. In the following example, we check whether addresses belong to the private address ranges.

Program.cs
using System.Net;

IPNetwork[] privateNetworks =
[
    IPNetwork.Parse("10.0.0.0/8"),
    IPNetwork.Parse("172.16.0.0/12"),
    IPNetwork.Parse("192.168.0.0/16"),
    IPNetwork.Parse("fc00::/7")
];

string[] addresses = ["192.168.1.20", "172.20.5.1", "172.32.0.1", "8.8.8.8", "fd12:3456::1"];

foreach (var a in addresses)
{
    IPAddress ip = IPAddress.Parse(a);
    int idx = Array.FindIndex(privateNetworks, n => n.Contains(ip));

    string res = idx >= 0 ? $"private ({privateNetworks[idx]})" : "public";
    Console.WriteLine($"{a,-14} {res}");
}

var net = IPNetwork.Parse("192.168.0.77/24");
Console.WriteLine($"{net} base: {net.BaseAddress}, prefix: {net.PrefixLength}");

Console.WriteLine(IPNetwork.TryParse("192.168.0.0/33", out _));

We define the private IPv4 networks from RFC 1918 and the IPv6 unique local network.

int idx = Array.FindIndex(privateNetworks, n => n.Contains(ip));

string res = idx >= 0 ? $"private ({privateNetworks[idx]})" : "public";

The Contains method checks if an address belongs to the network. We look for the first network that contains the address.

Note that IPNetwork is a structure. If we used FirstOrDefault to find the network, it would return the default value of the structure, 0.0.0.0/0, instead of null when there is no match; every address would look private. This is why we use Array.FindIndex, which returns -1 when nothing is found.

var net = IPNetwork.Parse("192.168.0.77/24");
Console.WriteLine($"{net} base: {net.BaseAddress}, prefix: {net.PrefixLength}");

The BaseAddress and PrefixLength properties give the parts of the network. If the given address has bits set beyond the prefix, .NET 10 clears them, so 192.168.0.77/24 becomes 192.168.0.0/24.

Console.WriteLine(IPNetwork.TryParse("192.168.0.0/33", out _));

An IPv4 prefix cannot be longer than 32 bits, so parsing fails.

$ dotnet run
192.168.1.20   private (192.168.0.0/16)
172.20.5.1     private (172.16.0.0/12)
172.32.0.1     public
8.8.8.8        public
fd12:3456::1   private (fc00::/7)
192.168.0.0/24 base: 192.168.0.0, prefix: 24
False

The 172.16.0.0/12 network spans the addresses from 172.16.0.0 to 172.31.255.255, so 172.32.0.1 is public.

C# IPEndPoint

An IPEndPoint is an IP address combined with a port number. It is used by sockets to specify where to connect or listen.

Program.cs
using System.Net;

IPEndPoint ep1 = IPEndPoint.Parse("192.168.0.10:8080");
IPEndPoint ep2 = IPEndPoint.Parse("[2001:db8::1]:443");

Console.WriteLine($"{ep1.Address} port {ep1.Port}");
Console.WriteLine($"{ep2.Address} port {ep2.Port}");

var ep3 = new IPEndPoint(IPAddress.Loopback, 5000);
Console.WriteLine(ep3);

Console.WriteLine(IPEndPoint.TryParse("example.com:80", out _));

We parse endpoints from strings and create one from an address and a port.

IPEndPoint ep2 = IPEndPoint.Parse("[2001:db8::1]:443");

An IPv6 address must be enclosed in square brackets; otherwise its colons could not be told apart from the port separator.

Console.WriteLine(IPEndPoint.TryParse("example.com:80", out _));

An IPEndPoint requires an IP address. For a host name, use the DnsEndPoint class.

$ dotnet run
192.168.0.10 port 8080
2001:db8::1 port 443
127.0.0.1:5000
False

Source

IPAddress class - language reference

IPNetwork struct - language reference

In this article we have worked with IP addresses, networks, and endpoints in C#.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all C# tutorials.