From 0d8954ca25771bc6c6f5d9cf9bfa38a2b1bbba6e Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 19 Oct 2017 22:06:20 +0300 Subject: Improve DNS resolver API Remove arbitrary size limits. * NEWS: Version 8.2.90 * configure.ac: Likewise. Require Mailutils 3.3 * doc/calloutd.texi: Update. * doc/functions.texi: Update. * doc/mailfromd.texi: Update. * doc/upgrade.texi: Update. * lib/dns.c: Rewrite. * lib/dns.h (MAXMXCOUNT, MXF_MAX): Remove. (mxbuf_init,dns_resolve_ipstr) (a_lookup,ptr_lookup,txt_lookup) (spf_lookup): Change protos. (dns_reply): New struct. (dns_reply_free,dns_reply_ip): New functions. * lib/libmf.h (getmxip): Change proto. * src/builtin/dns.bi: Remove runtime configuration statements: max-dns-reply-a, max-dns-reply-ptr, and max-dns-reply-mx. Rewrite using the new DNS API. * src/callout.c: Update. * src/mailfromd.h: Update. * src/main.c: Remove the max-match-mx configuration statement. * src/prog.c: Update. * src/spf.c: Update. * src/spf.h: Update. * src/srvcfg.c: Remove the max-callout-mx configuration statement. --- src/builtin/dns.bi | 94 ++++++++++++++++++++++-------------------------------- src/callout.c | 2 -- src/mailfromd.h | 3 +- src/main.c | 5 --- src/prog.c | 2 -- src/spf.c | 80 +++++++++++++++++++++------------------------- src/spf.h | 3 -- src/srvcfg.c | 5 --- 8 files changed, 76 insertions(+), 118 deletions(-) (limited to 'src') diff --git a/src/builtin/dns.bi b/src/builtin/dns.bi index 46433a00..faf8998d 100644 --- a/src/builtin/dns.bi +++ b/src/builtin/dns.bi @@ -21,20 +21,6 @@ #include "srvcfg.h" #include "global.h" -static size_t max_ptr = MAX_DNS_PTR; -static size_t max_a = MAX_DNS_A; -static size_t max_mx = MAX_DNS_MX; -static struct mu_cfg_param dns_cfg_param[] = { - { "max-dns-reply-a", mu_c_size, &max_a, 0, NULL, - N_("Maximum number of A records in a DNS reply.") }, - { "max-dns-reply-ptr", mu_c_size, &max_a, 0, NULL, - N_("Maximum number of PTR records in a DNS reply.") }, - { "max-dns-reply-mx", mu_c_size, &max_mx, 0, NULL, - N_("Maximum number of MX records in a DNS reply.") }, - { NULL } -}; - - MF_DEFUN(primitive_hostname, STRING, STRING string) { char *hbuf; @@ -75,8 +61,8 @@ END static int ipaddr_cmp(const void *a, const void *b) { - GACOPYZ_UINT32_T ipa = ntohl(*(GACOPYZ_UINT32_T*)a); - GACOPYZ_UINT32_T ipb = ntohl(*(GACOPYZ_UINT32_T*)b); + GACOPYZ_UINT32_T ipa = ntohl(**(GACOPYZ_UINT32_T**)a); + GACOPYZ_UINT32_T ipb = ntohl(**(GACOPYZ_UINT32_T**)b); if (ipa < ipb) return -1; if (ipa > ipb) @@ -86,37 +72,33 @@ ipaddr_cmp(const void *a, const void *b) MF_DEFUN(dns_getaddr, STRING, STRING string) { - GACOPYZ_UINT32_T *ipbuf; - size_t i, ipcount; + size_t i; unsigned long ttl; dns_status dnstat; - - ipbuf = mu_calloc(max_a, sizeof(ipbuf[0])); - dnstat = a_lookup(string, ipbuf, max_a, &ipcount, - &ttl, NULL, 0); + struct dns_reply r; + + dnstat = a_lookup(string, &r, &ttl); switch (dnstat) { case dns_success: { MF_OBSTACK_BEGIN(); - qsort(ipbuf, ipcount, sizeof ipbuf[0], ipaddr_cmp); - for (i = 0; i < ipcount; i++) { + qsort(r.base, r.count, sizeof r.base[0], ipaddr_cmp); + for (i = 0; i < r.count; i++) { struct in_addr addr; char *q; - addr.s_addr = ipbuf[i]; + addr.s_addr = dns_reply_ip(&r, i); q = inet_ntoa(addr); if (i > 0) MF_OBSTACK_1GROW(' '); MF_OBSTACK_GROW(q); } - free(ipbuf); + dns_reply_free(&r); MF_OBSTACK_1GROW(0); MF_RETURN_OBSTACK(); } case dns_not_found: - free(ipbuf); MF_RETURN(""); default: - free(ipbuf); MF_THROW(mf_status_to_exception(dns_to_mf_status(dnstat)), _("failed to get A record for %s"), string); } @@ -134,42 +116,33 @@ MF_DEFUN(dns_getname, STRING, STRING ipstr) dns_status dnstat; struct in_addr addr; unsigned long ttl; - char **names; - + struct dns_reply r; + MF_ASSERT(inet_aton(ipstr, &addr), mfe_invip, _("invalid IP: %s"), ipstr); - names = mu_calloc(max_ptr, sizeof(names[0])); - dnstat = ptr_lookup(addr, names, max_ptr, &ttl, NULL, 0); + dnstat = ptr_lookup(addr, &r, &ttl); switch (dnstat) { case dns_success: { size_t i; - size_t ncount; - for (ncount = 0; ncount < max_ptr && names[ncount]; - ncount++); - - qsort(names, ncount, sizeof names[0], hostname_cmp); + qsort(r.base, r.count, sizeof r.base[0], hostname_cmp); MF_OBSTACK_BEGIN(); - for (i = 0; i < ncount; i++) { + for (i = 0; i < r.count; i++) { if (i > 0) MF_OBSTACK_1GROW(' '); - MF_OBSTACK_GROW(names[i]); + MF_OBSTACK_GROW((char*)r.base[i]); } MF_OBSTACK_1GROW(0); - for (; i < ncount; i++) - free(names[i]); - free(names); + dns_reply_free(&r); MF_RETURN_OBSTACK(); } case dns_not_found: - free(names); MF_RETURN(""); default: - free(names); MF_THROW(mf_status_to_exception(dns_to_mf_status(dnstat)), _("failed to get PTR record for %s"), ipstr); } @@ -204,15 +177,12 @@ MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER no_resolve) GACOPYZ_UINT32_T *ipbuf; size_t ipcount; - ipbuf = mu_calloc(max_mx, sizeof(ipbuf[0])); - mxstat = getmxip(domain, ipbuf, max_mx, &ipcount); + mxstat = getmxip(domain, &ipbuf, &ipcount); if (!mf_resolved(mxstat)) { - free(ipbuf); MF_THROW(mf_status_to_exception(mxstat), _("cannot get MX records for %s"), domain); } if (mxstat == mf_not_found) { - free(ipbuf); MF_RETURN(""); } else { int i; @@ -233,8 +203,6 @@ MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER no_resolve) } else { struct mxbuf mxbuf; - mxbuf.mx_max = max_mx; - mxbuf.mx_flags = MXF_MAX; mxstat = getmx(domain, &mxbuf); if (!mf_resolved(mxstat)) { mxbuf_free(&mxbuf); @@ -301,11 +269,9 @@ MF_DEFUN(primitive_ismx, NUMBER, STRING domain, STRING ipstr) _("cannot resolve host name %s"), ipstr); ip = ntohl(ip); - ipbuf = mu_calloc(max_mx, sizeof(ipbuf[0])); - mxstat = getmxip(domain, ipbuf, max_mx, &ipcount); + mxstat = getmxip(domain, &ipbuf, &ipcount); if (mxstat != mf_success) { - free(ipbuf); MF_THROW(mf_status_to_exception(mxstat), _("cannot get MXs for %s"), domain); } @@ -328,6 +294,22 @@ MF_DEFUN(relayed, NUMBER, STRING s) } END -MF_INIT([< - mf_add_runtime_params(dns_cfg_param); - >]) +MF_DEFUN(ptr_validate, NUMBER, STRING s) +{ + int rc, res; + switch (rc = ptr_validate(s, NULL, NULL, NULL)) { + case dns_success: + res = 1; + break; + case dns_not_found: + res = 0; + break; + default: + MF_THROW(mf_status_to_exception(dns_to_mf_status(rc)), + _("failed to get PTR record for %s"), s); + } + MF_RETURN(res); +} +END + +MF_INIT diff --git a/src/callout.c b/src/callout.c index e59e8f04..633a33b7 100644 --- a/src/callout.c +++ b/src/callout.c @@ -637,8 +637,6 @@ callout_mx(struct smtp_io_data *iop, const char *hostname, int *pcount) struct mxbuf mxbuf; mf_status rc, mxstat; - mxbuf.mx_max = max_callout_mx; - mxbuf.mx_flags = MXF_MAX; mxstat = getmx(hostname, &mxbuf); if (pcount) diff --git a/src/mailfromd.h b/src/mailfromd.h index 5cc7136b..7f21e360 100644 --- a/src/mailfromd.h +++ b/src/mailfromd.h @@ -76,8 +76,7 @@ mf_status resolve_ipstr_domain(const char *ipstr, const char *domain, mf_status resolve_hostname(const char *host, char **pipbuf); mf_status getmx(const char *ipstr, struct mxbuf *mxbuf); -mf_status getmxip(char *host, GACOPYZ_UINT32_T *ipbuf, size_t ipmax, - size_t *pcount); +mf_status getmxip(char *host, GACOPYZ_UINT32_T **ipbuf, size_t *pcount); /* Debugging macros */ diff --git a/src/main.c b/src/main.c index 66a97808..9873ed0f 100644 --- a/src/main.c +++ b/src/main.c @@ -73,8 +73,6 @@ unsigned optimization_level = 1; /* Optimization level */ int stack_trace_option; /* Print stack traces on runtime errors */ -size_t max_match_mx = MAXMXCOUNT; - char *main_function_name = "main"; char *callout_server_url; @@ -853,9 +851,6 @@ struct mu_cfg_param mf_cfg_param[] = { N_("Set the time span between the two DBM locking attempts."), N_("time: interval") }, - { "max-match-mx", mu_c_size, &max_match_mx, 0, NULL, - N_("Maximum number of MXs used by MFL \"mx match\" operation.") }, - { "runtime", mu_cfg_section, NULL }, { NULL } diff --git a/src/prog.c b/src/prog.c index 12dc69e3..3e90472f 100644 --- a/src/prog.c +++ b/src/prog.c @@ -1602,8 +1602,6 @@ mx_match(eval_environ_t env, char *string, p++; else p = string; - mxbuf.mx_max = max_match_mx; - mxbuf.mx_flags = MXF_MAX; mxstat = getmx(p, &mxbuf); rc = 0; if (mxstat == mf_success) { diff --git a/src/spf.c b/src/spf.c index 236efa5a..9e8c1bfe 100644 --- a/src/spf.c +++ b/src/spf.c @@ -630,9 +630,10 @@ mech_a(spf_data *dat, spf_term_arg *arg, unsigned long masklen) const char *domain_spec; unsigned long netmask; struct in_addr addr; - GACOPYZ_UINT32_T ipbuf[64]; /* FIXME: arbitrary limit */ - size_t i, ipcount; + struct dns_reply r; + size_t i; unsigned long ttl; + spf_term_result res; if (arg) domain_spec = arg->v.domain_spec; @@ -644,23 +645,24 @@ mech_a(spf_data *dat, spf_term_arg *arg, unsigned long masklen) mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1, ("A domain_spec=%s, netmask=%lx", domain_spec, netmask)); - DNS_CATCH(a_lookup(domain_spec, ipbuf, NELEMS(ipbuf), &ipcount, - &ttl, NULL, 0)); + DNS_CATCH(a_lookup(domain_spec, &r, &ttl)); UPDATE_ANSWER_TTL(dat, ttl); addr.s_addr = dat->ipaddr.s_addr & netmask; mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE6, ("A: s_addr=%x", addr.s_addr)); - - for (i = 0; i < ipcount; i++) { - if ((ntohl(ipbuf[i]) & netmask) == addr.s_addr) { - mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1, - ("A matches")); - return spf_term_match; + + res = spf_term_nomatch; + for (i = 0; i < r.count; i++) { + if (ntohl(dns_reply_ip(&r, i) & netmask) == addr.s_addr) { + res = spf_term_match; + break; } } - mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1, ("A does not match")); - return spf_term_nomatch; + dns_reply_free(&r); + mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1, + (res == spf_term_match ? "A matches" : "A does not match")); + return res; } /* 5.4. @@ -685,8 +687,6 @@ mech_mx(spf_data *dat, spf_term_arg *arg, unsigned long masklen) ("MX domain_spec=%s, netmask=%lx", domain_spec, netmask)); - mxbuf.mx_flags = MXF_MAX; - mxbuf.mx_max = 10; DNS_CATCH(dns_get_mx_records(domain_spec, 1, &mxbuf, &ttl)); UPDATE_ANSWER_TTL(dat, ttl); @@ -779,6 +779,7 @@ static spf_term_result mech_exists(spf_data *dat, spf_term_arg *arg, unsigned long masklen) { unsigned long ttl; + struct dns_reply r; if (!arg) { mu_debug(MF_SOURCE_SPF, MU_DEBUG_ERROR, ("exists used without argument")); @@ -788,7 +789,8 @@ mech_exists(spf_data *dat, spf_term_arg *arg, unsigned long masklen) mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1, ("EXISTS domain_spec=%s", arg->v.domain_spec)); - DNS_CATCH(a_lookup(arg->v.domain_spec, NULL, 0, NULL, &ttl, NULL, 0)); + DNS_CATCH(a_lookup(arg->v.domain_spec, &r, &ttl)); + dns_reply_free(&r); UPDATE_ANSWER_TTL(dat, ttl); return spf_term_match; @@ -816,18 +818,17 @@ mod_redirect(spf_data *dat, spf_term_arg *arg, unsigned long masklen) static spf_term_result mod_exp(spf_data *dat, spf_term_arg *arg, unsigned long masklen) { - char *names[128]; /* FIXME: arbitrary limit */ + struct dns_reply r; + if (arg->v.domain_spec - && txt_lookup(arg->v.domain_spec, - names, NELEMS(names), NULL, - NULL, 0) == dns_success) { + && txt_lookup(arg->v.domain_spec, &r, NULL) == dns_success) { int i; char *text; - for (i = 0; names[i]; i++) { - mu_opool_appendz(dat->tmpool, names[i]); - free(names[i]); + for (i = 0; i < r.count; i++) { + mu_opool_appendz(dat->tmpool, r.base[i]); } + dns_reply_free(&r); mu_opool_append_char(dat->tmpool, 0); text = spf_data_ptr(dat); @@ -1213,8 +1214,10 @@ spf_test_record(const char *rec, spf_query_t *q, spf_answer_t *a) spf_result spf_check_host_internal(spf_query_t *q, spf_answer_t *a, size_t loopno) { - char *txt_rec[SPF_MAX_TXT_REC+1]; - int ntxt, i; + char **txt_rec; + size_t txt_num; + int i; + char *spf_rec = NULL; struct spf_data dat; spf_result result; #define SPF_RETURN(res, text) { \ @@ -1241,8 +1244,7 @@ spf_check_host_internal(spf_query_t *q, spf_answer_t *a, size_t loopno) if (strlen(q->domain) > 63) SPF_RETURN(spf_none, "domain too long"); - switch (spf_lookup(q->domain, txt_rec, NELEMS(txt_rec), - &ttl, NULL, 0)) { + switch (spf_lookup(q->domain, &txt_rec, &txt_num, &ttl)) { case dns_success: break; @@ -1256,40 +1258,32 @@ spf_check_host_internal(spf_query_t *q, spf_answer_t *a, size_t loopno) } /* Select SPF1 records */ - ntxt = 0; for (i = 0; txt_rec[i]; i++) { if (memcmp(txt_rec[i], "v=spf1", 6) == 0 && (txt_rec[i][6] == 0 || mu_isspace(txt_rec[i][6]))) { mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE6, ("record: %s", txt_rec[i])); - if (ntxt != i) { - txt_rec[ntxt++] = txt_rec[i]; - txt_rec[i] = NULL; - } else - ntxt = i + 1; - } else { - free(txt_rec[i]); - txt_rec[i] = NULL; + if (spf_rec) { + SPF_RETURN(spf_perm_error, + "too many SPF records published"); + } + spf_rec = txt_rec[i]; + break; } } - if (ntxt == 0) - SPF_RETURN(spf_none, "no SPF records published"); - if (ntxt > 1) - SPF_RETURN(spf_perm_error, "too many SPF records published"); - mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE0, - ("SPF record: %s", txt_rec[0])); + ("SPF record: %s", spf_rec)); if (a) UPDATE_TTL(a->ttl, ttl); if (spf_data_init(&dat, q, a, loopno + 1)) SPF_RETURN(spf_perm_error, "spf_data_init failed"); - result = spf_exec_query(txt_rec[0], &dat); + result = spf_exec_query(spf_rec, &dat); spf_data_free(&dat); - free(txt_rec[0]); + mu_argcv_free(txt_num, txt_rec); SPF_RETURN(result, ""); } diff --git a/src/spf.h b/src/spf.h index 9b3c8e63..229075e6 100644 --- a/src/spf.h +++ b/src/spf.h @@ -14,7 +14,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#define SPF_MAX_TXT_REC 10 #define SPF_MAX_RECURSION 10 typedef enum spf_result { @@ -49,8 +48,6 @@ typedef struct { spf_result spf_check_host(spf_query_t *query, spf_answer_t *ans); spf_result spf_test_record(const char *rec, spf_query_t *query, spf_answer_t *ans); -dns_status spf_lookup(const char *domain, char **txt, size_t maxtxt, - unsigned long *ttl, char *answer, size_t answer_size); void spf_answer_free(spf_answer_t *ans); void spf_answer_add_mech(spf_answer_t *ans, char const *mech); diff --git a/src/srvcfg.c b/src/srvcfg.c index f04e4c68..a9527a53 100644 --- a/src/srvcfg.c +++ b/src/srvcfg.c @@ -42,8 +42,6 @@ struct mu_sockaddr *source_address; /* Source address for TCP connections */ int mtasim_option; /* mtasim compatibility mode */ char *db_type_str = DEFAULT_DB_TYPE; -size_t max_callout_mx = MAXMXCOUNT; - /* Timeouts */ time_t smtp_timeout_soft[SMTP_NUM_TIMEOUT] = { 10, @@ -514,9 +512,6 @@ static struct mu_cfg_param srv_cfg_param[] = { { "acl", mu_cfg_section, &srvman_param.acl }, { "logger", mu_c_string, &log_stream, 0, NULL, N_("Set logger stream.") }, - { "max-callout-mx", mu_c_size, &max_callout_mx, 0, NULL, - N_("Maximum number of MXs to be polled during " - "callout verification.") }, { "state-directory", mu_cfg_callback, NULL, 0, cb_state_directory, N_("Set program state directory."), N_("dir: string") }, -- cgit v1.2.1