From: Jeremy Harris Date: Wed, 5 Sep 2012 20:38:23 +0000 (+0100) Subject: Add dnsdb lookup pseudo-type "a+". Addresses bug 1269. X-Git-Tag: exim-4_81_RC1~3^2~75 X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/3a7963704c5192e25046b1a2f808d4b8ed357386?ds=sidebyside;hp=97f42f10055f18c7f4c9230e6e88a02f31645a68 Add dnsdb lookup pseudo-type "a+". Addresses bug 1269. --- diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 99de2870b..f902fe856 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -6911,6 +6911,14 @@ has two space-separated fields: an authorization code and a target host name. The authorization code can be &"Y"& for yes, &"N"& for no, &"X"& for explicit authorization required but absent, or &"?"& for unknown. +.cindex "A+" "in &(dnsdb)& lookup" +The pseudo-type A+ performs an A6 lookup (if configured) followed by an AAAA +and then an A lookup. All results are returned; defer processing +(see below) is handled separately for each lookup. Example: +.code +${lookup dnsdb {>; a+=$sender_helo_name}} +.endd + .section "Multiple dnsdb lookups" "SECID67" In the previous sections, &(dnsdb)& lookups for a single domain are described. diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index e3d2fc2b6..c528ada99 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -66,6 +66,8 @@ JH/04 Add expansion item ${acl {name}{arg}...}, expansion condition JH/05 Permit multiple router/transport headers_add/remove lines. +JH/06 Add dnsdb pseudo-lookup "a+" to do an "aaaa" + "a" combination. + Exim version 4.80 ----------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 94307c8b6..7c02afbd5 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -112,6 +112,9 @@ Version 4.81 12. New ACL modifier "remove_header" can remove headers before message gets handled by routers/transports. +13. New dnsdb lookup pseudo-type "a+". A sequence of "a6" (if configured), + "aaaa" and "a" lookups is done and the full set of results returned. + Version 4.80 ------------ diff --git a/src/src/exim.h b/src/src/exim.h index 32871660d..2816fc98a 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -354,6 +354,7 @@ side, put in definitions for all the ones that Exim uses. */ #define T_ZNS (-1) #define T_MXH (-2) #define T_CSA (-3) +#define T_APL (-4) /* The resolv.h header defines __P(x) on some Solaris 2.5.1 systems (without checking that it is already defined, in fact). This conflicts with other diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index 0bbc86a56..ec1cd159a 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, @@ -280,157 +282,178 @@ 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 (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 + 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 + 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) - { - /* output only the first item of data */ - yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1), - (rr->data)[0]); - } - else + if (type == T_TXT || type == T_SPF) { - /* output all items */ - int data_offset = 0; - while (data_offset < rr->size) + if (outsep2 == NULL) { - 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 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) + { + 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) - { - 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) + else /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SRV */ { - /* 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 */ + int priority, weight, port; + uschar s[264]; + uschar *p = (uschar *)(rr->data); - /* 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 */ diff --git a/test/scripts/2250-dnsdb-ipv6/2250 b/test/scripts/2250-dnsdb-ipv6/2250 index 08cd326ad..fe5a41bef 100644 --- a/test/scripts/2250-dnsdb-ipv6/2250 +++ b/test/scripts/2250-dnsdb-ipv6/2250 @@ -3,4 +3,8 @@ exim -be ptr=V6NET:0:12:1:a00:20ff:fe86:a062 ${lookup dnsdb {ptr=<;V6NET:0:12:1:a00:20ff:fe86:a062}{$value}{fail}} ptr=V6NET:0:12:1:a00:20ff:fe86:a062 ${lookup dnsdb {ptr=V6NET:0:12:1:a00:20ff:fe86:a062}{$value}{fail}} + +a=46.test.ex ${lookup dnsdb{>; a=46.test.ex}{$value}fail} +aaaa=46.test.ex ${lookup dnsdb{>; aaaa=46.test.ex}{$value}fail} +a+=46.test.ex ${lookup dnsdb{>; a+=46.test.ex}{$value}fail} **** diff --git a/test/stdout/2250 b/test/stdout/2250 index 3b9e93a4a..8a3cf33d1 100644 --- a/test/stdout/2250 +++ b/test/stdout/2250 @@ -1,3 +1,7 @@ > ptr=V6NET:0:12:1:a00:20ff:fe86:a062 testptr-arpa.ipv6.test.ex > ptr=V6NET:0:12:1:a00:20ff:fe86:a062 testptr-arpa.ipv6.test.ex > +> a=46.test.ex V4NET.0.0.4 +> aaaa=46.test.ex V6NET:ffff:836f:a00:a:800:200a:c031 +> a+=46.test.ex V6NET:ffff:836f:a00:a:800:200a:c031;V4NET.0.0.4 +>