changeset 1127:b803ad2b9f4c

Merge pull request #11 from nshopik/patch-2 Prepend DROPBEAR for scp.c
author Matt Johnston <matt@ucc.asn.au>
date Fri, 12 Jun 2015 22:57:48 +0800
parents 7cb1f49d89a8 (diff) 2dee3eef5344 (current diff)
children a9e074b78cd5 45830474d83c
files
diffstat 61 files changed, 348 insertions(+), 273 deletions(-) [+]
line wrap: on
line diff
--- a/.travis.yml	Thu Mar 12 15:14:47 2015 +0300
+++ b/.travis.yml	Fri Jun 12 22:57:48 2015 +0800
@@ -3,7 +3,9 @@
   - gcc
 
 script: 
-  - autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst && make install
+  - autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst 
+  - test "$NOWRITEV" && sed -i s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h || true
+  - make install
   - ~/inst/bin/dropbearkey -t rsa -f testrsa
   - ~/inst/bin/dropbearkey -t dss -f testdss
   - ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
@@ -18,3 +20,4 @@
   - BUNDLEDLIBTOM=--disable-bundled-libtom
   - BUNDLEDLIBTOM=--enable-bundled-libtom
   - MULTI=1
+  - NOWRITEV=1
--- a/CHANGES	Thu Mar 12 15:14:47 2015 +0300
+++ b/CHANGES	Fri Jun 12 22:57:48 2015 +0800
@@ -1,19 +1,32 @@
-- Improve efficiency of writing data to local program/pipes, measured 30% for
-  connections to localhost
+- Improve efficiency of writing data to local program/pipes, measured 30% increase
+  increase in throughput for connections to localhost
 
 - Use TCP Fast Open on Linux if available. saves a round trip at connection
   to hosts that have previously been connected. 
   Needs a recent Linux kernel and possibly "sysctl -w net.ipv4.tcp_fastopen=3"
+  Client side is disabled by default pending further compatibility testing
+  with networks and systems.
 
 - Forwarded TCP ports connect asynchronously and retry with other available
-  addresses (IPv4 or IPv6)
+  addresses (IPv4 or IPv6, round robin IPs)
 
 - Free memory before exiting, patch from Thorsten Horstmann. Useful for
   Dropbear ports to embedded systems and for checking memory leaks
   with valgrind. Only partially implemented for client side.
 
+- Fix all compile warnings, patch from Gaƫl Portay
+  (note that configure with -Werror may not be successful on some platforms
+  such as OS X and some configuration options may result in unused variable
+  warnings)
+
 - Fix small ECC memory leaks
 
+- Tighten validation of Diffie-Hellman parameters, from Florent Daigniere of
+  Matt Consulting. Odds of bad values are around 2**-512 -- improbable.
+
+- Twofish-ctr cipher is supported though disabled by default
+
+
 2015.67 - Wednesday 28 January 2015
 
 - Call fsync() after generating private keys to ensure they aren't lost if a
--- a/LICENSE	Thu Mar 12 15:14:47 2015 +0300
+++ b/LICENSE	Fri Jun 12 22:57:48 2015 +0800
@@ -8,7 +8,7 @@
 Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
 same license:
 
-Copyright (c) 2002-2014 Matt Johnston
+Copyright (c) 2002-2015 Matt Johnston
 Portions copyright (c) 2004 Mihnea Stoenescu
 All rights reserved.
 
--- a/algo.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/algo.h	Fri Jun 12 22:57:48 2015 +0800
@@ -35,7 +35,7 @@
 
 struct Algo_Type {
 
-	const unsigned char *name; /* identifying name */
+	const char *name; /* identifying name */
 	char val; /* a value for this cipher, or -1 for invalid */
 	const void *data; /* algorithm specific data */
 	char usable; /* whether we can use this algorithm */
--- a/auth.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/auth.h	Fri Jun 12 22:57:48 2015 +0800
@@ -133,7 +133,7 @@
 	int no_x11_forwarding_flag;
 	int no_pty_flag;
 	/* "command=" option. */
-	unsigned char * forced_command;
+	char * forced_command;
 };
 #endif
 
--- a/buffer.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/buffer.c	Fri Jun 12 22:57:48 2015 +0800
@@ -203,10 +203,10 @@
 /* Return a null-terminated string, it is malloced, so must be free()ed
  * Note that the string isn't checked for null bytes, hence the retlen
  * may be longer than what is returned by strlen */
-unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
+char* buf_getstring(buffer* buf, unsigned int *retlen) {
 
 	unsigned int len;
-	unsigned char* ret;
+	char* ret;
 	len = buf_getint(buf);
 	if (len > MAX_STRING_LEN) {
 		dropbear_exit("String too long");
@@ -262,16 +262,16 @@
 }
 
 /* put a SSH style string into the buffer, increasing buffer len if required */
-void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
+void buf_putstring(buffer* buf, const char* str, unsigned int len) {
 	
 	buf_putint(buf, len);
-	buf_putbytes(buf, str, len);
+	buf_putbytes(buf, (const unsigned char*)str, len);
 
 }
 
 /* puts an entire buffer as a SSH string. ignore pos of buf_str. */
 void buf_putbufstring(buffer *buf, const buffer* buf_str) {
-	buf_putstring(buf, buf_str->data, buf_str->len);
+	buf_putstring(buf, (const char*)buf_str->data, buf_str->len);
 }
 
 /* put the set of len bytes into the buffer, incrementing the pos, increasing
--- a/buffer.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/buffer.h	Fri Jun 12 22:57:48 2015 +0800
@@ -56,11 +56,11 @@
 void buf_putbyte(buffer* buf, unsigned char val);
 unsigned char* buf_getptr(buffer* buf, unsigned int len);
 unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
-unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
+char* buf_getstring(buffer* buf, unsigned int *retlen);
 buffer * buf_getstringbuf(buffer *buf);
 void buf_eatstring(buffer *buf);
 void buf_putint(buffer* buf, unsigned int val);
-void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
+void buf_putstring(buffer* buf, const char* str, unsigned int len);
 void buf_putbufstring(buffer *buf, const buffer* buf_str);
 void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
 void buf_putmpint(buffer* buf, mp_int * mp);
--- a/channel.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/channel.h	Fri Jun 12 22:57:48 2015 +0800
@@ -106,7 +106,7 @@
 
 void chaninitialise(const struct ChanType *chantypes[]);
 void chancleanup();
-void setchannelfds(fd_set *readfd, fd_set *writefd);
+void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads);
 void channelio(fd_set *readfd, fd_set *writefd);
 struct Channel* getchannel();
 /* Returns an arbitrary channel that is in a ready state - not
@@ -135,7 +135,7 @@
 void recv_msg_channel_open_confirmation();
 void recv_msg_channel_open_failure();
 #endif
-void start_send_channel_request(struct Channel *channel, unsigned char *type);
+void start_send_channel_request(struct Channel *channel, char *type);
 
 void send_msg_request_success();
 void send_msg_request_failure();
--- a/chansession.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/chansession.h	Fri Jun 12 22:57:48 2015 +0800
@@ -39,14 +39,14 @@
 
 struct ChanSess {
 
-	unsigned char * cmd; /* command to exec */
+	char * cmd; /* command to exec */
 	pid_t pid; /* child process pid */
 
 	/* pty details */
 	int master; /* the master terminal fd*/
 	int slave;
-	unsigned char * tty;
-	unsigned char * term;
+	char * tty;
+	char * term;
 
 	/* exit details */
 	struct exitinfo exit;
--- a/circbuffer.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/circbuffer.c	Fri Jun 12 22:57:48 2015 +0800
@@ -67,23 +67,6 @@
 
 }
 
-unsigned int cbuf_readlen(circbuffer *cbuf) {
-
-	dropbear_assert(((2*cbuf->size)+cbuf->writepos-cbuf->readpos)%cbuf->size == cbuf->used%cbuf->size);
-	dropbear_assert(((2*cbuf->size)+cbuf->readpos-cbuf->writepos)%cbuf->size == (cbuf->size-cbuf->used)%cbuf->size);
-
-	if (cbuf->used == 0) {
-		TRACE(("cbuf_readlen: unused buffer"))
-		return 0;
-	}
-
-	if (cbuf->readpos < cbuf->writepos) {
-		return cbuf->writepos - cbuf->readpos;
-	}
-
-	return cbuf->size - cbuf->readpos;
-}
-
 unsigned int cbuf_writelen(circbuffer *cbuf) {
 
 	dropbear_assert(cbuf->used <= cbuf->size);
@@ -102,14 +85,6 @@
 	return cbuf->size - cbuf->writepos;
 }
 
-unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
-	if (len > cbuf_readlen(cbuf)) {
-		dropbear_exit("Bad cbuf read");
-	}
-
-	return &cbuf->data[cbuf->readpos];
-}
-
 void cbuf_readptrs(circbuffer *cbuf, 
 	unsigned char **p1, unsigned int *len1, 
 	unsigned char **p2, unsigned int *len2) {
@@ -146,12 +121,6 @@
 
 
 void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
-#if 0
-	if (len > cbuf_readlen(cbuf)) {
-		dropbear_exit("Bad cbuf read");
-	}
-#endif
-
 	dropbear_assert(cbuf->used >= len);
 	cbuf->used -= len;
 	cbuf->readpos = (cbuf->readpos + len) % cbuf->size;
--- a/circbuffer.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/circbuffer.h	Fri Jun 12 22:57:48 2015 +0800
@@ -40,10 +40,9 @@
 
 unsigned int cbuf_getused(circbuffer * cbuf); /* how much data stored */
 unsigned int cbuf_getavail(circbuffer * cbuf); /* how much we can write */
-unsigned int cbuf_readlen(circbuffer *cbuf); /* max linear read len */
 unsigned int cbuf_writelen(circbuffer *cbuf); /* max linear write len */
 
-unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len);
+/* returns pointers to the two portions of the circular buffer that can be read */
 void cbuf_readptrs(circbuffer *cbuf, 
 	unsigned char **p1, unsigned int *len1, 
 	unsigned char **p2, unsigned int *len2);
