From 0762e1a4d6de4b7b0206314302297c9dd6d7ae73 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Fri, 23 Dec 2022 18:02:25 +0000 Subject: [PATCH] Expand max_rcpt option on smtp transport. Bug 2946 --- doc/doc-docbook/spec.xfpt | 20 +++++++++++++----- doc/doc-txt/NewStuff | 3 ++- src/src/deliver.c | 12 +++++++---- src/src/functions.h | 10 ++++++++- src/src/globals.c | 2 +- src/src/macros.h | 4 ++++ src/src/structs.h | 2 +- src/src/transports/smtp.c | 12 ++++++----- test/confs/0285 | 15 +++++++++---- test/log/0285 | 4 ++++ test/scripts/0000-Basic/0285 | 29 +++++++++++++++++++++++++ test/stdout/0285 | 41 ++++++++++++++++++++++++++++++++++++ 12 files changed, 132 insertions(+), 22 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index cdac2a266..946f55b11 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -22397,7 +22397,7 @@ its removal from incoming messages, so that delivered messages can safely be resent to other recipients. &*Note:*& If used on a transport handling multiple recipients -(the smtp transport unless &%rcpt_max%& is 1, the appendfile, pipe or lmtp +(the smtp transport unless &%max_rcpt%& is 1, the appendfile, pipe or lmtp transport if &%batch_max%& is greater than 1) then information about Bcc recipients will be leaked. Doing so is generally not advised. @@ -25778,12 +25778,22 @@ If this option is set true when the &%protocol%& option is set to &"lmtp"&, the string &`IGNOREQUOTA`& is added to RCPT commands, provided that the LMTP server has advertised support for IGNOREQUOTA in its response to the LHLO command. -.option max_rcpt smtp integer 100 +.option max_rcpt smtp integer&!! 100 .cindex "RCPT" "maximum number of outgoing" -This option limits the number of RCPT commands that are sent in a single -SMTP message transaction. Each set of addresses is treated independently, and +This option, +.new +after expansion, +.wen +limits the number of RCPT commands that are sent in a single +SMTP message transaction. +A value setting of zero disables the limit. + +.new +If a constant is given, +.wen +each set of addresses is treated independently, and so can cause parallel connections to the same host if &%remote_max_parallel%& -permits this. A value setting of zero disables the limit. +permits this. .option message_linelength_limit smtp integer 998 diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 0d4557a8b..b00399511 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -16,7 +16,8 @@ Version 4.97 3. Variable $sender_helo_verified with the result of an ACL "verify = helo". 4. Predefined macros for expansion items, operators, conditions and variables. - 3. Variable $sender_helo_verified with the result of an ACL verify=helo. + + 5. The smtp transport option "max_rcpt" is now expanded before use. Version 4.96 ------------ diff --git a/src/src/deliver.c b/src/src/deliver.c index c5e00eaef..ca31df587 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -4290,10 +4290,14 @@ So look out for the place it gets used. } /* Get the maximum it can handle in one envelope, with zero meaning - unlimited, which is forced for the MUA wrapper case. */ - - address_count_max = tp->max_addresses; - if (address_count_max == 0 || mua_wrapper) address_count_max = 999999; + unlimited, which is forced for the MUA wrapper case and if the + value could vary depending on the messages. + For those, we only split (below) by (tpt,dest,erraddr,hdrs) and rely on the + transport splitting further by max_rcp. So we potentially lose some + parallellism. */ + + address_count_max = mua_wrapper || Ustrchr(tp->max_addresses, '$') + ? UNLIMITED_ADDRS : expand_max_rcpt(tp->max_addresses); /************************************************************************/ diff --git a/src/src/functions.h b/src/src/functions.h index 3ca346c04..1817144ea 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -1307,6 +1307,14 @@ debug_printf("cmdlog: '%s'\n", client_cmd_log ? client_cmd_log->s : US"(unset)") +static inline int +expand_max_rcpt(const uschar * str_max_rcpt) +{ +const uschar * s = expand_cstring(str_max_rcpt); +int res; +return !s || !*s || (res = Uatoi(s)) == 0 ? UNLIMITED_ADDRS : res; +} + # endif /* !COMPILE_UTILITY */ /******************************************************************************/ @@ -1314,6 +1322,6 @@ debug_printf("cmdlog: '%s'\n", client_cmd_log ? client_cmd_log->s : US"(unset)") #endif /* _FUNCTIONS_H_ */ -/* vi: aw +/* vi: aw ai sw=2 */ /* End of functions.h */ diff --git a/src/src/globals.c b/src/src/globals.c index e5b72592f..efe34902a 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -1592,7 +1592,7 @@ transport_instance transport_defaults = { /* All non-mentioned elements zero/NULL/FALSE */ .batch_max = 1, .multi_domain = TRUE, - .max_addresses = 100, + .max_addresses = US"100", .connection_max_messages = 500, .uid = (uid_t)(-1), .gid = (gid_t)(-1), diff --git a/src/src/macros.h b/src/src/macros.h index a631877a1..585067fc9 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1136,4 +1136,8 @@ typedef unsigned mcs_flags; #else # define EXIM_NOFOLLOW 0 #endif + +/* A big number for (effectively) unlimited envelope addresses */ +#define UNLIMITED_ADDRS 999999 + /* End of macros.h */ diff --git a/src/src/structs.h b/src/src/structs.h index e1d93a943..eae66e88d 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -183,7 +183,7 @@ typedef struct transport_instance { uschar *expand_multi_domain; /* ) */ BOOL multi_domain; /* ) */ BOOL overrides_hosts; /* ) Used only for remote transports */ - int max_addresses; /* ) */ + uschar *max_addresses; /* ) */ int connection_max_messages;/* ) */ /**************************************/ BOOL deliver_as_creator; /* Used only by pipe at present */ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index ed5f83b3e..c5951832b 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -114,7 +114,7 @@ optionlist smtp_transport_options[] = { { "interface", opt_stringptr, LOFF(interface) }, { "keepalive", opt_bool, LOFF(keepalive) }, { "lmtp_ignore_quota", opt_bool, LOFF(lmtp_ignore_quota) }, - { "max_rcpt", opt_int | opt_public, + { "max_rcpt", opt_stringptr | opt_public, OPT_OFF(transport_instance, max_addresses) }, { "message_linelength_limit", opt_int, LOFF(message_linelength_limit) }, { "multi_domain", opt_expand_bool | opt_public, @@ -2121,8 +2121,9 @@ sx->dane_required = verify_check_given_host(CUSS &ob->hosts_require_dane, sx->conn_args.host) == OK; #endif -if ((sx->max_mail = sx->conn_args.tblock->connection_max_messages) == 0) sx->max_mail = 999999; -if ((sx->max_rcpt = sx->conn_args.tblock->max_addresses) == 0) sx->max_rcpt = 999999; +if ((sx->max_mail = sx->conn_args.tblock->connection_max_messages) == 0) + sx->max_mail = UNLIMITED_ADDRS; +sx->max_rcpt = expand_max_rcpt(sx->conn_args.tblock->max_addresses); sx->igquotstr = US""; if (!sx->helo_data) sx->helo_data = ob->helo_data; @@ -2819,8 +2820,9 @@ if (tls_out.active.sock >= 0) #ifdef EXPERIMMENTAL_ESMTP_LIMITS /* As we are about to send another EHLO, forget any LIMITS received so far. */ sx->peer_limit_mail = sx->peer_limit_rcpt = sx->peer_limit_rcptdom = 0; - if ((sx->max_mail = sx->conn_args.tblock->connection_max_message) == 0) sx->max_mail = 999999; - if ((sx->max_rcpt = sx->conn_args.tblock->max_addresses) == 0) sx->max_rcpt = 999999; + if ((sx->max_mail = sx->conn_args.tblock->connection_max_message) == 0) + sx->max_mail = UNLIMITED_ADDRS; + sx->max_rcpt = expand_max_rcpt(sx->conn_args.tblock->max_addresses); sx->single_rcpt_domain = FALSE; #endif diff --git a/test/confs/0285 b/test/confs/0285 index 8b0ada1f1..20ec0263a 100644 --- a/test/confs/0285 +++ b/test/confs/0285 @@ -23,7 +23,7 @@ all: driver = manualroute route_list = * 127.0.0.1 byname self = send - transport = smtp + transport = ${if eq {$domain}{test.ex} {smtp}{magic_smtp}} # ----- Transports ----- @@ -31,10 +31,17 @@ all: begin transports smtp: - driver = smtp - port = PORT_S + driver = smtp + port = PORT_S hosts_try_fastopen = : - max_rcpt = 2 + max_rcpt = 2 + connection_max_messages = 3 + +magic_smtp: + driver = smtp + port = PORT_S + hosts_try_fastopen = : + max_rcpt = ${if match {$domain}{magic(\\d+)} {$1} {2}} connection_max_messages = 3 diff --git a/test/log/0285 b/test/log/0285 index 7828219ce..4da1f42dc 100644 --- a/test/log/0285 +++ b/test/log/0285 @@ -26,3 +26,7 @@ 1999-03-02 09:44:33 10HmbA-0005vi-00 Completed 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed 1999-03-02 09:44:33 End queue run: pid=p1235 +1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmbB-0005vi-00 => x@magic1.test.ex R=all T=magic_smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbB-0005vi-00 => y@magic1.test.ex R=all T=magic_smtp H=127.0.0.1 [127.0.0.1]* C="250 OK" +1999-03-02 09:44:33 10HmbB-0005vi-00 Completed diff --git a/test/scripts/0000-Basic/0285 b/test/scripts/0000-Basic/0285 index 1ecc64202..976058fa4 100644 --- a/test/scripts/0000-Basic/0285 +++ b/test/scripts/0000-Basic/0285 @@ -100,3 +100,32 @@ QUIT **** exim -odi -q **** +# +# Extended version of pulling a max_rcpt out of an expansion +# Expect log with two => lines on one conn +server PORT_S +220 ESMTP +EHLO +250-OK +250 HELP +MAIL FROM: +250 Sender OK +RCPT TO: +250 Recipient OK +DATA +354 Send data +. +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 Recipient OK +DATA +354 Send data +. +250 OK +QUIT +250 OK +**** +exim -odf x@magic1.test.ex y@magic1.test.ex +**** diff --git a/test/stdout/0285 b/test/stdout/0285 index 256a65070..de6245c6d 100644 --- a/test/stdout/0285 +++ b/test/stdout/0285 @@ -133,3 +133,44 @@ Date: Tue, 2 Mar 1999 09:44:33 +0000 QUIT 250 OK End of script +Listening on port 1224 ... +Connection request from [127.0.0.1] +220 ESMTP +EHLO myhost.test.ex +250-OK +250 HELP +MAIL FROM: +250 Sender OK +RCPT TO: +250 Recipient OK +DATA +354 Send data +Received: from CALLER by myhost.test.ex with local (Exim x.yz) + (envelope-from ) + id 10HmbB-0005vi-00; + Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 Recipient OK +DATA +354 Send data +Received: from CALLER by myhost.test.ex with local (Exim x.yz) + (envelope-from ) + id 10HmbB-0005vi-00; + Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 OK +QUIT +250 OK +End of script -- 2.30.2