2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 09:57:34 +00:00

postfix-3.9-20240227

This commit is contained in:
Wietse Z Venema 2024-02-27 00:00:00 -05:00 committed by Viktor Dukhovni
parent 03382b275a
commit f38f9d82f3
25 changed files with 662 additions and 91 deletions

View File

@ -27756,10 +27756,11 @@ Apologies for any names omitted.
or access control limitations. Files: smtpd/smtpd.[hc], or access control limitations. Files: smtpd/smtpd.[hc],
util/argv.[hc]. util/argv.[hc].
Workaround: some OS lies under load: it says that a socket Workaround: tlsmgr logfile spam. Some OS lies under load:
is readable, then it says that the socket has unread data, it says that a socket is readable, then it says that the
and then it says that read returns EOF, causing Postfix to socket has unread data, and then it says that read returns
spam the log with a warning message. File: tlsmgr/tlsmgr.c. EOF, causing Postfix to spam the log with a warning message.
File: tlsmgr/tlsmgr.c.
20240125 20240125
@ -27829,17 +27830,6 @@ Apologies for any names omitted.
20240209 20240209
Safety: enforce a sane but generous upper bound (100) for
the number of DNS resource records that the Postfix DNS
client library will admit into a list. This is 20x the
default smtp_mx_address_limit value for the number of DNS
records that the Postfix SMTP client is willing to consider.
Log a warning "dropping records after qname=X qtype=Y" when
a list cannot accept more elements. This prevents a tail
recursion crash that degrades mail delivery performance.
Problem report by Toshifumi Sakaguchi. Files: dns/dns_rr.[hc],
global/mail_params.h.
Performance: eliminate worst-case behavior where the queue Performance: eliminate worst-case behavior where the queue
manager deferred delivery to all destinations over a specific manager deferred delivery to all destinations over a specific
delivery transport, after only a single delivery agent delivery transport, after only a single delivery agent
@ -27920,3 +27910,27 @@ Apologies for any names omitted.
status. Files: postconf/postconf.c, postconf/postconf_dbms.c, status. Files: postconf/postconf.c, postconf/postconf_dbms.c,
postconf/postconf.h, conf/postfix-script, conf/post-install, postconf/postconf.h, conf/postfix-script, conf/post-install,
postfix-install. postfix-install.
20240221
Documentation: the text for TLS loglevel 2 was incomplete.
File: proto/postconf.proto.
20240226
Safety: drop and log over-size DNS responses resulting in
more than 100 records. This 20x larger than the number of
server addresses that the Postfix SMTP client is willing
to consider when delivering mail, and is well below the
number of records that could cause a tail recursion crash
in dns_rr_append() as reported by Toshifumi Sakaguchi. This
also limits the number of DNS requests from check_*_*_access
restrictions. Files: dns/dns.h, dns/dns_lookup.c, dns/dns_rr.c,
dns/test_dns_lookup.c, posttls-finger/posttls-finger.c,
smtp/smtp_addr.c, smtpd/smtpd_check.c.
20240227
Documentation: document the need to disable regular expression
special characters when using $name inside an inlined
pattern. Files: proto/pcre_table, proto/regexp_table.

View File

@ -191,8 +191,12 @@ PCRE_TABLE(5) PCRE_TABLE(5)
Postfix parses the result as if it is a file in /etc/postfix. Postfix parses the result as if it is a file in /etc/postfix.
Note: if a rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from trying to Note: if an inlined rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from
do <i>$name</i> expansion as it evaluates a parameter value. trying to do <i>$name</i> expansion as it evaluates a parameter value.
Note: when using <i>$name</i> inside an inlined pattern, use \Q<i>$name</i>\E to dis-
able metacharacters such as '.' in the <i>$name</i> expansion. Otherwise, the
pattern may have unexpected matches.
<b>EXAMPLE SMTPD ACCESS MAP</b> <b>EXAMPLE SMTPD ACCESS MAP</b>
# Protect your outgoing majordomo exploders # Protect your outgoing majordomo exploders

View File

@ -13597,7 +13597,9 @@ verification errors if server certificate verification is not required.
With Postfix 2.8 and earlier, log the summary message and unconditionally With Postfix 2.8 and earlier, log the summary message and unconditionally
log trust-chain verification errors. </dd> log trust-chain verification errors. </dd>
<dt> </dt> <dd> 2 Also log levels during TLS negotiation. </dd> <dt> </dt> <dd> 2 Also enable verbose logging in the Postfix TLS
library, log session cache operations, and enable OpenSSL logging
of the progress of the SSL handshake. </dd>
<dt> </dt> <dd> 3 Also log the hexadecimal and ASCII dump of the <dt> </dt> <dd> 3 Also log the hexadecimal and ASCII dump of the
TLS negotiation process. </dd> TLS negotiation process. </dd>
@ -18851,7 +18853,9 @@ if client certificate verification is not required. With Postfix 2.8 and
earlier, log the summary message, peer certificate summary information earlier, log the summary message, peer certificate summary information
and unconditionally log trust-chain verification errors. </dd> and unconditionally log trust-chain verification errors. </dd>
<dt> </dt> <dd> 2 Also log levels during TLS negotiation. </dd> <dt> </dt> <dd> 2 Also enable verbose logging in the Postfix TLS
library, log session cache operations, and enable OpenSSL logging
of the progress of the SSL handshake. </dd>
<dt> </dt> <dd> 3 Also log hexadecimal and ASCII dump of TLS negotiation <dt> </dt> <dd> 3 Also log hexadecimal and ASCII dump of TLS negotiation
process. </dd> process. </dd>

View File