--- a/cli-auth.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/cli-auth.c	Fri Jun 12 22:57:48 2015 +0800
@@ -43,9 +43,9 @@
 	TRACE(("enter cli_auth_getmethods"))
 	CHECKCLEARTOWRITE();
 	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
-	buf_putstring(ses.writepayload, cli_opts.username, 
+	buf_putstring(ses.writepayload, cli_opts.username,
 			strlen(cli_opts.username));
-	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, 
+	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
 			SSH_SERVICE_CONNECTION_LEN);
 	buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
 
@@ -75,7 +75,7 @@
 
 void recv_msg_userauth_banner() {
 
-	unsigned char* banner = NULL;
+	char* banner = NULL;
 	unsigned int bannerlen;
 	unsigned int i, linecount;
 
@@ -151,8 +151,8 @@
 
 void recv_msg_userauth_failure() {
 
-	unsigned char * methods = NULL;
-	unsigned char * tok = NULL;
+	char * methods = NULL;
+	char * tok = NULL;
 	unsigned int methlen = 0;
 	unsigned int partial = 0;
 	unsigned int i = 0;
--- a/cli-authinteract.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/cli-authinteract.c	Fri Jun 12 22:57:48 2015 +0800
@@ -31,10 +31,10 @@
 
 #ifdef ENABLE_CLI_INTERACT_AUTH
 
-static unsigned char* get_response(unsigned char* prompt)
+static char* get_response(char* prompt)
 {
 	FILE* tty = NULL;
-	unsigned char* response = NULL;
+	char* response = NULL;
 	/* not a password, but a reasonable limit */
 	char buf[DROPBEAR_MAX_CLI_PASS];
 	char* ret = NULL;
@@ -50,13 +50,13 @@
 	}
 
 	if (ret == NULL) {
-		response = (unsigned char*)m_strdup("");
+		response = m_strdup("");
 	} else {
 		unsigned int buflen = strlen(buf);
 		/* fgets includes newlines */
 		if (buflen > 0 && buf[buflen-1] == '\n')
 			buf[buflen-1] = '\0';
-		response = (unsigned char*)m_strdup(buf);
+		response = m_strdup(buf);
 	}
 
 	m_burn(buf, sizeof(buf));
@@ -66,14 +66,14 @@
 
 void recv_msg_userauth_info_request() {
 
-	unsigned char *name = NULL;
-	unsigned char *instruction = NULL;
+	char *name = NULL;
+	char *instruction = NULL;
 	unsigned int num_prompts = 0;
 	unsigned int i;
 
-	unsigned char *prompt = NULL;
+	char *prompt = NULL;
 	unsigned int echo = 0;
-	unsigned char *response = NULL;
+	char *response = NULL;
 
 	TRACE(("enter recv_msg_recv_userauth_info_request"))
 
@@ -121,7 +121,7 @@
 		echo = buf_getbool(ses.payload);
 
 		if (!echo) {
-			unsigned char* p = getpass_or_cancel(prompt);
+			char* p = getpass_or_cancel(prompt);
 			response = m_strdup(p);
 			m_burn(p, strlen(p));
 		} else {
@@ -153,7 +153,7 @@
 			strlen(cli_opts.username));
 
 	/* service name */
-	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, 
+	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
 			SSH_SERVICE_CONNECTION_LEN);
 
 	/* method */
--- a/cli-authpasswd.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/cli-authpasswd.c	Fri Jun 12 22:57:48 2015 +0800
@@ -143,10 +143,10 @@
 	buf_putstring(ses.writepayload, cli_opts.username,
 			strlen(cli_opts.username));
 
-	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, 
+	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
 			SSH_SERVICE_CONNECTION_LEN);
 
-	buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD, 
+	buf_putstring(ses.writepayload, AUTH_METHOD_PASSWORD,
 			AUTH_METHOD_PASSWORD_LEN);
 
 	buf_putbyte(ses.writepayload, 0); /* FALSE - so says the spec */
--- a/cli-authpubkey.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/cli-authpubkey.c	Fri Jun 12 22:57:48 2015 +0800
@@ -141,7 +141,7 @@
 static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
 
 	const char *algoname = NULL;
-	int algolen;
+	unsigned int algolen;
 	buffer* sigbuf = NULL;
 
 	TRACE(("enter send_msg_userauth_pubkey"))
@@ -152,10 +152,10 @@
 	buf_putstring(ses.writepayload, cli_opts.username,
 			strlen(cli_opts.username));
 
-	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, 
+	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
 			SSH_SERVICE_CONNECTION_LEN);
 
-	buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY, 
+	buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY,
 			AUTH_METHOD_PUBKEY_LEN);
 
 	buf_putbyte(ses.writepayload, realsign);
--- a/cli-chansession.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/cli-chansession.c	Fri Jun 12 22:57:48 2015 +0800
@@ -56,7 +56,7 @@
 
 static void cli_chansessreq(struct Channel *channel) {
 
-	unsigned char* type = NULL;
+	char* type = NULL;
 	int wantreply;
 
 	TRACE(("enter cli_chansessreq"))
@@ -272,7 +272,7 @@
 
 static void send_chansess_pty_req(struct Channel *channel) {
 
-	unsigned char* term = NULL;
+	char* term = NULL;
 
 	TRACE(("enter send_chansess_pty_req"))
 
@@ -305,7 +305,7 @@
 
 static void send_chansess_shell_req(struct Channel *channel) {
 
-	unsigned char* reqtype = NULL;
+	char* reqtype = NULL;
 
 	TRACE(("enter send_chansess_shell_req"))
 
@@ -392,7 +392,7 @@
 
 void cli_send_netcat_request() {
 
-	const unsigned char* source_host = "127.0.0.1";
+	const char* source_host = "127.0.0.1";
 	const int source_port = 22;
 
 	TRACE(("enter cli_send_netcat_request"))
@@ -403,7 +403,7 @@
 		dropbear_exit("Couldn't open initial channel");
 	}
 
-	buf_putstring(ses.writepayload, cli_opts.netcat_host, 
+	buf_putstring(ses.writepayload, cli_opts.netcat_host,
 			strlen(cli_opts.netcat_host));
 	buf_putint(ses.writepayload, cli_opts.netcat_port);
 
--- a/cli-kex.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/cli-kex.c	Fri Jun 12 22:57:48 2015 +0800
@@ -79,7 +79,7 @@
 				}
 				cli_ses.curve25519_param = gen_kexcurve25519_param();
 			}
-			buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
+			buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
 #endif
 			break;
 	}
@@ -322,7 +322,7 @@
 		}
 
 		/* Compare hostnames */
-		if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
+		if (strncmp(cli_opts.remotehost, (const char *) buf_getptr(line, hostlen),
 					hostlen) != 0) {
 			continue;
 		}
@@ -334,7 +334,7 @@
 			continue;
 		}
 
-		if (strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) {
+		if (strncmp((const char *) buf_getptr(line, algolen), algoname, algolen) != 0) {
 			TRACE(("algo doesn't match"))
 			continue;
 		}
@@ -346,7 +346,7 @@
 		}
 
 		/* Now we're at the interesting hostkey */
-		ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen,
+		ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algoname, algolen,
 						line, &fingerprint);
 
 		if (ret == DROPBEAR_SUCCESS) {
@@ -382,9 +382,9 @@
 		fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
 		buf_setpos(line, 0);
 		buf_setlen(line, 0);
-		buf_putbytes(line, cli_opts.remotehost, hostlen);
+		buf_putbytes(line, (const unsigned char *) cli_opts.remotehost, hostlen);
 		buf_putbyte(line, ' ');
-		buf_putbytes(line, algoname, algolen);
+		buf_putbytes(line, (const unsigned char *) algoname, algolen);
 		buf_putbyte(line, ' ');
 		len = line->size - line->pos;
 		/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
--- a/cli-runopts.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/cli-runopts.c	Fri Jun 12 22:57:48 2015 +0800
@@ -447,7 +447,7 @@
 	}
 #endif
 
-#ifdef DROPBEAR_DEFAULT_CLI_AUTHKEY
+#if defined(DROPBEAR_DEFAULT_CLI_AUTHKEY) && defined(ENABLE_CLI_PUBKEY_AUTH)
 	{
 		char *expand_path = expand_tilde(DROPBEAR_DEFAULT_CLI_AUTHKEY);
 		loadidentityfile(expand_path, 0);
@@ -498,11 +498,14 @@
 	m_list_elem *iter;
 	/* Fill out -i, -y, -W options that make sense for all
 	 * the intermediate processes */
+#ifdef ENABLE_CLI_PUBKEY_AUTH
 	for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
 	{
 		sign_key * key = (sign_key*)iter->item;
 		len += 3 + strlen(key->filename);
 	}
+#endif /* ENABLE_CLI_PUBKEY_AUTH */
+
 	len += 30; /* space for -W <size>, terminator. */
 	ret = m_malloc(len);
 	total = 0;
@@ -524,6 +527,7 @@
 		total += written;
 	}
 
