# How Fastfetch Discovers Local IP Addresses and Network Interfaces

> Learn how fastfetch detects local IP addresses and network interfaces using platform-specific modules on Linux, Windows, and macOS for detailed network information.

- Repository: [fastfetch-cli/fastfetch](https://github.com/fastfetch-cli/fastfetch)
- Tags: how-to-guide
- Published: 2026-03-30

---

**Fastfetch discovers local IP addresses by calling platform-specific detection modules—`getifaddrs()` on Linux/BSD/macOS and `GetAdaptersAddresses` on Windows—that enumerate network interfaces, filter them based on user options, and aggregate IPv4/IPv6 addresses, MAC addresses, MTU, speed, and default route information into a unified result list.**

The **fastfetch-cli/fastfetch** repository implements a robust cross-platform mechanism to detect and display local network configuration. When you query local IP information, fastfetch delegates the heavy lifting to dedicated detection modules that interact directly with operating system networking APIs, ensuring accurate and detailed interface enumeration across Linux, BSD, macOS, Haiku, and Windows.

## Platform-Specific Detection Modules

Fastfetch organizes its IP detection logic into two primary implementation files, each optimized for their respective operating system families.

### Linux, BSD, macOS, and Haiku Implementation

On Unix-like systems, fastfetch uses [`src/detection/localip/localip_linux.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/localip/localip_linux.c) to interface with the kernel. The core function `ffDetectLocalIps()` calls `getifaddrs()` at lines 79-86 to obtain a linked list of `struct ifaddrs` entries representing all network interfaces.

The implementation then iterates through each interface (lines 89-124), applying rigorous filters to exclude interfaces without addresses, interfaces not marked `IFF_RUNNING`, and loopback interfaces unless specifically requested. For each valid interface, the code constructs a temporary `FFAdapter` structure that groups MAC, IPv4, and IPv6 addresses together before final aggregation.

### Windows Implementation

For Windows systems, [`src/detection/localip/localip_windows.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/localip/localip_windows.c) implements the same `ffDetectLocalIps()` signature but uses the Win32 `GetAdaptersAddresses` API. The function first allocates a dynamic buffer (lines 33-61), repeatedly calling the API until the buffer size is sufficient to hold all adapter information.

The Windows module iterates over the `IP_ADAPTER_ADDRESSES` linked list (lines 72-122), skipping adapters that are not `IfOperStatusUp`, filtering by user-provided name prefixes, and checking for default-route status when the `defaultRouteOnly` flag is set. Each selected adapter populates an `FFLocalIpResult` structure with data copied from the adapter's `FriendlyName` field.

## The Detection Pipeline: From System Calls to Results

The process of discovering local IP addresses follows a structured pipeline that transforms raw system data into formatted output.

### Entry Point: `ffDetectLocalIps`

Both platforms expose the identical public function signature:

```c
const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results);

```

The **localip** module invokes this function with user-requested options encoded in `FFLocalIpOptions` and an empty `FFlist` that will hold `FFLocalIpResult` structures. This design ensures a uniform API across all supported platforms while allowing platform-specific optimizations underneath.

### Enumerating Network Interfaces

**On Linux**, the system call `getifaddrs()` returns a comprehensive list of interface addresses. Fastfetch loops through these entries and filters out:
- Interfaces lacking valid addresses
- Interfaces not in the `IFF_RUNNING` state
- Loopback interfaces unless `FF_LOCALIP_TYPE_LOOP_BIT` is enabled
- Interfaces failing to match user-provided name prefixes
- Non-IPv4/IPv6 address families unless MAC address retrieval is requested

**On Windows**, the `GetAdaptersAddresses` API provides similar functionality but includes additional metadata like adapter operational status and physical address length. The code specifically checks `IfOperStatusUp` to ensure only active adapters are considered.

### Filtering and Collecting IP Addresses

After enumerating interfaces, both implementations walk the per-adapter address lists to extract IP information.

In [`src/detection/localip/localip_linux.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/localip/localip_linux.c), the `appendIpv4` and `appendIpv6` helpers (lines 124-172) format addresses with optional CIDR notation, appending results to the output buffer. The main decision loop (lines 151-197) determines which addresses belong to the current adapter based on the `showType` bitmask.

In [`src/detection/localip/localip_windows.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/localip/localip_windows.c), the unicast address loop (lines 132-240) handles IPv4 (`AF_INET`) and IPv6 (`AF_INET6`) separately, using `RtlIpv4AddressToStringA` and `RtlIpv6AddressToStringA` for string conversion. The code discards non-preferred or temporary addresses unless the `ALL_IPS` flag is set, and tracks default route membership for each address.

### Resolving the Default Route

When users request `--localip default-route-only`, fastfetch must identify which interface carries the system's default gateway. The helper functions `ffNetifGetDefaultRouteV4()` and `ffNetifGetDefaultRouteV6()` in [`src/common/impl/netif.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/netif.c) provide this capability.

These functions lazily initialize a static `FFNetifDefaultRouteResult` on first call, then execute platform-specific logic to parse the routing table—reading `/proc/net/route` on Linux or calling `GetIpForwardTable2` on Windows. Both detection modules query these helpers to set the `defaultRoute` bitmask in their results, indicating whether an interface serves as the default IPv4 or IPv6 gateway.

## Optional Interface Properties

Beyond basic IP enumeration, fastfetch conditionally retrieves extended interface attributes based on the `options->showType` bitmask.

**MTU**: On Linux, the code opens a socket and calls `ioctl(SIOCGIFMTU)` (lines 553-563). On Windows, it directly reads `adapter->Mtu` (lines 49-51).

**Speed**: Linux uses `ioctl(SIOCETHTOOL)` with `struct ethtool_cmd` (lines 668-724), falling back to `ifmedia` on BSD systems. Windows divides `adapter->ReceiveLinkSpeed` by 1,000,000 to obtain Mbps values (lines 45-47).

**MAC Address**: Linux retrieves hardware addresses via `ioctl(SIOCGIFHWADDR)` or by reading `sockaddr_ll` / `sockaddr_dl` structures (lines 517-527). Windows formats the `PhysicalAddress` array from the adapter structure (lines 57-60).

**Flags**: The helper `ffLocalIpFillNIFlags()` converts binary interface flags into human-readable strings. On Linux, it processes `ifa_flags`; on Windows, it interprets `adapter->Flags` (lines 504-509 and 53-55 respectively).

## Using the Local IP Module

You can control fastfetch's local IP discovery through command-line flags that correspond directly to the internal `FF_LOCALIP_TYPE_*` bitmasks.

Show all IPv4 and IPv6 addresses with MAC and MTU information:

```bash
fastfetch --module localip \
    --localip showIpv4 showIpv6 showMac showMtu

```

Display only the interface handling the default route:

```bash
fastfetch --module localip \
    --localip defaultRouteOnly

```

Programmatically, you can invoke the detection function from C code using the fastfetch library:

```c
#include "fastfetch.h"

int main(void) {
    FFLocalIpOptions options = {
        .showType = FF_LOCALIP_TYPE_IPV4_BIT |
                    FF_LOCALIP_TYPE_IPV6_BIT |
                    FF_LOCALIP_TYPE_MAC_BIT   |
                    FF_LOCALIP_TYPE_MTU_BIT,
        .namePrefix = { .chars = "", .length = 0 },
        .ipv6Type   = FF_LOCALIP_IPV6_TYPE_AUTO,
    };

    FFlist results;
    ffListInit(&results, sizeof(FFLocalIpResult));

    const char *err = ffDetectLocalIps(&options, &results);
    if (err) {
        fprintf(stderr, "Failed to detect local IPs: %s\n", err);
        return 1;
    }

    FF_LIST_FOR_EACH(FFLocalIpResult, iface, results) {
        printf("%s: %s %s (MAC %s, MTU %d)\n",
            iface->name.chars,
            iface->ipv4.length ? iface->ipv4.chars : "(no IPv4)",
            iface->ipv6.length ? iface->ipv6.chars : "(no IPv6)",
            iface->mac.length  ? iface->mac.chars  : "(no MAC)",
            iface->mtu);
    }

    ffListDestroy(&results);
    return 0;
}

```

## Summary

- Fastfetch discovers local IP addresses through platform-specific modules in [`src/detection/localip/localip_linux.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/localip/localip_linux.c) and [`src/detection/localip/localip_windows.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/localip/localip_windows.c).
- **Linux/BSD/macOS** systems use the `getifaddrs()` system call, while **Windows** uses `GetAdaptersAddresses`.
- The `ffDetectLocalIps()` function serves as the unified entry point, returning results in a platform-agnostic `FFlist` of `FFLocalIpResult` structures.
- Default route detection relies on `ffNetifGetDefaultRouteV4()` and `ffNetifGetDefaultRouteV6()` in [`src/common/impl/netif.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/netif.c), which parse system routing tables.
- Optional properties like **MTU**, **link speed**, **MAC address**, and **interface flags** are retrieved through `ioctl` calls on Unix and adapter structure fields on Windows.

## Frequently Asked Questions

### What system calls does fastfetch use to enumerate network interfaces?

On Linux, BSD, macOS, and Haiku, fastfetch calls `getifaddrs()` to retrieve a linked list of network interfaces and their addresses. On Windows, it uses the Win32 API function `GetAdaptersAddresses`, allocating a dynamic buffer that expands until it can hold all adapter information. These system calls provide the raw data that `ffDetectLocalIps()` processes and filters according to user specifications.

### How does fastfetch determine which interface owns the default route?

Fastfetch determines the default route interface through the helper functions `ffNetifGetDefaultRouteV4()` and `ffNetifGetDefaultRouteV6()` defined in [`src/common/netif.h`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/netif.h) and implemented in [`src/common/impl/netif.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/common/impl/netif.c). These functions lazily initialize on first use, then parse the system routing table—reading `/proc/net/route` on Linux or using `GetIpForwardTable2` on Windows—to identify the interface index associated with the default gateway.

### Can fastfetch show MAC addresses and MTU information for network interfaces?

Yes, fastfetch can display **MAC addresses**, **MTU**, **link speed**, and **interface flags** when the corresponding bits are set in the `showType` option. On Linux, MAC addresses come from `ioctl(SIOCGIFHWADDR)` or socket address structures, while MTU uses `ioctl(SIOCGIFMTU)`. On Windows, these values are read directly from the `IP_ADAPTER_ADDRESSES` structure fields `PhysicalAddress` and `Mtu`.

### How does fastfetch handle temporary or non-preferred IP addresses on Windows?

On Windows, the detection code in [`src/detection/localip/localip_windows.c`](https://github.com/fastfetch-cli/fastfetch/blob/main/src/detection/localip/localip_windows.c) (lines 132-240) specifically checks address properties in the `IP_ADAPTER_UNICAST_ADDRESS` structure. By default, it discards non-preferred and temporary addresses unless the user has set the `ALL_IPS` flag in the options. This ensures that transient or deprecated addresses do not clutter the output unless explicitly requested.