summaryrefslogtreecommitdiffstats
path: root/src/dns/dns_rr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns/dns_rr.c')
-rw-r--r--src/dns/dns_rr.c79
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);
}