netsniff-ng: nlmsg: Display "(none)" instead of "()" for zero flags
[netsniff-ng.git] / flowtop.c
blob9df4bdb4739dee9f301abd308ef76338ebaa0c2d
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/fsuid.h>
23 #include <urcu.h>
24 #include <libgen.h>
25 #include <inttypes.h>
26 #include <poll.h>
27 #include <fcntl.h>
29 #include "die.h"
30 #include "xmalloc.h"
31 #include "conntrack.h"
32 #include "config.h"
33 #include "str.h"
34 #include "sig.h"
35 #include "lookup.h"
36 #include "geoip.h"
37 #include "built_in.h"
38 #include "locking.h"
39 #include "pkt_buff.h"
40 #include "screen.h"
41 #include "proc.h"
42 #include "sysctl.h"
44 #ifndef NSEC_PER_SEC
45 #define NSEC_PER_SEC 1000000000L
46 #endif
48 struct flow_entry {
49 uint32_t flow_id, use, status;
50 uint8_t l3_proto, l4_proto;
51 uint32_t ip4_src_addr, ip4_dst_addr;
52 uint32_t ip6_src_addr[4], ip6_dst_addr[4];
53 uint16_t port_src, port_dst;
54 uint8_t tcp_state, tcp_flags, sctp_state, dccp_state;
55 uint64_t pkts_src, bytes_src;
56 uint64_t pkts_dst, bytes_dst;
57 uint64_t timestamp_start, timestamp_stop;
58 char country_src[128], country_dst[128];
59 char city_src[128], city_dst[128];
60 char rev_dns_src[256], rev_dns_dst[256];
61 char cmdline[256];
62 struct flow_entry *next;
63 int inode;
64 unsigned int procnum;
65 bool is_visible;
66 struct nf_conntrack *ct;
69 struct flow_list {
70 struct flow_entry *head;
71 struct spinlock lock;
74 #ifndef ATTR_TIMESTAMP_START
75 # define ATTR_TIMESTAMP_START 63
76 #endif
77 #ifndef ATTR_TIMESTAMP_STOP
78 # define ATTR_TIMESTAMP_STOP 64
79 #endif
81 #define SCROLL_MAX 1000
83 #define INCLUDE_IPV4 (1 << 0)
84 #define INCLUDE_IPV6 (1 << 1)
85 #define INCLUDE_UDP (1 << 2)
86 #define INCLUDE_TCP (1 << 3)
87 #define INCLUDE_DCCP (1 << 4)
88 #define INCLUDE_ICMP (1 << 5)
89 #define INCLUDE_SCTP (1 << 6)
91 struct sysctl_params_ctx {
92 int nfct_acct;
93 int nfct_tstamp;
96 static volatile bool is_flow_collecting;
97 static volatile sig_atomic_t sigint = 0;
98 static int what = INCLUDE_IPV4 | INCLUDE_IPV6 | INCLUDE_TCP, show_src = 0;
99 static struct flow_list flow_list;
100 static struct sysctl_params_ctx sysctl = { -1, -1 };
102 static const char *short_options = "vhTUsDIS46u";
103 static const struct option long_options[] = {
104 {"ipv4", no_argument, NULL, '4'},
105 {"ipv6", no_argument, NULL, '6'},
106 {"tcp", no_argument, NULL, 'T'},
107 {"udp", no_argument, NULL, 'U'},
108 {"dccp", no_argument, NULL, 'D'},
109 {"icmp", no_argument, NULL, 'I'},
110 {"sctp", no_argument, NULL, 'S'},
111 {"show-src", no_argument, NULL, 's'},
112 {"update", no_argument, NULL, 'u'},
113 {"version", no_argument, NULL, 'v'},
114 {"help", no_argument, NULL, 'h'},
115 {NULL, 0, NULL, 0}
118 static const char *copyright = "Please report bugs to <bugs@netsniff-ng.org>\n"
119 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
120 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
121 "Swiss federal institute of technology (ETH Zurich)\n"
122 "License: GNU GPL version 2.0\n"
123 "This is free software: you are free to change and redistribute it.\n"
124 "There is NO WARRANTY, to the extent permitted by law.";
126 static const char *const l3proto2str[AF_MAX] = {
127 [AF_INET] = "ipv4",
128 [AF_INET6] = "ipv6",
131 static const char *const l4proto2str[IPPROTO_MAX] = {
132 [IPPROTO_TCP] = "tcp",
133 [IPPROTO_UDP] = "udp",
134 [IPPROTO_UDPLITE] = "udplite",
135 [IPPROTO_ICMP] = "icmp",
136 [IPPROTO_ICMPV6] = "icmpv6",
137 [IPPROTO_SCTP] = "sctp",
138 [IPPROTO_GRE] = "gre",
139 [IPPROTO_DCCP] = "dccp",
140 [IPPROTO_IGMP] = "igmp",
141 [IPPROTO_IPIP] = "ipip",
142 [IPPROTO_EGP] = "egp",
143 [IPPROTO_PUP] = "pup",
144 [IPPROTO_IDP] = "idp",
145 [IPPROTO_RSVP] = "rsvp",
146 [IPPROTO_IPV6] = "ip6tun",
147 [IPPROTO_ESP] = "esp",
148 [IPPROTO_AH] = "ah",
149 [IPPROTO_PIM] = "pim",
150 [IPPROTO_COMP] = "comp",
153 static const char *const tcp_state2str[TCP_CONNTRACK_MAX] = {
154 [TCP_CONNTRACK_NONE] = "NOSTATE",
155 [TCP_CONNTRACK_SYN_SENT] = "SYN_SENT",
156 [TCP_CONNTRACK_SYN_RECV] = "SYN_RECV",
157 [TCP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
158 [TCP_CONNTRACK_FIN_WAIT] = "FIN_WAIT",
159 [TCP_CONNTRACK_CLOSE_WAIT] = "CLOSE_WAIT",
160 [TCP_CONNTRACK_LAST_ACK] = "LAST_ACK",
161 [TCP_CONNTRACK_TIME_WAIT] = "TIME_WAIT",
162 [TCP_CONNTRACK_CLOSE] = "CLOSE",
163 [TCP_CONNTRACK_SYN_SENT2] = "SYN_SENT2",
166 static const char *const dccp_state2str[DCCP_CONNTRACK_MAX] = {
167 [DCCP_CONNTRACK_NONE] = "NOSTATE",
168 [DCCP_CONNTRACK_REQUEST] = "REQUEST",
169 [DCCP_CONNTRACK_RESPOND] = "RESPOND",
170 [DCCP_CONNTRACK_PARTOPEN] = "PARTOPEN",
171 [DCCP_CONNTRACK_OPEN] = "OPEN",
172 [DCCP_CONNTRACK_CLOSEREQ] = "CLOSEREQ",
173 [DCCP_CONNTRACK_CLOSING] = "CLOSING",
174 [DCCP_CONNTRACK_TIMEWAIT] = "TIMEWAIT",
175 [DCCP_CONNTRACK_IGNORE] = "IGNORE",
176 [DCCP_CONNTRACK_INVALID] = "INVALID",
179 static const char *const sctp_state2str[SCTP_CONNTRACK_MAX] = {
180 [SCTP_CONNTRACK_NONE] = "NOSTATE",
181 [SCTP_CONNTRACK_CLOSED] = "CLOSED",
182 [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE_WAIT",
183 [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE_ECHOED",
184 [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED",
185 [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTDOWN_SENT",
186 [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTDOWN_RECD",
187 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT",
190 static const struct nfct_filter_ipv4 filter_ipv4 = {
191 .addr = __constant_htonl(INADDR_LOOPBACK),
192 .mask = 0xffffffff,
195 static const struct nfct_filter_ipv6 filter_ipv6 = {
196 .addr = { 0x0, 0x0, 0x0, 0x1 },
197 .mask = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
200 static void signal_handler(int number)
202 switch (number) {
203 case SIGINT:
204 case SIGQUIT:
205 case SIGTERM:
206 sigint = 1;
207 break;
208 case SIGHUP:
209 default:
210 break;
214 static void flow_entry_from_ct(struct flow_entry *n, struct nf_conntrack *ct);
215 static void flow_entry_get_extended(struct flow_entry *n);
217 static void help(void)
219 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
220 VERSION_STRING);
221 puts("http://www.netsniff-ng.org\n\n"
222 "Usage: flowtop [options]\n"
223 "Options:\n"
224 " -4|--ipv4 Show only IPv4 flows (default)\n"
225 " -6|--ipv6 Show only IPv6 flows (default)\n"
226 " -T|--tcp Show only TCP flows (default)\n"
227 " -U|--udp Show only UDP flows\n"
228 " -D|--dccp Show only DCCP flows\n"
229 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
230 " -S|--sctp Show only SCTP flows\n"
231 " -s|--show-src Also show source, not only dest\n"
232 " -u|--update Update GeoIP databases\n"
233 " -v|--version Print version and exit\n"
234 " -h|--help Print this help and exit\n\n"
235 "Examples:\n"
236 " flowtop\n"
237 " flowtop -46UTDISs\n\n"
238 "Note:\n"
239 " If netfilter is not running, you can activate it with e.g.:\n"
240 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
241 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
242 puts(copyright);
243 die();
246 static void version(void)
248 printf("flowtop %s, Git id: %s\n", VERSION_LONG, GITVERSION);
249 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
250 "http://www.netsniff-ng.org\n");
251 puts(copyright);
252 die();
255 static inline struct flow_entry *flow_entry_xalloc(void)
257 return xzmalloc(sizeof(struct flow_entry));
260 static inline void flow_entry_xfree(struct flow_entry *n)
262 if (n->ct)
263 nfct_destroy(n->ct);
265 xfree(n);
268 static inline void flow_list_init(struct flow_list *fl)
270 fl->head = NULL;
271 spinlock_init(&fl->lock);
274 static inline bool nfct_is_dns(struct nf_conntrack *ct)
276 uint16_t port_src = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
277 uint16_t port_dst = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
279 return ntohs(port_src) == 53 || ntohs(port_dst) == 53;
282 static void flow_list_new_entry(struct flow_list *fl, struct nf_conntrack *ct)
284 struct flow_entry *n;
286 /* We don't want to analyze / display DNS itself, since we
287 * use it to resolve reverse dns.
289 if (nfct_is_dns(ct))
290 return;
292 n = flow_entry_xalloc();
294 n->ct = nfct_clone(ct);
296 flow_entry_from_ct(n, ct);
297 flow_entry_get_extended(n);
299 rcu_assign_pointer(n->next, fl->head);
300 rcu_assign_pointer(fl->head, n);
303 static struct flow_entry *flow_list_find_id(struct flow_list *fl,
304 uint32_t id)
306 struct flow_entry *n = rcu_dereference(fl->head);
308 while (n != NULL) {
309 if (n->flow_id == id)
310 return n;
312 n = rcu_dereference(n->next);
315 return NULL;
318 static struct flow_entry *flow_list_find_prev_id(struct flow_list *fl,
319 uint32_t id)
321 struct flow_entry *prev = rcu_dereference(fl->head), *next;
323 if (prev->flow_id == id)
324 return NULL;
326 while ((next = rcu_dereference(prev->next)) != NULL) {
327 if (next->flow_id == id)
328 return prev;
330 prev = next;
333 return NULL;
336 static void flow_list_update_entry(struct flow_list *fl,
337 struct nf_conntrack *ct)
339 struct flow_entry *n;
341 n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
342 if (n == NULL) {
343 flow_list_new_entry(fl, ct);
344 return;
347 flow_entry_from_ct(n, ct);
350 static void flow_list_destroy_entry(struct flow_list *fl,
351 struct nf_conntrack *ct)
353 struct flow_entry *n1, *n2;
354 uint32_t id = nfct_get_attr_u32(ct, ATTR_ID);
356 n1 = flow_list_find_id(fl, id);
357 if (n1) {
358 n2 = flow_list_find_prev_id(fl, id);
359 if (n2) {
360 rcu_assign_pointer(n2->next, n1->next);
361 n1->next = NULL;
363 flow_entry_xfree(n1);
364 } else {
365 struct flow_entry *next = fl->head->next;
367 flow_entry_xfree(fl->head);
368 fl->head = next;
373 static void flow_list_destroy(struct flow_list *fl)
375 struct flow_entry *n;
377 while (fl->head != NULL) {
378 n = rcu_dereference(fl->head->next);
379 fl->head->next = NULL;
381 flow_entry_xfree(fl->head);
382 rcu_assign_pointer(fl->head, n);
385 synchronize_rcu();
386 spinlock_destroy(&fl->lock);
389 static int walk_process(unsigned int pid, struct flow_entry *n)
391 int ret;
392 DIR *dir;
393 struct dirent *ent;
394 char path[1024];
396 if (snprintf(path, sizeof(path), "/proc/%u/fd", pid) == -1)
397 panic("giant process name! %u\n", pid);
399 dir = opendir(path);
400 if (!dir)
401 return 0;
403 while ((ent = readdir(dir))) {
404 struct stat statbuf;
406 if (snprintf(path, sizeof(path), "/proc/%u/fd/%s",
407 pid, ent->d_name) < 0)
408 continue;
410 if (stat(path, &statbuf) < 0)
411 continue;
413 if (S_ISSOCK(statbuf.st_mode) && (ino_t) n->inode == statbuf.st_ino) {
414 ret = proc_get_cmdline(pid, n->cmdline, sizeof(n->cmdline));
415 if (ret < 0)
416 panic("Failed to get process cmdline: %s\n", strerror(errno));
418 n->procnum = pid;
419 closedir(dir);
420 return 1;
424 closedir(dir);
425 return 0;
428 static void walk_processes(struct flow_entry *n)
430 int ret;
431 DIR *dir;
432 struct dirent *ent;
434 /* n->inode must be set */
435 if (n->inode <= 0) {
436 n->cmdline[0] = '\0';
437 return;
440 dir = opendir("/proc");
441 if (!dir)
442 panic("Cannot open /proc: %s\n", strerror(errno));
444 while ((ent = readdir(dir))) {
445 const char *name = ent->d_name;
446 char *end;
447 unsigned int pid = strtoul(name, &end, 10);
449 /* not a PID */
450 if (pid == 0 && end == name)
451 continue;
453 ret = walk_process(pid, n);
454 if (ret > 0)
455 break;
458 closedir(dir);
461 static int get_port_inode(uint16_t port, int proto, bool is_ip6)
463 int ret = -ENOENT;
464 char path[128], buff[1024];
465 FILE *proc;
467 memset(path, 0, sizeof(path));
468 snprintf(path, sizeof(path), "/proc/net/%s%s",
469 l4proto2str[proto], is_ip6 ? "6" : "");
471 proc = fopen(path, "r");
472 if (!proc)
473 return -EIO;
475 memset(buff, 0, sizeof(buff));
477 while (fgets(buff, sizeof(buff), proc) != NULL) {
478 int inode = 0;
479 unsigned int lport = 0;
481 buff[sizeof(buff) - 1] = 0;
482 if (sscanf(buff, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
483 "%*X %*u %*u %u", &lport, &inode) == 2) {
484 if ((uint16_t) lport == port) {
485 ret = inode;
486 break;
490 memset(buff, 0, sizeof(buff));
493 fclose(proc);
494 return ret;
497 #define CP_NFCT(elem, attr, x) \
498 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
499 #define CP_NFCT_BUFF(elem, attr) do { \
500 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
501 if (buff != NULL) \
502 memcpy(n->elem, buff, sizeof(n->elem)); \
503 } while (0)
505 static void flow_entry_from_ct(struct flow_entry *n, struct nf_conntrack *ct)
507 CP_NFCT(l3_proto, ATTR_ORIG_L3PROTO, 8);
508 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
510 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
511 CP_NFCT(ip4_dst_addr, ATTR_ORIG_IPV4_DST, 32);
513 CP_NFCT(port_src, ATTR_ORIG_PORT_SRC, 16);
514 CP_NFCT(port_dst, ATTR_ORIG_PORT_DST, 16);
516 CP_NFCT(status, ATTR_STATUS, 32);
518 CP_NFCT(tcp_state, ATTR_TCP_STATE, 8);
519 CP_NFCT(tcp_flags, ATTR_TCP_FLAGS_ORIG, 8);
520 CP_NFCT(sctp_state, ATTR_SCTP_STATE, 8);
521 CP_NFCT(dccp_state, ATTR_DCCP_STATE, 8);
523 CP_NFCT(pkts_src, ATTR_ORIG_COUNTER_PACKETS, 64);
524 CP_NFCT(bytes_src, ATTR_ORIG_COUNTER_BYTES, 64);
526 CP_NFCT(pkts_dst, ATTR_REPL_COUNTER_PACKETS, 64);
527 CP_NFCT(bytes_dst, ATTR_REPL_COUNTER_BYTES, 64);
529 CP_NFCT(timestamp_start, ATTR_TIMESTAMP_START, 64);
530 CP_NFCT(timestamp_stop, ATTR_TIMESTAMP_STOP, 64);
532 CP_NFCT(flow_id, ATTR_ID, 32);
533 CP_NFCT(use, ATTR_USE, 32);
535 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
536 CP_NFCT_BUFF(ip6_dst_addr, ATTR_ORIG_IPV6_DST);
538 n->port_src = ntohs(n->port_src);
539 n->port_dst = ntohs(n->port_dst);
541 n->ip4_src_addr = ntohl(n->ip4_src_addr);
542 n->ip4_dst_addr = ntohl(n->ip4_dst_addr);
545 enum flow_entry_direction {
546 flow_entry_src,
547 flow_entry_dst,
550 #define SELFLD(dir,src_member,dst_member) \
551 (((dir) == flow_entry_src) ? n->src_member : n->dst_member)
553 static void flow_entry_get_sain4_obj(struct flow_entry *n,
554 enum flow_entry_direction dir,
555 struct sockaddr_in *sa)
557 memset(sa, 0, sizeof(*sa));
558 sa->sin_family = PF_INET;
559 sa->sin_addr.s_addr = htonl(SELFLD(dir, ip4_src_addr, ip4_dst_addr));
562 static void flow_entry_get_sain6_obj(struct flow_entry *n,
563 enum flow_entry_direction dir,
564 struct sockaddr_in6 *sa)
566 memset(sa, 0, sizeof(*sa));
567 sa->sin6_family = PF_INET6;
569 memcpy(&sa->sin6_addr, SELFLD(dir, ip6_src_addr, ip6_dst_addr),
570 sizeof(sa->sin6_addr));
573 static void
574 flow_entry_geo_city_lookup_generic(struct flow_entry *n,
575 enum flow_entry_direction dir)
577 struct sockaddr_in sa4;
578 struct sockaddr_in6 sa6;
579 const char *city = NULL;
581 switch (n->l3_proto) {
582 default:
583 bug();
585 case AF_INET:
586 flow_entry_get_sain4_obj(n, dir, &sa4);
587 city = geoip4_city_name(&sa4);
588 break;
590 case AF_INET6:
591 flow_entry_get_sain6_obj(n, dir, &sa6);
592 city = geoip6_city_name(&sa6);
593 break;
596 build_bug_on(sizeof(n->city_src) != sizeof(n->city_dst));
598 if (city) {
599 memcpy(SELFLD(dir, city_src, city_dst), city,
600 min(sizeof(n->city_src), strlen(city)));
601 } else {
602 memset(SELFLD(dir, city_src, city_dst), 0,
603 sizeof(n->city_src));
607 static void
608 flow_entry_geo_country_lookup_generic(struct flow_entry *n,
609 enum flow_entry_direction dir)
611 struct sockaddr_in sa4;
612 struct sockaddr_in6 sa6;
613 const char *country = NULL;
615 switch (n->l3_proto) {
616 default:
617 bug();
619 case AF_INET:
620 flow_entry_get_sain4_obj(n, dir, &sa4);
621 country = geoip4_country_name(&sa4);
622 break;
624 case AF_INET6:
625 flow_entry_get_sain6_obj(n, dir, &sa6);
626 country = geoip6_country_name(&sa6);
627 break;
630 build_bug_on(sizeof(n->country_src) != sizeof(n->country_dst));
632 if (country) {
633 memcpy(SELFLD(dir, country_src, country_dst), country,
634 min(sizeof(n->country_src), strlen(country)));
635 } else {
636 memset(SELFLD(dir, country_src, country_dst), 0,
637 sizeof(n->country_src));
641 static void flow_entry_get_extended_geo(struct flow_entry *n,
642 enum flow_entry_direction dir)
644 flow_entry_geo_city_lookup_generic(n, dir);
645 flow_entry_geo_country_lookup_generic(n, dir);
648 static void flow_entry_get_extended_revdns(struct flow_entry *n,
649 enum flow_entry_direction dir)
651 size_t sa_len;
652 struct sockaddr_in sa4;
653 struct sockaddr_in6 sa6;
654 struct sockaddr *sa;
655 struct hostent *hent;
657 switch (n->l3_proto) {
658 default:
659 bug();
661 case AF_INET:
662 flow_entry_get_sain4_obj(n, dir, &sa4);
663 sa = (struct sockaddr *) &sa4;
664 sa_len = sizeof(sa4);
665 hent = gethostbyaddr(&sa4.sin_addr, sizeof(sa4.sin_addr), AF_INET);
666 break;
668 case AF_INET6:
669 flow_entry_get_sain6_obj(n, dir, &sa6);
670 sa = (struct sockaddr *) &sa6;
671 sa_len = sizeof(sa6);
672 hent = gethostbyaddr(&sa6.sin6_addr, sizeof(sa6.sin6_addr), AF_INET6);
673 break;
676 build_bug_on(sizeof(n->rev_dns_src) != sizeof(n->rev_dns_dst));
677 getnameinfo(sa, sa_len, SELFLD(dir, rev_dns_src, rev_dns_dst),
678 sizeof(n->rev_dns_src), NULL, 0, NI_NUMERICHOST);
680 if (hent) {
681 memset(n->rev_dns_dst, 0, sizeof(n->rev_dns_dst));
682 memcpy(SELFLD(dir, rev_dns_src, rev_dns_dst),
683 hent->h_name, min(sizeof(n->rev_dns_src),
684 strlen(hent->h_name)));
688 static void flow_entry_get_extended(struct flow_entry *n)
690 if (n->flow_id == 0)
691 return;
693 if (show_src) {
694 flow_entry_get_extended_revdns(n, flow_entry_src);
695 flow_entry_get_extended_geo(n, flow_entry_src);
698 flow_entry_get_extended_revdns(n, flow_entry_dst);
699 flow_entry_get_extended_geo(n, flow_entry_dst);
701 /* Lookup application */
702 n->inode = get_port_inode(n->port_src, n->l4_proto,
703 n->l3_proto == AF_INET6);
704 if (n->inode > 0)
705 walk_processes(n);
708 static uint16_t presenter_get_port(uint16_t src, uint16_t dst, bool is_tcp)
710 if (src < dst && src < 1024) {
711 return src;
712 } else if (dst < src && dst < 1024) {
713 return dst;
714 } else {
715 const char *tmp1, *tmp2;
716 if (is_tcp) {
717 tmp1 = lookup_port_tcp(src);
718 tmp2 = lookup_port_tcp(dst);
719 } else {
720 tmp1 = lookup_port_udp(src);
721 tmp2 = lookup_port_udp(dst);
723 if (tmp1 && !tmp2) {
724 return src;
725 } else if (!tmp1 && tmp2) {
726 return dst;
727 } else {
728 if (src < dst)
729 return src;
730 else
731 return dst;
736 static char *bandw2str(double bytes, char *buf, size_t len)
738 if (bytes > 1000000000.)
739 snprintf(buf, len, "%.1fG", bytes / 1000000000.);
740 else if (bytes > 1000000.)
741 snprintf(buf, len, "%.1fM", bytes / 1000000.);
742 else if (bytes > 1000.)
743 snprintf(buf, len, "%.1fK", bytes / 1000.);
744 else
745 snprintf(buf, len, "%g", bytes);
747 return buf;
750 static void presenter_print_counters(uint64_t bytes, uint64_t pkts, int color)
752 char bytes_str[64];
754 printw(" -> (");
755 attron(COLOR_PAIR(color));
756 printw("%"PRIu64" pkts, ", pkts);
757 printw("%s bytes", bandw2str(bytes, bytes_str, sizeof(bytes_str) - 1));
758 attroff(COLOR_PAIR(color));
759 printw(")");
762 static void presenter_print_flow_entry_time(struct flow_entry *n)
764 int h, m, s;
765 time_t now;
767 time(&now);
769 s = now - (n->timestamp_start / NSEC_PER_SEC);
770 if (s <= 0)
771 return;
773 h = s / 3600;
774 s -= h * 3600;
775 m = s / 60;
776 s -= m * 60;
778 printw(" [ time");
779 if (h > 0)
780 printw(" %dh", h);
781 if (m > 0)
782 printw(" %dm", m);
783 if (s > 0)
784 printw(" %ds", s);
785 printw(" ]");
788 static void presenter_screen_do_line(WINDOW *screen, struct flow_entry *n,
789 unsigned int *line)
791 char tmp[128], *pname = NULL;
792 uint16_t port;
794 mvwprintw(screen, *line, 2, "");
796 /* PID, application name */
797 if (n->procnum > 0) {
798 slprintf(tmp, sizeof(tmp), "%s(%d)", basename(n->cmdline),
799 n->procnum);
801 printw("[");
802 attron(COLOR_PAIR(3));
803 printw("%s", tmp);
804 attroff(COLOR_PAIR(3));
805 printw("]:");
808 /* L3 protocol, L4 protocol, states */
809 printw("%s:%s", l3proto2str[n->l3_proto], l4proto2str[n->l4_proto]);
810 printw("[");
811 attron(COLOR_PAIR(3));
812 switch (n->l4_proto) {
813 case IPPROTO_TCP:
814 printw("%s", tcp_state2str[n->tcp_state]);
815 break;
816 case IPPROTO_SCTP:
817 printw("%s", sctp_state2str[n->sctp_state]);
818 break;
819 case IPPROTO_DCCP:
820 printw("%s", dccp_state2str[n->dccp_state]);
821 break;
822 case IPPROTO_UDP:
823 case IPPROTO_UDPLITE:
824 case IPPROTO_ICMP:
825 case IPPROTO_ICMPV6:
826 printw("NOSTATE");
827 break;
829 attroff(COLOR_PAIR(3));
830 printw("]");
832 /* Guess application port */
833 switch (n->l4_proto) {
834 case IPPROTO_TCP:
835 port = presenter_get_port(n->port_src, n->port_dst, true);
836 pname = lookup_port_tcp(port);
837 break;
838 case IPPROTO_UDP:
839 case IPPROTO_UDPLITE:
840 port = presenter_get_port(n->port_src, n->port_dst, false);
841 pname = lookup_port_udp(port);
842 break;
844 if (pname) {
845 attron(A_BOLD);
846 printw(":%s", pname);
847 attroff(A_BOLD);
850 if (n->timestamp_start > 0)
851 presenter_print_flow_entry_time(n);
853 /* Show source information: reverse DNS, port, country, city, counters */
854 if (show_src) {
855 attron(COLOR_PAIR(1));
856 mvwprintw(screen, ++(*line), 8, "src: %s", n->rev_dns_src);
857 attroff(COLOR_PAIR(1));
859 printw(":%"PRIu16, n->port_src);
861 if (n->country_src[0]) {
862 printw(" (");
864 attron(COLOR_PAIR(4));
865 printw("%s", n->country_src);
866 attroff(COLOR_PAIR(4));
868 if (n->city_src[0])
869 printw(", %s", n->city_src);
871 printw(")");
874 if (n->pkts_src > 0 && n->bytes_src > 0)
875 presenter_print_counters(n->bytes_src, n->pkts_src, 1);
877 printw(" => ");
880 /* Show dest information: reverse DNS, port, country, city, counters */
881 attron(COLOR_PAIR(2));
882 mvwprintw(screen, ++(*line), 8, "dst: %s", n->rev_dns_dst);
883 attroff(COLOR_PAIR(2));
885 printw(":%"PRIu16, n->port_dst);
887 if (n->country_dst[0]) {
888 printw(" (");
890 attron(COLOR_PAIR(4));
891 printw("%s", n->country_dst);
892 attroff(COLOR_PAIR(4));
894 if (n->city_dst[0])
895 printw(", %s", n->city_dst);
897 printw(")");
900 if (n->pkts_dst > 0 && n->bytes_dst > 0)
901 presenter_print_counters(n->bytes_dst, n->pkts_dst, 2);
904 static inline bool presenter_flow_wrong_state(struct flow_entry *n)
906 switch (n->l4_proto) {
907 case IPPROTO_TCP:
908 switch (n->tcp_state) {
909 case TCP_CONNTRACK_SYN_SENT:
910 case TCP_CONNTRACK_SYN_RECV:
911 case TCP_CONNTRACK_ESTABLISHED:
912 case TCP_CONNTRACK_FIN_WAIT:
913 case TCP_CONNTRACK_CLOSE_WAIT:
914 case TCP_CONNTRACK_LAST_ACK:
915 case TCP_CONNTRACK_TIME_WAIT:
916 case TCP_CONNTRACK_CLOSE:
917 case TCP_CONNTRACK_SYN_SENT2:
918 case TCP_CONNTRACK_NONE:
919 return false;
920 break;
922 break;
923 case IPPROTO_SCTP:
924 switch (n->sctp_state) {
925 case SCTP_CONNTRACK_NONE:
926 case SCTP_CONNTRACK_CLOSED:
927 case SCTP_CONNTRACK_COOKIE_WAIT:
928 case SCTP_CONNTRACK_COOKIE_ECHOED:
929 case SCTP_CONNTRACK_ESTABLISHED:
930 case SCTP_CONNTRACK_SHUTDOWN_SENT:
931 case SCTP_CONNTRACK_SHUTDOWN_RECD:
932 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT:
933 return false;
934 break;
936 break;
937 case IPPROTO_DCCP:
938 switch (n->dccp_state) {
939 case DCCP_CONNTRACK_NONE:
940 case DCCP_CONNTRACK_REQUEST:
941 case DCCP_CONNTRACK_RESPOND:
942 case DCCP_CONNTRACK_PARTOPEN:
943 case DCCP_CONNTRACK_OPEN:
944 case DCCP_CONNTRACK_CLOSEREQ:
945 case DCCP_CONNTRACK_CLOSING:
946 case DCCP_CONNTRACK_TIMEWAIT:
947 case DCCP_CONNTRACK_IGNORE:
948 case DCCP_CONNTRACK_INVALID:
949 return false;
950 break;
952 break;
953 case IPPROTO_UDP:
954 case IPPROTO_UDPLITE:
955 case IPPROTO_ICMP:
956 case IPPROTO_ICMPV6:
957 return false;
958 break;
961 return true;
964 static void presenter_screen_update(WINDOW *screen, struct flow_list *fl,
965 int skip_lines)
967 int maxy;
968 int skip_left = skip_lines;
969 unsigned int flows = 0;
970 unsigned int line = 3;
971 struct flow_entry *n;
973 curs_set(0);
975 maxy = getmaxy(screen);
976 maxy -= 6;
978 start_color();
979 init_pair(1, COLOR_RED, COLOR_BLACK);
980 init_pair(2, COLOR_BLUE, COLOR_BLACK);
981 init_pair(3, COLOR_YELLOW, COLOR_BLACK);
982 init_pair(4, COLOR_GREEN, COLOR_BLACK);
984 wclear(screen);
985 clear();
987 rcu_read_lock();
989 n = rcu_dereference(fl->head);
990 if (!n)
991 mvwprintw(screen, line, 2, "(No active sessions! "
992 "Is netfilter running?)");
994 for (; n; n = rcu_dereference(n->next)) {
995 n->is_visible = false;
997 if (presenter_flow_wrong_state(n))
998 continue;
1000 /* count only flows which might be showed */
1001 flows++;
1003 if (maxy <= 0)
1004 continue;
1006 if (skip_left > 0) {
1007 skip_left--;
1008 continue;
1011 n->is_visible = true;
1013 presenter_screen_do_line(screen, n, &line);
1015 line++;
1016 maxy -= (2 + 1 * show_src);
1019 mvwprintw(screen, 1, 2,
1020 "Kernel netfilter flows(%u) for %s%s%s%s%s%s"
1021 "[+%d]", flows, what & INCLUDE_TCP ? "TCP, " : "",
1022 what & INCLUDE_UDP ? "UDP, " : "",
1023 what & INCLUDE_SCTP ? "SCTP, " : "",
1024 what & INCLUDE_DCCP ? "DCCP, " : "",
1025 what & INCLUDE_ICMP && what & INCLUDE_IPV4 ? "ICMP, " : "",
1026 what & INCLUDE_ICMP && what & INCLUDE_IPV6 ? "ICMP6, " : "",
1027 skip_lines);
1029 if (is_flow_collecting)
1030 printw(" [Collecting flows ...]");
1032 rcu_read_unlock();
1034 wrefresh(screen);
1035 refresh();
1038 static void presenter(void)
1040 int skip_lines = 0;
1041 WINDOW *screen;
1043 lookup_init_ports(PORTS_TCP);
1044 lookup_init_ports(PORTS_UDP);
1045 screen = screen_init(false);
1047 rcu_register_thread();
1048 while (!sigint) {
1049 switch (getch()) {
1050 case 'q':
1051 sigint = 1;
1052 break;
1053 case KEY_UP:
1054 case 'u':
1055 case 'k':
1056 skip_lines--;
1057 if (skip_lines < 0)
1058 skip_lines = 0;
1059 break;
1060 case KEY_DOWN:
1061 case 'd':
1062 case 'j':
1063 skip_lines++;
1064 if (skip_lines > SCROLL_MAX)
1065 skip_lines = SCROLL_MAX;
1066 break;
1067 default:
1068 fflush(stdin);
1069 break;
1072 presenter_screen_update(screen, &flow_list, skip_lines);
1073 usleep(200000);
1075 rcu_unregister_thread();
1077 screen_end();
1078 lookup_cleanup_ports(PORTS_UDP);
1079 lookup_cleanup_ports(PORTS_TCP);
1082 static int flow_event_cb(enum nf_conntrack_msg_type type,
1083 struct nf_conntrack *ct, void *data __maybe_unused)
1085 if (sigint)
1086 return NFCT_CB_STOP;
1088 synchronize_rcu();
1089 spinlock_lock(&flow_list.lock);
1091 switch (type) {
1092 case NFCT_T_NEW:
1093 flow_list_new_entry(&flow_list, ct);
1094 break;
1095 case NFCT_T_UPDATE:
1096 flow_list_update_entry(&flow_list, ct);
1097 break;
1098 case NFCT_T_DESTROY:
1099 flow_list_destroy_entry(&flow_list, ct);
1100 break;
1101 default:
1102 break;
1105 spinlock_unlock(&flow_list.lock);
1107 return NFCT_CB_CONTINUE;
1110 static void restore_sysctl(void *obj)
1112 struct sysctl_params_ctx *sysctl_ctx = obj;
1114 if (sysctl_ctx->nfct_acct == 0)
1115 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1116 sysctl_ctx->nfct_acct);
1118 if (sysctl_ctx->nfct_tstamp == 0)
1119 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1120 sysctl_ctx->nfct_tstamp);
1123 static void on_panic_handler(void *arg)
1125 restore_sysctl(arg);
1126 screen_end();
1129 static void conntrack_acct_enable(void)
1131 /* We can still work w/o traffic accounting so just warn about error */
1132 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl.nfct_acct)) {
1133 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1134 strerror(errno));
1135 return;
1138 if (sysctl.nfct_acct == 1)
1139 return;
1141 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1142 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1143 strerror(errno));
1147 static void conntrack_tstamp_enable(void)
1149 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl.nfct_tstamp)) {
1150 fprintf(stderr, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1151 strerror(errno));
1152 return;
1155 if (sysctl.nfct_tstamp == 1)
1156 return;
1158 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1159 fprintf(stderr, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1160 strerror(errno));
1164 static int flow_update_cb(enum nf_conntrack_msg_type type,
1165 struct nf_conntrack *ct, void *data __maybe_unused)
1167 struct flow_entry *n;
1169 if (type != NFCT_T_UPDATE)
1170 return NFCT_CB_CONTINUE;
1172 if (sigint)
1173 return NFCT_CB_STOP;
1175 n = flow_list_find_id(&flow_list, nfct_get_attr_u32(ct, ATTR_ID));
1176 if (!n)
1177 return NFCT_CB_CONTINUE;
1179 flow_entry_from_ct(n, ct);
1181 return NFCT_CB_CONTINUE;
1184 static void collector_refresh_flows(struct nfct_handle *handle)
1186 struct flow_entry *n;
1188 n = rcu_dereference(flow_list.head);
1189 for (; n; n = rcu_dereference(n->next)) {
1190 if (!n->is_visible)
1191 continue;
1193 nfct_query(handle, NFCT_Q_GET, n->ct);
1197 static void collector_create_filter(struct nfct_handle *nfct)
1199 struct nfct_filter *filter;
1200 int ret;
1202 filter = nfct_filter_create();
1203 if (!filter)
1204 panic("Cannot create a nfct filter: %s\n", strerror(errno));
1206 if (what & INCLUDE_UDP) {
1207 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
1208 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDPLITE);
1210 if (what & INCLUDE_TCP)
1211 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
1212 if (what & INCLUDE_DCCP)
1213 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_DCCP);
1214 if (what & INCLUDE_SCTP)
1215 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_SCTP);
1216 if (what & INCLUDE_ICMP && what & INCLUDE_IPV4)
1217 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMP);
1218 if (what & INCLUDE_ICMP && what & INCLUDE_IPV6)
1219 nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_ICMPV6);
1220 if (what & INCLUDE_IPV4) {
1221 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV4, NFCT_FILTER_LOGIC_NEGATIVE);
1222 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
1224 if (what & INCLUDE_IPV6) {
1225 nfct_filter_set_logic(filter, NFCT_FILTER_SRC_IPV6, NFCT_FILTER_LOGIC_NEGATIVE);
1226 nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV6, &filter_ipv6);
1229 ret = nfct_filter_attach(nfct_fd(nfct), filter);
1230 if (ret < 0)
1231 panic("Cannot attach filter to handle: %s\n", strerror(errno));
1233 nfct_filter_destroy(filter);
1236 /* This hand-crafted filter looks ugly but it allows to do not
1237 * flush nfct connections & filter them by user specified filter.
1238 * May be it is better to replace this one by nfct_cmp. */
1239 static int flow_dump_cb(enum nf_conntrack_msg_type type,
1240 struct nf_conntrack *ct, void *data __maybe_unused)
1242 struct flow_entry fl;
1243 struct flow_entry *n = &fl;
1245 if (sigint)
1246 return NFCT_CB_STOP;
1248 synchronize_rcu();
1249 spinlock_lock(&flow_list.lock);
1251 if (!(what & ~(INCLUDE_IPV4 | INCLUDE_IPV6)))
1252 goto check_addr;
1254 CP_NFCT(l4_proto, ATTR_ORIG_L4PROTO, 8);
1256 if (what & INCLUDE_UDP) {
1257 if (n->l4_proto == IPPROTO_UDP)
1258 goto check_addr;
1260 if (n->l4_proto == IPPROTO_UDPLITE)
1261 goto check_addr;
1264 if ((what & INCLUDE_TCP) && n->l4_proto == IPPROTO_TCP)
1265 goto check_addr;
1267 if ((what & INCLUDE_DCCP) && n->l4_proto == IPPROTO_DCCP)
1268 goto check_addr;
1270 if ((what & INCLUDE_SCTP) && n->l4_proto == IPPROTO_SCTP)
1271 goto check_addr;
1273 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV4) &&
1274 n->l4_proto == IPPROTO_ICMP) {
1275 goto check_addr;
1278 if ((what & INCLUDE_ICMP) && (what & INCLUDE_IPV6) &&
1279 n->l4_proto == IPPROTO_ICMPV6) {
1280 goto check_addr;
1283 goto skip_flow;
1285 check_addr:
1286 /* filter loopback addresses */
1287 if (what & INCLUDE_IPV4) {
1288 CP_NFCT(ip4_src_addr, ATTR_ORIG_IPV4_SRC, 32);
1290 if (n->ip4_src_addr == filter_ipv4.addr)
1291 goto skip_flow;
1293 if (what & INCLUDE_IPV6) {
1294 CP_NFCT_BUFF(ip6_src_addr, ATTR_ORIG_IPV6_SRC);
1296 if (n->ip6_src_addr[0] == 0x0 &&
1297 n->ip6_src_addr[1] == 0x0 &&
1298 n->ip6_src_addr[2] == 0x0 &&
1299 n->ip6_src_addr[3] == 0x1)
1300 goto skip_flow;
1303 flow_list_new_entry(&flow_list, ct);
1305 skip_flow:
1306 spinlock_unlock(&flow_list.lock);
1307 return NFCT_CB_CONTINUE;
1310 static void collector_dump_flows(void)
1312 struct nfct_handle *nfct = nfct_open(CONNTRACK, 0);
1314 if (!nfct)
1315 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1317 nfct_callback_register(nfct, NFCT_T_ALL, flow_dump_cb, NULL);
1319 is_flow_collecting = true;
1320 if (what & INCLUDE_IPV4) {
1321 int family = AF_INET;
1322 nfct_query(nfct, NFCT_Q_DUMP, &family);
1324 if (what & INCLUDE_IPV6) {
1325 int family = AF_INET6;
1326 nfct_query(nfct, NFCT_Q_DUMP, &family);
1328 is_flow_collecting = false;
1330 nfct_close(nfct);
1333 static void *collector(void *null __maybe_unused)
1335 struct nfct_handle *ct_update;
1336 struct nfct_handle *ct_event;
1337 struct pollfd poll_fd[1];
1339 flow_list_init(&flow_list);
1341 ct_event = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW |
1342 NF_NETLINK_CONNTRACK_UPDATE |
1343 NF_NETLINK_CONNTRACK_DESTROY);
1344 if (!ct_event)
1345 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1347 collector_create_filter(ct_event);
1349 nfct_callback_register(ct_event, NFCT_T_ALL, flow_event_cb, NULL);
1351 ct_update = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_UPDATE);
1352 if (!ct_update)
1353 panic("Cannot create a nfct handle: %s\n", strerror(errno));
1355 nfct_callback_register(ct_update, NFCT_T_ALL, flow_update_cb, NULL);
1357 poll_fd[0].fd = nfct_fd(ct_event);
1358 poll_fd[0].events = POLLIN;
1360 if (fcntl(nfct_fd(ct_event), F_SETFL, O_NONBLOCK) == -1)
1361 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1362 strerror(errno));
1364 if (fcntl(nfct_fd(ct_update), F_SETFL, O_NONBLOCK) == -1)
1365 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1366 strerror(errno));
1368 rcu_register_thread();
1370 collector_dump_flows();
1372 while (!sigint) {
1373 int status;
1375 usleep(300000);
1377 collector_refresh_flows(ct_update);
1379 status = poll(poll_fd, 1, 0);
1380 if (status < 0) {
1381 if (errno == EAGAIN || errno == EINTR)
1382 continue;
1384 panic("Error while polling: %s\n", strerror(errno));
1385 } else if (status == 0) {
1386 continue;
1389 if (poll_fd[0].revents & POLLIN)
1390 nfct_catch(ct_event);
1393 rcu_unregister_thread();
1395 flow_list_destroy(&flow_list);
1396 nfct_close(ct_event);
1397 nfct_close(ct_update);
1399 pthread_exit(NULL);
1402 int main(int argc, char **argv)
1404 pthread_t tid;
1405 int ret, c, opt_index, what_cmd = 0;
1407 setfsuid(getuid());
1408 setfsgid(getgid());
1410 while ((c = getopt_long(argc, argv, short_options, long_options,
1411 &opt_index)) != EOF) {
1412 switch (c) {
1413 case '4':
1414 what_cmd |= INCLUDE_IPV4;
1415 break;
1416 case '6':
1417 what_cmd |= INCLUDE_IPV6;
1418 break;
1419 case 'T':
1420 what_cmd |= INCLUDE_TCP;
1421 break;
1422 case 'U':
1423 what_cmd |= INCLUDE_UDP;
1424 break;
1425 case 'D':
1426 what_cmd |= INCLUDE_DCCP;
1427 break;
1428 case 'I':
1429 what_cmd |= INCLUDE_ICMP;
1430 break;
1431 case 'S':
1432 what_cmd |= INCLUDE_SCTP;
1433 break;
1434 case 's':
1435 show_src = 1;
1436 break;
1437 case 'u':
1438 update_geoip();
1439 die();
1440 break;
1441 case 'h':
1442 help();
1443 break;
1444 case 'v':
1445 version();
1446 break;
1447 default:
1448 break;
1452 if (what_cmd > 0) {
1453 what = what_cmd;
1455 if (!(what & (INCLUDE_IPV4 | INCLUDE_IPV6)))
1456 what |= INCLUDE_IPV4 | INCLUDE_IPV6;
1459 rcu_init();
1461 register_signal(SIGINT, signal_handler);
1462 register_signal(SIGQUIT, signal_handler);
1463 register_signal(SIGTERM, signal_handler);
1464 register_signal(SIGHUP, signal_handler);
1466 panic_handler_add(on_panic_handler, &sysctl);
1468 conntrack_acct_enable();
1469 conntrack_tstamp_enable();
1471 init_geoip(1);
1473 ret = pthread_create(&tid, NULL, collector, NULL);
1474 if (ret < 0)
1475 panic("Cannot create phthread!\n");
1477 presenter();
1479 destroy_geoip();
1481 restore_sysctl(&sysctl);
1483 return 0;