diff options
Diffstat (limited to 'src/dns/dns_rr.c')
-rw-r--r-- | src/dns/dns_rr.c | 79 |
1 files changed, 72 insertions, 7 deletions
diff --git a/src/dns/dns_rr.c b/src/dns/dns_rr.c index b550788..cf82f9f 100644 --- a/src/dns/dns_rr.c +++ b/src/dns/dns_rr.c @@ -49,6 +49,8 @@ /* DNS_RR *dns_rr_remove(list, record) /* DNS_RR *list; /* DNS_RR *record; +/* +/* int var_dns_rr_list_limit; /* DESCRIPTION /* The routines in this module maintain memory for DNS resource record /* information, and maintain lists of DNS resource records. @@ -65,9 +67,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. +/* 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 @@ -108,6 +118,16 @@ #include "dns.h" + /* + * 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 = 100; + /* dns_rr_create - fill in resource record structure */ DNS_RR *dns_rr_create(const char *qname, const char *rname, @@ -129,6 +149,7 @@ DNS_RR *dns_rr_create(const char *qname, const char *rname, memcpy(rr->data, data, data_len); rr->data_len = data_len; rr->next = 0; + rr->flags = 0; return (rr); } @@ -163,14 +184,58 @@ DNS_RR *dns_rr_copy(DNS_RR *src) return (dst); } -/* dns_rr_append - append resource record to list */ +/* dns_rr_append_with_limit - append resource record to limited list */ + +static void dns_rr_append_with_limit(DNS_RR *list, DNS_RR *rr, int limit) +{ + + /* + * 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 (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; + } + } +} + +/* dns_rr_append - append resource record(s) to list, or discard */ DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr) { - if (list == 0) { - list = rr; + + /* + * 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 { - list->next = dns_rr_append(list->next, rr); + dns_rr_free(rr); } return (list); } |