diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-07-21 17:27:38 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-07-21 17:44:57 +0300 |
commit | 4afb0614fa25dcbe960699508c589dd077dba3d1 (patch) | |
tree | 3a71e62de78e6e5fbec1300aa00d53425ceee136 | |
parent | 48c6ea21f359dd1a262c71a79726d29882530ee2 (diff) | |
download | mailfromd-4afb0614fa25dcbe960699508c589dd077dba3d1.tar.gz mailfromd-4afb0614fa25dcbe960699508c589dd077dba3d1.tar.bz2 |
Improve DNS interface. Number of MXs used in various operations is configurable.
* mfd/dnsbase.c (_getmx): Change prototype. Use struct mxbuf,
(dns_get_mx_records): Likewise.
(dns_freemx): Remove.
(mxbuf_init, mxbuf_free): New functions.
* mfd/dns.h (mxbuf): New struct.
(mxbuf_t): Remove typedef.
(mxbuf_init, mxbuf_free): New functions.
(dns_get_mx_records): Change proto.
(dns_freemx): Remove proto.
* mfd/dnscache.c (parse_value, dns_cache_get): Change signature. All callers
updated.
* mfd/mailfromd.h (getmx, getmxip): Change signature.
(max_callout_mx, max_match_mx): New externs.
(dns_cache_get): Change signature.
* mfd/main.c (max_callout_mx, max_match_mx): New globals.
(mf_cfg_param): New statements "max-callout-mx" and "max-match-mx".
* mfd/callout.c (callout_mx): Use new mxbuf interface.
* mfd/dns.c (getmx): Change signature. Use new mxbuf interface.
(getmxip): Likewise.
* mfd/prog.c (mx_match): Use new mxbuf interface. Limit number
of MXs by max_match_mx.
* mfd/spf.c (mech_mx): Use new mxbuf interface.
* mfd/builtin/dns.bi (dns_cfg_param): New statement "max-dns-reply-mx".
(primitive_hasmx,getmx)
(primitive_ismx): Rewrite to use new mxbuf interface.
* doc/values.texi (MAX_DNS_MX, MAXMXCOUNT): New values.
* doc/functions.texi: Update.
* doc/mailfromd.texi: Update.
* doc/pmult.texi: Update.
* doc/values.texi (MAX_DNS_MX, MAXMXCOUNT): New values.
-rw-r--r-- | doc/functions.texi | 16 | ||||
-rw-r--r-- | doc/mailfromd.texi | 32 | ||||
-rw-r--r-- | doc/pmult.texi | 3 | ||||
-rw-r--r-- | doc/values.texi | 2 | ||||
-rw-r--r-- | mfd/builtin/dns.bi | 75 | ||||
-rw-r--r-- | mfd/callout.c | 21 | ||||
-rw-r--r-- | mfd/dns.c | 37 | ||||
-rw-r--r-- | mfd/dns.h | 19 | ||||
-rw-r--r-- | mfd/dnsbase.c | 48 | ||||
-rw-r--r-- | mfd/dnscache.c | 10 | ||||
-rw-r--r-- | mfd/mailfromd.h | 9 | ||||
-rw-r--r-- | mfd/main.c | 10 | ||||
-rw-r--r-- | mfd/prog.c | 16 | ||||
-rw-r--r-- | mfd/spf.c | 17 |
14 files changed, 219 insertions, 96 deletions
diff --git a/doc/functions.texi b/doc/functions.texi index 51b4a8ff..4e227e41 100644 --- a/doc/functions.texi +++ b/doc/functions.texi @@ -1444,8 +1444,10 @@ getmx("org.pl") @result{} "" @emph{Notes}: @enumerate 1 -@item The @code{getmx} function returns at most 32 @acronym{MX} names or @acronym{IP} addresses. -@FIXME{This limit should be configurable.} +@item The number of @acronym{MX} names or @acronym{IP} addresses +returned by @code{getmx} is limited by the value of +@code{max-dns-reply-mx} configuration statement (default +@value{MAX_DNS_MX}). @xref{conf-runtime, max-dns-reply-mx}. @item The number of items returned by @code{getmx(@var{domain})} can differ from that obtained from @code{getmx(@var{domain}, 1)}, e.g.: @@ -1541,6 +1543,10 @@ exception @code{e_not_found}. If @acronym{DNS} query fails, the function raises @code{failure} or @code{temp_failure}, depending on the character of the failure. + + The number of @samp{MX} records examined by this function is limited +by the value of the @code{max-dns-reply-mx} configuration statement +(@pxref{conf-runtime, max-dns-reply-mx}. @end deftypefn @anchor{ismx} @@ -1553,7 +1559,11 @@ is a host name or @acronym{IP} address. records for the @var{domain}. Otherwise it returns @code{false}. If @var{domain} has no @samp{MX} records, or if the @acronym{DNS} query fails, the -function returns @code{false}. +function returns @code{false}. + + The number of @samp{MX} records examined by this function is limited +by the value of the @code{max-dns-reply-mx} configuration statement +(@pxref{conf-runtime, max-dns-reply-mx}. @end deftypefn @deftypefn {Built-in Function} string primitive_resolve (string @var{host}, @ diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi index 57e2fbb6..74f9a5a8 100644 --- a/doc/mailfromd.texi +++ b/doc/mailfromd.texi @@ -309,6 +309,7 @@ Configuring @command{mailfromd} * conf-priv:: Privilege Configuration * conf-database:: Database Configuration * conf-runtime:: Runtime Constants +* conf-other:: Other Configuration Statements * conf-mailutils:: Standard Mailutils Statements @command{Mailfromd} Command Line Syntax @@ -5367,7 +5368,7 @@ certain restrictions on the statements that can be used within them: @cindex @code{return} in @samp{end} @cindex @samp{end} and @code{return} @item @code{return} cannot be used in @samp{begin} and @samp{end} -handlers. @FIXME{It could be a useful feature, though.} +handlers. @cindex @code{accept} in @samp{begin} @cindex @samp{begin} and @code{accept} @@ -6071,6 +6072,7 @@ $f fnmatches "*org*" @result{} @code{true} @end group @end smallexample +@anchor{mx matches} @cindex mx matches Both operators have a special form, for @dfn{@samp{MX} pattern matching}. The expression: @@ -6098,6 +6100,10 @@ returns true. Otherwise, its result is false. returns true only if any of the @samp{MX}s for (domain or email) @var{x} match the globbing pattern @var{y}. + These operators examine at most @value{MAXMXCOUNT} @samp{MX} +records. To change this limit, use the @code{max-match-mx} +configuration statement (@pxref{conf-other, max-match-mx}). + Both @code{mx matches} and @code{mx fnmatches} can signal the following exceptions: @code{e_temp_failure}, @code{e_failure}. @@ -7484,7 +7490,7 @@ can be used in complex scripts to create non-local exits from deeply nested statements. @FIXME{Elaborate on that.} Notice, that the the @var{excode} argument must be an immediate -value: an exception identifier (either built-in one or one declared +value: an exception identifier (either a built-in one or one declared previously using a @code{dclex} statement). @node Polling @@ -8602,6 +8608,7 @@ Mailutils Manual}. * conf-priv:: Privilege Configuration * conf-database:: Database Configuration * conf-runtime:: Runtime Constants +* conf-other:: Other Configuration Statements * conf-mailutils:: Standard Mailutils Statements @end menu @@ -9049,6 +9056,11 @@ setvar mailfrom_address @var{string}; @end smallexample @end deffn +@deffn {Mailfromd Conf} max-callout-mx number + Sets the maximum number of MXs to be polled during a callout +verification. Defaults to @value{MAXMXCOUNT}. +@end deffn + @node conf-priv @section Privilege Configuration @@ -9188,6 +9200,22 @@ returned in a reply. This affects the @code{dns_getname} function (@pxref{DNS functions, dns_getname}). The default value is @value{MAX_DNS_PTR}. @end deffn +@deffn {runtime} max-dns-reply-mx number +Sets the maximum number of @acronym{DNS} @samp{MX} records to be +returned in a reply. This affects the following functions: +@code{getpx}, @code{ismx}, @code{primitive_mx} +(@pxref{DNS functions}). The default value is @value{MAX_DNS_MX}. +@end deffn + +@node conf-other +@section Other Configuration Statements + +@deffn {Mailfromd Conf} max-match-mx number +Sets the maximum number of MXs to use in @samp{mx matches} operations +(@pxref{mx matches}). Defaults to @value{MAXMXCOUNT}. +@end deffn + + @node conf-mailutils @section Standard Mailutils Statements diff --git a/doc/pmult.texi b/doc/pmult.texi index bf9bfb08..4c5af1ea 100644 --- a/doc/pmult.texi +++ b/doc/pmult.texi @@ -161,8 +161,7 @@ always @samp{1}. Defined in @code{envfrom} and subsequent handlers. @item nrcpts The number of validated recipients for a single message. Defined in -@code{envfrom} and @code{envrcpt} handlers. @FIXME{Verify if it -matches this semantics.} +@code{envfrom} and @code{envrcpt} handlers. @item r Protocol used to receive the message. The value of this macro is diff --git a/doc/values.texi b/doc/values.texi index 6d83ef47..c9c655d9 100644 --- a/doc/values.texi +++ b/doc/values.texi @@ -16,3 +16,5 @@ @set NMSGS 1024 @set MAX_DNS_A 64 @set MAX_DNS_PTR 64 +@set MAX_DNS_MX 32 +@set MAXMXCOUNT 32 diff --git a/mfd/builtin/dns.bi b/mfd/builtin/dns.bi index 9f4eed65..6782edf9 100644 --- a/mfd/builtin/dns.bi +++ b/mfd/builtin/dns.bi @@ -21,11 +21,14 @@ static size_t max_ptr = 64; static size_t max_a = 64; +static size_t max_mx = MAXMXCOUNT; static struct mu_cfg_param dns_cfg_param[] = { { "max-dns-reply-a", mu_cfg_size, &max_a, 0, NULL, N_("Maximum number of A records in a DNS reply.") }, { "max-dns-reply-ptr", mu_cfg_size, &max_a, 0, NULL, N_("Maximum number of PTR records in a DNS reply.") }, + { "max-dns-reply-mx", mu_cfg_size, &max_mx, 0, NULL, + N_("Maximum number of MX records in a DNS reply.") }, { NULL } }; @@ -173,18 +176,18 @@ END MF_DEFUN(primitive_hasmx, NUMBER, STRING string) { - mxbuf_t mxbuf; + struct mxbuf mxbuf; mf_status mxstat; - mxstat = getmx(string, mxbuf); + mxbuf.mx_flags = 0; + mxstat = getmx(string, &mxbuf); MF_ASSERT(mxstat == mf_success || mxstat == mf_not_found, mf_status_to_exception(mxstat), _("cannot get MX records for %s"), string); - + mxbuf_free(&mxbuf); if (mxstat == mf_success) { - dns_freemx(mxbuf); MF_RETURN(1); } MF_RETURN(0); @@ -196,16 +199,20 @@ MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER no_resolve) mf_status mxstat; if (MF_OPTVAL(no_resolve)) { - GACOPYZ_UINT32_T ipbuf[MAXMXCOUNT]; + GACOPYZ_UINT32_T *ipbuf; size_t ipcount; - - mxstat = getmxip(domain, ipbuf, &ipcount); - MF_ASSERT(mxstat == mf_success || mxstat == mf_not_found, - mf_status_to_exception(mxstat), - _("cannot get MX records for %s"), domain); - if (mxstat == mf_not_found) + + ipbuf = xcalloc(max_mx, sizeof(ipbuf[0])); + mxstat = getmxip(domain, ipbuf, max_mx, &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_STRING(""); - else { + } else { int i; MF_OBSTACK_BEGIN(); @@ -217,26 +224,35 @@ MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER no_resolve) MF_OBSTACK_1GROW(' '); MF_OBSTACK_GROW(inet_ntoa(s)); } + free(ipbuf); MF_OBSTACK_1GROW(0); MF_RETURN_OBSTACK(); } } else { - mxbuf_t mxbuf; - - mxstat = getmx(domain, mxbuf); - if (mxstat == mf_not_found) + struct mxbuf mxbuf; + + mxbuf.mx_max = max_mx; + mxbuf.mx_flags = MXF_MAX; + mxstat = getmx(domain, &mxbuf); + if (!mf_resolved(mxstat)) { + mxbuf_free(&mxbuf); + MF_THROW(mf_status_to_exception(mxstat), + _("cannot get MX records for %s"), domain); + } + if (mxstat == mf_not_found) { + mxbuf_free(&mxbuf); MF_RETURN_STRING(""); - else { + } else { int i; MF_OBSTACK_BEGIN(); - for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) { + for (i = 0; i < mxbuf.mx_cnt; i++) { if (i > 0) MF_OBSTACK_1GROW(' '); - MF_OBSTACK_GROW(mxbuf[i]); + MF_OBSTACK_GROW(mxbuf.mx_buf[i]); } MF_OBSTACK_1GROW(0); - dns_freemx(mxbuf); + mxbuf_free(&mxbuf); MF_RETURN_OBSTACK(); } } @@ -272,7 +288,7 @@ resolve_host(const char *string, unsigned long *ip) MF_DEFUN(primitive_ismx, NUMBER, STRING domain, STRING ipstr) { - GACOPYZ_UINT32_T ipbuf[MAXMXCOUNT]; + GACOPYZ_UINT32_T *ipbuf; size_t ipcount; mf_status mxstat; unsigned long ip; @@ -282,12 +298,15 @@ MF_DEFUN(primitive_ismx, NUMBER, STRING domain, STRING ipstr) MF_ASSERT(resolve_host(ipstr, &ip) == 0, mfe_noresolve, _("cannot resolve host name %s"), ipstr); ip = ntohl(ip); - - mxstat = getmxip(domain, ipbuf, &ipcount); - - MF_ASSERT(mxstat == mf_success, - mf_status_to_exception(mxstat), - _("cannot get MXs for %s"), domain); + + ipbuf = xcalloc(max_mx, sizeof(ipbuf[0])); + mxstat = getmxip(domain, ipbuf, max_mx, &ipcount); + + if (mxstat != mx_success) { + free(ipbuf); + MF_THROW(mf_status_to_exception(mxstat), + _("cannot get MXs for %s"), domain); + } for (i = 0; i < ipcount; i++) { if (ipbuf[i] == ip) { @@ -295,6 +314,8 @@ MF_DEFUN(primitive_ismx, NUMBER, STRING domain, STRING ipstr) break; } } + + free(ipbuf); MF_RETURN(rc); } END diff --git a/mfd/callout.c b/mfd/callout.c index 3d701577..57d0c3a6 100644 --- a/mfd/callout.c +++ b/mfd/callout.c @@ -591,8 +591,12 @@ mf_status callout_mx(struct smtp_io_data *iop, const char *hostname, int *pcount) { int i; - mxbuf_t mxbuf; - mf_status rc, mxstat = getmx(hostname, mxbuf); + struct mxbuf mxbuf; + mf_status rc, mxstat; + + mxbuf.mx_max = max_callout_mx; + mxbuf.mx_flags = MXF_MAX; + mxstat = getmx(hostname, &mxbuf); if (pcount) *pcount = 0; @@ -600,23 +604,20 @@ callout_mx(struct smtp_io_data *iop, const char *hostname, int *pcount) case mf_success: debug1(2,"Checking MX servers for %s", iop->email); rc = mf_not_found; - for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) { - rc = callout_host(iop, mxbuf[i]); + for (i = 0; i < mxbuf.mx_cnt; i++) { + rc = callout_host(iop, mxbuf.mx_buf[i]); if (mf_resolved(rc)) break; } - if (pcount) { - for (; i < MAXMXCOUNT && mxbuf[i]; i++) - ; - *pcount = i; - } - dns_freemx(mxbuf); + if (pcount) + *pcount = mxbuf.mx_cnt; break; default: rc = mxstat; break; } + mxbuf_free(&mxbuf); return rc; } @@ -37,17 +37,22 @@ dns_to_mf_status(dns_status stat) } mf_status -getmx(const char *host, mxbuf_t mxbuf) +getmx(const char *host, struct mxbuf *mxbuf) { - mf_status rc = dns_cache_get(T_MX, host, mxbuf, MAXMXCOUNT); + mf_status rc; + + mxbuf_init(mxbuf); + rc = dns_cache_get(T_MX, host, mxbuf->mx_buf, mxbuf->mx_max, + &mxbuf->mx_cnt); if (!mf_resolved(rc)) { dns_status status; unsigned long ttl; size_t mxcnt; - status = dns_get_mx_records(host, 1, mxbuf, &mxcnt, &ttl); + status = dns_get_mx_records(host, 1, mxbuf, &ttl); if (status == dns_success) - dns_cache_put(T_MX, host, ttl, mxbuf, mxcnt); + dns_cache_put(T_MX, host, ttl, + mxbuf->mx_buf, mxbuf->mx_cnt); else dns_cache_put(T_MX, host, 0, NULL, 0); rc = dns_to_mf_status(status); @@ -56,36 +61,38 @@ getmx(const char *host, mxbuf_t mxbuf) } mf_status -getmxip(char *host, GACOPYZ_UINT32_T ipbuf[MAXMXCOUNT], size_t *pcount) +getmxip(char *host, GACOPYZ_UINT32_T *ipbuf, size_t mxmax, size_t *pcount) { - mxbuf_t mxbuf; + struct mxbuf mxbuf; mf_status mxstat; size_t ipcount; size_t i; - mxstat = getmx(host, mxbuf); + mxbuf.mx_max = mxmax; + mxbuf.mx_flags = MXF_MAX; + mxstat = getmx(host, &mxbuf); if (mxstat != mf_success) return mxstat; ipcount = 0; - for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) { + for (i = 0; i < mxbuf.mx_cnt; i++) { size_t ipn; - mf_status stat = a_lookup(mxbuf[i], + mf_status stat = a_lookup(mxbuf.mx_buf[i], ipbuf + ipcount, - MAXMXCOUNT - ipcount, + mxmax - ipcount, &ipn, NULL, NULL, 0); if (stat == mf_success) { size_t n; - for (n = 0; ipcount < MAXMXCOUNT && n < ipn; + for (n = 0; ipcount < mxmax && n < ipn; n++, ipcount++) ipbuf[ipcount] = ntohl(ipbuf[ipcount]); - if (ipcount == MAXMXCOUNT) + if (ipcount == mxmax) break; } } - dns_freemx(mxbuf); + mxbuf_free(&mxbuf); *pcount = ipcount; return mf_success; } @@ -101,7 +108,7 @@ resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf) answer = xmalloc(MAXPACKET); debug1(80,"Getting canonical name for %s", ipstr); - status = dns_cache_get(T_PTR, ipstr, &hbuf, 1); + status = dns_cache_get(T_PTR, ipstr, &hbuf, 1, NULL); if (status == mf_success) { debug2(80, "%s resolved to %s (cached value)", ipstr, hbuf); *phbuf = hbuf; @@ -149,7 +156,7 @@ resolve_hostname(const char *host, char **pipbuf) if (!answer) answer = malloc(MAXPACKET); debug1(80,"Getting IP address for %s", host); - status = dns_cache_get(T_A, host, &ipbuf, 1); + status = dns_cache_get(T_A, host, &ipbuf, 1, NULL); if (status == mf_success) { debug2(80, "%s resolved to %s (cached value)", host, ipbuf); *pipbuf = ipbuf; @@ -29,8 +29,17 @@ typedef enum { #endif #define MAXMXCOUNT 32 -typedef char *mxbuf_t[MAXMXCOUNT]; +#define MXF_MAX 0x01 +#define MXF_REUSE 0x02 + +struct mxbuf { + int mx_flags; + size_t mx_max; + char **mx_buf; + size_t mx_cnt; +}; + #define MAXCNAMEDEPTH 24 /* FIXME */ #ifdef HAVE_PTHREAD @@ -66,10 +75,12 @@ typedef char *mxbuf_t[MAXMXCOUNT]; #define UPDATE_TTL(m, ttl) do { if ((m) > (ttl)) (m) = (ttl); } while(0) +void mxbuf_init(struct mxbuf *mxbuf); +void mxbuf_free(struct mxbuf *mxbuf); + int dns_str_is_ipv4(const char *addr); -dns_status dns_get_mx_records(const char *host, int maxdepth, mxbuf_t mxbuf, - size_t *mxcount, unsigned long *ttl); -void dns_freemx(mxbuf_t mxbuf); +dns_status dns_get_mx_records(const char *host, int maxdepth, + struct mxbuf *mxbuf, unsigned long *ttl); int dns_reverse_ipstr(const char *ipstr, char *revipstr); diff --git a/mfd/dnsbase.c b/mfd/dnsbase.c index b2b3087b..c3f985c3 100644 --- a/mfd/dnsbase.c +++ b/mfd/dnsbase.c @@ -56,7 +56,7 @@ comp_pref(const void *a, const void *b) static dns_status _getmx(const char *host, unsigned char *answer, size_t answer_size, - mxbuf_t mxbuf, size_t *pcount, unsigned long *pttl) + struct mxbuf *mxbuf, unsigned long *pttl) { int i, n, nmx; struct mx_buffer mx_buffer[MAXMXCOUNT]; @@ -138,7 +138,7 @@ _getmx(const char *host, unsigned char *answer, size_t answer_size, mx_buffer[nmx].name = strdup(tname); debug2(20,"MX %u %s", mx_buffer[nmx].pref, mx_buffer[nmx].name); - if (++nmx >= MAXMXCOUNT) + if (++nmx >= mxbuf->mx_max) break; } @@ -146,10 +146,10 @@ _getmx(const char *host, unsigned char *answer, size_t answer_size, qsort(mx_buffer, nmx, sizeof mx_buffer[0], comp_pref); /* Prepare return value */ - memset(mxbuf, 0, sizeof(mxbuf_t)); + mxbuf_init(mxbuf); for (i = 0; i < nmx; i++) - mxbuf[i] = mx_buffer[i].name; - *pcount = nmx; + mxbuf->mx_buf[i] = mx_buffer[i].name; + mxbuf->mx_cnt = nmx; return dns_success; } @@ -181,8 +181,8 @@ MUTEX_DCL(dns_mutex) to its parent domains until any record is found or recursion depth reaches MAXDEPTH */ dns_status -dns_get_mx_records(const char *host, int maxdepth, mxbuf_t mxbuf, - size_t *mxcount, unsigned long *ttl) +dns_get_mx_records(const char *host, int maxdepth, struct mxbuf *mxbuf, + unsigned long *ttl) { char *hbuf = NULL; dns_status status = dns_failure; @@ -207,7 +207,7 @@ dns_get_mx_records(const char *host, int maxdepth, mxbuf_t mxbuf, if (ttl) *ttl = ~(unsigned long)0; status = _getmx(p, answer, MAXPACKET, mxbuf, - mxcount, ttl); + ttl); if (status == dns_success || status == dns_temp_failure) break; @@ -224,11 +224,35 @@ dns_get_mx_records(const char *host, int maxdepth, mxbuf_t mxbuf, } void -dns_freemx(mxbuf_t mxbuf) +mxbuf_init(struct mxbuf *mxbuf) { - int i; - for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) - free(mxbuf[i]); + if (!(mxbuf->mx_flags & MXF_MAX)) + mxbuf->mx_max = MAXMXCOUNT; + if (mxbuf->mx_flags & MXF_REUSE) { + int i; + + for (i = 0; i < mxbuf->mx_max && mxbuf->mx_buf[i]; i++) { + free(mxbuf->mx_buf[i]); + mxbuf->mx_buf[i] = NULL; + } + } else { + mxbuf->mx_buf = xcalloc(mxbuf->mx_max, + sizeof(mxbuf->mx_buf[0])); + mxbuf->mx_flags |= MXF_REUSE; + } + mxbuf->mx_cnt = 0; +} + +void +mxbuf_free(struct mxbuf *mxbuf) +{ + if (mxbuf->mx_flags & MXF_REUSE) { + int i; + + for (i = 0; i < mxbuf->mx_max && mxbuf->mx_buf[i]; i++) + free(mxbuf->mx_buf[i]); + mxbuf->mx_buf = NULL; + } } #define LOOKUP_FAILURE -1 diff --git a/mfd/dnscache.c b/mfd/dnscache.c index ff1a1c25..47c72684 100644 --- a/mfd/dnscache.c +++ b/mfd/dnscache.c @@ -32,7 +32,7 @@ static mf_status parse_value(int qtype, const char *keystr, - int argc, char **argv, char **rbuf, size_t rcnt) + int argc, char **argv, char **rbuf, size_t rcnt, size_t *pcnt) { size_t i; char *p; @@ -56,6 +56,8 @@ parse_value(int qtype, const char *keystr, rbuf[i] = argv[i + 1]; argv[i + 1] = NULL; } + if (pcnt) + *pcnt = i; for (; i < rcnt; i++) rbuf[i] = NULL; return mf_success; @@ -101,7 +103,8 @@ dns_free_key(DBM_DATUM *key) } mf_status -dns_cache_get(int type, const char *keystr, char **rbuf, size_t rcnt) +dns_cache_get(int type, const char *keystr, char **rbuf, size_t rcnt, + size_t *pcnt) { mf_status rc; DBM_FILE db; @@ -140,7 +143,8 @@ dns_cache_get(int type, const char *keystr, char **rbuf, size_t rcnt) mu_strerror(rc)); rc = mf_failure; } else - rc = parse_value(type, keystr, argc, argv, rbuf, rcnt); + rc = parse_value(type, keystr, argc, argv, rbuf, rcnt, + pcnt); mu_argcv_free(argc, argv); mu_dbm_datum_free(&contents); } else { diff --git a/mfd/mailfromd.h b/mfd/mailfromd.h index 648a57d7..e3adbffe 100644 --- a/mfd/mailfromd.h +++ b/mfd/mailfromd.h @@ -150,8 +150,8 @@ mf_status resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf); mf_status resolve_hostname(const char *host, char **pipbuf); -mf_status getmx(const char *ipstr, mxbuf_t mxbuf); -mf_status getmxip(char *host, GACOPYZ_UINT32_T ipbuf[MAXMXCOUNT], +mf_status getmx(const char *ipstr, struct mxbuf *mxbuf); +mf_status getmxip(char *host, GACOPYZ_UINT32_T *ipbuf, size_t ipmax, size_t *pcount); @@ -244,6 +244,9 @@ enum stack_expand_policy { }; extern enum stack_expand_policy stack_expand_policy; +extern size_t max_callout_mx; +extern size_t max_match_mx; + /* Filter script parser */ @@ -1054,7 +1057,7 @@ mf_status cache_get2(const char *email, const char *client_addr); void cache_insert2(const char *email, const char *client_addr, mf_status rc); mf_status dns_cache_get(int type, const char *keystr, char **rbuf, - size_t rcnt); + size_t rcnt, size_t *pcnt); void dns_cache_put(int type, const char *keystr, time_t ttl, char **rbuf, size_t rcnt); @@ -111,6 +111,9 @@ int stack_trace_option; /* Print stack traces on runtime errors */ char *file_option; /* File name for DB management commands */ struct db_format *format_option; +size_t max_callout_mx = MAXMXCOUNT; +size_t max_match_mx = MAXMXCOUNT; + /* Timeouts */ time_t smtp_timeout_soft[SMTP_NUM_TIMEOUT] = { 10, @@ -2299,12 +2302,19 @@ struct mu_cfg_param mf_cfg_param[] = { { "database", mu_cfg_section, NULL }, + { "max-callout-mx", mu_cfg_size, &max_callout_mx, 0, NULL, + N_("Maximum number of MXs to be polled during " + "callout verification.") }, + { "callout-url", mu_cfg_callback, NULL, 0, cb_callout_url, N_("URL of the callout server"), N_("url") }, + { "max-match-mx", mu_cfg_size, &max_match_mx, 0, NULL, + N_("Maximum number of MXs used by MFL \"mx match\" operation.") }, + { "runtime", mu_cfg_section, NULL }, { NULL } @@ -1391,7 +1391,7 @@ mx_match(eval_environ_t env, char *string, int (*matcher)(const char *name, void *data), void *data) { int rc = 0; - mxbuf_t mxbuf; + struct mxbuf mxbuf; mf_status mxstat; char *p = strchr(string, '@'); @@ -1399,19 +1399,23 @@ mx_match(eval_environ_t env, char *string, p++; else p = string; - mxstat = getmx(p, mxbuf); + mxbuf.mx_max = max_match_mx; + mxbuf.mx_flags = MXF_MAX; + mxstat = getmx(p, &mxbuf); rc = 0; if (mxstat == mf_success) { int i; - for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) { - if (matcher(mxbuf[i], data)) { + for (i = 0; i < mxbuf.mx_cnt; i++) { + if (matcher(mxbuf.mx_buf[i], data)) { rc = 1; break; } } - dns_freemx(mxbuf); - } else if (mxstat != mf_not_found) + } + mxbuf_free(&mxbuf); + + if (!mf_resolved(mxstat)) env_throw(env, mxstat, "cannot get MXs for %s", p); return rc; } @@ -643,8 +643,8 @@ static spf_term_result mech_mx(spf_data *dat, spf_term_arg *arg, unsigned long masklen) { unsigned long netmask = make_netmask(masklen); - mxbuf_t mxbuf; - size_t i, mxcount; + struct mxbuf mxbuf; + size_t i; spf_term_result result = spf_term_nomatch; const char *domain_spec; unsigned long ttl; @@ -657,18 +657,17 @@ mech_mx(spf_data *dat, spf_term_arg *arg, unsigned long masklen) debug2(2, "MX domain_spec=%s, netmask=%x", domain_spec, netmask); - DNS_CATCH(dns_get_mx_records(domain_spec, 1, mxbuf, &mxcount, &ttl)); + mxbuf.mx_flags = MXF_MAX; + mxbuf.mx_max = 10; + DNS_CATCH(dns_get_mx_records(domain_spec, 1, &mxbuf, &ttl)); UPDATE_TTL(dat->ttl, ttl); - if (mxcount > 10) - mxcount = 10; - - for (i = 0; i < mxcount; i++) { + for (i = 0; i < mxbuf.mx_cnt; i++) { spf_term_arg targ; spf_term_result res; targ.type = spf_arg_domain_spec; - targ.v.domain_spec = mxbuf[i]; + targ.v.domain_spec = mxbuf.mx_buf[i]; res = mech_a(dat, &targ, masklen); if (res == spf_term_match) { result = res; @@ -676,7 +675,7 @@ mech_mx(spf_data *dat, spf_term_arg *arg, unsigned long masklen) } } - dns_freemx(mxbuf); + mxbuf_free(&mxbuf); return result; } |