Exemplo n.º 1
0
static void iter_action(DICT_CACHE_SREQ *cp, DICT_CACHE *dp, VSTRING *bp)
{
    const char *cache_key;
    const char *cache_val;
    const char *what;
    const char *suffix;

    if (dict_cache_sequence(dp, cp->first_next, &cache_key, &cache_val) == 0) {
	if (strcmp(cache_key, cache_val) != 0)
	    msg_warn("value \"%s\" differs from key \"%s\"",
		     cache_val, cache_key);
	suffix = cache_key + strspn(cache_key, "0123456789");
	if (suffix[0] == '-' && strcmp(suffix + 1, cp->suffix) == 0) {
	    cp->done += 1;
	    cp->todo = cp->done + 1;		/* XXX */
	    if ((cp->flags & DICT_CACHE_SREQ_FLAG_PURGE)
		&& dict_cache_delete(dp, cache_key) != 0) {
		if (dp->error)
		    msg_warn("purge_action: delete failed: %s: %m", STR(bp));
		else
		    msg_warn("purge_action: delete failed: %s", STR(bp));
	    }
	}
	cp->first_next = DICT_SEQ_FUN_NEXT;
    } else {
	what = (cp->flags & DICT_CACHE_SREQ_FLAG_PURGE) ? "purge" : "count";
	if (dp->error)
	    msg_warn("%s error after %d: %m", what, cp->done);
	else
	    vstream_printf("suffix=%s %s=%d\n", cp->suffix, what, cp->done);
	cp->todo = 0;
    }
}
Exemplo n.º 2
0
static void delete_action(DICT_CACHE_SREQ *cp, DICT_CACHE *dp, VSTRING *bp)
{
    make_tagged_key(bp, cp);
    if (dict_cache_delete(dp, STR(bp)) != 0) {
	if (dp->error)
	    msg_warn("delete_action: delete failed: %s: %m", STR(bp));
	else
	    msg_warn("delete_action: delete failed: %s", STR(bp));
    }
    cp->done += 1;
}
Exemplo n.º 3
0
static void verify_query_service(VSTREAM *client_stream)
{
    VSTRING *addr = vstring_alloc(10);
    VSTRING *get_buf = 0;
    VSTRING *put_buf = 0;
    const char *raw_data;
    int     addr_status;
    long    probed;
    long    updated;
    char   *text;

    if (attr_scan(client_stream, ATTR_FLAG_STRICT,
		  RECV_ATTR_STR(MAIL_ATTR_ADDR, addr),
		  ATTR_TYPE_END) == 1) {
	long    now = (long) time((time_t *) 0);

	/*
	 * Produce a default record when no usable record exists.
	 * 
	 * If negative caching is disabled, purge an expired record from the
	 * database.
	 * 
	 * XXX Assume that a probe is lost if no response is received in 1000
	 * seconds. If this number is too small the queue will slowly fill up
	 * with delayed probes.
	 * 
	 * XXX Maintain a moving average for the probe turnaround time, and
	 * allow probe "retransmission" when a probe is outstanding for, say
	 * some minimal amount of time (1000 sec) plus several times the
	 * observed probe turnaround time. This causes probing to back off
	 * when the mail system becomes congested.
	 */
#define POSITIVE_ENTRY_EXPIRED(addr_status, updated) \
    (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_exp < now)
#define NEGATIVE_ENTRY_EXPIRED(addr_status, updated) \
    (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_exp < now)
#define PROBE_TTL	1000

	/* FIX 200501 IPv6 patch did not neuter ":" in address literals. */
	translit(STR(addr), ":", "_");
	if ((raw_data = dict_cache_lookup(verify_map, STR(addr))) == 0	/* not found */
	    || ((get_buf = vstring_alloc(10)),
		vstring_strcpy(get_buf, raw_data),	/* malformed */
		verify_parse_entry(STR(get_buf), &addr_status, &probed,
				   &updated, &text) < 0)
	    || (now - probed > PROBE_TTL	/* safe to probe */
		&& (POSITIVE_ENTRY_EXPIRED(addr_status, updated)
		    || NEGATIVE_ENTRY_EXPIRED(addr_status, updated)))) {
	    addr_status = DEL_RCPT_STAT_TODO;
	    probed = 0;
	    updated = 0;
	    text = "Address verification in progress";
	    if (raw_data != 0 && var_verify_neg_cache == 0)
		dict_cache_delete(verify_map, STR(addr));
	}
	if (msg_verbose)
	    msg_info("GOT %s status=%d probed=%ld updated=%ld text=%s",
		     STR(addr), addr_status, probed, updated, text);

	/*
	 * Respond to the client.
	 */
	attr_print(client_stream, ATTR_FLAG_NONE,
		   SEND_ATTR_INT(MAIL_ATTR_STATUS, VRFY_STAT_OK),
		   SEND_ATTR_INT(MAIL_ATTR_ADDR_STATUS, addr_status),
		   SEND_ATTR_STR(MAIL_ATTR_WHY, text),
		   ATTR_TYPE_END);

	/*
	 * Send a new probe when the information needs to be refreshed.
	 * 
	 * XXX For an initial proof of concept implementation, use synchronous
	 * mail submission. This needs to be made async for high-volume
	 * sites, which makes it even more interesting to eliminate duplicate
	 * queries while a probe is being built.
	 * 
	 * If negative caching is turned off, update the database only when
	 * refreshing an existing entry.
	 */
#define POSITIVE_REFRESH_NEEDED(addr_status, updated) \
    (addr_status == DEL_RCPT_STAT_OK && updated + var_verify_pos_try < now)
#define NEGATIVE_REFRESH_NEEDED(addr_status, updated) \
    (addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_try < now)

	if (now - probed > PROBE_TTL
	    && (POSITIVE_REFRESH_NEEDED(addr_status, updated)
		|| NEGATIVE_REFRESH_NEEDED(addr_status, updated))) {
	    if (msg_verbose)
		msg_info("PROBE %s status=%d probed=%ld updated=%ld",
			 STR(addr), addr_status, now, updated);
	    post_mail_fopen_async(make_verify_sender_addr(), STR(addr),
				  MAIL_SRC_MASK_VERIFY,
				  DEL_REQ_FLAG_MTA_VRFY,
				  SMTPUTF8_FLAG_NONE,
				  (VSTRING *) 0,
				  verify_post_mail_action,
				  (void *) 0);
	    if (updated != 0 || var_verify_neg_cache != 0) {
		put_buf = vstring_alloc(10);
		verify_make_entry(put_buf, addr_status, now, updated, text);
		if (msg_verbose)
		    msg_info("PUT %s status=%d probed=%ld updated=%ld text=%s",
			     STR(addr), addr_status, now, updated, text);
		dict_cache_update(verify_map, STR(addr), STR(put_buf));
	    }
	}
    }
    vstring_free(addr);
    if (get_buf)
	vstring_free(get_buf);
    if (put_buf)
	vstring_free(put_buf);
}