]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-doveadm: Use dns_lookup() if dns_client_socket_path is set
authorMarkus Valentin <markus.valentin@open-xchange.com>
Thu, 8 Dec 2022 13:39:06 +0000 (14:39 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 16 Dec 2022 12:34:45 +0000 (12:34 +0000)
src/lib-doveadm/Makefile.am
src/lib-doveadm/doveadm-client.c
src/lib-doveadm/doveadm-client.h

index eb6410b340e45007892e15782ccf5161f3d84d30..b1233ae9e53ac14b0275e9780d61dce3758df6c7 100644 (file)
@@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libdoveadm.la
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
        -I$(top_srcdir)/src/lib-auth \
+       -I$(top_srcdir)/src/lib-dns \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-master \
        -I$(top_srcdir)/src/lib-ssl-iostream
index 007d4cda8e2e1d770ec9fd22319ff659255ee91e..9177568f13b99c2f1164d8f697eb05b1b1207ebe 100644 (file)
 #include "master-service.h"
 #include "doveadm-protocol.h"
 #include "doveadm-client.h"
+#include "dns-lookup.h"
+
+#include <sysexits.h>
 
 #define DOVEADM_LOG_CHANNEL_ID 'L'
 
 #define MAX_INBUF_SIZE (1024*32)
 
+#define DOVEADM_CLIENT_DNS_TIMEOUT_MSECS (1000*10)
+
 enum doveadm_client_reply_state {
        DOVEADM_CLIENT_REPLY_STATE_DONE = 0,
        DOVEADM_CLIENT_REPLY_STATE_PRINT,
@@ -33,6 +38,7 @@ struct doveadm_client {
 
        pool_t pool;
        struct timeout *to_destroy;
+       struct timeout *to_create_failed;
        struct io *io_log;
        struct istream *log_input;
        struct ssl_iostream *ssl_iostream;
@@ -43,6 +49,7 @@ struct doveadm_client {
        struct doveadm_client_cmd_settings delayed_set;
        doveadm_client_cmd_callback_t *callback;
 
+       struct dns_lookup *dns_lookup;
        unsigned int ips_count;
        struct ip_addr *ips;
 
@@ -80,6 +87,9 @@ void doveadm_client_settings_dup(const struct doveadm_client_settings *src,
        dest_r->ip = src->ip;
        dest_r->port = src->port;
 
+       dest_r->dns_client_socket_path = src->dns_client_socket_path != NULL ?
+               p_strdup(pool, src->dns_client_socket_path) : "";
+
        dest_r->username = p_strdup(pool, src->username);
        dest_r->password = p_strdup(pool, src->password);
 
@@ -643,6 +653,11 @@ static struct connection_settings doveadm_client_set = {
        .client_connect_timeout_msecs = DOVEADM_TCP_CONNECT_TIMEOUT_SECS*1000,
 };
 
+struct doveadm_client_dns_lookup_context {
+       struct doveadm_client *conn;
+       const char *error;
+};
+
 static void doveadm_client_connect_init(struct doveadm_client *conn)
 {
        connection_init_client_ip(doveadm_clients, &conn->conn,
@@ -661,6 +676,72 @@ static int doveadm_client_connect(struct doveadm_client *conn,
        return 0;
 }
 
+static void
+doveadm_client_create_failed(struct doveadm_client_dns_lookup_context *ctx)
+{
+       struct doveadm_client *conn = ctx->conn;
+       timeout_remove(&conn->to_create_failed);
+
+       struct doveadm_server_reply reply = {
+               .exit_code = EX_DATAERR,
+               .error  = ctx->error,
+       };
+       doveadm_client_callback(conn, &reply);
+       pool_unref(&conn->pool);
+}
+
+static void
+doveadm_client_dns_lookup_callback(const struct dns_lookup_result *result,
+                                  struct doveadm_client_dns_lookup_context *ctx)
+{
+       struct doveadm_client *conn = ctx->conn;
+       const char *error;
+
+       if (result->error != NULL) {
+               ctx->error = p_strdup_printf(conn->pool,
+                                            "dns_lookup(%s) failed: %s",
+                                            conn->set.hostname, result->error);
+               conn->to_create_failed =
+                       timeout_add_short(0, doveadm_client_create_failed, ctx);
+               return;
+       }
+
+       i_assert(result->ips_count > 0);
+       conn->ips = p_new(conn->pool, struct ip_addr, 1);
+       conn->ips[0] = result->ips[0];
+       conn->ips_count = 1;
+
+       doveadm_client_connect_init(conn);
+       if (doveadm_client_connect(conn, &error) < 0) {
+               ctx->error = p_strdup(conn->pool, error);
+               conn->to_create_failed =
+                       timeout_add_short(0, doveadm_client_create_failed, ctx);
+       }
+}
+
+static int doveadm_client_dns_lookup(struct doveadm_client *conn,
+                                    const char **error_r)
+{
+       struct doveadm_client_dns_lookup_context *ctx =
+               p_new(conn->pool, struct doveadm_client_dns_lookup_context, 1);
+       struct dns_lookup_settings dns_set;
+
+       i_zero(&dns_set);
+       dns_set.dns_client_socket_path = conn->set.dns_client_socket_path;
+       dns_set.timeout_msecs = DOVEADM_CLIENT_DNS_TIMEOUT_MSECS;
+       dns_set.event_parent = conn->conn.event;
+
+       ctx->conn = conn;
+
+       if (dns_lookup(conn->set.hostname, &dns_set,
+                      doveadm_client_dns_lookup_callback, ctx,
+                      &conn->dns_lookup) != 0) {
+               *error_r = t_strdup(ctx->error);
+               return -1;
+       }
+       return 0;
+}
+
 static int
 doveadm_client_resolve_hostname(struct doveadm_client *conn,
                                const char **error_r)
@@ -669,6 +750,14 @@ doveadm_client_resolve_hostname(struct doveadm_client *conn,
        unsigned int ips_count;
        int ret;
 
+       if (conn->set.dns_client_socket_path[0] != '\0') {
+               /* If there is an dns_client_socket_path do a dns
+                  lookup. */
+               if (doveadm_client_dns_lookup(conn, error_r) < 0)
+                       return -1;
+               return 0;
+       }
+
        ret = net_gethostbyname(conn->set.hostname, &ips, &ips_count);
        if (ret == 0) {
                conn->ips = p_new(conn->pool, struct ip_addr, 1);
@@ -720,12 +809,16 @@ int doveadm_client_create(const struct doveadm_client_settings *set,
                return -1;
        }
 
-       if (doveadm_client_connect(conn, error_r) < 0) {
-               connection_deinit(&conn->conn);
-               pool_unref(&pool);
-               return -1;
+       if (conn->dns_lookup == NULL) {
+               /* Only connect here if this is not using an async dns
+                  lookup. */
+               if (doveadm_client_connect(conn, error_r) < 0) {
+                       connection_deinit(&conn->conn);
+                       pool_unref(&pool);
+                       return -1;
+               }
+               conn->state = DOVEADM_CLIENT_REPLY_STATE_DONE;
        }
-       conn->state = DOVEADM_CLIENT_REPLY_STATE_DONE;
 
        *conn_r = conn;
        return 0;
@@ -782,6 +875,7 @@ static void doveadm_client_destroy(struct doveadm_client **_conn)
        *_conn = NULL;
 
        conn->destroyed = TRUE;
+       timeout_remove(&conn->to_create_failed);
        doveadm_client_destroy_int(conn);
        doveadm_client_unref(&conn);
 }
index 19ca5a21b5d7dd525558a99c441e41e9e4f2ad51..23ade6cd84c83438ffbd37920e78c6be343869c2 100644 (file)
@@ -38,6 +38,9 @@ struct doveadm_client_settings {
        /* Port to use for TCP connections. */
        in_port_t port;
 
+       /* UNIX socket path to connect to for dns lookups. */
+       const char *dns_client_socket_path;
+
        /* Username and password for authentication */
        const char *username, *password;