1*67b9b338Schristos /* $NetBSD: dns_sec.c,v 1.2 2022/10/08 16:12:45 christos Exp $ */
24a672054Schristos
34a672054Schristos /*++
44a672054Schristos /* NAME
54a672054Schristos /* dns_sec 3
64a672054Schristos /* SUMMARY
74a672054Schristos /* DNSSEC validation availability
84a672054Schristos /* SYNOPSIS
94a672054Schristos /* #include <dns.h>
104a672054Schristos /*
114a672054Schristos /* DNS_SEC_STATS_SET(
124a672054Schristos /* int flags)
134a672054Schristos /*
144a672054Schristos /* DNS_SEC_STATS_TEST(
154a672054Schristos /* int flags)
164a672054Schristos /*
174a672054Schristos /* void dns_sec_probe(
184a672054Schristos /* int rflags)
194a672054Schristos /* DESCRIPTION
204a672054Schristos /* This module maintains information about the availability of
214a672054Schristos /* DNSSEC validation, in global flags that summarize
224a672054Schristos /* process-lifetime history.
234a672054Schristos /* .IP DNS_SEC_FLAG_AVAILABLE
244a672054Schristos /* The process has received at least one DNSSEC validated
254a672054Schristos /* response to a query that requested DNSSEC validation.
264a672054Schristos /* .IP DNS_SEC_FLAG_DONT_PROBE
274a672054Schristos /* The process has sent a DNSSEC probe (see below), or DNSSEC
284a672054Schristos /* probing is disabled by configuration.
294a672054Schristos /* .PP
304a672054Schristos /* DNS_SEC_STATS_SET() sets one or more DNS_SEC_FLAG_* flags,
314a672054Schristos /* and DNS_SEC_STATS_TEST() returns non-zero if any of the
324a672054Schristos /* specified flags is set.
334a672054Schristos /*
344a672054Schristos /* dns_sec_probe() generates a query to the target specified
354a672054Schristos /* with the \fBdnssec_probe\fR configuration parameter. It
364a672054Schristos /* sets the DNS_SEC_FLAG_DONT_PROBE flag, and it calls
374a672054Schristos /* dns_lookup() which sets DNS_SEC_FLAG_AVAILABLE if it receives
384a672054Schristos /* a DNSSEC validated response. Preconditions:
394a672054Schristos /* .IP \(bu
404a672054Schristos /* The rflags argument must request DNSSEC validation (in the
414a672054Schristos /* same manner as dns_lookup() rflags argument).
424a672054Schristos /* .IP \(bu
434a672054Schristos /* The DNS_SEC_FLAG_AVAILABLE and DNS_SEC_FLAG_DONT_PROBE
444a672054Schristos /* flags must be false.
454a672054Schristos /* LICENSE
464a672054Schristos /* .ad
474a672054Schristos /* .fi
484a672054Schristos /* The Secure Mailer license must be distributed with this software.
494a672054Schristos /* AUTHOR(S)
504a672054Schristos /* Wietse Venema
514a672054Schristos /* Google, Inc.
524a672054Schristos /* 111 8th Avenue
534a672054Schristos /* New York, NY 10011, USA
544a672054Schristos /*--*/
554a672054Schristos
564a672054Schristos #include <sys_defs.h>
574a672054Schristos
584a672054Schristos /*
594a672054Schristos * Utility library.
604a672054Schristos */
614a672054Schristos #include <msg.h>
624a672054Schristos #include <mymalloc.h>
634a672054Schristos #include <split_at.h>
644a672054Schristos #include <vstring.h>
654a672054Schristos
664a672054Schristos /*
674a672054Schristos * Global library.
684a672054Schristos */
694a672054Schristos #include <mail_params.h>
704a672054Schristos
714a672054Schristos /*
724a672054Schristos * DNS library.
734a672054Schristos */
744a672054Schristos #include <dns.h>
754a672054Schristos
764a672054Schristos int dns_sec_stats;
774a672054Schristos
784a672054Schristos /* dns_sec_probe - send a probe to establish DNSSEC viability */
794a672054Schristos
dns_sec_probe(int rflags)804a672054Schristos void dns_sec_probe(int rflags)
814a672054Schristos {
824a672054Schristos const char myname[] = "dns_sec_probe";
834a672054Schristos char *saved_dnssec_probe;
844a672054Schristos char *qname;
854a672054Schristos int qtype;
864a672054Schristos DNS_RR *rrlist = 0;
874a672054Schristos int dns_status;
884a672054Schristos VSTRING *why;
894a672054Schristos
904a672054Schristos /*
914a672054Schristos * Sanity checks.
924a672054Schristos */
934a672054Schristos if (!DNS_WANT_DNSSEC_VALIDATION(rflags))
944a672054Schristos msg_panic("%s: DNSSEC is not requested", myname);
954a672054Schristos if (DNS_SEC_STATS_TEST(DNS_SEC_FLAG_DONT_PROBE))
964a672054Schristos msg_panic("%s: DNSSEC probe was already sent, or probing is disabled",
974a672054Schristos myname);
984a672054Schristos if (DNS_SEC_STATS_TEST(DNS_SEC_FLAG_AVAILABLE))
994a672054Schristos msg_panic("%s: already have validated DNS response", myname);
1004a672054Schristos
1014a672054Schristos /*
1024a672054Schristos * Don't recurse.
1034a672054Schristos */
1044a672054Schristos DNS_SEC_STATS_SET(DNS_SEC_FLAG_DONT_PROBE);
1054a672054Schristos
1064a672054Schristos /*
1074a672054Schristos * Don't probe.
1084a672054Schristos */
1094a672054Schristos if (*var_dnssec_probe == 0)
1104a672054Schristos return;
1114a672054Schristos
1124a672054Schristos /*
1134a672054Schristos * Parse the probe spec. Format is type:resource.
1144a672054Schristos */
1154a672054Schristos saved_dnssec_probe = mystrdup(var_dnssec_probe);
1164a672054Schristos if ((qname = split_at(saved_dnssec_probe, ':')) == 0 || *qname == 0
1174a672054Schristos || (qtype = dns_type(saved_dnssec_probe)) == 0)
1184a672054Schristos msg_fatal("malformed %s value: %s format is qtype:qname",
1194a672054Schristos VAR_DNSSEC_PROBE, var_dnssec_probe);
1204a672054Schristos
1214a672054Schristos why = vstring_alloc(100);
1224a672054Schristos dns_status = dns_lookup(qname, qtype, rflags, &rrlist, (VSTRING *) 0, why);
1234a672054Schristos if (!DNS_SEC_STATS_TEST(DNS_SEC_FLAG_AVAILABLE))
1244a672054Schristos msg_warn("DNSSEC validation may be unavailable");
1254a672054Schristos else if (msg_verbose)
1264a672054Schristos msg_info(VAR_DNSSEC_PROBE
1274a672054Schristos " '%s' received a response that is DNSSEC validated",
1284a672054Schristos var_dnssec_probe);
1294a672054Schristos switch (dns_status) {
1304a672054Schristos default:
1314a672054Schristos if (!DNS_SEC_STATS_TEST(DNS_SEC_FLAG_AVAILABLE))
1324a672054Schristos msg_warn("reason: " VAR_DNSSEC_PROBE
1334a672054Schristos " '%s' received a response that is not DNSSEC validated",
1344a672054Schristos var_dnssec_probe);
1354a672054Schristos if (rrlist)
1364a672054Schristos dns_rr_free(rrlist);
1374a672054Schristos break;
1384a672054Schristos case DNS_RETRY:
1394a672054Schristos case DNS_FAIL:
1404a672054Schristos msg_warn("reason: " VAR_DNSSEC_PROBE " '%s' received no response: %s",
1414a672054Schristos var_dnssec_probe, vstring_str(why));
1424a672054Schristos break;
1434a672054Schristos }
1444a672054Schristos myfree(saved_dnssec_probe);
1454a672054Schristos vstring_free(why);
1464a672054Schristos }
147