flowtop: Add tab control to switch between tables
[netsniff-ng.git] / flowtop.c
blob78ac253aeeea8bd2e6e001bb35ebf40bd30de392
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_entry {
56 struct cds_list_head entry;
57 struct rcu_head rcu;
59 uint32_t flow_id, use, status;
60 uint8_t l3_proto, l4_proto;
61 uint32_t ip4_src_addr, ip4_dst_addr;
62 uint32_t ip6_src_addr[4], ip6_dst_addr[4];
63 uint16_t port_src, port_dst;
64 uint8_t tcp_state, tcp_flags, sctp_state, dccp_state;
65 uint64_t pkts_src, bytes_src;
66 uint64_t pkts_dst, bytes_dst;
67 uint64_t timestamp_start, timestamp_stop;
68 char country_src[128], country_dst[128];
69 char country_code_src[4], country_code_dst[4];
70 char city_src[128], city_dst[128];
71 char rev_dns_src[256], rev_dns_dst[256];
72 char procname[256];
73 int inode;
74 unsigned int procnum;
75 bool is_visible;
76 struct nf_conntrack *ct;
77 struct timeval last_update;
78 double rate_bytes_src;
79 double rate_bytes_dst;
80 double rate_pkts_src;
81 double rate_pkts_dst;
84 struct flow_list {
85 struct cds_list_head head;
88 enum flow_direction {
89 FLOW_DIR_SRC,
90 FLOW_DIR_DST,
93 #ifndef ATTR_TIMESTAMP_START
94 # define ATTR_TIMESTAMP_START 63
95 #endif
96 #ifndef ATTR_TIMESTAMP_STOP
97 # define ATTR_TIMESTAMP_STOP 64
98 #endif
100 #define SCROLL_MAX 1000
102 #define INCLUDE_IPV4 (1 << 0)
103 #define INCLUDE_IPV6 (1 << 1)
104 #define INCLUDE_UDP (1 << 2)
105 #define INCLUDE_TCP (1 << 3)
106 #define INCLUDE_DCCP (1 << 4)
107 #define INCLUDE_ICMP (1 << 5)
108 #define INCLUDE_SCTP (1 << 6)
110 #define TOGGLE_FLAG(what, flag) \
111 do { \
112 if (what & flag) \
113 what &= ~flag; \
114 else \
115 what |= flag; \
116 } while (0)
118 struct sysctl_params_ctx {
119 int nfct_acct;
120 int nfct_tstamp;
123 enum rate_units {
124 RATE_BITS,
125 RATE_BYTES
128 static volatile bool do_reload_flows;
129 static volatile bool is_flow_collecting;
130 static volatile sig_atomic_t sigint = 0;
131 static int what = INCLUDE_IPV4 | INCLUDE_IPV6 | INCLUDE_TCP;
132 static struct flow_list flow_list;
133 static struct sysctl_params_ctx sysctl = { -1, -1 };
135 static unsigned int cols, rows;
136 static WINDOW *screen;
137 static int skip_lines;
139 static unsigned int interval = 1;
140 static bool show_src = false;
141 static bool resolve_dns = true;
142 static bool resolve_geoip = true;
143 static enum rate_units rate_type = RATE_BYTES;
144 static bool show_active_only = false;
146 enum tbl_flow_col {
147 TBL_FLOW_PROCESS,
148 TBL_FLOW_PID,
149 TBL_FLOW_PROTO,
150 TBL_FLOW_STATE,
151 TBL_FLOW_TIME,
152 TBL_FLOW_ADDRESS,
153 TBL_FLOW_PORT,
154 TBL_FLOW_GEO,
155 TBL_FLOW_BYTES,
156 TBL_FLOW_RATE,
159 static struct ui_table flows_tbl;
161 enum tab_entry {
162 TAB_FLOWS,
165 static const char *short_options = "vhTUsDIS46ut:nGb";
166 static const struct option long_options[] = {
167 {"ipv4", no_argument, NULL, '4'},
168 {"ipv6", no_argument, NULL, '6'},
169 {"tcp", no_argument, NULL, 'T'},
170 {"udp", no_argument, NULL, 'U'},
171 {"dccp", no_argument, NULL, 'D'},
172 {"icmp", no_argument, NULL, 'I'},
173 {"sctp", no_argument, NULL, 'S'},
174 {"no-dns", no_argument, NULL, 'n'},
175 {"no-geoip", no_argument, NULL, 'G'},
176 {"show-src", no_argument, NULL, 's'},
177 {"bits", no_argument, NULL, 'b'},
178 {"update", no_argument, NULL, 'u'},
179 {"interval", required_argument, NULL, 't'},
180 {"version", no_argument, NULL, 'v'},
181 {"help", no_argument, NULL, 'h'},
182 {NULL, 0, NULL, 0}
185 static const char *copyright = "Please report bugs to <netsniff-ng@googlegroups.com>\n"
186 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
187 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
188 "Swiss federal institute of technology (ETH Zurich)\n"
189 "License: GNU GPL version 2.0\n"
190 "This is free software: you are free to change and redistribute it.\n"
191 "There is NO WARRANTY, to the extent permitted by law.";
193 static const char *const l4proto2str[IPPROTO_MAX] = {
194 [IPPROTO_TCP] = "tcp",
195 [IPPROTO_UDP] = "udp",
196 [IPPROTO_UDPLITE] = "udplite",
197 [IPPROTO_ICMP] = "icmp",
198 [IPPROTO_ICMPV6] = "icmpv6",
199 [IPPROTO_SCTP] = "sctp",
200 [IPPROTO_GRE] = "gre",
201 [IPPROTO_DCCP] = "dccp",
202 [IPPROTO_IGMP] = "igmp",
203 [IPPROTO_IPIP] = "ipip",
204 [IPPROTO_EGP] = "egp",
205 [IPPROTO_PUP] = "pup",
206 [IPPROTO_IDP] = "idp",
207 [IPPROTO_RSVP] = "rsvp",
208 [IPPROTO_IPV6] = "ip6tun",
209 [IPPROTO_ESP] = "esp",
210 [IPPROTO_AH] = "ah",
211 [IPPROTO_PIM] = "pim",
212 [IPPROTO_COMP] = "comp",
215 static const char *const tcp_state2str[TCP_CONNTRACK_MAX] = {
216 [TCP_CONNTRACK_NONE] = "NONE",
217 [TCP_CONNTRACK_SYN_SENT] = "SYN-SENT",
218 [TCP_CONNTRACK_SYN_RECV] = "SYN-RECV",
219 [TCP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
220 [TCP_CONNTRACK_FIN_WAIT] = "FIN-WAIT",
221 [TCP_CONNTRACK_CLOSE_WAIT] = "CLOSE-WAIT",
222 [TCP_CONNTRACK_LAST_ACK] = "LAST-ACK",
223 [TCP_CONNTRACK_TIME_WAIT] = "TIME-WAIT",
224 [TCP_CONNTRACK_CLOSE] = "CLOSE",
225 [TCP_CONNTRACK_SYN_SENT2] = "SYN-SENT2",
228 static const char *const dccp_state2str[DCCP_CONNTRACK_MAX] = {
229 [DCCP_CONNTRACK_NONE] = "NONE",
230 [DCCP_CONNTRACK_REQUEST] = "REQUEST",
231 [DCCP_CONNTRACK_RESPOND] = "RESPOND",
232 [DCCP_CONNTRACK_PARTOPEN] = "PARTOPEN",
233 [DCCP_CONNTRACK_OPEN] = "OPEN",
234 [DCCP_CONNTRACK_CLOSEREQ] = "CLOSE-REQ",
235 [DCCP_CONNTRACK_CLOSING] = "CLOSING",
236 [DCCP_CONNTRACK_TIMEWAIT] = "TIME-WAIT",
237 [DCCP_CONNTRACK_IGNORE] = "IGNORE",
238 [DCCP_CONNTRACK_INVALID] = "INVALID",
241 static const char *const sctp_state2str[SCTP_CONNTRACK_MAX] = {
242 [SCTP_CONNTRACK_NONE] = "NONE",
243 [SCTP_CONNTRACK_CLOSED] = "CLOSED",
244 [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE-WAIT",
245 [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE-ECHO",
246 [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
247 [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTD-SENT",
248 [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTD-RCVD",
249 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTD-ACK",
252 static const struct nfct_filter_ipv4 filter_ipv4 = {
253 .addr = __constant_htonl(INADDR_LOOPBACK),
254 .mask = 0xffffffff,
257 static const struct nfct_filter_ipv6 filter_ipv6 = {
258 .addr = { 0x0, 0x0, 0x0, 0x1 },
259 .mask = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
262 static int64_t time_after_us(struct timeval *tv)
264 struct timeval now;
266 bug_on(gettimeofday(&now, NULL));
268 now.tv_sec -= tv->tv_sec;
269 now.tv_usec -= tv->tv_usec;
271 return now.tv_sec * USEC_PER_SEC + now.tv_usec;
274 static void signal_handler(int number)
276 switch (number) {
277 case SIGINT:
278 case SIGQUIT:
279 case SIGTERM:
280 sigint = 1;
281 break;
282 case SIGHUP:
283 default:
284 break;
288 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct);
289 static void flow_entry_get_extended(struct flow_entry *n);
291 static void help(void)
293 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
294 VERSION_STRING);
295 puts("http://www.netsniff-ng.org\n\n"
296 "Usage: flowtop [options]\n"
297 "Options:\n"
298 " -4|--ipv4 Show only IPv4 flows (default)\n"
299 " -6|--ipv6 Show only IPv6 flows (default)\n"
300 " -T|--tcp Show only TCP flows (default)\n"
301 " -U|--udp Show only UDP flows\n"
302 " -D|--dccp Show only DCCP flows\n"
303 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
304 " -S|--sctp Show only SCTP flows\n"
305 " -n|--no-dns Don't perform hostname lookup\n"
306 " -G|--no-geoip Don't perform GeoIP lookup\n"
307 " -s|--show-src Also show source, not only dest\n"
308 " -b|--bits Show rates in bits/s instead of bytes/s\n"
309 " -u|--update Update GeoIP databases\n"
310 " -t|--interval <time> Refresh time in seconds (default 1s)\n"
311 " -v|--version Print version and exit\n"
312 " -h|--help Print this help and exit\n\n"
313 "Examples:\n"
314 " flowtop\n"
315 " flowtop -46UTDISs\n\n"
316 "Note:\n"
317 " If netfilter is not running, you can activate it with e.g.:\n"
318 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
319 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
320 puts(copyright);
321 die();
324 static void version(void)
326 printf("flowtop %s, Git id: %s\n", VERSION_LONG, GITVERSION);
327 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
328 "http://www.netsniff-ng.org\n");
329 puts(copyright);
330 die();
333 static void flow_entry_update_time(struct flow_entry *n)
335 bug_on(gettimeofday(&n->last_update, NULL));
338 #define CALC_RATE(fld) do { \
339 n->rate_##fld = (((fld) > n->fld) ? (((fld) - n->fld) / sec) : 0); \
340 } while (0)
342 static void flow_entry_calc_rate(struct flow_entry *n, const struct nf_conntrack *ct)
344 uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES);
345 uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES);
346 uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS);
347 uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS);
348 double sec = (double)time_after_us(&n->last_update) / USEC_PER_SEC;
350 if (sec < 1)
351 return;
353 CALC_RATE(bytes_src);
354 CALC_RATE(bytes_dst);
355 CALC_RATE(pkts_src);
356 CALC_RATE(pkts_dst);
359 static inline struct flow_entry *flow_entry_xalloc(void)
361 return xzmalloc(sizeof(struct flow_entry));
364 static inline void flow_entry_xfree(struct flow_entry *n)
366 if (n->ct)
367 nfct_destroy(n->ct);
369 xfree(n);
372 static void flow_entry_xfree_rcu(struct rcu_head *head)
374 struct flow_entry *n = container_of(head, struct flow_entry, rcu);
376 flow_entry_xfree(n);
379 static inline void flow_list_init(struct flow_list *fl)
381 CDS_INIT_LIST_HEAD(&fl->head);
384 static inline bool nfct_is_dns(const struct nf_conntrack *ct)
386 uint16_t port_src = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
387 uint16_t port_dst = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
389 return ntohs(port_src) == 53 || ntohs(port_dst) == 53;
392 static int flow_list_new_entry(struct flow_list *fl, struct nf_conntrack *ct)
394 struct flow_entry *n;
396 /* We don't want to analyze / display DNS itself, since we
397 * use it to resolve reverse dns.
399 if (nfct_is_dns(ct))
400 return NFCT_CB_CONTINUE;
402 n = flow_entry_xalloc();
404 n->ct = ct;
406 flow_entry_update_time(n);
407 flow_entry_from_ct(n, ct);
408 flow_entry_get_extended(n);
410 cds_list_add_rcu(&n->entry, &fl->head);
412 n->is_visible = true;
414 return NFCT_CB_STOLEN;
417 static struct flow_entry *flow_list_find_id(struct flow_list *fl, uint32_t id)
419 struct flow_entry *n;
421 cds_list_for_each_entry_rcu(n, &fl->head, entry) {
422 if (n->flow_id == id)
423 return n;
426 return NULL;
429 static int flow_list_del_entry(struct flow_list *fl, const struct nf_conntrack *ct)
431 struct flow_entry *n;
433 n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
434 if (n) {
435 cds_list_del_rcu(&n->entry);
436 call_rcu(&n->rcu, flow_entry_xfree_rcu);
439 return NFCT_CB_CONTINUE;
442 static void flow_list_destroy(struct flow_list *fl)
444 struct flow_entry *n, *tmp;
446 cds_list_for_each_entry_safe(n, tmp, &fl->head, entry) {
447 cds_list_del_rcu(&n->entry);
448 call_rcu(&n->rcu, flow_entry_xfree_rcu);
452 static void flow_entry_find_process(struct flow_entry *n)
454 char cmdline[512];
455 pid_t pid;
456 int ret;
458 ret = proc_find_by_inode(n->inode, cmdline, sizeof(cmdline), &pid);
459 if (ret <= 0) {
460 n->procname[0] = '\0';
461 return;
464 if (snprintf(n->procname, sizeof(n->procname), "%s", basename(cmdline)) < 0)
465 n->procname[0] = '\0';
467 n->procnum = pid;
470 static int get_port_inode(uint16_t port, int proto, bool is_ip6)
472 int ret = -ENOENT;
473 char path[128], buff[1024];
474 FILE *proc;
476 memset(path, 0, sizeof(path));
477 snprintf(path, sizeof(path), "/proc/net/%s%s",
478 l4proto2str[proto], is_ip6 ? "6" : "");
480 proc = fopen(path, "r");
481 if (!proc)
482 return -EIO;
484 memset(buff, 0, sizeof(buff));
486 while (fgets(buff, sizeof(buff), proc) != NULL) {
487 int inode = 0;
488 unsigned int lport = 0;
490 buff[sizeof(buff) - 1] = 0;
491 if (sscanf(buff, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
492 "%*X %*u %*u %u", &lport, &inode) == 2) {
493 if ((uint16_t) lport == port) {
494 ret = inode;
495 break;
499 memset(buff, 0, sizeof(buff));
502 fclose(proc);
503 return ret;
506 #define CP_NFCT(elem, attr, x) \
507 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
508 #define CP_NFCT_BUFF(elem, attr) do { \
509 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
510 if (buff != NULL) \
511 memcpy(n->elem, buff, sizeof(n->elem)); \
512 } while (0)
514 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct)
516 CP_NFCT(l3_proto, ATTR_ORIG_L3PROTO, 8);
517 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
519 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
520 CP_NFCT(ip4_dst_addr, ATTR_ORIG_IPV4_DST, 32);
522 CP_NFCT(port_src, ATTR_ORIG_PORT_SRC, 16);
523 CP_NFCT(port_dst, ATTR_ORIG_PORT_DST, 16);
525 CP_NFCT(status, ATTR_STATUS, 32);
527 CP_NFCT(tcp_state, ATTR_TCP_STATE, 8);
528 CP_NFCT(tcp_flags, ATTR_TCP_FLAGS_ORIG, 8);
529 CP_NFCT(sctp_state, ATTR_SCTP_STATE, 8);
530 CP_NFCT(dccp_state, ATTR_DCCP_STATE, 8);
532 CP_NFCT(pkts_src, ATTR_ORIG_COUNTER_PACKETS, 64);
533 CP_NFCT(bytes_src, ATTR_ORIG_COUNTER_BYTES, 64);
535 CP_NFCT(pkts_dst, ATTR_REPL_COUNTER_PACKETS, 64);
536 CP_NFCT(bytes_dst, ATTR_REPL_COUNTER_BYTES, 64);
538 CP_NFCT(timestamp_start, ATTR_TIMESTAMP_START, 64);
539 CP_NFCT(timestamp_stop, ATTR_TIMESTAMP_STOP, 64);
541 CP_NFCT(flow_id, ATTR_ID, 32);
542 CP_NFCT(use, ATTR_USE, 32);
544 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
545 CP_NFCT_BUFF(ip6_dst_addr, ATTR_ORIG_IPV6_DST);
547 n->port_src = ntohs(n->port_src);
548 n->port_dst = ntohs(n->port_dst);
550 n->ip4_src_addr = ntohl(n->ip4_src_addr);
551 n->ip4_dst_addr = ntohl(n->ip4_dst_addr);
554 #define SELFLD(dir,src_member,dst_member) \
555 (((dir) == FLOW_DIR_SRC) ? n->src_member : n->dst_member)
557 static void flow_entry_get_sain4_obj(const struct flow_entry *n,
558 enum flow_direction dir,
559 struct sockaddr_in *sa)
561 memset(sa, 0, sizeof(*sa));
562 sa->sin_family = PF_INET;
563 sa->sin_addr.s_addr = htonl(SELFLD(dir, ip4_src_addr, ip4_dst_addr));
566 static void flow_entry_get_sain6_obj(const struct flow_entry *n,
567 enum flow_direction dir,
568 struct sockaddr_in6 *sa)
570 memset(sa, 0, sizeof(*sa));
571 sa->sin6_family = PF_INET6;
573 memcpy(&sa->sin6_addr, SELFLD(dir, ip6_src_addr, ip6_dst_addr),
574 sizeof(sa->sin6_addr));
577 static void
578 flow_entry_geo_city_lookup_generic(struct flow_entry *n,
579 enum flow_direction dir)
581 struct sockaddr_in sa4;
582 struct sockaddr_in6 sa6;
583 const char *city = NULL;
585 switch (n->l3_proto) {
586 default:
587 bug();
589 case AF_INET:
590 flow_entry_get_sain4_obj(n, dir, &sa4);
591 city = geoip4_city_name(&sa4);
592 break;
594 case AF_INET6:
595 flow_entry_get_sain6_obj(n, dir, &sa6);
596 city = geoip6_city_name(&sa6);
597 break;
600 build_bug_on(sizeof(n->city_src) != sizeof(n->city_dst));
602 if (city)
603 strlcpy(SELFLD(dir, city_src, city_dst), city,
604 sizeof(n->city_src));
605 else
606 SELFLD(dir, city_src, city_dst)[0] = '\0';
609 static void
610 flow_entry_geo_country_lookup_generic(struct flow_entry *n,
611 enum flow_direction dir)
613 struct sockaddr_in sa4;
614 struct sockaddr_in6 sa6;
615 const char *country = NULL;
616 const char *country_code = NULL;
618 switch (n->l3_proto) {
619 default:
620 bug();
622 case AF_INET:
623 flow_entry_get_sain4_obj(n, dir, &sa4);
624 country = geoip4_country_name(&sa4);
625 country_code = geoip4_country_code3_name(&sa4);
626 break;
628 case AF_INET6:
629 flow_entry_get_sain6_obj(n, dir, &sa6);
630 country = geoip6_country_name(&sa6);
631 country_code = geoip6_country_code3_name(&sa6);
632 break;
635 build_bug_on(sizeof(n->country_src) != sizeof(n->country_dst));
637 if (country)
638 strlcpy(SELFLD(dir, country_src, country_dst), country,
639 sizeof(n->country_src));
640 else
641 SELFLD(dir, country_src, country_dst)[0] = '\0';
643 build_bug_on(sizeof(n->country_code_src) != sizeof(n->country_code_dst));
645 if (country_code)
646 strlcpy(SELFLD(dir, country_code_src, country_code_dst),
647 country_code, sizeof(n->country_code_src));
648 else
649 SELFLD(dir, country_code_src, country_code_dst)[0] = '\0';
652 static void flow_entry_get_extended_geo(struct flow_entry *n,
653 enum flow_direction dir)
655 if (resolve_geoip) {
656 flow_entry_geo_city_lookup_generic(n, dir);
657 flow_entry_geo_country_lookup_generic(n, dir);
661 static void flow_entry_get_extended_revdns(struct flow_entry *n,
662 enum flow_direction dir)
664 size_t sa_len;
665 struct sockaddr_in sa4;
666 struct sockaddr_in6 sa6;
667 struct sockaddr *sa;
668 struct hostent *hent;
670 build_bug_on(sizeof(n->rev_dns_src) != sizeof(n->rev_dns_dst));
672 switch (n->l3_proto) {
673 default:
674 bug();
676 case AF_INET:
677 flow_entry_get_sain4_obj(n, dir, &sa4);
679 if (!resolve_dns) {
680 inet_ntop(AF_INET, &sa4.sin_addr,
681 SELFLD(dir, rev_dns_src, rev_dns_dst),
682 sizeof(n->rev_dns_src));
683 return;
686 sa = (struct sockaddr *) &sa4;
687 sa_len = sizeof(sa4);
688 hent = gethostbyaddr(&sa4.sin_addr, sizeof(sa4.sin_addr), AF_INET);
689 break;
691 case AF_INET6:
692 flow_entry_get_sain6_obj(n, dir, &sa6);
694 if (!resolve_dns) {
695 inet_ntop(AF_INET6, &sa6.sin6_addr,
696 SELFLD(dir, rev_dns_src, rev_dns_dst),
697 sizeof(n->rev_dns_src));
698 return;
701 sa = (struct sockaddr *) &sa6;
702 sa_len = sizeof(sa6);
703 hent = gethostbyaddr(&sa6.sin6_addr, sizeof(sa6.sin6_addr), AF_INET6);
704 break;
707 getnameinfo(sa, sa_len, SELFLD(dir, rev_dns_src, rev_dns_dst),
708 sizeof(n->rev_dns_src), NULL, 0, NI_NUMERICHOST);
710 if (hent)
711 strlcpy(SELFLD(dir, rev_dns_src, rev_dns_dst), hent->h_name,
712 sizeof(n->rev_dns_src));
715 static void flow_entry_get_extended(struct flow_entry *n)
717 if (n->flow_id == 0)
718 return;
720 flow_entry_get_extended_revdns(n, FLOW_DIR_SRC);
721 flow_entry_get_extended_geo(n, FLOW_DIR_SRC);
723 flow_entry_get_extended_revdns(n, FLOW_DIR_DST);
724 flow_entry_get_extended_geo(n, FLOW_DIR_DST);
726 /* Lookup application */
727 n->inode = get_port_inode(n->port_src, n->l4_proto,
728 n->l3_proto == AF_INET6);
729 if (n->inode > 0)
730 flow_entry_find_process(n);
733 static char *bandw2str(double bytes, char *buf, size_t len)
735 if (bytes <= 0) {
736 buf[0] = '\0';
737 return buf;
740 if (bytes > 1000000000.)
741 snprintf(buf, len, "%.1fGB", bytes / 1000000000.);
742 else if (bytes > 1000000.)
743 snprintf(buf, len, "%.1fMB", bytes / 1000000.);
744 else if (bytes > 1000.)
745 snprintf(buf, len, "%.1fkB", bytes / 1000.);
746 else
747 snprintf(buf, len, "%.0f", bytes);
749 return buf;
752 static char *rate2str(double rate, char *buf, size_t len)
754 const char * const unit_fmt[2][4] = {
755 { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%.0fbit/s" },
756 { "%.1fGB/s", "%.1fMB/s", "%.1fkB/s", "%.0fB/s" }
759 if (rate <= 0) {
760 buf[0] = '\0';
761 return buf;
764 if (rate_type == RATE_BITS)
765 rate *= 8;
767 if (rate > 1000000000.)
768 snprintf(buf, len, unit_fmt[rate_type][0], rate / 1000000000.);
769 else if (rate > 1000000.)
770 snprintf(buf, len, unit_fmt[rate_type][1], rate / 1000000.);
771 else if (rate > 1000.)
772 snprintf(buf, len, unit_fmt[rate_type][2], rate / 1000.);
773 else
774 snprintf(buf, len, unit_fmt[rate_type][3], rate);
776 return buf;
779 static char *time2str(uint64_t tstamp, char *str, size_t len)
781 time_t now;
782 int v, s;
784 time(&now);
786 s = now - (tstamp ? (tstamp / NSEC_PER_SEC) : now);
787 if (s <= 0) {
788 str[0] = '\0';
789 return str;
792 v = s / (3600 * 24);
793 if (v > 0) {
794 slprintf(str, len, "%dd", v);
795 return str;
798 v = s / 3600;
799 if (v > 0) {
800 slprintf(str, len, "%dh", v);
801 return str;
804 v = s / 60;
805 if (v > 0) {
806 slprintf(str, len, "%dm", v);
807 return str;
810 slprintf(str, len, "%ds", s);
811 return str;
815 static const char *flow_state2str(const struct flow_entry *n)
817 switch (n->l4_proto) {
818 case IPPROTO_TCP:
819 return tcp_state2str[n->tcp_state];
820 case IPPROTO_SCTP:
821 return sctp_state2str[n->sctp_state];
822 case IPPROTO_DCCP:
823 return dccp_state2str[n->dccp_state];
825 case IPPROTO_UDP:
826 case IPPROTO_UDPLITE:
827 case IPPROTO_ICMP:
828 case IPPROTO_ICMPV6:
829 default:
830 return "";
834 static char *flow_port2str(const struct flow_entry *n, char *str, size_t len,
835 enum flow_direction dir)
837 const char *tmp = NULL;
838 uint16_t port = 0;
840 port = SELFLD(dir, port_src, port_dst);
841 tmp = NULL;
843 switch (n->l4_proto) {
844 case IPPROTO_TCP:
845 tmp = lookup_port_tcp(port);
846 break;
847 case IPPROTO_UDP:
848 case IPPROTO_UDPLITE:
849 tmp = lookup_port_udp(port);
850 break;
853 if (!tmp && port)
854 slprintf(str, len, "%d", port);
855 else
856 slprintf(str, len, "%s", tmp ? tmp : "");
858 return str;
861 static void print_flow_peer_info(const struct flow_entry *n, enum flow_direction dir)
863 int counters_color = COLOR(YELLOW, BLACK);
864 int src_color = COLOR(RED, BLACK);
865 int dst_color = COLOR(BLUE, BLACK);
866 int country_color = COLOR(GREEN, BLACK);
867 int addr_color = dst_color;
868 int port_color = A_BOLD;
869 char tmp[128];
871 if (show_src && dir == FLOW_DIR_SRC) {
872 country_color = src_color;
873 counters_color = src_color;
874 port_color |= src_color;
875 addr_color = src_color;
876 } else if (show_src && FLOW_DIR_DST) {
877 country_color = dst_color;
878 counters_color = dst_color;
879 port_color |= dst_color;
880 addr_color = dst_color;
883 ui_table_col_color_set(&flows_tbl, TBL_FLOW_ADDRESS, addr_color);
884 ui_table_col_color_set(&flows_tbl, TBL_FLOW_PORT, port_color);
885 ui_table_col_color_set(&flows_tbl, TBL_FLOW_GEO, country_color);
886 ui_table_col_color_set(&flows_tbl, TBL_FLOW_BYTES, counters_color);
887 ui_table_col_color_set(&flows_tbl, TBL_FLOW_RATE, counters_color);
889 /* Reverse DNS/IP */
890 ui_table_row_col_set(&flows_tbl, TBL_FLOW_ADDRESS,
891 SELFLD(dir, rev_dns_src, rev_dns_dst));
893 /* Application port */
894 ui_table_row_col_set(&flows_tbl, TBL_FLOW_PORT,
895 flow_port2str(n, tmp, sizeof(tmp), dir));
897 /* GEO */
898 ui_table_row_col_set(&flows_tbl, TBL_FLOW_GEO,
899 SELFLD(dir, country_code_src, country_code_dst));
901 /* Bytes */
902 ui_table_row_col_set(&flows_tbl, TBL_FLOW_BYTES,
903 bandw2str(SELFLD(dir, bytes_src, bytes_dst),
904 tmp, sizeof(tmp) - 1));
906 /* Rate bytes */
907 ui_table_row_col_set(&flows_tbl, TBL_FLOW_RATE,
908 rate2str(SELFLD(dir, rate_bytes_src, rate_bytes_dst),
909 tmp, sizeof(tmp) - 1));
912 static void draw_flow_entry(const struct flow_entry *n)
914 char tmp[128];
916 ui_table_row_add(&flows_tbl);
918 /* Application */
919 ui_table_row_col_set(&flows_tbl, TBL_FLOW_PROCESS, n->procname);
921 /* PID */
922 slprintf(tmp, sizeof(tmp), "%.d", n->procnum);
923 ui_table_row_col_set(&flows_tbl, TBL_FLOW_PID, tmp);
925 /* L4 protocol */
926 ui_table_row_col_set(&flows_tbl, TBL_FLOW_PROTO, l4proto2str[n->l4_proto]);
928 /* L4 protocol state */
929 ui_table_row_col_set(&flows_tbl, TBL_FLOW_STATE, flow_state2str(n));
931 /* Time */
932 time2str(n->timestamp_start, tmp, sizeof(tmp));
933 ui_table_row_col_set(&flows_tbl, TBL_FLOW_TIME, tmp);
935 print_flow_peer_info(n, show_src ? FLOW_DIR_SRC : FLOW_DIR_DST);
937 ui_table_row_show(&flows_tbl);
939 if (show_src) {
940 ui_table_row_add(&flows_tbl);
942 ui_table_row_col_set(&flows_tbl, TBL_FLOW_PROCESS, "");
943 ui_table_row_col_set(&flows_tbl, TBL_FLOW_PID, "");
944 ui_table_row_col_set(&flows_tbl, TBL_FLOW_PROTO, "");
945 ui_table_row_col_set(&flows_tbl, TBL_FLOW_STATE, "");
946 ui_table_row_col_set(&flows_tbl, TBL_FLOW_TIME, "");
948 print_flow_peer_info(n, FLOW_DIR_DST);
949 ui_table_row_show(&flows_tbl);
953 static inline bool presenter_flow_wrong_state(struct flow_entry *n)
955 switch (n->l4_proto) {
956 case IPPROTO_TCP:
957 switch (n->tcp_state) {
958 case TCP_CONNTRACK_SYN_SENT:
959 case TCP_CONNTRACK_SYN_RECV:
960 case TCP_CONNTRACK_ESTABLISHED:
961 case TCP_CONNTRACK_FIN_WAIT:
962 case TCP_CONNTRACK_CLOSE_WAIT:
963 case TCP_CONNTRACK_LAST_ACK:
964 case TCP_CONNTRACK_TIME_WAIT:
965 case TCP_CONNTRACK_CLOSE:
966 case TCP_CONNTRACK_SYN_SENT2:
967 case TCP_CONNTRACK_NONE:
968 return false;
969 break;
971 break;
972 case IPPROTO_SCTP:
973 switch (n->sctp_state) {
974 case SCTP_CONNTRACK_NONE:
975 case SCTP_CONNTRACK_CLOSED:
976 case SCTP_CONNTRACK_COOKIE_WAIT:
977 case SCTP_CONNTRACK_COOKIE_ECHOED:
978 case SCTP_CONNTRACK_ESTABLISHED:
979 case SCTP_CONNTRACK_SHUTDOWN_SENT:
980 case SCTP_CONNTRACK_SHUTDOWN_RECD:
981 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT:
982 return false;
983 break;
985 break;
986 case IPPROTO_DCCP:
987 switch (n->dccp_state) {
988 case DCCP_CONNTRACK_NONE:
989 case DCCP_CONNTRACK_REQUEST:
990 case DCCP_CONNTRACK_RESPOND:
991 case DCCP_CONNTRACK_PARTOPEN:
992 case DCCP_CONNTRACK_OPEN:
993 case DCCP_CONNTRACK_CLOSEREQ:
994 case DCCP_CONNTRACK_CLOSING:
995 case DCCP_CONNTRACK_TIMEWAIT:
996 case DCCP_CONNTRACK_IGNORE:
997 case DCCP_CONNTRACK_INVALID:
998 return false;
999 break;
1001 break;
1002 case IPPROTO_UDP:
1003 case IPPROTO_UDPLITE:
1004 case IPPROTO_ICMP:
1005 case IPPROTO_ICMPV6:
1006 return false;
1007 break;
1010 return true;
1013 static void draw_flows(WINDOW *screen, struct flow_list *fl,
1014 int skip_lines)
1016 int row_width = show_src ? 2 : 1;
1017 unsigned int flows = 0;
1018 unsigned int line = 4;
1019 int skip = skip_lines;
1020 struct flow_entry *n;
1022 rcu_read_lock();
1024 if (cds_list_empty(&fl->head))
1025 mvwprintw(screen, line, 2, "(No sessions! "
1026 "Is netfilter running?)");
1028 ui_table_clear(&flows_tbl);
1029 ui_table_header_print(&flows_tbl);
1031 cds_list_for_each_entry_rcu(n, &fl->head, entry) {
1032 if (!n->is_visible)
1033 continue;
1034 if (presenter_flow_wrong_state(n))
1035 continue;
1037 /* count only flows which might be showed */
1038 flows++;
1040 if (line + row_width >= rows)
1041 continue;
1042 if (--skip >= 0)
1043 continue;
1045 draw_flow_entry(n);
1046 line += row_width;
1049 rcu_read_unlock();
1051 mvwprintw(screen, 1, 0, "%*s", COLS - 1, " ");
1052 mvwprintw(screen, 1, 2, "Kernel netfilter flows(%u) for ", flows);
1054 if (what & INCLUDE_IPV4)
1055 printw("IPv4,");
1056 if (what & INCLUDE_IPV6)
1057 printw("IPv6,");
1058 if (what & INCLUDE_TCP)
1059 printw("TCP,");
1060 if (what & INCLUDE_UDP)
1061 printw("UDP,");
1062 if (what & INCLUDE_SCTP)
1063 printw("SCTP,");
1064 if (what & INCLUDE_DCCP)
1065 printw("DCCP,");
1066 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1067 printw("ICMP,");
1068 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1069 printw("ICMP6,");
1070 if (show_active_only)
1071 printw("Active,");
1073 printw(" [+%d]", skip_lines);
1075 if (is_flow_collecting)
1076 printw(" [Collecting flows ...]");
1079 static void draw_help(void)
1081 int col = 0;
1082 int row = 1;
1083 int i;
1085 mvaddch(row, col, ACS_ULCORNER);
1086 mvaddch(rows - row - 1, col, ACS_LLCORNER);
1088 mvaddch(row, cols - 1, ACS_URCORNER);
1089 mvaddch(rows - row - 1, cols - 1, ACS_LRCORNER);
1091 for (i = 1; i < rows - row - 2; i++) {
1092 mvaddch(row + i, 0, ACS_VLINE);
1093 mvaddch(row + i, cols - 1, ACS_VLINE);
1095 for (i = 1; i < cols - col - 1; i++) {
1096 mvaddch(row, col + i, ACS_HLINE);
1097 mvaddch(rows - row - 1, col + i, ACS_HLINE);
1100 attron(A_BOLD);
1101 mvaddnstr(row, cols / 2 - 2, "| Help |", -1);
1103 attron(A_UNDERLINE);
1104 mvaddnstr(row + 2, col + 2, "Navigation", -1);
1105 attroff(A_BOLD | A_UNDERLINE);
1107 mvaddnstr(row + 4, col + 3, "Up, u, k Move up", -1);
1108 mvaddnstr(row + 5, col + 3, "Down, d, j Move down", -1);
1109 mvaddnstr(row + 6, col + 3, "Left,l Scroll left", -1);
1110 mvaddnstr(row + 7, col + 3, "Right,h Scroll right", -1);
1111 mvaddnstr(row + 8, col + 3, "? Toggle help window", -1);
1112 mvaddnstr(row + 9, col + 3, "q, Ctrl+C Quit", -1);
1114 attron(A_BOLD | A_UNDERLINE);
1115 mvaddnstr(row + 11, col + 2, "Display Settings", -1);
1116 attroff(A_BOLD | A_UNDERLINE);
1118 mvaddnstr(row + 13, col + 3, "b Toggle rate units (bits/bytes)", -1);
1119 mvaddnstr(row + 14, col + 3, "a Toggle display of active flows (rate > 0) only", -1);
1120 mvaddnstr(row + 15, col + 3, "s Toggle show source peer info", -1);
1122 mvaddnstr(row + 17, col + 3, "T Toggle display TCP flows", -1);
1123 mvaddnstr(row + 18, col + 3, "U Toggle display UDP flows", -1);
1124 mvaddnstr(row + 19, col + 3, "D Toggle display DCCP flows", -1);
1125 mvaddnstr(row + 20, col + 3, "I Toggle display ICMP flows", -1);
1126 mvaddnstr(row + 21, col + 3, "S Toggle display SCTP flows", -1);
1129 static void draw_header(WINDOW *screen)
1131 int i;
1133 attron(A_STANDOUT);
1135 for (i = 0; i < cols; i++)
1136 mvaddch(0, i, ' ');
1138 mvwprintw(screen, 0, 2, "flowtop %s", VERSION_LONG);
1139 attroff(A_STANDOUT);
1142 static void draw_footer(void)
1144 int i;
1146 attron(A_STANDOUT);
1148 for (i = 0; i < cols; i++)
1149 mvaddch(rows - 1, i, ' ');
1151 mvaddnstr(rows - 1, 1, "Press '?' for help", -1);
1152 addch(ACS_VLINE);
1153 attroff(A_STANDOUT);
1156 static void show_option_toggle(int opt)
1158 switch (opt) {
1159 case 'T':
1160 TOGGLE_FLAG(what, INCLUDE_TCP);
1161 break;
1162 case 'U':
1163 TOGGLE_FLAG(what, INCLUDE_UDP);
1164 break;
1165 case 'D':
1166 TOGGLE_FLAG(what, INCLUDE_DCCP);
1167 break;
1168 case 'I':
1169 TOGGLE_FLAG(what, INCLUDE_ICMP);
1170 break;
1171 case 'S':
1172 TOGGLE_FLAG(what, INCLUDE_SCTP);
1173 break;
1177 static void flows_table_init(struct ui_table *tbl)
1179 ui_table_init(tbl);
1181 ui_table_pos_set(tbl, 3, 0);
1182 ui_table_height_set(tbl, LINES - 3);
1184 ui_table_col_add(tbl, TBL_FLOW_PROCESS, "PROCESS", 13);
1185 ui_table_col_add(tbl, TBL_FLOW_PID, "PID", 7);
1186 ui_table_col_add(tbl, TBL_FLOW_PROTO, "PROTO", 6);
1187 ui_table_col_add(tbl, TBL_FLOW_STATE, "STATE", 11);
1188 ui_table_col_add(tbl, TBL_FLOW_TIME, "TIME", 4);
1189 ui_table_col_add(tbl, TBL_FLOW_ADDRESS, "ADDRESS", 50);
1190 ui_table_col_add(tbl, TBL_FLOW_PORT, "PORT", 8);
1191 ui_table_col_add(tbl, TBL_FLOW_GEO, "GEO", 3);
1192 ui_table_col_add(tbl, TBL_FLOW_BYTES, "BYTES", 10);
1193 ui_table_col_add(tbl, TBL_FLOW_RATE, "RATE", 10);
1195 ui_table_col_align_set(tbl, TBL_FLOW_TIME, UI_ALIGN_RIGHT);
1196 ui_table_col_align_set(tbl, TBL_FLOW_BYTES, UI_ALIGN_RIGHT);
1197 ui_table_col_align_set(tbl, TBL_FLOW_RATE, UI_ALIGN_RIGHT);
1199 ui_table_col_color_set(tbl, TBL_FLOW_PROCESS, COLOR(YELLOW, BLACK));
1200 ui_table_col_color_set(tbl, TBL_FLOW_PID, A_BOLD);
1201 ui_table_col_color_set(tbl, TBL_FLOW_STATE, COLOR(YELLOW, BLACK));
1203 ui_table_header_color_set(&flows_tbl, COLOR(BLACK, GREEN));
1206 static void tab_main_on_open(struct ui_tab *tab, enum ui_tab_event_t evt, uint32_t id)
1208 draw_flows(screen, &flow_list, skip_lines);
1211 static void presenter(void)
1213 bool show_help = false;
1214 struct ui_tab *tab_main;
1216 lookup_init(LT_PORTS_TCP);
1217 lookup_init(LT_PORTS_UDP);
1219 screen = screen_init(false);
1220 wclear(screen);
1221 halfdelay(1);
1223 start_color();
1224 INIT_COLOR(RED, BLACK);
1225 INIT_COLOR(BLUE, BLACK);
1226 INIT_COLOR(YELLOW, BLACK);
1227 INIT_COLOR(GREEN, BLACK);
1228 INIT_COLOR(BLACK, GREEN);
1230 flows_table_init(&flows_tbl);
1232 tab_main = ui_tab_create();
1233 ui_tab_event_cb_set(tab_main, tab_main_on_open);
1234 ui_tab_pos_set(tab_main, 2, 0);
1235 ui_tab_active_color_set(tab_main, COLOR(BLACK, GREEN));
1236 ui_tab_entry_add(tab_main, TAB_FLOWS, "Flows");
1238 rcu_register_thread();
1239 while (!sigint) {
1240 int ch;
1242 curs_set(0);
1243 getmaxyx(screen, rows, cols);
1245 ch = getch();
1246 switch (ch) {
1247 case 'q':
1248 sigint = 1;
1249 break;
1250 case KEY_UP:
1251 case 'u':
1252 case 'k':
1253 skip_lines--;
1254 if (skip_lines < 0)
1255 skip_lines = 0;
1256 break;
1257 case KEY_DOWN:
1258 case 'd':
1259 case 'j':
1260 skip_lines++;
1261 if (skip_lines > SCROLL_MAX)
1262 skip_lines = SCROLL_MAX;
1263 break;
1264 case KEY_LEFT:
1265 case 'h':
1266 ui_table_event_send(&flows_tbl, UI_EVT_SCROLL_LEFT);
1267 break;
1268 case KEY_RIGHT:
1269 case 'l':
1270 ui_table_event_send(&flows_tbl, UI_EVT_SCROLL_RIGHT);
1271 break;
1272 case 'b':
1273 if (rate_type == RATE_BYTES)
1274 rate_type = RATE_BITS;
1275 else
1276 rate_type = RATE_BYTES;
1277 break;
1278 case 'a':
1279 show_active_only = !show_active_only;
1280 break;
1281 case 's':
1282 show_src = !show_src;
1283 break;
1284 case '?':
1285 show_help = !show_help;
1286 wclear(screen);
1287 clear();
1288 break;
1289 case 'T':
1290 case 'U':
1291 case 'D':
1292 case 'I':
1293 case 'S':
1294 show_option_toggle(ch);
1295 do_reload_flows = true;
1296 break;
1297 case '\t':
1298 ui_tab_event_send(tab_main, UI_EVT_SELECT_NEXT);
1299 break;
1300 default:
1301 fflush(stdin);
1302 break;
1305 draw_header(screen);
1307 if (show_help)
1308 draw_help();
1309 else
1310 ui_tab_show(tab_main);
1312 draw_footer();
1314 rcu_unregister_thread();
1316 ui_table_uninit(&flows_tbl);
1317 ui_tab_destroy(tab_main);
1319 screen_end();
1320 lookup_cleanup(LT_PORTS_UDP);
1321 lookup_cleanup(LT_PORTS_TCP);
1324 static void restore_sysctl(void *obj)
1326 struct sysctl_params_ctx *sysctl_ctx = obj;
1328 if (sysctl_ctx->nfct_acct == 0)
1329 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1330 sysctl_ctx->nfct_acct);
1332 if (sysctl_ctx->nfct_tstamp == 0)
1333 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1334 sysctl_ctx->nfct_tstamp);
1337 static void on_panic_handler(void *arg)
1339 restore_sysctl(arg);
1340 screen_end();
1343 static void conntrack_acct_enable(void)
1345 /* We can still work w/o traffic accounting so just warn about error */
1346 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl.nfct_acct)) {
1347 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1348 strerror(errno));
1349 return;
1352 if (sysctl.nfct_acct == 1)
1353 return;
1355 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1356 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1357 strerror(errno));
1361 static void conntrack_tstamp_enable(void)
1363 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl.nfct_tstamp)) {
1364 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1365 strerror(errno));
1366 return;
1369 if (sysctl.nfct_tstamp == 1)
1370 return;
1372 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1373 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1374 strerror(errno));
1378 static void flow_entry_filter(struct flow_entry *n)
1380 if (show_active_only && !n->rate_bytes_src && !n->rate_bytes_dst)
1381 n->is_visible = false;
1382 else
1383 n->is_visible = true;
1386 static int flow_list_update_entry(struct flow_list *fl, struct nf_conntrack *ct)
1388 struct flow_entry *n;
1390 n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
1391 if (!n)
1392 return NFCT_CB_CONTINUE;
1394 flow_entry_calc_rate(n, ct);
1395 flow_entry_update_time(n);
1396 flow_entry_from_ct(n, ct);
1397 flow_entry_filter(n);
1399 return NFCT_CB_CONTINUE;
1402 static int flow_event_cb(enum nf_conntrack_msg_type type,
1403 struct nf_conntrack *ct, void *data __maybe_unused)
1405 if (sigint)
1406 return NFCT_CB_STOP;
1408 switch (type) {
1409 case NFCT_T_NEW:
1410 return flow_list_new_entry(&flow_list, ct);
1411 case NFCT_T_UPDATE:
1412 return flow_list_update_entry(&flow_list, ct);
1413 case NFCT_T_DESTROY:
1414 return flow_list_del_entry(&flow_list, ct);
1415 default:
1416 return NFCT_CB_CONTINUE;
1420 static void collector_refresh_flows(struct nfct_handle *handle)
1422 struct flow_entry *n;
1424 cds_list_for_each_entry_rcu(n, &flow_list.head, entry) {
1425 nfct_query(handle, NFCT_Q_GET, n->ct);
1429 static void collector_create_filter(struct nfct_handle *nfct)
1431 struct nfct_filter *filter;
1432 int ret;
1434 filter = nfct_filter_create();
1435 if (!filter)
1436 panic("Cannot create a nfct filter: %s\n", strerror(errno));
1438 if (what & INCLUDE_UDP) {
1439 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
1440 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDPLITE);
1442 if (what & INCLUDE_TCP)
1443 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
1444 if (what & INCLUDE_DCCP)
1445 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_DCCP);
1446 if (what & INCLUDE_SCTP)
1447 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_SCTP);
1448 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1449 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMP);
1450 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1451 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMPV6);
1452 if (what & INCLUDE_IPV4) {
1453 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV4, NFCT_FILTER_LOGIC_NEGATIVE);
1454 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
1456 if (what & INCLUDE_IPV6) {
1457 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV6, NFCT_FILTER_LOGIC_NEGATIVE);
1458 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV6, &filter_ipv6);
1461 ret = nfct_filter_attach(nfct_fd(nfct), filter);
1462 if (ret < 0)
1463 panic("Cannot attach filter to handle: %s\n", strerror(errno));
1465 nfct_filter_destroy(filter);
1468 /* This hand-crafted filter looks ugly but it allows to do not
1469 * flush nfct connections & filter them by user specified filter.
1470 * May be it is better to replace this one by nfct_cmp. */
1471 static int flow_dump_cb(enum nf_conntrack_msg_type type __maybe_unused,
1472 struct nf_conntrack *ct, void *data __maybe_unused)
1474 struct flow_entry fl;
1475 struct flow_entry *n = &fl;
1477 if (sigint)
1478 return NFCT_CB_STOP;
1480 if (!(what & ~(INCLUDE_IPV4 | INCLUDE_IPV6)))
1481 goto check_addr;
1483 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
1485 if (what & INCLUDE_UDP) {
1486 if (n->l4_proto == IPPROTO_UDP)
1487 goto check_addr;
1489 if (n->l4_proto == IPPROTO_UDPLITE)
1490 goto check_addr;
1493 if ((what & INCLUDE_TCP) && n->l4_proto == IPPROTO_TCP)
1494 goto check_addr;
1496 if ((what & INCLUDE_DCCP) && n->l4_proto == IPPROTO_DCCP)
1497 goto check_addr;
1499 if ((what & INCLUDE_SCTP) && n->l4_proto == IPPROTO_SCTP)
1500 goto check_addr;
1502 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV4) &&
1503 n->l4_proto == IPPROTO_ICMP) {
1504 goto check_addr;
1507 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV6) &&
1508 n->l4_proto == IPPROTO_ICMPV6) {
1509 goto check_addr;
1512 goto skip_flow;
1514 check_addr:
1515 /* filter loopback addresses */
1516 if (what & INCLUDE_IPV4) {
1517 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
1519 if (n->ip4_src_addr == filter_ipv4.addr)
1520 goto skip_flow;
1522 if (what & INCLUDE_IPV6) {
1523 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
1525 if (n->ip6_src_addr[0] == 0x0 &&
1526 n->ip6_src_addr[1] == 0x0 &&
1527 n->ip6_src_addr[2] == 0x0 &&
1528 n->ip6_src_addr[3] == 0x1)
1529 goto skip_flow;
1532 return flow_list_new_entry(&flow_list, ct);
1534 skip_flow:
1535 return NFCT_CB_CONTINUE;
1538 static void collector_dump_flows(void)
1540 struct nfct_handle *nfct = nfct_open(CONNTRACK, 0);
1542 if (!nfct)
1543 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1545 nfct_callback_register(nfct, NFCT_T_ALL, flow_dump_cb, NULL);
1547 is_flow_collecting = true;
1548 if (what & INCLUDE_IPV4) {
1549 int family = AF_INET;
1550 nfct_query(nfct, NFCT_Q_DUMP, &family);
1552 if (what & INCLUDE_IPV6) {
1553 int family = AF_INET6;
1554 nfct_query(nfct, NFCT_Q_DUMP, &family);
1556 is_flow_collecting = false;
1558 nfct_close(nfct);
1561 static void *collector(void *null __maybe_unused)
1563 struct nfct_handle *ct_event;
1564 struct pollfd poll_fd[1];
1566 flow_list_init(&flow_list);
1568 ct_event = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW |
1569 NF_NETLINK_CONNTRACK_UPDATE |
1570 NF_NETLINK_CONNTRACK_DESTROY);
1571 if (!ct_event)
1572 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1574 collector_create_filter(ct_event);
1576 nfct_callback_register(ct_event, NFCT_T_ALL, flow_event_cb, NULL);
1578 poll_fd[0].fd = nfct_fd(ct_event);
1579 poll_fd[0].events = POLLIN;
1581 if (fcntl(nfct_fd(ct_event), F_SETFL, O_NONBLOCK) == -1)
1582 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1583 strerror(errno));
1585 rcu_register_thread();
1587 collector_dump_flows();
1589 while (!sigint) {
1590 int status;
1592 if (!do_reload_flows) {
1593 usleep(USEC_PER_SEC * interval);
1594 } else {
1595 do_reload_flows = false;
1597 flow_list_destroy(&flow_list);
1599 collector_create_filter(ct_event);
1600 collector_dump_flows();
1603 collector_refresh_flows(ct_event);
1605 status = poll(poll_fd, 1, 0);
1606 if (status < 0) {
1607 if (errno == EAGAIN || errno == EINTR)
1608 continue;
1610 panic("Error while polling: %s\n", strerror(errno));
1611 } else if (status != 0) {
1612 if (poll_fd[0].revents & POLLIN)
1613 nfct_catch(ct_event);
1617 flow_list_destroy(&flow_list);
1619 rcu_unregister_thread();
1621 nfct_close(ct_event);
1623 pthread_exit(NULL);
1626 int main(int argc, char **argv)
1628 pthread_t tid;
1629 int ret, c, what_cmd = 0;
1631 setfsuid(getuid());
1632 setfsgid(getgid());
1634 while ((c = getopt_long(argc, argv, short_options, long_options,
1635 NULL)) != EOF) {
1636 switch (c) {
1637 case '4':
1638 what_cmd |= INCLUDE_IPV4;
1639 break;
1640 case '6':
1641 what_cmd |= INCLUDE_IPV6;
1642 break;
1643 case 'T':
1644 what_cmd |= INCLUDE_TCP;
1645 break;
1646 case 'U':
1647 what_cmd |= INCLUDE_UDP;
1648 break;
1649 case 'D':
1650 what_cmd |= INCLUDE_DCCP;
1651 break;
1652 case 'I':
1653 what_cmd |= INCLUDE_ICMP;
1654 break;
1655 case 'S':
1656 what_cmd |= INCLUDE_SCTP;
1657 break;
1658 case 's':
1659 show_src = true;
1660 break;
1661 case 'b':
1662 rate_type = RATE_BITS;
1663 break;
1664 case 'u':
1665 update_geoip();
1666 die();
1667 break;
1668 case 't':
1669 interval = strtoul(optarg, NULL, 10);
1670 break;
1671 case 'n':
1672 resolve_dns = false;
1673 break;
1674 case 'G':
1675 resolve_geoip = false;
1676 break;
1677 case 'h':
1678 help();
1679 break;
1680 case 'v':
1681 version();
1682 break;
1683 default:
1684 break;
1688 if (what_cmd > 0) {
1689 what = what_cmd;
1691 if (!(what & (INCLUDE_IPV4 | INCLUDE_IPV6)))
1692 what |= INCLUDE_IPV4 | INCLUDE_IPV6;
1695 rcu_init();
1697 register_signal(SIGINT, signal_handler);
1698 register_signal(SIGQUIT, signal_handler);
1699 register_signal(SIGTERM, signal_handler);
1700 register_signal(SIGHUP, signal_handler);
1702 panic_handler_add(on_panic_handler, &sysctl);
1704 conntrack_acct_enable();
1705 conntrack_tstamp_enable();
1707 if (resolve_geoip)
1708 init_geoip(1);
1710 ret = pthread_create(&tid, NULL, collector, NULL);
1711 if (ret < 0)
1712 panic("Cannot create phthread!\n");
1714 presenter();
1716 if (resolve_geoip)
1717 destroy_geoip();
1719 restore_sysctl(&sysctl);
1721 return 0;