mausezahn: use getopt_long instead of getopt
[netsniff-ng.git] / flowtop.c
blob62ce14d95e6569a403768f330aa275d4d6be7887
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 <sys/time.h>
21 #include <sys/fsuid.h>
22 #include <libgen.h>
23 #include <inttypes.h>
24 #include <poll.h>
25 #include <fcntl.h>
26 #include <arpa/inet.h>
28 #include <urcu.h>
29 #include <urcu/list.h>
30 #include <urcu/rculist.h>
32 #include "ui.h"
33 #include "die.h"
34 #include "xmalloc.h"
35 #include "conntrack.h"
36 #include "config.h"
37 #include "str.h"
38 #include "sig.h"
39 #include "lookup.h"
40 #include "geoip.h"
41 #include "built_in.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_stat {
56 uint64_t pkts_src, bytes_src;
57 uint64_t pkts_dst, bytes_dst;
58 double rate_bytes_src;
59 double rate_bytes_dst;
60 double rate_pkts_src;
61 double rate_pkts_dst;
64 struct proc_entry {
65 struct cds_list_head entry;
66 struct cds_list_head flows;
67 struct rcu_head rcu;
69 struct timeval last_update;
70 struct flow_stat stat;
71 unsigned int pid;
72 char name[256];
73 int flows_count;
76 struct flow_entry {
77 struct cds_list_head proc_head;
78 struct cds_list_head entry;
79 struct rcu_head rcu;
81 uint32_t flow_id, use, status;
82 uint8_t l3_proto, l4_proto;
83 uint32_t ip4_src_addr, ip4_dst_addr;
84 uint32_t ip6_src_addr[4], ip6_dst_addr[4];
85 uint16_t port_src, port_dst;
86 uint8_t tcp_state, tcp_flags, sctp_state, dccp_state;
87 uint64_t timestamp_start, timestamp_stop;
88 char country_src[128], country_dst[128];
89 char country_code_src[4], country_code_dst[4];
90 char city_src[128], city_dst[128];
91 char rev_dns_src[256], rev_dns_dst[256];
92 struct proc_entry *proc;
93 int inode;
94 bool is_visible;
95 struct nf_conntrack *ct;
96 struct timeval last_update;
97 struct flow_stat stat;
100 struct flow_list {
101 struct cds_list_head head;
104 struct proc_list {
105 struct cds_list_head head;
108 enum flow_direction {
109 FLOW_DIR_SRC,
110 FLOW_DIR_DST,
113 #ifndef ATTR_TIMESTAMP_START
114 # define ATTR_TIMESTAMP_START 63
115 #endif
116 #ifndef ATTR_TIMESTAMP_STOP
117 # define ATTR_TIMESTAMP_STOP 64
118 #endif
120 #define INCLUDE_IPV4 (1 << 0)
121 #define INCLUDE_IPV6 (1 << 1)
122 #define INCLUDE_UDP (1 << 2)
123 #define INCLUDE_TCP (1 << 3)
124 #define INCLUDE_DCCP (1 << 4)
125 #define INCLUDE_ICMP (1 << 5)
126 #define INCLUDE_SCTP (1 << 6)
128 #define TOGGLE_FLAG(what, flag) \
129 do { \
130 if (what & flag) \
131 what &= ~flag; \
132 else \
133 what |= flag; \
134 } while (0)
136 struct sysctl_params_ctx {
137 int nfct_acct;
138 int nfct_tstamp;
141 enum rate_units {
142 RATE_BITS,
143 RATE_BYTES
146 static volatile bool do_reload_flows;
147 static volatile bool is_flow_collecting;
148 static volatile sig_atomic_t sigint = 0;
149 static int what = INCLUDE_IPV4 | INCLUDE_IPV6 | INCLUDE_TCP;
150 static struct proc_list proc_list;
151 static struct flow_list flow_list;
152 static struct sysctl_params_ctx sysctl = { -1, -1 };
154 static unsigned int cols, rows;
155 static WINDOW *screen;
157 static unsigned int interval = 1;
158 static bool show_src = false;
159 static bool resolve_dns = true;
160 static bool resolve_geoip = true;
161 static enum rate_units rate_type = RATE_BYTES;
162 static bool show_active_only = false;
164 enum tbl_flow_col {
165 TBL_FLOW_PROCESS,
166 TBL_FLOW_PID,
167 TBL_FLOW_PROTO,
168 TBL_FLOW_STATE,
169 TBL_FLOW_TIME,
170 TBL_FLOW_ADDRESS,
171 TBL_FLOW_PORT,
172 TBL_FLOW_GEO,
173 TBL_FLOW_BYTES,
174 TBL_FLOW_RATE,
177 enum tbl_proc_col {
178 TBL_PROC_NAME,
179 TBL_PROC_PID,
180 TBL_PROC_FLOWS,
181 TBL_PROC_BYTES_SRC,
182 TBL_PROC_RATE_SRC,
183 TBL_PROC_BYTES_DST,
184 TBL_PROC_RATE_DST,
187 static struct ui_table flows_tbl;
188 static struct ui_table procs_tbl;
189 static struct ui_table *curr_tbl;
191 enum tab_entry {
192 TAB_FLOWS,
193 TAB_PROCS,
196 #define list_first_or_next(__ptr, __head, __entry) \
197 ({ \
198 struct cds_list_head *h; \
199 if (!__ptr) \
200 h = rcu_dereference((__head)->next); \
201 else if (rcu_dereference(__ptr->__entry.next) == (__head)) \
202 return NULL; \
203 else \
204 h = rcu_dereference(__ptr->__entry.next); \
205 cds_list_entry(h, __typeof(* (__ptr)), __entry); \
208 static const char *short_options = "vhTUsDIS46ut:nGb";
209 static const struct option long_options[] = {
210 {"ipv4", no_argument, NULL, '4'},
211 {"ipv6", no_argument, NULL, '6'},
212 {"tcp", no_argument, NULL, 'T'},
213 {"udp", no_argument, NULL, 'U'},
214 {"dccp", no_argument, NULL, 'D'},
215 {"icmp", no_argument, NULL, 'I'},
216 {"sctp", no_argument, NULL, 'S'},
217 {"no-dns", no_argument, NULL, 'n'},
218 {"no-geoip", no_argument, NULL, 'G'},
219 {"show-src", no_argument, NULL, 's'},
220 {"bits", no_argument, NULL, 'b'},
221 {"update", no_argument, NULL, 'u'},
222 {"interval", required_argument, NULL, 't'},
223 {"version", no_argument, NULL, 'v'},
224 {"help", no_argument, NULL, 'h'},
225 {NULL, 0, NULL, 0}
228 static const char *copyright =
229 "Please report bugs at https://github.com/netsniff-ng/netsniff-ng/issues\n"
230 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
231 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
232 "Swiss federal institute of technology (ETH Zurich)\n"
233 "License: GNU GPL version 2.0\n"
234 "This is free software: you are free to change and redistribute it.\n"
235 "There is NO WARRANTY, to the extent permitted by law.";
237 static const char *const l4proto2str[IPPROTO_MAX] = {
238 [IPPROTO_TCP] = "tcp",
239 [IPPROTO_UDP] = "udp",
240 [IPPROTO_UDPLITE] = "udplite",
241 [IPPROTO_ICMP] = "icmp",
242 [IPPROTO_ICMPV6] = "icmpv6",
243 [IPPROTO_SCTP] = "sctp",
244 [IPPROTO_GRE] = "gre",
245 [IPPROTO_DCCP] = "dccp",
246 [IPPROTO_IGMP] = "igmp",
247 [IPPROTO_IPIP] = "ipip",
248 [IPPROTO_EGP] = "egp",
249 [IPPROTO_PUP] = "pup",
250 [IPPROTO_IDP] = "idp",
251 [IPPROTO_RSVP] = "rsvp",
252 [IPPROTO_IPV6] = "ip6tun",
253 [IPPROTO_ESP] = "esp",
254 [IPPROTO_AH] = "ah",
255 [IPPROTO_PIM] = "pim",
256 [IPPROTO_COMP] = "comp",
259 static const char *const tcp_state2str[TCP_CONNTRACK_MAX] = {
260 [TCP_CONNTRACK_NONE] = "NONE",
261 [TCP_CONNTRACK_SYN_SENT] = "SYN-SENT",
262 [TCP_CONNTRACK_SYN_RECV] = "SYN-RECV",
263 [TCP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
264 [TCP_CONNTRACK_FIN_WAIT] = "FIN-WAIT",
265 [TCP_CONNTRACK_CLOSE_WAIT] = "CLOSE-WAIT",
266 [TCP_CONNTRACK_LAST_ACK] = "LAST-ACK",
267 [TCP_CONNTRACK_TIME_WAIT] = "TIME-WAIT",
268 [TCP_CONNTRACK_CLOSE] = "CLOSE",
269 [TCP_CONNTRACK_SYN_SENT2] = "SYN-SENT2",
272 static const char *const dccp_state2str[DCCP_CONNTRACK_MAX] = {
273 [DCCP_CONNTRACK_NONE] = "NONE",
274 [DCCP_CONNTRACK_REQUEST] = "REQUEST",
275 [DCCP_CONNTRACK_RESPOND] = "RESPOND",
276 [DCCP_CONNTRACK_PARTOPEN] = "PARTOPEN",
277 [DCCP_CONNTRACK_OPEN] = "OPEN",
278 [DCCP_CONNTRACK_CLOSEREQ] = "CLOSE-REQ",
279 [DCCP_CONNTRACK_CLOSING] = "CLOSING",
280 [DCCP_CONNTRACK_TIMEWAIT] = "TIME-WAIT",
281 [DCCP_CONNTRACK_IGNORE] = "IGNORE",
282 [DCCP_CONNTRACK_INVALID] = "INVALID",
285 static const char *const sctp_state2str[SCTP_CONNTRACK_MAX] = {
286 [SCTP_CONNTRACK_NONE] = "NONE",
287 [SCTP_CONNTRACK_CLOSED] = "CLOSED",
288 [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE-WAIT",
289 [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE-ECHO",
290 [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
291 [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTD-SENT",
292 [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTD-RCVD",
293 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTD-ACK",
296 static const struct nfct_filter_ipv4 filter_ipv4 = {
297 .addr = __constant_htonl(INADDR_LOOPBACK),
298 .mask = 0xffffffff,
301 static const struct nfct_filter_ipv6 filter_ipv6 = {
302 .addr = { 0x0, 0x0, 0x0, 0x1 },
303 .mask = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
306 static int64_t time_after_us(struct timeval *tv)
308 struct timeval now;
310 bug_on(gettimeofday(&now, NULL));
312 now.tv_sec -= tv->tv_sec;
313 now.tv_usec -= tv->tv_usec;
315 return now.tv_sec * USEC_PER_SEC + now.tv_usec;
318 static void signal_handler(int number)
320 switch (number) {
321 case SIGINT:
322 case SIGQUIT:
323 case SIGTERM:
324 sigint = 1;
325 break;
326 case SIGHUP:
327 default:
328 break;
332 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct);
333 static void flow_entry_get_extended(struct flow_entry *n);
335 static void help(void)
337 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
338 VERSION_STRING);
339 puts("http://www.netsniff-ng.org\n\n"
340 "Usage: flowtop [options]\n"
341 "Options:\n"
342 " -4|--ipv4 Show only IPv4 flows (default)\n"
343 " -6|--ipv6 Show only IPv6 flows (default)\n"
344 " -T|--tcp Show only TCP flows (default)\n"
345 " -U|--udp Show only UDP flows\n"
346 " -D|--dccp Show only DCCP flows\n"
347 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
348 " -S|--sctp Show only SCTP flows\n"
349 " -n|--no-dns Don't perform hostname lookup\n"
350 " -G|--no-geoip Don't perform GeoIP lookup\n"
351 " -s|--show-src Also show source, not only dest\n"
352 " -b|--bits Show rates in bits/s instead of bytes/s\n"
353 " -u|--update Update GeoIP databases\n"
354 " -t|--interval <time> Refresh time in seconds (default 1s)\n"
355 " -v|--version Print version and exit\n"
356 " -h|--help Print this help and exit\n\n"
357 "Examples:\n"
358 " flowtop\n"
359 " flowtop -46UTDISs\n\n"
360 "Note:\n"
361 " If netfilter is not running, you can activate it with e.g.:\n"
362 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
363 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
364 puts(copyright);
365 die();
368 static void version(void)
370 printf("flowtop %s, Git id: %s\n", VERSION_LONG, GITVERSION);
371 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
372 "http://www.netsniff-ng.org\n");
373 puts(copyright);
374 die();
377 static void flow_entry_update_time(struct flow_entry *n)
379 bug_on(gettimeofday(&n->last_update, NULL));
382 #define CALC_RATE(fld) do { \
383 n->stat.rate_##fld = (((fld) > n->stat.fld) ? \
384 (((fld) - n->stat.fld) / sec) : 0); \
385 } while (0)
387 static void flow_entry_calc_rate(struct flow_entry *n, const struct nf_conntrack *ct)
389 uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES);
390 uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES);
391 uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS);
392 uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS);
393 double sec = (double)time_after_us(&n->last_update) / USEC_PER_SEC;
395 if (sec < 1)
396 return;
398 CALC_RATE(bytes_src);
399 CALC_RATE(bytes_dst);
400 CALC_RATE(pkts_src);
401 CALC_RATE(pkts_dst);
404 static inline struct flow_entry *flow_entry_xalloc(void)
406 return xzmalloc(sizeof(struct flow_entry));
409 static inline void flow_entry_xfree(struct flow_entry *n)
411 if (n->ct)
412 nfct_destroy(n->ct);
414 xfree(n);
417 static void flow_entry_xfree_rcu(struct rcu_head *head)
419 struct flow_entry *n = container_of(head, struct flow_entry, rcu);
421 flow_entry_xfree(n);
424 static inline void flow_list_init(struct flow_list *fl)
426 CDS_INIT_LIST_HEAD(&fl->head);
429 static inline bool nfct_is_dns(const struct nf_conntrack *ct)
431 uint16_t port_src = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
432 uint16_t port_dst = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
434 return ntohs(port_src) == 53 || ntohs(port_dst) == 53;
437 static int flow_list_new_entry(struct flow_list *fl, struct nf_conntrack *ct)
439 struct flow_entry *n;
441 /* We don't want to analyze / display DNS itself, since we
442 * use it to resolve reverse dns.
444 if (nfct_is_dns(ct))
445 return NFCT_CB_CONTINUE;
447 n = flow_entry_xalloc();
449 n->ct = ct;
451 flow_entry_update_time(n);
452 flow_entry_from_ct(n, ct);
453 flow_entry_get_extended(n);
455 cds_list_add_rcu(&n->entry, &fl->head);
457 n->is_visible = true;
459 return NFCT_CB_STOLEN;
462 static struct flow_entry *flow_list_find_id(struct flow_list *fl, uint32_t id)
464 struct flow_entry *n;
466 cds_list_for_each_entry_rcu(n, &fl->head, entry) {
467 if (n->flow_id == id)
468 return n;
471 return NULL;
474 static void __flow_list_del_entry(struct flow_list *fl, struct flow_entry *n)
476 if (n->proc) {
477 cds_list_del_rcu(&n->proc_head);
478 n->proc->flows_count--;
481 cds_list_del_rcu(&n->entry);
482 call_rcu(&n->rcu, flow_entry_xfree_rcu);
485 static int flow_list_del_entry(struct flow_list *fl, const struct nf_conntrack *ct)
487 struct flow_entry *n;
489 n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
490 if (n)
491 __flow_list_del_entry(fl, n);
493 return NFCT_CB_CONTINUE;
496 static void flow_list_destroy(struct flow_list *fl)
498 struct flow_entry *n, *tmp;
500 cds_list_for_each_entry_safe(n, tmp, &fl->head, entry)
501 __flow_list_del_entry(fl, n);
504 static void proc_list_init(struct proc_list *proc_list)
506 CDS_INIT_LIST_HEAD(&proc_list->head);
509 static struct proc_entry *proc_list_new_entry(unsigned int pid)
511 struct proc_entry *proc;
513 cds_list_for_each_entry(proc, &proc_list.head, entry) {
514 if (proc->pid && proc->pid == pid)
515 return proc;
518 proc = xzmalloc(sizeof(*proc));
520 bug_on(gettimeofday(&proc->last_update, NULL));
521 CDS_INIT_LIST_HEAD(&proc->flows);
522 proc->pid = pid;
524 cds_list_add_tail(&proc->entry, &proc_list.head);
526 return proc;
529 static void proc_entry_xfree_rcu(struct rcu_head *head)
531 struct proc_entry *p = container_of(head, struct proc_entry, rcu);
533 xfree(p);
536 static void proc_list_destroy(struct proc_list *pl)
538 struct proc_entry *p, *tmp;
540 cds_list_for_each_entry_safe(p, tmp, &pl->head, entry) {
541 cds_list_del_rcu(&p->entry);
542 call_rcu(&p->rcu, proc_entry_xfree_rcu);
546 static void flow_entry_find_process(struct flow_entry *n)
548 struct proc_entry *p;
549 char cmdline[512];
550 pid_t pid;
551 int ret;
553 ret = proc_find_by_inode(n->inode, cmdline, sizeof(cmdline), &pid);
554 if (ret <= 0)
555 return;
557 p = proc_list_new_entry(pid);
559 if (snprintf(p->name, sizeof(p->name), "%s", basename(cmdline)) < 0)
560 p->name[0] = '\0';
562 p->stat.pkts_src += n->stat.pkts_src;
563 p->stat.pkts_dst += n->stat.pkts_dst;
564 p->stat.bytes_src += n->stat.bytes_src;
565 p->stat.bytes_dst += n->stat.bytes_dst;
566 p->flows_count++;
568 cds_list_add_rcu(&n->proc_head, &p->flows);
569 n->proc = p;
572 static int get_port_inode(uint16_t port, int proto, bool is_ip6)
574 int ret = -ENOENT;
575 char path[128], buff[1024];
576 FILE *proc;
578 memset(path, 0, sizeof(path));
579 snprintf(path, sizeof(path), "/proc/net/%s%s",
580 l4proto2str[proto], is_ip6 ? "6" : "");
582 proc = fopen(path, "r");
583 if (!proc)
584 return -EIO;
586 memset(buff, 0, sizeof(buff));
588 while (fgets(buff, sizeof(buff), proc) != NULL) {
589 int inode = 0;
590 unsigned int lport = 0;
592 buff[sizeof(buff) - 1] = 0;
593 if (sscanf(buff, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
594 "%*X %*u %*u %u", &lport, &inode) == 2) {
595 if ((uint16_t) lport == port) {
596 ret = inode;
597 break;
601 memset(buff, 0, sizeof(buff));
604 fclose(proc);
605 return ret;
608 #define CP_NFCT(elem, attr, x) \
609 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
610 #define CP_NFCT_BUFF(elem, attr) do { \
611 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
612 if (buff != NULL) \
613 memcpy(n->elem, buff, sizeof(n->elem)); \
614 } while (0)
616 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct)
618 uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES);
619 uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES);
620 uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS);
621 uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS);
623 /* Update stats diff to the related process entry */
624 if (n->proc) {
625 n->proc->stat.pkts_src += pkts_src - n->stat.pkts_src;
626 n->proc->stat.pkts_dst += pkts_dst - n->stat.pkts_dst;
627 n->proc->stat.bytes_src += bytes_src - n->stat.bytes_src;
628 n->proc->stat.bytes_dst += bytes_dst - n->stat.bytes_dst;
631 CP_NFCT(l3_proto, ATTR_ORIG_L3PROTO, 8);
632 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
634 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
635 CP_NFCT(ip4_dst_addr, ATTR_ORIG_IPV4_DST, 32);
637 CP_NFCT(port_src, ATTR_ORIG_PORT_SRC, 16);
638 CP_NFCT(port_dst, ATTR_ORIG_PORT_DST, 16);
640 CP_NFCT(status, ATTR_STATUS, 32);
642 CP_NFCT(tcp_state, ATTR_TCP_STATE, 8);
643 CP_NFCT(tcp_flags, ATTR_TCP_FLAGS_ORIG, 8);
644 CP_NFCT(sctp_state, ATTR_SCTP_STATE, 8);
645 CP_NFCT(dccp_state, ATTR_DCCP_STATE, 8);
647 CP_NFCT(stat.pkts_src, ATTR_ORIG_COUNTER_PACKETS, 64);
648 CP_NFCT(stat.bytes_src, ATTR_ORIG_COUNTER_BYTES, 64);
650 CP_NFCT(stat.pkts_dst, ATTR_REPL_COUNTER_PACKETS, 64);
651 CP_NFCT(stat.bytes_dst, ATTR_REPL_COUNTER_BYTES, 64);
653 CP_NFCT(timestamp_start, ATTR_TIMESTAMP_START, 64);
654 CP_NFCT(timestamp_stop, ATTR_TIMESTAMP_STOP, 64);
656 CP_NFCT(flow_id, ATTR_ID, 32);
657 CP_NFCT(use, ATTR_USE, 32);
659 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
660 CP_NFCT_BUFF(ip6_dst_addr, ATTR_ORIG_IPV6_DST);
662 n->port_src = ntohs(n->port_src);
663 n->port_dst = ntohs(n->port_dst);
665 n->ip4_src_addr = ntohl(n->ip4_src_addr);
666 n->ip4_dst_addr = ntohl(n->ip4_dst_addr);
669 #define SELFLD(dir,src_member,dst_member) \
670 (((dir) == FLOW_DIR_SRC) ? n->src_member : n->dst_member)
672 static void flow_entry_get_sain4_obj(const struct flow_entry *n,
673 enum flow_direction dir,
674 struct sockaddr_in *sa)
676 memset(sa, 0, sizeof(*sa));
677 sa->sin_family = PF_INET;
678 sa->sin_addr.s_addr = htonl(SELFLD(dir, ip4_src_addr, ip4_dst_addr));
681 static void flow_entry_get_sain6_obj(const struct flow_entry *n,
682 enum flow_direction dir,
683 struct sockaddr_in6 *sa)
685 memset(sa, 0, sizeof(*sa));
686 sa->sin6_family = PF_INET6;
688 memcpy(&sa->sin6_addr, SELFLD(dir, ip6_src_addr, ip6_dst_addr),
689 sizeof(sa->sin6_addr));
692 static void
693 flow_entry_geo_city_lookup_generic(struct flow_entry *n,
694 enum flow_direction dir)
696 struct sockaddr_in sa4;
697 struct sockaddr_in6 sa6;
698 char *city = NULL;
700 switch (n->l3_proto) {
701 default:
702 bug();
704 case AF_INET:
705 flow_entry_get_sain4_obj(n, dir, &sa4);
706 city = geoip4_city_name(&sa4);
707 break;
709 case AF_INET6:
710 flow_entry_get_sain6_obj(n, dir, &sa6);
711 city = geoip6_city_name(&sa6);
712 break;
715 build_bug_on(sizeof(n->city_src) != sizeof(n->city_dst));
717 if (city)
718 strlcpy(SELFLD(dir, city_src, city_dst), city,
719 sizeof(n->city_src));
720 else
721 SELFLD(dir, city_src, city_dst)[0] = '\0';
723 free(city);
726 static void
727 flow_entry_geo_country_lookup_generic(struct flow_entry *n,
728 enum flow_direction dir)
730 struct sockaddr_in sa4;
731 struct sockaddr_in6 sa6;
732 const char *country = NULL;
733 const char *country_code = NULL;
735 switch (n->l3_proto) {
736 default:
737 bug();
739 case AF_INET:
740 flow_entry_get_sain4_obj(n, dir, &sa4);
741 country = geoip4_country_name(&sa4);
742 country_code = geoip4_country_code3_name(&sa4);
743 break;
745 case AF_INET6:
746 flow_entry_get_sain6_obj(n, dir, &sa6);
747 country = geoip6_country_name(&sa6);
748 country_code = geoip6_country_code3_name(&sa6);
749 break;
752 build_bug_on(sizeof(n->country_src) != sizeof(n->country_dst));
754 if (country)
755 strlcpy(SELFLD(dir, country_src, country_dst), country,
756 sizeof(n->country_src));
757 else
758 SELFLD(dir, country_src, country_dst)[0] = '\0';
760 build_bug_on(sizeof(n->country_code_src) != sizeof(n->country_code_dst));
762 if (country_code)
763 strlcpy(SELFLD(dir, country_code_src, country_code_dst),
764 country_code, sizeof(n->country_code_src));
765 else
766 SELFLD(dir, country_code_src, country_code_dst)[0] = '\0';
769 static void flow_entry_get_extended_geo(struct flow_entry *n,
770 enum flow_direction dir)
772 if (resolve_geoip) {
773 flow_entry_geo_city_lookup_generic(n, dir);
774 flow_entry_geo_country_lookup_generic(n, dir);
778 static void flow_entry_get_extended_revdns(struct flow_entry *n,
779 enum flow_direction dir)
781 size_t sa_len;
782 struct sockaddr_in sa4;
783 struct sockaddr_in6 sa6;
784 struct sockaddr *sa;
785 struct hostent *hent;
787 build_bug_on(sizeof(n->rev_dns_src) != sizeof(n->rev_dns_dst));
789 switch (n->l3_proto) {
790 default:
791 bug();
793 case AF_INET:
794 flow_entry_get_sain4_obj(n, dir, &sa4);
796 if (!resolve_dns) {
797 inet_ntop(AF_INET, &sa4.sin_addr,
798 SELFLD(dir, rev_dns_src, rev_dns_dst),
799 sizeof(n->rev_dns_src));
800 return;
803 sa = (struct sockaddr *) &sa4;
804 sa_len = sizeof(sa4);
805 hent = gethostbyaddr(&sa4.sin_addr, sizeof(sa4.sin_addr), AF_INET);
806 break;
808 case AF_INET6:
809 flow_entry_get_sain6_obj(n, dir, &sa6);
811 if (!resolve_dns) {
812 inet_ntop(AF_INET6, &sa6.sin6_addr,
813 SELFLD(dir, rev_dns_src, rev_dns_dst),
814 sizeof(n->rev_dns_src));
815 return;
818 sa = (struct sockaddr *) &sa6;
819 sa_len = sizeof(sa6);
820 hent = gethostbyaddr(&sa6.sin6_addr, sizeof(sa6.sin6_addr), AF_INET6);
821 break;
824 getnameinfo(sa, sa_len, SELFLD(dir, rev_dns_src, rev_dns_dst),
825 sizeof(n->rev_dns_src), NULL, 0, NI_NUMERICHOST);
827 if (hent)
828 strlcpy(SELFLD(dir, rev_dns_src, rev_dns_dst), hent->h_name,
829 sizeof(n->rev_dns_src));
832 static void flow_entry_get_extended(struct flow_entry *n)
834 if (n->flow_id == 0)
835 return;
837 flow_entry_get_extended_revdns(n, FLOW_DIR_SRC);
838 flow_entry_get_extended_geo(n, FLOW_DIR_SRC);
840 flow_entry_get_extended_revdns(n, FLOW_DIR_DST);
841 flow_entry_get_extended_geo(n, FLOW_DIR_DST);
843 /* Lookup application */
844 n->inode = get_port_inode(n->port_src, n->l4_proto,
845 n->l3_proto == AF_INET6);
846 if (n->inode > 0)
847 flow_entry_find_process(n);
850 static char *bandw2str(double bytes, char *buf, size_t len)
852 if (bytes <= 0) {
853 buf[0] = '\0';
854 return buf;
857 if (bytes > 1000000000.)
858 snprintf(buf, len, "%.1fGB", bytes / 1000000000.);
859 else if (bytes > 1000000.)
860 snprintf(buf, len, "%.1fMB", bytes / 1000000.);
861 else if (bytes > 1000.)
862 snprintf(buf, len, "%.1fkB", bytes / 1000.);
863 else
864 snprintf(buf, len, "%.0f", bytes);
866 return buf;
869 static char *rate2str(double rate, char *buf, size_t len)
871 const char * const unit_fmt[2][4] = {
872 { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%.0fbit/s" },
873 { "%.1fGB/s", "%.1fMB/s", "%.1fkB/s", "%.0fB/s" }
876 if (rate <= 0) {
877 buf[0] = '\0';
878 return buf;
881 if (rate_type == RATE_BITS)
882 rate *= 8;
884 if (rate > 1000000000.)
885 snprintf(buf, len, unit_fmt[rate_type][0], rate / 1000000000.);
886 else if (rate > 1000000.)
887 snprintf(buf, len, unit_fmt[rate_type][1], rate / 1000000.);
888 else if (rate > 1000.)
889 snprintf(buf, len, unit_fmt[rate_type][2], rate / 1000.);
890 else
891 snprintf(buf, len, unit_fmt[rate_type][3], rate);
893 return buf;
896 static char *time2str(uint64_t tstamp, char *str, size_t len)
898 time_t now;
899 int v, s;
901 time(&now);
903 s = now - (tstamp ? (tstamp / NSEC_PER_SEC) : now);
904 if (s <= 0) {
905 str[0] = '\0';
906 return str;
909 v = s / (3600 * 24);
910 if (v > 0) {
911 slprintf(str, len, "%dd", v);
912 return str;
915 v = s / 3600;
916 if (v > 0) {
917 slprintf(str, len, "%dh", v);
918 return str;
921 v = s / 60;
922 if (v > 0) {
923 slprintf(str, len, "%dm", v);
924 return str;
927 slprintf(str, len, "%ds", s);
928 return str;
932 static const char *flow_state2str(const struct flow_entry *n)
934 switch (n->l4_proto) {
935 case IPPROTO_TCP:
936 return tcp_state2str[n->tcp_state];
937 case IPPROTO_SCTP:
938 return sctp_state2str[n->sctp_state];
939 case IPPROTO_DCCP:
940 return dccp_state2str[n->dccp_state];
942 case IPPROTO_UDP:
943 case IPPROTO_UDPLITE:
944 case IPPROTO_ICMP:
945 case IPPROTO_ICMPV6:
946 default:
947 return "";
951 static char *flow_port2str(const struct flow_entry *n, char *str, size_t len,
952 enum flow_direction dir)
954 const char *tmp = NULL;
955 uint16_t port = 0;
957 port = SELFLD(dir, port_src, port_dst);
958 tmp = NULL;
960 switch (n->l4_proto) {
961 case IPPROTO_TCP:
962 tmp = lookup_port_tcp(port);
963 break;
964 case IPPROTO_UDP:
965 case IPPROTO_UDPLITE:
966 tmp = lookup_port_udp(port);
967 break;
970 if (!tmp && port)
971 slprintf(str, len, "%d", port);
972 else
973 slprintf(str, len, "%s", tmp ? tmp : "");
975 return str;
978 static void print_flow_peer_info(const struct flow_entry *n, enum flow_direction dir)
980 int counters_color = COLOR(YELLOW, BLACK);
981 int src_color = COLOR(RED, BLACK);
982 int dst_color = COLOR(BLUE, BLACK);
983 int country_color = COLOR(GREEN, BLACK);
984 int addr_color = dst_color;
985 int port_color = A_BOLD;
986 char tmp[128];
988 if (show_src && dir == FLOW_DIR_SRC) {
989 country_color = src_color;
990 counters_color = src_color;
991 port_color |= src_color;
992 addr_color = src_color;
993 } else if (show_src && FLOW_DIR_DST) {
994 country_color = dst_color;
995 counters_color = dst_color;
996 port_color |= dst_color;
997 addr_color = dst_color;
1000 ui_table_col_color_set(&flows_tbl, TBL_FLOW_ADDRESS, addr_color);
1001 ui_table_col_color_set(&flows_tbl, TBL_FLOW_PORT, port_color);
1002 ui_table_col_color_set(&flows_tbl, TBL_FLOW_GEO, country_color);
1003 ui_table_col_color_set(&flows_tbl, TBL_FLOW_BYTES, counters_color);
1004 ui_table_col_color_set(&flows_tbl, TBL_FLOW_RATE, counters_color);
1006 /* Reverse DNS/IP */
1007 ui_table_row_col_set(&flows_tbl, TBL_FLOW_ADDRESS,
1008 SELFLD(dir, rev_dns_src, rev_dns_dst));
1010 /* Application port */
1011 ui_table_row_col_set(&flows_tbl, TBL_FLOW_PORT,
1012 flow_port2str(n, tmp, sizeof(tmp), dir));
1014 /* GEO */
1015 ui_table_row_col_set(&flows_tbl, TBL_FLOW_GEO,
1016 SELFLD(dir, country_code_src, country_code_dst));
1018 /* Bytes */
1019 ui_table_row_col_set(&flows_tbl, TBL_FLOW_BYTES,
1020 bandw2str(SELFLD(dir, stat.bytes_src, stat.bytes_dst),
1021 tmp, sizeof(tmp) - 1));
1023 /* Rate bytes */
1024 ui_table_row_col_set(&flows_tbl, TBL_FLOW_RATE,
1025 rate2str(SELFLD(dir, stat.rate_bytes_src, stat.rate_bytes_dst),
1026 tmp, sizeof(tmp) - 1));
1029 static void draw_flow_entry(struct ui_table *tbl, const void *data)
1031 const struct flow_entry *n = data;
1032 char tmp[128];
1034 ui_table_row_add(tbl);
1036 /* Application */
1037 ui_table_row_col_set(tbl, TBL_FLOW_PROCESS, n->proc ? n->proc->name : "");
1039 /* PID */
1040 slprintf(tmp, sizeof(tmp), "%.d", n->proc ? n->proc->pid : 0);
1041 ui_table_row_col_set(tbl, TBL_FLOW_PID, tmp);
1043 /* L4 protocol */
1044 ui_table_row_col_set(tbl, TBL_FLOW_PROTO, l4proto2str[n->l4_proto]);
1046 /* L4 protocol state */
1047 ui_table_row_col_set(tbl, TBL_FLOW_STATE, flow_state2str(n));
1049 /* Time */
1050 time2str(n->timestamp_start, tmp, sizeof(tmp));
1051 ui_table_row_col_set(tbl, TBL_FLOW_TIME, tmp);
1053 print_flow_peer_info(n, show_src ? FLOW_DIR_SRC : FLOW_DIR_DST);
1055 ui_table_row_show(tbl);
1057 if (show_src) {
1058 ui_table_row_add(tbl);
1060 ui_table_row_col_set(tbl, TBL_FLOW_PROCESS, "");
1061 ui_table_row_col_set(tbl, TBL_FLOW_PID, "");
1062 ui_table_row_col_set(tbl, TBL_FLOW_PROTO, "");
1063 ui_table_row_col_set(tbl, TBL_FLOW_STATE, "");
1064 ui_table_row_col_set(tbl, TBL_FLOW_TIME, "");
1066 print_flow_peer_info(n, FLOW_DIR_DST);
1067 ui_table_row_show(tbl);
1071 static inline bool presenter_flow_wrong_state(struct flow_entry *n)
1073 switch (n->l4_proto) {
1074 case IPPROTO_TCP:
1075 switch (n->tcp_state) {
1076 case TCP_CONNTRACK_SYN_SENT:
1077 case TCP_CONNTRACK_SYN_RECV:
1078 case TCP_CONNTRACK_ESTABLISHED:
1079 case TCP_CONNTRACK_FIN_WAIT:
1080 case TCP_CONNTRACK_CLOSE_WAIT:
1081 case TCP_CONNTRACK_LAST_ACK:
1082 case TCP_CONNTRACK_TIME_WAIT:
1083 case TCP_CONNTRACK_CLOSE:
1084 case TCP_CONNTRACK_SYN_SENT2:
1085 case TCP_CONNTRACK_NONE:
1086 return false;
1087 break;
1089 break;
1090 case IPPROTO_SCTP:
1091 switch (n->sctp_state) {
1092 case SCTP_CONNTRACK_NONE:
1093 case SCTP_CONNTRACK_CLOSED:
1094 case SCTP_CONNTRACK_COOKIE_WAIT:
1095 case SCTP_CONNTRACK_COOKIE_ECHOED:
1096 case SCTP_CONNTRACK_ESTABLISHED:
1097 case SCTP_CONNTRACK_SHUTDOWN_SENT:
1098 case SCTP_CONNTRACK_SHUTDOWN_RECD:
1099 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT:
1100 return false;
1101 break;
1103 break;
1104 case IPPROTO_DCCP:
1105 switch (n->dccp_state) {
1106 case DCCP_CONNTRACK_NONE:
1107 case DCCP_CONNTRACK_REQUEST:
1108 case DCCP_CONNTRACK_RESPOND:
1109 case DCCP_CONNTRACK_PARTOPEN:
1110 case DCCP_CONNTRACK_OPEN:
1111 case DCCP_CONNTRACK_CLOSEREQ:
1112 case DCCP_CONNTRACK_CLOSING:
1113 case DCCP_CONNTRACK_TIMEWAIT:
1114 case DCCP_CONNTRACK_IGNORE:
1115 case DCCP_CONNTRACK_INVALID:
1116 return false;
1117 break;
1119 break;
1120 case IPPROTO_UDP:
1121 case IPPROTO_UDPLITE:
1122 case IPPROTO_ICMP:
1123 case IPPROTO_ICMPV6:
1124 return false;
1125 break;
1128 return true;
1131 static void draw_filter_status(struct ui_table *tbl, char *title)
1133 mvwprintw(screen, 1, 0, "%*s", COLS - 1, " ");
1134 mvwprintw(screen, 1, 2, "%s(%u) for ", title, ui_table_data_count(tbl));
1136 if (what & INCLUDE_IPV4)
1137 printw("IPv4,");
1138 if (what & INCLUDE_IPV6)
1139 printw("IPv6,");
1140 if (what & INCLUDE_TCP)
1141 printw("TCP,");
1142 if (what & INCLUDE_UDP)
1143 printw("UDP,");
1144 if (what & INCLUDE_SCTP)
1145 printw("SCTP,");
1146 if (what & INCLUDE_DCCP)
1147 printw("DCCP,");
1148 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1149 printw("ICMP,");
1150 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1151 printw("ICMP6,");
1152 if (show_active_only)
1153 printw("Active,");
1155 printw(" [+%d]", ui_table_scroll_height(tbl));
1157 if (is_flow_collecting)
1158 printw(" [Collecting flows ...]");
1162 static void draw_flows(WINDOW *screen, struct flow_list *fl)
1164 rcu_read_lock();
1166 if (cds_list_empty(&fl->head))
1167 mvwprintw(screen, 4, 2, "(No sessions! "
1168 "Is netfilter running?)");
1170 ui_table_data_bind(&flows_tbl);
1172 rcu_read_unlock();
1174 draw_filter_status(&flows_tbl, "Kernel netfilter flows");
1177 static void draw_proc_entry(struct ui_table *tbl, const void *data)
1179 const struct proc_entry *p = data;
1180 char tmp[128];
1182 ui_table_row_add(tbl);
1184 /* Application */
1185 ui_table_row_col_set(tbl, TBL_PROC_NAME, p->name);
1187 /* PID */
1188 slprintf(tmp, sizeof(tmp), "%.d", p->pid);
1189 ui_table_row_col_set(tbl, TBL_PROC_PID, tmp);
1191 /* Flows */
1192 slprintf(tmp, sizeof(tmp), "%.d", p->flows_count);
1193 ui_table_row_col_set(tbl, TBL_PROC_FLOWS, tmp);
1195 /* Bytes Src */
1196 bandw2str(p->stat.bytes_src, tmp, sizeof(tmp) - 1);
1197 ui_table_row_col_set(tbl, TBL_PROC_BYTES_SRC, tmp);
1199 /* Rate Src */
1200 rate2str(p->stat.rate_bytes_src, tmp, sizeof(tmp) - 1);
1201 ui_table_row_col_set(tbl, TBL_PROC_RATE_SRC, tmp);
1203 /* Bytes Dest */
1204 bandw2str(p->stat.bytes_dst, tmp, sizeof(tmp) - 1);
1205 ui_table_row_col_set(tbl, TBL_PROC_BYTES_DST, tmp);
1207 /* Rate Dest */
1208 rate2str(p->stat.rate_bytes_dst, tmp, sizeof(tmp) - 1);
1209 ui_table_row_col_set(tbl, TBL_PROC_RATE_DST, tmp);
1211 ui_table_row_show(tbl);
1214 static void draw_procs(WINDOW *screen, struct flow_list *fl)
1216 rcu_read_lock();
1218 ui_table_data_bind(&procs_tbl);
1220 rcu_read_unlock();
1222 draw_filter_status(&procs_tbl, "Processes");
1225 static void draw_help(void)
1227 int col = 0;
1228 int row = 1;
1229 int i;
1231 mvaddch(row, col, ACS_ULCORNER);
1232 mvaddch(rows - row - 1, col, ACS_LLCORNER);
1234 mvaddch(row, cols - 1, ACS_URCORNER);
1235 mvaddch(rows - row - 1, cols - 1, ACS_LRCORNER);
1237 for (i = 1; i < rows - row - 2; i++) {
1238 mvaddch(row + i, 0, ACS_VLINE);
1239 mvaddch(row + i, cols - 1, ACS_VLINE);
1241 for (i = 1; i < cols - col - 1; i++) {
1242 mvaddch(row, col + i, ACS_HLINE);
1243 mvaddch(rows - row - 1, col + i, ACS_HLINE);
1246 attron(A_BOLD);
1247 mvaddnstr(row, cols / 2 - 2, "| Help |", -1);
1249 attron(A_UNDERLINE);
1250 mvaddnstr(row + 2, col + 2, "Navigation", -1);
1251 attroff(A_BOLD | A_UNDERLINE);
1253 mvaddnstr(row + 4, col + 3, "TAB Go to next tab panel", -1);
1254 mvaddnstr(row + 5, col + 3, "Up, u, k Move up", -1);
1255 mvaddnstr(row + 6, col + 3, "Down, d, j Move down", -1);
1256 mvaddnstr(row + 7, col + 3, "Left,l Scroll left", -1);
1257 mvaddnstr(row + 8, col + 3, "Right,h Scroll right", -1);
1258 mvaddnstr(row + 9, col + 3, "? Toggle help window", -1);
1259 mvaddnstr(row + 10, col + 3, "q, Ctrl+C Quit", -1);
1261 attron(A_BOLD | A_UNDERLINE);
1262 mvaddnstr(row + 12, col + 2, "Display Settings", -1);
1263 attroff(A_BOLD | A_UNDERLINE);
1265 mvaddnstr(row + 14, col + 3, "b Toggle rate units (bits/bytes)", -1);
1266 mvaddnstr(row + 15, col + 3, "a Toggle display of active flows (rate > 0) only", -1);
1267 mvaddnstr(row + 16, col + 3, "s Toggle show source peer info", -1);
1269 mvaddnstr(row + 18, col + 3, "T Toggle display TCP flows", -1);
1270 mvaddnstr(row + 19, col + 3, "U Toggle display UDP flows", -1);
1271 mvaddnstr(row + 20, col + 3, "D Toggle display DCCP flows", -1);
1272 mvaddnstr(row + 21, col + 3, "I Toggle display ICMP flows", -1);
1273 mvaddnstr(row + 22, col + 3, "S Toggle display SCTP flows", -1);
1276 static void draw_header(WINDOW *screen)
1278 int i;
1280 attron(A_STANDOUT);
1282 for (i = 0; i < cols; i++)
1283 mvaddch(0, i, ' ');
1285 mvwprintw(screen, 0, 2, "flowtop %s", VERSION_LONG);
1286 attroff(A_STANDOUT);
1289 static void draw_footer(void)
1291 int i;
1293 attron(A_STANDOUT);
1295 for (i = 0; i < cols; i++)
1296 mvaddch(rows - 1, i, ' ');
1298 mvaddnstr(rows - 1, 1, "Press '?' for help", -1);
1299 addch(ACS_VLINE);
1300 attroff(A_STANDOUT);
1303 static void show_option_toggle(int opt)
1305 switch (opt) {
1306 case 'T':
1307 TOGGLE_FLAG(what, INCLUDE_TCP);
1308 break;
1309 case 'U':
1310 TOGGLE_FLAG(what, INCLUDE_UDP);
1311 break;
1312 case 'D':
1313 TOGGLE_FLAG(what, INCLUDE_DCCP);
1314 break;
1315 case 'I':
1316 TOGGLE_FLAG(what, INCLUDE_ICMP);
1317 break;
1318 case 'S':
1319 TOGGLE_FLAG(what, INCLUDE_SCTP);
1320 break;
1324 void * flows_iter(void *data)
1326 struct flow_entry *n = data;
1328 do {
1329 n = list_first_or_next(n, &flow_list.head, entry);
1330 } while (n && (!n->is_visible || presenter_flow_wrong_state(n)));
1332 return n;
1335 static void flows_table_init(struct ui_table *tbl)
1337 ui_table_init(tbl);
1339 ui_table_pos_set(tbl, 3, 0);
1340 ui_table_height_set(tbl, LINES - 3);
1342 ui_table_col_add(tbl, TBL_FLOW_PROCESS, "PROCESS", 13);
1343 ui_table_col_add(tbl, TBL_FLOW_PID, "PID", 7);
1344 ui_table_col_add(tbl, TBL_FLOW_PROTO, "PROTO", 6);
1345 ui_table_col_add(tbl, TBL_FLOW_STATE, "STATE", 11);
1346 ui_table_col_add(tbl, TBL_FLOW_TIME, "TIME", 4);
1347 ui_table_col_add(tbl, TBL_FLOW_ADDRESS, "ADDRESS", 50);
1348 ui_table_col_add(tbl, TBL_FLOW_PORT, "PORT", 8);
1349 ui_table_col_add(tbl, TBL_FLOW_GEO, "GEO", 3);
1350 ui_table_col_add(tbl, TBL_FLOW_BYTES, "BYTES", 10);
1351 ui_table_col_add(tbl, TBL_FLOW_RATE, "RATE", 10);
1353 ui_table_col_align_set(tbl, TBL_FLOW_TIME, UI_ALIGN_RIGHT);
1354 ui_table_col_align_set(tbl, TBL_FLOW_BYTES, UI_ALIGN_RIGHT);
1355 ui_table_col_align_set(tbl, TBL_FLOW_RATE, UI_ALIGN_RIGHT);
1357 ui_table_col_color_set(tbl, TBL_FLOW_PROCESS, COLOR(YELLOW, BLACK));
1358 ui_table_col_color_set(tbl, TBL_FLOW_PID, A_BOLD);
1359 ui_table_col_color_set(tbl, TBL_FLOW_STATE, COLOR(YELLOW, BLACK));
1361 ui_table_header_color_set(&flows_tbl, COLOR(BLACK, GREEN));
1363 ui_table_data_bind_set(tbl, draw_flow_entry);
1364 ui_table_data_iter_set(tbl, flows_iter);
1367 void * procs_iter(void *data)
1369 struct proc_entry *p = data;
1371 return list_first_or_next(p, &proc_list.head, entry);
1374 static void procs_table_init(struct ui_table *tbl)
1376 ui_table_init(tbl);
1378 ui_table_pos_set(tbl, 3, 0);
1379 ui_table_height_set(tbl, LINES - 3);
1381 ui_table_col_add(tbl, TBL_PROC_NAME, "NAME", 13);
1382 ui_table_col_add(tbl, TBL_PROC_PID, "PID", 7);
1383 ui_table_col_add(tbl, TBL_PROC_FLOWS, "FLOWS", 7);
1384 ui_table_col_add(tbl, TBL_PROC_BYTES_SRC, "BYTES_SRC", 10);
1385 ui_table_col_add(tbl, TBL_PROC_BYTES_DST, "BYTES_DST", 10);
1386 ui_table_col_add(tbl, TBL_PROC_RATE_SRC, "RATE_SRC", 14);
1387 ui_table_col_add(tbl, TBL_PROC_RATE_DST, "RATE_DST", 14);
1389 ui_table_col_align_set(tbl, TBL_PROC_BYTES_SRC, UI_ALIGN_RIGHT);
1390 ui_table_col_align_set(tbl, TBL_PROC_RATE_SRC, UI_ALIGN_RIGHT);
1391 ui_table_col_align_set(tbl, TBL_PROC_BYTES_DST, UI_ALIGN_RIGHT);
1392 ui_table_col_align_set(tbl, TBL_PROC_RATE_DST, UI_ALIGN_RIGHT);
1394 ui_table_col_color_set(tbl, TBL_PROC_NAME, COLOR(YELLOW, BLACK));
1395 ui_table_col_color_set(tbl, TBL_PROC_PID, A_BOLD);
1396 ui_table_col_color_set(tbl, TBL_PROC_FLOWS, COLOR(YELLOW, BLACK));
1397 ui_table_col_color_set(tbl, TBL_PROC_BYTES_SRC, COLOR(RED, BLACK));
1398 ui_table_col_color_set(tbl, TBL_PROC_RATE_SRC, COLOR(RED, BLACK));
1399 ui_table_col_color_set(tbl, TBL_PROC_BYTES_DST, COLOR(BLUE, BLACK));
1400 ui_table_col_color_set(tbl, TBL_PROC_RATE_DST, COLOR(BLUE, BLACK));
1402 ui_table_header_color_set(tbl, COLOR(BLACK, GREEN));
1404 ui_table_data_bind_set(tbl, draw_proc_entry);
1405 ui_table_data_iter_set(tbl, procs_iter);
1408 static void tab_main_on_open(struct ui_tab *tab, enum ui_tab_event_t evt, uint32_t id)
1410 if (evt != UI_TAB_EVT_OPEN)
1411 return;
1413 if (id == TAB_FLOWS) {
1414 draw_flows(screen, &flow_list);
1415 curr_tbl = &flows_tbl;
1416 } else if (id == TAB_PROCS) {
1417 draw_procs(screen, &flow_list);
1418 curr_tbl = &procs_tbl;
1422 static void presenter(void)
1424 bool show_help = false;
1425 struct ui_tab *tab_main;
1427 lookup_init(LT_PORTS_TCP);
1428 lookup_init(LT_PORTS_UDP);
1430 screen = screen_init(false);
1431 wclear(screen);
1432 halfdelay(1);
1434 start_color();
1435 INIT_COLOR(RED, BLACK);
1436 INIT_COLOR(BLUE, BLACK);
1437 INIT_COLOR(YELLOW, BLACK);
1438 INIT_COLOR(GREEN, BLACK);
1439 INIT_COLOR(BLACK, GREEN);
1441 flows_table_init(&flows_tbl);
1442 procs_table_init(&procs_tbl);
1444 tab_main = ui_tab_create();
1445 ui_tab_event_cb_set(tab_main, tab_main_on_open);
1446 ui_tab_pos_set(tab_main, 2, 0);
1447 ui_tab_active_color_set(tab_main, COLOR(BLACK, GREEN));
1448 ui_tab_entry_add(tab_main, TAB_FLOWS, "Flows");
1449 ui_tab_entry_add(tab_main, TAB_PROCS, "Processes");
1451 rcu_register_thread();
1452 while (!sigint) {
1453 int ch;
1455 curs_set(0);
1456 getmaxyx(screen, rows, cols);
1458 ch = getch();
1459 switch (ch) {
1460 case 'q':
1461 sigint = 1;
1462 break;
1463 case KEY_UP:
1464 case 'u':
1465 case 'k':
1466 ui_table_event_send(curr_tbl, UI_EVT_SCROLL_UP);
1467 break;
1468 case KEY_DOWN:
1469 case 'd':
1470 case 'j':
1471 ui_table_event_send(curr_tbl, UI_EVT_SCROLL_DOWN);
1472 break;
1473 case KEY_LEFT:
1474 case 'h':
1475 ui_table_event_send(curr_tbl, UI_EVT_SCROLL_LEFT);
1476 break;
1477 case KEY_RIGHT:
1478 case 'l':
1479 ui_table_event_send(curr_tbl, UI_EVT_SCROLL_RIGHT);
1480 break;
1481 case 'b':
1482 if (rate_type == RATE_BYTES)
1483 rate_type = RATE_BITS;
1484 else
1485 rate_type = RATE_BYTES;
1486 break;
1487 case 'a':
1488 show_active_only = !show_active_only;
1489 break;
1490 case 's':
1491 show_src = !show_src;
1492 break;
1493 case '?':
1494 show_help = !show_help;
1495 wclear(screen);
1496 clear();
1497 break;
1498 case 'T':
1499 case 'U':
1500 case 'D':
1501 case 'I':
1502 case 'S':
1503 show_option_toggle(ch);
1504 do_reload_flows = true;
1505 break;
1506 case '\t':
1507 ui_tab_event_send(tab_main, UI_EVT_SELECT_NEXT);
1508 break;
1509 default:
1510 fflush(stdin);
1511 break;
1514 draw_header(screen);
1516 if (show_help)
1517 draw_help();
1518 else
1519 ui_tab_show(tab_main);
1521 draw_footer();
1523 rcu_unregister_thread();
1525 ui_table_uninit(&flows_tbl);
1526 ui_table_uninit(&procs_tbl);
1527 ui_tab_destroy(tab_main);
1529 screen_end();
1530 lookup_cleanup(LT_PORTS_UDP);
1531 lookup_cleanup(LT_PORTS_TCP);
1534 static void restore_sysctl(void *obj)
1536 struct sysctl_params_ctx *sysctl_ctx = obj;
1538 if (sysctl_ctx->nfct_acct == 0)
1539 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1540 sysctl_ctx->nfct_acct);
1542 if (sysctl_ctx->nfct_tstamp == 0)
1543 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1544 sysctl_ctx->nfct_tstamp);
1547 static void on_panic_handler(void *arg)
1549 restore_sysctl(arg);
1550 screen_end();
1553 static void conntrack_acct_enable(void)
1555 /* We can still work w/o traffic accounting so just warn about error */
1556 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl.nfct_acct)) {
1557 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1558 strerror(errno));
1559 return;
1562 if (sysctl.nfct_acct == 1)
1563 return;
1565 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1566 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1567 strerror(errno));
1571 static void conntrack_tstamp_enable(void)
1573 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl.nfct_tstamp)) {
1574 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1575 strerror(errno));
1576 return;
1579 if (sysctl.nfct_tstamp == 1)
1580 return;
1582 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1583 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1584 strerror(errno));
1588 static void flow_entry_filter(struct flow_entry *n)
1590 if (show_active_only && !n->stat.rate_bytes_src && !n->stat.rate_bytes_dst)
1591 n->is_visible = false;
1592 else
1593 n->is_visible = true;
1596 static int flow_list_update_entry(struct flow_list *fl, struct nf_conntrack *ct)
1598 struct flow_entry *n;
1600 n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
1601 if (!n)
1602 return NFCT_CB_CONTINUE;
1604 flow_entry_calc_rate(n, ct);
1605 flow_entry_update_time(n);
1606 flow_entry_from_ct(n, ct);
1607 flow_entry_filter(n);
1609 return NFCT_CB_CONTINUE;
1612 static int flow_event_cb(enum nf_conntrack_msg_type type,
1613 struct nf_conntrack *ct, void *data __maybe_unused)
1615 if (sigint)
1616 return NFCT_CB_STOP;
1618 switch (type) {
1619 case NFCT_T_NEW:
1620 return flow_list_new_entry(&flow_list, ct);
1621 case NFCT_T_UPDATE:
1622 return flow_list_update_entry(&flow_list, ct);
1623 case NFCT_T_DESTROY:
1624 return flow_list_del_entry(&flow_list, ct);
1625 default:
1626 return NFCT_CB_CONTINUE;
1630 static void collector_refresh_procs(void)
1632 struct proc_entry *p, *tmp;
1634 cds_list_for_each_entry_safe(p, tmp, &proc_list.head, entry) {
1635 double sec = (double)time_after_us(&p->last_update) / USEC_PER_SEC;
1636 struct flow_entry *n;
1638 if (sec < 1)
1639 continue;
1641 bug_on(gettimeofday(&p->last_update, NULL));
1643 if (!p->flows_count && !proc_exists(p->pid)) {
1644 cds_list_del_rcu(&p->entry);
1645 call_rcu(&p->rcu, proc_entry_xfree_rcu);
1646 continue;
1649 p->stat.rate_bytes_src = 0;
1650 p->stat.rate_bytes_dst = 0;
1651 p->stat.rate_pkts_src = 0;
1652 p->stat.rate_pkts_dst = 0;
1654 cds_list_for_each_entry_rcu(n, &p->flows, proc_head) {
1655 p->stat.rate_bytes_src += n->stat.rate_bytes_src;
1656 p->stat.rate_bytes_dst += n->stat.rate_bytes_dst;
1657 p->stat.rate_pkts_src += n->stat.rate_pkts_src;
1658 p->stat.rate_pkts_dst += n->stat.rate_pkts_dst;
1663 static void collector_refresh_flows(struct nfct_handle *handle)
1665 struct flow_entry *n;
1667 cds_list_for_each_entry_rcu(n, &flow_list.head, entry) {
1668 nfct_query(handle, NFCT_Q_GET, n->ct);
1672 static void collector_create_filter(struct nfct_handle *nfct)
1674 struct nfct_filter *filter;
1675 int ret;
1677 filter = nfct_filter_create();
1678 if (!filter)
1679 panic("Cannot create a nfct filter: %s\n", strerror(errno));
1681 if (what & INCLUDE_UDP) {
1682 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
1683 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDPLITE);
1685 if (what & INCLUDE_TCP)
1686 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
1687 if (what & INCLUDE_DCCP)
1688 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_DCCP);
1689 if (what & INCLUDE_SCTP)
1690 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_SCTP);
1691 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1692 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMP);
1693 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1694 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMPV6);
1695 if (what & INCLUDE_IPV4) {
1696 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV4, NFCT_FILTER_LOGIC_NEGATIVE);
1697 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
1699 if (what & INCLUDE_IPV6) {
1700 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV6, NFCT_FILTER_LOGIC_NEGATIVE);
1701 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV6, &filter_ipv6);
1704 ret = nfct_filter_attach(nfct_fd(nfct), filter);
1705 if (ret < 0)
1706 panic("Cannot attach filter to handle: %s\n", strerror(errno));
1708 nfct_filter_destroy(filter);
1711 /* This hand-crafted filter looks ugly but it allows to do not
1712 * flush nfct connections & filter them by user specified filter.
1713 * May be it is better to replace this one by nfct_cmp. */
1714 static int flow_dump_cb(enum nf_conntrack_msg_type type __maybe_unused,
1715 struct nf_conntrack *ct, void *data __maybe_unused)
1717 struct flow_entry fl;
1718 struct flow_entry *n = &fl;
1720 if (sigint)
1721 return NFCT_CB_STOP;
1723 if (!(what & ~(INCLUDE_IPV4 | INCLUDE_IPV6)))
1724 goto check_addr;
1726 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
1728 if (what & INCLUDE_UDP) {
1729 if (n->l4_proto == IPPROTO_UDP)
1730 goto check_addr;
1732 if (n->l4_proto == IPPROTO_UDPLITE)
1733 goto check_addr;
1736 if ((what & INCLUDE_TCP) && n->l4_proto == IPPROTO_TCP)
1737 goto check_addr;
1739 if ((what & INCLUDE_DCCP) && n->l4_proto == IPPROTO_DCCP)
1740 goto check_addr;
1742 if ((what & INCLUDE_SCTP) && n->l4_proto == IPPROTO_SCTP)
1743 goto check_addr;
1745 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV4) &&
1746 n->l4_proto == IPPROTO_ICMP) {
1747 goto check_addr;
1750 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV6) &&
1751 n->l4_proto == IPPROTO_ICMPV6) {
1752 goto check_addr;
1755 goto skip_flow;
1757 check_addr:
1758 /* filter loopback addresses */
1759 if (what & INCLUDE_IPV4) {
1760 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
1762 if (n->ip4_src_addr == filter_ipv4.addr)
1763 goto skip_flow;
1765 if (what & INCLUDE_IPV6) {
1766 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
1768 if (n->ip6_src_addr[0] == 0x0 &&
1769 n->ip6_src_addr[1] == 0x0 &&
1770 n->ip6_src_addr[2] == 0x0 &&
1771 n->ip6_src_addr[3] == 0x1)
1772 goto skip_flow;
1775 return flow_list_new_entry(&flow_list, ct);
1777 skip_flow:
1778 return NFCT_CB_CONTINUE;
1781 static void collector_dump_flows(void)
1783 struct nfct_handle *nfct = nfct_open(CONNTRACK, 0);
1785 if (!nfct)
1786 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1788 nfct_callback_register(nfct, NFCT_T_ALL, flow_dump_cb, NULL);
1790 is_flow_collecting = true;
1791 if (what & INCLUDE_IPV4) {
1792 int family = AF_INET;
1793 nfct_query(nfct, NFCT_Q_DUMP, &family);
1795 if (what & INCLUDE_IPV6) {
1796 int family = AF_INET6;
1797 nfct_query(nfct, NFCT_Q_DUMP, &family);
1799 is_flow_collecting = false;
1801 nfct_close(nfct);
1804 static void *collector(void *null __maybe_unused)
1806 struct nfct_handle *ct_event;
1807 struct pollfd poll_fd[1];
1809 proc_list_init(&proc_list);
1810 flow_list_init(&flow_list);
1812 ct_event = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW |
1813 NF_NETLINK_CONNTRACK_UPDATE |
1814 NF_NETLINK_CONNTRACK_DESTROY);
1815 if (!ct_event)
1816 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1818 collector_create_filter(ct_event);
1820 nfct_callback_register(ct_event, NFCT_T_ALL, flow_event_cb, NULL);
1822 poll_fd[0].fd = nfct_fd(ct_event);
1823 poll_fd[0].events = POLLIN;
1825 if (fcntl(nfct_fd(ct_event), F_SETFL, O_NONBLOCK) == -1)
1826 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1827 strerror(errno));
1829 rcu_register_thread();
1831 collector_dump_flows();
1833 while (!sigint) {
1834 int status;
1836 if (!do_reload_flows) {
1837 usleep(USEC_PER_SEC * interval);
1838 } else {
1839 do_reload_flows = false;
1841 flow_list_destroy(&flow_list);
1843 collector_create_filter(ct_event);
1844 collector_dump_flows();
1847 collector_refresh_procs();
1848 collector_refresh_flows(ct_event);
1850 status = poll(poll_fd, 1, 0);
1851 if (status < 0) {
1852 if (errno == EAGAIN || errno == EINTR)
1853 continue;
1855 panic("Error while polling: %s\n", strerror(errno));
1856 } else if (status != 0) {
1857 if (poll_fd[0].revents & POLLIN)
1858 nfct_catch(ct_event);
1862 flow_list_destroy(&flow_list);
1863 proc_list_destroy(&proc_list);
1865 rcu_unregister_thread();
1867 nfct_close(ct_event);
1869 pthread_exit(NULL);
1872 int main(int argc, char **argv)
1874 pthread_t tid;
1875 int ret, c, what_cmd = 0;
1877 setfsuid(getuid());
1878 setfsgid(getgid());
1880 while ((c = getopt_long(argc, argv, short_options, long_options,
1881 NULL)) != EOF) {
1882 switch (c) {
1883 case '4':
1884 what_cmd |= INCLUDE_IPV4;
1885 break;
1886 case '6':
1887 what_cmd |= INCLUDE_IPV6;
1888 break;
1889 case 'T':
1890 what_cmd |= INCLUDE_TCP;
1891 break;
1892 case 'U':
1893 what_cmd |= INCLUDE_UDP;
1894 break;
1895 case 'D':
1896 what_cmd |= INCLUDE_DCCP;
1897 break;
1898 case 'I':
1899 what_cmd |= INCLUDE_ICMP;
1900 break;
1901 case 'S':
1902 what_cmd |= INCLUDE_SCTP;
1903 break;
1904 case 's':
1905 show_src = true;
1906 break;
1907 case 'b':
1908 rate_type = RATE_BITS;
1909 break;
1910 case 'u':
1911 update_geoip();
1912 die();
1913 break;
1914 case 't':
1915 interval = strtoul(optarg, NULL, 10);
1916 break;
1917 case 'n':
1918 resolve_dns = false;
1919 break;
1920 case 'G':
1921 resolve_geoip = false;
1922 break;
1923 case 'h':
1924 help();
1925 break;
1926 case 'v':
1927 version();
1928 break;
1929 default:
1930 break;
1934 if (what_cmd > 0) {
1935 what = what_cmd;
1937 if (!(what & (INCLUDE_IPV4 | INCLUDE_IPV6)))
1938 what |= INCLUDE_IPV4 | INCLUDE_IPV6;
1941 rcu_init();
1943 register_signal(SIGINT, signal_handler);
1944 register_signal(SIGQUIT, signal_handler);
1945 register_signal(SIGTERM, signal_handler);
1946 register_signal(SIGHUP, signal_handler);
1948 panic_handler_add(on_panic_handler, &sysctl);
1950 conntrack_acct_enable();
1951 conntrack_tstamp_enable();
1953 if (resolve_geoip)
1954 init_geoip(1);
1956 ret = pthread_create(&tid, NULL, collector, NULL);
1957 if (ret < 0)
1958 panic("Cannot create phthread!\n");
1960 presenter();
1962 if (resolve_geoip)
1963 destroy_geoip();
1965 restore_sysctl(&sysctl);
1967 return 0;