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.
18 #include <netinet/in.h>
21 #include <sys/fsuid.h>
26 #include <arpa/inet.h>
29 #include <urcu/list.h>
30 #include <urcu/rculist.h>
35 #include "conntrack.h"
48 #define NSEC_PER_SEC 1000000000L
52 #define USEC_PER_SEC 1000000L
56 uint64_t pkts_src
, bytes_src
;
57 uint64_t pkts_dst
, bytes_dst
;
58 double rate_bytes_src
;
59 double rate_bytes_dst
;
65 struct cds_list_head entry
;
66 struct cds_list_head flows
;
69 struct timeval last_update
;
70 struct flow_stat stat
;
77 struct cds_list_head proc_head
;
78 struct cds_list_head entry
;
81 uint32_t flow_id
, use
, status
;
82 uint8_t l3_proto
, l4_proto
;
83 uint32_t ip4_src_addr
, ip4_dst_addr
;
84 uint32_t ip6_src_addr
[4], ip6_dst_addr
[4];
85 uint16_t port_src
, port_dst
;
86 uint8_t tcp_state
, tcp_flags
, sctp_state
, dccp_state
;
87 uint64_t timestamp_start
, timestamp_stop
;
88 char country_src
[128], country_dst
[128];
89 char country_code_src
[4], country_code_dst
[4];
90 char city_src
[128], city_dst
[128];
91 char rev_dns_src
[256], rev_dns_dst
[256];
92 struct proc_entry
*proc
;
95 struct nf_conntrack
*ct
;
96 struct timeval last_update
;
97 struct flow_stat stat
;
101 struct cds_list_head head
;
105 struct cds_list_head head
;
108 enum flow_direction
{
113 #ifndef ATTR_TIMESTAMP_START
114 # define ATTR_TIMESTAMP_START 63
116 #ifndef ATTR_TIMESTAMP_STOP
117 # define ATTR_TIMESTAMP_STOP 64
120 #define INCLUDE_IPV4 (1 << 0)
121 #define INCLUDE_IPV6 (1 << 1)
122 #define INCLUDE_UDP (1 << 2)
123 #define INCLUDE_TCP (1 << 3)
124 #define INCLUDE_DCCP (1 << 4)
125 #define INCLUDE_ICMP (1 << 5)
126 #define INCLUDE_SCTP (1 << 6)
128 #define TOGGLE_FLAG(what, flag) \
136 struct sysctl_params_ctx
{
146 static volatile bool do_reload_flows
;
147 static volatile bool is_flow_collecting
;
148 static volatile sig_atomic_t sigint
= 0;
149 static int what
= INCLUDE_IPV4
| INCLUDE_IPV6
| INCLUDE_TCP
;
150 static struct proc_list proc_list
;
151 static struct flow_list flow_list
;
152 static struct sysctl_params_ctx sysctl
= { -1, -1 };
154 static unsigned int cols
, rows
;
155 static WINDOW
*screen
;
157 static unsigned int interval
= 1;
158 static bool show_src
= false;
159 static bool resolve_dns
= true;
160 static bool resolve_geoip
= true;
161 static enum rate_units rate_type
= RATE_BYTES
;
162 static bool show_active_only
= false;
187 static struct ui_table flows_tbl
;
188 static struct ui_table procs_tbl
;
189 static struct ui_table
*curr_tbl
;
196 #define list_first_or_next(__ptr, __head, __entry) \
198 struct cds_list_head *h; \
200 h = rcu_dereference((__head)->next); \
201 else if (rcu_dereference(__ptr->__entry.next) == (__head)) \
204 h = rcu_dereference(__ptr->__entry.next); \
205 cds_list_entry(h, __typeof(* (__ptr)), __entry); \
208 static const char *short_options
= "vhTUsDIS46ut:nGb";
209 static const struct option long_options
[] = {
210 {"ipv4", no_argument
, NULL
, '4'},
211 {"ipv6", no_argument
, NULL
, '6'},
212 {"tcp", no_argument
, NULL
, 'T'},
213 {"udp", no_argument
, NULL
, 'U'},
214 {"dccp", no_argument
, NULL
, 'D'},
215 {"icmp", no_argument
, NULL
, 'I'},
216 {"sctp", no_argument
, NULL
, 'S'},
217 {"no-dns", no_argument
, NULL
, 'n'},
218 {"no-geoip", no_argument
, NULL
, 'G'},
219 {"show-src", no_argument
, NULL
, 's'},
220 {"bits", no_argument
, NULL
, 'b'},
221 {"update", no_argument
, NULL
, 'u'},
222 {"interval", required_argument
, NULL
, 't'},
223 {"version", no_argument
, NULL
, 'v'},
224 {"help", no_argument
, NULL
, 'h'},
228 static const char *copyright
=
229 "Please report bugs at https://github.com/netsniff-ng/netsniff-ng/issues\n"
230 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
231 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
232 "Swiss federal institute of technology (ETH Zurich)\n"
233 "License: GNU GPL version 2.0\n"
234 "This is free software: you are free to change and redistribute it.\n"
235 "There is NO WARRANTY, to the extent permitted by law.";
237 static const char *const l4proto2str
[IPPROTO_MAX
] = {
238 [IPPROTO_TCP
] = "tcp",
239 [IPPROTO_UDP
] = "udp",
240 [IPPROTO_UDPLITE
] = "udplite",
241 [IPPROTO_ICMP
] = "icmp",
242 [IPPROTO_ICMPV6
] = "icmpv6",
243 [IPPROTO_SCTP
] = "sctp",
244 [IPPROTO_GRE
] = "gre",
245 [IPPROTO_DCCP
] = "dccp",
246 [IPPROTO_IGMP
] = "igmp",
247 [IPPROTO_IPIP
] = "ipip",
248 [IPPROTO_EGP
] = "egp",
249 [IPPROTO_PUP
] = "pup",
250 [IPPROTO_IDP
] = "idp",
251 [IPPROTO_RSVP
] = "rsvp",
252 [IPPROTO_IPV6
] = "ip6tun",
253 [IPPROTO_ESP
] = "esp",
255 [IPPROTO_PIM
] = "pim",
256 [IPPROTO_COMP
] = "comp",
259 static const char *const tcp_state2str
[TCP_CONNTRACK_MAX
] = {
260 [TCP_CONNTRACK_NONE
] = "NONE",
261 [TCP_CONNTRACK_SYN_SENT
] = "SYN-SENT",
262 [TCP_CONNTRACK_SYN_RECV
] = "SYN-RECV",
263 [TCP_CONNTRACK_ESTABLISHED
] = "ESTABLISHED",
264 [TCP_CONNTRACK_FIN_WAIT
] = "FIN-WAIT",
265 [TCP_CONNTRACK_CLOSE_WAIT
] = "CLOSE-WAIT",
266 [TCP_CONNTRACK_LAST_ACK
] = "LAST-ACK",
267 [TCP_CONNTRACK_TIME_WAIT
] = "TIME-WAIT",
268 [TCP_CONNTRACK_CLOSE
] = "CLOSE",
269 [TCP_CONNTRACK_SYN_SENT2
] = "SYN-SENT2",
272 static const char *const dccp_state2str
[DCCP_CONNTRACK_MAX
] = {
273 [DCCP_CONNTRACK_NONE
] = "NONE",
274 [DCCP_CONNTRACK_REQUEST
] = "REQUEST",
275 [DCCP_CONNTRACK_RESPOND
] = "RESPOND",
276 [DCCP_CONNTRACK_PARTOPEN
] = "PARTOPEN",
277 [DCCP_CONNTRACK_OPEN
] = "OPEN",
278 [DCCP_CONNTRACK_CLOSEREQ
] = "CLOSE-REQ",
279 [DCCP_CONNTRACK_CLOSING
] = "CLOSING",
280 [DCCP_CONNTRACK_TIMEWAIT
] = "TIME-WAIT",
281 [DCCP_CONNTRACK_IGNORE
] = "IGNORE",
282 [DCCP_CONNTRACK_INVALID
] = "INVALID",
285 static const char *const sctp_state2str
[SCTP_CONNTRACK_MAX
] = {
286 [SCTP_CONNTRACK_NONE
] = "NONE",
287 [SCTP_CONNTRACK_CLOSED
] = "CLOSED",
288 [SCTP_CONNTRACK_COOKIE_WAIT
] = "COOKIE-WAIT",
289 [SCTP_CONNTRACK_COOKIE_ECHOED
] = "COOKIE-ECHO",
290 [SCTP_CONNTRACK_ESTABLISHED
] = "ESTABLISHED",
291 [SCTP_CONNTRACK_SHUTDOWN_SENT
] = "SHUTD-SENT",
292 [SCTP_CONNTRACK_SHUTDOWN_RECD
] = "SHUTD-RCVD",
293 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
] = "SHUTD-ACK",
296 static const struct nfct_filter_ipv4 filter_ipv4
= {
297 .addr
= __constant_htonl(INADDR_LOOPBACK
),
301 static const struct nfct_filter_ipv6 filter_ipv6
= {
302 .addr
= { 0x0, 0x0, 0x0, 0x1 },
303 .mask
= { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
306 static int64_t time_after_us(struct timeval
*tv
)
310 bug_on(gettimeofday(&now
, NULL
));
312 now
.tv_sec
-= tv
->tv_sec
;
313 now
.tv_usec
-= tv
->tv_usec
;
315 return now
.tv_sec
* USEC_PER_SEC
+ now
.tv_usec
;
318 static void signal_handler(int number
)
332 static void flow_entry_from_ct(struct flow_entry
*n
, const struct nf_conntrack
*ct
);
333 static void flow_entry_get_extended(struct flow_entry
*n
);
335 static void help(void)
337 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
339 puts("http://www.netsniff-ng.org\n\n"
340 "Usage: flowtop [options]\n"
342 " -4|--ipv4 Show only IPv4 flows (default)\n"
343 " -6|--ipv6 Show only IPv6 flows (default)\n"
344 " -T|--tcp Show only TCP flows (default)\n"
345 " -U|--udp Show only UDP flows\n"
346 " -D|--dccp Show only DCCP flows\n"
347 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
348 " -S|--sctp Show only SCTP flows\n"
349 " -n|--no-dns Don't perform hostname lookup\n"
350 " -G|--no-geoip Don't perform GeoIP lookup\n"
351 " -s|--show-src Also show source, not only dest\n"
352 " -b|--bits Show rates in bits/s instead of bytes/s\n"
353 " -u|--update Update GeoIP databases\n"
354 " -t|--interval <time> Refresh time in seconds (default 1s)\n"
355 " -v|--version Print version and exit\n"
356 " -h|--help Print this help and exit\n\n"
359 " flowtop -46UTDISs\n\n"
361 " If netfilter is not running, you can activate it with e.g.:\n"
362 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
363 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
368 static void version(void)
370 printf("flowtop %s, Git id: %s\n", VERSION_LONG
, GITVERSION
);
371 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
372 "http://www.netsniff-ng.org\n");
377 static void flow_entry_update_time(struct flow_entry
*n
)
379 bug_on(gettimeofday(&n
->last_update
, NULL
));
382 #define CALC_RATE(fld) do { \
383 n->stat.rate_##fld = (((fld) > n->stat.fld) ? \
384 (((fld) - n->stat.fld) / sec) : 0); \
387 static void flow_entry_calc_rate(struct flow_entry
*n
, const struct nf_conntrack
*ct
)
389 uint64_t bytes_src
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_BYTES
);
390 uint64_t bytes_dst
= nfct_get_attr_u64(ct
, ATTR_REPL_COUNTER_BYTES
);
391 uint64_t pkts_src
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_PACKETS
);
392 uint64_t pkts_dst
= nfct_get_attr_u64(ct
, ATTR_REPL_COUNTER_PACKETS
);
393 double sec
= (double)time_after_us(&n
->last_update
) / USEC_PER_SEC
;
398 CALC_RATE(bytes_src
);
399 CALC_RATE(bytes_dst
);
404 static inline struct flow_entry
*flow_entry_xalloc(void)
406 return xzmalloc(sizeof(struct flow_entry
));
409 static inline void flow_entry_xfree(struct flow_entry
*n
)
417 static void flow_entry_xfree_rcu(struct rcu_head
*head
)
419 struct flow_entry
*n
= container_of(head
, struct flow_entry
, rcu
);
424 static inline void flow_list_init(struct flow_list
*fl
)
426 CDS_INIT_LIST_HEAD(&fl
->head
);
429 static inline bool nfct_is_dns(const struct nf_conntrack
*ct
)
431 uint16_t port_src
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_SRC
);
432 uint16_t port_dst
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_DST
);
434 return ntohs(port_src
) == 53 || ntohs(port_dst
) == 53;
437 static int flow_list_new_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
439 struct flow_entry
*n
;
441 /* We don't want to analyze / display DNS itself, since we
442 * use it to resolve reverse dns.
445 return NFCT_CB_CONTINUE
;
447 n
= flow_entry_xalloc();
451 flow_entry_update_time(n
);
452 flow_entry_from_ct(n
, ct
);
453 flow_entry_get_extended(n
);
455 cds_list_add_rcu(&n
->entry
, &fl
->head
);
457 n
->is_visible
= true;
459 return NFCT_CB_STOLEN
;
462 static struct flow_entry
*flow_list_find_id(struct flow_list
*fl
, uint32_t id
)
464 struct flow_entry
*n
;
466 cds_list_for_each_entry_rcu(n
, &fl
->head
, entry
) {
467 if (n
->flow_id
== id
)
474 static void __flow_list_del_entry(struct flow_list
*fl
, struct flow_entry
*n
)
477 cds_list_del_rcu(&n
->proc_head
);
478 n
->proc
->flows_count
--;
481 cds_list_del_rcu(&n
->entry
);
482 call_rcu(&n
->rcu
, flow_entry_xfree_rcu
);
485 static int flow_list_del_entry(struct flow_list
*fl
, const struct nf_conntrack
*ct
)
487 struct flow_entry
*n
;
489 n
= flow_list_find_id(fl
, nfct_get_attr_u32(ct
, ATTR_ID
));
491 __flow_list_del_entry(fl
, n
);
493 return NFCT_CB_CONTINUE
;
496 static void flow_list_destroy(struct flow_list
*fl
)
498 struct flow_entry
*n
, *tmp
;
500 cds_list_for_each_entry_safe(n
, tmp
, &fl
->head
, entry
)
501 __flow_list_del_entry(fl
, n
);
504 static void proc_list_init(struct proc_list
*proc_list
)
506 CDS_INIT_LIST_HEAD(&proc_list
->head
);
509 static struct proc_entry
*proc_list_new_entry(unsigned int pid
)
511 struct proc_entry
*proc
;
513 cds_list_for_each_entry(proc
, &proc_list
.head
, entry
) {
514 if (proc
->pid
&& proc
->pid
== pid
)
518 proc
= xzmalloc(sizeof(*proc
));
520 bug_on(gettimeofday(&proc
->last_update
, NULL
));
521 CDS_INIT_LIST_HEAD(&proc
->flows
);
524 cds_list_add_tail(&proc
->entry
, &proc_list
.head
);
529 static void proc_entry_xfree_rcu(struct rcu_head
*head
)
531 struct proc_entry
*p
= container_of(head
, struct proc_entry
, rcu
);
536 static void proc_list_destroy(struct proc_list
*pl
)
538 struct proc_entry
*p
, *tmp
;
540 cds_list_for_each_entry_safe(p
, tmp
, &pl
->head
, entry
) {
541 cds_list_del_rcu(&p
->entry
);
542 call_rcu(&p
->rcu
, proc_entry_xfree_rcu
);
546 static void flow_entry_find_process(struct flow_entry
*n
)
548 struct proc_entry
*p
;
553 ret
= proc_find_by_inode(n
->inode
, cmdline
, sizeof(cmdline
), &pid
);
557 p
= proc_list_new_entry(pid
);
559 if (snprintf(p
->name
, sizeof(p
->name
), "%s", basename(cmdline
)) < 0)
562 p
->stat
.pkts_src
+= n
->stat
.pkts_src
;
563 p
->stat
.pkts_dst
+= n
->stat
.pkts_dst
;
564 p
->stat
.bytes_src
+= n
->stat
.bytes_src
;
565 p
->stat
.bytes_dst
+= n
->stat
.bytes_dst
;
568 cds_list_add_rcu(&n
->proc_head
, &p
->flows
);
572 static int get_port_inode(uint16_t port
, int proto
, bool is_ip6
)
575 char path
[128], buff
[1024];
578 memset(path
, 0, sizeof(path
));
579 snprintf(path
, sizeof(path
), "/proc/net/%s%s",
580 l4proto2str
[proto
], is_ip6
? "6" : "");
582 proc
= fopen(path
, "r");
586 memset(buff
, 0, sizeof(buff
));
588 while (fgets(buff
, sizeof(buff
), proc
) != NULL
) {
590 unsigned int lport
= 0;
592 buff
[sizeof(buff
) - 1] = 0;
593 if (sscanf(buff
, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
594 "%*X %*u %*u %u", &lport
, &inode
) == 2) {
595 if ((uint16_t) lport
== port
) {
601 memset(buff
, 0, sizeof(buff
));
608 #define CP_NFCT(elem, attr, x) \
609 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
610 #define CP_NFCT_BUFF(elem, attr) do { \
611 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
613 memcpy(n->elem, buff, sizeof(n->elem)); \
616 static void flow_entry_from_ct(struct flow_entry
*n
, const struct nf_conntrack
*ct
)
618 uint64_t bytes_src
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_BYTES
);
619 uint64_t bytes_dst
= nfct_get_attr_u64(ct
, ATTR_REPL_COUNTER_BYTES
);
620 uint64_t pkts_src
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_PACKETS
);
621 uint64_t pkts_dst
= nfct_get_attr_u64(ct
, ATTR_REPL_COUNTER_PACKETS
);
623 /* Update stats diff to the related process entry */
625 n
->proc
->stat
.pkts_src
+= pkts_src
- n
->stat
.pkts_src
;
626 n
->proc
->stat
.pkts_dst
+= pkts_dst
- n
->stat
.pkts_dst
;
627 n
->proc
->stat
.bytes_src
+= bytes_src
- n
->stat
.bytes_src
;
628 n
->proc
->stat
.bytes_dst
+= bytes_dst
- n
->stat
.bytes_dst
;
631 CP_NFCT(l3_proto
, ATTR_ORIG_L3PROTO
, 8);
632 CP_NFCT(l4_proto
, ATTR_ORIG_L4PROTO
, 8);
634 CP_NFCT(ip4_src_addr
, ATTR_ORIG_IPV4_SRC
, 32);
635 CP_NFCT(ip4_dst_addr
, ATTR_ORIG_IPV4_DST
, 32);
637 CP_NFCT(port_src
, ATTR_ORIG_PORT_SRC
, 16);
638 CP_NFCT(port_dst
, ATTR_ORIG_PORT_DST
, 16);
640 CP_NFCT(status
, ATTR_STATUS
, 32);
642 CP_NFCT(tcp_state
, ATTR_TCP_STATE
, 8);
643 CP_NFCT(tcp_flags
, ATTR_TCP_FLAGS_ORIG
, 8);
644 CP_NFCT(sctp_state
, ATTR_SCTP_STATE
, 8);
645 CP_NFCT(dccp_state
, ATTR_DCCP_STATE
, 8);
647 CP_NFCT(stat
.pkts_src
, ATTR_ORIG_COUNTER_PACKETS
, 64);
648 CP_NFCT(stat
.bytes_src
, ATTR_ORIG_COUNTER_BYTES
, 64);
650 CP_NFCT(stat
.pkts_dst
, ATTR_REPL_COUNTER_PACKETS
, 64);
651 CP_NFCT(stat
.bytes_dst
, ATTR_REPL_COUNTER_BYTES
, 64);
653 CP_NFCT(timestamp_start
, ATTR_TIMESTAMP_START
, 64);
654 CP_NFCT(timestamp_stop
, ATTR_TIMESTAMP_STOP
, 64);
656 CP_NFCT(flow_id
, ATTR_ID
, 32);
657 CP_NFCT(use
, ATTR_USE
, 32);
659 CP_NFCT_BUFF(ip6_src_addr
, ATTR_ORIG_IPV6_SRC
);
660 CP_NFCT_BUFF(ip6_dst_addr
, ATTR_ORIG_IPV6_DST
);
662 n
->port_src
= ntohs(n
->port_src
);
663 n
->port_dst
= ntohs(n
->port_dst
);
665 n
->ip4_src_addr
= ntohl(n
->ip4_src_addr
);
666 n
->ip4_dst_addr
= ntohl(n
->ip4_dst_addr
);
669 #define SELFLD(dir,src_member,dst_member) \
670 (((dir) == FLOW_DIR_SRC) ? n->src_member : n->dst_member)
672 static void flow_entry_get_sain4_obj(const struct flow_entry
*n
,
673 enum flow_direction dir
,
674 struct sockaddr_in
*sa
)
676 memset(sa
, 0, sizeof(*sa
));
677 sa
->sin_family
= PF_INET
;
678 sa
->sin_addr
.s_addr
= htonl(SELFLD(dir
, ip4_src_addr
, ip4_dst_addr
));
681 static void flow_entry_get_sain6_obj(const struct flow_entry
*n
,
682 enum flow_direction dir
,
683 struct sockaddr_in6
*sa
)
685 memset(sa
, 0, sizeof(*sa
));
686 sa
->sin6_family
= PF_INET6
;
688 memcpy(&sa
->sin6_addr
, SELFLD(dir
, ip6_src_addr
, ip6_dst_addr
),
689 sizeof(sa
->sin6_addr
));
693 flow_entry_geo_city_lookup_generic(struct flow_entry
*n
,
694 enum flow_direction dir
)
696 struct sockaddr_in sa4
;
697 struct sockaddr_in6 sa6
;
700 switch (n
->l3_proto
) {
705 flow_entry_get_sain4_obj(n
, dir
, &sa4
);
706 city
= geoip4_city_name(&sa4
);
710 flow_entry_get_sain6_obj(n
, dir
, &sa6
);
711 city
= geoip6_city_name(&sa6
);
715 build_bug_on(sizeof(n
->city_src
) != sizeof(n
->city_dst
));
718 strlcpy(SELFLD(dir
, city_src
, city_dst
), city
,
719 sizeof(n
->city_src
));
721 SELFLD(dir
, city_src
, city_dst
)[0] = '\0';
727 flow_entry_geo_country_lookup_generic(struct flow_entry
*n
,
728 enum flow_direction dir
)
730 struct sockaddr_in sa4
;
731 struct sockaddr_in6 sa6
;
732 const char *country
= NULL
;
733 const char *country_code
= NULL
;
735 switch (n
->l3_proto
) {
740 flow_entry_get_sain4_obj(n
, dir
, &sa4
);
741 country
= geoip4_country_name(&sa4
);
742 country_code
= geoip4_country_code3_name(&sa4
);
746 flow_entry_get_sain6_obj(n
, dir
, &sa6
);
747 country
= geoip6_country_name(&sa6
);
748 country_code
= geoip6_country_code3_name(&sa6
);
752 build_bug_on(sizeof(n
->country_src
) != sizeof(n
->country_dst
));
755 strlcpy(SELFLD(dir
, country_src
, country_dst
), country
,
756 sizeof(n
->country_src
));
758 SELFLD(dir
, country_src
, country_dst
)[0] = '\0';
760 build_bug_on(sizeof(n
->country_code_src
) != sizeof(n
->country_code_dst
));
763 strlcpy(SELFLD(dir
, country_code_src
, country_code_dst
),
764 country_code
, sizeof(n
->country_code_src
));
766 SELFLD(dir
, country_code_src
, country_code_dst
)[0] = '\0';
769 static void flow_entry_get_extended_geo(struct flow_entry
*n
,
770 enum flow_direction dir
)
773 flow_entry_geo_city_lookup_generic(n
, dir
);
774 flow_entry_geo_country_lookup_generic(n
, dir
);
778 static void flow_entry_get_extended_revdns(struct flow_entry
*n
,
779 enum flow_direction dir
)
782 struct sockaddr_in sa4
;
783 struct sockaddr_in6 sa6
;
785 struct hostent
*hent
;
787 build_bug_on(sizeof(n
->rev_dns_src
) != sizeof(n
->rev_dns_dst
));
789 switch (n
->l3_proto
) {
794 flow_entry_get_sain4_obj(n
, dir
, &sa4
);
797 inet_ntop(AF_INET
, &sa4
.sin_addr
,
798 SELFLD(dir
, rev_dns_src
, rev_dns_dst
),
799 sizeof(n
->rev_dns_src
));
803 sa
= (struct sockaddr
*) &sa4
;
804 sa_len
= sizeof(sa4
);
805 hent
= gethostbyaddr(&sa4
.sin_addr
, sizeof(sa4
.sin_addr
), AF_INET
);
809 flow_entry_get_sain6_obj(n
, dir
, &sa6
);
812 inet_ntop(AF_INET6
, &sa6
.sin6_addr
,
813 SELFLD(dir
, rev_dns_src
, rev_dns_dst
),
814 sizeof(n
->rev_dns_src
));
818 sa
= (struct sockaddr
*) &sa6
;
819 sa_len
= sizeof(sa6
);
820 hent
= gethostbyaddr(&sa6
.sin6_addr
, sizeof(sa6
.sin6_addr
), AF_INET6
);
824 getnameinfo(sa
, sa_len
, SELFLD(dir
, rev_dns_src
, rev_dns_dst
),
825 sizeof(n
->rev_dns_src
), NULL
, 0, NI_NUMERICHOST
);
828 strlcpy(SELFLD(dir
, rev_dns_src
, rev_dns_dst
), hent
->h_name
,
829 sizeof(n
->rev_dns_src
));
832 static void flow_entry_get_extended(struct flow_entry
*n
)
837 flow_entry_get_extended_revdns(n
, FLOW_DIR_SRC
);
838 flow_entry_get_extended_geo(n
, FLOW_DIR_SRC
);
840 flow_entry_get_extended_revdns(n
, FLOW_DIR_DST
);
841 flow_entry_get_extended_geo(n
, FLOW_DIR_DST
);
843 /* Lookup application */
844 n
->inode
= get_port_inode(n
->port_src
, n
->l4_proto
,
845 n
->l3_proto
== AF_INET6
);
847 flow_entry_find_process(n
);
850 static char *bandw2str(double bytes
, char *buf
, size_t len
)
857 if (bytes
> 1000000000.)
858 snprintf(buf
, len
, "%.1fGB", bytes
/ 1000000000.);
859 else if (bytes
> 1000000.)
860 snprintf(buf
, len
, "%.1fMB", bytes
/ 1000000.);
861 else if (bytes
> 1000.)
862 snprintf(buf
, len
, "%.1fkB", bytes
/ 1000.);
864 snprintf(buf
, len
, "%.0f", bytes
);
869 static char *rate2str(double rate
, char *buf
, size_t len
)
871 const char * const unit_fmt
[2][4] = {
872 { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%.0fbit/s" },
873 { "%.1fGB/s", "%.1fMB/s", "%.1fkB/s", "%.0fB/s" }
881 if (rate_type
== RATE_BITS
)
884 if (rate
> 1000000000.)
885 snprintf(buf
, len
, unit_fmt
[rate_type
][0], rate
/ 1000000000.);
886 else if (rate
> 1000000.)
887 snprintf(buf
, len
, unit_fmt
[rate_type
][1], rate
/ 1000000.);
888 else if (rate
> 1000.)
889 snprintf(buf
, len
, unit_fmt
[rate_type
][2], rate
/ 1000.);
891 snprintf(buf
, len
, unit_fmt
[rate_type
][3], rate
);
896 static char *time2str(uint64_t tstamp
, char *str
, size_t len
)
903 s
= now
- (tstamp
? (tstamp
/ NSEC_PER_SEC
) : now
);
911 slprintf(str
, len
, "%dd", v
);
917 slprintf(str
, len
, "%dh", v
);
923 slprintf(str
, len
, "%dm", v
);
927 slprintf(str
, len
, "%ds", s
);
932 static const char *flow_state2str(const struct flow_entry
*n
)
934 switch (n
->l4_proto
) {
936 return tcp_state2str
[n
->tcp_state
];
938 return sctp_state2str
[n
->sctp_state
];
940 return dccp_state2str
[n
->dccp_state
];
943 case IPPROTO_UDPLITE
:
951 static char *flow_port2str(const struct flow_entry
*n
, char *str
, size_t len
,
952 enum flow_direction dir
)
954 const char *tmp
= NULL
;
957 port
= SELFLD(dir
, port_src
, port_dst
);
960 switch (n
->l4_proto
) {
962 tmp
= lookup_port_tcp(port
);
965 case IPPROTO_UDPLITE
:
966 tmp
= lookup_port_udp(port
);
971 slprintf(str
, len
, "%d", port
);
973 slprintf(str
, len
, "%s", tmp
? tmp
: "");
978 static void print_flow_peer_info(const struct flow_entry
*n
, enum flow_direction dir
)
980 int counters_color
= COLOR(YELLOW
, BLACK
);
981 int src_color
= COLOR(RED
, BLACK
);
982 int dst_color
= COLOR(BLUE
, BLACK
);
983 int country_color
= COLOR(GREEN
, BLACK
);
984 int addr_color
= dst_color
;
985 int port_color
= A_BOLD
;
988 if (show_src
&& dir
== FLOW_DIR_SRC
) {
989 country_color
= src_color
;
990 counters_color
= src_color
;
991 port_color
|= src_color
;
992 addr_color
= src_color
;
993 } else if (show_src
&& FLOW_DIR_DST
) {
994 country_color
= dst_color
;
995 counters_color
= dst_color
;
996 port_color
|= dst_color
;
997 addr_color
= dst_color
;
1000 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_ADDRESS
, addr_color
);
1001 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_PORT
, port_color
);
1002 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_GEO
, country_color
);
1003 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_BYTES
, counters_color
);
1004 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_RATE
, counters_color
);
1006 /* Reverse DNS/IP */
1007 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_ADDRESS
,
1008 SELFLD(dir
, rev_dns_src
, rev_dns_dst
));
1010 /* Application port */
1011 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PORT
,
1012 flow_port2str(n
, tmp
, sizeof(tmp
), dir
));
1015 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_GEO
,
1016 SELFLD(dir
, country_code_src
, country_code_dst
));
1019 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_BYTES
,
1020 bandw2str(SELFLD(dir
, stat
.bytes_src
, stat
.bytes_dst
),
1021 tmp
, sizeof(tmp
) - 1));
1024 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_RATE
,
1025 rate2str(SELFLD(dir
, stat
.rate_bytes_src
, stat
.rate_bytes_dst
),
1026 tmp
, sizeof(tmp
) - 1));
1029 static void draw_flow_entry(struct ui_table
*tbl
, const void *data
)
1031 const struct flow_entry
*n
= data
;
1034 ui_table_row_add(tbl
);
1037 ui_table_row_col_set(tbl
, TBL_FLOW_PROCESS
, n
->proc
? n
->proc
->name
: "");
1040 slprintf(tmp
, sizeof(tmp
), "%.d", n
->proc
? n
->proc
->pid
: 0);
1041 ui_table_row_col_set(tbl
, TBL_FLOW_PID
, tmp
);
1044 ui_table_row_col_set(tbl
, TBL_FLOW_PROTO
, l4proto2str
[n
->l4_proto
]);
1046 /* L4 protocol state */
1047 ui_table_row_col_set(tbl
, TBL_FLOW_STATE
, flow_state2str(n
));
1050 time2str(n
->timestamp_start
, tmp
, sizeof(tmp
));
1051 ui_table_row_col_set(tbl
, TBL_FLOW_TIME
, tmp
);
1053 print_flow_peer_info(n
, show_src
? FLOW_DIR_SRC
: FLOW_DIR_DST
);
1055 ui_table_row_show(tbl
);
1058 ui_table_row_add(tbl
);
1060 ui_table_row_col_set(tbl
, TBL_FLOW_PROCESS
, "");
1061 ui_table_row_col_set(tbl
, TBL_FLOW_PID
, "");
1062 ui_table_row_col_set(tbl
, TBL_FLOW_PROTO
, "");
1063 ui_table_row_col_set(tbl
, TBL_FLOW_STATE
, "");
1064 ui_table_row_col_set(tbl
, TBL_FLOW_TIME
, "");
1066 print_flow_peer_info(n
, FLOW_DIR_DST
);
1067 ui_table_row_show(tbl
);
1071 static inline bool presenter_flow_wrong_state(struct flow_entry
*n
)
1073 switch (n
->l4_proto
) {
1075 switch (n
->tcp_state
) {
1076 case TCP_CONNTRACK_SYN_SENT
:
1077 case TCP_CONNTRACK_SYN_RECV
:
1078 case TCP_CONNTRACK_ESTABLISHED
:
1079 case TCP_CONNTRACK_FIN_WAIT
:
1080 case TCP_CONNTRACK_CLOSE_WAIT
:
1081 case TCP_CONNTRACK_LAST_ACK
:
1082 case TCP_CONNTRACK_TIME_WAIT
:
1083 case TCP_CONNTRACK_CLOSE
:
1084 case TCP_CONNTRACK_SYN_SENT2
:
1085 case TCP_CONNTRACK_NONE
:
1091 switch (n
->sctp_state
) {
1092 case SCTP_CONNTRACK_NONE
:
1093 case SCTP_CONNTRACK_CLOSED
:
1094 case SCTP_CONNTRACK_COOKIE_WAIT
:
1095 case SCTP_CONNTRACK_COOKIE_ECHOED
:
1096 case SCTP_CONNTRACK_ESTABLISHED
:
1097 case SCTP_CONNTRACK_SHUTDOWN_SENT
:
1098 case SCTP_CONNTRACK_SHUTDOWN_RECD
:
1099 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
:
1105 switch (n
->dccp_state
) {
1106 case DCCP_CONNTRACK_NONE
:
1107 case DCCP_CONNTRACK_REQUEST
:
1108 case DCCP_CONNTRACK_RESPOND
:
1109 case DCCP_CONNTRACK_PARTOPEN
:
1110 case DCCP_CONNTRACK_OPEN
:
1111 case DCCP_CONNTRACK_CLOSEREQ
:
1112 case DCCP_CONNTRACK_CLOSING
:
1113 case DCCP_CONNTRACK_TIMEWAIT
:
1114 case DCCP_CONNTRACK_IGNORE
:
1115 case DCCP_CONNTRACK_INVALID
:
1121 case IPPROTO_UDPLITE
:
1123 case IPPROTO_ICMPV6
:
1131 static void draw_filter_status(struct ui_table
*tbl
, char *title
)
1133 mvwprintw(screen
, 1, 0, "%*s", COLS
- 1, " ");
1134 mvwprintw(screen
, 1, 2, "%s(%u) for ", title
, ui_table_data_count(tbl
));
1136 if (what
& INCLUDE_IPV4
)
1138 if (what
& INCLUDE_IPV6
)
1140 if (what
& INCLUDE_TCP
)
1142 if (what
& INCLUDE_UDP
)
1144 if (what
& INCLUDE_SCTP
)
1146 if (what
& INCLUDE_DCCP
)
1148 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV4
)
1150 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV6
)
1152 if (show_active_only
)
1155 printw(" [+%d]", ui_table_scroll_height(tbl
));
1157 if (is_flow_collecting
)
1158 printw(" [Collecting flows ...]");
1162 static void draw_flows(WINDOW
*screen
, struct flow_list
*fl
)
1166 if (cds_list_empty(&fl
->head
))
1167 mvwprintw(screen
, 4, 2, "(No sessions! "
1168 "Is netfilter running?)");
1170 ui_table_data_bind(&flows_tbl
);
1174 draw_filter_status(&flows_tbl
, "Kernel netfilter flows");
1177 static void draw_proc_entry(struct ui_table
*tbl
, const void *data
)
1179 const struct proc_entry
*p
= data
;
1182 ui_table_row_add(tbl
);
1185 ui_table_row_col_set(tbl
, TBL_PROC_NAME
, p
->name
);
1188 slprintf(tmp
, sizeof(tmp
), "%.d", p
->pid
);
1189 ui_table_row_col_set(tbl
, TBL_PROC_PID
, tmp
);
1192 slprintf(tmp
, sizeof(tmp
), "%.d", p
->flows_count
);
1193 ui_table_row_col_set(tbl
, TBL_PROC_FLOWS
, tmp
);
1196 bandw2str(p
->stat
.bytes_src
, tmp
, sizeof(tmp
) - 1);
1197 ui_table_row_col_set(tbl
, TBL_PROC_BYTES_SRC
, tmp
);
1200 rate2str(p
->stat
.rate_bytes_src
, tmp
, sizeof(tmp
) - 1);
1201 ui_table_row_col_set(tbl
, TBL_PROC_RATE_SRC
, tmp
);
1204 bandw2str(p
->stat
.bytes_dst
, tmp
, sizeof(tmp
) - 1);
1205 ui_table_row_col_set(tbl
, TBL_PROC_BYTES_DST
, tmp
);
1208 rate2str(p
->stat
.rate_bytes_dst
, tmp
, sizeof(tmp
) - 1);
1209 ui_table_row_col_set(tbl
, TBL_PROC_RATE_DST
, tmp
);
1211 ui_table_row_show(tbl
);
1214 static void draw_procs(WINDOW
*screen
, struct flow_list
*fl
)
1218 ui_table_data_bind(&procs_tbl
);
1222 draw_filter_status(&procs_tbl
, "Processes");
1225 static void draw_help(void)
1231 mvaddch(row
, col
, ACS_ULCORNER
);
1232 mvaddch(rows
- row
- 1, col
, ACS_LLCORNER
);
1234 mvaddch(row
, cols
- 1, ACS_URCORNER
);
1235 mvaddch(rows
- row
- 1, cols
- 1, ACS_LRCORNER
);
1237 for (i
= 1; i
< rows
- row
- 2; i
++) {
1238 mvaddch(row
+ i
, 0, ACS_VLINE
);
1239 mvaddch(row
+ i
, cols
- 1, ACS_VLINE
);
1241 for (i
= 1; i
< cols
- col
- 1; i
++) {
1242 mvaddch(row
, col
+ i
, ACS_HLINE
);
1243 mvaddch(rows
- row
- 1, col
+ i
, ACS_HLINE
);
1247 mvaddnstr(row
, cols
/ 2 - 2, "| Help |", -1);
1249 attron(A_UNDERLINE
);
1250 mvaddnstr(row
+ 2, col
+ 2, "Navigation", -1);
1251 attroff(A_BOLD
| A_UNDERLINE
);
1253 mvaddnstr(row
+ 4, col
+ 3, "TAB Go to next tab panel", -1);
1254 mvaddnstr(row
+ 5, col
+ 3, "Up, u, k Move up", -1);
1255 mvaddnstr(row
+ 6, col
+ 3, "Down, d, j Move down", -1);
1256 mvaddnstr(row
+ 7, col
+ 3, "Left,l Scroll left", -1);
1257 mvaddnstr(row
+ 8, col
+ 3, "Right,h Scroll right", -1);
1258 mvaddnstr(row
+ 9, col
+ 3, "? Toggle help window", -1);
1259 mvaddnstr(row
+ 10, col
+ 3, "q, Ctrl+C Quit", -1);
1261 attron(A_BOLD
| A_UNDERLINE
);
1262 mvaddnstr(row
+ 12, col
+ 2, "Display Settings", -1);
1263 attroff(A_BOLD
| A_UNDERLINE
);
1265 mvaddnstr(row
+ 14, col
+ 3, "b Toggle rate units (bits/bytes)", -1);
1266 mvaddnstr(row
+ 15, col
+ 3, "a Toggle display of active flows (rate > 0) only", -1);
1267 mvaddnstr(row
+ 16, col
+ 3, "s Toggle show source peer info", -1);
1269 mvaddnstr(row
+ 18, col
+ 3, "T Toggle display TCP flows", -1);
1270 mvaddnstr(row
+ 19, col
+ 3, "U Toggle display UDP flows", -1);
1271 mvaddnstr(row
+ 20, col
+ 3, "D Toggle display DCCP flows", -1);
1272 mvaddnstr(row
+ 21, col
+ 3, "I Toggle display ICMP flows", -1);
1273 mvaddnstr(row
+ 22, col
+ 3, "S Toggle display SCTP flows", -1);
1276 static void draw_header(WINDOW
*screen
)
1282 for (i
= 0; i
< cols
; i
++)
1285 mvwprintw(screen
, 0, 2, "flowtop %s", VERSION_LONG
);
1286 attroff(A_STANDOUT
);
1289 static void draw_footer(void)
1295 for (i
= 0; i
< cols
; i
++)
1296 mvaddch(rows
- 1, i
, ' ');
1298 mvaddnstr(rows
- 1, 1, "Press '?' for help", -1);
1300 attroff(A_STANDOUT
);
1303 static void show_option_toggle(int opt
)
1307 TOGGLE_FLAG(what
, INCLUDE_TCP
);
1310 TOGGLE_FLAG(what
, INCLUDE_UDP
);
1313 TOGGLE_FLAG(what
, INCLUDE_DCCP
);
1316 TOGGLE_FLAG(what
, INCLUDE_ICMP
);
1319 TOGGLE_FLAG(what
, INCLUDE_SCTP
);
1324 void * flows_iter(void *data
)
1326 struct flow_entry
*n
= data
;
1329 n
= list_first_or_next(n
, &flow_list
.head
, entry
);
1330 } while (n
&& (!n
->is_visible
|| presenter_flow_wrong_state(n
)));
1335 static void flows_table_init(struct ui_table
*tbl
)
1339 ui_table_pos_set(tbl
, 3, 0);
1340 ui_table_height_set(tbl
, LINES
- 3);
1342 ui_table_col_add(tbl
, TBL_FLOW_PROCESS
, "PROCESS", 13);
1343 ui_table_col_add(tbl
, TBL_FLOW_PID
, "PID", 7);
1344 ui_table_col_add(tbl
, TBL_FLOW_PROTO
, "PROTO", 6);
1345 ui_table_col_add(tbl
, TBL_FLOW_STATE
, "STATE", 11);
1346 ui_table_col_add(tbl
, TBL_FLOW_TIME
, "TIME", 4);
1347 ui_table_col_add(tbl
, TBL_FLOW_ADDRESS
, "ADDRESS", 50);
1348 ui_table_col_add(tbl
, TBL_FLOW_PORT
, "PORT", 8);
1349 ui_table_col_add(tbl
, TBL_FLOW_GEO
, "GEO", 3);
1350 ui_table_col_add(tbl
, TBL_FLOW_BYTES
, "BYTES", 10);
1351 ui_table_col_add(tbl
, TBL_FLOW_RATE
, "RATE", 10);
1353 ui_table_col_align_set(tbl
, TBL_FLOW_TIME
, UI_ALIGN_RIGHT
);
1354 ui_table_col_align_set(tbl
, TBL_FLOW_BYTES
, UI_ALIGN_RIGHT
);
1355 ui_table_col_align_set(tbl
, TBL_FLOW_RATE
, UI_ALIGN_RIGHT
);
1357 ui_table_col_color_set(tbl
, TBL_FLOW_PROCESS
, COLOR(YELLOW
, BLACK
));
1358 ui_table_col_color_set(tbl
, TBL_FLOW_PID
, A_BOLD
);
1359 ui_table_col_color_set(tbl
, TBL_FLOW_STATE
, COLOR(YELLOW
, BLACK
));
1361 ui_table_header_color_set(&flows_tbl
, COLOR(BLACK
, GREEN
));
1363 ui_table_data_bind_set(tbl
, draw_flow_entry
);
1364 ui_table_data_iter_set(tbl
, flows_iter
);
1367 void * procs_iter(void *data
)
1369 struct proc_entry
*p
= data
;
1371 return list_first_or_next(p
, &proc_list
.head
, entry
);
1374 static void procs_table_init(struct ui_table
*tbl
)
1378 ui_table_pos_set(tbl
, 3, 0);
1379 ui_table_height_set(tbl
, LINES
- 3);
1381 ui_table_col_add(tbl
, TBL_PROC_NAME
, "NAME", 13);
1382 ui_table_col_add(tbl
, TBL_PROC_PID
, "PID", 7);
1383 ui_table_col_add(tbl
, TBL_PROC_FLOWS
, "FLOWS", 7);
1384 ui_table_col_add(tbl
, TBL_PROC_BYTES_SRC
, "BYTES_SRC", 10);
1385 ui_table_col_add(tbl
, TBL_PROC_BYTES_DST
, "BYTES_DST", 10);
1386 ui_table_col_add(tbl
, TBL_PROC_RATE_SRC
, "RATE_SRC", 14);
1387 ui_table_col_add(tbl
, TBL_PROC_RATE_DST
, "RATE_DST", 14);
1389 ui_table_col_align_set(tbl
, TBL_PROC_BYTES_SRC
, UI_ALIGN_RIGHT
);
1390 ui_table_col_align_set(tbl
, TBL_PROC_RATE_SRC
, UI_ALIGN_RIGHT
);
1391 ui_table_col_align_set(tbl
, TBL_PROC_BYTES_DST
, UI_ALIGN_RIGHT
);
1392 ui_table_col_align_set(tbl
, TBL_PROC_RATE_DST
, UI_ALIGN_RIGHT
);
1394 ui_table_col_color_set(tbl
, TBL_PROC_NAME
, COLOR(YELLOW
, BLACK
));
1395 ui_table_col_color_set(tbl
, TBL_PROC_PID
, A_BOLD
);
1396 ui_table_col_color_set(tbl
, TBL_PROC_FLOWS
, COLOR(YELLOW
, BLACK
));
1397 ui_table_col_color_set(tbl
, TBL_PROC_BYTES_SRC
, COLOR(RED
, BLACK
));
1398 ui_table_col_color_set(tbl
, TBL_PROC_RATE_SRC
, COLOR(RED
, BLACK
));
1399 ui_table_col_color_set(tbl
, TBL_PROC_BYTES_DST
, COLOR(BLUE
, BLACK
));
1400 ui_table_col_color_set(tbl
, TBL_PROC_RATE_DST
, COLOR(BLUE
, BLACK
));
1402 ui_table_header_color_set(tbl
, COLOR(BLACK
, GREEN
));
1404 ui_table_data_bind_set(tbl
, draw_proc_entry
);
1405 ui_table_data_iter_set(tbl
, procs_iter
);
1408 static void tab_main_on_open(struct ui_tab
*tab
, enum ui_tab_event_t evt
, uint32_t id
)
1410 if (evt
!= UI_TAB_EVT_OPEN
)
1413 if (id
== TAB_FLOWS
) {
1414 draw_flows(screen
, &flow_list
);
1415 curr_tbl
= &flows_tbl
;
1416 } else if (id
== TAB_PROCS
) {
1417 draw_procs(screen
, &flow_list
);
1418 curr_tbl
= &procs_tbl
;
1422 static void presenter(void)
1424 bool show_help
= false;
1425 struct ui_tab
*tab_main
;
1427 lookup_init(LT_PORTS_TCP
);
1428 lookup_init(LT_PORTS_UDP
);
1430 screen
= screen_init(false);
1435 INIT_COLOR(RED
, BLACK
);
1436 INIT_COLOR(BLUE
, BLACK
);
1437 INIT_COLOR(YELLOW
, BLACK
);
1438 INIT_COLOR(GREEN
, BLACK
);
1439 INIT_COLOR(BLACK
, GREEN
);
1441 flows_table_init(&flows_tbl
);
1442 procs_table_init(&procs_tbl
);
1444 tab_main
= ui_tab_create();
1445 ui_tab_event_cb_set(tab_main
, tab_main_on_open
);
1446 ui_tab_pos_set(tab_main
, 2, 0);
1447 ui_tab_active_color_set(tab_main
, COLOR(BLACK
, GREEN
));
1448 ui_tab_entry_add(tab_main
, TAB_FLOWS
, "Flows");
1449 ui_tab_entry_add(tab_main
, TAB_PROCS
, "Processes");
1451 rcu_register_thread();
1456 getmaxyx(screen
, rows
, cols
);
1466 ui_table_event_send(curr_tbl
, UI_EVT_SCROLL_UP
);
1471 ui_table_event_send(curr_tbl
, UI_EVT_SCROLL_DOWN
);
1475 ui_table_event_send(curr_tbl
, UI_EVT_SCROLL_LEFT
);
1479 ui_table_event_send(curr_tbl
, UI_EVT_SCROLL_RIGHT
);
1482 if (rate_type
== RATE_BYTES
)
1483 rate_type
= RATE_BITS
;
1485 rate_type
= RATE_BYTES
;
1488 show_active_only
= !show_active_only
;
1491 show_src
= !show_src
;
1494 show_help
= !show_help
;
1503 show_option_toggle(ch
);
1504 do_reload_flows
= true;
1507 ui_tab_event_send(tab_main
, UI_EVT_SELECT_NEXT
);
1514 draw_header(screen
);
1519 ui_tab_show(tab_main
);
1523 rcu_unregister_thread();
1525 ui_table_uninit(&flows_tbl
);
1526 ui_table_uninit(&procs_tbl
);
1527 ui_tab_destroy(tab_main
);
1530 lookup_cleanup(LT_PORTS_UDP
);
1531 lookup_cleanup(LT_PORTS_TCP
);
1534 static void restore_sysctl(void *obj
)
1536 struct sysctl_params_ctx
*sysctl_ctx
= obj
;
1538 if (sysctl_ctx
->nfct_acct
== 0)
1539 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1540 sysctl_ctx
->nfct_acct
);
1542 if (sysctl_ctx
->nfct_tstamp
== 0)
1543 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1544 sysctl_ctx
->nfct_tstamp
);
1547 static void on_panic_handler(void *arg
)
1549 restore_sysctl(arg
);
1553 static void conntrack_acct_enable(void)
1555 /* We can still work w/o traffic accounting so just warn about error */
1556 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl
.nfct_acct
)) {
1557 fprintf(stderr
, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1562 if (sysctl
.nfct_acct
== 1)
1565 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1566 fprintf(stderr
, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1571 static void conntrack_tstamp_enable(void)
1573 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl
.nfct_tstamp
)) {
1574 fprintf(stderr
, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1579 if (sysctl
.nfct_tstamp
== 1)
1582 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1583 fprintf(stderr
, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1588 static void flow_entry_filter(struct flow_entry
*n
)
1590 if (show_active_only
&& !n
->stat
.rate_bytes_src
&& !n
->stat
.rate_bytes_dst
)
1591 n
->is_visible
= false;
1593 n
->is_visible
= true;
1596 static int flow_list_update_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
1598 struct flow_entry
*n
;
1600 n
= flow_list_find_id(fl
, nfct_get_attr_u32(ct
, ATTR_ID
));
1602 return NFCT_CB_CONTINUE
;
1604 flow_entry_calc_rate(n
, ct
);
1605 flow_entry_update_time(n
);
1606 flow_entry_from_ct(n
, ct
);
1607 flow_entry_filter(n
);
1609 return NFCT_CB_CONTINUE
;
1612 static int flow_event_cb(enum nf_conntrack_msg_type type
,
1613 struct nf_conntrack
*ct
, void *data __maybe_unused
)
1616 return NFCT_CB_STOP
;
1620 return flow_list_new_entry(&flow_list
, ct
);
1622 return flow_list_update_entry(&flow_list
, ct
);
1623 case NFCT_T_DESTROY
:
1624 return flow_list_del_entry(&flow_list
, ct
);
1626 return NFCT_CB_CONTINUE
;
1630 static void collector_refresh_procs(void)
1632 struct proc_entry
*p
, *tmp
;
1634 cds_list_for_each_entry_safe(p
, tmp
, &proc_list
.head
, entry
) {
1635 double sec
= (double)time_after_us(&p
->last_update
) / USEC_PER_SEC
;
1636 struct flow_entry
*n
;
1641 bug_on(gettimeofday(&p
->last_update
, NULL
));
1643 if (!p
->flows_count
&& !proc_exists(p
->pid
)) {
1644 cds_list_del_rcu(&p
->entry
);
1645 call_rcu(&p
->rcu
, proc_entry_xfree_rcu
);
1649 p
->stat
.rate_bytes_src
= 0;
1650 p
->stat
.rate_bytes_dst
= 0;
1651 p
->stat
.rate_pkts_src
= 0;
1652 p
->stat
.rate_pkts_dst
= 0;
1654 cds_list_for_each_entry_rcu(n
, &p
->flows
, proc_head
) {
1655 p
->stat
.rate_bytes_src
+= n
->stat
.rate_bytes_src
;
1656 p
->stat
.rate_bytes_dst
+= n
->stat
.rate_bytes_dst
;
1657 p
->stat
.rate_pkts_src
+= n
->stat
.rate_pkts_src
;
1658 p
->stat
.rate_pkts_dst
+= n
->stat
.rate_pkts_dst
;
1663 static void collector_refresh_flows(struct nfct_handle
*handle
)
1665 struct flow_entry
*n
;
1667 cds_list_for_each_entry_rcu(n
, &flow_list
.head
, entry
) {
1668 nfct_query(handle
, NFCT_Q_GET
, n
->ct
);
1672 static void collector_create_filter(struct nfct_handle
*nfct
)
1674 struct nfct_filter
*filter
;
1677 filter
= nfct_filter_create();
1679 panic("Cannot create a nfct filter: %s\n", strerror(errno
));
1681 if (what
& INCLUDE_UDP
) {
1682 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_UDP
);
1683 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_UDPLITE
);
1685 if (what
& INCLUDE_TCP
)
1686 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_TCP
);
1687 if (what
& INCLUDE_DCCP
)
1688 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_DCCP
);
1689 if (what
& INCLUDE_SCTP
)
1690 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_SCTP
);
1691 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV4
)
1692 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_ICMP
);
1693 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV6
)
1694 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_ICMPV6
);
1695 if (what
& INCLUDE_IPV4
) {
1696 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV4
, NFCT_FILTER_LOGIC_NEGATIVE
);
1697 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV4
, &filter_ipv4
);
1699 if (what
& INCLUDE_IPV6
) {
1700 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV6
, NFCT_FILTER_LOGIC_NEGATIVE
);
1701 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV6
, &filter_ipv6
);
1704 ret
= nfct_filter_attach(nfct_fd(nfct
), filter
);
1706 panic("Cannot attach filter to handle: %s\n", strerror(errno
));
1708 nfct_filter_destroy(filter
);
1711 /* This hand-crafted filter looks ugly but it allows to do not
1712 * flush nfct connections & filter them by user specified filter.
1713 * May be it is better to replace this one by nfct_cmp. */
1714 static int flow_dump_cb(enum nf_conntrack_msg_type type __maybe_unused
,
1715 struct nf_conntrack
*ct
, void *data __maybe_unused
)
1717 struct flow_entry fl
;
1718 struct flow_entry
*n
= &fl
;
1721 return NFCT_CB_STOP
;
1723 if (!(what
& ~(INCLUDE_IPV4
| INCLUDE_IPV6
)))
1726 CP_NFCT(l4_proto
, ATTR_ORIG_L4PROTO
, 8);
1728 if (what
& INCLUDE_UDP
) {
1729 if (n
->l4_proto
== IPPROTO_UDP
)
1732 if (n
->l4_proto
== IPPROTO_UDPLITE
)
1736 if ((what
& INCLUDE_TCP
) && n
->l4_proto
== IPPROTO_TCP
)
1739 if ((what
& INCLUDE_DCCP
) && n
->l4_proto
== IPPROTO_DCCP
)
1742 if ((what
& INCLUDE_SCTP
) && n
->l4_proto
== IPPROTO_SCTP
)
1745 if ((what
& INCLUDE_ICMP
) && (what
& INCLUDE_IPV4
) &&
1746 n
->l4_proto
== IPPROTO_ICMP
) {
1750 if ((what
& INCLUDE_ICMP
) && (what
& INCLUDE_IPV6
) &&
1751 n
->l4_proto
== IPPROTO_ICMPV6
) {
1758 /* filter loopback addresses */
1759 if (what
& INCLUDE_IPV4
) {
1760 CP_NFCT(ip4_src_addr
, ATTR_ORIG_IPV4_SRC
, 32);
1762 if (n
->ip4_src_addr
== filter_ipv4
.addr
)
1765 if (what
& INCLUDE_IPV6
) {
1766 CP_NFCT_BUFF(ip6_src_addr
, ATTR_ORIG_IPV6_SRC
);
1768 if (n
->ip6_src_addr
[0] == 0x0 &&
1769 n
->ip6_src_addr
[1] == 0x0 &&
1770 n
->ip6_src_addr
[2] == 0x0 &&
1771 n
->ip6_src_addr
[3] == 0x1)
1775 return flow_list_new_entry(&flow_list
, ct
);
1778 return NFCT_CB_CONTINUE
;
1781 static void collector_dump_flows(void)
1783 struct nfct_handle
*nfct
= nfct_open(CONNTRACK
, 0);
1786 panic("Cannot create a nfct handle: %s\n", strerror(errno
));
1788 nfct_callback_register(nfct
, NFCT_T_ALL
, flow_dump_cb
, NULL
);
1790 is_flow_collecting
= true;
1791 if (what
& INCLUDE_IPV4
) {
1792 int family
= AF_INET
;
1793 nfct_query(nfct
, NFCT_Q_DUMP
, &family
);
1795 if (what
& INCLUDE_IPV6
) {
1796 int family
= AF_INET6
;
1797 nfct_query(nfct
, NFCT_Q_DUMP
, &family
);
1799 is_flow_collecting
= false;
1804 static void *collector(void *null __maybe_unused
)
1806 struct nfct_handle
*ct_event
;
1807 struct pollfd poll_fd
[1];
1809 proc_list_init(&proc_list
);
1810 flow_list_init(&flow_list
);
1812 ct_event
= nfct_open(CONNTRACK
, NF_NETLINK_CONNTRACK_NEW
|
1813 NF_NETLINK_CONNTRACK_UPDATE
|
1814 NF_NETLINK_CONNTRACK_DESTROY
);
1816 panic("Cannot create a nfct handle: %s\n", strerror(errno
));
1818 collector_create_filter(ct_event
);
1820 nfct_callback_register(ct_event
, NFCT_T_ALL
, flow_event_cb
, NULL
);
1822 poll_fd
[0].fd
= nfct_fd(ct_event
);
1823 poll_fd
[0].events
= POLLIN
;
1825 if (fcntl(nfct_fd(ct_event
), F_SETFL
, O_NONBLOCK
) == -1)
1826 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1829 rcu_register_thread();
1831 collector_dump_flows();
1836 if (!do_reload_flows
) {
1837 usleep(USEC_PER_SEC
* interval
);
1839 do_reload_flows
= false;
1841 flow_list_destroy(&flow_list
);
1843 collector_create_filter(ct_event
);
1844 collector_dump_flows();
1847 collector_refresh_procs();
1848 collector_refresh_flows(ct_event
);
1850 status
= poll(poll_fd
, 1, 0);
1852 if (errno
== EAGAIN
|| errno
== EINTR
)
1855 panic("Error while polling: %s\n", strerror(errno
));
1856 } else if (status
!= 0) {
1857 if (poll_fd
[0].revents
& POLLIN
)
1858 nfct_catch(ct_event
);
1862 flow_list_destroy(&flow_list
);
1863 proc_list_destroy(&proc_list
);
1865 rcu_unregister_thread();
1867 nfct_close(ct_event
);
1872 int main(int argc
, char **argv
)
1875 int ret
, c
, what_cmd
= 0;
1880 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
1884 what_cmd
|= INCLUDE_IPV4
;
1887 what_cmd
|= INCLUDE_IPV6
;
1890 what_cmd
|= INCLUDE_TCP
;
1893 what_cmd
|= INCLUDE_UDP
;
1896 what_cmd
|= INCLUDE_DCCP
;
1899 what_cmd
|= INCLUDE_ICMP
;
1902 what_cmd
|= INCLUDE_SCTP
;
1908 rate_type
= RATE_BITS
;
1915 interval
= strtoul(optarg
, NULL
, 10);
1918 resolve_dns
= false;
1921 resolve_geoip
= false;
1937 if (!(what
& (INCLUDE_IPV4
| INCLUDE_IPV6
)))
1938 what
|= INCLUDE_IPV4
| INCLUDE_IPV6
;
1943 register_signal(SIGINT
, signal_handler
);
1944 register_signal(SIGQUIT
, signal_handler
);
1945 register_signal(SIGTERM
, signal_handler
);
1946 register_signal(SIGHUP
, signal_handler
);
1948 panic_handler_add(on_panic_handler
, &sysctl
);
1950 conntrack_acct_enable();
1951 conntrack_tstamp_enable();
1956 ret
= pthread_create(&tid
, NULL
, collector
, NULL
);
1958 panic("Cannot create phthread!\n");
1965 restore_sysctl(&sysctl
);