]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lmtp: proxy: Changed implemention to use lib-smtp/smtp-client.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sun, 22 Jan 2017 14:27:29 +0000 (15:27 +0100)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Sun, 26 Nov 2017 20:30:01 +0000 (22:30 +0200)
src/lmtp/client.h
src/lmtp/commands.c
src/lmtp/lmtp-proxy.c
src/lmtp/lmtp-proxy.h

index b4d6ce99b1cda6b56d61bffdf42888e999d8a61f..f9cb37c1fc72e6e097e7909d46aef8d25e777ab3 100644 (file)
@@ -3,7 +3,6 @@
 
 #include "net.h"
 #include "smtp-params.h"
-#include "lmtp-client.h"
 
 #define CLIENT_MAIL_DATA_MAX_INMEMORY_SIZE (1024*128)
 
index 89071f165e2e2c95025252d9142e7b4dfece6847..c116602608b2cc637542e2f4f0d6e6559551f3bb 100644 (file)
@@ -231,11 +231,11 @@ client_proxy_rcpt_parse_fields(struct lmtp_proxy_rcpt_settings *set,
                        set->timeout_msecs *= 1000;
                } else if (strcmp(key, "protocol") == 0) {
                        if (strcmp(value, "lmtp") == 0) {
-                               set->protocol = LMTP_CLIENT_PROTOCOL_LMTP;
+                               set->protocol = SMTP_PROTOCOL_LMTP;
                                if (!port_set)
                                        set->port = 24;
                        } else if (strcmp(value, "smtp") == 0) {
-                               set->protocol = LMTP_CLIENT_PROTOCOL_SMTP;
+                               set->protocol = SMTP_PROTOCOL_SMTP;
                                if (!port_set)
                                        set->port = 25;
                        } else {
@@ -280,13 +280,13 @@ client_proxy_is_ourself(const struct client *client,
 static bool client_proxy_rcpt(struct client *client,
                              struct smtp_address *address,
                              const char *username, const char *detail, char delim,
-                             const struct lmtp_recipient_params *params)
+                             struct smtp_params_rcpt *params)
 {
        struct auth_master_connection *auth_conn;
        struct lmtp_proxy_rcpt_settings set;
        struct auth_user_info info;
        struct mail_storage_service_input input;
-       const char *args, *const *fields, *errstr, *orig_username = username;
+       const char *const *fields, *errstr, *orig_username = username;
        struct smtp_address *user;
        pool_t pool;
        int ret;
@@ -322,7 +322,7 @@ static bool client_proxy_rcpt(struct client *client,
 
        i_zero(&set);
        set.port = client->local_port;
-       set.protocol = LMTP_CLIENT_PROTOCOL_LMTP;
+       set.protocol = SMTP_PROTOCOL_LMTP;
        set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;
        set.params = *params;
 
@@ -385,27 +385,11 @@ static bool client_proxy_rcpt(struct client *client,
                proxy_set.proxy_ttl = client->proxy_ttl-1;
 
                client->proxy = lmtp_proxy_init(&proxy_set, client->output);
-               args = "";
-               switch (client->state.mail_params.body.type) {
-               case SMTP_PARAM_MAIL_BODY_TYPE_UNSPECIFIED:
-                       break;
-               case SMTP_PARAM_MAIL_BODY_TYPE_7BIT:
-                       args = " BODY=7BIT";
-                       break;
-               case SMTP_PARAM_MAIL_BODY_TYPE_8BITMIME:
-                       args = " BODY=8BITMIME";
-                       break;
-               case SMTP_PARAM_MAIL_BODY_TYPE_BINARYMIME:
-               case SMTP_PARAM_MAIL_BODY_TYPE_EXTENSION:
-                       i_unreached();
-               }
-               lmtp_proxy_mail_from(client->proxy,
-                       t_strdup_printf("<%s>%s",
-                               smtp_address_encode(client->state.mail_from), args));
+               lmtp_proxy_mail_from(client->proxy, client->state.mail_from,
+                       &client->state.mail_params);
        }
-       if (lmtp_proxy_add_rcpt(client->proxy,
-               smtp_address_encode(address), &set) < 0)
-               client_send_line(client, ERRSTR_TEMP_REMOTE_FAILURE);
+       if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0)
+               client_send_line(client, "451 4.4.0 Remote server not answering");
        else
                client_send_line(client, "250 2.1.5 OK");
        pool_unref(&pool);
@@ -588,12 +572,8 @@ int cmd_rcpt(struct client *client, const char *args)
                smtp_address_encode(address));
 
        if (client->lmtp_set->lmtp_proxy) {
-               struct lmtp_recipient_params params;
-
-               i_zero(&params);
-               params.dsn_orcpt = rcpt->params.orcpt.addr_raw;
                if (client_proxy_rcpt(client, address, username, detail, delim,
-                                     &params))
+                                     &rcpt->params))
                        return 0;
        }
 
