From fd3b6a4ad699259b80dcaed6287ec01ab5ec0105 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Thu, 24 Apr 2014 00:49:56 +0100 Subject: [PATCH] dnssec_strict, _lax, _never modifiers for dnsdb lookups Lacking testsuite coverage --- doc/doc-docbook/spec.xfpt | 21 +++++++-- doc/doc-txt/ChangeLog | 3 ++ src/src/lookups/dnsdb.c | 92 +++++++++++++++++++++++++++++---------- 3 files changed, 91 insertions(+), 25 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 6f0a16f37..612d147a5 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -6959,11 +6959,16 @@ The data from each lookup is concatenated, with newline separators by default, in the same way that multiple DNS records for a single item are handled. A different separator can be specified, as described above. +Modifiers for &(dnsdb)& lookups are givien by optional keywords, +each followed by a comma, +that may appear before the record type. + The &(dnsdb)& lookup fails only if all the DNS lookups fail. If there is a temporary DNS error for any of them, the behaviour is controlled by -an optional keyword followed by a comma that may appear before the record -type. The possible keywords are &"defer_strict"&, &"defer_never"&, and -&"defer_lax"&. With &"strict"& behaviour, any temporary DNS error causes the +a defer-option modifier. +The possible keywords are +&"defer_strict"&, &"defer_never"&, and &"defer_lax"&. +With &"strict"& behaviour, any temporary DNS error causes the whole lookup to defer. With &"never"& behaviour, a temporary DNS error is ignored, and the behaviour is as if the DNS lookup failed to find anything. With &"lax"& behaviour, all the queries are attempted, but a temporary DNS @@ -6976,6 +6981,16 @@ ${lookup dnsdb{a=one.host.com:two.host.com}} Thus, in the default case, as long as at least one of the DNS lookups yields some data, the lookup succeeds. +Use of &(DNSSEC)& is controlled by a dnssec modifier. +The possible keywords are +&"dnssec_strict"&, &"dnssec_lax"&, and &"dnssec_never"&. +With &"strict"& or &"lax"& DNSSEC information is requested +with the lookup. +With &"strict"& a response from the DNS resolver that +is not labelled as authenticated data +is treated as equivalent to a temporary DNS error. +The default is &"never". + diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 30b27a012..649b730f0 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -91,6 +91,9 @@ TL/08 Bugzilla 1453: New LDAP "SERVERS=" option allows admin to override list of ldap servers used for a specific lookup. Patch provided by Heiko Schlichting. +JH/18 New options dnssec_lax, dnssec_strict on dnsdb lookups. + + Exim version 4.82 ----------------- diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index a1eb2b658..b7e50588b 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -114,11 +114,15 @@ any defer causes the whole lookup to defer; 'lax', where a defer causes the whole lookup to defer only if none of the DNS queries succeeds; and 'never', where all defers are as if the lookup failed. The default is 'lax'. -(d) If the next sequence of characters is a sequence of letters and digits +(d) Another optional comma-sep field: 'dnssec_FOO', with 'strict', 'lax' +and 'never' (default); can appear before or after (c). The meanings are +require, try and don't-try dnssec respectively. + +(e) If the next sequence of characters is a sequence of letters and digits followed by '=', it is interpreted as the name of the DNS record type. The default is "TXT". -(e) Then there follows list of domain names. This is a generalized Exim list, +(f) Then there follows list of domain names. This is a generalized Exim list, which may start with '<' in order to set a specific separator. The default separator, as always, is colon. */ @@ -131,6 +135,7 @@ int size = 256; int ptr = 0; int sep = 0; int defer_mode = PASS; +int dnssec_mode = OK; int type; int failrc = FAIL; uschar *outsep = US"\n"; @@ -173,35 +178,64 @@ if (*keystring == '>') while (isspace(*keystring)) keystring++; } -/* Check for a defer behaviour keyword. */ +/* Check for a modifier keyword. */ -if (strncmpic(keystring, US"defer_", 6) == 0) +while ( strncmpic(keystring, US"defer_", 6) == 0 + || strncmpic(keystring, US"dnssec_", 7) == 0 + ) { - keystring += 6; - if (strncmpic(keystring, US"strict", 6) == 0) + if (strncmpic(keystring, US"defer_", 6) == 0) { - defer_mode = DEFER; keystring += 6; - } - else if (strncmpic(keystring, US"lax", 3) == 0) - { - defer_mode = PASS; - keystring += 3; - } - else if (strncmpic(keystring, US"never", 5) == 0) - { - defer_mode = OK; - keystring += 5; + if (strncmpic(keystring, US"strict", 6) == 0) + { + defer_mode = DEFER; + keystring += 6; + } + else if (strncmpic(keystring, US"lax", 3) == 0) + { + defer_mode = PASS; + keystring += 3; + } + else if (strncmpic(keystring, US"never", 5) == 0) + { + defer_mode = OK; + keystring += 5; + } + else + { + *errmsg = US"unsupported dnsdb defer behaviour"; + return DEFER; + } } else { - *errmsg = US"unsupported dnsdb defer behaviour"; - return DEFER; + keystring += 7; + if (strncmpic(keystring, US"strict", 6) == 0) + { + dnssec_mode = DEFER; + keystring += 6; + } + else if (strncmpic(keystring, US"lax", 3) == 0) + { + dnssec_mode = PASS; + keystring += 3; + } + else if (strncmpic(keystring, US"never", 5) == 0) + { + dnssec_mode = OK; + keystring += 5; + } + else + { + *errmsg = US"unsupported dnsdb dnssec behaviour"; + return DEFER; + } } while (isspace(*keystring)) keystring++; if (*keystring++ != ',') { - *errmsg = US"dnsdb defer behaviour syntax error"; + *errmsg = US"dnsdb modifier syntax error"; return DEFER; } while (isspace(*keystring)) keystring++; @@ -241,7 +275,7 @@ if ((equals = Ustrchr(keystring, '=')) != NULL) /* Initialize the resolver in case this is the first time it has been used. */ -dns_init(FALSE, FALSE, FALSE); /*XXX dnssec? */ +dns_init(FALSE, FALSE, dnssec_mode != OK); /* The remainder of the string must be a list of domains. As long as the lookup for at least one of them succeeds, we return success. Failure means that none @@ -323,10 +357,20 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer))) if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue; if (rc != DNS_SUCCEED) { - if (defer_mode == DEFER) return DEFER; /* always defer */ + if (defer_mode == DEFER) + { + dns_init(FALSE, FALSE, FALSE); + return DEFER; /* always defer */ + } if (defer_mode == PASS) failrc = DEFER; /* defer only if all do */ continue; /* treat defer as fail */ } + if (dnssec_mode == DEFER && !dns_is_secure(&dnsa)) + { + failrc = DEFER; + continue; + } + /* Search the returned records */ @@ -494,6 +538,8 @@ store_reset(yield + ptr + 1); /* If ptr == 0 we have not found anything. Otherwise, insert the terminating zero and return the result. */ +dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ + if (ptr == 0) return failrc; yield[ptr] = 0; *result = yield; @@ -538,4 +584,6 @@ static lookup_info _lookup_info = { static lookup_info *_lookup_list[] = { &_lookup_info }; lookup_module_info dnsdb_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 }; +/* vi: aw ai sw=2 +*/ /* End of lookups/dnsdb.c */ -- 2.30.2