summaryrefslogtreecommitdiffstats
path: root/src/modules/localip
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/modules/localip
Add the files
Diffstat (limited to 'src/modules/localip')
-rw-r--r--src/modules/localip/localip.c443
-rw-r--r--src/modules/localip/localip.h11
-rw-r--r--src/modules/localip/option.h44
3 files changed, 498 insertions, 0 deletions
diff --git a/src/modules/localip/localip.c b/src/modules/localip/localip.c
new file mode 100644
index 0000000..ef4a110
--- /dev/null
+++ b/src/modules/localip/localip.c
@@ -0,0 +1,443 @@
+#include "common/printing.h"
+#include "common/jsonconfig.h"
+#include "common/strutil.h"
+#include "detection/localip/localip.h"
+#include "modules/localip/localip.h"
+
+#define FF_LOCALIP_DISPLAY_NAME "Local IP"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
+
+static int sortIps(const FFLocalIpResult* left, const FFLocalIpResult* right) {
+ return ffStrbufComp(&left->name, &right->name);
+}
+
+static void formatKey(const FFLocalIpOptions* options, FFLocalIpResult* ip, uint32_t index, FFstrbuf* key) {
+ if (options->moduleArgs.key.length == 0) {
+ if (!ip->name.length) {
+ ffStrbufSetF(&ip->name, "unknown %u", (unsigned) index);
+ }
+
+ ffStrbufSetF(key, FF_LOCALIP_DISPLAY_NAME " (%s)", ip->name.chars);
+ } else {
+ ffStrbufClear(key);
+ FF_PARSE_FORMAT_STRING_CHECKED(key, &options->moduleArgs.key, ((FFformatarg[]) {
+ FF_ARG(index, "index"),
+ FF_ARG(ip->name, "ifname"),
+ FF_ARG(ip->mac, "mac"),
+ FF_ARG(options->moduleArgs.keyIcon, "icon"),
+ }));
+ }
+}
+
+static void appendSpeed(FFLocalIpResult* ip, FFstrbuf* strbuf) {
+ if (ip->speed >= 1000000) {
+ ffStrbufAppendDouble(strbuf, ip->speed / 1e6, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros == FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS);
+ ffStrbufAppendS(strbuf, " Tbps");
+ } else if (ip->speed >= 1000) {
+ ffStrbufAppendDouble(strbuf, ip->speed / 1e3, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros == FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS);
+ ffStrbufAppendS(strbuf, " Gbps");
+ } else {
+ ffStrbufAppendF(strbuf, "%u Mbps", (unsigned) ip->speed);
+ }
+}
+
+static void printIp(FFLocalIpResult* ip, bool markDefaultRoute, FFstrbuf* buffer) {
+ if (ip->ipv4.length) {
+ ffStrbufAppend(buffer, &ip->ipv4);
+ }
+ if (ip->ipv6.length) {
+ if (buffer->length) {
+ ffStrbufAppendC(buffer, ' ');
+ }
+ ffStrbufAppend(buffer, &ip->ipv6);
+ }
+ if (ip->mac.length) {
+ if (buffer->length) {
+ ffStrbufAppendF(buffer, " (%s)", ip->mac.chars);
+ } else {
+ ffStrbufAppend(buffer, &ip->mac);
+ }
+ }
+ if (ip->mtu > 0 || ip->speed > 0) {
+ bool flag = buffer->length > 0;
+ if (flag) {
+ ffStrbufAppendS(buffer, " [");
+ }
+ if (ip->speed > 0) {
+ if (ip->mtu > 0) {
+ ffStrbufAppendS(buffer, "Speed ");
+ }
+ appendSpeed(ip, buffer);
+ if (ip->mtu > 0) {
+ ffStrbufAppendS(buffer, " / MTU ");
+ }
+ }
+ if (ip->mtu > 0) {
+ ffStrbufAppendF(buffer, "%u", (unsigned) ip->mtu);
+ }
+ if (flag) {
+ ffStrbufAppendC(buffer, ']');
+ }
+ }
+ if (ip->flags.length) {
+ bool flag = buffer->length > 0;
+ if (flag) {
+ ffStrbufAppendS(buffer, " <");
+ }
+ ffStrbufAppend(buffer, &ip->flags);
+ if (flag) {
+ ffStrbufAppendC(buffer, '>');
+ }
+ }
+ if (markDefaultRoute && ip->defaultRoute) {
+ ffStrbufAppendS(buffer, " *");
+ }
+}
+
+bool ffPrintLocalIp(FFLocalIpOptions* options) {
+ FF_LIST_AUTO_DESTROY results = ffListCreate();
+
+ const char* error = ffDetectLocalIps(options, &results);
+
+ if (error) {
+ ffPrintError(FF_LOCALIP_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
+ return false;
+ }
+
+ if (results.length == 0) {
+ ffPrintError(FF_LOCALIP_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Failed to detect any IPs");
+ return false;
+ }
+
+ ffListSort(&results, sizeof(FFLocalIpResult), (const void*) sortIps);
+
+ FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
+
+ if (options->showType & FF_LOCALIP_TYPE_COMPACT_BIT) {
+ ffPrintLogoAndKey(FF_LOCALIP_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
+
+ FF_LIST_FOR_EACH (FFLocalIpResult, ip, results) {
+ if (buffer.length) {
+ ffStrbufAppendS(&buffer, " - ");
+ }
+ printIp(ip, false, &buffer);
+ }
+ ffStrbufPutTo(&buffer, stdout);
+ ffStrbufClear(&buffer);
+ } else {
+ FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
+ uint32_t index = 0;
+
+ FF_LIST_FOR_EACH (FFLocalIpResult, ip, results) {
+ formatKey(options, ip, results.length == 1 ? 0 : index + 1, &key);
+ if (options->moduleArgs.outputFormat.length == 0) {
+ ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY);
+ printIp(ip, !(options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT), &buffer);
+ ffStrbufPutTo(&buffer, stdout);
+ } else {
+ if (ip->speed > 0) {
+ appendSpeed(ip, &buffer);
+ }
+ FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) {
+ FF_ARG(ip->ipv4, "ipv4"),
+ FF_ARG(ip->ipv6, "ipv6"),
+ FF_ARG(ip->mac, "mac"),
+ FF_ARG(ip->name, "ifname"),
+ FF_ARG(ip->defaultRoute, "is-default-route"),
+ FF_ARG(ip->mtu, "mtu"),
+ FF_ARG(buffer, "speed"),
+ FF_ARG(ip->flags, "flags"),
+ }));
+ }
+ ++index;
+ ffStrbufClear(&buffer);
+ }
+ }
+
+ FF_LIST_FOR_EACH (FFLocalIpResult, ip, results) {
+ ffStrbufDestroy(&ip->name);
+ ffStrbufDestroy(&ip->ipv4);
+ ffStrbufDestroy(&ip->ipv6);
+ ffStrbufDestroy(&ip->mac);
+ ffStrbufDestroy(&ip->flags);
+ }
+
+ return true;
+}
+
+void ffParseLocalIpJsonObject(FFLocalIpOptions* options, yyjson_val* module) {
+ yyjson_val *key, *val;
+ size_t idx, max;
+ yyjson_obj_foreach (module, idx, max, key, val) {
+ if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) {
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "showIpv4")) {
+ if (yyjson_get_bool(val)) {
+ options->showType |= FF_LOCALIP_TYPE_IPV4_BIT;
+ } else {
+ options->showType &= ~FF_LOCALIP_TYPE_IPV4_BIT;
+ }
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "showIpv6")) {
+ 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;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "showMac")) {
+ if (yyjson_get_bool(val)) {
+ options->showType |= FF_LOCALIP_TYPE_MAC_BIT;
+ } else {
+ options->showType &= ~FF_LOCALIP_TYPE_MAC_BIT;
+ }
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "showLoop")) {
+ if (yyjson_get_bool(val)) {
+ options->showType |= FF_LOCALIP_TYPE_LOOP_BIT;
+ } else {
+ options->showType &= ~FF_LOCALIP_TYPE_LOOP_BIT;
+ }
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "showPrefixLen")) {
+ if (yyjson_get_bool(val)) {
+ options->showType |= FF_LOCALIP_TYPE_PREFIX_LEN_BIT;
+ } else {
+ options->showType &= ~FF_LOCALIP_TYPE_PREFIX_LEN_BIT;
+ }
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "showMtu")) {
+ if (yyjson_get_bool(val)) {
+ options->showType |= FF_LOCALIP_TYPE_MTU_BIT;
+ } else {
+ options->showType &= ~FF_LOCALIP_TYPE_MTU_BIT;
+ }
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "showSpeed")) {
+ if (yyjson_get_bool(val)) {
+ options->showType |= FF_LOCALIP_TYPE_SPEED_BIT;
+ } else {
+ options->showType &= ~FF_LOCALIP_TYPE_SPEED_BIT;
+ }
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "showFlags")) {
+ if (yyjson_get_bool(val)) {
+ options->showType |= FF_LOCALIP_TYPE_FLAGS_BIT;
+ } else {
+ options->showType &= ~FF_LOCALIP_TYPE_FLAGS_BIT;
+ }
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "compact")) {
+ if (yyjson_get_bool(val)) {
+ options->showType |= FF_LOCALIP_TYPE_COMPACT_BIT;
+ } else {
+ options->showType &= ~FF_LOCALIP_TYPE_COMPACT_BIT;
+ }
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "defaultRouteOnly")) {
+ 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 (unsafe_yyjson_equals_str(key, "showAllIps")) {
+ if (yyjson_get_bool(val)) {
+ options->showType |= FF_LOCALIP_TYPE_ALL_IPS_BIT;
+ } else {
+ options->showType &= ~FF_LOCALIP_TYPE_ALL_IPS_BIT;
+ }
+ continue;
+ }
+
+ if (unsafe_yyjson_equals_str(key, "namePrefix")) {
+ ffStrbufSetJsonVal(&options->namePrefix, val);
+ continue;
+ }
+
+ ffPrintError(FF_LOCALIP_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
+ }
+}
+
+void ffGenerateLocalIpJsonConfig(FFLocalIpOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
+ ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
+
+ yyjson_mut_obj_add_bool(doc, module, "showIpv4", !!(options->showType & FF_LOCALIP_TYPE_IPV4_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));
+
+ yyjson_mut_obj_add_bool(doc, module, "showLoop", !!(options->showType & FF_LOCALIP_TYPE_LOOP_BIT));
+
+ yyjson_mut_obj_add_bool(doc, module, "showPrefixLen", !!(options->showType & FF_LOCALIP_TYPE_PREFIX_LEN_BIT));
+
+ yyjson_mut_obj_add_bool(doc, module, "showMtu", !!(options->showType & FF_LOCALIP_TYPE_MTU_BIT));
+
+ yyjson_mut_obj_add_bool(doc, module, "showSpeed", !!(options->showType & FF_LOCALIP_TYPE_SPEED_BIT));
+
+ yyjson_mut_obj_add_bool(doc, module, "showFlags", !!(options->showType & FF_LOCALIP_TYPE_FLAGS_BIT));
+
+ yyjson_mut_obj_add_bool(doc, module, "compact", !!(options->showType & FF_LOCALIP_TYPE_COMPACT_BIT));
+
+ yyjson_mut_obj_add_bool(doc, module, "defaultRouteOnly", !!(options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT));
+
+ yyjson_mut_obj_add_bool(doc, module, "showAllIps", !!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT));
+
+ yyjson_mut_obj_add_strbuf(doc, module, "namePrefix", &options->namePrefix);
+}
+
+bool ffGenerateLocalIpJsonResult(FF_A_UNUSED FFLocalIpOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
+ FF_LIST_AUTO_DESTROY results = ffListCreate();
+
+ const char* error = ffDetectLocalIps(options, &results);
+
+ if (error) {
+ yyjson_mut_obj_add_str(doc, module, "error", error);
+ return false;
+ }
+
+ yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
+ FF_LIST_FOR_EACH (FFLocalIpResult, ip, results) {
+ yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
+ yyjson_mut_obj_add_strbuf(doc, obj, "name", &ip->name);
+ if (options->showType & (FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_IPV6_BIT)) {
+ yyjson_mut_val* defaultRoute = yyjson_mut_obj_add_obj(doc, obj, "defaultRoute");
+ if (options->showType & FF_LOCALIP_TYPE_IPV4_BIT) {
+ yyjson_mut_obj_add_bool(doc, defaultRoute, "ipv4", !!(ip->defaultRoute & FF_LOCALIP_TYPE_IPV4_BIT));
+ }
+ if (options->showType & FF_LOCALIP_TYPE_IPV6_BIT) {
+ yyjson_mut_obj_add_bool(doc, defaultRoute, "ipv6", !!(ip->defaultRoute & FF_LOCALIP_TYPE_IPV6_BIT));
+ }
+ }
+ if (options->showType & FF_LOCALIP_TYPE_IPV4_BIT) {
+ yyjson_mut_obj_add_strbuf(doc, obj, "ipv4", &ip->ipv4);
+ }
+ if (options->showType & FF_LOCALIP_TYPE_IPV6_BIT) {
+ yyjson_mut_obj_add_strbuf(doc, obj, "ipv6", &ip->ipv6);
+ }
+ if (options->showType & FF_LOCALIP_TYPE_MAC_BIT) {
+ yyjson_mut_obj_add_strbuf(doc, obj, "mac", &ip->mac);
+ }
+ if (options->showType & FF_LOCALIP_TYPE_MTU_BIT) {
+ yyjson_mut_obj_add_int(doc, obj, "mtu", ip->mtu);
+ }
+ if (options->showType & FF_LOCALIP_TYPE_SPEED_BIT) {
+ yyjson_mut_obj_add_int(doc, obj, "speed", ip->speed);
+ }
+ if (options->showType & FF_LOCALIP_TYPE_FLAGS_BIT) {
+ yyjson_mut_obj_add_strbuf(doc, obj, "flags", &ip->flags);
+ }
+ }
+
+ FF_LIST_FOR_EACH (FFLocalIpResult, ip, results) {
+ ffStrbufDestroy(&ip->name);
+ ffStrbufDestroy(&ip->ipv4);
+ ffStrbufDestroy(&ip->ipv6);
+ ffStrbufDestroy(&ip->mac);
+ ffStrbufDestroy(&ip->flags);
+ }
+
+ return true;
+}
+
+void ffInitLocalIpOptions(FFLocalIpOptions* options) {
+ ffOptionInitModuleArg(&options->moduleArgs, "󰩟");
+
+ options->showType = FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_PREFIX_LEN_BIT
+#if !__ANDROID__ /*Permission denied*/
+ | FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT
+#endif
+ ;
+ options->ipv6Type = FF_LOCALIP_IPV6_TYPE_AUTO;
+ ffStrbufInit(&options->namePrefix);
+}
+
+void ffDestroyLocalIpOptions(FFLocalIpOptions* options) {
+ ffOptionDestroyModuleArg(&options->moduleArgs);
+ ffStrbufDestroy(&options->namePrefix);
+}
+
+FFModuleBaseInfo ffLocalIPModuleInfo = {
+ .name = FF_LOCALIP_MODULE_NAME,
+ .description = "List local IP addresses (IPv4 or IPv6), MAC addresses, etc",
+ .initOptions = (void*) ffInitLocalIpOptions,
+ .destroyOptions = (void*) ffDestroyLocalIpOptions,
+ .parseJsonObject = (void*) ffParseLocalIpJsonObject,
+ .printModule = (void*) ffPrintLocalIp,
+ .generateJsonResult = (void*) ffGenerateLocalIpJsonResult,
+ .generateJsonConfig = (void*) ffGenerateLocalIpJsonConfig,
+ .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
+ { "IPv4 address", "ipv4" },
+ { "IPv6 address", "ipv6" },
+ { "MAC address", "mac" },
+ { "Interface name", "ifname" },
+ { "Is default route", "is-default-route" },
+ { "MTU size in bytes", "mtu" },
+ { "Link speed (formatted)", "speed" },
+ { "Interface flags", "flags" },
+ }))
+};
diff --git a/src/modules/localip/localip.h b/src/modules/localip/localip.h
new file mode 100644
index 0000000..f9e9c4e
--- /dev/null
+++ b/src/modules/localip/localip.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "option.h"
+
+#define FF_LOCALIP_MODULE_NAME "LocalIp"
+
+bool ffPrintLocalIp(FFLocalIpOptions* options);
+void ffInitLocalIpOptions(FFLocalIpOptions* options);
+void ffDestroyLocalIpOptions(FFLocalIpOptions* options);
+
+extern FFModuleBaseInfo ffLocalIPModuleInfo;
diff --git a/src/modules/localip/option.h b/src/modules/localip/option.h
new file mode 100644
index 0000000..0eae247
--- /dev/null
+++ b/src/modules/localip/option.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "common/option.h"
+
+typedef enum FF_A_PACKED FFLocalIpType {
+ FF_LOCALIP_TYPE_NONE,
+ FF_LOCALIP_TYPE_LOOP_BIT = 1 << 0,
+ FF_LOCALIP_TYPE_IPV4_BIT = 1 << 1,
+ FF_LOCALIP_TYPE_IPV6_BIT = 1 << 2,
+ FF_LOCALIP_TYPE_MAC_BIT = 1 << 3,
+ FF_LOCALIP_TYPE_PREFIX_LEN_BIT = 1 << 4,
+ FF_LOCALIP_TYPE_MTU_BIT = 1 << 5,
+ FF_LOCALIP_TYPE_SPEED_BIT = 1 << 6,
+ FF_LOCALIP_TYPE_FLAGS_BIT = 1 << 7,
+
+ FF_LOCALIP_TYPE_COMPACT_BIT = 1 << 10,
+ FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT = 1 << 11,
+ FF_LOCALIP_TYPE_ALL_IPS_BIT = 1 << 12,
+ FF_LOCALIP_TYPE_FORCE_UNSIGNED = UINT16_MAX,
+} FFLocalIpType;
+static_assert(sizeof(FFLocalIpType) == sizeof(uint16_t), "");
+
+typedef enum FF_A_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;
+
+static_assert(sizeof(FFLocalIpOptions) <= FF_OPTION_MAX_SIZE, "FFLocalIpOptions size exceeds maximum allowed size");