index e9ef775d571e7a99f94a9386b9e92900b932f61a..cfd092e0326252e7dcb99d4f80cc60e0cee16d22 100644 (file)
@@ -8,14 +8,17 @@
 #include "ostream.h"
 #include "str.h"
 #include "time-util.h"
-#include "lmtp-client.h"
+#include "smtp-reply.h"
+#include "smtp-client.h"
+#include "smtp-client-connection.h"
+#include "smtp-client-transaction.h"
 #include "lmtp-proxy.h"
 
 #define LMTP_MAX_LINE_LEN 1024
 
 struct lmtp_proxy_recipient {
        struct lmtp_proxy_connection *conn;
-       const char *address;
+       const struct smtp_address *address;
        const char *reply;
        unsigned int idx;
 
@@ -27,7 +30,7 @@ struct lmtp_proxy_connection {
        struct lmtp_proxy *proxy;
        struct lmtp_proxy_rcpt_settings set;
 
-       struct lmtp_client *client;
+       struct smtp_client_transaction *lmtp_trans;
        struct istream *data_input;
        struct timeout *to;
 
@@ -37,8 +40,12 @@ struct lmtp_proxy_connection {
 
 struct lmtp_proxy {
        pool_t pool;
-       const char *mail_from;
+       const struct smtp_address *mail_from;
+       struct smtp_params_mail mail_params;
        struct lmtp_proxy_settings set;
+       struct smtp_server_transaction *trans;
+
+       struct smtp_client *lmtp_client;
 
        ARRAY(struct lmtp_proxy_connection *) connections;
        ARRAY(struct lmtp_proxy_recipient *) rcpt_to;
@@ -56,12 +63,17 @@ struct lmtp_proxy {
        bool finished:1;
 };
 
-static void lmtp_conn_finish(void *context);
+static void
+lmtp_proxy_connection_finish(struct lmtp_proxy_connection *conn);
+static void
+lmtp_proxy_data_cb(const struct smtp_reply *reply,
+                  struct lmtp_proxy_recipient *rcpt);
 
 struct lmtp_proxy *
 lmtp_proxy_init(const struct lmtp_proxy_settings *set,
                struct ostream *client_output)
 {
+       struct smtp_client_settings lmtp_set;
        struct lmtp_proxy *proxy;
        pool_t pool;
 
@@ -81,6 +93,20 @@ lmtp_proxy_init(const struct lmtp_proxy_settings *set,
        proxy->set.proxy_ttl = set->proxy_ttl;
        i_array_init(&proxy->rcpt_to, 32);
        i_array_init(&proxy->connections, 32);
+
+       i_zero(&lmtp_set);
+       lmtp_set.my_hostname = set->my_hostname;
+       lmtp_set.dns_client_socket_path = set->dns_client_socket_path;
+
+       lmtp_set.proxy_data.source_ip = set->source_ip;
+       lmtp_set.proxy_data.source_port = set->source_port;
+       lmtp_set.proxy_data.ttl_plus_1 = set->proxy_ttl;
+       if (lmtp_set.proxy_data.ttl_plus_1 == 0)
+               lmtp_set.proxy_data.ttl_plus_1 = LMTP_PROXY_DEFAULT_TTL + 1;
+       else
+               lmtp_set.proxy_data.ttl_plus_1--;
+
+       proxy->lmtp_client = smtp_client_init(&lmtp_set);
        return proxy;
 }
 
@@ -91,7 +117,8 @@ static void lmtp_proxy_connections_deinit(struct lmtp_proxy *proxy)
        array_foreach(&proxy->connections, conns) {
                struct lmtp_proxy_connection *conn = *conns;
 
-               lmtp_client_deinit(&conn->client);
+               if (conn->lmtp_trans != NULL)
+                       smtp_client_transaction_destroy(&conn->lmtp_trans);
        }
 }
 
@@ -102,6 +129,7 @@ void lmtp_proxy_deinit(struct lmtp_proxy **_proxy)
        *_proxy = NULL;
 
        lmtp_proxy_connections_deinit(proxy);
+       smtp_client_deinit(&proxy->lmtp_client);
        i_stream_unref(&proxy->data_input);
        o_stream_unref(&proxy->client_output);
        timeout_remove(&proxy->to_finish);
@@ -110,39 +138,43 @@ void lmtp_proxy_deinit(struct lmtp_proxy **_proxy)
        pool_unref(&proxy->pool);
 }
 
-void lmtp_proxy_mail_from(struct lmtp_proxy *proxy, const char *value)
+void lmtp_proxy_mail_from(struct lmtp_proxy *proxy,
+                         const struct smtp_address *address,
+                         const struct smtp_params_mail *params)
 {
-       proxy->mail_from = p_strdup(proxy->pool, value);
+       proxy->mail_from = smtp_address_clone(proxy->pool, address);
+       smtp_params_mail_copy(proxy->pool, &proxy->mail_params, params);
+}
+
+static void
+lmtp_proxy_mail_cb(const struct smtp_reply *proxy_reply ATTR_UNUSED,
+                  struct lmtp_proxy_connection *conn ATTR_UNUSED)
+{
+       /* nothing */
 }
 
 static struct lmtp_proxy_connection *
 lmtp_proxy_get_connection(struct lmtp_proxy *proxy,
                          const struct lmtp_proxy_rcpt_settings *set)
 {
+       struct smtp_client_connection *lmtp_conn;
        struct lmtp_proxy_connection *const *conns, *conn;
-       struct lmtp_client_settings client_set;
 
        i_assert(set->timeout_msecs > 0);
 
        array_foreach(&proxy->connections, conns) {
                conn = *conns;
 
-               if (conn->set.port == set->port &&
+               if (conn->set.protocol == set->protocol &&
+                   conn->set.port == set->port &&
                    strcmp(conn->set.host, set->host) == 0)
                        return conn;
        }
 
-       i_zero(&client_set);
-       client_set.mail_from = proxy->mail_from;
-       client_set.my_hostname = proxy->set.my_hostname;
-       client_set.dns_client_socket_path = proxy->set.dns_client_socket_path;
-       client_set.source_ip = proxy->set.source_ip;
-       client_set.source_port = proxy->set.source_port;
-       client_set.proxy_ttl = proxy->set.proxy_ttl;
-       client_set.proxy_timeout_secs = set->timeout_msecs/1000;
-
        conn = p_new(proxy->pool, struct lmtp_proxy_connection, 1);
        conn->proxy = proxy;
+       conn->set.protocol = set->protocol;
+       conn->set.hostip = set->hostip;
        if (set->hostip.family == 0)
                conn->set.host = p_strdup(proxy->pool, set->host);
        else
@@ -151,10 +183,18 @@ lmtp_proxy_get_connection(struct lmtp_proxy *proxy,
        conn->set.timeout_msecs = set->timeout_msecs;
        array_append(&proxy->connections, &conn, 1);
 
-       conn->client = lmtp_client_init(&client_set, lmtp_conn_finish, conn);
-       if (lmtp_client_connect_tcp(conn->client, set->protocol,
-                                   conn->set.host, conn->set.port) < 0)
-               conn->failed = TRUE;
+       lmtp_conn = smtp_client_connection_create(proxy->lmtp_client,
+               set->protocol, set->host, set->port,
+               SMTP_CLIENT_SSL_MODE_NONE, NULL);
+       smtp_client_connection_connect(lmtp_conn, NULL, NULL);
+
+       conn->lmtp_trans = smtp_client_transaction_create(lmtp_conn,
+               proxy->mail_from, &proxy->mail_params,
+               lmtp_proxy_connection_finish, conn);
+       smtp_client_connection_unref(&lmtp_conn);
+
+       smtp_client_transaction_start(conn->lmtp_trans,
+                                     lmtp_proxy_mail_cb, conn);
 
        if (proxy->max_timeout_msecs < set->timeout_msecs)
                proxy->max_timeout_msecs = set->timeout_msecs;
@@ -210,37 +250,70 @@ static void lmtp_proxy_try_finish(struct lmtp_proxy *proxy)
        }
 }
 
-static void lmtp_conn_finish(void *context)
+static void
+lmtp_proxy_connection_finish(struct lmtp_proxy_connection *conn)
 {
-       struct lmtp_proxy_connection *conn = context;
-
        conn->finished = TRUE;
+       conn->lmtp_trans = NULL;
        timeout_remove(&conn->to);
        i_stream_unref(&conn->data_input);
        lmtp_proxy_try_finish(conn->proxy);
 }
 
 static void
-lmtp_proxy_conn_rcpt_to(enum lmtp_client_result result,
-                       const char *reply, void *context)
+lmtp_proxy_write_reply(string_t *reply, const struct smtp_reply *proxy_reply)
+{
+       if (smtp_reply_is_remote(proxy_reply)) {
+               smtp_reply_write(reply, proxy_reply);
+       } else {
+               str_append(reply, "451 4.4.0 Remote server not answering");
+               switch (proxy_reply->status) {
+               case SMTP_CLIENT_COMMAND_ERROR_HOST_LOOKUP_FAILED:
+                       str_append(reply, " (DNS lookup)");
+                       break;
+               case SMTP_CLIENT_COMMAND_ERROR_CONNECT_FAILED:
+               case SMTP_CLIENT_COMMAND_ERROR_AUTH_FAILED:
+                       str_append(reply, " (connect)");
+                       break;
+               case SMTP_CLIENT_COMMAND_ERROR_CONNECTION_LOST:
+                       str_append(reply, " (connection lost)");
+                       break;
+               case SMTP_CLIENT_COMMAND_ERROR_BAD_REPLY:
+                       str_append(reply, " (bad reply)");
+                       break;                  
+               case SMTP_CLIENT_COMMAND_ERROR_TIMED_OUT:
+                       str_append(reply, " (timed out)");
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void
+lmtp_proxy_rcpt_cb(const struct smtp_reply *proxy_reply,
+                  struct lmtp_proxy_recipient *rcpt)
 {
-       struct lmtp_proxy_recipient *rcpt = context;
        struct lmtp_proxy_connection *conn = rcpt->conn;
+       string_t *reply;
 
        i_assert(rcpt->reply == NULL);
 
-       rcpt->reply = p_strdup(conn->proxy->pool, reply);
-       rcpt->rcpt_to_failed = result != LMTP_CLIENT_RESULT_OK;
+       reply = t_str_new(128);
+       lmtp_proxy_write_reply(reply, proxy_reply);
+
+       rcpt->reply = p_strdup(conn->proxy->pool, str_c(reply));
+       rcpt->rcpt_to_failed = !smtp_reply_is_success(proxy_reply);
 }
 
 static void
-lmtp_proxy_conn_data(enum lmtp_client_result result,
-                    const char *reply, void *context)
+lmtp_proxy_data_cb(const struct smtp_reply *proxy_reply,
+                  struct lmtp_proxy_recipient *rcpt)
 {
-       struct lmtp_proxy_recipient *rcpt = context;
        struct lmtp_proxy_connection *conn = rcpt->conn;
-       const struct lmtp_client_times *times =
-               lmtp_client_get_times(conn->client);
+       const struct smtp_client_transaction_times *times =
+               smtp_client_transaction_get_times(conn->lmtp_trans);
+       string_t *reply;
        string_t *msg;
 
        i_assert(!rcpt->rcpt_to_failed);
@@ -250,40 +323,37 @@ lmtp_proxy_conn_data(enum lmtp_client_result result,
        if (conn->to != NULL)
                timeout_reset(conn->to);
 
-       rcpt->reply = p_strdup(conn->proxy->pool, reply);
+       reply = t_str_new(128);
+       lmtp_proxy_write_reply(reply, proxy_reply);
+
+       rcpt->reply = p_strdup(conn->proxy->pool, str_c(reply));
        rcpt->data_reply_received = TRUE;
 
        msg = t_str_new(128);
        str_printfa(msg, "%s: ", conn->proxy->set.session_id);
-       switch (result) {
-       case LMTP_CLIENT_RESULT_OK:
+       if (smtp_reply_is_success(proxy_reply))
                str_append(msg, "Sent message to");
-               break;
-       case LMTP_CLIENT_RESULT_REMOTE_ERROR:
-       case LMTP_CLIENT_RESULT_INTERNAL_ERROR:
+       else
                str_append(msg, "Failed to send message to");
-               break;
-       }
        str_printfa(msg, " <%s> at %s:%u: %s (%u/%u at %u ms)",
-                   rcpt->address, conn->set.host, conn->set.port, reply,
+                   smtp_address_encode(rcpt->address), conn->set.host,
+                   conn->set.port, str_c(reply),
                    rcpt->idx + 1, array_count(&conn->proxy->rcpt_to),
-                   timeval_diff_msecs(&ioloop_timeval, &times->connect_started));
-       switch (result) {
-       case LMTP_CLIENT_RESULT_OK:
-       case LMTP_CLIENT_RESULT_REMOTE_ERROR:
+                   timeval_diff_msecs(&ioloop_timeval, &times->started));
+       if (smtp_reply_is_success(proxy_reply) ||
+               smtp_reply_is_remote(proxy_reply)) {
                /* the problem isn't with the proxy, it's with the remote side.
                   so the remote side will log an error, while for us this is
                   just an info event */
                i_info("%s", str_c(msg));
-               break;
-       case LMTP_CLIENT_RESULT_INTERNAL_ERROR:
+       } else {
                i_error("%s", str_c(msg));
-               break;
        }
        lmtp_proxy_try_finish(conn->proxy);
 }
 
-int lmtp_proxy_add_rcpt(struct lmtp_proxy *proxy, const char *address,
+int lmtp_proxy_add_rcpt(struct lmtp_proxy *proxy,
+                       const struct smtp_address *address,
                        const struct lmtp_proxy_rcpt_settings *set)
 {
        struct lmtp_proxy_connection *conn;
@@ -296,24 +366,19 @@ int lmtp_proxy_add_rcpt(struct lmtp_proxy *proxy, const char *address,
        rcpt = p_new(proxy->pool, struct lmtp_proxy_recipient, 1);
        rcpt->idx = array_count(&proxy->rcpt_to);
        rcpt->conn = conn;
-       rcpt->address = p_strdup(proxy->pool, address);
+       rcpt->address = smtp_address_clone(proxy->pool, address);
        array_append(&proxy->rcpt_to, &rcpt, 1);
 
-       lmtp_client_add_rcpt_params(conn->client, address, &set->params,
-                                   lmtp_proxy_conn_rcpt_to,
-                                   lmtp_proxy_conn_data, rcpt);
+       smtp_client_transaction_add_rcpt(conn->lmtp_trans, address,
+               &set->params, lmtp_proxy_rcpt_cb, lmtp_proxy_data_cb, rcpt);
        return 0;
 }
 
-static void lmtp_proxy_conn_timeout(struct lmtp_proxy_connection *conn)
+static void
+lmtp_proxy_data_dummy_cb(const struct smtp_reply *proxy_reply ATTR_UNUSED,
+                        struct lmtp_proxy_connection *conn ATTR_UNUSED)
 {
-       const char *line;
-
-       line = t_strdup_printf(ERRSTR_TEMP_REMOTE_FAILURE
-                              " (timeout while waiting for reply to %s) <%s>",
-                              lmtp_client_state_to_string(conn->client),
-                              conn->proxy->set.session_id);
-       lmtp_client_fail(conn->client, line);
+       /* nothing */
 }
 
 void lmtp_proxy_start(struct lmtp_proxy *proxy, struct istream *data_input,
@@ -344,8 +409,6 @@ void lmtp_proxy_start(struct lmtp_proxy *proxy, struct istream *data_input,
                        continue;
                }
 
-               conn->to = timeout_add(proxy->max_timeout_msecs,
-                                      lmtp_proxy_conn_timeout, conn);
                if (size == (uoff_t)-1)
                        conn->data_input = i_stream_create_limit(data_input, (uoff_t)-1);
                else
@@ -357,9 +420,12 @@ void lmtp_proxy_start(struct lmtp_proxy *proxy, struct istream *data_input,
        array_foreach(&proxy->connections, conns) {
                struct lmtp_proxy_connection *conn = *conns;
 
+               smtp_client_transaction_set_timeout(conn->lmtp_trans,
+                       proxy->max_timeout_msecs);
                if (conn->data_input != NULL) {
-                       lmtp_client_send(conn->client, conn->data_input);
-                       lmtp_client_send_more(conn->client);
+                       smtp_client_transaction_send(conn->lmtp_trans,
+                               conn->data_input,
+                               lmtp_proxy_data_dummy_cb, conn);
                }
        }
        /* finish if all of the connections have already failed */
index d5c80e8a1cc1359728c45b6286c6c09a513a4099..05c7a0515976acc4847a96035ffe55159bac0e3c 100644 (file)
@@ -2,7 +2,9 @@
 #define LMTP_PROXY_H
 
 #include "net.h"
-#include "lmtp-client.h"
+#include "smtp-address.h"
+#include "smtp-params.h"
+#include "smtp-client.h"
 
 #define LMTP_PROXY_DEFAULT_TTL 5
 
@@ -18,12 +20,12 @@ struct lmtp_proxy_settings {
 };
 
 struct lmtp_proxy_rcpt_settings {
+       enum smtp_protocol protocol;
        const char *host;
        struct ip_addr hostip;
        in_port_t port;
        unsigned int timeout_msecs;
-       enum lmtp_client_protocol protocol;
-       struct lmtp_recipient_params params;
+       struct smtp_params_rcpt params;
 };
 
 typedef void lmtp_proxy_finish_callback_t(void *context);
@@ -33,11 +35,14 @@ lmtp_proxy_init(const struct lmtp_proxy_settings *set,
                struct ostream *client_output);
 void lmtp_proxy_deinit(struct lmtp_proxy **proxy);
 
-/* Set the "MAIL FROM:" line, including <> and options */
-void lmtp_proxy_mail_from(struct lmtp_proxy *proxy, const char *value);
+/* Set the "MAIL FROM:" parameters */
+void lmtp_proxy_mail_from(struct lmtp_proxy *proxy,
+                         const struct smtp_address *address,
+                         const struct smtp_params_mail *params);
 /* Add a new recipient. Returns -1 if we already know that the destination
    host can't be reached. */
-int lmtp_proxy_add_rcpt(struct lmtp_proxy *proxy, const char *address,
+int lmtp_proxy_add_rcpt(struct lmtp_proxy *proxy,
+                       const struct smtp_address *address,
                        const struct lmtp_proxy_rcpt_settings *set);
 /* Start proxying */
 void lmtp_proxy_start(struct lmtp_proxy *proxy, struct istream *data_input,