@ -148,8 +148,12 @@ REGEXP_TABLE(5) REGEXP_TABLE(5)
Postfix parses the result as if it is a file in /etc/postfix. Postfix parses the result as if it is a file in /etc/postfix.
Note: if a rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from trying to Note: if an inlined rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from
do <i>$name</i> expansion as it evaluates a parameter value. trying to do <i>$name</i> expansion as it evaluates a parameter value.
Note: when using <i>$name</i> inside an inlined pattern, this will not disable
metacharacters such as '.' in the <i>$name</i> expansion. To prevent unex-
pected matches, use a <a href="pcre_table.5.html">pcre</a>: table, and specify \Q<i>$name</i>\E.
<b>EXAMPLE SMTPD ACCESS MAP</b> <b>EXAMPLE SMTPD ACCESS MAP</b>
# Disallow sender-specified routing. This is a must if you relay mail # Disallow sender-specified routing. This is a must if you relay mail

View File

@ -206,9 +206,14 @@ in\-memory file:
Postfix parses the result as if it is a file in /etc/postfix. Postfix parses the result as if it is a file in /etc/postfix.
Note: if a rule contains \fB$\fR, specify \fB$$\fR to keep Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR
Postfix from trying to do \fI$name\fR expansion as it to keep Postfix from trying to do \fI$name\fR expansion as
evaluates a parameter value. it evaluates a parameter value.
Note: when using \fI$name\fR inside an inlined pattern, use
\eQ\fI$name\fR\eE to disable metacharacters such as '.' in
the \fI$name\fR expansion. Otherwise, the pattern may have
unexpected matches.
.SH "EXAMPLE SMTPD ACCESS MAP" .SH "EXAMPLE SMTPD ACCESS MAP"
.na .na
.nf .nf

View File

@ -9025,7 +9025,9 @@ With Postfix 2.8 and earlier, log the summary message and unconditionally
log trust\-chain verification errors. log trust\-chain verification errors.
.br .br
.IP "" .IP ""
2 Also log levels during TLS negotiation. 2 Also enable verbose logging in the Postfix TLS
library, log session cache operations, and enable OpenSSL logging
of the progress of the SSL handshake.
.br .br
.IP "" .IP ""
3 Also log the hexadecimal and ASCII dump of the 3 Also log the hexadecimal and ASCII dump of the
@ -13412,7 +13414,9 @@ earlier, log the summary message, peer certificate summary information
and unconditionally log trust\-chain verification errors. and unconditionally log trust\-chain verification errors.
.br .br
.IP "" .IP ""
2 Also log levels during TLS negotiation. 2 Also enable verbose logging in the Postfix TLS
library, log session cache operations, and enable OpenSSL logging
of the progress of the SSL handshake.
.br .br
.IP "" .IP ""
3 Also log hexadecimal and ASCII dump of TLS negotiation 3 Also log hexadecimal and ASCII dump of TLS negotiation

View File

@ -163,9 +163,14 @@ in\-memory file:
Postfix parses the result as if it is a file in /etc/postfix. Postfix parses the result as if it is a file in /etc/postfix.
Note: if a rule contains \fB$\fR, specify \fB$$\fR to keep Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR
Postfix from trying to do \fI$name\fR expansion as it to keep Postfix from trying to do \fI$name\fR expansion as
evaluates a parameter value. it evaluates a parameter value.
Note: when using \fI$name\fR inside an inlined pattern,
this will not disable metacharacters such as '.' in the
\fI$name\fR expansion. To prevent unexpected matches, use
a pcre: table, and specify \eQ\fI$name\fR\eE.
.SH "EXAMPLE SMTPD ACCESS MAP" .SH "EXAMPLE SMTPD ACCESS MAP"
.na .na
.nf .nf

View File

@ -190,9 +190,14 @@
# #
# Postfix parses the result as if it is a file in /etc/postfix. # Postfix parses the result as if it is a file in /etc/postfix.
# #
# Note: if a rule contains \fB$\fR, specify \fB$$\fR to keep # Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR
# Postfix from trying to do \fI$name\fR expansion as it # to keep Postfix from trying to do \fI$name\fR expansion as
# evaluates a parameter value. # it evaluates a parameter value.
#
# Note: when using \fI$name\fR inside an inlined pattern, use
# \eQ\fI$name\fR\eE to disable metacharacters such as '.' in
# the \fI$name\fR expansion. Otherwise, the pattern may have
# unexpected matches.
# EXAMPLE SMTPD ACCESS MAP # EXAMPLE SMTPD ACCESS MAP
# # Protect your outgoing majordomo exploders # # Protect your outgoing majordomo exploders
# /^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead # /^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead

View File

@ -9798,7 +9798,9 @@ if client certificate verification is not required. With Postfix 2.8 and
earlier, log the summary message, peer certificate summary information earlier, log the summary message, peer certificate summary information
and unconditionally log trust-chain verification errors. </dd> and unconditionally log trust-chain verification errors. </dd>
<dt> </dt> <dd> 2 Also log levels during TLS negotiation. </dd> <dt> </dt> <dd> 2 Also enable verbose logging in the Postfix TLS
library, log session cache operations, and enable OpenSSL logging
of the progress of the SSL handshake. </dd>
<dt> </dt> <dd> 3 Also log hexadecimal and ASCII dump of TLS negotiation <dt> </dt> <dd> 3 Also log hexadecimal and ASCII dump of TLS negotiation
process. </dd> process. </dd>
@ -10285,7 +10287,9 @@ verification errors if server certificate verification is not required.
With Postfix 2.8 and earlier, log the summary message and unconditionally With Postfix 2.8 and earlier, log the summary message and unconditionally
log trust-chain verification errors. </dd> log trust-chain verification errors. </dd>
<dt> </dt> <dd> 2 Also log levels during TLS negotiation. </dd> <dt> </dt> <dd> 2 Also enable verbose logging in the Postfix TLS
library, log session cache operations, and enable OpenSSL logging
of the progress of the SSL handshake. </dd>
<dt> </dt> <dd> 3 Also log the hexadecimal and ASCII dump of the <dt> </dt> <dd> 3 Also log the hexadecimal and ASCII dump of the
TLS negotiation process. </dd> TLS negotiation process. </dd>

View File

