ZetCode

C# NetworkInterface

last modified October 18, 2026

In this article we show how to work with network interfaces in C#.

A network interface is the point of interconnection between a computer and a private or public network. It can be a physical network interface card (NIC) or implemented as a virtual software interface, such as the loopback interface or a bridge created by Docker.

NetworkInterface provides configuration and statistical information for a network interface. It is available in the System.Net.NetworkInformation namespace.

$ ls /sys/class/net/
lo  wlp0s20f3

On Linux, we can find available interfaces in the /sys/class/net directory. The ip link command lists them as well. On Windows, we can use the ipconfig command.

C# GetIsNetworkAvailable

The GetIsNetworkAvailable method indicates whether any network connection is available.

Program.cs
using System.Net.NetworkInformation;

if (NetworkInterface.GetIsNetworkAvailable())
{
    Console.WriteLine("Network available");
}
else
{
    Console.WriteLine("Network not available");
}

The program prints if a network is available. A network connection is considered available if any interface other than the loopback and tunnel interfaces is up. It does not mean that the internet is reachable.

$ dotnet run
Network available

C# list network interfaces

In the following example, we list all active network interfaces.

Program.cs
using System.Net.NetworkInformation;

var nics = NetworkInterface.GetAllNetworkInterfaces()
    .Where(nic => nic.OperationalStatus == OperationalStatus.Up);

foreach (var nic in nics)
{
    Console.WriteLine($"Name: {nic.Name}");
    Console.WriteLine($"Description: {nic.Description}");
    Console.WriteLine($"Type: {nic.NetworkInterfaceType}");
    Console.WriteLine($"Status: {nic.OperationalStatus}");
    Console.WriteLine($"Speed: {nic.Speed}");

    Console.WriteLine("-----------------------------");
}

The GetAllNetworkInterfaces method returns objects that describe the network interfaces on the local computer. We keep only the interfaces that are up and print some of their properties.

$ dotnet run
Name: lo
Description: lo
Type: Loopback
Status: Up
Speed: -1
-----------------------------
Name: wlp0s20f3
Description: wlp0s20f3
Type: Ethernet
Status: Up
Speed: -1
-----------------------------

The output depends on the operating system. On Linux, the description is the same as the name, and wireless interfaces are reported as Ethernet. The Speed property is given in bits per second; -1 means that the speed is not known. On Windows, we get descriptive names of the adapters and their speed.

C# NetworkInterface MAC address

A MAC address, also called a hardware or physical address, is a unique identifier that is used to identify individual devices on a local network.

Program.cs
using System.Net.NetworkInformation;

var nics = NetworkInterface.GetAllNetworkInterfaces()
    .Where(nic => nic.NetworkInterfaceType != NetworkInterfaceType.Loopback
        && nic.OperationalStatus == OperationalStatus.Up);

foreach (var nic in nics)
{
    PhysicalAddress mac = nic.GetPhysicalAddress();
    string formatted = string.Join(":", mac.GetAddressBytes().Select(b => b.ToString("X2")));

    Console.WriteLine($"{nic.Name}: {mac} {formatted}");
}

We retrieve the MAC address with the GetPhysicalAddress method. We skip the loopback interface, which has no MAC address.

string formatted = string.Join(":", mac.GetAddressBytes().Select(b => b.ToString("X2")));

The ToString method of the PhysicalAddress prints the bytes without separators. We format the address in the usual way with colons between the bytes.

$ dotnet run
wlp0s20f3: 001A2B3C4D5E 00:1A:2B:3C:4D:5E

C# NetworkInterface IP properties

The GetIPProperties method returns an object that provides information about the IPv4 and IPv6 configuration of the interface: its addresses, DNS servers, and gateways.

Program.cs
using System.Net.NetworkInformation;
using System.Net.Sockets;

var nic = NetworkInterface.GetAllNetworkInterfaces()
    .FirstOrDefault(nic => nic.OperationalStatus == OperationalStatus.Up
        && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback
        && nic.GetIPProperties().GatewayAddresses.Count > 0);

if (nic is null)
{
    Console.WriteLine("no connected network interface found");
    return;
}

IPInterfaceProperties ipProps = nic.GetIPProperties();

