diff options
-rw-r--r-- | flowtop.c | 245 | ||||
-rw-r--r-- | flowtop/Makefile | 1 |
2 files changed, 141 insertions, 105 deletions
@@ -28,6 +28,7 @@ #include <fcntl.h> #include <arpa/inet.h> +#include "ui.h" #include "die.h" #include "xmalloc.h" #include "conntrack.h" @@ -139,6 +140,21 @@ static bool resolve_geoip = true; static enum rate_units rate_type = RATE_BYTES; static bool show_active_only = false; +enum tbl_flow_col { + TBL_FLOW_PROCESS, + TBL_FLOW_PID, + TBL_FLOW_PROTO, + TBL_FLOW_STATE, + TBL_FLOW_TIME, + TBL_FLOW_ADDRESS, + TBL_FLOW_PORT, + TBL_FLOW_GEO, + TBL_FLOW_BYTES, + TBL_FLOW_RATE, +}; + +static struct ui_table flows_tbl; + static const char *short_options = "vhTUsDIS46ut:nGb"; static const struct option long_options[] = { {"ipv4", no_argument, NULL, '4'}, @@ -878,127 +894,134 @@ static char *time2str(uint64_t tstamp, char *str, size_t len) return str; } -static void print_flow_peer_info(const struct flow_entry *n, int y, int x, - enum flow_direction dir) + +static const char *flow_state2str(const struct flow_entry *n) { - int counters_color = COLOR(YELLOW, BLACK); - int src_color = COLOR(RED, BLACK); - int dst_color = COLOR(BLUE, BLACK); - int country_color = COLOR(GREEN, BLACK); - int port_color = A_BOLD; - const char *str = NULL; - uint16_t port = 0; - char tmp[128]; + switch (n->l4_proto) { + case IPPROTO_TCP: + return tcp_state2str[n->tcp_state]; + case IPPROTO_SCTP: + return sctp_state2str[n->sctp_state]; + case IPPROTO_DCCP: + return dccp_state2str[n->dccp_state]; - if (show_src && dir == FLOW_DIR_SRC) { - country_color = counters_color = src_color; - port_color |= src_color; - } else if (show_src && FLOW_DIR_DST) { - country_color = counters_color = dst_color; - port_color |= dst_color; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + default: + return ""; } +} - mvprintw(y, x, ""); - - /* Reverse DNS/IP */ - attron(dir == FLOW_DIR_SRC ? src_color : dst_color); - printw(" %-*.*s", 50, 50, SELFLD(dir, rev_dns_src, rev_dns_dst)); - attroff(dir == FLOW_DIR_SRC ? src_color : dst_color); +static char *flow_port2str(const struct flow_entry *n, char *str, size_t len, + enum flow_direction dir) +{ + const char *tmp = NULL; + uint16_t port = 0; - /* Application port */ port = SELFLD(dir, port_src, port_dst); - str = NULL; + tmp = NULL; switch (n->l4_proto) { case IPPROTO_TCP: - str = lookup_port_tcp(port); + tmp = lookup_port_tcp(port); break; case IPPROTO_UDP: case IPPROTO_UDPLITE: - str = lookup_port_udp(port); + tmp = lookup_port_udp(port); break; } - if (!str && port) - slprintf(tmp, sizeof(tmp), "%d", port); + if (!tmp && port) + slprintf(str, len, "%d", port); else - slprintf(tmp, sizeof(tmp), "%s", str ? str : ""); + slprintf(str, len, "%s", tmp ? tmp : ""); + + return str; +} + +static void print_flow_peer_info(const struct flow_entry *n, enum flow_direction dir) +{ + int counters_color = COLOR(YELLOW, BLACK); + int src_color = COLOR(RED, BLACK); + int dst_color = COLOR(BLUE, BLACK); + int country_color = COLOR(GREEN, BLACK); + int addr_color = dst_color; + int port_color = A_BOLD; + char tmp[128]; + + if (show_src && dir == FLOW_DIR_SRC) { + country_color = src_color; + counters_color = src_color; + port_color |= src_color; + addr_color = src_color; + } else if (show_src && FLOW_DIR_DST) { + country_color = dst_color; + counters_color = dst_color; + port_color |= dst_color; + addr_color = dst_color; + } + + ui_table_col_color_set(&flows_tbl, TBL_FLOW_ADDRESS, addr_color); + ui_table_col_color_set(&flows_tbl, TBL_FLOW_PORT, port_color); + ui_table_col_color_set(&flows_tbl, TBL_FLOW_GEO, country_color); + ui_table_col_color_set(&flows_tbl, TBL_FLOW_BYTES, counters_color); + ui_table_col_color_set(&flows_tbl, TBL_FLOW_RATE, counters_color); + + /* Reverse DNS/IP */ + ui_table_row_print(&flows_tbl, TBL_FLOW_ADDRESS, + SELFLD(dir, rev_dns_src, rev_dns_dst)); - attron(port_color); - printw(" %-*.*s", 8, 8, tmp); - attroff(port_color); + /* Application port */ + ui_table_row_print(&flows_tbl, TBL_FLOW_PORT, + flow_port2str(n, tmp, sizeof(tmp), dir)); - /* Country code */ - attron(country_color); - printw(" %-*.*s", 3, 3, SELFLD(dir, country_code_src, country_code_dst)); - attroff(country_color); + /* GEO */ + ui_table_row_print(&flows_tbl, TBL_FLOW_GEO, + SELFLD(dir, country_code_src, country_code_dst)); /* Bytes */ - attron(counters_color); - printw(" %*.*s", 10, 10, - bandw2str(SELFLD(dir, bytes_src, bytes_dst), - tmp, sizeof(tmp) - 1)); - attroff(counters_color); - - /* Rate */ - attron(counters_color); - printw(" %*.*s", 10, 10, - rate2str(SELFLD(dir, rate_bytes_src, rate_bytes_dst), - tmp, sizeof(tmp) - 1)); - attroff(counters_color); + ui_table_row_print(&flows_tbl, TBL_FLOW_BYTES, + bandw2str(SELFLD(dir, bytes_src, bytes_dst), + tmp, sizeof(tmp) - 1)); + + /* Rate bytes */ + ui_table_row_print(&flows_tbl, TBL_FLOW_RATE, + rate2str(SELFLD(dir, rate_bytes_src, rate_bytes_dst), + tmp, sizeof(tmp) - 1)); } static void draw_flow_entry(WINDOW *scr, const struct flow_entry *n, int line) { - const char *str = NULL; char tmp[128]; - mvwprintw(scr, line, 0, ""); + ui_table_row_add(&flows_tbl); /* Application */ - COLOR_ON(YELLOW, BLACK); - printw("%-*.*s", 10, 10, n->procname); - COLOR_OFF(YELLOW, BLACK); + ui_table_row_print(&flows_tbl, TBL_FLOW_PROCESS, n->procname); /* PID */ slprintf(tmp, sizeof(tmp), "%.d", n->procnum); - attron(A_BOLD); - printw("%-*.*s", 7, 7, tmp); - attroff(A_BOLD); + ui_table_row_print(&flows_tbl, TBL_FLOW_PID, tmp); /* L4 protocol */ - printw(" %-*.*s", 6, 6, l4proto2str[n->l4_proto]); + ui_table_row_print(&flows_tbl, TBL_FLOW_PROTO, l4proto2str[n->l4_proto]); /* L4 protocol state */ - COLOR_ON(YELLOW, BLACK); - switch (n->l4_proto) { - case IPPROTO_TCP: - str = tcp_state2str[n->tcp_state]; - break; - case IPPROTO_SCTP: - str = sctp_state2str[n->sctp_state]; - break; - case IPPROTO_DCCP: - str = dccp_state2str[n->dccp_state]; - break; - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - str = ""; - break; - } - COLOR_OFF(YELLOW, BLACK); - printw(" %-*.*s", 11, 11, str); - attroff(COLOR_PAIR(3)); - COLOR_OFF(YELLOW, BLACK); + ui_table_row_print(&flows_tbl, TBL_FLOW_STATE, flow_state2str(n)); /* Time */ - printw(" %*.*s", 4, 4, time2str(n->timestamp_start, tmp, sizeof(tmp))); + time2str(n->timestamp_start, tmp, sizeof(tmp)); + ui_table_row_print(&flows_tbl, TBL_FLOW_TIME, tmp); + + print_flow_peer_info(n, show_src ? FLOW_DIR_SRC : FLOW_DIR_DST); + + if (show_src) { + ui_table_row_add(&flows_tbl); - print_flow_peer_info(n, line, 41, show_src ? FLOW_DIR_SRC : FLOW_DIR_DST); - if (show_src) - print_flow_peer_info(n, line + 1, 41, FLOW_DIR_DST); + print_flow_peer_info(n, FLOW_DIR_DST); + } } static inline bool presenter_flow_wrong_state(struct flow_entry *n) @@ -1061,27 +1084,6 @@ static inline bool presenter_flow_wrong_state(struct flow_entry *n) return true; } -static void draw_flows_header(WINDOW *scr, int line) -{ - COLOR_ON(BLACK, GREEN); - - mvwprintw(scr, line, 0, "%-*.*s", cols, cols, ""); - mvwprintw(scr, line, 0, ""); - - wprintw(scr, "%-*.*s", 10, 10, "PROCESS"); - wprintw(scr, "%-*.*s", 7, 7, "PID"); - wprintw(scr, " %-*.*s", 6, 6, "PROTO"); - wprintw(scr, " %-*.*s", 11, 11, "STATE"); - wprintw(scr, " %*.*s", 4, 4, "TIME"); - wprintw(scr, " %-*.*s", 50, 50, "ADDRESS"); - wprintw(scr, " %-*.*s", 8, 8, "PORT"); - wprintw(scr, " %-*.*s", 3, 3, "GEO"); - wprintw(scr, " %*.*s", 10, 10, "BYTES"); - wprintw(scr, " %*.*s", 10, 10, "RATE"); - - COLOR_OFF(BLACK, GREEN); -} - static void draw_flows(WINDOW *screen, struct flow_list *fl, int skip_lines) { @@ -1101,7 +1103,8 @@ static void draw_flows(WINDOW *screen, struct flow_list *fl, mvwprintw(screen, line, 2, "(No sessions! " "Is netfilter running?)"); - draw_flows_header(screen, line - 1); + ui_table_clear(&flows_tbl); + ui_table_header_print(&flows_tbl); for (; n; n = rcu_dereference(n->next)) { if (!n->is_visible) @@ -1246,6 +1249,34 @@ static void show_option_toggle(int opt) } } +static void flows_table_init(struct ui_table *tbl) +{ + ui_table_init(tbl); + + ui_table_pos_set(tbl, 3, 0); + + ui_table_col_add(tbl, TBL_FLOW_PROCESS, "PROCESS", 13); + ui_table_col_add(tbl, TBL_FLOW_PID, "PID", 7); + ui_table_col_add(tbl, TBL_FLOW_PROTO, "PROTO", 6); + ui_table_col_add(tbl, TBL_FLOW_STATE, "STATE", 11); + ui_table_col_add(tbl, TBL_FLOW_TIME, "TIME", 4); + ui_table_col_add(tbl, TBL_FLOW_ADDRESS, "ADDRESS", 50); + ui_table_col_add(tbl, TBL_FLOW_PORT, "PORT", 8); + ui_table_col_add(tbl, TBL_FLOW_GEO, "GEO", 3); + ui_table_col_add(tbl, TBL_FLOW_BYTES, "BYTES", 10); + ui_table_col_add(tbl, TBL_FLOW_RATE, "RATE", 10); + + ui_table_col_align_set(tbl, TBL_FLOW_TIME, UI_ALIGN_RIGHT); + ui_table_col_align_set(tbl, TBL_FLOW_BYTES, UI_ALIGN_RIGHT); + ui_table_col_align_set(tbl, TBL_FLOW_RATE, UI_ALIGN_RIGHT); + + ui_table_col_color_set(tbl, TBL_FLOW_PROCESS, COLOR(YELLOW, BLACK)); + ui_table_col_color_set(tbl, TBL_FLOW_PID, A_BOLD); + ui_table_col_color_set(tbl, TBL_FLOW_STATE, COLOR(YELLOW, BLACK)); + + ui_table_header_color_set(&flows_tbl, COLOR(BLACK, GREEN)); +} + static void presenter(void) { int time_sleep_us = 200000; @@ -1265,6 +1296,8 @@ static void presenter(void) INIT_COLOR(GREEN, BLACK); INIT_COLOR(BLACK, GREEN); + flows_table_init(&flows_tbl); + rcu_register_thread(); while (!sigint) { bool redraw_flows = true; @@ -1349,6 +1382,8 @@ static void presenter(void) } rcu_unregister_thread(); + ui_table_uninit(&flows_tbl); + screen_end(); lookup_cleanup(LT_PORTS_UDP); lookup_cleanup(LT_PORTS_TCP); diff --git a/flowtop/Makefile b/flowtop/Makefile index ddb031c..effe7eb 100644 --- a/flowtop/Makefile +++ b/flowtop/Makefile @@ -22,6 +22,7 @@ flowtop-objs = xmalloc.o \ screen.o \ die.o \ sysctl.o \ + ui.o \ flowtop.o ifeq ($(CONFIG_GEOIP), 1) |