@ -147,9 +147,14 @@
# #
# Postfix parses the result as if it is a file in /etc/postfix. # Postfix parses the result as if it is a file in /etc/postfix.
# #
# Note: if a rule contains \fB$\fR, specify \fB$$\fR to keep # Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR
# Postfix from trying to do \fI$name\fR expansion as it # to keep Postfix from trying to do \fI$name\fR expansion as
# evaluates a parameter value. # it evaluates a parameter value.
#
# Note: when using \fI$name\fR inside an inlined pattern,
# this will not disable metacharacters such as '.' in the
# \fI$name\fR expansion. To prevent unexpected matches, use
# a pcre: table, and specify \eQ\fI$name\fR\eE.
# EXAMPLE SMTPD ACCESS MAP # EXAMPLE SMTPD ACCESS MAP
# # Disallow sender-specified routing. This is a must if you relay mail # # Disallow sender-specified routing. This is a must if you relay mail
# # for other domains. # # for other domains.

View File

@ -1602,3 +1602,4 @@ GmbH
Hamid Hamid
LLC LLC
Maadani Maadani
GTEST

View File

@ -116,3 +116,5 @@ proto proto aliases proto virtual proto ADDRESS_REWRITING_README html
status Files postconf postconf c postconf postconf_dbms c status Files postconf postconf c postconf postconf_dbms c
postconf postconf h conf postfix script conf post install postconf postconf h conf postfix script conf post install
postconf postconf c postconf postconf_dbms c postconf postconf c postconf postconf_dbms c
File tlsmgr tlsmgr c
restrictions Files dns dns h dns dns_lookup c dns dns_rr c

View File

@ -357,3 +357,4 @@ the form of a domain name hostname hostname service hostname service
expected to become a list of comma separated names br br This expected to become a list of comma separated names br br This
Postfix Postfix can use MongoDB as a source for any of its lookups aliases 5 virtual 5 canonical 5 etc This allows you to keep information for your mail service in a replicated noSQL database with fine grained access controls By not storing it Postfix Postfix can use MongoDB as a source for any of its lookups aliases 5 virtual 5 canonical 5 etc This allows you to keep information for your mail service in a replicated noSQL database with fine grained access controls By not storing it
CCARGS CCARGS DHAS_MONGODB I usr include libmongoc 1 0 CCARGS CCARGS DHAS_MONGODB I usr include libmongoc 1 0
dt dt dd 2 Also enable verbose logging in the Postfix TLS

View File

@ -11,7 +11,8 @@ DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS) CFLAGS = $(DEBUG) $(OPT) $(DEFS)
INCL = INCL =
LIB = lib$(LIB_PREFIX)dns$(LIB_SUFFIX) LIB = lib$(LIB_PREFIX)dns$(LIB_SUFFIX)
TESTPROG= test_dns_lookup dns_rr_to_pa dns_rr_to_sa dns_sa_to_rr dns_rr_eq_sa TESTPROG= test_dns_lookup dns_rr_to_pa dns_rr_to_sa dns_sa_to_rr dns_rr_eq_sa \
dns_rr_test
LIBS = ../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \ LIBS = ../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX) ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
LIB_DIR = ../../lib LIB_DIR = ../../lib
@ -31,7 +32,7 @@ test: $(TESTPROG)
tests: test dns_rr_to_pa_test dns_rr_to_sa_test dns_sa_to_rr_test \ tests: test dns_rr_to_pa_test dns_rr_to_sa_test dns_sa_to_rr_test \
dns_rr_eq_sa_test no-a-test no-aaaa-test no-mx-test \ dns_rr_eq_sa_test no-a-test no-aaaa-test no-mx-test \
error-filter-test nullmx_test nxdomain_test mxonly_test \ error-filter-test nullmx_test nxdomain_test mxonly_test \
dnsbl_tests dnsbl_tests dns_rr_tests
dnsbl_tests: \ dnsbl_tests: \
dnsbl_ttl_127.0.0.2_bind_plain_test \ dnsbl_ttl_127.0.0.2_bind_plain_test \
@ -57,7 +58,7 @@ DNSBL_EXIST_REPLY_FIX = \
-e 's/ [0-9]* [0-9]* [0-9]* [0-9]* [0-9]*/ D D D D D/' \ -e 's/ [0-9]* [0-9]* [0-9]* [0-9]* [0-9]*/ D D D D D/' \
-e 's/127.0.0.[0-9]*$$/127.0.0.D/' \ -e 's/127.0.0.[0-9]*$$/127.0.0.D/' \
| uniq | uniq
root_tests: root_tests:
$(LIB): $(OBJS) $(LIB): $(OBJS)
@ -240,6 +241,12 @@ dnsbl_ttl_127.0.0.2_priv_ncache_test: test_dns_lookup dnsbl_ttl_127.0.0.2_bind_p
diff dnsbl_ttl_127.0.0.2_bind_plain.ref dnsbl_ttl_127.0.0.2_priv_ncache.tmp diff dnsbl_ttl_127.0.0.2_bind_plain.ref dnsbl_ttl_127.0.0.2_priv_ncache.tmp
rm -f dnsbl_ttl_127.0.0.2_priv_ncache.tmp rm -f dnsbl_ttl_127.0.0.2_priv_ncache.tmp
dns_rr_tests: dns_rr_test
$(SHLIB_ENV) $(VALGRIND) ./dns_rr_test
dns_rr_test: dns_rr_test.o $(LIB) $(LIBS)
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
printfck: $(OBJS) $(PROG) printfck: $(OBJS) $(PROG)
rm -rf printfck rm -rf printfck
mkdir printfck mkdir printfck
@ -286,7 +293,6 @@ dns_lookup.o: ../../include/vstring.h
dns_lookup.o: dns.h dns_lookup.o: dns.h
dns_lookup.o: dns_lookup.c dns_lookup.o: dns_lookup.c
dns_rr.o: ../../include/check_arg.h dns_rr.o: ../../include/check_arg.h
dns_rr.o: ../../include/mail_params.h
dns_rr.o: ../../include/msg.h dns_rr.o: ../../include/msg.h
dns_rr.o: ../../include/myaddrinfo.h dns_rr.o: ../../include/myaddrinfo.h
dns_rr.o: ../../include/mymalloc.h dns_rr.o: ../../include/mymalloc.h
@ -320,6 +326,19 @@ dns_rr_filter.o: ../../include/vstream.h
dns_rr_filter.o: ../../include/vstring.h dns_rr_filter.o: ../../include/vstring.h
dns_rr_filter.o: dns.h dns_rr_filter.o: dns.h
dns_rr_filter.o: dns_rr_filter.c dns_rr_filter.o: dns_rr_filter.c
dns_rr_test.o: ../../include/check_arg.h
dns_rr_test.o: ../../include/msg.h
dns_rr_test.o: ../../include/msg_vstream.h
dns_rr_test.o: ../../include/myaddrinfo.h
dns_rr_test.o: ../../include/mymalloc.h
dns_rr_test.o: ../../include/sock_addr.h
dns_rr_test.o: ../../include/stringops.h
dns_rr_test.o: ../../include/sys_defs.h
dns_rr_test.o: ../../include/vbuf.h
dns_rr_test.o: ../../include/vstream.h
dns_rr_test.o: ../../include/vstring.h
dns_rr_test.o: dns.h
dns_rr_test.o: dns_rr_test.c
dns_rr_to_pa.o: ../../include/check_arg.h dns_rr_to_pa.o: ../../include/check_arg.h
dns_rr_to_pa.o: ../../include/msg.h dns_rr_to_pa.o: ../../include/msg.h
dns_rr_to_pa.o: ../../include/myaddrinfo.h dns_rr_to_pa.o: ../../include/myaddrinfo.h

