flowtop: Add runtime command to change rate units
[netsniff-ng-new.git] / flowtop.c
blobdf190a432acd1b620121189f45c2f1d17c8d99d1
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 "die.h"
32 #include "xmalloc.h"
33 #include "conntrack.h"
34 #include "config.h"
35 #include "str.h"
36 #include "sig.h"
37 #include "lookup.h"
38 #include "geoip.h"
39 #include "built_in.h"
40 #include "locking.h"
41 #include "pkt_buff.h"
42 #include "screen.h"
43 #include "proc.h"
44 #include "sysctl.h"
46 #ifndef NSEC_PER_SEC
47 #define NSEC_PER_SEC 1000000000L
48 #endif
50 #ifndef USEC_PER_SEC
51 #define USEC_PER_SEC 1000000L
52 #endif
54 struct flow_entry {
55 uint32_t flow_id, use, status;
56 uint8_t l3_proto, l4_proto;
57 uint32_t ip4_src_addr, ip4_dst_addr;
58 uint32_t ip6_src_addr[4], ip6_dst_addr[4];
59 uint16_t port_src, port_dst;
60 uint8_t tcp_state, tcp_flags, sctp_state, dccp_state;
61 uint64_t pkts_src, bytes_src;
62 uint64_t pkts_dst, bytes_dst;
63 uint64_t timestamp_start, timestamp_stop;
64 char country_src[128], country_dst[128];
65 char city_src[128], city_dst[128];
66 char rev_dns_src[256], rev_dns_dst[256];
67 char procname[256];
68 struct flow_entry *next;
69 int inode;
70 unsigned int procnum;
71 bool is_visible;
72 struct nf_conntrack *ct;
73 struct timeval last_update;
74 double rate_bytes_src;
75 double rate_bytes_dst;
76 double rate_pkts_src;
77 double rate_pkts_dst;
80 struct flow_list {
81 struct flow_entry *head;
82 struct spinlock lock;
85 enum flow_direction {
86 FLOW_DIR_SRC,
87 FLOW_DIR_DST,
90 #ifndef ATTR_TIMESTAMP_START
91 # define ATTR_TIMESTAMP_START 63
92 #endif
93 #ifndef ATTR_TIMESTAMP_STOP
94 # define ATTR_TIMESTAMP_STOP 64
95 #endif
97 #define SCROLL_MAX 1000
99 #define INCLUDE_IPV4 (1 << 0)
100 #define INCLUDE_IPV6 (1 << 1)
101 #define INCLUDE_UDP (1 << 2)
102 #define INCLUDE_TCP (1 << 3)
103 #define INCLUDE_DCCP (1 << 4)
104 #define INCLUDE_ICMP (1 << 5)
105 #define INCLUDE_SCTP (1 << 6)
107 struct sysctl_params_ctx {
108 int nfct_acct;
109 int nfct_tstamp;
112 enum rate_units {
113 RATE_BITS,
114 RATE_BYTES
117 static volatile bool is_flow_collecting;
118 static volatile sig_atomic_t sigint = 0;
119 static int what = INCLUDE_IPV4 | INCLUDE_IPV6 | INCLUDE_TCP;
120 static struct flow_list flow_list;
121 static struct sysctl_params_ctx sysctl = { -1, -1 };
123 static unsigned int cols, rows;
125 static unsigned int interval = 1;
126 static bool show_src = false;
127 static bool resolve_dns = true;
128 static bool resolve_geoip = true;
129 static enum rate_units rate_type = RATE_BYTES;
131 static const char *short_options = "vhTUsDIS46ut:nGb";
132 static const struct option long_options[] = {
133 {"ipv4", no_argument, NULL, '4'},
134 {"ipv6", no_argument, NULL, '6'},
135 {"tcp", no_argument, NULL, 'T'},
136 {"udp", no_argument, NULL, 'U'},
137 {"dccp", no_argument, NULL, 'D'},
138 {"icmp", no_argument, NULL, 'I'},
139 {"sctp", no_argument, NULL, 'S'},
140 {"no-dns", no_argument, NULL, 'n'},
141 {"no-geoip", no_argument, NULL, 'G'},
142 {"show-src", no_argument, NULL, 's'},
143 {"bits", no_argument, NULL, 'b'},
144 {"update", no_argument, NULL, 'u'},
145 {"interval", required_argument, NULL, 't'},
146 {"version", no_argument, NULL, 'v'},
147 {"help", no_argument, NULL, 'h'},
148 {NULL, 0, NULL, 0}
151 static const char *copyright = "Please report bugs to <netsniff-ng@googlegroups.com>\n"
152 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
153 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
154 "Swiss federal institute of technology (ETH Zurich)\n"
155 "License: GNU GPL version 2.0\n"
156 "This is free software: you are free to change and redistribute it.\n"
157 "There is NO WARRANTY, to the extent permitted by law.";
159 static const char *const l3proto2str[AF_MAX] = {
160 [AF_INET] = "ipv4",
161 [AF_INET6] = "ipv6",
164 static const char *const l4proto2str[IPPROTO_MAX] = {
165 [IPPROTO_TCP] = "tcp",
166 [IPPROTO_UDP] = "udp",
167 [IPPROTO_UDPLITE] = "udplite",
168 [IPPROTO_ICMP] = "icmp",
169 [IPPROTO_ICMPV6] = "icmpv6",
170 [IPPROTO_SCTP] = "sctp",
171 [IPPROTO_GRE] = "gre",
172 [IPPROTO_DCCP] = "dccp",
173 [IPPROTO_IGMP] = "igmp",
174 [IPPROTO_IPIP] = "ipip",
175 [IPPROTO_EGP] = "egp",
176 [IPPROTO_PUP] = "pup",
177 [IPPROTO_IDP] = "idp",
178 [IPPROTO_RSVP] = "rsvp",
179 [IPPROTO_IPV6] = "ip6tun",
180 [IPPROTO_ESP] = "esp",
181 [IPPROTO_AH] = "ah",
182 [IPPROTO_PIM] = "pim",
183 [IPPROTO_COMP] = "comp",
186 static const char *const tcp_state2str[TCP_CONNTRACK_MAX] = {
187 [TCP_CONNTRACK_NONE] = "NOSTATE",
188 [TCP_CONNTRACK_SYN_SENT] = "SYN_SENT",
189 [TCP_CONNTRACK_SYN_RECV] = "SYN_RECV",
190 [TCP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
191 [TCP_CONNTRACK_FIN_WAIT] = "FIN_WAIT",
192 [TCP_CONNTRACK_CLOSE_WAIT] = "CLOSE_WAIT",
193 [TCP_CONNTRACK_LAST_ACK] = "LAST_ACK",
194 [TCP_CONNTRACK_TIME_WAIT] = "TIME_WAIT",
195 [TCP_CONNTRACK_CLOSE] = "CLOSE",
196 [TCP_CONNTRACK_SYN_SENT2] = "SYN_SENT2",
199 static const char *const dccp_state2str[DCCP_CONNTRACK_MAX] = {
200 [DCCP_CONNTRACK_NONE] = "NOSTATE",
201 [DCCP_CONNTRACK_REQUEST] = "REQUEST",
202 [DCCP_CONNTRACK_RESPOND] = "RESPOND",
203 [DCCP_CONNTRACK_PARTOPEN] = "PARTOPEN",
204 [DCCP_CONNTRACK_OPEN] = "OPEN",
205 [DCCP_CONNTRACK_CLOSEREQ] = "CLOSEREQ",
206 [DCCP_CONNTRACK_CLOSING] = "CLOSING",
207 [DCCP_CONNTRACK_TIMEWAIT] = "TIMEWAIT",
208 [DCCP_CONNTRACK_IGNORE] = "IGNORE",
209 [DCCP_CONNTRACK_INVALID] = "INVALID",
212 static const char *const sctp_state2str[SCTP_CONNTRACK_MAX] = {
213 [SCTP_CONNTRACK_NONE] = "NOSTATE",
214 [SCTP_CONNTRACK_CLOSED] = "CLOSED",
215 [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE_WAIT",
216 [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE_ECHOED",
217 [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
218 [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTDOWN_SENT",
219 [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTDOWN_RECD",
220 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT",
223 static const struct nfct_filter_ipv4 filter_ipv4 = {
224 .addr = __constant_htonl(INADDR_LOOPBACK),
225 .mask = 0xffffffff,
228 static const struct nfct_filter_ipv6 filter_ipv6 = {
229 .addr = { 0x0, 0x0, 0x0, 0x1 },
230 .mask = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
233 static int64_t time_after_us(struct timeval *tv)
235 struct timeval now;
237 bug_on(gettimeofday(&now, NULL));
239 now.tv_sec -= tv->tv_sec;
240 now.tv_usec -= tv->tv_usec;
242 return now.tv_sec * USEC_PER_SEC + now.tv_usec;
245 static void signal_handler(int number)
247 switch (number) {
248 case SIGINT:
249 case SIGQUIT:
250 case SIGTERM:
251 sigint = 1;
252 break;
253 case SIGHUP:
254 default:
255 break;
259 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct);
260 static void flow_entry_get_extended(struct flow_entry *n);
262 static void help(void)
264 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
265 VERSION_STRING);
266 puts("http://www.netsniff-ng.org\n\n"
267 "Usage: flowtop [options]\n"
268 "Options:\n"
269 " -4|--ipv4 Show only IPv4 flows (default)\n"
270 " -6|--ipv6 Show only IPv6 flows (default)\n"
271 " -T|--tcp Show only TCP flows (default)\n"
272 " -U|--udp Show only UDP flows\n"
273 " -D|--dccp Show only DCCP flows\n"
274 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
275 " -S|--sctp Show only SCTP flows\n"
276 " -n|--no-dns Don't perform hostname lookup\n"
277 " -G|--no-geoip Don't perform GeoIP lookup\n"
278 " -s|--show-src Also show source, not only dest\n"
279 " -b|--bits Show rates in bits/s instead of bytes/s\n"
280 " -u|--update Update GeoIP databases\n"
281 " -t|--interval <time> Refresh time in seconds (default 1s)\n"
282 " -v|--version Print version and exit\n"
283 " -h|--help Print this help and exit\n\n"
284 "Examples:\n"
285 " flowtop\n"
286 " flowtop -46UTDISs\n\n"
287 "Note:\n"
288 " If netfilter is not running, you can activate it with e.g.:\n"
289 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
290 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
291 puts(copyright);
292 die();
295 static void version(void)
297 printf("flowtop %s, Git id: %s\n", VERSION_LONG, GITVERSION);
298 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
299 "http://www.netsniff-ng.org\n");
300 puts(copyright);
301 die();
304 static void flow_entry_update_time(struct flow_entry *n)
306 bug_on(gettimeofday(&n->last_update, NULL));
309 #define CALC_RATE(fld) do { \
310 n->rate_##fld = (((fld) > n->fld) ? (((fld) - n->fld) / sec) : 0); \
311 } while (0)
313 static void flow_entry_calc_rate(struct flow_entry *n, const struct nf_conntrack *ct)
315 uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES);
316 uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES);
317 uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS);
318 uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS);
319 double sec = (double)time_after_us(&n->last_update) / USEC_PER_SEC;
321 if (sec < 1)
322 return;
324 CALC_RATE(bytes_src);
325 CALC_RATE(bytes_dst);
326 CALC_RATE(pkts_src);
327 CALC_RATE(pkts_dst);
330 static inline struct flow_entry *flow_entry_xalloc(void)
332 return xzmalloc(sizeof(struct flow_entry));
335 static inline void flow_entry_xfree(struct flow_entry *n)
337 if (n->ct)
338 nfct_destroy(n->ct);
340 xfree(n);
343 static inline void flow_list_init(struct flow_list *fl)
345 fl->head = NULL;
346 spinlock_init(&fl->lock);
349 static inline bool nfct_is_dns(const struct nf_conntrack *ct)
351 uint16_t port_src = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
352 uint16_t port_dst = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
354 return ntohs(port_src) == 53 || ntohs(port_dst) == 53;
357 static void flow_list_new_entry(struct flow_list *fl, const struct nf_conntrack *ct)
359 struct flow_entry *n;
361 /* We don't want to analyze / display DNS itself, since we
362 * use it to resolve reverse dns.
364 if (nfct_is_dns(ct))
365 return;
367 n = flow_entry_xalloc();
369 n->ct = nfct_clone(ct);
371 flow_entry_update_time(n);
372 flow_entry_from_ct(n, ct);
373 flow_entry_get_extended(n);
375 rcu_assign_pointer(n->next, fl->head);
376 rcu_assign_pointer(fl->head, n);
379 static struct flow_entry *flow_list_find_id(struct flow_list *fl,
380 uint32_t id)
382 struct flow_entry *n = rcu_dereference(fl->head);
384 while (n != NULL) {
385 if (n->flow_id == id)
386 return n;
388 n = rcu_dereference(n->next);
391 return NULL;
394 static struct flow_entry *flow_list_find_prev_id(const struct flow_list *fl,
395 uint32_t id)
397 struct flow_entry *prev = rcu_dereference(fl->head), *next;
399 if (prev->flow_id == id)
400 return NULL;
402 while ((next = rcu_dereference(prev->next)) != NULL) {
403 if (next->flow_id == id)
404 return prev;
406 prev = next;
409 return NULL;
412 static void flow_list_update_entry(struct flow_list *fl,
413 const struct nf_conntrack *ct)
415 struct flow_entry *n;
417 n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
418 if (n == NULL) {
419 flow_list_new_entry(fl, ct);
420 return;
423 flow_entry_from_ct(n, ct);
426 static void flow_list_destroy_entry(struct flow_list *fl,
427 const struct nf_conntrack *ct)
429 struct flow_entry *n1, *n2;
430 uint32_t id = nfct_get_attr_u32(ct, ATTR_ID);
432 n1 = flow_list_find_id(fl, id);
433 if (n1) {
434 n2 = flow_list_find_prev_id(fl, id);
435 if (n2) {
436 rcu_assign_pointer(n2->next, n1->next);
437 n1->next = NULL;
439 flow_entry_xfree(n1);
440 } else {
441 struct flow_entry *next = fl->head->next;
443 flow_entry_xfree(fl->head);
444 fl->head = next;
449 static void flow_list_destroy(struct flow_list *fl)
451 struct flow_entry *n;
453 while (fl->head != NULL) {
454 n = rcu_dereference(fl->head->next);
455 fl->head->next = NULL;
457 flow_entry_xfree(fl->head);
458 rcu_assign_pointer(fl->head, n);
461 synchronize_rcu();
462 spinlock_destroy(&fl->lock);
465 static int walk_process(unsigned int pid, struct flow_entry *n)
467 int ret;
468 DIR *dir;
469 struct dirent *ent;
470 char path[1024];
472 if (snprintf(path, sizeof(path), "/proc/%u/fd", pid) == -1)
473 panic("giant process name! %u\n", pid);
475 dir = opendir(path);
476 if (!dir)
477 return 0;
479 while ((ent = readdir(dir))) {
480 struct stat statbuf;
482 if (snprintf(path, sizeof(path), "/proc/%u/fd/%s",
483 pid, ent->d_name) < 0)
484 continue;
486 if (stat(path, &statbuf) < 0)
487 continue;
489 if (S_ISSOCK(statbuf.st_mode) && (ino_t) n->inode == statbuf.st_ino) {
490 char cmdline[256];
492 ret = proc_get_cmdline(pid, cmdline, sizeof(cmdline));
493 if (ret < 0)
494 panic("Failed to get process cmdline: %s\n", strerror(errno));
496 if (snprintf(n->procname, sizeof(n->procname), "%s", basename(cmdline)) < 0)
497 n->procname[0] = '\0';
498 n->procnum = pid;
499 closedir(dir);
500 return 1;
504 closedir(dir);
505 return 0;
508 static void walk_processes(struct flow_entry *n)
510 int ret;
511 DIR *dir;
512 struct dirent *ent;
514 /* n->inode must be set */
515 if (n->inode <= 0) {
516 n->procname[0] = '\0';
517 return;
520 dir = opendir("/proc");
521 if (!dir)
522 panic("Cannot open /proc: %s\n", strerror(errno));
524 while ((ent = readdir(dir))) {
525 const char *name = ent->d_name;
526 char *end;
527 unsigned int pid = strtoul(name, &end, 10);
529 /* not a PID */
530 if (pid == 0 && end == name)
531 continue;
533 ret = walk_process(pid, n);
534 if (ret > 0)
535 break;
538 closedir(dir);
541 static int get_port_inode(uint16_t port, int proto, bool is_ip6)
543 int ret = -ENOENT;
544 char path[128], buff[1024];
545 FILE *proc;
547 memset(path, 0, sizeof(path));
548 snprintf(path, sizeof(path), "/proc/net/%s%s",
549 l4proto2str[proto], is_ip6 ? "6" : "");
551 proc = fopen(path, "r");
552 if (!proc)
553 return -EIO;
555 memset(buff, 0, sizeof(buff));
557 while (fgets(buff, sizeof(buff), proc) != NULL) {
558 int inode = 0;
559 unsigned int lport = 0;
561 buff[sizeof(buff) - 1] = 0;
562 if (sscanf(buff, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
563 "%*X %*u %*u %u", &lport, &inode) == 2) {
564 if ((uint16_t) lport == port) {
565 ret = inode;
566 break;
570 memset(buff, 0, sizeof(buff));
573 fclose(proc);
574 return ret;
577 #define CP_NFCT(elem, attr, x) \
578 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
579 #define CP_NFCT_BUFF(elem, attr) do { \
580 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
581 if (buff != NULL) \
582 memcpy(n->elem, buff, sizeof(n->elem)); \
583 } while (0)
585 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct)
587 CP_NFCT(l3_proto, ATTR_ORIG_L3PROTO, 8);
588 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
590 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
591 CP_NFCT(ip4_dst_addr, ATTR_ORIG_IPV4_DST, 32);
593 CP_NFCT(port_src, ATTR_ORIG_PORT_SRC, 16);
594 CP_NFCT(port_dst, ATTR_ORIG_PORT_DST, 16);
596 CP_NFCT(status, ATTR_STATUS, 32);
598 CP_NFCT(tcp_state, ATTR_TCP_STATE, 8);
599 CP_NFCT(tcp_flags, ATTR_TCP_FLAGS_ORIG, 8);
600 CP_NFCT(sctp_state, ATTR_SCTP_STATE, 8);
601 CP_NFCT(dccp_state, ATTR_DCCP_STATE, 8);
603 CP_NFCT(pkts_src, ATTR_ORIG_COUNTER_PACKETS, 64);
604 CP_NFCT(bytes_src, ATTR_ORIG_COUNTER_BYTES, 64);
606 CP_NFCT(pkts_dst, ATTR_REPL_COUNTER_PACKETS, 64);
607 CP_NFCT(bytes_dst, ATTR_REPL_COUNTER_BYTES, 64);
609 CP_NFCT(timestamp_start, ATTR_TIMESTAMP_START, 64);
610 CP_NFCT(timestamp_stop, ATTR_TIMESTAMP_STOP, 64);
612 CP_NFCT(flow_id, ATTR_ID, 32);
613 CP_NFCT(use, ATTR_USE, 32);
615 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
616 CP_NFCT_BUFF(ip6_dst_addr, ATTR_ORIG_IPV6_DST);
618 n->port_src = ntohs(n->port_src);
619 n->port_dst = ntohs(n->port_dst);
621 n->ip4_src_addr = ntohl(n->ip4_src_addr);
622 n->ip4_dst_addr = ntohl(n->ip4_dst_addr);
625 #define SELFLD(dir,src_member,dst_member) \
626 (((dir) == FLOW_DIR_SRC) ? n->src_member : n->dst_member)
628 static void flow_entry_get_sain4_obj(const struct flow_entry *n,
629 enum flow_direction dir,
630 struct sockaddr_in *sa)
632 memset(sa, 0, sizeof(*sa));
633 sa->sin_family = PF_INET;
634 sa->sin_addr.s_addr = htonl(SELFLD(dir, ip4_src_addr, ip4_dst_addr));
637 static void flow_entry_get_sain6_obj(const struct flow_entry *n,
638 enum flow_direction dir,
639 struct sockaddr_in6 *sa)
641 memset(sa, 0, sizeof(*sa));
642 sa->sin6_family = PF_INET6;
644 memcpy(&sa->sin6_addr, SELFLD(dir, ip6_src_addr, ip6_dst_addr),
645 sizeof(sa->sin6_addr));
648 static void
649 flow_entry_geo_city_lookup_generic(struct flow_entry *n,
650 enum flow_direction dir)
652 struct sockaddr_in sa4;
653 struct sockaddr_in6 sa6;
654 const char *city = NULL;
656 switch (n->l3_proto) {
657 default:
658 bug();
660 case AF_INET:
661 flow_entry_get_sain4_obj(n, dir, &sa4);
662 city = geoip4_city_name(&sa4);
663 break;
665 case AF_INET6:
666 flow_entry_get_sain6_obj(n, dir, &sa6);
667 city = geoip6_city_name(&sa6);
668 break;
671 build_bug_on(sizeof(n->city_src) != sizeof(n->city_dst));
673 if (city)
674 strlcpy(SELFLD(dir, city_src, city_dst), city,
675 sizeof(n->city_src));
676 else
677 SELFLD(dir, city_src, city_dst)[0] = '\0';
680 static void
681 flow_entry_geo_country_lookup_generic(struct flow_entry *n,
682 enum flow_direction dir)
684 struct sockaddr_in sa4;
685 struct sockaddr_in6 sa6;
686 const char *country = NULL;
688 switch (n->l3_proto) {
689 default:
690 bug();
692 case AF_INET:
693 flow_entry_get_sain4_obj(n, dir, &sa4);
694 country = geoip4_country_name(&sa4);
695 break;
697 case AF_INET6:
698 flow_entry_get_sain6_obj(n, dir, &sa6);
699 country = geoip6_country_name(&sa6);
700 break;
703 build_bug_on(sizeof(n->country_src) != sizeof(n->country_dst));
705 if (country)
706 strlcpy(SELFLD(dir, country_src, country_dst), country,
707 sizeof(n->country_src));
708 else
709 SELFLD(dir, country_src, country_dst)[0] = '\0';
712 static void flow_entry_get_extended_geo(struct flow_entry *n,
713 enum flow_direction dir)
715 if (resolve_geoip) {
716 flow_entry_geo_city_lookup_generic(n, dir);
717 flow_entry_geo_country_lookup_generic(n, dir);
721 static void flow_entry_get_extended_revdns(struct flow_entry *n,
722 enum flow_direction dir)
724 size_t sa_len;
725 struct sockaddr_in sa4;
726 struct sockaddr_in6 sa6;
727 struct sockaddr *sa;
728 struct hostent *hent;
730 build_bug_on(sizeof(n->rev_dns_src) != sizeof(n->rev_dns_dst));
732 switch (n->l3_proto) {
733 default:
734 bug();
736 case AF_INET:
737 flow_entry_get_sain4_obj(n, dir, &sa4);
739 if (!resolve_dns) {
740 inet_ntop(AF_INET, &sa4.sin_addr,
741 SELFLD(dir, rev_dns_src, rev_dns_dst),
742 sizeof(n->rev_dns_src));
743 return;
746 sa = (struct sockaddr *) &sa4;
747 sa_len = sizeof(sa4);
748 hent = gethostbyaddr(&sa4.sin_addr, sizeof(sa4.sin_addr), AF_INET);
749 break;
751 case AF_INET6:
752 flow_entry_get_sain6_obj(n, dir, &sa6);
754 if (!resolve_dns) {
755 inet_ntop(AF_INET6, &sa6.sin6_addr,
756 SELFLD(dir, rev_dns_src, rev_dns_dst),
757 sizeof(n->rev_dns_src));
758 return;
761 sa = (struct sockaddr *) &sa6;
762 sa_len = sizeof(sa6);
763 hent = gethostbyaddr(&sa6.sin6_addr, sizeof(sa6.sin6_addr), AF_INET6);
764 break;
767 getnameinfo(sa, sa_len, SELFLD(dir, rev_dns_src, rev_dns_dst),
768 sizeof(n->rev_dns_src), NULL, 0, NI_NUMERICHOST);
770 if (hent)
771 strlcpy(SELFLD(dir, rev_dns_src, rev_dns_dst), hent->h_name,
772 sizeof(n->rev_dns_src));
775 static void flow_entry_get_extended(struct flow_entry *n)
777 if (n->flow_id == 0)
778 return;
780 if (show_src) {
781 flow_entry_get_extended_revdns(n, FLOW_DIR_SRC);
782 flow_entry_get_extended_geo(n, FLOW_DIR_SRC);
785 flow_entry_get_extended_revdns(n, FLOW_DIR_DST);
786 flow_entry_get_extended_geo(n, FLOW_DIR_DST);
788 /* Lookup application */
789 n->inode = get_port_inode(n->port_src, n->l4_proto,
790 n->l3_proto == AF_INET6);
791 if (n->inode > 0)
792 walk_processes(n);
795 static uint16_t presenter_get_port(uint16_t src, uint16_t dst, bool is_tcp)
797 if (src < dst && src < 1024) {
798 return src;
799 } else if (dst < src && dst < 1024) {
800 return dst;
801 } else {
802 const char *tmp1, *tmp2;
803 if (is_tcp) {
804 tmp1 = lookup_port_tcp(src);
805 tmp2 = lookup_port_tcp(dst);
806 } else {
807 tmp1 = lookup_port_udp(src);
808 tmp2 = lookup_port_udp(dst);
810 if (tmp1 && !tmp2) {
811 return src;
812 } else if (!tmp1 && tmp2) {
813 return dst;
814 } else {
815 if (src < dst)
816 return src;
817 else
818 return dst;
823 static char *bandw2str(double bytes, char *buf, size_t len)
825 if (bytes > 1000000000.)
826 snprintf(buf, len, "%.1fGB", bytes / 1000000000.);
827 else if (bytes > 1000000.)
828 snprintf(buf, len, "%.1fMB", bytes / 1000000.);
829 else if (bytes > 1000.)
830 snprintf(buf, len, "%.1fkB", bytes / 1000.);
831 else
832 snprintf(buf, len, "%g bytes", bytes);
834 return buf;
837 static char *rate2str(double rate, char *buf, size_t len)
839 const char * const unit_fmt[2][4] = {
840 { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%gbit/s" },
841 { "%.1fGB/s", "%.1fMB/s", "%.1fkB/s", "%gB/s" }
844 if (rate_type == RATE_BITS)
845 rate *= 8;
847 if (rate > 1000000000.)
848 snprintf(buf, len, unit_fmt[rate_type][0], rate / 1000000000.);
849 else if (rate > 1000000.)
850 snprintf(buf, len, unit_fmt[rate_type][1], rate / 1000000.);
851 else if (rate > 1000.)
852 snprintf(buf, len, unit_fmt[rate_type][2], rate / 1000.);
853 else
854 snprintf(buf, len, unit_fmt[rate_type][3], rate);
856 return buf;
859 static void presenter_print_counters(uint64_t bytes, uint64_t pkts,
860 double rate_bytes, double rate_pkts,
861 int color)
863 char bytes_str[64];
865 printw(" -> (");
866 attron(COLOR_PAIR(color));
867 printw("%"PRIu64" pkts", pkts);
868 if (rate_pkts) {
869 attron(COLOR_PAIR(3));
870 printw("(%.1fpps)", rate_pkts);
871 attron(COLOR_PAIR(color));
874 printw(", %s", bandw2str(bytes, bytes_str, sizeof(bytes_str) - 1));
875 if (rate_bytes) {
876 attron(COLOR_PAIR(3));
877 printw("(%s)", rate2str(rate_bytes, bytes_str,
878 sizeof(bytes_str) - 1));
879 attron(COLOR_PAIR(color));
881 attroff(COLOR_PAIR(color));
882 printw(")");
885 static void presenter_print_flow_entry_time(const struct flow_entry *n)
887 int h, m, s;
888 time_t now;
890 time(&now);
892 s = now - (n->timestamp_start / NSEC_PER_SEC);
893 if (s <= 0)
894 return;
896 h = s / 3600;
897 s -= h * 3600;
898 m = s / 60;
899 s -= m * 60;
901 printw(" [ time");
902 if (h > 0)
903 printw(" %dh", h);
904 if (m > 0)
905 printw(" %dm", m);
906 if (s > 0)
907 printw(" %ds", s);
908 printw(" ]");
911 static void draw_flow_entry(WINDOW *screen, const struct flow_entry *n,
912 unsigned int *line)
914 char tmp[128], *pname = NULL;
915 uint16_t port;
917 mvwprintw(screen, *line, 2, "");
919 /* PID, application name */
920 if (n->procnum > 0) {
921 slprintf(tmp, sizeof(tmp), "%s(%d)", n->procname, n->procnum);
923 printw("[");
924 attron(COLOR_PAIR(3));
925 printw("%s", tmp);
926 attroff(COLOR_PAIR(3));
927 printw("]:");
930 /* L3 protocol, L4 protocol, states */
931 printw("%s:%s", l3proto2str[n->l3_proto], l4proto2str[n->l4_proto]);
932 printw("[");
933 attron(COLOR_PAIR(3));
934 switch (n->l4_proto) {
935 case IPPROTO_TCP:
936 printw("%s", tcp_state2str[n->tcp_state]);
937 break;
938 case IPPROTO_SCTP:
939 printw("%s", sctp_state2str[n->sctp_state]);
940 break;
941 case IPPROTO_DCCP:
942 printw("%s", dccp_state2str[n->dccp_state]);
943 break;
944 case IPPROTO_UDP:
945 case IPPROTO_UDPLITE:
946 case IPPROTO_ICMP:
947 case IPPROTO_ICMPV6:
948 printw("NOSTATE");
949 break;
951 attroff(COLOR_PAIR(3));
952 printw("]");
954 /* Guess application port */
955 switch (n->l4_proto) {
956 case IPPROTO_TCP:
957 port = presenter_get_port(n->port_src, n->port_dst, true);
958 pname = lookup_port_tcp(port);
959 break;
960 case IPPROTO_UDP:
961 case IPPROTO_UDPLITE:
962 port = presenter_get_port(n->port_src, n->port_dst, false);
963 pname = lookup_port_udp(port);
964 break;
966 if (pname) {
967 attron(A_BOLD);
968 printw(":%s", pname);
969 attroff(A_BOLD);
972 if (n->timestamp_start > 0)
973 presenter_print_flow_entry_time(n);
975 /* Show source information: reverse DNS, port, country, city, counters */
976 if (show_src) {
977 attron(COLOR_PAIR(1));
978 mvwprintw(screen, ++(*line), 8, "src: %s", n->rev_dns_src);
979 attroff(COLOR_PAIR(1));
981 printw(":%"PRIu16, n->port_src);
983 if (n->country_src[0]) {
984 printw(" (");
986 attron(COLOR_PAIR(4));
987 printw("%s", n->country_src);
988 attroff(COLOR_PAIR(4));
990 if (n->city_src[0])
991 printw(", %s", n->city_src);
993 printw(")");
996 if (n->pkts_src > 0 && n->bytes_src > 0)
997 presenter_print_counters(n->bytes_src, n->pkts_src,
998 n->rate_bytes_src,
999 n->rate_pkts_src, 1);
1001 printw(" => ");
1004 /* Show dest information: reverse DNS, port, country, city, counters */
1005 attron(COLOR_PAIR(2));
1006 mvwprintw(screen, ++(*line), 8, "dst: %s", n->rev_dns_dst);
1007 attroff(COLOR_PAIR(2));
1009 printw(":%"PRIu16, n->port_dst);
1011 if (n->country_dst[0]) {
1012 printw(" (");
1014 attron(COLOR_PAIR(4));
1015 printw("%s", n->country_dst);
1016 attroff(COLOR_PAIR(4));
1018 if (n->city_dst[0])
1019 printw(", %s", n->city_dst);
1021 printw(")");
1024 if (n->pkts_dst > 0 && n->bytes_dst > 0)
1025 presenter_print_counters(n->bytes_dst, n->pkts_dst,
1026 n->rate_bytes_dst,
1027 n->rate_pkts_dst, 2);
1030 static inline bool presenter_flow_wrong_state(struct flow_entry *n)
1032 switch (n->l4_proto) {
1033 case IPPROTO_TCP:
1034 switch (n->tcp_state) {
1035 case TCP_CONNTRACK_SYN_SENT:
1036 case TCP_CONNTRACK_SYN_RECV:
1037 case TCP_CONNTRACK_ESTABLISHED:
1038 case TCP_CONNTRACK_FIN_WAIT:
1039 case TCP_CONNTRACK_CLOSE_WAIT:
1040 case TCP_CONNTRACK_LAST_ACK:
1041 case TCP_CONNTRACK_TIME_WAIT:
1042 case TCP_CONNTRACK_CLOSE:
1043 case TCP_CONNTRACK_SYN_SENT2:
1044 case TCP_CONNTRACK_NONE:
1045 return false;
1046 break;
1048 break;
1049 case IPPROTO_SCTP:
1050 switch (n->sctp_state) {
1051 case SCTP_CONNTRACK_NONE:
1052 case SCTP_CONNTRACK_CLOSED:
1053 case SCTP_CONNTRACK_COOKIE_WAIT:
1054 case SCTP_CONNTRACK_COOKIE_ECHOED:
1055 case SCTP_CONNTRACK_ESTABLISHED:
1056 case SCTP_CONNTRACK_SHUTDOWN_SENT:
1057 case SCTP_CONNTRACK_SHUTDOWN_RECD:
1058 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT:
1059 return false;
1060 break;
1062 break;
1063 case IPPROTO_DCCP:
1064 switch (n->dccp_state) {
1065 case DCCP_CONNTRACK_NONE:
1066 case DCCP_CONNTRACK_REQUEST:
1067 case DCCP_CONNTRACK_RESPOND:
1068 case DCCP_CONNTRACK_PARTOPEN:
1069 case DCCP_CONNTRACK_OPEN:
1070 case DCCP_CONNTRACK_CLOSEREQ:
1071 case DCCP_CONNTRACK_CLOSING:
1072 case DCCP_CONNTRACK_TIMEWAIT:
1073 case DCCP_CONNTRACK_IGNORE:
1074 case DCCP_CONNTRACK_INVALID:
1075 return false;
1076 break;
1078 break;
1079 case IPPROTO_UDP:
1080 case IPPROTO_UDPLITE:
1081 case IPPROTO_ICMP:
1082 case IPPROTO_ICMPV6:
1083 return false;
1084 break;
1087 return true;
1090 static void draw_flows(WINDOW *screen, struct flow_list *fl,
1091 int skip_lines)
1093 int skip_left = skip_lines;
1094 unsigned int flows = 0;
1095 unsigned int line = 3;
1096 struct flow_entry *n;
1097 int maxy = rows - 6;
1099 wclear(screen);
1100 clear();
1102 rcu_read_lock();
1104 n = rcu_dereference(fl->head);
1105 if (!n)
1106 mvwprintw(screen, line, 2, "(No active sessions! "
1107 "Is netfilter running?)");
1109 for (; n; n = rcu_dereference(n->next)) {
1110 n->is_visible = false;
1112 if (presenter_flow_wrong_state(n))
1113 continue;
1115 /* count only flows which might be showed */
1116 flows++;
1118 if (maxy <= 0)
1119 continue;
1121 if (skip_left > 0) {
1122 skip_left--;
1123 continue;
1126 n->is_visible = true;
1128 draw_flow_entry(screen, n, &line);
1130 line++;
1131 maxy -= (2 + (show_src ? 1 : 0));
1134 mvwprintw(screen, 1, 2,
1135 "Kernel netfilter flows(%u) for %s%s%s%s%s%s"
1136 "[+%d]", flows, what & INCLUDE_TCP ? "TCP, " : "",
1137 what & INCLUDE_UDP ? "UDP, " : "",
1138 what & INCLUDE_SCTP ? "SCTP, " : "",
1139 what & INCLUDE_DCCP ? "DCCP, " : "",
1140 what & INCLUDE_ICMP && what & INCLUDE_IPV4 ? "ICMP, " : "",
1141 what & INCLUDE_ICMP && what & INCLUDE_IPV6 ? "ICMP6, " : "",
1142 skip_lines);
1144 if (is_flow_collecting)
1145 printw(" [Collecting flows ...]");
1147 rcu_read_unlock();
1150 static void draw_help(WINDOW *screen)
1152 int col = 0;
1153 int row = 0;
1154 int i;
1156 mvaddch(row, col, ACS_ULCORNER);
1157 mvaddch(rows - row - 2, col, ACS_LLCORNER);
1159 mvaddch(row, cols - 1, ACS_URCORNER);
1160 mvaddch(rows - row - 2, cols - col - 1, ACS_LRCORNER);
1162 for (i = 1; i < rows - row - 2; i++) {
1163 mvaddch(row + i, 0, ACS_VLINE);
1164 mvaddch(row + i, cols - col - 1, ACS_VLINE);
1166 for (i = 1; i < cols - col - 1; i++) {
1167 mvaddch(0, col + i, ACS_HLINE);
1168 mvaddch(rows - row - 2, col + i, ACS_HLINE);
1171 attron(A_BOLD);
1172 mvaddnstr(row, cols / 2 - 2, "| Help |", -1);
1174 attron(A_UNDERLINE);
1175 mvaddnstr(row + 2, col + 2, "Navigation", -1);
1176 attroff(A_BOLD | A_UNDERLINE);
1178 mvaddnstr(row + 4, col + 3, "Up, u, k Move up", -1);
1179 mvaddnstr(row + 5, col + 3, "Down, d, j Move down", -1);
1180 mvaddnstr(row + 6, col + 3, "? Toggle help window", -1);
1181 mvaddnstr(row + 7, col + 3, "q, Ctrl+C Quit", -1);
1183 attron(A_BOLD | A_UNDERLINE);
1184 mvaddnstr(row + 9, col + 2, "Display Settings", -1);
1185 attroff(A_BOLD | A_UNDERLINE);
1187 mvaddnstr(row + 11, col + 3, "b Toggle rate units (bits/bytes)", -1);
1190 static void draw_footer(WINDOW *screen)
1192 int i;
1194 attron(A_STANDOUT);
1196 for (i = 0; i < cols; i++)
1197 mvaddch(rows - 1, i, ' ');
1199 mvaddnstr(rows - 1, 1, "Press '?' for help", -1);
1200 addch(ACS_VLINE);
1201 attroff(A_STANDOUT);
1204 static void presenter(void)
1206 int time_sleep_us = 200000;
1207 int time_passed_us = 0;
1208 bool show_help = false;
1209 int skip_lines = 0;
1210 WINDOW *screen;
1212 lookup_init_ports(PORTS_TCP);
1213 lookup_init_ports(PORTS_UDP);
1214 screen = screen_init(false);
1216 start_color();
1217 init_pair(1, COLOR_RED, COLOR_BLACK);
1218 init_pair(2, COLOR_BLUE, COLOR_BLACK);
1219 init_pair(3, COLOR_YELLOW, COLOR_BLACK);
1220 init_pair(4, COLOR_GREEN, COLOR_BLACK);
1222 rcu_register_thread();
1223 while (!sigint) {
1224 bool redraw_flows = true;
1226 curs_set(0);
1227 getmaxyx(screen, rows, cols);
1229 switch (getch()) {
1230 case 'q':
1231 sigint = 1;
1232 break;
1233 case KEY_UP:
1234 case 'u':
1235 case 'k':
1236 skip_lines--;
1237 if (skip_lines < 0)
1238 skip_lines = 0;
1239 break;
1240 case KEY_DOWN:
1241 case 'd':
1242 case 'j':
1243 skip_lines++;
1244 if (skip_lines > SCROLL_MAX)
1245 skip_lines = SCROLL_MAX;
1246 break;
1247 case 'b':
1248 if (rate_type == RATE_BYTES)
1249 rate_type = RATE_BITS;
1250 else
1251 rate_type = RATE_BYTES;
1252 break;
1253 case '?':
1254 if (show_help)
1255 show_help = false;
1256 else
1257 show_help = true;
1259 wclear(screen);
1260 clear();
1261 break;
1262 default:
1263 fflush(stdin);
1264 redraw_flows = false;
1265 break;
1268 if (!redraw_flows)
1269 redraw_flows = time_passed_us >= 1 * USEC_PER_SEC;
1271 if (show_help)
1272 redraw_flows = false;
1274 if (redraw_flows) {
1275 draw_flows(screen, &flow_list, skip_lines);
1276 time_passed_us = 0;
1277 } else {
1278 time_passed_us += time_sleep_us;
1281 if (show_help)
1282 draw_help(screen);
1284 draw_footer(screen);
1286 wrefresh(screen);
1287 refresh();
1288 usleep(time_sleep_us);
1290 rcu_unregister_thread();
1292 screen_end();
1293 lookup_cleanup_ports(PORTS_UDP);
1294 lookup_cleanup_ports(PORTS_TCP);
1297 static int flow_event_cb(enum nf_conntrack_msg_type type,
1298 struct nf_conntrack *ct, void *data __maybe_unused)
1300 if (sigint)
1301 return NFCT_CB_STOP;
1303 synchronize_rcu();
1304 spinlock_lock(&flow_list.lock);
1306 switch (type) {
1307 case NFCT_T_NEW:
1308 flow_list_new_entry(&flow_list, ct);
1309 break;
1310 case NFCT_T_UPDATE:
1311 flow_list_update_entry(&flow_list, ct);
1312 break;
1313 case NFCT_T_DESTROY:
1314 flow_list_destroy_entry(&flow_list, ct);
1315 break;
1316 default:
1317 break;
1320 spinlock_unlock(&flow_list.lock);
1322 return NFCT_CB_CONTINUE;
1325 static void restore_sysctl(void *obj)
1327 struct sysctl_params_ctx *sysctl_ctx = obj;
1329 if (sysctl_ctx->nfct_acct == 0)
1330 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1331 sysctl_ctx->nfct_acct);
1333 if (sysctl_ctx->nfct_tstamp == 0)
1334 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1335 sysctl_ctx->nfct_tstamp);
1338 static void on_panic_handler(void *arg)
1340 restore_sysctl(arg);
1341 screen_end();
1344 static void conntrack_acct_enable(void)
1346 /* We can still work w/o traffic accounting so just warn about error */
1347 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl.nfct_acct)) {
1348 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1349 strerror(errno));
1350 return;
1353 if (sysctl.nfct_acct == 1)
1354 return;
1356 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1357 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1358 strerror(errno));
1362 static void conntrack_tstamp_enable(void)
1364 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl.nfct_tstamp)) {
1365 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1366 strerror(errno));
1367 return;
1370 if (sysctl.nfct_tstamp == 1)
1371 return;
1373 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1374 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1375 strerror(errno));
1379 static int flow_update_cb(enum nf_conntrack_msg_type type,
1380 struct nf_conntrack *ct, void *data __maybe_unused)
1382 struct flow_entry *n;
1384 if (type != NFCT_T_UPDATE)
1385 return NFCT_CB_CONTINUE;
1387 if (sigint)
1388 return NFCT_CB_STOP;
1390 n = flow_list_find_id(&flow_list, 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);
1398 return NFCT_CB_CONTINUE;
1401 static void collector_refresh_flows(struct nfct_handle *handle)
1403 struct flow_entry *n;
1405 n = rcu_dereference(flow_list.head);
1406 for (; n; n = rcu_dereference(n->next)) {
1407 if (!n->is_visible)
1408 continue;
1410 nfct_query(handle, NFCT_Q_GET, n->ct);
1414 static void collector_create_filter(struct nfct_handle *nfct)
1416 struct nfct_filter *filter;
1417 int ret;
1419 filter = nfct_filter_create();
1420 if (!filter)
1421 panic("Cannot create a nfct filter: %s\n", strerror(errno));
1423 if (what & INCLUDE_UDP) {
1424 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
1425 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDPLITE);
1427 if (what & INCLUDE_TCP)
1428 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
1429 if (what & INCLUDE_DCCP)
1430 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_DCCP);
1431 if (what & INCLUDE_SCTP)
1432 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_SCTP);
1433 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1434 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMP);
1435 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1436 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMPV6);
1437 if (what & INCLUDE_IPV4) {
1438 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV4, NFCT_FILTER_LOGIC_NEGATIVE);
1439 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
1441 if (what & INCLUDE_IPV6) {
1442 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV6, NFCT_FILTER_LOGIC_NEGATIVE);
1443 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV6, &filter_ipv6);
1446 ret = nfct_filter_attach(nfct_fd(nfct), filter);
1447 if (ret < 0)
1448 panic("Cannot attach filter to handle: %s\n", strerror(errno));
1450 nfct_filter_destroy(filter);
1453 /* This hand-crafted filter looks ugly but it allows to do not
1454 * flush nfct connections & filter them by user specified filter.
1455 * May be it is better to replace this one by nfct_cmp. */
1456 static int flow_dump_cb(enum nf_conntrack_msg_type type,
1457 struct nf_conntrack *ct, void *data __maybe_unused)
1459 struct flow_entry fl;
1460 struct flow_entry *n = &fl;
1462 if (sigint)
1463 return NFCT_CB_STOP;
1465 synchronize_rcu();
1466 spinlock_lock(&flow_list.lock);
1468 if (!(what & ~(INCLUDE_IPV4 | INCLUDE_IPV6)))
1469 goto check_addr;
1471 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
1473 if (what & INCLUDE_UDP) {
1474 if (n->l4_proto == IPPROTO_UDP)
1475 goto check_addr;
1477 if (n->l4_proto == IPPROTO_UDPLITE)
1478 goto check_addr;
1481 if ((what & INCLUDE_TCP) && n->l4_proto == IPPROTO_TCP)
1482 goto check_addr;
1484 if ((what & INCLUDE_DCCP) && n->l4_proto == IPPROTO_DCCP)
1485 goto check_addr;
1487 if ((what & INCLUDE_SCTP) && n->l4_proto == IPPROTO_SCTP)
1488 goto check_addr;
1490 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV4) &&
1491 n->l4_proto == IPPROTO_ICMP) {
1492 goto check_addr;
1495 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV6) &&
1496 n->l4_proto == IPPROTO_ICMPV6) {
1497 goto check_addr;
1500 goto skip_flow;
1502 check_addr:
1503 /* filter loopback addresses */
1504 if (what & INCLUDE_IPV4) {
1505 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
1507 if (n->ip4_src_addr == filter_ipv4.addr)
1508 goto skip_flow;
1510 if (what & INCLUDE_IPV6) {
1511 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
1513 if (n->ip6_src_addr[0] == 0x0 &&
1514 n->ip6_src_addr[1] == 0x0 &&
1515 n->ip6_src_addr[2] == 0x0 &&
1516 n->ip6_src_addr[3] == 0x1)
1517 goto skip_flow;
1520 flow_list_new_entry(&flow_list, ct);
1522 skip_flow:
1523 spinlock_unlock(&flow_list.lock);
1524 return NFCT_CB_CONTINUE;
1527 static void collector_dump_flows(void)
1529 struct nfct_handle *nfct = nfct_open(CONNTRACK, 0);
1531 if (!nfct)
1532 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1534 nfct_callback_register(nfct, NFCT_T_ALL, flow_dump_cb, NULL);
1536 is_flow_collecting = true;
1537 if (what & INCLUDE_IPV4) {
1538 int family = AF_INET;
1539 nfct_query(nfct, NFCT_Q_DUMP, &family);
1541 if (what & INCLUDE_IPV6) {
1542 int family = AF_INET6;
1543 nfct_query(nfct, NFCT_Q_DUMP, &family);
1545 is_flow_collecting = false;
1547 nfct_close(nfct);
1550 static void *collector(void *null __maybe_unused)
1552 struct nfct_handle *ct_update;
1553 struct nfct_handle *ct_event;
1554 struct pollfd poll_fd[1];
1556 flow_list_init(&flow_list);
1558 ct_event = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW |
1559 NF_NETLINK_CONNTRACK_UPDATE |
1560 NF_NETLINK_CONNTRACK_DESTROY);
1561 if (!ct_event)
1562 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1564 collector_create_filter(ct_event);
1566 nfct_callback_register(ct_event, NFCT_T_ALL, flow_event_cb, NULL);
1568 ct_update = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_UPDATE);
1569 if (!ct_update)
1570 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1572 nfct_callback_register(ct_update, NFCT_T_ALL, flow_update_cb, NULL);
1574 poll_fd[0].fd = nfct_fd(ct_event);
1575 poll_fd[0].events = POLLIN;
1577 if (fcntl(nfct_fd(ct_event), F_SETFL, O_NONBLOCK) == -1)
1578 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1579 strerror(errno));
1581 if (fcntl(nfct_fd(ct_update), 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 usleep(USEC_PER_SEC * interval);
1594 collector_refresh_flows(ct_update);
1596 status = poll(poll_fd, 1, 0);
1597 if (status < 0) {
1598 if (errno == EAGAIN || errno == EINTR)
1599 continue;
1601 panic("Error while polling: %s\n", strerror(errno));
1602 } else if (status == 0) {
1603 continue;
1606 if (poll_fd[0].revents & POLLIN)
1607 nfct_catch(ct_event);
1610 rcu_unregister_thread();
1612 flow_list_destroy(&flow_list);
1613 nfct_close(ct_event);
1614 nfct_close(ct_update);
1616 pthread_exit(NULL);
1619 int main(int argc, char **argv)
1621 pthread_t tid;
1622 int ret, c, opt_index, what_cmd = 0;
1624 setfsuid(getuid());
1625 setfsgid(getgid());
1627 while ((c = getopt_long(argc, argv, short_options, long_options,
1628 &opt_index)) != EOF) {
1629 switch (c) {
1630 case '4':
1631 what_cmd |= INCLUDE_IPV4;
1632 break;
1633 case '6':
1634 what_cmd |= INCLUDE_IPV6;
1635 break;
1636 case 'T':
1637 what_cmd |= INCLUDE_TCP;
1638 break;
1639 case 'U':
1640 what_cmd |= INCLUDE_UDP;
1641 break;
1642 case 'D':
1643 what_cmd |= INCLUDE_DCCP;
1644 break;
1645 case 'I':
1646 what_cmd |= INCLUDE_ICMP;
1647 break;
1648 case 'S':
1649 what_cmd |= INCLUDE_SCTP;
1650 break;
1651 case 's':
1652 show_src = true;
1653 break;
1654 case 'b':
1655 rate_type = RATE_BITS;
1656 break;
1657 case 'u':
1658 update_geoip();
1659 die();
1660 break;
1661 case 't':
1662 interval = strtoul(optarg, NULL, 10);
1663 break;
1664 case 'n':
1665 resolve_dns = false;
1666 break;
1667 case 'G':
1668 resolve_geoip = false;
1669 break;
1670 case 'h':
1671 help();
1672 break;
1673 case 'v':
1674 version();
1675 break;
1676 default:
1677 break;
1681 if (what_cmd > 0) {
1682 what = what_cmd;
1684 if (!(what & (INCLUDE_IPV4 | INCLUDE_IPV6)))
1685 what |= INCLUDE_IPV4 | INCLUDE_IPV6;
1688 rcu_init();
1690 register_signal(SIGINT, signal_handler);
1691 register_signal(SIGQUIT, signal_handler);
1692 register_signal(SIGTERM, signal_handler);
1693 register_signal(SIGHUP, signal_handler);
1695 panic_handler_add(on_panic_handler, &sysctl);
1697 conntrack_acct_enable();
1698 conntrack_tstamp_enable();
1700 if (resolve_geoip)
1701 init_geoip(1);
1703 ret = pthread_create(&tid, NULL, collector, NULL);
1704 if (ret < 0)
1705 panic("Cannot create phthread!\n");
1707 presenter();
1709 if (resolve_geoip)
1710 destroy_geoip();
1712 restore_sysctl(&sysctl);
1714 return 0;