master
h 1,898 lines 66.4 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_LOCAL_SOCKETS_H
4 #define NETDATA_LOCAL_SOCKETS_H
5
6 #include "libnetdata/libnetdata.h"
7
8 #ifndef _countof
9 #define _countof(x) (sizeof(x) / sizeof(*(x)))
10 #endif
11
12 // Network-namespace switching via setns() is Linux-only.
13 #if defined(OS_LINUX)
14 #define LOCAL_SOCKETS_USE_SETNS
15 #define USE_LIBMNL_AFTER_SETNS
16 #endif
17
18 #if defined(HAVE_LIBMNL)
19 #include <linux/rtnetlink.h>
20 #include <linux/inet_diag.h>
21 #include <linux/sock_diag.h>
22 #include <linux/unix_diag.h>
23 #include <linux/netlink.h>
24 #include <libmnl/libmnl.h>
25 #endif
26
27 #define UID_UNSET (uid_t)(UINT32_MAX)
28
29 // FreeBSD uses TCPS_* values from tcp_fsm.h (different numbering from Linux).
30 // Define Linux-compatible TCP_* constants here so the rest of the code —
31 // direction detection (TCP_LISTEN check) and TCP_STATE_2str display — works
32 // unchanged on FreeBSD. The FreeBSD backend converts TCPS_* → TCP_* before
33 // storing the state in LOCAL_SOCKET.state.
34 #if defined(OS_FREEBSD)
35 #define TCP_ESTABLISHED 1
36 #define TCP_SYN_SENT 2
37 #define TCP_SYN_RECV 3
38 #define TCP_FIN_WAIT1 4
39 #define TCP_FIN_WAIT2 5
40 #define TCP_TIME_WAIT 6
41 #define TCP_CLOSE 7
42 #define TCP_CLOSE_WAIT 8
43 #define TCP_LAST_ACK 9
44 #define TCP_LISTEN 10
45 #define TCP_CLOSING 11
46 #endif
47
48 // max cmdline bytes read from /proc/<pid>/cmdline — reader-side guard must match
49 #define LOCAL_SOCKETS_CMDLINE_MAX 8192
50
51 // --------------------------------------------------------------------------------------------------------------------
52 // hashtable for keeping the namespaces
53 // key and value is the namespace inode
54
55 #define SIMPLE_HASHTABLE_KEY_TYPE uint64_t
56 #define SIMPLE_HASHTABLE_VALUE_TYPE_IS_NOT_POINTER
57 #define SIMPLE_HASHTABLE_VALUE_TYPE uint64_t
58 #define SIMPLE_HASHTABLE_NAME _NET_NS
59 #include "libnetdata/simple_hashtable/simple_hashtable.h"
60
61 // --------------------------------------------------------------------------------------------------------------------
62 // hashtable for keeping the sockets of PIDs
63 // key is the inode
64
65 struct pid_socket;
66 #define SIMPLE_HASHTABLE_VALUE_TYPE struct pid_socket *
67 #define SIMPLE_HASHTABLE_NAME _PID_SOCKET
68 #include "libnetdata/simple_hashtable/simple_hashtable.h"
69
70 // --------------------------------------------------------------------------------------------------------------------
71 // hashtable for keeping all the sockets
72 // key is the inode
73
74 struct local_socket;
75 #define SIMPLE_HASHTABLE_VALUE_TYPE struct local_socket *
76 #define SIMPLE_HASHTABLE_NAME _LOCAL_SOCKET
77 #include "libnetdata/simple_hashtable/simple_hashtable.h"
78
79 // --------------------------------------------------------------------------------------------------------------------
80 // hashtable for keeping all local IPs
81 // key is XXH3_64bits hash of the IP
82
83 union ipv46;
84 #define SIMPLE_HASHTABLE_VALUE_TYPE union ipv46 *
85 #define SIMPLE_HASHTABLE_NAME _LOCAL_IP
86 #include "libnetdata/simple_hashtable/simple_hashtable.h"
87
88 // --------------------------------------------------------------------------------------------------------------------
89 // hashtable for keeping all listening ports
90 // key is XXH3_64bits hash of the family, protocol, port number, namespace
91
92 struct local_port;
93 #define SIMPLE_HASHTABLE_VALUE_TYPE struct local_port *
94 #define SIMPLE_HASHTABLE_NAME _LISTENING_PORT
95 #include "libnetdata/simple_hashtable/simple_hashtable.h"
96
97 // --------------------------------------------------------------------------------------------------------------------
98
99 struct local_socket_state;
100 typedef void (*local_sockets_cb_t)(struct local_socket_state *state, const struct local_socket *n, void *data);
101
102 struct local_sockets_config {
103 bool listening;
104 bool inbound;
105 bool outbound;
106 bool local;
107 bool tcp4;
108 bool tcp6;
109 bool udp4;
110 bool udp6;
111 bool pid;
112 bool cmdline;
113 bool comm;
114 bool uid;
115 bool namespaces;
116 bool tcp_info;
117 bool no_mnl;
118 bool procfile;
119 bool report;
120
121 size_t max_errors;
122 size_t max_concurrent_namespaces;
123
124 local_sockets_cb_t cb;
125 void *data;
126
127 const char *host_prefix;
128 };
129
130 struct local_sockets_state {
131 uint32_t nl_seq;
132 uint64_t net_ns_inode;
133 pid_t net_ns_pid;
134 };
135
136 struct timing_work {
137 usec_t start_ut;
138 usec_t end_ut;
139 const char *name;
140 };
141
142 struct local_sockets_ns_req {
143 struct local_sockets_config config;
144 struct local_sockets_state ns_state;
145 };
146
147 typedef struct local_socket_state {
148 struct local_sockets_config config;
149 struct local_sockets_state ns_state;
150
151 struct {
152 size_t mnl_sends;
153 size_t tcp_info_received;
154 size_t pid_fds_processed;
155 size_t pid_fds_opendir_failed;
156 size_t pid_fds_readlink_failed;
157 size_t pid_fds_parse_failed;
158 size_t errors_encountered;
159
160 size_t sockets_added;
161
162 size_t namespaces_found;
163 size_t namespaces_absent;
164 size_t namespaces_invalid;
165 #if defined(LOCAL_SOCKETS_USE_SETNS)
166 size_t namespaces_forks_attempted;
167 size_t namespaces_forks_failed;
168 size_t namespaces_forks_unresponsive;
169 size_t namespaces_sockets_new;
170 size_t namespaces_sockets_existing;
171 #endif
172
173 struct procfile_stats ff;
174 } stats;
175
176 size_t timings_idx;
177 struct timing_work timings[30];
178
179 #if defined(LOCAL_SOCKETS_USE_SETNS)
180 bool spawn_server_is_mine;
181 SPAWN_SERVER *spawn_server;
182 #endif
183
184 #if defined(HAVE_LIBMNL)
185 uint16_t tmp_protocol;
186 #endif
187
188 procfile *ff;
189
190 ARAL *local_socket_aral;
191 ARAL *pid_socket_aral;
192 SPINLOCK spinlock; // for namespaces
193
194 uint64_t proc_self_net_ns_inode;
195
196 SIMPLE_HASHTABLE_NET_NS ns_hashtable;
197 SIMPLE_HASHTABLE_PID_SOCKET pid_sockets_hashtable;
198 SIMPLE_HASHTABLE_LOCAL_SOCKET sockets_hashtable;
199 SIMPLE_HASHTABLE_LOCAL_IP local_ips_hashtable;
200 SIMPLE_HASHTABLE_LISTENING_PORT listening_ports_hashtable;
201 } LS_STATE;
202
203 // --------------------------------------------------------------------------------------------------------------------
204
205 typedef enum __attribute__((packed)) {
206 SOCKET_DIRECTION_NONE = 0,
207 SOCKET_DIRECTION_LISTEN = (1 << 0), // a listening socket
208 SOCKET_DIRECTION_INBOUND = (1 << 1), // an inbound socket connecting a remote system to a local listening socket
209 SOCKET_DIRECTION_OUTBOUND = (1 << 2), // a socket initiated by this system, connecting to another system
210 SOCKET_DIRECTION_LOCAL_INBOUND = (1 << 3), // the socket connecting 2 localhost applications
211 SOCKET_DIRECTION_LOCAL_OUTBOUND = (1 << 4), // the socket connecting 2 localhost applications
212 } SOCKET_DIRECTION;
213
214 #ifndef TASK_COMM_LEN
215 #define TASK_COMM_LEN 16
216 #endif
217
218 struct pid_socket {
219 uint64_t inode;
220 pid_t pid;
221 pid_t ppid;
222 uid_t uid;
223 uint64_t net_ns_inode;
224 char *cmdline;
225 char comm[TASK_COMM_LEN];
226 };
227
228 struct local_port {
229 uint16_t protocol;
230 uint16_t family;
231 uint16_t port;
232 uint64_t net_ns_inode;
233 };
234
235 union ipv46 {
236 uint32_t ipv4;
237 struct in6_addr ipv6;
238 };
239
240 struct socket_endpoint {
241 uint16_t protocol;
242 uint16_t family;
243 uint16_t port;
244 union ipv46 ip;
245 };
246
247 static inline void ipv6_to_in6_addr(const char *ipv6_str, struct in6_addr *d) {
248 char buf[9];
249
250 for (size_t k = 0; k < 4; ++k) {
251 memcpy(buf, ipv6_str + (k * 8), 8);
252 buf[sizeof(buf) - 1] = '\0';
253 d->s6_addr32[k] = str2uint32_hex(buf, NULL);
254 }
255 }
256
257 typedef struct local_socket {
258 uint64_t inode;
259 uint64_t net_ns_inode;
260
261 int state;
262 struct socket_endpoint local;
263 struct socket_endpoint remote;
264 pid_t pid;
265 pid_t ppid;
266
267 SOCKET_DIRECTION direction;
268
269 uint8_t timer;
270 uint8_t retransmits; // the # of packets currently queued for retransmission (not yet acknowledged)
271 uint32_t expires;
272 uint32_t rqueue;
273 uint32_t wqueue;
274 uid_t uid;
275
276 struct {
277 bool checked;
278 bool ipv46;
279 } ipv6ony;
280
281 union {
282 struct tcp_info tcp;
283 } info;
284
285 char comm[TASK_COMM_LEN];
286 STRING *cmdline;
287
288 struct local_port local_port_key;
289
290 XXH64_hash_t local_ip_hash;
291 XXH64_hash_t remote_ip_hash;
292 XXH64_hash_t local_port_hash;
293
294 #ifdef LOCAL_SOCKETS_EXTENDED_MEMBERS
295 LOCAL_SOCKETS_EXTENDED_MEMBERS
296 #endif
297 } LOCAL_SOCKET;
298
299 #if defined(LOCAL_SOCKETS_USE_SETNS)
300 static inline int local_sockets_spawn_server_callback(SPAWN_REQUEST *request);
301 #endif
302
303 // --------------------------------------------------------------------------------------------------------------------
304
305 static inline void local_sockets_log(LS_STATE *ls, const char *format, ...) PRINTFLIKE(2, 3);
306 static inline void local_sockets_log(LS_STATE *ls, const char *format, ...) {
307 if(ls && ++ls->stats.errors_encountered == ls->config.max_errors) {
308 nd_log(NDLS_COLLECTORS, NDLP_ERR, "LOCAL-SOCKETS: max number of logs reached. Not logging anymore");
309 return;
310 }
311
312 if(ls && ls->stats.errors_encountered > ls->config.max_errors)
313 return;
314
315 char buf[16384];
316 va_list args;
317 va_start(args, format);
318 vsnprintf(buf, sizeof(buf), format, args);
319 va_end(args);
320
321 nd_log(NDLS_COLLECTORS, NDLP_ERR, "LOCAL-SOCKETS: %s", buf);
322 }
323
324 // --------------------------------------------------------------------------------------------------------------------
325
326 static bool local_sockets_is_ipv4_mapped_ipv6_address(const struct in6_addr *addr) {
327 // An IPv4-mapped IPv6 address starts with 80 bits of zeros followed by 16 bits of ones
328 static const unsigned char ipv4_mapped_prefix[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
329 return memcmp(addr->s6_addr, ipv4_mapped_prefix, 12) == 0;
330 }
331
332 static bool local_sockets_is_loopback_address(const struct socket_endpoint *se) {
333 if (se->family == AF_INET) {
334 // For IPv4, loopback addresses are in the 127.0.0.0/8 range
335 return (ntohl(se->ip.ipv4) >> 24) == 127; // Check if the first byte is 127
336 } else if (se->family == AF_INET6) {
337 // Check if the address is an IPv4-mapped IPv6 address
338 if (local_sockets_is_ipv4_mapped_ipv6_address(&se->ip.ipv6)) {
339 // Extract the last 32 bits (IPv4 address) and check if it's in the 127.0.0.0/8 range
340 uint8_t *ip6 = (uint8_t *)&se->ip.ipv6;
341 const uint32_t ipv4_addr = *((const uint32_t *)(ip6 + 12));
342 return (ntohl(ipv4_addr) >> 24) == 127;
343 }
344
345 // For IPv6, loopback address is ::1
346 return memcmp(&se->ip.ipv6, &in6addr_loopback, sizeof(se->ip.ipv6)) == 0;
347 }
348
349 return false;
350 }
351
352 static inline bool local_sockets_is_ipv4_reserved_address(uint32_t ip) {
353 // Check for the reserved address ranges
354 ip = ntohl(ip);
355 return (
356 (ip >> 24 == 10) || // Private IP range (A class)
357 (ip >> 20 == (172 << 4) + 1) || // Private IP range (B class)
358 (ip >> 16 == (192 << 8) + 168) || // Private IP range (C class)
359 (ip >> 24 == 127) || // Loopback address (127.0.0.0)
360 (ip >> 24 == 0) || // Reserved (0.0.0.0)
361 (ip >> 24 == 169 && (ip >> 16) == 254) || // Link-local address (169.254.0.0)
362 (ip >> 16 == (192 << 8) + 0) // Test-Net (192.0.0.0)
363 );
364 }
365
366 static inline bool local_sockets_is_private_address(const struct socket_endpoint *se) {
367 if (se->family == AF_INET) {
368 return local_sockets_is_ipv4_reserved_address(se->ip.ipv4);
369 }
370 else if (se->family == AF_INET6) {
371 uint8_t *ip6 = (uint8_t *)&se->ip.ipv6;
372
373 // Check if the address is an IPv4-mapped IPv6 address
374 if (local_sockets_is_ipv4_mapped_ipv6_address(&se->ip.ipv6)) {
375 // Extract the last 32 bits (IPv4 address) and check if it's in the 127.0.0.0/8 range
376 const uint32_t ipv4_addr = *((const uint32_t *)(ip6 + 12));
377 return local_sockets_is_ipv4_reserved_address(ipv4_addr);
378 }
379
380 // Check for link-local addresses (fe80::/10)
381 if ((ip6[0] == 0xFE) && ((ip6[1] & 0xC0) == 0x80))
382 return true;
383
384 // Check for Unique Local Addresses (ULA) (fc00::/7)
385 if ((ip6[0] & 0xFE) == 0xFC)
386 return true;
387
388 // Check for multicast addresses (ff00::/8)
389 if (ip6[0] == 0xFF)
390 return true;
391
392 // For IPv6, loopback address is :: or ::1
393 return memcmp(&se->ip.ipv6, &in6addr_any, sizeof(se->ip.ipv6)) == 0 ||
394 memcmp(&se->ip.ipv6, &in6addr_loopback, sizeof(se->ip.ipv6)) == 0;
395 }
396
397 return false;
398 }
399
400 static bool local_sockets_is_multicast_address(const struct socket_endpoint *se) {
401 if (se->family == AF_INET) {
402 // For IPv4, check if the address is 0.0.0.0
403 uint32_t ip = htonl(se->ip.ipv4);
404 return (ip >= 0xE0000000 && ip <= 0xEFFFFFFF); // Multicast address range (224.0.0.0/4)
405 }
406 else if (se->family == AF_INET6) {
407 // For IPv6, check if the address is ff00::/8
408 uint8_t *ip6 = (uint8_t *)&se->ip.ipv6;
409 return ip6[0] == 0xff;
410 }
411
412 return false;
413 }
414
415 static bool local_sockets_is_zero_address(const struct socket_endpoint *se) {
416 if (se->family == AF_INET) {
417 // For IPv4, check if the address is 0.0.0.0
418 return se->ip.ipv4 == 0;
419 }
420 else if (se->family == AF_INET6) {
421 // For IPv6, check if the address is ::
422 return memcmp(&se->ip.ipv6, &in6addr_any, sizeof(se->ip.ipv6)) == 0;
423 }
424
425 return false;
426 }
427
428 static inline const char *local_sockets_address_space(const struct socket_endpoint *se) {
429 if(local_sockets_is_zero_address(se))
430 return "zero";
431 else if(local_sockets_is_loopback_address(se))
432 return "loopback";
433 else if(local_sockets_is_multicast_address(se))
434 return "multicast";
435 else if(local_sockets_is_private_address(se))
436 return "private";
437 else
438 return "public";
439 }
440
441 static inline void ipv6_address_to_txt(const struct in6_addr *in6_addr, char *dst) {
442 struct sockaddr_in6 sa = { 0 };
443
444 sa.sin6_family = AF_INET6;
445 sa.sin6_port = htons(0);
446 sa.sin6_addr = *in6_addr;
447
448 // Convert to human-readable format
449 if (inet_ntop(AF_INET6, &(sa.sin6_addr), dst, INET6_ADDRSTRLEN) == NULL)
450 *dst = '\0';
451 }
452
453 static inline void ipv4_address_to_txt(uint32_t ip, char *dst) {
454 uint8_t octets[4];
455 octets[0] = ip & 0xFF;
456 octets[1] = (ip >> 8) & 0xFF;
457 octets[2] = (ip >> 16) & 0xFF;
458 octets[3] = (ip >> 24) & 0xFF;
459 sprintf(dst, "%u.%u.%u.%u", octets[0], octets[1], octets[2], octets[3]);
460 }
461
462 static inline bool is_local_socket_ipv46(const LOCAL_SOCKET *n) {
463 return n->local.family == AF_INET6 &&
464 n->direction == SOCKET_DIRECTION_LISTEN &&
465 local_sockets_is_zero_address(&n->local) &&
466 n->ipv6ony.checked &&
467 n->ipv6ony.ipv46;
468 }
469
470 static inline const char *local_sockets_protocol_name(LOCAL_SOCKET *n) {
471 if(n->local.family == AF_INET) {
472 if(n->local.protocol == IPPROTO_TCP)
473 return "TCP";
474 else if(n->local.protocol == IPPROTO_UDP)
475 return "UDP";
476 else
477 return "UNKNOWN_IPV4";
478 }
479 else if(is_local_socket_ipv46(n)) {
480 if (n->local.protocol == IPPROTO_TCP)
481 return "TCP46";
482 else if(n->local.protocol == IPPROTO_UDP)
483 return "UDP46";
484 else
485 return "UNKNOWN_IPV46";
486 }
487 else if(n->local.family == AF_INET6) {
488 if (n->local.protocol == IPPROTO_TCP)
489 return "TCP6";
490 else if(n->local.protocol == IPPROTO_UDP)
491 return "UDP6";
492 else
493 return "UNKNOWN_IPV6";
494 }
495 else
496 return "UNKNOWN";
497 }
498
499 static inline void local_listeners_print_socket(LS_STATE *ls __maybe_unused, const LOCAL_SOCKET *nn, void *data __maybe_unused) {
500 LOCAL_SOCKET *n = (LOCAL_SOCKET *)nn;
501
502 char local_address[INET6_ADDRSTRLEN] = "";
503 char remote_address[INET6_ADDRSTRLEN] = "";
504
505 if(n->local.family == AF_INET) {
506 ipv4_address_to_txt(n->local.ip.ipv4, local_address);
507 ipv4_address_to_txt(n->remote.ip.ipv4, remote_address);
508 }
509 else if(n->local.family == AF_INET6) {
510 ipv6_address_to_txt(&n->local.ip.ipv6, local_address);
511 ipv6_address_to_txt(&n->remote.ip.ipv6, remote_address);
512 }
513
514 printf("%s, direction=%s%s%s%s%s pid=%d, ppid=%d, state=0x%0x, ns=%"PRIu64", local=%s[:%u], remote=%s[:%u], uid=%u, inode=%"PRIu64", comm=%s\n",
515 local_sockets_protocol_name(n),
516 (n->direction & SOCKET_DIRECTION_LISTEN) ? "LISTEN," : "",
517 (n->direction & SOCKET_DIRECTION_INBOUND) ? "INBOUND," : "",
518 (n->direction & SOCKET_DIRECTION_OUTBOUND) ? "OUTBOUND," : "",
519 (n->direction & (SOCKET_DIRECTION_LOCAL_INBOUND|SOCKET_DIRECTION_LOCAL_OUTBOUND)) ? "LOCAL," : "",
520 (n->direction == 0) ? "NONE," : "",
521 n->pid,
522 n->ppid,
523 (unsigned int)n->state,
524 n->net_ns_inode,
525 local_address, n->local.port,
526 remote_address, n->remote.port,
527 n->uid,
528 n->inode,
529 n->comm);
530 }
531
532 // --------------------------------------------------------------------------------------------------------------------
533
534 static void local_sockets_foreach_local_socket_call_cb(LS_STATE *ls) {
535 for(SIMPLE_HASHTABLE_SLOT_LOCAL_SOCKET *sl = simple_hashtable_first_read_only_LOCAL_SOCKET(&ls->sockets_hashtable);
536 sl;
537 sl = simple_hashtable_next_read_only_LOCAL_SOCKET(&ls->sockets_hashtable, sl)) {
538 LOCAL_SOCKET *n = SIMPLE_HASHTABLE_SLOT_DATA(sl);
539 if(!n) continue;
540
541 if((ls->config.listening && n->direction & SOCKET_DIRECTION_LISTEN) ||
542 (ls->config.local && n->direction & (SOCKET_DIRECTION_LOCAL_INBOUND|SOCKET_DIRECTION_LOCAL_OUTBOUND)) ||
543 (ls->config.inbound && n->direction & SOCKET_DIRECTION_INBOUND) ||
544 (ls->config.outbound && n->direction & SOCKET_DIRECTION_OUTBOUND)
545 ) {
546 // we have to call the callback for this socket
547 if (ls->config.cb)
548 ls->config.cb(ls, n, ls->config.data);
549 }
550 }
551 }
552
553 // --------------------------------------------------------------------------------------------------------------------
554
555 static inline void local_sockets_fix_cmdline(char* str) {
556 char *s = str;
557
558 // map invalid characters to underscores
559 while(*s) {
560 if(*s == '|' || iscntrl(*s)) *s = '_';
561 s++;
562 }
563 }
564
565 // --------------------------------------------------------------------------------------------------------------------
566
567 static inline bool
568 local_sockets_read_proc_inode_link(LS_STATE *ls, const char *filename, uint64_t *inode, const char *type) {
569 char link_target[FILENAME_MAX + 1];
570
571 *inode = 0;
572
573 ssize_t len = readlink(filename, link_target, sizeof(link_target) - 1);
574 if (len == -1) {
575 local_sockets_log(ls, "cannot read '%s' link '%s'", type, filename);
576
577 ls->stats.pid_fds_readlink_failed++;
578 return false;
579 }
580 link_target[len] = '\0';
581
582 len = strlen(type);
583 if(strncmp(link_target, type, len) == 0 && link_target[len] == ':' && link_target[len + 1] == '[' && isdigit(link_target[len + 2])) {
584 *inode = strtoull(&link_target[len + 2], NULL, 10);
585 // ll_log(ls, "read link of type '%s' '%s' from '%s', inode = %"PRIu64, type, link_target, filename, *inode);
586 return true;
587 }
588 else {
589 // ll_log(ls, "cannot read '%s' link '%s' from '%s'", type, link_target, filename);
590 ls->stats.pid_fds_processed++;
591 return false;
592 }
593 }
594
595 #if !defined(OS_FREEBSD) // /proc-based PID + FD walking is Linux-only
596
597 static inline bool local_sockets_is_path_a_pid(const char *s) {
598 if(!s || !*s) return false;
599
600 while(*s) {
601 if(!isdigit(*s++))
602 return false;
603 }
604
605 return true;
606 }
607
608 static inline bool local_sockets_find_all_sockets_in_proc(LS_STATE *ls, const char *proc_filename) {
609 DIR *proc_dir;
610 struct dirent *proc_entry;
611 char filename[FILENAME_MAX + 1];
612 char comm[TASK_COMM_LEN];
613 char cmdline[LOCAL_SOCKETS_CMDLINE_MAX];
614 const char *cmdline_trimmed;
615 uint64_t net_ns_inode;
616
617 proc_dir = opendir(proc_filename);
618 if (proc_dir == NULL) {
619 local_sockets_log(ls, "cannot opendir() '%s'", proc_filename);
620 ls->stats.pid_fds_readlink_failed++;
621 return false;
622 }
623
624 while ((proc_entry = readdir(proc_dir)) != NULL) {
625 if(proc_entry->d_type != DT_DIR)
626 continue;
627
628 if(!strcmp(proc_entry->d_name, ".") || !strcmp(proc_entry->d_name, ".."))
629 continue;
630
631 if(!local_sockets_is_path_a_pid(proc_entry->d_name))
632 continue;
633
634 // Build the path to the fd directory of the process
635 snprintfz(filename, FILENAME_MAX, "%s/%s/fd/", proc_filename, proc_entry->d_name);
636 DIR *fd_dir = opendir(filename);
637 if (fd_dir == NULL) {
638 local_sockets_log(ls, "cannot opendir() '%s'", filename);
639 ls->stats.pid_fds_opendir_failed++;
640 continue;
641 }
642
643 comm[0] = '\0';
644 cmdline[0] = '\0';
645 cmdline_trimmed = NULL;
646 pid_t pid = (pid_t)strtoul(proc_entry->d_name, NULL, 10);
647 if(!pid) {
648 local_sockets_log(ls, "cannot parse pid of '%s'", proc_entry->d_name);
649 closedir(fd_dir);
650 continue;
651 }
652 pid_t ppid = 0;
653 bool ppid_checked = false;
654 bool status_checked = false;
655 bool status_failed = false;
656 net_ns_inode = 0;
657 uid_t uid = UID_UNSET;
658
659 struct dirent *fd_entry;
660 while ((fd_entry = readdir(fd_dir)) != NULL) {
661 if(fd_entry->d_type != DT_LNK)
662 continue;
663
664 snprintfz(filename, sizeof(filename), "%s/%s/fd/%s", proc_filename, proc_entry->d_name, fd_entry->d_name);
665 uint64_t inode = 0;
666 if(!local_sockets_read_proc_inode_link(ls, filename, &inode, "socket"))
667 continue;
668
669 // fprintf(stderr, "%d: PID %d is using socket inode %"PRIu64"\n", gettid_uncached(), pid, inode);
670 XXH64_hash_t inode_hash = XXH3_64bits(&inode, sizeof(inode));
671 SIMPLE_HASHTABLE_SLOT_PID_SOCKET *sl = simple_hashtable_get_slot_PID_SOCKET(&ls->pid_sockets_hashtable, inode_hash, &inode, true);
672 struct pid_socket *ps = SIMPLE_HASHTABLE_SLOT_DATA(sl);
673 if(!ps || (ps->pid == 1 && pid != 1)) {
674 if(!status_checked && !status_failed &&
675 ((uid == UID_UNSET && ls->config.uid) || (!ppid_checked && ls->config.pid))) {
676 char status_buf[512];
677
678 snprintfz(filename, sizeof(filename), "%s/%s/status", proc_filename, proc_entry->d_name);
679 if (read_txt_file(filename, status_buf, sizeof(status_buf))) {
680 status_failed = true;
681 local_sockets_log(ls, "cannot open file: %s\n", filename);
682 }
683 else {
684 status_checked = true;
685 if(ls->config.pid)
686 ppid_checked = true;
687
688 if(ls->config.uid) {
689 char *u = strstr(status_buf, "Uid:");
690 if(u) {
691 u += 4;
692 while(isspace((unsigned char)*u)) u++; // skip spaces
693 while(*u >= '0' && *u <= '9') u++; // skip the first number (real uid)
694 while(isspace((unsigned char)*u)) u++; // skip spaces again
695 uid = strtol(u, NULL, 10); // parse the 2nd number (effective uid)
696 }
697 }
698
699 if(ls->config.pid) {
700 char *p = strstr(status_buf, "PPid:");
701 if(p) {
702 p += 5;
703 while(isspace((unsigned char)*p)) p++; // skip spaces
704 ppid = (pid_t)strtol(p, NULL, 10); // parse parent pid
705 }
706 }
707 }
708 }
709 if(!comm[0] && ls->config.comm) {
710 snprintfz(filename, sizeof(filename), "%s/%s/comm", proc_filename, proc_entry->d_name);
711 if (read_txt_file(filename, comm, sizeof(comm)))
712 local_sockets_log(ls, "cannot open file: %s\n", filename);
713 else {
714 size_t clen = strlen(comm);
715 if(comm[clen - 1] == '\n')
716 comm[clen - 1] = '\0';
717 }
718 }
719 if(!cmdline[0] && ls->config.cmdline) {
720 snprintfz(filename, sizeof(filename), "%s/%s/cmdline", proc_filename, proc_entry->d_name);
721 if (read_proc_cmdline(filename, cmdline, sizeof(cmdline)))
722 local_sockets_log(ls, "cannot open file: %s\n", filename);
723 else {
724 local_sockets_fix_cmdline(cmdline);
725 cmdline_trimmed = trim(cmdline);
726 }
727 }
728 if(!net_ns_inode && ls->config.namespaces) {
729 snprintfz(filename, sizeof(filename), "%s/%s/ns/net", proc_filename, proc_entry->d_name);
730 if(local_sockets_read_proc_inode_link(ls, filename, &net_ns_inode, "net")) {
731 XXH64_hash_t net_ns_inode_hash = XXH3_64bits(&net_ns_inode, sizeof(net_ns_inode));
732 SIMPLE_HASHTABLE_SLOT_NET_NS *sl_ns = simple_hashtable_get_slot_NET_NS(&ls->ns_hashtable, net_ns_inode_hash, &net_ns_inode, true);
733 simple_hashtable_set_slot_NET_NS(&ls->ns_hashtable, sl_ns, net_ns_inode, net_ns_inode);
734 }
735 }
736
737 if(!ps)
738 ps = aral_callocz(ls->pid_socket_aral);
739
740 ps->inode = inode;
741 ps->pid = pid;
742 ps->ppid = ppid;
743 ps->uid = uid;
744 ps->net_ns_inode = net_ns_inode;
745 strncpyz(ps->comm, comm, sizeof(ps->comm) - 1);
746
747 if(ps->cmdline)
748 freez(ps->cmdline);
749
750 ps->cmdline = cmdline_trimmed ? strdupz(cmdline_trimmed) : NULL;
751 simple_hashtable_set_slot_PID_SOCKET(&ls->pid_sockets_hashtable, sl, inode_hash, ps);
752 // fprintf(stderr, "%d: PID %d indexed for using socket inode %"PRIu64"\n", gettid_uncached(), pid, inode);
753 }
754 }
755
756 closedir(fd_dir);
757 }
758
759 closedir(proc_dir);
760 return true;
761 }
762
763 #endif // !OS_FREEBSD
764
765 // --------------------------------------------------------------------------------------------------------------------
766
767 static inline void local_sockets_index_listening_port(LS_STATE *ls, LOCAL_SOCKET *n) {
768 if(n->direction & SOCKET_DIRECTION_LISTEN) {
769 // for the listening sockets, keep a hashtable with all the local ports
770 // so that we will be able to detect INBOUND sockets
771
772 SIMPLE_HASHTABLE_SLOT_LISTENING_PORT *sl_port =
773 simple_hashtable_get_slot_LISTENING_PORT(&ls->listening_ports_hashtable, n->local_port_hash, &n->local_port_key, true);
774
775 struct local_port *port = SIMPLE_HASHTABLE_SLOT_DATA(sl_port);
776 if(!port)
777 simple_hashtable_set_slot_LISTENING_PORT(&ls->listening_ports_hashtable, sl_port, n->local_port_hash, &n->local_port_key);
778 }
779 }
780
781 static inline bool local_sockets_add_socket(LS_STATE *ls, LOCAL_SOCKET *tmp) {
782 if(!tmp->inode) return false;
783
784 XXH64_hash_t inode_hash = XXH3_64bits(&tmp->inode, sizeof(tmp->inode));
785 SIMPLE_HASHTABLE_SLOT_LOCAL_SOCKET *sl = simple_hashtable_get_slot_LOCAL_SOCKET(&ls->sockets_hashtable, inode_hash, &tmp->inode, true);
786 LOCAL_SOCKET *n = SIMPLE_HASHTABLE_SLOT_DATA(sl);
787 if(n) {
788 local_sockets_log(ls, "inode %" PRIu64" already exists in hashtable - ignoring duplicate", tmp->inode);
789 return false;
790 }
791
792 ls->stats.sockets_added++;
793
794 n = aral_mallocz(ls->local_socket_aral);
795 *n = *tmp; // copy all contents
796
797 // fix the key
798 n->local_port_key.port = n->local.port;
799 n->local_port_key.family = n->local.family;
800 n->local_port_key.protocol = n->local.protocol;
801 n->local_port_key.net_ns_inode = ls->proc_self_net_ns_inode;
802
803 n->local_ip_hash = XXH3_64bits(&n->local.ip, sizeof(n->local.ip));
804 n->remote_ip_hash = XXH3_64bits(&n->remote.ip, sizeof(n->remote.ip));
805 n->local_port_hash = XXH3_64bits(&n->local_port_key, sizeof(n->local_port_key));
806
807 // --- look up a pid for it -----------------------------------------------------------------------------------
808
809 SIMPLE_HASHTABLE_SLOT_PID_SOCKET *sl_pid = simple_hashtable_get_slot_PID_SOCKET(&ls->pid_sockets_hashtable, inode_hash, &n->inode, false);
810 struct pid_socket *ps = SIMPLE_HASHTABLE_SLOT_DATA(sl_pid);
811 if(ps) {
812 n->net_ns_inode = ps->net_ns_inode;
813 n->pid = ps->pid;
814 n->ppid = ps->ppid;
815
816 if(ps->uid != UID_UNSET && n->uid == UID_UNSET)
817 n->uid = ps->uid;
818
819 if(ps->cmdline) {
820 if(n->cmdline) string_freez(n->cmdline);
821 n->cmdline = string_strdupz(ps->cmdline);
822 }
823
824 strncpyz(n->comm, ps->comm, sizeof(n->comm) - 1);
825 }
826 // else
827 // fprintf(stderr, "%d: No PID found for inode %"PRIu64"\n", gettid_uncached(), n->inode);
828
829 // --- index it -----------------------------------------------------------------------------------------------
830
831 simple_hashtable_set_slot_LOCAL_SOCKET(&ls->sockets_hashtable, sl, inode_hash, n);
832
833 if(!local_sockets_is_zero_address(&n->local)) {
834 // put all the local IPs into the local_ips hashtable
835 // so, we learn all local IPs the system has
836
837 SIMPLE_HASHTABLE_SLOT_LOCAL_IP *sl_ip =
838 simple_hashtable_get_slot_LOCAL_IP(&ls->local_ips_hashtable, n->local_ip_hash, &n->local.ip, true);
839
840 union ipv46 *ip = SIMPLE_HASHTABLE_SLOT_DATA(sl_ip);
841 if(!ip)
842 simple_hashtable_set_slot_LOCAL_IP(&ls->local_ips_hashtable, sl_ip, n->local_ip_hash, &n->local.ip);
843 }
844
845 // --- 1st phase for direction detection ----------------------------------------------------------------------
846
847 if((n->local.protocol == IPPROTO_TCP && n->state == TCP_LISTEN) ||
848 local_sockets_is_zero_address(&n->local) ||
849 local_sockets_is_zero_address(&n->remote)) {
850 // the socket is either in a TCP LISTEN, or
851 // the remote address is zero
852 n->direction |= SOCKET_DIRECTION_LISTEN;
853 }
854 else {
855 // we can't say yet if it is inbound or outboud
856 // so, mark it as both inbound and outbound
857 n->direction |= SOCKET_DIRECTION_INBOUND | SOCKET_DIRECTION_OUTBOUND;
858 }
859
860 // --- index it in LISTENING_PORT -----------------------------------------------------------------------------
861
862 local_sockets_index_listening_port(ls, n);
863
864 return true;
865 }
866
867 #if defined(HAVE_LIBMNL)
868
869 static inline int local_sockets_libmnl_cb_data(const struct nlmsghdr *nlh, void *data) {
870 LS_STATE *ls = data;
871
872 struct inet_diag_msg *diag_msg = mnl_nlmsg_get_payload(nlh);
873
874 LOCAL_SOCKET n = {
875 .inode = diag_msg->idiag_inode,
876 .direction = SOCKET_DIRECTION_NONE,
877 .state = diag_msg->idiag_state,
878 .ipv6ony = {
879 .checked = false,
880 .ipv46 = false,
881 },
882 .local = {
883 .protocol = ls->tmp_protocol,
884 .family = diag_msg->idiag_family,
885 .port = ntohs(diag_msg->id.idiag_sport),
886 },
887 .remote = {
888 .protocol = ls->tmp_protocol,
889 .family = diag_msg->idiag_family,
890 .port = ntohs(diag_msg->id.idiag_dport),
891 },
892 .timer = diag_msg->idiag_timer,
893 .retransmits = diag_msg->idiag_retrans,
894 .expires = diag_msg->idiag_expires,
895 .rqueue = diag_msg->idiag_rqueue,
896 .wqueue = diag_msg->idiag_wqueue,
897 .uid = diag_msg->idiag_uid,
898 };
899
900 if (diag_msg->idiag_family == AF_INET) {
901 memcpy(&n.local.ip.ipv4, diag_msg->id.idiag_src, sizeof(n.local.ip.ipv4));
902 memcpy(&n.remote.ip.ipv4, diag_msg->id.idiag_dst, sizeof(n.remote.ip.ipv4));
903 }
904 else if (diag_msg->idiag_family == AF_INET6) {
905 memcpy(&n.local.ip.ipv6, diag_msg->id.idiag_src, sizeof(n.local.ip.ipv6));
906 memcpy(&n.remote.ip.ipv6, diag_msg->id.idiag_dst, sizeof(n.remote.ip.ipv6));
907 }
908
909 struct rtattr *attr = (struct rtattr *)(diag_msg + 1);
910 int rtattrlen = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*diag_msg));
911 for (; !n.ipv6ony.checked && RTA_OK(attr, rtattrlen); attr = RTA_NEXT(attr, rtattrlen)) {
912 switch (attr->rta_type) {
913 case INET_DIAG_INFO: {
914 if(ls->tmp_protocol == IPPROTO_TCP) {
915 struct tcp_info *info = (struct tcp_info *)RTA_DATA(attr);
916 n.info.tcp = *info;
917 ls->stats.tcp_info_received++;
918 }
919 }
920 break;
921
922 case INET_DIAG_SKV6ONLY: {
923 n.ipv6ony.checked = true;
924 int ipv6only = *(int *)RTA_DATA(attr);
925 n.ipv6ony.ipv46 = !ipv6only;
926 }
927 break;
928
929 default:
930 break;
931 }
932 }
933
934 local_sockets_add_socket(ls, &n);
935
936 return MNL_CB_OK;
937 }
938
939 static inline bool local_sockets_libmnl_get_sockets(LS_STATE *ls, uint16_t family, uint16_t protocol) {
940 ls->tmp_protocol = protocol;
941
942 struct mnl_socket *nl = mnl_socket_open(NETLINK_INET_DIAG);
943 if (nl == NULL) {
944 local_sockets_log(ls, "mnl_socket_open() failed");
945 return false;
946 }
947
948 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
949 local_sockets_log(ls, "mnl_socket_bind() failed");
950 mnl_socket_close(nl);
951 return false;
952 }
953
954 char buf[MNL_SOCKET_BUFFER_SIZE];
955 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
956 nlh->nlmsg_type = SOCK_DIAG_BY_FAMILY;
957 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
958 nlh->nlmsg_seq = ls->ns_state.nl_seq ? ls->ns_state.nl_seq++ : (uint32_t)time(NULL);
959
960 struct inet_diag_req_v2 req = {
961 .sdiag_family = family,
962 .sdiag_protocol = protocol,
963 .idiag_states = ~0, // Request all socket states
964 .idiag_ext = 0,
965 };
966
967 if(family == AF_INET6)
968 req.idiag_ext |= 1 << (INET_DIAG_SKV6ONLY - 1);
969
970 if(protocol == IPPROTO_TCP && ls->config.tcp_info)
971 req.idiag_ext |= 1 << (INET_DIAG_INFO - 1);
972
973 mnl_nlmsg_put_extra_header(nlh, sizeof(req));
974 memcpy(mnl_nlmsg_get_payload(nlh), &req, sizeof(req));
975
976 ls->stats.mnl_sends++;
977 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
978 local_sockets_log(ls, "mnl_socket_sendto() failed");
979 mnl_socket_close(nl);
980 return false;
981 }
982
983 bool rc = true;
984 size_t received = 0;
985 ssize_t ret;
986 while ((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
987 ret = mnl_cb_run(buf, ret, 0, 0, local_sockets_libmnl_cb_data, ls);
988 if (ret == MNL_CB_ERROR) {
989 local_sockets_log(ls, "mnl_cb_run() failed");
990 rc = false;
991 break;
992 }
993 else if (ret <= MNL_CB_STOP)
994 break;
995
996 received++;
997 }
998 mnl_socket_close(nl);
999
1000 if (ret == -1) {
1001 local_sockets_log(ls, "mnl_socket_recvfrom() failed");
1002 rc = false;
1003 }
1004
1005 return rc;
1006 }
1007 #endif // HAVE_LIBMNL
1008
1009 #if !defined(OS_FREEBSD) // /proc-based socket tables and pcblist reading is Linux-only
1010
1011 static inline bool local_sockets_process_proc_line(LS_STATE *ls, const char *filename, uint16_t family, uint16_t protocol, size_t line, char **words, size_t num_words) {
1012 // char *sl_txt = get_word(words, num_words, 0);
1013 char *local_ip_txt = get_word(words, num_words, 1);
1014 char *local_port_txt = get_word(words, num_words, 2);
1015 char *remote_ip_txt = get_word(words, num_words, 3);
1016 char *remote_port_txt = get_word(words, num_words, 4);
1017 char *state_txt = get_word(words, num_words, 5);
1018 char *tx_queue_txt = get_word(words, num_words, 6);
1019 char *rx_queue_txt = get_word(words, num_words, 7);
1020 char *tr_txt = get_word(words, num_words, 8);
1021 char *tm_when_txt = get_word(words, num_words, 9);
1022 char *retrans_txt = get_word(words, num_words, 10);
1023 char *uid_txt = get_word(words, num_words, 11);
1024 // char *timeout_txt = get_word(words, num_words, 12);
1025 char *inode_txt = get_word(words, num_words, 13);
1026
1027 if(!local_ip_txt || !local_port_txt || !remote_ip_txt || !remote_port_txt || !state_txt ||
1028 !tx_queue_txt || !rx_queue_txt || !tr_txt || !tm_when_txt || !retrans_txt || !uid_txt || !inode_txt) {
1029 local_sockets_log(ls, "cannot parse ipv4 line No %zu of filename '%s'", line, filename);
1030 return false;
1031 }
1032
1033 LOCAL_SOCKET n = {
1034 .direction = SOCKET_DIRECTION_NONE,
1035 .ipv6ony = {
1036 .checked = false,
1037 .ipv46 = false,
1038 },
1039 .local = {
1040 .family = family,
1041 .protocol = protocol,
1042 },
1043 .remote = {
1044 .family = family,
1045 .protocol = protocol,
1046 },
1047 .uid = UID_UNSET,
1048 };
1049
1050 n.local.port = str2uint32_hex(local_port_txt, NULL);
1051 n.remote.port = str2uint32_hex(remote_port_txt, NULL);
1052 n.state = str2uint32_hex(state_txt, NULL);
1053 n.wqueue = str2uint32_hex(tx_queue_txt, NULL);
1054 n.rqueue = str2uint32_hex(rx_queue_txt, NULL);
1055 n.timer = str2uint32_hex(tr_txt, NULL);
1056 n.expires = str2uint32_hex(tm_when_txt, NULL);
1057 n.retransmits = str2uint32_hex(retrans_txt, NULL);
1058 n.uid = str2uint32_t(uid_txt, NULL);
1059 n.inode = str2uint64_t(inode_txt, NULL);
1060
1061 if(family == AF_INET) {
1062 n.local.ip.ipv4 = str2uint32_hex(local_ip_txt, NULL);
1063 n.remote.ip.ipv4 = str2uint32_hex(remote_ip_txt, NULL);
1064 }
1065 else if(family == AF_INET6) {
1066 ipv6_to_in6_addr(local_ip_txt, &n.local.ip.ipv6);
1067 ipv6_to_in6_addr(remote_ip_txt, &n.remote.ip.ipv6);
1068 }
1069
1070 local_sockets_add_socket(ls, &n);
1071 return true;
1072 }
1073
1074 static inline bool local_sockets_read_proc_net_x_getline(LS_STATE *ls, const char *filename, uint16_t family, uint16_t protocol) {
1075 static bool is_space[256] = {
1076 [':'] = true,
1077 [' '] = true,
1078 };
1079
1080 if(family != AF_INET && family != AF_INET6)
1081 return false;
1082
1083 FILE *fp = fopen(filename, "r");
1084 if (fp == NULL)
1085 return false;
1086
1087 char *line = malloc(1024); // no mallocz() here because getline() may resize
1088 if(!line) {
1089 fclose(fp);
1090 return false;
1091 }
1092
1093 size_t len = 1024;
1094 ssize_t read;
1095
1096 ssize_t min_line_length = (family == AF_INET) ? 105 : 155;
1097 size_t counter = 0;
1098
1099 // Read line by line
1100 while ((read = getline(&line, &len, fp)) != -1) {
1101 if(counter++ == 0) continue; // skip the first line
1102
1103 if(read < min_line_length) {
1104 local_sockets_log(ls, "too small line No %zu of filename '%s': %s", counter, filename, line);
1105 continue;
1106 }
1107
1108 char *words[32];
1109 size_t num_words = quoted_strings_splitter(line, words, 32, is_space);
1110 local_sockets_process_proc_line(ls, filename, family, protocol, counter, words, num_words);
1111 }
1112
1113 fclose(fp);
1114
1115 if (line)
1116 free(line); // no freez() here because getline() may resize
1117
1118 return true;
1119 }
1120
1121 #define INITIALLY_EXPECTED_PROC_NET_LINES 16384
1122 #define PROC_NET_BYTES_PER_LINE 155 // 105 for IPv4, 155 for IPv6
1123 #define PROC_NET_WORDS_PER_LINE 22
1124 #define INITIALLY_EXPECTED_PROC_NET_WORDS (INITIALLY_EXPECTED_PROC_NET_LINES * PROC_NET_WORDS_PER_LINE)
1125 #define INITIALLY_EXPECTED_PROC_NET_BYTES (INITIALLY_EXPECTED_PROC_NET_LINES * PROC_NET_BYTES_PER_LINE)
1126
1127 static inline bool local_sockets_read_proc_net_x_procfile(LS_STATE *ls, const char *filename, uint16_t family, uint16_t protocol) {
1128 if(family != AF_INET && family != AF_INET6)
1129 return false;
1130
1131 procfile_set_adaptive_allocation(true, INITIALLY_EXPECTED_PROC_NET_BYTES, INITIALLY_EXPECTED_PROC_NET_LINES, INITIALLY_EXPECTED_PROC_NET_WORDS);
1132
1133 bool copy_initial_ff_stats = ls->ff == NULL && ls->stats.ff.memory > 0;
1134 ls->ff = procfile_reopen(ls->ff, filename, ls->ff ? NULL :" :", PROCFILE_FLAG_DEFAULT);
1135
1136 // we just created ff, copy our old stats to it
1137 if(ls->ff && copy_initial_ff_stats) ls->ff->stats = ls->stats.ff;
1138
1139 ls->ff = procfile_readall(ls->ff);
1140 if(!ls->ff) return false;
1141
1142 // get the latest stats from ff;
1143 ls->stats.ff = ls->ff->stats;
1144
1145 for(size_t l = 1; l < procfile_lines(ls->ff) ;l++) {
1146 size_t w = procfile_linewords(ls->ff, l);
1147 if(!w) continue;
1148 if(w < 14) {
1149 local_sockets_log(ls, "too small line No %zu of filename '%s' (has %zu words)", l, filename, w);
1150 continue;
1151 }
1152
1153 char *words[14] = { 0 };
1154 words[0] = procfile_lineword(ls->ff, l, 0);
1155 words[1] = procfile_lineword(ls->ff, l, 1);
1156 words[2] = procfile_lineword(ls->ff, l, 2);
1157 words[3] = procfile_lineword(ls->ff, l, 3);
1158 words[4] = procfile_lineword(ls->ff, l, 4);
1159 words[5] = procfile_lineword(ls->ff, l, 5);
1160 words[6] = procfile_lineword(ls->ff, l, 6);
1161 words[7] = procfile_lineword(ls->ff, l, 7);
1162 words[8] = procfile_lineword(ls->ff, l, 8);
1163 words[9] = procfile_lineword(ls->ff, l, 9);
1164 words[10] = procfile_lineword(ls->ff, l, 10);
1165 words[11] = procfile_lineword(ls->ff, l, 11);
1166 words[12] = procfile_lineword(ls->ff, l, 12);
1167 words[13] = procfile_lineword(ls->ff, l, 13);
1168 local_sockets_process_proc_line(ls, filename, family, protocol, l, words, _countof(words));
1169 }
1170
1171 return true;
1172 }
1173
1174 #endif // !OS_FREEBSD
1175
1176 // --------------------------------------------------------------------------------------------------------------------
1177 // Generic helpers – compiled on all platforms.
1178
1179 static inline void local_sockets_detect_directions(LS_STATE *ls) {
1180 for(SIMPLE_HASHTABLE_SLOT_LOCAL_SOCKET *sl = simple_hashtable_first_read_only_LOCAL_SOCKET(&ls->sockets_hashtable);
1181 sl ;
1182 sl = simple_hashtable_next_read_only_LOCAL_SOCKET(&ls->sockets_hashtable, sl)) {
1183 LOCAL_SOCKET *n = SIMPLE_HASHTABLE_SLOT_DATA(sl);
1184 if (!n) continue;
1185
1186 if ((n->direction & (SOCKET_DIRECTION_INBOUND|SOCKET_DIRECTION_OUTBOUND)) !=
1187 (SOCKET_DIRECTION_INBOUND|SOCKET_DIRECTION_OUTBOUND))
1188 continue;
1189
1190 // check if the local port is one of our listening ports
1191 {
1192 SIMPLE_HASHTABLE_SLOT_LISTENING_PORT *sl_port =
1193 simple_hashtable_get_slot_LISTENING_PORT(&ls->listening_ports_hashtable, n->local_port_hash, &n->local_port_key, false);
1194
1195 struct local_port *port = SIMPLE_HASHTABLE_SLOT_DATA(sl_port); // do not reference this pointer - is invalid
1196 if(port) {
1197 // the local port of this socket is a port we listen to
1198 n->direction &= ~SOCKET_DIRECTION_OUTBOUND;
1199 }
1200 else
1201 n->direction &= ~SOCKET_DIRECTION_INBOUND;
1202 }
1203
1204 // check if the remote IP is one of our local IPs
1205 {
1206 SIMPLE_HASHTABLE_SLOT_LOCAL_IP *sl_ip =
1207 simple_hashtable_get_slot_LOCAL_IP(&ls->local_ips_hashtable, n->remote_ip_hash, &n->remote.ip, false);
1208
1209 union ipv46 *d = SIMPLE_HASHTABLE_SLOT_DATA(sl_ip);
1210 if (d) {
1211 // the remote IP of this socket is one of our local IPs
1212 if(n->direction & SOCKET_DIRECTION_INBOUND) {
1213 n->direction &= ~SOCKET_DIRECTION_INBOUND;
1214 n->direction |= SOCKET_DIRECTION_LOCAL_INBOUND;
1215 }
1216 else if(n->direction & SOCKET_DIRECTION_OUTBOUND) {
1217 n->direction &= ~SOCKET_DIRECTION_OUTBOUND;
1218 n->direction |= SOCKET_DIRECTION_LOCAL_OUTBOUND;
1219 }
1220 continue;
1221 }
1222 }
1223
1224 if (local_sockets_is_loopback_address(&n->local) ||
1225 local_sockets_is_loopback_address(&n->remote)) {
1226 // both IP addresses are loopback
1227 if(n->direction & SOCKET_DIRECTION_INBOUND) {
1228 n->direction &= ~SOCKET_DIRECTION_INBOUND;
1229 n->direction |= SOCKET_DIRECTION_LOCAL_INBOUND;
1230 }
1231 else if(n->direction & SOCKET_DIRECTION_OUTBOUND) {
1232 n->direction &= ~SOCKET_DIRECTION_OUTBOUND;
1233 n->direction |= SOCKET_DIRECTION_LOCAL_OUTBOUND;
1234 }
1235 }
1236 }
1237 }
1238
1239 // --------------------------------------------------------------------------------------------------------------------
1240
1241 static inline void local_sockets_init(LS_STATE *ls) {
1242 ls->config.host_prefix = netdata_configured_host_prefix;
1243
1244 spinlock_init(&ls->spinlock);
1245
1246 simple_hashtable_init_NET_NS(&ls->ns_hashtable, 1024);
1247 simple_hashtable_init_PID_SOCKET(&ls->pid_sockets_hashtable, 65535);
1248 simple_hashtable_init_LOCAL_SOCKET(&ls->sockets_hashtable, 65535);
1249 simple_hashtable_init_LOCAL_IP(&ls->local_ips_hashtable, 4096);
1250 simple_hashtable_init_LISTENING_PORT(&ls->listening_ports_hashtable, 4096);
1251
1252 ls->local_socket_aral = aral_create(
1253 "local-sockets",
1254 sizeof(LOCAL_SOCKET),
1255 65536 / sizeof(LOCAL_SOCKET),
1256 65536,
1257 NULL, NULL, NULL, false, true, true);
1258
1259 ls->pid_socket_aral = aral_create(
1260 "pid-sockets",
1261 sizeof(struct pid_socket),
1262 65536 / sizeof(struct pid_socket),
1263 65536,
1264 NULL, NULL, NULL, false, true, true);
1265
1266 memset(&ls->stats, 0, sizeof(ls->stats));
1267
1268 #if defined(HAVE_LIBMNL)
1269 ls->tmp_protocol = 0;
1270 #endif
1271
1272 #if defined(LOCAL_SOCKETS_USE_SETNS)
1273 if(ls->config.namespaces && ls->spawn_server == NULL) {
1274 ls->spawn_server = spawn_server_create(SPAWN_SERVER_OPTION_CALLBACK, NULL, local_sockets_spawn_server_callback, 0, NULL);
1275 ls->spawn_server_is_mine = true;
1276 }
1277 else
1278 ls->spawn_server_is_mine = false;
1279 #endif
1280 }
1281
1282 static inline void local_sockets_cleanup(LS_STATE *ls) {
1283 if(ls->ff) {
1284 ls->stats.ff = ls->ff->stats;
1285 procfile_close(ls->ff);
1286 ls->ff = NULL;
1287 }
1288
1289 #if defined(LOCAL_SOCKETS_USE_SETNS)
1290 if(ls->spawn_server_is_mine) {
1291 spawn_server_destroy(ls->spawn_server);
1292 ls->spawn_server = NULL;
1293 ls->spawn_server_is_mine = false;
1294 }
1295 #endif
1296
1297 // free the sockets hashtable data
1298 for(SIMPLE_HASHTABLE_SLOT_LOCAL_SOCKET *sl = simple_hashtable_first_read_only_LOCAL_SOCKET(&ls->sockets_hashtable);
1299 sl;
1300 sl = simple_hashtable_next_read_only_LOCAL_SOCKET(&ls->sockets_hashtable, sl)) {
1301 LOCAL_SOCKET *n = SIMPLE_HASHTABLE_SLOT_DATA(sl);
1302 if(!n) continue;
1303
1304 string_freez(n->cmdline);
1305 aral_freez(ls->local_socket_aral, n);
1306 }
1307
1308 // free the pid_socket hashtable data
1309 for(SIMPLE_HASHTABLE_SLOT_PID_SOCKET *sl = simple_hashtable_first_read_only_PID_SOCKET(&ls->pid_sockets_hashtable);
1310 sl;
1311 sl = simple_hashtable_next_read_only_PID_SOCKET(&ls->pid_sockets_hashtable, sl)) {
1312 struct pid_socket *ps = SIMPLE_HASHTABLE_SLOT_DATA(sl);
1313 if(!ps) continue;
1314
1315 freez(ps->cmdline);
1316 aral_freez(ls->pid_socket_aral, ps);
1317 }
1318
1319 // free the hashtable
1320 simple_hashtable_destroy_NET_NS(&ls->ns_hashtable);
1321 simple_hashtable_destroy_PID_SOCKET(&ls->pid_sockets_hashtable);
1322 simple_hashtable_destroy_LISTENING_PORT(&ls->listening_ports_hashtable);
1323 simple_hashtable_destroy_LOCAL_IP(&ls->local_ips_hashtable);
1324 simple_hashtable_destroy_LOCAL_SOCKET(&ls->sockets_hashtable);
1325
1326 aral_destroy(ls->local_socket_aral);
1327 aral_destroy(ls->pid_socket_aral);
1328 }
1329
1330 // --------------------------------------------------------------------------------------------------------------------
1331
1332 static inline void local_sockets_track_time(LS_STATE *ls, const char *name) {
1333 if(!ls->config.report || ls->timings_idx >= _countof(ls->timings))
1334 return;
1335
1336 usec_t now_ut = now_monotonic_usec();
1337
1338 if(ls->timings_idx == 0 && !ls->timings[0].start_ut) {
1339 ls->timings[0].start_ut = now_ut;
1340 ls->timings[0].name = name;
1341 }
1342 else if(ls->timings_idx + 1 < _countof(ls->timings)) {
1343 ls->timings[ls->timings_idx].end_ut = now_ut;
1344 ls->timings_idx++;
1345 ls->timings[ls->timings_idx].start_ut = now_ut;
1346 ls->timings[ls->timings_idx].name = name;
1347 }
1348 else if(ls->timings_idx + 1 == _countof(ls->timings)) {
1349 ls->timings[ls->timings_idx].end_ut = now_ut;
1350 ls->timings_idx++; // out of bounds
1351 }
1352 }
1353
1354 static void local_sockets_track_time_by_protocol(LS_STATE *ls, bool mnl, uint16_t family, uint16_t protocol) {
1355 if(mnl) {
1356 if(family == AF_INET) {
1357 if(protocol == IPPROTO_TCP)
1358 local_sockets_track_time(ls, "mnl_read_tcp4");
1359 else if(protocol == IPPROTO_UDP)
1360 local_sockets_track_time(ls, "mnl_read_udp4");
1361 }
1362 else if(family == AF_INET6) {
1363 if(protocol == IPPROTO_TCP)
1364 local_sockets_track_time(ls, "mnl_read_tcp6");
1365 else if(protocol == IPPROTO_UDP)
1366 local_sockets_track_time(ls, "mnl_read_udp6");
1367 }
1368 else
1369 local_sockets_track_time(ls, "mnl_read_unknown");
1370 }
1371 else {
1372 if(family == AF_INET) {
1373 if(protocol == IPPROTO_TCP)
1374 local_sockets_track_time(ls, "proc_read_tcp4");
1375 else if(protocol == IPPROTO_UDP)
1376 local_sockets_track_time(ls, "proc_read_udp4");
1377 }
1378 else if(family == AF_INET6) {
1379 if(protocol == IPPROTO_TCP)
1380 local_sockets_track_time(ls, "proc_read_tcp6");
1381 else if(protocol == IPPROTO_UDP)
1382 local_sockets_track_time(ls, "proc_read_udp6");
1383 }
1384 else
1385 local_sockets_track_time(ls, "proc_read_unknown");
1386 }
1387 }
1388
1389 #if !defined(OS_FREEBSD) // /proc-based socket reading is Linux-only
1390
1391 static inline void local_sockets_do_family_protocol(LS_STATE *ls, const char *filename, uint16_t family, uint16_t protocol) {
1392 #if defined(HAVE_LIBMNL)
1393 if(!ls->config.no_mnl) {
1394 local_sockets_track_time_by_protocol(ls, true, family, protocol);
1395 if(local_sockets_libmnl_get_sockets(ls, family, protocol))
1396 return;
1397
1398 // else, do proc
1399 }
1400 #endif
1401
1402 local_sockets_track_time_by_protocol(ls, false, family, protocol);
1403
1404 if(ls->config.procfile)
1405 local_sockets_read_proc_net_x_procfile(ls, filename, family, protocol);
1406 else
1407 local_sockets_read_proc_net_x_getline(ls, filename, family, protocol);
1408 }
1409
1410 static inline void local_sockets_read_all_system_sockets(LS_STATE *ls) {
1411 char path[FILENAME_MAX + 1];
1412
1413 if(ls->config.namespaces) {
1414 local_sockets_track_time(ls, "read_namespaces");
1415 snprintfz(path, sizeof(path), "%s/proc/self/ns/net", ls->config.host_prefix);
1416 local_sockets_read_proc_inode_link(ls, path, &ls->proc_self_net_ns_inode, "net");
1417 }
1418
1419 if(ls->config.cmdline || ls->config.comm || ls->config.pid || ls->config.namespaces) {
1420 local_sockets_track_time(ls, "proc_read_pids");
1421 snprintfz(path, sizeof(path), "%s/proc", ls->config.host_prefix);
1422 local_sockets_find_all_sockets_in_proc(ls, path);
1423 }
1424
1425 if(ls->config.tcp4) {
1426 snprintfz(path, sizeof(path), "%s/proc/net/tcp", ls->config.host_prefix);
1427 local_sockets_do_family_protocol(ls, path, AF_INET, IPPROTO_TCP);
1428 }
1429
1430 if(ls->config.udp4) {
1431 snprintfz(path, sizeof(path), "%s/proc/net/udp", ls->config.host_prefix);
1432 local_sockets_do_family_protocol(ls, path, AF_INET, IPPROTO_UDP);
1433 }
1434
1435 if(ls->config.tcp6) {
1436 snprintfz(path, sizeof(path), "%s/proc/net/tcp6", ls->config.host_prefix);
1437 local_sockets_do_family_protocol(ls, path, AF_INET6, IPPROTO_TCP);
1438 }
1439
1440 if(ls->config.udp6) {
1441 snprintfz(path, sizeof(path), "%s/proc/net/udp6", ls->config.host_prefix);
1442 local_sockets_do_family_protocol(ls, path, AF_INET6, IPPROTO_UDP);
1443 }
1444 }
1445
1446 #elif defined(OS_FREEBSD)
1447 // FreeBSD: local_sockets_read_all_system_sockets() is provided by the FreeBSD backend.
1448 #include "local-sockets-freebsd.h"
1449 #endif // !OS_FREEBSD
1450
1451 // --------------------------------------------------------------------------------------------------------------------
1452 // switch namespaces to read namespace sockets (Linux/setns only)
1453
1454 #if defined(LOCAL_SOCKETS_USE_SETNS)
1455
1456 struct local_sockets_child_work {
1457 int fd;
1458 uint64_t net_ns_inode;
1459 };
1460
1461 #define LOCAL_SOCKET_TERMINATOR (struct local_socket) { \
1462 .expires = UINT32_MAX, \
1463 .timer = UINT8_MAX, \
1464 .inode = UINT64_MAX, \
1465 .net_ns_inode = UINT64_MAX, \
1466 }
1467
1468 static inline bool local_socket_is_terminator(const struct local_socket *n) {
1469 static const struct local_socket t = LOCAL_SOCKET_TERMINATOR;
1470 return (n->expires == t.expires &&
1471 n->timer == t.timer &&
1472 n->inode == t.inode &&
1473 n->net_ns_inode == t.net_ns_inode);
1474 }
1475
1476 static inline void local_sockets_send_to_parent(struct local_socket_state *ls, const struct local_socket *n, void *data) {
1477 struct local_sockets_child_work *cw = data;
1478 int fd = cw->fd;
1479
1480 if(!local_socket_is_terminator(n)) {
1481 ls->stats.errors_encountered = 0;
1482 // local_sockets_log(
1483 // ls,
1484 // "child is sending inode %"PRIu64" of namespace %"PRIu64", from namespace %"PRIu64" for pid %d",
1485 // n->inode, n->net_ns_inode, ls->proc_self_net_ns_inode, ls->ns_state.net_ns_pid);
1486 }
1487
1488 if(write(fd, n, sizeof(*n)) != sizeof(*n))
1489 local_sockets_log(ls, "failed to write local socket to pipe");
1490
1491 size_t len = n->cmdline ? string_strlen(n->cmdline) + 1 : 0;
1492 if(write(fd, &len, sizeof(len)) != sizeof(len))
1493 local_sockets_log(ls, "failed to write cmdline length to pipe");
1494
1495 if(len)
1496 if(write(fd, string2str(n->cmdline), len) != (ssize_t)len)
1497 local_sockets_log(ls, "failed to write cmdline to pipe");
1498 }
1499
1500 static inline int local_sockets_spawn_server_callback(SPAWN_REQUEST *request) {
1501 static const struct local_socket terminator = LOCAL_SOCKET_TERMINATOR;
1502
1503 struct local_sockets_ns_req *req = (struct local_sockets_ns_req *)request->data;
1504
1505 LS_STATE ls = { 0 };
1506 ls.config = req->config;
1507 ls.ns_state = req->ns_state;
1508 ls.ns_state.nl_seq += gettid_uncached() * 10;
1509
1510 // we don't need these inside namespaces
1511 ls.config.cmdline = false;
1512 ls.config.comm = false;
1513 ls.config.pid = false;
1514 ls.config.namespaces = false;
1515
1516 #if !defined(USE_LIBMNL_AFTER_SETNS)
1517 ls.config.no_mnl = true; // disable mnl since this collects all sockets from the entire system
1518 #endif
1519
1520 // initialize local sockets
1521 local_sockets_init(&ls);
1522 ls.proc_self_net_ns_inode = ls.ns_state.net_ns_inode;
1523 ls.config.host_prefix = ""; // we need the /proc of the container
1524
1525 struct local_sockets_child_work cw = {
1526 .net_ns_inode = ls.proc_self_net_ns_inode,
1527 .fd = request->fds[1], // stdout
1528 };
1529
1530 ls.config.cb = local_sockets_send_to_parent;
1531 ls.config.data = &cw;
1532
1533 // switch namespace using the custom fd passed via the spawn server
1534 if (setns(request->fds[3], CLONE_NEWNET) == -1) {
1535 local_sockets_log(&ls, "failed to switch network namespace at child process using fd %d", request->fds[3]);
1536 return EXIT_FAILURE;
1537 }
1538
1539 // close the custom fd
1540 close(request->fds[3]); request->fds[3] = -1;
1541
1542 // read all sockets from /proc
1543 local_sockets_read_all_system_sockets(&ls);
1544
1545 // send all sockets to parent
1546 local_sockets_foreach_local_socket_call_cb(&ls);
1547
1548 // send the terminating socket
1549 local_sockets_send_to_parent(&ls, &terminator, &cw);
1550
1551 local_sockets_cleanup(&ls);
1552
1553 return EXIT_SUCCESS;
1554 }
1555
1556 static inline bool local_sockets_get_namespace_sockets_with_pid(LS_STATE *ls, struct pid_socket *ps) {
1557 char filename[1024];
1558 snprintfz(filename, sizeof(filename), "%s/proc/%d/ns/net", ls->config.host_prefix, ps->pid);
1559
1560 // verify the pid is in the target namespace
1561 int fd = open(filename, O_RDONLY | O_CLOEXEC);
1562 if (fd == -1) {
1563 local_sockets_log(ls, "cannot open file '%s'", filename);
1564 if(ls->config.report)
1565 __atomic_add_fetch(&ls->stats.namespaces_absent, 1, __ATOMIC_RELAXED);
1566 return false;
1567 }
1568
1569 struct stat statbuf;
1570 if (fstat(fd, &statbuf) == -1) {
1571 close(fd);
1572 local_sockets_log(ls, "failed to get file statistics for '%s'", filename);
1573 if(ls->config.report)
1574 __atomic_add_fetch(&ls->stats.namespaces_absent, 1, __ATOMIC_RELAXED);
1575 return false;
1576 }
1577
1578 if (statbuf.st_ino != ps->net_ns_inode) {
1579 close(fd);
1580 local_sockets_log(ls, "pid %d is not in the wanted network namespace", ps->pid);
1581 if(ls->config.report)
1582 __atomic_add_fetch(&ls->stats.namespaces_invalid, 1, __ATOMIC_RELAXED);
1583 return false;
1584 }
1585
1586 if(ls->spawn_server == NULL) {
1587 close(fd);
1588 local_sockets_log(ls, "spawn server is not available");
1589 if(ls->config.report)
1590 __atomic_add_fetch(&ls->stats.namespaces_forks_failed, 1, __ATOMIC_RELAXED);
1591 return false;
1592 }
1593
1594 struct local_sockets_ns_req req = {
1595 .config = ls->config,
1596 .ns_state = ls->ns_state,
1597 };
1598 req.ns_state.net_ns_pid = ps->pid;
1599 req.ns_state.net_ns_inode = ps->net_ns_inode;
1600
1601 SPAWN_INSTANCE *si = spawn_server_exec(ls->spawn_server, STDERR_FILENO, fd, NULL, &req, sizeof(req), SPAWN_INSTANCE_TYPE_CALLBACK);
1602 close(fd); fd = -1;
1603
1604 if(ls->config.report)
1605 __atomic_add_fetch(&ls->stats.namespaces_forks_attempted, 1, __ATOMIC_RELAXED);
1606
1607 if(si == NULL) {
1608 local_sockets_log(ls, "cannot create spawn instance");
1609
1610 if(ls->config.report)
1611 __atomic_add_fetch(&ls->stats.namespaces_forks_failed, 1, __ATOMIC_RELAXED);
1612
1613 return false;
1614 }
1615
1616 size_t received = 0;
1617 struct local_socket buf;
1618 while(read(spawn_server_instance_read_fd(si), &buf, sizeof(buf)) == sizeof(buf)) {
1619 size_t len = 0;
1620 if(read(spawn_server_instance_read_fd(si), &len, sizeof(len)) != sizeof(len))
1621 local_sockets_log(ls, "failed to read cmdline length from pipe");
1622
1623 if(len > LOCAL_SOCKETS_CMDLINE_MAX) {
1624 // broken pipe protocol: writer caps at LOCAL_SOCKETS_CMDLINE_MAX bytes
1625 local_sockets_log(ls, "cmdline length %zu from child exceeds limit (%d), aborting namespace socket collection", len, LOCAL_SOCKETS_CMDLINE_MAX);
1626 break;
1627 }
1628
1629 if(len) {
1630 CLEAN_CHAR_P *cmdline = mallocz(len + 1);
1631 if(read(spawn_server_instance_read_fd(si), cmdline, len) != (ssize_t)len)
1632 local_sockets_log(ls, "failed to read cmdline from pipe");
1633 else {
1634 cmdline[len] = '\0';
1635 buf.cmdline = string_strdupz(cmdline);
1636 }
1637 }
1638 else
1639 buf.cmdline = NULL;
1640
1641 received++;
1642
1643 if(local_socket_is_terminator(&buf))
1644 // the child finished
1645 break;
1646
1647 // overwrite the net_ns_inode we receive
1648 buf.net_ns_inode = ps->net_ns_inode;
1649
1650 spinlock_lock(&ls->spinlock);
1651
1652 if(!local_sockets_add_socket(ls, &buf)) {
1653 // fprintf(stderr, "Failed to add duplicate namespace socket inode %"PRIu64"\n", buf.inode);
1654 string_freez(buf.cmdline);
1655 if(ls->config.report)
1656 __atomic_add_fetch(&ls->stats.namespaces_sockets_existing, 1, __ATOMIC_RELAXED);
1657 }
1658 else {
1659 // fprintf(stderr, "Added namespace socket inode %"PRIu64"\n", buf.inode);
1660 if(ls->config.report)
1661 __atomic_add_fetch(&ls->stats.namespaces_sockets_new, 1, __ATOMIC_RELAXED);
1662 }
1663
1664 spinlock_unlock(&ls->spinlock);
1665 }
1666
1667 spawn_server_exec_kill(ls->spawn_server, si, 0);
1668
1669 if(ls->config.report && received == 0)
1670 __atomic_add_fetch(&ls->stats.namespaces_forks_unresponsive, 1, __ATOMIC_RELAXED);
1671
1672 return received > 0;
1673 }
1674
1675 struct local_sockets_namespace_worker {
1676 LS_STATE *ls;
1677 uint64_t inode;
1678 };
1679
1680 static inline void local_sockets_get_namespace_sockets_worker(void *arg) {
1681 struct local_sockets_namespace_worker *data = arg;
1682 LS_STATE *ls = data->ls;
1683 const uint64_t inode = data->inode;
1684
1685 spinlock_lock(&ls->spinlock);
1686
1687 // find a pid_socket that has this namespace
1688 for(SIMPLE_HASHTABLE_SLOT_PID_SOCKET *sl_pid = simple_hashtable_first_read_only_PID_SOCKET(&ls->pid_sockets_hashtable) ;
1689 sl_pid ;
1690 sl_pid = simple_hashtable_next_read_only_PID_SOCKET(&ls->pid_sockets_hashtable, sl_pid)) {
1691 struct pid_socket *ps = SIMPLE_HASHTABLE_SLOT_DATA(sl_pid);
1692 if(!ps || ps->net_ns_inode != inode) continue;
1693
1694 // now we have a pid that has the same namespace inode
1695
1696 spinlock_unlock(&ls->spinlock);
1697 const bool worked = local_sockets_get_namespace_sockets_with_pid(ls, ps);
1698 spinlock_lock(&ls->spinlock);
1699
1700 if(worked)
1701 break;
1702 }
1703
1704 spinlock_unlock(&ls->spinlock);
1705 }
1706
1707 static inline void local_sockets_namespaces(LS_STATE *ls) {
1708 size_t threads = ls->config.max_concurrent_namespaces;
1709 if(threads == 0) threads = 5;
1710 if(threads > 100) threads = 100;
1711
1712 size_t last_thread = 0;
1713 ND_THREAD **workers = callocz(threads, sizeof(*workers));
1714 struct local_sockets_namespace_worker *workers_data = callocz(threads, sizeof(*workers_data));
1715
1716 spinlock_lock(&ls->spinlock);
1717
1718 for(SIMPLE_HASHTABLE_SLOT_NET_NS *sl = simple_hashtable_first_read_only_NET_NS(&ls->ns_hashtable);
1719 sl;
1720 sl = simple_hashtable_next_read_only_NET_NS(&ls->ns_hashtable, sl)) {
1721 const uint64_t inode = (uint64_t)SIMPLE_HASHTABLE_SLOT_DATA(sl);
1722
1723 if(inode == ls->proc_self_net_ns_inode)
1724 // skip our own namespace, we already have them
1725 continue;
1726
1727 spinlock_unlock(&ls->spinlock);
1728
1729 ls->stats.namespaces_found++;
1730
1731 if(workers[last_thread] != NULL) {
1732 if(++last_thread >= threads)
1733 last_thread = 0;
1734
1735 if(workers[last_thread]) {
1736 nd_thread_join(workers[last_thread]);
1737 workers[last_thread] = NULL;
1738 }
1739 }
1740
1741 workers_data[last_thread].ls = ls;
1742 workers_data[last_thread].inode = inode;
1743 workers[last_thread] = nd_thread_create(
1744 "local-sockets-worker",
1745 NETDATA_THREAD_OPTION_DEFAULT,
1746 local_sockets_get_namespace_sockets_worker,
1747 &workers_data[last_thread]);
1748
1749 spinlock_lock(&ls->spinlock);
1750 }
1751
1752 spinlock_unlock(&ls->spinlock);
1753
1754 // wait all the threads running
1755 for(size_t i = 0; i < threads ;i++) {
1756 if(workers[i])
1757 nd_thread_join(workers[i]);
1758 }
1759
1760 freez(workers_data);
1761 freez(workers);
1762 }
1763
1764 #endif // LOCAL_SOCKETS_USE_SETNS
1765
1766 // --------------------------------------------------------------------------------------------------------------------
1767 // read namespace sockets from the host's /proc (Linux without setns only)
1768
1769 #if !defined(LOCAL_SOCKETS_USE_SETNS) && !defined(OS_FREEBSD)
1770
1771 static inline bool local_sockets_namespaces_from_proc_with_pid(LS_STATE *ls, struct pid_socket *ps) {
1772 char filename[1024];
1773 snprintfz(filename, sizeof(filename), "%s/proc/%d/ns/net", ls->config.host_prefix, ps->pid);
1774
1775 // verify the pid is in the target namespace
1776 int fd = open(filename, O_RDONLY | O_CLOEXEC);
1777 if (fd == -1) {
1778 local_sockets_log(ls, "cannot open file '%s'", filename);
1779 if(ls->config.report)
1780 __atomic_add_fetch(&ls->stats.namespaces_absent, 1, __ATOMIC_RELAXED);
1781 return false;
1782 }
1783
1784 struct stat statbuf;
1785 if (fstat(fd, &statbuf) == -1) {
1786 close(fd);
1787 local_sockets_log(ls, "failed to get file statistics for '%s'", filename);
1788 if(ls->config.report)
1789 __atomic_add_fetch(&ls->stats.namespaces_absent, 1, __ATOMIC_RELAXED);
1790 return false;
1791 }
1792
1793 if (statbuf.st_ino != ps->net_ns_inode) {
1794 close(fd);
1795 local_sockets_log(ls, "pid %d is not in the wanted network namespace", ps->pid);
1796 if(ls->config.report)
1797 __atomic_add_fetch(&ls->stats.namespaces_invalid, 1, __ATOMIC_RELAXED);
1798 return false;
1799 }
1800
1801 char path[FILENAME_MAX + 1];
1802
1803 if(ls->config.tcp4) {
1804 snprintfz(path, sizeof(path), "%s/proc/%d/net/tcp", ls->config.host_prefix, ps->pid);
1805 if(!local_sockets_read_proc_net_x(ls, path, AF_INET, IPPROTO_TCP))
1806 return false;
1807 }
1808
1809 if(ls->config.udp4) {
1810 snprintfz(path, sizeof(path), "%s/proc/%d/net/udp", ls->config.host_prefix, ps->pid);
1811 if(!local_sockets_read_proc_net_x(ls, path, AF_INET, IPPROTO_UDP))
1812 return false;
1813 }
1814
1815 if(ls->config.tcp6) {
1816 snprintfz(path, sizeof(path), "%s/proc/%d/net/tcp6", ls->config.host_prefix, ps->pid);
1817 if(!local_sockets_read_proc_net_x(ls, path, AF_INET6, IPPROTO_TCP))
1818 return false;
1819 }
1820
1821 if(ls->config.udp6) {
1822 snprintfz(path, sizeof(path), "%s/proc/%d/net/udp6", ls->config.host_prefix, ps->pid);
1823 if(!local_sockets_read_proc_net_x(ls, path, AF_INET6, IPPROTO_UDP))
1824 return false;
1825 }
1826
1827 return true;
1828 }
1829
1830 static inline void local_sockets_namespaces_from_proc(LS_STATE *ls) {
1831 for(SIMPLE_HASHTABLE_SLOT_NET_NS *sl = simple_hashtable_first_read_only_NET_NS(&ls->ns_hashtable);
1832 sl;
1833 sl = simple_hashtable_next_read_only_NET_NS(&ls->ns_hashtable, sl)) {
1834 const uint64_t inode = (uint64_t)SIMPLE_HASHTABLE_SLOT_DATA(sl);
1835
1836 if (inode == ls->proc_self_net_ns_inode)
1837 // skip our own namespace, we already have them
1838 continue;
1839
1840 ls->stats.namespaces_found++;
1841
1842 for(SIMPLE_HASHTABLE_SLOT_PID_SOCKET *sl_pid = simple_hashtable_first_read_only_PID_SOCKET(&ls->pid_sockets_hashtable) ;
1843 sl_pid ;
1844 sl_pid = simple_hashtable_next_read_only_PID_SOCKET(&ls->pid_sockets_hashtable, sl_pid)) {
1845 struct pid_socket *ps = SIMPLE_HASHTABLE_SLOT_DATA(sl_pid);
1846 if(!ps || ps->net_ns_inode != inode) continue;
1847
1848 // now we have a pid that has the same namespace inode
1849
1850 if(local_sockets_namespaces_from_proc_with_pid(ls, ps))
1851 break;
1852 }
1853 }
1854 }
1855
1856 #endif
1857
1858 // --------------------------------------------------------------------------------------------------------------------
1859
1860 static inline void local_sockets_process(LS_STATE *ls) {
1861 ls->timings_idx = 0;
1862 local_sockets_track_time(ls, "init");
1863
1864 // initialize our hashtables
1865 local_sockets_init(ls);
1866
1867 local_sockets_track_time(ls, "all_sockets");
1868
1869 // read all sockets from /proc
1870 local_sockets_read_all_system_sockets(ls);
1871
1872 // check all socket namespaces
1873 if(ls->config.namespaces) {
1874 local_sockets_track_time(ls, "switch_namespaces");
1875 #if defined(LOCAL_SOCKETS_USE_SETNS)
1876 local_sockets_namespaces(ls);
1877 #elif !defined(OS_FREEBSD)
1878 local_sockets_namespaces_from_proc(ls);
1879 #endif
1880 // FreeBSD: jails are a different isolation model; namespace switching not supported.
1881 }
1882
1883 // detect the directions of the sockets
1884 if(ls->config.inbound || ls->config.outbound || ls->config.local) {
1885 local_sockets_track_time(ls, "detect_direction");
1886 local_sockets_detect_directions(ls);
1887 }
1888
1889 // call the callback for each socket
1890 local_sockets_track_time(ls, "output");
1891 local_sockets_foreach_local_socket_call_cb(ls);
1892
1893 // free all memory
1894 local_sockets_track_time(ls, "cleanup");
1895 local_sockets_cleanup(ls);
1896 }
1897
1898 #endif //NETDATA_LOCAL_SOCKETS_H