View File

@ -164,9 +164,14 @@ typedef struct DNS_RR {
struct DNS_RR *next; /* linkage */ struct DNS_RR *next; /* linkage */
size_t data_len; /* actual data size */ size_t data_len; /* actual data size */
char *data; /* a bunch of data */ char *data; /* a bunch of data */
int flags; /* DNS_RR_FLAG_XX, see below */
/* Add new fields at the end, for ABI forward compatibility. */ /* Add new fields at the end, for ABI forward compatibility. */
} DNS_RR; } DNS_RR;
#define DNS_RR_FLAG_TRUNCATED (1<<0)
#define DNS_RR_IS_TRUNCATED(rr) ((rr)->flags & DNS_RR_FLAG_TRUNCATED)
/* /*
* dns_strerror.c * dns_strerror.c
*/ */
@ -215,6 +220,7 @@ extern int dns_rr_compare_pref_any(DNS_RR *, DNS_RR *);
extern int dns_rr_compare_pref(DNS_RR *, DNS_RR *); extern int dns_rr_compare_pref(DNS_RR *, DNS_RR *);
extern DNS_RR *dns_rr_shuffle(DNS_RR *); extern DNS_RR *dns_rr_shuffle(DNS_RR *);
extern DNS_RR *dns_rr_remove(DNS_RR *, DNS_RR *); extern DNS_RR *dns_rr_remove(DNS_RR *, DNS_RR *);
extern int var_dns_rr_list_limit;
/* /*
* dns_rr_to_pa.c * dns_rr_to_pa.c

View File

@ -984,6 +984,8 @@ static int dns_get_answer(const char *orig_name, DNS_REPLY *reply, int type,
resource_found++; resource_found++;
rr->dnssec_valid = *maybe_secure ? reply->dnssec_ad : 0; rr->dnssec_valid = *maybe_secure ? reply->dnssec_ad : 0;
*rrlist = dns_rr_append(*rrlist, rr); *rrlist = dns_rr_append(*rrlist, rr);
if (DNS_RR_IS_TRUNCATED(*rrlist))
break;
} else if (status == DNS_NULLMX || status == DNS_NULLSRV) { } else if (status == DNS_NULLMX || status == DNS_NULLSRV) {
CORRUPT(status); /* TODO: use better name */ CORRUPT(status); /* TODO: use better name */
} else if (not_found_status != DNS_RETRY) } else if (not_found_status != DNS_RETRY)
@ -1214,8 +1216,11 @@ int dns_lookup_rl(const char *name, unsigned flags, DNS_RR **rrlist,
name, dns_strtype(type), dns_str_resflags(flags)); name, dns_strtype(type), dns_str_resflags(flags));
status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0, status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
fqdn, why, rcode, lflags); fqdn, why, rcode, lflags);
if (rrlist && rr) if (rrlist && rr) {
*rrlist = dns_rr_append(*rrlist, rr); *rrlist = dns_rr_append(*rrlist, rr);
if (DNS_RR_IS_TRUNCATED(*rrlist))
break;
}
if (status == DNS_OK) { if (status == DNS_OK) {
if (lflags & DNS_REQ_FLAG_STOP_OK) if (lflags & DNS_REQ_FLAG_STOP_OK)
break; break;
@ -1266,8 +1271,11 @@ int dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist,
name, dns_strtype(type), dns_str_resflags(flags)); name, dns_strtype(type), dns_str_resflags(flags));
status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0, status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
fqdn, why, rcode, lflags); fqdn, why, rcode, lflags);
if (rrlist && rr) if (rrlist && rr) {
*rrlist = dns_rr_append(*rrlist, rr); *rrlist = dns_rr_append(*rrlist, rr);
if (DNS_RR_IS_TRUNCATED(*rrlist))
break;
}
if (status == DNS_OK) { if (status == DNS_OK) {
if (lflags & DNS_REQ_FLAG_STOP_OK) if (lflags & DNS_REQ_FLAG_STOP_OK)
break; break;

View File

@ -97,12 +97,17 @@
/* /*
/* dns_rr_copy() makes a copy of a resource record. /* dns_rr_copy() makes a copy of a resource record.
/* /*
/* dns_rr_append() appends a resource record to a (list of) resource /* dns_rr_append() appends an input resource record list to
/* record(s). /* an output list. Null arguments are explicitly allowed.
/* A null input list is explicitly allowed. /* When the result would be longer than var_dns_rr_list_limit
/* This function will log a warning and will discard the /* (default: 100), dns_rr_append() logs a warning, flags the
/* resource record, when a list already contains var_dns_rr_list_limit /* output list as truncated, and discards the excess elements.
/* elements (default: 100). /* Once an output list is flagged as truncated (test with
/* DNS_RR_IS_TRUNCATED()), the caller is expected to stop
/* trying to append records to that list. Note: the 'truncated'
/* flag is transitive, i.e. when appending a input list that
/* was flagged as truncated to an output list, the output list
/* will also be flagged as truncated.
/* /*
/* dns_rr_sort() sorts a list of resource records into ascending /* dns_rr_sort() sorts a list of resource records into ascending
/* order according to a user-specified criterion. The result is the /* order according to a user-specified criterion. The result is the
@ -151,18 +156,19 @@
#include <mymalloc.h> #include <mymalloc.h>
#include <myrand.h> #include <myrand.h>
/* Global library. */
#include <mail_params.h>
/* DNS library. */ /* DNS library. */
#include "dns.h" #include "dns.h"
/* /*
* Global, to make code testable. * A generous safety limit for the number of DNS resource records that the
* Postfix DNS client library will admit into a list. The default value 100
* is 20x the default limit on the number address records that the Postfix
* SMTP client is willing to consider.
*
* Mutable, to make code testable.
*/ */
int var_dns_rr_list_limit = DEF_DNS_RR_LIST_LIMIT; int var_dns_rr_list_limit = 100;
/* dns_rr_create - fill in resource record structure */ /* dns_rr_create - fill in resource record structure */
@ -195,6 +201,7 @@ DNS_RR *dns_rr_create(const char *qname, const char *rname,
} }
rr->data_len = data_len; rr->data_len = data_len;
rr->next = 0; rr->next = 0;
rr->flags = 0;
return (rr); return (rr);
} }
@ -234,36 +241,58 @@ DNS_RR *dns_rr_copy(DNS_RR *src)
/* dns_rr_append_with_limit - append resource record to limited list */ /* dns_rr_append_with_limit - append resource record to limited list */
static DNS_RR *dns_rr_append_with_limit(DNS_RR *list, DNS_RR *rr, int limit) static void dns_rr_append_with_limit(DNS_RR *list, DNS_RR *rr, int limit)
{ {
/* /*
* To avoid log spam, remember a limited amount of information about a * Pre: list != 0, all lists are concatenated with dns_rr_append().
* past warning. When anomalies happen frequently, then it is OK that *
* some anomaly will not be logged, as long as the limit is enforced. * Post: all elements have the DNS_RR_FLAG_TRUNCATED flag value set, or all
* elements have it cleared, so that there is no need to update code in
* legacy stable releases that deletes or reorders elements.
*/ */
if (list == 0) { if (limit <= 1) {
list = rr; if (list->next || rr) {
} else if (limit > 1) { msg_warn("DNS record count limit (%d) exceeded -- dropping"
list->next = dns_rr_append_with_limit(list->next, rr, limit - 1); " excess record(s) after qname=%s qtype=%s",
} else { var_dns_rr_list_limit, list->qname,
static DNS_RR *logged_node; dns_strtype(list->type));
list->flags |= DNS_RR_FLAG_TRUNCATED;
if (logged_node != list) { dns_rr_free(list->next);
logged_node = list; dns_rr_free(rr);
msg_warn("dns_rr_append: dropping records after qname=%s qtype=%s", list->next = 0;
list->qname, dns_strtype(list->type)); }
} else {
if (list->next == 0 && rr) {
list->next = rr;
rr = 0;
}
if (list->next) {
dns_rr_append_with_limit(list->next, rr, limit - 1);
list->flags |= list->next->flags;
} }
dns_rr_free(rr);
} }
return (list);
} }
/* dns_rr_append - append resource record to list */ /* dns_rr_append - append resource record(s) to list, or discard */
DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr) DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr)
{ {
return (dns_rr_append_with_limit(list, rr, var_dns_rr_list_limit));
/*
* Note: rr is not length checked; when multiple lists are concatenated,
* the output length may be a small multiple of var_dns_rr_list_limit.
*/
if (rr == 0)
return (list);
if (list == 0)
return (rr);
if (!DNS_RR_IS_TRUNCATED(list)) {
dns_rr_append_with_limit(list, rr, var_dns_rr_list_limit);
} else {
dns_rr_free(rr);
}
return (list);
} }
/* dns_rr_compare_pref_ipv6 - compare records by preference, ipv6 preferred */ /* dns_rr_compare_pref_ipv6 - compare records by preference, ipv6 preferred */

