diff --git a/CHANGELOG.md b/CHANGELOG.md index d027ea8c3..ddf6b647e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,16 @@ Changes: Features: * Support `st` terminal font detection for font configuration compiled in `st` binary (TerminalFont, Linux) -* Support option `--color-output` to change output color of all modules except `Title`, `Separator` +* Add option `--color-output` to change output color of all modules except `Title`, `Separator` * `display.color.output` in JSONC config file -* Support option `---output-color` to change output color of one specified module, which overrides the global option `--color-output` +* Add option `---output-color` to change output color of one specified module, which overrides the global option `--color-output` * Add option `--publicip-ipv6` to print IPv6 address (PublicIP) * Add new module `Loadavg` to print load averages (Loadavg) * Add new module `PhysicalMemory` to print information of physical memory devices (PhysicalMemory) * Requires root permission to work on Linux and FreeBSD * Support specifying `--logo-width` only for `--kitty-direct` and `--iterm` (Logo) +* Add option `--localip-show-all-ips` to show all IPs assigned to the same interface (LocalIP) + * By default first IP will be shown only Bugfixes: * Rename option `--temperature-unit` to `--temp-unit` as stated in help messages diff --git a/doc/json_schema.json b/doc/json_schema.json index 7b0efd4c8..ac3bfad9c 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1510,6 +1510,11 @@ "type": "boolean", "default": true }, + "showAllIps": { + "description": "Show all IPs bound to the same interface.\nBy default only the first IP is shown", + "type": "boolean", + "default": false + }, "compact": { "description": "Show all IPs in one line", "type": "boolean", diff --git a/src/data/help.json b/src/data/help.json index 7801aafbf..7e3631e35 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1298,6 +1298,15 @@ "default": true } }, + { + "long": "localip-show-all-ips", + "desc": "Show all IPs bound to the same interface. By default only the first IP is shown", + "arg": { + "type": "bool", + "optional": true, + "default": false + } + }, { "long": "localip-compact", "desc": "Show all IPs in one line", diff --git a/src/detection/localip/localip_linux.c b/src/detection/localip/localip_linux.c index 905dec568..9c23b987f 100644 --- a/src/detection/localip/localip_linux.c +++ b/src/detection/localip/localip_linux.c @@ -17,7 +17,7 @@ #include #endif -static void addNewIp(FFlist* list, const char* name, const char* addr, int type, bool defaultRoute) +static void addNewIp(FFlist* list, const char* name, const char* addr, int type, bool defaultRoute, bool firstOnly) { FFLocalIpResult* ip = NULL; @@ -40,11 +40,19 @@ static void addNewIp(FFlist* list, const char* name, const char* addr, int type, switch (type) { case AF_INET: - if (ip->ipv4.length) ffStrbufAppendC(&ip->ipv4, ','); + if (ip->ipv4.length) + { + if (firstOnly) return; + ffStrbufAppendC(&ip->ipv4, ','); + } ffStrbufAppendS(&ip->ipv4, addr); break; case AF_INET6: - if (ip->ipv6.length) ffStrbufAppendC(&ip->ipv6, ','); + if (ip->ipv6.length) + { + if (firstOnly) return; + ffStrbufAppendC(&ip->ipv6, ','); + } ffStrbufAppendS(&ip->ipv6, addr); break; case -1: @@ -67,7 +75,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) continue; bool isDefaultRoute = ffStrEquals(defaultRouteIfName, ifa->ifa_name); - if (options->defaultRouteOnly && !isDefaultRoute) + if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute) continue; if ((ifa->ifa_flags & IFF_LOOPBACK) && !(options->showType & FF_LOCALIP_TYPE_LOOP_BIT)) @@ -96,7 +104,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) } } - addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET, isDefaultRoute); + addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET, isDefaultRoute, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT)); } else if (ifa->ifa_addr->sa_family == AF_INET6) { @@ -121,7 +129,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) } } - addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET6, isDefaultRoute); + addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET6, isDefaultRoute, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT)); } #if defined(__FreeBSD__) || defined(__APPLE__) else if (ifa->ifa_addr->sa_family == AF_LINK) @@ -133,7 +141,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) uint8_t* ptr = (uint8_t*) LLADDR((struct sockaddr_dl *)ifa->ifa_addr); snprintf(addressBuffer, sizeof(addressBuffer), "%02x:%02x:%02x:%02x:%02x:%02x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); - addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute); + addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute, false); } #else else if (ifa->ifa_addr->sa_family == AF_PACKET) @@ -145,7 +153,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) uint8_t* ptr = ((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr; snprintf(addressBuffer, sizeof(addressBuffer), "%02x:%02x:%02x:%02x:%02x:%02x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); - addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute); + addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute, false); } #endif } diff --git a/src/detection/localip/localip_windows.c b/src/detection/localip/localip_windows.c index 96463c331..0650ae54a 100644 --- a/src/detection/localip/localip_windows.c +++ b/src/detection/localip/localip_windows.c @@ -78,7 +78,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next) { bool isDefaultRoute = adapter->IfIndex == defaultRouteIfIndex; - if (options->defaultRouteOnly && !isDefaultRoute) + if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute) continue; bool isLoop = adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK; @@ -102,10 +102,14 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) newIp = false; } + uint32_t typesToAdd = options->showType & (FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_IPV6_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT); + for (IP_ADAPTER_UNICAST_ADDRESS* ifa = adapter->FirstUnicastAddress; ifa; ifa = ifa->Next) { if (ifa->Address.lpSockaddr->sa_family == AF_INET) { + if (!(typesToAdd & (FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT))) continue; + SOCKADDR_IN* ipv4 = (SOCKADDR_IN*) ifa->Address.lpSockaddr; char addressBuffer[INET_ADDRSTRLEN + 4]; inet_ntop(AF_INET, &ipv4->sin_addr, addressBuffer, INET_ADDRSTRLEN); @@ -118,9 +122,14 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) addNewIp(results, name, addressBuffer, AF_INET, newIp, isDefaultRoute); newIp = false; + + typesToAdd &= ~(unsigned) FF_LOCALIP_TYPE_IPV4_BIT; + if (typesToAdd == 0) break; } else if (ifa->Address.lpSockaddr->sa_family == AF_INET6) { + if (!(typesToAdd & (FF_LOCALIP_TYPE_IPV6_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT))) continue; + SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr; char addressBuffer[INET6_ADDRSTRLEN + 4]; inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN); @@ -133,6 +142,9 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) addNewIp(results, name, addressBuffer, AF_INET6, newIp, isDefaultRoute); newIp = false; + + typesToAdd &= ~(unsigned) FF_LOCALIP_TYPE_IPV6_BIT; + if (typesToAdd == 0) break; } } } diff --git a/src/modules/localip/localip.c b/src/modules/localip/localip.c index 6f02338ad..9cb042eb2 100644 --- a/src/modules/localip/localip.c +++ b/src/modules/localip/localip.c @@ -192,15 +192,27 @@ bool ffParseLocalIpCommandOptions(FFLocalIpOptions* options, const char* key, co return true; } - if (ffStrEqualsIgnCase(subKey, "name-prefix")) + if (ffStrEqualsIgnCase(subKey, "default-route-only")) { - ffOptionParseString(key, value, &options->namePrefix); + if (ffOptionParseBoolean(value)) + options->showType |= FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT; + else + options->showType &= ~FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT; return true; } - if (ffStrEqualsIgnCase(subKey, "default-route-only")) + if (ffStrEqualsIgnCase(subKey, "show-all-ips")) { - options->defaultRouteOnly = ffOptionParseBoolean(value); + if (ffOptionParseBoolean(value)) + options->showType |= FF_LOCALIP_TYPE_ALL_IPS_BIT; + else + options->showType &= ~FF_LOCALIP_TYPE_ALL_IPS_BIT; + return true; + } + + if (ffStrEqualsIgnCase(subKey, "name-prefix")) + { + ffOptionParseString(key, value, &options->namePrefix); return true; } @@ -274,15 +286,27 @@ void ffParseLocalIpJsonObject(FFLocalIpOptions* options, yyjson_val* module) continue; } - if (ffStrEqualsIgnCase(key, "namePrefix")) + if (ffStrEqualsIgnCase(key, "defaultRouteOnly")) { - ffStrbufSetS(&options->namePrefix, yyjson_get_str(val)); + if (yyjson_get_bool(val)) + options->showType |= FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT; + else + options->showType &= ~FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT; continue; } - if (ffStrEqualsIgnCase(key, "defaultRouteOnly")) + if (ffStrEqualsIgnCase(key, "showAllIps")) { - options->defaultRouteOnly = yyjson_get_bool(val); + if (yyjson_get_bool(val)) + options->showType |= FF_LOCALIP_TYPE_ALL_IPS_BIT; + else + options->showType &= ~FF_LOCALIP_TYPE_ALL_IPS_BIT; + continue; + } + + if (ffStrEqualsIgnCase(key, "namePrefix")) + { + ffStrbufSetS(&options->namePrefix, yyjson_get_str(val)); continue; } @@ -316,13 +340,16 @@ void ffGenerateLocalIpJsonConfig(FFLocalIpOptions* options, yyjson_mut_doc* doc, if (options->showType & FF_LOCALIP_TYPE_COMPACT_BIT) yyjson_mut_obj_add_bool(doc, module, "compact", true); + + if (options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) + yyjson_mut_obj_add_bool(doc, module, "defaultRouteOnly", true); + + if (options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) + yyjson_mut_obj_add_bool(doc, module, "showAllIps", true); } if (!ffStrbufEqual(&options->namePrefix, &defaultOptions.namePrefix)) yyjson_mut_obj_add_strbuf(doc, module, "namePrefix", &options->namePrefix); - - if (options->defaultRouteOnly != defaultOptions.defaultRouteOnly) - yyjson_mut_obj_add_bool(doc, module, "defaultRouteOnly", options->defaultRouteOnly); } void ffGenerateLocalIpJsonResult(FF_MAYBE_UNUSED FFLocalIpOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -383,15 +410,12 @@ void ffInitLocalIpOptions(FFLocalIpOptions* options) ); ffOptionInitModuleArg(&options->moduleArgs); - options->showType = FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_PREFIX_LEN_BIT; - ffStrbufInit(&options->namePrefix); - options->defaultRouteOnly = - #ifdef __ANDROID__ - false - #else - true + options->showType = FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_PREFIX_LEN_BIT + #ifndef __ANDROID__ + | FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT #endif ; + ffStrbufInit(&options->namePrefix); } void ffDestroyLocalIpOptions(FFLocalIpOptions* options) diff --git a/src/modules/localip/option.h b/src/modules/localip/option.h index 56092e98d..55b9192cd 100644 --- a/src/modules/localip/option.h +++ b/src/modules/localip/option.h @@ -13,7 +13,9 @@ typedef enum FFLocalIpType FF_LOCALIP_TYPE_MAC_BIT = 1 << 3, FF_LOCALIP_TYPE_PREFIX_LEN_BIT = 1 << 4, - FF_LOCALIP_TYPE_COMPACT_BIT = 1 << 10, + FF_LOCALIP_TYPE_COMPACT_BIT = 1 << 10, + FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT = 1 << 11, + FF_LOCALIP_TYPE_ALL_IPS_BIT = 1 << 12, } FFLocalIpType; typedef struct FFLocalIpOptions @@ -23,5 +25,4 @@ typedef struct FFLocalIpOptions FFLocalIpType showType; FFstrbuf namePrefix; - bool defaultRouteOnly; } FFLocalIpOptions;