From: Sebastian Andrzej Siewior <sebastian@xxxxxxxxxxxxx> The raw/compressed bytes sent/received are only shown with the verbose option enabled once the connection is closed. Add a escape key `S' which shows the statistics on demand. The statistics is extended by the amount of bytes sent/recevied which includes cryptographic overhead (like MAC and block size). Signed-off-by: Sebastian Andrzej Siewior <sebastian@xxxxxxxxxxxxx> --- clientloop.c | 13 +++++++- packet.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ packet.h | 1 + 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/clientloop.c b/clientloop.c index ebd0dbca186f0..e431a7096b9fb 100644 --- a/clientloop.c +++ b/clientloop.c @@ -909,6 +909,7 @@ static struct escape_help_text esc_txt[] = { {"B", "send a BREAK to the remote system", SUPPRESS_NEVER}, {"C", "open a command line", SUPPRESS_MUXCLIENT}, {"R", "request rekey", SUPPRESS_NEVER}, + {"S", "Show statistics", SUPPRESS_NEVER}, {"V/v", "decrease/increase verbosity (LogLevel)", SUPPRESS_MUXCLIENT}, {"^Z", "suspend ssh", SUPPRESS_MUXCLIENT}, {"#", "list forwarded connections", SUPPRESS_NEVER}, @@ -1051,7 +1052,17 @@ process_escapes(struct ssh *ssh, Channel *c, else need_rekeying = 1; continue; - + case 'S': + if ((r = sshbuf_putf(berr, "%c#\r\n", + efc->escape_char)) != 0) + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); + s = sshpkt_get_stats(ssh); + if ((r = sshbuf_put(berr, s, strlen(s))) != 0) + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); + free(s); + continue; case 'V': /* FALLTHROUGH */ case 'v': diff --git a/packet.c b/packet.c index cdae1401196eb..1b8a45ba6b631 100644 --- a/packet.c +++ b/packet.c @@ -685,6 +685,91 @@ ssh_packet_close_internal(struct ssh *ssh, int do_close) } } +char * +sshpkt_get_stats(struct ssh *ssh) +{ + struct session_state *state = ssh->state; + u_int64_t ibytes, obytes; + struct sshbuf *buf; + char *ret; + int r; + + if ((buf = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new", __func__); + + if ((r = sshbuf_putf(buf, "Connection statistics ")) != 0) + fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); + + if (state->compression_buffer) { +#ifdef WITH_ZLIB + if (state->compression_out_started == COMP_ZLIB) { + if ((r = sshbuf_putf(buf, "zlib compressed:\r\n")) != 0) + fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); + z_streamp stream = &state->compression_out_stream; + r = sshbuf_putf(buf, "compress outgoing: " + "raw data %llu, compressed %llu, factor %.2f\r\n", + (unsigned long long)stream->total_in, + (unsigned long long)stream->total_out, + stream->total_in == 0 ? 0.0 : + (double) stream->total_out / stream->total_in); + if (r) + fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); + } + if (state->compression_in_started == COMP_ZLIB) { + z_streamp stream = &state->compression_in_stream; + r = sshbuf_putf(buf, "compress incoming: " + "raw data %llu, compressed %llu, factor %.2f\r\n", + (unsigned long long)stream->total_out, + (unsigned long long)stream->total_in, + stream->total_out == 0 ? 0.0 : + (double) stream->total_in / stream->total_out); + if (r) + fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); + } +#endif /* WITH_ZLIB */ +#ifdef HAVE_LIBZSTD + if (state->compression_out_started == COMP_ZSTD) { + if ((r = sshbuf_putf(buf, "zstd compressed:\r\n")) != 0) + fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); + r = sshbuf_putf(buf, "compress outgoing: " + "raw data %llu, compressed %llu, factor %.2f\r\n", + (unsigned long long)state->compress_zstd_out_raw, + (unsigned long long)state->compress_zstd_out_comp, + state->compress_zstd_out_raw == 0 ? 0.0 : + (double) state->compress_zstd_out_comp / + state->compress_zstd_out_raw); + if (r) + fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); + } + if (state->compression_in_started == COMP_ZSTD) { + r = sshbuf_putf(buf, "compress incoming: " + "raw data %llu, compressed %llu, factor %.2f\r\n", + (unsigned long long)state->compress_zstd_in_raw, + (unsigned long long)state->compress_zstd_in_comp, + state->compress_zstd_in_raw == 0 ? 0.0 : + (double) state->compress_zstd_in_comp / + state->compress_zstd_in_raw); + if (r) + fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); + } +#endif /* HAVE_LIBZSTD */ + } else { + + if ((r = sshbuf_putf(buf, "not compressed:\r\n")) != 0) + fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); + } + ssh_packet_get_bytes(ssh, &ibytes, &obytes); + r = sshbuf_putf(buf, "Total sent %llu, received %llu bytes.\r\n", + (unsigned long long)obytes, (unsigned long long)ibytes); + if (r) + fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); + + if ((ret = sshbuf_dup_string(buf)) == NULL) + fatal("%s: sshbuf_dup_string", __func__); + sshbuf_free(buf); + return ret; +} + void ssh_packet_close(struct ssh *ssh) { diff --git a/packet.h b/packet.h index 8ccfd2e05e8ab..cdb1963822ec6 100644 --- a/packet.h +++ b/packet.h @@ -171,6 +171,7 @@ void *ssh_packet_get_input(struct ssh *); void *ssh_packet_get_output(struct ssh *); /* new API */ +char *sshpkt_get_stats(struct ssh *ssh); int sshpkt_start(struct ssh *ssh, u_char type); int sshpkt_send(struct ssh *ssh); int sshpkt_disconnect(struct ssh *, const char *fmt, ...) -- 2.26.0.rc2 _______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev