Changed flows list layout to look more a top-like output
with header and in 1 line. When -s option is specified
then layout changes to 2 lines view including with src peer
info and dst under it on next line.

Also shortified flow state names to allocate less space.

Removed presenter_get_port be cause ports are printed for both peers
separately.

The flow duration time is printed in very short form in one of the
units:
    XXd - days
    XXh - hours
    XXm - minutes
    XXs - seconds

the reason is that it is enough to have actually generic understanding
about flow time in the biggest time unit.

Signed-off-by: Vadim Kochan <vadi...@gmail.com>
---
 flowtop.c | 405 ++++++++++++++++++++++++++++++--------------------------------
 1 file changed, 194 insertions(+), 211 deletions(-)

diff --git a/flowtop.c b/flowtop.c
index 4c15c06..8201321 100644
--- a/flowtop.c
+++ b/flowtop.c
@@ -62,6 +62,7 @@ struct flow_entry {
        uint64_t pkts_dst, bytes_dst;
        uint64_t timestamp_start, timestamp_stop;
        char country_src[128], country_dst[128];
+       char country_code_src[4], country_code_dst[4];
        char city_src[128], city_dst[128];
        char rev_dns_src[256], rev_dns_dst[256];
        char procname[256];
@@ -166,11 +167,6 @@ static const char *copyright = "Please report bugs to 
<netsniff-ng@googlegroups.
        "This is free software: you are free to change and redistribute it.\n"
        "There is NO WARRANTY, to the extent permitted by law.";
 
-static const char *const l3proto2str[AF_MAX] = {
-       [AF_INET]                       = "ipv4",
-       [AF_INET6]                      = "ipv6",
-};
-
 static const char *const l4proto2str[IPPROTO_MAX] = {
        [IPPROTO_TCP]                   = "tcp",
        [IPPROTO_UDP]                   = "udp",
@@ -194,40 +190,40 @@ static const char *const l4proto2str[IPPROTO_MAX] = {
 };
 
 static const char *const tcp_state2str[TCP_CONNTRACK_MAX] = {
-       [TCP_CONNTRACK_NONE]            = "NOSTATE",
-       [TCP_CONNTRACK_SYN_SENT]        = "SYN_SENT",
-       [TCP_CONNTRACK_SYN_RECV]        = "SYN_RECV",
-       [TCP_CONNTRACK_ESTABLISHED]     = "ESTABLISHED",
-       [TCP_CONNTRACK_FIN_WAIT]        = "FIN_WAIT",
-       [TCP_CONNTRACK_CLOSE_WAIT]      = "CLOSE_WAIT",
-       [TCP_CONNTRACK_LAST_ACK]        = "LAST_ACK",
-       [TCP_CONNTRACK_TIME_WAIT]       = "TIME_WAIT",
-       [TCP_CONNTRACK_CLOSE]           = "CLOSE",
-       [TCP_CONNTRACK_SYN_SENT2]       = "SYN_SENT2",
+       [TCP_CONNTRACK_NONE]            = "NO",
+       [TCP_CONNTRACK_SYN_SENT]        = "SS",
+       [TCP_CONNTRACK_SYN_RECV]        = "SR",
+       [TCP_CONNTRACK_ESTABLISHED]     = "EST",
+       [TCP_CONNTRACK_FIN_WAIT]        = "FWT",
+       [TCP_CONNTRACK_CLOSE_WAIT]      = "CWT",
+       [TCP_CONNTRACK_LAST_ACK]        = "LAC",
+       [TCP_CONNTRACK_TIME_WAIT]       = "TWT",
+       [TCP_CONNTRACK_CLOSE]           = "CLO",
+       [TCP_CONNTRACK_SYN_SENT2]       = "SS2",
 };
 
 static const char *const dccp_state2str[DCCP_CONNTRACK_MAX] = {
-       [DCCP_CONNTRACK_NONE]           = "NOSTATE",
-       [DCCP_CONNTRACK_REQUEST]        = "REQUEST",
-       [DCCP_CONNTRACK_RESPOND]        = "RESPOND",
-       [DCCP_CONNTRACK_PARTOPEN]       = "PARTOPEN",
-       [DCCP_CONNTRACK_OPEN]           = "OPEN",
-       [DCCP_CONNTRACK_CLOSEREQ]       = "CLOSEREQ",
-       [DCCP_CONNTRACK_CLOSING]        = "CLOSING",
-       [DCCP_CONNTRACK_TIMEWAIT]       = "TIMEWAIT",
-       [DCCP_CONNTRACK_IGNORE]         = "IGNORE",
-       [DCCP_CONNTRACK_INVALID]        = "INVALID",
+       [DCCP_CONNTRACK_NONE]           = "NO",
+       [DCCP_CONNTRACK_REQUEST]        = "REQ",
+       [DCCP_CONNTRACK_RESPOND]        = "RES",
+       [DCCP_CONNTRACK_PARTOPEN]       = "POP",
+       [DCCP_CONNTRACK_OPEN]           = "OPN",
+       [DCCP_CONNTRACK_CLOSEREQ]       = "CLQ",
+       [DCCP_CONNTRACK_CLOSING]        = "CLN",
+       [DCCP_CONNTRACK_TIMEWAIT]       = "TWT",
+       [DCCP_CONNTRACK_IGNORE]         = "IGN",
+       [DCCP_CONNTRACK_INVALID]        = "INV",
 };
 
 static const char *const sctp_state2str[SCTP_CONNTRACK_MAX] = {
-       [SCTP_CONNTRACK_NONE]           = "NOSTATE",
-       [SCTP_CONNTRACK_CLOSED]         = "CLOSED",
-       [SCTP_CONNTRACK_COOKIE_WAIT]    = "COOKIE_WAIT",
-       [SCTP_CONNTRACK_COOKIE_ECHOED]  = "COOKIE_ECHOED",
-       [SCTP_CONNTRACK_ESTABLISHED]    = "ESTABLISHED",
-       [SCTP_CONNTRACK_SHUTDOWN_SENT]  = "SHUTDOWN_SENT",
-       [SCTP_CONNTRACK_SHUTDOWN_RECD]  = "SHUTDOWN_RECD",
-       [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT",
+       [SCTP_CONNTRACK_NONE]           = "NO",
+       [SCTP_CONNTRACK_CLOSED]         = "CLO",
+       [SCTP_CONNTRACK_COOKIE_WAIT]    = "CKW",
+       [SCTP_CONNTRACK_COOKIE_ECHOED]  = "CKE",
+       [SCTP_CONNTRACK_ESTABLISHED]    = "EST",
+       [SCTP_CONNTRACK_SHUTDOWN_SENT]  = "SHS",
+       [SCTP_CONNTRACK_SHUTDOWN_RECD]  = "SHR",
+       [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SAS",
 };
 
 static const struct nfct_filter_ipv4 filter_ipv4 = {
@@ -684,6 +680,7 @@ flow_entry_geo_country_lookup_generic(struct flow_entry *n,
        struct sockaddr_in sa4;
        struct sockaddr_in6 sa6;
        const char *country = NULL;
+       const char *country_code = NULL;
 
        switch (n->l3_proto) {
        default:
@@ -692,11 +689,13 @@ flow_entry_geo_country_lookup_generic(struct flow_entry 
*n,
        case AF_INET:
                flow_entry_get_sain4_obj(n, dir, &sa4);
                country = geoip4_country_name(&sa4);
+               country_code = geoip4_country_code3_name(&sa4);
                break;
 
        case AF_INET6:
                flow_entry_get_sain6_obj(n, dir, &sa6);
                country = geoip6_country_name(&sa6);
+               country_code = geoip6_country_code3_name(&sa6);
                break;
        }
 
@@ -707,6 +706,14 @@ flow_entry_geo_country_lookup_generic(struct flow_entry *n,
                        sizeof(n->country_src));
        else
                SELFLD(dir, country_src, country_dst)[0] = '\0';
+
+       build_bug_on(sizeof(n->country_code_src) != 
sizeof(n->country_code_dst));
+
+       if (country_code)
+               strlcpy(SELFLD(dir, country_code_src, country_code_dst),
+                       country_code, sizeof(n->country_code_src));
+       else
+               SELFLD(dir, country_code_src, country_code_dst)[0] = '\0';
 }
 
 static void flow_entry_get_extended_geo(struct flow_entry *n,
@@ -792,36 +799,13 @@ static void flow_entry_get_extended(struct flow_entry *n)
                walk_processes(n);
 }
 
-static uint16_t presenter_get_port(uint16_t src, uint16_t dst, bool is_tcp)
+static char *bandw2str(double bytes, char *buf, size_t len)
 {
-       if (src < dst && src < 1024) {
-               return src;
-       } else if (dst < src && dst < 1024) {
-               return dst;
-       } else {
-               const char *tmp1, *tmp2;
-               if (is_tcp) {
-                       tmp1 = lookup_port_tcp(src);
-                       tmp2 = lookup_port_tcp(dst);
-               } else {
-                       tmp1 = lookup_port_udp(src);
-                       tmp2 = lookup_port_udp(dst);
-               }
-               if (tmp1 && !tmp2) {
-                       return src;
-               } else if (!tmp1 && tmp2) {
-                       return dst;
-               } else {
-                       if (src < dst)
-                               return src;
-                       else
-                               return dst;
-               }
+       if (bytes <= 0) {
+               buf[0] = '\0';
+               return buf;
        }
-}
 
-static char *bandw2str(double bytes, char *buf, size_t len)
-{
        if (bytes > 1000000000.)
                snprintf(buf, len, "%.1fGB", bytes / 1000000000.);
        else if (bytes > 1000000.)
@@ -829,7 +813,7 @@ static char *bandw2str(double bytes, char *buf, size_t len)
        else if (bytes > 1000.)
                snprintf(buf, len, "%.1fkB", bytes / 1000.);
        else
-               snprintf(buf, len, "%g bytes", bytes);
+               snprintf(buf, len, "%.0f", bytes);
 
        return buf;
 }
@@ -837,10 +821,15 @@ static char *bandw2str(double bytes, char *buf, size_t 
len)
 static char *rate2str(double rate, char *buf, size_t len)
 {
        const char * const unit_fmt[2][4] = {
-               { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%gbit/s" },
-               { "%.1fGB/s",   "%.1fMB/s",   "%.1fkB/s",   "%gB/s"   }
+               { "%.1fGbit/s", "%.1fMbit/s", "%.1fkbit/s", "%.0fbit/s" },
+               { "%.1fGB/s",   "%.1fMB/s",   "%.1fkB/s",   "%.0fB/s"   }
        };
 
+       if (rate <= 0) {
+               buf[0] = '\0';
+               return buf;
+       }
+
        if (rate_type == RATE_BITS)
                rate *= 8;
 
@@ -856,176 +845,153 @@ static char *rate2str(double rate, char *buf, size_t 
len)
        return buf;
 }
 
-static void presenter_print_counters(uint64_t bytes, uint64_t pkts,
-                                    double rate_bytes, double rate_pkts,
-                                    int color)
+static char *time2str(uint64_t tstamp, char *str, size_t len)
 {
-       char bytes_str[64];
-
-       printw(" -> (");
-       attron(COLOR_PAIR(color));
-       printw("%"PRIu64" pkts", pkts);
-       if (rate_pkts) {
-               attron(COLOR_PAIR(3));
-               printw("(%.1fpps)", rate_pkts);
-               attron(COLOR_PAIR(color));
+       time_t now;
+       int v, s;
+
+       time(&now);
+
+       s = now - (tstamp ? (tstamp / NSEC_PER_SEC) : now);
+       if (s <= 0) {
+               str[0] = '\0';
+               return str;
        }
 
-       printw(", %s", bandw2str(bytes, bytes_str, sizeof(bytes_str) - 1));
-       if (rate_bytes) {
-               attron(COLOR_PAIR(3));
-               printw("(%s)", rate2str(rate_bytes, bytes_str,
-                       sizeof(bytes_str) - 1));
-               attron(COLOR_PAIR(color));
+       v = s / (3600 * 24);
+       if (v > 0) {
+               slprintf(str, len, "%dd", v);
+               return str;
        }
-       attroff(COLOR_PAIR(color));
-       printw(")");
+
+       v = s / 3600;
+       if (v > 0) {
+               slprintf(str, len, "%dh", v);
+               return str;
+       }
+
+       v = s / 60;
+       if (v > 0) {
+               slprintf(str, len, "%dm", v);
+               return str;
+       }
+
+       slprintf(str, len, "%ds", s);
+       return str;
 }
 
-static void presenter_print_flow_entry_time(const struct flow_entry *n)
+static void print_flow_peer_info(const struct flow_entry *n, int y, int x,
+                                enum flow_direction dir)
 {
-       int h, m, s;
-       time_t now;
+       int counters_color = COLOR_PAIR(3);
+       int country_color = COLOR_PAIR(4);
+       int port_color = A_BOLD;
+       const char *str = NULL;
+       uint16_t port = 0;
+       char tmp[128];
 
-       time(&now);
+       if (show_src && dir == FLOW_DIR_SRC) {
+               counters_color = COLOR_PAIR(1);
+               country_color = COLOR_PAIR(1);
+               port_color |= COLOR_PAIR(1);
+       } else if (show_src && FLOW_DIR_DST) {
+               counters_color = COLOR_PAIR(2);
+               country_color = COLOR_PAIR(2);
+               port_color |= COLOR_PAIR(2);
+       }
 
-       s = now - (n->timestamp_start / NSEC_PER_SEC);
-       if (s <= 0)
-               return;
+       mvprintw(y, x, "");
 
-       h = s / 3600;
-       s -= h * 3600;
-       m = s / 60;
-       s -= m * 60;
-
-       printw(" [ time");
-       if (h > 0)
-               printw(" %dh", h);
-       if (m > 0)
-               printw(" %dm", m);
-       if (s > 0)
-               printw(" %ds", s);
-       printw(" ]");
+       /* Reverse DNS/IP */
+       attron(COLOR_PAIR(dir == FLOW_DIR_SRC ? 1 : 2));
+       printw(" %-*.*s", 50, 50, SELFLD(dir, rev_dns_src, rev_dns_dst));
+       attroff(COLOR_PAIR(dir == FLOW_DIR_SRC ? 1 : 2));
+
+       /* Application port */
+       port = SELFLD(dir, port_src, port_dst);
+       str = NULL;
+
+       switch (n->l4_proto) {
+       case IPPROTO_TCP:
+               str = lookup_port_tcp(port);
+               break;
+       case IPPROTO_UDP:
+       case IPPROTO_UDPLITE:
+               str = lookup_port_udp(port);
+               break;
+       }
+       if (!str && port)
+               slprintf(tmp, sizeof(tmp), "%d", port);
+       else
+               slprintf(tmp, sizeof(tmp), "%s", str ? str : "");
+
+       attron(port_color);
+       printw(" %-*.*s", 8, 8, tmp);
+       attroff(port_color);
+
+       /* Country code */
+       attron(country_color);
+       printw(" %-*.*s", 3, 3, SELFLD(dir, country_code_src, 
country_code_dst));
+       attroff(country_color);
+
+       /* 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);
 }
 
-static void draw_flow_entry(WINDOW *screen, const struct flow_entry *n,
-                           unsigned int *line)
+static void draw_flow_entry(WINDOW *scr, const struct flow_entry *n, int line)
 {
+       const char *str = NULL;
        char tmp[128];
-       const char *pname = NULL;
-       uint16_t port;
 
-       mvwprintw(screen, *line, 2, "");
+       mvwprintw(scr, line, 0, "");
 
-       /* PID, application name */
-       if (n->procnum > 0) {
-               slprintf(tmp, sizeof(tmp), "%s(%d)", n->procname, n->procnum);
+       /* Application */
+       attron(COLOR_PAIR(3));
+       printw("%-*.*s", 10, 10, n->procname);
+       attroff(COLOR_PAIR(3));
 
-               printw("[");
-               attron(COLOR_PAIR(3));
-               printw("%s", tmp);
-               attroff(COLOR_PAIR(3));
-               printw("]:");
-       }
+       /* L4 protocol */
+       printw(" %-*.*s", 6, 6, l4proto2str[n->l4_proto]);
 
-       /* L3 protocol, L4 protocol, states */
-       printw("%s:%s", l3proto2str[n->l3_proto], l4proto2str[n->l4_proto]);
-       printw("[");
+       /* L4 protocol state */
        attron(COLOR_PAIR(3));
        switch (n->l4_proto) {
        case IPPROTO_TCP:
-               printw("%s", tcp_state2str[n->tcp_state]);
+               str = tcp_state2str[n->tcp_state];
                break;
        case IPPROTO_SCTP:
-               printw("%s", sctp_state2str[n->sctp_state]);
+               str = sctp_state2str[n->sctp_state];
                break;
        case IPPROTO_DCCP:
-               printw("%s", dccp_state2str[n->dccp_state]);
+               str = dccp_state2str[n->dccp_state];
                break;
        case IPPROTO_UDP:
        case IPPROTO_UDPLITE:
        case IPPROTO_ICMP:
        case IPPROTO_ICMPV6:
-               printw("NOSTATE");
+               str = "";
                break;
        }
+       printw(" %-*.*s", 4, 4, str);
        attroff(COLOR_PAIR(3));
-       printw("]");
-
-       /* Guess application port */
-       switch (n->l4_proto) {
-       case IPPROTO_TCP:
-               port = presenter_get_port(n->port_src, n->port_dst, true);
-               pname = lookup_port_tcp(port);
-               break;
-       case IPPROTO_UDP:
-       case IPPROTO_UDPLITE:
-               port = presenter_get_port(n->port_src, n->port_dst, false);
-               pname = lookup_port_udp(port);
-               break;
-       }
-       if (pname) {
-               attron(A_BOLD);
-               printw(":%s", pname);
-               attroff(A_BOLD);
-       }
-
-       if (n->timestamp_start > 0)
-               presenter_print_flow_entry_time(n);
-
-       /* Show source information: reverse DNS, port, country, city, counters 
*/
-       if (show_src) {
-               attron(COLOR_PAIR(1));
-               mvwprintw(screen, ++(*line), 8, "src: %s", n->rev_dns_src);
-               attroff(COLOR_PAIR(1));
-
-               printw(":%"PRIu16, n->port_src);
-
-               if (n->country_src[0]) {
-                       printw(" (");
 
-                       attron(COLOR_PAIR(4));
-                       printw("%s", n->country_src);
-                       attroff(COLOR_PAIR(4));
+       /* Time */
+       printw(" %*.*s", 4, 4, time2str(n->timestamp_start, tmp, sizeof(tmp)));
 
-                       if (n->city_src[0])
-                               printw(", %s", n->city_src);
-
-                       printw(")");
-               }
-
-               if (n->pkts_src > 0 && n->bytes_src > 0)
-                       presenter_print_counters(n->bytes_src, n->pkts_src,
-                                                n->rate_bytes_src,
-                                                n->rate_pkts_src, 1);
-
-               printw(" => ");
-       }
-
-       /* Show dest information: reverse DNS, port, country, city, counters */
-       attron(COLOR_PAIR(2));
-       mvwprintw(screen, ++(*line), 8, "dst: %s", n->rev_dns_dst);
-       attroff(COLOR_PAIR(2));
-
-       printw(":%"PRIu16, n->port_dst);
-
-       if (n->country_dst[0]) {
-               printw(" (");
-
-               attron(COLOR_PAIR(4));
-               printw("%s", n->country_dst);
-               attroff(COLOR_PAIR(4));
-
-               if (n->city_dst[0])
-                       printw(", %s", n->city_dst);
-
-               printw(")");
-       }
-
-       if (n->pkts_dst > 0 && n->bytes_dst > 0)
-               presenter_print_counters(n->bytes_dst, n->pkts_dst,
-                                        n->rate_bytes_dst,
-                                        n->rate_pkts_dst, 2);
+       print_flow_peer_info(n, line, 28, show_src ? FLOW_DIR_SRC : 
FLOW_DIR_DST);
+       if (show_src)
+               print_flow_peer_info(n, line + 1, 28, FLOW_DIR_DST);
 }
 
 static inline bool presenter_flow_wrong_state(struct flow_entry *n)
@@ -1088,14 +1054,34 @@ static inline bool presenter_flow_wrong_state(struct 
flow_entry *n)
        return true;
 }
 
+static void draw_flows_header(WINDOW *scr, int line)
+{
+       attron(COLOR_PAIR(5));
+
+       mvwprintw(scr, line, 0, "%-*.*s", cols, cols, "");
+       mvwprintw(scr, line, 0, "");
+
+       wprintw(scr, "%-*.*s", 10, 10, "PROCESS");
+       wprintw(scr, " %-*.*s", 6, 6, "PROTO");
+       wprintw(scr, " %-*.*s", 4, 4, "STAT");
+       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");
+
+       attroff(COLOR_PAIR(5));
+}
+
 static void draw_flows(WINDOW *screen, struct flow_list *fl,
                       int skip_lines)
 {
-       int skip_left = skip_lines;
+       int row_width = show_src ? 2 : 1;
        unsigned int flows = 0;
-       unsigned int line = 3;
+       unsigned int line = 4;
+       int skip = skip_lines;
        struct flow_entry *n;
-       int maxy = rows - 6;
 
        wclear(screen);
        clear();
@@ -1107,28 +1093,24 @@ 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);
+
        for (; n; n = rcu_dereference(n->next)) {
                if (!n->is_visible)
                        continue;
-
                if (presenter_flow_wrong_state(n))
                        continue;
 
                /* count only flows which might be showed */
                flows++;
 
-               if (maxy <= 0)
+               if (line + row_width >= rows - 3)
                        continue;
-
-               if (skip_left > 0) {
-                       skip_left--;
+               if (--skip >= 0)
                        continue;
-               }
-
-               draw_flow_entry(screen, n, &line);
 
-               line++;
-               maxy -= (2 + (show_src ? 1 : 0));
+               draw_flow_entry(screen, n, line);
+               line += row_width;
        }
 
        mvwprintw(screen, 1, 2, "Kernel netfilter flows(%u) for ", flows);
@@ -1272,6 +1254,7 @@ static void presenter(void)
        init_pair(2, COLOR_BLUE, COLOR_BLACK);
        init_pair(3, COLOR_YELLOW, COLOR_BLACK);
        init_pair(4, COLOR_GREEN, COLOR_BLACK);
+       init_pair(5, COLOR_BLACK, COLOR_GREEN);
 
        rcu_register_thread();
        while (!sigint) {
-- 
2.6.3

-- 
You received this message because you are subscribed to the Google Groups 
"netsniff-ng" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to netsniff-ng+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to