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