X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/899b8bbc6d360af6362c2a41d40b786279f41492..dec766a1977250758eb7a3e127e079a9271afd89:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index a1b677e19..d3af04cc8 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2017 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ #include "../exim.h" @@ -105,7 +105,7 @@ optionlist smtp_transport_options[] = { { "hosts_require_auth", opt_stringptr, (void *)offsetof(smtp_transport_options_block, hosts_require_auth) }, #ifdef SUPPORT_TLS -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE { "hosts_require_dane", opt_stringptr, (void *)offsetof(smtp_transport_options_block, hosts_require_dane) }, # endif @@ -120,7 +120,7 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, hosts_try_auth) }, { "hosts_try_chunking", opt_stringptr, (void *)offsetof(smtp_transport_options_block, hosts_try_chunking) }, -#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE) +#if defined(SUPPORT_TLS) && defined(SUPPORT_DANE) { "hosts_try_dane", opt_stringptr, (void *)offsetof(smtp_transport_options_block, hosts_try_dane) }, #endif @@ -219,7 +219,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { .hosts_try_auth = NULL, .hosts_require_auth = NULL, .hosts_try_chunking = US"*", -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE .hosts_try_dane = NULL, .hosts_require_dane = NULL, #endif @@ -1190,7 +1190,7 @@ return FALSE; -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE /* Lookup TLSA record for host/port. Return: OK success with dnssec; DANE mode DEFER Do not use this host now, may retry later @@ -1490,7 +1490,7 @@ Returns: OK - the connection was made and the delivery attempted; int smtp_setup_conn(smtp_context * sx, BOOL suppress_tls) { -#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE) +#if defined(SUPPORT_TLS) && defined(SUPPORT_DANE) dns_answer tlsa_dnsa; #endif BOOL pass_message = FALSE; @@ -1512,7 +1512,7 @@ sx->esmtp_sent = FALSE; sx->utf8_needed = FALSE; #endif sx->dsn_all_lasthop = TRUE; -#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE) +#if defined(SUPPORT_TLS) && defined(SUPPORT_DANE) sx->dane = FALSE; sx->dane_required = verify_check_given_host(&sx->ob->hosts_require_dane, sx->host) == OK; #endif @@ -1586,7 +1586,7 @@ if (!continue_hostname) smtp_port_for_connect(sx->host, sx->port); -#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE) +#if defined(SUPPORT_TLS) && defined(SUPPORT_DANE) /* Do TLSA lookup for DANE */ { tls_out.dane_verified = FALSE; @@ -1936,7 +1936,7 @@ if ( smtp_peer_options & OPTION_TLS address_item * addr; uschar * errstr; int rc = tls_client_start(sx->inblock.sock, sx->host, sx->addrlist, sx->tblock, -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE sx->dane ? &tlsa_dnsa : NULL, # endif &errstr); @@ -1947,7 +1947,7 @@ if ( smtp_peer_options & OPTION_TLS if (rc != OK) { -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE if (sx->dane) log_write(0, LOG_MAIN, "DANE attempt failed; TLS connection to %s [%s]: %s", sx->host->name, sx->host->address, errstr); @@ -2034,7 +2034,7 @@ if (tls_out.active >= 0) have one. */ else if ( sx->smtps -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE || sx->dane # endif || verify_check_given_host(&sx->ob->hosts_require_tls, sx->host) == OK @@ -2234,7 +2234,7 @@ if (sx->send_quit) (void)smtp_write_command(&sx->outblock, SCMD_FLUSH, "QUIT\r\n"); #ifdef SUPPORT_TLS -tls_close(FALSE, TRUE); +tls_close(FALSE, TLS_SHUTDOWN_NOWAIT); #endif /* Close the socket, and return the appropriate value, first setting @@ -2668,7 +2668,7 @@ for (fd_bits = 3; fd_bits; ) if ((rc = read(pfd[0], buf, bsize)) <= 0) { fd_bits = 0; - tls_close(FALSE, TRUE); + tls_close(FALSE, TLS_SHUTDOWN_NOWAIT); } else { @@ -3458,7 +3458,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit) a new EHLO. If we don't get a good response, we don't attempt to pass the socket on. */ - tls_close(FALSE, TRUE); + tls_close(FALSE, TLS_SHUTDOWN_WAIT); smtp_peer_options = smtp_peer_options_wrap; sx.ok = !sx.smtps && smtp_write_command(&sx.outblock, SCMD_FLUSH, @@ -3523,7 +3523,7 @@ propagate it from the initial close(pfd[0]); /* tidy the inter-proc to disconn the proxy proc */ waitpid(pid, NULL, 0); - tls_close(FALSE, FALSE); + tls_close(FALSE, TLS_NO_SHUTDOWN); (void)close(sx.inblock.sock); continue_transport = NULL; continue_hostname = NULL; @@ -3569,7 +3569,7 @@ if (sx.send_quit) (void)smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n") END_OFF: #ifdef SUPPORT_TLS -tls_close(FALSE, TRUE); +tls_close(FALSE, TLS_SHUTDOWN_NOWAIT); #endif /* Close the socket, and return the appropriate value, first setting @@ -3733,7 +3733,7 @@ uschar *tid = string_sprintf("%s transport", tblock->name); smtp_transport_options_block *ob = (smtp_transport_options_block *)(tblock->options_block); host_item *hostlist = addrlist->host_list; -host_item *host = NULL; +host_item *host; DEBUG(D_transport) { @@ -3744,7 +3744,7 @@ DEBUG(D_transport) { debug_printf("hostlist:\n"); for (host = hostlist; host; host = host->next) - debug_printf(" %s:%d\n", host->name, host->port); + debug_printf(" '%s' IP %s port %d\n", host->name, host->address, host->port); } if (continue_hostname) debug_printf("already connected to %s [%s] (on fd %d)\n", @@ -3925,7 +3925,9 @@ for (cutoff_retry = 0; { host_item *nexthost = NULL; int unexpired_hosts_tried = 0; + BOOL continue_host_tried = FALSE; +retry_non_continued: for (host = hostlist; host && unexpired_hosts_tried < ob->hosts_max_try @@ -3990,7 +3992,7 @@ for (cutoff_retry = 0; /* Find by name if so configured, or if it's an IP address. We don't just copy the IP address, because we need the test-for-local to happen. */ - flags = HOST_FIND_BY_A; + flags = HOST_FIND_BY_A | HOST_FIND_BY_AAAA; if (ob->dns_qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE; if (ob->dns_search_parents) flags |= HOST_FIND_SEARCH_PARENTS; @@ -4058,14 +4060,16 @@ for (cutoff_retry = 0; result of the lookup. Set expired FALSE, to save the outer loop executing twice. */ - if ( continue_hostname - && ( Ustrcmp(continue_hostname, host->name) != 0 - || Ustrcmp(continue_host_address, host->address) != 0 - ) ) - { - expired = FALSE; - continue; /* With next host */ - } + if (continue_hostname) + if ( Ustrcmp(continue_hostname, host->name) != 0 + || Ustrcmp(continue_host_address, host->address) != 0 + ) + { + expired = FALSE; + continue; /* With next host */ + } + else + continue_host_tried = TRUE; /* Reset the default next host in case a multihomed host whose addresses are not looked up till just above added to the host list. */ @@ -4523,6 +4527,32 @@ for (cutoff_retry = 0; } } /* End of loop for trying multiple hosts. */ + /* If we failed to find a matching host in the list, for an already-open + connection, just close it and start over with the list. This can happen + for routing that changes from run to run, or big multi-IP sites with + round-robin DNS. */ + + if (continue_hostname && !continue_host_tried) + { + int fd = cutthrough.fd >= 0 ? cutthrough.fd : 0; + + DEBUG(D_transport) debug_printf("no hosts match already-open connection\n"); +#ifdef SUPPORT_TLS + if (tls_out.active == fd) + { + (void) tls_write(FALSE, US"QUIT\r\n", 6, FALSE); + tls_close(FALSE, TLS_SHUTDOWN_NOWAIT); + } + else +#else + (void) write(fd, US"QUIT\r\n", 6); +#endif + (void) close(fd); + cutthrough.fd = -1; + continue_hostname = NULL; + goto retry_non_continued; + } + /* This is the end of the loop that repeats iff expired is TRUE and ob->delay_after_cutoff is FALSE. The second time round we will try those hosts that haven't been tried since the message arrived. */