X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/c2f669a4994192344613569e198c7b503d46d45e..e0e21929b7426b9b5bbf5e3747797043801b1151:/src/src/lookups/dnsdb.c diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index da3495beb..1985964da 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -2,7 +2,8 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2015 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ #include "../exim.h" @@ -14,17 +15,17 @@ header files. */ #ifndef T_TXT -#define T_TXT 16 +# define T_TXT 16 #endif /* Many systems do not have T_SPF. */ #ifndef T_SPF -#define T_SPF 99 +# define T_SPF 99 #endif /* New TLSA record for DANE */ #ifndef T_TLSA -#define T_TLSA 52 +# define T_TLSA 52 #endif /* Table of recognized DNS record types and their integer values. */ @@ -77,7 +78,7 @@ 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 */ @@ -112,7 +113,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,15 +131,14 @@ 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 size = 256; -int ptr = 0; int sep = 0; int defer_mode = PASS; -int dnssec_mode = OK; +int dnssec_mode = PASS; int save_retrans = dns_retrans; int save_retry = dns_retry; int type; @@ -147,14 +147,13 @@ const uschar *outsep = CUS"\n"; const uschar *outsep2 = NULL; uschar *equals, *domain, *found; -/* Because we're the working in the search pool, we try to reclaim as much -store as possible later, so we preallocate the result here */ +dns_answer * dnsa = store_get_dns_answer(); +dns_scan dnss; -uschar *yield = store_get(size); +/* Because we're working in the search pool, we try to reclaim as much +store as possible later, so we preallocate the result here */ -dns_record *rr; -dns_answer dnsa; -dns_scan dnss; +gstring * yield = string_get(256); handle = handle; /* Keep picky compilers happy */ filename = filename; @@ -261,17 +260,15 @@ if ((equals = Ustrchr(keystring, '=')) != NULL) while (tend > keystring && isspace(tend[-1])) tend--; len = tend - keystring; - for (i = 0; i < sizeof(type_names)/sizeof(uschar *); i++) - { + for (i = 0; i < nelem(type_names); i++) if (len == Ustrlen(type_names[i]) && strncmpic(keystring, US type_names[i], len) == 0) { type = type_values[i]; break; } - } - if (i >= sizeof(type_names)/sizeof(uschar *)) + if (i >= nelem(type_names)) { *errmsg = US"unsupported DNS record type"; return DEFER; @@ -317,10 +314,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 @@ -330,14 +326,11 @@ 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 { - DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", domain); + DEBUG(D_lookup) debug_printf_indent("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_ADDRESSES and T_MXH. @@ -354,18 +347,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) @@ -382,22 +375,18 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* Search the returned records */ - for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); - rr != NULL; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + 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 (rr->type != searchtype) continue; - if (*do_cache > rr->ttl) *do_cache = rr->ttl; if (type == T_A || type == T_AAAA || type == T_ADDRESSES) { - dns_address *da; - for (da = dns_address_from_rr(&dnsa, rr); da; da = da->next) + for (dns_address * da = dns_address_from_rr(dnsa, rr); da; da = da->next) { - if (ptr != 0) yield = string_catn(yield, &size, &ptr, outsep, 1); - yield = string_cat(yield, &size, &ptr, da->address); + if (yield->ptr) yield = string_catn(yield, outsep, 1); + yield = string_cat(yield, da->address); } continue; } @@ -405,16 +394,12 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* 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_catn(yield, &size, &ptr, outsep, 1); + if (yield->ptr) yield = string_catn(yield, outsep, 1); if (type == T_TXT || type == T_SPF) { - if (outsep2 == NULL) - { - /* output only the first item of data */ - yield = string_catn(yield, &size, &ptr, (uschar *)(rr->data+1), - (rr->data)[0]); - } + if (outsep2 == NULL) /* output only the first item of data */ + yield = string_catn(yield, US (rr->data+1), (rr->data)[0]); else { /* output all items */ @@ -423,9 +408,8 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) { uschar chunk_len = (rr->data)[data_offset++]; if (outsep2[0] != '\0' && data_offset != 1) - yield = string_catn(yield, &size, &ptr, outsep2, 1); - yield = string_catn(yield, &size, &ptr, - US ((rr->data)+data_offset), chunk_len); + yield = string_catn(yield, outsep2, 1); + yield = string_catn(yield, US ((rr->data)+data_offset), chunk_len); data_offset += chunk_len; } } @@ -433,7 +417,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) else if (type == T_TLSA) { uint8_t usage, selector, matching_type; - uint16_t i, payload_length; + uint16_t payload_length; uschar s[MAX_TLSA_EXPANDED_SIZE]; uschar * sp = s; uschar * p = US rr->data; @@ -446,12 +430,10 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) sp += sprintf(CS s, "%d%c%d%c%d%c", usage, *outsep2, selector, *outsep2, matching_type, *outsep2); /* Now append the cert/identifier, one hex char at a time */ - for (i=0; - i < payload_length && sp-s < (MAX_TLSA_EXPANDED_SIZE - 4); - i++) - sp += sprintf(CS sp, "%02x", (unsigned char)p[i]); + while (payload_length-- > 0 && sp-s < (MAX_TLSA_EXPANDED_SIZE - 4)) + sp += sprintf(CS sp, "%02x", *p++); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); } else /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SOA, T_SRV */ { @@ -469,7 +451,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) case T_MX: GETSHORT(priority, p); sprintf(CS s, "%d%c", priority, *outsep2); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); break; case T_SRV: @@ -478,7 +460,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) GETSHORT(port, p); sprintf(CS s, "%d%c%d%c%d%c", priority, *outsep2, weight, *outsep2, port, *outsep2); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); break; case T_CSA: @@ -507,7 +489,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) } s[1] = ' '; - yield = string_catn(yield, &size, &ptr, s, 2); + yield = string_catn(yield, s, 2); break; default: @@ -516,7 +498,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 @@ -528,16 +510,16 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) "domain=%s", dns_text_type(type), domain); break; } - else yield = string_cat(yield, &size, &ptr, s); + else yield = string_cat(yield, s); if (type == T_SOA && outsep2 != NULL) { unsigned long serial, refresh, retry, expire, minimum; p += rc; - yield = string_catn(yield, &size, &ptr, outsep2, 1); + 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) { @@ -545,7 +527,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) "domain=%s", dns_text_type(type), domain); break; } - else yield = string_cat(yield, &size, &ptr, s); + else yield = string_cat(yield, s); p += rc; GETLONG(serial, p); GETLONG(refresh, p); @@ -553,30 +535,30 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) sprintf(CS s, "%c%lu%c%lu%c%lu%c%lu%c%lu", *outsep2, serial, *outsep2, refresh, *outsep2, retry, *outsep2, expire, *outsep2, minimum); - yield = string_cat(yield, &size, &ptr, s); + yield = string_cat(yield, s); } } } /* Loop for list of returned records */ - /* Loop for set of A-lookupu types */ + /* Loop for set of A-lookup types */ } while (type == T_ADDRESSES && searchtype != T_A); } /* Loop for list of domains */ /* Reclaim unused memory */ -store_reset(yield + ptr + 1); +gstring_release_unused(yield); -/* If ptr == 0 we have not found anything. Otherwise, insert the terminating +/* If yield NULL we have not found anything. Otherwise, insert the terminating zero and return the result. */ dns_retrans = save_retrans; dns_retry = save_retry; dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ -if (ptr == 0) return failrc; -yield[ptr] = 0; -*result = yield; +if (!yield || !yield->ptr) return failrc; + +*result = string_from_gstring(yield); return OK; } @@ -600,15 +582,15 @@ fprintf(f, "Library version: DNSDB: Exim version %s\n", EXIM_VERSION_STR); 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