View File

@ -0,0 +1,433 @@
/*
* System library.
*/
#include <sys_defs.h>
#include <stdlib.h>
/*
* Utility library.
*/
#include <msg.h>
#include <msg_vstream.h>
#include <mymalloc.h>
#include <stringops.h>
#include <vstring.h>
/*
* DNS library.
*/
#include <dns.h>
#define STR(x) vstring_str(x)
/*
* Test helpers. TODO: move eq_dns_rr() to testing/dns_rr_testers.c; need to
* verify that the expected difference is reported, or use a GTEST matcher.
*/
/* print_dns_rr - format as { qname, reply, flags } */
static char *print_dns_rr(VSTRING *buf, DNS_RR *rr)
{
static VSTRING *tmp;
if (tmp == 0)
tmp = vstring_alloc(100);
vstring_sprintf(buf, "{qname=%s, reply='%s', flags=0x%x}",
rr->qname, dns_strrecord(tmp, rr), rr->flags);
return (STR(buf));
}
/* eq_dns_rr - predicate that two lists are equivalent */
static int eq_dns_rr(DNS_RR *got, DNS_RR *want)
{
VSTRING *got_buf = 0;
VSTRING *want_buf = 0;
#define EQ_DNS_RR_RETURN(val) do { \
if (got_buf) \
vstring_free(got_buf); \
if (want_buf) \
vstring_free(want_buf); \
return (val); \
} while (0)
/* Same length. */
if (got == 0 && want == 0)
EQ_DNS_RR_RETURN(1);
if (want == 0) {
msg_warn("got %s, want null",
print_dns_rr(got_buf = vstring_alloc(100), got));
}
if (got == 0) {
msg_warn("got null, want %s",
print_dns_rr(want_buf = vstring_alloc(100), want));
EQ_DNS_RR_RETURN(0);
}
/* Same query name, resource record, flags. */
if (strcmp(print_dns_rr(got_buf = vstring_alloc(100), got),
print_dns_rr(want_buf = vstring_alloc(100), want)) != 0) {
msg_warn("got %s, want %s", STR(want_buf), STR(got_buf));
EQ_DNS_RR_RETURN(0);
}
/* Same children. */
EQ_DNS_RR_RETURN(eq_dns_rr(got->next, want->next));
}
static int eq_dns_rr_free(DNS_RR *got, DNS_RR *want)
{
int res = eq_dns_rr(got, want);
dns_rr_free(got);
dns_rr_free(want);
return (res);
}
/*
* Tests and test cases.
*/
typedef struct TEST_CASE {
const char *label; /* identifies test case */
int (*fn) (void);
} TEST_CASE;
#define PASS (0)
#define FAIL (1)
/*
* Begin helper tests. TODO: move these to testing/dns_rr_testers_test.c.
*/
static int eq_dns_rr_qname_differ(void)
{
DNS_RR *got = dns_rr_create("qa", "ra", T_SRV, C_IN, 3600, 1, 25, 1, "mxa", 3);
DNS_RR *want = dns_rr_copy(got);
myfree(want->qname);
want->qname = mystrdup("qb");
return (!eq_dns_rr_free(got, want));
}
static int eq_dns_rr_reply_differ(void)
{
DNS_RR *got = dns_rr_create("qa", "ra", T_SRV, C_IN, 3600, 1, 25, 1, "mxa", 3);
DNS_RR *want = dns_rr_copy(got);
want->port += 1;
return (!eq_dns_rr_free(got, want));
}
/*
* End helper tests.
*/
/*
* Begin DNS_RR tests.
*/
static int eq_dns_rr_flags_differ(void)
{
DNS_RR *got = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *want = dns_rr_copy(got);
want->flags |= DNS_RR_FLAG_TRUNCATED;
return (!eq_dns_rr_free(got, want));
}
static int append_to_null_from_null(void)
{
DNS_RR *got = dns_rr_append((DNS_RR *) 0, (DNS_RR *) 0);
DNS_RR *want = 0;
return (eq_dns_rr_free(got, want));
}
static int append_to_elem_from_null(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *got, *want;
got = dns_rr_append(dns_rr_copy(a), (DNS_RR *) 0);
want = a;
return (eq_dns_rr_free(got, want));
}
static int appent_to_null_from_elem(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *got, *want;
got = dns_rr_append((DNS_RR *) 0, dns_rr_copy(a));
want = a;
return (eq_dns_rr_free(got, want));
}
static int append_to_elem_from_elem(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *got, *want;
got = dns_rr_append(dns_rr_copy(a), dns_rr_copy(b));
(want = a)->next = b;
return (eq_dns_rr_free(got, want));
}
static int append_to_elem_from_list(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *got, *want;
got = dns_rr_append(dns_rr_copy(a),
dns_rr_append(dns_rr_copy(b),
dns_rr_copy(c)));
((want = a)->next = b)->next = c;
return (eq_dns_rr_free(got, want));
}
static int append_to_list_from_elem(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *got, *want;
got = dns_rr_append(dns_rr_append(dns_rr_copy(a),
dns_rr_copy(b)),
dns_rr_copy(c));
((want = a)->next = b)->next = c;
return (eq_dns_rr_free(got, want));
}
static int append_to_list_from_list(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *d = dns_rr_create_noport("qd", "rd", T_MX, C_IN, 3600, 1, "mxd", 3);
DNS_RR *got, *want;
got = dns_rr_append(dns_rr_append(dns_rr_copy(a),
dns_rr_copy(b)),
dns_rr_append(dns_rr_copy(c),
dns_rr_copy(d)));
(((want = a)->next = b)->next = c)->next = d;
return (eq_dns_rr_free(got, want));
}
static int append_propagates_flags(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *d = dns_rr_create_noport("qd", "rd", T_MX, C_IN, 3600, 1, "mxd", 3);
DNS_RR *left = dns_rr_append(dns_rr_copy(a), dns_rr_copy(b));
DNS_RR *rite = dns_rr_append(dns_rr_copy(c), dns_rr_copy(d));
DNS_RR *got, *want, *rr;
for (rr = rite; rr; rr = rr->next)
rr->flags |= DNS_RR_FLAG_TRUNCATED;
got = dns_rr_append(left, rite);
(((want = a)->next = b)->next = c)->next = d;
for (rr = want; rr; rr = rr->next)
rr->flags |= DNS_RR_FLAG_TRUNCATED;
return (eq_dns_rr_free(got, want));
}
static int append_to_list_from_list_truncate(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *d = dns_rr_create_noport("qd", "rd", T_MX, C_IN, 3600, 1, "mxd", 3);
DNS_RR *got, *want, *rr;
var_dns_rr_list_limit = 3;
((want = dns_rr_copy(a))->next = dns_rr_copy(b))->next = dns_rr_copy(c);
for (rr = want; rr; rr = rr->next)
rr->flags |= DNS_RR_FLAG_TRUNCATED;
got = dns_rr_append(dns_rr_append(a, b),
dns_rr_append(c, d));
return (eq_dns_rr_free(got, want));
}
static int append_to_list_from_elem_elem_truncate(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *d = dns_rr_create_noport("qd", "rd", T_MX, C_IN, 3600, 1, "mxd", 3);
DNS_RR *got, *want, *rr;
var_dns_rr_list_limit = 2;
(want = dns_rr_copy(a))->next = dns_rr_copy(b);
for (rr = want; rr; rr = rr->next)
rr->flags |= DNS_RR_FLAG_TRUNCATED;
got = dns_rr_append(a, b);
got = dns_rr_append(got, c); /* should be logged */
got = dns_rr_append(got, d); /* should be silent */
return (eq_dns_rr_free(got, want));
}
static int append_to_list_from_elem_truncate(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *got, *want, *rr;
var_dns_rr_list_limit = 2;
(want = dns_rr_copy(a))->next = dns_rr_copy(b);
for (rr = want; rr; rr = rr->next)
rr->flags |= DNS_RR_FLAG_TRUNCATED;
got = dns_rr_append(dns_rr_append(a, b), c);
return (eq_dns_rr_free(got, want));
}
static int append_to_elem_from_list_truncate(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *got, *want, *rr;
var_dns_rr_list_limit = 2;
(want = dns_rr_copy(a))->next = dns_rr_copy(b);
for (rr = want; rr; rr = rr->next)
rr->flags |= DNS_RR_FLAG_TRUNCATED;
got = dns_rr_append(a, dns_rr_append(b, c));
return (eq_dns_rr_free(got, want));
}
static int append_to_list_from_elem_exact_fit(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *got, *want;
var_dns_rr_list_limit = 3;
((want = dns_rr_copy(a))->next = dns_rr_copy(b))->next = dns_rr_copy(c);
got = dns_rr_append(dns_rr_append(a, b), c);
return (eq_dns_rr_free(got, want));
}
static int append_to_elem_from_list_exact_fit(void)
{
DNS_RR *a = dns_rr_create_noport("qa", "ra", T_MX, C_IN, 3600, 1, "mxa", 3);
DNS_RR *b = dns_rr_create_noport("qb", "rb", T_MX, C_IN, 3600, 1, "mxb", 3);
DNS_RR *c = dns_rr_create_noport("qc", "rc", T_MX, C_IN, 3600, 1, "mxc", 3);
DNS_RR *got, *want;
var_dns_rr_list_limit = 3;
((want = dns_rr_copy(a))->next = dns_rr_copy(b))->next = dns_rr_copy(c);
got = dns_rr_append(a, dns_rr_append(b, c));
return (eq_dns_rr_free(got, want));
}
/*
* The test cases.
*/
static const TEST_CASE test_cases[] = {
/*
* Test eq_dns_rr; TODO: move to testing/dns_rr_testers_test.c
*/
"eq_dns_rr qname differ", eq_dns_rr_qname_differ,
"eq_dns_rr reply differ", eq_dns_rr_reply_differ,
"eq_dns_rr flags differ", eq_dns_rr_flags_differ,
/*
* Test dns_rr_append() without truncation.
*/
"append to null from null", append_to_null_from_null,
"append to null from element", appent_to_null_from_elem,
"append to element from null", append_to_elem_from_null,
"append to element from element", append_to_elem_from_elem,
"append to element from list", append_to_elem_from_list,
"append to list from element", append_to_list_from_elem,
"append to list from list", append_to_list_from_list,
/*
* Test dns_rr_append() flag propagation.
*/
"append propagates flags", append_propagates_flags,
/*
* Test dns_rr_append() with truncation.
*/
"append to list from list truncate", append_to_list_from_list_truncate,
"append to list from element element truncate", append_to_list_from_elem_elem_truncate,
"append to list from element truncate", append_to_list_from_elem_truncate,
"append to element from list truncate", append_to_elem_from_list_truncate,
"append to list from element exact fit", append_to_list_from_elem_exact_fit,
"append to element from list exact fit", append_to_elem_from_list_exact_fit,
/*
* TODO: tests dns_rr_sort(), dns_rr_srv_sort(), dns_rr_remove(),
* dns_rr_shuffle(), etc.
*/
0,
};
int main(int argc, char **argv)
{
const TEST_CASE *tp;
int pass = 0;
int fail = 0;
VSTRING *res_buf = vstring_alloc(100);
int saved_limit = var_dns_rr_list_limit;
msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
for (tp = test_cases; tp->label != 0; tp++) {
msg_info("RUN %s", tp->label);
if (tp->fn() == 0) {
fail++;
msg_info("FAIL %s", tp->label);
} else {
msg_info("PASS %s", tp->label);
pass++;
}
var_dns_rr_list_limit = saved_limit;
}
msg_info("PASS=%d FAIL=%d", pass, fail);
vstring_free(res_buf);
exit(fail != 0);
}

