mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-30 00:37:23 +01:00
LocalIP: adds IPv6 type selection for local IP display
`{ "type": "localip", "showIpv6": "ula" /* Show ULA only */ }`
Fixes #1459
This commit is contained in:
+26
-1
@@ -2920,7 +2920,32 @@
|
||||
},
|
||||
"showIpv6": {
|
||||
"description": "Show IPv6 addresses",
|
||||
"type": "boolean",
|
||||
"oneOf": [
|
||||
{
|
||||
"const": true,
|
||||
"description": "Show the most useful IPv6 addresses"
|
||||
},
|
||||
{
|
||||
"const": false,
|
||||
"description": "Do not show IPv6 addresses"
|
||||
},
|
||||
{
|
||||
"const": "gua",
|
||||
"description": "Show only global unicast IPv6 addresses (2000::/3)"
|
||||
},
|
||||
{
|
||||
"const": "ula",
|
||||
"description": "Show only unique local IPv6 addresses (fc00::/7)"
|
||||
},
|
||||
{
|
||||
"const": "lla",
|
||||
"description": "Show only link-local IPv6 addresses (fe80::/10)"
|
||||
},
|
||||
{
|
||||
"const": "unknown",
|
||||
"description": "Show only IPv6 addresses that are not gua, ula or lla"
|
||||
}
|
||||
],
|
||||
"default": false
|
||||
},
|
||||
"showSpeed": {
|
||||
|
||||
@@ -3,6 +3,19 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/localip/option.h"
|
||||
|
||||
#ifndef IN6_IS_ADDR_GLOBAL
|
||||
#define IN6_IS_ADDR_GLOBAL(a) \
|
||||
((((const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl(0x20000000))
|
||||
#endif
|
||||
#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
|
||||
#define IN6_IS_ADDR_UNIQUE_LOCAL(a) \
|
||||
((((const uint32_t *) (a))[0] & htonl(0xfe000000)) == htonl(0xfc000000))
|
||||
#endif
|
||||
#ifndef IN6_IS_ADDR_LINKLOCAL
|
||||
#define IN6_IS_ADDR_LINKLOCAL(a) \
|
||||
((((const uint32_t *) (a))[0] & htonl(0xffc00000)) == htonl(0xfe800000))
|
||||
#endif
|
||||
|
||||
typedef struct FFLocalIpResult
|
||||
{
|
||||
FFstrbuf name;
|
||||
|
||||
@@ -111,47 +111,32 @@ static const FFLocalIpNIFlag niFlagOptions[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFIPv6Type
|
||||
{
|
||||
FF_IPV6_Other,
|
||||
FF_IPV6_GUA = 0b0001,
|
||||
FF_IPV6_GUA_SECONDARY = 0b0101,
|
||||
FF_IPV6_ULA = 0b0010,
|
||||
FF_IPV6_ULA_SECONDARY = 0b0110,
|
||||
FF_IPV6_TYPE_MASK = 0b0011,
|
||||
FF_IPV6_SECONDARY_FLAG = 0b1100,
|
||||
FF_IPV6_PREFERRED = UINT8_MAX,
|
||||
} FFIPv6Type;
|
||||
|
||||
static FFIPv6Type getIpType(struct ifaddrs* ifa)
|
||||
static FFLocalIpIpv6Type getIpv6Type(struct ifaddrs* ifa)
|
||||
{
|
||||
struct sockaddr_in6* addr = (struct sockaddr_in6*) ifa->ifa_addr;
|
||||
|
||||
FF_DEBUG("Checking IPv6 type for interface %s", ifa->ifa_name);
|
||||
|
||||
#ifndef IN6_IS_ADDR_GLOBAL
|
||||
#define IN6_IS_ADDR_GLOBAL(a) \
|
||||
((((const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl(0x20000000))
|
||||
#endif
|
||||
#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
|
||||
#define IN6_IS_ADDR_UNIQUE_LOCAL(a) \
|
||||
((((const uint32_t *) (a))[0] & htonl(0xfe000000)) == htonl(0xfc000000))
|
||||
#endif
|
||||
FFIPv6Type result = FF_IPV6_Other;
|
||||
FFLocalIpIpv6Type result = FF_LOCALIP_IPV6_TYPE_NONE;
|
||||
if (IN6_IS_ADDR_GLOBAL(&addr->sin6_addr))
|
||||
{
|
||||
result = FF_IPV6_GUA;
|
||||
result = FF_LOCALIP_IPV6_TYPE_GUA_BIT;
|
||||
FF_DEBUG("Interface %s has Global Unicast Address", ifa->ifa_name);
|
||||
}
|
||||
else if (IN6_IS_ADDR_UNIQUE_LOCAL(&addr->sin6_addr))
|
||||
{
|
||||
result = FF_IPV6_ULA;
|
||||
result = FF_LOCALIP_IPV6_TYPE_ULA_BIT;
|
||||
FF_DEBUG("Interface %s has Unique Local Address", ifa->ifa_name);
|
||||
}
|
||||
else if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
|
||||
{
|
||||
result = FF_LOCALIP_IPV6_TYPE_LLA_BIT;
|
||||
FF_DEBUG("Interface %s has Link-Local Address", ifa->ifa_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Interface %s has other IPv6 address type", ifa->ifa_name);
|
||||
return FF_IPV6_Other;
|
||||
FF_DEBUG("Interface %s has unknown IPv6 address type", ifa->ifa_name);
|
||||
return FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT;
|
||||
}
|
||||
|
||||
#ifdef SIOCGIFAFLAG_IN6
|
||||
@@ -178,13 +163,13 @@ static FFIPv6Type getIpType(struct ifaddrs* ifa)
|
||||
|
||||
#ifdef IN6_IFF_PREFER_SOURCE
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_PREFER_SOURCE)
|
||||
return FF_IPV6_PREFERRED;
|
||||
result |= FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT;
|
||||
#endif
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY | IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED
|
||||
#ifdef IN6_IFF_OPTIMISTIC
|
||||
| IN6_IFF_OPTIMISTIC
|
||||
#endif
|
||||
)) result |= FF_IPV6_SECONDARY_FLAG;
|
||||
)) result |= FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT;
|
||||
return result;
|
||||
#elif __linux__
|
||||
static FFlist addresses = {};
|
||||
@@ -220,13 +205,13 @@ static FFIPv6Type getIpType(struct ifaddrs* ifa)
|
||||
if (memcmp(&addr->sin6_addr, entry, sizeof(struct in6_addr)) == 0)
|
||||
return result;
|
||||
}
|
||||
result |= FF_IPV6_SECONDARY_FLAG;
|
||||
result |= FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT;
|
||||
return result;
|
||||
#elif __sun
|
||||
if (ifa->ifa_flags & IFF_PREFERRED)
|
||||
return FF_IPV6_PREFERRED;
|
||||
result |= FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT;
|
||||
if (ifa->ifa_flags & (IFF_DEPRECATED | IFF_TEMPORARY | IFF_DUPLICATE))
|
||||
result |= FF_IPV6_SECONDARY_FLAG;
|
||||
result |= FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT;
|
||||
return result;
|
||||
#else
|
||||
return result;
|
||||
@@ -509,46 +494,65 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
|
||||
if (options->ipv6Type == FF_LOCALIP_IPV6_TYPE_AUTO)
|
||||
{
|
||||
struct ifaddrs* selected = NULL;
|
||||
struct ifaddrs* secondary = NULL;
|
||||
|
||||
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
|
||||
{
|
||||
FFIPv6Type type = getIpType(*pifa);
|
||||
if (type == FF_IPV6_PREFERRED)
|
||||
struct ifaddrs* selected = NULL;
|
||||
struct ifaddrs* secondary = NULL;
|
||||
|
||||
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
|
||||
{
|
||||
selected = *pifa;
|
||||
FF_DEBUG("Found preferred IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
break;
|
||||
FFLocalIpIpv6Type type = getIpv6Type(*pifa);
|
||||
if (type & FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT)
|
||||
{
|
||||
selected = *pifa;
|
||||
FF_DEBUG("Found preferred IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
break;
|
||||
}
|
||||
else if ((type & FF_LOCALIP_IPV6_TYPE_GUA_BIT) && !(type & FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT) && !selected)
|
||||
{
|
||||
selected = *pifa;
|
||||
FF_DEBUG("Found GUA IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
}
|
||||
else if ((type & FF_LOCALIP_IPV6_TYPE_ULA_BIT) && !(type & FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT) && !secondary)
|
||||
{
|
||||
secondary = *pifa;
|
||||
FF_DEBUG("Found ULA IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
}
|
||||
}
|
||||
else if (type == FF_IPV6_GUA && !selected)
|
||||
if (!selected) selected = secondary;
|
||||
|
||||
if (selected)
|
||||
appendIpv6(options, &item->ipv6, selected);
|
||||
else if (adapter->ipv6.length > 0)
|
||||
{
|
||||
selected = *pifa;
|
||||
FF_DEBUG("Found GUA IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
}
|
||||
else if (type == FF_IPV6_ULA && !secondary)
|
||||
{
|
||||
secondary = *pifa;
|
||||
FF_DEBUG("Found ULA IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
appendIpv6(options, &item->ipv6, *FF_LIST_GET(struct ifaddrs*, adapter->ipv6, 0));
|
||||
FF_DEBUG("Using first IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
}
|
||||
}
|
||||
if (!selected) selected = secondary;
|
||||
|
||||
if (selected)
|
||||
appendIpv6(options, &item->ipv6, selected);
|
||||
else if (adapter->ipv6.length > 0)
|
||||
else
|
||||
{
|
||||
appendIpv6(options, &item->ipv6, *FF_LIST_GET(struct ifaddrs*, adapter->ipv6, 0));
|
||||
FF_DEBUG("Using first IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
FF_DEBUG("Adding all IPv6 addresses for interface %s", adapter->mac->ifa_name);
|
||||
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
|
||||
appendIpv6(options, &item->ipv6, *pifa);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Adding all IPv6 addresses for interface %s", adapter->mac->ifa_name);
|
||||
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
|
||||
appendIpv6(options, &item->ipv6, *pifa);
|
||||
{
|
||||
FFLocalIpIpv6Type type = getIpv6Type(*pifa);
|
||||
if (type & options->ipv6Type)
|
||||
{
|
||||
if ((options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) || !(type & FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT))
|
||||
{
|
||||
appendIpv6(options, &item->ipv6, *pifa);
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mac:
|
||||
|
||||
@@ -140,13 +140,24 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
|
||||
for (IP_ADAPTER_UNICAST_ADDRESS* ifa = adapter->FirstUnicastAddress; ifa; ifa = ifa->Next)
|
||||
{
|
||||
FF_DEBUG("Processing unicast address: family=%d, DadState=%d",
|
||||
ifa->Address.lpSockaddr->sa_family, ifa->DadState);
|
||||
FF_DEBUG("Processing unicast address: prefix origin=%d, suffix origin=%d, family=%d, DadState=%d",
|
||||
ifa->PrefixOrigin, ifa->SuffixOrigin, ifa->Address.lpSockaddr->sa_family, ifa->DadState);
|
||||
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) && ifa->DadState != IpDadStatePreferred)
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
|
||||
{
|
||||
FF_DEBUG("Skipping address (DadState=%d, not preferred)", ifa->DadState);
|
||||
continue;
|
||||
if (ifa->DadState != IpDadStatePreferred)
|
||||
{
|
||||
FF_DEBUG("Skipping address (not preferred)");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifa->SuffixOrigin == IpSuffixOriginRandom)
|
||||
{
|
||||
FF_DEBUG("Skipping temporary address (random suffix)");
|
||||
continue;
|
||||
}
|
||||
|
||||
// MIB_UNICASTIPADDRESS_ROW::SkipAsSource
|
||||
}
|
||||
|
||||
if (ifa->Address.lpSockaddr->sa_family == AF_INET)
|
||||
@@ -192,6 +203,20 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
continue;
|
||||
}
|
||||
|
||||
SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr;
|
||||
|
||||
FFLocalIpIpv6Type ipv6Type = FF_LOCALIP_IPV6_TYPE_NONE;
|
||||
if (IN6_IS_ADDR_GLOBAL(&ipv6->sin6_addr)) ipv6Type |= FF_LOCALIP_IPV6_TYPE_GUA_BIT;
|
||||
else if (IN6_IS_ADDR_UNIQUE_LOCAL(&ipv6->sin6_addr)) ipv6Type |= FF_LOCALIP_IPV6_TYPE_ULA_BIT;
|
||||
else if (IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr)) ipv6Type |= FF_LOCALIP_IPV6_TYPE_LLA_BIT;
|
||||
else ipv6Type |= FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT;
|
||||
|
||||
if (!(options->ipv6Type & ipv6Type))
|
||||
{
|
||||
FF_DEBUG("Skipping IPv6 address (doesn't match requested type 0x%X)", options->ipv6Type);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isDefaultRoute = ((options->showType & FF_LOCALIP_TYPE_IPV6_BIT) && ffNetifGetDefaultRouteV6()->ifIndex == adapter->IfIndex);
|
||||
if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute)
|
||||
{
|
||||
@@ -199,7 +224,6 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
continue;
|
||||
}
|
||||
|
||||
SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr;
|
||||
char addressBuffer[INET6_ADDRSTRLEN + 6];
|
||||
inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN);
|
||||
|
||||
|
||||
@@ -198,10 +198,33 @@ void ffParseLocalIpJsonObject(FFLocalIpOptions* options, yyjson_val* module)
|
||||
|
||||
if (unsafe_yyjson_equals_str(key, "showIpv6"))
|
||||
{
|
||||
if (yyjson_get_bool(val))
|
||||
options->showType |= FF_LOCALIP_TYPE_IPV6_BIT;
|
||||
else
|
||||
options->showType &= ~FF_LOCALIP_TYPE_IPV6_BIT;
|
||||
if (yyjson_is_bool(val))
|
||||
{
|
||||
options->ipv6Type = FF_LOCALIP_IPV6_TYPE_AUTO;
|
||||
if (unsafe_yyjson_get_bool(val))
|
||||
options->showType |= FF_LOCALIP_TYPE_IPV6_BIT;
|
||||
else
|
||||
options->showType &= ~FF_LOCALIP_TYPE_IPV6_BIT;
|
||||
}
|
||||
else if (yyjson_is_str(val))
|
||||
{
|
||||
int value;
|
||||
const char* error = ffJsonConfigParseEnum(val, &value, (FFKeyValuePair[]) {
|
||||
{ "auto", FF_LOCALIP_IPV6_TYPE_AUTO },
|
||||
{ "gua", FF_LOCALIP_IPV6_TYPE_GUA_BIT },
|
||||
{ "ula", FF_LOCALIP_IPV6_TYPE_ULA_BIT },
|
||||
{ "lla", FF_LOCALIP_IPV6_TYPE_LLA_BIT },
|
||||
{ "unknown", FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT },
|
||||
{},
|
||||
});
|
||||
if (error)
|
||||
ffPrintError(FF_LOCALIP_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Invalid %s value: %s", unsafe_yyjson_get_str(key), error);
|
||||
else
|
||||
{
|
||||
options->showType |= FF_LOCALIP_TYPE_IPV6_BIT;
|
||||
options->ipv6Type = (FFLocalIpIpv6Type) value;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -302,7 +325,21 @@ void ffGenerateLocalIpJsonConfig(FFLocalIpOptions* options, yyjson_mut_doc* doc,
|
||||
|
||||
yyjson_mut_obj_add_bool(doc, module, "showIpv4", !!(options->showType & FF_LOCALIP_TYPE_IPV4_BIT));
|
||||
|
||||
yyjson_mut_obj_add_bool(doc, module, "showIpv6", !!(options->showType & FF_LOCALIP_TYPE_IPV6_BIT));
|
||||
if (options->ipv6Type == FF_LOCALIP_IPV6_TYPE_AUTO)
|
||||
yyjson_mut_obj_add_bool(doc, module, "showIpv6", !!(options->showType & FF_LOCALIP_TYPE_IPV6_BIT));
|
||||
else
|
||||
{
|
||||
const char* str = NULL;
|
||||
switch (options->ipv6Type)
|
||||
{
|
||||
case FF_LOCALIP_IPV6_TYPE_GUA_BIT: str = "gua"; break;
|
||||
case FF_LOCALIP_IPV6_TYPE_ULA_BIT: str = "ula"; break;
|
||||
case FF_LOCALIP_IPV6_TYPE_LLA_BIT: str = "lla"; break;
|
||||
case FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT: str = "unknown"; break;
|
||||
default: str = "auto"; break;
|
||||
}
|
||||
yyjson_mut_obj_add_str(doc, module, "showIpv6", str);
|
||||
}
|
||||
|
||||
yyjson_mut_obj_add_bool(doc, module, "showMac", !!(options->showType & FF_LOCALIP_TYPE_MAC_BIT));
|
||||
|
||||
@@ -385,6 +422,7 @@ void ffInitLocalIpOptions(FFLocalIpOptions* options)
|
||||
| FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT
|
||||
#endif
|
||||
;
|
||||
options->ipv6Type = FF_LOCALIP_IPV6_TYPE_AUTO;
|
||||
ffStrbufInit(&options->namePrefix);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,26 @@ typedef enum __attribute__((__packed__)) FFLocalIpType
|
||||
} FFLocalIpType;
|
||||
static_assert(sizeof(FFLocalIpType) == sizeof(uint16_t), "");
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFLocalIpIpv6Type
|
||||
{
|
||||
FF_LOCALIP_IPV6_TYPE_NONE = 0b00000000,
|
||||
FF_LOCALIP_IPV6_TYPE_GUA_BIT = 0b00000001,
|
||||
FF_LOCALIP_IPV6_TYPE_ULA_BIT = 0b00000010,
|
||||
FF_LOCALIP_IPV6_TYPE_LLA_BIT = 0b00000100,
|
||||
FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT = 0b00001000, // IPv4-mapped, loopback, etc.
|
||||
FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT = 0b01000000, // Temporary, duplicated, etc.
|
||||
FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT = 0b10000000, // PREFER_SOURCE (manually set)
|
||||
FF_LOCALIP_IPV6_TYPE_TYPE_MASK = 0b00011111,
|
||||
FF_LOCALIP_IPV6_TYPE_AUTO = 0b11111111, // Used for detect option
|
||||
} FFLocalIpIpv6Type;
|
||||
static_assert(sizeof(FFLocalIpIpv6Type) == sizeof(uint8_t), "");
|
||||
|
||||
typedef struct FFLocalIpOptions
|
||||
{
|
||||
FFModuleArgs moduleArgs;
|
||||
|
||||
FFLocalIpType showType;
|
||||
FFLocalIpIpv6Type ipv6Type;
|
||||
FFstrbuf namePrefix;
|
||||
} FFLocalIpOptions;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user