Here's an update to unbound 1.5.4. There was some file reorganisation so
I am providing two diffs: the one inline in this email shows the *code*
changes only for those who are interested to review it; this will not
build on its own.

For applying and testing, use http://junkpile.org/unbound-1.5.4.diff
instead (with "patch -Ep0") which has all the Makefile changes, #include
path changes etc as well.

Test reports, comments and OKs welcome.

Changelog entries since what we have in tree:

+------------------
| 29 June 2015: Wouter
|       - iana portlist update.
|       - Fix alloc with log for allocation size checks.
| 
| 26 June 2015: Wouter
|       - Fix #677 Fix DNAME responses from cache that failed internal chain
|         test.
|       - iana portlist update.
| 
| 22 June 2015: Wouter
|       - Fix #677 Fix CNAME corresponding to a DNAME was checked incorrectly
|         and was therefore always synthesized (thanks to Valentin Dietrich).
| 
| 4 June 2015: Wouter
|       - RFC 7553 RR type URI support, is now enabled by default.
| 
| 2 June 2015: Wouter
|       - Fix #674: Do not free pointers given by getenv.
| 
| 29 May 2015: Wouter
|       - Fix that unparseable error responses are ratelimited.
|       - SOA negative TTL is capped at minimumttl in its rdata section.
|       - cache-max-negative-ttl config option, default 3600.
| 
| 26 May 2015: Wouter
|       - Document that ratelimit works with unbound-control set_option.
| 
| 21 May 2015: Wouter
|       - iana portlist update.
|       - documentation proposes ratelimit of 1000 (closer to what upstream
|         servers expect from us).
| 
| 20 May 2015: Wouter
|       - DLV is going to be decommissioned.  Advice to stop using it, and
|         put text in the example configuration and man page to that effect.
| 
| 10 May 2015: Wouter
|       - Change syntax of particular validator error to be easier for
|         machine parse, swap rrset and ip adres info so it looks like:
|         validation failure <www.example.nl. TXT IN>: signature crypto
|         failed from 2001:DB8:7:bba4::53 for <*.example.nl. NSEC IN>
| 
| 1 May 2015: Wouter
|       - caps-whitelist in unbound.conf allows whitelist of loadbalancers
|         that cannot work with caps-for-id or its fallback.
| 
| 30 April 2015: Wouter
|       - Unit test for type ANY synthesis.
| 
| 22 April 2015: Wouter
|       - Removed contrib/unbound_unixsock.diff, because it has been
|         integrated, use control-interface: /path in unbound.conf.
|       - iana portlist update.
| 
| 17 April 2015: Wouter
|       - Synthesize ANY responses from cache.  Does not search exhaustively,
|         but MX,A,AAAA,SOA,NS also CNAME.
|       - Fix leaked dns64prefix configuration string.
| 
| 16 April 2015: Wouter
|       - Add local-zone type inform_deny, that logs query and drops answer.
|       - Ratelimit does not apply to prefetched queries, and ratelimit-factor
|         is default 10.  Repeated normal queries get resolved and with
|         prefetch stay in the cache.
|       - Fix bug#664: libunbound python3 related fixes (from Tomas Hozza)
|         Use print_function also for Python2.
|         libunbound examples: produce sorted output.
|         libunbound-Python: libldns is not used anymore.
|         Fix issue with Python 3 mapping of FILE* using file_py3.i from ldns.
| 
| 10 April 2015: Wouter
|       - unbound-control ratelimit_list lists high rate domains.
|       - ratelimit feature, ratelimit: 100, or some sensible qps, can be
|         used to turn it on.  It ratelimits recursion effort per zone.
|         For particular names you can configure exceptions in unbound.conf.
|       - Fix that get_option for cache-sizes does not print double newline.
|       - Fix#663: ssl handshake fails when using unix socket because dh size
|         is too small.
| 
| 8 April 2015: Wouter
|       - Fix crash in dnstap: Do not try to log TCP responses after timeout.
| 
| 7 April 2015: Wouter
|       - Libunbound skips dos-line-endings from etc/hosts.
|       - Unbound exits with a fatal error when the auto-trust-anchor-file
|         fails to be writable.  This is seconds after startup.  You can
|         load a readonly auto-trust-anchor-file with trust-anchor-file.
|         The file has to be writable to notice the trust anchor change,
|         without it, a trust anchor change will be unnoticed and the system
|         will then become inoperable.
|       - unbound-control list_insecure command shows the negative trust
|         anchors currently configured, patch from Jelte Jansen.
| 
| 2 April 2015: Wouter
|       - Fix #660: Fix interface-automatic broken in the presence of
|         asymmetric routing.
| 
| 26 March 2015: Wouter
|       - remote.c probedelay line is easier to read.
|       - rename ldns subdirectory to sldns to avoid name collision.
| 
| 25 March 2015: Wouter
|       - Fix #657:  libunbound(3) recommends deprecated
|         CRYPTO_set_id_callback.
|       - If unknown trust anchor algorithm, and libressl is used, error
|         message encourages upgrade of the libressl package.
| 
| 23 March 2015: Wouter
|       - Fix segfault on user not found at startup (from Maciej Soltysiak).
| 
| 20 March 2015: Wouter
|       - Fixed to add integer overflow checks on allocation (defense in depth).
| 
| 19 March 2015: Wouter
|       - Add ip-transparent config option for bind to non-local addresses.
| 
| 17 March 2015: Wouter
|       - Use reallocarray for integer overflow protection, patch submitted
|         by Loganaden Velvindron.
| 
| 16 March 2015: Wouter
|       - Fixup compile on cygwin, more portable openssl thread id.
| 
| 12 March 2015: Wouter
|       - Updated default keylength in unbound-control-setup to 3k.
| 
| 10 March 2015: Wouter
|       - Fix lintian warning in unbound-checkconf man page (from Andreas
|         Schulze).
|       - print svnroot when building windows dist.
|       - iana portlist update.
|       - Fix warning on sign compare in getentropy_linux.
| 
| 9 March 2015: Wouter
|       - Fix #644: harden-algo-downgrade option, if turned off, fixes the
|         reported excessive validation failure when multiple algorithms
|         are present.  It allows the weakest algorithm to validate the zone.
|       - iana portlist update.
| 
| 5 March 2015: Wouter
|       - contrib/unbound_smf22.tar.gz: Solaris SMF installation/removal
|         scripts.  Contributed by Yuri Voinov.
|       - Document that incoming-num-tcp increase is good for large servers.
|       - stats reports tcp usage, of incoming-num-tcp buffers.
| 
| 4 March 2015: Wouter
|       - Patch from Brad Smith that syncs compat/getentropy_linux with
|         OpenBSD's version (2015-03-04).
|       - 0x20 fallback improved: servfail responses do not count as missing
|         comparisons (except if all responses are errors),
|         inability to find nameservers does not fail equality comparisons,
|         many nameservers does not try to compare more than max-sent-count,
|         parse failures start 0x20 fallback procedure.
|       - store caps_response with best response in case downgrade response
|         happens to be the last one.
|       - Document windows 8 tests.
| 
| 3 March 2015: Wouter
|       - tag 1.5.3rc1
|       [ This became 1.5.3 on 10 March, trunk is 1.5.4 in development ]
| 
| 2 March 2015: Wouter
|       - iana portlist update.
| 
| 20 February 2015: Wouter
|       - Use the getrandom syscall introduced in Linux 3.17 (from Heiner
|         Kallweit).
|       - Fix #645 Portability to Solaris 10, use AF_LOCAL.
|       - Fix #646 Portability to Solaris, -lrt for getentropy_solaris.
|       - Fix #647 crash in 1.5.2 because pwd.db no longer accessible after
|         reload.
| 
| 19 February 2015: Wouter
|       - 1.5.2 release tag.
|       - svn trunk contains 1.5.3 under development.
+------------------

diff -uNp -r ./daemon/cachedump.c ../unbound/daemon/cachedump.c
--- ./daemon/cachedump.c        Thu Nov 20 01:15:19 2014
+++ ../unbound/daemon/cachedump.c       Thu Mar 26 10:21:38 2015
@@ -223,6 +223,8 @@ copy_msg(struct regional* region, struct lruhash_entry
        struct query_info** k, struct reply_info** d)
 {
        struct reply_info* rep = (struct reply_info*)e->data;
+       if(rep->rrset_count > RR_COUNT_MAX)
+               return 0; /* to protect against integer overflow */
        *d = (struct reply_info*)regional_alloc_init(region, e->data,
                sizeof(struct reply_info) + 
                sizeof(struct rrset_ref) * (rep->rrset_count-1) +
@@ -470,6 +472,10 @@ load_rrset(SSL* ssl, sldns_buffer* buf, struct worker*
                log_warn("bad rrset without contents");
                return 0;
        }
+       if(rr_count > RR_COUNT_MAX || rrsig_count > RR_COUNT_MAX) {
+               log_warn("bad rrset with too many rrs");
+               return 0;
+       }
        d->count = (size_t)rr_count;
        d->rrsig_count = (size_t)rrsig_count;
        d->security = (enum sec_status)security;
@@ -646,6 +652,10 @@ load_msg(SSL* ssl, sldns_buffer* buf, struct worker* w
        rep.ttl = (time_t)ttl;
        rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl);
        rep.security = (enum sec_status)security;
+       if(an > RR_COUNT_MAX || ns > RR_COUNT_MAX || ar > RR_COUNT_MAX) {
+               log_warn("error too many rrsets");
+               return 0; /* protect against integer overflow in alloc */
+       }
        rep.an_numrrsets = (size_t)an;
        rep.ns_numrrsets = (size_t)ns;
        rep.ar_numrrsets = (size_t)ar;
diff -uNp -r ./daemon/remote.c ../unbound/daemon/remote.c
--- ./daemon/remote.c   Sun Mar  8 15:29:15 2015
+++ ../unbound/daemon/remote.c  Fri Apr 10 14:56:12 2015
@@ -140,34 +140,45 @@ timeval_divide(struct timeval* avg, const struct timev
 
 /*
  * The following function was generated using the openssl utility, using
- * the command : "openssl dhparam -dsaparam -C 512"
+ * the command : "openssl dhparam -dsaparam -C 1024"
+ * (some openssl versions reject DH that is 'too small', eg. 512).
  */
 #ifndef S_SPLINT_S
-DH *get_dh512()
+DH *get_dh1024()
 {
-       static unsigned char dh512_p[]={
-               0xC9,0xD7,0x05,0xDA,0x5F,0xAB,0x14,0xE8,0x11,0x56,0x77,0x85,
-               0xB1,0x24,0x2C,0x95,0x60,0xEA,0xE2,0x10,0x6F,0x0F,0x84,0xEC,
-               0xF4,0x45,0xE8,0x90,0x7A,0xA7,0x03,0xFF,0x5B,0x88,0x53,0xDE,
-               0xC4,0xDE,0xBC,0x42,0x78,0x71,0x23,0x7E,0x24,0xA5,0x5E,0x4E,
-               0xEF,0x6F,0xFF,0x5F,0xAF,0xBE,0x8A,0x77,0x62,0xB4,0x65,0x82,
-               0x7E,0xC9,0xED,0x2F,
-       };
-       static unsigned char dh512_g[]={
-               0x8D,0x3A,0x52,0xBC,0x8A,0x71,0x94,0x33,0x2F,0xE1,0xE8,0x4C,
-               0x73,0x47,0x03,0x4E,0x7D,0x40,0xE5,0x84,0xA0,0xB5,0x6D,0x10,
-               0x6F,0x90,0x43,0x05,0x1A,0xF9,0x0B,0x6A,0xD1,0x2A,0x9C,0x25,
-               0x0A,0xB9,0xD1,0x14,0xDC,0x35,0x1C,0x48,0x7C,0xC6,0x0C,0x6D,
-               0x32,0x1D,0xD3,0xC8,0x10,0xA8,0x82,0x14,0xA2,0x1C,0xF4,0x53,
-               0x23,0x3B,0x1C,0xB9,
-       };
+       static unsigned char dh1024_p[]={
+               0xB3,0x67,0x2E,0x3B,0x68,0xC5,0xDA,0x58,0x46,0xD6,0x2B,0xD3,
+               0x41,0x78,0x97,0xE4,0xE1,0x61,0x71,0x68,0xE6,0x0F,0x1D,0x78,
+               0x05,0xAA,0xF0,0xFF,0x30,0xDF,0xAC,0x49,0x7F,0xE0,0x90,0xFE,
+               0xB9,0x56,0x4E,0x3F,0xE2,0x98,0x8A,0xED,0xF5,0x28,0x39,0xEF,
+               0x2E,0xA6,0xB7,0x67,0xB2,0x43,0xE4,0x53,0xF8,0xEB,0x2C,0x1F,
+               0x06,0x77,0x3A,0x6F,0x62,0x98,0xC1,0x3B,0xF7,0xBA,0x4D,0x93,
+               0xF7,0xEB,0x5A,0xAD,0xC5,0x5F,0xF0,0xB7,0x24,0x35,0x81,0xF7,
+               0x7F,0x1F,0x24,0xC0,0xDF,0xD3,0xD8,0x40,0x72,0x7E,0xF3,0x19,
+               0x2B,0x26,0x27,0xF4,0xB6,0xB3,0xD4,0x7D,0x08,0x23,0xBE,0x68,
+               0x2B,0xCA,0xB4,0x46,0xA8,0x9E,0xDD,0x6C,0x3D,0x75,0xA6,0x48,
+               0xF7,0x44,0x43,0xBF,0x91,0xC2,0xB4,0x49,
+               };
+       static unsigned char dh1024_g[]={
+               0x5F,0x37,0xB5,0x80,0x4D,0xB4,0xC4,0xB2,0x37,0x12,0xD5,0x2F,
+               0x56,0x81,0xB0,0xDF,0x3D,0x27,0xA2,0x54,0xE7,0x14,0x65,0x2D,
+               0x72,0xA8,0x97,0xE0,0xA9,0x4A,0x09,0x5E,0x89,0xBE,0x34,0x9A,
+               0x90,0x98,0xC1,0xE8,0xBB,0x01,0x2B,0xC2,0x74,0x74,0x90,0x59,
+               0x0B,0x72,0x62,0x5C,0xFD,0x49,0x63,0x4B,0x38,0x91,0xF1,0x7F,
+               0x13,0x25,0xEB,0x52,0x50,0x47,0xA2,0x8C,0x32,0x28,0x42,0xAC,
+               0xBD,0x7A,0xCC,0x58,0xBE,0x36,0xDA,0x6A,0x24,0x06,0xC7,0xF1,
+               0xDA,0x8D,0x8A,0x3B,0x03,0xFA,0x6F,0x25,0xE5,0x20,0xA7,0xD6,
+               0x6F,0x74,0x61,0x53,0x14,0x81,0x29,0x04,0xB5,0x61,0x12,0x53,
+               0xA3,0xD6,0x09,0x98,0x0C,0x8F,0x1C,0xBB,0xD7,0x1C,0x2C,0xEE,
+               0x56,0x4B,0x74,0x8F,0x4A,0xF8,0xA9,0xD5,
+               };
        DH *dh;
 
        if ((dh=DH_new()) == NULL) return(NULL);
-       dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
-       dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+       dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
+       dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
        if ((dh->p == NULL) || (dh->g == NULL))
-       { DH_free(dh); return(NULL); }
+               { DH_free(dh); return(NULL); }
        dh->length = 160;
        return(dh);
 }
@@ -218,7 +229,7 @@ daemon_remote_create(struct config_file* cfg)
                /* Since we have no certificates and hence no source of
                 * DH params, let's generate and set them
                 */
-               if(!SSL_CTX_set_tmp_dh(rc->ctx,get_dh512())) {
+               if(!SSL_CTX_set_tmp_dh(rc->ctx,get_dh1024())) {
                        log_crypto_err("Wanted to set DH param, but failed");
                        return NULL;
                }
@@ -328,7 +339,8 @@ add_open(const char* ip, int nr, struct listen_port** 
                 */
                if(fd != -1) {
 #ifdef HAVE_CHOWN
-                       if (cfg->username && cfg->username[0])
+                       if (cfg->username && cfg->username[0] &&
+                               cfg_uid != (uid_t)-1)
                                chown(ip, cfg_uid, cfg_gid);
                        chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | 
S_IWGRP));
 #else
@@ -357,7 +369,8 @@ add_open(const char* ip, int nr, struct listen_port** 
                }
 
                /* open fd */
-               fd = create_tcp_accept_sock(res, 1, &noproto, 0);
+               fd = create_tcp_accept_sock(res, 1, &noproto, 0,
+                       cfg->ip_transparent);
                freeaddrinfo(res);
        }
 
@@ -724,6 +737,8 @@ print_stats(SSL* ssl, const char* nm, struct stats_inf
                (long long)avg.tv_sec, (int)avg.tv_usec)) return 0;
        if(!ssl_printf(ssl, "%s.recursion.time.median"SQ"%g\n", nm, 
                s->mesh_time_median)) return 0;
+       if(!ssl_printf(ssl, "%s.tcpusage"SQ"%lu\n", nm,
+               (unsigned long)s->svr.tcp_accept_usage)) return 0;
        return 1;
 }
 
@@ -1888,6 +1903,21 @@ do_insecure_remove(SSL* ssl, struct worker* worker, ch
        send_ok(ssl);
 }
 
+static void
+do_insecure_list(SSL* ssl, struct worker* worker)
+{
+       char buf[257];
+       struct trust_anchor* a;
+       if(worker->env.anchors) {
+               RBTREE_FOR(a, struct trust_anchor*, worker->env.anchors->tree) {
+                       if(a->numDS == 0 && a->numDNSKEY == 0) {
+                               dname_str(a->name, buf);
+                               ssl_printf(ssl, "%s\n", buf);
+                       }
+               }
+       }
+}
+
 /** do the status command */
 static void
 do_status(SSL* ssl, struct worker* worker)
@@ -2073,7 +2103,7 @@ dump_infra_host(struct lruhash_entry* e, void* arg)
                d->rtt.srtt, d->rtt.rttvar, rtt_notimeout(&d->rtt), d->rtt.rto,
                d->timeout_A, d->timeout_AAAA, d->timeout_other,
                (int)d->edns_lame_known, (int)d->edns_version,
-               (int)(a->now<d->probedelay?d->probedelay-a->now:0),
+               (int)(a->now<d->probedelay?(d->probedelay - a->now):0),
                (int)d->isdnsseclame, (int)d->rec_lame, (int)d->lame_type_A,
                (int)d->lame_other)) {
                a->ssl_failed = 1;
@@ -2248,6 +2278,54 @@ do_list_local_data(SSL* ssl, struct worker* worker)
        lock_rw_unlock(&zones->lock);
 }
 
