flowtop: Use new UI table API for draw flows list
[netsniff-ng-new.git] / flowtop.c
blob32459aa3bff7c778e54aac1a28191290c6753932
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2011 - 2013 Daniel Borkmann.
4 * Copyright 2011 Emmanuel Roullit.
5 * Subject to the GPL, version 2.
6 */
8 #define _LGPL_SOURCE
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <signal.h>
13 #include <getopt.h>
14 #include <pthread.h>
15 #include <signal.h>
16 #include <netdb.h>
17 #include <ctype.h>
18 #include <netinet/in.h>
19 #include <curses.h>
20 #include <dirent.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <sys/fsuid.h>
24 #include <urcu.h>
25 #include <libgen.h>
26 #include <inttypes.h>
27 #include <poll.h>
28 #include <fcntl.h>
29 #include <arpa/inet.h>
31 #include "ui.h"
32 #include "die.h"
33 #include "xmalloc.h"
34 #include "conntrack.h"
35 #include "config.h"
36 #include "str.h"
37 #include "sig.h"
38 #include "lookup.h"
39 #include "geoip.h"
40 #include "built_in.h"
41 #include "locking.h"
42 #include "pkt_buff.h"
43 #include "screen.h"
44 #include "proc.h"
45 #include "sysctl.h"
47 #ifndef NSEC_PER_SEC
48 #define NSEC_PER_SEC 1000000000L
49 #endif
51 #ifndef USEC_PER_SEC
52 #define USEC_PER_SEC 1000000L
53 #endif
55 struct flow_entry {
56 uint32_t flow_id, use, status;
57 uint8_t l3_proto, l4_proto;
58 uint32_t ip4_src_addr, ip4_dst_addr;
59 uint32_t ip6_src_addr[4], ip6_dst_addr[4];
60 uint16_t port_src, port_dst;
61 uint8_t tcp_state, tcp_flags, sctp_state, dccp_state;
62 uint64_t pkts_src, bytes_src;
63 uint64_t pkts_dst, bytes_dst;
64 uint64_t timestamp_start, timestamp_stop;
65 char country_src[128], country_dst[128];
66 char country_code_src[4], country_code_dst[4];
67 char city_src[128], city_dst[128];
68 char rev_dns_src[256], rev_dns_dst[256];
69 char procname[256];
70 struct flow_entry *next;
71 int inode;
72 unsigned int procnum;
73 bool is_visible;
74 struct nf_conntrack *ct;
75 struct timeval last_update;
76 double rate_bytes_src;
77 double rate_bytes_dst;
78 double rate_pkts_src;
79 double rate_pkts_dst;
82 struct flow_list {
83 struct flow_entry *head;
84 struct spinlock lock;
87 enum flow_direction {
88 FLOW_DIR_SRC,
89 FLOW_DIR_DST,
92 #ifndef ATTR_TIMESTAMP_START
93 # define ATTR_TIMESTAMP_START 63
94 #endif
95 #ifndef ATTR_TIMESTAMP_STOP
96 # define ATTR_TIMESTAMP_STOP 64
97 #endif
99 #define SCROLL_MAX 1000
101 #define INCLUDE_IPV4 (1 << 0)
102 #define INCLUDE_IPV6 (1 << 1)
103 #define INCLUDE_UDP (1 << 2)
104 #define INCLUDE_TCP (1 << 3)
105 #define INCLUDE_DCCP (1 << 4)
106 #define INCLUDE_ICMP (1 << 5)
107 #define INCLUDE_SCTP (1 << 6)
109 #define TOGGLE_FLAG(what, flag) \
110 do { \
111 if (what & flag) \
112 what &= ~flag; \
113 else \
114 what |= flag; \
115 } while (0)
117 struct sysctl_params_ctx {
118 int nfct_acct;
119 int nfct_tstamp;
122 enum rate_units {
123 RATE_BITS,
124 RATE_BYTES
127 static volatile bool do_reload_flows;
128 static volatile bool is_flow_collecting;
129 static volatile sig_atomic_t sigint = 0;
130 static int what = INCLUDE_IPV4 | INCLUDE_IPV6 | INCLUDE_TCP;
131 static struct flow_list flow_list;
132 static struct sysctl_params_ctx sysctl = { -1, -1 };
134 static unsigned int cols, rows;
136 static unsigned int interval = 1;
137 static bool show_src = false;
138 static bool resolve_dns = true;
139 static bool resolve_geoip = true;
140 static enum rate_units rate_type = RATE_BYTES;
141 static bool show_active_only = false;
143 enum tbl_flow_col {
144 TBL_FLOW_PROCESS,
145 TBL_FLOW_PID,
146 TBL_FLOW_PROTO,
147 TBL_FLOW_STATE,
148 TBL_FLOW_TIME,
149 TBL_FLOW_ADDRESS,
150 TBL_FLOW_PORT,
151 TBL_FLOW_GEO,
152 TBL_FLOW_BYTES,
153 TBL_FLOW_RATE,
156 static struct ui_table flows_tbl;
158 static const char *short_options = "vhTUsDIS46ut:nGb";
159 static const struct option long_options[] = {
160 {"ipv4", no_argument, NULL, '4'},
161 {"ipv6", no_argument, NULL, '6'},
162 {"tcp", no_argument, NULL, 'T'},
163 {"udp", no_argument, NULL, 'U'},
164 {"dccp", no_argument, NULL, 'D'},
165 {"icmp", no_argument, NULL, 'I'},
166 {"sctp", no_argument, NULL, 'S'},
167 {"no-dns", no_argument, NULL, 'n'},
168 {"no-geoip", no_argument, NULL, 'G'},
169 {"show-src", no_argument, NULL, 's'},
170 {"bits", no_argument, NULL, 'b'},
171 {"update", no_argument, NULL, 'u'},
172 {"interval", required_argument, NULL, 't'},
173 {"version", no_argument, NULL, 'v'},
174 {"help", no_argument, NULL, 'h'},
175 {NULL, 0, NULL, 0}
178 static const char *copyright = "Please report bugs to <netsniff-ng@googlegroups.com>\n"
179 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
180 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
181 "Swiss federal institute of technology (ETH Zurich)\n"
182 "License: GNU GPL version 2.0\n"
183 "This is free software: you are free to change and redistribute it.\n"
184 "There is NO WARRANTY, to the extent permitted by law.";
186 static const char *const l4proto2str[IPPROTO_MAX] = {
187 [IPPROTO_TCP] = "tcp",
188 [IPPROTO_UDP] = "udp",
189 [IPPROTO_UDPLITE] = "udplite",
190 [IPPROTO_ICMP] = "icmp",
191 [IPPROTO_ICMPV6] = "icmpv6",
192 [IPPROTO_SCTP] = "sctp",
193 [IPPROTO_GRE] = "gre",
194 [IPPROTO_DCCP] = "dccp",
195 [IPPROTO_IGMP] = "igmp",
196 [IPPROTO_IPIP] = "ipip",
197 [IPPROTO_EGP] = "egp",
198 [IPPROTO_PUP] = "pup",
199 [IPPROTO_IDP] = "idp",
200 [IPPROTO_RSVP] = "rsvp",
201 [IPPROTO_IPV6] = "ip6tun",
202 [IPPROTO_ESP] = "esp",
203 [IPPROTO_AH] = "ah",
204 [IPPROTO_PIM] = "pim",
205 [IPPROTO_COMP] = "comp",
208 static const char *const tcp_state2str[TCP_CONNTRACK_MAX] = {
209 [TCP_CONNTRACK_NONE] = "NONE",
210 [TCP_CONNTRACK_SYN_SENT] = "SYN-SENT",
211 [TCP_CONNTRACK_SYN_RECV] = "SYN-RECV",
212 [TCP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
213 [TCP_CONNTRACK_FIN_WAIT] = "FIN-WAIT",
214 [TCP_CONNTRACK_CLOSE_WAIT] = "CLOSE-WAIT",
215 [TCP_CONNTRACK_LAST_ACK] = "LAST-ACK",
216 [TCP_CONNTRACK_TIME_WAIT] = "TIME-WAIT",
217 [TCP_CONNTRACK_CLOSE] = "CLOSE",
218 [TCP_CONNTRACK_SYN_SENT2] = "SYN-SENT2",
221 static const char *const dccp_state2str[DCCP_CONNTRACK_MAX] = {
222 [DCCP_CONNTRACK_NONE] = "NONE",
223 [DCCP_CONNTRACK_REQUEST] = "REQUEST",
224 [DCCP_CONNTRACK_RESPOND] = "RESPOND",
225 [DCCP_CONNTRACK_PARTOPEN] = "PARTOPEN",
226 [DCCP_CONNTRACK_OPEN] = "OPEN",
227 [DCCP_CONNTRACK_CLOSEREQ] = "CLOSE-REQ",
228 [DCCP_CONNTRACK_CLOSING] = "CLOSING",
229 [DCCP_CONNTRACK_TIMEWAIT] = "TIME-WAIT",
230 [DCCP_CONNTRACK_IGNORE] = "IGNORE",
231 [DCCP_CONNTRACK_INVALID] = "INVALID",
234 static const char *const sctp_state2str[SCTP_CONNTRACK_MAX] = {
235 [SCTP_CONNTRACK_NONE] = "NONE",
236 [SCTP_CONNTRACK_CLOSED] = "CLOSED",
237 [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE-WAIT",
238 [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE-ECHO",
239 [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
240 [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTD-SENT",
241 [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTD-RCVD",
242 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTD-ACK",
245 static const struct nfct_filter_ipv4 filter_ipv4 = {
246 .addr = __constant_htonl(INADDR_LOOPBACK),
247 .mask = 0xffffffff,
250 static const struct nfct_filter_ipv6 filter_ipv6 = {
251 .addr = { 0x0, 0x0, 0x0, 0x1 },
252 .mask = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
255 static int64_t time_after_us(struct timeval *tv)
257 struct timeval now;
259 bug_on(gettimeofday(&now, NULL));
261 now.tv_sec -= tv->tv_sec;
262 now.tv_usec -= tv->tv_usec;
264 return now.tv_sec * USEC_PER_SEC + now.tv_usec;
267 static void signal_handler(int number)
269 switch (number) {
270 case SIGINT:
271 case SIGQUIT:
272 case SIGTERM:
273 sigint = 1;
274 break;
275 case SIGHUP:
276 default:
277 break;
281 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct);
282 static void flow_entry_get_extended(struct flow_entry *n);
284 static void help(void)
286 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
287 VERSION_STRING);
288 puts("http://www.netsniff-ng.org\n\n"
289 "Usage: flowtop [options]\n"
290 "Options:\n"
291 " -4|--ipv4 Show only IPv4 flows (default)\n"
292 " -6|--ipv6 Show only IPv6 flows (default)\n"
293 " -T|--tcp Show only TCP flows (default)\n"
294 " -U|--udp Show only UDP flows\n"
295 " -D|--dccp Show only DCCP flows\n"
296 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
297 " -S|--sctp Show only SCTP flows\n"
298 " -n|--no-dns Don't perform hostname lookup\n"
299 " -G|--no-geoip Don't perform GeoIP lookup\n"
300 " -s|--show-src Also show source, not only dest\n"
301 " -b|--bits Show rates in bits/s instead of bytes/s\n"
302 " -u|--update Update GeoIP databases\n"
303 " -t|--interval <time> Refresh time in seconds (default 1s)\n"
304 " -v|--version Print version and exit\n"
305 " -h|--help Print this help and exit\n\n"
306 "Examples:\n"
307 " flowtop\n"
308 " flowtop -46UTDISs\n\n"
309 "Note:\n"
310 " If netfilter is not running, you can activate it with e.g.:\n"
311 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
312 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
313 puts(copyright);
314 die();
317 static void version(void)
319 printf("flowtop %s, Git id: %s\n", VERSION_LONG, GITVERSION);
320 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
321 "http://www.netsniff-ng.org\n");
322 puts(copyright);
323 die();
326 static void flow_entry_update_time(struct flow_entry *n)
328 bug_on(gettimeofday(&n->last_update, NULL));
331 #define CALC_RATE(fld) do { \
332 n->rate_##fld = (((fld) > n->fld) ? (((fld) - n->fld) / sec) : 0); \
333 } while (0)
335 static void flow_entry_calc_rate(struct flow_entry *n, const struct nf_conntrack *ct)
337 uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES);
338 uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES);
339 uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS);
340 uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS);
341 double sec = (double)time_after_us(&n->last_update) / USEC_PER_SEC;
343 if (sec < 1)
344 return;
346 CALC_RATE(bytes_src);
347 CALC_RATE(bytes_dst);
348 CALC_RATE(pkts_src);
349 CALC_RATE(pkts_dst);
352 static inline struct flow_entry *flow_entry_xalloc(void)
354 return xzmalloc(sizeof(struct flow_entry));
357 static inline void flow_entry_xfree(struct flow_entry *n)
359 if (n->ct)
360 nfct_destroy(n->ct);
362 xfree(n);
365 static inline void flow_list_init(struct flow_list *fl)
367 fl->head = NULL;
368 spinlock_init(&fl->lock);
371 static inline bool nfct_is_dns(const struct nf_conntrack *ct)
373 uint16_t port_src = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
374 uint16_t port_dst = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
376 return ntohs(port_src) == 53 || ntohs(port_dst) == 53;
379 static void flow_list_new_entry(struct flow_list *fl, const struct nf_conntrack *ct)
381 struct flow_entry *n;
383 /* We don't want to analyze / display DNS itself, since we
384 * use it to resolve reverse dns.
386 if (nfct_is_dns(ct))
387 return;
389 n = flow_entry_xalloc();
391 n->ct = nfct_clone(ct);
393 flow_entry_update_time(n);
394 flow_entry_from_ct(n, ct);
395 flow_entry_get_extended(n);
397 rcu_assign_pointer(n->next, fl->head);
398 rcu_assign_pointer(fl->head, n);
400 n->is_visible = true;
403 static struct flow_entry *flow_list_find_id(struct flow_list *fl,
404 uint32_t id)
406 struct flow_entry *n = rcu_dereference(fl->head);
408 while (n != NULL) {
409 if (n->flow_id == id)
410 return n;
412 n = rcu_dereference(n->next);
415 return NULL;
418 static struct flow_entry *flow_list_find_prev_id(const struct flow_list *fl,
419 uint32_t id)
421 struct flow_entry *prev = rcu_dereference(fl->head), *next;
423 if (prev->flow_id == id)
424 return NULL;
426 while ((next = rcu_dereference(prev->next)) != NULL) {
427 if (next->flow_id == id)
428 return prev;
430 prev = next;
433 return NULL;
436 static void flow_list_destroy_entry(struct flow_list *fl,
437 const struct nf_conntrack *ct)
439 struct flow_entry *n1, *n2;
440 uint32_t id = nfct_get_attr_u32(ct, ATTR_ID);
442 n1 = flow_list_find_id(fl, id);
443 if (n1) {
444 n2 = flow_list_find_prev_id(fl, id);
445 if (n2) {
446 rcu_assign_pointer(n2->next, n1->next);
447 n1->next = NULL;
449 flow_entry_xfree(n1);
450 } else {
451 struct flow_entry *next = fl->head->next;
453 flow_entry_xfree(fl->head);
454 fl->head = next;
459 static void flow_list_destroy(struct flow_list *fl)
461 struct flow_entry *n;
463 synchronize_rcu();
464 spinlock_lock(&flow_list.lock);
466 while (fl->head != NULL) {
467 n = rcu_dereference(fl->head->next);
468 fl->head->next = NULL;
470 flow_entry_xfree(fl->head);
471 rcu_assign_pointer(fl->head, n);
474 spinlock_unlock(&flow_list.lock);
477 static int walk_process(unsigned int pid, struct flow_entry *n)
479 int ret;
480 DIR *dir;
481 struct dirent *ent;
482 char path[1024];
484 if (snprintf(path, sizeof(path), "/proc/%u/fd", pid) == -1)
485 panic("giant process name! %u\n", pid);
487 dir = opendir(path);
488 if (!dir)
489 return 0;
491 while ((ent = readdir(dir))) {
492 struct stat statbuf;
494 if (snprintf(path, sizeof(path), "/proc/%u/fd/%s",
495 pid, ent->d_name) < 0)
496 continue;
498 if (stat(path, &statbuf) < 0)
499 continue;
501 if (S_ISSOCK(statbuf.st_mode) && (ino_t) n->inode == statbuf.st_ino) {
502 char cmdline[256];
504 ret = proc_get_cmdline(pid, cmdline, sizeof(cmdline));
505 if (ret < 0)
506 panic("Failed to get process cmdline: %s\n", strerror(errno));
508 if (snprintf(n->procname, sizeof(n->procname), "%s", basename(cmdline)) < 0)
509 n->procname[0] = '\0';
510 n->procnum = pid;
511 closedir(dir);
512 return 1;
516 closedir(dir);
517 return 0;
520 static void walk_processes(struct flow_entry *n)
522 int ret;
523 DIR *dir;
524 struct dirent *ent;
526 /* n->inode must be set */
527 if (n->inode <= 0) {
528 n->procname[0] = '\0';
529 return;
532 dir = opendir("/proc");
533 if (!dir)
534 panic("Cannot open /proc: %s\n", strerror(errno));
536 while ((ent = readdir(dir))) {
537 const char *name = ent->d_name;
538 char *end;
539 unsigned int pid = strtoul(name, &end, 10);
541 /* not a PID */
542 if (pid == 0 && end == name)
543 continue;
545 ret = walk_process(pid, n);
546 if (ret > 0)
547 break;
550 closedir(dir);
553 static int get_port_inode(uint16_t port, int proto, bool is_ip6)
555 int ret = -ENOENT;
556 char path[128], buff[1024];
557 FILE *proc;
559 memset(path, 0, sizeof(path));
560 snprintf(path, sizeof(path), "/proc/net/%s%s",
561 l4proto2str[proto], is_ip6 ? "6" : "");
563 proc = fopen(path, "r");
564 if (!proc)
565 return -EIO;
567 memset(buff, 0, sizeof(buff));
569 while (fgets(buff, sizeof(buff), proc) != NULL) {
570 int inode = 0;
571 unsigned int lport = 0;
573 buff[sizeof(buff) - 1] = 0;
574 if (sscanf(buff, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
575 "%*X %*u %*u %u", &lport, &inode) == 2) {
576 if ((uint16_t) lport == port) {
577 ret = inode;
578 break;
582 memset(buff, 0, sizeof(buff));
585 fclose(proc);
586 return ret;
589 #define CP_NFCT(elem, attr, x) \
590 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
591 #define CP_NFCT_BUFF(elem, attr) do { \
592 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
593 if (buff != NULL) \
594 memcpy(n->elem, buff, sizeof(n->elem)); \
595 } while (0)
597 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct)
599 CP_NFCT(l3_proto, ATTR_ORIG_L3PROTO, 8);
600 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
602 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
603 CP_NFCT(ip4_dst_addr, ATTR_ORIG_IPV4_DST, 32);
605 CP_NFCT(port_src, ATTR_ORIG_PORT_SRC, 16);
606 CP_NFCT(port_dst, ATTR_ORIG_PORT_DST, 16);
608 CP_NFCT(status, ATTR_STATUS, 32);
610 CP_NFCT(tcp_state, ATTR_TCP_STATE, 8);
611 CP_NFCT(tcp_flags, ATTR_TCP_FLAGS_ORIG, 8);
612 CP_NFCT(sctp_state, ATTR_SCTP_STATE, 8);
613 CP_NFCT(dccp_state, ATTR_DCCP_STATE, 8);
615 CP_NFCT(pkts_src, ATTR_ORIG_COUNTER_PACKETS, 64);
616 CP_NFCT(bytes_src, ATTR_ORIG_COUNTER_BYTES, 64);
618 CP_NFCT(pkts_dst, ATTR_REPL_COUNTER_PACKETS, 64);
619 CP_NFCT(bytes_dst, ATTR_REPL_COUNTER_BYTES, 64);
621 CP_NFCT(timestamp_start, ATTR_TIMESTAMP_START, 64);
622 CP_NFCT(timestamp_stop, ATTR_TIMESTAMP_STOP, 64);
624 CP_NFCT(flow_id, ATTR_ID, 32);
625 CP_NFCT(use, ATTR_USE, 32);
627 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
628 CP_NFCT_BUFF(ip6_dst_addr, ATTR_ORIG_IPV6_DST);
630 n->port_src = ntohs(n->port_src);
631 n->port_dst = ntohs(n->port_dst);
633 n->ip4_src_addr = ntohl(n->ip4_src_addr);
634 n->ip4_dst_addr = ntohl(n->ip4_dst_addr);
637 #define SELFLD(dir,src_member,dst_member) \
638 (((dir) == FLOW_DIR_SRC) ? n->src_member : n->dst_member)
640 static void flow_entry_get_sain4_obj(const struct flow_entry *n,
641 enum flow_direction dir,
642 struct sockaddr_in *sa)
644 memset(sa, 0, sizeof(*sa));
645 sa->sin_family = PF_INET;
646 sa->sin_addr.s_addr = htonl(SELFLD(dir, ip4_src_addr, ip4_dst_addr));
649 static void flow_entry_get_sain6_obj(const struct flow_entry *n,
650 enum flow_direction dir,
651 struct sockaddr_in6 *sa)
653 memset(sa, 0, sizeof(*sa));
654 sa->sin6_family = PF_INET6;
656 memcpy(&sa->sin6_addr, SELFLD(dir, ip6_src_addr, ip6_dst_addr),
657 sizeof(sa->sin6_addr));
660 static void
661 flow_entry_geo_city_lookup_generic(struct flow_entry *n,
662 enum flow_direction dir)
664 struct sockaddr_in sa4;
665 struct sockaddr_in6 sa6;
666 const char *city = NULL;
668 switch (n->l3_proto) {
669 default:
670 bug();
672 case AF_INET:
673 flow_entry_get_sain4_obj(n, dir, &sa4);
674 city = geoip4_city_name(&sa4);
675 break;
677 case AF_INET6:
678 flow_entry_get_sain6_obj(n, dir, &sa6);
679 city = geoip6_city_name(&sa6);
680 break;
683 build_bug_on(sizeof(n->city_src) != sizeof(n->city_dst));
685 if (city)
686 strlcpy(SELFLD(dir, city_src, city_dst), city,
687 sizeof(n->city_src));
688 else
689 SELFLD(dir, city_src, city_dst)[0] = '\0';
692 static void
693 flow_entry_geo_country_lookup_generic(struct flow_entry *n,
694 enum flow_direction dir)
696 struct sockaddr_in sa4;
697 struct sockaddr_in6 sa6;
698 const char *country = NULL;
699 const char *country_code = NULL;
701 switch (n->l3_proto) {
702 default:
703 bug();
705 case AF_INET:
706 flow_entry_get_sain4_obj(n, dir, &sa4);
707 country = geoip4_country_name(&sa4);
708 country_code = geoip4_country_code3_name(&sa4);
709 break;
711 case AF_INET6:
712 flow_entry_get_sain6_obj(n, dir, &sa6);
713 country = geoip6_country_name(&sa6);
714 country_code = geoip6_country_code3_name(&sa6);
715 break;
718 build_bug_on(sizeof(n->country_src) != sizeof(n->country_dst));
720 if (country)
721 strlcpy(SELFLD(dir, country_src, country_dst), country,
722 sizeof(n->country_src));
723 else
724 SELFLD(dir, country_src, country_dst)[0] = '\0';
726 build_bug_on(sizeof(n->country_code_src) != sizeof(n->country_code_dst));
728 if (country_code)
729 strlcpy(SELFLD(dir, country_code_src, country_code_dst),
730 country_code, sizeof(n->country_code_src));
731 else
732 SELFLD(dir, country_code_src, country_code_dst)[0] = '\0';
735 static void flow_entry_get_extended_geo(struct flow_entry *n,
736 enum flow_direction dir)
738 if (resolve_geoip) {
739 flow_entry_geo_city_lookup_generic(n, dir);
740 flow_entry_geo_country_lookup_generic(n, dir);
744 static void flow_entry_get_extended_revdns(struct flow_entry *n,
745 enum flow_direction dir)
747 size_t sa_len;
748 struct sockaddr_in sa4;
749 struct sockaddr_in6 sa6;
750 struct sockaddr *sa;
751 struct hostent *hent;
753 build_bug_on(sizeof(n->rev_dns_src) != sizeof(n->rev_dns_dst));
755 switch (n->l3_proto) {
756 default:
757 bug();
759 case AF_INET:
760 flow_entry_get_sain4_obj(n, dir, &sa4);
762 if (!resolve_dns) {
763 inet_ntop(AF_INET, &sa4.sin_addr,
764 SELFLD(dir, rev_dns_src, rev_dns_dst),
765 sizeof(n->rev_dns_src));
766 return;
769 sa = (struct sockaddr *) &sa4;
770 sa_len = sizeof(sa4);
771 hent = gethostbyaddr(&sa4.sin_addr, sizeof(sa4.sin_addr), AF_INET);
772 break;
774 case AF_INET6:
775 flow_entry_get_sain6_obj(n, dir, &sa6);
777 if (!resolve_dns) {
778 inet_ntop(AF_INET6, &sa6.sin6_addr,
779 SELFLD(dir, rev_dns_src, rev_dns_dst),
780 sizeof(n->rev_dns_src));
781 return;
784 sa = (struct sockaddr *) &sa6;
785 sa_len = sizeof(sa6);
786 hent = gethostbyaddr(&sa6.sin6_addr, sizeof(sa6.sin6_addr), AF_INET6);
787 break;
790 getnameinfo(sa, sa_len, SELFLD(dir, rev_dns_src, rev_dns_dst),
791 sizeof(n->rev_dns_src), NULL, 0, NI_NUMERICHOST);
793 if (hent)
794 strlcpy(SELFLD(dir, rev_dns_src, rev_dns_dst), hent->h_name,
795 sizeof(n->rev_dns_src));
798 static void flow_entry_get_extended(struct flow_entry *n)
800 if (n->flow_id == 0)
801 return;
803 flow_entry_get_extended_revdns(n, FLOW_DIR_SRC);
804 flow_entry_get_extended_geo(n, FLOW_DIR_SRC);
806 flow_entry_get_extended_revdns(n, FLOW_DIR_DST);
807 flow_entry_get_extended_geo(n, FLOW_DIR_DST);
809 /* Lookup application */
810 n->inode = get_port_inode(n->port_src, n->l4_proto,
811 n->l3_proto == AF_INET6);
812 if (n->inode > 0)
813 walk_processes(n);
816 static char *bandw2str(double bytes, char *buf, size_t len)
818 if (bytes <= 0) {
819 buf[0] = '\0';
820 return buf;
823 if (bytes > 1000000000.)
824 snprintf(buf, len, "%.1fGB", bytes / 1000000000.);
825 else if (bytes > 1000000.)
826 snprintf(buf, len, "%.1fMB", bytes / 1000000.);
827 else if (bytes > 1000.)
828 snprintf(buf, len, "%.1fkB", bytes / 1000.);
829 else
830 snprintf(buf, len, "%.0f", bytes);
832 return buf;
835 static char *rate2str(double rate, char *buf, size_t len)
837 const char * const unit_fmt[2][4] = {
838 { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%.0fbit/s" },
839 { "%.1fGB/s", "%.1fMB/s", "%.1fkB/s", "%.0fB/s" }
842 if (rate <= 0) {
843 buf[0] = '\0';
844 return buf;
847 if (rate_type == RATE_BITS)
848 rate *= 8;
850 if (rate > 1000000000.)
851 snprintf(buf, len, unit_fmt[rate_type][0], rate / 1000000000.);
852 else if (rate > 1000000.)
853 snprintf(buf, len, unit_fmt[rate_type][1], rate / 1000000.);
854 else if (rate > 1000.)
855 snprintf(buf, len, unit_fmt[rate_type][2], rate / 1000.);
856 else
857 snprintf(buf, len, unit_fmt[rate_type][3], rate);
859 return buf;
862 static char *time2str(uint64_t tstamp, char *str, size_t len)
864 time_t now;
865 int v, s;
867 time(&now);
869 s = now - (tstamp ? (tstamp / NSEC_PER_SEC) : now);
870 if (s <= 0) {
871 str[0] = '\0';
872 return str;
875 v = s / (3600 * 24);
876 if (v > 0) {
877 slprintf(str, len, "%dd", v);
878 return str;
881 v = s / 3600;
882 if (v > 0) {
883 slprintf(str, len, "%dh", v);
884 return str;
887 v = s / 60;
888 if (v > 0) {
889 slprintf(str, len, "%dm", v);
890 return str;
893 slprintf(str, len, "%ds", s);
894 return str;
898 static const char *flow_state2str(const struct flow_entry *n)
900 switch (n->l4_proto) {
901 case IPPROTO_TCP:
902 return tcp_state2str[n->tcp_state];
903 case IPPROTO_SCTP:
904 return sctp_state2str[n->sctp_state];
905 case IPPROTO_DCCP:
906 return dccp_state2str[n->dccp_state];
908 case IPPROTO_UDP:
909 case IPPROTO_UDPLITE:
910 case IPPROTO_ICMP:
911 case IPPROTO_ICMPV6:
912 default:
913 return "";
917 static char *flow_port2str(const struct flow_entry *n, char *str, size_t len,
918 enum flow_direction dir)
920 const char *tmp = NULL;
921 uint16_t port = 0;
923 port = SELFLD(dir, port_src, port_dst);
924 tmp = NULL;
926 switch (n->l4_proto) {
927 case IPPROTO_TCP:
928 tmp = lookup_port_tcp(port);
929 break;
930 case IPPROTO_UDP:
931 case IPPROTO_UDPLITE:
932 tmp = lookup_port_udp(port);
933 break;
936 if (!tmp && port)
937 slprintf(str, len, "%d", port);
938 else
939 slprintf(str, len, "%s", tmp ? tmp : "");
941 return str;
944 static void print_flow_peer_info(const struct flow_entry *n, enum flow_direction dir)
946 int counters_color = COLOR(YELLOW, BLACK);
947 int src_color = COLOR(RED, BLACK);
948 int dst_color = COLOR(BLUE, BLACK);
949 int country_color = COLOR(GREEN, BLACK);
950 int addr_color = dst_color;
951 int port_color = A_BOLD;
952 char tmp[128];
954 if (show_src && dir == FLOW_DIR_SRC) {
955 country_color = src_color;
956 counters_color = src_color;
957 port_color |= src_color;
958 addr_color = src_color;
959 } else if (show_src && FLOW_DIR_DST) {
960 country_color = dst_color;
961 counters_color = dst_color;
962 port_color |= dst_color;
963 addr_color = dst_color;
966 ui_table_col_color_set(&flows_tbl, TBL_FLOW_ADDRESS, addr_color);
967 ui_table_col_color_set(&flows_tbl, TBL_FLOW_PORT, port_color);
968 ui_table_col_color_set(&flows_tbl, TBL_FLOW_GEO, country_color);
969 ui_table_col_color_set(&flows_tbl, TBL_FLOW_BYTES, counters_color);
970 ui_table_col_color_set(&flows_tbl, TBL_FLOW_RATE, counters_color);
972 /* Reverse DNS/IP */
973 ui_table_row_print(&flows_tbl, TBL_FLOW_ADDRESS,
974 SELFLD(dir, rev_dns_src, rev_dns_dst));
976 /* Application port */
977 ui_table_row_print(&flows_tbl, TBL_FLOW_PORT,
978 flow_port2str(n, tmp, sizeof(tmp), dir));
980 /* GEO */
981 ui_table_row_print(&flows_tbl, TBL_FLOW_GEO,
982 SELFLD(dir, country_code_src, country_code_dst));
984 /* Bytes */
985 ui_table_row_print(&flows_tbl, TBL_FLOW_BYTES,
986 bandw2str(SELFLD(dir, bytes_src, bytes_dst),
987 tmp, sizeof(tmp) - 1));
989 /* Rate bytes */
990 ui_table_row_print(&flows_tbl, TBL_FLOW_RATE,
991 rate2str(SELFLD(dir, rate_bytes_src, rate_bytes_dst),
992 tmp, sizeof(tmp) - 1));
995 static void draw_flow_entry(WINDOW *scr, const struct flow_entry *n, int line)
997 char tmp[128];
999 ui_table_row_add(&flows_tbl);
1001 /* Application */
1002 ui_table_row_print(&flows_tbl, TBL_FLOW_PROCESS, n->procname);
1004 /* PID */
1005 slprintf(tmp, sizeof(tmp), "%.d", n->procnum);
1006 ui_table_row_print(&flows_tbl, TBL_FLOW_PID, tmp);
1008 /* L4 protocol */
1009 ui_table_row_print(&flows_tbl, TBL_FLOW_PROTO, l4proto2str[n->l4_proto]);
1011 /* L4 protocol state */
1012 ui_table_row_print(&flows_tbl, TBL_FLOW_STATE, flow_state2str(n));
1014 /* Time */
1015 time2str(n->timestamp_start, tmp, sizeof(tmp));
1016 ui_table_row_print(&flows_tbl, TBL_FLOW_TIME, tmp);
1018 print_flow_peer_info(n, show_src ? FLOW_DIR_SRC : FLOW_DIR_DST);
1020 if (show_src) {
1021 ui_table_row_add(&flows_tbl);
1023 print_flow_peer_info(n, FLOW_DIR_DST);
1027 static inline bool presenter_flow_wrong_state(struct flow_entry *n)
1029 switch (n->l4_proto) {
1030 case IPPROTO_TCP:
1031 switch (n->tcp_state) {
1032 case TCP_CONNTRACK_SYN_SENT:
1033 case TCP_CONNTRACK_SYN_RECV:
1034 case TCP_CONNTRACK_ESTABLISHED:
1035 case TCP_CONNTRACK_FIN_WAIT:
1036 case TCP_CONNTRACK_CLOSE_WAIT:
1037 case TCP_CONNTRACK_LAST_ACK:
1038 case TCP_CONNTRACK_TIME_WAIT:
1039 case TCP_CONNTRACK_CLOSE:
1040 case TCP_CONNTRACK_SYN_SENT2:
1041 case TCP_CONNTRACK_NONE:
1042 return false;
1043 break;
1045 break;
1046 case IPPROTO_SCTP:
1047 switch (n->sctp_state) {
1048 case SCTP_CONNTRACK_NONE:
1049 case SCTP_CONNTRACK_CLOSED:
1050 case SCTP_CONNTRACK_COOKIE_WAIT:
1051 case SCTP_CONNTRACK_COOKIE_ECHOED:
1052 case SCTP_CONNTRACK_ESTABLISHED:
1053 case SCTP_CONNTRACK_SHUTDOWN_SENT:
1054 case SCTP_CONNTRACK_SHUTDOWN_RECD:
1055 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT:
1056 return false;
1057 break;
1059 break;
1060 case IPPROTO_DCCP:
1061 switch (n->dccp_state) {
1062 case DCCP_CONNTRACK_NONE:
1063 case DCCP_CONNTRACK_REQUEST:
1064 case DCCP_CONNTRACK_RESPOND:
1065 case DCCP_CONNTRACK_PARTOPEN:
1066 case DCCP_CONNTRACK_OPEN:
1067 case DCCP_CONNTRACK_CLOSEREQ:
1068 case DCCP_CONNTRACK_CLOSING:
1069 case DCCP_CONNTRACK_TIMEWAIT:
1070 case DCCP_CONNTRACK_IGNORE:
1071 case DCCP_CONNTRACK_INVALID:
1072 return false;
1073 break;
1075 break;
1076 case IPPROTO_UDP:
1077 case IPPROTO_UDPLITE:
1078 case IPPROTO_ICMP:
1079 case IPPROTO_ICMPV6:
1080 return false;
1081 break;
1084 return true;
1087 static void draw_flows(WINDOW *screen, struct flow_list *fl,
1088 int skip_lines)
1090 int row_width = show_src ? 2 : 1;
1091 unsigned int flows = 0;
1092 unsigned int line = 4;
1093 int skip = skip_lines;
1094 struct flow_entry *n;
1096 wclear(screen);
1097 clear();
1099 rcu_read_lock();
1101 n = rcu_dereference(fl->head);
1102 if (!n)
1103 mvwprintw(screen, line, 2, "(No sessions! "
1104 "Is netfilter running?)");
1106 ui_table_clear(&flows_tbl);
1107 ui_table_header_print(&flows_tbl);
1109 for (; n; n = rcu_dereference(n->next)) {
1110 if (!n->is_visible)
1111 continue;
1112 if (presenter_flow_wrong_state(n))
1113 continue;
1115 /* count only flows which might be showed */
1116 flows++;
1118 if (line + row_width >= rows)
1119 continue;
1120 if (--skip >= 0)
1121 continue;
1123 draw_flow_entry(screen, n, line);
1124 line += row_width;
1127 mvwprintw(screen, 1, 2, "Kernel netfilter flows(%u) for ", flows);
1129 if (what & INCLUDE_IPV4)
1130 printw("IPv4,");
1131 if (what & INCLUDE_IPV6)
1132 printw("IPv6,");
1133 if (what & INCLUDE_TCP)
1134 printw("TCP,");
1135 if (what & INCLUDE_UDP)
1136 printw("UDP,");
1137 if (what & INCLUDE_SCTP)
1138 printw("SCTP,");
1139 if (what & INCLUDE_DCCP)
1140 printw("DCCP,");
1141 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1142 printw("ICMP,");
1143 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1144 printw("ICMP6,");
1145 if (show_active_only)
1146 printw("Active,");
1148 printw(" [+%d]", skip_lines);
1150 if (is_flow_collecting)
1151 printw(" [Collecting flows ...]");
1153 rcu_read_unlock();
1156 static void draw_help(WINDOW *screen)
1158 int col = 0;
1159 int row = 1;
1160 int i;
1162 mvaddch(row, col, ACS_ULCORNER);
1163 mvaddch(rows - row - 1, col, ACS_LLCORNER);
1165 mvaddch(row, cols - 1, ACS_URCORNER);
1166 mvaddch(rows - row - 1, cols - 1, ACS_LRCORNER);
1168 for (i = 1; i < rows - row - 2; i++) {
1169 mvaddch(row + i, 0, ACS_VLINE);
1170 mvaddch(row + i, cols - 1, ACS_VLINE);
1172 for (i = 1; i < cols - col - 1; i++) {
1173 mvaddch(row, col + i, ACS_HLINE);
1174 mvaddch(rows - row - 1, col + i, ACS_HLINE);
1177 attron(A_BOLD);
1178 mvaddnstr(row, cols / 2 - 2, "| Help |", -1);
1180 attron(A_UNDERLINE);
1181 mvaddnstr(row + 2, col + 2, "Navigation", -1);
1182 attroff(A_BOLD | A_UNDERLINE);
1184 mvaddnstr(row + 4, col + 3, "Up, u, k Move up", -1);
1185 mvaddnstr(row + 5, col + 3, "Down, d, j Move down", -1);
1186 mvaddnstr(row + 6, col + 3, "? Toggle help window", -1);
1187 mvaddnstr(row + 7, col + 3, "q, Ctrl+C Quit", -1);
1189 attron(A_BOLD | A_UNDERLINE);
1190 mvaddnstr(row + 9, col + 2, "Display Settings", -1);
1191 attroff(A_BOLD | A_UNDERLINE);
1193 mvaddnstr(row + 11, col + 3, "b Toggle rate units (bits/bytes)", -1);
1194 mvaddnstr(row + 12, col + 3, "a Toggle display of active flows (rate > 0) only", -1);
1195 mvaddnstr(row + 13, col + 3, "s Toggle show source peer info", -1);
1197 mvaddnstr(row + 15, col + 3, "T Toggle display TCP flows", -1);
1198 mvaddnstr(row + 16, col + 3, "U Toggle display UDP flows", -1);
1199 mvaddnstr(row + 17, col + 3, "D Toggle display DCCP flows", -1);
1200 mvaddnstr(row + 18, col + 3, "I Toggle display ICMP flows", -1);
1201 mvaddnstr(row + 19, col + 3, "S Toggle display SCTP flows", -1);
1204 static void draw_header(WINDOW *screen)
1206 int i;
1208 attron(A_STANDOUT);
1210 for (i = 0; i < cols; i++)
1211 mvaddch(0, i, ' ');
1213 mvwprintw(screen, 0, 2, "flowtop %s", VERSION_LONG);
1214 attroff(A_STANDOUT);
1217 static void draw_footer(WINDOW *screen)
1219 int i;
1221 attron(A_STANDOUT);
1223 for (i = 0; i < cols; i++)
1224 mvaddch(rows - 1, i, ' ');
1226 mvaddnstr(rows - 1, 1, "Press '?' for help", -1);
1227 addch(ACS_VLINE);
1228 attroff(A_STANDOUT);
1231 static void show_option_toggle(int opt)
1233 switch (opt) {
1234 case 'T':
1235 TOGGLE_FLAG(what, INCLUDE_TCP);
1236 break;
1237 case 'U':
1238 TOGGLE_FLAG(what, INCLUDE_UDP);
1239 break;
1240 case 'D':
1241 TOGGLE_FLAG(what, INCLUDE_DCCP);
1242 break;
1243 case 'I':
1244 TOGGLE_FLAG(what, INCLUDE_ICMP);
1245 break;
1246 case 'S':
1247 TOGGLE_FLAG(what, INCLUDE_SCTP);
1248 break;
1252 static void flows_table_init(struct ui_table *tbl)
1254 ui_table_init(tbl);
1256 ui_table_pos_set(tbl, 3, 0);
1258 ui_table_col_add(tbl, TBL_FLOW_PROCESS, "PROCESS", 13);
1259 ui_table_col_add(tbl, TBL_FLOW_PID, "PID", 7);
1260 ui_table_col_add(tbl, TBL_FLOW_PROTO, "PROTO", 6);
1261 ui_table_col_add(tbl, TBL_FLOW_STATE, "STATE", 11);
1262 ui_table_col_add(tbl, TBL_FLOW_TIME, "TIME", 4);
1263 ui_table_col_add(tbl, TBL_FLOW_ADDRESS, "ADDRESS", 50);
1264 ui_table_col_add(tbl, TBL_FLOW_PORT, "PORT", 8);
1265 ui_table_col_add(tbl, TBL_FLOW_GEO, "GEO", 3);
1266 ui_table_col_add(tbl, TBL_FLOW_BYTES, "BYTES", 10);
1267 ui_table_col_add(tbl, TBL_FLOW_RATE, "RATE", 10);
1269 ui_table_col_align_set(tbl, TBL_FLOW_TIME, UI_ALIGN_RIGHT);
1270 ui_table_col_align_set(tbl, TBL_FLOW_BYTES, UI_ALIGN_RIGHT);
1271 ui_table_col_align_set(tbl, TBL_FLOW_RATE, UI_ALIGN_RIGHT);
1273 ui_table_col_color_set(tbl, TBL_FLOW_PROCESS, COLOR(YELLOW, BLACK));
1274 ui_table_col_color_set(tbl, TBL_FLOW_PID, A_BOLD);
1275 ui_table_col_color_set(tbl, TBL_FLOW_STATE, COLOR(YELLOW, BLACK));
1277 ui_table_header_color_set(&flows_tbl, COLOR(BLACK, GREEN));
1280 static void presenter(void)
1282 int time_sleep_us = 200000;
1283 int time_passed_us = 0;
1284 bool show_help = false;
1285 int skip_lines = 0;
1286 WINDOW *screen;
1288 lookup_init(LT_PORTS_TCP);
1289 lookup_init(LT_PORTS_UDP);
1290 screen = screen_init(false);
1292 start_color();
1293 INIT_COLOR(RED, BLACK);
1294 INIT_COLOR(BLUE, BLACK);
1295 INIT_COLOR(YELLOW, BLACK);
1296 INIT_COLOR(GREEN, BLACK);
1297 INIT_COLOR(BLACK, GREEN);
1299 flows_table_init(&flows_tbl);
1301 rcu_register_thread();
1302 while (!sigint) {
1303 bool redraw_flows = true;
1304 int ch;
1306 curs_set(0);
1307 getmaxyx(screen, rows, cols);
1309 ch = getch();
1310 switch (ch) {
1311 case 'q':
1312 sigint = 1;
1313 break;
1314 case KEY_UP:
1315 case 'u':
1316 case 'k':
1317 skip_lines--;
1318 if (skip_lines < 0)
1319 skip_lines = 0;
1320 break;
1321 case KEY_DOWN:
1322 case 'd':
1323 case 'j':
1324 skip_lines++;
1325 if (skip_lines > SCROLL_MAX)
1326 skip_lines = SCROLL_MAX;
1327 break;
1328 case 'b':
1329 if (rate_type == RATE_BYTES)
1330 rate_type = RATE_BITS;
1331 else
1332 rate_type = RATE_BYTES;
1333 break;
1334 case 'a':
1335 show_active_only = !show_active_only;
1336 break;
1337 case 's':
1338 show_src = !show_src;
1339 break;
1340 case '?':
1341 show_help = !show_help;
1342 wclear(screen);
1343 clear();
1344 break;
1345 case 'T':
1346 case 'U':
1347 case 'D':
1348 case 'I':
1349 case 'S':
1350 show_option_toggle(ch);
1351 do_reload_flows = true;
1352 break;
1353 default:
1354 fflush(stdin);
1355 redraw_flows = false;
1356 break;
1359 if (!redraw_flows)
1360 redraw_flows = time_passed_us >= 1 * USEC_PER_SEC;
1362 if (show_help)
1363 redraw_flows = false;
1365 if (redraw_flows) {
1366 draw_flows(screen, &flow_list, skip_lines);
1367 time_passed_us = 0;
1368 } else {
1369 time_passed_us += time_sleep_us;
1372 draw_header(screen);
1374 if (show_help)
1375 draw_help(screen);
1377 draw_footer(screen);
1379 wrefresh(screen);
1380 refresh();
1381 usleep(time_sleep_us);
1383 rcu_unregister_thread();
1385 ui_table_uninit(&flows_tbl);
1387 screen_end();
1388 lookup_cleanup(LT_PORTS_UDP);
1389 lookup_cleanup(LT_PORTS_TCP);
1392 static void restore_sysctl(void *obj)
1394 struct sysctl_params_ctx *sysctl_ctx = obj;
1396 if (sysctl_ctx->nfct_acct == 0)
1397 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1398 sysctl_ctx->nfct_acct);
1400 if (sysctl_ctx->nfct_tstamp == 0)
1401 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1402 sysctl_ctx->nfct_tstamp);
1405 static void on_panic_handler(void *arg)
1407 restore_sysctl(arg);
1408 screen_end();
1411 static void conntrack_acct_enable(void)
1413 /* We can still work w/o traffic accounting so just warn about error */
1414 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl.nfct_acct)) {
1415 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1416 strerror(errno));
1417 return;
1420 if (sysctl.nfct_acct == 1)
1421 return;
1423 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1424 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1425 strerror(errno));
1429 static void conntrack_tstamp_enable(void)
1431 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl.nfct_tstamp)) {
1432 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1433 strerror(errno));
1434 return;
1437 if (sysctl.nfct_tstamp == 1)
1438 return;
1440 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1441 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1442 strerror(errno));
1446 static void flow_entry_filter(struct flow_entry *n)
1448 if (show_active_only && !n->rate_bytes_src && !n->rate_bytes_dst)
1449 n->is_visible = false;
1450 else
1451 n->is_visible = true;
1454 static int flow_list_update_entry(struct flow_list *fl, struct nf_conntrack *ct)
1456 struct flow_entry *n;
1458 n = flow_list_find_id(&flow_list, nfct_get_attr_u32(ct, ATTR_ID));
1459 if (!n)
1460 return NFCT_CB_CONTINUE;
1462 flow_entry_calc_rate(n, ct);
1463 flow_entry_update_time(n);
1464 flow_entry_from_ct(n, ct);
1465 flow_entry_filter(n);
1467 return NFCT_CB_CONTINUE;
1470 static int flow_event_cb(enum nf_conntrack_msg_type type,
1471 struct nf_conntrack *ct, void *data __maybe_unused)
1473 if (sigint)
1474 return NFCT_CB_STOP;
1476 synchronize_rcu();
1477 spinlock_lock(&flow_list.lock);
1479 switch (type) {
1480 case NFCT_T_NEW:
1481 flow_list_new_entry(&flow_list, ct);
1482 break;
1483 case NFCT_T_UPDATE:
1484 flow_list_update_entry(&flow_list, ct);
1485 break;
1486 case NFCT_T_DESTROY:
1487 flow_list_destroy_entry(&flow_list, ct);
1488 break;
1489 default:
1490 break;
1493 spinlock_unlock(&flow_list.lock);
1495 if (sigint)
1496 return NFCT_CB_STOP;
1498 return NFCT_CB_CONTINUE;
1501 static void collector_refresh_flows(struct nfct_handle *handle)
1503 struct flow_entry *n;
1505 n = rcu_dereference(flow_list.head);
1506 for (; n; n = rcu_dereference(n->next))
1507 nfct_query(handle, NFCT_Q_GET, n->ct);
1510 static void collector_create_filter(struct nfct_handle *nfct)
1512 struct nfct_filter *filter;
1513 int ret;
1515 filter = nfct_filter_create();
1516 if (!filter)
1517 panic("Cannot create a nfct filter: %s\n", strerror(errno));
1519 if (what & INCLUDE_UDP) {
1520 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
1521 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDPLITE);
1523 if (what & INCLUDE_TCP)
1524 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
1525 if (what & INCLUDE_DCCP)
1526 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_DCCP);
1527 if (what & INCLUDE_SCTP)
1528 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_SCTP);
1529 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1530 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMP);
1531 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1532 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMPV6);
1533 if (what & INCLUDE_IPV4) {
1534 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV4, NFCT_FILTER_LOGIC_NEGATIVE);
1535 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
1537 if (what & INCLUDE_IPV6) {
1538 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV6, NFCT_FILTER_LOGIC_NEGATIVE);
1539 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV6, &filter_ipv6);
1542 ret = nfct_filter_attach(nfct_fd(nfct), filter);
1543 if (ret < 0)
1544 panic("Cannot attach filter to handle: %s\n", strerror(errno));
1546 nfct_filter_destroy(filter);
1549 /* This hand-crafted filter looks ugly but it allows to do not
1550 * flush nfct connections & filter them by user specified filter.
1551 * May be it is better to replace this one by nfct_cmp. */
1552 static int flow_dump_cb(enum nf_conntrack_msg_type type,
1553 struct nf_conntrack *ct, void *data __maybe_unused)
1555 struct flow_entry fl;
1556 struct flow_entry *n = &fl;
1558 if (sigint)
1559 return NFCT_CB_STOP;
1561 synchronize_rcu();
1562 spinlock_lock(&flow_list.lock);
1564 if (!(what & ~(INCLUDE_IPV4 | INCLUDE_IPV6)))
1565 goto check_addr;
1567 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
1569 if (what & INCLUDE_UDP) {
1570 if (n->l4_proto == IPPROTO_UDP)
1571 goto check_addr;
1573 if (n->l4_proto == IPPROTO_UDPLITE)
1574 goto check_addr;
1577 if ((what & INCLUDE_TCP) && n->l4_proto == IPPROTO_TCP)
1578 goto check_addr;
1580 if ((what & INCLUDE_DCCP) && n->l4_proto == IPPROTO_DCCP)
1581 goto check_addr;
1583 if ((what & INCLUDE_SCTP) && n->l4_proto == IPPROTO_SCTP)
1584 goto check_addr;
1586 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV4) &&
1587 n->l4_proto == IPPROTO_ICMP) {
1588 goto check_addr;
1591 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV6) &&
1592 n->l4_proto == IPPROTO_ICMPV6) {
1593 goto check_addr;
1596 goto skip_flow;
1598 check_addr:
1599 /* filter loopback addresses */
1600 if (what & INCLUDE_IPV4) {
1601 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
1603 if (n->ip4_src_addr == filter_ipv4.addr)
1604 goto skip_flow;
1606 if (what & INCLUDE_IPV6) {
1607 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
1609 if (n->ip6_src_addr[0] == 0x0 &&
1610 n->ip6_src_addr[1] == 0x0 &&
1611 n->ip6_src_addr[2] == 0x0 &&
1612 n->ip6_src_addr[3] == 0x1)
1613 goto skip_flow;
1616 flow_list_new_entry(&flow_list, ct);
1618 skip_flow:
1619 spinlock_unlock(&flow_list.lock);
1620 return NFCT_CB_CONTINUE;
1623 static void collector_dump_flows(void)
1625 struct nfct_handle *nfct = nfct_open(CONNTRACK, 0);
1627 if (!nfct)
1628 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1630 nfct_callback_register(nfct, NFCT_T_ALL, flow_dump_cb, NULL);
1632 is_flow_collecting = true;
1633 if (what & INCLUDE_IPV4) {
1634 int family = AF_INET;
1635 nfct_query(nfct, NFCT_Q_DUMP, &family);
1637 if (what & INCLUDE_IPV6) {
1638 int family = AF_INET6;
1639 nfct_query(nfct, NFCT_Q_DUMP, &family);
1641 is_flow_collecting = false;
1643 nfct_close(nfct);
1646 static void *collector(void *null __maybe_unused)
1648 struct nfct_handle *ct_event;
1649 struct pollfd poll_fd[1];
1651 flow_list_init(&flow_list);
1653 ct_event = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW |
1654 NF_NETLINK_CONNTRACK_UPDATE |
1655 NF_NETLINK_CONNTRACK_DESTROY);
1656 if (!ct_event)
1657 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1659 collector_create_filter(ct_event);
1661 nfct_callback_register(ct_event, NFCT_T_ALL, flow_event_cb, NULL);
1663 poll_fd[0].fd = nfct_fd(ct_event);
1664 poll_fd[0].events = POLLIN;
1666 if (fcntl(nfct_fd(ct_event), F_SETFL, O_NONBLOCK) == -1)
1667 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1668 strerror(errno));
1670 rcu_register_thread();
1672 collector_dump_flows();
1674 while (!sigint) {
1675 int status;
1677 if (!do_reload_flows) {
1678 usleep(USEC_PER_SEC * interval);
1679 } else {
1680 do_reload_flows = false;
1682 flow_list_destroy(&flow_list);
1684 collector_create_filter(ct_event);
1685 collector_dump_flows();
1688 collector_refresh_flows(ct_event);
1690 status = poll(poll_fd, 1, 0);
1691 if (status < 0) {
1692 if (errno == EAGAIN || errno == EINTR)
1693 continue;
1695 panic("Error while polling: %s\n", strerror(errno));
1696 } else if (status == 0) {
1697 continue;
1700 if (poll_fd[0].revents & POLLIN)
1701 nfct_catch(ct_event);
1704 rcu_unregister_thread();
1706 flow_list_destroy(&flow_list);
1707 spinlock_destroy(&flow_list.lock);
1709 nfct_close(ct_event);
1711 pthread_exit(NULL);
1714 int main(int argc, char **argv)
1716 pthread_t tid;
1717 int ret, c, opt_index, what_cmd = 0;
1719 setfsuid(getuid());
1720 setfsgid(getgid());
1722 while ((c = getopt_long(argc, argv, short_options, long_options,
1723 &opt_index)) != EOF) {
1724 switch (c) {
1725 case '4':
1726 what_cmd |= INCLUDE_IPV4;
1727 break;
1728 case '6':
1729 what_cmd |= INCLUDE_IPV6;
1730 break;
1731 case 'T':
1732 what_cmd |= INCLUDE_TCP;
1733 break;
1734 case 'U':
1735 what_cmd |= INCLUDE_UDP;
1736 break;
1737 case 'D':
1738 what_cmd |= INCLUDE_DCCP;
1739 break;
1740 case 'I':
1741 what_cmd |= INCLUDE_ICMP;
1742 break;
1743 case 'S':
1744 what_cmd |= INCLUDE_SCTP;
1745 break;
1746 case 's':
1747 show_src = true;
1748 break;
1749 case 'b':
1750 rate_type = RATE_BITS;
1751 break;
1752 case 'u':
1753 update_geoip();
1754 die();
1755 break;
1756 case 't':
1757 interval = strtoul(optarg, NULL, 10);
1758 break;
1759 case 'n':
1760 resolve_dns = false;
1761 break;
1762 case 'G':
1763 resolve_geoip = false;
1764 break;
1765 case 'h':
1766 help();
1767 break;
1768 case 'v':
1769 version();
1770 break;
1771 default:
1772 break;
1776 if (what_cmd > 0) {
1777 what = what_cmd;
1779 if (!(what & (INCLUDE_IPV4 | INCLUDE_IPV6)))
1780 what |= INCLUDE_IPV4 | INCLUDE_IPV6;
1783 rcu_init();
1785 register_signal(SIGINT, signal_handler);
1786 register_signal(SIGQUIT, signal_handler);
1787 register_signal(SIGTERM, signal_handler);
1788 register_signal(SIGHUP, signal_handler);
1790 panic_handler_add(on_panic_handler, &sysctl);
1792 conntrack_acct_enable();
1793 conntrack_tstamp_enable();
1795 if (resolve_geoip)
1796 init_geoip(1);
1798 ret = pthread_create(&tid, NULL, collector, NULL);
1799 if (ret < 0)
1800 panic("Cannot create phthread!\n");
1802 presenter();
1804 if (resolve_geoip)
1805 destroy_geoip();
1807 restore_sysctl(&sysctl);
1809 return 0;