/*++
/* NAME
/*	dns_sec 3
/* SUMMARY
/*	DNSSEC validation availability
/* SYNOPSIS
/*	#include <dns.h>
/*
/*	DNS_SEC_STATS_SET(
/*	int	flags)
/*
/*	DNS_SEC_STATS_TEST(
/*	int	flags)
/*
/*	void	dns_sec_probe(
/*	int	rflags)
/* DESCRIPTION
/*	This module maintains information about the availability of
/*	DNSSEC validation, in global flags that summarize
/*	process-lifetime history.
/* .IP DNS_SEC_FLAG_AVAILABLE
/*	The process has received at least one DNSSEC validated
/*	response to a query that requested DNSSEC validation.
/* .IP DNS_SEC_FLAG_DONT_PROBE
/*	The process has sent a DNSSEC probe (see below), or DNSSEC
/*	probing is disabled by configuration.
/* .PP
/*	DNS_SEC_STATS_SET() sets one or more DNS_SEC_FLAG_* flags,
/*	and DNS_SEC_STATS_TEST() returns non-zero if any of the
/*	specified flags is set.
/*
/*	dns_sec_probe() generates a query to the target specified
/*	with the \fBdnssec_probe\fR configuration parameter. It
/*	sets the DNS_SEC_FLAG_DONT_PROBE flag, and it calls
/*	dns_lookup() which sets DNS_SEC_FLAG_AVAILABLE if it receives
/*	a DNSSEC validated response. Preconditions:
/* .IP \(bu
/*	The rflags argument must request DNSSEC validation (in the
/*	same manner as dns_lookup() rflags argument).
/* .IP \(bu
/*	The DNS_SEC_FLAG_AVAILABLE and DNS_SEC_FLAG_DONT_PROBE
/*	flags must be false.
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	Google, Inc.
/*	111 8th Avenue
/*	New York, NY 10011, USA
/*--*/

#include <sys_defs.h>

 /*
  * Utility library.
  */
#include <msg.h>
#include <mymalloc.h>
#include <split_at.h>
#include <vstring.h>

 /*
  * Global library.
  */
#include <mail_params.h>

 /*
  * DNS library.
  */
#include <dns.h>

int     dns_sec_stats;

/* dns_sec_probe - send a probe to establish DNSSEC viability */

void    dns_sec_probe(int rflags)
{
    const char myname[] = "dns_sec_probe";
    char   *saved_dnssec_probe;
    char   *qname;
    int     qtype;
    DNS_RR *rrlist = 0;
    int     dns_status;
    VSTRING *why;

    /*
     * Sanity checks.
     */
    if (!DNS_WANT_DNSSEC_VALIDATION(rflags))
	msg_panic("%s: DNSSEC is not requested", myname);
    if (DNS_SEC_STATS_TEST(DNS_SEC_FLAG_DONT_PROBE))
	msg_panic("%s: DNSSEC probe was already sent, or probing is disabled",
		  myname);
    if (DNS_SEC_STATS_TEST(DNS_SEC_FLAG_AVAILABLE))
	msg_panic("%s: already have validated DNS response", myname);

    /*
     * Don't recurse.
     */
    DNS_SEC_STATS_SET(DNS_SEC_FLAG_DONT_PROBE);

    /*
     * Don't probe.
     */
    if (*var_dnssec_probe == 0)
	return;

    /*
     * Parse the probe spec. Format is type:resource.
     */
    saved_dnssec_probe = mystrdup(var_dnssec_probe);
    if ((qname = split_at(saved_dnssec_probe, ':')) == 0 || *qname == 0
	|| (qtype = dns_type(saved_dnssec_probe)) == 0)
	msg_fatal("malformed %s value: %s format is qtype:qname",
		  VAR_DNSSEC_PROBE, var_dnssec_probe);

    why = vstring_alloc(100);
    dns_status = dns_lookup(qname, qtype, rflags, &rrlist, (VSTRING *) 0, why);
    if (!DNS_SEC_STATS_TEST(DNS_SEC_FLAG_AVAILABLE))
	msg_warn("DNSSEC validation may be unavailable");
    else if (msg_verbose)
	msg_info(VAR_DNSSEC_PROBE
		 " '%s' received a response that is DNSSEC validated",
		 var_dnssec_probe);
    switch (dns_status) {
    default:
	if (!DNS_SEC_STATS_TEST(DNS_SEC_FLAG_AVAILABLE))
	    msg_warn("reason: " VAR_DNSSEC_PROBE
		     " '%s' received a response that is not DNSSEC validated",
		     var_dnssec_probe);
	if (rrlist)
	    dns_rr_free(rrlist);
	break;
    case DNS_RETRY:
    case DNS_FAIL:
	msg_warn("reason: " VAR_DNSSEC_PROBE " '%s' received no response: %s",
		 var_dnssec_probe, vstring_str(why));
	break;
    }
    myfree(saved_dnssec_probe);
    vstring_free(why);
}
