summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/doc-docbook/spec.xfpt8
-rw-r--r--doc/doc-txt/ChangeLog2
-rw-r--r--doc/doc-txt/NewStuff3
-rw-r--r--src/src/exim.h1
-rw-r--r--src/src/lookups/dnsdb.c273
-rw-r--r--test/scripts/2250-dnsdb-ipv6/22504
-rw-r--r--test/stdout/22504
7 files changed, 170 insertions, 125 deletions
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
+>