-/* $OpenBSD: clientloop.c,v 1.417 2025/10/16 00:00:36 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.418 2025/11/27 02:18:48 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
SUPPRESS_MUXCLIENT},
{"B", "send a BREAK to the remote system", SUPPRESS_NEVER},
{"C", "open a command line", SUPPRESS_MUXCLIENT|SUPPRESS_NOCMDLINE},
+ {"I", "show connection information", SUPPRESS_NEVER},
{"R", "request rekey", SUPPRESS_NEVER},
{"V/v", "decrease/increase verbosity (LogLevel)", SUPPRESS_MUXCLIENT},
{"^Z", "suspend ssh", SUPPRESS_MUXCLIENT},
fatal_fr(r, "send packet");
continue;
+ case 'I':
+ if ((r = sshbuf_putf(berr, "%cI\r\n",
+ efc->escape_char)) != 0)
+ fatal_fr(r, "sshbuf_putf");
+ s = connection_info_message(ssh);
+ if ((r = sshbuf_put(berr, s, strlen(s))) != 0)
+ fatal_fr(r, "sshbuf_put");
+ free(s);
+ continue;
+
case 'R':
if (ssh->compat & SSH_BUG_NOREKEY)
logit("Server does not "
-/* $OpenBSD: packet.c,v 1.323 2025/09/25 06:33:19 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.324 2025/11/27 02:18:48 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
#include <poll.h>
#include <signal.h>
#include <time.h>
+#include <util.h>
/*
* Explicitly include OpenSSL before zlib as some versions of OpenSSL have
ssh->state->extra_pad = pad;
return 0;
}
+
+static char *
+format_traffic_stats(struct packet_state *ps)
+{
+ char *stats = NULL, bytes[FMT_SCALED_STRSIZE];
+
+ if (ps->bytes > LLONG_MAX || fmt_scaled(ps->bytes, bytes) != 0)
+ strlcpy(bytes, "OVERFLOW", sizeof(bytes));
+
+ xasprintf(&stats, "%lu pkts %llu blks %sB",
+ (unsigned long)ps->packets, (unsigned long long)ps->blocks, bytes);
+ return stats;
+}
+
+static char *
+dedupe_alg_names(const char *in, const char *out)
+{
+ char *names = NULL;
+
+ if (in == NULL)
+ in = "<implicit>";
+ if (out == NULL)
+ out = "<implicit>";
+
+ if (strcmp(in, out) == 0) {
+ names = xstrdup(in);
+ } else {
+ xasprintf(&names, "%s in, %s out", in, out);
+ }
+ return names;
+}
+
+char *
+connection_info_message(struct ssh *ssh)
+{
+ char *ret = NULL, *cipher = NULL, *mac = NULL, *comp = NULL;
+ char *rekey_volume = NULL, *rekey_time = NULL;
+ struct kex *kex;
+ struct session_state *state;
+ struct newkeys *nk_in, *nk_out;
+ char *stats_in = NULL, *stats_out = NULL;
+ u_int64_t epoch = (u_int64_t)time(NULL) - monotime();
+
+ if (ssh == NULL)
+ return NULL;
+ state = ssh->state;
+ kex = ssh->kex;
+
+ nk_in = ssh->state->newkeys[MODE_IN];
+ nk_out = ssh->state->newkeys[MODE_OUT];
+ stats_in = format_traffic_stats(&ssh->state->p_read);
+ stats_out = format_traffic_stats(&ssh->state->p_send);
+
+ cipher = dedupe_alg_names(nk_in->enc.name, nk_out->enc.name);
+ mac = dedupe_alg_names(nk_in->mac.name, nk_out->mac.name);
+ comp = dedupe_alg_names(nk_in->comp.name, nk_out->comp.name);
+
+ /* Volume based rekeying. */
+ if (state->rekey_limit == 0) {
+ xasprintf(&rekey_volume, "limit none");
+ } else {
+ char *volumes = NULL, in[32], out[32];
+
+ snprintf(in, sizeof(in), "%llu",
+ (unsigned long long)state->max_blocks_in);
+ snprintf(out, sizeof(out), "%llu",
+ (unsigned long long)state->max_blocks_out);
+ volumes = dedupe_alg_names(in, out);
+ xasprintf(&rekey_volume, "limit blocks %s", volumes);
+ free(volumes);
+ }
+
+ /* Time based rekeying. */
+ if (state->rekey_interval == 0) {
+ rekey_time = xstrdup("interval none");
+ } else {
+ char rekey_next[64];
+
+ format_absolute_time(epoch + state->rekey_time +
+ state->rekey_interval, rekey_next, sizeof(rekey_next));
+ xasprintf(&rekey_time, "interval %s, next %s",
+ fmt_timeframe(state->rekey_interval), rekey_next);
+ }
+
+ xasprintf(&ret, "Connection information for peer %s port %d:\r\n"
+ " kexalgorithm %s\r\n hostkeyalgorithm %s\r\n"
+ " cipher %s\r\n mac %s\r\n compression %s\r\n"
+ " rekey %s %s\r\n"
+ " traffic %s in, %s out\r\n",
+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
+ kex->name, kex->hostkey_alg,
+ cipher, mac, comp,
+ rekey_volume, rekey_time,
+ stats_in, stats_out
+ );
+ free(cipher);
+ free(mac);
+ free(comp);
+ free(stats_in);
+ free(stats_out);
+ free(rekey_volume);
+ free(rekey_time);
+ return ret;
+}
+