diff --git a/CHANGELOG b/CHANGELOG index 12432dcb3..e542ec66c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ # Nmap Changelog ($Id$); -*-text-*- +o [Ncat][GH#773] Ncat in server mode properly handles TLS renegotiations and + other situations where SSL_read returns a non-fatal error. This was causing + SSL-over-TCP connections to be dropped. [Daniel Miller] + o [Ncat][GH#157] Ncat will now continue trying to connect to each resolved address for a hostname before declaring the connection refused, allowing it to fallback from IPv6 to IPv4 or to connect to names that use DNS failover. diff --git a/ncat/ncat_listen.c b/ncat/ncat_listen.c index fa8bbe48b..e41369df9 100644 --- a/ncat/ncat_listen.c +++ b/ncat/ncat_listen.c @@ -628,6 +628,9 @@ int read_socket(int recv_fd) char buf[DEFAULT_TCP_BUF_LEN]; struct fdinfo *fdn; int nbytes, pending; +#ifdef HAVE_OPENSSL + int err = SSL_ERROR_NONE; +#endif fdn = get_fdinfo(&client_fdlist, recv_fd); ncat_assert(fdn != NULL); @@ -637,11 +640,28 @@ int read_socket(int recv_fd) int n; n = ncat_recv(fdn, buf, sizeof(buf), &pending); - if (n <= 0) { +#ifdef HAVE_OPENSSL + /* SSL_read returns <0 in some cases like renegotiation. In these + * cases, SSL_get_error gives SSL_ERROR_WANT_{READ,WRITE}, and we + * should try the SSL_read again. */ + if (n < 0 && o.ssl && fdn->ssl) { + err = SSL_get_error(fdn->ssl, n); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + pending = 1; + } + } +#endif + /* If return value is 0, it's a clean shutdown from the other side, SSL + * or plain. If <0, it's an error. If pending, the error may be + * recoverable with a second SSL_read, so don't shut down yet. */ + if (n <= 0 && !pending) { if (o.debug) - logdebug("Closing connection.\n"); + logdebug("Closing fd %d.\n", recv_fd); #ifdef HAVE_OPENSSL if (o.ssl && fdn->ssl) { + if (n < 0 && o.debug) { + logdebug("SSL error on %d: %s\n", recv_fd, ERR_error_string(err, NULL));; + } if (nbytes == 0) SSL_shutdown(fdn->ssl); SSL_free(fdn->ssl); @@ -659,9 +679,10 @@ int read_socket(int recv_fd) return n; } - - Write(STDOUT_FILENO, buf, n); - nbytes += n; + else if (n > 0) { + Write(STDOUT_FILENO, buf, n); + nbytes += n; + } } while (pending); return nbytes;