View File

@ -78,11 +78,12 @@ char *dns_strrecord(VSTRING *buf, DNS_RR *rr)
vstring_sprintf_append(buf, "%s", rr->data); vstring_sprintf_append(buf, "%s", rr->data);
break; break;
case T_MX: case T_MX:
vstring_sprintf_append(buf, "%u %s.", rr->pref, rr->data); vstring_sprintf_append(buf, "%u %.*s.", rr->pref,
(int) rr->data_len, rr->data);
break; break;
case T_SRV: case T_SRV:
vstring_sprintf_append(buf, "%u %u %u %s.", rr->pref, rr->weight, vstring_sprintf_append(buf, "%u %u %u %.*s.", rr->pref, rr->weight,
rr->port, rr->data); rr->port, (int) rr->data_len, rr->data);
break; break;
case T_TLSA: case T_TLSA:
if (rr->data_len >= 3) { if (rr->data_len >= 3) {

View File

@ -124,9 +124,11 @@ int main(int argc, char **argv)
vstream_printf("%s: fqdn: %s\n", name, vstring_str(fqdn)); vstream_printf("%s: fqdn: %s\n", name, vstring_str(fqdn));
buf = vstring_alloc(100); buf = vstring_alloc(100);
print_rr(buf, rr); print_rr(buf, rr);
vstream_fflush(VSTREAM_OUT);
if (DNS_RR_IS_TRUNCATED(rr))
msg_warn("one or more excess DNS_RR records were dropped");
dns_rr_free(rr); dns_rr_free(rr);
vstring_free(buf); vstring_free(buf);
vstream_fflush(VSTREAM_OUT);
} }
} }
myfree((void *) types); myfree((void *) types);

