-/* $Cambridge: exim/src/src/lookups/dnsdb.c,v 1.3 2004/11/19 15:18:57 ph10 Exp $ */
+/* $Cambridge: exim/src/src/lookups/dnsdb.c,v 1.8 2005/01/04 10:00:44 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2004 */
+/* Copyright (c) University of Cambridge 1995 - 2005 */
/* See the file NOTICE for conditions of use and distribution. */
#include "../exim.h"
#endif
"cname",
"mx",
+ "mxh",
"ns",
"ptr",
"srv",
#endif
T_CNAME,
T_MX,
+ T_MXH, /* Private type for "MX hostnames" */
T_NS,
T_PTR,
T_SRV,
separator character that is used when multiple records are found. The default
separator is newline.
-(b) If the next sequence of characters is a sequence of letters and digits
+(b) 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
+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'.
+
+(c) 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 "A".
+default is "TXT".
-(c) Then there follows list of domain names. This is a generalized Exim list,
+(d) 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. */
int size = 256;
int ptr = 0;
int sep = 0;
+int defer_mode = PASS;
int type = T_TXT;
+int failrc = FAIL;
uschar *outsep = US"\n";
uschar *equals, *domain;
uschar buffer[256];
while (isspace(*keystring)) keystring++;
}
+/* Check for a defer behaviour keyword. */
+
+if (strncmpic(keystring, US"defer_", 6) == 0)
+ {
+ keystring += 6;
+ 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;
+ }
+ while (isspace(*keystring)) keystring++;
+ if (*keystring++ != ',')
+ {
+ *errmsg = US"dnsdb defer behaviour syntax error";
+ return DEFER;
+ }
+ while (isspace(*keystring)) keystring++;
+ }
+
/* If the keystring contains an = this must be preceded by a valid type name. */
if ((equals = Ustrchr(keystring, '=')) != NULL)
!= NULL)
{
uschar rbuffer[256];
+ int searchtype = (type == T_ZNS)? T_NS : /* record type we want */
+ (type == T_MXH)? T_MX : type;
- /* If the type is PTR, we have to construct the relevant magic lookup
- key. This code is now in a separate function. */
+ /* If the type is PTR, we have to construct the relevant magic lookup key if
+ the original is an IP address (some experimental protocols are using PTR
+ records for different purposes where the key string is a host name). This
+ code for doing the reversal is now in a separate function. */
- if (type == T_PTR)
+ if (type == T_PTR && string_is_ip_address(domain, NULL))
{
dns_build_reverse(domain, rbuffer);
domain = rbuffer;
DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", domain);
- /* Do the lookup and sort out the result. We use the special
- lookup function that knows about pseudo types like "zns". If the lookup
- fails, continue with the next domain. */
+ /* Do the lookup and sort out the result. There are two special types that
+ are handled specially: T_ZNS and T_MXH. The former is 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. */
rc = dns_special_lookup(&dnsa, domain, type, NULL);
if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue;
- if (rc != DNS_SUCCEED) return DEFER;
-
- /* If the lookup was a pseudo-type, change it to the correct type for
- searching the returned records; then search for them. */
+ if (rc != DNS_SUCCEED)
+ {
+ 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 */
+ }
- if (type == T_ZNS) type = T_NS;
+ /* Search the returned records */
+
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
rr != NULL;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
{
- if (rr->type != type) continue;
+ 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
yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1),
(rr->data)[0]);
}
- else /* T_CNAME, T_MX, T_NS, T_SRV, T_PTR */
+ else /* T_CNAME, T_MX, T_MXH, T_NS, T_SRV, T_PTR */
{
+ int num;
uschar s[264];
uschar *p = (uschar *)(rr->data);
- if (type == T_MX)
+
+ if (type == T_MXH)
+ {
+ /* mxh ignores the priority number and includes only the hostnames */
+ GETSHORT(num, p); /* pointer is advanced */
+ }
+ else if (type == T_MX)
{
- int num;
GETSHORT(num, p); /* pointer is advanced */
sprintf(CS s, "%d ", num);
yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
}
else if (type == T_SRV)
{
- int num, weight, port;
+ int weight, port;
GETSHORT(num, p); /* pointer is advanced */
GETSHORT(weight, p);
GETSHORT(port, p);
sprintf(CS s, "%d %d %d ", num, weight, port);
yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
}
+
rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
(DN_EXPAND_ARG4_TYPE)(s), sizeof(s));
/* If ptr == 0 we have not found anything. Otherwise, insert the terminating
zero and return the result. */
-if (ptr == 0) return FAIL;
+if (ptr == 0) return failrc;
yield[ptr] = 0;
*result = yield;
return OK;