summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Pennock <pdp@exim.org>2013-03-24 07:16:51 -0400
committerPhil Pennock <pdp@exim.org>2013-03-24 07:16:51 -0400
commita85014fc1b8496db77b5cf38f4d861b13db97c23 (patch)
treee030da7667b1a79e5b89574b16ee8ac31ac98507
parent0fbd9bff71b47e3a32e54629c3f67e7eda1812fe (diff)
downloadexim4-a85014fc1b8496db77b5cf38f4d861b13db97c23.tar.gz
DNSSEC outbound, need_dnssec option.
need_dnssec on dnslookup & manualroute routers, smtp transport. @mx* addresslists gain /dnssec modifier. DNSSEC chapter of the spec. The `test_host` test-driver for host.c gains help and various new options. Fix documentation dns_use_dnssec -> dns_dnssec_ok.
-rw-r--r--doc/doc-docbook/spec.xfpt187
-rw-r--r--doc/doc-txt/ChangeLog3
-rw-r--r--doc/doc-txt/NewStuff22
-rw-r--r--doc/doc-txt/OptionLists.txt7
-rw-r--r--src/src/exim.c5
-rw-r--r--src/src/functions.h2
-rw-r--r--src/src/host.c82
-rw-r--r--src/src/macros.h2
-rw-r--r--src/src/match.c9
-rw-r--r--src/src/readconf.c44
-rw-r--r--src/src/routers/dnslookup.c23
-rw-r--r--src/src/routers/dnslookup.h2
-rw-r--r--src/src/routers/manualroute.c22
-rw-r--r--src/src/routers/manualroute.h2
-rw-r--r--src/src/routers/queryprogram.c2
-rw-r--r--src/src/routers/rf_functions.h2
-rw-r--r--src/src/routers/rf_lookup_hostlist.c8
-rw-r--r--src/src/structs.h1
-rw-r--r--src/src/transports/smtp.c30
-rw-r--r--src/src/transports/smtp.h2
-rw-r--r--src/src/verify.c5
21 files changed, 408 insertions, 54 deletions
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 92d0a2287..2d6e1d757 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -7858,6 +7858,11 @@ example, a single-component domain will &'not'& be expanded by adding the
resolver's default domain. See the &%qualify_single%& and &%search_parents%&
options of the &(dnslookup)& router for a discussion of domain widening.
+If you wish to constrain results to only include those for which DNSSEC
+verification can prove the data authentic, then follow the pattern with
+&`/dnssec`&. If this is combined with the &`/ignore`& in the next paragraph,
+then this option must come first (to not be part of the ignore list).
+
Sometimes you may want to ignore certain IP addresses when using one of these
patterns. You can specify this by following the pattern with &`/ignore=`&<&'ip
list'&>, where <&'ip list'&> is a list of IP addresses. These addresses are
@@ -11858,7 +11863,7 @@ other times, this variable is false.
It is likely that you will need to coerce DNSSEC support on in the resolver
library, by setting:
.code
-dns_use_dnssec = 1
+dns_dnssec_ok
.endd
Exim does not perform DNSSEC validation itself, instead leaving that to a
@@ -13074,7 +13079,7 @@ See also the &'Policy controls'& section above.
.row &%dns_ipv4_lookup%& "only v4 lookup for these domains"
.row &%dns_retrans%& "parameter for resolver"
.row &%dns_retry%& "parameter for resolver"
-.row &%dns_use_dnssec%& "parameter for resolver"
+.row &%dns_dnssec_ok%& "parameter for resolver"
.row &%dns_use_edns0%& "parameter for resolver"
.row &%hold_domains%& "hold delivery for these domains"
.row &%local_interfaces%& "for routing checks"
@@ -13723,24 +13728,26 @@ See &%dns_retrans%& above.
.new
-.option dns_use_dnssec main integer -1
+.option dns_dnssec_ok main boolean unset
.cindex "DNS" "resolver options"
.cindex "DNS" "DNSSEC"
-If this option is set to a non-negative number then Exim will initialise the
+If this option is set, whether true or false, then Exim will initialise the
DNS resolver library to either use or not use DNSSEC, overriding the system
-default. A value of 0 coerces DNSSEC off, a value of 1 coerces DNSSEC on.
+default.
If the resolver library does not support DNSSEC then this option has no effect.
+
+If &%dns_use_edns0%& has been explicitly set false, then this option will
+be ignored.
.wen
-.option dns_use_edns0 main integer -1
+.option dns_use_edns0 main boolean unset
.cindex "DNS" "resolver options"
.cindex "DNS" "EDNS0"
-If this option is set to a non-negative number then Exim will initialise the
+If this option is set, whether true or false, then Exim will initialise the
DNS resolver library to either use or not use EDNS0 extensions, overriding
-the system default. A value of 0 coerces EDNS0 off, a value of 1 coerces EDNS0
-on.
+the system default.
If the resolver library does not support EDNS0 then this option has no effect.
@@ -17506,6 +17513,14 @@ DNS lookup error, Exim behaves as if no MX records were found. See section
+.option need_dnssec dnslookup boolean&!! false
+If this option is set, then DNSSEC results must be verifiable, and both bogus
+and unsigned data will be ignored. Setting this without setting
+&%dns_dnssec_ok%& in the main section is probably a mistake.
+
+See chapter &<<CHAPdnssec>>& for more discussion.
+
+
.option qualify_single dnslookup boolean true
.cindex "DNS" "resolver options"
@@ -17868,6 +17883,14 @@ randomized host list is passed to an &(smtp)& transport that also has
&%hosts_randomize set%&, the list is not re-randomized.
+.option need_dnssec manualroute boolean&!! false
+If this option is set, then DNSSEC results must be verifiable, and both bogus
+and unsigned data will be ignored. Setting this without setting
+&%dns_dnssec_ok%& in the main section is probably a mistake.
+
+See chapter &<<CHAPdnssec>>& for more discussion.
+
+
.option route_data manualroute string&!! unset
If this option is set, it must expand to yield the data part of a routing rule.
Typically, the expansion string includes a lookup based on the domain. For
@@ -22666,6 +22689,14 @@ handling only one domain at a time. This is useful if you want to use
is a single domain involved in a remote delivery.
+.option need_dnssec smtp boolean&!! false
+If this option is set, then DNSSEC results must be verifiable, and both bogus
+and unsigned data will be ignored. Setting this without setting
+&%dns_dnssec_ok%& in the main section is probably a mistake.
+
+See chapter &<<CHAPdnssec>>& for more discussion.
+
+
.option port smtp string&!! "see below"
.cindex "port" "sending TCP/IP"
.cindex "TCP/IP" "setting outgoing port"
@@ -26004,6 +26035,144 @@ Open-source PKI book, available online at
. ////////////////////////////////////////////////////////////////////////////
. ////////////////////////////////////////////////////////////////////////////
+
+.chapter "DNS Security Extensions" "CHAPdnssec"
+.scindex IIDdnssec1 "DNS" "DNSSEC"
+.scindex IIDdnssec2 "security" "DNS"
+.cindex DNSSEC
+Exim is able to make some use of the DNSSEC security extensions to DNS; this
+chapter describes what DNS security is and how Exim can make use of it.
+
+If Exim was built with DISABLE_DNSSEC then the facilities described in this
+chapter are not available. Running Exim with the &%-bV%& flag will list
+DNSSEC in the &"Support for"& line if support is present.
+
+
+.section "Types of DNS security" "SECTsecurednstypes"
+There are two types of security available within DNS: link-level security and
+object-level security.
+
+Link-level security, as provided by TSIG, provides for symmetric encryption
+between DNS speakers, for confidentiality and authentication. In practice,
+this is primarily used between authoritative servers to secure zone transfers.
+Whilst the TKEY DNS extensions might make TSIG more widely useful, in practice
+it remains rare.
+
+Exim does not contain any special support for TSIG at this time.
+
+Object-level security is data which is published by the authoritative servers
+for a zone, passing unchanged through caches, so that clients can verify
+that the data received is the data published. This is handled by the DNSSEC
+extensions to DNS.
+
+In DNSSEC, each zone has one or more sets of keys, used to sign data, published
+at the apex of the zone in &`DNSKEY`& records.
+Typically, there are two current keys, a zone-signing-key (ZSK) and a stronger
+key-signing-key (KSK). The KSK is used to sign the ZSK records, the ZSK is
+used to sign the remaining records.
+This permits the KSK to be used as a trust anchor, and ideally kept off-line,
+while the ZSK is used to periodically re-sign data. A fingerprint of the KSK
+is published in a DS record in the &'parent'& zone. Across a DNS zone cut,
+only the &`DS`& records are authoritative in the parent, not the child.
+
+Any piece of software which has access to a trust anchor for some parent of
+a domain can verify all signatures for that domain and reject invalid
+signatures. Today, the DNS root zone has been signed, so only one trust
+anchor is normally needed.
+
+Useful websites for verifying that DNSSEC has been correctly deployed for a
+zone include &url(http://dnsviz.net/) and &url(http://secspider.cs.ucla.edu/).
+
+&*Note 1*&: Beware that DNSSEC records make responses larger, often more than
+the 512 historical size limit on DNS packets, before the EDNS0 extension
+allowed them to grow larger. Some broken NAT boxes are known to interfere with
+any large DNS packets because of hard-coded assumptions that DNS "can't" be
+that large.
+
+&*Note 2*&: DNSSEC validation requires that your system clock does not
+vehemently disagree with the consensus time and date of the rest of the world.
+You do not need to be fully NTP synchronised, but if you can't get the time to
+the right hour of the right day, you may encounter vexing issues.
+
+
+.section "DNSSEC Validation" "SECTdnssecvalidation"
+Exim does not itself implement any knowledge of validation records, trust
+anchors or the rest of the machinery. Instead, Exim is ably to work with
+a validating resolver.
+
+If you have a trusted path between Exim and a resolver, and trust the resolver
+to do its job right, then this is all that is needed. This encapsulates all
+the DNSSEC logic needed to handle new algorithms inside software maintained
+by DNS experts. Typically, you might run the validating resolver on the same
+machine as Exim.
+
+When the &%dns_dnssec_ok%& option is set in Exim's main configuration section,
+Exim will configure the system resolver library to send the EDNS0 option with
+the &"DNSSEC OK"& (DO) flag. This will cause the resolver to return results
+where for validated entries the results header will include the
+&"Authenticated Data"& (AD) flag.
+
+&*Warning*&: Successful use of DNSSEC by Exim is highly likely to be contingent
+upon &%dns_dnssec_ok%& being set.
+
+In a DNSSEC world, all responses can be one of: &'Secure'&, &'Insecure'&,
+&'Bogus'& or &'Indeterminate'&. Now that the root zone has been signed,
+&'Indeterminate'& is a sign of resolver misconfiguration.
+A Validating Resolver will filter out &'Bogus'& results, where the DNSSEC shows
+that something is wrong, but return both &'Secure'& and &'Insecure'& results,
+typically without setting the AD flag to distinguish between them unless
+explicitly asked to, via the DO flag.
+
+Without setting &%dns_dnssec_ok%&, &'Secure'& and &'Insecure'& can not be
+distinguished; asking Exim to only accept &'Secure'& answers without setting
+this option is only likely to yield useful results if the resolver returns AD
+regardless of the state of DO.
+
+When a connection is made to Exim and &$sender_host_name$& has been populated
+from reverse DNS, then the &$sender_host_dnssec$& boolean will be set true by
+Exim if the reverse DNS is &'Secure'&.
+
+When resolving DNS in a &(dnslookup)& or &(manualroute)& router or in an
+&(smtp)& transport, if the &%need_dnssec%& option is set then host resolution
+will skip &'Insecure'& results too and it will appear that only &'Secure'&
+results exist in DNS.
+
+.section "Resolver Setup" "SECTdnssecressetup"
+
+When validation is working, &'www.cam.ac.uk'& will have the AD flag set on the
+resolution results, while &'www.dnssec-failed.org'& will disappear from DNS
+unless you explicitly disable checking:
+.code
+$ dig +dnssec www.cam.ac.uk
+$ dig www.dnssec-failed.org
+$ dig +cd www.dnssec-failed.org
+.endd
+
+Unbound (&url(http://unbound.net/)) is a validating, recursive, and caching DNS
+resolver. In the &`server:`& block of configuration, set
+&`auto-trust-anchor-file:`& to a path which can be updated by the unbound
+runtime user and make sure to run &(unbound-anchor)& before starting
+&(unbound)&. The daemon will keep the anchor up-to-date, the
+&(unbound-anchor)& command will get the anchor in the first place and recover
+from serious errors, so should be run before starting unbound.
+
+That's it, for Unbound.
+
+Configuring Bind is more involved; see descriptions at
+&url(http://fanf.livejournal.com/107310.html) or
+&url(https://dnssec.surfnet.nl/?p=402).
+
+. ////
+. In future, we'll document DANE here.
+. ////
+
+.ecindex IIDdnssec1
+.ecindex IIDdnssec2
+
+
+. ////////////////////////////////////////////////////////////////////////////
+. ////////////////////////////////////////////////////////////////////////////
+
.chapter "Access control lists" "CHAPACL"
.scindex IIDacl "&ACL;" "description"
.cindex "control of incoming mail"
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index abaee5659..2ed405c61 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -185,6 +185,9 @@ PP/19 Renamed DNSSEC-enabling option to "dns_dnssec_ok", to make it
clearer that Exim is using the DO (DNSSEC OK) EDNS0 resolver flag,
not performing validation itself.
+PP/20 Added need_dnssec for SMTP Transport, dnslookup & manualroute
+ Routers. @mx..* options get /dnssec modifier.
+
Exim version 4.80.1
-------------------
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index ab8589e53..71b8f2fc0 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -31,14 +31,30 @@ Version 4.82
Unless you really know what you are doing, leave it alone.
- 4. If not built with DISABLE_DNSSEC, Exim now has the main option
- dns_dnssec_ok; if set to 1 then Exim will initialise the resolver library
+ 4. If not built with DISABLE_DNSSEC, Exim now has the main boolean option
+ dns_dnssec_ok; if set then Exim will initialise the resolver library
to send the DO flag to your recursive resolver. If you have a recursive
resolver, which can set the Authenticated Data (AD) flag in results, Exim
can now detect this. Exim does not perform validation itself, instead
relying upon a trusted path to the resolver.
- Current status: work-in-progress; $sender_host_dnssec variable added.
+ For inbound mails, if there is reverse DNS for the sender IP, then the
+ new $sender_host_dnssec variable will be set true.
+
+ For outbound mails, a dnslookup or manualroute Router can set the
+ need_dnssec option, to cause resolution to fail if the AD flag is not set
+ in results. Setting this option without setting dns_dnssec_ok is likely
+ a poor choice, as on most DNS resolver implementations AD can only be set
+ if DO is set in the query.
+
+ The smtp Transport also gains a need_dnssec option, used when it needs to
+ map names to IPs.
+
+ need_dnssec is always expanded.
+
+ The @mx* family of address-lists have gained an /dnssec option; if both
+ this and /ignore are present, then /dnssec must come first (as /ignore=
+ swallows the rest of that parameter as an address-list).
5. DSCP support for outbound connections: on a transport using the smtp driver,
set "dscp = ef", for instance, to cause the connections to have the relevant
diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt
index fa692bfb1..c3a9352a1 100644
--- a/doc/doc-txt/OptionLists.txt
+++ b/doc/doc-txt/OptionLists.txt
@@ -180,8 +180,8 @@ dns_qualify_single boolean true smtp
dns_retrans time 0s main 1.60
dns_retry integer 0 main 1.60
dns_search_parents boolean false smtp
-dns_use_dnssec integer -1 main 4.82
-dns_use_edns0 integer -1 main 4.76
+dns_dnssec_ok boolean (unset) main 4.82 default set by platform resolver
+dns_use_edns0 boolean (unset) main 4.76 default set by platform resolver
domains domain list unset routers 4.00
driver string unset authenticators
unset routers 4.00
@@ -370,6 +370,9 @@ multi_domain boolean true smtp
mx_domains domain list unset dnslookup 4.00
mx_fail_domains domain list unset dnslookup 4.43
mysql_servers string list unset main 3.03
+need_dnssec boolean* false dnslookup 4.82
+ manualroute 4.82
+ smtp 4.82
never_users string list unset main
notify_comsat boolean false appendfile
once string* unset autoreply
diff --git a/src/src/exim.c b/src/src/exim.c
index e66a9664d..9af8cab5b 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -789,6 +789,11 @@ fprintf(f, "Support for:");
fprintf(f, " OpenSSL");
#endif
#endif
+#ifndef DISABLE_DNSSEC
+# ifdef RES_USE_DNSSEC
+ fprintf(f, " DNSSEC");
+# endif
+#endif
#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
fprintf(f, " translate_ip_address");
#endif
diff --git a/src/src/functions.h b/src/src/functions.h
index 604dd4a6a..90f0f9aea 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -154,7 +154,7 @@ extern void host_build_log_info(void);
extern void host_build_sender_fullhost(void);
extern BOOL host_find_byname(host_item *, uschar *, int, uschar **, BOOL);
extern int host_find_bydns(host_item *, uschar *, int, uschar *, uschar *,
- uschar *,uschar **, BOOL *);
+ uschar *,uschar **, BOOL *, BOOL);
extern ip_address_item *host_find_interfaces(void);
extern BOOL host_is_in_net(uschar *, uschar *, int);
extern BOOL host_is_tls_on_connect_port(int);
diff --git a/src/src/host.c b/src/src/host.c
index 785eea412..406107c33 100644
--- a/src/src/host.c
+++ b/src/src/host.c
@@ -2192,6 +2192,7 @@ Arguments:
extended because multihomed)
ignore_target_hosts list of hosts to ignore
allow_ip if TRUE, recognize an IP address and return it
+ need_dnssec if TRUE, DNSSEC required
fully_qualified_name if not NULL, return fully qualified name here if
the contents are different (i.e. it must be preset
to something)
@@ -2204,7 +2205,8 @@ Returns: HOST_FIND_FAILED couldn't find A record
static int
set_address_from_dns(host_item *host, host_item **lastptr,
- uschar *ignore_target_hosts, BOOL allow_ip, uschar **fully_qualified_name)
+ uschar *ignore_target_hosts, BOOL allow_ip, BOOL need_dnssec,
+ uschar **fully_qualified_name)
{
dns_record *rr;
host_item *thishostlast = NULL; /* Indicates not yet filled in anything */
@@ -2266,6 +2268,13 @@ for (; i >= 0; i--)
int rc = dns_lookup(&dnsa, host->name, type, fully_qualified_name);
+ if (need_dnssec && rc != DNS_NODATA && !dns_is_secure(&dnsa))
+ {
+ DEBUG(D_host_lookup)
+ debug_printf("DNSSEC required for \"%s\" but AD missing\n", host->name);
+ return HOST_FIND_AGAIN;
+ }
+
/* We want to return HOST_FIND_AGAIN if one of the A, A6, or AAAA lookups
fails or times out, but not if another one succeeds. (In the early
IPv6 days there are name servers that always fail on AAAA, but are happy
@@ -2435,6 +2444,7 @@ Arguments:
mx_fail_domains DNS errors for these domains => assume nonexist
fully_qualified_name if not NULL, return fully-qualified name
removed set TRUE if local host was removed from the list
+ need_dnssec set TRUE if should fail without DNSSEC
Returns: HOST_FIND_FAILED Failed to find the host or domain;
if there was a syntax error,
@@ -2450,7 +2460,7 @@ Returns: HOST_FIND_FAILED Failed to find the host or domain;
int
host_find_bydns(host_item *host, uschar *ignore_target_hosts, int whichrrs,
uschar *srv_service, uschar *srv_fail_domains, uschar *mx_fail_domains,
- uschar **fully_qualified_name, BOOL *removed)
+ uschar **fully_qualified_name, BOOL *removed, BOOL need_dnssec)
{
host_item *h, *last;
dns_record *rr;
@@ -2491,6 +2501,14 @@ if ((whichrrs & HOST_FIND_BY_SRV) != 0)
if (temp_fully_qualified_name != buffer && fully_qualified_name != NULL)
*fully_qualified_name = temp_fully_qualified_name + prefix_length;
+ /* See if we're allowed to continue */
+ if (need_dnssec && !dns_is_secure(&dnsa))
+ {
+ DEBUG(D_host_lookup)
+ debug_printf("SRV lookup for \"%s\" not AD but AD required\n", buffer);
+ return HOST_FIND_AGAIN;
+ }
+
/* On DNS failures, we give the "try again" error unless the domain is
listed as one for which we continue. */
@@ -2517,6 +2535,12 @@ if (rc != DNS_SUCCEED && (whichrrs & HOST_FIND_BY_MX) != 0)
{
ind_type = T_MX;
rc = dns_lookup(&dnsa, host->name, ind_type, fully_qualified_name);
+ if (need_dnssec && !dns_is_secure(&dnsa))
+ {
+ DEBUG(D_host_lookup)
+ debug_printf("MX lookup for \"%s\" not AD but AD required\n", host->name);
+ return HOST_FIND_AGAIN;
+ }
if (rc == DNS_NOMATCH) return HOST_FIND_FAILED;
if (rc == DNS_FAIL || rc == DNS_AGAIN)
{
@@ -2546,7 +2570,7 @@ if (rc != DNS_SUCCEED)
host->mx = MX_NONE;
host->port = PORT_NONE;
rc = set_address_from_dns(host, &last, ignore_target_hosts, FALSE,
- fully_qualified_name);
+ need_dnssec, fully_qualified_name);
/* If one or more address records have been found, check that none of them
are local. Since we know the host items all have their IP addresses
@@ -2872,7 +2896,8 @@ dns_init(FALSE, FALSE); /* Disable qualify_single and search_parents */
for (h = host; h != last->next; h = h->next)
{
if (h->address != NULL) continue; /* Inserted by a multihomed host */
- rc = set_address_from_dns(h, &last, ignore_target_hosts, allow_mx_to_ip, NULL);
+ rc = set_address_from_dns(h, &last, ignore_target_hosts,
+ allow_mx_to_ip, need_dnssec, NULL);
if (rc != HOST_FOUND)
{
h->status = hstatus_unusable;
@@ -3002,6 +3027,7 @@ int whichrrs = HOST_FIND_BY_MX | HOST_FIND_BY_A;
BOOL byname = FALSE;
BOOL qualify_single = TRUE;
BOOL search_parents = FALSE;
+BOOL need_dnssec = FALSE;
uschar **argv = USS cargv;
uschar buffer[256];
@@ -3019,6 +3045,15 @@ debug_selector = D_host_lookup | D_dns;
if (argc > 1) primary_hostname = argv[1];
+#define BOOLSETVERBOSE(Variable, NewValue) do { \
+ Variable = (NewValue); \
+ printf("%s set %s\n", #Variable , (Variable) ? "true" : "false"); \
+ } while (0)
+#define BOOLTOGGLERESOPT(Field) do { \
+ _res.options ^= Field; \
+ printf("Set resolver option %s to %s\n", #Field , (_res.options & Field) ? "true" : "false"); \
+ } while (0)
+
/* So that debug level changes can be done first */
dns_init(qualify_single, search_parents);
@@ -3036,8 +3071,16 @@ while (Ufgets(buffer, 256, stdin) != NULL)
if (Ustrcmp(buffer, "q") == 0) break;
- if (Ustrcmp(buffer, "byname") == 0) byname = TRUE;
- else if (Ustrcmp(buffer, "no_byname") == 0) byname = FALSE;
+ if ((Ustrcmp(buffer, "help") == 0) || (Ustrcmp(buffer, "?") == 0))
+ {
+ printf(": (no_){byname,qualify_single,search_parents,need_dnssec}\n");
+ printf(": a_only mx_only srv_only srv+a srv+mx srv+mx+a\n");
+ printf("toggles: test_harness ipv6 edns0 dnssec_ok res_debug\n");
+ printf("numeric args: retrans retry\n");
+ printf("to progress to next type of lookup: q\n");
+ }
+ else if (Ustrcmp(buffer, "byname") == 0) BOOLSETVERBOSE(byname, TRUE);
+ else if (Ustrcmp(buffer, "no_byname") == 0) BOOLSETVERBOSE(byname, FALSE);
else if (Ustrcmp(buffer, "a_only") == 0) whichrrs = HOST_FIND_BY_A;
else if (Ustrcmp(buffer, "mx_only") == 0) whichrrs = HOST_FIND_BY_MX;
else if (Ustrcmp(buffer, "srv_only") == 0) whichrrs = HOST_FIND_BY_SRV;
@@ -3047,17 +3090,22 @@ while (Ufgets(buffer, 256, stdin) != NULL)
whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_MX;
else if (Ustrcmp(buffer, "srv+mx+a") == 0)
whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_MX | HOST_FIND_BY_A;
- else if (Ustrcmp(buffer, "qualify_single") == 0) qualify_single = TRUE;
- else if (Ustrcmp(buffer, "no_qualify_single") == 0) qualify_single = FALSE;
- else if (Ustrcmp(buffer, "search_parents") == 0) search_parents = TRUE;
- else if (Ustrcmp(buffer, "no_search_parents") == 0) search_parents = FALSE;
+ else if (Ustrcmp(buffer, "qualify_single") == 0) BOOLSETVERBOSE(qualify_single, TRUE);
+ else if (Ustrcmp(buffer, "no_qualify_single") == 0) BOOLSETVERBOSE(qualify_single, FALSE);
+ else if (Ustrcmp(buffer, "search_parents") == 0) BOOLSETVERBOSE(search_parents, TRUE);
+ else if (Ustrcmp(buffer, "no_search_parents") == 0) BOOLSETVERBOSE(search_parents, FALSE);
else if (Ustrcmp(buffer, "test_harness") == 0)
- running_in_test_harness = !running_in_test_harness;
- else if (Ustrcmp(buffer, "ipv6") == 0) disable_ipv6 = !disable_ipv6;
- else if (Ustrcmp(buffer, "res_debug") == 0)
- {
- _res.options ^= RES_DEBUG;
- }
+ BOOLSETVERBOSE(running_in_test_harness, !running_in_test_harness);
+ else if (Ustrcmp(buffer, "ipv6") == 0) BOOLSETVERBOSE(disable_ipv6, !disable_ipv6);
+ else if (Ustrcmp(buffer, "need_dnssec") == 0) BOOLSETVERBOSE(need_dnssec, TRUE);
+ else if (Ustrcmp(buffer, "no_need_dnssec") == 0) BOOLSETVERBOSE(need_dnssec, FALSE);
+#ifdef RES_USE_EDNS0
+ else if (Ustrcmp(buffer, "edns0") == 0) BOOLTOGGLERESOPT(RES_USE_EDNS0);
+#endif
+#ifdef RES_USE_DNSSEC
+ else if (Ustrcmp(buffer, "dnssec_ok") == 0) BOOLTOGGLERESOPT(RES_USE_DNSSEC);
+#endif
+ else if (Ustrcmp(buffer, "res_debug") == 0) BOOLTOGGLERESOPT(RES_DEBUG);
else if (Ustrncmp(buffer, "retrans", 7) == 0)
{
(void)sscanf(CS(buffer+8), "%d", &dns_retrans);
@@ -3087,7 +3135,7 @@ while (Ufgets(buffer, 256, stdin) != NULL)
host_find_byname(&h, NULL, flags, &fully_qualified_name, TRUE)
:
host_find_bydns(&h, NULL, flags, US"smtp", NULL, NULL,
- &fully_qualified_name, NULL);
+ &fully_qualified_name, NULL, need_dnssec);
if (rc == HOST_FIND_FAILED) printf("Failed\n");
else if (rc == HOST_FIND_AGAIN) printf("Again\n");
diff --git a/src/src/macros.h b/src/src/macros.h
index b878b415c..8de445e3a 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -608,7 +608,7 @@ those defined here start from 32. The boolean ones must all be together so they
can be easily tested as a group. That is the only use of opt_bool_last. */
enum { opt_bit = 32, opt_bool_verify, opt_bool_set, opt_expand_bool,
- opt_bool_last,
+ opt_bool_tern, opt_bool_last,
opt_rewrite, opt_timelist, opt_uid, opt_gid, opt_uidlist, opt_gidlist,
opt_expand_uid, opt_expand_gid, opt_void };
diff --git a/src/src/match.c b/src/src/match.c
index 66ae3dddb..281f8ddee 100644
--- a/src/src/match.c
+++ b/src/src/match.c
@@ -192,6 +192,7 @@ if (cb->at_is_special && pattern[0] == '@')
BOOL prim = FALSE;
BOOL secy = FALSE;
BOOL removed = FALSE;
+ BOOL need_dnssec = FALSE;
uschar *ss = pattern + 4;
uschar *ignore_target_hosts = NULL;
@@ -208,6 +209,11 @@ if (cb->at_is_special && pattern[0] == '@')
}
else goto NOT_AT_SPECIAL;
+ if (strncmpic(ss, US"/dnssec", 7) == 0)
+ {
+ ss += 7;
+ need_dnssec = TRUE;
+ }
if (strncmpic(ss, US"/ignore=", 8) == 0) ignore_target_hosts = ss + 8;
else if (*ss != 0) goto NOT_AT_SPECIAL;
@@ -222,7 +228,8 @@ if (cb->at_is_special && pattern[0] == '@')
NULL, /* srv_fail_domains not relevant */
NULL, /* mx_fail_domains not relevant */
NULL, /* no feedback FQDN */
- &removed); /* feedback if local removed */
+ &removed, /* feedback if local removed */
+ need_dnssec);
if (rc == HOST_FIND_AGAIN)
{
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 77836d157..b7edeb7ec 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -219,8 +219,8 @@ static optionlist optionlist_config[] = {
{ "dns_ipv4_lookup", opt_stringptr, &dns_ipv4_lookup },
{ "dns_retrans", opt_time, &dns_retrans },
{ "dns_retry", opt_int, &dns_retry },
- { "dns_dnssec_ok", opt_int, &dns_dnssec_ok },
- { "dns_use_edns0", opt_int, &dns_use_edns0 },
+ { "dns_dnssec_ok", opt_bool_tern, &dns_dnssec_ok },
+ { "dns_use_edns0", opt_bool_tern, &dns_use_edns0 },
/* This option is now a no-op, retained for compability */
{ "drop_cr", opt_bool, &drop_cr },
/*********************************************************/
@@ -1465,8 +1465,8 @@ if (type < opt_bool || type > opt_bool_last)
}
/* If a boolean wasn't preceded by "no[t]_" it can be followed by = and
-true/false/yes/no, or, in the case of opt_expanded_bool, a general string that
-ultimately expands to one of those values. */
+true/false/yes/no/1/0, or, in the case of opt_expanded_bool, a general string
+that ultimately expands to one of those values. */
else if (*s != 0 && (offset != 0 || *s != '='))
extra_chars_error(s, US"boolean option ", name, US"");
@@ -1827,20 +1827,48 @@ switch (type)
/* Fall through */
/* Boolean: if no characters follow, the value is boolvalue. Otherwise
- look for yes/not/true/false. Some booleans are stored in a single bit in
+ look for yes/no/true/false/1/0. Some booleans are stored in a single bit in
a single int. There's a special fudge for verify settings; without a suffix
they set both xx_sender and xx_recipient. The table points to the sender
value; search subsequently for the recipient. There's another special case:
- opt_bool_set also notes when a boolean has been set. */
+ opt_bool_set also notes when a boolean has been set.
+
+ opt_bool_tern is guaranteed to be an int which can be < 0 when unset; for
+ backwards compatibility, it can be configured as an int. A mistake by Phil.
+ */
+
+ case opt_bool_tern:
+ n = 0;
+ if (*s != 0)
+ {
+ uschar *endptr;
+ long int lvalue;
+
+ errno = 0;
+ lvalue = strtol(CS s, CSS &endptr, intbase);
+ if ((endptr != s) && (errno == 0))
+ {
+ n = 1;
+ if (lvalue > 0)
+ boolvalue = lvalue ? TRUE : FALSE;
+ }
+ s = endptr;
+ }
+ /* Fall through */
case opt_bool:
case opt_bit:
case opt_bool_verify:
case opt_bool_set:
+ if (type != opt_bool_tern)
+ n = 0;
if (*s != 0)
{
- s = readconf_readname(name2, 64, s);
- if (strcmpic(name2, US"true") == 0 || strcmpic(name2, US"yes") == 0)
+ if (n == 0)
+ s = readconf_readname(name2, 64, s);
+ if (n > 0)
+ /* handled as int (for ternary) */;
+ else if (strcmpic(name2, US"true") == 0 || strcmpic(name2, US"yes") == 0)
boolvalue = TRUE;
else if (strcmpic(name2, US"false") == 0 || strcmpic(name2, US"no") == 0)
boolvalue = FALSE;
diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c
index 057a2a15d..da7cd917f 100644
--- a/src/src/routers/dnslookup.c
+++ b/src/src/routers/dnslookup.c
@@ -14,6 +14,8 @@
/* Options specific to the dnslookup router. */
optionlist dnslookup_router_options[] = {
+ { "*expand_need_dnssec", opt_stringptr | opt_hidden,
+ (void *)(offsetof(dnslookup_router_options_block, expand_need_dnssec)) },
{ "check_secondary_mx", opt_bool,
(void *)(offsetof(dnslookup_router_options_block, check_secondary_mx)) },
{ "check_srv", opt_stringptr,
@@ -22,6 +24,8 @@ optionlist dnslookup_router_options[] = {
(void *)(offsetof(dnslookup_router_options_block, mx_domains)) },
{ "mx_fail_domains", opt_stringptr,
(void *)(offsetof(dnslookup_router_options_block, mx_fail_domains)) },
+ { "need_dnssec", opt_expand_bool,
+ (void *)(offsetof(dnslookup_router_options_block, need_dnssec)) },
{ "qualify_single", opt_bool,
(void *)(offsetof(dnslookup_router_options_block, qualify_single)) },
{ "rewrite_headers", opt_bool,
@@ -49,11 +53,13 @@ dnslookup_router_options_block dnslookup_router_option_defaults = {
TRUE, /* qualify_single */
FALSE, /* search_parents */
TRUE, /* rewrite_headers */
+ FALSE, /* need_dnssec */
NULL, /* widen_domains */
NULL, /* mx_domains */
NULL, /* mx_fail_domains */
NULL, /* srv_fail_domains */
- NULL /* check_srv */
+ NULL, /* check_srv */
+ NULL /* expand_need_dnssec */
};
@@ -153,6 +159,18 @@ DEBUG(D_route)
debug_printf("%s router called for %s\n domain = %s\n",
rblock->name, addr->address, addr->domain);
+/* Expand expandable options */
+if (ob->expand_need_dnssec)
+ ob->need_dnssec = expand_check_condition(ob->expand_need_dnssec,
+ US"need_dnssec in dnslookup router", rblock->name);
+
+/* It's conceivable that resolvers will permit setting the DO flag by default
+without an application needing to do it, so we can't outright call it an error.
+But without DO set, we won't get AD, so if Exim isn't asking for DO then we
+should at least complain loudly during a debug run. */
+DEBUG(D_any) if (ob->need_dnssec && dns_dnssec_ok < 0)
+ debug_printf("WARNING: need_dnssec true but dns_dnssec_ok not set in main configuration\n");
+
/* If an SRV check is required, expand the service name */
if (ob->check_srv != NULL)
@@ -261,7 +279,8 @@ for (;;)
}
rc = host_find_bydns(&h, rblock->ignore_target_hosts, flags, srv_service,
- ob->srv_fail_domains, ob->mx_fail_domains, &fully_qualified_name, &removed);
+ ob->srv_fail_domains, ob->mx_fail_domains, &fully_qualified_name, &removed,
+ ob->need_dnssec);
if (removed) setflag(addr, af_local_host_removed);
/* If host found with only address records, test for the domain's being in
diff --git a/src/src/routers/dnslookup.h b/src/src/routers/dnslookup.h
index b0c384367..0c79147ff 100644
--- a/src/src/routers/dnslookup.h
+++ b/src/src/routers/dnslookup.h
@@ -12,11 +12,13 @@ typedef struct {
BOOL qualify_single;
BOOL search_parents;
BOOL rewrite_headers;
+ BOOL need_dnssec;
uschar *widen_domains;
uschar *mx_domains;
uschar *mx_fail_domains;
uschar *srv_fail_domains;
uschar *check_srv;
+ uschar *expand_need_dnssec;
} dnslookup_router_options_block;
/* Data for reading the private options. */
diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c
index cb047e2ca..4478b881a 100644
--- a/src/src/routers/manualroute.c
+++ b/src/src/routers/manualroute.c
@@ -14,12 +14,16 @@
/* Options specific to the manualroute router. */
optionlist manualroute_router_options[] = {
+ { "*expand_need_dnssec", opt_stringptr | opt_hidden,
+ (void *)(offsetof(manualroute_router_options_block, expand_need_dnssec)) },
{ "host_all_ignored", opt_stringptr,
(void *)(offsetof(manualroute_router_options_block, host_all_ignored)) },
{ "host_find_failed", opt_stringptr,
(void *)(offsetof(manualroute_router_options_block, host_find_failed)) },
{ "hosts_randomize", opt_bool,
(void *)(offsetof(manualroute_router_options_block, hosts_randomize)) },
+ { "need_dnssec", opt_expand_bool,
+ (void *)(offsetof(manualroute_router_options_block, need_dnssec)) },
{ "route_data", opt_stringptr,
(void *)(offsetof(manualroute_router_options_block, route_data)) },
{ "route_list", opt_stringptr,
@@ -40,10 +44,12 @@ manualroute_router_options_block manualroute_router_option_defaults = {
-1, /* host_all_ignored code (unset) */
-1, /* host_find_failed code (unset) */
FALSE, /* hosts_randomize */
+ FALSE, /* need_dnssec */
US"defer", /* host_all_ignored */
US"freeze", /* host_find_failed */
NULL, /* route_data */
- NULL /* route_list */
+ NULL, /* route_list */
+ NULL /* expand_need_dnssec */
};
@@ -111,6 +117,18 @@ if ((ob->route_list == NULL && ob->route_data == NULL) ||
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
"route_list or route_data (but not both) must be specified",
rblock->name);
+
+/* Expand expandable options */
+if (ob->expand_need_dnssec)
+ ob->need_dnssec = expand_check_condition(ob->expand_need_dnssec,
+ US"need_dnssec in manualroute router", rblock->name);
+
+/* It's conceivable that resolvers will permit setting the DO flag by default
+without an application needing to do it, so we can't outright call it an error.
+But without DO set, we won't get AD, so if Exim isn't asking for DO then we
+should at least complain loudly during a debug run. */
+DEBUG(D_any) if (ob->need_dnssec && dns_dnssec_ok < 0)
+ debug_printf("WARNING: need_dnssec true but dns_dnssec_ok not set in main configuration\n");
}
@@ -425,7 +443,7 @@ for the list of configured hosts, and then finding their addresses. */
host_build_hostlist(&(addr->host_list), hostlist, randomize);
rc = rf_lookup_hostlist(rblock, addr, rblock->ignore_target_hosts, lookup_type,
- ob->hff_code, addr_new);
+ ob->hff_code, addr_new, ob->need_dnssec);
if (rc != OK) return rc;
/* If host_find_failed is set to "ignore", it is possible for all the hosts to
diff --git a/src/src/routers/manualroute.h b/src/src/routers/manualroute.h
index 9c20b6fa0..0dfa0d3f1 100644
--- a/src/src/routers/manualroute.h
+++ b/src/src/routers/manualroute.h
@@ -13,10 +13,12 @@ typedef struct {
int hai_code;
int hff_code;
BOOL hosts_randomize;
+ BOOL need_dnssec;
uschar *host_all_ignored;
uschar *host_find_failed;
uschar *route_data;
uschar *route_list;
+ uschar *expand_need_dnssec;
} manualroute_router_options_block;
/* Data for reading the private options. */
diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c
index 11e1fdc34..9ad1e6b11 100644
--- a/src/src/routers/queryprogram.c
+++ b/src/src/routers/queryprogram.c
@@ -519,7 +519,7 @@ if (*s != 0)
host_build_hostlist(&(addr->host_list), s, FALSE); /* pro tem no randomize */
rc = rf_lookup_hostlist(rblock, addr, rblock->ignore_target_hosts,
- lookup_type, hff_defer, addr_new);
+ lookup_type, hff_defer, addr_new, FALSE /* no DNSSEC support */);
if (rc != OK) return rc;
}
lookup_value = NULL;
diff --git a/src/src/routers/rf_functions.h b/src/src/routers/rf_functions.h
index 29f37cf5d..6799271f7 100644
--- a/src/src/routers/rf_functions.h
+++ b/src/src/routers/rf_functions.h
@@ -21,7 +21,7 @@ extern BOOL rf_get_transport(uschar *, transport_instance **, address_item *,
uschar *, uschar *);
extern BOOL rf_get_ugid(router_instance *, address_item *, ugid_block *);
extern int rf_lookup_hostlist(router_instance *, address_item *, uschar *,
- int, int, address_item **);
+ int, int, address_item **, BOOL);
extern BOOL rf_queue_add(address_item *, address_item **, address_item **,
router_instance *, struct passwd *);
extern int rf_self_action(address_item *, host_item *, int, BOOL, uschar *,
diff --git a/src/src/routers/rf_lookup_hostlist.c b/src/src/routers/rf_lookup_hostlist.c
index eadcd5df7..005a4ec50 100644
--- a/src/src/routers/rf_lookup_hostlist.c
+++ b/src/src/routers/rf_lookup_hostlist.c
@@ -38,6 +38,7 @@ Arguments:
lookup_type lk_default or lk_byname or lk_bydns
hff_code what to do for host find failed
addr_new passed to rf_self_action for self=reroute
+ need_dnssec whether or not to require DNSSEC
Returns: OK
DEFER host lookup defer
@@ -49,7 +50,7 @@ Returns: OK
int
rf_lookup_hostlist(router_instance *rblock, address_item *addr,
uschar *ignore_target_hosts, int lookup_type, int hff_code,
- address_item **addr_new)
+ address_item **addr_new, BOOL need_dnssec)
{
BOOL self_send = FALSE;
host_item *h, *next_h, *prev;
@@ -95,7 +96,8 @@ for (h = addr->host_list; h != NULL; h = next_h)
NULL, /* failing srv domains not relevant */
NULL, /* no special mx failing domains */
NULL, /* fully_qualified_name */
- NULL); /* indicate local host removed */
+ NULL, /* indicate local host removed */
+ need_dnssec);
}
/* If explicitly configured to look up by name, or if the "host name" is
@@ -117,7 +119,7 @@ for (h = addr->host_list; h != NULL; h = next_h)
BOOL removed;
DEBUG(D_route|D_host_lookup) debug_printf("doing DNS lookup\n");
rc = host_find_bydns(h, ignore_target_hosts, HOST_FIND_BY_A, NULL, NULL,
- NULL, &canonical_name, &removed);
+ NULL, &canonical_name, &removed, need_dnssec);
if (rc == HOST_FOUND)
{
if (removed) setflag(addr, af_local_host_removed);
diff --git a/src/src/structs.h b/src/src/structs.h
index d11e91adb..7b5427aee 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -92,6 +92,7 @@ typedef struct transport_feedback {
BOOL gethostbyname;
BOOL qualify_single;
BOOL search_parents;
+ BOOL dnssec;
} transport_feedback;
/* Routers, transports, and authenticators have similar data blocks. Each
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index ee260a129..851f35d12 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -19,6 +19,8 @@ before the lower case letters). Some live in the transport_instance block so as
to be publicly visible; these are flagged with opt_public. */
optionlist smtp_transport_options[] = {
+ { "*expand_need_dnssec", opt_bool | opt_hidden,
+ (void *)offsetof(smtp_transport_options_block, expand_need_dnssec) },
{ "address_retry_include_sender", opt_bool,
(void *)offsetof(smtp_transport_options_block, address_retry_include_sender) },
{ "allow_localhost", opt_bool,
@@ -124,6 +126,8 @@ optionlist smtp_transport_options[] = {
(void *)offsetof(transport_instance, max_addresses) },
{ "multi_domain", opt_bool | opt_public,
(void *)offsetof(transport_instance, multi_domain) },
+ { "need_dnssec", opt_expand_bool,
+ (void *)offsetof(smtp_transport_options_block, need_dnssec) },
{ "port", opt_stringptr,
(void *)offsetof(smtp_transport_options_block, port) },
{ "protocol", opt_stringptr,
@@ -185,6 +189,7 @@ smtp_transport_options_block smtp_transport_option_defaults = {
NULL, /* hosts_avoid_pipelining */
NULL, /* hosts_avoid_esmtp */
NULL, /* hosts_nopass_tls */
+ NULL, /* expand_need_dnssec */
5*60, /* command_timeout */
5*60, /* connect_timeout; shorter system default overrides */
5*60, /* data timeout */
@@ -198,6 +203,7 @@ smtp_transport_options_block smtp_transport_option_defaults = {
FALSE, /* gethostbyname */
TRUE, /* dns_qualify_single */
FALSE, /* dns_search_parents */
+ FALSE, /* need_dnssec */
TRUE, /* delay_after_cutoff */
FALSE, /* hosts_override */
FALSE, /* hosts_randomize */
@@ -269,6 +275,11 @@ errmsg = errmsg; /* Keep picky compilers happy */
uid = uid;
gid = gid;
+/* expand the dnssec option if it contained a $ */
+if (ob->expand_need_dnssec)
+ ob->need_dnssec = expand_check_condition(ob->expand_need_dnssec,
+ US"'need_dnssec' in transport", tblock->name);
+
/* Pass back options if required. This interface is getting very messy. */
if (tf != NULL)
@@ -283,6 +294,7 @@ if (tf != NULL)
tf->qualify_single = ob->dns_qualify_single;
tf->search_parents = ob->dns_search_parents;
tf->helo_data = ob->helo_data;
+ tf->dnssec = ob->need_dnssec;
}
/* Set the fallback host list for all the addresses that don't have fallback
@@ -2663,10 +2675,26 @@ for (cutoff_retry = 0; expired &&
if (ob->dns_search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
if (ob->gethostbyname || string_is_ip_address(host->name, NULL) != 0)
+ {
+#ifndef DISABLE_DNSSEC
+ if (ob->need_dnssec)
+ {
+ DEBUG(D_transport)
+ debug_printf("dnssec required but configured to use gethostbyname(), deferring\n");
+ rc = HOST_FIND_FAILED;
+ }
+ else
+#endif
rc = host_find_byname(host, NULL, flags, &canonical_name, TRUE);
+ }
else
+ {
rc = host_find_bydns(host, NULL, flags, NULL, NULL, NULL,
- &canonical_name, NULL);
+ &canonical_name, NULL, ob->need_dnssec);
+ /* security: unless built with DISABLE_DNSSEC, that will have failed
+ to resolve if AD was not set in the response; in effect, need_dnssec in
+ Router options means any unsigned data disappears from DNS. */
+ }
/* Update the host (and any additional blocks, resulting from
multihoming) with a host-specific port, if any. */
diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h
index ef53292bc..33e49e2e1 100644
--- a/src/src/transports/smtp.h
+++ b/src/src/transports/smtp.h
@@ -30,6 +30,7 @@ typedef struct {
uschar *hosts_avoid_pipelining;
uschar *hosts_avoid_esmtp;
uschar *hosts_nopass_tls;
+ uschar *expand_need_dnssec;
int command_timeout;
int connect_timeout;
int data_timeout;
@@ -43,6 +44,7 @@ typedef struct {
BOOL gethostbyname;
BOOL dns_qualify_single;
BOOL dns_search_parents;
+ BOOL need_dnssec;
BOOL delay_after_cutoff;
BOOL hosts_override;
BOOL hosts_randomize;
diff --git a/src/src/verify.c b/src/src/verify.c
index a1b8142a9..22cd9f40b 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -1645,7 +1645,8 @@ while (addr_new != NULL)
FALSE, /* hosts_randomize */
FALSE, /* gethostbyname */
TRUE, /* qualify_single */
- FALSE /* search_parents */
+ FALSE, /* search_parents */
+ FALSE /* dnssec */
};
/* If verification yielded a remote transport, we want to use that
@@ -1705,7 +1706,7 @@ while (addr_new != NULL)
(void)host_find_byname(host, NULL, flags, &canonical_name, TRUE);
else
(void)host_find_bydns(host, NULL, flags, NULL, NULL, NULL,
- &canonical_name, NULL);
+ &canonical_name, NULL, tf.dnssec);
}
}
}