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);
}
Exemple #2
0
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);
}