Blob Blame History Raw
From 370bf84857d5674a092f46fa5932a0c92ad5bbf5 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 24 Nov 2021 17:25:18 +0100
Subject: [PATCH] ldap: add socket timeout

During the discovery phase realmd tries to open LDAP connections to
multiple DC addresses returned by DNS. When cleaning up we have to call
ldap_destroy() to release the resources allocated for the LDAP context.
ldap_destroy() tries to send a LDAP unbind request independent of the
connection state. If the related address is block by a firewall or a not
properly routed IPv6 address there might be no reply on the TCP level
and the request might be stuck for quite some tome in the kernel.

To avoid the unexpected long delays will block realmd this patch lowers
the timeout considerably to 5s. As multiple other timeouts this value is
currently hardcoded.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1817869
---
 service/realm-ldap.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/service/realm-ldap.c b/service/realm-ldap.c
index bdfb96c..f7b6d13 100644
--- a/service/realm-ldap.c
+++ b/service/realm-ldap.c
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>
 
 #include <errno.h>
 
@@ -179,6 +180,7 @@ static GSourceFuncs socket_source_funcs = {
 
 /* Not included in ldap.h but documented */
 int ldap_init_fd (ber_socket_t fd, int proto, LDAP_CONST char *url, struct ldap **ldp);
+#define LDAP_SOCKET_TIMEOUT 5
 
 GSource *
 realm_ldap_connect_anonymous (GSocketAddress *address,
@@ -202,6 +204,8 @@ realm_ldap_connect_anonymous (GSocketAddress *address,
 	int opt_rc;
 	int ldap_opt_val;
 	const char *errmsg = NULL;
+	struct timeval tv = {LDAP_SOCKET_TIMEOUT, 0};
+	unsigned int milli = LDAP_SOCKET_TIMEOUT * 1000;
 
 	g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), NULL);
 
@@ -244,6 +248,23 @@ realm_ldap_connect_anonymous (GSocketAddress *address,
 		if (!g_unix_set_fd_nonblocking (ls->sock, FALSE, NULL))
 			g_warning ("couldn't set to blocking");
 
+		/* Lower the kernel defaults which might be minutes to hours */
+		rc = setsockopt (ls->sock, SOL_SOCKET, SO_RCVTIMEO,
+		                 &tv, sizeof (tv));
+		if (rc != 0) {
+			g_warning ("couldn't set SO_RCVTIMEO");
+		}
+		rc = setsockopt (ls->sock, SOL_SOCKET, SO_SNDTIMEO,
+		                 &tv, sizeof (tv));
+		if (rc != 0) {
+			g_warning ("couldn't set SO_SNDTIMEO");
+		}
+		rc = setsockopt (ls->sock, IPPROTO_TCP, TCP_USER_TIMEOUT,
+		                 &milli, sizeof (milli));
+		if (rc != 0) {
+			g_warning ("couldn't set TCP_USER_TIMEOUT");
+		}
+
 		if (family == G_SOCKET_FAMILY_IPV4) {
 			url = g_strdup_printf ("%s://%s:%d",
 			                       use_ldaps ? "ldaps" : "ldap",
-- 
2.34.1