Continued-transport: check interface option. Bug 1141
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 30 Jul 2024 12:33:37 +0000 (13:33 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 30 Jul 2024 12:33:37 +0000 (13:33 +0100)
doc/doc-txt/ChangeLog
src/src/deliver.c
src/src/transports/smtp.c
test/confs/0638 [new file with mode: 0644]
test/log/0638 [new file with mode: 0644]
test/scripts/0000-Basic/0638 [new file with mode: 0644]

index 7a4f1757e3d2a16bad3272de8d1e227a6dc560b6..a02911cae45beb20e7b338f88da12ca2fade2aa3 100644 (file)
@@ -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
 -----------------
 
index 9d26d07c03580cf8634eb7e8bd6b1b9d71786e4b..67ba505d1a1d3a489eb9870dba394549e04be565 100644 (file)
@@ -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;
index 769c5d235698b073524787bd3b2e96d997a3aa69..03de9dcaddf887d91e23e2a0019a89bf706ee128 100644 (file)
@@ -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 (file)
index 0000000..d9171f3
--- /dev/null
@@ -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 (file)
index 0000000..a57174d
--- /dev/null
@@ -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: <usery@test.ex> 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 (file)
index 0000000..4b57656
--- /dev/null
@@ -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