Example #1
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);
}
Example #2
0
int     main(int argc, char **argv)
{
    const char *verify_sender;
    const char *valid_sender;

    msg_vstream_init(argv[0], VSTREAM_ERR);

    /*
     * Prepare to talk to the address rewriting service.
     */
    mail_conf_read();
    vstream_printf("using config files in %s\n", var_config_dir);
    if (chdir(var_queue_dir) < 0)
	msg_fatal("chdir %s: %m", var_queue_dir);

    /*
     * Parse JCL.
     */
    if (argc != 3)
	msg_fatal("usage: %s address_verify_sender address_verify_sender_ttl",
		  argv[0]);
    var_verify_sender = argv[1];
    if (conv_time(argv[2], &var_verify_sender_ttl, 's') == 0)
	msg_fatal("bad time value: %s", argv[2]);
    verify_time = time((time_t *) 0);

    /*
     * Compute the current probe sender address.
     */
    verify_sender = make_verify_sender_addr();

    /*
     * Check two past time slots.
     */
    if (var_verify_sender_ttl > 0) {
	verify_time -= 2 * var_verify_sender_ttl;
	vstream_printf("\"%s\" matches prev2: \"%s\"\n", verify_sender,
	     (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
		       valid_sender : "nope");
	verify_time += var_verify_sender_ttl;
	vstream_printf("\"%s\" matches prev1: \"%s\"\n", verify_sender,
	     (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
		       valid_sender : "nope");
	verify_time += var_verify_sender_ttl;
    }

    /*
     * Check the current time slot.
     */
    vstream_printf("\"%s\" matches self: \"%s\"\n", verify_sender,
	     (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
		   valid_sender : "nope");

    /*
     * Check two future time slots.
     */
    if (var_verify_sender_ttl > 0) {
	verify_time += var_verify_sender_ttl;
	vstream_printf("\"%s\" matches next1: \"%s\"\n", verify_sender,
	     (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
		       valid_sender : "nope");
	verify_time += var_verify_sender_ttl;
	vstream_printf("\"%s\" matches next2: \"%s\"\n", verify_sender,
	     (valid_sender = valid_verify_sender_addr(verify_sender)) != 0 ?
		       valid_sender : "nope");
    }
    vstream_fflush(VSTREAM_OUT);
    exit(0);
}