dovecot-2.2: smtp/lmtp client: Send XCLIENT ADDR+PORT when possi...

dovecot at dovecot.org dovecot at dovecot.org
Thu Feb 23 11:59:23 EET 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/3144001fae84
changeset: 14150:3144001fae84
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Feb 23 11:58:35 2012 +0200
description:
smtp/lmtp client: Send XCLIENT ADDR+PORT when possible.

diffstat:

 src/lib-lda/lmtp-client.c |  91 +++++++++++++++++++++++++++++++++++++++++++---
 src/lib-lda/lmtp-client.h |   7 +++
 2 files changed, 91 insertions(+), 7 deletions(-)

diffs (234 lines):

diff -r 1af2a0497f3f -r 3144001fae84 src/lib-lda/lmtp-client.c
--- a/src/lib-lda/lmtp-client.c	Thu Feb 23 11:12:04 2012 +0200
+++ b/src/lib-lda/lmtp-client.c	Thu Feb 23 11:58:35 2012 +0200
@@ -6,6 +6,7 @@
 #include "network.h"
 #include "istream.h"
 #include "ostream.h"
+#include "str.h"
 #include "dns-lookup.h"
 #include "lmtp-client.h"
 
@@ -20,7 +21,8 @@
 	LMTP_INPUT_STATE_MAIL_FROM,
 	LMTP_INPUT_STATE_RCPT_TO,
 	LMTP_INPUT_STATE_DATA_CONTINUE,
-	LMTP_INPUT_STATE_DATA
+	LMTP_INPUT_STATE_DATA,
+	LMTP_INPUT_STATE_XCLIENT
 };
 
 struct lmtp_rcpt {
@@ -44,6 +46,8 @@
 	enum lmtp_client_protocol protocol;
 	enum lmtp_input_state input_state;
 	const char *global_fail_string;
+	string_t *input_multiline;
+	const char **xclient_args;
 
 	struct istream *input;
 	struct ostream *output;
@@ -64,6 +68,7 @@
 	struct istream *data_input;
 	unsigned char output_last;
 
+	unsigned int xclient_sent:1;
 	unsigned int rcpt_to_successes:1;
 	unsigned int output_finished:1;
 	unsigned int finish_called:1;
@@ -89,9 +94,12 @@
 	client->set.my_hostname = p_strdup(pool, set->my_hostname);
 	client->set.dns_client_socket_path =
 		p_strdup(pool, set->dns_client_socket_path);
+	client->set.source_ip = set->source_ip;
+	client->set.source_port = set->source_port;
 	client->finish_callback = finish_callback;
 	client->finish_context = context;
 	client->fd = -1;
+	client->input_multiline = str_new(default_pool, 128);
 	p_array_init(&client->recipients, pool, 16);
 	return client;
 }
@@ -138,6 +146,7 @@
 		i_stream_unref(&client->input);
 	if (client->output != NULL)
 		o_stream_unref(&client->output);
+	str_free(&client->input_multiline);
 	pool_unref(&client->pool);
 }
 
@@ -177,6 +186,8 @@
 			return t_strdup_printf("DATA (%"PRIuUOFF_T"/?)",
 					       client->data_input->v_offset);
 		}
+	case LMTP_INPUT_STATE_XCLIENT:
+		return "XCLIENT";
 	}
 	return "??";
 }
@@ -356,7 +367,8 @@
 	}
 }
 
-static int lmtp_input_get_reply_code(const char *line, int *reply_code_r)
+static int lmtp_input_get_reply_code(const char *line, int *reply_code_r,
+				     string_t *multiline)
 {
 	if (!i_isdigit(line[0]) || !i_isdigit(line[1]) || !i_isdigit(line[2]))
 		return -1;
@@ -369,7 +381,9 @@
 		/* final reply */
 		return 1;
 	} else if (line[3] == '-') {
-		/* multiline reply. just ignore it. */
+		/* multiline reply. */
+		str_append(multiline, line);
+		str_append_c(multiline, '\n');
 		return 0;
 	} else {
 		/* invalid input */
@@ -377,11 +391,58 @@
 	}
 }
 
