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>
23 #include <sys/fsuid.h>
29 #include <arpa/inet.h>
34 #include "conntrack.h"
48 #define NSEC_PER_SEC 1000000000L
52 #define USEC_PER_SEC 1000000L
56 uint32_t flow_id
, use
, status
;
57 uint8_t l3_proto
, l4_proto
;
58 uint32_t ip4_src_addr
, ip4_dst_addr
;
59 uint32_t ip6_src_addr
[4], ip6_dst_addr
[4];
60 uint16_t port_src
, port_dst
;
61 uint8_t tcp_state
, tcp_flags
, sctp_state
, dccp_state
;
62 uint64_t pkts_src
, bytes_src
;
63 uint64_t pkts_dst
, bytes_dst
;
64 uint64_t timestamp_start
, timestamp_stop
;
65 char country_src
[128], country_dst
[128];
66 char country_code_src
[4], country_code_dst
[4];
67 char city_src
[128], city_dst
[128];
68 char rev_dns_src
[256], rev_dns_dst
[256];
70 struct flow_entry
*next
;
74 struct nf_conntrack
*ct
;
75 struct timeval last_update
;
76 double rate_bytes_src
;
77 double rate_bytes_dst
;
83 struct flow_entry
*head
;
92 #ifndef ATTR_TIMESTAMP_START
93 # define ATTR_TIMESTAMP_START 63
95 #ifndef ATTR_TIMESTAMP_STOP
96 # define ATTR_TIMESTAMP_STOP 64
99 #define SCROLL_MAX 1000
101 #define INCLUDE_IPV4 (1 << 0)
102 #define INCLUDE_IPV6 (1 << 1)
103 #define INCLUDE_UDP (1 << 2)
104 #define INCLUDE_TCP (1 << 3)
105 #define INCLUDE_DCCP (1 << 4)
106 #define INCLUDE_ICMP (1 << 5)
107 #define INCLUDE_SCTP (1 << 6)
109 #define TOGGLE_FLAG(what, flag) \
117 struct sysctl_params_ctx
{
127 static volatile bool do_reload_flows
;
128 static volatile bool is_flow_collecting
;
129 static volatile sig_atomic_t sigint
= 0;
130 static int what
= INCLUDE_IPV4
| INCLUDE_IPV6
| INCLUDE_TCP
;
131 static struct flow_list flow_list
;
132 static struct sysctl_params_ctx sysctl
= { -1, -1 };
134 static unsigned int cols
, rows
;
136 static unsigned int interval
= 1;
137 static bool show_src
= false;
138 static bool resolve_dns
= true;
139 static bool resolve_geoip
= true;
140 static enum rate_units rate_type
= RATE_BYTES
;
141 static bool show_active_only
= false;
156 static struct ui_table flows_tbl
;
158 static const char *short_options
= "vhTUsDIS46ut:nGb";
159 static const struct option long_options
[] = {
160 {"ipv4", no_argument
, NULL
, '4'},
161 {"ipv6", no_argument
, NULL
, '6'},
162 {"tcp", no_argument
, NULL
, 'T'},
163 {"udp", no_argument
, NULL
, 'U'},
164 {"dccp", no_argument
, NULL
, 'D'},
165 {"icmp", no_argument
, NULL
, 'I'},
166 {"sctp", no_argument
, NULL
, 'S'},
167 {"no-dns", no_argument
, NULL
, 'n'},
168 {"no-geoip", no_argument
, NULL
, 'G'},
169 {"show-src", no_argument
, NULL
, 's'},
170 {"bits", no_argument
, NULL
, 'b'},
171 {"update", no_argument
, NULL
, 'u'},
172 {"interval", required_argument
, NULL
, 't'},
173 {"version", no_argument
, NULL
, 'v'},
174 {"help", no_argument
, NULL
, 'h'},
178 static const char *copyright
= "Please report bugs to <netsniff-ng@googlegroups.com>\n"
179 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>\n"
180 "Copyright (C) 2011-2012 Emmanuel Roullit <emmanuel.roullit@gmail.com>\n"
181 "Swiss federal institute of technology (ETH Zurich)\n"
182 "License: GNU GPL version 2.0\n"
183 "This is free software: you are free to change and redistribute it.\n"
184 "There is NO WARRANTY, to the extent permitted by law.";
186 static const char *const l4proto2str
[IPPROTO_MAX
] = {
187 [IPPROTO_TCP
] = "tcp",
188 [IPPROTO_UDP
] = "udp",
189 [IPPROTO_UDPLITE
] = "udplite",
190 [IPPROTO_ICMP
] = "icmp",
191 [IPPROTO_ICMPV6
] = "icmpv6",
192 [IPPROTO_SCTP
] = "sctp",
193 [IPPROTO_GRE
] = "gre",
194 [IPPROTO_DCCP
] = "dccp",
195 [IPPROTO_IGMP
] = "igmp",
196 [IPPROTO_IPIP
] = "ipip",
197 [IPPROTO_EGP
] = "egp",
198 [IPPROTO_PUP
] = "pup",
199 [IPPROTO_IDP
] = "idp",
200 [IPPROTO_RSVP
] = "rsvp",
201 [IPPROTO_IPV6
] = "ip6tun",
202 [IPPROTO_ESP
] = "esp",
204 [IPPROTO_PIM
] = "pim",
205 [IPPROTO_COMP
] = "comp",
208 static const char *const tcp_state2str
[TCP_CONNTRACK_MAX
] = {
209 [TCP_CONNTRACK_NONE
] = "NONE",
210 [TCP_CONNTRACK_SYN_SENT
] = "SYN-SENT",
211 [TCP_CONNTRACK_SYN_RECV
] = "SYN-RECV",
212 [TCP_CONNTRACK_ESTABLISHED
] = "ESTABLISHED",
213 [TCP_CONNTRACK_FIN_WAIT
] = "FIN-WAIT",
214 [TCP_CONNTRACK_CLOSE_WAIT
] = "CLOSE-WAIT",
215 [TCP_CONNTRACK_LAST_ACK
] = "LAST-ACK",
216 [TCP_CONNTRACK_TIME_WAIT
] = "TIME-WAIT",
217 [TCP_CONNTRACK_CLOSE
] = "CLOSE",
218 [TCP_CONNTRACK_SYN_SENT2
] = "SYN-SENT2",
221 static const char *const dccp_state2str
[DCCP_CONNTRACK_MAX
] = {
222 [DCCP_CONNTRACK_NONE
] = "NONE",
223 [DCCP_CONNTRACK_REQUEST
] = "REQUEST",
224 [DCCP_CONNTRACK_RESPOND
] = "RESPOND",
225 [DCCP_CONNTRACK_PARTOPEN
] = "PARTOPEN",
226 [DCCP_CONNTRACK_OPEN
] = "OPEN",
227 [DCCP_CONNTRACK_CLOSEREQ
] = "CLOSE-REQ",
228 [DCCP_CONNTRACK_CLOSING
] = "CLOSING",
229 [DCCP_CONNTRACK_TIMEWAIT
] = "TIME-WAIT",
230 [DCCP_CONNTRACK_IGNORE
] = "IGNORE",
231 [DCCP_CONNTRACK_INVALID
] = "INVALID",
234 static const char *const sctp_state2str
[SCTP_CONNTRACK_MAX
] = {
235 [SCTP_CONNTRACK_NONE
] = "NONE",
236 [SCTP_CONNTRACK_CLOSED
] = "CLOSED",
237 [SCTP_CONNTRACK_COOKIE_WAIT
] = "COOKIE-WAIT",
238 [SCTP_CONNTRACK_COOKIE_ECHOED
] = "COOKIE-ECHO",
239 [SCTP_CONNTRACK_ESTABLISHED
] = "ESTABLISHED",
240 [SCTP_CONNTRACK_SHUTDOWN_SENT
] = "SHUTD-SENT",
241 [SCTP_CONNTRACK_SHUTDOWN_RECD
] = "SHUTD-RCVD",
242 [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
] = "SHUTD-ACK",
245 static const struct nfct_filter_ipv4 filter_ipv4
= {
246 .addr
= __constant_htonl(INADDR_LOOPBACK
),
250 static const struct nfct_filter_ipv6 filter_ipv6
= {
251 .addr
= { 0x0, 0x0, 0x0, 0x1 },
252 .mask
= { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
255 static int64_t time_after_us(struct timeval
*tv
)
259 bug_on(gettimeofday(&now
, NULL
));
261 now
.tv_sec
-= tv
->tv_sec
;
262 now
.tv_usec
-= tv
->tv_usec
;
264 return now
.tv_sec
* USEC_PER_SEC
+ now
.tv_usec
;
267 static void signal_handler(int number
)
281 static void flow_entry_from_ct(struct flow_entry
*n
, const struct nf_conntrack
*ct
);
282 static void flow_entry_get_extended(struct flow_entry
*n
);
284 static void help(void)
286 printf("flowtop %s, top-like netfilter TCP/UDP/SCTP/.. flow tracking\n",
288 puts("http://www.netsniff-ng.org\n\n"
289 "Usage: flowtop [options]\n"
291 " -4|--ipv4 Show only IPv4 flows (default)\n"
292 " -6|--ipv6 Show only IPv6 flows (default)\n"
293 " -T|--tcp Show only TCP flows (default)\n"
294 " -U|--udp Show only UDP flows\n"
295 " -D|--dccp Show only DCCP flows\n"
296 " -I|--icmp Show only ICMP/ICMPv6 flows\n"
297 " -S|--sctp Show only SCTP flows\n"
298 " -n|--no-dns Don't perform hostname lookup\n"
299 " -G|--no-geoip Don't perform GeoIP lookup\n"
300 " -s|--show-src Also show source, not only dest\n"
301 " -b|--bits Show rates in bits/s instead of bytes/s\n"
302 " -u|--update Update GeoIP databases\n"
303 " -t|--interval <time> Refresh time in seconds (default 1s)\n"
304 " -v|--version Print version and exit\n"
305 " -h|--help Print this help and exit\n\n"
308 " flowtop -46UTDISs\n\n"
310 " If netfilter is not running, you can activate it with e.g.:\n"
311 " iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT\n"
312 " iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT\n");
317 static void version(void)
319 printf("flowtop %s, Git id: %s\n", VERSION_LONG
, GITVERSION
);
320 puts("top-like netfilter TCP/UDP/SCTP/.. flow tracking\n"
321 "http://www.netsniff-ng.org\n");
326 static void flow_entry_update_time(struct flow_entry
*n
)
328 bug_on(gettimeofday(&n
->last_update
, NULL
));
331 #define CALC_RATE(fld) do { \
332 n->rate_##fld = (((fld) > n->fld) ? (((fld) - n->fld) / sec) : 0); \
335 static void flow_entry_calc_rate(struct flow_entry
*n
, const struct nf_conntrack
*ct
)
337 uint64_t bytes_src
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_BYTES
);
338 uint64_t bytes_dst
= nfct_get_attr_u64(ct
, ATTR_REPL_COUNTER_BYTES
);
339 uint64_t pkts_src
= nfct_get_attr_u64(ct
, ATTR_ORIG_COUNTER_PACKETS
);
340 uint64_t pkts_dst
= nfct_get_attr_u64(ct
, ATTR_REPL_COUNTER_PACKETS
);
341 double sec
= (double)time_after_us(&n
->last_update
) / USEC_PER_SEC
;
346 CALC_RATE(bytes_src
);
347 CALC_RATE(bytes_dst
);
352 static inline struct flow_entry
*flow_entry_xalloc(void)
354 return xzmalloc(sizeof(struct flow_entry
));
357 static inline void flow_entry_xfree(struct flow_entry
*n
)
365 static inline void flow_list_init(struct flow_list
*fl
)
368 spinlock_init(&fl
->lock
);
371 static inline bool nfct_is_dns(const struct nf_conntrack
*ct
)
373 uint16_t port_src
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_SRC
);
374 uint16_t port_dst
= nfct_get_attr_u16(ct
, ATTR_ORIG_PORT_DST
);
376 return ntohs(port_src
) == 53 || ntohs(port_dst
) == 53;
379 static void flow_list_new_entry(struct flow_list
*fl
, const struct nf_conntrack
*ct
)
381 struct flow_entry
*n
;
383 /* We don't want to analyze / display DNS itself, since we
384 * use it to resolve reverse dns.
389 n
= flow_entry_xalloc();
391 n
->ct
= nfct_clone(ct
);
393 flow_entry_update_time(n
);
394 flow_entry_from_ct(n
, ct
);
395 flow_entry_get_extended(n
);
397 rcu_assign_pointer(n
->next
, fl
->head
);
398 rcu_assign_pointer(fl
->head
, n
);
400 n
->is_visible
= true;
403 static struct flow_entry
*flow_list_find_id(struct flow_list
*fl
,
406 struct flow_entry
*n
= rcu_dereference(fl
->head
);
409 if (n
->flow_id
== id
)
412 n
= rcu_dereference(n
->next
);
418 static struct flow_entry
*flow_list_find_prev_id(const struct flow_list
*fl
,
421 struct flow_entry
*prev
= rcu_dereference(fl
->head
), *next
;
423 if (prev
->flow_id
== id
)
426 while ((next
= rcu_dereference(prev
->next
)) != NULL
) {
427 if (next
->flow_id
== id
)
436 static void flow_list_destroy_entry(struct flow_list
*fl
,
437 const struct nf_conntrack
*ct
)
439 struct flow_entry
*n1
, *n2
;
440 uint32_t id
= nfct_get_attr_u32(ct
, ATTR_ID
);
442 n1
= flow_list_find_id(fl
, id
);
444 n2
= flow_list_find_prev_id(fl
, id
);
446 rcu_assign_pointer(n2
->next
, n1
->next
);
449 flow_entry_xfree(n1
);
451 struct flow_entry
*next
= fl
->head
->next
;
453 flow_entry_xfree(fl
->head
);
459 static void flow_list_destroy(struct flow_list
*fl
)
461 struct flow_entry
*n
;
464 spinlock_lock(&flow_list
.lock
);
466 while (fl
->head
!= NULL
) {
467 n
= rcu_dereference(fl
->head
->next
);
468 fl
->head
->next
= NULL
;
470 flow_entry_xfree(fl
->head
);
471 rcu_assign_pointer(fl
->head
, n
);
474 spinlock_unlock(&flow_list
.lock
);
477 static int walk_process(unsigned int pid
, struct flow_entry
*n
)
484 if (snprintf(path
, sizeof(path
), "/proc/%u/fd", pid
) == -1)
485 panic("giant process name! %u\n", pid
);
491 while ((ent
= readdir(dir
))) {
494 if (snprintf(path
, sizeof(path
), "/proc/%u/fd/%s",
495 pid
, ent
->d_name
) < 0)
498 if (stat(path
, &statbuf
) < 0)
501 if (S_ISSOCK(statbuf
.st_mode
) && (ino_t
) n
->inode
== statbuf
.st_ino
) {
504 ret
= proc_get_cmdline(pid
, cmdline
, sizeof(cmdline
));
506 panic("Failed to get process cmdline: %s\n", strerror(errno
));
508 if (snprintf(n
->procname
, sizeof(n
->procname
), "%s", basename(cmdline
)) < 0)
509 n
->procname
[0] = '\0';
520 static void walk_processes(struct flow_entry
*n
)
526 /* n->inode must be set */
528 n
->procname
[0] = '\0';
532 dir
= opendir("/proc");
534 panic("Cannot open /proc: %s\n", strerror(errno
));
536 while ((ent
= readdir(dir
))) {
537 const char *name
= ent
->d_name
;
539 unsigned int pid
= strtoul(name
, &end
, 10);
542 if (pid
== 0 && end
== name
)
545 ret
= walk_process(pid
, n
);
553 static int get_port_inode(uint16_t port
, int proto
, bool is_ip6
)
556 char path
[128], buff
[1024];
559 memset(path
, 0, sizeof(path
));
560 snprintf(path
, sizeof(path
), "/proc/net/%s%s",
561 l4proto2str
[proto
], is_ip6
? "6" : "");
563 proc
= fopen(path
, "r");
567 memset(buff
, 0, sizeof(buff
));
569 while (fgets(buff
, sizeof(buff
), proc
) != NULL
) {
571 unsigned int lport
= 0;
573 buff
[sizeof(buff
) - 1] = 0;
574 if (sscanf(buff
, "%*u: %*X:%X %*X:%*X %*X %*X:%*X %*X:%*X "
575 "%*X %*u %*u %u", &lport
, &inode
) == 2) {
576 if ((uint16_t) lport
== port
) {
582 memset(buff
, 0, sizeof(buff
));
589 #define CP_NFCT(elem, attr, x) \
590 do { n->elem = nfct_get_attr_u##x(ct,(attr)); } while (0)
591 #define CP_NFCT_BUFF(elem, attr) do { \
592 const uint8_t *buff = nfct_get_attr(ct,(attr)); \
594 memcpy(n->elem, buff, sizeof(n->elem)); \
597 static void flow_entry_from_ct(struct flow_entry
*n
, const struct nf_conntrack
*ct
)
599 CP_NFCT(l3_proto
, ATTR_ORIG_L3PROTO
, 8);
600 CP_NFCT(l4_proto
, ATTR_ORIG_L4PROTO
, 8);
602 CP_NFCT(ip4_src_addr
, ATTR_ORIG_IPV4_SRC
, 32);
603 CP_NFCT(ip4_dst_addr
, ATTR_ORIG_IPV4_DST
, 32);
605 CP_NFCT(port_src
, ATTR_ORIG_PORT_SRC
, 16);
606 CP_NFCT(port_dst
, ATTR_ORIG_PORT_DST
, 16);
608 CP_NFCT(status
, ATTR_STATUS
, 32);
610 CP_NFCT(tcp_state
, ATTR_TCP_STATE
, 8);
611 CP_NFCT(tcp_flags
, ATTR_TCP_FLAGS_ORIG
, 8);
612 CP_NFCT(sctp_state
, ATTR_SCTP_STATE
, 8);
613 CP_NFCT(dccp_state
, ATTR_DCCP_STATE
, 8);
615 CP_NFCT(pkts_src
, ATTR_ORIG_COUNTER_PACKETS
, 64);
616 CP_NFCT(bytes_src
, ATTR_ORIG_COUNTER_BYTES
, 64);
618 CP_NFCT(pkts_dst
, ATTR_REPL_COUNTER_PACKETS
, 64);
619 CP_NFCT(bytes_dst
, ATTR_REPL_COUNTER_BYTES
, 64);
621 CP_NFCT(timestamp_start
, ATTR_TIMESTAMP_START
, 64);
622 CP_NFCT(timestamp_stop
, ATTR_TIMESTAMP_STOP
, 64);
624 CP_NFCT(flow_id
, ATTR_ID
, 32);
625 CP_NFCT(use
, ATTR_USE
, 32);
627 CP_NFCT_BUFF(ip6_src_addr
, ATTR_ORIG_IPV6_SRC
);
628 CP_NFCT_BUFF(ip6_dst_addr
, ATTR_ORIG_IPV6_DST
);
630 n
->port_src
= ntohs(n
->port_src
);
631 n
->port_dst
= ntohs(n
->port_dst
);
633 n
->ip4_src_addr
= ntohl(n
->ip4_src_addr
);
634 n
->ip4_dst_addr
= ntohl(n
->ip4_dst_addr
);
637 #define SELFLD(dir,src_member,dst_member) \
638 (((dir) == FLOW_DIR_SRC) ? n->src_member : n->dst_member)
640 static void flow_entry_get_sain4_obj(const struct flow_entry
*n
,
641 enum flow_direction dir
,
642 struct sockaddr_in
*sa
)
644 memset(sa
, 0, sizeof(*sa
));
645 sa
->sin_family
= PF_INET
;
646 sa
->sin_addr
.s_addr
= htonl(SELFLD(dir
, ip4_src_addr
, ip4_dst_addr
));
649 static void flow_entry_get_sain6_obj(const struct flow_entry
*n
,
650 enum flow_direction dir
,
651 struct sockaddr_in6
*sa
)
653 memset(sa
, 0, sizeof(*sa
));
654 sa
->sin6_family
= PF_INET6
;
656 memcpy(&sa
->sin6_addr
, SELFLD(dir
, ip6_src_addr
, ip6_dst_addr
),
657 sizeof(sa
->sin6_addr
));
661 flow_entry_geo_city_lookup_generic(struct flow_entry
*n
,
662 enum flow_direction dir
)
664 struct sockaddr_in sa4
;
665 struct sockaddr_in6 sa6
;
666 const char *city
= NULL
;
668 switch (n
->l3_proto
) {
673 flow_entry_get_sain4_obj(n
, dir
, &sa4
);
674 city
= geoip4_city_name(&sa4
);
678 flow_entry_get_sain6_obj(n
, dir
, &sa6
);
679 city
= geoip6_city_name(&sa6
);
683 build_bug_on(sizeof(n
->city_src
) != sizeof(n
->city_dst
));
686 strlcpy(SELFLD(dir
, city_src
, city_dst
), city
,
687 sizeof(n
->city_src
));
689 SELFLD(dir
, city_src
, city_dst
)[0] = '\0';
693 flow_entry_geo_country_lookup_generic(struct flow_entry
*n
,
694 enum flow_direction dir
)
696 struct sockaddr_in sa4
;
697 struct sockaddr_in6 sa6
;
698 const char *country
= NULL
;
699 const char *country_code
= NULL
;
701 switch (n
->l3_proto
) {
706 flow_entry_get_sain4_obj(n
, dir
, &sa4
);
707 country
= geoip4_country_name(&sa4
);
708 country_code
= geoip4_country_code3_name(&sa4
);
712 flow_entry_get_sain6_obj(n
, dir
, &sa6
);
713 country
= geoip6_country_name(&sa6
);
714 country_code
= geoip6_country_code3_name(&sa6
);
718 build_bug_on(sizeof(n
->country_src
) != sizeof(n
->country_dst
));
721 strlcpy(SELFLD(dir
, country_src
, country_dst
), country
,
722 sizeof(n
->country_src
));
724 SELFLD(dir
, country_src
, country_dst
)[0] = '\0';
726 build_bug_on(sizeof(n
->country_code_src
) != sizeof(n
->country_code_dst
));
729 strlcpy(SELFLD(dir
, country_code_src
, country_code_dst
),
730 country_code
, sizeof(n
->country_code_src
));
732 SELFLD(dir
, country_code_src
, country_code_dst
)[0] = '\0';
735 static void flow_entry_get_extended_geo(struct flow_entry
*n
,
736 enum flow_direction dir
)
739 flow_entry_geo_city_lookup_generic(n
, dir
);
740 flow_entry_geo_country_lookup_generic(n
, dir
);
744 static void flow_entry_get_extended_revdns(struct flow_entry
*n
,
745 enum flow_direction dir
)
748 struct sockaddr_in sa4
;
749 struct sockaddr_in6 sa6
;
751 struct hostent
*hent
;
753 build_bug_on(sizeof(n
->rev_dns_src
) != sizeof(n
->rev_dns_dst
));
755 switch (n
->l3_proto
) {
760 flow_entry_get_sain4_obj(n
, dir
, &sa4
);
763 inet_ntop(AF_INET
, &sa4
.sin_addr
,
764 SELFLD(dir
, rev_dns_src
, rev_dns_dst
),
765 sizeof(n
->rev_dns_src
));
769 sa
= (struct sockaddr
*) &sa4
;
770 sa_len
= sizeof(sa4
);
771 hent
= gethostbyaddr(&sa4
.sin_addr
, sizeof(sa4
.sin_addr
), AF_INET
);
775 flow_entry_get_sain6_obj(n
, dir
, &sa6
);
778 inet_ntop(AF_INET6
, &sa6
.sin6_addr
,
779 SELFLD(dir
, rev_dns_src
, rev_dns_dst
),
780 sizeof(n
->rev_dns_src
));
784 sa
= (struct sockaddr
*) &sa6
;
785 sa_len
= sizeof(sa6
);
786 hent
= gethostbyaddr(&sa6
.sin6_addr
, sizeof(sa6
.sin6_addr
), AF_INET6
);
790 getnameinfo(sa
, sa_len
, SELFLD(dir
, rev_dns_src
, rev_dns_dst
),
791 sizeof(n
->rev_dns_src
), NULL
, 0, NI_NUMERICHOST
);
794 strlcpy(SELFLD(dir
, rev_dns_src
, rev_dns_dst
), hent
->h_name
,
795 sizeof(n
->rev_dns_src
));
798 static void flow_entry_get_extended(struct flow_entry
*n
)
803 flow_entry_get_extended_revdns(n
, FLOW_DIR_SRC
);
804 flow_entry_get_extended_geo(n
, FLOW_DIR_SRC
);
806 flow_entry_get_extended_revdns(n
, FLOW_DIR_DST
);
807 flow_entry_get_extended_geo(n
, FLOW_DIR_DST
);
809 /* Lookup application */
810 n
->inode
= get_port_inode(n
->port_src
, n
->l4_proto
,
811 n
->l3_proto
== AF_INET6
);
816 static char *bandw2str(double bytes
, char *buf
, size_t len
)
823 if (bytes
> 1000000000.)
824 snprintf(buf
, len
, "%.1fGB", bytes
/ 1000000000.);
825 else if (bytes
> 1000000.)
826 snprintf(buf
, len
, "%.1fMB", bytes
/ 1000000.);
827 else if (bytes
> 1000.)
828 snprintf(buf
, len
, "%.1fkB", bytes
/ 1000.);
830 snprintf(buf
, len
, "%.0f", bytes
);
835 static char *rate2str(double rate
, char *buf
, size_t len
)
837 const char * const unit_fmt
[2][4] = {
838 { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%.0fbit/s" },
839 { "%.1fGB/s", "%.1fMB/s", "%.1fkB/s", "%.0fB/s" }
847 if (rate_type
== RATE_BITS
)
850 if (rate
> 1000000000.)
851 snprintf(buf
, len
, unit_fmt
[rate_type
][0], rate
/ 1000000000.);
852 else if (rate
> 1000000.)
853 snprintf(buf
, len
, unit_fmt
[rate_type
][1], rate
/ 1000000.);
854 else if (rate
> 1000.)
855 snprintf(buf
, len
, unit_fmt
[rate_type
][2], rate
/ 1000.);
857 snprintf(buf
, len
, unit_fmt
[rate_type
][3], rate
);
862 static char *time2str(uint64_t tstamp
, char *str
, size_t len
)
869 s
= now
- (tstamp
? (tstamp
/ NSEC_PER_SEC
) : now
);
877 slprintf(str
, len
, "%dd", v
);
883 slprintf(str
, len
, "%dh", v
);
889 slprintf(str
, len
, "%dm", v
);
893 slprintf(str
, len
, "%ds", s
);
898 static const char *flow_state2str(const struct flow_entry
*n
)
900 switch (n
->l4_proto
) {
902 return tcp_state2str
[n
->tcp_state
];
904 return sctp_state2str
[n
->sctp_state
];
906 return dccp_state2str
[n
->dccp_state
];
909 case IPPROTO_UDPLITE
:
917 static char *flow_port2str(const struct flow_entry
*n
, char *str
, size_t len
,
918 enum flow_direction dir
)
920 const char *tmp
= NULL
;
923 port
= SELFLD(dir
, port_src
, port_dst
);
926 switch (n
->l4_proto
) {
928 tmp
= lookup_port_tcp(port
);
931 case IPPROTO_UDPLITE
:
932 tmp
= lookup_port_udp(port
);
937 slprintf(str
, len
, "%d", port
);
939 slprintf(str
, len
, "%s", tmp
? tmp
: "");
944 static void print_flow_peer_info(const struct flow_entry
*n
, enum flow_direction dir
)
946 int counters_color
= COLOR(YELLOW
, BLACK
);
947 int src_color
= COLOR(RED
, BLACK
);
948 int dst_color
= COLOR(BLUE
, BLACK
);
949 int country_color
= COLOR(GREEN
, BLACK
);
950 int addr_color
= dst_color
;
951 int port_color
= A_BOLD
;
954 if (show_src
&& dir
== FLOW_DIR_SRC
) {
955 country_color
= src_color
;
956 counters_color
= src_color
;
957 port_color
|= src_color
;
958 addr_color
= src_color
;
959 } else if (show_src
&& FLOW_DIR_DST
) {
960 country_color
= dst_color
;
961 counters_color
= dst_color
;
962 port_color
|= dst_color
;
963 addr_color
= dst_color
;
966 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_ADDRESS
, addr_color
);
967 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_PORT
, port_color
);
968 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_GEO
, country_color
);
969 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_BYTES
, counters_color
);
970 ui_table_col_color_set(&flows_tbl
, TBL_FLOW_RATE
, counters_color
);
973 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_ADDRESS
,
974 SELFLD(dir
, rev_dns_src
, rev_dns_dst
));
976 /* Application port */
977 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PORT
,
978 flow_port2str(n
, tmp
, sizeof(tmp
), dir
));
981 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_GEO
,
982 SELFLD(dir
, country_code_src
, country_code_dst
));
985 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_BYTES
,
986 bandw2str(SELFLD(dir
, bytes_src
, bytes_dst
),
987 tmp
, sizeof(tmp
) - 1));
990 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_RATE
,
991 rate2str(SELFLD(dir
, rate_bytes_src
, rate_bytes_dst
),
992 tmp
, sizeof(tmp
) - 1));
995 static void draw_flow_entry(const struct flow_entry
*n
)
999 ui_table_row_add(&flows_tbl
);
1002 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PROCESS
, n
->procname
);
1005 slprintf(tmp
, sizeof(tmp
), "%.d", n
->procnum
);
1006 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PID
, tmp
);
1009 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PROTO
, l4proto2str
[n
->l4_proto
]);
1011 /* L4 protocol state */
1012 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_STATE
, flow_state2str(n
));
1015 time2str(n
->timestamp_start
, tmp
, sizeof(tmp
));
1016 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_TIME
, tmp
);
1018 print_flow_peer_info(n
, show_src
? FLOW_DIR_SRC
: FLOW_DIR_DST
);
1020 ui_table_row_show(&flows_tbl
);
1023 ui_table_row_add(&flows_tbl
);
1025 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PROCESS
, "");
1026 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PID
, "");
1027 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_PROTO
, "");
1028 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_STATE
, "");
1029 ui_table_row_col_set(&flows_tbl
, TBL_FLOW_TIME
, "");
1031 print_flow_peer_info(n
, FLOW_DIR_DST
);
1032 ui_table_row_show(&flows_tbl
);
1036 static inline bool presenter_flow_wrong_state(struct flow_entry
*n
)
1038 switch (n
->l4_proto
) {
1040 switch (n
->tcp_state
) {
1041 case TCP_CONNTRACK_SYN_SENT
:
1042 case TCP_CONNTRACK_SYN_RECV
:
1043 case TCP_CONNTRACK_ESTABLISHED
:
1044 case TCP_CONNTRACK_FIN_WAIT
:
1045 case TCP_CONNTRACK_CLOSE_WAIT
:
1046 case TCP_CONNTRACK_LAST_ACK
:
1047 case TCP_CONNTRACK_TIME_WAIT
:
1048 case TCP_CONNTRACK_CLOSE
:
1049 case TCP_CONNTRACK_SYN_SENT2
:
1050 case TCP_CONNTRACK_NONE
:
1056 switch (n
->sctp_state
) {
1057 case SCTP_CONNTRACK_NONE
:
1058 case SCTP_CONNTRACK_CLOSED
:
1059 case SCTP_CONNTRACK_COOKIE_WAIT
:
1060 case SCTP_CONNTRACK_COOKIE_ECHOED
:
1061 case SCTP_CONNTRACK_ESTABLISHED
:
1062 case SCTP_CONNTRACK_SHUTDOWN_SENT
:
1063 case SCTP_CONNTRACK_SHUTDOWN_RECD
:
1064 case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
:
1070 switch (n
->dccp_state
) {
1071 case DCCP_CONNTRACK_NONE
:
1072 case DCCP_CONNTRACK_REQUEST
:
1073 case DCCP_CONNTRACK_RESPOND
:
1074 case DCCP_CONNTRACK_PARTOPEN
:
1075 case DCCP_CONNTRACK_OPEN
:
1076 case DCCP_CONNTRACK_CLOSEREQ
:
1077 case DCCP_CONNTRACK_CLOSING
:
1078 case DCCP_CONNTRACK_TIMEWAIT
:
1079 case DCCP_CONNTRACK_IGNORE
:
1080 case DCCP_CONNTRACK_INVALID
:
1086 case IPPROTO_UDPLITE
:
1088 case IPPROTO_ICMPV6
:
1096 static void draw_flows(WINDOW
*screen
, struct flow_list
*fl
,
1099 int row_width
= show_src
? 2 : 1;
1100 unsigned int flows
= 0;
1101 unsigned int line
= 4;
1102 int skip
= skip_lines
;
1103 struct flow_entry
*n
;
1107 n
= rcu_dereference(fl
->head
);
1109 mvwprintw(screen
, line
, 2, "(No sessions! "
1110 "Is netfilter running?)");
1112 ui_table_clear(&flows_tbl
);
1113 ui_table_header_print(&flows_tbl
);
1115 for (; n
; n
= rcu_dereference(n
->next
)) {
1118 if (presenter_flow_wrong_state(n
))
1121 /* count only flows which might be showed */
1124 if (line
+ row_width
>= rows
)
1133 mvwprintw(screen
, 1, 0, "%*s", COLS
- 1, " ");
1134 mvwprintw(screen
, 1, 2, "Kernel netfilter flows(%u) for ", flows
);
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]", skip_lines
);
1157 if (is_flow_collecting
)
1158 printw(" [Collecting flows ...]");
1163 static void draw_help(void)
1169 mvaddch(row
, col
, ACS_ULCORNER
);
1170 mvaddch(rows
- row
- 1, col
, ACS_LLCORNER
);
1172 mvaddch(row
, cols
- 1, ACS_URCORNER
);
1173 mvaddch(rows
- row
- 1, cols
- 1, ACS_LRCORNER
);
1175 for (i
= 1; i
< rows
- row
- 2; i
++) {
1176 mvaddch(row
+ i
, 0, ACS_VLINE
);
1177 mvaddch(row
+ i
, cols
- 1, ACS_VLINE
);
1179 for (i
= 1; i
< cols
- col
- 1; i
++) {
1180 mvaddch(row
, col
+ i
, ACS_HLINE
);
1181 mvaddch(rows
- row
- 1, col
+ i
, ACS_HLINE
);
1185 mvaddnstr(row
, cols
/ 2 - 2, "| Help |", -1);
1187 attron(A_UNDERLINE
);
1188 mvaddnstr(row
+ 2, col
+ 2, "Navigation", -1);
1189 attroff(A_BOLD
| A_UNDERLINE
);
1191 mvaddnstr(row
+ 4, col
+ 3, "Up, u, k Move up", -1);
1192 mvaddnstr(row
+ 5, col
+ 3, "Down, d, j Move down", -1);
1193 mvaddnstr(row
+ 6, col
+ 3, "Left,l Scroll left", -1);
1194 mvaddnstr(row
+ 7, col
+ 3, "Right,h Scroll right", -1);
1195 mvaddnstr(row
+ 8, col
+ 3, "? Toggle help window", -1);
1196 mvaddnstr(row
+ 9, col
+ 3, "q, Ctrl+C Quit", -1);
1198 attron(A_BOLD
| A_UNDERLINE
);
1199 mvaddnstr(row
+ 11, col
+ 2, "Display Settings", -1);
1200 attroff(A_BOLD
| A_UNDERLINE
);
1202 mvaddnstr(row
+ 13, col
+ 3, "b Toggle rate units (bits/bytes)", -1);
1203 mvaddnstr(row
+ 14, col
+ 3, "a Toggle display of active flows (rate > 0) only", -1);
1204 mvaddnstr(row
+ 15, col
+ 3, "s Toggle show source peer info", -1);
1206 mvaddnstr(row
+ 17, col
+ 3, "T Toggle display TCP flows", -1);
1207 mvaddnstr(row
+ 18, col
+ 3, "U Toggle display UDP flows", -1);
1208 mvaddnstr(row
+ 19, col
+ 3, "D Toggle display DCCP flows", -1);
1209 mvaddnstr(row
+ 20, col
+ 3, "I Toggle display ICMP flows", -1);
1210 mvaddnstr(row
+ 21, col
+ 3, "S Toggle display SCTP flows", -1);
1213 static void draw_header(WINDOW
*screen
)
1219 for (i
= 0; i
< cols
; i
++)
1222 mvwprintw(screen
, 0, 2, "flowtop %s", VERSION_LONG
);
1223 attroff(A_STANDOUT
);
1226 static void draw_footer(void)
1232 for (i
= 0; i
< cols
; i
++)
1233 mvaddch(rows
- 1, i
, ' ');
1235 mvaddnstr(rows
- 1, 1, "Press '?' for help", -1);
1237 attroff(A_STANDOUT
);
1240 static void show_option_toggle(int opt
)
1244 TOGGLE_FLAG(what
, INCLUDE_TCP
);
1247 TOGGLE_FLAG(what
, INCLUDE_UDP
);
1250 TOGGLE_FLAG(what
, INCLUDE_DCCP
);
1253 TOGGLE_FLAG(what
, INCLUDE_ICMP
);
1256 TOGGLE_FLAG(what
, INCLUDE_SCTP
);
1261 static void flows_table_init(struct ui_table
*tbl
)
1265 ui_table_pos_set(tbl
, 3, 0);
1266 ui_table_height_set(tbl
, LINES
- 3);
1268 ui_table_col_add(tbl
, TBL_FLOW_PROCESS
, "PROCESS", 13);
1269 ui_table_col_add(tbl
, TBL_FLOW_PID
, "PID", 7);
1270 ui_table_col_add(tbl
, TBL_FLOW_PROTO
, "PROTO", 6);
1271 ui_table_col_add(tbl
, TBL_FLOW_STATE
, "STATE", 11);
1272 ui_table_col_add(tbl
, TBL_FLOW_TIME
, "TIME", 4);
1273 ui_table_col_add(tbl
, TBL_FLOW_ADDRESS
, "ADDRESS", 50);
1274 ui_table_col_add(tbl
, TBL_FLOW_PORT
, "PORT", 8);
1275 ui_table_col_add(tbl
, TBL_FLOW_GEO
, "GEO", 3);
1276 ui_table_col_add(tbl
, TBL_FLOW_BYTES
, "BYTES", 10);
1277 ui_table_col_add(tbl
, TBL_FLOW_RATE
, "RATE", 10);
1279 ui_table_col_align_set(tbl
, TBL_FLOW_TIME
, UI_ALIGN_RIGHT
);
1280 ui_table_col_align_set(tbl
, TBL_FLOW_BYTES
, UI_ALIGN_RIGHT
);
1281 ui_table_col_align_set(tbl
, TBL_FLOW_RATE
, UI_ALIGN_RIGHT
);
1283 ui_table_col_color_set(tbl
, TBL_FLOW_PROCESS
, COLOR(YELLOW
, BLACK
));
1284 ui_table_col_color_set(tbl
, TBL_FLOW_PID
, A_BOLD
);
1285 ui_table_col_color_set(tbl
, TBL_FLOW_STATE
, COLOR(YELLOW
, BLACK
));
1287 ui_table_header_color_set(&flows_tbl
, COLOR(BLACK
, GREEN
));
1290 static void presenter(void)
1292 bool show_help
= false;
1296 lookup_init(LT_PORTS_TCP
);
1297 lookup_init(LT_PORTS_UDP
);
1299 screen
= screen_init(false);
1303 INIT_COLOR(RED
, BLACK
);
1304 INIT_COLOR(BLUE
, BLACK
);
1305 INIT_COLOR(YELLOW
, BLACK
);
1306 INIT_COLOR(GREEN
, BLACK
);
1307 INIT_COLOR(BLACK
, GREEN
);
1309 flows_table_init(&flows_tbl
);
1311 rcu_register_thread();
1316 getmaxyx(screen
, rows
, cols
);
1334 if (skip_lines
> SCROLL_MAX
)
1335 skip_lines
= SCROLL_MAX
;
1339 ui_table_event_send(&flows_tbl
, UI_EVT_SCROLL_LEFT
);
1343 ui_table_event_send(&flows_tbl
, UI_EVT_SCROLL_RIGHT
);
1346 if (rate_type
== RATE_BYTES
)
1347 rate_type
= RATE_BITS
;
1349 rate_type
= RATE_BYTES
;
1352 show_active_only
= !show_active_only
;
1355 show_src
= !show_src
;
1358 show_help
= !show_help
;
1367 show_option_toggle(ch
);
1368 do_reload_flows
= true;
1375 draw_header(screen
);
1380 draw_flows(screen
, &flow_list
, skip_lines
);
1386 rcu_unregister_thread();
1388 ui_table_uninit(&flows_tbl
);
1391 lookup_cleanup(LT_PORTS_UDP
);
1392 lookup_cleanup(LT_PORTS_TCP
);
1395 static void restore_sysctl(void *obj
)
1397 struct sysctl_params_ctx
*sysctl_ctx
= obj
;
1399 if (sysctl_ctx
->nfct_acct
== 0)
1400 sysctl_set_int("net/netfilter/nf_conntrack_acct",
1401 sysctl_ctx
->nfct_acct
);
1403 if (sysctl_ctx
->nfct_tstamp
== 0)
1404 sysctl_set_int("net/netfilter/nf_conntrack_timestamp",
1405 sysctl_ctx
->nfct_tstamp
);
1408 static void on_panic_handler(void *arg
)
1410 restore_sysctl(arg
);
1414 static void conntrack_acct_enable(void)
1416 /* We can still work w/o traffic accounting so just warn about error */
1417 if (sysctl_get_int("net/netfilter/nf_conntrack_acct", &sysctl
.nfct_acct
)) {
1418 fprintf(stderr
, "Can't read net/netfilter/nf_conntrack_acct: %s\n",
1423 if (sysctl
.nfct_acct
== 1)
1426 if (sysctl_set_int("net/netfilter/nf_conntrack_acct", 1)) {
1427 fprintf(stderr
, "Can't write net/netfilter/nf_conntrack_acct: %s\n",
1432 static void conntrack_tstamp_enable(void)
1434 if (sysctl_get_int("net/netfilter/nf_conntrack_timestamp", &sysctl
.nfct_tstamp
)) {
1435 fprintf(stderr
, "Can't read net/netfilter/nf_conntrack_timestamp: %s\n",
1440 if (sysctl
.nfct_tstamp
== 1)
1443 if (sysctl_set_int("net/netfilter/nf_conntrack_timestamp", 1)) {
1444 fprintf(stderr
, "Can't write net/netfilter/nf_conntrack_timestamp: %s\n",
1449 static void flow_entry_filter(struct flow_entry
*n
)
1451 if (show_active_only
&& !n
->rate_bytes_src
&& !n
->rate_bytes_dst
)
1452 n
->is_visible
= false;
1454 n
->is_visible
= true;
1457 static int flow_list_update_entry(struct flow_list
*fl
, struct nf_conntrack
*ct
)
1459 struct flow_entry
*n
;
1461 n
= flow_list_find_id(fl
, nfct_get_attr_u32(ct
, ATTR_ID
));
1463 return NFCT_CB_CONTINUE
;
1465 flow_entry_calc_rate(n
, ct
);
1466 flow_entry_update_time(n
);
1467 flow_entry_from_ct(n
, ct
);
1468 flow_entry_filter(n
);
1470 return NFCT_CB_CONTINUE
;
1473 static int flow_event_cb(enum nf_conntrack_msg_type type
,
1474 struct nf_conntrack
*ct
, void *data __maybe_unused
)
1477 return NFCT_CB_STOP
;
1480 spinlock_lock(&flow_list
.lock
);
1484 flow_list_new_entry(&flow_list
, ct
);
1487 flow_list_update_entry(&flow_list
, ct
);
1489 case NFCT_T_DESTROY
:
1490 flow_list_destroy_entry(&flow_list
, ct
);
1496 spinlock_unlock(&flow_list
.lock
);
1499 return NFCT_CB_STOP
;
1501 return NFCT_CB_CONTINUE
;
1504 static void collector_refresh_flows(struct nfct_handle
*handle
)
1506 struct flow_entry
*n
;
1508 n
= rcu_dereference(flow_list
.head
);
1509 for (; n
; n
= rcu_dereference(n
->next
))
1510 nfct_query(handle
, NFCT_Q_GET
, n
->ct
);
1513 static void collector_create_filter(struct nfct_handle
*nfct
)
1515 struct nfct_filter
*filter
;
1518 filter
= nfct_filter_create();
1520 panic("Cannot create a nfct filter: %s\n", strerror(errno
));
1522 if (what
& INCLUDE_UDP
) {
1523 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_UDP
);
1524 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_UDPLITE
);
1526 if (what
& INCLUDE_TCP
)
1527 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_TCP
);
1528 if (what
& INCLUDE_DCCP
)
1529 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_DCCP
);
1530 if (what
& INCLUDE_SCTP
)
1531 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_SCTP
);
1532 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV4
)
1533 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_ICMP
);
1534 if (what
& INCLUDE_ICMP
&& what
& INCLUDE_IPV6
)
1535 nfct_filter_add_attr_u32(filter
, NFCT_FILTER_L4PROTO
, IPPROTO_ICMPV6
);
1536 if (what
& INCLUDE_IPV4
) {
1537 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV4
, NFCT_FILTER_LOGIC_NEGATIVE
);
1538 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV4
, &filter_ipv4
);
1540 if (what
& INCLUDE_IPV6
) {
1541 nfct_filter_set_logic(filter
, NFCT_FILTER_SRC_IPV6
, NFCT_FILTER_LOGIC_NEGATIVE
);
1542 nfct_filter_add_attr(filter
, NFCT_FILTER_SRC_IPV6
, &filter_ipv6
);
1545 ret
= nfct_filter_attach(nfct_fd(nfct
), filter
);
1547 panic("Cannot attach filter to handle: %s\n", strerror(errno
));
1549 nfct_filter_destroy(filter
);
1552 /* This hand-crafted filter looks ugly but it allows to do not
1553 * flush nfct connections & filter them by user specified filter.
1554 * May be it is better to replace this one by nfct_cmp. */
1555 static int flow_dump_cb(enum nf_conntrack_msg_type type __maybe_unused
,
1556 struct nf_conntrack
*ct
, void *data __maybe_unused
)
1558 struct flow_entry fl
;
1559 struct flow_entry
*n
= &fl
;
1562 return NFCT_CB_STOP
;
1565 spinlock_lock(&flow_list
.lock
);
1567 if (!(what
& ~(INCLUDE_IPV4
| INCLUDE_IPV6
)))
1570 CP_NFCT(l4_proto
, ATTR_ORIG_L4PROTO
, 8);
1572 if (what
& INCLUDE_UDP
) {
1573 if (n
->l4_proto
== IPPROTO_UDP
)
1576 if (n
->l4_proto
== IPPROTO_UDPLITE
)
1580 if ((what
& INCLUDE_TCP
) && n
->l4_proto
== IPPROTO_TCP
)
1583 if ((what
& INCLUDE_DCCP
) && n
->l4_proto
== IPPROTO_DCCP
)
1586 if ((what
& INCLUDE_SCTP
) && n
->l4_proto
== IPPROTO_SCTP
)
1589 if ((what
& INCLUDE_ICMP
) && (what
& INCLUDE_IPV4
) &&
1590 n
->l4_proto
== IPPROTO_ICMP
) {
1594 if ((what
& INCLUDE_ICMP
) && (what
& INCLUDE_IPV6
) &&
1595 n
->l4_proto
== IPPROTO_ICMPV6
) {
1602 /* filter loopback addresses */
1603 if (what
& INCLUDE_IPV4
) {
1604 CP_NFCT(ip4_src_addr
, ATTR_ORIG_IPV4_SRC
, 32);
1606 if (n
->ip4_src_addr
== filter_ipv4
.addr
)
1609 if (what
& INCLUDE_IPV6
) {
1610 CP_NFCT_BUFF(ip6_src_addr
, ATTR_ORIG_IPV6_SRC
);
1612 if (n
->ip6_src_addr
[0] == 0x0 &&
1613 n
->ip6_src_addr
[1] == 0x0 &&
1614 n
->ip6_src_addr
[2] == 0x0 &&
1615 n
->ip6_src_addr
[3] == 0x1)
1619 flow_list_new_entry(&flow_list
, ct
);
1622 spinlock_unlock(&flow_list
.lock
);
1623 return NFCT_CB_CONTINUE
;
1626 static void collector_dump_flows(void)
1628 struct nfct_handle
*nfct
= nfct_open(CONNTRACK
, 0);
1631 panic("Cannot create a nfct handle: %s\n", strerror(errno
));
1633 nfct_callback_register(nfct
, NFCT_T_ALL
, flow_dump_cb
, NULL
);
1635 is_flow_collecting
= true;
1636 if (what
& INCLUDE_IPV4
) {
1637 int family
= AF_INET
;
1638 nfct_query(nfct
, NFCT_Q_DUMP
, &family
);
1640 if (what
& INCLUDE_IPV6
) {
1641 int family
= AF_INET6
;
1642 nfct_query(nfct
, NFCT_Q_DUMP
, &family
);
1644 is_flow_collecting
= false;
1649 static void *collector(void *null __maybe_unused
)
1651 struct nfct_handle
*ct_event
;
1652 struct pollfd poll_fd
[1];
1654 flow_list_init(&flow_list
);
1656 ct_event
= nfct_open(CONNTRACK
, NF_NETLINK_CONNTRACK_NEW
|
1657 NF_NETLINK_CONNTRACK_UPDATE
|
1658 NF_NETLINK_CONNTRACK_DESTROY
);
1660 panic("Cannot create a nfct handle: %s\n", strerror(errno
));
1662 collector_create_filter(ct_event
);
1664 nfct_callback_register(ct_event
, NFCT_T_ALL
, flow_event_cb
, NULL
);
1666 poll_fd
[0].fd
= nfct_fd(ct_event
);
1667 poll_fd
[0].events
= POLLIN
;
1669 if (fcntl(nfct_fd(ct_event
), F_SETFL
, O_NONBLOCK
) == -1)
1670 panic("Cannot set non-blocking socket: fcntl(): %s\n",
1673 rcu_register_thread();
1675 collector_dump_flows();
1680 if (!do_reload_flows
) {
1681 usleep(USEC_PER_SEC
* interval
);
1683 do_reload_flows
= false;
1685 flow_list_destroy(&flow_list
);
1687 collector_create_filter(ct_event
);
1688 collector_dump_flows();
1691 collector_refresh_flows(ct_event
);
1693 status
= poll(poll_fd
, 1, 0);
1695 if (errno
== EAGAIN
|| errno
== EINTR
)
1698 panic("Error while polling: %s\n", strerror(errno
));
1699 } else if (status
== 0) {
1703 if (poll_fd
[0].revents
& POLLIN
)
1704 nfct_catch(ct_event
);
1707 rcu_unregister_thread();
1709 flow_list_destroy(&flow_list
);
1710 spinlock_destroy(&flow_list
.lock
);
1712 nfct_close(ct_event
);
1717 int main(int argc
, char **argv
)
1720 int ret
, c
, opt_index
, what_cmd
= 0;
1725 while ((c
= getopt_long(argc
, argv
, short_options
, long_options
,
1726 &opt_index
)) != EOF
) {
1729 what_cmd
|= INCLUDE_IPV4
;
1732 what_cmd
|= INCLUDE_IPV6
;
1735 what_cmd
|= INCLUDE_TCP
;
1738 what_cmd
|= INCLUDE_UDP
;
1741 what_cmd
|= INCLUDE_DCCP
;
1744 what_cmd
|= INCLUDE_ICMP
;
1747 what_cmd
|= INCLUDE_SCTP
;
1753 rate_type
= RATE_BITS
;
1760 interval
= strtoul(optarg
, NULL
, 10);
1763 resolve_dns
= false;
1766 resolve_geoip
= false;
1782 if (!(what
& (INCLUDE_IPV4
| INCLUDE_IPV6
)))
1783 what
|= INCLUDE_IPV4
| INCLUDE_IPV6
;
1788 register_signal(SIGINT
, signal_handler
);
1789 register_signal(SIGQUIT
, signal_handler
);
1790 register_signal(SIGTERM
, signal_handler
);
1791 register_signal(SIGHUP
, signal_handler
);
1793 panic_handler_add(on_panic_handler
, &sysctl
);
1795 conntrack_acct_enable();
1796 conntrack_tstamp_enable();
1801 ret
= pthread_create(&tid
, NULL
, collector
, NULL
);
1803 panic("Cannot create phthread!\n");
1810 restore_sysctl(&sysctl
);