X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/f3ebb786e451da973560f1c9d8cdb151d25108b5..87a97abbfb57cb6583c330e09446c3e8549fd32f:/src/src/lookups/dnsdb.c diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index 5654b5615..1563eda56 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -2,8 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2020 - 2022 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "../exim.h" #include "lf_functions.h" @@ -77,10 +79,8 @@ static int type_values[] = { /* See local README for interface description. */ static void * -dnsdb_open(uschar *filename, uschar **errmsg) +dnsdb_open(const uschar * filename, uschar **errmsg) { -filename = filename; /* Keep picky compilers happy */ -errmsg = errmsg; /* Ditto */ return (void *)(-1); /* Any non-0 value */ } @@ -112,7 +112,7 @@ terminates option processing. Recognised options are: 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'. -- 'dnssec_FOO', with 'strict', 'lax' and 'never' (default). The meanings are +- 'dnssec_FOO', with 'strict', 'lax' (default), and 'never'. The meanings are require, try and don't-try dnssec respectively. - 'retrans_VAL', set the timeout value. VAL is an Exim time specification @@ -130,34 +130,27 @@ which may start with '<' in order to set a specific separator. The default separator, as always, is colon. */ static int -dnsdb_find(void *handle, uschar *filename, const uschar *keystring, int length, - uschar **result, uschar **errmsg, uint *do_cache) +dnsdb_find(void * handle, const uschar * filename, const uschar * keystring, + int length, uschar ** result, uschar ** errmsg, uint * do_cache, + const uschar * opts) { int rc; int sep = 0; -int defer_mode = PASS; -int dnssec_mode = OK; -int save_retrans = dns_retrans; -int save_retry = dns_retry; +int defer_mode = PASS, dnssec_mode = PASS; +int save_retrans = dns_retrans, save_retry = dns_retry; int type; int failrc = FAIL; -const uschar *outsep = CUS"\n"; -const uschar *outsep2 = NULL; -uschar *equals, *domain, *found; +const uschar * outsep = CUS"\n", * outsep2 = NULL; +uschar * equals, * domain, * found; + +dns_answer * dnsa = store_get_dns_answer(); +dns_scan dnss; /* Because we're working in the search pool, we try to reclaim as much store as possible later, so we preallocate the result here */ gstring * yield = string_get(256); -dns_answer dnsa; -dns_scan dnss; - -handle = handle; /* Keep picky compilers happy */ -filename = filename; -length = length; -do_cache = do_cache; - /* If the string starts with '>' we change the output separator. If it's followed by ';' or ',' we set the TXT output separator. */ @@ -195,7 +188,8 @@ for (;;) else { *errmsg = US"unsupported dnsdb defer behaviour"; - return DEFER; + rc = DEFER; + goto out; } } else if (strncmpic(keystring, US"dnssec_", 7) == 0) @@ -210,7 +204,8 @@ for (;;) else { *errmsg = US"unsupported dnsdb dnssec behaviour"; - return DEFER; + rc = DEFER; + goto out; } } else if (strncmpic(keystring, US"retrans_", 8) == 0) @@ -219,7 +214,8 @@ for (;;) if ((timeout_sec = readconf_readtime(keystring += 8, ',', FALSE)) <= 0) { *errmsg = US"unsupported dnsdb timeout value"; - return DEFER; + rc = DEFER; + goto out; } dns_retrans = timeout_sec; while (*keystring != ',') keystring++; @@ -230,7 +226,8 @@ for (;;) if ((retries = (int)strtol(CCS keystring + 6, CSS &keystring, 0)) < 0) { *errmsg = US"unsupported dnsdb retry count"; - return DEFER; + rc = DEFER; + goto out; } dns_retry = retries; } @@ -241,7 +238,8 @@ for (;;) if (*keystring++ != ',') { *errmsg = US"dnsdb modifier syntax error"; - return DEFER; + rc = DEFER; + goto out; } while (isspace(*keystring)) keystring++; } @@ -269,7 +267,8 @@ if ((equals = Ustrchr(keystring, '=')) != NULL) if (i >= nelem(type_names)) { *errmsg = US"unsupported DNS record type"; - return DEFER; + rc = DEFER; + goto out; } keystring = equals + 1; @@ -312,10 +311,9 @@ if (!outsep2) switch(type) while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) { - uschar rbuffer[256]; - int searchtype = (type == T_CSA)? T_SRV : /* record type we want */ - (type == T_MXH)? T_MX : - (type == T_ZNS)? T_NS : type; + int searchtype = type == T_CSA ? T_SRV : /* record type we want */ + type == T_MXH ? T_MX : + type == T_ZNS ? T_NS : type; /* If the type is PTR or CSA, we have to construct the relevant magic lookup key if the original is an IP address (some experimental protocols are using @@ -325,10 +323,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) if ((type == T_PTR || type == T_CSA) && string_is_ip_address(domain, NULL) != 0) - { - dns_build_reverse(domain, rbuffer); - domain = rbuffer; - } + domain = dns_build_reverse(domain); do { @@ -349,18 +344,18 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) { if (searchtype == T_ADDRESSES) searchtype = T_AAAA; else if (searchtype == T_AAAA) searchtype = T_A; - rc = dns_special_lookup(&dnsa, domain, searchtype, CUSS &found); + rc = dns_special_lookup(dnsa, domain, searchtype, CUSS &found); } else #endif - rc = dns_special_lookup(&dnsa, domain, type, CUSS &found); + rc = dns_special_lookup(dnsa, domain, type, CUSS &found); lookup_dnssec_authenticated = dnssec_mode==OK ? NULL - : dns_is_secure(&dnsa) ? US"yes" : US"no"; + : dns_is_secure(dnsa) ? US"yes" : US"no"; if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue; if ( rc != DNS_SUCCEED - || (dnssec_mode == DEFER && !dns_is_secure(&dnsa)) + || (dnssec_mode == DEFER && !dns_is_secure(dnsa)) ) { if (defer_mode == DEFER) @@ -368,7 +363,8 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) dns_retrans = save_retrans; dns_retry = save_retry; dns_init(FALSE, FALSE, FALSE); /* clr dnssec bit */ - return DEFER; /* always defer */ + rc = DEFER; /* always defer */ + goto out; } if (defer_mode == PASS) failrc = DEFER; /* defer only if all do */ continue; /* treat defer as fail */ @@ -377,19 +373,16 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* Search the returned records */ - for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == searchtype) + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == searchtype) { if (*do_cache > rr->ttl) *do_cache = rr->ttl; if (type == T_A || type == T_AAAA || type == T_ADDRESSES) { - for (dns_address * da = dns_address_from_rr(&dnsa, rr); da; da = da->next) - { - if (yield->ptr) yield = string_catn(yield, outsep, 1); - yield = string_cat(yield, da->address); - } + for (dns_address * da = dns_address_from_rr(dnsa, rr); da; da = da->next) + yield = string_append_listele(yield, *outsep, da->address); continue; } @@ -400,21 +393,17 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) if (type == T_TXT || type == T_SPF) { - if (outsep2 == NULL) /* output only the first item of data */ + if (!outsep2) /* output only the first item of data */ yield = string_catn(yield, US (rr->data+1), (rr->data)[0]); else - { - /* output all items */ - int data_offset = 0; - while (data_offset < rr->size) + for (unsigned data_offset = 0; data_offset < rr->size; ) { - uschar chunk_len = (rr->data)[data_offset++]; - if (outsep2[0] != '\0' && data_offset != 1) + uschar chunk_len = (rr->data)[data_offset]; + if (*outsep2 && data_offset != 0) yield = string_catn(yield, outsep2, 1); - yield = string_catn(yield, US ((rr->data)+data_offset), chunk_len); + yield = string_catn(yield, US ((rr->data) + ++data_offset), chunk_len); data_offset += chunk_len; } - } } else if (type == T_TLSA) { @@ -500,7 +489,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* GETSHORT() has advanced the pointer to the target domain. */ - rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, + 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 @@ -521,7 +510,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) p += rc; yield = string_catn(yield, outsep2, 1); - rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p, + rc = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, (DN_EXPAND_ARG4_TYPE)s, sizeof(s)); if (rc < 0) { @@ -558,10 +547,18 @@ dns_retrans = save_retrans; dns_retry = save_retry; dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ -if (!yield || !yield->ptr) return failrc; +if (!yield || !yield->ptr) + rc = failrc; +else + { + *result = string_from_gstring(yield); + rc = OK; + } + +out: -*result = string_from_gstring(yield); -return OK; +store_free_dns_answer(dnsa); +return rc; } @@ -574,25 +571,26 @@ return OK; #include "../version.h" -void -dnsdb_version_report(FILE *f) +gstring * +dnsdb_version_report(gstring * g) { #ifdef DYNLOOKUP -fprintf(f, "Library version: DNSDB: Exim version %s\n", EXIM_VERSION_STR); +g = string_fmt_append(g, "Library version: DNSDB: Exim version %s\n", EXIM_VERSION_STR); #endif +return g; } 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 */ + .name = US"dnsdb", /* lookup name */ + .type = lookup_querystyle, /* query style */ + .open = dnsdb_open, /* open function */ + .check = NULL, /* check function */ + .find = dnsdb_find, /* find function */ + .close = NULL, /* no close function */ + .tidy = NULL, /* no tidy function */ + .quote = NULL, /* no quoting function */ + .version_report = dnsdb_version_report /* version reporting */ }; #ifdef DYNLOOKUP