lookup: Make lookup type and function names more generic
[netsniff-ng.git] / flowtop.c
blobcf0e478ad885722dc2b4c0b18d5c25f48f591d77
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;
130 static bool show_active_only = false;
132 static const char *short_options = "vhTUsDIS46ut:nGb";
133 static const struct option long_options[] = {
134 {"ipv4", no_argument, NULL, '4'},
135 {"ipv6", no_argument, NULL, '6'},
136 {"tcp", no_argument, NULL, 'T'},
137 {"udp", no_argument, NULL, 'U'},
138 {"dccp", no_argument, NULL, 'D'},
139 {"icmp", no_argument, NULL, 'I'},
140 {"sctp", no_argument, NULL, 'S'},
141 {"no-dns", no_argument, NULL, 'n'},
142 {"no-geoip", no_argument, NULL, 'G'},
143 {"show-src", no_argument, NULL, 's'},
144 {"bits", no_argument, NULL, 'b'},
145 {"update", no_argument, NULL, 'u'},
146 {"interval", required_argument, NULL, 't'},
147 {"version", no_argument, NULL, 'v'},
148 {"help", no_argument, NULL, 'h'},
149 {NULL, 0, NULL, 0}
152 static const char *copyright = "Please report bugs to <netsniff-ng@googlegroups.com>\n"
153 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
154 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
155 "Swiss federal institute of technology (ETH Zurich)\n"
156 "License: GNU GPL version 2.0\n"
157 "This is free software: you are free to change and redistribute it.\n"
158 "There is NO WARRANTY, to the extent permitted by law.";
160 static const char *const l3proto2str[AF_MAX] = {
161 [AF_INET] = "ipv4",
162 [AF_INET6] = "ipv6",
165 static const char *const l4proto2str[IPPROTO_MAX] = {
166 [IPPROTO_TCP] = "tcp",
167 [IPPROTO_UDP] = "udp",
168 [IPPROTO_UDPLITE] = "udplite",
169 [IPPROTO_ICMP] = "icmp",
170 [IPPROTO_ICMPV6] = "icmpv6",
171 [IPPROTO_SCTP] = "sctp",
172 [IPPROTO_GRE] = "gre",
173 [IPPROTO_DCCP] = "dccp",
174 [IPPROTO_IGMP] = "igmp",
175 [IPPROTO_IPIP] = "ipip",
176 [IPPROTO_EGP] = "egp",
177 [IPPROTO_PUP] = "pup",
178 [IPPROTO_IDP] = "idp",
179 [IPPROTO_RSVP] = "rsvp",
180 [IPPROTO_IPV6] = "ip6tun",
181 [IPPROTO_ESP] = "esp",
182 [IPPROTO_AH] = "ah",
183 [IPPROTO_PIM] = "pim",
184 [IPPROTO_COMP] = "comp",
187 static const char *const tcp_state2str[TCP_CONNTRACK_MAX] = {
188 [TCP_CONNTRACK_NONE] = "NOSTATE",
189 [TCP_CONNTRACK_SYN_SENT] = "SYN_SENT",
190 [TCP_CONNTRACK_SYN_RECV] = "SYN_RECV",
191 [TCP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
192 [TCP_CONNTRACK_FIN_WAIT] = "FIN_WAIT",
193 [TCP_CONNTRACK_CLOSE_WAIT] = "CLOSE_WAIT",
194 [TCP_CONNTRACK_LAST_ACK] = "LAST_ACK",
195 [TCP_CONNTRACK_TIME_WAIT] = "TIME_WAIT",
196 [TCP_CONNTRACK_CLOSE] = "CLOSE",
197 [TCP_CONNTRACK_SYN_SENT2] = "SYN_SENT2",
200 static const char *const dccp_state2str[DCCP_CONNTRACK_MAX] = {
201 [DCCP_CONNTRACK_NONE] = "NOSTATE",
202 [DCCP_CONNTRACK_REQUEST] = "REQUEST",
203 [DCCP_CONNTRACK_RESPOND] = "RESPOND",
204 [DCCP_CONNTRACK_PARTOPEN] = "PARTOPEN",
205 [DCCP_CONNTRACK_OPEN] = "OPEN",
206 [DCCP_CONNTRACK_CLOSEREQ] = "CLOSEREQ",
207 [DCCP_CONNTRACK_CLOSING] = "CLOSING",
208 [DCCP_CONNTRACK_TIMEWAIT] = "TIMEWAIT",
209 [DCCP_CONNTRACK_IGNORE] = "IGNORE",
210 [DCCP_CONNTRACK_INVALID] = "INVALID",
213 static const char *const sctp_state2str[SCTP_CONNTRACK_MAX] = {
214 [SCTP_CONNTRACK_NONE] = "NOSTATE",
215 [SCTP_CONNTRACK_CLOSED] = "CLOSED",
216 [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE_WAIT",
217 [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE_ECHOED",
218 [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
219 [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTDOWN_SENT",
220 [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTDOWN_RECD",
221 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT",
224 static const struct nfct_filter_ipv4 filter_ipv4 = {
225 .addr = __constant_htonl(INADDR_LOOPBACK),
226 .mask = 0xffffffff,
229 static const struct nfct_filter_ipv6 filter_ipv6 = {
230 .addr = { 0x0, 0x0, 0x0, 0x1 },
231 .mask = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
234 static int64_t time_after_us(struct timeval *tv)
236 struct timeval now;
238 bug_on(gettimeofday(&now, NULL));
240 now.tv_sec -= tv->tv_sec;
241 now.tv_usec -= tv->tv_usec;
243 return now.tv_sec * USEC_PER_SEC + now.tv_usec;
246 static void signal_handler(int number)
248 switch (number) {
249 case SIGINT:
250 case SIGQUIT:
251 case SIGTERM:
252 sigint = 1;
253 break;
254 case SIGHUP:
255 default:
256 break;
260 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct);
261 static void flow_entry_get_extended(struct flow_entry *n);
263 static void help(void)
265 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
266 VERSION_STRING);
267 puts("http://www.netsniff-ng.org\n\n"
268 "Usage: flowtop [options]\n"
269 "Options:\n"
270 " -4|--ipv4 Show only IPv4 flows (default)\n"
271 " -6|--ipv6 Show only IPv6 flows (default)\n"
272 " -T|--tcp Show only TCP flows (default)\n"
273 " -U|--udp Show only UDP flows\n"
274 " -D|--dccp Show only DCCP flows\n"
275 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
276 " -S|--sctp Show only SCTP flows\n"
277 " -n|--no-dns Don't perform hostname lookup\n"
278 " -G|--no-geoip Don't perform GeoIP lookup\n"
279 " -s|--show-src Also show source, not only dest\n"
280 " -b|--bits Show rates in bits/s instead of bytes/s\n"
281 " -u|--update Update GeoIP databases\n"
282 " -t|--interval <time> Refresh time in seconds (default 1s)\n"
283 " -v|--version Print version and exit\n"
284 " -h|--help Print this help and exit\n\n"
285 "Examples:\n"
286 " flowtop\n"
287 " flowtop -46UTDISs\n\n"
288 "Note:\n"
289 " If netfilter is not running, you can activate it with e.g.:\n"
290 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
291 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
292 puts(copyright);
293 die();
296 static void version(void)
298 printf("flowtop %s, Git id: %s\n", VERSION_LONG, GITVERSION);
299 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
300 "http://www.netsniff-ng.org\n");
301 puts(copyright);
302 die();
305 static void flow_entry_update_time(struct flow_entry *n)
307 bug_on(gettimeofday(&n->last_update, NULL));
310 #define CALC_RATE(fld) do { \
311 n->rate_##fld = (((fld) > n->fld) ? (((fld) - n->fld) / sec) : 0); \
312 } while (0)
314 static void flow_entry_calc_rate(struct flow_entry *n, const struct nf_conntrack *ct)
316 uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES);
317 uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES);
318 uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS);
319 uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS);
320 double sec = (double)time_after_us(&n->last_update) / USEC_PER_SEC;
322 if (sec < 1)
323 return;
325 CALC_RATE(bytes_src);
326 CALC_RATE(bytes_dst);
327 CALC_RATE(pkts_src);
328 CALC_RATE(pkts_dst);
331 static inline struct flow_entry *flow_entry_xalloc(void)
333 return xzmalloc(sizeof(struct flow_entry));
336 static inline void flow_entry_xfree(struct flow_entry *n)
338 if (n->ct)
339 nfct_destroy(n->ct);
341 xfree(n);
344 static inline void flow_list_init(struct flow_list *fl)
346 fl->head = NULL;
347 spinlock_init(&fl->lock);
350 static inline bool nfct_is_dns(const struct nf_conntrack *ct)
352 uint16_t port_src = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
353 uint16_t port_dst = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
355 return ntohs(port_src) == 53 || ntohs(port_dst) == 53;
358 static void flow_list_new_entry(struct flow_list *fl, const struct nf_conntrack *ct)
360 struct flow_entry *n;
362 /* We don't want to analyze / display DNS itself, since we
363 * use it to resolve reverse dns.
365 if (nfct_is_dns(ct))
366 return;
368 n = flow_entry_xalloc();
370 n->ct = nfct_clone(ct);
372 flow_entry_update_time(n);
373 flow_entry_from_ct(n, ct);
374 flow_entry_get_extended(n);
376 rcu_assign_pointer(n->next, fl->head);
377 rcu_assign_pointer(fl->head, n);
379 n->is_visible = true;
382 static struct flow_entry *flow_list_find_id(struct flow_list *fl,
383 uint32_t id)
385 struct flow_entry *n = rcu_dereference(fl->head);
387 while (n != NULL) {
388 if (n->flow_id == id)
389 return n;
391 n = rcu_dereference(n->next);
394 return NULL;
397 static struct flow_entry *flow_list_find_prev_id(const struct flow_list *fl,
398 uint32_t id)
400 struct flow_entry *prev = rcu_dereference(fl->head), *next;
402 if (prev->flow_id == id)
403 return NULL;
405 while ((next = rcu_dereference(prev->next)) != NULL) {
406 if (next->flow_id == id)
407 return prev;
409 prev = next;
412 return NULL;
415 static void flow_list_update_entry(struct flow_list *fl,
416 const struct nf_conntrack *ct)
418 struct flow_entry *n;
420 n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
421 if (n == NULL) {
422 flow_list_new_entry(fl, ct);
423 return;
426 flow_entry_from_ct(n, ct);
429 static void flow_list_destroy_entry(struct flow_list *fl,
430 const struct nf_conntrack *ct)
432 struct flow_entry *n1, *n2;
433 uint32_t id = nfct_get_attr_u32(ct, ATTR_ID);
435 n1 = flow_list_find_id(fl, id);
436 if (n1) {
437 n2 = flow_list_find_prev_id(fl, id);
438 if (n2) {
439 rcu_assign_pointer(n2->next, n1->next);
440 n1->next = NULL;
442 flow_entry_xfree(n1);
443 } else {
444 struct flow_entry *next = fl->head->next;
446 flow_entry_xfree(fl->head);
447 fl->head = next;
452 static void flow_list_destroy(struct flow_list *fl)
454 struct flow_entry *n;
456 while (fl->head != NULL) {
457 n = rcu_dereference(fl->head->next);
458 fl->head->next = NULL;
460 flow_entry_xfree(fl->head);
461 rcu_assign_pointer(fl->head, n);
464 synchronize_rcu();
465 spinlock_destroy(&fl->lock);
468 static int walk_process(unsigned int pid, struct flow_entry *n)
470 int ret;
471 DIR *dir;
472 struct dirent *ent;
473 char path[1024];
475 if (snprintf(path, sizeof(path), "/proc/%u/fd", pid) == -1)
476 panic("giant process name! %u\n", pid);
478 dir = opendir(path);
479 if (!dir)
480 return 0;
482 while ((ent = readdir(dir))) {
483 struct stat statbuf;
485 if (snprintf(path, sizeof(path), "/proc/%u/fd/%s",
486 pid, ent->d_name) < 0)
487 continue;
489 if (stat(path, &statbuf) < 0)
490 continue;
492 if (S_ISSOCK(statbuf.st_mode) && (ino_t) n->inode == statbuf.st_ino) {
493 char cmdline[256];
495 ret = proc_get_cmdline(pid, cmdline, sizeof(cmdline));
496 if (ret < 0)
497 panic("Failed to get process cmdline: %s\n", strerror(errno));
499 if (snprintf(n->procname, sizeof(n->procname), "%s", basename(cmdline)) < 0)
500 n->procname[0] = '\0';
501 n->procnum = pid;
502 closedir(dir);
503 return 1;
507 closedir(dir);
508 return 0;
511 static void walk_processes(struct flow_entry *n)
513 int ret;
514 DIR *dir;
515 struct dirent *ent;
517 /* n->inode must be set */
518 if (n->inode <= 0) {
519 n->procname[0] = '\0';
520 return;
523 dir = opendir("/proc");
524 if (!dir)
525 panic("Cannot open /proc: %s\n", strerror(errno));
527 while ((ent = readdir(dir))) {
528 const char *name = ent->d_name;
529 char *end;
530 unsigned int pid = strtoul(name, &end, 10);
532 /* not a PID */
533 if (pid == 0 && end == name)
534 continue;
536 ret = walk_process(pid, n);
537 if (ret > 0)
538 break;
541 closedir(dir);
544 static int get_port_inode(uint16_t port, int proto, bool is_ip6)
546 int ret = -ENOENT;
547 char path[128], buff[1024];
548 FILE *proc;
550 memset(path, 0, sizeof(path));
551 snprintf(path, sizeof(path), "/proc/net/%s%s",
552 l4proto2str[proto], is_ip6 ? "6" : "");
554 proc = fopen(path, "r");
555 if (!proc)
556 return -EIO;
558 memset(buff, 0, sizeof(buff));
560 while (fgets(buff, sizeof(buff), proc) != NULL) {
561 int inode = 0;
562 unsigned int lport = 0;
564 buff[sizeof(buff) - 1] = 0;
565 if (sscanf(buff, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
566 "%*X %*u %*u %u", &lport, &inode) == 2) {
567 if ((uint16_t) lport == port) {
568 ret = inode;
569 break;
573 memset(buff, 0, sizeof(buff));
576 fclose(proc);
577 return ret;
580 #define CP_NFCT(elem, attr, x) \
581 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
582 #define CP_NFCT_BUFF(elem, attr) do { \
583 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
584 if (buff != NULL) \
585 memcpy(n->elem, buff, sizeof(n->elem)); \
586 } while (0)
588 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct)
590 CP_NFCT(l3_proto, ATTR_ORIG_L3PROTO, 8);
591 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
593 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
594 CP_NFCT(ip4_dst_addr, ATTR_ORIG_IPV4_DST, 32);
596 CP_NFCT(port_src, ATTR_ORIG_PORT_SRC, 16);
597 CP_NFCT(port_dst, ATTR_ORIG_PORT_DST, 16);
599 CP_NFCT(status, ATTR_STATUS, 32);
601 CP_NFCT(tcp_state, ATTR_TCP_STATE, 8);
602 CP_NFCT(tcp_flags, ATTR_TCP_FLAGS_ORIG, 8);
603 CP_NFCT(sctp_state, ATTR_SCTP_STATE, 8);
604 CP_NFCT(dccp_state, ATTR_DCCP_STATE, 8);
606 CP_NFCT(pkts_src, ATTR_ORIG_COUNTER_PACKETS, 64);
607 CP_NFCT(bytes_src, ATTR_ORIG_COUNTER_BYTES, 64);
609 CP_NFCT(pkts_dst, ATTR_REPL_COUNTER_PACKETS, 64);
610 CP_NFCT(bytes_dst, ATTR_REPL_COUNTER_BYTES, 64);
612 CP_NFCT(timestamp_start, ATTR_TIMESTAMP_START, 64);
613 CP_NFCT(timestamp_stop, ATTR_TIMESTAMP_STOP, 64);
615 CP_NFCT(flow_id, ATTR_ID, 32);
616 CP_NFCT(use, ATTR_USE, 32);
618 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
619 CP_NFCT_BUFF(ip6_dst_addr, ATTR_ORIG_IPV6_DST);
621 n->port_src = ntohs(n->port_src);
622 n->port_dst = ntohs(n->port_dst);
624 n->ip4_src_addr = ntohl(n->ip4_src_addr);
625 n->ip4_dst_addr = ntohl(n->ip4_dst_addr);
628 #define SELFLD(dir,src_member,dst_member) \
629 (((dir) == FLOW_DIR_SRC) ? n->src_member : n->dst_member)
631 static void flow_entry_get_sain4_obj(const struct flow_entry *n,
632 enum flow_direction dir,
633 struct sockaddr_in *sa)
635 memset(sa, 0, sizeof(*sa));
636 sa->sin_family = PF_INET;
637 sa->sin_addr.s_addr = htonl(SELFLD(dir, ip4_src_addr, ip4_dst_addr));
640 static void flow_entry_get_sain6_obj(const struct flow_entry *n,
641 enum flow_direction dir,
642 struct sockaddr_in6 *sa)
644 memset(sa, 0, sizeof(*sa));
645 sa->sin6_family = PF_INET6;
647 memcpy(&sa->sin6_addr, SELFLD(dir, ip6_src_addr, ip6_dst_addr),
648 sizeof(sa->sin6_addr));
651 static void
652 flow_entry_geo_city_lookup_generic(struct flow_entry *n,
653 enum flow_direction dir)
655 struct sockaddr_in sa4;
656 struct sockaddr_in6 sa6;
657 const char *city = NULL;
659 switch (n->l3_proto) {
660 default:
661 bug();
663 case AF_INET:
664 flow_entry_get_sain4_obj(n, dir, &sa4);
665 city = geoip4_city_name(&sa4);
666 break;
668 case AF_INET6:
669 flow_entry_get_sain6_obj(n, dir, &sa6);
670 city = geoip6_city_name(&sa6);
671 break;
674 build_bug_on(sizeof(n->city_src) != sizeof(n->city_dst));
676 if (city)
677 strlcpy(SELFLD(dir, city_src, city_dst), city,
678 sizeof(n->city_src));
679 else
680 SELFLD(dir, city_src, city_dst)[0] = '\0';
683 static void
684 flow_entry_geo_country_lookup_generic(struct flow_entry *n,
685 enum flow_direction dir)
687 struct sockaddr_in sa4;
688 struct sockaddr_in6 sa6;
689 const char *country = NULL;
691 switch (n->l3_proto) {
692 default:
693 bug();
695 case AF_INET:
696 flow_entry_get_sain4_obj(n, dir, &sa4);
697 country = geoip4_country_name(&sa4);
698 break;
700 case AF_INET6:
701 flow_entry_get_sain6_obj(n, dir, &sa6);
702 country = geoip6_country_name(&sa6);
703 break;
706 build_bug_on(sizeof(n->country_src) != sizeof(n->country_dst));
708 if (country)
709 strlcpy(SELFLD(dir, country_src, country_dst), country,
710 sizeof(n->country_src));
711 else
712 SELFLD(dir, country_src, country_dst)[0] = '\0';
715 static void flow_entry_get_extended_geo(struct flow_entry *n,
716 enum flow_direction dir)
718 if (resolve_geoip) {
719 flow_entry_geo_city_lookup_generic(n, dir);
720 flow_entry_geo_country_lookup_generic(n, dir);
724 static void flow_entry_get_extended_revdns(struct flow_entry *n,
725 enum flow_direction dir)
727 size_t sa_len;
728 struct sockaddr_in sa4;
729 struct sockaddr_in6 sa6;
730 struct sockaddr *sa;
731 struct hostent *hent;
733 build_bug_on(sizeof(n->rev_dns_src) != sizeof(n->rev_dns_dst));
735 switch (n->l3_proto) {
736 default:
737 bug();
739 case AF_INET:
740 flow_entry_get_sain4_obj(n, dir, &sa4);
742 if (!resolve_dns) {
743 inet_ntop(AF_INET, &sa4.sin_addr,
744 SELFLD(dir, rev_dns_src, rev_dns_dst),
745 sizeof(n->rev_dns_src));
746 return;
749 sa = (struct sockaddr *) &sa4;
750 sa_len = sizeof(sa4);
751 hent = gethostbyaddr(&sa4.sin_addr, sizeof(sa4.sin_addr), AF_INET);
752 break;
754 case AF_INET6:
755 flow_entry_get_sain6_obj(n, dir, &sa6);
757 if (!resolve_dns) {
758 inet_ntop(AF_INET6, &sa6.sin6_addr,
759 SELFLD(dir, rev_dns_src, rev_dns_dst),
760 sizeof(n->rev_dns_src));
761 return;
764 sa = (struct sockaddr *) &sa6;
765 sa_len = sizeof(sa6);
766 hent = gethostbyaddr(&sa6.sin6_addr, sizeof(sa6.sin6_addr), AF_INET6);
767 break;
770 getnameinfo(sa, sa_len, SELFLD(dir, rev_dns_src, rev_dns_dst),
771 sizeof(n->rev_dns_src), NULL, 0, NI_NUMERICHOST);
773 if (hent)
774 strlcpy(SELFLD(dir, rev_dns_src, rev_dns_dst), hent->h_name,
775 sizeof(n->rev_dns_src));
778 static void flow_entry_get_extended(struct flow_entry *n)
780 if (n->flow_id == 0)
781 return;
783 if (show_src) {
784 flow_entry_get_extended_revdns(n, FLOW_DIR_SRC);
785 flow_entry_get_extended_geo(n, FLOW_DIR_SRC);
788 flow_entry_get_extended_revdns(n, FLOW_DIR_DST);
789 flow_entry_get_extended_geo(n, FLOW_DIR_DST);
791 /* Lookup application */
792 n->inode = get_port_inode(n->port_src, n->l4_proto,
793 n->l3_proto == AF_INET6);
794 if (n->inode > 0)
795 walk_processes(n);
798 static uint16_t presenter_get_port(uint16_t src, uint16_t dst, bool is_tcp)
800 if (src < dst && src < 1024) {
801 return src;
802 } else if (dst < src && dst < 1024) {
803 return dst;
804 } else {
805 const char *tmp1, *tmp2;
806 if (is_tcp) {
807 tmp1 = lookup_port_tcp(src);
808 tmp2 = lookup_port_tcp(dst);
809 } else {
810 tmp1 = lookup_port_udp(src);
811 tmp2 = lookup_port_udp(dst);
813 if (tmp1 && !tmp2) {
814 return src;
815 } else if (!tmp1 && tmp2) {
816 return dst;
817 } else {
818 if (src < dst)
819 return src;
820 else
821 return dst;
826 static char *bandw2str(double bytes, char *buf, size_t len)
828 if (bytes > 1000000000.)
829 snprintf(buf, len, "%.1fGB", bytes / 1000000000.);
830 else if (bytes > 1000000.)
831 snprintf(buf, len, "%.1fMB", bytes / 1000000.);
832 else if (bytes > 1000.)
833 snprintf(buf, len, "%.1fkB", bytes / 1000.);
834 else
835 snprintf(buf, len, "%g bytes", bytes);
837 return buf;
840 static char *rate2str(double rate, char *buf, size_t len)
842 const char * const unit_fmt[2][4] = {
843 { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%gbit/s" },
844 { "%.1fGB/s", "%.1fMB/s", "%.1fkB/s", "%gB/s" }
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 void presenter_print_counters(uint64_t bytes, uint64_t pkts,
863 double rate_bytes, double rate_pkts,
864 int color)
866 char bytes_str[64];
868 printw(" -> (");
869 attron(COLOR_PAIR(color));
870 printw("%"PRIu64" pkts", pkts);
871 if (rate_pkts) {
872 attron(COLOR_PAIR(3));
873 printw("(%.1fpps)", rate_pkts);
874 attron(COLOR_PAIR(color));
877 printw(", %s", bandw2str(bytes, bytes_str, sizeof(bytes_str) - 1));
878 if (rate_bytes) {
879 attron(COLOR_PAIR(3));
880 printw("(%s)", rate2str(rate_bytes, bytes_str,
881 sizeof(bytes_str) - 1));
882 attron(COLOR_PAIR(color));
884 attroff(COLOR_PAIR(color));
885 printw(")");
888 static void presenter_print_flow_entry_time(const struct flow_entry *n)
890 int h, m, s;
891 time_t now;
893 time(&now);
895 s = now - (n->timestamp_start / NSEC_PER_SEC);
896 if (s <= 0)
897 return;
899 h = s / 3600;
900 s -= h * 3600;
901 m = s / 60;
902 s -= m * 60;
904 printw(" [ time");
905 if (h > 0)
906 printw(" %dh", h);
907 if (m > 0)
908 printw(" %dm", m);
909 if (s > 0)
910 printw(" %ds", s);
911 printw(" ]");
914 static void draw_flow_entry(WINDOW *screen, const struct flow_entry *n,
915 unsigned int *line)
917 char tmp[128], *pname = NULL;
918 uint16_t port;
920 mvwprintw(screen, *line, 2, "");
922 /* PID, application name */
923 if (n->procnum > 0) {
924 slprintf(tmp, sizeof(tmp), "%s(%d)", n->procname, n->procnum);
926 printw("[");
927 attron(COLOR_PAIR(3));
928 printw("%s", tmp);
929 attroff(COLOR_PAIR(3));
930 printw("]:");
933 /* L3 protocol, L4 protocol, states */
934 printw("%s:%s", l3proto2str[n->l3_proto], l4proto2str[n->l4_proto]);
935 printw("[");
936 attron(COLOR_PAIR(3));
937 switch (n->l4_proto) {
938 case IPPROTO_TCP:
939 printw("%s", tcp_state2str[n->tcp_state]);
940 break;
941 case IPPROTO_SCTP:
942 printw("%s", sctp_state2str[n->sctp_state]);
943 break;
944 case IPPROTO_DCCP:
945 printw("%s", dccp_state2str[n->dccp_state]);
946 break;
947 case IPPROTO_UDP:
948 case IPPROTO_UDPLITE:
949 case IPPROTO_ICMP:
950 case IPPROTO_ICMPV6:
951 printw("NOSTATE");
952 break;
954 attroff(COLOR_PAIR(3));
955 printw("]");
957 /* Guess application port */
958 switch (n->l4_proto) {
959 case IPPROTO_TCP:
960 port = presenter_get_port(n->port_src, n->port_dst, true);
961 pname = lookup_port_tcp(port);
962 break;
963 case IPPROTO_UDP:
964 case IPPROTO_UDPLITE:
965 port = presenter_get_port(n->port_src, n->port_dst, false);
966 pname = lookup_port_udp(port);
967 break;
969 if (pname) {
970 attron(A_BOLD);
971 printw(":%s", pname);
972 attroff(A_BOLD);
975 if (n->timestamp_start > 0)
976 presenter_print_flow_entry_time(n);
978 /* Show source information: reverse DNS, port, country, city, counters */
979 if (show_src) {
980 attron(COLOR_PAIR(1));
981 mvwprintw(screen, ++(*line), 8, "src: %s", n->rev_dns_src);
982 attroff(COLOR_PAIR(1));
984 printw(":%"PRIu16, n->port_src);
986 if (n->country_src[0]) {
987 printw(" (");
989 attron(COLOR_PAIR(4));
990 printw("%s", n->country_src);
991 attroff(COLOR_PAIR(4));
993 if (n->city_src[0])
994 printw(", %s", n->city_src);
996 printw(")");
999 if (n->pkts_src > 0 && n->bytes_src > 0)
1000 presenter_print_counters(n->bytes_src, n->pkts_src,
1001 n->rate_bytes_src,
1002 n->rate_pkts_src, 1);
1004 printw(" => ");
1007 /* Show dest information: reverse DNS, port, country, city, counters */
1008 attron(COLOR_PAIR(2));
1009 mvwprintw(screen, ++(*line), 8, "dst: %s", n->rev_dns_dst);
1010 attroff(COLOR_PAIR(2));
1012 printw(":%"PRIu16, n->port_dst);
1014 if (n->country_dst[0]) {
1015 printw(" (");
1017 attron(COLOR_PAIR(4));
1018 printw("%s", n->country_dst);
1019 attroff(COLOR_PAIR(4));
1021 if (n->city_dst[0])
1022 printw(", %s", n->city_dst);
1024 printw(")");
1027 if (n->pkts_dst > 0 && n->bytes_dst > 0)
1028 presenter_print_counters(n->bytes_dst, n->pkts_dst,
1029 n->rate_bytes_dst,
1030 n->rate_pkts_dst, 2);
1033 static inline bool presenter_flow_wrong_state(struct flow_entry *n)
1035 switch (n->l4_proto) {
1036 case IPPROTO_TCP:
1037 switch (n->tcp_state) {
1038 case TCP_CONNTRACK_SYN_SENT:
1039 case TCP_CONNTRACK_SYN_RECV:
1040 case TCP_CONNTRACK_ESTABLISHED:
1041 case TCP_CONNTRACK_FIN_WAIT:
1042 case TCP_CONNTRACK_CLOSE_WAIT:
1043 case TCP_CONNTRACK_LAST_ACK:
1044 case TCP_CONNTRACK_TIME_WAIT:
1045 case TCP_CONNTRACK_CLOSE:
1046 case TCP_CONNTRACK_SYN_SENT2:
1047 case TCP_CONNTRACK_NONE:
1048 return false;
1049 break;
1051 break;
1052 case IPPROTO_SCTP:
1053 switch (n->sctp_state) {
1054 case SCTP_CONNTRACK_NONE:
1055 case SCTP_CONNTRACK_CLOSED:
1056 case SCTP_CONNTRACK_COOKIE_WAIT:
1057 case SCTP_CONNTRACK_COOKIE_ECHOED:
1058 case SCTP_CONNTRACK_ESTABLISHED:
1059 case SCTP_CONNTRACK_SHUTDOWN_SENT:
1060 case SCTP_CONNTRACK_SHUTDOWN_RECD:
1061 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT:
1062 return false;
1063 break;
1065 break;
1066 case IPPROTO_DCCP:
1067 switch (n->dccp_state) {
1068 case DCCP_CONNTRACK_NONE:
1069 case DCCP_CONNTRACK_REQUEST:
1070 case DCCP_CONNTRACK_RESPOND:
1071 case DCCP_CONNTRACK_PARTOPEN:
1072 case DCCP_CONNTRACK_OPEN:
1073 case DCCP_CONNTRACK_CLOSEREQ:
1074 case DCCP_CONNTRACK_CLOSING:
1075 case DCCP_CONNTRACK_TIMEWAIT:
1076 case DCCP_CONNTRACK_IGNORE:
1077 case DCCP_CONNTRACK_INVALID:
1078 return false;
1079 break;
1081 break;
1082 case IPPROTO_UDP:
1083 case IPPROTO_UDPLITE:
1084 case IPPROTO_ICMP:
1085 case IPPROTO_ICMPV6:
1086 return false;
1087 break;
1090 return true;
1093 static void draw_flows(WINDOW *screen, struct flow_list *fl,
1094 int skip_lines)
1096 int skip_left = skip_lines;
1097 unsigned int flows = 0;
1098 unsigned int line = 3;
1099 struct flow_entry *n;
1100 int maxy = rows - 6;
1102 wclear(screen);
1103 clear();
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 for (; n; n = rcu_dereference(n->next)) {
1113 if (!n->is_visible)
1114 continue;
1116 if (presenter_flow_wrong_state(n))
1117 continue;
1119 /* count only flows which might be showed */
1120 flows++;
1122 if (maxy <= 0)
1123 continue;
1125 if (skip_left > 0) {
1126 skip_left--;
1127 continue;
1130 draw_flow_entry(screen, n, &line);
1132 line++;
1133 maxy -= (2 + (show_src ? 1 : 0));
1136 mvwprintw(screen, 1, 2,
1137 "Kernel netfilter flows(%u) for %s%s%s%s%s%s"
1138 "[+%d]", flows, what & INCLUDE_TCP ? "TCP, " : "",
1139 what & INCLUDE_UDP ? "UDP, " : "",
1140 what & INCLUDE_SCTP ? "SCTP, " : "",
1141 what & INCLUDE_DCCP ? "DCCP, " : "",
1142 what & INCLUDE_ICMP && what & INCLUDE_IPV4 ? "ICMP, " : "",
1143 what & INCLUDE_ICMP && what & INCLUDE_IPV6 ? "ICMP6, " : "",
1144 skip_lines);
1146 if (is_flow_collecting)
1147 printw(" [Collecting flows ...]");
1149 rcu_read_unlock();
1152 static void draw_help(WINDOW *screen)
1154 int col = 0;
1155 int row = 0;
1156 int i;
1158 mvaddch(row, col, ACS_ULCORNER);
1159 mvaddch(rows - row - 2, col, ACS_LLCORNER);
1161 mvaddch(row, cols - 1, ACS_URCORNER);
1162 mvaddch(rows - row - 2, cols - col - 1, ACS_LRCORNER);
1164 for (i = 1; i < rows - row - 2; i++) {
1165 mvaddch(row + i, 0, ACS_VLINE);
1166 mvaddch(row + i, cols - col - 1, ACS_VLINE);
1168 for (i = 1; i < cols - col - 1; i++) {
1169 mvaddch(0, col + i, ACS_HLINE);
1170 mvaddch(rows - row - 2, col + i, ACS_HLINE);
1173 attron(A_BOLD);
1174 mvaddnstr(row, cols / 2 - 2, "| Help |", -1);
1176 attron(A_UNDERLINE);
1177 mvaddnstr(row + 2, col + 2, "Navigation", -1);
1178 attroff(A_BOLD | A_UNDERLINE);
1180 mvaddnstr(row + 4, col + 3, "Up, u, k Move up", -1);
1181 mvaddnstr(row + 5, col + 3, "Down, d, j Move down", -1);
1182 mvaddnstr(row + 6, col + 3, "? Toggle help window", -1);
1183 mvaddnstr(row + 7, col + 3, "q, Ctrl+C Quit", -1);
1185 attron(A_BOLD | A_UNDERLINE);
1186 mvaddnstr(row + 9, col + 2, "Display Settings", -1);
1187 attroff(A_BOLD | A_UNDERLINE);
1189 mvaddnstr(row + 11, col + 3, "b Toggle rate units (bits/bytes)", -1);
1190 mvaddnstr(row + 12, col + 3, "a Toggle display of active flows (rate > 0) only", -1);
1193 static void draw_footer(WINDOW *screen)
1195 int i;
1197 attron(A_STANDOUT);
1199 for (i = 0; i < cols; i++)
1200 mvaddch(rows - 1, i, ' ');
1202 mvaddnstr(rows - 1, 1, "Press '?' for help", -1);
1203 addch(ACS_VLINE);
1204 attroff(A_STANDOUT);
1207 static void presenter(void)
1209 int time_sleep_us = 200000;
1210 int time_passed_us = 0;
1211 bool show_help = false;
1212 int skip_lines = 0;
1213 WINDOW *screen;
1215 lookup_init(LT_PORTS_TCP);
1216 lookup_init(LT_PORTS_UDP);
1217 screen = screen_init(false);
1219 start_color();
1220 init_pair(1, COLOR_RED, COLOR_BLACK);
1221 init_pair(2, COLOR_BLUE, COLOR_BLACK);
1222 init_pair(3, COLOR_YELLOW, COLOR_BLACK);
1223 init_pair(4, COLOR_GREEN, COLOR_BLACK);
1225 rcu_register_thread();
1226 while (!sigint) {
1227 bool redraw_flows = true;
1229 curs_set(0);
1230 getmaxyx(screen, rows, cols);
1232 switch (getch()) {
1233 case 'q':
1234 sigint = 1;
1235 break;
1236 case KEY_UP:
1237 case 'u':
1238 case 'k':
1239 skip_lines--;
1240 if (skip_lines < 0)
1241 skip_lines = 0;
1242 break;
1243 case KEY_DOWN:
1244 case 'd':
1245 case 'j':
1246 skip_lines++;
1247 if (skip_lines > SCROLL_MAX)
1248 skip_lines = SCROLL_MAX;
1249 break;
1250 case 'b':
1251 if (rate_type == RATE_BYTES)
1252 rate_type = RATE_BITS;
1253 else
1254 rate_type = RATE_BYTES;
1255 break;
1256 case 'a':
1257 show_active_only = !show_active_only;
1258 break;
1259 case '?':
1260 show_help = !show_help;
1261 wclear(screen);
1262 clear();
1263 break;
1264 default:
1265 fflush(stdin);
1266 redraw_flows = false;
1267 break;
1270 if (!redraw_flows)
1271 redraw_flows = time_passed_us >= 1 * USEC_PER_SEC;
1273 if (show_help)
1274 redraw_flows = false;
1276 if (redraw_flows) {
1277 draw_flows(screen, &flow_list, skip_lines);
1278 time_passed_us = 0;
1279 } else {
1280 time_passed_us += time_sleep_us;
1283 if (show_help)
1284 draw_help(screen);
1286 draw_footer(screen);
1288 wrefresh(screen);
1289 refresh();
1290 usleep(time_sleep_us);
1292 rcu_unregister_thread();
1294 screen_end();
1295 lookup_cleanup(LT_PORTS_UDP);
1296 lookup_cleanup(LT_PORTS_TCP);
1299 static int flow_event_cb(enum nf_conntrack_msg_type type,
1300 struct nf_conntrack *ct, void *data __maybe_unused)
1302 if (sigint)
1303 return NFCT_CB_STOP;
1305 synchronize_rcu();
1306 spinlock_lock(&flow_list.lock);
1308 switch (type) {
1309 case NFCT_T_NEW:
1310 flow_list_new_entry(&flow_list, ct);
1311 break;
1312 case NFCT_T_UPDATE:
1313 flow_list_update_entry(&flow_list, ct);
1314 break;
1315 case NFCT_T_DESTROY:
1316 flow_list_destroy_entry(&flow_list, ct);
1317 break;
1318 default:
1319 break;
1322 spinlock_unlock(&flow_list.lock);
1324 return NFCT_CB_CONTINUE;
1327 static void restore_sysctl(void *obj)
1329 struct sysctl_params_ctx *sysctl_ctx = obj;
1331 if (sysctl_ctx->nfct_acct == 0)
1332 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1333 sysctl_ctx->nfct_acct);
1335 if (sysctl_ctx->nfct_tstamp == 0)
1336 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1337 sysctl_ctx->nfct_tstamp);
1340 static void on_panic_handler(void *arg)
1342 restore_sysctl(arg);
1343 screen_end();
1346 static void conntrack_acct_enable(void)
1348 /* We can still work w/o traffic accounting so just warn about error */
1349 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl.nfct_acct)) {
1350 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1351 strerror(errno));
1352 return;
1355 if (sysctl.nfct_acct == 1)
1356 return;
1358 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1359 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1360 strerror(errno));
1364 static void conntrack_tstamp_enable(void)
1366 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl.nfct_tstamp)) {
1367 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1368 strerror(errno));
1369 return;
1372 if (sysctl.nfct_tstamp == 1)
1373 return;
1375 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1376 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1377 strerror(errno));
1381 static void flow_entry_filter(struct flow_entry *n)
1383 if (show_active_only && !n->rate_bytes_src && !n->rate_bytes_dst)
1384 n->is_visible = false;
1385 else
1386 n->is_visible = true;
1389 static int flow_update_cb(enum nf_conntrack_msg_type type,
1390 struct nf_conntrack *ct, void *data __maybe_unused)
1392 struct flow_entry *n;
1394 if (type != NFCT_T_UPDATE)
1395 return NFCT_CB_CONTINUE;
1397 if (sigint)
1398 return NFCT_CB_STOP;
1400 n = flow_list_find_id(&flow_list, nfct_get_attr_u32(ct, ATTR_ID));
1401 if (!n)
1402 return NFCT_CB_CONTINUE;
1404 flow_entry_calc_rate(n, ct);
1405 flow_entry_update_time(n);
1406 flow_entry_from_ct(n, ct);
1407 flow_entry_filter(n);
1409 return NFCT_CB_CONTINUE;
1412 static void collector_refresh_flows(struct nfct_handle *handle)
1414 struct flow_entry *n;
1416 n = rcu_dereference(flow_list.head);
1417 for (; n; n = rcu_dereference(n->next))
1418 nfct_query(handle, NFCT_Q_GET, n->ct);
1421 static void collector_create_filter(struct nfct_handle *nfct)
1423 struct nfct_filter *filter;
1424 int ret;
1426 filter = nfct_filter_create();
1427 if (!filter)
1428 panic("Cannot create a nfct filter: %s\n", strerror(errno));
1430 if (what & INCLUDE_UDP) {
1431 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
1432 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDPLITE);
1434 if (what & INCLUDE_TCP)
1435 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
1436 if (what & INCLUDE_DCCP)
1437 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_DCCP);
1438 if (what & INCLUDE_SCTP)
1439 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_SCTP);
1440 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1441 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMP);
1442 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1443 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMPV6);
1444 if (what & INCLUDE_IPV4) {
1445 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV4, NFCT_FILTER_LOGIC_NEGATIVE);
1446 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
1448 if (what & INCLUDE_IPV6) {
1449 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV6, NFCT_FILTER_LOGIC_NEGATIVE);
1450 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV6, &filter_ipv6);
1453 ret = nfct_filter_attach(nfct_fd(nfct), filter);
1454 if (ret < 0)
1455 panic("Cannot attach filter to handle: %s\n", strerror(errno));
1457 nfct_filter_destroy(filter);
1460 /* This hand-crafted filter looks ugly but it allows to do not
1461 * flush nfct connections & filter them by user specified filter.
1462 * May be it is better to replace this one by nfct_cmp. */
1463 static int flow_dump_cb(enum nf_conntrack_msg_type type,
1464 struct nf_conntrack *ct, void *data __maybe_unused)
1466 struct flow_entry fl;
1467 struct flow_entry *n = &fl;
1469 if (sigint)
1470 return NFCT_CB_STOP;
1472 synchronize_rcu();
1473 spinlock_lock(&flow_list.lock);
1475 if (!(what & ~(INCLUDE_IPV4 | INCLUDE_IPV6)))
1476 goto check_addr;
1478 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
1480 if (what & INCLUDE_UDP) {
1481 if (n->l4_proto == IPPROTO_UDP)
1482 goto check_addr;
1484 if (n->l4_proto == IPPROTO_UDPLITE)
1485 goto check_addr;
1488 if ((what & INCLUDE_TCP) && n->l4_proto == IPPROTO_TCP)
1489 goto check_addr;
1491 if ((what & INCLUDE_DCCP) && n->l4_proto == IPPROTO_DCCP)
1492 goto check_addr;
1494 if ((what & INCLUDE_SCTP) && n->l4_proto == IPPROTO_SCTP)
1495 goto check_addr;
1497 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV4) &&
1498 n->l4_proto == IPPROTO_ICMP) {
1499 goto check_addr;
1502 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV6) &&
1503 n->l4_proto == IPPROTO_ICMPV6) {
1504 goto check_addr;
1507 goto skip_flow;
1509 check_addr:
1510 /* filter loopback addresses */
1511 if (what & INCLUDE_IPV4) {
1512 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
1514 if (n->ip4_src_addr == filter_ipv4.addr)
1515 goto skip_flow;
1517 if (what & INCLUDE_IPV6) {
1518 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
1520 if (n->ip6_src_addr[0] == 0x0 &&
1521 n->ip6_src_addr[1] == 0x0 &&
1522 n->ip6_src_addr[2] == 0x0 &&
1523 n->ip6_src_addr[3] == 0x1)
1524 goto skip_flow;
1527 flow_list_new_entry(&flow_list, ct);
1529 skip_flow:
1530 spinlock_unlock(&flow_list.lock);
1531 return NFCT_CB_CONTINUE;
1534 static void collector_dump_flows(void)
1536 struct nfct_handle *nfct = nfct_open(CONNTRACK, 0);
1538 if (!nfct)
1539 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1541 nfct_callback_register(nfct, NFCT_T_ALL, flow_dump_cb, NULL);
1543 is_flow_collecting = true;
1544 if (what & INCLUDE_IPV4) {
1545 int family = AF_INET;
1546 nfct_query(nfct, NFCT_Q_DUMP, &family);
1548 if (what & INCLUDE_IPV6) {
1549 int family = AF_INET6;
1550 nfct_query(nfct, NFCT_Q_DUMP, &family);
1552 is_flow_collecting = false;
1554 nfct_close(nfct);
1557 static void *collector(void *null __maybe_unused)
1559 struct nfct_handle *ct_update;
1560 struct nfct_handle *ct_event;
1561 struct pollfd poll_fd[1];
1563 flow_list_init(&flow_list);
1565 ct_event = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW |
1566 NF_NETLINK_CONNTRACK_UPDATE |
1567 NF_NETLINK_CONNTRACK_DESTROY);
1568 if (!ct_event)
1569 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1571 collector_create_filter(ct_event);
1573 nfct_callback_register(ct_event, NFCT_T_ALL, flow_event_cb, NULL);
1575 ct_update = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_UPDATE);
1576 if (!ct_update)
1577 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1579 nfct_callback_register(ct_update, NFCT_T_ALL, flow_update_cb, NULL);
1581 poll_fd[0].fd = nfct_fd(ct_event);
1582 poll_fd[0].events = POLLIN;
1584 if (fcntl(nfct_fd(ct_event), F_SETFL, O_NONBLOCK) == -1)
1585 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1586 strerror(errno));
1588 if (fcntl(nfct_fd(ct_update), F_SETFL, O_NONBLOCK) == -1)
1589 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1590 strerror(errno));
1592 rcu_register_thread();
1594 collector_dump_flows();
1596 while (!sigint) {
1597 int status;
1599 usleep(USEC_PER_SEC * interval);
1601 collector_refresh_flows(ct_update);
1603 status = poll(poll_fd, 1, 0);
1604 if (status < 0) {
1605 if (errno == EAGAIN || errno == EINTR)
1606 continue;
1608 panic("Error while polling: %s\n", strerror(errno));
1609 } else if (status == 0) {
1610 continue;
1613 if (poll_fd[0].revents & POLLIN)
1614 nfct_catch(ct_event);
1617 rcu_unregister_thread();
1619 flow_list_destroy(&flow_list);
1620 nfct_close(ct_event);
1621 nfct_close(ct_update);
1623 pthread_exit(NULL);
1626 int main(int argc, char **argv)
1628 pthread_t tid;
1629 int ret, c, opt_index, what_cmd = 0;
1631 setfsuid(getuid());
1632 setfsgid(getgid());
1634 while ((c = getopt_long(argc, argv, short_options, long_options,
1635 &opt_index)) != 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;