X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/3a7963704c5192e25046b1a2f808d4b8ed357386..9d9c374678ae4b04869c90bc5980acfcfb68c336:/src/src/lookups/dnsdb.c diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index ec1cd159a..5c077fb31 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2012 */ +/* Copyright (c) University of Cambridge 1995 - 2014 */ /* See the file NOTICE for conditions of use and distribution. */ #include "../exim.h" @@ -22,6 +22,11 @@ header files. */ #define T_SPF 99 #endif +/* New TLSA record for DANE */ +#ifndef T_TLSA +#define T_TLSA 52 +#endif + /* Table of recognized DNS record types and their integer values. */ static const char *type_names[] = { @@ -41,6 +46,7 @@ static const char *type_names[] = { "ptr", "spf", "srv", + "tlsa", "txt", "zns" }; @@ -62,6 +68,7 @@ static int type_values[] = { T_PTR, T_SPF, T_SRV, + T_TLSA, T_TXT, T_ZNS /* Private type for "zone nameservers" */ }; @@ -107,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. */ @@ -124,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"; @@ -166,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++; @@ -234,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); +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 @@ -296,28 +337,43 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer))) the final "nothing found" result, but carry on to the next domain. */ found = domain; +#if HAVE_IPV6 if (type == T_APL) /* NB cannot happen unless HAVE_IPV6 */ { -#if HAVE_IPV6 && defined(SUPPORT_A6) - if (searchtype == T_APL) searchtype = T_A6; -#endif -#if HAVE_IPV6 && !defined(SUPPORT_A6) - if (searchtype == T_APL) searchtype = T_AAAA; -#endif + if (searchtype == T_APL) +# if defined(SUPPORT_A6) + searchtype = T_A6; +# else + searchtype = T_AAAA; +# endif else if (searchtype == T_A6) searchtype = T_AAAA; else if (searchtype == T_AAAA) searchtype = T_A; rc = dns_special_lookup(&dnsa, domain, searchtype, &found); } else +#endif rc = dns_special_lookup(&dnsa, domain, type, &found); + lookup_dnssec_authenticated = dnssec_mode==OK ? NULL + : dns_is_secure(&dnsa) ? US"yes" : US"no"; + 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); /* clr dnssec bit */ + 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 */ @@ -376,6 +432,29 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer))) } } } + else if (type == T_TLSA) + { + uint8_t usage, selector, matching_type; + uint16_t i, payload_length; + uschar s[MAX_TLSA_EXPANDED_SIZE]; + uschar * sp = s; + uschar *p = (uschar *)(rr->data); + + usage = *p++; + selector = *p++; + matching_type = *p++; + /* What's left after removing the first 3 bytes above */ + payload_length = rr->size - 3; + sp += sprintf(CS s, "%d %d %d ", usage, selector, matching_type); + /* Now append the cert/identifier, one hex char at a time */ + for (i=0; + i < payload_length && sp-s < (MAX_TLSA_EXPANDED_SIZE - 4); + i++) + { + sp += sprintf(CS sp, "%02x", (unsigned char)p[i]); + } + yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + } else /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SRV */ { int priority, weight, port; @@ -462,6 +541,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; @@ -506,4 +587,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 */