diff options
author | Costa Tsaousis <costa@netdata.cloud> | 2023-07-06 17:19:15 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-06 17:19:15 +0300 |
commit | 9af8a73e255ee66c89175844eb2f3759672e5cc2 (patch) | |
tree | 7c3ce3effa90ada46a42351a240d2fc2eecfcac6 /collectors/plugins.d | |
parent | 4f5228e65463cf680d2ec3fedaf71c813d69309b (diff) |
local-listener using libnetdata (#15319)
Diffstat (limited to 'collectors/plugins.d')
-rw-r--r-- | collectors/plugins.d/local_listeners.c | 217 |
1 files changed, 105 insertions, 112 deletions
diff --git a/collectors/plugins.d/local_listeners.c b/collectors/plugins.d/local_listeners.c index 6d755e0542..a45fe3c97a 100644 --- a/collectors/plugins.d/local_listeners.c +++ b/collectors/plugins.d/local_listeners.c @@ -1,10 +1,12 @@ +#include "libnetdata/libnetdata.h" +#include "libnetdata/required_dummies.h" + #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <dirent.h> #include <string.h> #include <unistd.h> -#include <errno.h> #include <ctype.h> #include <arpa/inet.h> @@ -15,6 +17,12 @@ typedef enum { PROC_NET_PROTOCOL_UDP6, } PROC_NET_PROTOCOLS; +#define MAX_ERROR_LOGS 10 + +static size_t pid_fds_processed = 0; +static size_t pid_fds_failed = 0; +static size_t errors_encountered = 0; + static inline const char *protocol_name(PROC_NET_PROTOCOLS protocol) { switch(protocol) { default: @@ -32,26 +40,70 @@ static inline const char *protocol_name(PROC_NET_PROTOCOLS protocol) { } } +static inline int read_cmdline(pid_t pid, char* buffer, size_t bufferSize) { + char path[FILENAME_MAX + 1]; + snprintfz(path, FILENAME_MAX, "/proc/%d/cmdline", pid); + + FILE* file = fopen(path, "r"); + if (!file) { + if(++errors_encountered < MAX_ERROR_LOGS) + collector_error("LOCAL-LISTENERS: error opening file: %s\n", path); + + return -1; + } + + size_t bytesRead = fread(buffer, 1, bufferSize - 1, file); + buffer[bytesRead] = '\0'; // Ensure null-terminated + + // Replace null characters in cmdline with spaces + for (size_t i = 0; i < bytesRead; i++) { + if (buffer[i] == '\0') { + buffer[i] = ' '; + } + } + + fclose(file); + return 0; +} + +static inline void fix_cmdline(char* str) { + if (str == NULL) + return; + + char *s = str; + + do { + if(*s == '|' || iscntrl(*s)) + *s = '_'; + + } while(*++s); + + + while(s > str && *(s-1) == ' ') + *--s = '\0'; +} + +// ---------------------------------------------------------------------------- + #define HASH_TABLE_SIZE 100000 -#define MAX_ERROR_LOGS 10 typedef struct Node { - unsigned int inode; + unsigned int inode; // key + + // values unsigned int port; char local_address[INET6_ADDRSTRLEN]; PROC_NET_PROTOCOLS protocol; bool processed; - struct Node *next; + + // linking + struct Node *prev, *next; } Node; typedef struct HashTable { Node *table[HASH_TABLE_SIZE]; } HashTable; -static size_t pid_fds_processed = 0; -static size_t pid_fds_failed = 0; -static size_t errors_encountered = 0; - static HashTable *hashTable_key_inode_port_value = NULL; static inline void generate_output(const char *protocol, const char *address, unsigned int port, const char *cmdline) { @@ -59,7 +111,7 @@ static inline void generate_output(const char *protocol, const char *address, un } HashTable* createHashTable() { - HashTable *hashTable = (HashTable*)malloc(sizeof(HashTable)); + HashTable *hashTable = (HashTable*)mallocz(sizeof(HashTable)); memset(hashTable, 0, sizeof(HashTable)); return hashTable; } @@ -70,100 +122,49 @@ static inline unsigned int hashFunction(unsigned int inode) { static inline void insertHashTable(HashTable *hashTable, unsigned int inode, unsigned int port, PROC_NET_PROTOCOLS protocol, char *local_address) { unsigned int index = hashFunction(inode); - Node *newNode = (Node*)malloc(sizeof(Node)); + Node *newNode = (Node*)mallocz(sizeof(Node)); newNode->inode = inode; newNode->port = port; newNode->protocol = protocol; - strncpy(newNode->local_address, local_address, INET6_ADDRSTRLEN); - newNode->local_address[INET6_ADDRSTRLEN - 1] = '\0'; - newNode->next = hashTable->table[index]; - hashTable->table[index] = newNode; + strncpyz(newNode->local_address, local_address, INET6_ADDRSTRLEN - 1); + DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(hashTable->table[index], newNode, prev, next); } -static inline unsigned int lookupHashTable(HashTable *hashTable, unsigned int inode, PROC_NET_PROTOCOLS *protocol, char **local_address) { +static inline bool lookupHashTable_and_execute(HashTable *hashTable, unsigned int inode, pid_t pid) { unsigned int index = hashFunction(inode); - Node *node = hashTable->table[index]; - while (node) { - if (node->inode == inode) { - *protocol = node->protocol; - *local_address = node->local_address; - node->processed = true; - return node->port; + for(Node *node = hashTable->table[index], *next = NULL ; node ; node = next) { + next = node->next; + + if(node->inode == inode && node->port) { + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(hashTable->table[index], node, prev, next); + char cmdline[8192] = ""; + read_cmdline(pid, cmdline, sizeof(cmdline)); + fix_cmdline(cmdline); + generate_output(protocol_name(node->protocol), node->local_address, node->port, cmdline); + freez(node); + return true; } - node = node->next; } - return 0; // Not found + + return false; } void freeHashTable(HashTable *hashTable) { for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++) { - Node *node = hashTable->table[i]; - while (node) { - Node *tmp = node; - if(!tmp->processed) - generate_output(protocol_name(tmp->protocol), tmp->local_address, tmp->port, ""); - node = node->next; - free(tmp); - } - } - free(hashTable); -} - -static inline int read_cmdline(pid_t pid, char* buffer, size_t bufferSize) { - char path[FILENAME_MAX + 1]; - snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); - path[FILENAME_MAX] = '\0'; - - FILE* file = fopen(path, "r"); - if (!file) { - if(++errors_encountered < MAX_ERROR_LOGS) - fprintf(stderr, "local-listeners: error opening file: %s\n", path); - - return -1; - } - - size_t bytesRead = fread(buffer, 1, bufferSize - 1, file); - buffer[bytesRead] = '\0'; // Ensure null-terminated - - // Replace null characters in cmdline with spaces - for (size_t i = 0; i < bytesRead; i++) { - if (buffer[i] == '\0') { - buffer[i] = ' '; + while(hashTable->table[i]) { + Node *tmp = hashTable->table[i]; + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(hashTable->table[i], tmp, prev, next); + generate_output(protocol_name(tmp->protocol), tmp->local_address, tmp->port, ""); + freez(tmp); } } - - fclose(file); - return 0; + freez(hashTable); } -static inline void fix_cmdline(char* str) { - if (str == NULL) - return; - - char *s = str; - - do { - if(*s == '|' || iscntrl(*s)) - *s = '_'; - - } while(*++s); - - - while(s > str && *(s-1) == ' ') - *--s = '\0'; -} +// ---------------------------------------------------------------------------- static inline void found_this_socket_inode(pid_t pid, unsigned int inode) { - PROC_NET_PROTOCOLS protocol = 0; - char *address = NULL; - unsigned int port = lookupHashTable(hashTable_key_inode_port_value, inode, &protocol, &address); - - if(port) { - char cmdline[8192] = ""; - read_cmdline(pid, cmdline, sizeof(cmdline)); - fix_cmdline(cmdline); - generate_output(protocol_name(protocol), address, port, cmdline); - } + lookupHashTable_and_execute(hashTable_key_inode_port_value, inode, pid); } bool find_all_sockets_in_proc(const char *proc_filename) { @@ -174,7 +175,7 @@ bool find_all_sockets_in_proc(const char *proc_filename) { proc_dir = opendir(proc_filename); if (proc_dir == NULL) { if(++errors_encountered < MAX_ERROR_LOGS) - fprintf(stderr, "local-listeners: cannot opendir() '%s' (error: %s)\n", proc_filename, strerror(errno)); + collector_error("LOCAL-LISTENERS: cannot opendir() '%s'", proc_filename); pid_fds_failed++; return false; @@ -194,13 +195,12 @@ bool find_all_sockets_in_proc(const char *proc_filename) { continue; // Build the path to the fd directory of the process - snprintf(path_buffer, FILENAME_MAX, "%s/%s/fd/", proc_filename, proc_entry->d_name); - path_buffer[FILENAME_MAX] = '\0'; + snprintfz(path_buffer, FILENAME_MAX, "%s/%s/fd/", proc_filename, proc_entry->d_name); fd_dir = opendir(path_buffer); if (fd_dir == NULL) { if(++errors_encountered < MAX_ERROR_LOGS) - fprintf(stderr, "local-listeners: cannot opendir() '%s' (error: %s)\n", path_buffer, strerror(errno)); + collector_error("LOCAL-LISTENERS: cannot opendir() '%s'", path_buffer); pid_fds_failed++; continue; @@ -210,18 +210,17 @@ bool find_all_sockets_in_proc(const char *proc_filename) { if(!strcmp(fd_entry->d_name, ".") || !strcmp(fd_entry->d_name, "..")) continue; - char link_path[512]; - char link_target[512]; + char link_path[FILENAME_MAX + 1]; + char link_target[FILENAME_MAX + 1]; int inode; // Build the path to the file descriptor link - strncpy(link_path, path_buffer, sizeof(link_path)); - strncat(link_path, fd_entry->d_name, sizeof(link_path) - strlen(link_path) - 1); + snprintfz(link_path, FILENAME_MAX, "%s/%s", path_buffer, fd_entry->d_name); ssize_t len = readlink(link_path, link_target, sizeof(link_target) - 1); if (len == -1) { if(++errors_encountered < MAX_ERROR_LOGS) - fprintf(stderr, "local-listeners: cannot read link '%s' (error: %s)\n", link_path, strerror(errno)); + collector_error("LOCAL-LISTENERS: cannot read link '%s'", link_path); pid_fds_failed++; continue; @@ -242,6 +241,8 @@ bool find_all_sockets_in_proc(const char *proc_filename) { return true; } +// ---------------------------------------------------------------------------- + static inline void add_port_and_inode(PROC_NET_PROTOCOLS protocol, unsigned int port, unsigned int inode, char *local_address) { insertHashTable(hashTable_key_inode_port_value, inode, port, protocol, local_address); } @@ -336,38 +337,30 @@ bool read_proc_net_x(const char *filename, PROC_NET_PROTOCOLS protocol) { return true; } -int main(int argc, char **argv) { - (void)argc; - (void)argv; - - char *netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX"); - if(!netdata_configured_host_prefix) netdata_configured_host_prefix = ""; +// ---------------------------------------------------------------------------- +int main(int argc __maybe_unused, char **argv __maybe_unused) { char path[FILENAME_MAX + 1]; - hashTable_key_inode_port_value = createHashTable(); - snprintf(path, FILENAME_MAX, "%s/proc/net/tcp", netdata_configured_host_prefix); - path[FILENAME_MAX] = '\0'; + netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX"); + if(!netdata_configured_host_prefix) netdata_configured_host_prefix = ""; + + snprintfz(path, FILENAME_MAX, "%s/proc/net/tcp", netdata_configured_host_prefix); read_proc_net_x(path, PROC_NET_PROTOCOL_TCP); - snprintf(path, FILENAME_MAX, "%s/proc/net/udp", netdata_configured_host_prefix); - path[FILENAME_MAX] = '\0'; + snprintfz(path, FILENAME_MAX, "%s/proc/net/udp", netdata_configured_host_prefix); read_proc_net_x(path, PROC_NET_PROTOCOL_UDP); - snprintf(path, FILENAME_MAX, "%s/proc/net/tcp6", netdata_configured_host_prefix); - path[FILENAME_MAX] = '\0'; + snprintfz(path, FILENAME_MAX, "%s/proc/net/tcp6", netdata_configured_host_prefix); read_proc_net_x(path, PROC_NET_PROTOCOL_TCP6); - snprintf(path, FILENAME_MAX, "%s/proc/net/udp6", netdata_configured_host_prefix); - path[FILENAME_MAX] = '\0'; + snprintfz(path, FILENAME_MAX, "%s/proc/net/udp6", netdata_configured_host_prefix); read_proc_net_x(path, PROC_NET_PROTOCOL_UDP6); - snprintf(path, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix); - path[FILENAME_MAX] = '\0'; + snprintfz(path, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix); find_all_sockets_in_proc(path); freeHashTable(hashTable_key_inode_port_value); - return 0; } |