+#ifdef ENABLE_CLI_PUBKEY_AUTH
 	for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
 	{
 		sign_key * key = (sign_key*)iter->item;
@@ -532,6 +536,7 @@
 		dropbear_assert((unsigned int)written < size);
 		total += written;
 	}
+#endif /* ENABLE_CLI_PUBKEY_AUTH */
 
 	/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
 	if (total > 0) 
--- a/cli-session.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/cli-session.c	Fri Jun 12 22:57:48 2015 +0800
@@ -124,6 +124,8 @@
 	/* Exchange identification */
 	send_session_identification();
 
+	kexfirstinitialise(); /* initialise the kex state */
+
 	send_msg_kexinit();
 
 	session_loop(cli_sessionloop);
@@ -372,10 +374,10 @@
 /* Operates in-place turning dirty (untrusted potentially containing control
  * characters) text into clean text. 
  * Note: this is safe only with ascii - other charsets could have problems. */
-void cleantext(unsigned char* dirtytext) {
+void cleantext(char* dirtytext) {
 
 	unsigned int i, j;
-	unsigned char c;
+	char c;
 
 	j = 0;
 	for (i = 0; dirtytext[i] != '\0'; i++) {
--- a/common-algo.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/common-algo.c	Fri Jun 12 22:57:48 2015 +0800
@@ -144,12 +144,15 @@
 #ifdef DROPBEAR_AES256
 	{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
 #endif
+#ifdef DROPBEAR_TWOFISH_CTR
+/* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
 #ifdef DROPBEAR_TWOFISH256
 	{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
 #endif
 #ifdef DROPBEAR_TWOFISH128
 	{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
 #endif
+#endif /* DROPBEAR_TWOFISH_CTR */
 #endif /* DROPBEAR_ENABLE_CTR_MODE */
 
 #ifdef DROPBEAR_ENABLE_CBC_MODE
@@ -322,10 +325,10 @@
 				buf_putbyte(algolist, ',');
 			donefirst = 1;
 			len = strlen(localalgos[i].name);
-			buf_putbytes(algolist, localalgos[i].name, len);
+			buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
 		}
 	}
-	buf_putstring(buf, algolist->data, algolist->len);
+	buf_putstring(buf, (const char*)algolist->data, algolist->len);
 	buf_free(algolist);
 }
 
@@ -338,12 +341,12 @@
 		enum kexguess2_used *kexguess2, int *goodguess)
 {
 
-	unsigned char * algolist = NULL;
-	const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
+	char * algolist = NULL;
+	const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
 	unsigned int len;
 	unsigned int remotecount, localcount, clicount, servcount, i, j;
 	algo_type * ret = NULL;
-	const unsigned char **clinames, **servnames;
+	const char **clinames, **servnames;
 
 	if (goodguess) {
 		*goodguess = 0;
@@ -488,7 +491,7 @@
 	buf_setpos(b, b->len);
 	buf_putbyte(b, '\0');
 	buf_setpos(b, 4);
-	ret_list = m_strdup(buf_getptr(b, b->len - b->pos));
+	ret_list = m_strdup((const char *) buf_getptr(b, b->len - b->pos));
 	buf_free(b);
 	return ret_list;
 }
--- a/common-channel.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/common-channel.c	Fri Jun 12 22:57:48 2015 +0800
@@ -38,7 +38,7 @@
 #include "netio.h"
 
 static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
-		const unsigned char *text, const unsigned char *lang);
+		const char *text, const char *lang);
 static void send_msg_channel_open_confirmation(struct Channel* channel,
 		unsigned int recvwindow, 
 		unsigned int recvmaxpacket);
@@ -434,10 +434,36 @@
 	TRACE(("leave send_msg_channel_eof"))
 }
 
-/* Called to write data out to the local side of the channel. 
-   Writes the circular buffer contents and also the "moredata" buffer
-   if not null. Will ignore EAGAIN */
-static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
+#ifndef HAVE_WRITEV
+static void writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
+	const unsigned char *UNUSED(moredata), unsigned int *morelen) {
+
+	unsigned char *circ_p1, *circ_p2;
+	unsigned int circ_len1, circ_len2;
+	ssize_t written;
+
+	if (morelen) {
+		/* fallback doesn't consume moredata */
+		*morelen = 0;
+	}
+
+	/* Write the first portion of the circular buffer */
+	cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
+	written = write(fd, circ_p1, circ_len1);
+	if (written < 0) {
+		if (errno != EINTR && errno != EAGAIN) {
+			TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
+			close_chan_fd(channel, fd, SHUT_WR);
+		}
+	} else {
+		cbuf_incrread(cbuf, written);
+		channel->recvdonelen += written;
+	}
+}
+#endif /* !HAVE_WRITEV */
+
+#ifdef HAVE_WRITEV
+static void writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf,
 	const unsigned char *moredata, unsigned int *morelen) {
 
 	struct iovec iov[3];
@@ -445,9 +471,7 @@
 	unsigned int circ_len1, circ_len2;
 	int io_count = 0;
 
-	int written;
-
-	TRACE(("enter writechannel fd %d", fd))
+	ssize_t written;
 
 	cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
 
@@ -473,6 +497,14 @@
 		io_count++;
 	}
 
+	if (io_count == 0) {
+		/* writechannel may sometimes be called twice in a main loop iteration.
+		From common_recv_msg_channel_data() then channelio().
+		The second call may not have any data to write, so we just return. */
+		TRACE(("leave writechannel, no data"))
+		return;
+	}
+
 	if (morelen) {
 		/* Default return value, none consumed */
 		*morelen = 0;
@@ -482,7 +514,7 @@
 
 	if (written < 0) {
 		if (errno != EINTR && errno != EAGAIN) {
-			TRACE(("errno %d len %d", errno, len))
+			TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
 			close_chan_fd(channel, fd, SHUT_WR);
 		}
 	} else {
@@ -494,24 +526,19 @@
 		channel->recvdonelen += written;
 	}
 
-#if 0
-
-	maxlen = cbuf_readlen(cbuf);
+}
+#endif /* HAVE_WRITEV */
 
-	/* Write the data out */
-	len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
-	if (len <= 0) {
-		TRACE(("errno %d len %d", errno, len))
-		if (len < 0 && errno != EINTR) {
-			close_chan_fd(channel, fd, SHUT_WR);
-		}
-		TRACE(("leave writechannel: len <= 0"))
-		return;
-	}
-	TRACE(("writechannel wrote %d", len))
-
-	cbuf_incrread(cbuf, len);
-	channel->recvdonelen += len;
+/* Called to write data out to the local side of the channel. 
+   Writes the circular buffer contents and also the "moredata" buffer
+   if not null. Will ignore EAGAIN */
+static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
+	const unsigned char *moredata, unsigned int *morelen) {
+	TRACE(("enter writechannel fd %d", fd))
+#ifdef HAVE_WRITEV
+	writechannel_writev(channel, fd, cbuf, moredata, morelen);
+#else
+	writechannel_fallback(channel, fd, cbuf, moredata, morelen);
 #endif
 
 	/* Window adjust handling */
@@ -529,9 +556,10 @@
 	TRACE(("leave writechannel"))
 }
 
+
 /* Set the file descriptors for the main select in session.c
  * This avoid channels which don't have any window available, are closed, etc*/
