Mailing List Archive

[PATCH 5/5] Add a escape key to show packet statistics.
From: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>

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@breakpoint.cc>
---
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 c82b084da1bb0..7a62af9db4907 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -897,6 +897,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},
@@ -1039,7 +1040,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 d49c9594cf60d..eef82766425f8 100644
--- a/packet.c
+++ b/packet.c
@@ -690,6 +690,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 c2544bd966078..9487ba9c21a54 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.28.0

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev