summaryrefslogtreecommitdiff
path: root/lib/dns/adb.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/adb.c')
-rw-r--r--lib/dns/adb.c217
1 files changed, 216 insertions, 1 deletions
diff --git a/lib/dns/adb.c b/lib/dns/adb.c
index ebc43604..b6109ec7 100644
--- a/lib/dns/adb.c
+++ b/lib/dns/adb.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: adb.c,v 1.258 2011-03-13 02:49:28 marka Exp $ */
+/* $Id: adb.c,v 1.262 2011-10-28 04:57:34 marka Exp $ */
/*! \file
*
@@ -34,6 +34,7 @@
#include <isc/netaddr.h>
#include <isc/random.h>
#include <isc/stats.h>
+#include <isc/stdio.h> /* temporary */
#include <isc/string.h> /* Required for HP/UX (and others?) */
#include <isc/task.h>
#include <isc/util.h>
@@ -65,6 +66,24 @@
#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6')
#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
+/***
+ *** Constants for EDNS0 packets
+ *** DNS_ADB_EDNS0_MAX_LEN - max udpsize for edns0, should come from
+ *** named.conf
+ *** DNS_ADB_EDNS0_MIN_LEN - min udpsize for edns0
+ *** DNS_ADB_EDNS_RESET_TIME - after this period of time, drop count
+ *** is set to 0 and EDNS may be tried at
+ *** bigger size - surface to user?
+ *** DNS_ADB_EDNS_MAX_DROP_COUNT - after this many times EDNS has been
+ *** reduced, edns->fetch_flag set
+ *** DNS_ADB_EDNS_MAX_DROP_TIME - after this time retry EDNS at larger size
+ ***/
+#define DNS_ADB_EDNS0_MAX_LEN 4096
+#define DNS_ADB_EDNS0_MIN_LEN 512
+#define DNS_ADB_EDNS_RESET_TIME 300 /*make this user configurable?*/
+#define DNS_ADB_EDNS_MAX_DROP_COUNT 5 /*make this user configurable?*/
+#define DNS_ADB_EDNS_MAX_DROP_TIME 3600 /*make this user configurable?*/
+
/*!
* For type 3 negative cache entries, we will remember that the address is
* broken for this long. XXXMLG This is also used for actual addresses, too.
@@ -252,8 +271,34 @@ struct dns_adbentry {
* name.
*/
+
+ unsigned int edns_big_size;
+ unsigned int edns_last_size;
+ unsigned int edns_fetch_flag;
+ unsigned int edns_drop_count;
+ isc_stdtime_t edns_drop_timestamp;
+ isc_stdtime_t edns_expires_timestamp;
+ isc_boolean_t edns_timer_set;
+ /*%<
+ * The above fields beginning with edns_* determine
+ * past success with edns for this server.
+ * edns_big_size - biggest successful size received (e.g., 512)
+ * edns_last_size - last packet size received
+ * edns_fetch_flag - current EDNS state for this server (one of
+ * DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_EDNS512 or
+ * 0 meaning use DNS_ADB_EDNS0_MAX_LEN)
+ * edns_drop_count - keeps count of the number of times EDNS udpsize
+ * was dropped - reset to 0 every
+ * DNS_ADB_EDNS_RESET_TIME
+ * edns_drop_timestamp - The time at which the first EDNS drop
+ * in packet size was recorded
+ *
+ * See also dns_adb_drop/setednssize()
+ */
+
ISC_LIST(dns_adblameinfo_t) lameinfo;
ISC_LINK(dns_adbentry_t) plink;
+
};
/*
@@ -1746,6 +1791,13 @@ new_adbentry(dns_adb_t *adb) {
isc_random_get(&r);
e->srtt = (r & 0x1f) + 1;
e->expires = 0;
+ e->edns_big_size = 0;
+ e->edns_last_size = 0;
+ e->edns_fetch_flag = 0;
+ e->edns_drop_timestamp = 0;
+ e->edns_drop_count = 0;
+ e->edns_expires_timestamp = 0;
+ e->edns_timer_set = isc_boolean_false;
ISC_LIST_INIT(e->lameinfo);
ISC_LINK_INIT(e, plink);
LOCK(&adb->entriescntlock);
@@ -3909,6 +3961,169 @@ dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
UNLOCK(&adb->entrylocks[bucket]);
}
+unsigned int
+dns_adb_getednsflag(dns_adb_t *adb, dns_adbaddrinfo_t *addr, isc_stdtime_t now)
+{
+ int bucket = 0;
+ int flag_to_use = 0; /* assume max by default */
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ /*
+ * The purpose of this function is to return
+ * edns_fetch_flag, which effectively sets the udpsize for EDNS
+ * or turns off EDNS (if NOEDNS0 has been recorded).
+ *
+ * Also, this function checks to see if the timer needs resetting.
+ * ---> this part should really be done via a callback?
+ */
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+
+ if((addr->entry->edns_timer_set) &&
+ (now >= addr->entry->edns_expires_timestamp)) {
+
+ /* Eventually, we may support more sizes */
+ if((addr->entry->edns_big_size <= 512) &&
+ (addr->entry->edns_big_size > 0))
+ flag_to_use = DNS_FETCHOPT_EDNS512;
+
+ addr->entry->edns_fetch_flag = flag_to_use;
+ addr->entry->edns_expires_timestamp = 0;
+ addr->entry->edns_timer_set = isc_boolean_false;
+
+ }
+
+ flag_to_use = addr->entry->edns_fetch_flag;
+
+ UNLOCK(&adb->entrylocks[bucket]);
+
+ return(flag_to_use);
+}
+
+void
+dns_adb_setednssize(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
+ unsigned int length)
+{
+ int bucket = 0;
+ unsigned int length_to_use;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+
+ /*
+ * The purpose of this function is to record
+ * the maximum sized udp response seen from the
+ * instant server.
+ */
+
+ length_to_use = addr->entry->edns_big_size;
+
+ if (length > DNS_ADB_EDNS0_MAX_LEN)
+ length = DNS_ADB_EDNS0_MAX_LEN;
+ if (length < DNS_ADB_EDNS0_MIN_LEN)
+ length = DNS_ADB_EDNS0_MIN_LEN;
+ if (length > length_to_use)
+ length_to_use = length;
+
+ addr->entry->edns_big_size = length_to_use;
+
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
+void
+dns_adb_dropednssize(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
+ unsigned int length, isc_stdtime_t now)
+{
+ isc_stdtime_t expires_ts_to_use;
+ isc_boolean_t timer_setting_to_use;
+ unsigned int length_to_use;
+ unsigned int drop_counter_to_use;
+ unsigned int drop_ts_to_use;
+ unsigned int flag_to_use;
+ int bucket = 0;
+
+ REQUIRE(DNS_ADB_VALID(adb));
+ REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+
+ if (length > DNS_ADB_EDNS0_MAX_LEN)
+ length = DNS_ADB_EDNS0_MAX_LEN;
+ if (length < DNS_ADB_EDNS0_MIN_LEN)
+ length = DNS_ADB_EDNS0_MIN_LEN;
+
+ bucket = addr->entry->lock_bucket;
+ LOCK(&adb->entrylocks[bucket]);
+
+ expires_ts_to_use = addr->entry->edns_expires_timestamp;
+ timer_setting_to_use = addr->entry->edns_timer_set;
+ length_to_use = addr->entry->edns_big_size;
+ drop_ts_to_use = addr->entry->edns_drop_timestamp;
+ flag_to_use = addr->entry->edns_fetch_flag;
+
+ /*
+ * This function keeps a count of the number of times
+ * within DNS_ADB_EDNS_RESET_TIME that a particular server
+ * has dropped the udpsize in order to communicate with the
+ * server. If the number of times this occurs exceeds
+ * DNS_ADB_EDNS_MAX_DROP_COUNT, then the udpsize is reduced
+ * by way of edns_fetch_flag for DNS_ADB_EDNS_MAX_DROP_TIME,
+ * after which the largest size is retried again.
+ * NOTE: currently, only 4096 and 512 are supported sizes
+ */
+
+ if (length > length_to_use)
+ length_to_use = length;
+
+ if ((now - addr->entry->edns_drop_timestamp) >=
+ DNS_ADB_EDNS_RESET_TIME) {
+
+ drop_counter_to_use = 1;
+ drop_ts_to_use = now;
+ } else {
+
+ drop_counter_to_use = addr->entry->edns_drop_count + 1;
+
+ if (drop_counter_to_use >= DNS_ADB_EDNS_MAX_DROP_COUNT) {
+ /*
+ * At this point, we are dropping down the
+ * udpsize because we've had too many misses
+ * at larger sizes.
+ */
+ if (timer_setting_to_use == isc_boolean_false) {
+ /*
+ * if we haven't already set a timer,
+ * do so now. After DNS_ADB_EDNS_MAX_DROP_TIME,
+ * we'll go back to the largest size
+ */
+ expires_ts_to_use =
+ now + DNS_ADB_EDNS_MAX_DROP_TIME;
+ timer_setting_to_use = isc_boolean_true;
+ }
+
+ if (length == 0)
+ flag_to_use = DNS_FETCHOPT_NOEDNS0;
+ else /* eventually, more edns sizes here */
+ flag_to_use = DNS_FETCHOPT_EDNS512;
+
+ drop_ts_to_use = 0;
+ drop_counter_to_use = 0;
+ }
+ }
+
+ addr->entry->edns_drop_timestamp = drop_ts_to_use;
+ addr->entry->edns_drop_count = drop_counter_to_use;
+ addr->entry->edns_fetch_flag = flag_to_use;
+ addr->entry->edns_expires_timestamp = expires_ts_to_use;
+ addr->entry->edns_timer_set = timer_setting_to_use;
+
+ UNLOCK(&adb->entrylocks[bucket]);
+}
+
void
dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
unsigned int bits, unsigned int mask)