From b29b78b321e584ea716e5624cc4c968f1ccdbcac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 26 Sep 2023 22:34:37 +0800 Subject: [PATCH] NetUsage: finish module --- doc/json_schema.json | 31 +++++++++++++++ src/common/commandoption.c | 2 +- src/common/jsonconfig.c | 8 ++++ src/detection/netusage/netusage.c | 16 ++++---- src/detection/netusage/netusage.h | 3 +- src/detection/netusage/netusage_bsd.c | 20 ++++++++-- src/detection/netusage/netusage_linux.c | 16 +++++++- src/detection/netusage/netusage_windows.c | 18 +++++++-- src/modules/netusage/netusage.c | 47 +++++++++++++++++++++-- src/modules/netusage/netusage.h | 2 +- src/modules/netusage/option.h | 3 ++ src/util/FFstrbuf.h | 2 +- 12 files changed, 145 insertions(+), 23 deletions(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index 4151686dc..7623f0a02 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -558,6 +558,7 @@ "media", "memory", "monitor", + "netusage", "opencl", "opengl", "os", @@ -1019,6 +1020,36 @@ }, "additionalProperties": false }, + { + "title": "Network throughput (usage)", + "properties": { + "type": { + "const": "netusage" + }, + "namePrefix": { + "title": "Show IPs with given name prefix only", + "type": "string" + }, + "defaultRouteOnly": { + "title": "Show ips that are used for default routing only", + "type": "boolean", + "default": false + }, + "key": { + "$ref": "#/$defs/key" + }, + "keyColor": { + "$ref": "#/$defs/keyColor" + }, + "keyWidth": { + "$ref": "#/$defs/keyWidth" + }, + "format": { + "$ref": "#/$defs/format" + } + }, + "additionalProperties": false + }, { "title": "OpenGL", "properties": { diff --git a/src/common/commandoption.c b/src/common/commandoption.c index 6454f51e9..45369a163 100644 --- a/src/common/commandoption.c +++ b/src/common/commandoption.c @@ -61,7 +61,7 @@ void ffPrepareCommandOption(FFdata* data) ffPrepareCPUUsage(); if(ffStrbufContainIgnCaseS(&data->structure, FF_NETUSAGE_MODULE_NAME)) - ffPrepareNetUsage(); + ffPrepareNetUsage(&instance.config.netUsage); if(instance.config.multithreading) { diff --git a/src/common/jsonconfig.c b/src/common/jsonconfig.c index 0b257be53..5d6027f4a 100644 --- a/src/common/jsonconfig.c +++ b/src/common/jsonconfig.c @@ -112,6 +112,14 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) ffPrepareCPUUsage(); break; } + case 'n': case 'N': { + if (ffStrEqualsIgnCase(type, FF_NETUSAGE_MODULE_NAME)) + { + if (module) ffParseNetUsageJsonObject(&cfg->netUsage, module); + ffPrepareNetUsage(&cfg->netUsage); + } + break; + } case 'p': case 'P': { if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME)) { diff --git a/src/detection/netusage/netusage.c b/src/detection/netusage/netusage.c index af885edb2..88888c28a 100644 --- a/src/detection/netusage/netusage.c +++ b/src/detection/netusage/netusage.c @@ -2,31 +2,33 @@ #include "common/time.h" -const char* ffNetUsageGetIoCounters(FFlist* result); +const char* ffNetUsageGetIoCounters(FFlist* result, FFNetUsageOptions* options); static FFlist ioCounters1; static uint64_t time1; -void ffPrepareNetUsage(void) +void ffPrepareNetUsage(FFNetUsageOptions* options) { ffListInit(&ioCounters1, sizeof(FFNetUsageIoCounters)); - ffNetUsageGetIoCounters(&ioCounters1); + ffNetUsageGetIoCounters(&ioCounters1, options); time1 = ffTimeGetNow(); } -const char* ffDetectNetUsage(FFlist* result) +const char* ffDetectNetUsage(FFlist* result, FFNetUsageOptions* options) { const char* error = NULL; if (time1 == 0) { ffListInit(&ioCounters1, sizeof(FFNetUsageIoCounters)); - error = ffNetUsageGetIoCounters(&ioCounters1); + error = ffNetUsageGetIoCounters(&ioCounters1, options); if (error) return error; time1 = ffTimeGetNow(); - ffTimeSleep(1000); } + if (ioCounters1.length == 0) + return "No network interfaces found"; + uint64_t time2 = ffTimeGetNow(); while (time2 - time1 < 1000) { @@ -34,7 +36,7 @@ const char* ffDetectNetUsage(FFlist* result) time2 = ffTimeGetNow(); } - error = ffNetUsageGetIoCounters(result); + error = ffNetUsageGetIoCounters(result, options); if (error) return error; diff --git a/src/detection/netusage/netusage.h b/src/detection/netusage/netusage.h index 35a95367f..bb6234ee1 100644 --- a/src/detection/netusage/netusage.h +++ b/src/detection/netusage/netusage.h @@ -3,6 +3,7 @@ typedef struct FFNetUsageIoCounters { FFstrbuf name; + bool defaultRoute; uint64_t txBytes; uint64_t rxBytes; uint64_t txPackets; @@ -13,4 +14,4 @@ typedef struct FFNetUsageIoCounters uint64_t txDrops; } FFNetUsageIoCounters; -const char* ffDetectNetUsage(FFlist* result); +const char* ffDetectNetUsage(FFlist* result, FFNetUsageOptions* options); diff --git a/src/detection/netusage/netusage_bsd.c b/src/detection/netusage/netusage_bsd.c index ffd430dfa..c6ec58a3e 100644 --- a/src/detection/netusage/netusage_bsd.c +++ b/src/detection/netusage/netusage_bsd.c @@ -1,6 +1,7 @@ #include "netusage.h" #include "common/io/io.h" +#include "common/netif/netif.h" #include "util/mallocHelper.h" #include @@ -10,7 +11,7 @@ #include #include -const char* ffNetUsageGetIoCounters(FFlist* result) +const char* ffNetUsageGetIoCounters(FFlist* result, FFNetUsageOptions* options) { size_t bufSize = 0; if (sysctl((int[]) { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0 }, 6, NULL, &bufSize, 0, 0) < 0) @@ -20,6 +21,8 @@ const char* ffNetUsageGetIoCounters(FFlist* result) if (sysctl((int[]) { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0 }, 6, buf, &bufSize, 0, 0) < 0) return "sysctl({ CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0 }, 6, buf, &bufSize, 0, 0) failed"; + const char* defaultRouteIface = ffNetifGetDefaultRoute(); + for (struct if_msghdr2* ifm = buf; ifm < (struct if_msghdr2*) ((uint8_t*) buf + bufSize); ifm = (struct if_msghdr2*) ((uint8_t*) ifm + ifm->ifm_msglen)) @@ -29,9 +32,19 @@ const char* ffNetUsageGetIoCounters(FFlist* result) struct sockaddr_dl* sdl = (struct sockaddr_dl*) (ifm + 1); assert(sdl->sdl_family == AF_LINK); if (sdl->sdl_type != IFT_ETHER && !(ifm->ifm_flags & IFF_LOOPBACK)) continue; - FFNetUsageIoCounters* counters = (FFNetUsageIoCounters*) ffListAdd(result); + sdl->sdl_data[sdl->sdl_nlen] = 0; + + bool isDefaultRoute = ffStrEquals(sdl->sdl_data, defaultRouteIface); + if(options->defaultRouteOnly && !isDefaultRoute) + continue; + + if (options->namePrefix.length && strncmp(sdl->sdl_data, options->namePrefix.chars, options->namePrefix.length) != 0) + continue; + + FFNetUsageIoCounters* counters = (FFNetUsageIoCounters*) ffListAdd(result); *counters = (FFNetUsageIoCounters) { + .name = ffStrbufCreateNS(sdl->sdl_nlen, sdl->sdl_data), .txBytes = ifm->ifm_data.ifi_obytes, .rxBytes = ifm->ifm_data.ifi_ibytes, .txPackets = ifm->ifm_data.ifi_opackets, @@ -40,9 +53,8 @@ const char* ffNetUsageGetIoCounters(FFlist* result) .rxErrors = ifm->ifm_data.ifi_ierrors, .txDrops = 0, // unsupported .rxDrops = ifm->ifm_data.ifi_iqdrops, + .defaultRoute = isDefaultRoute, }; - - ffStrbufInitNS(&counters->name, sdl->sdl_nlen, sdl->sdl_data); } return NULL; diff --git a/src/detection/netusage/netusage_linux.c b/src/detection/netusage/netusage_linux.c index aea66b463..a5d64be5b 100644 --- a/src/detection/netusage/netusage_linux.c +++ b/src/detection/netusage/netusage_linux.c @@ -1,10 +1,12 @@ #include "netusage.h" #include "common/io/io.h" +#include "common/netif/netif.h" +#include "util/stringUtils.h" #include -const char* ffNetUsageGetIoCounters(FFlist* result) +const char* ffNetUsageGetIoCounters(FFlist* result, FFNetUsageOptions* options) { FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/net"); if (!dirp) return "opendir(\"/sys/class/net\") == NULL"; @@ -12,20 +14,30 @@ const char* ffNetUsageGetIoCounters(FFlist* result) FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateA(64); FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + const char* defaultRouteIface = ffNetifGetDefaultRoute(); + struct dirent* entry; while((entry = readdir(dirp)) != NULL) { if(entry->d_name[0] == '.') continue; + bool isDefaultRoute = ffStrEquals(entry->d_name, defaultRouteIface); + if(options->defaultRouteOnly && !isDefaultRoute) + continue; + + if (options->namePrefix.length && strncmp(entry->d_name, options->namePrefix.chars, options->namePrefix.length) != 0) + continue; + ffStrbufSetF(&path, "/sys/class/net/%s/operstate", entry->d_name); if(!ffReadFileBuffer(path.chars, &buffer) || !ffStrbufEqualS(&buffer, "up")) continue; FFNetUsageIoCounters* counters = (FFNetUsageIoCounters*) ffListAdd(result); ffStrbufInitS(&counters->name, entry->d_name); + counters->defaultRoute = isDefaultRoute; - ffStrbufSetF(&path, "/sys/class/net/%s/statistics/"); + ffStrbufSetF(&path, "/sys/class/net/%s/statistics/", entry->d_name); uint32_t statLen = path.length; ffStrbufAppendS(&path, "rx_bytes"); diff --git a/src/detection/netusage/netusage_windows.c b/src/detection/netusage/netusage_windows.c index 1604b61de..b9d45f3e7 100644 --- a/src/detection/netusage/netusage_windows.c +++ b/src/detection/netusage/netusage_windows.c @@ -1,13 +1,13 @@ #include "netusage.h" -#include "common/io/io.h" +#include "common/netif/netif.h" #include "util/mallocHelper.h" #include "util/windows/unicode.h" #include #include -const char* ffNetUsageGetIoCounters(FFlist* result) +const char* ffNetUsageGetIoCounters(FFlist* result, FFNetUsageOptions* options) { IP_ADAPTER_ADDRESSES* FF_AUTO_FREE adapter_addresses = NULL; @@ -37,14 +37,26 @@ const char* ffNetUsageGetIoCounters(FFlist* result) return "GetAdaptersAddresses() failed"; } + uint32_t defaultRouteIfIndex = ffNetifGetDefaultRoute(); + // Iterate through all of the adapters for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next) { + bool isDefaultRoute = adapter->IfIndex == defaultRouteIfIndex; + if (options->defaultRouteOnly && !isDefaultRoute) + continue; + + char name[128]; + WideCharToMultiByte(CP_UTF8, 0, adapter->FriendlyName, -1, name, sizeof(name), NULL, NULL); + if (options->namePrefix.length && strncmp(name, options->namePrefix.chars, options->namePrefix.length) != 0) + continue; + MIB_IF_ROW2 ifRow = { .InterfaceIndex = adapter->IfIndex }; if (GetIfEntry2(&ifRow) == NO_ERROR) { FFNetUsageIoCounters* counters = (FFNetUsageIoCounters*) ffListAdd(result); *counters = (FFNetUsageIoCounters) { + .name = ffStrbufCreateS(name), .txBytes = ifRow.OutOctets, .rxBytes = ifRow.InOctets, .txPackets = (ifRow.OutUcastPkts + ifRow.OutNUcastPkts), @@ -53,8 +65,8 @@ const char* ffNetUsageGetIoCounters(FFlist* result) .txErrors = ifRow.OutErrors, .rxDrops = ifRow.InDiscards, .txDrops = ifRow.OutDiscards, + .defaultRoute = isDefaultRoute, }; - ffStrbufSetWS(&counters->name, adapter->FriendlyName); } } diff --git a/src/modules/netusage/netusage.c b/src/modules/netusage/netusage.c index 51a3c1f6b..75e0bfdf2 100644 --- a/src/modules/netusage/netusage.c +++ b/src/modules/netusage/netusage.c @@ -35,7 +35,7 @@ static void formatKey(const FFNetUsageOptions* options, FFNetUsageIoCounters* in void ffPrintNetUsage(FFNetUsageOptions* options) { FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFNetUsageIoCounters)); - const char* error = ffDetectNetUsage(&result); + const char* error = ffDetectNetUsage(&result, options); if(error) { @@ -63,6 +63,8 @@ void ffPrintNetUsage(FFNetUsageOptions* options) ffStrbufAppendS(&buffer, "/s (in) - "); ffParseSize(inf->txBytes, &buffer); ffStrbufAppendS(&buffer, "/s (out)"); + if (!options->defaultRouteOnly && inf->defaultRoute) + ffStrbufAppendS(&buffer, " *"); ffStrbufPutTo(&buffer, stdout); } else @@ -82,16 +84,25 @@ void ffPrintNetUsage(FFNetUsageOptions* options) {FF_FORMAT_ARG_TYPE_UINT64, &inf->txErrors}, {FF_FORMAT_ARG_TYPE_UINT64, &inf->rxDrops}, {FF_FORMAT_ARG_TYPE_UINT64, &inf->txDrops}, + {FF_FORMAT_ARG_TYPE_BOOL, &inf->defaultRoute}, }); } ++index; } + + FF_LIST_FOR_EACH(FFNetUsageIoCounters, inf, result) + { + ffStrbufDestroy(&inf->name); + } } void ffInitNetUsageOptions(FFNetUsageOptions* options) { ffOptionInitModuleBaseInfo(&options->moduleInfo, FF_NETUSAGE_MODULE_NAME, ffParseNetUsageCommandOptions, ffParseNetUsageJsonObject, ffPrintNetUsage, ffGenerateNetUsageJson); ffOptionInitModuleArg(&options->moduleArgs); + + ffStrbufInit(&options->namePrefix); + options->defaultRouteOnly = false; } bool ffParseNetUsageCommandOptions(FFNetUsageOptions* options, const char* key, const char* value) @@ -101,12 +112,25 @@ bool ffParseNetUsageCommandOptions(FFNetUsageOptions* options, const char* key, if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) return true; + if (ffStrEqualsIgnCase(subKey, "name-prefix")) + { + ffOptionParseString(key, value, &options->namePrefix); + return true; + } + + if (ffStrEqualsIgnCase(subKey, "default-route-only")) + { + options->defaultRouteOnly = ffOptionParseBoolean(value); + return true; + } + return false; } void ffDestroyNetUsageOptions(FFNetUsageOptions* options) { ffOptionDestroyModuleArg(&options->moduleArgs); + ffStrbufDestroy(&options->namePrefix); } void ffParseNetUsageJsonObject(FFNetUsageOptions* options, yyjson_val* module) @@ -122,14 +146,26 @@ void ffParseNetUsageJsonObject(FFNetUsageOptions* options, yyjson_val* module) if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; + if (ffStrEqualsIgnCase(key, "namePrefix")) + { + ffStrbufSetS(&options->namePrefix, yyjson_get_str(val)); + continue; + } + + if (ffStrEqualsIgnCase(key, "defaultRouteOnly")) + { + options->defaultRouteOnly = yyjson_get_bool(val); + continue; + } + ffPrintError(FF_NETUSAGE_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } -void ffGenerateNetUsageJson(FF_MAYBE_UNUSED FFNetUsageOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +void ffGenerateNetUsageJson(FFNetUsageOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFNetUsageIoCounters)); - const char* error = ffDetectNetUsage(&result); + const char* error = ffDetectNetUsage(&result, options); if(error) { @@ -150,6 +186,11 @@ void ffGenerateNetUsageJson(FF_MAYBE_UNUSED FFNetUsageOptions* options, yyjson_m yyjson_mut_obj_add_uint(doc, obj, "txErrors", counter->txErrors); yyjson_mut_obj_add_uint(doc, obj, "rxDrops", counter->rxDrops); yyjson_mut_obj_add_uint(doc, obj, "txDrops", counter->txDrops); + yyjson_mut_obj_add_bool(doc, obj, "defaultRoute", counter->defaultRoute); + } + FF_LIST_FOR_EACH(FFNetUsageIoCounters, inf, result) + { + ffStrbufDestroy(&inf->name); } } diff --git a/src/modules/netusage/netusage.h b/src/modules/netusage/netusage.h index 4067d6899..4feaee10a 100644 --- a/src/modules/netusage/netusage.h +++ b/src/modules/netusage/netusage.h @@ -4,7 +4,7 @@ #define FF_NETUSAGE_MODULE_NAME "NetUsage" -void ffPrepareNetUsage(); +void ffPrepareNetUsage(FFNetUsageOptions* options); void ffPrintNetUsage(FFNetUsageOptions* options); void ffInitNetUsageOptions(FFNetUsageOptions* options); diff --git a/src/modules/netusage/option.h b/src/modules/netusage/option.h index 59463249f..ff436aaf2 100644 --- a/src/modules/netusage/option.h +++ b/src/modules/netusage/option.h @@ -8,4 +8,7 @@ typedef struct FFNetUsageOptions { FFModuleBaseInfo moduleInfo; FFModuleArgs moduleArgs; + + FFstrbuf namePrefix; + bool defaultRouteOnly; } FFNetUsageOptions; diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 77db4be96..9a28bafb4 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -50,7 +50,7 @@ void ffStrbufPrependNS(FFstrbuf* strbuf, uint32_t length, const char* value); void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value); void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value); -void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...); +FF_C_PRINTF(2, 3) void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...); void ffStrbufTrimLeft(FFstrbuf* strbuf, char c); void ffStrbufTrimRight(FFstrbuf* strbuf, char c);