summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS19
-rw-r--r--configure.ac2
-rw-r--r--doc/calloutd.texi1
-rw-r--r--doc/functions.texi22
-rw-r--r--doc/mailfromd.texi89
-rw-r--r--doc/upgrade.texi23
-rw-r--r--lib/dns.c397
-rw-r--r--lib/dns.h46
-rw-r--r--lib/libmf.h2
-rw-r--r--src/builtin/dns.bi94
-rw-r--r--src/callout.c2
-rw-r--r--src/mailfromd.h3
-rw-r--r--src/main.c5
-rw-r--r--src/prog.c2
-rw-r--r--src/spf.c80
-rw-r--r--src/spf.h3
-rw-r--r--src/srvcfg.c5
17 files changed, 370 insertions, 425 deletions
diff --git a/NEWS b/NEWS
index c372865..9e7a8d7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,27 @@
1Mailfromd NEWS -- history of user-visible changes. 2017-10-18 1Mailfromd NEWS -- history of user-visible changes. 2017-10-19
2Copyright (C) 2005-2017 Sergey Poznyakoff 2Copyright (C) 2005-2017 Sergey Poznyakoff
3See the end of file for copying conditions. 3See the end of file for copying conditions.
4 4
5Please send Mailfromd bug reports to <bug-mailfromd@gnu.org.ua> 5Please send Mailfromd bug reports to <bug-mailfromd@gnu.org.ua>
6 6
7 7
8Version 8.2.90
9
10* Removed arbitrary limits on the sizes of DNS RRs
11
12The following configuration statements are removed:
13
14** runtime.max-dns-reply-a
15
16** runtime.max-dns-reply-ptr
17
18** runtime.max-dns-reply-mx
19
20** max-match-mx
21
22** max-callout-mx
23
24
8Version 8.2, 2017-10-18 25Version 8.2, 2017-10-18
9 26
10The purpose of this release is to simplify packaging with alpha 27The purpose of this release is to simplify packaging with alpha
diff --git a/configure.ac b/configure.ac
index 53e8742..2dd23ba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
17AC_PREREQ(2.63) 17AC_PREREQ(2.63)
18m4_define([MF_VERSION_MAJOR], 8) 18m4_define([MF_VERSION_MAJOR], 8)
19m4_define([MF_VERSION_MINOR], 2) 19m4_define([MF_VERSION_MINOR], 2)
20dnl m4_define([MF_VERSION_PATCH], 0) 20m4_define([MF_VERSION_PATCH], 90)
21AC_INIT([mailfromd], 21AC_INIT([mailfromd],
22 MF_VERSION_MAJOR.MF_VERSION_MINOR[]m4_ifdef([MF_VERSION_PATCH],.MF_VERSION_PATCH), 22 MF_VERSION_MAJOR.MF_VERSION_MINOR[]m4_ifdef([MF_VERSION_PATCH],.MF_VERSION_PATCH),
23 [bug-mailfromd@gnu.org.ua], 23 [bug-mailfromd@gnu.org.ua],
diff --git a/doc/calloutd.texi b/doc/calloutd.texi
index 87f5d62..5bd9191 100644
--- a/doc/calloutd.texi
+++ b/doc/calloutd.texi
@@ -81,7 +81,6 @@ mailutils, GNU Mailutils Manual}.
81@item @code{mailer} @tab @xref{mailer statement, Mailutils Configuration File,, 81@item @code{mailer} @tab @xref{mailer statement, Mailutils Configuration File,,
82mailutils, GNU Mailutils Manual}. 82mailutils, GNU Mailutils Manual}.
83@item @code{mail-from-address} @tab @xref{conf-callout, mail-from-address}. 83@item @code{mail-from-address} @tab @xref{conf-callout, mail-from-address}.
84@item @code{max-callout-mx} @tab @xref{conf-callout, max-callout-mx}.
85@item @code{pidfile} @tab @xref{conf-calloutd-setup, pidfile}. 84@item @code{pidfile} @tab @xref{conf-calloutd-setup, pidfile}.
86@item @code{server} @tab @xref{conf-calloutd-server}. 85@item @code{server} @tab @xref{conf-calloutd-server}.
87@item @code{source-ip} @tab @xref{conf-calloutd-setup, source-ip}. 86@item @code{source-ip} @tab @xref{conf-calloutd-setup, source-ip}.
diff --git a/doc/functions.texi b/doc/functions.texi
index b5a33c7..a9fb3e3 100644
--- a/doc/functions.texi
+++ b/doc/functions.texi
@@ -1920,18 +1920,14 @@ require dns
1920 1920
1921@deftypefn {Built-in Function} string dns_getaddr (string @var{domain}) 1921@deftypefn {Built-in Function} string dns_getaddr (string @var{domain})
1922 Returns a whitespace-separated list of @acronym{IP} addresses (@code{A} 1922 Returns a whitespace-separated list of @acronym{IP} addresses (@code{A}
1923records) for @var{domain}. At most @value{MAX_DNS_A} addresses are 1923records) for @var{domain}.
1924returned. @xref{conf-runtime, max-dns-reply-a}, for a description of how
1925to change this limit.
1926 1924
1927 This function does not use the @acronym{DNS} cache. 1925 This function does not use the @acronym{DNS} cache.
1928@end deftypefn 1926@end deftypefn
1929 1927
1930@deftypefn {Built-in Function} string dns_getname (string @var{ipstr}) 1928@deftypefn {Built-in Function} string dns_getname (string @var{ipstr})
1931 Returns a whitespace-separated list of domain names (@code{PTR} 1929 Returns a whitespace-separated list of domain names (@code{PTR}
1932records) for the @acronym{IP}v4 address @var{ipstr}. At most 1930records) for the @acronym{IP}v4 address @var{ipstr}.
1933@value{MAX_DNS_PTR} names are returned. @xref{conf-runtime,
1934max-dns-reply-ptr}, for a description of how to change this limit.
1935 1931
1936 This function does not use the @acronym{DNS} cache. 1932 This function does not use the @acronym{DNS} cache.
1937@end deftypefn 1933@end deftypefn
@@ -1955,12 +1951,8 @@ getmx("gnu.org") @result{} "mx10.gnu.org mx20.gnu.org"
1955getmx("org.pl") @result{} "" 1951getmx("org.pl") @result{} ""
1956@end smallexample 1952@end smallexample
1957 1953
1958@emph{Notes}: 1954@emph{Note}:
1959@enumerate 1 1955@enumerate 1
1960@item The number of @acronym{MX} names or @acronym{IP} addresses
1961returned by @code{getmx} is limited by the value of
1962@code{max-dns-reply-mx} configuration statement (default
1963@value{MAX_DNS_MX}). @xref{conf-runtime, max-dns-reply-mx}.
1964 1956
1965@item The number of items returned by @code{getmx(@var{domain})} can 1957@item The number of items returned by @code{getmx(@var{domain})} can
1966differ from that obtained from @code{getmx(@var{domain}, 1)}, e.g.: 1958differ from that obtained from @code{getmx(@var{domain}, 1)}, e.g.:
@@ -2056,10 +2048,6 @@ exception @code{e_not_found}.
2056 2048
2057 If @acronym{DNS} query fails, the function raises @code{failure} or 2049 If @acronym{DNS} query fails, the function raises @code{failure} or
2058@code{temp_failure}, depending on the character of the failure. 2050@code{temp_failure}, depending on the character of the failure.
2059
2060 The number of @samp{MX} records examined by this function is limited
2061by the value of the @code{max-dns-reply-mx} configuration statement
2062(@pxref{conf-runtime, max-dns-reply-mx}.
2063@end deftypefn 2051@end deftypefn
2064 2052
2065@anchor{ismx} 2053@anchor{ismx}
@@ -2073,10 +2061,6 @@ records for the @var{domain}. Otherwise it returns @code{false}.
2073 2061
2074 If @var{domain} has no @samp{MX} records, or if the @acronym{DNS} query fails, the 2062 If @var{domain} has no @samp{MX} records, or if the @acronym{DNS} query fails, the
2075function returns @code{false}. 2063function returns @code{false}.
2076
2077 The number of @samp{MX} records examined by this function is limited
2078by the value of the @code{max-dns-reply-mx} configuration statement
2079(@pxref{conf-runtime, max-dns-reply-mx}.
2080@end deftypefn 2064@end deftypefn
2081 2065
2082@deftypefn {Built-in Function} string primitive_resolve (string @var{host}, @ 2066@deftypefn {Built-in Function} string primitive_resolve (string @var{host}, @
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi
index 05c9e83..d28915f 100644
--- a/doc/mailfromd.texi
+++ b/doc/mailfromd.texi
@@ -339,7 +339,6 @@ Configuring @command{mailfromd}
339* conf-priv:: Privilege Configuration 339* conf-priv:: Privilege Configuration
340* conf-database:: Database Configuration 340* conf-database:: Database Configuration
341* conf-runtime:: Runtime Constants 341* conf-runtime:: Runtime Constants
342* conf-other:: Other Configuration Statements
343* conf-mailutils:: Standard Mailutils Statements 342* conf-mailutils:: Standard Mailutils Statements
344 343
345@command{Mailfromd} Command Line Syntax 344@command{Mailfromd} Command Line Syntax
@@ -471,38 +470,38 @@ possibilities.
471 470
472 After a short run on my mail servers, I discovered that the utility 471 After a short run on my mail servers, I discovered that the utility
473was not flexible enough. It took less than a month to implement a 472was not flexible enough. It took less than a month to implement a
474configuration file that allowed to control program and data flow 473configuration file that allowed the user to control program and data flow
475during the @samp{envfrom} @acronym{SMTP} state. The new version, 1.0, 474during the @samp{envfrom} @acronym{SMTP} state. The new version, 1.0,
476appeared in June, 2005. 475appeared in June, 2005.
477 476
478 The next major release, 1.2 (1.1 contained mostly bugfixes), 477 Next major release, 1.2 (1.1 contained mostly bugfixes),
479appeared two months later, which introduced @dfn{mail sending rate} 478appeared two months later, and introduced @dfn{mail sending rate}
480control (@pxref{Rate Limit}). 479control (@pxref{Rate Limit}).
481 480
482 The program evolved during the next year, which led to the 481 The program evolved during the next year, and the version 2.0 was
483release of version 2.0 in September, 2006. This version was a major 482released in September, 2006. This version was a major change in the
484change in the main idea of the program. Configuration file become a 483main idea of the program. Configuration file become a flexible filter
485flexible filter script allowing to control almost all @acronym{SMTP} 484script allowing the operator to control almost all @acronym{SMTP} states. The
486states. The program supplied in the script file 485program supplied in the script file was compiled into a pseudo-code at
487was compiled into a pseudo-code at startup, this code being subsequently 486startup, this code being subsequently evaluated each time the filter
488evaluated each time the filter was invoked. This caused a considerable 487was invoked. This caused a considerable speed-up in comparison with
489speed-up in comparison with the previous versions, where the run-time 488the previous versions, where the run-time evaluator was traversing the
490evaluator was traversing the parse tree. This version also introduced 489parse tree. This version also introduced (implicitly, at the time),
491(implicitly, at the time), two separate data types for the entities 490two separate data types for the entities declared in the script, which
492declared in the script, which also played its role in the speed 491also played its role in the speed improvement (in the previous
493improvement (in the previous versions all data were considered 492versions all data were considered strings). Lots of improvements were
494strings). Lots of improvements were made in the filter language 493made in the filter language (@acronym{MFL}, @pxref{MFL}) itself, such
495(@acronym{MFL}, @pxref{MFL}) itself, such as user-defined functions, 494as user-defined functions, the @code{switch} statement, the @code{catch}
496@code{switch} statement, @code{catch} statement that allows to handle 495statement for handling run-time errors, etc. The set of
497run-time errors, etc. The set of built-in functions extended 496built-in functions extended considerably. A testsuite (using
498considerably. A testsuite (using @i{DejaGNU}) was introduced in this version. 497@i{DejaGNU}) was introduced in this version.
499 498
500 During this initial development period the limitations 499 During this initial development period the limitations
501imposed by @command{libmilter} implementation became obvious. Finally, 500imposed by @command{libmilter} implementation became obvious. Finally,
502I felt they were stopping further development, and decided 501I felt they were stopping further development, and decided
503that @command{mailfromd} should use its own @samp{Milter} 502that @command{mailfromd} should use its own @samp{Milter}
504implementation. This new library, @command{libgacopyz} was the main 503implementation. This new library, @command{libgacopyz} was the main
505new feature of the 3.0 release, that was released in November, 2006. 504new feature of the 3.0 release, which was released in November, 2006.
506Another major feature was the @option{--dump-macros} option and 505Another major feature was the @option{--dump-macros} option and
507@option{macros} to @command{rc.mailfromd} script, that were intended 506@option{macros} to @command{rc.mailfromd} script, that were intended
508to facilitate the configuration on @samp{Sendmail} side. 507to facilitate the configuration on @samp{Sendmail} side.
@@ -521,7 +520,7 @@ eliminated many run-time errors. This version also provided a
521foundation for @acronym{MFL} module system. The code generation 520foundation for @acronym{MFL} module system. The code generation
522was re-implemented to facilitate introduction of object files in 521was re-implemented to facilitate introduction of object files in
523future versions. Another new features in this release include 522future versions. Another new features in this release include
524@acronym{SPF} support and @command{mtasim} utility, an @acronym{MTA} 523@acronym{SPF} support and @command{mtasim} utility --- an @acronym{MTA}
525simulator designed for testing @command{mailfromd} scripts 524simulator designed for testing @command{mailfromd} scripts
526(@pxref{mtasim}). The test suite in this version was made portable by 525(@pxref{mtasim}). The test suite in this version was made portable by
527rewriting it in @i{Autotest}. 526rewriting it in @i{Autotest}.
@@ -541,9 +540,9 @@ a full-fledged modular system, akin to that of Python, and quite a few
541improvements to the language. such as explicit type casts, 540improvements to the language. such as explicit type casts,
542concatenation operator, static variables, etc. 541concatenation operator, static variables, etc.
543 542
544 Starting from version 7.0, main focus of further development of 543 Starting from version 7.0, the focus of further development of
545@command{mailfromd} has shifted. While previously it was regarded 544@command{mailfromd} has shifted. While previously it had been regarded
546as a mail-filtering server, now it is being developed as a system for 545as a mail-filtering server, since then it was developed as a system for
547extending @acronym{MTA} functionality in the broad sense, mail 546extending @acronym{MTA} functionality in the broad sense, mail
548filtering being only one of features it provides. 547filtering being only one of features it provides.
549 548
@@ -6468,10 +6467,6 @@ returns true. Otherwise, its result is false.
6468returns true only if any of the @samp{MX}s for (domain or email) @var{x} 6467returns true only if any of the @samp{MX}s for (domain or email) @var{x}
6469match the globbing pattern @var{y}. 6468match the globbing pattern @var{y}.
6470 6469
6471 These operators examine at most @value{MAX_DNS_MX} @samp{MX}
6472records. To change this limit, use the @code{max-match-mx}
6473configuration statement (@pxref{conf-other, max-match-mx}).
6474
6475 Both @code{mx matches} and @code{mx fnmatches} can signal the 6470 Both @code{mx matches} and @code{mx fnmatches} can signal the
6476following exceptions: @code{e_temp_failure}, @code{e_failure}. 6471following exceptions: @code{e_temp_failure}, @code{e_failure}.
6477 6472
@@ -9088,7 +9083,6 @@ program calloutd @{
9088* conf-priv:: Privilege Configuration 9083* conf-priv:: Privilege Configuration
9089* conf-database:: Database Configuration 9084* conf-database:: Database Configuration
9090* conf-runtime:: Runtime Constants 9085* conf-runtime:: Runtime Constants
9091* conf-other:: Other Configuration Statements
9092* conf-mailutils:: Standard Mailutils Statements 9086* conf-mailutils:: Standard Mailutils Statements
9093@end menu 9087@end menu
9094 9088
@@ -9532,11 +9526,6 @@ setvar mailfrom_address @var{string};
9532@end smallexample 9526@end smallexample
9533@end deffn 9527@end deffn
9534 9528
9535@deffn {Mailfromd Conf} max-callout-mx number
9536 Sets the maximum number of MXs to be polled during a callout
9537verification. Defaults to @value{MAX_DNS_MX}.
9538@end deffn
9539
9540@deffn {Mailfromd Conf} enable-vrfy bool 9529@deffn {Mailfromd Conf} enable-vrfy bool
9541@cindex VRFY, SMTP statement 9530@cindex VRFY, SMTP statement
9542 Enables the use of SMTP VRFY statement prior to normal callout 9531 Enables the use of SMTP VRFY statement prior to normal callout
@@ -9680,34 +9669,6 @@ using the @code{mailbox_get_message} function. @xref{Message
9680functions}, for details. 9669functions}, for details.
9681@end deffn 9670@end deffn
9682 9671
9683@deffn {runtime} max-dns-reply-a number
9684Sets the maximum number of @acronym{DNS} @samp{A} records to be
9685returned in a reply. This affects the @code{dns_getaddr} function
9686(@pxref{DNS functions, dns_getaddr}). The default value is @value{MAX_DNS_A}.
9687@end deffn
9688
9689@deffn {runtime} max-dns-reply-ptr number
9690Sets the maximum number of @acronym{DNS} @samp{PTR} records to be
9691returned in a reply. This affects the @code{dns_getname} function
9692(@pxref{DNS functions, dns_getname}). The default value is @value{MAX_DNS_PTR}.
9693@end deffn
9694
9695@deffn {runtime} max-dns-reply-mx number
9696Sets the maximum number of @acronym{DNS} @samp{MX} records to be
9697returned in a reply. This affects the following functions:
9698@code{getpx}, @code{ismx}, @code{primitive_mx}
9699(@pxref{DNS functions}). The default value is @value{MAX_DNS_MX}.
9700@end deffn
9701
9702@node conf-other
9703@section Other Configuration Statements
9704
9705@deffn {Mailfromd Conf} max-match-mx number
9706Sets the maximum number of MXs to use in @samp{mx matches} operations
9707(@pxref{mx matches}). Defaults to @value{MAX_DNS_MX}.
9708@end deffn
9709
9710
9711@node conf-mailutils 9672@node conf-mailutils
9712@section Standard Mailutils Statements 9673@section Standard Mailutils Statements
9713 9674
diff --git a/doc/upgrade.texi b/doc/upgrade.texi
index ab7f7ec..03c3f59 100644
--- a/doc/upgrade.texi
+++ b/doc/upgrade.texi
@@ -10,6 +10,7 @@ The following sections describe procedures for upgrading
10between the consecutive Mailfromd releases. 10between the consecutive Mailfromd releases.
11 11
12@menu 12@menu
13* 820-830:: Upgrading from 8.2 to 8.3
13* 700-800:: Upgrading from 7.0 to 8.0 14* 700-800:: Upgrading from 7.0 to 8.0
14* 600-700:: Upgrading from 6.0 to 7.0 15* 600-700:: Upgrading from 6.0 to 7.0
15* 5x0-600:: Upgrading from 5.x to 6.0 16* 5x0-600:: Upgrading from 5.x to 6.0
@@ -25,6 +26,28 @@ between the consecutive Mailfromd releases.
25* 1x-2x:: Upgrading from 1.x to 2.x 26* 1x-2x:: Upgrading from 1.x to 2.x
26@end menu 27@end menu
27 28
29@node 820-830
30@appendixsec Upgrading from 8.2 to 8.3
31@cindex Upgrading from 8.2 to 8.3
32
33 Version 8.3 contains significant improvements in the DNS
34resolver. In particular, it removes arbitrary limits on the sizes
35of the RRs. Consequently, the following configurations statements
36are withdrawn:
37
38@table @code
39@item runtime.max-dns-reply-a
40
41@item runtime.max-dns-reply-ptr
42
43@item runtime.max-dns-reply-mx
44
45@item max-match-mx
46
47@item max-callout-mx
48@end table
49
50
28@node 700-800 51@node 700-800
29@appendixsec Upgrading from 7.0 to 8.0 52@appendixsec Upgrading from 7.0 to 8.0
30@cindex Upgrading from 7.0 to 8.0 53@cindex Upgrading from 7.0 to 8.0
diff --git a/lib/dns.c b/lib/dns.c
index e23e9ce..73c2364 100644
--- a/lib/dns.c
+++ b/lib/dns.c
@@ -31,6 +31,7 @@
31#include "libmf.h" 31#include "libmf.h"
32#include "dns.h" 32#include "dns.h"
33#include "mailutils/alloc.h" 33#include "mailutils/alloc.h"
34#include "mailutils/argcv.h"
34 35
35struct mx_buffer { 36struct mx_buffer {
36 unsigned pref; 37 unsigned pref;
@@ -70,8 +71,10 @@ static dns_status
70_getmx(const char *host, unsigned char *answer, size_t answer_size, 71_getmx(const char *host, unsigned char *answer, size_t answer_size,
71 struct mxbuf *mxbuf, unsigned long *pttl) 72 struct mxbuf *mxbuf, unsigned long *pttl)
72{ 73{
73 int i, n, nmx; 74 struct mx_buffer *mx_buffer = NULL;
74 struct mx_buffer mx_buffer[MAXMXCOUNT]; 75 size_t mx_max = 0;
76 size_t nmx = 0;
77 int i, n;
75 HEADER *hp; 78 HEADER *hp;
76 unsigned char *eom, *cp; 79 unsigned char *eom, *cp;
77 unsigned short qdcount, ancount; 80 unsigned short qdcount, ancount;
@@ -149,23 +152,28 @@ _getmx(const char *host, unsigned char *answer, size_t answer_size,
149 tname, sizeof tname)) < 0) 152 tname, sizeof tname)) < 0)
150 break; 153 break;
151 cp += n; 154 cp += n;
155 if (nmx == mx_max)
156 mx_buffer = mu_2nrealloc(mx_buffer,
157 &mx_max,
158 sizeof(mx_buffer[0]));
159
152 mx_buffer[nmx].pref = pref; 160 mx_buffer[nmx].pref = pref;
153 mx_buffer[nmx].name = strdup(tname); 161 mx_buffer[nmx].name = mu_strdup(tname);
154 mu_debug(debug_handle, MU_DEBUG_TRACE2, 162 mu_debug(debug_handle, MU_DEBUG_TRACE2,
155 ("MX %u %s", mx_buffer[nmx].pref, 163 ("MX %u %s", mx_buffer[nmx].pref,
156 mx_buffer[nmx].name)); 164 mx_buffer[nmx].name));
157 if (++nmx >= mxbuf->mx_max) 165 nmx++;
158 break;
159 } 166 }
160 167
161 /* Sort according to preference value */ 168 /* Sort according to preference value */
162 qsort(mx_buffer, nmx, sizeof mx_buffer[0], comp_pref); 169 qsort(mx_buffer, nmx, sizeof mx_buffer[0], comp_pref);
163 170
164 /* Prepare return value */ 171 /* Prepare return value */
165 mxbuf_init(mxbuf); 172 mxbuf_init(mxbuf, nmx);
166 for (i = 0; i < nmx; i++) 173 for (i = 0; i < nmx; i++)
167 mxbuf->mx_buf[i] = mx_buffer[i].name; 174 mxbuf->mx_buf[i] = mx_buffer[i].name;
168 mxbuf->mx_cnt = nmx; 175 mxbuf->mx_cnt = i;
176 free(mx_buffer);
169 return dns_success; 177 return dns_success;
170} 178}
171 179
@@ -211,28 +219,23 @@ dns_get_mx_records(const char *host, int maxdepth, struct mxbuf *mxbuf,
211 } 219 }
212 220
213 if (host) { 221 if (host) {
214 unsigned char *answer = malloc(MAXPACKET); 222 unsigned char *answer = mu_alloc(MAXPACKET);
215 if (!answer) 223 const char *p;
216 status = dns_failure; 224 int depth;
217 else {
218 const char *p;
219 int depth;
220 225
221 for (p = host, depth = 0; p && depth < maxdepth; 226 for (p = host, depth = 0; p && depth < maxdepth;
222 p++, depth++) { 227 p++, depth++) {
223 if (ttl) 228 if (ttl)
224 *ttl = ~(unsigned long)0; 229 *ttl = ~(unsigned long)0;
225 status = _getmx(p, answer, MAXPACKET, mxbuf, 230 status = _getmx(p, answer, MAXPACKET, mxbuf, ttl);
226 ttl); 231 if (status == dns_success
227 if (status == dns_success 232 || status == dns_temp_failure)
228 || status == dns_temp_failure) 233 break;
229 break; 234 p = strchr(p, '.');
230 p = strchr(p, '.'); 235 if (!p)
231 if (!p) 236 break;
232 break;
233 }
234 free(answer);
235 } 237 }
238 free(answer);
236 } 239 }
237 MUTEX_UNLOCK(dns_mutex); 240 MUTEX_UNLOCK(dns_mutex);
238 free(hbuf); 241 free(hbuf);
@@ -240,20 +243,24 @@ dns_get_mx_records(const char *host, int maxdepth, struct mxbuf *mxbuf,
240} 243}
241 244
242void 245void
243mxbuf_init(struct mxbuf *mxbuf) 246mxbuf_init(struct mxbuf *mxbuf, size_t nmx)
244{ 247{
245 if (!(mxbuf->mx_flags & MXF_MAX))
246 mxbuf->mx_max = MAXMXCOUNT;
247 if (mxbuf->mx_flags & MXF_REUSE) { 248 if (mxbuf->mx_flags & MXF_REUSE) {
248 int i; 249 size_t i;
249 250
250 for (i = 0; i < mxbuf->mx_max && mxbuf->mx_buf[i]; i++) { 251 for (i = 0; i < mxbuf->mx_cnt; i++) {
251 free(mxbuf->mx_buf[i]); 252 free(mxbuf->mx_buf[i]);
252 mxbuf->mx_buf[i] = NULL; 253 mxbuf->mx_buf[i] = NULL;
253 } 254 }
255 if (nmx > mxbuf->mx_max) {
256 mxbuf->mx_buf =
257 mu_realloc(mxbuf->mx_buf,
258 nmx * sizeof(mxbuf->mx_buf[0]));
259 mxbuf->mx_max = nmx;
260 }
254 } else { 261 } else {
255 mxbuf->mx_buf = mu_calloc(mxbuf->mx_max, 262 mxbuf->mx_buf = mu_calloc(nmx, sizeof(mxbuf->mx_buf[0]));
256 sizeof(mxbuf->mx_buf[0])); 263 mxbuf->mx_max = nmx;
257 mxbuf->mx_flags |= MXF_REUSE; 264 mxbuf->mx_flags |= MXF_REUSE;
258 } 265 }
259 mxbuf->mx_cnt = 0; 266 mxbuf->mx_cnt = 0;
@@ -267,7 +274,10 @@ mxbuf_free(struct mxbuf *mxbuf)
267 274
268 for (i = 0; i < mxbuf->mx_max && mxbuf->mx_buf[i]; i++) 275 for (i = 0; i < mxbuf->mx_max && mxbuf->mx_buf[i]; i++)
269 free(mxbuf->mx_buf[i]); 276 free(mxbuf->mx_buf[i]);
277 free(mxbuf->mx_buf);
270 mxbuf->mx_buf = NULL; 278 mxbuf->mx_buf = NULL;
279 mxbuf->mx_flags &= ~MXF_REUSE;
280 mxbuf->mx_cnt = mxbuf->mx_max = 0;
271 } 281 }
272} 282}
273 283
@@ -275,6 +285,44 @@ mxbuf_free(struct mxbuf *mxbuf)
275#define LOOKUP_SUCCESS 0 285#define LOOKUP_SUCCESS 0
276#define LOOKUP_CNAME 1 286#define LOOKUP_CNAME 1
277 287
288void
289dns_reply_free(struct dns_reply *r)
290{
291 if (r->base) {
292 size_t i;
293 for (i = 0; i < r->count; i++)
294 free(r->base[i]);
295 free(r->base);
296 }
297}
298
299static void
300dns_reply_append(struct dns_reply *r, void *ptr, size_t len, int last)
301{
302 if (r->count == r->max)
303 r->base = mu_2nrealloc(r->base,
304 &r->max,
305 sizeof(r->base[0]));
306 if (last && r->count) {
307 while (r->last_len + len > r->last_max)
308 r->base[r->count-1] =
309 mu_2nrealloc(r->base[r->count-1],
310 &r->last_max,
311 1);
312 } else if (ptr == NULL) {
313 r->base[r->count] = NULL;
314 return;
315 } else {
316 r->base[r->count] = mu_alloc(len);
317 r->count++;
318 r->last_len = 0;
319 r->last_max = len;
320 }
321
322 memcpy((char*)r->base[r->count-1] + r->last_len, ptr, len);
323 r->last_len += len;
324}
325
278struct loop_data { 326struct loop_data {
279 int qtype; /* Type of the query */ 327 int qtype; /* Type of the query */
280 char *name; /* Key to look up */ 328 char *name; /* Key to look up */
@@ -285,9 +333,7 @@ struct loop_data {
285 size_t answer_size; /* Size of answer buffer */ 333 size_t answer_size; /* Size of answer buffer */
286 334
287 /* Return data: */ 335 /* Return data: */
288 char *hbuf; /* Return buffer */ 336 struct dns_reply repl;
289 size_t hbsize; /* Size of return buffer */
290 size_t hbcount; /* Number of items returned */
291 337
292 time_t ttl; /* TTL value */ 338 time_t ttl; /* TTL value */
293 dns_status status; /* Status */ 339 dns_status status; /* Status */
@@ -431,20 +477,11 @@ cname_loop_body(struct loop_data *lp)
431 if (bp + n >= nbuf + blen) { 477 if (bp + n >= nbuf + blen) {
432 mu_debug(debug_handle, MU_DEBUG_TRACE0, 478 mu_debug(debug_handle, MU_DEBUG_TRACE0,
433 ("size (%d) too big", n)); 479 ("size (%d) too big", n));
480 } else if (n != sizeof(GACOPYZ_UINT32_T)) {
481 mu_debug(debug_handle, MU_DEBUG_TRACE0,
482 ("unsupported address size: %d", n));
434 } else { 483 } else {
435 if (n != sizeof(GACOPYZ_UINT32_T)) { 484 dns_reply_append(&lp->repl, cp, n, 0);
436 mu_debug(debug_handle, MU_DEBUG_TRACE0,
437 ("unsupported address size: %d",
438 n));
439 } else if (lp->hbcount * sizeof(GACOPYZ_UINT32_T) >= lp->hbsize)
440 mu_debug(debug_handle, MU_DEBUG_TRACE0,
441 ("Too many addresses"));
442 else {
443 memmove((GACOPYZ_UINT32_T *)
444 lp->hbuf + lp->hbcount,
445 cp, n);
446 lp->hbcount++;
447 }
448 } 485 }
449 bp += n; 486 bp += n;
450 blen -= n; 487 blen -= n;
@@ -460,13 +497,8 @@ cname_loop_body(struct loop_data *lp)
460 nbuf, sizeof(nbuf))) < 0) { 497 nbuf, sizeof(nbuf))) < 0) {
461 SET_STATUS(lp, dns_failure); 498 SET_STATUS(lp, dns_failure);
462 return LOOKUP_FAILURE; 499 return LOOKUP_FAILURE;
463 } 500 }
464 l = strlen(nbuf); 501 dns_reply_append(&lp->repl, nbuf, strlen(nbuf) + 1, 0);
465 if (lp->hbcount + l >= lp->hbsize)
466 break;
467 memcpy(lp->hbuf + lp->hbcount, nbuf, l);
468 lp->hbcount += l;
469 lp->hbuf[lp->hbcount++] = 0;
470 lp->atype = T_PTR; 502 lp->atype = T_PTR;
471 SET_STATUS(lp, dns_success); 503 SET_STATUS(lp, dns_success);
472 break; 504 break;
@@ -476,17 +508,18 @@ cname_loop_body(struct loop_data *lp)
476 continue; 508 continue;
477 else { 509 else {
478 unsigned char *cur, *end; 510 unsigned char *cur, *end;
511 int i = 0;
512
479 cur = cp; 513 cur = cp;
480 end = cp + n; 514 end = cp + n;
481 while (cur < end) { 515 while (cur < end) {
482 l = *cur++; 516 l = *cur++;
483 if (lp->hbcount + l >= lp->hbsize) 517 dns_reply_append(&lp->repl,
484 break; 518 cur, l,
485 memcpy(lp->hbuf + lp->hbcount, cur, l); 519 i > 0);
486 lp->hbcount += l; 520 i++;
487 cur += l;
488 } 521 }
489 lp->hbuf[lp->hbcount++] = 0; 522 dns_reply_append(&lp->repl, "", 1, 1);
490 lp->atype = T_TXT; 523 lp->atype = T_TXT;
491 SET_STATUS(lp, dns_success); 524 SET_STATUS(lp, dns_success);
492 } 525 }
@@ -534,6 +567,14 @@ static void
534cnameloop(struct loop_data *lp) 567cnameloop(struct loop_data *lp)
535{ 568{
536 MUTEX_LOCK(dns_mutex); 569 MUTEX_LOCK(dns_mutex);
570
571 lp->ttl = ~(unsigned long)0;
572 lp->repl.base = NULL;
573 lp->repl.max = 0;
574 lp->repl.count = 0;
575 lp->status = dns_failure;
576 lp->loopcnt = MAXCNAMEDEPTH;
577
537 if (!lp->answer) { 578 if (!lp->answer) {
538 static unsigned char *answer; 579 static unsigned char *answer;
539 if (!answer) 580 if (!answer)
@@ -587,7 +628,7 @@ dns_reverse_ipstr(const char *ipstr, char *revipstr)
587dns_status 628dns_status
588dns_resolve_ipstr(const char *ipstr, const char *domain, 629dns_resolve_ipstr(const char *ipstr, const char *domain,
589 unsigned char *answer, size_t answer_size, 630 unsigned char *answer, size_t answer_size,
590 char *hbuf, size_t hbsize, unsigned long *ttl) 631 char **hbuf, unsigned long *ttl)
591{ 632{
592 char namebuf[NSIZE]; 633 char namebuf[NSIZE];
593 char domainbuf[NSIZE]; 634 char domainbuf[NSIZE];
@@ -613,21 +654,19 @@ dns_resolve_ipstr(const char *ipstr, const char *domain,
613 ld.domain_size = sizeof domainbuf; 654 ld.domain_size = sizeof domainbuf;
614 ld.answer = answer; 655 ld.answer = answer;
615 ld.answer_size = answer_size; 656 ld.answer_size = answer_size;
616 ld.hbuf = hbuf;
617 ld.hbsize = hbsize;
618 ld.hbcount = 0;
619 ld.ttl = ~(unsigned long)0;
620 ld.status = dns_failure;
621 ld.loopcnt = MAXCNAMEDEPTH;
622 657
623 cnameloop(&ld); 658 cnameloop(&ld);
624 659
625 if (ld.status == dns_success && ld.atype == T_A) { 660 if (ld.status == dns_success) {
626 struct in_addr s; 661 if (ld.atype == T_A) {
627 char *p; 662 struct in_addr s;
628 s.s_addr = *(GACOPYZ_UINT32_T*)hbuf; 663 s.s_addr = *(GACOPYZ_UINT32_T*)ld.repl.base[0];
629 p = inet_ntoa(s); 664 *hbuf = mu_strdup(inet_ntoa(s));
630 strncpy(hbuf, p, hbsize); 665 } else if (ld.atype == T_PTR) {
666 *hbuf = mu_strdup(ld.repl.base[0]);
667 } else
668 abort();
669 dns_reply_free(&ld.repl);
631 } 670 }
632 671
633 *ttl = ld.ttl; 672 *ttl = ld.ttl;
@@ -637,7 +676,7 @@ dns_resolve_ipstr(const char *ipstr, const char *domain,
637dns_status 676dns_status
638dns_resolve_hostname(const char *host, 677dns_resolve_hostname(const char *host,
639 unsigned char *answer, size_t answer_size, 678 unsigned char *answer, size_t answer_size,
640 char *ipbuf, size_t ipbsize, unsigned long *ttl) 679 char **ipbuf, unsigned long *ttl)
641{ 680{
642 struct loop_data ld; 681 struct loop_data ld;
643 char namebuf[NSIZE]; 682 char namebuf[NSIZE];
@@ -653,21 +692,14 @@ dns_resolve_hostname(const char *host,
653 ld.domain_size = sizeof domainbuf; 692 ld.domain_size = sizeof domainbuf;
654 ld.answer = answer; 693 ld.answer = answer;
655 ld.answer_size = answer_size; 694 ld.answer_size = answer_size;
656 ld.hbuf = ipbuf;
657 ld.hbsize = ipbsize;
658 ld.hbcount = 0;
659 ld.ttl = ~(unsigned long)0;
660 ld.status = dns_failure;
661 ld.loopcnt = MAXCNAMEDEPTH;
662 695
663 cnameloop(&ld); 696 cnameloop(&ld);
664 697
665 if (ld.status == dns_success && ld.atype == T_A) { 698 if (ld.status == dns_success && ld.atype == T_A) {
666 struct in_addr s; 699 struct in_addr s;
667 char *p; 700 s.s_addr = *(GACOPYZ_UINT32_T*)ld.repl.base[0];
668 s.s_addr = *(GACOPYZ_UINT32_T*)ipbuf; 701 *ipbuf = mu_strdup(inet_ntoa(s));
669 p = inet_ntoa(s); 702 dns_reply_free(&ld.repl);
670 strncpy(ipbuf, p, ipbsize);
671 } 703 }
672 704
673 *ttl = ld.ttl; 705 *ttl = ld.ttl;
@@ -676,9 +708,7 @@ dns_resolve_hostname(const char *host,
676 708
677 709
678dns_status 710dns_status
679a_lookup(const char *host, 711a_lookup(const char *host, struct dns_reply *repl, unsigned long *ttl)
680 GACOPYZ_UINT32_T *ipbuf, size_t ipbsize, size_t *ipcount,
681 unsigned long *ttl, unsigned char *answer, size_t answer_size)
682{ 712{
683 struct loop_data ld; 713 struct loop_data ld;
684 char namebuf[NSIZE]; 714 char namebuf[NSIZE];
@@ -691,45 +721,23 @@ a_lookup(const char *host,
691 ld.name_size = sizeof namebuf; 721 ld.name_size = sizeof namebuf;
692 ld.domain = domainbuf; 722 ld.domain = domainbuf;
693 ld.domain_size = sizeof domainbuf; 723 ld.domain_size = sizeof domainbuf;
694 ld.answer = answer; 724 ld.answer = NULL;
695 ld.answer_size = answer_size; 725 ld.answer_size = 0;
696 ld.hbuf = (char*) ipbuf;
697 ld.hbsize = ipbsize * sizeof ipbuf[0];
698 ld.hbcount = 0;
699 ld.ttl = ~(unsigned long)0;
700 ld.status = dns_failure;
701 ld.loopcnt = MAXCNAMEDEPTH;
702 726
703 cnameloop(&ld); 727 cnameloop(&ld);
704 if (ld.status == dns_success) { 728 if (ld.status == dns_success) {
705 if (ipcount) 729 *repl = ld.repl;
706 *ipcount = ld.hbcount;
707 if (ttl) 730 if (ttl)
708 *ttl = ld.ttl; 731 *ttl = ld.ttl;
709 } 732 }
710 return ld.status; 733 return ld.status;
711} 734}
712 735
713static void
714textbuf_to_argv(const char *hbuf, size_t hsize, char **argv, size_t argc)
715{
716 size_t i;
717 const char *p;
718
719 for (i = 0, p = hbuf; i < argc - 1 && p < hbuf + hsize;
720 p += strlen(p) + 1)
721 argv[i++] = mu_strdup(p);
722 argv[i] = NULL;
723}
724
725dns_status 736dns_status
726ptr_lookup(struct in_addr ip, 737ptr_lookup(struct in_addr ip, struct dns_reply *repl, unsigned long *ttl)
727 char **names, size_t maxnames, unsigned long *ttl,
728 unsigned char *answer, size_t answer_size)
729{ 738{
730 char namebuf[NSIZE]; 739 char namebuf[NSIZE];
731 char domainbuf[NSIZE]; 740 char domainbuf[NSIZE];
732 char hbuf[NSIZE];
733 struct loop_data ld; 741 struct loop_data ld;
734 char *p; 742 char *p;
735 743
@@ -743,19 +751,13 @@ ptr_lookup(struct in_addr ip,
743 ld.domain = domainbuf; 751 ld.domain = domainbuf;
744 strcpy(domainbuf, "in-addr.arpa"); 752 strcpy(domainbuf, "in-addr.arpa");
745 ld.domain_size = sizeof domainbuf; 753 ld.domain_size = sizeof domainbuf;
746 ld.answer = answer; 754 ld.answer = NULL;
747 ld.answer_size = answer_size; 755 ld.answer_size = 0;
748 ld.hbuf = hbuf;
749 ld.hbsize = sizeof hbuf;
750 ld.hbcount = 0;
751 ld.ttl = ~(unsigned long)0;
752 ld.status = dns_failure;
753 ld.loopcnt = MAXCNAMEDEPTH;
754 756
755 cnameloop(&ld); 757 cnameloop(&ld);
756 758
757 if (ld.status == dns_success) { 759 if (ld.status == dns_success) {
758 textbuf_to_argv(ld.hbuf, ld.hbcount, names, maxnames); 760 *repl = ld.repl;
759 if (ttl) 761 if (ttl)
760 *ttl = ld.ttl; 762 *ttl = ld.ttl;
761 } 763 }
@@ -764,12 +766,9 @@ ptr_lookup(struct in_addr ip,
764} 766}
765 767
766dns_status 768dns_status
767txt_lookup(const char *name, 769txt_lookup(const char *name, struct dns_reply *repl, unsigned long *ttl)
768 char **names, size_t maxnames, unsigned long *ttl,
769 unsigned char *answer, size_t answer_size)
770{ 770{
771 char domainbuf[NSIZE]; 771 char domainbuf[NSIZE];
772 char hbuf[NSIZE];
773 struct loop_data ld; 772 struct loop_data ld;
774 773
775 ld.qtype = T_TXT; 774 ld.qtype = T_TXT;
@@ -779,21 +778,15 @@ txt_lookup(const char *name,
779 domainbuf[0] = 0; 778 domainbuf[0] = 0;
780 ld.domain = domainbuf; 779 ld.domain = domainbuf;
781 ld.domain_size = sizeof domainbuf; 780 ld.domain_size = sizeof domainbuf;
782 ld.answer = answer; 781 ld.answer = NULL;
783 ld.answer_size = answer_size; 782 ld.answer_size = 0;
784 ld.hbuf = hbuf;
785 ld.hbsize = sizeof hbuf;
786 ld.hbcount = 0;
787 ld.ttl = ~(unsigned long)0;
788 ld.status = dns_failure;
789 ld.loopcnt = MAXCNAMEDEPTH;
790 783
791 cnameloop(&ld); 784 cnameloop(&ld);
792 785
793 free(ld.name); 786 free(ld.name);
794 787
795 if (ld.status == dns_success) { 788 if (ld.status == dns_success) {
796 textbuf_to_argv(ld.hbuf, ld.hbcount, names, maxnames); 789 *repl = ld.repl;
797 if (ttl) 790 if (ttl)
798 *ttl = ld.ttl; 791 *ttl = ld.ttl;
799 } 792 }
@@ -801,16 +794,19 @@ txt_lookup(const char *name,
801 return ld.status; 794 return ld.status;
802} 795}
803 796
804/* FIXME: This is a placeholder for a function that should look up for any
805 SPF or TXT records for DOMAIN. If any SPF are found, TXT should be
806 discarded.
807 For the time being, it handles only TXT */
808dns_status 797dns_status
809spf_lookup(const char *domain, 798spf_lookup(const char *domain,
810 char **txt, size_t maxtxt, unsigned long *ttl, 799 char ***txtv, size_t *txtc, unsigned long *ttl)
811 unsigned char *answer, size_t answer_size)
812{ 800{
813 return txt_lookup(domain, txt, maxtxt, ttl, answer, answer_size); 801 dns_status res;
802 struct dns_reply r;
803 res = txt_lookup(domain, &r, ttl);
804 if (res == dns_success) {
805 *txtv = (char**)r.base;
806 if (txtc)
807 *txtc = r.count;
808 }
809 return res;
814} 810}
815 811
816/* rfc4408, chapter 5.5 */ 812/* rfc4408, chapter 5.5 */
@@ -819,60 +815,58 @@ ptr_validate(const char *ipstr, char ***vnptr, size_t *vcount,
819 unsigned long *pttl) 815 unsigned long *pttl)
820{ 816{
821 struct in_addr ip; 817 struct in_addr ip;
822 char *names[11], **p; 818 size_t i;
823 char *vnames[10];
824 size_t vi = 0;
825 int status; 819 int status;
826 unsigned long minttl = ~(unsigned long)0; 820 unsigned long minttl = ~(unsigned long)0;
827 unsigned long ttl; 821 unsigned long ttl;
822 struct dns_reply ptr_repl;
823 char **sv = NULL;
824 size_t sc = 0;
825 size_t sn = 0;
828 826
829 if (!inet_aton(ipstr, &ip)) 827 if (!inet_aton(ipstr, &ip))
830 return dns_failure; 828 return dns_failure;
831 829
832 status = ptr_lookup(ip, names, NELEMS(names), &ttl, NULL, 0); 830 status = ptr_lookup(ip, &ptr_repl, &ttl);
833 831
834 if (status != dns_success) 832 if (status != dns_success)
835 return status; 833 return status;
836 834
837 UPDATE_TTL(minttl, ttl); 835 UPDATE_TTL(minttl, ttl);
836 for (i = 0; i < ptr_repl.count; i++) {
837 struct dns_reply r;
838 status = a_lookup((char*)ptr_repl.base[i], &r, &ttl);
839 if (status == dns_success) {
840 size_t k;
838 841
839 for (p = names; *p; p++) {
840 GACOPYZ_UINT32_T ipbuf[10];
841 size_t ipcount;
842 status = a_lookup(*p,
843 ipbuf, NELEMS(ipbuf),
844 &ipcount,
845 &ttl, NULL, 0);
846 if (status == dns_success && vi < NELEMS(vnames[0])) {
847 size_t i;
848
849 UPDATE_TTL(minttl, ttl); 842 UPDATE_TTL(minttl, ttl);
850 for (i = 0; i < ipcount; i++) 843 for (k = 0; k < r.count; k++) {
851 if (ipbuf[i] == ip.s_addr) { 844 if (dns_reply_ip(&r, k) == ip.s_addr) {
852 vnames[vi++] = *p; 845 if (sc == sn)
853 if (vnptr) 846 sv = mu_2nrealloc(sv, &sn,
854 *p = NULL; 847 sizeof(sv[0]));
848 sv[sc++] = mu_strdup(ptr_repl.base[i]);
855 break; 849 break;
856 } 850 }
851 }
852 dns_reply_free(&r);
857 } 853 }
858 free(*p);
859 } 854 }
860 855 dns_reply_free(&ptr_repl);
861 if (vi > 0) { 856
862 if (pttl) 857 if (sc == 0) {
863 *pttl = minttl; 858 return dns_not_found;
864 if (vnptr) {
865 size_t i;
866
867 *vnptr = mu_calloc(vi+1, sizeof vnptr[0]);
868 for (i = 0; i < vi; i++)
869 (*vnptr)[i] = vnames[i];
870 (*vnptr)[i] = NULL;
871 *vcount = vi;
872 }
873 } 859 }
860 if (pttl)
861 *pttl = minttl;
862 if (vcount)
863 *vcount = sc;
864 if (vnptr)
865 *vnptr = sv;
866 else
867 mu_argcv_free(sc, sv);
874 868
875 return vi > 0 ? dns_success : dns_not_found; 869 return dns_success;
876} 870}
877 871
878 872
@@ -891,43 +885,41 @@ mf_to_dns_status(mf_status stat)
891mf_status 885mf_status
892getmx(const char *host, struct mxbuf *mxbuf) 886getmx(const char *host, struct mxbuf *mxbuf)
893{ 887{
894 mxbuf_init(mxbuf);
895 return dns_to_mf_status(dns_get_mx_records(host, 1, mxbuf, NULL)); 888 return dns_to_mf_status(dns_get_mx_records(host, 1, mxbuf, NULL));
896} 889}
897 890
898mf_status 891mf_status
899getmxip(char *host, GACOPYZ_UINT32_T *ipbuf, size_t mxmax, size_t *pcount) 892getmxip(char *host, GACOPYZ_UINT32_T **pipbuf, size_t *pcount)
900{ 893{
901 struct mxbuf mxbuf; 894 struct mxbuf mxbuf;
902 mf_status mxstat; 895 mf_status mxstat;
903 size_t ipcount; 896 GACOPYZ_UINT32_T *ipbuf = NULL;
897 size_t ipcount = 0;
898 size_t ipmax = 0;
904 size_t i; 899 size_t i;
905 900
906 mxbuf.mx_max = mxmax;
907 mxbuf.mx_flags = MXF_MAX;
908 mxstat = getmx(host, &mxbuf); 901 mxstat = getmx(host, &mxbuf);
909 if (mxstat != mf_success) 902 if (mxstat != mf_success)
910 return mxstat; 903 return mxstat;
911 904
912 ipcount = 0; 905 ipcount = 0;
913 for (i = 0; i < mxbuf.mx_cnt; i++) { 906 for (i = 0; i < mxbuf.mx_cnt; i++) {
914 size_t ipn; 907 struct dns_reply r;
915 dns_status stat = a_lookup(mxbuf.mx_buf[i], 908 dns_status stat = a_lookup(mxbuf.mx_buf[i], &r, NULL);
916 ipbuf + ipcount,
917 mxmax - ipcount,
918 &ipn,
919 NULL, NULL, 0);
920 if (stat == dns_success) { 909 if (stat == dns_success) {
921 size_t n; 910 size_t n;
922 for (n = 0; ipcount < mxmax && n < ipn; 911 for (n = 0; n < r.count; n++, ipcount++) {
923 n++, ipcount++) 912 if (ipcount == ipmax)
924 ipbuf[ipcount] = ntohl(ipbuf[ipcount]); 913 ipbuf = mu_2nrealloc(ipbuf, &ipmax,
925 if (ipcount == mxmax) 914 sizeof(ipbuf));
926 break; 915 ipbuf[ipcount] = ntohl(dns_reply_ip(&r, n));
916 }
917 dns_reply_free(&r);
927 } 918 }
928 } 919 }
929 920
930 mxbuf_free(&mxbuf); 921 mxbuf_free(&mxbuf);
922 *pipbuf = ipbuf;
931 *pcount = ipcount; 923 *pcount = ipcount;
932 return mf_success; 924 return mf_success;
933} 925}
@@ -937,7 +929,7 @@ resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf)
937{ 929{
938 static unsigned char *answer; 930 static unsigned char *answer;
939 unsigned long ttl; 931 unsigned long ttl;
940 char buffer[256]; 932 char *hbuf;
941 dns_status dstat; 933 dns_status dstat;
942 934
943 if (!answer) 935 if (!answer)
@@ -946,13 +938,13 @@ resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf)
946 ("Getting canonical name for %s", ipstr)); 938 ("Getting canonical name for %s", ipstr));
947 939
948 dstat = dns_resolve_ipstr(ipstr, domain, answer, MAXPACKET, 940 dstat = dns_resolve_ipstr(ipstr, domain, answer, MAXPACKET,
949 buffer, sizeof buffer, &ttl); 941 &hbuf, &ttl);
950 942
951 switch (dstat) { 943 switch (dstat) {
952 case dns_success: 944 case dns_success:
953 mu_debug(debug_handle, MU_DEBUG_TRACE8, 945 mu_debug(debug_handle, MU_DEBUG_TRACE8,
954 ("%s resolved to %s", ipstr, buffer)); 946 ("%s resolved to %s", ipstr, hbuf));
955 *phbuf = mu_strdup(buffer); 947 *phbuf = hbuf;
956 break; 948 break;
957 949
958 default: 950 default:
@@ -972,24 +964,21 @@ mf_status
972 resolve_hostname(const char *host, char **pipbuf) 964 resolve_hostname(const char *host, char **pipbuf)
973{ 965{
974 static unsigned char *answer; 966 static unsigned char *answer;
975 char buffer[256];
976 char *ipbuf; 967 char *ipbuf;
977 unsigned long ttl; 968 unsigned long ttl;
978 char *tmphost = mu_strdup(host); 969 char *tmphost = mu_strdup(host);
979 dns_status dstat; 970 dns_status dstat;
980 971
981 if (!answer) 972 if (!answer)
982 answer = malloc(MAXPACKET); 973 answer = mu_alloc(MAXPACKET);
983 mu_debug(debug_handle, MU_DEBUG_TRACE8, 974 mu_debug(debug_handle, MU_DEBUG_TRACE8,
984 ("Getting IP address for %s", host)); 975 ("Getting IP address for %s", host));
985 976
986 dstat = dns_resolve_hostname(tmphost, answer, MAXPACKET, 977 dstat = dns_resolve_hostname(tmphost, answer, MAXPACKET,
987 buffer, sizeof buffer, 978 &ipbuf, &ttl);
988 &ttl);
989 free(tmphost); 979 free(tmphost);
990 switch (dstat) { 980 switch (dstat) {
991 case dns_success: 981 case dns_success:
992 ipbuf = mu_strdup(buffer);
993 mu_debug(debug_handle, MU_DEBUG_TRACE8, 982 mu_debug(debug_handle, MU_DEBUG_TRACE8,
994 ("%s resolved to %s", host, ipbuf)); 983 ("%s resolved to %s", host, ipbuf));
995 *pipbuf = ipbuf; 984 *pipbuf = ipbuf;
diff --git a/lib/dns.h b/lib/dns.h
index b2884b0..000c6da 100644
--- a/lib/dns.h
+++ b/lib/dns.h
@@ -31,9 +31,6 @@ typedef enum {
31 # define MAXPACKET 8192/* max packet size used internally by BIND */ 31 # define MAXPACKET 8192/* max packet size used internally by BIND */
32#endif 32#endif
33 33
34#define MAXMXCOUNT 32
35
36#define MXF_MAX 0x01
37#define MXF_REUSE 0x02 34#define MXF_REUSE 0x02
38 35
39struct mxbuf { 36struct mxbuf {
@@ -78,7 +75,7 @@ struct mxbuf {
78 75
79#define UPDATE_TTL(m, ttl) do { if ((m) > (ttl)) (m) = (ttl); } while(0) 76#define UPDATE_TTL(m, ttl) do { if ((m) > (ttl)) (m) = (ttl); } while(0)
80 77
81void mxbuf_init(struct mxbuf *mxbuf); 78void mxbuf_init(struct mxbuf *mxbuf, size_t n);
82void mxbuf_free(struct mxbuf *mxbuf); 79void mxbuf_free(struct mxbuf *mxbuf);
83 80
84int dns_str_is_ipv4(const char *addr); 81int dns_str_is_ipv4(const char *addr);
@@ -89,25 +86,42 @@ int dns_reverse_ipstr(const char *ipstr, char *revipstr);
89 86
90dns_status dns_resolve_ipstr(const char *ipstr, const char *domain, 87dns_status dns_resolve_ipstr(const char *ipstr, const char *domain,
91 unsigned char *answer, size_t answer_size, 88 unsigned char *answer, size_t answer_size,
92 char *hbuf, size_t hbsize, unsigned long *ttl); 89 char **hbuf, unsigned long *ttl);
93 90
94dns_status dns_resolve_hostname(const char *host, 91dns_status dns_resolve_hostname(const char *host,
95 unsigned char *answer, size_t answer_size, 92 unsigned char *answer, size_t answer_size,
96 char *ipbuf, size_t ipbsize, 93 char **ipbuf, unsigned long *ttl);
97 unsigned long *ttl); 94
98dns_status a_lookup(const char *host, 95struct dns_reply {
99 GACOPYZ_UINT32_T *ipbuf, size_t ipbsize, size_t *ipcount, 96 size_t count;
100 unsigned long *ttl, 97 size_t max;
101 unsigned char *answer, size_t answer_size); 98
99 void **base;
100 size_t last_len;
101 size_t last_max;
102};
103
104void dns_reply_free(struct dns_reply *r);
105
106static inline GACOPYZ_UINT32_T
107dns_reply_ip(struct dns_reply const *repl, size_t n)
108{
109 return *(GACOPYZ_UINT32_T*)repl->base[n];
110}
111
112dns_status a_lookup(const char *host,
113 struct dns_reply *repl, unsigned long *ttl);
102 114
103dns_status ptr_lookup(struct in_addr ip, 115dns_status ptr_lookup(struct in_addr ip,
104 char **names, size_t maxnames, unsigned long *ttl, 116 struct dns_reply *repl, unsigned long *ttl);
105 unsigned char *answer, size_t answer_size);
106dns_status txt_lookup(const char *name, 117dns_status txt_lookup(const char *name,
107 char **names, size_t maxnames, unsigned long *ttl, 118 struct dns_reply *repl, unsigned long *ttl);
108 unsigned char *answer, size_t answer_size);
109 119
110dns_status ptr_validate(const char *ipstr, char ***vnptr, size_t *vcount, 120dns_status ptr_validate(const char *ipstr, char ***vnptr, size_t *vcount,
111 unsigned long *pttl); 121 unsigned long *pttl);
112 122
123dns_status spf_lookup(const char *domain,
124 char ***txtv, size_t *txtc, unsigned long *ttl);
125
126
113#endif 127#endif
diff --git a/lib/libmf.h b/lib/libmf.h
index 9842b75..5336b21 100644
--- a/lib/libmf.h
+++ b/lib/libmf.h
@@ -283,7 +283,7 @@ void dnsbase_init();
283mf_status dns_to_mf_status(dns_status stat); 283mf_status dns_to_mf_status(dns_status stat);
284dns_status mf_to_dns_status(mf_status stat); 284dns_status mf_to_dns_status(mf_status stat);
285mf_status getmx(const char *host, struct mxbuf *mxbuf); 285mf_status getmx(const char *host, struct mxbuf *mxbuf);
286mf_status getmxip(char *host, GACOPYZ_UINT32_T *ipbuf, size_t mxmax, size_t *pcount); 286mf_status getmxip(char *host, GACOPYZ_UINT32_T **ipbuf, size_t *pcount);
287mf_status resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf); 287mf_status resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf);
288 mf_status resolve_ipstr(const char *ipstr, char **phbuf); 288 mf_status resolve_ipstr(const char *ipstr, char **phbuf);
289 mf_status resolve_hostname(const char *host, char **pipbuf); 289 mf_status resolve_hostname(const char *host, char **pipbuf);
diff --git a/src/builtin/dns.bi b/src/builtin/dns.bi
index 46433a0..faf8998 100644
--- a/src/builtin/dns.bi
+++ b/src/builtin/dns.bi
@@ -21,20 +21,6 @@
21#include "srvcfg.h" 21#include "srvcfg.h"
22#include "global.h" 22#include "global.h"
23 23
24static size_t max_ptr = MAX_DNS_PTR;
25static size_t max_a = MAX_DNS_A;
26static size_t max_mx = MAX_DNS_MX;
27static struct mu_cfg_param dns_cfg_param[] = {
28 { "max-dns-reply-a", mu_c_size, &max_a, 0, NULL,
29 N_("Maximum number of A records in a DNS reply.") },
30 { "max-dns-reply-ptr", mu_c_size, &max_a, 0, NULL,
31 N_("Maximum number of PTR records in a DNS reply.") },
32 { "max-dns-reply-mx", mu_c_size, &max_mx, 0, NULL,
33 N_("Maximum number of MX records in a DNS reply.") },
34 { NULL }
35};
36
37
38MF_DEFUN(primitive_hostname, STRING, STRING string) 24MF_DEFUN(primitive_hostname, STRING, STRING string)
39{ 25{
40 char *hbuf; 26 char *hbuf;
@@ -75,8 +61,8 @@ END
75static int 61static int
76ipaddr_cmp(const void *a, const void *b) 62ipaddr_cmp(const void *a, const void *b)
77{ 63{
78 GACOPYZ_UINT32_T ipa = ntohl(*(GACOPYZ_UINT32_T*)a); 64 GACOPYZ_UINT32_T ipa = ntohl(**(GACOPYZ_UINT32_T**)a);
79 GACOPYZ_UINT32_T ipb = ntohl(*(GACOPYZ_UINT32_T*)b); 65 GACOPYZ_UINT32_T ipb = ntohl(**(GACOPYZ_UINT32_T**)b);
80 if (ipa < ipb) 66 if (ipa < ipb)
81 return -1; 67 return -1;
82 if (ipa > ipb) 68 if (ipa > ipb)
@@ -86,37 +72,33 @@ ipaddr_cmp(const void *a, const void *b)
86 72
87MF_DEFUN(dns_getaddr, STRING, STRING string) 73MF_DEFUN(dns_getaddr, STRING, STRING string)
88{ 74{
89 GACOPYZ_UINT32_T *ipbuf; 75 size_t i;
90 size_t i, ipcount;
91 unsigned long ttl; 76 unsigned long ttl;
92 dns_status dnstat; 77 dns_status dnstat;
93 78 struct dns_reply r;
94 ipbuf = mu_calloc(max_a, sizeof(ipbuf[0])); 79
95 dnstat = a_lookup(string, ipbuf, max_a, &ipcount, 80 dnstat = a_lookup(string, &r, &ttl);
96 &ttl, NULL, 0);
97 switch (dnstat) { 81 switch (dnstat) {
98 case dns_success: { 82 case dns_success: {
99 MF_OBSTACK_BEGIN(); 83 MF_OBSTACK_BEGIN();
100 qsort(ipbuf, ipcount, sizeof ipbuf[0], ipaddr_cmp); 84 qsort(r.base, r.count, sizeof r.base[0], ipaddr_cmp);
101 for (i = 0; i < ipcount; i++) { 85 for (i = 0; i < r.count; i++) {
102 struct in_addr addr; 86 struct in_addr addr;
103 char *q; 87 char *q;
104 88
105 addr.s_addr = ipbuf[i]; 89 addr.s_addr = dns_reply_ip(&r, i);
106 q = inet_ntoa(addr); 90 q = inet_ntoa(addr);
107 if (i > 0) 91 if (i > 0)
108 MF_OBSTACK_1GROW(' '); 92 MF_OBSTACK_1GROW(' ');
109 MF_OBSTACK_GROW(q); 93 MF_OBSTACK_GROW(q);
110 } 94 }
111 free(ipbuf); 95 dns_reply_free(&r);
112 MF_OBSTACK_1GROW(0); 96 MF_OBSTACK_1GROW(0);
113 MF_RETURN_OBSTACK(); 97 MF_RETURN_OBSTACK();
114 } 98 }
115 case dns_not_found: 99 case dns_not_found:
116 free(ipbuf);
117 MF_RETURN(""); 100 MF_RETURN("");
118 default: 101 default:
119 free(ipbuf);
120 MF_THROW(mf_status_to_exception(dns_to_mf_status(dnstat)), 102 MF_THROW(mf_status_to_exception(dns_to_mf_status(dnstat)),
121 _("failed to get A record for %s"), string); 103 _("failed to get A record for %s"), string);
122 } 104 }
@@ -134,42 +116,33 @@ MF_DEFUN(dns_getname, STRING, STRING ipstr)
134 dns_status dnstat; 116 dns_status dnstat;
135 struct in_addr addr; 117 struct in_addr addr;
136 unsigned long ttl; 118 unsigned long ttl;
137 char **names; 119 struct dns_reply r;
138 120
139 MF_ASSERT(inet_aton(ipstr, &addr), 121 MF_ASSERT(inet_aton(ipstr, &addr),
140 mfe_invip, 122 mfe_invip,
141 _("invalid IP: %s"), ipstr); 123 _("invalid IP: %s"), ipstr);
142 124
143 names = mu_calloc(max_ptr, sizeof(names[0])); 125 dnstat = ptr_lookup(addr, &r, &ttl);
144 dnstat = ptr_lookup(addr, names, max_ptr, &ttl, NULL, 0);
145 switch (dnstat) { 126 switch (dnstat) {
146 case dns_success: { 127 case dns_success: {
147 size_t i; 128 size_t i;
148 size_t ncount;
149 129
150 for (ncount = 0; ncount < max_ptr && names[ncount]; 130 qsort(r.base, r.count, sizeof r.base[0], hostname_cmp);
151 ncount++);
152
153 qsort(names, ncount, sizeof names[0], hostname_cmp);
154 131
155 MF_OBSTACK_BEGIN(); 132 MF_OBSTACK_BEGIN();
156 for (i = 0; i < ncount; i++) { 133 for (i = 0; i < r.count; i++) {
157 if (i > 0) 134 if (i > 0)
158 MF_OBSTACK_1GROW(' '); 135 MF_OBSTACK_1GROW(' ');
159 MF_OBSTACK_GROW(names[i]); 136 MF_OBSTACK_GROW((char*)r.base[i]);
160 } 137 }
161 MF_OBSTACK_1GROW(0); 138 MF_OBSTACK_1GROW(0);
162 139
163 for (; i < ncount; i++) 140 dns_reply_free(&r);
164 free(names[i]);
165 free(names);
166 MF_RETURN_OBSTACK(); 141 MF_RETURN_OBSTACK();
167 } 142 }
168 case dns_not_found: 143 case dns_not_found:
169 free(names);
170 MF_RETURN(""); 144 MF_RETURN("");
171 default: 145 default:
172 free(names);
173 MF_THROW(mf_status_to_exception(dns_to_mf_status(dnstat)), 146 MF_THROW(mf_status_to_exception(dns_to_mf_status(dnstat)),
174 _("failed to get PTR record for %s"), ipstr); 147 _("failed to get PTR record for %s"), ipstr);
175 } 148 }
@@ -204,15 +177,12 @@ MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER no_resolve)
204 GACOPYZ_UINT32_T *ipbuf; 177 GACOPYZ_UINT32_T *ipbuf;
205 size_t ipcount; 178 size_t ipcount;
206 179
207 ipbuf = mu_calloc(max_mx, sizeof(ipbuf[0])); 180 mxstat = getmxip(domain, &ipbuf, &ipcount);
208 mxstat = getmxip(domain, ipbuf, max_mx, &ipcount);
209 if (!mf_resolved(mxstat)) { 181 if (!mf_resolved(mxstat)) {
210 free(ipbuf);
211 MF_THROW(mf_status_to_exception(mxstat), 182 MF_THROW(mf_status_to_exception(mxstat),
212 _("cannot get MX records for %s"), domain); 183 _("cannot get MX records for %s"), domain);
213 } 184 }
214 if (mxstat == mf_not_found) { 185 if (mxstat == mf_not_found) {
215 free(ipbuf);
216 MF_RETURN(""); 186 MF_RETURN("");
217 } else { 187 } else {
218 int i; 188 int i;
@@ -233,8 +203,6 @@ MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER no_resolve)
233 } else { 203 } else {
234 struct mxbuf mxbuf; 204 struct mxbuf mxbuf;
235 205
236 mxbuf.mx_max = max_mx;
237 mxbuf.mx_flags = MXF_MAX;
238 mxstat = getmx(domain, &mxbuf); 206 mxstat = getmx(domain, &mxbuf);
239 if (!mf_resolved(mxstat)) { 207 if (!mf_resolved(mxstat)) {
240 mxbuf_free(&mxbuf); 208 mxbuf_free(&mxbuf);
@@ -301,11 +269,9 @@ MF_DEFUN(primitive_ismx, NUMBER, STRING domain, STRING ipstr)
301 _("cannot resolve host name %s"), ipstr); 269 _("cannot resolve host name %s"), ipstr);
302 ip = ntohl(ip); 270 ip = ntohl(ip);
303 271
304 ipbuf = mu_calloc(max_mx, sizeof(ipbuf[0])); 272 mxstat = getmxip(domain, &ipbuf, &ipcount);
305 mxstat = getmxip(domain, ipbuf, max_mx, &ipcount);
306 273
307 if (mxstat != mf_success) { 274 if (mxstat != mf_success) {
308 free(ipbuf);
309 MF_THROW(mf_status_to_exception(mxstat), 275 MF_THROW(mf_status_to_exception(mxstat),
310 _("cannot get MXs for %s"), domain); 276 _("cannot get MXs for %s"), domain);
311 } 277 }
@@ -328,6 +294,22 @@ MF_DEFUN(relayed, NUMBER, STRING s)
328} 294}
329END 295END
330 296
331MF_INIT([< 297MF_DEFUN(ptr_validate, NUMBER, STRING s)
332 mf_add_runtime_params(dns_cfg_param); 298{
333 >]) 299 int rc, res;
300 switch (rc = ptr_validate(s, NULL, NULL, NULL)) {
301 case dns_success:
302 res = 1;
303 break;
304 case dns_not_found:
305 res = 0;
306 break;
307 default:
308 MF_THROW(mf_status_to_exception(dns_to_mf_status(rc)),
309 _("failed to get PTR record for %s"), s);
310 }
311 MF_RETURN(res);
312}
313END
314
315MF_INIT
diff --git a/src/callout.c b/src/callout.c
index e59e8f0..633a33b 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)
637 struct mxbuf mxbuf; 637 struct mxbuf mxbuf;
638 mf_status rc, mxstat; 638 mf_status rc, mxstat;
639 639
640 mxbuf.mx_max = max_callout_mx;
641 mxbuf.mx_flags = MXF_MAX;
642 mxstat = getmx(hostname, &mxbuf); 640 mxstat = getmx(hostname, &mxbuf);
643 641
644 if (pcount) 642 if (pcount)
diff --git a/src/mailfromd.h b/src/mailfromd.h
index 5cc7136..7f21e36 100644
--- a/src/mailfromd.h
+++ b/src/mailfromd.h
@@ -76,8 +76,7 @@ mf_status resolve_ipstr_domain(const char *ipstr, const char *domain,
76mf_status resolve_hostname(const char *host, char **pipbuf); 76mf_status resolve_hostname(const char *host, char **pipbuf);
77 77
78mf_status getmx(const char *ipstr, struct mxbuf *mxbuf); 78mf_status getmx(const char *ipstr, struct mxbuf *mxbuf);
79mf_status getmxip(char *host, GACOPYZ_UINT32_T *ipbuf, size_t ipmax, 79mf_status getmxip(char *host, GACOPYZ_UINT32_T **ipbuf, size_t *pcount);
80 size_t *pcount);
81 80
82 81
83/* Debugging macros */ 82/* Debugging macros */
diff --git a/src/main.c b/src/main.c
index 66a9780..9873ed0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -73,8 +73,6 @@ unsigned optimization_level = 1; /* Optimization level */
73 73
74int stack_trace_option; /* Print stack traces on runtime errors */ 74int stack_trace_option; /* Print stack traces on runtime errors */
75 75
76size_t max_match_mx = MAXMXCOUNT;
77
78char *main_function_name = "main"; 76char *main_function_name = "main";
79char *callout_server_url; 77char *callout_server_url;
80 78
@@ -853,9 +851,6 @@ struct mu_cfg_param mf_cfg_param[] = {
853 N_("Set the time span between the two DBM locking attempts."), 851 N_("Set the time span between the two DBM locking attempts."),
854 N_("time: interval") }, 852 N_("time: interval") },
855 853
856 { "max-match-mx", mu_c_size, &max_match_mx, 0, NULL,
857 N_("Maximum number of MXs used by MFL \"mx match\" operation.") },
858
859 { "runtime", mu_cfg_section, NULL }, 854 { "runtime", mu_cfg_section, NULL },
860 855
861 { NULL } 856 { NULL }
diff --git a/src/prog.c b/src/prog.c
index 12dc69e..3e90472 100644
--- a/src/prog.c
+++ b/src/prog.c
@@ -1602,8 +1602,6 @@ mx_match(eval_environ_t env, char *string,
1602 p++; 1602 p++;
1603 else 1603 else
1604 p = string; 1604 p = string;
1605 mxbuf.mx_max = max_match_mx;
1606 mxbuf.mx_flags = MXF_MAX;
1607 mxstat = getmx(p, &mxbuf); 1605 mxstat = getmx(p, &mxbuf);
1608 rc = 0; 1606 rc = 0;
1609 if (mxstat == mf_success) { 1607 if (mxstat == mf_success) {
diff --git a/src/spf.c b/src/spf.c
index 236efa5..9e8c1bf 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)
630 const char *domain_spec; 630 const char *domain_spec;
631 unsigned long netmask; 631 unsigned long netmask;
632 struct in_addr addr; 632 struct in_addr addr;
633 GACOPYZ_UINT32_T ipbuf[64]; /* FIXME: arbitrary limit */ 633 struct dns_reply r;
634 size_t i, ipcount; 634 size_t i;
635 unsigned long ttl; 635 unsigned long ttl;
636 spf_term_result res;
636 637
637 if (arg) 638 if (arg)
638 domain_spec = arg->v.domain_spec; 639 domain_spec = arg->v.domain_spec;
@@ -644,23 +645,24 @@ mech_a(spf_data *dat, spf_term_arg *arg, unsigned long masklen)
644 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1, 645 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1,
645 ("A domain_spec=%s, netmask=%lx", domain_spec, netmask)); 646 ("A domain_spec=%s, netmask=%lx", domain_spec, netmask));
646 647
647 DNS_CATCH(a_lookup(domain_spec, ipbuf, NELEMS(ipbuf), &ipcount, 648 DNS_CATCH(a_lookup(domain_spec, &r, &ttl));
648 &ttl, NULL, 0));
649 UPDATE_ANSWER_TTL(dat, ttl); 649 UPDATE_ANSWER_TTL(dat, ttl);
650 650
651 addr.s_addr = dat->ipaddr.s_addr & netmask; 651 addr.s_addr = dat->ipaddr.s_addr & netmask;
652 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE6, 652 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE6,
653 ("A: s_addr=%x", addr.s_addr)); 653 ("A: s_addr=%x", addr.s_addr));
654 654
655 for (i = 0; i < ipcount; i++) { 655 res = spf_term_nomatch;
656 if ((ntohl(ipbuf[i]) & netmask) == addr.s_addr) { 656 for (i = 0; i < r.count; i++) {
657 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1, 657 if (ntohl(dns_reply_ip(&r, i) & netmask) == addr.s_addr) {
658 ("A matches")); 658 res = spf_term_match;
659 return spf_term_match; 659 break;
660 } 660 }
661 } 661 }
662 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1, ("A does not match")); 662 dns_reply_free(&r);
663 return spf_term_nomatch; 663 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1,
664 (res == spf_term_match ? "A matches" : "A does not match"));
665 return res;
664} 666}
665 667
666/* 5.4. 668/* 5.4.
@@ -685,8 +687,6 @@ mech_mx(spf_data *dat, spf_term_arg *arg, unsigned long masklen)
685 ("MX domain_spec=%s, netmask=%lx", 687 ("MX domain_spec=%s, netmask=%lx",
686 domain_spec, netmask)); 688 domain_spec, netmask));
687 689
688 mxbuf.mx_flags = MXF_MAX;
689 mxbuf.mx_max = 10;
690 DNS_CATCH(dns_get_mx_records(domain_spec, 1, &mxbuf, &ttl)); 690 DNS_CATCH(dns_get_mx_records(domain_spec, 1, &mxbuf, &ttl));
691 UPDATE_ANSWER_TTL(dat, ttl); 691 UPDATE_ANSWER_TTL(dat, ttl);
692 692
@@ -779,6 +779,7 @@ static spf_term_result
779mech_exists(spf_data *dat, spf_term_arg *arg, unsigned long masklen) 779mech_exists(spf_data *dat, spf_term_arg *arg, unsigned long masklen)
780{ 780{
781 unsigned long ttl; 781 unsigned long ttl;
782 struct dns_reply r;
782 if (!arg) { 783 if (!arg) {
783 mu_debug(MF_SOURCE_SPF, MU_DEBUG_ERROR, 784 mu_debug(MF_SOURCE_SPF, MU_DEBUG_ERROR,
784 ("exists used without argument")); 785 ("exists used without argument"));
@@ -788,7 +789,8 @@ mech_exists(spf_data *dat, spf_term_arg *arg, unsigned long masklen)
788 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1, 789 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE1,
789 ("EXISTS domain_spec=%s", arg->v.domain_spec)); 790 ("EXISTS domain_spec=%s", arg->v.domain_spec));
790 791
791 DNS_CATCH(a_lookup(arg->v.domain_spec, NULL, 0, NULL, &ttl, NULL, 0)); 792 DNS_CATCH(a_lookup(arg->v.domain_spec, &r, &ttl));
793 dns_reply_free(&r);
792 UPDATE_ANSWER_TTL(dat, ttl); 794 UPDATE_ANSWER_TTL(dat, ttl);
793 795
794 return spf_term_match; 796 return spf_term_match;
@@ -816,18 +818,17 @@ mod_redirect(spf_data *dat, spf_term_arg *arg, unsigned long masklen)
816static spf_term_result 818static spf_term_result
817mod_exp(spf_data *dat, spf_term_arg *arg, unsigned long masklen) 819mod_exp(spf_data *dat, spf_term_arg *arg, unsigned long masklen)
818{ 820{
819 char *names[128]; /* FIXME: arbitrary limit */ 821 struct dns_reply r;
822
820 if (arg->v.domain_spec 823 if (arg->v.domain_spec
821 && txt_lookup(arg->v.domain_spec, 824 && txt_lookup(arg->v.domain_spec, &r, NULL) == dns_success) {
822 names, NELEMS(names), NULL,
823 NULL, 0) == dns_success) {
824 int i; 825 int i;
825 char *text; 826 char *text;
826 827
827 for (i = 0; names[i]; i++) { 828 for (i = 0; i < r.count; i++) {
828 mu_opool_appendz(dat->tmpool, names[i]); 829 mu_opool_appendz(dat->tmpool, r.base[i]);
829 free(names[i]);
830 } 830 }
831 dns_reply_free(&r);
831 mu_opool_append_char(dat->tmpool, 0); 832 mu_opool_append_char(dat->tmpool, 0);
832 text = spf_data_ptr(dat); 833 text = spf_data_ptr(dat);
833 834
@@ -1213,8 +1214,10 @@ spf_test_record(const char *rec, spf_query_t *q, spf_answer_t *a)
1213spf_result 1214spf_result
1214spf_check_host_internal(spf_query_t *q, spf_answer_t *a, size_t loopno) 1215spf_check_host_internal(spf_query_t *q, spf_answer_t *a, size_t loopno)
1215{ 1216{
1216 char *txt_rec[SPF_MAX_TXT_REC+1]; 1217 char **txt_rec;
1217 int ntxt, i; 1218 size_t txt_num;
1219 int i;
1220 char *spf_rec = NULL;
1218 struct spf_data dat; 1221 struct spf_data dat;
1219 spf_result result; 1222 spf_result result;
1220 #define SPF_RETURN(res, text) { \ 1223 #define SPF_RETURN(res, text) { \
@@ -1241,8 +1244,7 @@ spf_check_host_internal(spf_query_t *q, spf_answer_t *a, size_t loopno)
1241 if (strlen(q->domain) > 63) 1244 if (strlen(q->domain) > 63)
1242 SPF_RETURN(spf_none, "domain too long"); 1245 SPF_RETURN(spf_none, "domain too long");
1243 1246
1244 switch (spf_lookup(q->domain, txt_rec, NELEMS(txt_rec), 1247 switch (spf_lookup(q->domain, &txt_rec, &txt_num, &ttl)) {
1245 &ttl, NULL, 0)) {
1246 case dns_success: 1248 case dns_success:
1247 break; 1249 break;
1248 1250
@@ -1256,40 +1258,32 @@ spf_check_host_internal(spf_query_t *q, spf_answer_t *a, size_t loopno)
1256 } 1258 }
1257 1259
1258 /* Select SPF1 records */ 1260 /* Select SPF1 records */
1259 ntxt = 0;
1260 for (i = 0; txt_rec[i]; i++) { 1261 for (i = 0; txt_rec[i]; i++) {
1261 if (memcmp(txt_rec[i], "v=spf1", 6) == 0 1262 if (memcmp(txt_rec[i], "v=spf1", 6) == 0
1262 && (txt_rec[i][6] == 0 || mu_isspace(txt_rec[i][6]))) { 1263 && (txt_rec[i][6] == 0 || mu_isspace(txt_rec[i][6]))) {
1263 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE6, 1264 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE6,
1264 ("record: %s", txt_rec[i])); 1265 ("record: %s", txt_rec[i]));
1265 if (ntxt != i) { 1266 if (spf_rec) {
1266 txt_rec[ntxt++] = txt_rec[i]; 1267 SPF_RETURN(spf_perm_error,
1267 txt_rec[i] = NULL; 1268 "too many SPF records published");
1268 } else 1269 }
1269 ntxt = i + 1; 1270 spf_rec = txt_rec[i];
1270 } else { 1271 break;
1271 free(txt_rec[i]);
1272 txt_rec[i] = NULL;
1273 } 1272 }
1274 } 1273 }
1275 1274
1276 if (ntxt == 0)
1277 SPF_RETURN(spf_none, "no SPF records published");
1278 if (ntxt > 1)
1279 SPF_RETURN(spf_perm_error, "too many SPF records published");
1280
1281 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE0, 1275 mu_debug(MF_SOURCE_SPF, MU_DEBUG_TRACE0,
1282 ("SPF record: %s", txt_rec[0])); 1276 ("SPF record: %s", spf_rec));
1283 1277
1284 if (a) 1278 if (a)
1285 UPDATE_TTL(a->ttl, ttl); 1279 UPDATE_TTL(a->ttl, ttl);
1286 if (spf_data_init(&dat, q, a, loopno + 1)) 1280 if (spf_data_init(&dat, q, a, loopno + 1))
1287 SPF_RETURN(spf_perm_error, "spf_data_init failed"); 1281 SPF_RETURN(spf_perm_error, "spf_data_init failed");
1288 1282
1289 result = spf_exec_query(txt_rec[0], &dat); 1283 result = spf_exec_query(spf_rec, &dat);
1290 1284
1291 spf_data_free(&dat); 1285 spf_data_free(&dat);
1292 free(txt_rec[0]); 1286 mu_argcv_free(txt_num, txt_rec);
1293 1287
1294 SPF_RETURN(result, ""); 1288 SPF_RETURN(result, "");
1295} 1289}
diff --git a/src/spf.h b/src/spf.h
index 9b3c8e6..229075e 100644
--- a/src/spf.h
+++ b/src/spf.h
@@ -14,7 +14,6 @@
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16 16
17#define SPF_MAX_TXT_REC 10
18#define SPF_MAX_RECURSION 10 17#define SPF_MAX_RECURSION 10
19 18
20typedef enum spf_result { 19typedef enum spf_result {
@@ -49,8 +48,6 @@ typedef struct {
49spf_result spf_check_host(spf_query_t *query, spf_answer_t *ans); 48spf_result spf_check_host(spf_query_t *query, spf_answer_t *ans);
50spf_result spf_test_record(const char *rec, 49spf_result spf_test_record(const char *rec,
51 spf_query_t *query, spf_answer_t *ans); 50 spf_query_t *query, spf_answer_t *ans);
52dns_status spf_lookup(const char *domain, char **txt, size_t maxtxt,
53 unsigned long *ttl, char *answer, size_t answer_size);
54 51
55void spf_answer_free(spf_answer_t *ans); 52void spf_answer_free(spf_answer_t *ans);
56void spf_answer_add_mech(spf_answer_t *ans, char const *mech); 53void spf_answer_add_mech(spf_answer_t *ans, char const *mech);
diff --git a/src/srvcfg.c b/src/srvcfg.c
index f04e4c6..a9527a5 100644
--- a/src/srvcfg.c
+++ b/src/srvcfg.c
@@ -42,8 +42,6 @@ struct mu_sockaddr *source_address; /* Source address for TCP connections */
42int mtasim_option; /* mtasim compatibility mode */ 42int mtasim_option; /* mtasim compatibility mode */
43char *db_type_str = DEFAULT_DB_TYPE; 43char *db_type_str = DEFAULT_DB_TYPE;
44 44
45size_t max_callout_mx = MAXMXCOUNT;
46
47/* Timeouts */ 45/* Timeouts */
48time_t smtp_timeout_soft[SMTP_NUM_TIMEOUT] = { 46time_t smtp_timeout_soft[SMTP_NUM_TIMEOUT] = {
49 10, 47 10,
@@ -514,9 +512,6 @@ static struct mu_cfg_param srv_cfg_param[] = {
514 { "acl", mu_cfg_section, &srvman_param.acl }, 512 { "acl", mu_cfg_section, &srvman_param.acl },
515 { "logger", mu_c_string, &log_stream, 0, NULL, 513 { "logger", mu_c_string, &log_stream, 0, NULL,
516 N_("Set logger stream.") }, 514 N_("Set logger stream.") },
517 { "max-callout-mx", mu_c_size, &max_callout_mx, 0, NULL,
518 N_("Maximum number of MXs to be polled during "
519 "callout verification.") },
520 { "state-directory", mu_cfg_callback, NULL, 0, cb_state_directory, 515 { "state-directory", mu_cfg_callback, NULL, 0, cb_state_directory,
521 N_("Set program state directory."), 516 N_("Set program state directory."),
522 N_("dir: string") }, 517 N_("dir: string") },

Return to:

Send suggestions and report system problems to the System administrator.