Console.WriteLine($"Interface: {nic.Name}");
Console.WriteLine("-----------------------------------");

foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
{
    if (addr.Address.AddressFamily == AddressFamily.InterNetwork)
    {
        Console.WriteLine($"IPv4: {addr.Address}/{addr.PrefixLength} mask {addr.IPv4Mask}");
    }
    else
    {
        Console.WriteLine($"IPv6: {addr.Address}/{addr.PrefixLength}");
    }
}

Console.WriteLine("-----------------------------------");
Console.WriteLine($"DNS suffix: {ipProps.DnsSuffix}");
Console.WriteLine($"DNS servers: {string.Join(", ", ipProps.DnsAddresses)}");

Console.WriteLine("-----------------------------------");

foreach (GatewayIPAddressInformation gw in ipProps.GatewayAddresses)
{
    Console.WriteLine($"Gateway: {gw.Address}");
}

The example prints the IP addresses, DNS, and gateway information of the interface that connects us to the network.

var nic = NetworkInterface.GetAllNetworkInterfaces()
    .FirstOrDefault(nic => nic.OperationalStatus == OperationalStatus.Up
        && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback
        && nic.GetIPProperties().GatewayAddresses.Count > 0);

We pick the first active interface with a gateway. This skips virtual interfaces, such as Docker bridges, which are up but do not lead to other networks.

foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
{
    if (addr.Address.AddressFamily == AddressFamily.InterNetwork)
    {
        Console.WriteLine($"IPv4: {addr.Address}/{addr.PrefixLength} mask {addr.IPv4Mask}");
    }
    else
    {
        Console.WriteLine($"IPv6: {addr.Address}/{addr.PrefixLength}");
    }
}

An interface often has several addresses. We tell IPv4 and IPv6 addresses apart by their address family. The network mask is meaningful only for IPv4 addresses; for both families, the PrefixLength gives the number of bits of the network part.

$ dotnet run
Interface: wlp0s20f3
-----------------------------------
IPv4: 192.168.0.35/24 mask 255.255.255.0
IPv6: 2001:db8:1:2::35/64
IPv6: fe80::1c3b:5e0c:5371:bddc%2/64
-----------------------------------
DNS suffix: .
DNS servers: 127.0.0.53
-----------------------------------
Gateway: 192.168.0.1
Gateway: fe80::20b:ff:fe00:add0%2

On Ubuntu, the DNS server is 127.0.0.53, which is the local resolver of systemd-resolved.

C# NetworkInterface IP statistics

With the GetIPStatistics method, we can get IP statistical data for a network interface on the local computer.

Program.cs
using System.Net.NetworkInformation;

var nics = NetworkInterface.GetAllNetworkInterfaces()
    .Where(nic => nic.OperationalStatus == OperationalStatus.Up);

foreach (var nic in nics)
{
    IPInterfaceStatistics stats = nic.GetIPStatistics();

    Console.WriteLine(nic.Name);
    Console.WriteLine($"  Bytes received: {stats.BytesReceived:N0}");
    Console.WriteLine($"  Bytes sent: {stats.BytesSent:N0}");
    Console.WriteLine($"  Incoming packets with errors: {stats.IncomingPacketsWithErrors}");
    Console.WriteLine($"  Outgoing packets with errors: {stats.OutgoingPacketsWithErrors}");
    Console.WriteLine($"  Incoming packets discarded: {stats.IncomingPacketsDiscarded}");
    Console.WriteLine($"  Outgoing packets discarded: {stats.OutgoingPacketsDiscarded}");
}

The example prints the number of bytes received and sent and the number of packets with errors and packets discarded for each active interface. The counters are cumulative since the interface was brought up.

Not all statistics are available on all platforms. For instance, the OutgoingPacketsDiscarded property is not supported on macOS; the compiler's platform compatibility analyzer reports this with the CA1416 warning.

$ dotnet run
lo
  Bytes received: 387,837
  Bytes sent: 387,837
  Incoming packets with errors: 0
  Outgoing packets with errors: 0
  Incoming packets discarded: 0
  Outgoing packets discarded: 0
