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 struct cds_list_head entry
;
59 uint32_t flow_id
, use
, status
;
60 uint8_t l3_proto
, l4_proto
;
61 uint32_t ip4_src_addr
, ip4_dst_addr
;
62 uint32_t ip6_src_addr
[4], ip6_dst_addr
[4];
63 uint16_t port_src
, port_dst
;
64 uint8_t tcp_state
, tcp_flags
, sctp_state
, dccp_state
;
65 uint64_t pkts_src
, bytes_src
;
66 uint64_t pkts_dst
, bytes_dst
;
67 uint64_t timestamp_start
, timestamp_stop
;
68 char country_src
[128], country_dst
[128];
69 char country_code_src
[4], country_code_dst
[4];
70 char city_src
[128], city_dst
[128];
71 char rev_dns_src
[256], rev_dns_dst
[256];
76 struct nf_conntrack
*ct
;
77 struct timeval last_update
;
78 double rate_bytes_src
;
79 double rate_bytes_dst
;
85 struct cds_list_head head
;
93 #ifndef ATTR_TIMESTAMP_START
94 # define ATTR_TIMESTAMP_START 63
96 #ifndef ATTR_TIMESTAMP_STOP
97 # define ATTR_TIMESTAMP_STOP 64
100 #define SCROLL_MAX 1000
102 #define INCLUDE_IPV4 (1 << 0)
103 #define INCLUDE_IPV6 (1 << 1)
104 #define INCLUDE_UDP (1 << 2)
105 #define INCLUDE_TCP (1 << 3)
106 #define INCLUDE_DCCP (1 << 4)
107 #define INCLUDE_ICMP (1 << 5)
108 #define INCLUDE_SCTP (1 << 6)
110 #define TOGGLE_FLAG(what, flag) \
118 struct sysctl_params_ctx
{
128 static volatile bool do_reload_flows
;
129 static volatile bool is_flow_collecting
;
130 static volatile sig_atomic_t sigint
= 0;
131 static int what
= INCLUDE_IPV4
| INCLUDE_IPV6
| INCLUDE_TCP
;
132 static struct flow_list flow_list
;
133 static struct sysctl_params_ctx sysctl
= { -1, -1 };
135 static unsigned int cols
, rows
;
136 static WINDOW
*screen
;
137 static int skip_lines
;
139 static unsigned int interval
= 1;
140 static bool show_src
= false;
141 static bool resolve_dns
= true;
142 static bool resolve_geoip
= true;
143 static enum rate_units rate_type
= RATE_BYTES
;
144 static bool show_active_only
= false;
159 static struct ui_table flows_tbl
;
165 static const char *short_options
= "vhTUsDIS46ut:nGb";
166 static const struct option long_options
[] = {
167 {"ipv4", no_argument
, NULL
, '4'},
168 {"ipv6", no_argument
, NULL
, '6'},
169 {"tcp", no_argument
, NULL
, 'T'},
170 {"udp", no_argument
, NULL
, 'U'},
171 {"dccp", no_argument
, NULL
, 'D'},
172 {"icmp", no_argument
, NULL
, 'I'},
173 {"sctp", no_argument
, NULL
, 'S'},
174 {"no-dns", no_argument
, NULL
, 'n'},
175 {"no-geoip", no_argument
, NULL
, 'G'},
176 {"show-src", no_argument
, NULL
, 's'},
177 {"bits", no_argument
, NULL
, 'b'},
178 {"update", no_argument
, NULL
, 'u'},
179 {"interval", required_argument
, NULL
, 't'},
180 {"version", no_argument
, NULL
, 'v'},
181 {"help", no_argument
, NULL
, 'h'},
185 static const char *copyright
= "Please report bugs to <netsniff-ng@googlegroups.com>\n"
186 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
187 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
188 "Swiss federal institute of technology (ETH Zurich)\n"
189 "License: GNU GPL version 2.0\n"
190 "This is free software: you are free to change and redistribute it.\n"
191 "There is NO WARRANTY, to the extent permitted by law.";
193 static const char *const l4proto2str
[IPPROTO_MAX
] = {
194 [IPPROTO_TCP
] = "tcp",
195 [IPPROTO_UDP
] = "udp",
196 [IPPROTO_UDPLITE
] = "udplite",
197 [IPPROTO_ICMP
] = "icmp",
198 [IPPROTO_ICMPV6
] = "icmpv6",
199 [IPPROTO_SCTP
] = "sctp",
200 [IPPROTO_GRE
] = "gre",
201 [IPPROTO_DCCP
] = "dccp",
202 [IPPROTO_IGMP
] = "igmp",
203 [IPPROTO_IPIP
] = "ipip",
204 [IPPROTO_EGP
] = "egp",
205 [IPPROTO_PUP
] = "pup",
206 [IPPROTO_IDP
] = "idp",
207 [IPPROTO_RSVP
] = "rsvp",
208 [IPPROTO_IPV6
] = "ip6tun",
209 [IPPROTO_ESP
] = "esp",
211 [IPPROTO_PIM
] = "pim",
212 [IPPROTO_COMP
] = "comp",
215 static const char *const tcp_state2str
[TCP_CONNTRACK_MAX
] = {
216 [TCP_CONNTRACK_NONE
] = "NONE",
217 [TCP_CONNTRACK_SYN_SENT
] = "SYN-SENT",
218 [TCP_CONNTRACK_SYN_RECV
] = "SYN-RECV",
219 [TCP_CONNTRACK_ESTABLISHED
] = "ESTABLISHED",
220 [TCP_CONNTRACK_FIN_WAIT
] = "FIN-WAIT",
221 [TCP_CONNTRACK_CLOSE_WAIT
] = "CLOSE-WAIT",
222 [TCP_CONNTRACK_LAST_ACK
] = "LAST-ACK",
223 [TCP_CONNTRACK_TIME_WAIT
] = "TIME-WAIT",
224 [TCP_CONNTRACK_CLOSE
] = "CLOSE",
225 [TCP_CONNTRACK_SYN_SENT2
] = "SYN-SENT2",
228 static const char *const dccp_state2str
[DCCP_CONNTRACK_MAX
] = {
229 [DCCP_CONNTRACK_NONE
] = "NONE",
230 [DCCP_CONNTRACK_REQUEST
] = "REQUEST",
231 [DCCP_CONNTRACK_RESPOND
] = "RESPOND",
232 [DCCP_CONNTRACK_PARTOPEN
] = "PARTOPEN",
233 [DCCP_CONNTRACK_OPEN
] = "OPEN",
234 [DCCP_CONNTRACK_CLOSEREQ
] = "CLOSE-REQ",
235 [DCCP_CONNTRACK_CLOSING
] = "CLOSING",
236 [DCCP_CONNTRACK_TIMEWAIT
] = "TIME-WAIT",
237 [DCCP_CONNTRACK_IGNORE
] = "IGNORE",
238 [DCCP_CONNTRACK_INVALID
] = "INVALID",
241 static const char *const sctp_state2str
[SCTP_CONNTRACK_MAX
] = {
242 [SCTP_CONNTRACK_NONE
] = "NONE",
243 [SCTP_CONNTRACK_CLOSED
] = "CLOSED",
244 [SCTP_CONNTRACK_COOKIE_WAIT
] = "COOKIE-WAIT",
245 [SCTP_CONNTRACK_COOKIE_ECHOED
] = "COOKIE-ECHO",
246 [SCTP_CONNTRACK_ESTABLISHED
] = "ESTABLISHED",
247 [SCTP_CONNTRACK_SHUTDOWN_SENT
] = "SHUTD-SENT",
248 [SCTP_CONNTRACK_SHUTDOWN_RECD
] = "SHUTD-RCVD",
249 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
] = "SHUTD-ACK",
252 static const struct nfct_filter_ipv4 filter_ipv4
= {
253 .addr
= __constant_htonl(INADDR_LOOPBACK
),
257 static const struct nfct_filter_ipv6 filter_ipv6
= {
258 .addr
= { 0x0, 0x0, 0x0, 0x1 },
259 .mask
= { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
262 static int64_t time_after_us(struct timeval
*tv
)
266 bug_on(gettimeofday(&now
, NULL
));
268 now
.tv_sec
-= tv
->tv_sec
;
269 now
.tv_usec
-= tv
->tv_usec
;
271 return now
.tv_sec
* USEC_PER_SEC
+ now
.tv_usec
;
274 static void signal_handler(int number
)
288 static void flow_entry_from_ct(struct flow_entry
*n
, const struct nf_conntrack
*ct
);
289 static void flow_entry_get_extended(struct flow_entry
*n
);
291 static void help(void)
293 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
295 puts("http://www.netsniff-ng.org\n\n"
296 "Usage: flowtop [options]\n"
298 " -4|--ipv4 Show only IPv4 flows (default)\n"
299 " -6|--ipv6 Show only IPv6 flows (default)\n"
300 " -T|--tcp Show only TCP flows (default)\n"
301 " -U|--udp Show only UDP flows\n"
302 " -D|--dccp Show only DCCP flows\n"
303 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
304 " -S|--sctp Show only SCTP flows\n"
305 " -n|--no-dns Don't perform hostname lookup\n"
306 " -G|--no-geoip Don't perform GeoIP lookup\n"
307 " -s|--show-src Also show source, not only dest\n"
308 " -b|--bits Show rates in bits/s instead of bytes/s\n"
309 " -u|--update Update GeoIP databases\n"
310 " -t|--interval <time> Refresh time in seconds (default 1s)\n"
311 " -v|--version Print version and exit\n"
312 " -h|--help Print this help and exit\n\n"
315 " flowtop -46UTDISs\n\n"
317 " If netfilter is not running, you can activate it with e.g.:\n"
318 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
319 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
324 static void version(void)
326 printf("flowtop %s, Git id: %s\n", VERSION_LONG
, GITVERSION
);
327 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
328 "http://www.netsniff-ng.org\n");
333 static void flow_entry_update_time(struct flow_entry
*n
)
335 bug_on(gettimeofday(&n
->last_update
, NULL
));
338 #define CALC_RATE(fld) do { \
339 n->rate_##fld = (((fld) > n->fld) ? (((fld) - n->fld) / sec) : 0); \
342 static void flow_entry_calc_rate(struct flow_entry
*n
, const struct nf_conntrack
*ct
)
344 uint64_t bytes_src
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_BYTES
);
345 uint64_t bytes_dst
= nfct_get_attr_u64(ct
, ATTR_REPL_COUNTER_BYTES
);
346 uint64_t pkts_src
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_PACKETS
);
347 uint64_t pkts_dst
= nfct_get_attr_u64(ct
, ATTR_REPL_COUNTER_PACKETS
);
348 double sec
= (double)time_after_us(&n
->last_update
) / USEC_PER_SEC
;
353 CALC_RATE(bytes_src
);
354 CALC_RATE(bytes_dst
);
359 static inline struct flow_entry
*flow_entry_xalloc(void)
361 return xzmalloc(sizeof(struct flow_entry
));
364 static inline void flow_entry_xfree(struct flow_entry
*n
)
372 static void flow_entry_xfree_rcu(struct rcu_head
*head
)
374 struct flow_entry
*n
= container_of(head
, struct flow_entry
, rcu
);
379 static inline void flow_list_init(struct flow_list
*fl
)
381 CDS_INIT_LIST_HEAD(&fl
->head
);
384 static inline bool nfct_is_dns(const struct nf_conntrack
*ct
)
386 uint16_t port_src
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_SRC
);
387 uint16_t port_dst
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_DST
);
389 return ntohs(port_src
) == 53 || ntohs(port_dst
) == 53;
392 static int flow_list_new_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
394 struct flow_entry
*n
;
396 /* We don't want to analyze / display DNS itself, since we
397 * use it to resolve reverse dns.
400 return NFCT_CB_CONTINUE
;
402 n
= flow_entry_xalloc();
406 flow_entry_update_time(n
);
407 flow_entry_from_ct(n
, ct
);
408 flow_entry_get_extended(n
);
410 cds_list_add_rcu(&n
->entry
, &fl
->head
);
412 n
->is_visible
= true;
414 return NFCT_CB_STOLEN
;
417 static struct flow_entry
*flow_list_find_id(struct flow_list
*fl
, uint32_t id
)
419 struct flow_entry
*n
;
421 cds_list_for_each_entry_rcu(n
, &fl
->head
, entry
) {
422 if (n
->flow_id
== id
)
429 static int flow_list_del_entry(struct flow_list
*fl
, const struct nf_conntrack
*ct
)
431 struct flow_entry
*n
;
433 n
= flow_list_find_id(fl
, nfct_get_attr_u32(ct
, ATTR_ID
));
435 cds_list_del_rcu(&n
->entry
);
436 call_rcu(&n
->rcu
, flow_entry_xfree_rcu
);
439 return NFCT_CB_CONTINUE
;
442 static void flow_list_destroy(struct flow_list
*fl
)
444 struct flow_entry
*n
, *tmp
;
446 cds_list_for_each_entry_safe(n
, tmp
, &fl
->head
, entry
) {
447 cds_list_del_rcu(&n
->entry
);
448 call_rcu(&n
->rcu
, flow_entry_xfree_rcu
);
452 static void flow_entry_find_process(struct flow_entry
*n
)
458 ret
= proc_find_by_inode(n
->inode
, cmdline
, sizeof(cmdline
), &pid
);
460 n
->procname
[0] = '\0';
464 if (snprintf(n
->procname
, sizeof(n
->procname
), "%s", basename(cmdline
)) < 0)
465 n
->procname
[0] = '\0';
470 static int get_port_inode(uint16_t port
, int proto
, bool is_ip6
)
473 char path
[128], buff
[1024];
476 memset(path
, 0, sizeof(path
));
477 snprintf(path
, sizeof(path
), "/proc/net/%s%s",
478 l4proto2str
[proto
], is_ip6
? "6" : "");
480 proc
= fopen(path
, "r");
484 memset(buff
, 0, sizeof(buff
));
486 while (fgets(buff
, sizeof(buff
), proc
) != NULL
) {
488 unsigned int lport
= 0;
490 buff
[sizeof(buff
) - 1] = 0;
491 if (sscanf(buff
, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
492 "%*X %*u %*u %u", &lport
, &inode
) == 2) {
493 if ((uint16_t) lport
== port
) {
499 memset(buff
, 0, sizeof(buff
));
506 #define CP_NFCT(elem, attr, x) \
507 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
508 #define CP_NFCT_BUFF(elem, attr) do { \
509 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
511 memcpy(n->elem, buff, sizeof(n->elem)); \
514 static void flow_entry_from_ct(struct flow_entry
*n
, const struct nf_conntrack
*ct
)
516 CP_NFCT(l3_proto
, ATTR_ORIG_L3PROTO
, 8);
517 CP_NFCT(l4_proto
, ATTR_ORIG_L4PROTO
, 8);
519 CP_NFCT(ip4_src_addr
, ATTR_ORIG_IPV4_SRC
, 32);
520 CP_NFCT(ip4_dst_addr
, ATTR_ORIG_IPV4_DST
, 32);
522 CP_NFCT(port_src
, ATTR_ORIG_PORT_SRC
, 16);
523 CP_NFCT(port_dst
, ATTR_ORIG_PORT_DST
, 16);
525 CP_NFCT(status
, ATTR_STATUS
, 32);
527 CP_NFCT(tcp_state
, ATTR_TCP_STATE
, 8);
528 CP_NFCT(tcp_flags
, ATTR_TCP_FLAGS_ORIG
, 8);
529 CP_NFCT(sctp_state
, ATTR_SCTP_STATE
, 8);
530 CP_NFCT(dccp_state
, ATTR_DCCP_STATE
, 8);
532 CP_NFCT(pkts_src
, ATTR_ORIG_COUNTER_PACKETS
, 64);
533 CP_NFCT(bytes_src
, ATTR_ORIG_COUNTER_BYTES
, 64);
535 CP_NFCT(pkts_dst
, ATTR_REPL_COUNTER_PACKETS
, 64);
536 CP_NFCT(bytes_dst
, ATTR_REPL_COUNTER_BYTES
, 64);
538 CP_NFCT(timestamp_start
, ATTR_TIMESTAMP_START
, 64);
539 CP_NFCT(timestamp_stop
, ATTR_TIMESTAMP_STOP
, 64);
541 CP_NFCT(flow_id
, ATTR_ID
, 32);
542 CP_NFCT(use
, ATTR_USE
, 32);
544 CP_NFCT_BUFF(ip6_src_addr
, ATTR_ORIG_IPV6_SRC
);
545 CP_NFCT_BUFF(ip6_dst_addr
, ATTR_ORIG_IPV6_DST
);
547 n
->port_src
= ntohs(n
->port_src
);
548 n
->port_dst
= ntohs(n
->port_dst
);
550 n
->ip4_src_addr
= ntohl(n
->ip4_src_addr
);
551 n
->ip4_dst_addr
= ntohl(n
->ip4_dst_addr
);
554 #define SELFLD(dir,src_member,dst_member) \
555 (((dir) == FLOW_DIR_SRC) ? n->src_member : n->dst_member)
557 static void flow_entry_get_sain4_obj(const struct flow_entry
*n
,
558 enum flow_direction dir
,
559 struct sockaddr_in
*sa
)
561 memset(sa
, 0, sizeof(*sa
));
562 sa
->sin_family
= PF_INET
;
563 sa
->sin_addr
.s_addr
= htonl(SELFLD(dir
, ip4_src_addr
, ip4_dst_addr
));
566 static void flow_entry_get_sain6_obj(const struct flow_entry
*n
,
567 enum flow_direction dir
,
568 struct sockaddr_in6
*sa
)
570 memset(sa
, 0, sizeof(*sa
));
571 sa
->sin6_family
= PF_INET6
;
573 memcpy(&sa
->sin6_addr
, SELFLD(dir
, ip6_src_addr
, ip6_dst_addr
),
574 sizeof(sa
->sin6_addr
));
578 flow_entry_geo_city_lookup_generic(struct flow_entry
*n
,
579 enum flow_direction dir
)
581 struct sockaddr_in sa4
;
582 struct sockaddr_in6 sa6
;
583 const char *city
= NULL
;
585 switch (n
->l3_proto
) {
590 flow_entry_get_sain4_obj(n
, dir
, &sa4
);
591 city
= geoip4_city_name(&sa4
);
595 flow_entry_get_sain6_obj(n
, dir
, &sa6
);
596 city
= geoip6_city_name(&sa6
);
600 build_bug_on(sizeof(n
->city_src
) != sizeof(n
->city_dst
));
603 strlcpy(SELFLD(dir
, city_src
, city_dst
), city
,
604 sizeof(n
->city_src
));
606 SELFLD(dir
, city_src
, city_dst
)[0] = '\0';
610 flow_entry_geo_country_lookup_generic(struct flow_entry
*n
,
611 enum flow_direction dir
)
613 struct sockaddr_in sa4
;
614 struct sockaddr_in6 sa6
;
615 const char *country
= NULL
;
616 const char *country_code
= NULL
;
618 switch (n
->l3_proto
) {
623 flow_entry_get_sain4_obj(n
, dir
, &sa4
);
624 country
= geoip4_country_name(&sa4
);
625 country_code
= geoip4_country_code3_name(&sa4
);
629 flow_entry_get_sain6_obj(n
, dir
, &sa6
);
630 country
= geoip6_country_name(&sa6
);
631 country_code
= geoip6_country_code3_name(&sa6
);
635 build_bug_on(sizeof(n
->country_src
) != sizeof(n
->country_dst
));
638 strlcpy(SELFLD(dir
, country_src
, country_dst
), country
,
639 sizeof(n
->country_src
));
641 SELFLD(dir
, country_src
, country_dst
)[0] = '\0';
643 build_bug_on(sizeof(n
->country_code_src
) != sizeof(n
->country_code_dst
));
646 strlcpy(SELFLD(dir
, country_code_src
, country_code_dst
),
647 country_code
, sizeof(n
->country_code_src
));
649 SELFLD(dir
, country_code_src
, country_code_dst
)[0] = '\0';
652 static void flow_entry_get_extended_geo(struct flow_entry
*n
,
653 enum flow_direction dir
)
656 flow_entry_geo_city_lookup_generic(n
, dir
);
657 flow_entry_geo_country_lookup_generic(n
, dir
);
661 static void flow_entry_get_extended_revdns(struct flow_entry
*n
,
662 enum flow_direction dir
)
665 struct sockaddr_in sa4
;
666 struct sockaddr_in6 sa6
;
668 struct hostent
*hent
;
670 build_bug_on(sizeof(n
->rev_dns_src
) != sizeof(n
->rev_dns_dst
));
672 switch (n
->l3_proto
) {
677 flow_entry_get_sain4_obj(n
, dir
, &sa4
);
680 inet_ntop(AF_INET
, &sa4
.sin_addr
,
681 SELFLD(dir
, rev_dns_src
, rev_dns_dst
),
682 sizeof(n
->rev_dns_src
));
686 sa
= (struct sockaddr
*) &sa4
;
687 sa_len
= sizeof(sa4
);
688 hent
= gethostbyaddr(&sa4
.sin_addr
, sizeof(sa4
.sin_addr
), AF_INET
);
692 flow_entry_get_sain6_obj(n
, dir
, &sa6
);
695 inet_ntop(AF_INET6
, &sa6
.sin6_addr
,
696 SELFLD(dir
, rev_dns_src
, rev_dns_dst
),
697 sizeof(n
->rev_dns_src
));
701 sa
= (struct sockaddr
*) &sa6
;
702 sa_len
= sizeof(sa6
);
703 hent
= gethostbyaddr(&sa6
.sin6_addr
, sizeof(sa6
.sin6_addr
), AF_INET6
);
707 getnameinfo(sa
, sa_len
, SELFLD(dir
, rev_dns_src
, rev_dns_dst
),
708 sizeof(n
->rev_dns_src
), NULL
, 0, NI_NUMERICHOST
);
711 strlcpy(SELFLD(dir
, rev_dns_src
, rev_dns_dst
), hent
->h_name
,
712 sizeof(n
->rev_dns_src
));
715 static void flow_entry_get_extended(struct flow_entry
*n
)
720 flow_entry_get_extended_revdns(n
, FLOW_DIR_SRC
);
721 flow_entry_get_extended_geo(n
, FLOW_DIR_SRC
);
723 flow_entry_get_extended_revdns(n
, FLOW_DIR_DST
);
724 flow_entry_get_extended_geo(n
, FLOW_DIR_DST
);
726 /* Lookup application */
727 n
->inode
= get_port_inode(n
->port_src
, n
->l4_proto
,
728 n
->l3_proto
== AF_INET6
);
730 flow_entry_find_process(n
);
733 static char *bandw2str(double bytes
, char *buf
, size_t len
)
740 if (bytes
> 1000000000.)
741 snprintf(buf
, len
, "%.1fGB", bytes
/ 1000000000.);
742 else if (bytes
> 1000000.)
743 snprintf(buf
, len
, "%.1fMB", bytes
/ 1000000.);
744 else if (bytes
> 1000.)
745 snprintf(buf
, len
, "%.1fkB", bytes
/ 1000.);
747 snprintf(buf
, len
, "%.0f", bytes
);
752 static char *rate2str(double rate
, char *buf
, size_t len
)
754 const char * const unit_fmt
[2][4] = {
755 { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%.0fbit/s" },
756 { "%.1fGB/s", "%.1fMB/s", "%.1fkB/s", "%.0fB/s" }
764 if (rate_type
== RATE_BITS
)
767 if (rate
> 1000000000.)
768 snprintf(buf
, len
, unit_fmt
[rate_type
][0], rate
/ 1000000000.);
769 else if (rate
> 1000000.)
770 snprintf(buf
, len
, unit_fmt
[rate_type
][1], rate
/ 1000000.);
771 else if (rate
> 1000.)
772 snprintf(buf
, len
, unit_fmt
[rate_type
][2], rate
/ 1000.);
774 snprintf(buf
, len
, unit_fmt
[rate_type
][3], rate
);
779 static char *time2str(uint64_t tstamp
, char *str
, size_t len
)
786 s
= now
- (tstamp
? (tstamp
/ NSEC_PER_SEC
) : now
);
794 slprintf(str
, len
, "%dd", v
);
800 slprintf(str
, len
, "%dh", v
);
806 slprintf(str
, len
, "%dm", v
);
810 slprintf(str
, len
, "%ds", s
);
815 static const char *flow_state2str(const struct flow_entry
*n
)
817 switch (n
->l4_proto
) {
819 return tcp_state2str
[n
->tcp_state
];
821 return sctp_state2str
[n
->sctp_state
];
823 return dccp_state2str
[n
->dccp_state
];
826 case IPPROTO_UDPLITE
:
834 static char *flow_port2str(const struct flow_entry
*n
, char *str
, size_t len
,
835 enum flow_direction dir
)
837 const char *tmp
= NULL
;
840 port
= SELFLD(dir
, port_src
, port_dst
);
843 switch (n
->l4_proto
) {
845 tmp
= lookup_port_tcp(port
);
848 case IPPROTO_UDPLITE
:
849 tmp
= lookup_port_udp(port
);
854 slprintf(str
, len
, "%d", port
);
856 slprintf(str
, len
, "%s", tmp
? tmp
: "");
861 static void print_flow_peer_info(const struct flow_entry
*n
, enum flow_direction dir
)
863 int counters_color
= COLOR(YELLOW
, BLACK
);
864 int src_color
= COLOR(RED
, BLACK
);
865 int dst_color
= COLOR(BLUE
, BLACK
);
866 int country_color
= COLOR(GREEN
, BLACK
);
867 int addr_color
= dst_color
;
868 int port_color
= A_BOLD
;
871 if (show_src
&& dir
== FLOW_DIR_SRC
) {
872 country_color
= src_color
;
873 counters_color
= src_color
;
874 port_color
|= src_color
;
875 addr_color
= src_color
;
876 } else if (show_src
&& FLOW_DIR_DST
) {
877 country_color
= dst_color
;
878 counters_color
= dst_color
;
879 port_color
|= dst_color
;
880 addr_color
= dst_color
;
883 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_ADDRESS
, addr_color
);
884 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_PORT
, port_color
);
885 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_GEO
, country_color
);
886 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_BYTES
, counters_color
);
887 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_RATE
, counters_color
);
890 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_ADDRESS
,
891 SELFLD(dir
, rev_dns_src
, rev_dns_dst
));
893 /* Application port */
894 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PORT
,
895 flow_port2str(n
, tmp
, sizeof(tmp
), dir
));
898 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_GEO
,
899 SELFLD(dir
, country_code_src
, country_code_dst
));
902 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_BYTES
,
903 bandw2str(SELFLD(dir
, bytes_src
, bytes_dst
),
904 tmp
, sizeof(tmp
) - 1));
907 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_RATE
,
908 rate2str(SELFLD(dir
, rate_bytes_src
, rate_bytes_dst
),
909 tmp
, sizeof(tmp
) - 1));
912 static void draw_flow_entry(const struct flow_entry
*n
)
916 ui_table_row_add(&flows_tbl
);
919 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PROCESS
, n
->procname
);
922 slprintf(tmp
, sizeof(tmp
), "%.d", n
->procnum
);
923 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PID
, tmp
);
926 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PROTO
, l4proto2str
[n
->l4_proto
]);
928 /* L4 protocol state */
929 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_STATE
, flow_state2str(n
));
932 time2str(n
->timestamp_start
, tmp
, sizeof(tmp
));
933 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_TIME
, tmp
);
935 print_flow_peer_info(n
, show_src
? FLOW_DIR_SRC
: FLOW_DIR_DST
);
937 ui_table_row_show(&flows_tbl
);
940 ui_table_row_add(&flows_tbl
);
942 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PROCESS
, "");
943 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PID
, "");
944 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PROTO
, "");
945 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_STATE
, "");
946 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_TIME
, "");
948 print_flow_peer_info(n
, FLOW_DIR_DST
);
949 ui_table_row_show(&flows_tbl
);
953 static inline bool presenter_flow_wrong_state(struct flow_entry
*n
)
955 switch (n
->l4_proto
) {
957 switch (n
->tcp_state
) {
958 case TCP_CONNTRACK_SYN_SENT
:
959 case TCP_CONNTRACK_SYN_RECV
:
960 case TCP_CONNTRACK_ESTABLISHED
:
961 case TCP_CONNTRACK_FIN_WAIT
:
962 case TCP_CONNTRACK_CLOSE_WAIT
:
963 case TCP_CONNTRACK_LAST_ACK
:
964 case TCP_CONNTRACK_TIME_WAIT
:
965 case TCP_CONNTRACK_CLOSE
:
966 case TCP_CONNTRACK_SYN_SENT2
:
967 case TCP_CONNTRACK_NONE
:
973 switch (n
->sctp_state
) {
974 case SCTP_CONNTRACK_NONE
:
975 case SCTP_CONNTRACK_CLOSED
:
976 case SCTP_CONNTRACK_COOKIE_WAIT
:
977 case SCTP_CONNTRACK_COOKIE_ECHOED
:
978 case SCTP_CONNTRACK_ESTABLISHED
:
979 case SCTP_CONNTRACK_SHUTDOWN_SENT
:
980 case SCTP_CONNTRACK_SHUTDOWN_RECD
:
981 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
:
987 switch (n
->dccp_state
) {
988 case DCCP_CONNTRACK_NONE
:
989 case DCCP_CONNTRACK_REQUEST
:
990 case DCCP_CONNTRACK_RESPOND
:
991 case DCCP_CONNTRACK_PARTOPEN
:
992 case DCCP_CONNTRACK_OPEN
:
993 case DCCP_CONNTRACK_CLOSEREQ
:
994 case DCCP_CONNTRACK_CLOSING
:
995 case DCCP_CONNTRACK_TIMEWAIT
:
996 case DCCP_CONNTRACK_IGNORE
:
997 case DCCP_CONNTRACK_INVALID
:
1003 case IPPROTO_UDPLITE
:
1005 case IPPROTO_ICMPV6
:
1013 static void draw_flows(WINDOW
*screen
, struct flow_list
*fl
,
1016 int row_width
= show_src
? 2 : 1;
1017 unsigned int flows
= 0;
1018 unsigned int line
= 4;
1019 int skip
= skip_lines
;
1020 struct flow_entry
*n
;
1024 if (cds_list_empty(&fl
->head
))
1025 mvwprintw(screen
, line
, 2, "(No sessions! "
1026 "Is netfilter running?)");
1028 ui_table_clear(&flows_tbl
);
1029 ui_table_header_print(&flows_tbl
);
1031 cds_list_for_each_entry_rcu(n
, &fl
->head
, entry
) {
1034 if (presenter_flow_wrong_state(n
))
1037 /* count only flows which might be showed */
1040 if (line
+ row_width
>= rows
)
1051 mvwprintw(screen
, 1, 0, "%*s", COLS
- 1, " ");
1052 mvwprintw(screen
, 1, 2, "Kernel netfilter flows(%u) for ", flows
);
1054 if (what
& INCLUDE_IPV4
)
1056 if (what
& INCLUDE_IPV6
)
1058 if (what
& INCLUDE_TCP
)
1060 if (what
& INCLUDE_UDP
)
1062 if (what
& INCLUDE_SCTP
)
1064 if (what
& INCLUDE_DCCP
)
1066 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV4
)
1068 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV6
)
1070 if (show_active_only
)
1073 printw(" [+%d]", skip_lines
);
1075 if (is_flow_collecting
)
1076 printw(" [Collecting flows ...]");
1079 static void draw_help(void)
1085 mvaddch(row
, col
, ACS_ULCORNER
);
1086 mvaddch(rows
- row
- 1, col
, ACS_LLCORNER
);
1088 mvaddch(row
, cols
- 1, ACS_URCORNER
);
1089 mvaddch(rows
- row
- 1, cols
- 1, ACS_LRCORNER
);
1091 for (i
= 1; i
< rows
- row
- 2; i
++) {
1092 mvaddch(row
+ i
, 0, ACS_VLINE
);
1093 mvaddch(row
+ i
, cols
- 1, ACS_VLINE
);
1095 for (i
= 1; i
< cols
- col
- 1; i
++) {
1096 mvaddch(row
, col
+ i
, ACS_HLINE
);
1097 mvaddch(rows
- row
- 1, col
+ i
, ACS_HLINE
);
1101 mvaddnstr(row
, cols
/ 2 - 2, "| Help |", -1);
1103 attron(A_UNDERLINE
);
1104 mvaddnstr(row
+ 2, col
+ 2, "Navigation", -1);
1105 attroff(A_BOLD
| A_UNDERLINE
);
1107 mvaddnstr(row
+ 4, col
+ 3, "Up, u, k Move up", -1);
1108 mvaddnstr(row
+ 5, col
+ 3, "Down, d, j Move down", -1);
1109 mvaddnstr(row
+ 6, col
+ 3, "Left,l Scroll left", -1);
1110 mvaddnstr(row
+ 7, col
+ 3, "Right,h Scroll right", -1);
1111 mvaddnstr(row
+ 8, col
+ 3, "? Toggle help window", -1);
1112 mvaddnstr(row
+ 9, col
+ 3, "q, Ctrl+C Quit", -1);
1114 attron(A_BOLD
| A_UNDERLINE
);
1115 mvaddnstr(row
+ 11, col
+ 2, "Display Settings", -1);
1116 attroff(A_BOLD
| A_UNDERLINE
);
1118 mvaddnstr(row
+ 13, col
+ 3, "b Toggle rate units (bits/bytes)", -1);
1119 mvaddnstr(row
+ 14, col
+ 3, "a Toggle display of active flows (rate > 0) only", -1);
1120 mvaddnstr(row
+ 15, col
+ 3, "s Toggle show source peer info", -1);
1122 mvaddnstr(row
+ 17, col
+ 3, "T Toggle display TCP flows", -1);
1123 mvaddnstr(row
+ 18, col
+ 3, "U Toggle display UDP flows", -1);
1124 mvaddnstr(row
+ 19, col
+ 3, "D Toggle display DCCP flows", -1);
1125 mvaddnstr(row
+ 20, col
+ 3, "I Toggle display ICMP flows", -1);
1126 mvaddnstr(row
+ 21, col
+ 3, "S Toggle display SCTP flows", -1);
1129 static void draw_header(WINDOW
*screen
)
1135 for (i
= 0; i
< cols
; i
++)
1138 mvwprintw(screen
, 0, 2, "flowtop %s", VERSION_LONG
);
1139 attroff(A_STANDOUT
);
1142 static void draw_footer(void)
1148 for (i
= 0; i
< cols
; i
++)
1149 mvaddch(rows
- 1, i
, ' ');
1151 mvaddnstr(rows
- 1, 1, "Press '?' for help", -1);
1153 attroff(A_STANDOUT
);
1156 static void show_option_toggle(int opt
)
1160 TOGGLE_FLAG(what
, INCLUDE_TCP
);
1163 TOGGLE_FLAG(what
, INCLUDE_UDP
);
1166 TOGGLE_FLAG(what
, INCLUDE_DCCP
);
1169 TOGGLE_FLAG(what
, INCLUDE_ICMP
);
1172 TOGGLE_FLAG(what
, INCLUDE_SCTP
);
1177 static void flows_table_init(struct ui_table
*tbl
)
1181 ui_table_pos_set(tbl
, 3, 0);
1182 ui_table_height_set(tbl
, LINES
- 3);
1184 ui_table_col_add(tbl
, TBL_FLOW_PROCESS
, "PROCESS", 13);
1185 ui_table_col_add(tbl
, TBL_FLOW_PID
, "PID", 7);
1186 ui_table_col_add(tbl
, TBL_FLOW_PROTO
, "PROTO", 6);
1187 ui_table_col_add(tbl
, TBL_FLOW_STATE
, "STATE", 11);
1188 ui_table_col_add(tbl
, TBL_FLOW_TIME
, "TIME", 4);
1189 ui_table_col_add(tbl
, TBL_FLOW_ADDRESS
, "ADDRESS", 50);
1190 ui_table_col_add(tbl
, TBL_FLOW_PORT
, "PORT", 8);
1191 ui_table_col_add(tbl
, TBL_FLOW_GEO
, "GEO", 3);
1192 ui_table_col_add(tbl
, TBL_FLOW_BYTES
, "BYTES", 10);
1193 ui_table_col_add(tbl
, TBL_FLOW_RATE
, "RATE", 10);
1195 ui_table_col_align_set(tbl
, TBL_FLOW_TIME
, UI_ALIGN_RIGHT
);
1196 ui_table_col_align_set(tbl
, TBL_FLOW_BYTES
, UI_ALIGN_RIGHT
);
1197 ui_table_col_align_set(tbl
, TBL_FLOW_RATE
, UI_ALIGN_RIGHT
);
1199 ui_table_col_color_set(tbl
, TBL_FLOW_PROCESS
, COLOR(YELLOW
, BLACK
));
1200 ui_table_col_color_set(tbl
, TBL_FLOW_PID
, A_BOLD
);
1201 ui_table_col_color_set(tbl
, TBL_FLOW_STATE
, COLOR(YELLOW
, BLACK
));
1203 ui_table_header_color_set(&flows_tbl
, COLOR(BLACK
, GREEN
));
1206 static void tab_main_on_open(struct ui_tab
*tab
, enum ui_tab_event_t evt
, uint32_t id
)
1208 draw_flows(screen
, &flow_list
, skip_lines
);
1211 static void presenter(void)
1213 bool show_help
= false;
1214 struct ui_tab
*tab_main
;
1216 lookup_init(LT_PORTS_TCP
);
1217 lookup_init(LT_PORTS_UDP
);
1219 screen
= screen_init(false);
1224 INIT_COLOR(RED
, BLACK
);
1225 INIT_COLOR(BLUE
, BLACK
);
1226 INIT_COLOR(YELLOW
, BLACK
);
1227 INIT_COLOR(GREEN
, BLACK
);
1228 INIT_COLOR(BLACK
, GREEN
);
1230 flows_table_init(&flows_tbl
);
1232 tab_main
= ui_tab_create();
1233 ui_tab_event_cb_set(tab_main
, tab_main_on_open
);
1234 ui_tab_pos_set(tab_main
, 2, 0);
1235 ui_tab_active_color_set(tab_main
, COLOR(BLACK
, GREEN
));
1236 ui_tab_entry_add(tab_main
, TAB_FLOWS
, "Flows");
1238 rcu_register_thread();
1243 getmaxyx(screen
, rows
, cols
);
1261 if (skip_lines
> SCROLL_MAX
)
1262 skip_lines
= SCROLL_MAX
;
1266 ui_table_event_send(&flows_tbl
, UI_EVT_SCROLL_LEFT
);
1270 ui_table_event_send(&flows_tbl
, UI_EVT_SCROLL_RIGHT
);
1273 if (rate_type
== RATE_BYTES
)
1274 rate_type
= RATE_BITS
;
1276 rate_type
= RATE_BYTES
;
1279 show_active_only
= !show_active_only
;
1282 show_src
= !show_src
;
1285 show_help
= !show_help
;
1294 show_option_toggle(ch
);
1295 do_reload_flows
= true;
1298 ui_tab_event_send(tab_main
, UI_EVT_SELECT_NEXT
);
1305 draw_header(screen
);
1310 ui_tab_show(tab_main
);
1314 rcu_unregister_thread();
1316 ui_table_uninit(&flows_tbl
);
1317 ui_tab_destroy(tab_main
);
1320 lookup_cleanup(LT_PORTS_UDP
);
1321 lookup_cleanup(LT_PORTS_TCP
);
1324 static void restore_sysctl(void *obj
)
1326 struct sysctl_params_ctx
*sysctl_ctx
= obj
;
1328 if (sysctl_ctx
->nfct_acct
== 0)
1329 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1330 sysctl_ctx
->nfct_acct
);
1332 if (sysctl_ctx
->nfct_tstamp
== 0)
1333 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1334 sysctl_ctx
->nfct_tstamp
);
1337 static void on_panic_handler(void *arg
)
1339 restore_sysctl(arg
);
1343 static void conntrack_acct_enable(void)
1345 /* We can still work w/o traffic accounting so just warn about error */
1346 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl
.nfct_acct
)) {
1347 fprintf(stderr
, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1352 if (sysctl
.nfct_acct
== 1)
1355 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1356 fprintf(stderr
, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1361 static void conntrack_tstamp_enable(void)
1363 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl
.nfct_tstamp
)) {
1364 fprintf(stderr
, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1369 if (sysctl
.nfct_tstamp
== 1)
1372 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1373 fprintf(stderr
, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1378 static void flow_entry_filter(struct flow_entry
*n
)
1380 if (show_active_only
&& !n
->rate_bytes_src
&& !n
->rate_bytes_dst
)
1381 n
->is_visible
= false;
1383 n
->is_visible
= true;
1386 static int flow_list_update_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
1388 struct flow_entry
*n
;
1390 n
= flow_list_find_id(fl
, nfct_get_attr_u32(ct
, ATTR_ID
));
1392 return NFCT_CB_CONTINUE
;
1394 flow_entry_calc_rate(n
, ct
);
1395 flow_entry_update_time(n
);
1396 flow_entry_from_ct(n
, ct
);
1397 flow_entry_filter(n
);
1399 return NFCT_CB_CONTINUE
;
1402 static int flow_event_cb(enum nf_conntrack_msg_type type
,
1403 struct nf_conntrack
*ct
, void *data __maybe_unused
)
1406 return NFCT_CB_STOP
;
1410 return flow_list_new_entry(&flow_list
, ct
);
1412 return flow_list_update_entry(&flow_list
, ct
);
1413 case NFCT_T_DESTROY
:
1414 return flow_list_del_entry(&flow_list
, ct
);
1416 return NFCT_CB_CONTINUE
;
1420 static void collector_refresh_flows(struct nfct_handle
*handle
)
1422 struct flow_entry
*n
;
1424 cds_list_for_each_entry_rcu(n
, &flow_list
.head
, entry
) {
1425 nfct_query(handle
, NFCT_Q_GET
, n
->ct
);
1429 static void collector_create_filter(struct nfct_handle
*nfct
)
1431 struct nfct_filter
*filter
;
1434 filter
= nfct_filter_create();
1436 panic("Cannot create a nfct filter: %s\n", strerror(errno
));
1438 if (what
& INCLUDE_UDP
) {
1439 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_UDP
);
1440 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_UDPLITE
);
1442 if (what
& INCLUDE_TCP
)
1443 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_TCP
);
1444 if (what
& INCLUDE_DCCP
)
1445 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_DCCP
);
1446 if (what
& INCLUDE_SCTP
)
1447 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_SCTP
);
1448 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV4
)
1449 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_ICMP
);
1450 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV6
)
1451 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_ICMPV6
);
1452 if (what
& INCLUDE_IPV4
) {
1453 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV4
, NFCT_FILTER_LOGIC_NEGATIVE
);
1454 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV4
, &filter_ipv4
);
1456 if (what
& INCLUDE_IPV6
) {
1457 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV6
, NFCT_FILTER_LOGIC_NEGATIVE
);
1458 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV6
, &filter_ipv6
);
1461 ret
= nfct_filter_attach(nfct_fd(nfct
), filter
);
1463 panic("Cannot attach filter to handle: %s\n", strerror(errno
));
1465 nfct_filter_destroy(filter
);
1468 /* This hand-crafted filter looks ugly but it allows to do not
1469 * flush nfct connections & filter them by user specified filter.
1470 * May be it is better to replace this one by nfct_cmp. */
1471 static int flow_dump_cb(enum nf_conntrack_msg_type type __maybe_unused
,
1472 struct nf_conntrack
*ct
, void *data __maybe_unused
)
1474 struct flow_entry fl
;
1475 struct flow_entry
*n
= &fl
;
1478 return NFCT_CB_STOP
;
1480 if (!(what
& ~(INCLUDE_IPV4
| INCLUDE_IPV6
)))
1483 CP_NFCT(l4_proto
, ATTR_ORIG_L4PROTO
, 8);
1485 if (what
& INCLUDE_UDP
) {
1486 if (n
->l4_proto
== IPPROTO_UDP
)
1489 if (n
->l4_proto
== IPPROTO_UDPLITE
)
1493 if ((what
& INCLUDE_TCP
) && n
->l4_proto
== IPPROTO_TCP
)
1496 if ((what
& INCLUDE_DCCP
) && n
->l4_proto
== IPPROTO_DCCP
)
1499 if ((what
& INCLUDE_SCTP
) && n
->l4_proto
== IPPROTO_SCTP
)
1502 if ((what
& INCLUDE_ICMP
) && (what
& INCLUDE_IPV4
) &&
1503 n
->l4_proto
== IPPROTO_ICMP
) {
1507 if ((what
& INCLUDE_ICMP
) && (what
& INCLUDE_IPV6
) &&
1508 n
->l4_proto
== IPPROTO_ICMPV6
) {
1515 /* filter loopback addresses */
1516 if (what
& INCLUDE_IPV4
) {
1517 CP_NFCT(ip4_src_addr
, ATTR_ORIG_IPV4_SRC
, 32);
1519 if (n
->ip4_src_addr
== filter_ipv4
.addr
)
1522 if (what
& INCLUDE_IPV6
) {
1523 CP_NFCT_BUFF(ip6_src_addr
, ATTR_ORIG_IPV6_SRC
);
1525 if (n
->ip6_src_addr
[0] == 0x0 &&
1526 n
->ip6_src_addr
[1] == 0x0 &&
1527 n
->ip6_src_addr
[2] == 0x0 &&
1528 n
->ip6_src_addr
[3] == 0x1)
1532 return flow_list_new_entry(&flow_list
, ct
);
1535 return NFCT_CB_CONTINUE
;
1538 static void collector_dump_flows(void)
1540 struct nfct_handle
*nfct
= nfct_open(CONNTRACK
, 0);
1543 panic("Cannot create a nfct handle: %s\n", strerror(errno
));
1545 nfct_callback_register(nfct
, NFCT_T_ALL
, flow_dump_cb
, NULL
);
1547 is_flow_collecting
= true;
1548 if (what
& INCLUDE_IPV4
) {
1549 int family
= AF_INET
;
1550 nfct_query(nfct
, NFCT_Q_DUMP
, &family
);
1552 if (what
& INCLUDE_IPV6
) {
1553 int family
= AF_INET6
;
1554 nfct_query(nfct
, NFCT_Q_DUMP
, &family
);
1556 is_flow_collecting
= false;
1561 static void *collector(void *null __maybe_unused
)
1563 struct nfct_handle
*ct_event
;
1564 struct pollfd poll_fd
[1];
1566 flow_list_init(&flow_list
);
1568 ct_event
= nfct_open(CONNTRACK
, NF_NETLINK_CONNTRACK_NEW
|
1569 NF_NETLINK_CONNTRACK_UPDATE
|
1570 NF_NETLINK_CONNTRACK_DESTROY
);
1572 panic("Cannot create a nfct handle: %s\n", strerror(errno
));
1574 collector_create_filter(ct_event
);
1576 nfct_callback_register(ct_event
, NFCT_T_ALL
, flow_event_cb
, NULL
);
1578 poll_fd
[0].fd
= nfct_fd(ct_event
);
1579 poll_fd
[0].events
= POLLIN
;
1581 if (fcntl(nfct_fd(ct_event
), F_SETFL
, O_NONBLOCK
) == -1)
1582 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1585 rcu_register_thread();
1587 collector_dump_flows();
1592 if (!do_reload_flows
) {
1593 usleep(USEC_PER_SEC
* interval
);
1595 do_reload_flows
= false;
1597 flow_list_destroy(&flow_list
);
1599 collector_create_filter(ct_event
);
1600 collector_dump_flows();
1603 collector_refresh_flows(ct_event
);
1605 status
= poll(poll_fd
, 1, 0);
1607 if (errno
== EAGAIN
|| errno
== EINTR
)
1610 panic("Error while polling: %s\n", strerror(errno
));
1611 } else if (status
!= 0) {
1612 if (poll_fd
[0].revents
& POLLIN
)
1613 nfct_catch(ct_event
);
1617 flow_list_destroy(&flow_list
);
1619 rcu_unregister_thread();
1621 nfct_close(ct_event
);
1626 int main(int argc
, char **argv
)
1629 int ret
, c
, what_cmd
= 0;
1634 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
1638 what_cmd
|= INCLUDE_IPV4
;
1641 what_cmd
|= INCLUDE_IPV6
;
1644 what_cmd
|= INCLUDE_TCP
;
1647 what_cmd
|= INCLUDE_UDP
;
1650 what_cmd
|= INCLUDE_DCCP
;
1653 what_cmd
|= INCLUDE_ICMP
;
1656 what_cmd
|= INCLUDE_SCTP
;
1662 rate_type
= RATE_BITS
;
1669 interval
= strtoul(optarg
, NULL
, 10);
1672 resolve_dns
= false;
1675 resolve_geoip
= false;
1691 if (!(what
& (INCLUDE_IPV4
| INCLUDE_IPV6
)))
1692 what
|= INCLUDE_IPV4
| INCLUDE_IPV6
;
1697 register_signal(SIGINT
, signal_handler
);
1698 register_signal(SIGQUIT
, signal_handler
);
1699 register_signal(SIGTERM
, signal_handler
);
1700 register_signal(SIGHUP
, signal_handler
);
1702 panic_handler_add(on_panic_handler
, &sysctl
);
1704 conntrack_acct_enable();
1705 conntrack_tstamp_enable();
1710 ret
= pthread_create(&tid
, NULL
, collector
, NULL
);
1712 panic("Cannot create phthread!\n");
1719 restore_sysctl(&sysctl
);