changeset 1044:a4afc89f6ea8

irccd: detect SSL handshake failure
author David Demelier <markand@malikania.fr>
date Sun, 20 Jun 2021 08:42:22 +0200
parents 0e48e22a7493
children 13e374b9c522
files lib/irccd/conn.c lib/irccd/conn.h
diffstat 2 files changed, 19 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/lib/irccd/conn.c	Thu Jun 17 13:57:37 2021 +0200
+++ b/lib/irccd/conn.c	Sun Jun 20 08:42:22 2021 +0200
@@ -275,20 +275,23 @@
 		}
 
 		/*
-		 * From SSL_do_handshake manual page:
-		 *  < 0 -> fatal error
-		 * == 0 -> incomplete handshake
-		 * == 1 -> success
+		 * AFAIK, there is no way to detect that we're discussing with
+		 * a non SSL server, as a consequence SSL_get_error will return
+		 * SSL_ERROR_WANT_READ indefinitely. What we do is to detect
+		 * the failure to complete SSL_do_handshake in the amount of
+		 * three seconds before indicating that we've failed to
+		 * connect.
 		 */
-		if ((r = SSL_do_handshake(conn->ssl)) < 0) {
-			irc_log_warn("server %s: handshake failed (is the port SSL?)", conn->sv->name);
-			irc_conn_disconnect(conn);
-			return -1;
+		if ((r = SSL_do_handshake(conn->ssl)) <= 0) {
+			if (difftime(time(NULL), conn->statetime) >= 3)
+				return irc_log_warn("server %s: unable to complete handshake", conn->sv->name), -1;
+
+			irc_log_debug("server %s: handshake incomplete", conn->sv->name);
+
+			return update_ssl_state(conn, r);
 		}
 
-		if (r == 0)
-			return update_ssl_state(conn, r);
-
+		conn->statetime = time(NULL);
 		conn->state = IRC_CONN_STATE_READY;
 		conn->ssl_cond = IRC_CONN_SSL_ACT_NONE;
 		conn->ssl_step = IRC_CONN_SSL_ACT_NONE;
@@ -400,6 +403,8 @@
 {
 	assert(conn);
 
+	conn->statetime = time(NULL);
+
 	if (lookup(conn) < 0)
 		return irc_conn_disconnect(conn), -1;
 
--- a/lib/irccd/conn.h	Thu Jun 17 13:57:37 2021 +0200
+++ b/lib/irccd/conn.h	Sun Jun 20 08:42:22 2021 +0200
@@ -25,6 +25,8 @@
 #       include <openssl/ssl.h>
 #endif
 
+#include <time.h>
+
 #include "limits.h"
 
 #if defined(__cplusplus)
@@ -68,6 +70,7 @@
 	enum irc_conn_state state;
 	enum irc_conn_flags flags;
 	struct irc_server *sv;
+	time_t statetime;
 
 #if defined(IRCCD_WITH_SSL)
 	SSL_CTX *ctx;