wlp0s20f3
  Bytes received: 352,919,722
  Bytes sent: 12,808,662
  Incoming packets with errors: 0
  Outgoing packets with errors: 0
  Incoming packets discarded: 0
  Outgoing packets discarded: 0

C# IPGlobalProperties

The IPGlobalProperties class provides information about the network connectivity of the whole computer, not of a single interface. We can get the active TCP connections and listeners, UDP listeners, and protocol statistics.

Program.cs
using System.Net.NetworkInformation;

IPGlobalProperties props = IPGlobalProperties.GetIPGlobalProperties();

Console.WriteLine($"Host name: {props.HostName}");
Console.WriteLine("Listening TCP ports:");

var ports = props.GetActiveTcpListeners()
    .Select(ep => ep.Port)
    .Distinct()
    .Order();

Console.WriteLine(string.Join(", ", ports));

Console.WriteLine("Established TCP connections:");

var connections = props.GetActiveTcpConnections()
    .Where(c => c.State == TcpState.Established);

foreach (TcpConnectionInformation c in connections)
{
    Console.WriteLine($"{c.LocalEndPoint} -> {c.RemoteEndPoint}");
}

The program lists the TCP ports on which the local services listen and the established TCP connections, similar to the netstat or ss tools.

var ports = props.GetActiveTcpListeners()
    .Select(ep => ep.Port)
    .Distinct()
    .Order();

A service often listens on both IPv4 and IPv6 addresses, so we remove the duplicate port numbers and sort them.

$ dotnet run
Host name: universum
Listening TCP ports:
53, 80, 631, 3389, 5432, 6379
Established TCP connections:
192.168.0.35:33332 -> 93.184.215.14:443
192.168.0.35:40086 -> 172.67.68.208:443
...

C# NetworkChange

The NetworkChange class raises events when the network configuration changes: the NetworkAvailabilityChanged event when the network becomes available or unavailable, and the NetworkAddressChanged event when an IP address of an interface changes, for instance when Wi-Fi reconnects or a VPN starts.

Program.cs
using System.Net.NetworkInformation;
using System.Net.Sockets;

NetworkChange.NetworkAvailabilityChanged += (_, e) =>
{
    Console.WriteLine($"{DateTime.Now:HH:mm:ss} network available: {e.IsAvailable}");
};

NetworkChange.NetworkAddressChanged += (_, _) =>
{
    Console.WriteLine($"{DateTime.Now:HH:mm:ss} network addresses changed");
    PrintAddresses();
};

PrintAddresses();
Console.WriteLine("Watching for network changes; press Enter to quit");
Console.ReadLine();

static void PrintAddresses()
{
    var nics = NetworkInterface.GetAllNetworkInterfaces()
        .Where(nic => nic.OperationalStatus == OperationalStatus.Up);

    foreach (var nic in nics)
    {
        var ipv4 = nic.GetIPProperties().UnicastAddresses
            .Where(a => a.Address.AddressFamily == AddressFamily.InterNetwork)
            .Select(a => $"{a.Address}/{a.PrefixLength}");

        Console.WriteLine($"  {nic.Name}: {string.Join(", ", ipv4)}");
    }
}

The program prints the IPv4 addresses of the active interfaces and prints them again whenever the addresses change.

NetworkChange.NetworkAddressChanged += (_, _) =>
{
    Console.WriteLine($"{DateTime.Now:HH:mm:ss} network addresses changed");
    PrintAddresses();
};

The event does not say what has changed, so we query the interfaces again. The handlers run on a thread pool thread.

$ dotnet run
  lo: 127.0.0.1/8
  wlp0s20f3: 192.168.0.35/24
Watching for network changes; press Enter to quit
19:25:40 network addresses changed
  lo: 127.0.0.1/8
  wlp0s20f3: 192.168.0.35/24
19:25:40 network available: True
19:25:44 network addresses changed
  lo: 127.0.0.1/8
  wlp0s20f3: 192.168.0.35/24
19:25:44 network available: True

To trigger the events, we created and removed a Docker network in another terminal with docker network create test and docker network rm test. Docker adds and removes a bridge interface; the bridge has no connected containers, so it is not up and does not appear in the list.

Source

NetworkInterface class - language reference

In this article we have worked with network interfaces 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.