From e3ca0513a08bd3cab28df0944aa82da2922e367d Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Fri, 11 Sep 2009 14:02:04 +0000
Subject: [PATCH] - Disable compression for non-final multihops

--HG--
extra : convert_revision : c507a2aacb9e0db4c0266891b8915c614e32857e
---
 algo.h        |  3 ++-
 cli-runopts.c |  7 +++++++
 common-algo.c |  7 ++++++-
 common-kex.c  | 19 ++++++++++++++-----
 runopts.h     |  9 ++++++++-
 session.h     |  3 +++
 svr-runopts.c |  3 +++
 7 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/algo.h b/algo.h
index c83cfff..87e524d 100644
--- a/algo.h
+++ b/algo.h
@@ -50,7 +50,8 @@ extern algo_type sshkex[];
 extern algo_type sshhostkey[];
 extern algo_type sshciphers[];
 extern algo_type sshhashes[];
-extern algo_type sshcompress[];
+extern algo_type ssh_compress[];
+extern algo_type ssh_nocompress[];
 
 extern const struct dropbear_cipher dropbear_nocipher;
 extern const struct dropbear_cipher_mode dropbear_mode_none;
diff --git a/cli-runopts.c b/cli-runopts.c
index 93329f2..aedd4b7 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -144,6 +144,9 @@ void cli_getopts(int argc, char ** argv) {
 #endif
 #ifdef ENABLE_CLI_PROXYCMD
 	cli_opts.proxycmd = NULL;
+#endif
+#ifndef DISABLE_ZLIB
+	opts.enable_compress = 1;
 #endif
 	/* not yet
 	opts.ipv4 = 1;
@@ -530,6 +533,10 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
 		snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s", 
 				argv0, cli_opts.remotehost, cli_opts.remoteport, 
 				passthrough_args, remainder);
+#ifndef DISABLE_ZLIB
+		/* The stream will be incompressible since it's encrypted. */
+		opts.enable_compress = 0;
+#endif
 		m_free(passthrough_args);
 	}
 	m_free(hostbuf);
diff --git a/common-algo.c b/common-algo.c
index 892399f..7d694d2 100644
--- a/common-algo.c
+++ b/common-algo.c
@@ -168,11 +168,16 @@ algo_type sshhashes[] = {
 	{NULL, 0, NULL, 0, NULL}
 };
 
-algo_type sshcompress[] = {
 #ifndef DISABLE_ZLIB
+algo_type ssh_compress[] = {
 	{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
 	{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
+	{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
+	{NULL, 0, NULL, 0, NULL}
+};
 #endif
+
+algo_type ssh_nocompress[] = {
 	{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
 	{NULL, 0, NULL, 0, NULL}
 };
diff --git a/common-kex.c b/common-kex.c
index cb5cd96..8c47a48 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -33,6 +33,7 @@
 #include "packet.h"
 #include "bignum.h"
 #include "random.h"
+#include "runopts.h"
 
 /* diffie-hellman-group1-sha1 value for p */
 static const unsigned char dh_p_val[] = {
@@ -91,10 +92,10 @@ void send_msg_kexinit() {
 	buf_put_algolist(ses.writepayload, sshhashes);
 
 	/* compression_algorithms_client_to_server */
-	buf_put_algolist(ses.writepayload, sshcompress);
+	buf_put_algolist(ses.writepayload, ses.compress_algos);
 
 	/* compression_algorithms_server_to_client */
-	buf_put_algolist(ses.writepayload, sshcompress);
+	buf_put_algolist(ses.writepayload, ses.compress_algos);
 
 	/* languages_client_to_server */
 	buf_putstring(ses.writepayload, "", 0);
@@ -180,8 +181,16 @@ void recv_msg_newkeys() {
 
 /* Set up the kex for the first time */
 void kexfirstinitialise() {
-
 	ses.kexstate.donefirstkex = 0;
+
+#ifndef DISABLE_ZLIB
+	if (opts.enable_compress) {
+		ses.compress_algos = ssh_compress;
+	} else
+#endif
+	{
+		ses.compress_algos = ssh_nocompress;
+	}
 	kexinitialise();
 }
 
@@ -670,7 +679,7 @@ static void read_kex_algos() {
 	TRACE(("hash s2c is  %s", s2c_hash_algo->name))
 
 	/* compression_algorithms_client_to_server */
-	c2s_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
+	c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
 	if (c2s_comp_algo == NULL) {
 		erralgo = "comp c->s";
 		goto error;
@@ -678,7 +687,7 @@ static void read_kex_algos() {
 	TRACE(("hash c2s is  %s", c2s_comp_algo->name))
 
 	/* compression_algorithms_server_to_client */
-	s2c_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
+	s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
 	if (s2c_comp_algo == NULL) {
 		erralgo = "comp s->c";
 		goto error;
diff --git a/runopts.h b/runopts.h
index 9bf0c26..83b5861 100644
--- a/runopts.h
+++ b/runopts.h
@@ -40,6 +40,14 @@ typedef struct runopts {
 	time_t keepalive_secs;
 	time_t idle_timeout_secs;
 
+#ifndef DISABLE_ZLIB
+	/* TODO: add a commandline flag. Currently this is on by default if compression
+	 * is compiled in, but disabled for a client's non-final multihop stages. (The
+	 * intermediate stages are compressed streams, so are uncompressible. */
+	int enable_compress;
+#endif
+
+
 } runopts;
 
 extern runopts opts;
@@ -135,7 +143,6 @@ typedef struct cli_runopts {
 #ifdef ENABLE_CLI_PROXYCMD
 	char *proxycmd;
 #endif
-
 } cli_runopts;
 
 extern cli_runopts cli_opts;
diff --git a/session.h b/session.h
index 20a90a4..355cf03 100644
--- a/session.h
+++ b/session.h
@@ -160,6 +160,9 @@ struct sshsession {
 	buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
 	buffer* transkexinit; /* the kexinit packet we send should be kept so we
 							 can add it to the hash when generating keys */
+
+	/* Enables/disables compression */
+	algo_type *compress_algos;
 							
 	/* a list of queued replies that should be sent after a KEX has
 	   concluded (ie, while dataallowed was unset)*/
diff --git a/svr-runopts.c b/svr-runopts.c
index 4e59b75..8a3396a 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -124,6 +124,9 @@ void svr_getopts(int argc, char ** argv) {
 #endif
 #ifdef ENABLE_SVR_REMOTETCPFWD
 	svr_opts.noremotetcp = 0;
+#endif
+#ifndef DISABLE_ZLIB
+	opts.enable_compress = 1;
 #endif
 	/* not yet
 	opts.ipv4 = 1;