X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/c4ceed07f17f67af7d96e7fd27c92eb374e62e19..bc338899110ea22098559081f77cbd0f7a8044bd:/src/src/lookups/dnsdb.c diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index 3fd9f981b..a8eab2e47 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -27,6 +27,7 @@ header files. */ static const char *type_names[] = { "a", #if HAVE_IPV6 + "a+", "aaaa", #ifdef SUPPORT_A6 "a6", @@ -47,6 +48,7 @@ static const char *type_names[] = { static int type_values[] = { T_A, #if HAVE_IPV6 + T_APL, /* Private type for AAAA + A */ T_AAAA, #ifdef SUPPORT_A6 T_A6, @@ -96,7 +98,8 @@ separator is newline. character used for multiple items of text in "TXT" records. Alternatively, if the next character is ';' then these multiple items are concatenated with no separator. With neither of these options specified, only the first item -is output. +is output. Similarly for "SPF" records, but the default for joining multiple +items in one SPF record is the empty string, for direct concatenation. (c) If the next sequence of characters is 'defer_FOO' followed by a comma, the defer behaviour is set to FOO. The possible behaviours are: 'strict', where @@ -121,7 +124,7 @@ int size = 256; int ptr = 0; int sep = 0; int defer_mode = PASS; -int type = T_TXT; +int type; int failrc = FAIL; uschar *outsep = US"\n"; uschar *outsep2 = NULL; @@ -197,8 +200,10 @@ if (strncmpic(keystring, US"defer_", 6) == 0) while (isspace(*keystring)) keystring++; } -/* If the keystring contains an = this must be preceded by a valid type name. */ +/* Figure out the "type" value if it is not T_TXT. +If the keystring contains an = this must be preceded by a valid type name. */ +type = T_TXT; if ((equals = Ustrchr(keystring, '=')) != NULL) { int i, len; @@ -246,6 +251,14 @@ if (type == T_PTR && keystring[0] != '<' && string_is_ip_address(keystring, NULL) != 0) sep = -1; +/* SPF strings should be concatenated without a separator, thus make +it the default if not defined (see RFC 4408 section 3.1.3). +Multiple SPF records are forbidden (section 3.1.2) but are currently +not handled specially, thus they are concatenated with \n by default. */ + +if (type == T_SPF && outsep2 == NULL) + outsep2 = US""; + /* Now scan the list and do a lookup for each item */ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer))) @@ -269,157 +282,180 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer))) domain = rbuffer; } - DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", domain); - - /* Do the lookup and sort out the result. There are three special types that - are handled specially: T_CSA, T_ZNS and T_MXH. The former two are handled in - a special lookup function so that the facility could be used from other - parts of the Exim code. The latter affects only what happens later on in - this function, but for tidiness it is handled in a similar way. If the - lookup fails, continue with the next domain. In the case of DEFER, adjust - the final "nothing found" result, but carry on to the next domain. */ - - found = domain; - rc = dns_special_lookup(&dnsa, domain, type, &found); - - if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue; - if (rc != DNS_SUCCEED) + do { - if (defer_mode == DEFER) return DEFER; /* always defer */ - else if (defer_mode == PASS) failrc = DEFER; /* defer only if all do */ - continue; /* treat defer as fail */ - } - - /* Search the returned records */ + DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", domain); + + /* Do the lookup and sort out the result. There are four special types that + are handled specially: T_CSA, T_ZNS, T_APL and T_MXH. + The first two are handled in a special lookup function so that the facility + could be used from other parts of the Exim code. T_APL is handled by looping + over the types of A lookup. T_MXH affects only what happens later on in + this function, but for tidiness it is handled by the "special". If the + lookup fails, continue with the next domain. In the case of DEFER, adjust + 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 (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); - for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); - rr != NULL; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) - { - if (rr->type != searchtype) continue; + if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue; + if (rc != DNS_SUCCEED) + { + if (defer_mode == DEFER) return DEFER; /* always defer */ + if (defer_mode == PASS) failrc = DEFER; /* defer only if all do */ + continue; /* treat defer as fail */ + } - /* There may be several addresses from an A6 record. Put the configured - separator between them, just as for between several records. However, A6 - support is not normally configured these days. */ + /* Search the returned records */ - if (type == T_A || - #ifdef SUPPORT_A6 - type == T_A6 || - #endif - type == T_AAAA) + for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + rr != NULL; + rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) { - dns_address *da; - for (da = dns_address_from_rr(&dnsa, rr); da != NULL; da = da->next) + if (rr->type != searchtype) continue; + + /* There may be several addresses from an A6 record. Put the configured + separator between them, just as for between several records. However, A6 + support is not normally configured these days. */ + + if (type == T_A || + #ifdef SUPPORT_A6 + type == T_A6 || + #endif + type == T_AAAA || + type == T_APL) { - if (ptr != 0) yield = string_cat(yield, &size, &ptr, outsep, 1); - yield = string_cat(yield, &size, &ptr, da->address, - Ustrlen(da->address)); + dns_address *da; + for (da = dns_address_from_rr(&dnsa, rr); da != NULL; da = da->next) + { + if (ptr != 0) yield = string_cat(yield, &size, &ptr, outsep, 1); + yield = string_cat(yield, &size, &ptr, da->address, + Ustrlen(da->address)); + } + continue; } - continue; - } - /* Other kinds of record just have one piece of data each, but there may be - several of them, of course. */ + /* Other kinds of record just have one piece of data each, but there may be + several of them, of course. */ - if (ptr != 0) yield = string_cat(yield, &size, &ptr, outsep, 1); + if (ptr != 0) yield = string_cat(yield, &size, &ptr, outsep, 1); - if (type == T_TXT || type == T_SPF) - { - if (outsep2 == NULL) + if (type == T_TXT || type == T_SPF) { - /* output only the first item of data */ - yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1), - (rr->data)[0]); - } - else - { - /* output all items */ - int data_offset = 0; - while (data_offset < rr->size) + if (outsep2 == NULL) + { + /* output only the first item of data */ + yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1), + (rr->data)[0]); + } + else { - uschar chunk_len = (rr->data)[data_offset++]; - if (outsep2[0] != '\0' && data_offset != 1) - yield = string_cat(yield, &size, &ptr, outsep2, 1); - yield = string_cat(yield, &size, &ptr, + /* output all items */ + int data_offset = 0; + while (data_offset < rr->size) + { + uschar chunk_len = (rr->data)[data_offset++]; + if (outsep2[0] != '\0' && data_offset != 1) + yield = string_cat(yield, &size, &ptr, outsep2, 1); + yield = string_cat(yield, &size, &ptr, (uschar *)((rr->data)+data_offset), chunk_len); - data_offset += chunk_len; + data_offset += chunk_len; + } } } - } - else /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SRV */ - { - int priority, weight, port; - uschar s[264]; - uschar *p = (uschar *)(rr->data); - - if (type == T_MXH) - { - /* mxh ignores the priority number and includes only the hostnames */ - GETSHORT(priority, p); - } - else if (type == T_MX) - { - GETSHORT(priority, p); - sprintf(CS s, "%d ", priority); - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); - } - else if (type == T_SRV) + else /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SRV */ { - GETSHORT(priority, p); - GETSHORT(weight, p); - GETSHORT(port, p); - sprintf(CS s, "%d %d %d ", priority, weight, port); - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); - } - else if (type == T_CSA) - { - /* See acl_verify_csa() for more comments about CSA. */ - - GETSHORT(priority, p); - GETSHORT(weight, p); - GETSHORT(port, p); + int priority, weight, port; + uschar s[264]; + uschar *p = (uschar *)(rr->data); - if (priority != 1) continue; /* CSA version must be 1 */ - - /* If the CSA record we found is not the one we asked for, analyse - the subdomain assertions in the port field, else analyse the direct - authorization status in the weight field. */ - - if (found != domain) + if (type == T_MXH) { - if (port & 1) *s = 'X'; /* explicit authorization required */ - else *s = '?'; /* no subdomain assertions here */ + /* mxh ignores the priority number and includes only the hostnames */ + GETSHORT(priority, p); } - else + else if (type == T_MX) { - if (weight < 2) *s = 'N'; /* not authorized */ - else if (weight == 2) *s = 'Y'; /* authorized */ - else if (weight == 3) *s = '?'; /* unauthorizable */ - else continue; /* invalid */ + GETSHORT(priority, p); + sprintf(CS s, "%d ", priority); + yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + } + else if (type == T_SRV) + { + GETSHORT(priority, p); + GETSHORT(weight, p); + GETSHORT(port, p); + sprintf(CS s, "%d %d %d ", priority, weight, port); + yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + } + else if (type == T_CSA) + { + /* See acl_verify_csa() for more comments about CSA. */ + + GETSHORT(priority, p); + GETSHORT(weight, p); + GETSHORT(port, p); + + if (priority != 1) continue; /* CSA version must be 1 */ + + /* If the CSA record we found is not the one we asked for, analyse + the subdomain assertions in the port field, else analyse the direct + authorization status in the weight field. */ + + if (found != domain) + { + if (port & 1) *s = 'X'; /* explicit authorization required */ + else *s = '?'; /* no subdomain assertions here */ + } + else + { + if (weight < 2) *s = 'N'; /* not authorized */ + else if (weight == 2) *s = 'Y'; /* authorized */ + else if (weight == 3) *s = '?'; /* unauthorizable */ + else continue; /* invalid */ + } + + s[1] = ' '; + yield = string_cat(yield, &size, &ptr, s, 2); } - s[1] = ' '; - yield = string_cat(yield, &size, &ptr, s, 2); - } - - /* GETSHORT() has advanced the pointer to the target domain. */ + /* GETSHORT() has advanced the pointer to the target domain. */ - rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, - (DN_EXPAND_ARG4_TYPE)(s), sizeof(s)); + rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, + (DN_EXPAND_ARG4_TYPE)(s), sizeof(s)); - /* If an overlong response was received, the data will have been - truncated and dn_expand may fail. */ + /* If an overlong response was received, the data will have been + truncated and dn_expand may fail. */ - if (rc < 0) - { - log_write(0, LOG_MAIN, "host name alias list truncated: type=%s " - "domain=%s", dns_text_type(type), domain); - break; + if (rc < 0) + { + log_write(0, LOG_MAIN, "host name alias list truncated: type=%s " + "domain=%s", dns_text_type(type), domain); + break; + } + else yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); } - else yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); - } - } /* Loop for list of returned records */ - } /* Loop for list of domains */ + } /* Loop for list of returned records */ + + /* Loop for set of A-lookupu types */ + } while (type == T_APL && searchtype != T_A); + + } /* Loop for list of domains */ /* Reclaim unused memory */