static int smtp_reuse_session(SMTP_STATE *state, int lookup_mx, const char *domain, unsigned port, DNS_RR **addr_list, int domain_best_pref) { int session_count = 0; DNS_RR *addr; DNS_RR *next; MAI_HOSTADDR_STR hostaddr; SMTP_SESSION *session; /* * First, search the cache by logical destination. We truncate the server * address list when all the sessions for this destination are used up, * to reduce the number of variables that need to be checked later. * * Note: lookup by logical destination restores the "best MX" bit. */ if (*addr_list && SMTP_RCPT_LEFT(state) > 0 && (session = smtp_reuse_domain(state, lookup_mx, domain, port)) != 0) { session_count = 1; smtp_update_addr_list(addr_list, session->addr, session_count); if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP) && *addr_list == 0) state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER; smtp_xfer(state); smtp_cleanup_session(state); } /* * Second, search the cache by primary MX address. Again, we use address * list truncation so that we have to check fewer variables later. * * XXX This loop is safe because smtp_update_addr_list() either truncates * the list to zero length, or removes at most one list element. */ for (addr = *addr_list; SMTP_RCPT_LEFT(state) > 0 && addr; addr = next) { if (addr->pref != domain_best_pref) break; next = addr->next; if (dns_rr_to_pa(addr, &hostaddr) != 0 && (session = smtp_reuse_addr(state, hostaddr.buf, port)) != 0) { session->features |= SMTP_FEATURE_BEST_MX; session_count += 1; smtp_update_addr_list(addr_list, session->addr, session_count); if (*addr_list == 0) next = 0; if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP) && next == 0) state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER; smtp_xfer(state); smtp_cleanup_session(state); } } return (session_count); }
static int smtp_reuse_session(SMTP_STATE *state, DNS_RR **addr_list, int domain_best_pref) { int session_count = 0; DNS_RR *addr; DNS_RR *next; MAI_HOSTADDR_STR hostaddr; SMTP_SESSION *session; SMTP_ITERATOR *iter = state->iterator; DSN_BUF *why = state->why; /* * First, search the cache by request nexthop. We truncate the server * address list when all the sessions for this destination are used up, * to reduce the number of variables that need to be checked later. * * Note: lookup by logical destination restores the "best MX" bit. * * smtp_reuse_nexthop() clobbers the iterators's "dest" attribute. We save * and restore it here, so that subsequent connections will use the * proper nexthop information. * * We request a dummy "TLS disabled" policy for connection-cache lookup by * request nexthop only. If we find a saved connection, then we know that * plaintext was permitted, because we never save a connection after * turning on TLS. */ #ifdef USE_TLS smtp_tls_policy_dummy(state->tls); #endif SMTP_ITER_SAVE_DEST(state->iterator); if (*addr_list && SMTP_RCPT_LEFT(state) > 0 && HAVE_NEXTHOP_STATE(state) && (session = smtp_reuse_nexthop(state, SMTP_KEY_MASK_SCACHE_DEST_LABEL)) != 0) { session_count = 1; smtp_update_addr_list(addr_list, STR(iter->addr), session_count); if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP) && *addr_list == 0) state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER; smtp_xfer(state); smtp_cleanup_session(state); } SMTP_ITER_RESTORE_DEST(state->iterator); /* * Second, search the cache by primary MX address. Again, we use address * list truncation so that we have to check fewer variables later. * * XXX This loop is safe because smtp_update_addr_list() either truncates * the list to zero length, or removes at most one list element. * * Currently, we use smtp_reuse_addr() only for SASL-unauthenticated * connections. Furthermore, we rely on smtp_reuse_addr() to look up an * existing SASL-unauthenticated connection only when a new connection * would be guaranteed not to require SASL authentication. * * In addition, we rely on smtp_reuse_addr() to look up an existing * plaintext connection only when a new connection would be guaranteed * not to use TLS. * * For more precise control over reuse, the iterator should look up SASL and * TLS policy as it evaluates mail exchangers in order, instead of * relying on duplicate lookup request code in smtp_reuse(3) and * smtp_session(3). */ for (addr = *addr_list; SMTP_RCPT_LEFT(state) > 0 && addr; addr = next) { if (addr->pref != domain_best_pref) break; next = addr->next; if (dns_rr_to_pa(addr, &hostaddr) == 0) { msg_warn("cannot convert type %s record to printable address", dns_strtype(addr->type)); /* XXX Assume there is no code at the end of this loop. */ continue; } vstring_strcpy(iter->addr, hostaddr.buf); vstring_strcpy(iter->host, SMTP_HNAME(addr)); iter->rr = addr; #ifdef USE_TLS if (!smtp_tls_policy_cache_query(why, state->tls, iter)) { msg_warn("TLS policy lookup error for %s/%s: %s", STR(iter->dest), STR(iter->host), STR(why->reason)); continue; /* XXX Assume there is no code at the end of this loop. */ } #endif if ((session = smtp_reuse_addr(state, SMTP_KEY_MASK_SCACHE_ENDP_LABEL)) != 0) { session->features |= SMTP_FEATURE_BEST_MX; session_count += 1; smtp_update_addr_list(addr_list, STR(iter->addr), session_count); if (*addr_list == 0) next = 0; if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP) && next == 0) state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER; smtp_xfer(state); smtp_cleanup_session(state); } } return (session_count); }