View File

@ -4384,16 +4384,6 @@ extern int var_idna2003_compat;
#define DEF_DNS_NCACHE_TTL_FIX 0 #define DEF_DNS_NCACHE_TTL_FIX 0
extern bool var_dns_ncache_ttl_fix; extern bool var_dns_ncache_ttl_fix;
/*
* A generous safety limit for the number of DNS resource records that the
* Postfix DNS client library will admit into a list. The default is 20x the
* default limit on the number address records that the Postfix SMTP client
* is willing to consider.
*/
#define VAR_DNS_RR_LIST_LIMIT "dns_resource_list_limit"
#define DEF_DNS_RR_LIST_LIMIT 100
extern int var_dns_rr_list_limit;
/* /*
* Logging. As systems evolve over time, logging becomes more challenging. * Logging. As systems evolve over time, logging becomes more challenging.
*/ */

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20240218" #define MAIL_RELEASE_DATE "20240227"
#define MAIL_VERSION_NUMBER "3.9" #define MAIL_VERSION_NUMBER "3.9"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@ -1280,6 +1280,8 @@ static DNS_RR *addr_one(STATE *state, DNS_RR *addr_list, const char *host,
msg_fatal("host %s: conversion error for address family %d: %m", msg_fatal("host %s: conversion error for address family %d: %m",
host, ((struct sockaddr *) (res0->ai_addr))->sa_family); host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
addr_list = dns_rr_append(addr_list, addr); addr_list = dns_rr_append(addr_list, addr);
if (DNS_RR_IS_TRUNCATED(addr_list))
break;
} }
freeaddrinfo(res0); freeaddrinfo(res0);
if (found == 0) { if (found == 0) {
@ -1317,6 +1319,8 @@ static DNS_RR *mx_addr_list(STATE *state, DNS_RR *mx_names)
msg_panic("%s: bad resource type: %d", myname, rr->type); msg_panic("%s: bad resource type: %d", myname, rr->type);
addr_list = addr_one(state, addr_list, (char *) rr->data, res_opt, addr_list = addr_one(state, addr_list, (char *) rr->data, res_opt,
rr->pref, rr->port); rr->pref, rr->port);
if (addr_list && DNS_RR_IS_TRUNCATED(addr_list))
break;
} }
return (addr_list); return (addr_list);
} }

