From 5032d1cf500b102849d9a47867fbb7b34d871683 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 13 Jan 2015 11:19:32 +0000 Subject: [PATCH] Multi-recipient cutthrough delivery. Bug 1542 Testing and fixes by: Heiko Schlittermann --- doc/doc-docbook/spec.xfpt | 13 +- doc/doc-txt/ChangeLog | 3 + src/src/acl.c | 36 +-- src/src/globals.c | 7 +- src/src/globals.h | 12 +- src/src/receive.c | 74 +++--- src/src/smtp_in.c | 2 +- src/src/verify.c | 261 +++++++++++++++------ test/confs/5400 | 17 +- test/log/5400 | 48 +++- test/scripts/5400-cutthrough/5400 | 321 ++++++++++++++++++++++++-- test/stderr/5400 | 235 ------------------- test/stdout/5400 | 364 +++++++++++++++++++++++++++++- 13 files changed, 999 insertions(+), 394 deletions(-) delete mode 100644 test/stderr/5400 diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index d78797fb7..d5a16cacc 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -28003,14 +28003,18 @@ is what is wanted for subsequent tests. .cindex "cutthrough" "requesting" This option requests delivery be attempted while the item is being received. -The option usable in the RCPT ACL. +The option is usable in the RCPT ACL. If enabled for a message recieved via smtp and routed to an smtp transport, -and the message has only one recipient, +and only one transport, interface, destination host and port combination +is used for all recipients of the message, then the delivery connection is made while the receiving connection is open and data is copied from one to the other. +An attempt to set this option for any recipient but the first +for a mail will be quietly ignored. If a recipient-verify callout connection is subsequently -requested in the same ACL it is held open and used for the data, +requested in the same ACL it is held open and used for +any subsequent receipients and the data, otherwise one is made after the initial RCPT ACL completes. Note that routers are used in verify mode, @@ -28022,12 +28026,13 @@ Headers may be modified by routers (subject to the above) and transports. Cutthrough delivery is not supported via transport-filters or when DKIM signing of outgoing messages is done, because it sends data to the ultimate destination before the entire message has been received from the source. +It is not supported for messages recieved with the SMTP PRDR option in use. Should the ultimate destination system positively accept or reject the mail, a corresponding indication is given to the source system and nothing is queued. If there is a temporary error the item is queued for later delivery in the usual fashion. If the item is successfully delivered in cutthrough mode -the log line is tagged with ">>" rather than "=>" and appears +the delivery log lines are tagged with ">>" rather than "=>" and appear before the acceptance "<=" line. Delivery in this mode avoids the generation of a bounce mail to a diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index eeefef71c..57df78280 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -44,6 +44,9 @@ JH/10 The smtp_receive_timeout main option is now expanded before use. JH/11 The incoming_interface log option now also enables logging of the local interface on delivery outgoing connections. +JH/12 The cutthrough-routing facility now supports multi-recipient mails, + if the interface and destination host and port all match. + Exim version 4.85 diff --git a/src/src/acl.c b/src/src/acl.c index 8fdae0390..06c1c494c 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -3354,19 +3354,27 @@ for (; cb != NULL; cb = cb->next) break; case CONTROL_CUTTHROUGH_DELIVERY: - if (deliver_freeze) - *log_msgptr = US"frozen"; - else if (queue_only_policy) - *log_msgptr = US"queue-only"; - else if (fake_response == FAIL) - *log_msgptr = US"fakereject"; + if (prdr_requested) + /* Too hard to think about for now. We might in future cutthrough + the case where both sides handle prdr and this-node prdr acl + is "accept" */ + *log_msgptr = string_sprintf(US"PRDR on %s reception\n", arg); else { - cutthrough_delivery = TRUE; - break; + if (deliver_freeze) + *log_msgptr = US"frozen"; + else if (queue_only_policy) + *log_msgptr = US"queue-only"; + else if (fake_response == FAIL) + *log_msgptr = US"fakereject"; + else + { + if (rcpt_count == 1) cutthrough.delivery = TRUE; + break; + } + *log_msgptr = string_sprintf("\"control=%s\" on %s item", + arg, *log_msgptr); } - *log_msgptr = string_sprintf("\"control=%s\" on %s item", - arg, *log_msgptr); return ERROR; } break; @@ -4351,9 +4359,9 @@ ratelimiters_cmd = NULL; log_reject_target = LOG_MAIN|LOG_REJECT; #ifndef DISABLE_PRDR -if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR ) +if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR) #else -if (where == ACL_WHERE_RCPT ) +if (where == ACL_WHERE_RCPT) #endif { adb = address_defaults; @@ -4397,9 +4405,7 @@ case ACL_WHERE_RCPT: #ifndef DISABLE_PRDR case ACL_WHERE_PRDR: #endif - if( rcpt_count > 1 ) - cancel_cutthrough_connection("more than one recipient"); - else if (rc == OK && cutthrough_delivery && cutthrough_fd < 0) + if (rc == OK && cutthrough.delivery && rcpt_count > cutthrough.nrcpt) open_cutthrough_connection(addr); break; diff --git a/src/src/globals.c b/src/src/globals.c index a8670e414..a066f3595 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -506,8 +506,11 @@ int continue_sequence = 1; uschar *continue_transport = NULL; uschar *csa_status = NULL; -BOOL cutthrough_delivery = FALSE; -int cutthrough_fd = -1; +cut_t cutthrough = { + FALSE, /* delivery: when to attempt */ + -1, /* fd: open connection */ + 0, /* nrcpt: number of addresses */ +}; BOOL daemon_listen = FALSE; uschar *daemon_smtp_port = US"smtp"; diff --git a/src/src/globals.h b/src/src/globals.h index 5495f54db..b5ea8a49b 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -291,8 +291,16 @@ extern int continue_sequence; /* Sequence num for continued delivery */ extern uschar *continue_transport; /* Transport for continued delivery */ extern uschar *csa_status; /* Client SMTP Authorization result */ -extern BOOL cutthrough_delivery; /* Deliver in foreground */ -extern int cutthrough_fd; /* Connection for ditto */ + +typedef struct { + BOOL delivery; /* When to attempt */ + int fd; /* Open connection */ + int nrcpt; /* Count of addresses */ + uschar * interface; /* (address of) */ + host_item host; /* Host used */ + address_item addr; /* (Chain of) addresses */ +} cut_t; +extern cut_t cutthrough; /* Deliver-concurrently */ extern BOOL daemon_listen; /* True if listening required */ extern uschar *daemon_smtp_port; /* Can be a list of ports */ diff --git a/src/src/receive.c b/src/src/receive.c index 8ab3166d0..977150c1d 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -997,7 +997,7 @@ switch(where) case ACL_WHERE_DKIM: case ACL_WHERE_MIME: case ACL_WHERE_DATA: - if (cutthrough_fd >= 0 && (acl_removed_headers || acl_added_headers)) + if (cutthrough.fd >= 0 && (acl_removed_headers || acl_added_headers)) { log_write(0, LOG_MAIN|LOG_PANIC, "Header modification in data ACLs" " will not take effect on cutthrough deliveries"); @@ -2807,12 +2807,11 @@ if (filter_test != FTEST_NONE) } /* Cutthrough delivery: - We have to create the Received header now rather than at the end of reception, - so the timestamp behaviour is a change to the normal case. - XXX Ensure this gets documented XXX. - Having created it, send the headers to the destination. -*/ -if (cutthrough_fd >= 0) +We have to create the Received header now rather than at the end of reception, +so the timestamp behaviour is a change to the normal case. +XXX Ensure this gets documented XXX. +Having created it, send the headers to the destination. */ +if (cutthrough.fd >= 0) { if (received_count > received_headers_max) { @@ -3184,56 +3183,61 @@ else rc = OK; while ((item = string_nextinlist(&ptr, &sep, itembuf, - sizeof(itembuf))) != NULL) + sizeof(itembuf)))) { /* Prevent running ACL for an empty item */ if (!item || (item[0] == '\0')) continue; - /* Only run ACL once for each domain or identity, no matter how often it - appears in the expanded list. */ - if (seen_items != NULL) + + /* Only run ACL once for each domain or identity, + no matter how often it appears in the expanded list. */ + if (seen_items) { uschar *seen_item = NULL; uschar seen_item_buf[256]; uschar *seen_items_list = seen_items; - int seen_this_item = 0; + BOOL seen_this_item = FALSE; while ((seen_item = string_nextinlist(&seen_items_list, &sep, seen_item_buf, - sizeof(seen_item_buf))) != NULL) - { - if (Ustrcmp(seen_item,item) == 0) - { - seen_this_item = 1; - break; - } - } - - if (seen_this_item > 0) + sizeof(seen_item_buf)))) + if (Ustrcmp(seen_item,item) == 0) + { + seen_this_item = TRUE; + break; + } + + if (seen_this_item) { DEBUG(D_receive) - debug_printf("acl_smtp_dkim: skipping signer %s, already seen\n", item); + debug_printf("acl_smtp_dkim: skipping signer %s, " + "already seen\n", item); continue; } - seen_items = string_append(seen_items,&seen_items_size,&seen_items_offset,1,":"); + seen_items = string_append(seen_items, &seen_items_size, + &seen_items_offset, 1, ":"); } - seen_items = string_append(seen_items,&seen_items_size,&seen_items_offset,1,item); + seen_items = string_append(seen_items, &seen_items_size, + &seen_items_offset, 1, item); seen_items[seen_items_offset] = '\0'; DEBUG(D_receive) - debug_printf("calling acl_smtp_dkim for dkim_cur_signer=%s\n", item); + debug_printf("calling acl_smtp_dkim for dkim_cur_signer=%s\n", + item); dkim_exim_acl_setup(item); - rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, &user_msg, &log_msg); + rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, + &user_msg, &log_msg); if (rc != OK) - { - DEBUG(D_receive) - debug_printf("acl_smtp_dkim: acl_check returned %d on %s, skipping remaining items\n", rc, item); - cancel_cutthrough_connection("dkim acl not ok"); - break; - } + { + DEBUG(D_receive) + debug_printf("acl_smtp_dkim: acl_check returned %d on %s, " + "skipping remaining items\n", rc, item); + cancel_cutthrough_connection("dkim acl not ok"); + break; + } } add_acl_headers(ACL_WHERE_DKIM, US"DKIM"); if (rc == DISCARD) @@ -3957,7 +3961,7 @@ for this message. */ XXX We do not handle queue-only, freezing, or blackholes. */ -if(cutthrough_fd >= 0) +if(cutthrough.fd >= 0) { uschar * msg= cutthrough_finaldot(); /* Ask the target system to accept the messsage */ /* Logging was done in finaldot() */ @@ -4103,7 +4107,7 @@ if (smtp_input) case TMP_REJ: message_id[0] = 0; /* Prevent a delivery from starting */ default:break; } - cutthrough_delivery = FALSE; + cutthrough.delivery = FALSE; } /* For batched SMTP, generate an error message on failure, and do diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 4fc2cfd41..4e4cdb825 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -4448,7 +4448,7 @@ while (done <= 0) ACL may have delayed. To handle cutthrough delivery enforce a dummy call to get the DATA command sent. */ - if (acl_smtp_predata == NULL && cutthrough_fd < 0) rc = OK; else + if (acl_smtp_predata == NULL && cutthrough.fd < 0) rc = OK; else { uschar * acl= acl_smtp_predata ? acl_smtp_predata : US"accept"; enable_dollar_recipients = TRUE; diff --git a/src/src/verify.c b/src/src/verify.c index 96740f8f3..4474f2c5b 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -14,7 +14,6 @@ caching was contributed by Kevin Fleming (but I hacked it around a bit). */ #define CUTTHROUGH_CMD_TIMEOUT 30 /* timeout for cutthrough-routing calls */ #define CUTTHROUGH_DATA_TIMEOUT 60 /* timeout for cutthrough-routing calls */ -address_item cutthrough_addr; static smtp_outblock ctblock; uschar ctbuffer[8192]; @@ -39,6 +38,7 @@ static tree_node *dnsbl_cache = NULL; #define MT_NOT 1 #define MT_ALL 2 +static uschar cutthrough_response(char, uschar **); /************************************************* @@ -189,12 +189,12 @@ from_address = US""; if (is_recipient) { - if ((options & vopt_callout_recipsender) != 0) + if (options & vopt_callout_recipsender) { address_key = string_sprintf("%s/<%s>", addr->address, sender_address); from_address = sender_address; } - else if ((options & vopt_callout_recippmaster) != 0) + else if (options & vopt_callout_recippmaster) { address_key = string_sprintf("%s/", addr->address, qualify_domain_sender); @@ -410,6 +410,113 @@ else if (smtp_out != NULL && !disable_callout_flush) mac_smtp_fflush(); +/* cutthrough-multi: if a nonfirst rcpt has the same routing as the first, +and we are holding a cutthrough conn open, we can just append the rcpt to +that conn for verification purposes (and later delivery also). Simplest +coding means skipping this whole loop and doing the append separately. + +We will need to remember it has been appended so that rcpt-acl tail code +can do it there for the non-rcpt-verify case. For this we keep an addresscount. +*/ + + /* Can we re-use an open cutthrough connection? */ + if ( cutthrough.fd >= 0 + && (options & (vopt_callout_recipsender | vopt_callout_recippmaster)) + == vopt_callout_recipsender + && !random_local_part + && !pm_mailfrom + ) + { + if (addr->transport == cutthrough.addr.transport) + for (host = host_list; host; host = host->next) + if (Ustrcmp(host->address, cutthrough.host.address) == 0) + { + int host_af; + uschar *interface = NULL; /* Outgoing interface to use; NULL => any */ + int port = 25; + + deliver_host = host->name; + deliver_host_address = host->address; + deliver_host_port = host->port; + deliver_domain = addr->domain; + transport_name = addr->transport->name; + + host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6; + + if (!smtp_get_interface(tf->interface, host_af, addr, NULL, &interface, + US"callout") || + !smtp_get_port(tf->port, addr, &port, US"callout")) + log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address, + addr->message); + + if ( ( interface == cutthrough.interface + || ( interface + && cutthrough.interface + && Ustrcmp(interface, cutthrough.interface) == 0 + ) ) + && port == cutthrough.host.port + ) + { + uschar * resp; + + /* Match! Send the RCPT TO, append the addr, set done */ + done = + smtp_write_command(&ctblock, FALSE, "RCPT TO:<%.1000s>\r\n", + transport_rcpt_address(addr, + (addr->transport == NULL)? FALSE : + addr->transport->rcpt_include_affixes)) >= 0 && + cutthrough_response('2', &resp) == '2'; + + /* This would go horribly wrong if a callout fail was ignored by ACL. + We punt by abandoning cutthrough on a reject, like the + first-rcpt does. */ + + if (done) + { + address_item * na = store_get(sizeof(address_item)); + *na = cutthrough.addr; + cutthrough.addr = *addr; + cutthrough.addr.host_used = &cutthrough.host; + cutthrough.addr.next = na; + + cutthrough.nrcpt++; + } + else + { + cancel_cutthrough_connection("recipient rejected"); + if (errno == ETIMEDOUT) + { + HDEBUG(D_verify) debug_printf("SMTP timeout\n"); + } + else if (errno == 0) + { + if (*resp == 0) + Ustrcpy(resp, US"connection dropped"); + + addr->message = + string_sprintf("response to \"%s\" from %s [%s] was: %s", + big_buffer, host->name, host->address, + string_printing(resp)); + + addr->user_message = + string_sprintf("Callout verification failed:\n%s", resp); + + /* Hard rejection ends the process */ + + if (resp[0] == '5') /* Address rejected */ + { + yield = FAIL; + done = TRUE; + } + } + } + } + break; + } + if (!done) + cancel_cutthrough_connection("incompatible connection"); + } + /* Now make connections to the hosts and do real callouts. The list of hosts is passed in as an argument. */ @@ -692,9 +799,9 @@ else ob->command_timeout = callout; rc = tls_client_start(inblock.sock, host, addr, addr->transport -#ifdef EXPERIMENTAL_DANE +# ifdef EXPERIMENTAL_DANE , dane ? &tlsa_dnsa : NULL -#endif +# endif ); ob->command_timeout = oldtimeout; @@ -709,10 +816,10 @@ else ) { (void)close(inblock.sock); -#ifdef EXPERIMENTAL_EVENT +# ifdef EXPERIMENTAL_EVENT (void) event_raise(addr->transport->event_action, US"tcp:close", NULL); -#endif +# endif log_write(0, LOG_MAIN, "TLS session failure: delivering unencrypted " "to %s [%s] (not in hosts_require_tls)", host->name, host->address); suppress_tls = TRUE; @@ -741,9 +848,9 @@ else /* If the host is required to use a secure channel, ensure that we have one. */ if (tls_out.active < 0) if ( -#ifdef EXPERIMENTAL_DANE +# ifdef EXPERIMENTAL_DANE dane || -#endif +# endif verify_check_given_host(&ob->hosts_require_tls, host) == OK ) { @@ -757,7 +864,7 @@ else goto TLS_FAILED; } - #endif /*SUPPORT_TLS*/ +#endif /*SUPPORT_TLS*/ done = TRUE; /* so far so good; have response to HELO */ @@ -765,17 +872,17 @@ else /* For now, transport_filter by cutthrough-delivery is not supported */ /* Need proper integration with the proper transport mechanism. */ - if (cutthrough_delivery) + if (cutthrough.delivery) { if (addr->transport->filter_command) { - cutthrough_delivery= FALSE; + cutthrough.delivery = FALSE; HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of transport filter\n"); } #ifndef DISABLE_DKIM if (ob->dkim_domain) { - cutthrough_delivery= FALSE; + cutthrough.delivery = FALSE; HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of DKIM signing\n"); } #endif @@ -887,6 +994,8 @@ else else if (errno == 0) { + cancel_cutthrough_connection("random-recipient"); + if (randombuffer[0] == '5') new_domain_record.random_result = ccache_reject; @@ -932,8 +1041,9 @@ else if (done && pm_mailfrom != NULL) { - /*XXX not suitable for cutthrough - sequencing problems */ - cutthrough_delivery= FALSE; + /*XXX not suitable for cutthrough - we cannot afford to do an RSET + and lose the original mail-from */ + cancel_cutthrough_connection("postmaster verify"); HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of postmaster verify\n"); done = @@ -1028,30 +1138,34 @@ else /* End the SMTP conversation and close the connection. */ - /* Cutthrough - on a successfull connect and recipient-verify with use-sender - and we have no cutthrough conn so far + /* Cutthrough - on a successfull connect and recipient-verify with + use-sender and we are 1st rcpt and have no cutthrough conn so far here is where we want to leave the conn open */ - if ( cutthrough_delivery + if ( cutthrough.delivery + && rcpt_count == 1 && done && yield == OK && (options & (vopt_callout_recipsender|vopt_callout_recippmaster)) == vopt_callout_recipsender && !random_local_part && !pm_mailfrom - && cutthrough_fd < 0 + && cutthrough.fd < 0 ) { - cutthrough_fd= outblock.sock; /* We assume no buffer in use in the outblock */ - cutthrough_addr = *addr; /* Save the address_item for later logging */ - cutthrough_addr.next = NULL; - cutthrough_addr.host_used = store_get(sizeof(host_item)); - *(cutthrough_addr.host_used) = *host; + cutthrough.fd = outblock.sock; /* We assume no buffer in use in the outblock */ + cutthrough.nrcpt = 1; + cutthrough.interface = interface; + cutthrough.host = *host; + cutthrough.addr = *addr; /* Save the address_item for later logging */ + cutthrough.addr.next = NULL; + cutthrough.addr.host_used = &cutthrough.host; if (addr->parent) - *(cutthrough_addr.parent = store_get(sizeof(address_item)))= *addr->parent; + *(cutthrough.addr.parent = store_get(sizeof(address_item))) = + *addr->parent; ctblock.buffer = ctbuffer; ctblock.buffersize = sizeof(ctbuffer); ctblock.ptr = ctbuffer; /* ctblock.cmd_count = 0; ctblock.authenticating = FALSE; */ - ctblock.sock = cutthrough_fd; + ctblock.sock = cutthrough.fd; } else { @@ -1176,7 +1290,8 @@ address_item addr2; get rewritten. */ addr2 = *addr; -HDEBUG(D_acl) debug_printf("----------- start cutthrough setup ------------\n"); +HDEBUG(D_acl) debug_printf("----------- %s cutthrough setup ------------\n", + rcpt_count > 1 ? "more" : "start"); (void) verify_address(&addr2, NULL, vopt_is_recipient | vopt_callout_recipsender | vopt_callout_no_cache, CUTTHROUGH_CMD_TIMEOUT, -1, -1, @@ -1191,14 +1306,14 @@ return; static BOOL cutthrough_send(int n) { -if(cutthrough_fd < 0) +if(cutthrough.fd < 0) return TRUE; if( #ifdef SUPPORT_TLS - (tls_out.active == cutthrough_fd) ? tls_write(FALSE, ctblock.buffer, n) : + (tls_out.active == cutthrough.fd) ? tls_write(FALSE, ctblock.buffer, n) : #endif - send(cutthrough_fd, ctblock.buffer, n, 0) > 0 + send(cutthrough.fd, ctblock.buffer, n, 0) > 0 ) { transport_count += n; @@ -1230,7 +1345,7 @@ return TRUE; BOOL cutthrough_puts(uschar * cp, int n) { -if (cutthrough_fd < 0) return TRUE; +if (cutthrough.fd < 0) return TRUE; if (_cutthrough_puts(cp, n)) return TRUE; cancel_cutthrough_connection("transmit failed"); return FALSE; @@ -1238,7 +1353,7 @@ return FALSE; static BOOL -_cutthrough_flush_send( void ) +_cutthrough_flush_send(void) { int n= ctblock.ptr-ctblock.buffer; @@ -1251,7 +1366,7 @@ return TRUE; /* Send out any bufferred output. Return boolean success. */ BOOL -cutthrough_flush_send( void ) +cutthrough_flush_send(void) { if (_cutthrough_flush_send()) return TRUE; cancel_cutthrough_connection("transmit failed"); @@ -1260,7 +1375,7 @@ return FALSE; BOOL -cutthrough_put_nl( void ) +cutthrough_put_nl(void) { return cutthrough_puts(US"\r\n", 2); } @@ -1278,7 +1393,7 @@ inblock.buffer = inbuffer; inblock.buffersize = sizeof(inbuffer); inblock.ptr = inbuffer; inblock.ptrend = inbuffer; -inblock.sock = cutthrough_fd; +inblock.sock = cutthrough.fd; /* this relies on (inblock.sock == tls_out.active) */ if(!smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), expect, CUTTHROUGH_DATA_TIMEOUT)) cancel_cutthrough_connection("target timeout on read"); @@ -1286,7 +1401,7 @@ if(!smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), expect, if(copy != NULL) { uschar * cp; - *copy= cp= string_copy(responsebuffer); + *copy = cp = string_copy(responsebuffer); /* Trim the trailing end of line */ cp += Ustrlen(responsebuffer); if(cp > *copy && cp[-1] == '\n') *--cp = '\0'; @@ -1299,9 +1414,9 @@ return responsebuffer[0]; /* Negotiate dataphase with the cutthrough target, returning success boolean */ BOOL -cutthrough_predata( void ) +cutthrough_predata(void) { -if(cutthrough_fd < 0) +if(cutthrough.fd < 0) return FALSE; HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP>> DATA\n"); @@ -1332,9 +1447,9 @@ return TRUE; /* Expands newlines to wire format (CR,NL). */ /* Also sends header-terminating blank line. */ BOOL -cutthrough_headers_send( void ) +cutthrough_headers_send(void) { -if(cutthrough_fd < 0) +if(cutthrough.fd < 0) return FALSE; /* We share a routine with the mainline transport to handle header add/remove/rewrites, @@ -1342,10 +1457,12 @@ if(cutthrough_fd < 0) */ HDEBUG(D_acl) debug_printf("----------- start cutthrough headers send -----------\n"); -if (!transport_headers_send(&cutthrough_addr, cutthrough_fd, - cutthrough_addr.transport->add_headers, cutthrough_addr.transport->remove_headers, +if (!transport_headers_send(&cutthrough.addr, cutthrough.fd, + cutthrough.addr.transport->add_headers, + cutthrough.addr.transport->remove_headers, &cutthrough_write_chunk, TRUE, - cutthrough_addr.transport->rewrite_rules, cutthrough_addr.transport->rewrite_existflags)) + cutthrough.addr.transport->rewrite_rules, + cutthrough.addr.transport->rewrite_existflags)) return FALSE; HDEBUG(D_acl) debug_printf("----------- done cutthrough headers send ------------\n"); @@ -1354,9 +1471,9 @@ return TRUE; static void -close_cutthrough_connection( const char * why ) +close_cutthrough_connection(const char * why) { -if(cutthrough_fd >= 0) +if(cutthrough.fd >= 0) { /* We could be sending this after a bunch of data, but that is ok as the only way to cancel the transfer in dataphase is to drop the tcp @@ -1371,18 +1488,18 @@ if(cutthrough_fd >= 0) #ifdef SUPPORT_TLS tls_close(FALSE, TRUE); #endif - (void)close(cutthrough_fd); - cutthrough_fd= -1; + (void)close(cutthrough.fd); + cutthrough.fd = -1; HDEBUG(D_acl) debug_printf("----------- cutthrough shutdown (%s) ------------\n", why); } ctblock.ptr = ctbuffer; } void -cancel_cutthrough_connection( const char * why ) +cancel_cutthrough_connection(const char * why) { close_cutthrough_connection(why); -cutthrough_delivery= FALSE; +cutthrough.delivery = FALSE; } @@ -1394,33 +1511,45 @@ cutthrough_delivery= FALSE; Return smtp response-class digit. */ uschar * -cutthrough_finaldot( void ) +cutthrough_finaldot(void) { +uschar res; +address_item * addr; HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP>> .\n"); /* Assume data finshed with new-line */ -if(!cutthrough_puts(US".", 1) || !cutthrough_put_nl() || !cutthrough_flush_send()) - return cutthrough_addr.message; +if( !cutthrough_puts(US".", 1) + || !cutthrough_put_nl() + || !cutthrough_flush_send() + ) + return cutthrough.addr.message; -switch(cutthrough_response('2', &cutthrough_addr.message)) +res = cutthrough_response('2', &cutthrough.addr.message); +for (addr = &cutthrough.addr; addr; addr = addr->next) { - case '2': - delivery_log(LOG_MAIN, &cutthrough_addr, (int)'>', NULL); - close_cutthrough_connection("delivered"); - break; + addr->message = cutthrough.addr.message; + switch(res) + { + case '2': + delivery_log(LOG_MAIN, addr, (int)'>', NULL); + close_cutthrough_connection("delivered"); + break; - case '4': - delivery_log(LOG_MAIN, &cutthrough_addr, 0, US"tmp-reject from cutthrough after DATA:"); - break; + case '4': + delivery_log(LOG_MAIN, addr, 0, + US"tmp-reject from cutthrough after DATA:"); + break; - case '5': - delivery_log(LOG_MAIN|LOG_REJECT, &cutthrough_addr, 0, US"rejected after DATA:"); - break; + case '5': + delivery_log(LOG_MAIN|LOG_REJECT, addr, 0, + US"rejected after DATA:"); + break; - default: - break; + default: + break; + } } - return cutthrough_addr.message; +return cutthrough.addr.message; } diff --git a/test/confs/5400 b/test/confs/5400 index 09a0aafcf..5948ce8d2 100644 --- a/test/confs/5400 +++ b/test/confs/5400 @@ -8,6 +8,8 @@ log_file_path = DIR/spool/log/%slog gecos_pattern = "" gecos_name = CALLER_NAME +log_selector = +received_recipients + # ----- Main settings ----- domainlist local_domains = test.ex : *.test.ex @@ -27,12 +29,18 @@ ar: begin routers +dns: + driver = dnslookup + domains = localhost.test.ex : thishost.test.ex + self = send + transport = smtp + all: driver = manualroute domains = ! +local_domains - route_list = * 127.0.0.1 + route_list = special.com HOSTIPV4 ; * 127.0.0.1 self = send - transport = smtp + transport = ${if eq {special_tpt}{$local_part} {smtp2}{smtp}} headers_remove = X-hdr-rtr headers_add = X-hdr-rtr-new: $h_X-hdr-rtr:+++ no_more @@ -48,5 +56,10 @@ smtp: port = PORT_S headers_add = ${if def:h_X-hdr-rtr {X-hdr-tpt-new: new} {}} +smtp2: + driver = smtp + interface = HOSTIPV4 + port = PORT_S + # End diff --git a/test/log/5400 b/test/log/5400 index 6b51348c3..c6f366272 100644 --- a/test/log/5400 +++ b/test/log/5400 @@ -1,18 +1,54 @@ 1999-03-02 09:44:33 rcpt for userx@domain.com 1999-03-02 09:44:33 10HmaX-0005vi-00 >> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" -1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userx@domain.com 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed 1999-03-02 09:44:33 rcpt for userz@domain.com 1999-03-02 09:44:33 10HmaY-0005vi-00 >> userz@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" -1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userz@domain.com 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed 1999-03-02 09:44:33 rcpt for usery@domain.com 1999-03-02 09:44:33 rcpt for userx@domain.com -1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss -1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" -1999-03-02 09:44:33 10HmaZ-0005vi-00 -> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmaZ-0005vi-00 >> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmaZ-0005vi-00 >> usery@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for usery@domain.com userx@domain.com 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed 1999-03-02 09:44:33 rcpt for userx@domain.com 1999-03-02 09:44:33 10HmbA-0005vi-00 >> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" -1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss +1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userx@domain.com 1999-03-02 09:44:33 10HmbA-0005vi-00 Completed +1999-03-02 09:44:33 rcpt for no@domain.com +1999-03-02 09:44:33 rcpt for userx@domain.com +1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for no@domain.com userx@domain.com +1999-03-02 09:44:33 10HmbB-0005vi-00 => no@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbB-0005vi-00 -> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbB-0005vi-00 Completed +1999-03-02 09:44:33 rcpt for userx@domain.com +1999-03-02 09:44:33 rcpt for no@domain.com +1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userx@domain.com no@domain.com +1999-03-02 09:44:33 10HmbC-0005vi-00 => userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbC-0005vi-00 -> no@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbC-0005vi-00 Completed +1999-03-02 09:44:33 rcpt for userx@domain.com +1999-03-02 09:44:33 rcpt for special_tpt@domain.com +1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userx@domain.com special_tpt@domain.com +1999-03-02 09:44:33 10HmbD-0005vi-00 => userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbD-0005vi-00 => special_tpt@domain.com R=all T=smtp2 H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbD-0005vi-00 Completed +1999-03-02 09:44:33 rcpt for userx@domain1.com +1999-03-02 09:44:33 rcpt for usery@domain2.com +1999-03-02 09:44:33 10HmbE-0005vi-00 >> usery@domain2.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbE-0005vi-00 >> userx@domain1.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userx@domain1.com usery@domain2.com +1999-03-02 09:44:33 10HmbE-0005vi-00 Completed +1999-03-02 09:44:33 rcpt for userx@domain.com +1999-03-02 09:44:33 rcpt for usery@special.com +1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userx@domain.com usery@special.com +1999-03-02 09:44:33 10HmbF-0005vi-00 => userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbF-0005vi-00 => usery@special.com R=all T=smtp H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK" +1999-03-02 09:44:33 10HmbF-0005vi-00 Completed +1999-03-02 09:44:33 rcpt for userx@localhost.test.ex +1999-03-02 09:44:33 rcpt for usery@thishost.test.ex +1999-03-02 09:44:33 10HmbG-0005vi-00 >> usery@thishost.test.ex R=dns T=smtp H=localhost.test.ex [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbG-0005vi-00 >> userx@localhost.test.ex R=dns T=smtp H=localhost.test.ex [127.0.0.1] C="250 OK" +1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userx@localhost.test.ex usery@thishost.test.ex +1999-03-02 09:44:33 10HmbG-0005vi-00 Completed diff --git a/test/scripts/5400-cutthrough/5400 b/test/scripts/5400-cutthrough/5400 index 3e56b43b8..79072d749 100644 --- a/test/scripts/5400-cutthrough/5400 +++ b/test/scripts/5400-cutthrough/5400 @@ -16,7 +16,7 @@ DATA QUIT 250 OK **** -exim -d-all+acl+transport -bs +exim -bs EHLO myhost.test.ex MAIL FROM: RCPT TO: @@ -43,7 +43,7 @@ DATA QUIT 250 OK **** -exim -d-all+acl+transport -bs +exim -bs EHLO myhost.test.ex MAIL FROM: RCPT TO: @@ -52,8 +52,8 @@ DATA . QUIT **** -# cutthrough cancelled by multiple recipients -server PORT_S 2 +# cutthrough for 2 recipients in one domain +server PORT_S 220 ESMTP EHLO 250 OK @@ -61,8 +61,32 @@ MAIL FROM: 250 Sender OK RCPT TO: 250 Recipient OK +RCPT TO: +250 Recipient OK +DATA +354 Send data +. +250 OK QUIT -*eof +250 OK +**** +exim -bs +EHLO myhost.test.ex +MAIL FROM: +RCPT TO: +RCPT TO: +DATA + +. +QUIT +**** +# +# +# +# +# +# cutthrough_delivery basic operation, again +server PORT_S 220 ESMTP EHLO 250 OK @@ -70,8 +94,53 @@ MAIL FROM: 250 Sender OK RCPT TO: 250 Recipient OK +DATA +354 Send data +. +250 OK +QUIT +250 OK +**** +exim -bs +EHLO myhost.test.ex +MAIL FROM: +RCPT TO: +DATA +X-hdr-rtr: qqq +X-hdr-tpt: zzz + +body +. +QUIT +**** +# +# +# +# +# cutthrough for 2 recipients in one domain +# first one denied +# so we get a 2nd conn with the traditional delivery +# (for both because it's not a real verify=recipient) +server PORT_S 2 +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK RCPT TO: -250 Recipient OK +550 Not that one +QUIT +250 OK +*eof +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +RCPT TO: +250 ok rcpt-2 DATA 354 Send data . @@ -79,23 +148,138 @@ DATA QUIT 250 OK **** -exim -d-all+acl+transport -bs +exim -bs EHLO myhost.test.ex MAIL FROM: -RCPT TO: +RCPT TO: RCPT TO: DATA . QUIT **** -sleep 1 # # # # # -# cutthrough_delivery basic operation, again +# cutthrough for 2 recipients in one domain +# second one denied +# so we get a 2nd conn with the traditional delivery +# (for both because it's not a real verify=recipient) +server PORT_S 2 +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 first recipient ok +RCPT TO: +550 Not that one +QUIT +250 OK +*eof +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +. +250 OK +QUIT +250 OK +**** +exim -bs +EHLO myhost.test.ex +MAIL FROM: +RCPT TO: +RCPT TO: +DATA + +. +QUIT +**** +# +# +# +# +# +# cutthrough for 2 recipients in one domain +# second one uses a different transport +# so we get a 2nd conn with 2nd rcpt, doing the fake verify +# then 3rd & 4th conns with the traditional deliveries on the different transports +server PORT_S 4 +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 first recipient ok +QUIT +250 OK +*eof +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 second recipient ok +QUIT +250 OK +*eof +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +DATA +354 Send data +. +250 OK +QUIT +250 OK +*eof +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +. +250 OK +QUIT +250 OK +**** +exim -bs +EHLO myhost.test.ex +MAIL FROM: +RCPT TO: +RCPT TO: +DATA + +. +QUIT +**** +# +# +# +# +# +# cutthrough for 2 recipients in different domains, handled by the same tpt & host server PORT_S 220 ESMTP EHLO @@ -103,7 +287,9 @@ EHLO MAIL FROM: 250 Sender OK RCPT TO: -250 Recipient OK +250 ok rcpt-1 +RCPT TO: +250 ok rcpt-2 DATA 354 Send data . @@ -111,15 +297,120 @@ DATA QUIT 250 OK **** -exim -d-all+acl+transport -bs +exim -bs +EHLO myhost.test.ex +MAIL FROM: +RCPT TO: +RCPT TO: +DATA + +. +QUIT +**** +# +# +# +# +# +# cutthrough for 2 recipients in different domains, handled by the same tpt but different hosts +# so we get a 2nd conn with 2nd rcpt, doing the fake verify +# then 3rd & 4th conns with the traditional deliveries on the different transports +server PORT_S 4 +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 first recipient ok +QUIT +250 OK +*eof +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 second recipient ok +QUIT +250 OK +*eof +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +DATA +354 Send data +. +250 OK +QUIT +250 OK +*eof +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +. +250 OK +QUIT +250 OK +**** +exim -bs EHLO myhost.test.ex MAIL FROM: RCPT TO: +RCPT TO: +DATA + +. +QUIT +**** +# +# +# +# +# +# cutthrough for 2 recipients in different domains, handled by the same tpt & host +# but via a dnslookup router (all previous were manualroute) +server PORT_S +220 ESMTP +EHLO +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +. +250 OK +QUIT +250 OK +**** +exim -bs +EHLO myhost.test.ex +MAIL FROM: +RCPT TO: +RCPT TO: DATA -X-hdr-rtr: qqq -X-hdr-tpt: zzz -body . QUIT **** +# +# +# +# +# +sleep 1 diff --git a/test/stderr/5400 b/test/stderr/5400 deleted file mode 100644 index 9fa77d5f2..000000000 --- a/test/stderr/5400 +++ /dev/null @@ -1,235 +0,0 @@ -Exim version x.yz .... -configuration file is TESTSUITE/test-config -admin user -LOG: smtp_connection MAIN - SMTP connection from CALLER -using ACL "ar" -processing "accept" -check control = cutthrough_delivery -check logwrite = rcpt for $local_part@$domain - = rcpt for userx@domain.com -LOG: MAIN - rcpt for userx@domain.com -created log directory TESTSUITE/spool/log -accept: condition test succeeded in ACL "ar" -end of ACL "ar": ACCEPT ------------ start cutthrough setup ------------ -Connecting to 127.0.0.1 [127.0.0.1]:1224 from ip4.ip4.ip4.ip4 ... connected - SMTP<< 220 ESMTP - SMTP>> EHLO myhost.test.ex - SMTP<< 250 OK - SMTP>> MAIL FROM: - SMTP<< 250 Sender OK - SMTP>> RCPT TO: - SMTP<< 250 Recipient OK ------------ end cutthrough setup ------------ -processing "accept" -accept: condition test succeeded in inline ACL -end of inline ACL: ACCEPT - SMTP>> DATA - SMTP<< 354 Send data ------------ start cutthrough headers send ----------- -added header line(s): -X-hdr-rtr-new: +++ ---- ------------ done cutthrough headers send ------------ - SMTP>> . - SMTP<< 250 OK -LOG: MAIN - >> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" - SMTP>> QUIT ------------ cutthrough shutdown (delivered) ------------ -LOG: MAIN - <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss -LOG: MAIN - Completed -LOG: smtp_connection MAIN - SMTP connection from CALLER closed by QUIT ->>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> -Exim version x.yz .... -configuration file is TESTSUITE/test-config -admin user -LOG: smtp_connection MAIN - SMTP connection from CALLER -using ACL "ar" -processing "accept" -check control = cutthrough_delivery -check logwrite = rcpt for $local_part@$domain - = rcpt for userz@domain.com -LOG: MAIN - rcpt for userz@domain.com -accept: condition test succeeded in ACL "ar" -end of ACL "ar": ACCEPT ------------ start cutthrough setup ------------ -Connecting to 127.0.0.1 [127.0.0.1]:1224 from ip4.ip4.ip4.ip4 ... connected - SMTP<< 220 SMTP only spoken here - SMTP>> EHLO myhost.test.ex - SMTP<< 550 Not here, mate - SMTP>> HELO myhost.test.ex - SMTP<< 250 OK - SMTP>> MAIL FROM: - SMTP<< 250 Sender OK - SMTP>> RCPT TO: - SMTP<< 250 Recipient OK ------------ end cutthrough setup ------------ -processing "accept" -accept: condition test succeeded in inline ACL -end of inline ACL: ACCEPT - SMTP>> DATA - SMTP<< 354 Send data ------------ start cutthrough headers send ----------- -added header line(s): -X-hdr-rtr-new: +++ ---- ------------ done cutthrough headers send ------------ - SMTP>> . - SMTP<< 250 OK -LOG: MAIN - >> userz@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" - SMTP>> QUIT ------------ cutthrough shutdown (delivered) ------------ -LOG: MAIN - <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss -LOG: MAIN - Completed -LOG: smtp_connection MAIN - SMTP connection from CALLER closed by QUIT ->>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> -Exim version x.yz .... -configuration file is TESTSUITE/test-config -admin user -LOG: smtp_connection MAIN - SMTP connection from CALLER -using ACL "ar" -processing "accept" -check control = cutthrough_delivery -check logwrite = rcpt for $local_part@$domain - = rcpt for usery@domain.com -LOG: MAIN - rcpt for usery@domain.com -accept: condition test succeeded in ACL "ar" -end of ACL "ar": ACCEPT ------------ start cutthrough setup ------------ -Connecting to 127.0.0.1 [127.0.0.1]:1224 from ip4.ip4.ip4.ip4 ... connected - SMTP<< 220 ESMTP - SMTP>> EHLO myhost.test.ex - SMTP<< 250 OK - SMTP>> MAIL FROM: - SMTP<< 250 Sender OK - SMTP>> RCPT TO: - SMTP<< 250 Recipient OK ------------ end cutthrough setup ------------ -using ACL "ar" -processing "accept" -check control = cutthrough_delivery -check logwrite = rcpt for $local_part@$domain - = rcpt for userx@domain.com -LOG: MAIN - rcpt for userx@domain.com -accept: condition test succeeded in ACL "ar" -end of ACL "ar": ACCEPT - SMTP>> QUIT ------------ cutthrough shutdown (more than one recipient) ------------ -LOG: MAIN - <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss -LOG: smtp_connection MAIN - SMTP connection from CALLER closed by QUIT ->>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> -Exim version x.yz .... -configuration file is TESTSUITE/test-config -trusted user -admin user ->>>>>>>>>>>>>>>> Remote deliveries >>>>>>>>>>>>>>>> ---------> usery@domain.com <-------- -smtp transport entered - usery@domain.com - userx@domain.com -checking status of 127.0.0.1 -127.0.0.1 [127.0.0.1]:1111 status = usable -delivering 10HmaZ-0005vi-00 to 127.0.0.1 [127.0.0.1] (usery@domain.com, ...) -Connecting to 127.0.0.1 [127.0.0.1]:1224 from ip4.ip4.ip4.ip4 ... connected - SMTP<< 220 ESMTP - SMTP>> EHLO myhost.test.ex - SMTP<< 250 OK -not using PIPELINING -use_dsn=0 - SMTP>> MAIL FROM: - SMTP<< 250 Sender OK - SMTP>> RCPT TO: - SMTP<< 250 Recipient OK - SMTP>> RCPT TO: - SMTP<< 250 Recipient OK - SMTP>> DATA - SMTP<< 354 Send data - SMTP>> writing message and terminating "." -added header line(s): -X-hdr-rtr-new: +++ ---- -writing data block fd=dddd size=sss timeout=300 - SMTP<< 250 OK -ok=1 send_quit=1 send_rset=0 continue_more=0 yield=0 first_address is NULL -transport_check_waiting entered - sequence=1 local_max=500 global_max=-1 -no messages waiting for 127.0.0.1 - SMTP>> QUIT -Leaving smtp transport -LOG: MAIN - => usery@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" -LOG: MAIN - -> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" -LOG: MAIN - Completed ->>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> -Exim version x.yz .... -configuration file is TESTSUITE/test-config -admin user -LOG: smtp_connection MAIN - SMTP connection from CALLER -using ACL "ar" -processing "accept" -check control = cutthrough_delivery -check logwrite = rcpt for $local_part@$domain - = rcpt for userx@domain.com -LOG: MAIN - rcpt for userx@domain.com -accept: condition test succeeded in ACL "ar" -end of ACL "ar": ACCEPT ------------ start cutthrough setup ------------ -Connecting to 127.0.0.1 [127.0.0.1]:1224 from ip4.ip4.ip4.ip4 ... connected - SMTP<< 220 ESMTP - SMTP>> EHLO myhost.test.ex - SMTP<< 250 OK - SMTP>> MAIL FROM: - SMTP<< 250 Sender OK - SMTP>> RCPT TO: - SMTP<< 250 Recipient OK ------------ end cutthrough setup ------------ -processing "accept" -accept: condition test succeeded in inline ACL -end of inline ACL: ACCEPT - SMTP>> DATA - SMTP<< 354 Send data ------------ start cutthrough headers send ----------- -removed header line: -X-hdr-rtr: qqq ---- -added header line(s): -X-hdr-rtr-new: +++ ---- -added header line: -X-hdr-tpt-new: new ---- ------------ done cutthrough headers send ------------ - SMTP>> . - SMTP<< 250 OK -LOG: MAIN - >> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK" - SMTP>> QUIT ------------ cutthrough shutdown (delivered) ------------ -LOG: MAIN - <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss -LOG: MAIN - Completed -LOG: smtp_connection MAIN - SMTP connection from CALLER closed by QUIT ->>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> diff --git a/test/stdout/5400 b/test/stdout/5400 index 4895072a3..3452a9cc1 100644 --- a/test/stdout/5400 +++ b/test/stdout/5400 @@ -43,6 +43,78 @@ 354 Enter message, ending with "." on a line by itself 250 OK id=10HmbA-0005vi-00 221 myhost.test.ex closing connection +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at myhost.test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmbB-0005vi-00 +221 myhost.test.ex closing connection +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at myhost.test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmbC-0005vi-00 +221 myhost.test.ex closing connection +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at myhost.test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmbD-0005vi-00 +221 myhost.test.ex closing connection +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at myhost.test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmbE-0005vi-00 +221 myhost.test.ex closing connection +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at myhost.test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmbF-0005vi-00 +221 myhost.test.ex closing connection +220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +250-myhost.test.ex Hello CALLER at myhost.test.ex +250-SIZE 52428800 +250-8BITMIME +250-PIPELINING +250 HELP +250 OK +250 Accepted +250 Accepted +354 Enter message, ending with "." on a line by itself +250 OK id=10HmbG-0005vi-00 +221 myhost.test.ex closing connection ******** SERVER ******** Listening on port 1224 ... @@ -108,17 +180,6 @@ MAIL FROM: 250 Sender OK RCPT TO: 250 Recipient OK -QUIT -Expected EOF read from client -Listening on port 1224 ... -Connection request from [ip4.ip4.ip4.ip4] -220 ESMTP -EHLO myhost.test.ex -250 OK -MAIL FROM: -250 Sender OK -RCPT TO: -250 Recipient OK RCPT TO: 250 Recipient OK DATA @@ -166,3 +227,284 @@ body QUIT 250 OK End of script +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +550 Not that one +QUIT +250 OK +Expected EOF read from client +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +Received: from CALLER (helo=myhost.test.ex) + by myhost.test.ex with local-esmtp (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 +X-hdr-rtr-new: +++ + +. +250 OK +QUIT +250 OK +End of script +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 first recipient ok +RCPT TO: +550 Not that one +QUIT +250 OK +Expected EOF read from client +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +Received: from CALLER (helo=myhost.test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmbC-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ + +. +250 OK +QUIT +250 OK +End of script +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 first recipient ok +QUIT +250 OK +Expected EOF read from client +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 second recipient ok +QUIT +250 OK +Expected EOF read from client +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +DATA +354 Send data +Received: from CALLER (helo=myhost.test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmbD-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ + +. +250 OK +QUIT +250 OK +Expected EOF read from client +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +Received: from CALLER (helo=myhost.test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmbD-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ + +. +250 OK +QUIT +250 OK +End of script +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +Received: from CALLER (helo=myhost.test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmbE-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ + +. +250 OK +QUIT +250 OK +End of script +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 first recipient ok +QUIT +250 OK +Expected EOF read from client +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 second recipient ok +QUIT +250 OK +Expected EOF read from client +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +DATA +354 Send data +Received: from CALLER (helo=myhost.test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmbF-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ + +. +250 OK +QUIT +250 OK +Expected EOF read from client +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +Received: from CALLER (helo=myhost.test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmbF-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 +X-hdr-rtr-new: +++ + +. +250 OK +QUIT +250 OK +End of script +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +220 ESMTP +EHLO myhost.test.ex +250 OK +MAIL FROM: +250 Sender OK +RCPT TO: +250 ok rcpt-1 +RCPT TO: +250 ok rcpt-2 +DATA +354 Send data +Received: from CALLER (helo=myhost.test.ex) + by myhost.test.ex with local-esmtp (Exim x.yz) + (envelope-from ) + id 10HmbG-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.25.1