How Fastfetch Discovers Local IP Addresses and Network Interfaces

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 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 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:

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, 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, 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 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:

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

Display only the interface handling the default route:

fastfetch --module localip \
    --localip defaultRouteOnly

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

#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 and 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, 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 and implemented in 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 (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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →