2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 18:07:41 +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],
util/argv.[hc].
Workaround: some OS lies under load: it says that a socket
is readable, then it says that the socket has unread data,
and then it says that read returns EOF, causing Postfix to
spam the log with a warning message. File: tlsmgr/tlsmgr.c.
Workaround: tlsmgr logfile spam. Some OS lies under load:
it says that a socket is readable, then it says that the
socket has unread data, and then it says that read returns
EOF, causing Postfix to spam the log with a warning message.
File: tlsmgr/tlsmgr.c.
20240125
@ -27829,17 +27830,6 @@ Apologies for any names omitted.
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
manager deferred delivery to all destinations over a specific
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,
postconf/postconf.h, conf/postfix-script, conf/post-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.
Note: if a rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from trying to
do <i>$name</i> expansion as it evaluates a parameter value.
Note: if an inlined rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from
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>
# 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
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
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
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
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.
Note: if a rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from trying to
do <i>$name</i> expansion as it evaluates a parameter value.
Note: if an inlined rule contains <b>$</b>, specify <b>$$</b> to keep Postfix from
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>
# 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.
Note: if a rule contains \fB$\fR, specify \fB$$\fR to keep
Postfix from trying to do \fI$name\fR expansion as it
evaluates a parameter value.
Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR
to keep Postfix from trying to do \fI$name\fR expansion as
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"
.na
.nf

View File

@ -9025,7 +9025,9 @@ With Postfix 2.8 and earlier, log the summary message and unconditionally
log trust\-chain verification errors.
.br
.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
.IP ""
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.
.br
.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
.IP ""
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.
Note: if a rule contains \fB$\fR, specify \fB$$\fR to keep
Postfix from trying to do \fI$name\fR expansion as it
evaluates a parameter value.
Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR
to keep Postfix from trying to do \fI$name\fR expansion as
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"
.na
.nf

View File

@ -190,9 +190,14 @@
#
# 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
# Postfix from trying to do \fI$name\fR expansion as it
# evaluates a parameter value.
# Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR
# to keep Postfix from trying to do \fI$name\fR expansion as
# 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
# # Protect your outgoing majordomo exploders
# /^(?!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
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
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
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
TLS negotiation process. </dd>

View File

@ -147,9 +147,14 @@
#
# 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
# Postfix from trying to do \fI$name\fR expansion as it
# evaluates a parameter value.
# Note: if an inlined rule contains \fB$\fR, specify \fB$$\fR
# to keep Postfix from trying to do \fI$name\fR expansion as
# 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
# # Disallow sender-specified routing. This is a must if you relay mail
# # for other domains.

View File

@ -1602,3 +1602,4 @@ GmbH
Hamid
LLC
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
postconf postconf h conf postfix script conf post install
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
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
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)
INCL =
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) \
../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
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 \
dns_rr_eq_sa_test no-a-test no-aaaa-test no-mx-test \
error-filter-test nullmx_test nxdomain_test mxonly_test \
dnsbl_tests
dnsbl_tests dns_rr_tests
dnsbl_tests: \
dnsbl_ttl_127.0.0.2_bind_plain_test \
@ -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
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)
rm -rf printfck
mkdir printfck
@ -286,7 +293,6 @@ dns_lookup.o: ../../include/vstring.h
dns_lookup.o: dns.h
dns_lookup.o: dns_lookup.c
dns_rr.o: ../../include/check_arg.h
dns_rr.o: ../../include/mail_params.h
dns_rr.o: ../../include/msg.h
dns_rr.o: ../../include/myaddrinfo.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: dns.h
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/msg.h
dns_rr_to_pa.o: ../../include/myaddrinfo.h

View File

@ -164,9 +164,14 @@ typedef struct DNS_RR {
struct DNS_RR *next; /* linkage */
size_t data_len; /* actual data size */
char *data; /* a bunch of data */
int flags; /* DNS_RR_FLAG_XX, see below */
/* Add new fields at the end, for ABI forward compatibility. */
} DNS_RR;
#define DNS_RR_FLAG_TRUNCATED (1<<0)
#define DNS_RR_IS_TRUNCATED(rr) ((rr)->flags & DNS_RR_FLAG_TRUNCATED)
/*
* 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 DNS_RR *dns_rr_shuffle(DNS_RR *);
extern DNS_RR *dns_rr_remove(DNS_RR *, DNS_RR *);
extern int var_dns_rr_list_limit;
/*
* 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++;
rr->dnssec_valid = *maybe_secure ? reply->dnssec_ad : 0;
*rrlist = dns_rr_append(*rrlist, rr);
if (DNS_RR_IS_TRUNCATED(*rrlist))
break;
} else if (status == DNS_NULLMX || status == DNS_NULLSRV) {
CORRUPT(status); /* TODO: use better name */
} 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));
status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
fqdn, why, rcode, lflags);
if (rrlist && rr)
if (rrlist && rr) {
*rrlist = dns_rr_append(*rrlist, rr);
if (DNS_RR_IS_TRUNCATED(*rrlist))
break;
}
if (status == DNS_OK) {
if (lflags & DNS_REQ_FLAG_STOP_OK)
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));
status = dns_lookup_x(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
fqdn, why, rcode, lflags);
if (rrlist && rr)
if (rrlist && rr) {
*rrlist = dns_rr_append(*rrlist, rr);
if (DNS_RR_IS_TRUNCATED(*rrlist))
break;
}
if (status == DNS_OK) {
if (lflags & DNS_REQ_FLAG_STOP_OK)
break;

View File

@ -97,12 +97,17 @@
/*
/* dns_rr_copy() makes a copy of a resource record.
/*
/* dns_rr_append() appends a resource record to a (list of) resource
/* record(s).
/* A null input list is explicitly allowed.
/* This function will log a warning and will discard the
/* resource record, when a list already contains var_dns_rr_list_limit
/* elements (default: 100).
/* dns_rr_append() appends an input resource record list to
/* an output list. Null arguments are explicitly allowed.
/* When the result would be longer than var_dns_rr_list_limit
/* (default: 100), dns_rr_append() logs a warning, flags the
/* output list as truncated, and discards the excess elements.
/* 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
/* order according to a user-specified criterion. The result is the
@ -151,18 +156,19 @@
#include <mymalloc.h>
#include <myrand.h>
/* Global library. */
#include <mail_params.h>
/* DNS library. */
#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 */
@ -195,6 +201,7 @@ DNS_RR *dns_rr_create(const char *qname, const char *rname,
}
rr->data_len = data_len;
rr->next = 0;
rr->flags = 0;
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 */
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
* past warning. When anomalies happen frequently, then it is OK that
* some anomaly will not be logged, as long as the limit is enforced.
* Pre: list != 0, all lists are concatenated with dns_rr_append().
*
* 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) {
list = rr;
} else if (limit > 1) {
list->next = dns_rr_append_with_limit(list->next, rr, limit - 1);
} else {
static DNS_RR *logged_node;
if (logged_node != list) {
logged_node = list;
msg_warn("dns_rr_append: dropping records after qname=%s qtype=%s",
list->qname, dns_strtype(list->type));
}
if (limit <= 1) {
if (list->next || rr) {
msg_warn("DNS record count limit (%d) exceeded -- dropping"
" excess record(s) after qname=%s qtype=%s",
var_dns_rr_list_limit, list->qname,
dns_strtype(list->type));
list->flags |= DNS_RR_FLAG_TRUNCATED;
dns_rr_free(list->next);
dns_rr_free(rr);
list->next = 0;
}
} 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;
}
}
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)
{
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 */

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);
break;
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;
case T_SRV:
vstring_sprintf_append(buf, "%u %u %u %s.", rr->pref, rr->weight,
rr->port, rr->data);
vstring_sprintf_append(buf, "%u %u %u %.*s.", rr->pref, rr->weight,
rr->port, (int) rr->data_len, rr->data);
break;
case T_TLSA:
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));
buf = vstring_alloc(100);
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);
vstring_free(buf);
vstream_fflush(VSTREAM_OUT);
}
}
myfree((void *) types);

View File

@ -4384,16 +4384,6 @@ extern int var_idna2003_compat;
#define DEF_DNS_NCACHE_TTL_FIX 0
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.
*/

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20240218"
#define MAIL_RELEASE_DATE "20240227"
#define MAIL_VERSION_NUMBER "3.9"
#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",
host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
addr_list = dns_rr_append(addr_list, addr);
if (DNS_RR_IS_TRUNCATED(addr_list))
break;
}
freeaddrinfo(res0);
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);
addr_list = addr_one(state, addr_list, (char *) rr->data, res_opt,
rr->pref, rr->port);
if (addr_list && DNS_RR_IS_TRUNCATED(addr_list))
break;
}
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)
msg_fatal("host %s: conversion error for address family "
"%d: %m", host, res0->ai_addr->sa_family);
addr_list = dns_rr_append(addr_list, addr);
addr->pref = pref;
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);
freeaddrinfo(res0);
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 "
"%d: %m", host, res0->ai_addr->sa_family);
addr_list = dns_rr_append(addr_list, addr);
if (DNS_RR_IS_TRUNCATED(addr_list))
break;
if (msg_verbose) {
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);
addr_list = smtp_addr_one(addr_list, (char *) rr->data, res_opt,
rr->pref, rr->port, why);
if (addr_list && DNS_RR_IS_TRUNCATED(addr_list))
break;
}
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.
*/
/*
* 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.
*/

View File

@ -3021,6 +3021,7 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
struct addrinfo *res;
int status;
const INET_PROTO_INFO *proto_info;
int server_addr_count = 0;
/*
* 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",
myname, dns_strtype(type), (char *) server->data);
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 (msg_verbose)
msg_info("skipping address family %d for host %s",