+/** struct for user arg ratelimit list */
+struct ratelimit_list_arg {
+       /** the infra cache */
+       struct infra_cache* infra;
+       /** the SSL to print to */
+       SSL* ssl;
+       /** all or only ratelimited */
+       int all;
+       /** current time */
+       time_t now;
+};
+
+/** list items in the ratelimit table */
+static void
+rate_list(struct lruhash_entry* e, void* arg)
+{
+       struct ratelimit_list_arg* a = (struct ratelimit_list_arg*)arg;
+       struct rate_key* k = (struct rate_key*)e->key;
+       struct rate_data* d = (struct rate_data*)e->data;
+       char buf[257];
+       int lim = infra_find_ratelimit(a->infra, k->name, k->namelen);
+       int max = infra_rate_max(d, a->now);
+       if(a->all == 0) {
+               if(max < lim)
+                       return;
+       }
+       dname_str(k->name, buf);
+       ssl_printf(a->ssl, "%s %d limit %d\n", buf, max, lim);
+}
+
+/** do the ratelimit_list command */
+static void
+do_ratelimit_list(SSL* ssl, struct worker* worker, char* arg)
+{
+       struct ratelimit_list_arg a;
+       a.all = 0;
+       a.infra = worker->env.infra_cache;
+       a.now = *worker->env.now;
+       a.ssl = ssl;
+       arg = skipwhite(arg);
+       if(strcmp(arg, "+a") == 0)
+               a.all = 1;
+       if(a.infra->domain_rates==NULL ||
+               (a.all == 0 && infra_dp_ratelimit == 0))
+               return;
+       slabhash_traverse(a.infra->domain_rates, 0, rate_list, &a);
+}
+
 /** tell other processes to execute the command */
 static void
 distribute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd)
