@cryptotaxi247 / netdata-1 / commits / 9af8a73e2

local-listener using libnetdata (#15319)

Costa Tsaousis committed Jul 6, 2023 at 17:19 UTC 9af8a73e255ee66c89175844eb2f3759672e5cc2
3 files changed +109 -114
Makefile.am
+2
@@ -283,6 +283,7 @@ CGROUP_NETWORK_FILES = \
283
284 LOCAL_LISTENERS_FILES = \
285 collectors/plugins.d/local_listeners.c \
286 + $(LIBNETDATA_FILES) \
287 $(NULL)
288
289 DISKSPACE_PLUGIN_FILES = \
@@ -1213,6 +1214,7 @@ if ENABLE_PLUGIN_LOCAL_LISTENERS
1214 plugins_PROGRAMS += local-listeners
1215 local_listeners_SOURCES = $(LOCAL_LISTENERS_FILES)
1216 local_listeners_LDADD = \
1217 + $(NETDATA_COMMON_LIBS) \
1218 $(NULL)
1219 endif
1220
collectors/plugins.d/local_listeners.c
+105 -112
@@ -1,10 +1,12 @@
1 +#include "libnetdata/libnetdata.h"
2 +#include "libnetdata/required_dummies.h"
3 +
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <stdbool.h>
7 #include <dirent.h>
8 #include <string.h>
9 #include <unistd.h>
7 -#include <errno.h>
10 #include <ctype.h>
11 #include <arpa/inet.h>
12
@@ -15,6 +17,12 @@ typedef enum {
17 PROC_NET_PROTOCOL_UDP6,
18 } PROC_NET_PROTOCOLS;
19
20 +#define MAX_ERROR_LOGS 10
21 +
22 +static size_t pid_fds_processed = 0;
23 +static size_t pid_fds_failed = 0;
24 +static size_t errors_encountered = 0;
25 +
26 static inline const char *protocol_name(PROC_NET_PROTOCOLS protocol) {
27 switch(protocol) {
28 default:
@@ -32,26 +40,70 @@ static inline const char *protocol_name(PROC_NET_PROTOCOLS protocol) {
40 }
41 }
42
43 +static inline int read_cmdline(pid_t pid, char* buffer, size_t bufferSize) {
44 + char path[FILENAME_MAX + 1];
45 + snprintfz(path, FILENAME_MAX, "/proc/%d/cmdline", pid);
46 +
47 + FILE* file = fopen(path, "r");
48 + if (!file) {
49 + if(++errors_encountered < MAX_ERROR_LOGS)
50 + collector_error("LOCAL-LISTENERS: error opening file: %s\n", path);
51 +
52 + return -1;
53 + }
54 +
55 + size_t bytesRead = fread(buffer, 1, bufferSize - 1, file);
56 + buffer[bytesRead] = '\0'; // Ensure null-terminated
57 +
58 + // Replace null characters in cmdline with spaces
59 + for (size_t i = 0; i < bytesRead; i++) {
60 + if (buffer[i] == '\0') {
61 + buffer[i] = ' ';
62 + }
63 + }
64 +
65 + fclose(file);
66 + return 0;
67 +}
68 +
69 +static inline void fix_cmdline(char* str) {
70 + if (str == NULL)
71 + return;
72 +
73 + char *s = str;
74 +
75 + do {
76 + if(*s == '|' || iscntrl(*s))
77 + *s = '_';
78 +
79 + } while(*++s);
80 +
81 +
82 + while(s > str && *(s-1) == ' ')
83 + *--s = '\0';
84 +}
85 +
86 +// ----------------------------------------------------------------------------
87 +
88 #define HASH_TABLE_SIZE 100000
36 -#define MAX_ERROR_LOGS 10
89
90 typedef struct Node {
39 - unsigned int inode;
91 + unsigned int inode; // key
92 +
93 + // values
94 unsigned int port;
95 char local_address[INET6_ADDRSTRLEN];
96 PROC_NET_PROTOCOLS protocol;
97 bool processed;
44 - struct Node *next;
98 +
99 + // linking
100 + struct Node *prev, *next;
101 } Node;
102
103 typedef struct HashTable {
104 Node *table[HASH_TABLE_SIZE];
105 } HashTable;
106
51 -static size_t pid_fds_processed = 0;
52 -static size_t pid_fds_failed = 0;
53 -static size_t errors_encountered = 0;
54 -
107 static HashTable *hashTable_key_inode_port_value = NULL;
108
109 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
111 }
112
113 HashTable* createHashTable() {
62 - HashTable *hashTable = (HashTable*)malloc(sizeof(HashTable));
114 + HashTable *hashTable = (HashTable*)mallocz(sizeof(HashTable));
115 memset(hashTable, 0, sizeof(HashTable));
116 return hashTable;
117 }
@@ -70,100 +122,49 @@ static inline unsigned int hashFunction(unsigned int inode) {
122
123 static inline void insertHashTable(HashTable *hashTable, unsigned int inode, unsigned int port, PROC_NET_PROTOCOLS protocol, char *local_address) {
124 unsigned int index = hashFunction(inode);
73 - Node *newNode = (Node*)malloc(sizeof(Node));
125 + Node *newNode = (Node*)mallocz(sizeof(Node));
126 newNode->inode = inode;
127 newNode->port = port;
128 newNode->protocol = protocol;
77 - strncpy(newNode->local_address, local_address, INET6_ADDRSTRLEN);
78 - newNode->local_address[INET6_ADDRSTRLEN - 1] = '\0';
79 - newNode->next = hashTable->table[index];
80 - hashTable->table[index] = newNode;
129 + strncpyz(newNode->local_address, local_address, INET6_ADDRSTRLEN - 1);
130 + DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(hashTable->table[index], newNode, prev, next);
131 }
132
83 -static inline unsigned int lookupHashTable(HashTable *hashTable, unsigned int inode, PROC_NET_PROTOCOLS *protocol, char **local_address) {
133 +static inline bool lookupHashTable_and_execute(HashTable *hashTable, unsigned int inode, pid_t pid) {
134 unsigned int index = hashFunction(inode);
85 - Node *node = hashTable->table[index];
86 - while (node) {
87 - if (node->inode == inode) {
88 - *protocol = node->protocol;
89 - *local_address = node->local_address;
90 - node->processed = true;
91 - return node->port;
135 + for(Node *node = hashTable->table[index], *next = NULL ; node ; node = next) {
136 + next = node->next;
137 +
138 + if(node->inode == inode && node->port) {
139 + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(hashTable->table[index], node, prev, next);
140 + char cmdline[8192] = "";
141 + read_cmdline(pid, cmdline, sizeof(cmdline));
142 + fix_cmdline(cmdline);
143 + generate_output(protocol_name(node->protocol), node->local_address, node->port, cmdline);
144 + freez(node);
145 + return true;
146 }
93 - node = node->next;
147 }
95 - return 0; // Not found
148 +
149 + return false;
150 }
151
152 void freeHashTable(HashTable *hashTable) {
153 for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++) {
100 - Node *node = hashTable->table[i];
101 - while (node) {
102 - Node *tmp = node;
103 - if(!tmp->processed)
104 - generate_output(protocol_name(tmp->protocol), tmp->local_address, tmp->port, "");
105 - node = node->next;
106 - free(tmp);
107 - }
108 - }
109 - free(hashTable);
110 -}
111 -
112 -static inline int read_cmdline(pid_t pid, char* buffer, size_t bufferSize) {
113 - char path[FILENAME_MAX + 1];
114 - snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
115 - path[FILENAME_MAX] = '\0';
116 -
117 - FILE* file = fopen(path, "r");
118 - if (!file) {
119 - if(++errors_encountered < MAX_ERROR_LOGS)
120 - fprintf(stderr, "local-listeners: error opening file: %s\n", path);
121 -
122 - return -1;
123 - }
124 -
125 - size_t bytesRead = fread(buffer, 1, bufferSize - 1, file);
126 - buffer[bytesRead] = '\0'; // Ensure null-terminated
127 -
128 - // Replace null characters in cmdline with spaces
129 - for (size_t i = 0; i < bytesRead; i++) {
130 - if (buffer[i] == '\0') {
131 - buffer[i] = ' ';
154 + while(hashTable->table[i]) {
155 + Node *tmp = hashTable->table[i];
156 + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(hashTable->table[i], tmp, prev, next);
157 + generate_output(protocol_name(tmp->protocol), tmp->local_address, tmp->port, "");
158 + freez(tmp);
159 }
160 }
134 -
135 - fclose(file);
136 - return 0;
161 + freez(hashTable);
162 }
163
139 -static inline void fix_cmdline(char* str) {
140 - if (str == NULL)
141 - return;
142 -
143 - char *s = str;
144 -
145 - do {
146 - if(*s == '|' || iscntrl(*s))
147 - *s = '_';
148 -
149 - } while(*++s);
150 -
151 -
152 - while(s > str && *(s-1) == ' ')
153 - *--s = '\0';
154 -}
164 +// ----------------------------------------------------------------------------
165
166 static inline void found_this_socket_inode(pid_t pid, unsigned int inode) {
157 - PROC_NET_PROTOCOLS protocol = 0;
158 - char *address = NULL;
159 - unsigned int port = lookupHashTable(hashTable_key_inode_port_value, inode, &protocol, &address);
160 -
161 - if(port) {
162 - char cmdline[8192] = "";
163 - read_cmdline(pid, cmdline, sizeof(cmdline));
164 - fix_cmdline(cmdline);
165 - generate_output(protocol_name(protocol), address, port, cmdline);
166 - }
167 + lookupHashTable_and_execute(hashTable_key_inode_port_value, inode, pid);
168 }
169
170 bool find_all_sockets_in_proc(const char *proc_filename) {
@@ -174,7 +175,7 @@ bool find_all_sockets_in_proc(const char *proc_filename) {
175 proc_dir = opendir(proc_filename);
176 if (proc_dir == NULL) {
177 if(++errors_encountered < MAX_ERROR_LOGS)
177 - fprintf(stderr, "local-listeners: cannot opendir() '%s' (error: %s)\n", proc_filename, strerror(errno));
178 + collector_error("LOCAL-LISTENERS: cannot opendir() '%s'", proc_filename);
179
180 pid_fds_failed++;
181 return false;
@@ -194,13 +195,12 @@ bool find_all_sockets_in_proc(const char *proc_filename) {
195 continue;
196
197 // Build the path to the fd directory of the process
197 - snprintf(path_buffer, FILENAME_MAX, "%s/%s/fd/", proc_filename, proc_entry->d_name);
198 - path_buffer[FILENAME_MAX] = '\0';
198 + snprintfz(path_buffer, FILENAME_MAX, "%s/%s/fd/", proc_filename, proc_entry->d_name);
199
200 fd_dir = opendir(path_buffer);
201 if (fd_dir == NULL) {
202 if(++errors_encountered < MAX_ERROR_LOGS)
203 - fprintf(stderr, "local-listeners: cannot opendir() '%s' (error: %s)\n", path_buffer, strerror(errno));
203 + collector_error("LOCAL-LISTENERS: cannot opendir() '%s'", path_buffer);
204
205 pid_fds_failed++;
206 continue;
@@ -210,18 +210,17 @@ bool find_all_sockets_in_proc(const char *proc_filename) {
210 if(!strcmp(fd_entry->d_name, ".") || !strcmp(fd_entry->d_name, ".."))
211 continue;
212
213 - char link_path[512];
214 - char link_target[512];
213 + char link_path[FILENAME_MAX + 1];
214 + char link_target[FILENAME_MAX + 1];
215 int inode;
216
217 // Build the path to the file descriptor link
218 - strncpy(link_path, path_buffer, sizeof(link_path));
219 - strncat(link_path, fd_entry->d_name, sizeof(link_path) - strlen(link_path) - 1);
218 + snprintfz(link_path, FILENAME_MAX, "%s/%s", path_buffer, fd_entry->d_name);
219
220 ssize_t len = readlink(link_path, link_target, sizeof(link_target) - 1);
221 if (len == -1) {
222 if(++errors_encountered < MAX_ERROR_LOGS)
224 - fprintf(stderr, "local-listeners: cannot read link '%s' (error: %s)\n", link_path, strerror(errno));
223 + collector_error("LOCAL-LISTENERS: cannot read link '%s'", link_path);
224
225 pid_fds_failed++;
226 continue;
@@ -242,6 +241,8 @@ bool find_all_sockets_in_proc(const char *proc_filename) {
241 return true;
242 }
243
244 +// ----------------------------------------------------------------------------
245 +
246 static inline void add_port_and_inode(PROC_NET_PROTOCOLS protocol, unsigned int port, unsigned int inode, char *local_address) {
247 insertHashTable(hashTable_key_inode_port_value, inode, port, protocol, local_address);
248 }
@@ -336,38 +337,30 @@ bool read_proc_net_x(const char *filename, PROC_NET_PROTOCOLS protocol) {
337 return true;
338 }
339
339 -int main(int argc, char **argv) {
340 - (void)argc;
341 - (void)argv;
342 -
343 - char *netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
344 - if(!netdata_configured_host_prefix) netdata_configured_host_prefix = "";
340 +// ----------------------------------------------------------------------------
341
342 +int main(int argc __maybe_unused, char **argv __maybe_unused) {
343 char path[FILENAME_MAX + 1];
347 -
344 hashTable_key_inode_port_value = createHashTable();
345
350 - snprintf(path, FILENAME_MAX, "%s/proc/net/tcp", netdata_configured_host_prefix);
351 - path[FILENAME_MAX] = '\0';
346 + netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
347 + if(!netdata_configured_host_prefix) netdata_configured_host_prefix = "";
348 +
349 + snprintfz(path, FILENAME_MAX, "%s/proc/net/tcp", netdata_configured_host_prefix);
350 read_proc_net_x(path, PROC_NET_PROTOCOL_TCP);
351
354 - snprintf(path, FILENAME_MAX, "%s/proc/net/udp", netdata_configured_host_prefix);
355 - path[FILENAME_MAX] = '\0';
352 + snprintfz(path, FILENAME_MAX, "%s/proc/net/udp", netdata_configured_host_prefix);
353 read_proc_net_x(path, PROC_NET_PROTOCOL_UDP);
354
358 - snprintf(path, FILENAME_MAX, "%s/proc/net/tcp6", netdata_configured_host_prefix);
359 - path[FILENAME_MAX] = '\0';
355 + snprintfz(path, FILENAME_MAX, "%s/proc/net/tcp6", netdata_configured_host_prefix);
356 read_proc_net_x(path, PROC_NET_PROTOCOL_TCP6);
357
362 - snprintf(path, FILENAME_MAX, "%s/proc/net/udp6", netdata_configured_host_prefix);
363 - path[FILENAME_MAX] = '\0';
358 + snprintfz(path, FILENAME_MAX, "%s/proc/net/udp6", netdata_configured_host_prefix);
359 read_proc_net_x(path, PROC_NET_PROTOCOL_UDP6);
360
366 - snprintf(path, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
367 - path[FILENAME_MAX] = '\0';
361 + snprintfz(path, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
362 find_all_sockets_in_proc(path);
363
364 freeHashTable(hashTable_key_inode_port_value);
371 -
365 return 0;
366 }
libnetdata/log/log.c
+2 -2
@@ -781,7 +781,7 @@ void debug_int( const char *file, const char *function, const unsigned long line
781 void info_int( int is_collector, const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, const char *fmt, ... )
782 {
783 va_list args;
784 - FILE *fp = (is_collector) ? stderr : stderror;
784 + FILE *fp = (is_collector || !stderror) ? stderr : stderror;
785
786 log_lock();
787
@@ -910,7 +910,7 @@ void error_limit_int(ERROR_LIMIT *erl, const char *prefix, const char *file __ma
910 void error_int(int is_collector, const char *prefix, const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, const char *fmt, ... ) {
911 // save a copy of errno - just in case this function generates a new error
912 int __errno = errno;
913 - FILE *fp = (is_collector) ? stderr : stderror;
913 + FILE *fp = (is_collector || !stderror) ? stderr : stderror;
914
915 va_list args;
916