From 02bb17535ff02789a1016b8c330127632fc70413 Mon Sep 17 00:00:00 2001 From: Wietse Z Venema Date: Thu, 22 Feb 2024 00:00:00 -0500 Subject: [PATCH] postfix-3.9-20240222-nonprod --- postfix/HISTORY | 11 +++ postfix/makedefs | 2 +- postfix/src/dns/Makefile.in | 1 - postfix/src/dns/dns.h | 6 ++ postfix/src/dns/dns_lookup.c | 18 ++-- postfix/src/dns/dns_rr.c | 98 +++++++++++++-------- postfix/src/dns/test_dns_lookup.c | 4 +- postfix/src/global/mail_params.h | 10 --- postfix/src/global/mail_version.h | 2 +- postfix/src/posttls-finger/posttls-finger.c | 31 ++++++- postfix/src/smtp/smtp_addr.c | 40 ++++++++- postfix/src/smtpd/smtpd_check.c | 14 +++ 12 files changed, 174 insertions(+), 63 deletions(-) diff --git a/postfix/HISTORY b/postfix/HISTORY index 5fec159d4..0539d07f0 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -27920,3 +27920,14 @@ 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. + +20240222 + + Safety: drop and log over-size DNS responses resulting in + more than 100 records. This prevents a tail recursion error + in dns_rr_append(), reported by Toshifumi Sakaguchi, and + prevents DNS request multiplication in check_xx_yy_access. + 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. + diff --git a/postfix/makedefs b/postfix/makedefs index 430324d4e..1ee5fd4ca 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -973,7 +973,7 @@ CCARGS="$CCARGS -DSNAPSHOT" # Non-production: needs thorough testing, or major changes are still # needed before the code stabilizes. -#CCARGS="$CCARGS -DNONPROD" +CCARGS="$CCARGS -DNONPROD" # Workaround: prepend Postfix include files before other include files. CCARGS="-I. -I../../include $CCARGS" diff --git a/postfix/src/dns/Makefile.in b/postfix/src/dns/Makefile.in index 769354508..3ebf75f81 100644 --- a/postfix/src/dns/Makefile.in +++ b/postfix/src/dns/Makefile.in @@ -286,7 +286,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 diff --git a/postfix/src/dns/dns.h b/postfix/src/dns/dns.h index 2b77015cb..63360418c 100644 --- a/postfix/src/dns/dns.h +++ b/postfix/src/dns/dns.h @@ -26,6 +26,7 @@ #include #endif #include +#include /* INT_MAX */ /* * Name server compatibility. These undocumented macros appear in the file @@ -164,9 +165,12 @@ typedef struct DNS_RR { struct DNS_RR *next; /* linkage */ size_t data_len; /* actual data size */ char *data; /* a bunch of data */ + int len; /* list length or DNS_RR_DISCARDED */ /* Add new fields at the end, for ABI forward compatibility. */ } DNS_RR; +#define DNS_RR_DISCARDED INT_MAX /* sentinel */ + /* * dns_strerror.c */ @@ -207,6 +211,7 @@ extern DNS_RR *dns_rr_create(const char *, const char *, extern void dns_rr_free(DNS_RR *); extern DNS_RR *dns_rr_copy(DNS_RR *); extern DNS_RR *dns_rr_append(DNS_RR *, DNS_RR *); +extern DNS_RR *dns_rr_append_discard(DNS_RR *, DNS_RR *); extern DNS_RR *dns_rr_sort(DNS_RR *, int (*) (DNS_RR *, DNS_RR *)); extern DNS_RR *dns_srv_rr_sort(DNS_RR *); extern int dns_rr_compare_pref_ipv6(DNS_RR *, DNS_RR *); @@ -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 diff --git a/postfix/src/dns/dns_lookup.c b/postfix/src/dns/dns_lookup.c index bccdd83f5..60098f94c 100644 --- a/postfix/src/dns/dns_lookup.c +++ b/postfix/src/dns/dns_lookup.c @@ -983,7 +983,9 @@ static int dns_get_answer(const char *orig_name, DNS_REPLY *reply, int type, &fixed)) == DNS_OK) { resource_found++; rr->dnssec_valid = *maybe_secure ? reply->dnssec_ad : 0; - *rrlist = dns_rr_append(*rrlist, rr); + *rrlist = dns_rr_append_discard(*rrlist, rr); + if (*rrlist && (*rrlist)->len == DNS_RR_DISCARDED) + 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) - *rrlist = dns_rr_append(*rrlist, rr); + if (rrlist && rr) { + *rrlist = dns_rr_append_discard(*rrlist, rr); + if (*rrlist && (*rrlist)->len == DNS_RR_DISCARDED) + 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) - *rrlist = dns_rr_append(*rrlist, rr); + if (rrlist && rr) { + *rrlist = dns_rr_append_discard(*rrlist, rr); + if (*rrlist && (*rrlist)->len == DNS_RR_DISCARDED) + break; + } if (status == DNS_OK) { if (lflags & DNS_REQ_FLAG_STOP_OK) break; diff --git a/postfix/src/dns/dns_rr.c b/postfix/src/dns/dns_rr.c index deba784b7..20a51f421 100644 --- a/postfix/src/dns/dns_rr.c +++ b/postfix/src/dns/dns_rr.c @@ -29,6 +29,10 @@ /* DNS_RR *list; /* DNS_RR *record; /* +/* DNS_RR *dns_rr_append_discard(list, record) +/* DNS_RR *list; +/* DNS_RR *record; +/* /* DNS_RR *dns_rr_sort(list, compar) /* DNS_RR *list /* int (*compar)(DNS_RR *, DNS_RR *); @@ -100,9 +104,16 @@ /* 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_discard() appends of discards a resource +/* record list. When the existing list already contains +/* var_dns_rr_list_limit elements (default: 100), +/* dns_rr_append_discard() logs a warning, sets the existing +/* list length to the sentinel value DNS_RR_DISCARDED and +/* discards the new resource record(s) instead of appending +/* them. Once a list length is set to DNS_RR_DISCARDED, the +/* caller is expected to stop trying to append records to that +/* list. /* /* dns_rr_sort() sorts a list of resource records into ascending /* order according to a user-specified criterion. The result is the @@ -151,18 +162,19 @@ #include #include -/* Global library. */ - -#include - /* 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 +207,7 @@ DNS_RR *dns_rr_create(const char *qname, const char *rname, } rr->data_len = data_len; rr->next = 0; + rr->len = 1; return (rr); } @@ -232,38 +245,49 @@ DNS_RR *dns_rr_copy(DNS_RR *src) return (dst); } -/* 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) -{ - - /* - * 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. - */ - 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)); - } - dns_rr_free(rr); - } - return (list); -} - /* dns_rr_append - append resource record to list */ DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr) { - return (dns_rr_append_with_limit(list, rr, var_dns_rr_list_limit)); + if (rr == 0) + return (list); + if (list == 0) { + list = rr; + } else { + list->next = dns_rr_append(list->next, rr); + /* Non-sentinel lengths are o(100) an are always safe to add. */ + if (list->len == DNS_RR_DISCARDED || rr->len == DNS_RR_DISCARDED) + list->len = DNS_RR_DISCARDED; + else + list->len += rr->len; + } + return (list); +} + +/* dns_rr_append_discard - append resource record to list, or discard */ + +DNS_RR *dns_rr_append_discard(DNS_RR *list, DNS_RR *rr) +{ + if (rr == 0) + return (list); + if (list == 0) { + list = rr; + } else if (list->len < var_dns_rr_list_limit) { + list->next = dns_rr_append(list->next, rr); + /* Non-sentinel lengths are o(100) an are always safe to add. */ + if (rr->len == DNS_RR_DISCARDED) + list->len = DNS_RR_DISCARDED; + else + list->len += rr->len; + } else { + if (list->len != DNS_RR_DISCARDED) { + msg_warn("dropping excess records for qname=%s qtype=%s", + rr->qname, dns_strtype(rr->type)); + list->len = DNS_RR_DISCARDED; + } + dns_rr_free(rr); + } + return (list); } /* dns_rr_compare_pref_ipv6 - compare records by preference, ipv6 preferred */ diff --git a/postfix/src/dns/test_dns_lookup.c b/postfix/src/dns/test_dns_lookup.c index 9c0692b0d..380425ba1 100644 --- a/postfix/src/dns/test_dns_lookup.c +++ b/postfix/src/dns/test_dns_lookup.c @@ -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 (rr && rr->len == DNS_RR_DISCARDED) + 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); diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index fea312ad0..1f03b0b34 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -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. */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index d1dd2cf8d..6763a14eb 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 "20240222" #define MAIL_VERSION_NUMBER "3.9" #ifdef SNAPSHOT diff --git a/postfix/src/posttls-finger/posttls-finger.c b/postfix/src/posttls-finger/posttls-finger.c index 9df556082..4dab73087 100644 --- a/postfix/src/posttls-finger/posttls-finger.c +++ b/postfix/src/posttls-finger/posttls-finger.c @@ -1207,7 +1207,7 @@ static DNS_RR *addr_one(STATE *state, DNS_RR *addr_list, const char *host, host, ((struct sockaddr *) (res0->ai_addr))->sa_family); addr->pref = pref; addr->port = port; - addr_list = dns_rr_append(addr_list, addr); + addr_list = dns_rr_append_discard(addr_list, addr); freeaddrinfo(res0); return (addr_list); } @@ -1227,7 +1227,7 @@ static DNS_RR *addr_one(STATE *state, DNS_RR *addr_list, const char *host, rr->pref = pref; rr->port = port; } - addr_list = dns_rr_append(addr_list, addr); + addr_list = dns_rr_append_discard(addr_list, addr); return (addr_list); default: dsb_status(why, "4.4.3"); @@ -1279,7 +1279,9 @@ static DNS_RR *addr_one(STATE *state, DNS_RR *addr_list, const char *host, if ((addr = dns_sa_to_rr(host, pref, res->ai_addr)) == 0) 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); + addr_list = dns_rr_append_discard(addr_list, addr); + if (addr_list->len == DNS_RR_DISCARDED) + 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 && addr_list->len == DNS_RR_DISCARDED) + break; } return (addr_list); } @@ -1361,6 +1365,10 @@ static DNS_RR *domain_addr(STATE *state, char *domain) dsb_status(state->why, "5.4.3"); break; case DNS_OK: + if (mx_names && mx_names->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up MX records for domain %s", + var_dns_rr_list_limit, aname); mx_names = dns_rr_sort(mx_names, dns_rr_compare_pref_any); addr_list = mx_addr_list(state, mx_names); state->mx = dns_rr_copy(mx_names); @@ -1369,6 +1377,10 @@ static DNS_RR *domain_addr(STATE *state, char *domain) msg_warn("no MX host for %s has a valid address record", domain); break; } + if (addr_list->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up MX host addresses for domain %s", + var_dns_rr_list_limit, aname); #define COMPARE_ADDR(flags) \ ((flags & MISC_FLAG_PREF_IPV6) ? dns_rr_compare_pref_ipv6 : \ (flags & MISC_FLAG_PREF_IPV4) ? dns_rr_compare_pref_ipv4 : \ @@ -1433,6 +1445,10 @@ static DNS_RR *service_addr(STATE *state, const char *domain, dsb_status(state->why, "5.4.3"); break; case DNS_OK: + if (srv_names && srv_names->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up SRV records for domain %s", + var_dns_rr_list_limit, aname); /* Shuffle then sort the SRV rr records by priority and weight. */ srv_names = dns_srv_rr_sort(srv_names); addr_list = mx_addr_list(state, srv_names); @@ -1443,6 +1459,10 @@ static DNS_RR *service_addr(STATE *state, const char *domain, str_srv_qname); break; } + if (addr_list->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up SRV host addresses for domain %s", + var_dns_rr_list_limit, aname); /* TODO: sort by priority, weight, and address family preference. */ break; case DNS_NOTFOUND: @@ -1482,6 +1502,11 @@ static DNS_RR *host_addr(STATE *state, const char *host) #define PREF0 0 #define NOPORT 0 addr_list = addr_one(state, (DNS_RR *) 0, ahost, res_opt, PREF0, NOPORT); + if (addr_list && addr_list->len == DNS_RR_DISCARDED) { + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up addresses for host %s", + var_dns_rr_list_limit, ahost); + } if (addr_list && addr_list->next) { addr_list = dns_rr_shuffle(addr_list); if (inet_proto_info()->ai_family_list[1] != 0) diff --git a/postfix/src/smtp/smtp_addr.c b/postfix/src/smtp/smtp_addr.c index 5e23388d6..6eb2bd61b 100644 --- a/postfix/src/smtp/smtp_addr.c +++ b/postfix/src/smtp/smtp_addr.c @@ -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_discard(addr_list, addr); + if (msg_verbose && addr_list->len != DNS_RR_DISCARDED) msg_info("%s: using numerical host %s", myname, host); freeaddrinfo(res0); return (addr_list); @@ -206,7 +206,7 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt, rr->pref = pref; rr->port = port; } - addr_list = dns_rr_append(addr_list, addr); + addr_list = dns_rr_append_discard(addr_list, addr); return (addr_list); default: dsb_status(why, "4.4.3"); @@ -261,7 +261,9 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt, if ((addr = dns_sa_to_rr(host, pref, res->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_list = dns_rr_append_discard(addr_list, addr); + if (addr_list->len == DNS_RR_DISCARDED) + 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 && addr_list->len == DNS_RR_DISCARDED) + break; } return (addr_list); } @@ -496,6 +500,14 @@ static DNS_RR *smtp_balance_inet_proto(DNS_RR *addr_list, int misc_flags, msg_panic("%s: unexpected record type: %s", myname, dns_strtype(rr->type)); } + + /* + * addr_list is the concatenation of multi-element lists, and may + * be longer than var_dns_rr_limit. When both the addr_list + * length and addr_limit are > var_dns_rr_limit, calling + * dns_rr_append_discard() below could discard inputs and violate + * an invariant of the balancing algorithm. Let's keep it simple. + */ if (*p > 0) { stripped_list = dns_rr_append(stripped_list, rr); *p -= 1; @@ -618,6 +630,10 @@ DNS_RR *smtp_domain_addr(const char *name, DNS_RR **mxrr, int misc_flags, addr_list = smtp_host_addr(aname, misc_flags, why); break; case DNS_OK: + if (mx_names && mx_names->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up MX records for domain %s", + var_dns_rr_list_limit, aname); mx_names = dns_rr_sort(mx_names, dns_rr_compare_pref_any); best_pref = (mx_names ? mx_names->pref : IMPOSSIBLE_PREFERENCE); addr_list = smtp_addr_list(mx_names, why); @@ -637,6 +653,10 @@ DNS_RR *smtp_domain_addr(const char *name, DNS_RR **mxrr, int misc_flags, msg_warn("no MX host for %s has a valid address record", name); break; } + if (addr_list->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up MX host addresses for domain %s", + var_dns_rr_list_limit, aname); best_found = (addr_list ? addr_list->pref : IMPOSSIBLE_PREFERENCE); if (msg_verbose) smtp_print_addr(name, addr_list); @@ -709,6 +729,10 @@ DNS_RR *smtp_host_addr(const char *host, int misc_flags, DSN_BUF *why) */ #define PREF0 0 addr_list = smtp_addr_one((DNS_RR *) 0, ahost, res_opt, PREF0, 0, why); + if (addr_list && addr_list->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up host addresses for %s", + var_dns_rr_list_limit, ahost); if (addr_list && (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) && smtp_find_self(addr_list) != 0) { @@ -797,6 +821,10 @@ DNS_RR *smtp_service_addr(const char *name, const char *service, DNS_RR **mxrr, dsb_status(why, "5.1.0"); break; case DNS_OK: + if (srv_names && srv_names->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up SRV records for domain %s", + var_dns_rr_list_limit, aname); /* Shuffle then sort the SRV rr records by priority and weight. */ srv_names = dns_srv_rr_sort(srv_names); best_pref = (srv_names ? srv_names->pref : IMPOSSIBLE_PREFERENCE); @@ -809,6 +837,10 @@ DNS_RR *smtp_service_addr(const char *name, const char *service, DNS_RR **mxrr, str_srv_qname); break; } + if (addr_list->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up SRV host addresses for domain %s", + var_dns_rr_list_limit, aname); /* Optional loop prevention, similar to smtp_domain_addr(). */ best_found = (addr_list ? addr_list->pref : IMPOSSIBLE_PREFERENCE); if (msg_verbose) diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index d541e40a2..fce3857de 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -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. @@ -3133,6 +3134,11 @@ static int check_server_access(SMTPD_STATE *state, const char *table, return (SMTPD_CHECK_DUNNO); } } + if (server_list && server_list->len == DNS_RR_DISCARDED) + msg_warn("DNS resource record limit (%d) exceeded" + "while looking up %s records for %s", + var_dns_rr_list_limit, dns_strtype(type), + domain && domain[1] ? domain : name); /* * No bare returns after this point or we have a memory leak. @@ -3172,6 +3178,14 @@ 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("Host address count limit (%d) exceeded" + "while looking up host addresses for %s", + var_dns_rr_list_limit, (char *) server->data); + 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",