@@ -2308,11 +2386,17 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* 
        } else if(cmdcmp(p, "list_stubs", 10)) {
                do_list_stubs(ssl, worker);
                return;
+       } else if(cmdcmp(p, "list_insecure", 13)) {
+               do_insecure_list(ssl, worker);
+               return;
        } else if(cmdcmp(p, "list_local_zones", 16)) {
                do_list_local_zones(ssl, worker);
                return;
        } else if(cmdcmp(p, "list_local_data", 15)) {
                do_list_local_data(ssl, worker);
+               return;
+       } else if(cmdcmp(p, "ratelimit_list", 14)) {
+               do_ratelimit_list(ssl, worker, p+14);
                return;
        } else if(cmdcmp(p, "stub_add", 8)) {
                /* must always distribute this cmd */
diff -uNp -r ./daemon/stats.c ../unbound/daemon/stats.c
--- ./daemon/stats.c    Thu Nov 20 00:00:37 2014
+++ ../unbound/daemon/stats.c   Thu Mar 26 10:21:38 2015
@@ -50,12 +50,13 @@
 #include "daemon/daemon.h"
 #include "services/mesh.h"
 #include "services/outside_network.h"
+#include "services/listen_dnsport.h"
 #include "util/config_file.h"
 #include "util/tube.h"
 #include "util/timehist.h"
 #include "util/net_help.h"
 #include "validator/validator.h"
-#include "ldns/sbuffer.h"
+#include "sldns/sbuffer.h"
 #include "services/cache/rrset.h"
 #include "services/cache/infra.h"
 #include "validator/val_kcache.h"
@@ -140,6 +141,7 @@ void
 server_stats_compile(struct worker* worker, struct stats_info* s, int reset)
 {
        int i;
+       struct listen_list* lp;
 
        s->svr = worker->stats;
        s->mesh_num_states = worker->env.mesh->all.count;
@@ -174,6 +176,13 @@ server_stats_compile(struct worker* worker, struct sta
                s->svr.key_cache_count = 
count_slabhash_entries(worker->env.key_cache->slab);
        else    s->svr.key_cache_count = 0;
 
+       /* get tcp accept usage */
+       s->svr.tcp_accept_usage = 0;
+       for(lp = worker->front->cps; lp; lp = lp->next) {
+               if(lp->com->type == comm_tcp_accept)
+                       s->svr.tcp_accept_usage += lp->com->cur_tcp_count;
+       }
+
        if(reset && !worker->env.cfg->stat_cumulative) {
                worker_stats_clear(worker);
        }
@@ -247,6 +256,7 @@ void server_stats_add(struct stats_info* total, struct
                total->svr.rrset_bogus += a->svr.rrset_bogus;
                total->svr.unwanted_replies += a->svr.unwanted_replies;
                total->svr.unwanted_queries += a->svr.unwanted_queries;
+               total->svr.tcp_accept_usage += a->svr.tcp_accept_usage;
                for(i=0; i<STATS_QTYPE_NUM; i++)
                        total->svr.qtype[i] += a->svr.qtype[i];
                for(i=0; i<STATS_QCLASS_NUM; i++)
diff -uNp -r ./daemon/stats.h ../unbound/daemon/stats.h
--- ./daemon/stats.h    Thu Nov 20 00:00:37 2014
+++ ../unbound/daemon/stats.h   Thu Mar  5 15:23:14 2015
@@ -129,6 +129,8 @@ struct server_stats {
        size_t unwanted_replies;
        /** unwanted traffic received on client-facing ports */
        size_t unwanted_queries;
+       /** usage of tcp accept list */
+       size_t tcp_accept_usage;
 
        /** histogram data exported to array 
         * if the array is the same size, no data is lost, and
diff -uNp -r ./daemon/unbound.c ../unbound/daemon/unbound.c
--- ./daemon/unbound.c  Sun Mar  8 15:29:15 2015
+++ ../unbound/daemon/unbound.c Mon Mar 23 20:20:15 2015
@@ -503,7 +503,7 @@ perform_setup(struct daemon* daemon, struct config_fil
 #ifdef HAVE_KILL
        if(cfg->pidfile && cfg->pidfile[0]) {
                writepid(daemon->pidfile, getpid());
-               if(cfg->username && cfg->username[0]) {
+               if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) {
 #  ifdef HAVE_CHOWN
                        if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) {
                                log_err("cannot chown %u.%u %s: %s",
@@ -519,7 +519,7 @@ perform_setup(struct daemon* daemon, struct config_fil
 
        /* Set user context */
 #ifdef HAVE_GETPWNAM
-       if(cfg->username && cfg->username[0]) {
+       if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) {
 #ifdef HAVE_SETUSERCONTEXT
                /* setusercontext does initgroups, setuid, setgid, and
                 * also resource limits from login config, but we
@@ -586,7 +586,7 @@ perform_setup(struct daemon* daemon, struct config_fil
 
        /* drop permissions after chroot, getpwnam, pidfile, syslog done*/
 #ifdef HAVE_GETPWNAM
-       if(cfg->username && cfg->username[0]) {
+       if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) {
 #  ifdef HAVE_INITGROUPS
                if(initgroups(cfg->username, cfg_gid) != 0)
                        log_warn("unable to initgroups %s: %s",
diff -uNp -r ./daemon/worker.c ../unbound/daemon/worker.c
--- ./daemon/worker.c   Tue Feb 17 10:03:59 2015
+++ ../unbound/daemon/worker.c  Fri Jun 26 08:27:32 2015
@@ -71,7 +71,7 @@
 #include "validator/val_anchor.h"
 #include "libunbound/context.h"
 #include "libunbound/libworker.h"
-#include "ldns/sbuffer.h"
+#include "sldns/sbuffer.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
@@ -86,6 +86,8 @@
 
 /** Size of an UDP datagram */
 #define NORMAL_UDP_SIZE        512 /* bytes */
+/** ratelimit for error responses */
+#define ERROR_RATELIMIT 100 /* qps */
 
 /** 
  * seconds to add to prefetch leeway.  This is a TTL that expires old rrsets
@@ -291,6 +293,26 @@ worker_handle_service_reply(struct comm_point* c, void
        return 0;
 }
 
+/** ratelimit error replies
+ * @param worker: the worker struct with ratelimit counter
+ * @param err: error code that would be wanted.
+ * @return value of err if okay, or -1 if it should be discarded instead.
+ */
+static int
+worker_err_ratelimit(struct worker* worker, int err)
+{
+       if(worker->err_limit_time == *worker->env.now) {
+               /* see if limit is exceeded for this second */
+               if(worker->err_limit_count++ > ERROR_RATELIMIT)
+                       return -1;
+       } else {
+               /* new second, new limits */
+               worker->err_limit_time = *worker->env.now;
+               worker->err_limit_count = 1;
+       }
+       return err;
+}
+
 /** check request sanity.
  * @param pkt: the wire packet to examine for sanity.
  * @param worker: parameters for checking.
@@ -315,32 +337,32 @@ worker_check_request(sldns_buffer* pkt, struct worker*
        if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
                LDNS_TC_CLR(sldns_buffer_begin(pkt));
                verbose(VERB_QUERY, "request bad, has TC bit on");
-               return LDNS_RCODE_FORMERR;
+               return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
        }
        if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
                verbose(VERB_QUERY, "request unknown opcode %d", 
                        LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
-               return LDNS_RCODE_NOTIMPL;
+               return worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL);
        }
        if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
                verbose(VERB_QUERY, "request wrong nr qd=%d", 
                        LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
-               return LDNS_RCODE_FORMERR;
+               return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
        }
        if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) {
                verbose(VERB_QUERY, "request wrong nr an=%d", 
                        LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
-               return LDNS_RCODE_FORMERR;
+               return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
        }
        if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) {
                verbose(VERB_QUERY, "request wrong nr ns=%d", 
                        LDNS_NSCOUNT(sldns_buffer_begin(pkt)));
-               return LDNS_RCODE_FORMERR;
+               return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
        }
        if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
                verbose(VERB_QUERY, "request wrong nr ar=%d", 
                        LDNS_ARCOUNT(sldns_buffer_begin(pkt)));
-               return LDNS_RCODE_FORMERR;
+               return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
        }
        return 0;
 }
@@ -546,7 +568,7 @@ answer_from_cache(struct worker* worker, struct query_
        if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type == 
                htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type == 
                htons(LDNS_RR_TYPE_DNAME))) {
-               if(!reply_check_cname_chain(rep)) {
+               if(!reply_check_cname_chain(qinfo, rep)) {
                        /* cname chain invalid, redo iterator steps */
                        verbose(VERB_ALGO, "Cache reply: cname chain broken");
                bail_out:
@@ -813,6 +835,10 @@ worker_handle_request(struct comm_point* c, void* arg,
        if(!query_info_parse(&qinfo, c->buffer)) {
                verbose(VERB_ALGO, "worker parse request: formerror.");
                log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+               if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
+                       comm_point_drop_reply(repinfo);
+                       return 0;
+               }
                sldns_buffer_rewind(c->buffer);
                LDNS_QR_SET(sldns_buffer_begin(c->buffer));
                LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 
diff -uNp -r ./daemon/worker.h ../unbound/daemon/worker.h
--- ./daemon/worker.h   Thu Nov 20 00:11:14 2014
+++ ../unbound/daemon/worker.h  Fri May 29 10:27:42 2015
@@ -103,6 +103,10 @@ struct worker {
        struct comm_point* cmd_com;
        /** timer for statistics */
        struct comm_timer* stat_timer;
+       /** ratelimit for errors, time value */
+       time_t err_limit_time;
+       /** ratelimit for errors, packet count */
+       unsigned int err_limit_count;
 
        /** random() table for this worker. */
        struct ub_randstate* rndstate;
diff -uNp -r ./dns64/dns64.c ../unbound/dns64/dns64.c
--- ./dns64/dns64.c     Thu Nov 20 01:15:19 2014
+++ ../unbound/dns64/dns64.c    Fri Mar 20 15:36:25 2015
@@ -590,6 +590,10 @@ dns64_synth_aaaa_data(const struct ub_packed_rrset_key
         * for the RRs themselves. Each RR has a length, TTL, pointer to 
wireformat
         * data, 2 bytes of data length, and 16 bytes of IPv6 address.
         */
+       if(fd->count > RR_COUNT_MAX) {
+               *dd_out = NULL;
+               return; /* integer overflow protection in alloc */
+       }
        if (!(dd = *dd_out = regional_alloc(region,
                  sizeof(struct packed_rrset_data)
                  + fd->count * (sizeof(size_t) + sizeof(time_t) +
@@ -713,6 +717,8 @@ dns64_adjust_a(int id, struct module_qstate* super, st
                if(i<rep->an_numrrsets && fk->rk.type == htons(LDNS_RR_TYPE_A)) 
{
                        /* also sets dk->entry.hash */
                        dns64_synth_aaaa_data(fk, fd, dk, &dd, super->region, 
dns64_env);
+                       if(!dd)
+                               return;
                        /* Delete negative AAAA record from cache stored by
                         * the iterator module */
                        rrset_cache_remove(super->env->rrset_cache, 
dk->rk.dname, 
diff -uNp -r ./iterator/iter_scrub.c ../unbound/iterator/iter_scrub.c
--- ./iterator/iter_scrub.c     Wed Feb 11 00:09:33 2015
+++ ../unbound/iterator/iter_scrub.c    Mon Jun 22 10:23:43 2015
@@ -372,7 +372,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* m
                                /* check next cname */
                                uint8_t* t = NULL;
                                size_t tlen = 0;
-                               if(!parse_get_cname_target(rrset, &t, &tlen))
+                               if(!parse_get_cname_target(nx, &t, &tlen))
                                        return 0;
                                if(dname_pkt_compare(pkt, alias, t) == 0) {
                                        /* it's OK and better capitalized */
diff -uNp -r ./iterator/iter_utils.c ../unbound/iterator/iter_utils.c
--- ./iterator/iter_utils.c     Sat Jan 31 23:34:17 2015
+++ ../unbound/iterator/iter_utils.c    Fri May  1 14:35:02 2015
@@ -64,7 +64,8 @@
 #include "validator/val_kentry.h"
 #include "validator/val_utils.h"
 #include "validator/val_sigcrypt.h"
-#include "ldns/sbuffer.h"
+#include "sldns/sbuffer.h"
+#include "sldns/str2wire.h"
 
 /** time when nameserver glue is said to be 'recent' */
 #define SUSPICION_RECENT_EXPIRY 86400
@@ -105,6 +106,40 @@ read_fetch_policy(struct iter_env* ie, const char* str
        return 1;
 }
 
+/** apply config caps whitelist items to name tree */
+static int
+caps_white_apply_cfg(rbtree_t* ntree, struct config_file* cfg)
+{
+       struct config_strlist* p;
+       for(p=cfg->caps_whitelist; p; p=p->next) {
+               struct name_tree_node* n;
+               size_t len;
+               uint8_t* nm = sldns_str2wire_dname(p->str, &len);
+               if(!nm) {
+                       log_err("could not parse %s", p->str);
+                       return 0;
+               }
+               n = (struct name_tree_node*)calloc(1, sizeof(*n));
+               if(!n) {
+                       log_err("out of memory");
+                       free(nm);
+                       return 0;
+               }
+               n->node.key = n;
+               n->name = nm;
+               n->len = len;
+               n->labs = dname_count_labels(nm);
+               n->dclass = LDNS_RR_CLASS_IN;
+               if(!name_tree_insert(ntree, n, nm, len, n->labs, n->dclass)) {
+                       /* duplicate element ignored, idempotent */
+                       free(n->name);
+                       free(n);
+               }
+       }
+       name_tree_init_parents(ntree);
+       return 1;
+}
+
 int 
 iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
 {
@@ -128,6 +163,16 @@ iter_apply_cfg(struct iter_env* iter_env, struct confi
                log_err("Could not set private addresses");
                return 0;
        }
+       if(cfg->caps_whitelist) {
+               if(!iter_env->caps_white)
+                       iter_env->caps_white = rbtree_create(name_tree_compare);
+               if(!iter_env->caps_white || !caps_white_apply_cfg(
+                       iter_env->caps_white, cfg)) {
+                       log_err("Could not set capsforid whitelist");
+                       return 0;
+               }
+
+       }
        iter_env->supports_ipv6 = cfg->do_ip6;
        iter_env->supports_ipv4 = cfg->do_ip4;
        return 1;
@@ -748,6 +793,12 @@ caps_strip_reply(struct reply_info* rep)
                        break;
                }
        }
+}
+
+int caps_failed_rcode(struct reply_info* rep)
+{
+       return !(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR ||
+               FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN);
 }
 
 void 
diff -uNp -r ./iterator/iter_utils.h ../unbound/iterator/iter_utils.h
--- ./iterator/iter_utils.h     Sat Jan 31 23:34:17 2015
+++ ../unbound/iterator/iter_utils.h    Wed Mar  4 08:30:17 2015
@@ -232,6 +232,14 @@ int reply_equal(struct reply_info* p, struct reply_inf
 void caps_strip_reply(struct reply_info* rep);
 
 /**
+ * see if reply has a 'useful' rcode for capsforid comparison, so
+ * not SERVFAIL or REFUSED, and thus NOERROR or NXDOMAIN.
+ * @param rep: reply to check.
+ * @return true if the rcode is a bad type of message.
+ */
+int caps_failed_rcode(struct reply_info* rep);
+
+/**
  * Store parent-side rrset in seperate rrset cache entries for later 
  * last-resort * lookups in case the child-side versions of this information 
  * fails.
diff -uNp -r ./iterator/iterator.c ../unbound/iterator/iterator.c
--- ./iterator/iterator.c       Tue Feb 17 10:03:59 2015
+++ ../unbound/iterator/iterator.c      Fri May  1 13:36:16 2015
@@ -61,10 +61,11 @@
 #include "util/data/msgencode.h"
 #include "util/fptr_wlist.h"
 #include "util/config_file.h"
-#include "ldns/rrdef.h"
-#include "ldns/wire2str.h"
-#include "ldns/parseutil.h"
-#include "ldns/sbuffer.h"
+#include "util/random.h"
+#include "sldns/rrdef.h"
+#include "sldns/wire2str.h"
+#include "sldns/parseutil.h"
+#include "sldns/sbuffer.h"
 
 int 
 iter_init(struct module_env* env, int id)
@@ -83,6 +84,16 @@ iter_init(struct module_env* env, int id)
        return 1;
 }
 
+/** delete caps_whitelist element */
+static void
+caps_free(struct rbnode_t* n, void* ATTR_UNUSED(d))
+{
+       if(n) {
+               free(((struct name_tree_node*)n)->name);
+               free(n);
+       }
+}
+
 void 
 iter_deinit(struct module_env* env, int id)
 {
@@ -93,6 +104,10 @@ iter_deinit(struct module_env* env, int id)
        free(iter_env->target_fetch_policy);
        priv_delete(iter_env->priv);
        donotq_delete(iter_env->donotq);
+       if(iter_env->caps_white) {
+               traverse_postorder(iter_env->caps_white, caps_free, NULL);
+               free(iter_env->caps_white);
+       }
        free(iter_env);
        env->modinfo[id] = NULL;
 }
@@ -120,6 +135,7 @@ iter_new(struct module_qstate* qstate, int id)
        iq->query_restart_count = 0;
        iq->referral_count = 0;
        iq->sent_count = 0;
+       iq->ratelimit_ok = 0;
        iq->target_count = NULL;
        iq->wait_priming_stub = 0;
        iq->refetch_glue = 0;
@@ -308,6 +324,8 @@ iter_prepend(struct iter_qstate* iq, struct dns_msg* m
        if(num_an + num_ns == 0)
                return 1;
        verbose(VERB_ALGO, "prepending %d rrsets", (int)num_an + (int)num_ns);
+       if(num_an > RR_COUNT_MAX || num_ns > RR_COUNT_MAX ||
+               msg->rep->rrset_count > RR_COUNT_MAX) return 0; /* overflow */
        sets = regional_alloc(region, (num_an+num_ns+msg->rep->rrset_count) *
                sizeof(struct ub_packed_rrset_key*));
        if(!sets) 
@@ -455,6 +473,16 @@ handle_cname_response(struct module_qstate* qstate, st
        return 1;
 }
 
+/** see if target name is caps-for-id whitelisted */
+static int
+is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
+{
+       if(!ie->caps_white) return 0; /* no whitelist, or no capsforid */
+       return name_tree_lookup(ie->caps_white, iq->qchase.qname,
+               iq->qchase.qname_len, dname_count_labels(iq->qchase.qname),
+               iq->qchase.qclass) != NULL;
+}
+
 /** create target count structure for this query */
 static void
 target_count_create(struct iter_qstate* iq)
@@ -1123,6 +1151,32 @@ processInitRequest(struct module_qstate* qstate, struc
                         * results of priming. */
                        return 0;
                }
+               if(!iq->ratelimit_ok && qstate->prefetch_leeway)
+                       iq->ratelimit_ok = 1; /* allow prefetches, this keeps
+                       otherwise valid data in the cache */
+               if(!iq->ratelimit_ok && infra_ratelimit_exceeded(
+                       qstate->env->infra_cache, iq->dp->name,
+                       iq->dp->namelen, *qstate->env->now)) {
+                       /* and increment the rate, so that the rate for time
+                        * now will also exceed the rate, keeping cache fresh */
+                       (void)infra_ratelimit_inc(qstate->env->infra_cache,
+                               iq->dp->name, iq->dp->namelen,
+                               *qstate->env->now);
+                       /* see if we are passed through with slip factor */
+                       if(qstate->env->cfg->ratelimit_factor != 0 &&
+                               ub_random_max(qstate->env->rnd,
+                                   qstate->env->cfg->ratelimit_factor) == 1) {
+                               iq->ratelimit_ok = 1;
+                               log_nametypeclass(VERB_ALGO, "ratelimit allowed 
through for "
+                                       "delegation point", iq->dp->name,
+                                       LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
+                       } else {
+                               log_nametypeclass(VERB_ALGO, "ratelimit 
exceeded with "
+                                       "delegation point", iq->dp->name,
+                                       LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
+                               return error_response(qstate, id, 
LDNS_RCODE_SERVFAIL);
+                       }
+               }
 
                /* see if this dp not useless.
                 * It is useless if:
@@ -1787,11 +1841,13 @@ processQueryTargets(struct module_qstate* qstate, stru
                 * the original query is one that matched too, so we have
                 * caps_server+1 number of matching queries now */
                if(iq->caps_server+1 >= naddr*3 ||
-                       iq->caps_server+1 >= MAX_SENT_COUNT) {
+                       iq->caps_server*2+2 >= MAX_SENT_COUNT) {
+                       /* *2 on sentcount check because ipv6 may fail */
                        /* we're done, process the response */
                        verbose(VERB_ALGO, "0x20 fallback had %d responses "
                                "match for %d wanted, done.", 
                                (int)iq->caps_server+1, (int)naddr*3);
+                       iq->response = iq->caps_response;
                        iq->caps_fallback = 0;
                        iter_dec_attempts(iq->dp, 3); /* space for fallback */
                        iq->num_current_queries++; /* RespState decrements it*/
@@ -1866,6 +1922,24 @@ processQueryTargets(struct module_qstate* qstate, stru
                        /* Since a target query might have been made, we 
                         * need to check again. */
                        if(iq->num_target_queries == 0) {
+                               /* if in capsforid fallback, instead of last
+                                * resort, we agree with the current reply
+                                * we have (if any) (our count of addrs bad)*/
+                               if(iq->caps_fallback && iq->caps_reply) {
+                                       /* we're done, process the response */
+                                       verbose(VERB_ALGO, "0x20 fallback had 
%d responses, "
+                                               "but no more servers except "
+                                               "last resort, done.", 
+                                               (int)iq->caps_server+1);
+                                       iq->response = iq->caps_response;
+                                       iq->caps_fallback = 0;
+                                       iter_dec_attempts(iq->dp, 3); /* space 
for fallback */
+                                       iq->num_current_queries++; /* RespState 
decrements it*/
+                                       iq->referral_count++; /* make sure we 
don't loop */
+                                       iq->sent_count = 0;
+                                       iq->state = QUERY_RESP_STATE;
+                                       return 1;
+                               }
                                return processLastResort(qstate, iq, ie, id);
                        }
                }
@@ -1892,6 +1966,15 @@ processQueryTargets(struct module_qstate* qstate, stru
                return 0;
        }
 
+       /* if not forwarding, check ratelimits per delegationpoint name */
+       if(!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok) {
+               if(!infra_ratelimit_inc(qstate->env->infra_cache, iq->dp->name,
+                       iq->dp->namelen, *qstate->env->now)) {
+                       verbose(VERB_ALGO, "query exceeded ratelimits");
+                       return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+               }
+       }
+
        /* We have a valid target. */
        if(verbosity >= VERB_QUERY) {
                log_query_info(VERB_QUERY, "sending query:", &iq->qchase);
@@ -1906,11 +1989,15 @@ processQueryTargets(struct module_qstate* qstate, stru
                iq->qchase.qname, iq->qchase.qname_len, 
                iq->qchase.qtype, iq->qchase.qclass, 
                iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), EDNS_DO|BIT_CD, 
-               iq->dnssec_expected, iq->caps_fallback, &target->addr,
-               target->addrlen, iq->dp->name, iq->dp->namelen, qstate);
+               iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
+               ie, iq), &target->addr, target->addrlen, iq->dp->name,
+               iq->dp->namelen, qstate);
        if(!outq) {
                log_addr(VERB_DETAIL, "error sending query to auth server", 
                        &target->addr, target->addrlen);
+               if(!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok)
+                   infra_ratelimit_dec(qstate->env->infra_cache, iq->dp->name,
+                       iq->dp->namelen, *qstate->env->now);
                return next_state(iq, QUERYTARGETS_STATE);
        }
        outbound_list_insert(&iq->outlist, outq);
@@ -2061,6 +2148,14 @@ processQueryResponse(struct module_qstate* qstate, str
                 * delegation point, and back to the QUERYTARGETS_STATE. */
                verbose(VERB_DETAIL, "query response was REFERRAL");
 
+               if(!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok) {
+                       /* we have a referral, no ratelimit, we can send
+                        * our queries to the given name */
+                       infra_ratelimit_dec(qstate->env->infra_cache,
+                               iq->dp->name, iq->dp->namelen,
+                               *qstate->env->now);
+               }
+
                /* if hardened, only store referral if we asked for it */
                if(!qstate->env->cfg->harden_referral_path ||
                    (  qstate->qinfo.qtype == LDNS_RR_TYPE_NS 
@@ -2529,6 +2624,12 @@ processClassResponse(struct module_qstate* qstate, int
                        /* copy appropriate rcode */
                        to->rep->flags = from->rep->flags;
                        /* copy rrsets */
+                       if(from->rep->rrset_count > RR_COUNT_MAX ||
+                               to->rep->rrset_count > RR_COUNT_MAX) {
+                               log_err("malloc failed (too many rrsets) in 
collect ANY"); 
+                               foriq->state = FINISHED_STATE;
+                               return; /* integer overflow protection */
+                       }
                        dest = regional_alloc(forq->region, sizeof(dest[0])*n);
                        if(!dest) {
                                log_err("malloc failed in collect ANY"); 
@@ -2825,6 +2926,7 @@ process_response(struct module_qstate* qstate, struct 
                        iq->caps_fallback = 1;
                        iq->caps_server = 0;
                        iq->caps_reply = NULL;
+                       iq->caps_response = NULL;
                        iq->state = QUERYTARGETS_STATE;
                        iq->num_current_queries--;
                        /* need fresh attempts for the 0x20 fallback, if
@@ -2867,8 +2969,19 @@ process_response(struct module_qstate* qstate, struct 
 
        /* normalize and sanitize: easy to delete items from linked lists */
        if(!scrub_message(pkt, prs, &iq->qchase, iq->dp->name, 
-               qstate->env->scratch, qstate->env, ie))
+               qstate->env->scratch, qstate->env, ie)) {
+               /* if 0x20 enabled, start fallback, but we have no message */
+               if(event == module_event_capsfail && !iq->caps_fallback) {
+                       iq->caps_fallback = 1;
+                       iq->caps_server = 0;
+                       iq->caps_reply = NULL;
+                       iq->caps_response = NULL;
+                       iq->state = QUERYTARGETS_STATE;
+                       iq->num_current_queries--;
+                       verbose(VERB_DETAIL, "Capsforid: scrub failed, starting 
fallback with no response");
+               }
                goto handle_it;
+       }
 
        /* allocate response dns_msg in region */
        iq->response = dns_alloc_msg(pkt, prs, qstate->region);
@@ -2890,6 +3003,7 @@ process_response(struct module_qstate* qstate, struct 
                        iq->caps_fallback = 1;
                        iq->caps_server = 0;
                        iq->caps_reply = iq->response->rep;
+                       iq->caps_response = iq->response;
                        iq->state = QUERYTARGETS_STATE;
                        iq->num_current_queries--;
                        verbose(VERB_DETAIL, "Capsforid: starting fallback");
@@ -2898,8 +3012,24 @@ process_response(struct module_qstate* qstate, struct 
                        /* check if reply is the same, otherwise, fail */
                        if(!iq->caps_reply) {
                                iq->caps_reply = iq->response->rep;
+                               iq->caps_response = iq->response;
                                iq->caps_server = -1; /*become zero at ++,
                                so that we start the full set of trials */
+                       } else if(caps_failed_rcode(iq->caps_reply) &&
+                               !caps_failed_rcode(iq->response->rep)) {
+                               /* prefer to upgrade to non-SERVFAIL */
+                               iq->caps_reply = iq->response->rep;
+                               iq->caps_response = iq->response;
+                       } else if(!caps_failed_rcode(iq->caps_reply) &&
+                               caps_failed_rcode(iq->response->rep)) {
+                               /* if we have non-SERVFAIL as answer then 
+                                * we can ignore SERVFAILs for the equality
+                                * comparison */
+                               /* no instructions here, skip other else */
+                       } else if(caps_failed_rcode(iq->caps_reply) &&
+                               caps_failed_rcode(iq->response->rep)) {
+                               /* failure is same as other failure in fallbk*/
+                               /* no instructions here, skip other else */
                        } else if(!reply_equal(iq->response->rep, 
iq->caps_reply,
                                qstate->env->scratch)) {
                                verbose(VERB_DETAIL, "Capsforid fallback: "
diff -uNp -r ./iterator/iterator.h ../unbound/iterator/iterator.h
--- ./iterator/iterator.h       Mon Dec  8 21:12:33 2014
+++ ../unbound/iterator/iterator.h      Fri May  1 13:36:16 2015
@@ -51,6 +51,7 @@ struct iter_forwards;
 struct iter_donotq;
 struct iter_prep_list;
 struct iter_priv;
+struct rbtree_t;
 
 /** max number of targets spawned for a query and its subqueries */
 #define MAX_TARGET_COUNT       32
@@ -96,6 +97,9 @@ struct iter_env {
        /** private address space and private domains */
        struct iter_priv* priv;
 
+       /** whitelist for capsforid names */
+       struct rbtree_t* caps_white;
+
        /** The maximum dependency depth that this resolver will pursue. */
        int max_dependency_depth;
 
@@ -235,6 +239,7 @@ struct iter_qstate {
        /** state for capsfail: stored query for comparisons. Can be NULL if
         * no response had been seen prior to starting the fallback. */
        struct reply_info* caps_reply;
+       struct dns_msg* caps_response;
 
        /** Current delegation message - returned for non-RD queries */
        struct dns_msg* deleg_msg;
@@ -257,6 +262,9 @@ struct iter_qstate {
        /** number of target queries spawned in [1], for this query and its
         * subqueries, the malloced-array is shared, [0] refcount. */
        int* target_count;
+
+       /** if true, already tested for ratelimiting and passed the test */
+       int ratelimit_ok;
 
        /**
         * The query must store NS records from referrals as parentside RRs
diff -uNp -r ./libunbound/context.c ../unbound/libunbound/context.c
--- ./libunbound/context.c      Sun Mar 16 11:38:29 2014
+++ ../unbound/libunbound/context.c     Thu Mar 26 10:21:38 2015
@@ -360,7 +360,7 @@ context_serialize_cancel(struct ctx_query* q, uint32_t
        /* format of cancel:
         *      o uint32 cmd
         *      o uint32 async-id */
-       uint8_t* p = (uint8_t*)malloc(2*sizeof(uint32_t));
+       uint8_t* p = (uint8_t*)reallocarray(NULL, sizeof(uint32_t), 2);
        if(!p) return NULL;
        *len = 2*sizeof(uint32_t);
        sldns_write_uint32(p, UB_LIBCMD_CANCEL);
diff -uNp -r ./libunbound/libunbound.c ../unbound/libunbound/libunbound.c
--- ./libunbound/libunbound.c   Thu Nov 20 00:00:38 2014
+++ ../unbound/libunbound/libunbound.c  Tue Jun  2 08:31:43 2015
@@ -1028,7 +1028,6 @@ ub_ctx_hosts(struct ub_ctx* ctx, const char* fname)
                                        "\\hosts");
                                retval=ub_ctx_hosts(ctx, buf);
                        }
-                       free(name);
                        return retval;
                }
                return UB_READFILE;
@@ -1053,6 +1052,8 @@ ub_ctx_hosts(struct ub_ctx* ctx, const char* fname)
                /* skip addr */
                while(isxdigit((unsigned char)*parse) || *parse == '.' || 
*parse == ':')
                        parse++;
+               if(*parse == '\r')
+                       parse++;
                if(*parse == '\n' || *parse == 0)
                        continue;
                if(*parse == '%') 
@@ -1066,7 +1067,8 @@ ub_ctx_hosts(struct ub_ctx* ctx, const char* fname)
                *parse++ = 0; /* end delimiter for addr ... */
                /* go to names and add them */
                while(*parse) {
-                       while(*parse == ' ' || *parse == '\t' || *parse=='\n')
+                       while(*parse == ' ' || *parse == '\t' || *parse=='\n'
+                               || *parse=='\r')
                                parse++;
                        if(*parse == 0 || *parse == '#')
                                break;
diff -uNp -r ./services/cache/dns.c ../unbound/services/cache/dns.c
--- ./services/cache/dns.c      Thu Nov 20 01:15:19 2014
+++ ../unbound/services/cache/dns.c     Fri Jun 26 08:27:32 2015
@@ -366,6 +366,8 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16
                sizeof(struct reply_info)-sizeof(struct rrset_ref));
        if(!msg->rep)
                return NULL;
+       if(capacity > RR_COUNT_MAX)
+               return NULL; /* integer overflow protection */
        msg->rep->flags = BIT_QR; /* with QR, no AA */
        msg->rep->qdcount = 1;
        msg->rep->rrsets = (struct ub_packed_rrset_key**)
@@ -387,6 +389,18 @@ dns_msg_authadd(struct dns_msg* msg, struct regional* 
        return 1;
 }
 
+/** add rrset to answer section */
+static int
+dns_msg_ansadd(struct dns_msg* msg, struct regional* region, 
+       struct ub_packed_rrset_key* rrset, time_t now)
+{
+       if(!(msg->rep->rrsets[msg->rep->rrset_count++] = 
+               packed_rrset_copy_region(rrset, region, now)))
+               return 0;
+       msg->rep->an_numrrsets++;
+       return 1;
+}
+
 struct delegpt* 
 dns_cache_find_delegation(struct module_env* env, uint8_t* qname, 
        size_t qnamelen, uint16_t qtype, uint16_t qclass, 
@@ -453,6 +467,8 @@ gen_dns_msg(struct regional* region, struct query_info
                sizeof(struct reply_info) - sizeof(struct rrset_ref));
        if(!msg->rep)
                return NULL;
+       if(num > RR_COUNT_MAX)
+               return NULL; /* integer overflow protection */
        msg->rep->rrsets = (struct ub_packed_rrset_key**)
                regional_alloc(region,
                num * sizeof(struct ub_packed_rrset_key*));
@@ -489,7 +505,7 @@ tomsg(struct module_env* env, struct query_info* q, st
                return NULL;
        if(r->an_numrrsets > 0 && (r->rrsets[0]->rk.type == htons(
                LDNS_RR_TYPE_CNAME) || r->rrsets[0]->rk.type == htons(
-               LDNS_RR_TYPE_DNAME)) && !reply_check_cname_chain(r)) {
+               LDNS_RR_TYPE_DNAME)) && !reply_check_cname_chain(q, r)) {
                /* cname chain is now invalid, reconstruct msg */
                rrset_array_unlock(r->ref, r->rrset_count);
                return NULL;
@@ -631,6 +647,58 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, str
        return msg;
 }
 
+/** Fill TYPE_ANY response with some data from cache */
+static struct dns_msg*
+fill_any(struct module_env* env,
+       uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
+       struct regional* region)
+{
+       time_t now = *env->now;
+       struct dns_msg* msg = NULL;
+       uint16_t lookup[] = {LDNS_RR_TYPE_A, LDNS_RR_TYPE_AAAA,
+               LDNS_RR_TYPE_MX, LDNS_RR_TYPE_SOA, LDNS_RR_TYPE_NS, 0};
+       int i, num=5; /* number of RR types to look up */
+       log_assert(lookup[num] == 0);
+
+       for(i=0; i<num; i++) {
+               /* look up this RR for inclusion in type ANY response */
+               struct ub_packed_rrset_key* rrset = rrset_cache_lookup(
+                       env->rrset_cache, qname, qnamelen, lookup[i],
+                       qclass, 0, now, 0);
+               struct packed_rrset_data *d;
+               if(!rrset)
+                       continue;
+
+               /* only if rrset from answer section */
+               d = (struct packed_rrset_data*)rrset->entry.data;
+               if(d->trust == rrset_trust_add_noAA ||
+                       d->trust == rrset_trust_auth_noAA ||
+                       d->trust == rrset_trust_add_AA ||
+                       d->trust == rrset_trust_auth_AA) {
+                       lock_rw_unlock(&rrset->entry.lock);
+                       continue;
+               }
+
+               /* create msg if none */
+               if(!msg) {
+                       msg = dns_msg_create(qname, qnamelen, qtype, qclass,
+                               region, (size_t)(num-i));
+                       if(!msg) {
+                               lock_rw_unlock(&rrset->entry.lock);
+                               return NULL;
+                       }
+               }
+
+               /* add RRset to response */
+               if(!dns_msg_ansadd(msg, region, rrset, now)) {
+                       lock_rw_unlock(&rrset->entry.lock);
+                       return NULL;
+               }
+               lock_rw_unlock(&rrset->entry.lock);
+       }
+       return msg;
+}
+
 struct dns_msg* 
 dns_cache_lookup(struct module_env* env,
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
@@ -741,6 +809,11 @@ dns_cache_lookup(struct module_env* env,
                        }
                        lock_rw_unlock(&e->lock);
                }
+       }
+
+       /* fill common RR types for ANY response to avoid requery */
+       if(qtype == LDNS_RR_TYPE_ANY) {
+               return fill_any(env, qname, qnamelen, qtype, qclass, region);
        }
 
        return NULL;
diff -uNp -r ./services/cache/infra.c ../unbound/services/cache/infra.c
--- ./services/cache/infra.c    Sun Mar 16 11:38:26 2014
+++ ../unbound/services/cache/infra.c   Fri Apr 10 13:19:30 2015
@@ -39,7 +39,8 @@
  * This file contains the infrastructure cache.
  */
 #include "config.h"
-#include "ldns/rrdef.h"
+#include "sldns/rrdef.h"
+#include "sldns/str2wire.h"
 #include "services/cache/infra.h"
 #include "util/storage/slabhash.h"
 #include "util/storage/lookup3.h"
@@ -57,6 +58,9 @@
  * can do this number of packets (until those all timeout too) */
 #define TIMEOUT_COUNT_MAX 3
 
+/** ratelimit value for delegation point */
+int infra_dp_ratelimit = 0;
+
 size_t 
 infra_sizefunc(void* k, void* ATTR_UNUSED(d))
 {
@@ -99,6 +103,114 @@ infra_deldatafunc(void* d, void* ATTR_UNUSED(arg))
        free(data);
 }
 
+size_t 
+rate_sizefunc(void* k, void* ATTR_UNUSED(d))
+{
+       struct rate_key* key = (struct rate_key*)k;
+       return sizeof(*key) + sizeof(struct rate_data) + key->namelen
+               + lock_get_mem(&key->entry.lock);
+}
+
+int 
+rate_compfunc(void* key1, void* key2)
+{
+       struct rate_key* k1 = (struct rate_key*)key1;
+       struct rate_key* k2 = (struct rate_key*)key2;
+       if(k1->namelen != k2->namelen) {
+               if(k1->namelen < k2->namelen)
+                       return -1;
+               return 1;
+       }
+       return query_dname_compare(k1->name, k2->name);
+}
+
+void 
+rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
+{
+       struct rate_key* key = (struct rate_key*)k;
+       if(!key)
+               return;
+       lock_rw_destroy(&key->entry.lock);
+       free(key->name);
+       free(key);
+}
+
+void 
+rate_deldatafunc(void* d, void* ATTR_UNUSED(arg))
+{
+       struct rate_data* data = (struct rate_data*)d;
+       free(data);
+}
+
+/** find or create element in domainlimit tree */
+static struct domain_limit_data* domain_limit_findcreate(
+       struct infra_cache* infra, char* name)
+{
+       uint8_t* nm;
+       int labs;
+       size_t nmlen;
+       struct domain_limit_data* d;
+
+       /* parse name */
+       nm = sldns_str2wire_dname(name, &nmlen);
+       if(!nm) {
+               log_err("could not parse %s", name);
+               return NULL;
+       }
+       labs = dname_count_labels(nm);
+
+       /* can we find it? */
+       d = (struct domain_limit_data*)name_tree_find(&infra->domain_limits,
+               nm, nmlen, labs, LDNS_RR_CLASS_IN);
+       if(d) {
+               free(nm);
+               return d;
+       }
+       
+       /* create it */
+       d = (struct domain_limit_data*)calloc(1, sizeof(*d));
+       if(!d) {
+               free(nm);
+               return NULL;
+       }
+       d->node.node.key = &d->node;
+       d->node.name = nm;
+       d->node.len = nmlen;
+       d->node.labs = labs;
+       d->node.dclass = LDNS_RR_CLASS_IN;
+       d->lim = -1;
+       d->below = -1;
+       if(!name_tree_insert(&infra->domain_limits, &d->node, nm, nmlen,
+               labs, LDNS_RR_CLASS_IN)) {
+               log_err("duplicate element in domainlimit tree");
+               free(nm);
+               free(d);
+               return NULL;
+       }
+       return d;
+}
+
+/** insert rate limit configuration into lookup tree */
+static int infra_ratelimit_cfg_insert(struct infra_cache* infra,
+       struct config_file* cfg)
+{
+       struct config_str2list* p;
+       struct domain_limit_data* d;
+       for(p = cfg->ratelimit_for_domain; p; p = p->next) {
+               d = domain_limit_findcreate(infra, p->str);
+               if(!d)
+                       return 0;
+               d->lim = atoi(p->str2);
+       }
+       for(p = cfg->ratelimit_below_domain; p; p = p->next) {
+               d = domain_limit_findcreate(infra, p->str);
+               if(!d)
+                       return 0;
+               d->below = atoi(p->str2);
+       }
+       return 1;
+}
+
 struct infra_cache* 
 infra_create(struct config_file* cfg)
 {
@@ -114,15 +226,44 @@ infra_create(struct config_file* cfg)
                return NULL;
        }
        infra->host_ttl = cfg->host_ttl;
+       name_tree_init(&infra->domain_limits);
+       infra_dp_ratelimit = cfg->ratelimit;
+       if(cfg->ratelimit != 0) {
+               infra->domain_rates = slabhash_create(cfg->ratelimit_slabs,
+                       INFRA_HOST_STARTSIZE, cfg->ratelimit_size,
+                       &rate_sizefunc, &rate_compfunc, &rate_delkeyfunc,
+                       &rate_deldatafunc, NULL);
+               if(!infra->domain_rates) {
+                       infra_delete(infra);
+                       return NULL;
+               }
+               /* insert config data into ratelimits */
+               if(!infra_ratelimit_cfg_insert(infra, cfg)) {
+                       infra_delete(infra);
+                       return NULL;
+               }
+               name_tree_init_parents(&infra->domain_limits);
+       }
        return infra;
 }
 
+/** delete domain_limit entries */
+static void domain_limit_free(rbnode_t* n, void* ATTR_UNUSED(arg))
+{
+       if(n) {
+               free(((struct domain_limit_data*)n)->node.name);
+               free(n);
+       }
+}
+
 void 
 infra_delete(struct infra_cache* infra)
 {
        if(!infra)
                return;
        slabhash_delete(infra->hosts);
+       slabhash_delete(infra->domain_rates);
+       traverse_postorder(&infra->domain_limits, domain_limit_free, NULL);
        free(infra);
 }
 
@@ -562,8 +703,178 @@ infra_get_lame_rtt(struct infra_cache* infra,
        return 1;
 }
 
+int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
+       size_t namelen)
+{
+       int labs = dname_count_labels(name);
+       struct domain_limit_data* d = (struct domain_limit_data*)
+               name_tree_lookup(&infra->domain_limits, name, namelen, labs,
+               LDNS_RR_CLASS_IN);
+       if(!d) return infra_dp_ratelimit;
+
+       if(d->node.labs == labs && d->lim != -1)
+               return d->lim; /* exact match */
+
+       /* find 'below match' */
+       if(d->node.labs == labs)
+               d = (struct domain_limit_data*)d->node.parent;
+       while(d) {
+               if(d->below != -1)
+                       return d->below;
+               d = (struct domain_limit_data*)d->node.parent;
+       }
+       return infra_dp_ratelimit;
+}
+
+/** find data item in array, for write access, caller unlocks */
+static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra,
+       uint8_t* name, size_t namelen, int wr)
+{
+       struct rate_key key;
+       hashvalue_t h = dname_query_hash(name, 0xab);
+       memset(&key, 0, sizeof(key));
+       key.name = name;
+       key.namelen = namelen;
+       key.entry.hash = h;
+       return slabhash_lookup(infra->domain_rates, h, &key, wr);
+}
+
+/** create rate data item for name, number 1 in now */
+static void infra_create_ratedata(struct infra_cache* infra,
+       uint8_t* name, size_t namelen, time_t timenow)
+{
+       hashvalue_t h = dname_query_hash(name, 0xab);
+       struct rate_key* k = (struct rate_key*)calloc(1, sizeof(*k));
+       struct rate_data* d = (struct rate_data*)calloc(1, sizeof(*d));
+       if(!k || !d) {
+               free(k);
+               free(d);
+               return; /* alloc failure */
+       }
+       k->namelen = namelen;
+       k->name = memdup(name, namelen);
+       if(!k->name) {
+               free(k);
+               free(d);
+               return; /* alloc failure */
+       }
+       lock_rw_init(&k->entry.lock);
+       k->entry.hash = h;
+       k->entry.key = k;
+       k->entry.data = d;
+       d->qps[0] = 1;
+       d->timestamp[0] = timenow;
+       slabhash_insert(infra->domain_rates, h, &k->entry, d, NULL);
+}
+
+/** find the second and return its rate counter, if none, remove oldest */
+static int* infra_rate_find_second(void* data, time_t t)
+{
+       struct rate_data* d = (struct rate_data*)data;
+       int i, oldest;
+       for(i=0; i<RATE_WINDOW; i++) {
+               if(d->timestamp[i] == t)
+                       return &(d->qps[i]);
+       }
+       /* remove oldest timestamp, and insert it at t with 0 qps */
+       oldest = 0;
+       for(i=0; i<RATE_WINDOW; i++) {
+               if(d->timestamp[i] < d->timestamp[oldest])
+                       oldest = i;
+       }
+       d->timestamp[oldest] = t;
+       d->qps[oldest] = 0;
+       return &(d->qps[oldest]);
+}
+
+int infra_rate_max(void* data, time_t now)
+{
+       struct rate_data* d = (struct rate_data*)data;
+       int i, max = 0;
+       for(i=0; i<RATE_WINDOW; i++) {
+               if(now-d->timestamp[i] <= RATE_WINDOW) {
+                       if(d->qps[i] > max)
+                               max = d->qps[i];
+               }
+       }
+       return max;
+}
+
+int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
+       size_t namelen, time_t timenow)
+{
+       int lim, max;
+       struct lruhash_entry* entry;
+
+       if(!infra_dp_ratelimit)
+               return 1; /* not enabled */
+
+       /* find ratelimit */
+       lim = infra_find_ratelimit(infra, name, namelen);
+       
+       /* find or insert ratedata */
+       entry = infra_find_ratedata(infra, name, namelen, 1);
+       if(entry) {
+               int premax = infra_rate_max(entry->data, timenow);
+               int* cur = infra_rate_find_second(entry->data, timenow);
+               (*cur)++;
+               max = infra_rate_max(entry->data, timenow);
+               lock_rw_unlock(&entry->lock);
+
+               if(premax < lim && max >= lim) {
+                       char buf[257];
+                       dname_str(name, buf);
+                       verbose(VERB_OPS, "ratelimit exceeded %s %d", buf, lim);
+               }
+               return (max < lim);
+       }
+
+       /* create */
+       infra_create_ratedata(infra, name, namelen, timenow);
+       return (1 < lim);
+}
+
+void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name,
+       size_t namelen, time_t timenow)
+{
+       struct lruhash_entry* entry;
+       int* cur;
+       if(!infra_dp_ratelimit)
+               return; /* not enabled */
+       entry = infra_find_ratedata(infra, name, namelen, 1);
+       if(!entry) return; /* not cached */
+       cur = infra_rate_find_second(entry->data, timenow);
+       if((*cur) > 0)
+               (*cur)--;
+       lock_rw_unlock(&entry->lock);
+}
+
+int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
+       size_t namelen, time_t timenow)
+{
+       struct lruhash_entry* entry;
+       int lim, max;
+       if(!infra_dp_ratelimit)
+               return 0; /* not enabled */
+
+       /* find ratelimit */
+       lim = infra_find_ratelimit(infra, name, namelen);
+
+       /* find current rate */
+       entry = infra_find_ratedata(infra, name, namelen, 0);
+       if(!entry)
+               return 0; /* not cached */
+       max = infra_rate_max(entry->data, timenow);
+       lock_rw_unlock(&entry->lock);
+
+       return (max >= lim);
+}
+
 size_t 
 infra_get_mem(struct infra_cache* infra)
 {
-       return sizeof(*infra) + slabhash_get_mem(infra->hosts);
+       size_t s = sizeof(*infra) + slabhash_get_mem(infra->hosts);
+       if(infra->domain_rates) s += slabhash_get_mem(infra->domain_rates);
+       /* ignore domain_limits because walk through tree is big */
+       return s;
 }
diff -uNp -r ./services/cache/infra.h ../unbound/services/cache/infra.h
--- ./services/cache/infra.h    Sun Mar 16 11:38:26 2014
+++ ../unbound/services/cache/infra.h   Fri Apr 10 13:19:30 2015
@@ -42,6 +42,7 @@
 #ifndef SERVICES_CACHE_INFRA_H
 #define SERVICES_CACHE_INFRA_H
 #include "util/storage/lruhash.h"
+#include "util/storage/dnstree.h"
 #include "util/rtt.h"
 struct slabhash;
 struct config_file;
@@ -108,8 +109,57 @@ struct infra_cache {
        struct slabhash* hosts;
        /** TTL value for host information, in seconds */
        int host_ttl;
+       /** hash table with query rates per name: rate_key, rate_data */
+       struct slabhash* domain_rates;
+       /** ratelimit settings for domains, struct domain_limit_data */
+       rbtree_t domain_limits;
 };
 
+/** ratelimit, unless overridden by domain_limits, 0 is off */
+extern int infra_dp_ratelimit;
+
+/**
+ * ratelimit settings for domains
+ */
+struct domain_limit_data {
+       /** key for rbtree, must be first in struct, name of domain */
+       struct name_tree_node node;
+       /** ratelimit for exact match with this name, -1 if not set */
+       int lim;
+       /** ratelimit for names below this name, -1 if not set */
+       int below;
+};
+
+/**
+ * key for ratelimit lookups, a domain name
+ */
+struct rate_key {
+       /** lruhash key entry */
+       struct lruhash_entry entry;
+       /** domain name in uncompressed wireformat */
+       uint8_t* name;
+       /** length of name */
+       size_t namelen;
+};
+
+/** number of seconds to track qps rate */
+#define RATE_WINDOW 2
+
+/**
+ * Data for ratelimits per domain name
+ * It is incremented when a non-cache-lookup happens for that domain name.
+ * The name is the delegation point we have for the name.
+ * If a new delegation point is found (a referral reply), the previous
+ * delegation point is decremented, and the new one is charged with the query.
+ */
+struct rate_data {
+       /** queries counted, for that second. 0 if not in use. */
+       int qps[RATE_WINDOW];
+       /** what the timestamp is of the qps array members, counter is
+        * valid for that timestamp.  Usually now and now-1. */
+       time_t timestamp[RATE_WINDOW];
+};
+
 /** infra host cache default hash lookup size */
 #define INFRA_HOST_STARTSIZE 32
 /** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */
@@ -287,6 +337,51 @@ long long infra_get_host_rto(struct infra_cache* infra
        int* tA, int* tAAAA, int* tother);
 
 /**
+ * Increment the query rate counter for a delegation point.
+ * @param infra: infra cache.
+ * @param name: zone name
+ * @param namelen: zone name length
+ * @param timenow: what time it is now.
+ * @return 1 if it could be incremented. 0 if the increment overshot the
+ * ratelimit or if in the previous second the ratelimit was exceeded.
+ * Failures like alloc failures are not returned (probably as 1).
+ */
+int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
+       size_t namelen, time_t timenow);
+
+/**
+ * Decrement the query rate counter for a delegation point.
+ * Because the reply received for the delegation point was pleasant,
+ * we do not charge this delegation point with it (i.e. it was a referral).
+ * Should call it with same second as when inc() was called.
+ * @param infra: infra cache.
+ * @param name: zone name
+ * @param namelen: zone name length
+ * @param timenow: what time it is now.
+ */
+void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name,
+       size_t namelen, time_t timenow);
+
+/**
+ * See if the query rate counter for a delegation point is exceeded.
+ * So, no queries are going to be allowed.
+ * @param infra: infra cache.
+ * @param name: zone name
+ * @param namelen: zone name length
+ * @param timenow: what time it is now.
+ * @return true if exceeded.
+ */
+int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
+       size_t namelen, time_t timenow);
+
+/** find the maximum rate stored, not too old. 0 if no information. */
+int infra_rate_max(void* data, time_t now);
+
+/** find the ratelimit in qps for a domain */
+int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
+       size_t namelen);
+
+/**
  * Get memory used by the infra cache.
  * @param infra: infrastructure cache.
  * @return memory in use in bytes.
@@ -305,5 +400,17 @@ void infra_delkeyfunc(void* k, void* arg);
 
 /** delete data and destroy the lameness hashtable */
 void infra_deldatafunc(void* d, void* arg);
+
+/** calculate size for the hashtable */
+size_t rate_sizefunc(void* k, void* d);
+
+/** compare two names, returns -1, 0, or +1 */
+int rate_compfunc(void* key1, void* key2);
+
+/** delete key, and destroy the lock */
+void rate_delkeyfunc(void* k, void* arg);
+
+/** delete data */
+void rate_deldatafunc(void* d, void* arg);
 
 #endif /* SERVICES_CACHE_INFRA_H */
diff -uNp -r ./services/cache/rrset.c ../unbound/services/cache/rrset.c
--- ./services/cache/rrset.c    Sun Mar 16 11:38:26 2014
+++ ../unbound/services/cache/rrset.c   Thu Mar 26 13:15:55 2015
@@ -40,7 +40,7 @@
  */
 #include "config.h"
 #include "services/cache/rrset.h"
-#include "ldns/rrdef.h"
+#include "sldns/rrdef.h"
 #include "util/storage/slabhash.h"
 #include "util/config_file.h"
 #include "util/data/packed_rrset.h"
@@ -304,10 +304,11 @@ rrset_array_unlock_touch(struct rrset_cache* r, struct
 {
        hashvalue_t* h;
        size_t i;
-       if(!(h = (hashvalue_t*)regional_alloc(scratch, 
-               sizeof(hashvalue_t)*count)))
+       if(count > RR_COUNT_MAX || !(h = (hashvalue_t*)regional_alloc(scratch, 
+               sizeof(hashvalue_t)*count))) {
                log_warn("rrset LRU: memory allocation failed");
-       else    /* store hash values */
+               h = NULL;
+       } else  /* store hash values */
                for(i=0; i<count; i++)
                        h[i] = ref[i].key->entry.hash;
        /* unlock */
diff -uNp -r ./services/listen_dnsport.c ../unbound/services/listen_dnsport.c
--- ./services/listen_dnsport.c Tue Feb 17 10:03:59 2015
+++ ../unbound/services/listen_dnsport.c        Thu Mar 26 10:21:38 2015
@@ -49,7 +49,7 @@
 #include "util/log.h"
 #include "util/config_file.h"
 #include "util/net_help.h"
-#include "ldns/sbuffer.h"
+#include "sldns/sbuffer.h"
 
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
@@ -96,10 +96,10 @@ verbose_print_addr(struct addrinfo *addr)
 int
 create_udp_sock(int family, int socktype, struct sockaddr* addr,
         socklen_t addrlen, int v6only, int* inuse, int* noproto,
-       int rcv, int snd, int listen, int* reuseport)
+       int rcv, int snd, int listen, int* reuseport, int transparent)
 {
        int s;
-#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU)
+#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || 
defined(IPV6_USE_MIN_MTU)  || defined(IP_TRANSPARENT)
        int on=1;
 #endif
 #ifdef IPV6_MTU
@@ -114,6 +114,9 @@ create_udp_sock(int family, int socktype, struct socka
 #ifndef IPV6_V6ONLY
        (void)v6only;
 #endif
+#ifndef IP_TRANSPARENT
+       (void)transparent;
+#endif
        if((s = socket(family, socktype, 0)) == -1) {
                *inuse = 0;
 #ifndef USE_WINSOCK
@@ -177,6 +180,14 @@ create_udp_sock(int family, int socktype, struct socka
 #else
                (void)reuseport;
 #endif /* defined(SO_REUSEPORT) */
+#ifdef IP_TRANSPARENT
+               if (transparent &&
+                   setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on,
+                   (socklen_t)sizeof(on)) < 0) {
+                       log_warn("setsockopt(.. IP_TRANSPARENT ..) failed: %s",
+                       strerror(errno));
+               }
+#endif /* IP_TRANSPARENT */
        }
        if(rcv) {
 #ifdef SO_RCVBUF
@@ -472,12 +483,15 @@ create_udp_sock(int family, int socktype, struct socka
 
 int
 create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
-       int* reuseport)
+       int* reuseport, int transparent)
 {
        int s;
-#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY)
+#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) || 
defined(IP_TRANSPARENT)
        int on = 1;
-#endif /* SO_REUSEADDR || IPV6_V6ONLY */
+#endif
+#ifndef IP_TRANSPARENT
+       (void)transparent;
+#endif
        verbose_print_addr(addr);
        *noproto = 0;
        if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) {
@@ -552,6 +566,14 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6on
 #else
        (void)v6only;
 #endif /* IPV6_V6ONLY */
+#ifdef IP_TRANSPARENT
+       if (transparent &&
+           setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on,
+           (socklen_t)sizeof(on)) < 0) {
+               log_warn("setsockopt(.. IP_TRANSPARENT ..) failed: %s",
+                       strerror(errno));
+       }
+#endif /* IP_TRANSPARENT */
        if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) {
 #ifndef USE_WINSOCK
                /* detect freebsd jail with no ipv6 permission */
@@ -609,7 +631,7 @@ create_local_accept_sock(const char *path, int* noprot
        /* length is 92-108, 104 on FreeBSD */
        (void)strlcpy(usock.sun_path, path, sizeof(usock.sun_path));
 
-       if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) {
+       if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
                log_err("Cannot create local socket %s (%s)",
                        path, strerror(errno));
                return -1;
@@ -656,7 +678,7 @@ create_local_accept_sock(const char *path, int* noprot
 static int
 make_sock(int stype, const char* ifname, const char* port, 
        struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
-       int* reuseport)
+       int* reuseport, int transparent)
 {
        struct addrinfo *res = NULL;
        int r, s, inuse, noproto;
@@ -684,14 +706,15 @@ make_sock(int stype, const char* ifname, const char* p
                s = create_udp_sock(res->ai_family, res->ai_socktype,
                        (struct sockaddr*)res->ai_addr, res->ai_addrlen,
                        v6only, &inuse, &noproto, (int)rcv, (int)snd, 1,
-                       reuseport);
+                       reuseport, transparent);
                if(s == -1 && inuse) {
                        log_err("bind: address already in use");
                } else if(s == -1 && noproto && hints->ai_family == AF_INET6){
                        *noip6 = 1;
                }
        } else  {
-               s = create_tcp_accept_sock(res, v6only, &noproto, reuseport);
+               s = create_tcp_accept_sock(res, v6only, &noproto, reuseport,
+                       transparent);
                if(s == -1 && noproto && hints->ai_family == AF_INET6){
                        *noip6 = 1;
                }
@@ -704,7 +727,7 @@ make_sock(int stype, const char* ifname, const char* p
 static int
 make_sock_port(int stype, const char* ifname, const char* port, 
        struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
-       int* reuseport)
+       int* reuseport, int transparent)
 {
        char* s = strchr(ifname, '@');
        if(s) {
@@ -726,10 +749,10 @@ make_sock_port(int stype, const char* ifname, const ch
                (void)strlcpy(p, s+1, sizeof(p));
                p[strlen(s+1)]=0;
                return make_sock(stype, newif, p, hints, v6only, noip6,
-                       rcv, snd, reuseport);
+                       rcv, snd, reuseport, transparent);
        }
        return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd,
-               reuseport);
+               reuseport, transparent);
 }
 
 /**
@@ -823,19 +846,20 @@ set_recvpktinfo(int s, int family) 
  * @param ssl_port: ssl service port number
  * @param reuseport: try to set SO_REUSEPORT if nonNULL and true.
  *     set to false on exit if reuseport failed due to no kernel support.
+ * @param transparent: set IP_TRANSPARENT socket option.
  * @return: returns false on error.
  */
 static int
 ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, 
        struct addrinfo *hints, const char* port, struct listen_port** list,
-       size_t rcv, size_t snd, int ssl_port, int* reuseport)
+       size_t rcv, size_t snd, int ssl_port, int* reuseport, int transparent)
 {
        int s, noip6=0;
        if(!do_udp && !do_tcp)
                return 0;
        if(do_auto) {
                if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, 
-                       &noip6, rcv, snd, reuseport)) == -1) {
+                       &noip6, rcv, snd, reuseport, transparent)) == -1) {
                        if(noip6) {
                                log_warn("IPv6 protocol not available");
                                return 1;
@@ -862,7 +886,7 @@ ports_create_if(const char* ifname, int do_auto, int d
        } else if(do_udp) {
                /* regular udp socket */
                if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, 
-                       &noip6, rcv, snd, reuseport)) == -1) {
+                       &noip6, rcv, snd, reuseport, transparent)) == -1) {
                        if(noip6) {
                                log_warn("IPv6 protocol not available");
                                return 1;
@@ -883,7 +907,7 @@ ports_create_if(const char* ifname, int do_auto, int d
                        atoi(strchr(ifname, '@')+1) == ssl_port) ||
                        (!strchr(ifname, '@') && atoi(port) == ssl_port));
                if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1, 
-                       &noip6, 0, 0, reuseport)) == -1) {
+                       &noip6, 0, 0, reuseport, transparent)) == -1) {
                        if(noip6) {
                                /*log_warn("IPv6 protocol not available");*/
                                return 1;
@@ -1039,7 +1063,8 @@ listening_ports_open(struct config_file* cfg, int* reu
                                do_auto, cfg->do_udp, do_tcp, 
                                &hints, portbuf, &list,
                                cfg->so_rcvbuf, cfg->so_sndbuf,
-                               cfg->ssl_port, reuseport)) {
+                               cfg->ssl_port, reuseport,
+                               cfg->ip_transparent)) {
                                listening_ports_free(list);
                                return NULL;
                        }
@@ -1050,7 +1075,8 @@ listening_ports_open(struct config_file* cfg, int* reu
                                do_auto, cfg->do_udp, do_tcp, 
                                &hints, portbuf, &list,
                                cfg->so_rcvbuf, cfg->so_sndbuf,
-                               cfg->ssl_port, reuseport)) {
+                               cfg->ssl_port, reuseport,
+                               cfg->ip_transparent)) {
                                listening_ports_free(list);
                                return NULL;
                        }
@@ -1063,7 +1089,8 @@ listening_ports_open(struct config_file* cfg, int* reu
                        if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp, 
                                do_tcp, &hints, portbuf, &list, 
                                cfg->so_rcvbuf, cfg->so_sndbuf,
-                               cfg->ssl_port, reuseport)) {
+                               cfg->ssl_port, reuseport,
+                               cfg->ip_transparent)) {
                                listening_ports_free(list);
                                return NULL;
                        }
@@ -1074,7 +1101,8 @@ listening_ports_open(struct config_file* cfg, int* reu
                        if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp, 
                                do_tcp, &hints, portbuf, &list, 
                                cfg->so_rcvbuf, cfg->so_sndbuf,
-                               cfg->ssl_port, reuseport)) {
+                               cfg->ssl_port, reuseport,
+                               cfg->ip_transparent)) {
                                listening_ports_free(list);
                                return NULL;
                        }
diff -uNp -r ./services/listen_dnsport.h ../unbound/services/listen_dnsport.h
--- ./services/listen_dnsport.h Tue Feb 17 10:03:59 2015
+++ ../unbound/services/listen_dnsport.h        Thu Mar 19 09:50:35 2015
@@ -189,11 +189,12 @@ void listen_start_accept(struct listen_dnsport* listen
  *     set SO_REUSEADDR on it.
  * @param reuseport: if nonNULL and true, try to set SO_REUSEPORT on
  *     listening UDP port.  Set to false on return if it failed to do so.
+ * @param transparent: set IP_TRANSPARENT socket option.
  * @return: the socket. -1 on error.
  */
 int create_udp_sock(int family, int socktype, struct sockaddr* addr, 
        socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv,
-       int snd, int listen, int* reuseport);
+       int snd, int listen, int* reuseport, int transparent);
 
 /**
  * Create and bind TCP listening socket
@@ -202,10 +203,11 @@ int create_udp_sock(int family, int socktype, struct s
  * @param noproto: if error caused by lack of protocol support.
  * @param reuseport: if nonNULL and true, try to set SO_REUSEPORT on
  *     listening UDP port.  Set to false on return if it failed to do so.
+ * @param transparent: set IP_TRANSPARENT socket option.
  * @return: the socket. -1 on error.
  */
 int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
-       int* reuseport);
+       int* reuseport, int transparent);
 
 /**
  * Create and bind local listening socket
diff -uNp -r ./services/localzone.c ../unbound/services/localzone.c
--- ./services/localzone.c      Tue Feb 17 10:01:53 2015
+++ ../unbound/services/localzone.c     Thu Apr 16 09:23:06 2015
@@ -40,8 +40,8 @@
  */
 #include "config.h"
 #include "services/localzone.h"
-#include "ldns/str2wire.h"
-#include "ldns/sbuffer.h"
+#include "sldns/str2wire.h"
+#include "sldns/sbuffer.h"
 #include "util/regional.h"
 #include "util/config_file.h"
 #include "util/data/dname.h"
@@ -1027,6 +1027,10 @@ void local_zones_print(struct local_zones* zones)
                        log_nametypeclass(0, "inform zone", 
                                z->name, 0, z->dclass);
                        break;
+               case local_zone_inform_deny:
+                       log_nametypeclass(0, "inform_deny zone", 
+                               z->name, 0, z->dclass);
+                       break;
                default:
                        log_nametypeclass(0, "badtyped zone", 
                                z->name, 0, z->dclass);
@@ -1124,7 +1128,7 @@ lz_zone_answer(struct local_zone* z, struct query_info
        struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
        struct local_data* ld)
 {
-       if(z->type == local_zone_deny) {
+       if(z->type == local_zone_deny || z->type == local_zone_inform_deny) {
                /** no reply at all, signal caller by clearing buffer. */
                sldns_buffer_clear(buf);
                sldns_buffer_flip(buf);
@@ -1211,7 +1215,8 @@ local_zones_answer(struct local_zones* zones, struct q
        lock_rw_rdlock(&z->lock);
        lock_rw_unlock(&zones->lock);
 
-       if(z->type == local_zone_inform && repinfo)
+       if((z->type == local_zone_inform || z->type == local_zone_inform_deny)
+               && repinfo)
                lz_inform_print(z, qinfo, repinfo);
 
        if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) {
@@ -1234,6 +1239,7 @@ const char* local_zone_type2str(enum localzone_type t)
                case local_zone_static: return "static";
                case local_zone_nodefault: return "nodefault";
                case local_zone_inform: return "inform";
+               case local_zone_inform_deny: return "inform_deny";
        }
        return "badtyped"; 
 }
@@ -1254,6 +1260,8 @@ int local_zone_str2type(const char* type, enum localzo
                *t = local_zone_redirect;
        else if(strcmp(type, "inform") == 0)
                *t = local_zone_inform;
+       else if(strcmp(type, "inform_deny") == 0)
+               *t = local_zone_inform_deny;
        else return 0;
        return 1;
 }
diff -uNp -r ./services/localzone.h ../unbound/services/localzone.h
--- ./services/localzone.h      Tue Feb 17 10:01:53 2015
+++ ../unbound/services/localzone.h     Thu Apr 16 09:23:06 2015
@@ -73,7 +73,9 @@ enum localzone_type {
         * nodefault is used in config not during service. */
        local_zone_nodefault,
        /** log client address, but no block (transparent) */
-       local_zone_inform
+       local_zone_inform,
+       /** log client address, and block (drop) */
+       local_zone_inform_deny
 };
 
 /**
diff -uNp -r ./services/outside_network.c ../unbound/services/outside_network.c
--- ./services/outside_network.c        Thu Nov 20 00:00:33 2014
+++ ../unbound/services/outside_network.c       Fri May  1 13:36:16 2015
@@ -893,13 +893,13 @@ udp_sockport(struct sockaddr_storage* addr, socklen_t 
                sa->sin6_port = (in_port_t)htons((uint16_t)port);
                fd = create_udp_sock(AF_INET6, SOCK_DGRAM, 
                        (struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
-                       0, 0, 0, NULL);
+                       0, 0, 0, NULL, 0);
        } else {
                struct sockaddr_in* sa = (struct sockaddr_in*)addr;
                sa->sin_port = (in_port_t)htons((uint16_t)port);
                fd = create_udp_sock(AF_INET, SOCK_DGRAM, 
                        (struct sockaddr*)addr, addrlen, 1, inuse, &noproto,
-                       0, 0, 0, NULL);
+                       0, 0, 0, NULL, 0);
        }
        return fd;
 }
@@ -1510,7 +1510,8 @@ serviced_callbacks(struct serviced_query* sq, int erro
        log_assert(rem); /* should have been present */
        sq->to_be_deleted = 1; 
        verbose(VERB_ALGO, "svcd callbacks start");
-       if(sq->outnet->use_caps_for_id && error == NETEVENT_NOERROR && c) {
+       if(sq->outnet->use_caps_for_id && error == NETEVENT_NOERROR && c &&
+               !sq->nocaps) {
                /* noerror and nxdomain must have a qname in reply */
                if(sldns_buffer_read_u16_at(c->buffer, 4) == 0 &&
                        (LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer))
@@ -1590,7 +1591,7 @@ serviced_tcp_callback(struct comm_point* c, void* arg,
                infra_update_tcp_works(sq->outnet->infra, &sq->addr,
                        sq->addrlen, sq->zone, sq->zonelen);
 #ifdef USE_DNSTAP
-       if(sq->outnet->dtenv &&
+       if(error==NETEVENT_NOERROR && sq->outnet->dtenv &&
           (sq->outnet->dtenv->log_resolver_response_messages ||
            sq->outnet->dtenv->log_forwarder_response_messages))
                dt_msg_send_outside_response(sq->outnet->dtenv, &sq->addr,
diff -uNp -r ./sldns/rrdef.c ../unbound/sldns/rrdef.c
--- ./sldns/rrdef.c     Thu Nov 20 00:00:34 2014
+++ ../unbound/sldns/rrdef.c    Thu Jun  4 13:30:29 2015
@@ -213,13 +213,11 @@ static const sldns_rdf_type type_eui48_wireformat[] = 
 static const sldns_rdf_type type_eui64_wireformat[] = {
        LDNS_RDF_TYPE_EUI64
 };
-#ifdef DRAFT_RRTYPES
 static const sldns_rdf_type type_uri_wireformat[] = {
        LDNS_RDF_TYPE_INT16,
        LDNS_RDF_TYPE_INT16,
        LDNS_RDF_TYPE_LONG_STR
 };
-#endif
 static const sldns_rdf_type type_caa_wireformat[] = {
        LDNS_RDF_TYPE_INT8,
        LDNS_RDF_TYPE_TAG,
@@ -590,12 +588,8 @@ static sldns_rr_descriptor rdata_field_descriptors[] =
        /* ANY: A request for all (available) records */
 {LDNS_RR_TYPE_ANY, "ANY", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, 
LDNS_RR_NO_COMPRESS, 0 },
 
-#ifdef DRAFT_RRTYPES
        /* 256 */
        {LDNS_RR_TYPE_URI, "URI", 3, 3, type_uri_wireformat, 
LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
-#else
-{LDNS_RR_TYPE_NULL, "TYPE256", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, 
LDNS_RR_NO_COMPRESS, 0 },
-#endif
        /* 257 */
        {LDNS_RR_TYPE_CAA, "CAA", 3, 3, type_caa_wireformat, 
LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
 
diff -uNp -r ./sldns/rrdef.h ../unbound/sldns/rrdef.h
--- ./sldns/rrdef.h     Thu Nov 20 00:00:34 2014
+++ ../unbound/sldns/rrdef.h    Thu Jun  4 13:30:29 2015
@@ -220,8 +220,7 @@ enum sldns_enum_rr_type
        LDNS_RR_TYPE_MAILA = 254,
        /**  any type (wildcard) */
        LDNS_RR_TYPE_ANY = 255,
-       /** draft-faltstrom-uri-06 */
-       LDNS_RR_TYPE_URI = 256,
+       LDNS_RR_TYPE_URI = 256, /* RFC 7553 */
        LDNS_RR_TYPE_CAA = 257, /* RFC 6844 */
 
        /** DNSSEC Trust Authorities */
diff -uNp -r ./smallapp/unbound-anchor.c ../unbound/smallapp/unbound-anchor.c
--- ./smallapp/unbound-anchor.c Thu Nov 20 00:00:32 2014
+++ ../unbound/smallapp/unbound-anchor.c        Thu Mar 26 10:21:38 2015
@@ -915,7 +915,10 @@ read_data_chunk(SSL* ssl, size_t len)
 {
        size_t got = 0;
        int r;
-       char* data = malloc(len+1);
+       char* data;
+       if(len >= 0xfffffff0)
+               return NULL; /* to protect against integer overflow in malloc*/
+       data = malloc(len+1);
        if(!data) {
                if(verb) printf("out of memory\n");
                return NULL;
diff -uNp -r ./smallapp/unbound-control-setup.sh.in 
../unbound/smallapp/unbound-control-setup.sh.in
--- ./smallapp/unbound-control-setup.sh.in      Mon Jan  5 13:28:44 2015
+++ ../unbound/smallapp/unbound-control-setup.sh.in     Thu Mar 12 15:34:03 2015
@@ -46,7 +46,7 @@ CLIENTNAME=unbound-control
 DAYS=7200
 
 # size of keys in bits
-BITS=1536
+BITS=3072
 
 # hash algorithm
 HASH=sha256
diff -uNp -r ./smallapp/unbound-control.c ../unbound/smallapp/unbound-control.c
--- ./smallapp/unbound-control.c        Tue Feb 17 10:01:54 2015
+++ ../unbound/smallapp/unbound-control.c       Fri Apr 10 13:13:59 2015
@@ -109,6 +109,7 @@ usage()
        printf("  get_option opt                get option value\n");
        printf("  list_stubs                    list stub-zones and root hints 
in use\n");
        printf("  list_forwards                 list forward-zones in use\n");
+       printf("  list_insecure                 list domain-insecure zones\n");
        printf("  list_local_zones              list local-zones in use\n");
        printf("  list_local_data               list local-data RRs in use\n");
        printf("  insecure_add zone             add domain-insecure zone\n");
@@ -122,6 +123,8 @@ usage()
        printf("  forward [off | addr ...]      without arg show forward 
setup\n");
        printf("                                or off to turn off root 
forwarding\n");
        printf("                                or give list of ip 
addresses\n");
+       printf("  ratelimit_list [+a]           list ratelimited domains\n");
+       printf("                +a              list all, also not 
ratelimited\n");
        printf("Version %s\n", PACKAGE_VERSION);
        printf("BSD licensed, see LICENSE in source package for details.\n");
        printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
diff -uNp -r ./util/alloc.c ../unbound/util/alloc.c
--- ./util/alloc.c      Sun Mar 16 11:38:22 2014
+++ ../unbound/util/alloc.c     Mon Jun 29 14:37:34 2015
@@ -364,11 +364,18 @@ void *unbound_stat_malloc(size_t size)
 #ifdef calloc
 #undef calloc
 #endif
+#ifndef INT_MAX
+#define INT_MAX (((int)-1)>>1)
+#endif
 /** calloc with stats */
 void *unbound_stat_calloc(size_t nmemb, size_t size)
 {
-       size_t s = (nmemb*size==0)?(size_t)1:nmemb*size;
-       void* res = calloc(1, s+16);
+       size_t s;
+       void* res;
+       if(nmemb != 0 && INT_MAX/nmemb < size)
+               return NULL; /* integer overflow check */
+       s = (nmemb*size==0)?(size_t)1:nmemb*size;
+       res = calloc(1, s+16);
        if(!res) return NULL;
        log_info("stat %p=calloc(%u, %u)", res+16, (unsigned)nmemb, 
(unsigned)size);
        unbound_mem_alloc += s;
@@ -503,8 +510,12 @@ void *unbound_stat_malloc_lite(size_t size, const char
 void *unbound_stat_calloc_lite(size_t nmemb, size_t size, const char* file,
         int line, const char* func)
 {
-       size_t req = nmemb * size;
-       void* res = malloc(req+lite_pad*2+sizeof(size_t));
+       size_t req;
+       void* res;
+       if(nmemb != 0 && INT_MAX/nmemb < size)
+               return NULL; /* integer overflow check */
+       req = nmemb * size;
+       res = malloc(req+lite_pad*2+sizeof(size_t));
        if(!res) return NULL;
        memmove(res, lite_pre, lite_pad);
        memmove(res+lite_pad, &req, sizeof(size_t));
diff -uNp -r ./util/config_file.c ../unbound/util/config_file.c
--- ./util/config_file.c        Sun Mar  8 15:29:15 2015
+++ ../unbound/util/config_file.c       Fri May 29 15:51:36 2015
@@ -56,8 +56,9 @@
 #include "util/fptr_wlist.h"
 #include "util/data/dname.h"
 #include "util/rtt.h"
-#include "ldns/wire2str.h"
-#include "ldns/parseutil.h"
+#include "services/cache/infra.h"
+#include "sldns/wire2str.h"
+#include "sldns/parseutil.h"
 #ifdef HAVE_GLOB_H
 # include <glob.h>
 #endif
@@ -131,6 +132,7 @@ config_create(void)
        cfg->bogus_ttl = 60;
        cfg->min_ttl = 0;
        cfg->max_ttl = 3600 * 24;
+       cfg->max_negative_ttl = 3600;
        cfg->prefetch = 0;
        cfg->prefetch_key = 0;
        cfg->infra_cache_slabs = 4;
@@ -156,6 +158,7 @@ config_create(void)
        cfg->so_rcvbuf = 0;
        cfg->so_sndbuf = 0;
        cfg->so_reuseport = 0;
+       cfg->ip_transparent = 0;
        cfg->num_ifs = 0;
        cfg->ifs = NULL;
        cfg->num_out_ifs = 0;
@@ -169,7 +172,9 @@ config_create(void)
        cfg->harden_dnssec_stripped = 1;
        cfg->harden_below_nxdomain = 0;
        cfg->harden_referral_path = 0;
+       cfg->harden_algo_downgrade = 1;
        cfg->use_caps_bits_for_id = 0;
+       cfg->caps_whitelist = NULL;
        cfg->private_address = NULL;
        cfg->private_domain = NULL;
        cfg->unwanted_threshold = 0;
@@ -226,6 +231,12 @@ config_create(void)
        if(!(cfg->dnstap_socket_path = strdup(DNSTAP_SOCKET_PATH)))
                goto error_exit;
 #endif
+       cfg->ratelimit = 0;
+       cfg->ratelimit_slabs = 4;
+       cfg->ratelimit_size = 4*1024*1024;
+       cfg->ratelimit_for_domain = NULL;
+       cfg->ratelimit_below_domain = NULL;
+       cfg->ratelimit_factor = 10;
        return cfg;
 error_exit:
        config_delete(cfg); 
@@ -372,12 +383,15 @@ int config_set_option(struct config_file* cfg, const c
        else S_MEMSIZE("so-rcvbuf:", so_rcvbuf)
        else S_MEMSIZE("so-sndbuf:", so_sndbuf)
        else S_YNO("so-reuseport:", so_reuseport)
+       else S_YNO("ip-transparent:", ip_transparent)
        else S_MEMSIZE("rrset-cache-size:", rrset_cache_size)
        else S_POW2("rrset-cache-slabs:", rrset_cache_slabs)
        else S_YNO("prefetch:", prefetch)
        else S_YNO("prefetch-key:", prefetch_key)
        else if(strcmp(opt, "cache-max-ttl:") == 0)
        { IS_NUMBER_OR_ZERO; cfg->max_ttl = atoi(val); 
MAX_TTL=(time_t)cfg->max_ttl;}
+       else if(strcmp(opt, "cache-max-negative-ttl:") == 0)
+       { IS_NUMBER_OR_ZERO; cfg->max_negative_ttl = atoi(val); 
MAX_NEG_TTL=(time_t)cfg->max_negative_ttl;}
        else if(strcmp(opt, "cache-min-ttl:") == 0)
        { IS_NUMBER_OR_ZERO; cfg->min_ttl = atoi(val); 
MIN_TTL=(time_t)cfg->min_ttl;}
        else if(strcmp(opt, "infra-cache-min-rtt:") == 0) {
@@ -404,7 +418,9 @@ int config_set_option(struct config_file* cfg, const c
        else S_YNO("harden-dnssec-stripped:", harden_dnssec_stripped)
        else S_YNO("harden-below-nxdomain:", harden_below_nxdomain)
        else S_YNO("harden-referral-path:", harden_referral_path)
+       else S_YNO("harden-algo-downgrade:", harden_algo_downgrade)
        else S_YNO("use-caps-for-id", use_caps_bits_for_id)
+       else S_STRLIST("caps-whitelist:", caps_whitelist)
        else S_SIZET_OR_ZERO("unwanted-reply-threshold:", unwanted_threshold)
        else S_STRLIST("private-address:", private_address)
        else S_STRLIST("private-domain:", private_domain)
@@ -444,6 +460,13 @@ int config_set_option(struct config_file* cfg, const c
        else S_STR("control-cert-file:", control_cert_file)
        else S_STR("module-config:", module_conf)
        else S_STR("python-script:", python_script)
+       else if(strcmp(opt, "ratelimit:") == 0) {
+           IS_NUMBER_OR_ZERO; cfg->ratelimit = atoi(val);
+           infra_dp_ratelimit=cfg->ratelimit;
+       }
+       else S_MEMSIZE("ratelimit-size:", ratelimit_size)
+       else S_POW2("ratelimit-slabs:", ratelimit_slabs)
+       else S_NUMBER_OR_ZERO("ratelimit-factor:", ratelimit_factor)
        /* val_sig_skew_min and max are copied into val_env during init,
         * so this does not update val_env with set_option */
        else if(strcmp(opt, "val-sig-skew-min:") == 0)
@@ -452,7 +475,8 @@ int config_set_option(struct config_file* cfg, const c
        { IS_NUMBER_OR_ZERO; cfg->val_sig_skew_max = (int32_t)atoi(val); }
        else if (strcmp(opt, "outgoing-interface:") == 0) {
                char* d = strdup(val);
-               char** oi = (char**)malloc((cfg->num_out_ifs+1)*sizeof(char*));
+               char** oi = 
+               (char**)reallocarray(NULL, (size_t)cfg->num_out_ifs+1, 
sizeof(char*));
                if(!d || !oi) { free(d); free(oi); return -1; }
                if(cfg->out_ifs && cfg->num_out_ifs) {
                        memmove(oi, cfg->out_ifs, 
cfg->num_out_ifs*sizeof(char*));
@@ -465,7 +489,8 @@ int config_set_option(struct config_file* cfg, const c
                 * interface, outgoing-interface, access-control, 
                 * stub-zone, name, stub-addr, stub-host, stub-prime
                 * forward-first, stub-first,
-                * forward-zone, name, forward-addr, forward-host */
+                * forward-zone, name, forward-addr, forward-host,
+                * ratelimit-for-domain, ratelimit-below-domain */
                return 0;
        }
        return 1;
@@ -577,8 +602,8 @@ config_collate_cat(struct config_strlist* list)
 #define O_MEM(opt, str, var) if(strcmp(opt, str)==0) { \
        if(cfg->var > 1024*1024*1024) { \
          size_t f=cfg->var/(size_t)1000000, b=cfg->var%(size_t)1000000; \
-         snprintf(buf, len, "%u%6.6u\n", (unsigned)f, (unsigned)b); \
-       } else snprintf(buf, len, "%u\n", (unsigned)cfg->var); \
+         snprintf(buf, len, "%u%6.6u", (unsigned)f, (unsigned)b); \
+       } else snprintf(buf, len, "%u", (unsigned)cfg->var); \
        func(buf, arg);}
 /** compare and print list option */
 #define O_LST(opt, name, lst) if(strcmp(opt, name)==0) { \
@@ -624,11 +649,13 @@ config_get_option(struct config_file* cfg, const char*
        else O_MEM(opt, "so-rcvbuf", so_rcvbuf)
        else O_MEM(opt, "so-sndbuf", so_sndbuf)
        else O_YNO(opt, "so-reuseport", so_reuseport)
+       else O_YNO(opt, "ip-transparent", ip_transparent)
        else O_MEM(opt, "rrset-cache-size", rrset_cache_size)
        else O_DEC(opt, "rrset-cache-slabs", rrset_cache_slabs)
        else O_YNO(opt, "prefetch-key", prefetch_key)
        else O_YNO(opt, "prefetch", prefetch)
        else O_DEC(opt, "cache-max-ttl", max_ttl)
+       else O_DEC(opt, "cache-max-negative-ttl", max_negative_ttl)
        else O_DEC(opt, "cache-min-ttl", min_ttl)
        else O_DEC(opt, "infra-host-ttl", host_ttl)
        else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs)
@@ -662,7 +689,9 @@ config_get_option(struct config_file* cfg, const char*
        else O_YNO(opt, "harden-dnssec-stripped", harden_dnssec_stripped)
        else O_YNO(opt, "harden-below-nxdomain", harden_below_nxdomain)
        else O_YNO(opt, "harden-referral-path", harden_referral_path)
+       else O_YNO(opt, "harden-algo-downgrade", harden_algo_downgrade)
        else O_YNO(opt, "use-caps-for-id", use_caps_bits_for_id)
+       else O_LST(opt, "caps-whitelist", caps_whitelist)
        else O_DEC(opt, "unwanted-reply-threshold", unwanted_threshold)
        else O_YNO(opt, "do-not-query-localhost", donotquery_localhost)
        else O_STR(opt, "module-config", module_conf)
@@ -703,6 +732,12 @@ config_get_option(struct config_file* cfg, const char*
        else O_YNO(opt, "unblock-lan-zones", unblock_lan_zones)
        else O_DEC(opt, "max-udp-size", max_udp_size)
        else O_STR(opt, "python-script", python_script)
+       else O_DEC(opt, "ratelimit", ratelimit)
+       else O_MEM(opt, "ratelimit-size", ratelimit_size)
+       else O_DEC(opt, "ratelimit-slabs", ratelimit_slabs)
+       else O_LS2(opt, "ratelimit-for-domain", ratelimit_for_domain)
+       else O_LS2(opt, "ratelimit-below-domain", ratelimit_below_domain)
+       else O_DEC(opt, "ratelimit-factor", ratelimit_factor)
        else O_DEC(opt, "val-sig-skew-min", val_sig_skew_min)
        else O_DEC(opt, "val-sig-skew-max", val_sig_skew_max)
        /* not here:
@@ -890,6 +925,7 @@ config_delete(struct config_file* cfg)
        free(cfg->version);
        free(cfg->module_conf);
        free(cfg->outgoing_avail_ports);
+       config_delstrlist(cfg->caps_whitelist);
        config_delstrlist(cfg->private_address);
        config_delstrlist(cfg->private_domain);
        config_delstrlist(cfg->auto_trust_anchor_file_list);
@@ -909,9 +945,12 @@ config_delete(struct config_file* cfg)
        free(cfg->server_cert_file);
        free(cfg->control_key_file);
        free(cfg->control_cert_file);
+       free(cfg->dns64_prefix);
        free(cfg->dnstap_socket_path);
        free(cfg->dnstap_identity);
        free(cfg->dnstap_version);
+       config_deldblstrlist(cfg->ratelimit_for_domain);
+       config_deldblstrlist(cfg->ratelimit_below_domain);
        free(cfg);
 }
 
@@ -998,7 +1037,7 @@ int cfg_condense_ports(struct config_file* cfg, int** 
        *avail = NULL;
        if(num == 0)
                return 0;
-       *avail = (int*)malloc(sizeof(int)*num);
+       *avail = (int*)reallocarray(NULL, (size_t)num, sizeof(int));
        if(!*avail)
                return 0;
        for(i=0; i<65536; i++) {
@@ -1198,6 +1237,7 @@ config_apply(struct config_file* config)
 {
        MAX_TTL = (time_t)config->max_ttl;
        MIN_TTL = (time_t)config->min_ttl;
+       MAX_NEG_TTL = (time_t)config->max_negative_ttl;
        RTT_MIN_TIMEOUT = config->infra_cache_min_rtt;
        EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;
        MINIMAL_RESPONSES = config->minimal_responses;
@@ -1211,10 +1251,10 @@ void config_lookup_uid(struct config_file* cfg)
        /* translate username into uid and gid */
        if(cfg->username && cfg->username[0]) {
                struct passwd *pwd;
-               if((pwd = getpwnam(cfg->username)) == NULL)
-                       fatal_exit("user '%s' does not exist.", cfg->username);
-               cfg_uid = pwd->pw_uid;
-               cfg_gid = pwd->pw_gid;
+               if((pwd = getpwnam(cfg->username)) != NULL) {
+                       cfg_uid = pwd->pw_uid;
+                       cfg_gid = pwd->pw_gid;
+               }
        }
 #else
        (void)cfg;
diff -uNp -r ./util/config_file.h ../unbound/util/config_file.h
--- ./util/config_file.h        Sun Mar  8 15:29:15 2015
+++ ../unbound/util/config_file.h       Fri May 29 15:51:36 2015
@@ -136,6 +136,8 @@ struct config_file {
        size_t so_sndbuf;
        /** SO_REUSEPORT requested on port 53 sockets */
        int so_reuseport;
+       /** IP_TRANSPARENT socket option requested on port 53 sockets */
+       int ip_transparent;
 
        /** number of interfaces to open. If 0 default all interfaces. */
        int num_ifs;
@@ -173,8 +175,12 @@ struct config_file {
        int harden_below_nxdomain;
        /** harden the referral path, query for NS,A,AAAA and validate */
        int harden_referral_path;
+       /** harden against algorithm downgrade */
+       int harden_algo_downgrade;
        /** use 0x20 bits in query as random ID bits */
        int use_caps_bits_for_id;
+       /** 0x20 whitelist, domains that do not use capsforid */
+       struct config_strlist* caps_whitelist;
        /** strip away these private addrs from answers, no DNS Rebinding */
        struct config_strlist* private_address;
        /** allow domain (and subdomains) to use private address space */
@@ -185,6 +191,8 @@ struct config_file {
        int max_ttl;
        /** the number of seconds minimum TTL used for RRsets and messages */
        int min_ttl;
+       /** the number of seconds maximal negative TTL for SOA in auth */
+       int max_negative_ttl;
        /** if prefetching of messages should be performed. */
        int prefetch;
        /** if prefetching of DNSKEYs should be performed. */
@@ -341,6 +349,19 @@ struct config_file {
        int dnstap_log_forwarder_query_messages;
        /** true to log dnstap FORWARDER_RESPONSE message events */
        int dnstap_log_forwarder_response_messages;
+
+       /** ratelimit 0 is off, otherwise qps (unless overridden) */
+       int ratelimit;
+       /** number of slabs for ratelimit cache */
+       size_t ratelimit_slabs;
+       /** memory size in bytes for ratelimit cache */
+       size_t ratelimit_size;
+       /** ratelimits for domain (exact match) */
+       struct config_str2list* ratelimit_for_domain;
+       /** ratelimits below domain */
+       struct config_str2list* ratelimit_below_domain;
+       /** ratelimit factor, 0 blocks all, 10 allows 1/10 of traffic */
+       int ratelimit_factor;
 };
 
 /** from cfg username, after daemonise setup performed */
diff -uNp -r ./util/configlexer.lex ../unbound/util/configlexer.lex
--- ./util/configlexer.lex      Tue Feb 17 10:01:55 2015
+++ ../unbound/util/configlexer.lex     Fri May 29 15:51:36 2015
@@ -226,6 +226,7 @@ interface-automatic{COLON}  { YDVAR(1, VAR_INTERFACE_AU
 so-rcvbuf{COLON}               { YDVAR(1, VAR_SO_RCVBUF) }
 so-sndbuf{COLON}               { YDVAR(1, VAR_SO_SNDBUF) }
 so-reuseport{COLON}            { YDVAR(1, VAR_SO_REUSEPORT) }
+ip-transparent{COLON}          { YDVAR(1, VAR_IP_TRANSPARENT) }
 chroot{COLON}                  { YDVAR(1, VAR_CHROOT) }
 username{COLON}                        { YDVAR(1, VAR_USERNAME) }
 directory{COLON}               { YDVAR(1, VAR_DIRECTORY) }
@@ -239,6 +240,7 @@ msg-cache-slabs{COLON}              { YDVAR(1, 
VAR_MSG_CACHE_SLABS
 rrset-cache-size{COLON}                { YDVAR(1, VAR_RRSET_CACHE_SIZE) }
 rrset-cache-slabs{COLON}       { YDVAR(1, VAR_RRSET_CACHE_SLABS) }
 cache-max-ttl{COLON}           { YDVAR(1, VAR_CACHE_MAX_TTL) }
+cache-max-negative-ttl{COLON}   { YDVAR(1, VAR_CACHE_MAX_NEGATIVE_TTL) }
 cache-min-ttl{COLON}           { YDVAR(1, VAR_CACHE_MIN_TTL) }
 infra-host-ttl{COLON}          { YDVAR(1, VAR_INFRA_HOST_TTL) }
 infra-lame-ttl{COLON}          { YDVAR(1, VAR_INFRA_LAME_TTL) }
@@ -256,7 +258,9 @@ harden-glue{COLON}          { YDVAR(1, VAR_HARDEN_GLUE) }
 harden-dnssec-stripped{COLON}  { YDVAR(1, VAR_HARDEN_DNSSEC_STRIPPED) }
 harden-below-nxdomain{COLON}   { YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) }
 harden-referral-path{COLON}    { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) }
+harden-algo-downgrade{COLON}   { YDVAR(1, VAR_HARDEN_ALGO_DOWNGRADE) }
 use-caps-for-id{COLON}         { YDVAR(1, VAR_USE_CAPS_FOR_ID) }
+caps-whitelist{COLON}          { YDVAR(1, VAR_CAPS_WHITELIST) }
 unwanted-reply-threshold{COLON}        { YDVAR(1, 
VAR_UNWANTED_REPLY_THRESHOLD) }
 private-address{COLON}         { YDVAR(1, VAR_PRIVATE_ADDRESS) }
 private-domain{COLON}          { YDVAR(1, VAR_PRIVATE_DOMAIN) }
@@ -348,6 +352,12 @@ dnstap-log-forwarder-query-messages{COLON} {
                YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) }
 dnstap-log-forwarder-response-messages{COLON}  {
                YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) }
+ratelimit{COLON}               { YDVAR(1, VAR_RATELIMIT) }
+ratelimit-slabs{COLON}         { YDVAR(1, VAR_RATELIMIT_SLABS) }
+ratelimit-size{COLON}          { YDVAR(1, VAR_RATELIMIT_SIZE) }
+ratelimit-for-domain{COLON}    { YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) }
+ratelimit-below-domain{COLON}  { YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) }
+ratelimit-factor{COLON}                { YDVAR(1, VAR_RATELIMIT_FACTOR) }
 <INITIAL,val>{NEWLINE}         { LEXOUT(("NL\n")); cfg_parser->line++; }
 
        /* Quoted strings. Strip leading and ending quotes */
diff -uNp -r ./util/configparser.y ../unbound/util/configparser.y
--- ./util/configparser.y       Tue Feb 17 10:01:55 2015
+++ ../unbound/util/configparser.y      Fri May 29 15:51:36 2015
@@ -118,6 +118,10 @@ extern struct config_parser_state* cfg_parser;
 %token VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES
 %token VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES
 %token VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES
+%token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT
+%token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE
+%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN VAR_RATELIMIT_FACTOR
+%token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL
 
 %%
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -177,7 +181,11 @@ content_server: server_num_threads | server_verbosity 
        server_minimal_responses | server_rrset_roundrobin | 
server_max_udp_size |
        server_so_reuseport | server_delay_close | server_unblock_lan_zones |
        server_dns64_prefix | server_dns64_synthall |
-       server_infra_cache_min_rtt
+       server_infra_cache_min_rtt | server_harden_algo_downgrade |
+       server_ip_transparent | server_ratelimit | server_ratelimit_slabs |
+       server_ratelimit_size | server_ratelimit_for_domain |
+       server_ratelimit_below_domain | server_ratelimit_factor |
+       server_caps_whitelist | server_cache_max_negative_ttl
        ;
 stubstart: VAR_STUB_ZONE
        {
@@ -620,6 +628,16 @@ server_so_reuseport: VAR_SO_REUSEPORT STRING_ARG
         free($2);
     }
     ;
+server_ip_transparent: VAR_IP_TRANSPARENT STRING_ARG
+    {
+        OUTYY(("P(server_ip_transparent:%s)\n", $2));
+        if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+            yyerror("expected yes or no.");
+        else cfg_parser->cfg->ip_transparent =
+            (strcmp($2, "yes")==0);
+        free($2);
+    }
+    ;
 server_edns_buffer_size: VAR_EDNS_BUFFER_SIZE STRING_ARG
        {
                OUTYY(("P(server_edns_buffer_size:%s)\n", $2));
@@ -846,6 +864,16 @@ server_harden_referral_path: VAR_HARDEN_REFERRAL_PATH 
                free($2);
        }
        ;
+server_harden_algo_downgrade: VAR_HARDEN_ALGO_DOWNGRADE STRING_ARG
+       {
+               OUTYY(("P(server_harden_algo_downgrade:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->harden_algo_downgrade = 
+                       (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG
        {
                OUTYY(("P(server_use_caps_for_id:%s)\n", $2));
@@ -856,6 +884,13 @@ server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG
                free($2);
        }
        ;
+server_caps_whitelist: VAR_CAPS_WHITELIST STRING_ARG
+       {
+               OUTYY(("P(server_caps_whitelist:%s)\n", $2));
+               if(!cfg_strlist_insert(&cfg_parser->cfg->caps_whitelist, $2))
+                       yyerror("out of memory");
+       }
+       ;
 server_private_address: VAR_PRIVATE_ADDRESS STRING_ARG
        {
                OUTYY(("P(server_private_address:%s)\n", $2));
@@ -991,6 +1026,15 @@ server_cache_max_ttl: VAR_CACHE_MAX_TTL STRING_ARG
                free($2);
        }
        ;
+server_cache_max_negative_ttl: VAR_CACHE_MAX_NEGATIVE_TTL STRING_ARG
+       {
+               OUTYY(("P(server_cache_max_negative_ttl:%s)\n", $2));
+               if(atoi($2) == 0 && strcmp($2, "0") != 0)
+                       yyerror("number expected");
+               else cfg_parser->cfg->max_negative_ttl = atoi($2);
+               free($2);
+       }
+       ;
 server_cache_min_ttl: VAR_CACHE_MIN_TTL STRING_ARG
        {
                OUTYY(("P(server_cache_min_ttl:%s)\n", $2));
@@ -1117,10 +1161,11 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_AR
                   strcmp($3, "refuse")!=0 && strcmp($3, "redirect")!=0 &&
                   strcmp($3, "transparent")!=0 && strcmp($3, "nodefault")!=0
                   && strcmp($3, "typetransparent")!=0 &&
-                  strcmp($3, "inform")!=0)
+                  strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0)
                        yyerror("local-zone type: expected static, deny, "
                                "refuse, redirect, transparent, "
-                               "typetransparent, inform or nodefault");
+                               "typetransparent, inform, inform_deny "
+                               "or nodefault");
                else if(strcmp($3, "nodefault")==0) {
                        if(!cfg_strlist_insert(&cfg_parser->cfg->
                                local_zones_nodefault, $2))
@@ -1195,6 +1240,71 @@ server_dns64_synthall: VAR_DNS64_SYNTHALL STRING_ARG
                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
                        yyerror("expected yes or no.");
                else cfg_parser->cfg->dns64_synthall = (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
+server_ratelimit: VAR_RATELIMIT STRING_ARG 
+       { 
+               OUTYY(("P(server_ratelimit:%s)\n", $2)); 
+               if(atoi($2) == 0 && strcmp($2, "0") != 0)
+                       yyerror("number expected");
+               else cfg_parser->cfg->ratelimit = atoi($2);
+               free($2);
+       }
+       ;
+server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG
+       {
+               OUTYY(("P(server_ratelimit_size:%s)\n", $2));
+               if(!cfg_parse_memsize($2, &cfg_parser->cfg->ratelimit_size))
+                       yyerror("memory size expected");
+               free($2);
+       }
+       ;
+server_ratelimit_slabs: VAR_RATELIMIT_SLABS STRING_ARG
+       {
+               OUTYY(("P(server_ratelimit_slabs:%s)\n", $2));
+               if(atoi($2) == 0)
+                       yyerror("number expected");
+               else {
+                       cfg_parser->cfg->ratelimit_slabs = atoi($2);
+                       if(!is_pow2(cfg_parser->cfg->ratelimit_slabs))
+                               yyerror("must be a power of 2");
+               }
+               free($2);
+       }
+       ;
+server_ratelimit_for_domain: VAR_RATELIMIT_FOR_DOMAIN STRING_ARG STRING_ARG
+       {
+               OUTYY(("P(server_ratelimit_for_domain:%s %s)\n", $2, $3));
+               if(atoi($3) == 0 && strcmp($3, "0") != 0) {
+                       yyerror("number expected");
+               } else {
+                       if(!cfg_str2list_insert(&cfg_parser->cfg->
+                               ratelimit_for_domain, $2, $3))
+                               fatal_exit("out of memory adding "
+                                       "ratelimit-for-domain");
+               }
+       }
+       ;
+server_ratelimit_below_domain: VAR_RATELIMIT_BELOW_DOMAIN STRING_ARG STRING_ARG
+       {
+               OUTYY(("P(server_ratelimit_below_domain:%s %s)\n", $2, $3));
+               if(atoi($3) == 0 && strcmp($3, "0") != 0) {
+                       yyerror("number expected");
+               } else {
+                       if(!cfg_str2list_insert(&cfg_parser->cfg->
+                               ratelimit_below_domain, $2, $3))
+                               fatal_exit("out of memory adding "
+                                       "ratelimit-below-domain");
+               }
+       }
+       ;
+server_ratelimit_factor: VAR_RATELIMIT_FACTOR STRING_ARG 
+       { 
+               OUTYY(("P(server_ratelimit_factor:%s)\n", $2)); 
+               if(atoi($2) == 0 && strcmp($2, "0") != 0)
+                       yyerror("number expected");
+               else cfg_parser->cfg->ratelimit_factor = atoi($2);
                free($2);
        }
        ;
diff -uNp -r ./util/data/msgparse.h ../unbound/util/data/msgparse.h
--- ./util/data/msgparse.h      Sun Mar 16 11:38:24 2014
+++ ../unbound/util/data/msgparse.h     Fri May 29 15:51:36 2015
@@ -76,6 +76,8 @@ struct regional;
 extern time_t MAX_TTL;
 /** Minimum TTL that is allowed. */
 extern time_t MIN_TTL;
+/** Maximum Negative TTL that is allowed */
+extern time_t MAX_NEG_TTL;
 /** Negative cache time (for entries without any RRs.) */
 #define NORR_TTL 5 /* seconds */
 
diff -uNp -r ./util/data/msgreply.c ../unbound/util/data/msgreply.c
--- ./util/data/msgreply.c      Thu Dec 11 16:26:58 2014
+++ ../unbound/util/data/msgreply.c     Fri Jun 26 08:27:32 2015
@@ -50,13 +50,15 @@
 #include "util/regional.h"
 #include "util/data/msgparse.h"
 #include "util/data/msgencode.h"
-#include "ldns/sbuffer.h"
-#include "ldns/wire2str.h"
+#include "sldns/sbuffer.h"
+#include "sldns/wire2str.h"
 
 /** MAX TTL default for messages and rrsets */
 time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
 /** MIN TTL default for messages and rrsets */
 time_t MIN_TTL = 0;
+/** MAX Negative TTL, for SOA records in authority section */
+time_t MAX_NEG_TTL = 3600; /* one hour */
 
 /** allocate qinfo, return 0 on error */
 static int
@@ -87,6 +89,7 @@ construct_reply_info_base(struct regional* region, uin
        /* rrset_count-1 because the first ref is part of the struct. */
        size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) +
                sizeof(struct ub_packed_rrset_key*) * total;
+       if(total >= RR_COUNT_MAX) return NULL; /* sanity check on numRRS*/
        if(region)
                rep = (struct reply_info*)regional_alloc(region, s);
        else    rep = (struct reply_info*)malloc(s + 
@@ -152,10 +155,23 @@ repinfo_alloc_rrset_keys(struct reply_info* rep, struc
        return 1;
 }
 
+/** find the minimumttl in the rdata of SOA record */
+static time_t
+soa_find_minttl(struct rr_parse* rr)
+{
+       uint16_t rlen = sldns_read_uint16(rr->ttl_data+4);
+       if(rlen < 20)
+               return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */
+       /* minimum TTL is the last 32bit value in the rdata of the record */
+       /* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/
+       return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4);
+}
+
 /** do the rdata copy */
 static int
 rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 
-       struct rr_parse* rr, time_t* rr_ttl, uint16_t type)
+       struct rr_parse* rr, time_t* rr_ttl, uint16_t type,
+       sldns_pkt_section section)
 {
        uint16_t pkt_len;
        const sldns_rr_descriptor* desc;
@@ -164,6 +180,14 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data
        /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
        if(*rr_ttl & 0x80000000U)
                *rr_ttl = 0;
+       if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
+               /* negative response. see if TTL of SOA record larger than the
+                * minimum-ttl in the rdata of the SOA record */
+               if(*rr_ttl > soa_find_minttl(rr))
+                       *rr_ttl = soa_find_minttl(rr);
+               if(*rr_ttl > MAX_NEG_TTL)
+                       *rr_ttl = MAX_NEG_TTL;
+       }
        if(*rr_ttl < MIN_TTL)
                *rr_ttl = MIN_TTL;
        if(*rr_ttl < data->ttl)
@@ -253,7 +277,7 @@ parse_rr_copy(sldns_buffer* pkt, struct rrset_parse* p
                data->rr_data[i] = nextrdata;
                nextrdata += rr->size;
                if(!rdata_copy(pkt, data, data->rr_data[i], rr, 
-                       &data->rr_ttl[i], pset->type))
+                       &data->rr_ttl[i], pset->type, pset->section))
                        return 0;
                rr = rr->next;
        }
@@ -264,7 +288,7 @@ parse_rr_copy(sldns_buffer* pkt, struct rrset_parse* p
                data->rr_data[i] = nextrdata;
                nextrdata += rr->size;
                if(!rdata_copy(pkt, data, data->rr_data[i], rr, 
-                       &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG))
+                       &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG, pset->section))
                        return 0;
                rr = rr->next;
        }
@@ -277,7 +301,11 @@ parse_create_rrset(sldns_buffer* pkt, struct rrset_par
        struct packed_rrset_data** data, struct regional* region)
 {
        /* allocate */
-       size_t s = sizeof(struct packed_rrset_data) + 
+       size_t s;
+       if(pset->rr_count > RR_COUNT_MAX || pset->rrsig_count > RR_COUNT_MAX ||
+               pset->size > RR_COUNT_MAX)
+               return 0; /* protect against integer overflow */
+       s = sizeof(struct packed_rrset_data) + 
                (pset->rr_count + pset->rrsig_count) * 
                (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) + 
                pset->size;
@@ -794,13 +822,13 @@ log_query_info(enum verbosity_value v, const char* str
 }
 
 int
-reply_check_cname_chain(struct reply_info* rep) 
+reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep) 
 {
        /* check only answer section rrs for matching cname chain.
         * the cache may return changed rdata, but owner names are untouched.*/
        size_t i;
-       uint8_t* sname = rep->rrsets[0]->rk.dname;
-       size_t snamelen = rep->rrsets[0]->rk.dname_len;
+       uint8_t* sname = qinfo->qname;
+       size_t snamelen = qinfo->qname_len;
        for(i=0; i<rep->an_numrrsets; i++) {
                uint16_t t = ntohs(rep->rrsets[i]->rk.type);
                if(t == LDNS_RR_TYPE_DNAME)
diff -uNp -r ./util/data/msgreply.h ../unbound/util/data/msgreply.h
--- ./util/data/msgreply.h      Thu Nov 20 01:15:19 2014
+++ ../unbound/util/data/msgreply.h     Fri Jun 26 08:27:32 2015
@@ -359,10 +359,11 @@ uint8_t* reply_find_final_cname_target(struct query_in
 
 /**
  * Check if cname chain in cached reply is still valid.
+ * @param qinfo: query info with query name.
  * @param rep: reply to check.
  * @return: true if valid, false if invalid.
  */
-int reply_check_cname_chain(struct reply_info* rep);
+int reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep);
 
 /**
  * Check security status of all RRs in the message.
diff -uNp -r ./util/data/packed_rrset.h ../unbound/util/data/packed_rrset.h
--- ./util/data/packed_rrset.h  Thu Nov 20 00:00:29 2014
+++ ../unbound/util/data/packed_rrset.h Fri Mar 20 15:36:25 2015
@@ -58,6 +58,12 @@ typedef uint64_t rrset_id_t;
  * from the SOA in the answer section from a direct SOA query or ANY query. */
 #define PACKED_RRSET_SOA_NEG 0x4
 
+/** number of rrs and rrsets for integer overflow protection.  More than
+ * this is not really possible (64K packet has much less RRs and RRsets) in
+ * a message.  And this is small enough that also multiplied there is no
+ * integer overflow. */
+#define RR_COUNT_MAX 0xffffff
+
 /**
  * The identifying information for an RRset.
  */
diff -uNp -r ./util/fptr_wlist.c ../unbound/util/fptr_wlist.c
--- ./util/fptr_wlist.c Thu Nov 20 01:15:19 2014
+++ ../unbound/util/fptr_wlist.c        Fri Apr 10 10:59:57 2015
@@ -210,6 +210,7 @@ fptr_whitelist_hash_sizefunc(lruhash_sizefunc_t fptr)
        else if(fptr == &ub_rrset_sizefunc) return 1;
        else if(fptr == &infra_sizefunc) return 1;
        else if(fptr == &key_entry_sizefunc) return 1;
+       else if(fptr == &rate_sizefunc) return 1;
        else if(fptr == &test_slabhash_sizefunc) return 1;
        return 0;
 }
@@ -221,6 +222,7 @@ fptr_whitelist_hash_compfunc(lruhash_compfunc_t fptr)
        else if(fptr == &ub_rrset_compare) return 1;
        else if(fptr == &infra_compfunc) return 1;
        else if(fptr == &key_entry_compfunc) return 1;
+       else if(fptr == &rate_compfunc) return 1;
        else if(fptr == &test_slabhash_compfunc) return 1;
        return 0;
 }
@@ -232,6 +234,7 @@ fptr_whitelist_hash_delkeyfunc(lruhash_delkeyfunc_t fp
        else if(fptr == &ub_rrset_key_delete) return 1;
        else if(fptr == &infra_delkeyfunc) return 1;
        else if(fptr == &key_entry_delkeyfunc) return 1;
+       else if(fptr == &rate_delkeyfunc) return 1;
        else if(fptr == &test_slabhash_delkey) return 1;
        return 0;
 }
@@ -243,6 +246,7 @@ fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_t 
        else if(fptr == &rrset_data_delete) return 1;
        else if(fptr == &infra_deldatafunc) return 1;
        else if(fptr == &key_entry_deldatafunc) return 1;
+       else if(fptr == &rate_deldatafunc) return 1;
        else if(fptr == &test_slabhash_deldata) return 1;
        return 0;
 }
diff -uNp -r ./util/iana_ports.inc ../unbound/util/iana_ports.inc
--- ./util/iana_ports.inc       Tue Feb 17 10:01:55 2015
+++ ../unbound/util/iana_ports.inc      Mon Jun 29 08:09:04 2015
@@ -1066,7 +1066,6 @@
 1404,
 1405,
 1406,
-1407,
 1408,
 1409,
 1410,
@@ -3791,7 +3790,6 @@
 4321,
 4322,
 4323,
-4324,
 4325,
 4326,
 4327,
@@ -4015,6 +4013,7 @@
 4952,
 4969,
 4970,
+4980,
 4986,
 4987,
 4988,
@@ -4359,6 +4358,7 @@
 6072,
 6073,
 6074,
+6080,
 6081,
 6082,
 6083,
@@ -4433,6 +4433,7 @@
 6389,
 6390,
 6417,
+6419,
 6420,
 6421,
 6443,
@@ -4786,6 +4787,7 @@
 8379,
 8380,
 8383,
+8384,
 8400,
 8401,
 8402,
@@ -4802,6 +4804,7 @@
 8474,
 8500,
 8501,
+8503,
 8554,
 8555,
 8567,
@@ -4844,6 +4847,8 @@
 8912,
 8913,
 8954,
+8980,
+8981,
 8989,
 8990,
 8991,
@@ -4851,6 +4856,7 @@
 9000,
 9001,
 9002,
+9006,
 9007,
 9009,
 9020,
@@ -5029,6 +5035,7 @@
 10200,
 10201,
 10252,
+10253,
 10260,
 10288,
 10439,
@@ -5235,6 +5242,7 @@
 22005,
 22273,
 22305,
+22335,
 22343,
 22347,
 22350,
@@ -5374,6 +5382,7 @@
 40843,
 40853,
 41111,
+41230,
 41794,
 41795,
 42508,
diff -uNp -r ./util/log.c ../unbound/util/log.c
--- ./util/log.c        Thu Nov 20 00:00:27 2014
+++ ../unbound/util/log.c       Thu Mar 26 10:21:38 2015
@@ -162,6 +162,14 @@ void log_file(FILE *f)
 void log_thread_set(int* num)
 {
        ub_thread_key_set(logkey, num);
+}
+
+int log_thread_get(void)
+{
+       unsigned int* tid;
+       if(!key_created) return 0;
+       tid = (unsigned int*)ub_thread_key_get(logkey);
+       return (int)(tid?*tid:0);
 }
 
 void log_ident_set(const char* id)
diff -uNp -r ./util/log.h ../unbound/util/log.h
--- ./util/log.h        Sun Mar 16 11:38:23 2014
+++ ../unbound/util/log.h       Mon Mar 16 10:51:32 2015
@@ -98,6 +98,15 @@ void log_file(FILE *f);
 void log_thread_set(int* num);
 
 /**
+ * Get the thread id from logging system.  Set after log_init is
+ * initialised, or log_thread_set for newly created threads.
+ * This initialisation happens in unbound as a daemon, in daemon
+ * startup code, when that spawns threads.
+ * @return thread number, from 0 and up.  Before initialised, returns 0.
+ */
+int log_thread_get(void);
+
+/**
  * Set identity to print, default is 'unbound'. 
  * @param id: string to print. Name of executable.
  */
diff -uNp -r ./util/net_help.c ../unbound/util/net_help.c
--- ./util/net_help.c   Tue Feb 17 10:03:59 2015
+++ ../unbound/util/net_help.c  Thu Mar 26 10:21:38 2015
@@ -770,7 +770,7 @@ static lock_basic_t *ub_openssl_locks = NULL;
 static unsigned long
 ub_crypto_id_cb(void)
 {
-       return (unsigned long)ub_thread_self();
+       return (unsigned long)log_thread_get();
 }
 
 static void
@@ -789,8 +789,8 @@ int ub_openssl_lock_init(void)
 {
 #if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
        int i;
-       ub_openssl_locks = (lock_basic_t*)malloc(
-               sizeof(lock_basic_t)*CRYPTO_num_locks());
+       ub_openssl_locks = (lock_basic_t*)reallocarray(
+               NULL, (size_t)CRYPTO_num_locks(), sizeof(lock_basic_t));
        if(!ub_openssl_locks)
                return 0;
        for(i=0; i<CRYPTO_num_locks(); i++) {
diff -uNp -r ./util/netevent.c ../unbound/util/netevent.c
--- ./util/netevent.c   Thu Nov 20 00:11:14 2014
+++ ../unbound/util/netevent.c  Thu Apr  2 11:02:01 2015
@@ -498,12 +498,16 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns
        cmsg = CMSG_FIRSTHDR(&msg);
        if(r->srctype == 4) {
 #ifdef IP_PKTINFO
+               void* cmsg_data;
                msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
                log_assert(msg.msg_controllen <= sizeof(control));
                cmsg->cmsg_level = IPPROTO_IP;
                cmsg->cmsg_type = IP_PKTINFO;
                memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info,
                        sizeof(struct in_pktinfo));
+               /* unset the ifindex to not bypass the routing tables */
+               cmsg_data = CMSG_DATA(cmsg);
+               ((struct in_pktinfo *) cmsg_data)->ipi_ifindex = 0;
                cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
 #elif defined(IP_SENDSRCADDR)
                msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
@@ -518,12 +522,16 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns
                msg.msg_control = NULL;
 #endif /* IP_PKTINFO or IP_SENDSRCADDR */
        } else if(r->srctype == 6) {
+               void* cmsg_data;
                msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
                log_assert(msg.msg_controllen <= sizeof(control));
                cmsg->cmsg_level = IPPROTO_IPV6;
                cmsg->cmsg_type = IPV6_PKTINFO;
                memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info,
                        sizeof(struct in6_pktinfo));
+               /* unset the ifindex to not bypass the routing tables */
+               cmsg_data = CMSG_DATA(cmsg);
+               ((struct in6_pktinfo *) cmsg_data)->ipi6_ifindex = 0;
                cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
        } else {
                /* try to pass all 0 to use default route */
@@ -879,12 +887,12 @@ comm_point_tcp_accept_callback(int fd, short event, vo
        }
 
        /* grab the tcp handler buffers */
+       c->cur_tcp_count++;
        c->tcp_free = c_hdl->tcp_free;
        if(!c->tcp_free) {
                /* stop accepting incoming queries for now. */
                comm_point_stop_listening(c);
        }
-       /* addr is dropped. Not needed for tcp reply. */
        setup_tcp_handler(c_hdl, new_fd);
 }
 
@@ -902,6 +910,7 @@ reclaim_tcp_handler(struct comm_point* c)
        }
        comm_point_close(c);
        if(c->tcp_parent) {
+               c->tcp_parent->cur_tcp_count--;
                c->tcp_free = c->tcp_parent->tcp_free;
                c->tcp_parent->tcp_free = c;
                if(!c->tcp_free) {
@@ -1528,6 +1537,7 @@ comm_point_create_udp(struct comm_base *base, int fd, 
        c->tcp_byte_count = 0;
        c->tcp_parent = NULL;
        c->max_tcp_count = 0;
+       c->cur_tcp_count = 0;
        c->tcp_handlers = NULL;
        c->tcp_free = NULL;
        c->type = comm_udp;
@@ -1578,6 +1588,7 @@ comm_point_create_udp_ancil(struct comm_base *base, in
        c->tcp_byte_count = 0;
        c->tcp_parent = NULL;
        c->max_tcp_count = 0;
+       c->cur_tcp_count = 0;
        c->tcp_handlers = NULL;
        c->tcp_free = NULL;
        c->type = comm_udp;
@@ -1639,6 +1650,7 @@ comm_point_create_tcp_handler(struct comm_base *base, 
        c->tcp_byte_count = 0;
        c->tcp_parent = parent;
        c->max_tcp_count = 0;
+       c->cur_tcp_count = 0;
        c->tcp_handlers = NULL;
        c->tcp_free = NULL;
        c->type = comm_tcp;
@@ -1691,6 +1703,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, 
        c->tcp_byte_count = 0;
        c->tcp_parent = NULL;
        c->max_tcp_count = num;
+       c->cur_tcp_count = 0;
        c->tcp_handlers = (struct comm_point**)calloc((size_t)num,
                sizeof(struct comm_point*));
        if(!c->tcp_handlers) {
@@ -1758,6 +1771,7 @@ comm_point_create_tcp_out(struct comm_base *base, size
        c->tcp_byte_count = 0;
        c->tcp_parent = NULL;
        c->max_tcp_count = 0;
+       c->cur_tcp_count = 0;
        c->tcp_handlers = NULL;
        c->tcp_free = NULL;
        c->type = comm_tcp;
@@ -1810,6 +1824,7 @@ comm_point_create_local(struct comm_base *base, int fd
        c->tcp_byte_count = 0;
        c->tcp_parent = NULL;
        c->max_tcp_count = 0;
+       c->cur_tcp_count = 0;
        c->tcp_handlers = NULL;
        c->tcp_free = NULL;
        c->type = comm_local;
@@ -1857,6 +1872,7 @@ comm_point_create_raw(struct comm_base* base, int fd, 
        c->tcp_byte_count = 0;
        c->tcp_parent = NULL;
        c->max_tcp_count = 0;
+       c->cur_tcp_count = 0;
        c->tcp_handlers = NULL;
        c->tcp_free = NULL;
        c->type = comm_raw;
diff -uNp -r ./util/netevent.h ../unbound/util/netevent.h
--- ./util/netevent.h   Thu Nov 20 00:11:14 2014
+++ ../unbound/util/netevent.h  Thu Mar  5 15:23:14 2015
@@ -164,6 +164,8 @@ struct comm_point {
        /* -------- TCP Accept -------- */
        /** the number of TCP handlers for this tcp-accept socket */
        int max_tcp_count;
+       /** current number of tcp handler in-use for this accept socket */
+       int cur_tcp_count;
        /** malloced array of tcp handlers for a tcp-accept, 
            of size max_tcp_count. */
        struct comm_point** tcp_handlers;
diff -uNp -r ./validator/autotrust.c ../unbound/validator/autotrust.c
--- ./validator/autotrust.c     Thu Nov 20 00:00:37 2014
+++ ../unbound/validator/autotrust.c    Tue Apr  7 13:03:05 2015
@@ -1184,7 +1184,7 @@ void autr_write_file(struct module_env* env, struct tr
        verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf);
        out = fopen(tempf, "w");
        if(!out) {
-               log_err("could not open autotrust file for writing, %s: %s",
+               fatal_exit("could not open autotrust file for writing, %s: %s",
                        tempf, strerror(errno));
                return;
        }
@@ -1192,11 +1192,11 @@ void autr_write_file(struct module_env* env, struct tr
                /* failed to write contents (completely) */
                fclose(out);
                unlink(tempf);
-               log_err("could not completely write: %s", fname);
+               fatal_exit("could not completely write: %s", fname);
                return;
        }
        if(fclose(out) != 0) {
-               log_err("could not complete write: %s: %s",
+               fatal_exit("could not complete write: %s: %s",
                        fname, strerror(errno));
                unlink(tempf);
                return;
@@ -1207,7 +1207,7 @@ void autr_write_file(struct module_env* env, struct tr
        (void)unlink(fname); /* windows does not replace file with rename() */
 #endif
        if(rename(tempf, fname) < 0) {
-               log_err("rename(%s to %s): %s", tempf, fname, strerror(errno));
+               fatal_exit("rename(%s to %s): %s", tempf, fname, 
strerror(errno));
        }
 }
 
diff -uNp -r ./validator/val_anchor.c ../unbound/validator/val_anchor.c
--- ./validator/val_anchor.c    Thu Nov 20 00:00:35 2014
+++ ../unbound/validator/val_anchor.c   Thu Mar 26 10:21:38 2015
@@ -882,14 +882,14 @@ assemble_it(struct trust_anchor* ta, size_t num, uint1
        memset(pd, 0, sizeof(*pd));
        pd->count = num;
        pd->trust = rrset_trust_ultimate;
-       pd->rr_len = (size_t*)malloc(num*sizeof(size_t));
+       pd->rr_len = (size_t*)reallocarray(NULL, num, sizeof(size_t));
        if(!pd->rr_len) {
                free(pd);
                free(pkey->rk.dname);
                free(pkey);
                return NULL;
        }
-       pd->rr_ttl = (time_t*)malloc(num*sizeof(time_t));
+       pd->rr_ttl = (time_t*)reallocarray(NULL, num, sizeof(time_t));
        if(!pd->rr_ttl) {
                free(pd->rr_len);
                free(pd);
@@ -897,7 +897,7 @@ assemble_it(struct trust_anchor* ta, size_t num, uint1
                free(pkey);
                return NULL;
        }
-       pd->rr_data = (uint8_t**)malloc(num*sizeof(uint8_t*));
+       pd->rr_data = (uint8_t**)reallocarray(NULL, num, sizeof(uint8_t*));
        if(!pd->rr_data) {
                free(pd->rr_ttl);
                free(pd->rr_len);
@@ -1020,7 +1020,13 @@ anchors_assemble_rrsets(struct val_anchors* anchors)
                        dname_str(ta->name, b);
                        log_warn("trust anchor %s has no supported algorithms,"
                                " the anchor is ignored (check if you need to"
-                               " upgrade unbound and openssl)", b);
+                               " upgrade unbound and "
+#ifdef HAVE_LIBRESSL
+                               "libressl"
+#else
+                               "openssl"
+#endif
+                               ")", b);
                        (void)rbtree_delete(anchors->tree, &ta->node);
                        lock_basic_unlock(&ta->lock);
                        anchors_delfunc(&ta->node, NULL);
diff -uNp -r ./validator/val_sigcrypt.c ../unbound/validator/val_sigcrypt.c
--- ./validator/val_sigcrypt.c  Sun Mar 16 11:38:28 2014
+++ ../unbound/validator/val_sigcrypt.c Thu Mar 26 10:21:38 2015
@@ -1079,6 +1079,8 @@ int rrset_canonical_equal(struct regional* region,
        fd.rr_data = fdata;
        rbtree_init(&sortree1, &canonical_tree_compare);
        rbtree_init(&sortree2, &canonical_tree_compare);
+       if(d1->count > RR_COUNT_MAX || d2->count > RR_COUNT_MAX)
+               return 1; /* protection against integer overflow */
        rrs1 = regional_alloc(region, sizeof(struct canon_rr)*d1->count);
        rrs2 = regional_alloc(region, sizeof(struct canon_rr)*d2->count);
        if(!rrs1 || !rrs2) return 1; /* alloc failure */
@@ -1135,6 +1137,8 @@ rrset_canonical(struct regional* region, sldns_buffer*
                        sizeof(rbtree_t));
                if(!*sortree)
                        return 0;
+               if(d->count > RR_COUNT_MAX)
+                       return 0; /* integer overflow protection */
                rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count);
                if(!rrs) {
                        *sortree = NULL;
diff -uNp -r ./validator/validator.c ../unbound/validator/validator.c
--- ./validator/validator.c     Tue Feb 10 22:07:42 2015
+++ ../unbound/validator/validator.c    Wed May 20 07:24:06 2015
@@ -226,6 +226,8 @@ val_new_getmsg(struct module_qstate* qstate, struct va
                sizeof(struct reply_info) - sizeof(struct rrset_ref));
        if(!vq->chase_reply)
                return NULL;
+       if(vq->orig_msg->rep->rrset_count > RR_COUNT_MAX)
+               return NULL; /* protect against integer overflow */
        vq->chase_reply->rrsets = regional_alloc_init(qstate->region,
                vq->orig_msg->rep->rrsets, sizeof(struct ub_packed_rrset_key*)
                        * vq->orig_msg->rep->rrset_count);
@@ -517,8 +519,8 @@ validate_msg_signatures(struct module_qstate* qstate, 
                                "has failed AUTHORITY rrset:", s->rk.dname,
                                ntohs(s->rk.type), ntohs(s->rk.rrset_class));
                        errinf(qstate, reason);
-                       errinf_rrset(qstate, s);
                        errinf_origin(qstate, qstate->reply_origin);
+                       errinf_rrset(qstate, s);
                        chase_reply->security = sec_status_bogus;
                        return 0;
                }
@@ -1813,6 +1815,8 @@ processValidate(struct module_qstate* qstate, struct v
 
 /**
  * Init DLV check.
+ * DLV is going to be decommissioned, but the code is still here for some time.
+ *
  * Called when a query is determined by other trust anchors to be insecure
  * (or indeterminate).  Then we look if there is a key in the DLV.
  * Performs aggressive negative cache check to see if there is no key.
@@ -2352,7 +2356,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_r
        struct key_entry_key* kkey = NULL;
        enum sec_status sec = sec_status_unchecked;
        char* reason = NULL;
-       int downprot = 1;
+       int downprot = qstate->env->cfg->harden_algo_downgrade;
 
        if(!dnskey_rrset) {
                log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "

Reply via email to