X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/97696d5986bd0e129a01d63b69a04aa7141a82bd..542bc632dd2ab452f87e0304e3356534e49f71f3:/src/src/lookups/dnsdb.c diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index 169fd67f1..0bbc86a56 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -1,15 +1,12 @@ -/* $Cambridge: exim/src/src/lookups/dnsdb.c,v 1.13 2005/06/10 13:38:06 tom Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2012 */ /* See the file NOTICE for conditions of use and distribution. */ #include "../exim.h" #include "lf_functions.h" -#include "dnsdb.h" @@ -20,9 +17,14 @@ header files. */ #define T_TXT 16 #endif +/* Many systems do not have T_SPF. */ +#ifndef T_SPF +#define T_SPF 99 +#endif + /* Table of recognized DNS record types and their integer values. */ -static char *type_names[] = { +static const char *type_names[] = { "a", #if HAVE_IPV6 "aaaa", @@ -36,6 +38,7 @@ static char *type_names[] = { "mxh", "ns", "ptr", + "spf", "srv", "txt", "zns" @@ -55,6 +58,7 @@ static int type_values[] = { T_MXH, /* Private type for "MX hostnames" */ T_NS, T_PTR, + T_SPF, T_SRV, T_TXT, T_ZNS /* Private type for "zone nameservers" */ @@ -67,7 +71,7 @@ static int type_values[] = { /* See local README for interface description. */ -void * +static void * dnsdb_open(uschar *filename, uschar **errmsg) { filename = filename; /* Keep picky compilers happy */ @@ -88,21 +92,28 @@ consist of a number of parts. separator character that is used when multiple records are found. The default separator is newline. -(b) If the next sequence of characters is 'defer_FOO' followed by a comma, +(b) If the next character is ',' then the next character is the separator +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. 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 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 +(d) 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". -(d) Then there follows list of domain names. This is a generalized Exim list, +(e) 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 +static int dnsdb_find(void *handle, uschar *filename, uschar *keystring, int length, uschar **result, uschar **errmsg, BOOL *do_cache) { @@ -111,9 +122,10 @@ 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; uschar *equals, *domain, *found; uschar buffer[256]; @@ -131,13 +143,24 @@ filename = filename; length = length; do_cache = do_cache; -/* If the string starts with '>' we change the output separator */ +/* If the string starts with '>' we change the output separator. +If it's followed by ';' or ',' we set the TXT output separator. */ while (isspace(*keystring)) keystring++; if (*keystring == '>') { outsep = keystring + 1; keystring += 2; + if (*keystring == ',') + { + outsep2 = keystring + 1; + keystring += 2; + } + else if (*keystring == ';') + { + outsep2 = US""; + keystring++; + } while (isspace(*keystring)) keystring++; } @@ -175,8 +198,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; @@ -221,9 +246,17 @@ remaining string is valid as an IP address, set an impossible separator so that it is treated as one item. */ if (type == T_PTR && keystring[0] != '<' && - string_is_ip_address(keystring, NULL) > 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))) @@ -241,7 +274,7 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer))) doing the reversal is now in a separate function. */ if ((type == T_PTR || type == T_CSA) && - string_is_ip_address(domain, NULL) > 0) + string_is_ip_address(domain, NULL) != 0) { dns_build_reverse(domain, rbuffer); domain = rbuffer; @@ -249,13 +282,13 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer))) DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", 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. */ + /* 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); @@ -301,10 +334,28 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer))) if (ptr != 0) yield = string_cat(yield, &size, &ptr, outsep, 1); - if (type == T_TXT) + if (type == T_TXT || type == T_SPF) { - yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1), - (rr->data)[0]); + if (outsep2 == NULL) + { + /* 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; + } + } } else /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SRV */ { @@ -394,4 +445,42 @@ yield[ptr] = 0; return OK; } + + +/************************************************* +* Version reporting entry point * +*************************************************/ + +/* See local README for interface description. */ + +#include "../version.h" + +void +dnsdb_version_report(FILE *f) +{ +#ifdef DYNLOOKUP +fprintf(f, "Library version: DNSDB: Exim version %s\n", EXIM_VERSION_STR); +#endif +} + + +static lookup_info _lookup_info = { + US"dnsdb", /* lookup name */ + lookup_querystyle, /* query style */ + dnsdb_open, /* open function */ + NULL, /* check function */ + dnsdb_find, /* find function */ + NULL, /* no close function */ + NULL, /* no tidy function */ + NULL, /* no quoting function */ + dnsdb_version_report /* version reporting */ +}; + +#ifdef DYNLOOKUP +#define dnsdb_lookup_module_info _lookup_module_info +#endif + +static lookup_info *_lookup_list[] = { &_lookup_info }; +lookup_module_info dnsdb_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 }; + /* End of lookups/dnsdb.c */