From 237b2df13410c86663e788be831de721a782525a Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 30 Jul 2024 13:33:37 +0100 Subject: [PATCH 1/1] Continued-transport: check interface option. Bug 1141 --- doc/doc-txt/ChangeLog | 4 +++ src/src/deliver.c | 2 +- src/src/transports/smtp.c | 28 +++++++++++++++++++++ test/confs/0638 | 49 ++++++++++++++++++++++++++++++++++++ test/log/0638 | 13 ++++++++++ test/scripts/0000-Basic/0638 | 20 +++++++++++++++ 6 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 test/confs/0638 create mode 100644 test/log/0638 create mode 100644 test/scripts/0000-Basic/0638 diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 7a4f1757e..a02911cae 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -27,6 +27,10 @@ JH/05 Fix hintsdb support for dbmjz when compiled using sqlite3. Previously uses keys with embedded NUL bytes. The builtin hintsdb use is unaffected, but installations using dbmjz will need to rebuild those DBs. +JH/06 Bug 1141: When operating a continued-connection transport, verify that + the interface option, if specified, evaluates to match the connection. + Previously, a queued message for the same host was sent without checking. + Exim version 4.98 ----------------- diff --git a/src/src/deliver.c b/src/src/deliver.c index 9d26d07c0..67ba505d1 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -5167,7 +5167,7 @@ do_remote_deliveries par_reduce par_wait par_read_pipe wait-db ones, but for all continue-more ones (though any after the delivery proc has the info are pointless). */ - if (continue_hostname) + if (continue_hostname && continue_fd >= 0) { { uschar * ptr = big_buffer; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 769c5d235..03de9dcad 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -5614,6 +5614,31 @@ retry_non_continued: { if (!smtp_get_interface(s, host_af, addrlist, &interface, tid)) return FALSE; + + if (continue_sequence > 1) + { + union sockaddr_46 interface_sock; + EXIM_SOCKLEN_T size = sizeof(interface_sock); + const uschar * local_ip_addr; + + /* Assume the connection is on fd 0 */ + if (getsockname(0, (struct sockaddr *) &interface_sock, &size) < 0) + { + DEBUG(D_transport) + debug_printf_indent("failed getsockname: %s\n", strerror(errno)); + return FALSE; + } + local_ip_addr = host_ntoa(-1, &interface_sock, NULL, &sending_port); + if (Ustrcmp(interface, local_ip_addr) != 0) + { + DEBUG(D_transport) debug_printf_indent( + "tpt interface option mismatch with continued-connection\n"); + /* Close the conn and recheck retry info */ + continue_host_tried = FALSE; + break; + } + } + pistring = string_sprintf("%s/%s", pistring, interface); } } @@ -6039,6 +6064,7 @@ retry_non_continued: int fd = cutthrough.cctx.sock >= 0 ? cutthrough.cctx.sock : 0; DEBUG(D_transport) debug_printf("no hosts match already-open connection\n"); + DEBUG(D_transport) debug_printf(" SMTP>>QUIT\n"); #ifndef DISABLE_TLS /* A TLS conn could be open for a cutthrough, but not for a plain continued- transport */ @@ -6055,6 +6081,8 @@ retry_non_continued: #else (void) write(fd, US"QUIT\r\n", 6); #endif + + DEBUG(D_transport) debug_printf(" SMTP(close)>>\n"); (void) close(fd); cutthrough.cctx.sock = -1; continue_hostname = NULL; diff --git a/test/confs/0638 b/test/confs/0638 new file mode 100644 index 000000000..d9171f349 --- /dev/null +++ b/test/confs/0638 @@ -0,0 +1,49 @@ +# Exim test configuration 0143 + +.include DIR/aux-var/std_conf_prefix + +SERVER= +primary_hostname = myhost.test.ex + +# ----- Main settings ----- + +log_selector = +received_recipients +domainlist local_domains = test.ex : *.test.ex + +acl_not_smtp = accept set acl_m_control = CONTROL +acl_smtp_rcpt = accept + +# ----- Routers ----- + +begin routers + +server_blackhole: + driver = redirect + condition = ${if eq {SERVER}{server}} + data = :blackhole: + +my_main_router: + driver = manualroute + route_list = * 127.0.0.1 + self = send + transport = my_smtp + no_more + + +# ----- Transports ----- + +begin transports + +my_smtp: + driver = smtp + interface = $acl_m_control + port = PORT_D + hosts_try_fastopen = : + + +# ----- Retry ----- +begin retry + +* * F,5d,10s + +# End diff --git a/test/log/0638 b/test/log/0638 new file mode 100644 index 000000000..a57174d84 --- /dev/null +++ b/test/log/0638 @@ -0,0 +1,13 @@ +1999-03-02 09:44:33 10HmaX-000000005vi-0000 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userx@test.ex +1999-03-02 09:44:33 10HmaX-000000005vi-0000 H=127.0.0.1 [127.0.0.1] Connection refused +1999-03-02 09:44:33 10HmaX-000000005vi-0000 == userx@test.ex R=my_main_router T=my_smtp defer (dd): Connection refused +1999-03-02 09:44:33 10HmaY-000000005vi-0000 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for usery@test.ex +1999-03-02 09:44:33 10HmaY-000000005vi-0000 => usery@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmaZ-000000005vi-0000" +1999-03-02 09:44:33 10HmaY-000000005vi-0000 Completed +1999-03-02 09:44:33 10HmaX-000000005vi-0000 == userx@test.ex R=my_main_router T=my_smtp defer (-54): some host address lookups failed and retry time not reached for other hosts or connection limit reached for 'test.ex' + +******** SERVER ******** +1999-03-02 09:44:33 exim x.yz daemon started: pid=p1234, no queue runs, listening for SMTP on port PORT_D +1999-03-02 09:44:33 10HmaZ-000000005vi-0000 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaY-000000005vi-0000@myhost.test.ex for usery@test.ex +1999-03-02 09:44:33 10HmaZ-000000005vi-0000 => :blackhole: R=server_blackhole +1999-03-02 09:44:33 10HmaZ-000000005vi-0000 Completed diff --git a/test/scripts/0000-Basic/0638 b/test/scripts/0000-Basic/0638 new file mode 100644 index 000000000..4b5765680 --- /dev/null +++ b/test/scripts/0000-Basic/0638 @@ -0,0 +1,20 @@ +# transport interface option and queued message +need_ipv4 +# +# This one fails to connect; creates a retry record and is queued +exim -odf -DCONTROL=127.0.0.1 userx@test.ex +**** +# +# Now put a server up +exim -bd -DSERVER=server -oX PORT_D +**** +# +# Send another, using a different local IP +# That should be received by the server, but the same conn should +# NOT be used for the first message +exim -odf -DCONTROL=HOSTIPV4 usery@test.ex +**** +# +killdaemon +no_msglog_check +no_message_check -- 2.30.2