View File

@ -179,10 +179,10 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt,
if ((addr = dns_sa_to_rr(host, pref, res0->ai_addr)) == 0) if ((addr = dns_sa_to_rr(host, pref, res0->ai_addr)) == 0)
msg_fatal("host %s: conversion error for address family " msg_fatal("host %s: conversion error for address family "
"%d: %m", host, res0->ai_addr->sa_family); "%d: %m", host, res0->ai_addr->sa_family);
addr_list = dns_rr_append(addr_list, addr);
addr->pref = pref; addr->pref = pref;
addr->port = port; addr->port = port;
if (msg_verbose) addr_list = dns_rr_append(addr_list, addr);
if (msg_verbose && !DNS_RR_IS_TRUNCATED(addr_list))
msg_info("%s: using numerical host %s", myname, host); msg_info("%s: using numerical host %s", myname, host);
freeaddrinfo(res0); freeaddrinfo(res0);
return (addr_list); return (addr_list);
@ -262,6 +262,8 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt,
msg_fatal("host %s: conversion error for address family " msg_fatal("host %s: conversion error for address family "
"%d: %m", host, res0->ai_addr->sa_family); "%d: %m", host, res0->ai_addr->sa_family);
addr_list = dns_rr_append(addr_list, addr); addr_list = dns_rr_append(addr_list, addr);
if (DNS_RR_IS_TRUNCATED(addr_list))
break;
if (msg_verbose) { if (msg_verbose) {
MAI_HOSTADDR_STR hostaddr_str; MAI_HOSTADDR_STR hostaddr_str;
@ -327,6 +329,8 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, DSN_BUF *why)
msg_panic("smtp_addr_list: bad resource type: %d", rr->type); msg_panic("smtp_addr_list: bad resource type: %d", rr->type);
addr_list = smtp_addr_one(addr_list, (char *) rr->data, res_opt, addr_list = smtp_addr_one(addr_list, (char *) rr->data, res_opt,
rr->pref, rr->port, why); rr->pref, rr->port, why);
if (addr_list && DNS_RR_IS_TRUNCATED(addr_list))
break;
} }
return (addr_list); return (addr_list);
} }
@ -420,6 +424,13 @@ static DNS_RR *smtp_balance_inet_proto(DNS_RR *addr_list, int misc_flags,
* relative list order is unchanged, but some elements are removed. * relative list order is unchanged, but some elements are removed.
*/ */
/*
* Ensure that dns_rr_append() won't interfere with the protocol
* balancing goals.
*/
if (addr_limit > var_dns_rr_list_limit)
addr_limit = var_dns_rr_list_limit;
/* /*
* Count the number of IPv6 and IPv4 addresses. * Count the number of IPv6 and IPv4 addresses.
*/ */

View File

@ -3021,6 +3021,7 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
struct addrinfo *res; struct addrinfo *res;
int status; int status;
const INET_PROTO_INFO *proto_info; const INET_PROTO_INFO *proto_info;
int server_addr_count = 0;
/* /*
* Sanity check. * Sanity check.
@ -3172,6 +3173,15 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
msg_info("%s: %s host address check: %s", msg_info("%s: %s host address check: %s",
myname, dns_strtype(type), (char *) server->data); myname, dns_strtype(type), (char *) server->data);
for (res = res0; res != 0; res = res->ai_next) { for (res = res0; res != 0; res = res->ai_next) {
server_addr_count += 1;
if (server_addr_count > var_dns_rr_list_limit) {
msg_warn("%s: %s server address count limit (%d) exceeded"
" for %s %s -- ignoring the remainder", myname,
dns_strtype(type), var_dns_rr_list_limit,
reply_class, reply_name);
freeaddrinfo(res0);
CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO);
}
if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) { if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
if (msg_verbose) if (msg_verbose)
msg_info("skipping address family %d for host %s", msg_info("skipping address family %d for host %s",