+static void
+lmtp_client_parse_capabilities(struct lmtp_client *client, const char *lines)
+{
+	const char *const *linep;
+
+	for (linep = t_strsplit(lines, "\n"); *linep != NULL; linep++) {
+		const char *line = *linep;
+
+		line += 4; /* already checked this is valid */
+		if (strncasecmp(line, "XCLIENT ", 8) == 0) {
+			client->xclient_args =
+				(void *)p_strsplit(client->pool, line + 8, " ");
+		}
+	}
+}
+
+static bool lmtp_client_send_xclient(struct lmtp_client *client)
+{
+	string_t *str;
+	unsigned int empty_len;
+
+	if (client->xclient_args == NULL) {
+		/* not supported */
+		return FALSE;
+	}
+	if (client->xclient_sent)
+		return FALSE;
+
+	str = t_str_new(64);
+	str_append(str, "XCLIENT");
+	empty_len = str_len(str);
+	if (client->set.source_ip.family != 0 &&
+	    str_array_icase_find(client->xclient_args, "ADDR"))
+		str_printfa(str, " ADDR=%s", net_ip2addr(&client->set.source_ip));
+	if (client->set.source_port != 0 &&
+	    str_array_icase_find(client->xclient_args, "PORT"))
+		str_printfa(str, " PORT=%u", client->set.source_port);
+
+	if (str_len(str) == empty_len)
+		return FALSE;
+
+	str_append(str, "\r\n");
+	o_stream_send(client->output, str_data(str), str_len(str));
+	return TRUE;
+}
+
 static int lmtp_client_input_line(struct lmtp_client *client, const char *line)
 {
 	int ret, reply_code = 0;
 
-	if ((ret = lmtp_input_get_reply_code(line, &reply_code)) <= 0) {
+	if ((ret = lmtp_input_get_reply_code(line, &reply_code,
+					     client->input_multiline)) <= 0) {
 		if (ret == 0)
 			return 0;
 		lmtp_client_fail(client, line);
@@ -390,12 +451,13 @@
 
 	switch (client->input_state) {
 	case LMTP_INPUT_STATE_GREET:
+	case LMTP_INPUT_STATE_XCLIENT:
 		if (reply_code != 220) {
 			lmtp_client_fail(client, line);
 			return -1;
 		}
 		lmtp_client_send_handshake(client);
-		client->input_state++;
+		client->input_state = LMTP_INPUT_STATE_LHLO;
 		break;
 	case LMTP_INPUT_STATE_LHLO:
 	case LMTP_INPUT_STATE_MAIL_FROM:
@@ -403,6 +465,15 @@
 			lmtp_client_fail(client, line);
 			return -1;
 		}
+		str_append(client->input_multiline, line);
+		lmtp_client_parse_capabilities(client,
+			str_c(client->input_multiline));
+		if (client->input_state == LMTP_INPUT_STATE_LHLO &&
+		    lmtp_client_send_xclient(client)) {
+			client->input_state = LMTP_INPUT_STATE_XCLIENT;
+			client->xclient_sent = TRUE;
+			break;
+		}
 		if (client->input_state == LMTP_INPUT_STATE_LHLO) {
 			o_stream_send_str(client->output,
 				t_strdup_printf("MAIL FROM:%s\r\n",
@@ -435,21 +506,27 @@
 			return -1;
 		break;
 	}
-	return 0;
+	return 1;
 }
 
 static void lmtp_client_input(struct lmtp_client *client)
 {
 	const char *line;
+	int ret;
 
 	lmtp_client_ref(client);
 	o_stream_cork(client->output);
 	while ((line = i_stream_read_next_line(client->input)) != NULL) {
-		if (lmtp_client_input_line(client, line) < 0) {
+		T_BEGIN {
+			ret = lmtp_client_input_line(client, line);
+		} T_END;
+		if (ret < 0) {
 			o_stream_uncork(client->output);
 			lmtp_client_unref(&client);
 			return;
 		}
+		if (ret > 0)
+			str_truncate(client->input_multiline, 0);
 	}
 
 	if (client->input->stream_errno != 0) {
diff -r 1af2a0497f3f -r 3144001fae84 src/lib-lda/lmtp-client.h
--- a/src/lib-lda/lmtp-client.h	Thu Feb 23 11:12:04 2012 +0200
+++ b/src/lib-lda/lmtp-client.h	Thu Feb 23 11:58:35 2012 +0200
@@ -1,6 +1,8 @@
 #ifndef LMTP_CLIENT_H
 #define LMTP_CLIENT_H
 
+#include "network.h"
+
 #define ERRSTR_TEMP_REMOTE_FAILURE "451 4.4.0 Remote server not answering"
 
 /* LMTP/SMTP client code. */
@@ -14,6 +16,11 @@
 	const char *my_hostname;
 	const char *mail_from;
 	const char *dns_client_socket_path;
+
+	/* if remote server supports XCLIENT capability,
+	   send the these as ADDR/PORT */
+	struct ip_addr source_ip;
+	unsigned int source_port;
 };
 
 /* reply contains the reply coming from remote server, or NULL


More information about the dovecot-cvs mailing list