flowtop: man: Add notice about rate info
[netsniff-ng.git] / flowtop.c
blobc58ae0a69a465c8a3c6e5b89a8a6c0995230a7ca
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>
30 #include "die.h"
31 #include "xmalloc.h"
32 #include "conntrack.h"
33 #include "config.h"
34 #include "str.h"
35 #include "sig.h"
36 #include "lookup.h"
37 #include "geoip.h"
38 #include "built_in.h"
39 #include "locking.h"
40 #include "pkt_buff.h"
41 #include "screen.h"
42 #include "proc.h"
43 #include "sysctl.h"
45 #ifndef NSEC_PER_SEC
46 #define NSEC_PER_SEC 1000000000L
47 #endif
49 struct flow_entry {
50 uint32_t flow_id, use, status;
51 uint8_t l3_proto, l4_proto;
52 uint32_t ip4_src_addr, ip4_dst_addr;
53 uint32_t ip6_src_addr[4], ip6_dst_addr[4];
54 uint16_t port_src, port_dst;
55 uint8_t tcp_state, tcp_flags, sctp_state, dccp_state;
56 uint64_t pkts_src, bytes_src;
57 uint64_t pkts_dst, bytes_dst;
58 uint64_t timestamp_start, timestamp_stop;
59 char country_src[128], country_dst[128];
60 char city_src[128], city_dst[128];
61 char rev_dns_src[256], rev_dns_dst[256];
62 char procname[256];
63 struct flow_entry *next;
64 int inode;
65 unsigned int procnum;
66 bool is_visible;
67 struct nf_conntrack *ct;
68 struct timeval last_update;
69 double rate_bytes_src;
70 double rate_bytes_dst;
71 double rate_pkts_src;
72 double rate_pkts_dst;
75 struct flow_list {
76 struct flow_entry *head;
77 struct spinlock lock;
80 #ifndef ATTR_TIMESTAMP_START
81 # define ATTR_TIMESTAMP_START 63
82 #endif
83 #ifndef ATTR_TIMESTAMP_STOP
84 # define ATTR_TIMESTAMP_STOP 64
85 #endif
87 #define SCROLL_MAX 1000
89 #define INCLUDE_IPV4 (1 << 0)
90 #define INCLUDE_IPV6 (1 << 1)
91 #define INCLUDE_UDP (1 << 2)
92 #define INCLUDE_TCP (1 << 3)
93 #define INCLUDE_DCCP (1 << 4)
94 #define INCLUDE_ICMP (1 << 5)
95 #define INCLUDE_SCTP (1 << 6)
97 struct sysctl_params_ctx {
98 int nfct_acct;
99 int nfct_tstamp;
102 static volatile bool is_flow_collecting;
103 static volatile sig_atomic_t sigint = 0;
104 static int what = INCLUDE_IPV4 | INCLUDE_IPV6 | INCLUDE_TCP, show_src = 0;
105 static struct flow_list flow_list;
106 static struct sysctl_params_ctx sysctl = { -1, -1 };
108 static const char *short_options = "vhTUsDIS46u";
109 static const struct option long_options[] = {
110 {"ipv4", no_argument, NULL, '4'},
111 {"ipv6", no_argument, NULL, '6'},
112 {"tcp", no_argument, NULL, 'T'},
113 {"udp", no_argument, NULL, 'U'},
114 {"dccp", no_argument, NULL, 'D'},
115 {"icmp", no_argument, NULL, 'I'},
116 {"sctp", no_argument, NULL, 'S'},
117 {"show-src", no_argument, NULL, 's'},
118 {"update", no_argument, NULL, 'u'},
119 {"version", no_argument, NULL, 'v'},
120 {"help", no_argument, NULL, 'h'},
121 {NULL, 0, NULL, 0}
124 static const char *copyright = "Please report bugs to <bugs@netsniff-ng.org>\n"
125 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
126 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
127 "Swiss federal institute of technology (ETH Zurich)\n"
128 "License: GNU GPL version 2.0\n"
129 "This is free software: you are free to change and redistribute it.\n"
130 "There is NO WARRANTY, to the extent permitted by law.";
132 static const char *const l3proto2str[AF_MAX] = {
133 [AF_INET] = "ipv4",
134 [AF_INET6] = "ipv6",
137 static const char *const l4proto2str[IPPROTO_MAX] = {
138 [IPPROTO_TCP] = "tcp",
139 [IPPROTO_UDP] = "udp",
140 [IPPROTO_UDPLITE] = "udplite",
141 [IPPROTO_ICMP] = "icmp",
142 [IPPROTO_ICMPV6] = "icmpv6",
143 [IPPROTO_SCTP] = "sctp",
144 [IPPROTO_GRE] = "gre",
145 [IPPROTO_DCCP] = "dccp",
146 [IPPROTO_IGMP] = "igmp",
147 [IPPROTO_IPIP] = "ipip",
148 [IPPROTO_EGP] = "egp",
149 [IPPROTO_PUP] = "pup",
150 [IPPROTO_IDP] = "idp",
151 [IPPROTO_RSVP] = "rsvp",
152 [IPPROTO_IPV6] = "ip6tun",
153 [IPPROTO_ESP] = "esp",
154 [IPPROTO_AH] = "ah",
155 [IPPROTO_PIM] = "pim",
156 [IPPROTO_COMP] = "comp",
159 static const char *const tcp_state2str[TCP_CONNTRACK_MAX] = {
160 [TCP_CONNTRACK_NONE] = "NOSTATE",
161 [TCP_CONNTRACK_SYN_SENT] = "SYN_SENT",
162 [TCP_CONNTRACK_SYN_RECV] = "SYN_RECV",
163 [TCP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
164 [TCP_CONNTRACK_FIN_WAIT] = "FIN_WAIT",
165 [TCP_CONNTRACK_CLOSE_WAIT] = "CLOSE_WAIT",
166 [TCP_CONNTRACK_LAST_ACK] = "LAST_ACK",
167 [TCP_CONNTRACK_TIME_WAIT] = "TIME_WAIT",
168 [TCP_CONNTRACK_CLOSE] = "CLOSE",
169 [TCP_CONNTRACK_SYN_SENT2] = "SYN_SENT2",
172 static const char *const dccp_state2str[DCCP_CONNTRACK_MAX] = {
173 [DCCP_CONNTRACK_NONE] = "NOSTATE",
174 [DCCP_CONNTRACK_REQUEST] = "REQUEST",
175 [DCCP_CONNTRACK_RESPOND] = "RESPOND",
176 [DCCP_CONNTRACK_PARTOPEN] = "PARTOPEN",
177 [DCCP_CONNTRACK_OPEN] = "OPEN",
178 [DCCP_CONNTRACK_CLOSEREQ] = "CLOSEREQ",
179 [DCCP_CONNTRACK_CLOSING] = "CLOSING",
180 [DCCP_CONNTRACK_TIMEWAIT] = "TIMEWAIT",
181 [DCCP_CONNTRACK_IGNORE] = "IGNORE",
182 [DCCP_CONNTRACK_INVALID] = "INVALID",
185 static const char *const sctp_state2str[SCTP_CONNTRACK_MAX] = {
186 [SCTP_CONNTRACK_NONE] = "NOSTATE",
187 [SCTP_CONNTRACK_CLOSED] = "CLOSED",
188 [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE_WAIT",
189 [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE_ECHOED",
190 [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
191 [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTDOWN_SENT",
192 [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTDOWN_RECD",
193 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT",
196 static const struct nfct_filter_ipv4 filter_ipv4 = {
197 .addr = __constant_htonl(INADDR_LOOPBACK),
198 .mask = 0xffffffff,
201 static const struct nfct_filter_ipv6 filter_ipv6 = {
202 .addr = { 0x0, 0x0, 0x0, 0x1 },
203 .mask = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
206 static int64_t time_after_us(struct timeval *tv)
208 struct timeval now;
210 gettimeofday(&now, NULL);
212 now.tv_sec -= tv->tv_sec;
213 now.tv_usec -= tv->tv_usec;
215 return now.tv_sec * 1000000 + now.tv_usec;
218 static void signal_handler(int number)
220 switch (number) {
221 case SIGINT:
222 case SIGQUIT:
223 case SIGTERM:
224 sigint = 1;
225 break;
226 case SIGHUP:
227 default:
228 break;
232 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct);
233 static void flow_entry_get_extended(struct flow_entry *n);
235 static void help(void)
237 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
238 VERSION_STRING);
239 puts("http://www.netsniff-ng.org\n\n"
240 "Usage: flowtop [options]\n"
241 "Options:\n"
242 " -4|--ipv4 Show only IPv4 flows (default)\n"
243 " -6|--ipv6 Show only IPv6 flows (default)\n"
244 " -T|--tcp Show only TCP flows (default)\n"
245 " -U|--udp Show only UDP flows\n"
246 " -D|--dccp Show only DCCP flows\n"
247 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
248 " -S|--sctp Show only SCTP flows\n"
249 " -s|--show-src Also show source, not only dest\n"
250 " -u|--update Update GeoIP databases\n"
251 " -v|--version Print version and exit\n"
252 " -h|--help Print this help and exit\n\n"
253 "Examples:\n"
254 " flowtop\n"
255 " flowtop -46UTDISs\n\n"
256 "Note:\n"
257 " If netfilter is not running, you can activate it with e.g.:\n"
258 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
259 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
260 puts(copyright);
261 die();
264 static void version(void)
266 printf("flowtop %s, Git id: %s\n", VERSION_LONG, GITVERSION);
267 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
268 "http://www.netsniff-ng.org\n");
269 puts(copyright);
270 die();
273 static void flow_entry_update_time(struct flow_entry *n)
275 gettimeofday(&n->last_update, NULL);
278 static void flow_entry_calc_rate(struct flow_entry *n, const struct nf_conntrack *ct)
280 uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES);
281 uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES);
282 uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS);
283 uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS);
284 double sec = time_after_us(&n->last_update) / 1000000.0;
286 if (sec <= 0)
287 return;
289 n->rate_bytes_src = (bytes_src - n->bytes_src) / sec;
290 n->rate_bytes_dst = (bytes_dst - n->bytes_dst) / sec;
291 n->rate_pkts_src = (pkts_src - n->pkts_src) / sec;
292 n->rate_pkts_dst = (pkts_dst - n->pkts_dst) / sec;
295 static inline struct flow_entry *flow_entry_xalloc(void)
297 return xzmalloc(sizeof(struct flow_entry));
300 static inline void flow_entry_xfree(struct flow_entry *n)
302 if (n->ct)
303 nfct_destroy(n->ct);
305 xfree(n);
308 static inline void flow_list_init(struct flow_list *fl)
310 fl->head = NULL;
311 spinlock_init(&fl->lock);
314 static inline bool nfct_is_dns(const struct nf_conntrack *ct)
316 uint16_t port_src = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
317 uint16_t port_dst = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
319 return ntohs(port_src) == 53 || ntohs(port_dst) == 53;
322 static void flow_list_new_entry(struct flow_list *fl, const struct nf_conntrack *ct)
324 struct flow_entry *n;
326 /* We don't want to analyze / display DNS itself, since we
327 * use it to resolve reverse dns.
329 if (nfct_is_dns(ct))
330 return;
332 n = flow_entry_xalloc();
334 n->ct = nfct_clone(ct);
336 flow_entry_update_time(n);
337 flow_entry_from_ct(n, ct);
338 flow_entry_get_extended(n);
340 rcu_assign_pointer(n->next, fl->head);
341 rcu_assign_pointer(fl->head, n);
344 static struct flow_entry *flow_list_find_id(struct flow_list *fl,
345 uint32_t id)
347 struct flow_entry *n = rcu_dereference(fl->head);
349 while (n != NULL) {
350 if (n->flow_id == id)
351 return n;
353 n = rcu_dereference(n->next);
356 return NULL;
359 static struct flow_entry *flow_list_find_prev_id(const struct flow_list *fl,
360 uint32_t id)
362 struct flow_entry *prev = rcu_dereference(fl->head), *next;
364 if (prev->flow_id == id)
365 return NULL;
367 while ((next = rcu_dereference(prev->next)) != NULL) {
368 if (next->flow_id == id)
369 return prev;
371 prev = next;
374 return NULL;
377 static void flow_list_update_entry(struct flow_list *fl,
378 const struct nf_conntrack *ct)
380 struct flow_entry *n;
382 n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
383 if (n == NULL) {
384 flow_list_new_entry(fl, ct);
385 return;
388 flow_entry_from_ct(n, ct);
391 static void flow_list_destroy_entry(struct flow_list *fl,
392 const struct nf_conntrack *ct)
394 struct flow_entry *n1, *n2;
395 uint32_t id = nfct_get_attr_u32(ct, ATTR_ID);
397 n1 = flow_list_find_id(fl, id);
398 if (n1) {
399 n2 = flow_list_find_prev_id(fl, id);
400 if (n2) {
401 rcu_assign_pointer(n2->next, n1->next);
402 n1->next = NULL;
404 flow_entry_xfree(n1);
405 } else {
406 struct flow_entry *next = fl->head->next;
408 flow_entry_xfree(fl->head);
409 fl->head = next;
414 static void flow_list_destroy(struct flow_list *fl)
416 struct flow_entry *n;
418 while (fl->head != NULL) {
419 n = rcu_dereference(fl->head->next);
420 fl->head->next = NULL;
422 flow_entry_xfree(fl->head);
423 rcu_assign_pointer(fl->head, n);
426 synchronize_rcu();
427 spinlock_destroy(&fl->lock);
430 static int walk_process(unsigned int pid, struct flow_entry *n)
432 int ret;
433 DIR *dir;
434 struct dirent *ent;
435 char path[1024];
437 if (snprintf(path, sizeof(path), "/proc/%u/fd", pid) == -1)
438 panic("giant process name! %u\n", pid);
440 dir = opendir(path);
441 if (!dir)
442 return 0;
444 while ((ent = readdir(dir))) {
445 struct stat statbuf;
447 if (snprintf(path, sizeof(path), "/proc/%u/fd/%s",
448 pid, ent->d_name) < 0)
449 continue;
451 if (stat(path, &statbuf) < 0)
452 continue;
454 if (S_ISSOCK(statbuf.st_mode) && (ino_t) n->inode == statbuf.st_ino) {
455 char cmdline[256];
457 ret = proc_get_cmdline(pid, cmdline, sizeof(cmdline));
458 if (ret < 0)
459 panic("Failed to get process cmdline: %s\n", strerror(errno));
461 if (snprintf(n->procname, sizeof(n->procname), "%s", basename(cmdline)) < 0)
462 n->procname[0] = '\0';
463 n->procnum = pid;
464 closedir(dir);
465 return 1;
469 closedir(dir);
470 return 0;
473 static void walk_processes(struct flow_entry *n)
475 int ret;
476 DIR *dir;
477 struct dirent *ent;
479 /* n->inode must be set */
480 if (n->inode <= 0) {
481 n->procname[0] = '\0';
482 return;
485 dir = opendir("/proc");
486 if (!dir)
487 panic("Cannot open /proc: %s\n", strerror(errno));
489 while ((ent = readdir(dir))) {
490 const char *name = ent->d_name;
491 char *end;
492 unsigned int pid = strtoul(name, &end, 10);
494 /* not a PID */
495 if (pid == 0 && end == name)
496 continue;
498 ret = walk_process(pid, n);
499 if (ret > 0)
500 break;
503 closedir(dir);
506 static int get_port_inode(uint16_t port, int proto, bool is_ip6)
508 int ret = -ENOENT;
509 char path[128], buff[1024];
510 FILE *proc;
512 memset(path, 0, sizeof(path));
513 snprintf(path, sizeof(path), "/proc/net/%s%s",
514 l4proto2str[proto], is_ip6 ? "6" : "");
516 proc = fopen(path, "r");
517 if (!proc)
518 return -EIO;
520 memset(buff, 0, sizeof(buff));
522 while (fgets(buff, sizeof(buff), proc) != NULL) {
523 int inode = 0;
524 unsigned int lport = 0;
526 buff[sizeof(buff) - 1] = 0;
527 if (sscanf(buff, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
528 "%*X %*u %*u %u", &lport, &inode) == 2) {
529 if ((uint16_t) lport == port) {
530 ret = inode;
531 break;
535 memset(buff, 0, sizeof(buff));
538 fclose(proc);
539 return ret;
542 #define CP_NFCT(elem, attr, x) \
543 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
544 #define CP_NFCT_BUFF(elem, attr) do { \
545 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
546 if (buff != NULL) \
547 memcpy(n->elem, buff, sizeof(n->elem)); \
548 } while (0)
550 static void flow_entry_from_ct(struct flow_entry *n, const struct nf_conntrack *ct)
552 CP_NFCT(l3_proto, ATTR_ORIG_L3PROTO, 8);
553 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
555 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
556 CP_NFCT(ip4_dst_addr, ATTR_ORIG_IPV4_DST, 32);
558 CP_NFCT(port_src, ATTR_ORIG_PORT_SRC, 16);
559 CP_NFCT(port_dst, ATTR_ORIG_PORT_DST, 16);
561 CP_NFCT(status, ATTR_STATUS, 32);
563 CP_NFCT(tcp_state, ATTR_TCP_STATE, 8);
564 CP_NFCT(tcp_flags, ATTR_TCP_FLAGS_ORIG, 8);
565 CP_NFCT(sctp_state, ATTR_SCTP_STATE, 8);
566 CP_NFCT(dccp_state, ATTR_DCCP_STATE, 8);
568 CP_NFCT(pkts_src, ATTR_ORIG_COUNTER_PACKETS, 64);
569 CP_NFCT(bytes_src, ATTR_ORIG_COUNTER_BYTES, 64);
571 CP_NFCT(pkts_dst, ATTR_REPL_COUNTER_PACKETS, 64);
572 CP_NFCT(bytes_dst, ATTR_REPL_COUNTER_BYTES, 64);
574 CP_NFCT(timestamp_start, ATTR_TIMESTAMP_START, 64);
575 CP_NFCT(timestamp_stop, ATTR_TIMESTAMP_STOP, 64);
577 CP_NFCT(flow_id, ATTR_ID, 32);
578 CP_NFCT(use, ATTR_USE, 32);
580 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
581 CP_NFCT_BUFF(ip6_dst_addr, ATTR_ORIG_IPV6_DST);
583 n->port_src = ntohs(n->port_src);
584 n->port_dst = ntohs(n->port_dst);
586 n->ip4_src_addr = ntohl(n->ip4_src_addr);
587 n->ip4_dst_addr = ntohl(n->ip4_dst_addr);
590 enum flow_entry_direction {
591 flow_entry_src,
592 flow_entry_dst,
595 #define SELFLD(dir,src_member,dst_member) \
596 (((dir) == flow_entry_src) ? n->src_member : n->dst_member)
598 static void flow_entry_get_sain4_obj(const struct flow_entry *n,
599 enum flow_entry_direction dir,
600 struct sockaddr_in *sa)
602 memset(sa, 0, sizeof(*sa));
603 sa->sin_family = PF_INET;
604 sa->sin_addr.s_addr = htonl(SELFLD(dir, ip4_src_addr, ip4_dst_addr));
607 static void flow_entry_get_sain6_obj(const struct flow_entry *n,
608 enum flow_entry_direction dir,
609 struct sockaddr_in6 *sa)
611 memset(sa, 0, sizeof(*sa));
612 sa->sin6_family = PF_INET6;
614 memcpy(&sa->sin6_addr, SELFLD(dir, ip6_src_addr, ip6_dst_addr),
615 sizeof(sa->sin6_addr));
618 static void
619 flow_entry_geo_city_lookup_generic(struct flow_entry *n,
620 enum flow_entry_direction dir)
622 struct sockaddr_in sa4;
623 struct sockaddr_in6 sa6;
624 const char *city = NULL;
626 switch (n->l3_proto) {
627 default:
628 bug();
630 case AF_INET:
631 flow_entry_get_sain4_obj(n, dir, &sa4);
632 city = geoip4_city_name(&sa4);
633 break;
635 case AF_INET6:
636 flow_entry_get_sain6_obj(n, dir, &sa6);
637 city = geoip6_city_name(&sa6);
638 break;
641 build_bug_on(sizeof(n->city_src) != sizeof(n->city_dst));
643 if (city) {
644 memcpy(SELFLD(dir, city_src, city_dst), city,
645 min(sizeof(n->city_src), strlen(city)));
646 } else {
647 memset(SELFLD(dir, city_src, city_dst), 0,
648 sizeof(n->city_src));
652 static void
653 flow_entry_geo_country_lookup_generic(struct flow_entry *n,
654 enum flow_entry_direction dir)
656 struct sockaddr_in sa4;
657 struct sockaddr_in6 sa6;
658 const char *country = NULL;
660 switch (n->l3_proto) {
661 default:
662 bug();
664 case AF_INET:
665 flow_entry_get_sain4_obj(n, dir, &sa4);
666 country = geoip4_country_name(&sa4);
667 break;
669 case AF_INET6:
670 flow_entry_get_sain6_obj(n, dir, &sa6);
671 country = geoip6_country_name(&sa6);
672 break;
675 build_bug_on(sizeof(n->country_src) != sizeof(n->country_dst));
677 if (country) {
678 memcpy(SELFLD(dir, country_src, country_dst), country,
679 min(sizeof(n->country_src), strlen(country)));
680 } else {
681 memset(SELFLD(dir, country_src, country_dst), 0,
682 sizeof(n->country_src));
686 static void flow_entry_get_extended_geo(struct flow_entry *n,
687 enum flow_entry_direction dir)
689 flow_entry_geo_city_lookup_generic(n, dir);
690 flow_entry_geo_country_lookup_generic(n, dir);
693 static void flow_entry_get_extended_revdns(struct flow_entry *n,
694 enum flow_entry_direction dir)
696 size_t sa_len;
697 struct sockaddr_in sa4;
698 struct sockaddr_in6 sa6;
699 struct sockaddr *sa;
700 struct hostent *hent;
702 switch (n->l3_proto) {
703 default:
704 bug();
706 case AF_INET:
707 flow_entry_get_sain4_obj(n, dir, &sa4);
708 sa = (struct sockaddr *) &sa4;
709 sa_len = sizeof(sa4);
710 hent = gethostbyaddr(&sa4.sin_addr, sizeof(sa4.sin_addr), AF_INET);
711 break;
713 case AF_INET6:
714 flow_entry_get_sain6_obj(n, dir, &sa6);
715 sa = (struct sockaddr *) &sa6;
716 sa_len = sizeof(sa6);
717 hent = gethostbyaddr(&sa6.sin6_addr, sizeof(sa6.sin6_addr), AF_INET6);
718 break;
721 build_bug_on(sizeof(n->rev_dns_src) != sizeof(n->rev_dns_dst));
722 getnameinfo(sa, sa_len, SELFLD(dir, rev_dns_src, rev_dns_dst),
723 sizeof(n->rev_dns_src), NULL, 0, NI_NUMERICHOST);
725 if (hent) {
726 memset(n->rev_dns_dst, 0, sizeof(n->rev_dns_dst));
727 memcpy(SELFLD(dir, rev_dns_src, rev_dns_dst),
728 hent->h_name, min(sizeof(n->rev_dns_src),
729 strlen(hent->h_name)));
733 static void flow_entry_get_extended(struct flow_entry *n)
735 if (n->flow_id == 0)
736 return;
738 if (show_src) {
739 flow_entry_get_extended_revdns(n, flow_entry_src);
740 flow_entry_get_extended_geo(n, flow_entry_src);
743 flow_entry_get_extended_revdns(n, flow_entry_dst);
744 flow_entry_get_extended_geo(n, flow_entry_dst);
746 /* Lookup application */
747 n->inode = get_port_inode(n->port_src, n->l4_proto,
748 n->l3_proto == AF_INET6);
749 if (n->inode > 0)
750 walk_processes(n);
753 static uint16_t presenter_get_port(uint16_t src, uint16_t dst, bool is_tcp)
755 if (src < dst && src < 1024) {
756 return src;
757 } else if (dst < src && dst < 1024) {
758 return dst;
759 } else {
760 const char *tmp1, *tmp2;
761 if (is_tcp) {
762 tmp1 = lookup_port_tcp(src);
763 tmp2 = lookup_port_tcp(dst);
764 } else {
765 tmp1 = lookup_port_udp(src);
766 tmp2 = lookup_port_udp(dst);
768 if (tmp1 && !tmp2) {
769 return src;
770 } else if (!tmp1 && tmp2) {
771 return dst;
772 } else {
773 if (src < dst)
774 return src;
775 else
776 return dst;
781 static char *bandw2str(double bytes, char *buf, size_t len)
783 if (bytes > 1000000000.)
784 snprintf(buf, len, "%.1fGB", bytes / 1000000000.);
785 else if (bytes > 1000000.)
786 snprintf(buf, len, "%.1fMB", bytes / 1000000.);
787 else if (bytes > 1000.)
788 snprintf(buf, len, "%.1fKB", bytes / 1000.);
789 else
790 snprintf(buf, len, "%g bytes", bytes);
792 return buf;
795 static char *rate2str(double rate, char *buf, size_t len)
797 if (rate > 1000000000.)
798 snprintf(buf, len, "%.1fGB/s", rate / 1000000000.);
799 else if (rate > 1000000.)
800 snprintf(buf, len, "%.1fMB/s", rate / 1000000.);
801 else if (rate > 1000.)
802 snprintf(buf, len, "%.1fKB/s", rate / 1000.);
803 else
804 snprintf(buf, len, "%gB/s", rate);
806 return buf;
809 static void presenter_print_counters(uint64_t bytes, uint64_t pkts,
810 double rate_bytes, double rate_pkts,
811 int color)
813 char bytes_str[64];
815 printw(" -> (");
816 attron(COLOR_PAIR(color));
817 printw("%"PRIu64" pkts", pkts);
818 if (rate_pkts)
819 printw("(%.1fpps)", rate_pkts);
821 printw(", %s", bandw2str(bytes, bytes_str, sizeof(bytes_str) - 1));
822 if (rate_bytes)
823 printw("(%s)", rate2str(rate_bytes, bytes_str,
824 sizeof(bytes_str) - 1));
825 attroff(COLOR_PAIR(color));
826 printw(")");
829 static void presenter_print_flow_entry_time(const struct flow_entry *n)
831 int h, m, s;
832 time_t now;
834 time(&now);
836 s = now - (n->timestamp_start / NSEC_PER_SEC);
837 if (s <= 0)
838 return;
840 h = s / 3600;
841 s -= h * 3600;
842 m = s / 60;
843 s -= m * 60;
845 printw(" [ time");
846 if (h > 0)
847 printw(" %dh", h);
848 if (m > 0)
849 printw(" %dm", m);
850 if (s > 0)
851 printw(" %ds", s);
852 printw(" ]");
855 static void presenter_screen_do_line(WINDOW *screen, const struct flow_entry *n,
856 unsigned int *line)
858 char tmp[128], *pname = NULL;
859 uint16_t port;
861 mvwprintw(screen, *line, 2, "");
863 /* PID, application name */
864 if (n->procnum > 0) {
865 slprintf(tmp, sizeof(tmp), "%s(%d)", n->procname, n->procnum);
867 printw("[");
868 attron(COLOR_PAIR(3));
869 printw("%s", tmp);
870 attroff(COLOR_PAIR(3));
871 printw("]:");
874 /* L3 protocol, L4 protocol, states */
875 printw("%s:%s", l3proto2str[n->l3_proto], l4proto2str[n->l4_proto]);
876 printw("[");
877 attron(COLOR_PAIR(3));
878 switch (n->l4_proto) {
879 case IPPROTO_TCP:
880 printw("%s", tcp_state2str[n->tcp_state]);
881 break;
882 case IPPROTO_SCTP:
883 printw("%s", sctp_state2str[n->sctp_state]);
884 break;
885 case IPPROTO_DCCP:
886 printw("%s", dccp_state2str[n->dccp_state]);
887 break;
888 case IPPROTO_UDP:
889 case IPPROTO_UDPLITE:
890 case IPPROTO_ICMP:
891 case IPPROTO_ICMPV6:
892 printw("NOSTATE");
893 break;
895 attroff(COLOR_PAIR(3));
896 printw("]");
898 /* Guess application port */
899 switch (n->l4_proto) {
900 case IPPROTO_TCP:
901 port = presenter_get_port(n->port_src, n->port_dst, true);
902 pname = lookup_port_tcp(port);
903 break;
904 case IPPROTO_UDP:
905 case IPPROTO_UDPLITE:
906 port = presenter_get_port(n->port_src, n->port_dst, false);
907 pname = lookup_port_udp(port);
908 break;
910 if (pname) {
911 attron(A_BOLD);
912 printw(":%s", pname);
913 attroff(A_BOLD);
916 if (n->timestamp_start > 0)
917 presenter_print_flow_entry_time(n);
919 /* Show source information: reverse DNS, port, country, city, counters */
920 if (show_src) {
921 attron(COLOR_PAIR(1));
922 mvwprintw(screen, ++(*line), 8, "src: %s", n->rev_dns_src);
923 attroff(COLOR_PAIR(1));
925 printw(":%"PRIu16, n->port_src);
927 if (n->country_src[0]) {
928 printw(" (");
930 attron(COLOR_PAIR(4));
931 printw("%s", n->country_src);
932 attroff(COLOR_PAIR(4));
934 if (n->city_src[0])
935 printw(", %s", n->city_src);
937 printw(")");
940 if (n->pkts_src > 0 && n->bytes_src > 0)
941 presenter_print_counters(n->bytes_src, n->pkts_src,
942 n->rate_bytes_src,
943 n->rate_pkts_src, 1);
945 printw(" => ");
948 /* Show dest information: reverse DNS, port, country, city, counters */
949 attron(COLOR_PAIR(2));
950 mvwprintw(screen, ++(*line), 8, "dst: %s", n->rev_dns_dst);
951 attroff(COLOR_PAIR(2));
953 printw(":%"PRIu16, n->port_dst);
955 if (n->country_dst[0]) {
956 printw(" (");
958 attron(COLOR_PAIR(4));
959 printw("%s", n->country_dst);
960 attroff(COLOR_PAIR(4));
962 if (n->city_dst[0])
963 printw(", %s", n->city_dst);
965 printw(")");
968 if (n->pkts_dst > 0 && n->bytes_dst > 0)
969 presenter_print_counters(n->bytes_dst, n->pkts_dst,
970 n->rate_bytes_dst,
971 n->rate_pkts_dst, 2);
974 static inline bool presenter_flow_wrong_state(struct flow_entry *n)
976 switch (n->l4_proto) {
977 case IPPROTO_TCP:
978 switch (n->tcp_state) {
979 case TCP_CONNTRACK_SYN_SENT:
980 case TCP_CONNTRACK_SYN_RECV:
981 case TCP_CONNTRACK_ESTABLISHED:
982 case TCP_CONNTRACK_FIN_WAIT:
983 case TCP_CONNTRACK_CLOSE_WAIT:
984 case TCP_CONNTRACK_LAST_ACK:
985 case TCP_CONNTRACK_TIME_WAIT:
986 case TCP_CONNTRACK_CLOSE:
987 case TCP_CONNTRACK_SYN_SENT2:
988 case TCP_CONNTRACK_NONE:
989 return false;
990 break;
992 break;
993 case IPPROTO_SCTP:
994 switch (n->sctp_state) {
995 case SCTP_CONNTRACK_NONE:
996 case SCTP_CONNTRACK_CLOSED:
997 case SCTP_CONNTRACK_COOKIE_WAIT:
998 case SCTP_CONNTRACK_COOKIE_ECHOED:
999 case SCTP_CONNTRACK_ESTABLISHED:
1000 case SCTP_CONNTRACK_SHUTDOWN_SENT:
1001 case SCTP_CONNTRACK_SHUTDOWN_RECD:
1002 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT:
1003 return false;
1004 break;
1006 break;
1007 case IPPROTO_DCCP:
1008 switch (n->dccp_state) {
1009 case DCCP_CONNTRACK_NONE:
1010 case DCCP_CONNTRACK_REQUEST:
1011 case DCCP_CONNTRACK_RESPOND:
1012 case DCCP_CONNTRACK_PARTOPEN:
1013 case DCCP_CONNTRACK_OPEN:
1014 case DCCP_CONNTRACK_CLOSEREQ:
1015 case DCCP_CONNTRACK_CLOSING:
1016 case DCCP_CONNTRACK_TIMEWAIT:
1017 case DCCP_CONNTRACK_IGNORE:
1018 case DCCP_CONNTRACK_INVALID:
1019 return false;
1020 break;
1022 break;
1023 case IPPROTO_UDP:
1024 case IPPROTO_UDPLITE:
1025 case IPPROTO_ICMP:
1026 case IPPROTO_ICMPV6:
1027 return false;
1028 break;
1031 return true;
1034 static void presenter_screen_update(WINDOW *screen, struct flow_list *fl,
1035 int skip_lines)
1037 int maxy;
1038 int skip_left = skip_lines;
1039 unsigned int flows = 0;
1040 unsigned int line = 3;
1041 struct flow_entry *n;
1043 curs_set(0);
1045 maxy = getmaxy(screen);
1046 maxy -= 6;
1048 start_color();
1049 init_pair(1, COLOR_RED, COLOR_BLACK);
1050 init_pair(2, COLOR_BLUE, COLOR_BLACK);
1051 init_pair(3, COLOR_YELLOW, COLOR_BLACK);
1052 init_pair(4, COLOR_GREEN, COLOR_BLACK);
1054 wclear(screen);
1055 clear();
1057 rcu_read_lock();
1059 n = rcu_dereference(fl->head);
1060 if (!n)
1061 mvwprintw(screen, line, 2, "(No active sessions! "
1062 "Is netfilter running?)");
1064 for (; n; n = rcu_dereference(n->next)) {
1065 n->is_visible = false;
1067 if (presenter_flow_wrong_state(n))
1068 continue;
1070 /* count only flows which might be showed */
1071 flows++;
1073 if (maxy <= 0)
1074 continue;
1076 if (skip_left > 0) {
1077 skip_left--;
1078 continue;
1081 n->is_visible = true;
1083 presenter_screen_do_line(screen, n, &line);
1085 line++;
1086 maxy -= (2 + 1 * show_src);
1089 mvwprintw(screen, 1, 2,
1090 "Kernel netfilter flows(%u) for %s%s%s%s%s%s"
1091 "[+%d]", flows, what & INCLUDE_TCP ? "TCP, " : "",
1092 what & INCLUDE_UDP ? "UDP, " : "",
1093 what & INCLUDE_SCTP ? "SCTP, " : "",
1094 what & INCLUDE_DCCP ? "DCCP, " : "",
1095 what & INCLUDE_ICMP && what & INCLUDE_IPV4 ? "ICMP, " : "",
1096 what & INCLUDE_ICMP && what & INCLUDE_IPV6 ? "ICMP6, " : "",
1097 skip_lines);
1099 if (is_flow_collecting)
1100 printw(" [Collecting flows ...]");
1102 rcu_read_unlock();
1104 wrefresh(screen);
1105 refresh();
1108 static void presenter(void)
1110 int skip_lines = 0;
1111 WINDOW *screen;
1113 lookup_init_ports(PORTS_TCP);
1114 lookup_init_ports(PORTS_UDP);
1115 screen = screen_init(false);
1117 rcu_register_thread();
1118 while (!sigint) {
1119 switch (getch()) {
1120 case 'q':
1121 sigint = 1;
1122 break;
1123 case KEY_UP:
1124 case 'u':
1125 case 'k':
1126 skip_lines--;
1127 if (skip_lines < 0)
1128 skip_lines = 0;
1129 break;
1130 case KEY_DOWN:
1131 case 'd':
1132 case 'j':
1133 skip_lines++;
1134 if (skip_lines > SCROLL_MAX)
1135 skip_lines = SCROLL_MAX;
1136 break;
1137 default:
1138 fflush(stdin);
1139 break;
1142 presenter_screen_update(screen, &flow_list, skip_lines);
1143 usleep(200000);
1145 rcu_unregister_thread();
1147 screen_end();
1148 lookup_cleanup_ports(PORTS_UDP);
1149 lookup_cleanup_ports(PORTS_TCP);
1152 static int flow_event_cb(enum nf_conntrack_msg_type type,
1153 struct nf_conntrack *ct, void *data __maybe_unused)
1155 if (sigint)
1156 return NFCT_CB_STOP;
1158 synchronize_rcu();
1159 spinlock_lock(&flow_list.lock);
1161 switch (type) {
1162 case NFCT_T_NEW:
1163 flow_list_new_entry(&flow_list, ct);
1164 break;
1165 case NFCT_T_UPDATE:
1166 flow_list_update_entry(&flow_list, ct);
1167 break;
1168 case NFCT_T_DESTROY:
1169 flow_list_destroy_entry(&flow_list, ct);
1170 break;
1171 default:
1172 break;
1175 spinlock_unlock(&flow_list.lock);
1177 return NFCT_CB_CONTINUE;
1180 static void restore_sysctl(void *obj)
1182 struct sysctl_params_ctx *sysctl_ctx = obj;
1184 if (sysctl_ctx->nfct_acct == 0)
1185 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1186 sysctl_ctx->nfct_acct);
1188 if (sysctl_ctx->nfct_tstamp == 0)
1189 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1190 sysctl_ctx->nfct_tstamp);
1193 static void on_panic_handler(void *arg)
1195 restore_sysctl(arg);
1196 screen_end();
1199 static void conntrack_acct_enable(void)
1201 /* We can still work w/o traffic accounting so just warn about error */
1202 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl.nfct_acct)) {
1203 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1204 strerror(errno));
1205 return;
1208 if (sysctl.nfct_acct == 1)
1209 return;
1211 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1212 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1213 strerror(errno));
1217 static void conntrack_tstamp_enable(void)
1219 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl.nfct_tstamp)) {
1220 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1221 strerror(errno));
1222 return;
1225 if (sysctl.nfct_tstamp == 1)
1226 return;
1228 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1229 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1230 strerror(errno));
1234 static int flow_update_cb(enum nf_conntrack_msg_type type,
1235 struct nf_conntrack *ct, void *data __maybe_unused)
1237 struct flow_entry *n;
1239 if (type != NFCT_T_UPDATE)
1240 return NFCT_CB_CONTINUE;
1242 if (sigint)
1243 return NFCT_CB_STOP;
1245 n = flow_list_find_id(&flow_list, nfct_get_attr_u32(ct, ATTR_ID));
1246 if (!n)
1247 return NFCT_CB_CONTINUE;
1249 flow_entry_calc_rate(n, ct);
1250 flow_entry_update_time(n);
1251 flow_entry_from_ct(n, ct);
1253 return NFCT_CB_CONTINUE;
1256 static void collector_refresh_flows(struct nfct_handle *handle)
1258 struct flow_entry *n;
1260 n = rcu_dereference(flow_list.head);
1261 for (; n; n = rcu_dereference(n->next)) {
1262 if (!n->is_visible)
1263 continue;
1265 nfct_query(handle, NFCT_Q_GET, n->ct);
1269 static void collector_create_filter(struct nfct_handle *nfct)
1271 struct nfct_filter *filter;
1272 int ret;
1274 filter = nfct_filter_create();
1275 if (!filter)
1276 panic("Cannot create a nfct filter: %s\n", strerror(errno));
1278 if (what & INCLUDE_UDP) {
1279 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
1280 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDPLITE);
1282 if (what & INCLUDE_TCP)
1283 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
1284 if (what & INCLUDE_DCCP)
1285 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_DCCP);
1286 if (what & INCLUDE_SCTP)
1287 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_SCTP);
1288 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1289 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMP);
1290 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1291 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMPV6);
1292 if (what & INCLUDE_IPV4) {
1293 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV4, NFCT_FILTER_LOGIC_NEGATIVE);
1294 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
1296 if (what & INCLUDE_IPV6) {
1297 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV6, NFCT_FILTER_LOGIC_NEGATIVE);
1298 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV6, &filter_ipv6);
1301 ret = nfct_filter_attach(nfct_fd(nfct), filter);
1302 if (ret < 0)
1303 panic("Cannot attach filter to handle: %s\n", strerror(errno));
1305 nfct_filter_destroy(filter);
1308 /* This hand-crafted filter looks ugly but it allows to do not
1309 * flush nfct connections & filter them by user specified filter.
1310 * May be it is better to replace this one by nfct_cmp. */
1311 static int flow_dump_cb(enum nf_conntrack_msg_type type,
1312 struct nf_conntrack *ct, void *data __maybe_unused)
1314 struct flow_entry fl;
1315 struct flow_entry *n = &fl;
1317 if (sigint)
1318 return NFCT_CB_STOP;
1320 synchronize_rcu();
1321 spinlock_lock(&flow_list.lock);
1323 if (!(what & ~(INCLUDE_IPV4 | INCLUDE_IPV6)))
1324 goto check_addr;
1326 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
1328 if (what & INCLUDE_UDP) {
1329 if (n->l4_proto == IPPROTO_UDP)
1330 goto check_addr;
1332 if (n->l4_proto == IPPROTO_UDPLITE)
1333 goto check_addr;
1336 if ((what & INCLUDE_TCP) && n->l4_proto == IPPROTO_TCP)
1337 goto check_addr;
1339 if ((what & INCLUDE_DCCP) && n->l4_proto == IPPROTO_DCCP)
1340 goto check_addr;
1342 if ((what & INCLUDE_SCTP) && n->l4_proto == IPPROTO_SCTP)
1343 goto check_addr;
1345 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV4) &&
1346 n->l4_proto == IPPROTO_ICMP) {
1347 goto check_addr;
1350 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV6) &&
1351 n->l4_proto == IPPROTO_ICMPV6) {
1352 goto check_addr;
1355 goto skip_flow;
1357 check_addr:
1358 /* filter loopback addresses */
1359 if (what & INCLUDE_IPV4) {
1360 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
1362 if (n->ip4_src_addr == filter_ipv4.addr)
1363 goto skip_flow;
1365 if (what & INCLUDE_IPV6) {
1366 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
1368 if (n->ip6_src_addr[0] == 0x0 &&
1369 n->ip6_src_addr[1] == 0x0 &&
1370 n->ip6_src_addr[2] == 0x0 &&
1371 n->ip6_src_addr[3] == 0x1)
1372 goto skip_flow;
1375 flow_list_new_entry(&flow_list, ct);
1377 skip_flow:
1378 spinlock_unlock(&flow_list.lock);
1379 return NFCT_CB_CONTINUE;
1382 static void collector_dump_flows(void)
1384 struct nfct_handle *nfct = nfct_open(CONNTRACK, 0);
1386 if (!nfct)
1387 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1389 nfct_callback_register(nfct, NFCT_T_ALL, flow_dump_cb, NULL);
1391 is_flow_collecting = true;
1392 if (what & INCLUDE_IPV4) {
1393 int family = AF_INET;
1394 nfct_query(nfct, NFCT_Q_DUMP, &family);
1396 if (what & INCLUDE_IPV6) {
1397 int family = AF_INET6;
1398 nfct_query(nfct, NFCT_Q_DUMP, &family);
1400 is_flow_collecting = false;
1402 nfct_close(nfct);
1405 static void *collector(void *null __maybe_unused)
1407 struct nfct_handle *ct_update;
1408 struct nfct_handle *ct_event;
1409 struct pollfd poll_fd[1];
1411 flow_list_init(&flow_list);
1413 ct_event = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW |
1414 NF_NETLINK_CONNTRACK_UPDATE |
1415 NF_NETLINK_CONNTRACK_DESTROY);
1416 if (!ct_event)
1417 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1419 collector_create_filter(ct_event);
1421 nfct_callback_register(ct_event, NFCT_T_ALL, flow_event_cb, NULL);
1423 ct_update = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_UPDATE);
1424 if (!ct_update)
1425 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1427 nfct_callback_register(ct_update, NFCT_T_ALL, flow_update_cb, NULL);
1429 poll_fd[0].fd = nfct_fd(ct_event);
1430 poll_fd[0].events = POLLIN;
1432 if (fcntl(nfct_fd(ct_event), F_SETFL, O_NONBLOCK) == -1)
1433 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1434 strerror(errno));
1436 if (fcntl(nfct_fd(ct_update), F_SETFL, O_NONBLOCK) == -1)
1437 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1438 strerror(errno));
1440 rcu_register_thread();
1442 collector_dump_flows();
1444 while (!sigint) {
1445 int status;
1447 usleep(1000000);
1449 collector_refresh_flows(ct_update);
1451 status = poll(poll_fd, 1, 0);
1452 if (status < 0) {
1453 if (errno == EAGAIN || errno == EINTR)
1454 continue;
1456 panic("Error while polling: %s\n", strerror(errno));
1457 } else if (status == 0) {
1458 continue;
1461 if (poll_fd[0].revents & POLLIN)
1462 nfct_catch(ct_event);
1465 rcu_unregister_thread();
1467 flow_list_destroy(&flow_list);
1468 nfct_close(ct_event);
1469 nfct_close(ct_update);
1471 pthread_exit(NULL);
1474 int main(int argc, char **argv)
1476 pthread_t tid;
1477 int ret, c, opt_index, what_cmd = 0;
1479 setfsuid(getuid());
1480 setfsgid(getgid());
1482 while ((c = getopt_long(argc, argv, short_options, long_options,
1483 &opt_index)) != EOF) {
1484 switch (c) {
1485 case '4':
1486 what_cmd |= INCLUDE_IPV4;
1487 break;
1488 case '6':
1489 what_cmd |= INCLUDE_IPV6;
1490 break;
1491 case 'T':
1492 what_cmd |= INCLUDE_TCP;
1493 break;
1494 case 'U':
1495 what_cmd |= INCLUDE_UDP;
1496 break;
1497 case 'D':
1498 what_cmd |= INCLUDE_DCCP;
1499 break;
1500 case 'I':
1501 what_cmd |= INCLUDE_ICMP;
1502 break;
1503 case 'S':
1504 what_cmd |= INCLUDE_SCTP;
1505 break;
1506 case 's':
1507 show_src = 1;
1508 break;
1509 case 'u':
1510 update_geoip();
1511 die();
1512 break;
1513 case 'h':
1514 help();
1515 break;
1516 case 'v':
1517 version();
1518 break;
1519 default:
1520 break;
1524 if (what_cmd > 0) {
1525 what = what_cmd;
1527 if (!(what & (INCLUDE_IPV4 | INCLUDE_IPV6)))
1528 what |= INCLUDE_IPV4 | INCLUDE_IPV6;
1531 rcu_init();
1533 register_signal(SIGINT, signal_handler);
1534 register_signal(SIGQUIT, signal_handler);
1535 register_signal(SIGTERM, signal_handler);
1536 register_signal(SIGHUP, signal_handler);
1538 panic_handler_add(on_panic_handler, &sysctl);
1540 conntrack_acct_enable();
1541 conntrack_tstamp_enable();
1543 init_geoip(1);
1545 ret = pthread_create(&tid, NULL, collector, NULL);
1546 if (ret < 0)
1547 panic("Cannot create phthread!\n");
1549 presenter();
1551 destroy_geoip();
1553 restore_sysctl(&sysctl);
1555 return 0;