-void setchannelfds(fd_set *readfds, fd_set *writefds) {
+void setchannelfds(fd_set *readfds, fd_set *writefds, int allow_reads) {
 	
 	unsigned int i;
 	struct Channel * channel;
@@ -549,7 +577,7 @@
 		FD if there's the possibility of "~."" to kill an 
 		interactive session (the read_mangler) */
 		if (channel->transwindow > 0
-		   && (ses.dataallowed || channel->read_mangler)) {
+		   && ((ses.dataallowed && allow_reads) || channel->read_mangler)) {
 
 			if (channel->readfd >= 0) {
 				FD_SET(channel->readfd, readfds);
@@ -830,6 +858,7 @@
 	channel->recvwindow -= datalen;
 	dropbear_assert(channel->recvwindow <= opts.recv_window);
 
+	/* Attempt to write the data immediately without having to put it in the circular buffer */
 	consumed = datalen;
 	writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed);
 
@@ -892,7 +921,7 @@
 /* Handle a new channel request, performing any channel-type-specific setup */
 void recv_msg_channel_open() {
 
-	unsigned char *type;
+	char *type;
 	unsigned int typelen;
 	unsigned int remotechan, transwindow, transmaxpacket;
 	struct Channel *channel;
@@ -1010,7 +1039,7 @@
 /* Send a channel open failure message, with a corresponding reason
  * code (usually resource shortage or unknown chan type) */
 static void send_msg_channel_open_failure(unsigned int remotechan, 
-		int reason, const unsigned char *text, const unsigned char *lang) {
+		int reason, const char *text, const char *lang) {
 
 	TRACE(("enter send_msg_channel_open_failure"))
 	CHECKCLEARTOWRITE();
@@ -1018,8 +1047,8 @@
 	buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN_FAILURE);
 	buf_putint(ses.writepayload, remotechan);
 	buf_putint(ses.writepayload, reason);
-	buf_putstring(ses.writepayload, text, strlen((char*)text));
-	buf_putstring(ses.writepayload, lang, strlen((char*)lang));
+	buf_putstring(ses.writepayload, text, strlen(text));
+	buf_putstring(ses.writepayload, lang, strlen(lang));
 
 	encrypt_packet();
 	TRACE(("leave send_msg_channel_open_failure"))
@@ -1215,7 +1244,7 @@
 }
 
 void start_send_channel_request(struct Channel *channel, 
-		unsigned char *type) {
+		char *type) {
 
 	CHECKCLEARTOWRITE();
 	buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
--- a/common-kex.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/common-kex.c	Fri Jun 12 22:57:48 2015 +0800
@@ -511,7 +511,7 @@
 
 	/* start the kex hash */
 	local_ident_len = strlen(LOCAL_IDENT);
-	remote_ident_len = strlen((char*)ses.remoteident);
+	remote_ident_len = strlen(ses.remoteident);
 
 	kexhashbuf_len = local_ident_len + remote_ident_len
 		+ ses.transkexinit->len + ses.payload->len
@@ -525,18 +525,17 @@
 		read_kex_algos();
 
 		/* V_C, the client's version string (CR and NL excluded) */
-	    buf_putstring(ses.kexhashbuf,
-			(unsigned char*)LOCAL_IDENT, local_ident_len);
+	    buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
 		/* V_S, the server's version string (CR and NL excluded) */
 	    buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
 
 		/* I_C, the payload of the client's SSH_MSG_KEXINIT */
 	    buf_putstring(ses.kexhashbuf,
-			ses.transkexinit->data, ses.transkexinit->len);
+			(const char*)ses.transkexinit->data, ses.transkexinit->len);
 		/* I_S, the payload of the server's SSH_MSG_KEXINIT */
 	    buf_setpos(ses.payload, ses.payload_beginning);
 	    buf_putstring(ses.kexhashbuf, 
-	    	buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
+	    	(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
 	    	ses.payload->len-ses.payload->pos);
 		ses.requirenext = SSH_MSG_KEXDH_REPLY;
 	} else {
@@ -547,18 +546,17 @@
 		/* V_C, the client's version string (CR and NL excluded) */
 	    buf_putstring(ses.kexhashbuf, ses.remoteident, remote_ident_len);
 		/* V_S, the server's version string (CR and NL excluded) */
-	    buf_putstring(ses.kexhashbuf, 
-				(unsigned char*)LOCAL_IDENT, local_ident_len);
+	    buf_putstring(ses.kexhashbuf, LOCAL_IDENT, local_ident_len);
 
 		/* I_C, the payload of the client's SSH_MSG_KEXINIT */
 	    buf_setpos(ses.payload, ses.payload_beginning);
 	    buf_putstring(ses.kexhashbuf, 
-	    	buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
+	    	(const char*)buf_getptr(ses.payload, ses.payload->len-ses.payload->pos),
 	    	ses.payload->len-ses.payload->pos);
 
 		/* I_S, the payload of the server's SSH_MSG_KEXINIT */
 	    buf_putstring(ses.kexhashbuf,
-			ses.transkexinit->data, ses.transkexinit->len);
+			(const char*)ses.transkexinit->data, ses.transkexinit->len);
 
 		ses.requirenext = SSH_MSG_KEXDH_INIT;
 	}
@@ -783,9 +781,9 @@
 	/* K_S, the host key */
 	buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
 	/* Q_C, client's ephemeral public key octet string */
-	buf_putstring(ses.kexhashbuf, Q_C, CURVE25519_LEN);
+	buf_putstring(ses.kexhashbuf, (const char*)Q_C, CURVE25519_LEN);
 	/* Q_S, server's ephemeral public key octet string */
-	buf_putstring(ses.kexhashbuf, Q_S, CURVE25519_LEN);
+	buf_putstring(ses.kexhashbuf, (const char*)Q_S, CURVE25519_LEN);
 	/* K, the shared secret */
 	buf_putmpint(ses.kexhashbuf, ses.dh_K);
 
--- a/common-session.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/common-session.c	Fri Jun 12 22:57:48 2015 +0800
@@ -1,7 +1,7 @@
 /*
  * Dropbear - a SSH2 server
  * 
- * Copyright (c) 2002,2003 Matt Johnston
+ * Copyright (c) Matt Johnston
  * All rights reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -64,6 +64,13 @@
 	ses.sock_out = sock_out;
 	ses.maxfd = MAX(sock_in, sock_out);
 
+	if (sock_in >= 0) {
+		setnonblocking(sock_in);
+	}
+	if (sock_out >= 0) {
+		setnonblocking(sock_out);
+	}
+
 	ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
 	/* Sets it to lowdelay */
 	update_channel_prio();
@@ -83,8 +90,6 @@
 	ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
 	ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
 	
-	kexfirstinitialise(); /* initialise the kex state */
-
 	ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
 	ses.transseq = 0;
 
@@ -145,6 +150,7 @@
 
 	/* main loop, select()s for all sockets in use */
 	for(;;) {
+		const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);
 
 		timeout.tv_sec = select_timeout();
 		timeout.tv_usec = 0;
@@ -155,8 +161,12 @@
 		/* We delay reading from the input socket during initial setup until
 		after we have written out our initial KEXINIT packet (empty writequeue). 
 		This means our initial packet can be in-flight while we're doing a blocking
-		read for the remote ident */
-		if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
+		read for the remote ident.
+		We also avoid reading from the socket if the writequeue is full, that avoids
+		replies backing up */
+		if (ses.sock_in != -1 
+			&& (ses.remoteident || isempty(&ses.writequeue)) 
+			&& writequeue_has_space) {
 			FD_SET(ses.sock_in, &readfd);
 		}
 		if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
@@ -168,7 +178,7 @@
 		FD_SET(ses.signal_pipe[0], &readfd);
 
 		/* set up for channels which can be read/written */
-		setchannelfds(&readfd, &writefd);
+		setchannelfds(&readfd, &writefd, writequeue_has_space);
 
 		/* Pending connections to test */
 		set_connect_fds(&writefd);
@@ -268,7 +278,7 @@
 		return;
 	}
 
-	/* Beware of changing order of functions here. */
+	/* BEWARE of changing order of functions here. */
 
 	/* Must be before extra_session_cleanup() */
 	chancleanup();
@@ -277,7 +287,7 @@
 		ses.extra_session_cleanup();
 	}
 
-	/* After these are freed most functions will exit */
+	/* After these are freed most functions will fail */
 #ifdef DROPBEAR_CLEANUP
 	/* listeners call cleanup functions, this should occur before
 	other session state is freed. */
@@ -317,10 +327,8 @@
 
 void send_session_identification() {
 	buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
-	buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
-	buf_putbyte(writebuf, 0x0); /* packet type */
-	buf_setpos(writebuf, 0);
-	enqueue(&ses.writequeue, writebuf);
+	buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
+	writebuf_enqueue(writebuf, 0);
 }
 
 static void read_session_identification() {
--- a/configure.ac	Thu Mar 12 15:14:47 2015 +0300
+++ b/configure.ac	Fri Jun 12 22:57:48 2015 +0800
@@ -265,7 +265,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 		]],
-		[[ struct sockaddr_storage s; ]])],
+		[[ if (sizeof(struct sockaddr_storage)) return 0 ]])],
 		[ ac_cv_have_struct_sockaddr_storage="yes" ],
 		[ ac_cv_have_struct_sockaddr_storage="no" ]
 	)
@@ -279,7 +279,7 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 		]],
-		[[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
+		[[ if (sizeof(struct sockaddr_in6)) return 0 ]])],
 		[ ac_cv_have_struct_sockaddr_in6="yes" ],
 		[ ac_cv_have_struct_sockaddr_in6="no" ]
 	)
@@ -293,7 +293,7 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 		]],
-		[[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
+		[[ if (sizeof(struct in6_addr)) return 0 ]])],
 		[ ac_cv_have_struct_in6_addr="yes" ],
 		[ ac_cv_have_struct_in6_addr="no" ]
 	)
@@ -308,7 +308,7 @@
 #include <sys/socket.h>
 #include <netdb.h>
 		]],
-		[[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
+		[[ if (sizeof(struct addrinfo)) return 0 ]])],
 		[ ac_cv_have_struct_addrinfo="yes" ],
 		[ ac_cv_have_struct_addrinfo="no" ]
 	)
--- a/dbrandom.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/dbrandom.c	Fri Jun 12 22:57:48 2015 +0800
@@ -141,7 +141,7 @@
 	return ret;
 }
 
-void addrandom(char * buf, unsigned int len)
+void addrandom(unsigned char * buf, unsigned int len)
 {
 	hash_state hs;
 
--- a/dbrandom.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/dbrandom.h	Fri Jun 12 22:57:48 2015 +0800
@@ -29,7 +29,7 @@
 
 void seedrandom();
 void genrandom(unsigned char* buf, unsigned int len);
-void addrandom(char * buf, unsigned int len);
+void addrandom(unsigned char * buf, unsigned int len);
 void gen_random_mpint(mp_int *max, mp_int *rand);
 
 #endif /* DROPBEAR_RANDOM_H_ */
--- a/dss.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/dss.c	Fri Jun 12 22:57:48 2015 +0800
@@ -165,7 +165,7 @@
 	DEF_MP_INT(val3);
 	DEF_MP_INT(val4);
 	char * string = NULL;
-	int stringlen;
+	unsigned int stringlen;
 
 	TRACE(("enter buf_dss_verify"))
 	dropbear_assert(key != NULL);
@@ -186,7 +186,7 @@
 	/* create the signature - s' and r' are the received signatures in buf */
 	/* w = (s')-1 mod q */
 	/* let val1 = s' */
-	bytes_to_mp(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
+	bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
 
 	if (mp_cmp(&val1, key->q) != MP_LT) {
 		TRACE(("verify failed, s' >= q"))
@@ -208,7 +208,7 @@
 
 	/* u2 = ((r')w) mod q */
 	/* let val1 = r' */
-	bytes_to_mp(&val1, &string[0], SHA1_HASH_SIZE);
+	bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
 	if (mp_cmp(&val1, key->q) != MP_LT) {
 		TRACE(("verify failed, r' >= q"))
 		goto out;
--- a/ecc.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/ecc.h	Fri Jun 12 22:57:48 2015 +0800
@@ -12,7 +12,7 @@
 	int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
 	const ltc_ecc_set_type *dp; /* curve domain parameters */
 	const struct ltc_hash_descriptor *hash_desc;
-	const unsigned char *name;
+	const char *name;
 };
 
 extern struct dropbear_ecc_curve ecc_curve_nistp256;
--- a/ecdsa.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/ecdsa.c	Fri Jun 12 22:57:48 2015 +0800
@@ -83,9 +83,9 @@
 	ecc_key *new_key = NULL;
 
 	/* string   "ecdsa-sha2-[identifier]" */
-	key_ident = buf_getstring(buf, &key_ident_len);
+	key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
 	/* string   "[identifier]" */
-	identifier = buf_getstring(buf, &identifier_len);
+	identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
 
 	if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
 		TRACE(("Bad identifier lengths"))
@@ -140,10 +140,10 @@
 
 void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
 	struct dropbear_ecc_curve *curve = NULL;
-	unsigned char key_ident[30];
+	char key_ident[30];
 
 	curve = curve_for_dp(key->dp);
-	snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
+	snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
 	buf_putstring(buf, key_ident, strlen(key_ident));
 	buf_putstring(buf, curve->name, strlen(curve->name));
 	buf_put_ecc_raw_pubkey_string(buf, key);
@@ -161,7 +161,7 @@
 	hash_state hs;
 	unsigned char hash[64];
 	void *e = NULL, *p = NULL, *s = NULL, *r;
-	unsigned char key_ident[30];
+	char key_ident[30];
 	buffer *sigbuf = NULL;
 
 	TRACE(("buf_put_ecdsa_sign"))
@@ -222,7 +222,7 @@
 		}
 	}
 
-	snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
+	snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
 	buf_putstring(buf, key_ident, strlen(key_ident));
 	/* enough for nistp521 */
 	sigbuf = buf_new(200);
--- a/gendss.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/gendss.c	Fri Jun 12 22:57:48 2015 +0800
@@ -67,7 +67,7 @@
 
 static void getq(dropbear_dss_key *key) {
 
-	char buf[QSIZE];
+	unsigned char buf[QSIZE];
 
 	/* 160 bit prime */
 	genrandom(buf, QSIZE);
--- a/keyimport.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/keyimport.c	Fri Jun 12 22:57:48 2015 +0800
@@ -193,7 +193,7 @@
 static void base64_encode_fp(FILE * fp, unsigned char *data,
 		int datalen, int cpl)
 {
-    char out[100];
+	unsigned char out[100];
     int n;
 	unsigned long outlen;
 	int rawcpl;
@@ -445,7 +445,7 @@
 						ret->keyblob_size);
 			}
 			outlen = ret->keyblob_size - ret->keyblob_len;
-			if (base64_decode(buffer, len, 
+			if (base64_decode((const unsigned char *)buffer, len,
 						ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
 				errmsg = "Error decoding base64";
 				goto error;
@@ -507,7 +507,7 @@
 	int i, num_integers = 0;
 	sign_key *retval = NULL;
 	char *errmsg;
-	char *modptr = NULL;
+	unsigned char *modptr = NULL;
 	int modlen = -9999;
 	enum signkey_type type;
 
@@ -646,12 +646,12 @@
 			 */
 			if (i == 1) {
 				/* Save the details for after we deal with number 2. */
-				modptr = (char *)p;
+				modptr = p;
 				modlen = len;
 			} else if (i >= 2 && i <= 5) {
-				buf_putstring(blobbuf, p, len);
+				buf_putstring(blobbuf, (const char*)p, len);
 				if (i == 2) {
-					buf_putstring(blobbuf, modptr, modlen);
+					buf_putstring(blobbuf, (const char*)modptr, modlen);
 				}
 			}
 		} else if (key->type == OSSH_DSA) {
@@ -659,7 +659,7 @@
 			 * OpenSSH key order is p, q, g, y, x,
 			 * we want the same.
 			 */
-			buf_putstring(blobbuf, p, len);
+			buf_putstring(blobbuf, (const char*)p, len);
 		}
 
 		/* Skip past the number. */
@@ -1043,7 +1043,7 @@
 		int curve_oid_len = 0;
 		const void* curve_oid = NULL;
 		unsigned long pubkey_size = 2*curve_size+1;
-		unsigned int k_size;
+		int k_size;
 		int err = 0;
 
 		/* version. less than 10 bytes */
--- a/libtomcrypt/src/ciphers/aes/aes.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/libtomcrypt/src/ciphers/aes/aes.c	Fri Jun 12 22:57:48 2015 +0800
@@ -122,9 +122,10 @@
  */
 int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
 {
-    int i, j;
+    int i;
     ulong32 temp, *rk;
 #ifndef ENCRYPT_ONLY
+    int j;
     ulong32 *rrk;
 #endif    
     LTC_ARGCHK(key  != NULL);
@@ -148,7 +149,9 @@
     LOAD32H(rk[2], key +  8);
     LOAD32H(rk[3], key + 12);
     if (keylen == 16) {
+        #ifndef ENCRYPT_ONLY
         j = 44;
+        #endif
         for (;;) {
             temp  = rk[3];
             rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i];
@@ -161,7 +164,9 @@
             rk += 4;
         }
     } else if (keylen == 24) {
+        #ifndef ENCRYPT_ONLY
         j = 52;   
+        #endif
         LOAD32H(rk[4], key + 16);
         LOAD32H(rk[5], key + 20);
         for (;;) {
@@ -182,7 +187,9 @@
             rk += 6;
         }
     } else if (keylen == 32) {
+        #ifndef ENCRYPT_ONLY
         j = 60;
+        #endif
         LOAD32H(rk[4], key + 16);
         LOAD32H(rk[5], key + 20);
         LOAD32H(rk[6], key + 24);
@@ -728,6 +735,7 @@
 */
 void ECB_DONE(symmetric_key *skey)
 {
+   (void)skey;
 }
 
 
--- a/libtomcrypt/src/ciphers/des.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/libtomcrypt/src/ciphers/des.c	Fri Jun 12 22:57:48 2015 +0800
@@ -1871,6 +1871,7 @@
 */
 void des3_done(symmetric_key *skey)
 {
+   (void)skey;
 }
 
 
--- a/libtomcrypt/src/ciphers/twofish/twofish.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/libtomcrypt/src/ciphers/twofish/twofish.c	Fri Jun 12 22:57:48 2015 +0800
@@ -684,6 +684,7 @@
 */
 void twofish_done(symmetric_key *skey)
 {
+   (void)skey;
 }
 
 /**
--- a/libtomcrypt/src/hashes/helper/hash_file.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/libtomcrypt/src/hashes/helper/hash_file.c	Fri Jun 12 22:57:48 2015 +0800
@@ -25,6 +25,7 @@
 int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen)
 {
 #ifdef LTC_NO_FILE
+    (void)hash; (void)fname; (void)out; (void)outlen;
     return CRYPT_NOP;
 #else
     FILE *in;
--- a/libtomcrypt/src/hashes/helper/hash_filehandle.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/libtomcrypt/src/hashes/helper/hash_filehandle.c	Fri Jun 12 22:57:48 2015 +0800
@@ -26,6 +26,7 @@
 int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen)
 {
 #ifdef LTC_NO_FILE
+    (void)hash; (void)in; (void)out; (void)outlen;
     return CRYPT_NOP;
 #else
     hash_state md;
--- a/libtomcrypt/src/mac/hmac/hmac_file.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/libtomcrypt/src/mac/hmac/hmac_file.c	Fri Jun 12 22:57:48 2015 +0800
@@ -32,6 +32,7 @@
                     unsigned char *out, unsigned long *outlen)
 {
 #ifdef LTC_NO_FILE
+    (void)hash; (void)fname; (void)key; (void)keylen; (void)out; (void)outlen;
     return CRYPT_NOP;
 #else
    hmac_state hmac;
--- a/libtomcrypt/src/misc/crypt/crypt_argchk.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/libtomcrypt/src/misc/crypt/crypt_argchk.c	Fri Jun 12 22:57:48 2015 +0800
@@ -21,7 +21,7 @@
 {
  fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
          v, d, s);
- (void)raise(SIGABRT);
+ abort();
 }
 #endif
 
--- a/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c	Fri Jun 12 22:57:48 2015 +0800
@@ -40,7 +40,7 @@
    int        i, j, err;
    void       *mu, *mp;
    unsigned long buf;
-   int        first, bitbuf, bitcpy, bitcnt, mode, digidx;
+   int        bitcnt, mode, digidx;
 
    LTC_ARGCHK(k       != NULL);
    LTC_ARGCHK(G       != NULL);
@@ -98,8 +98,6 @@
    bitcnt = 1;
    buf    = 0;
    digidx = mp_get_digit_count(k) - 1;
-   bitcpy = bitbuf = 0;
-   first  = 1;
 
    /* perform ops */
    for (;;) {
--- a/netio.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/netio.c	Fri Jun 12 22:57:48 2015 +0800
@@ -70,13 +70,13 @@
 	struct addrinfo *r;
 	int res = 0;
 	int fastopen = 0;
-#ifdef DROPBEAR_TCP_FAST_OPEN
+#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
 	struct msghdr message;
 #endif
 
 	for (r = c->res_iter; r; r = r->ai_next)
 	{
-		assert(c->sock == -1);
+		dropbear_assert(c->sock == -1);
 
 		c->sock = socket(c->res_iter->ai_family, c->res_iter->ai_socktype, c->res_iter->ai_protocol);
 		if (c->sock < 0) {
@@ -91,31 +91,36 @@
 		set_piggyback_ack(c->sock);
 #endif
 
-#ifdef DROPBEAR_TCP_FAST_OPEN
+#ifdef DROPBEAR_CLIENT_TCP_FAST_OPEN
 		fastopen = (c->writequeue != NULL);
 
-		memset(&message, 0x0, sizeof(message));
-		message.msg_name = r->ai_addr;
-		message.msg_namelen = r->ai_addrlen;
-
-		if (c->writequeue) {
-			int iovlen; /* Linux msg_iovlen is a size_t */
-			message.msg_iov = packet_queue_to_iovec(c->writequeue, &iovlen);
+		if (fastopen) {
+			memset(&message, 0x0, sizeof(message));
+			message.msg_name = r->ai_addr;
+			message.msg_namelen = r->ai_addrlen;
+			/* 6 is arbitrary, enough to hold initial packets */
+			unsigned int iovlen = 6; /* Linux msg_iovlen is a size_t */
+			struct iovec iov[6];
+			packet_queue_to_iovec(c->writequeue, iov, &iovlen);
+			message.msg_iov = iov;
 			message.msg_iovlen = iovlen;
 			res = sendmsg(c->sock, &message, MSG_FASTOPEN);
-			if (res < 0 && errno != EINPROGRESS) {
-				m_free(c->errstring);
-				c->errstring = m_strdup(strerror(errno));
-				/* Not entirely sure which kind of errors are normal - 2.6.32 seems to 
-				return EPIPE for any (nonblocking?) sendmsg(). just fall back */
-				TRACE(("sendmsg tcp_fastopen failed, falling back. %s", strerror(errno)));
-				/* No kernel MSG_FASTOPEN support. Fall back below */
-				fastopen = 0;
-				/* Set to NULL to avoid trying again */
-				c->writequeue = NULL;
+			/* Returns EINPROGRESS if FASTOPEN wasn't available */
+			if (res < 0) {
+				if (errno != EINPROGRESS) {
+					m_free(c->errstring);
+					c->errstring = m_strdup(strerror(errno));
+					/* Not entirely sure which kind of errors are normal - 2.6.32 seems to 
+					return EPIPE for any (nonblocking?) sendmsg(). just fall back */
+					TRACE(("sendmsg tcp_fastopen failed, falling back. %s", strerror(errno)));
+					/* No kernel MSG_FASTOPEN support. Fall back below */
+					fastopen = 0;
+					/* Set to NULL to avoid trying again */
+					c->writequeue = NULL;
+				}
+			} else {
+				packet_queue_consume(c->writequeue, res);
 			}
-			m_free(message.msg_iov);
-			packet_queue_consume(c->writequeue, res);
 		}
 #endif
 
@@ -163,7 +168,7 @@
 
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_family = PF_UNSPEC;
+	hints.ai_family = AF_UNSPEC;
 
 	err = getaddrinfo(remotehost, remoteport, &hints, &c->res);
 	if (err) {
@@ -258,8 +263,7 @@
 	c->writequeue = writequeue;
 }
 
-struct iovec * packet_queue_to_iovec(struct Queue *queue, int *ret_iov_count) {
-	struct iovec *iov = NULL;
+void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count) {
 	struct Link *l;
 	unsigned int i;
 	int len;
@@ -269,10 +273,9 @@
 	#define IOV_MAX UIO_MAXIOV
 	#endif
 
-	*ret_iov_count = MIN(queue->count, IOV_MAX);
+	*iov_count = MIN(MIN(queue->count, IOV_MAX), *iov_count);
 
-	iov = m_malloc(sizeof(*iov) * *ret_iov_count);
-	for (l = queue->head, i = 0; l; l = l->link, i++)
+	for (l = queue->head, i = 0; i < *iov_count; l = l->link, i++)
 	{
 		writebuf = (buffer*)l->item;
 		len = writebuf->len - 1 - writebuf->pos;
@@ -282,8 +285,6 @@
 		iov[i].iov_base = buf_getptr(writebuf, len);
 		iov[i].iov_len = len;
 	}
-
-	return iov;
 }
 
 void packet_queue_consume(struct Queue *queue, ssize_t written) {
@@ -312,7 +313,7 @@
 	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
 }
 
-#ifdef DROPBEAR_TCP_FAST_OPEN
+#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
 void set_listen_fast_open(int sock) {
 	int qlen = MAX(MAX_UNAUTH_PER_IP, 5);
 	if (setsockopt(sock, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) != 0) {
--- a/netio.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/netio.h	Fri Jun 12 22:57:48 2015 +0800
@@ -44,10 +44,11 @@
 void connect_set_writequeue(struct dropbear_progress_connection *c, struct Queue *writequeue);
 
 /* TODO: writev #ifdef guard */
-struct iovec * packet_queue_to_iovec(struct Queue *queue, int *ret_iov_count);
+/* Fills out iov which contains iov_count slots, returning the number filled in iov_count */
+void packet_queue_to_iovec(struct Queue *queue, struct iovec *iov, unsigned int *iov_count);
 void packet_queue_consume(struct Queue *queue, ssize_t written);
 
-#ifdef DROPBEAR_TCP_FAST_OPEN
+#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
 /* Try for any Linux builds, will fall back if the kernel doesn't support it */
 void set_listen_fast_open(int sock);
 /* Define values which may be supported by the kernel even if the libc is too old */
--- a/options.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/options.h	Fri Jun 12 22:57:48 2015 +0800
@@ -103,10 +103,15 @@
 #define DROPBEAR_ENABLE_CBC_MODE
 
 /* Enable "Counter Mode" for ciphers. This is more secure than normal
- * CBC mode against certain attacks. This adds around 1kB to binary 
- * size and is recommended for most cases */
+ * CBC mode against certain attacks. It is recommended for security
+ * and forwards compatibility */
 #define DROPBEAR_ENABLE_CTR_MODE
 
+/* Twofish counter mode is disabled by default because it 
+has not been tested for interoperability with other SSH implementations.
+If you test it please contact the Dropbear author */
+/* #define DROPBEAR_TWOFISH_CTR */
+
 /* You can compile with no encryption if you want. In some circumstances
  * this could be safe security-wise, though make sure you know what
  * you're doing. Anyone can see everything that goes over the wire, so
--- a/packet.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/packet.c	Fri Jun 12 22:57:48 2015 +0800
@@ -58,8 +58,13 @@
 
 	ssize_t written;
 #ifdef HAVE_WRITEV
-	struct iovec *iov = NULL;
-	int iov_count;
+	/* 50 is somewhat arbitrary */
+	unsigned int iov_count = 50;
+	struct iovec iov[50];
+#else
+	int len;
+	buffer* writebuf;
+	int packet_type;
 #endif
 	
 	TRACE2(("enter write_packet"))
@@ -67,7 +72,7 @@
 
 #if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
 
-	iov = packet_queue_to_iovec(&ses.writequeue, &iov_count);
+	packet_queue_to_iovec(&ses.writequeue, iov, &iov_count);
 	/* This may return EAGAIN. The main loop sometimes
 	calls write_packet() without bothering to test with select() since
 	it's likely to be necessary */
@@ -75,15 +80,14 @@
 	if (written < 0) {
 		if (errno == EINTR || errno == EAGAIN) {
 			TRACE2(("leave write_packet: EINTR"))
-			m_free(iov);
 			return;
 		} else {
 			dropbear_exit("Error writing: %s", strerror(errno));
 		}
 	}
-	m_free(iov);
 
 	packet_queue_consume(&ses.writequeue, written);
+	ses.writequeue_len -= written;
 
 	if (written == 0) {
 		ses.remoteclosed();
@@ -97,6 +101,8 @@
 	 * a cleartext packet_type indicator */
 	packet_type = writebuf->data[writebuf->len-1];
 	len = writebuf->len - 1 - writebuf->pos;
+	TRACE2(("write_packet type %d len %d/%d", packet_type,
+			len, writebuf->len-1))
 	dropbear_assert(len > 0);
 	/* Try to write as much as possible */
 	written = write(ses.sock_out, buf_getptr(writebuf, len), len);
@@ -114,6 +120,8 @@
 		ses.remoteclosed();
 	}
 
+	ses.writequeue_len -= written;
+
 	if (written == len) {
 		/* We've finished with the packet, free it */
 		dequeue(&ses.writequeue);
@@ -571,15 +579,12 @@
     /* stick the MAC on it */
     buf_putbytes(writebuf, mac_bytes, mac_size);
 
-	/* The last byte of the buffer stores the cleartext packet_type. It is not
-	 * transmitted but is used for transmit timeout purposes */
-	buf_putbyte(writebuf, packet_type);
-	/* enqueue the packet for sending. It will get freed after transmission. */
-	buf_setpos(writebuf, 0);
-	enqueue(&ses.writequeue, (void*)writebuf);
+	/* Update counts */
+	ses.kexstate.datatrans += writebuf->len;
+
+	writebuf_enqueue(writebuf, packet_type);
 
 	/* Update counts */
-	ses.kexstate.datatrans += writebuf->len;
 	ses.transseq++;
 
 	now = monotonic_now();
@@ -597,6 +602,16 @@
 	TRACE2(("leave encrypt_packet()"))
 }
 
+void writebuf_enqueue(buffer * writebuf, unsigned char packet_type) {
+	/* The last byte of the buffer stores the cleartext packet_type. It is not
+	 * transmitted but is used for transmit timeout purposes */
+	buf_putbyte(writebuf, packet_type);
+	/* enqueue the packet for sending. It will get freed after transmission. */
+	buf_setpos(writebuf, 0);
+	enqueue(&ses.writequeue, (void*)writebuf);
+	ses.writequeue_len += writebuf->len-1;
+}
+
 
 /* Create the packet mac, and append H(seqno|clearbuf) to the output */
 /* output_mac must have ses.keys->trans.algo_mac->hashsize bytes. */
--- a/packet.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/packet.h	Fri Jun 12 22:57:48 2015 +0800
@@ -28,12 +28,15 @@
 
 #include "includes.h"
 #include "queue.h"
+#include "buffer.h"
 
 void write_packet();
 void read_packet();
 void decrypt_packet();
 void encrypt_packet();
 
+void writebuf_enqueue(buffer * writebuf, unsigned char packet_type);
+
 void process_packet();
 
 void maybe_flush_reply_queue();
--- a/session.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/session.h	Fri Jun 12 22:57:48 2015 +0800
@@ -63,7 +63,7 @@
 /* Client */
 void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress) ATTRIB_NORETURN;
 void cli_connected(int result, int sock, void* userdata, const char *errstring);
-void cleantext(unsigned char* dirtytext);
+void cleantext(char* dirtytext);
 
 /* crypto parameters that are stored individually for transmit and receive */
 struct key_context_directional {
@@ -115,7 +115,7 @@
 	/* remotehost will be initially NULL as we delay
 	 * reading the remote version string. it will be set
 	 * by the time any recv_() packet methods are called */
-	unsigned char *remoteident; 
+	char *remoteident;
 
 	int maxfd; /* the maximum file descriptor to check with select() */
 
@@ -125,6 +125,7 @@
 							 throughout the code, as handlers fill out this
 							 buffer with the packet to send. */
 	struct Queue writequeue; /* A queue of encrypted packets to send */
+	unsigned int writequeue_len; /* Number of bytes pending to send in writequeue */
 	buffer *readbuf; /* From the wire, decrypted in-place */
 	buffer *payload; /* Post-decompression, the actual SSH packet. 
 						May have extra data at the beginning, will be
--- a/signkey.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/signkey.c	Fri Jun 12 22:57:48 2015 +0800
@@ -138,7 +138,7 @@
  * on return is set to the type read (useful when type = _ANY) */
 int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
 
-	unsigned char* ident;
+	char *ident;
 	unsigned int len;
 	enum signkey_type keytype;
 	int ret = DROPBEAR_FAILURE;
@@ -209,7 +209,7 @@
  * on return is set to the type read (useful when type = _ANY) */
 int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
 
-	unsigned char* ident;
+	char *ident;
 	unsigned int len;
 	enum signkey_type keytype;
 	int ret = DROPBEAR_FAILURE;
@@ -515,7 +515,7 @@
  * signature blob */
 int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
 	
-	unsigned char * type_name = NULL;
+	char *type_name = NULL;
 	unsigned int type_name_len = 0;
 	enum signkey_type type;
 
--- a/svr-auth.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-auth.c	Fri Jun 12 22:57:48 2015 +0800
@@ -36,7 +36,7 @@
 #include "dbrandom.h"
 
 static void authclear();
-static int checkusername(unsigned char *username, unsigned int userlen);
+static int checkusername(char *username, unsigned int userlen);
 
 /* initialise the first time for a session, resetting all parameters */
 void svr_authinitialise() {
@@ -100,7 +100,7 @@
  * checking, and handle success or failure */
 void recv_msg_userauth_request() {
 
-	unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
+	char *username = NULL, *servicename = NULL, *methodname = NULL;
 	unsigned int userlen, servicelen, methodlen;
 	int valid_user = 0;
 
@@ -227,7 +227,7 @@
 
 /* Check that the username exists and isn't disallowed (root), and has a valid shell.
  * returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
-static int checkusername(unsigned char *username, unsigned int userlen) {
+static int checkusername(char *username, unsigned int userlen) {
 
 	char* listshell = NULL;
 	char* usershell = NULL;
@@ -333,14 +333,14 @@
 	typebuf = buf_new(30); /* long enough for PUBKEY and PASSWORD */
 
 	if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
-		buf_putbytes(typebuf, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
+		buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN);
 		if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
 			buf_putbyte(typebuf, ',');
 		}
 	}
 	
 	if (ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
-		buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
+		buf_putbytes(typebuf, (const unsigned char *)AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
 	}
 
 	buf_putbufstring(ses.writepayload, typebuf);
--- a/svr-authpam.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-authpam.c	Fri Jun 12 22:57:48 2015 +0800
@@ -188,7 +188,7 @@
 
 	pam_handle_t* pamHandlep = NULL;
 
-	unsigned char * password = NULL;
+	char * password = NULL;
 	unsigned int passwordlen;
 
 	int rc = PAM_SUCCESS;
--- a/svr-authpasswd.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-authpasswd.c	Fri Jun 12 22:57:48 2015 +0800
@@ -33,6 +33,8 @@
 
 #ifdef ENABLE_SVR_PASSWORD_AUTH
 
+/* not constant time when strings are differing lengths. 
+ string content isn't leaked, and crypt hashes are predictable length. */
 static int constant_time_strcmp(const char* a, const char* b) {
 	size_t la = strlen(a);
 	size_t lb = strlen(b);
@@ -50,7 +52,7 @@
 	
 	char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */
 	char * testcrypt = NULL; /* crypt generated from the user's password sent */
-	unsigned char * password;
+	char * password;
 	unsigned int passwordlen;
 
 	unsigned int changepw;
@@ -73,7 +75,7 @@
 	password = buf_getstring(ses.payload, &passwordlen);
 
 	/* the first bytes of passwdcrypt are the salt */
-	testcrypt = crypt((char*)password, passwdcrypt);
+	testcrypt = crypt(password, passwdcrypt);
 	m_burn(password, passwordlen);
 	m_free(password);
 
--- a/svr-authpubkey.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-authpubkey.c	Fri Jun 12 22:57:48 2015 +0800
@@ -70,10 +70,10 @@
 #define MIN_AUTHKEYS_LINE 10 /* "ssh-rsa AB" - short but doesn't matter */
 #define MAX_AUTHKEYS_LINE 4200 /* max length of a line in authkeys */
 
-static int checkpubkey(unsigned char* algo, unsigned int algolen,
+static int checkpubkey(char* algo, unsigned int algolen,
 		unsigned char* keyblob, unsigned int keybloblen);
 static int checkpubkeyperms();
-static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
+static void send_msg_userauth_pk_ok(char* algo, unsigned int algolen,
 		unsigned char* keyblob, unsigned int keybloblen);
 static int checkfileperm(char * filename);
 
@@ -82,7 +82,7 @@
 void svr_auth_pubkey() {
 
 	unsigned char testkey; /* whether we're just checking if a key is usable */
-	unsigned char* algo = NULL; /* pubkey algo */
+	char* algo = NULL; /* pubkey algo */
 	unsigned int algolen;
 	unsigned char* keyblob = NULL;
 	unsigned int keybloblen;
@@ -173,7 +173,7 @@
 /* Reply that the key is valid for auth, this is sent when the user sends
  * a straight copy of their pubkey to test, to avoid having to perform
  * expensive signing operations with a worthless key */
-static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
+static void send_msg_userauth_pk_ok(char* algo, unsigned int algolen,
 		unsigned char* keyblob, unsigned int keybloblen) {
 
 	TRACE(("enter send_msg_userauth_pk_ok"))
@@ -181,7 +181,7 @@
 
 	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_PK_OK);
 	buf_putstring(ses.writepayload, algo, algolen);
-	buf_putstring(ses.writepayload, keyblob, keybloblen);
+	buf_putstring(ses.writepayload, (const char*)keyblob, keybloblen);
 
 	encrypt_packet();
 	TRACE(("leave send_msg_userauth_pk_ok"))
@@ -191,7 +191,7 @@
 /* Checks whether a specified publickey (and associated algorithm) is an
  * acceptable key for authentication */
 /* Returns DROPBEAR_SUCCESS if key is ok for auth, DROPBEAR_FAILURE otherwise */
-static int checkpubkey(unsigned char* algo, unsigned int algolen,
+static int checkpubkey(char* algo, unsigned int algolen,
 		unsigned char* keyblob, unsigned int keybloblen) {
 
 	FILE * authfile = NULL;
@@ -260,9 +260,9 @@
 		/* check the key type - will fail if there are options */
 		TRACE(("a line!"))
 
-		if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) {
+		if (strncmp((const char *) buf_getptr(line, algolen), algo, algolen) != 0) {
 			int is_comment = 0;
-			char *options_start = NULL;
+			unsigned char *options_start = NULL;
 			int options_len = 0;
 			int escape, quoted;
 			
@@ -308,7 +308,7 @@
 			if (line->pos + algolen+3 > line->len) {
 				continue;
 			}
-			if (strncmp(buf_getptr(line, algolen), algo, algolen) != 0) { 
+			if (strncmp((const char *) buf_getptr(line, algolen), algo, algolen) != 0) {
 				continue;
 			}
 		}
@@ -330,7 +330,7 @@
 
 		TRACE(("checkpubkey: line pos = %d len = %d", line->pos, line->len))
 
-		ret = cmp_base64_key(keyblob, keybloblen, algo, algolen, line, NULL);
+		ret = cmp_base64_key(keyblob, keybloblen, (const unsigned char *) algo, algolen, line, NULL);
 
 		if (ret == DROPBEAR_SUCCESS && options_buf) {
 			ret = svr_add_pubkey_options(options_buf, line_num, filename);
--- a/svr-authpubkeyoptions.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-authpubkeyoptions.c	Fri Jun 12 22:57:48 2015 +0800
@@ -120,7 +120,7 @@
 	if (options_buf->len - options_buf->pos < len) {
 		return DROPBEAR_FAILURE;
 	}
-	if (strncasecmp(buf_getptr(options_buf, len), opt_name, len) == 0) {
+	if (strncasecmp((const char *) buf_getptr(options_buf, len), opt_name, len) == 0) {
 		buf_incrpos(options_buf, len);
 		return DROPBEAR_SUCCESS;
 	}
--- a/svr-chansession.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-chansession.c	Fri Jun 12 22:57:48 2015 +0800
@@ -343,7 +343,7 @@
  * or x11/authagent forwarding. These are passed to appropriate handlers */
 static void chansessionrequest(struct Channel *channel) {
 
-	unsigned char * type = NULL;
+	char * type = NULL;
 	unsigned int typelen;
 	unsigned char wantreply;
 	int ret = 1;
@@ -406,7 +406,7 @@
 static int sessionsignal(struct ChanSess *chansess) {
 
 	int sig = 0;
-	unsigned char* signame = NULL;
+	char* signame = NULL;
 	int i;
 
 	if (chansess->pid == 0) {
@@ -557,7 +557,7 @@
 static int sessionpty(struct ChanSess * chansess) {
 
 	unsigned int termlen;
-	unsigned char namebuf[65];
+	char namebuf[65];
 	struct passwd * pw = NULL;
 
 	TRACE(("enter sessionpty"))
@@ -583,7 +583,7 @@
 		return DROPBEAR_FAILURE;
 	}
 	
-	chansess->tty = (char*)m_strdup(namebuf);
+	chansess->tty = m_strdup(namebuf);
 	if (!chansess->tty) {
 		dropbear_exit("Out of memory"); /* TODO disconnect */
 	}
@@ -603,6 +603,7 @@
 	return DROPBEAR_SUCCESS;
 }
 
+#ifndef USE_VFORK
 static void make_connection_string(struct ChanSess *chansess) {
 	char *local_ip, *local_port, *remote_ip, *remote_port;
 	size_t len;
@@ -624,6 +625,7 @@
 	m_free(remote_ip);
 	m_free(remote_port);
 }
+#endif
 
 /* Handle a command request from the client. This is used for both shell
  * and command-execution requests, and passes the command to
--- a/svr-kex.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-kex.c	Fri Jun 12 22:57:48 2015 +0800
@@ -247,7 +247,7 @@
 			{
 			struct kex_curve25519_param *param = gen_kexcurve25519_param();
 			kexcurve25519_comb_key(param, ecdh_qs, svr_opts.hostkey);
-			buf_putstring(ses.writepayload, param->pub, CURVE25519_LEN);
+			buf_putstring(ses.writepayload, (const char*)param->pub, CURVE25519_LEN);
 			free_kexcurve25519_param(param);
 			}
 #endif
--- a/svr-main.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-main.c	Fri Jun 12 22:57:48 2015 +0800
@@ -429,7 +429,7 @@
 		for (n = 0; n < (unsigned int)nsock; n++) {
 			int sock = socks[sockpos + n];
 			set_sock_priority(sock, DROPBEAR_PRIO_LOWDELAY);
-#ifdef DROPBEAR_TCP_FAST_OPEN
+#ifdef DROPBEAR_SERVER_TCP_FAST_OPEN
 			set_listen_fast_open(sock);
 #endif
 		}
--- a/svr-service.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-service.c	Fri Jun 12 22:57:48 2015 +0800
@@ -30,13 +30,13 @@
 #include "ssh.h"
 #include "auth.h"
 
-static void send_msg_service_accept(unsigned char *name, int len);
+static void send_msg_service_accept(char *name, int len);
 
 /* processes a SSH_MSG_SERVICE_REQUEST, returning 0 if finished,
  * 1 if not */
 void recv_msg_service_request() {
 
-	unsigned char * name;
+	char * name;
 	unsigned int len;
 
 	TRACE(("enter recv_msg_service_request"))
@@ -73,7 +73,7 @@
 
 }
 
-static void send_msg_service_accept(unsigned char *name, int len) {
+static void send_msg_service_accept(char *name, int len) {
 
 	TRACE(("accepting service %s", name))
 
--- a/svr-session.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-session.c	Fri Jun 12 22:57:48 2015 +0800
@@ -138,6 +138,8 @@
 
 	/* exchange identification, version etc */
 	send_session_identification();
+	
+	kexfirstinitialise(); /* initialise the kex state */
 
 	/* start off with key exchange */
 	send_msg_kexinit();
--- a/svr-tcpfwd.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-tcpfwd.c	Fri Jun 12 22:57:48 2015 +0800
@@ -65,7 +65,7 @@
  * similar to the request-switching in chansession.c */
 void recv_msg_global_request_remotetcp() {
 
-	unsigned char* reqname = NULL;
+	char* reqname = NULL;
 	unsigned int namelen;
 	unsigned int wantreply = 0;
 	int ret = DROPBEAR_FAILURE;
@@ -120,7 +120,7 @@
 static int svr_cancelremotetcp() {
 
 	int ret = DROPBEAR_FAILURE;
-	unsigned char * bindaddr = NULL;
+	char * bindaddr = NULL;
 	unsigned int addrlen;
 	unsigned int port;
 	struct Listener * listener = NULL;
@@ -155,7 +155,7 @@
 static int svr_remotetcpreq() {
 
 	int ret = DROPBEAR_FAILURE;
-	unsigned char * request_addr = NULL;
+	char * request_addr = NULL;
 	unsigned int addrlen;
 	struct TCPListener *tcpinfo = NULL;
 	unsigned int port;
@@ -232,12 +232,12 @@
  * address */
 static int newtcpdirect(struct Channel * channel) {
 
-	unsigned char* desthost = NULL;
+	char* desthost = NULL;
 	unsigned int destport;
-	unsigned char* orighost = NULL;
+	char* orighost = NULL;
 	unsigned int origport;
 	char portstring[NI_MAXSERV];
-	int len;
+	unsigned int len;
 	int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
 
 	TRACE(("newtcpdirect channel %d", channel->index))
--- a/svr-x11fwd.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/svr-x11fwd.c	Fri Jun 12 22:57:48 2015 +0800
@@ -107,7 +107,7 @@
 
 	int fd;
 	struct sockaddr_in addr;
-	int len;
+	socklen_t len;
 	int ret;
 	struct ChanSess * chansess = (struct ChanSess *)(listener->typedata);
 
--- a/sysoptions.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/sysoptions.h	Fri Jun 12 22:57:48 2015 +0800
@@ -262,9 +262,12 @@
 /* Use this string since some implementations might special-case it */
 #define DROPBEAR_KEEPALIVE_STRING "[email protected]"
 
-/* Linux will attempt TCP fast open, falling back if not supported by the kernel */
+/* Linux will attempt TCP fast open, falling back if not supported by the kernel.
+ * Currently server is enabled but client is disabled by default until there
+ * is further compatibility testing */
 #ifdef __linux__
-#define DROPBEAR_TCP_FAST_OPEN 1
+#define DROPBEAR_SERVER_TCP_FAST_OPEN
+/* #define DROPBEAR_CLIENT_TCP_FAST_OPEN */
 #endif
 
 /* no include guard for this file */
--- a/tcp-accept.c	Thu Mar 12 15:14:47 2015 +0300
+++ b/tcp-accept.c	Fri Jun 12 22:57:48 2015 +0800
@@ -75,7 +75,7 @@
 	}
 
 	if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) {
-		unsigned char* addr = NULL;
+		char* addr = NULL;
 		unsigned int port = 0;
 
 		if (tcpinfo->tcp_type == direct) {
--- a/tcpfwd.h	Thu Mar 12 15:14:47 2015 +0300
+++ b/tcpfwd.h	Fri Jun 12 22:57:48 2015 +0800
@@ -31,16 +31,16 @@
 
 	/* For a direct-tcpip request, it's the addr/port we want the other
 	 * end to connect to */
-	unsigned char *sendaddr;
+	char *sendaddr;
 	unsigned int sendport;
 
 	/* This is the address/port that we listen on. The address has special
 	 * meanings as per the rfc, "" for all interfaces, "localhost" for 
 	 * localhost, or a normal interface name. */
-	unsigned char *listenaddr;
+	char *listenaddr;
 	unsigned int listenport;
 	/* The address that the remote host asked to listen on */
-	unsigned char *request_listenaddr;
+	char *request_listenaddr;
 
 	const struct ChanType *chantype;
 	enum {direct, forwarded} tcp_type;
@@ -48,9 +48,9 @@
 
 /* A forwarding entry */
 struct TCPFwdEntry {
-	const unsigned char* connectaddr;
+	const char *connectaddr;
 	unsigned int connectport;
-	const unsigned char* listenaddr;
+	const char *listenaddr;
 	unsigned int listenport;
 	unsigned int have_reply; /* is set to 1 after a reply has been received
 								when setting up the forwarding */