diff --git a/patches/nginx-1.9.7-resolver_security_fixes.patch b/patches/nginx-1.9.7-resolver_security_fixes.patch
new file mode 100644
index 0000000..cdef0c3
--- /dev/null
+++ b/patches/nginx-1.9.7-resolver_security_fixes.patch
@@ -0,0 +1,565 @@
+diff -upr nginx-1.9.7-old/src/core/ngx_resolver.c nginx-1.9.7/src/core/ngx_resolver.c
+--- nginx-1.9.7-old/src/core/ngx_resolver.c	2016-01-26 11:54:55.915406799 -0800
++++ nginx-1.9.7/src/core/ngx_resolver.c	2016-01-26 11:55:27.067782268 -0800
+@@ -59,15 +59,15 @@ ngx_int_t ngx_udp_connect(ngx_udp_connec
+ static void ngx_resolver_cleanup(void *data);
+ static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
+ static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
+-    ngx_resolver_ctx_t *ctx);
++    ngx_resolver_ctx_t *ctx, ngx_str_t *name);
+ static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
+     ngx_queue_t *queue);
+ static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
+     ngx_resolver_node_t *rn);
+-static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn,
+-    ngx_resolver_ctx_t *ctx);
+-static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn,
+-    ngx_resolver_ctx_t *ctx);
++static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r,
++    ngx_resolver_node_t *rn, ngx_str_t *name);
++static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r,
++    ngx_resolver_node_t *rn, ngx_addr_t *addr);
+ static void ngx_resolver_resend_handler(ngx_event_t *ev);
+ static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
+     ngx_queue_t *queue);
+@@ -376,7 +376,7 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx
+ 
+     /* lock name mutex */
+ 
+-    rc = ngx_resolve_name_locked(r, ctx);
++    rc = ngx_resolve_name_locked(r, ctx, &ctx->name);
+ 
+     if (rc == NGX_OK) {
+         return NGX_OK;
+@@ -403,7 +403,6 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx
+ void
+ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
+ {
+-    uint32_t              hash;
+     ngx_resolver_t       *r;
+     ngx_resolver_ctx_t   *w, **p;
+     ngx_resolver_node_t  *rn;
+@@ -423,11 +422,9 @@ ngx_resolve_name_done(ngx_resolver_ctx_t
+ 
+     /* lock name mutex */
+ 
+-    if (ctx->state == NGX_AGAIN) {
+-
+-        hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
++    if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
+ 
+-        rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
++        rn = ctx->node;
+ 
+         if (rn) {
+             p = &rn->waiting;
+@@ -472,23 +469,28 @@ done:
+ 
+ 
+ static ngx_int_t
+-ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
++ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx,
++    ngx_str_t *name)
+ {
+     uint32_t              hash;
+     ngx_int_t             rc;
++    ngx_str_t             cname;
+     ngx_uint_t            naddrs;
+     ngx_addr_t           *addrs;
+-    ngx_resolver_ctx_t   *next;
++    ngx_resolver_ctx_t   *next, *last;
+     ngx_resolver_node_t  *rn;
+ 
+-    ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len);
++    ngx_strlow(name->data, name->data, name->len);
+ 
+-    hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
++    hash = ngx_crc32_short(name->data, name->len);
+ 
+-    rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
++    rn = ngx_resolver_lookup_name(r, name, hash);
+ 
+     if (rn) {
+ 
++        /* ctx can be a list after NGX_RESOLVE_CNAME */
++        for (last = ctx; last->next; last = last->next);
++
+         if (rn->valid >= ngx_time()) {
+ 
+             ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
+@@ -516,7 +518,7 @@ ngx_resolve_name_locked(ngx_resolver_t *
+                     }
+                 }
+ 
+-                ctx->next = rn->waiting;
++                last->next = rn->waiting;
+                 rn->waiting = NULL;
+ 
+                 /* unlock name mutex */
+@@ -556,13 +558,13 @@ ngx_resolve_name_locked(ngx_resolver_t *
+ 
+             if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
+ 
+-                ctx->name.len = rn->cnlen;
+-                ctx->name.data = rn->u.cname;
++                cname.len = rn->cnlen;
++                cname.data = rn->u.cname;
+ 
+-                return ngx_resolve_name_locked(r, ctx);
++                return ngx_resolve_name_locked(r, ctx, &cname);
+             }
+ 
+-            ctx->next = rn->waiting;
++            last->next = rn->waiting;
+             rn->waiting = NULL;
+ 
+             /* unlock name mutex */
+@@ -581,10 +583,29 @@ ngx_resolve_name_locked(ngx_resolver_t *
+ 
+         if (rn->waiting) {
+ 
+-            ctx->next = rn->waiting;
++            if (ctx->event == NULL) {
++                ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
++                if (ctx->event == NULL) {
++                    return NGX_ERROR;
++                }
++
++                ctx->event->handler = ngx_resolver_timeout_handler;
++                ctx->event->data = ctx;
++                ctx->event->log = r->log;
++                ctx->ident = -1;
++
++                ngx_add_timer(ctx->event, ctx->timeout);
++            }
++
++            last->next = rn->waiting;
+             rn->waiting = ctx;
+             ctx->state = NGX_AGAIN;
+ 
++            do {
++                ctx->node = rn;
++                ctx = ctx->next;
++            } while (ctx);
++
+             return NGX_AGAIN;
+         }
+ 
+@@ -623,14 +644,14 @@ ngx_resolve_name_locked(ngx_resolver_t *
+             return NGX_ERROR;
+         }
+ 
+-        rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len);
++        rn->name = ngx_resolver_dup(r, name->data, name->len);
+         if (rn->name == NULL) {
+             ngx_resolver_free(r, rn);
+             return NGX_ERROR;
+         }
+ 
+         rn->node.key = hash;
+-        rn->nlen = (u_short) ctx->name.len;
++        rn->nlen = (u_short) name->len;
+         rn->query = NULL;
+ #if (NGX_HAVE_INET6)
+         rn->query6 = NULL;
+@@ -639,7 +660,7 @@ ngx_resolve_name_locked(ngx_resolver_t *
+         ngx_rbtree_insert(&r->name_rbtree, &rn->node);
+     }
+ 
+-    rc = ngx_resolver_create_name_query(rn, ctx);
++    rc = ngx_resolver_create_name_query(r, rn, name);
+ 
+     if (rc == NGX_ERROR) {
+         goto failed;
+@@ -652,8 +673,14 @@ ngx_resolve_name_locked(ngx_resolver_t *
+         ngx_resolver_free(r, rn->name);
+         ngx_resolver_free(r, rn);
+ 
+-        ctx->state = NGX_RESOLVE_NXDOMAIN;
+-        ctx->handler(ctx);
++        do {
++            ctx->state = NGX_RESOLVE_NXDOMAIN;
++            next = ctx->next;
++
++            ctx->handler(ctx);
++
++            ctx = next;
++        } while (ctx);
+ 
+         return NGX_OK;
+     }
+@@ -674,9 +701,9 @@ ngx_resolve_name_locked(ngx_resolver_t *
+         }
+ 
+         ctx->event->handler = ngx_resolver_timeout_handler;
+-        ctx->event->data = rn;
++        ctx->event->data = ctx;
+         ctx->event->log = r->log;
+-        rn->ident = -1;
++        ctx->ident = -1;
+ 
+         ngx_add_timer(ctx->event, ctx->timeout);
+     }
+@@ -697,6 +724,11 @@ ngx_resolve_name_locked(ngx_resolver_t *
+ 
+     ctx->state = NGX_AGAIN;
+ 
++    do {
++        ctx->node = rn;
++        ctx = ctx->next;
++    } while (ctx);
++
+     return NGX_AGAIN;
+ 
+ failed:
+@@ -804,9 +836,22 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx
+ 
+         if (rn->waiting) {
+ 
++            ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
++            if (ctx->event == NULL) {
++                return NGX_ERROR;
++            }
++
++            ctx->event->handler = ngx_resolver_timeout_handler;
++            ctx->event->data = ctx;
++            ctx->event->log = r->log;
++            ctx->ident = -1;
++
++            ngx_add_timer(ctx->event, ctx->timeout);
++
+             ctx->next = rn->waiting;
+             rn->waiting = ctx;
+             ctx->state = NGX_AGAIN;
++            ctx->node = rn;
+ 
+             /* unlock addr mutex */
+ 
+@@ -848,7 +893,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx
+         ngx_rbtree_insert(tree, &rn->node);
+     }
+ 
+-    if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
++    if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) {
+         goto failed;
+     }
+ 
+@@ -867,9 +912,9 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx
+     }
+ 
+     ctx->event->handler = ngx_resolver_timeout_handler;
+-    ctx->event->data = rn;
++    ctx->event->data = ctx;
+     ctx->event->log = r->log;
+-    rn->ident = -1;
++    ctx->ident = -1;
+ 
+     ngx_add_timer(ctx->event, ctx->timeout);
+ 
+@@ -892,6 +937,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx
+     /* unlock addr mutex */
+ 
+     ctx->state = NGX_AGAIN;
++    ctx->node = rn;
+ 
+     return NGX_OK;
+ 
+@@ -922,17 +968,11 @@ failed:
+ void
+ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
+ {
+-    in_addr_t             addr;
+     ngx_queue_t          *expire_queue;
+     ngx_rbtree_t         *tree;
+     ngx_resolver_t       *r;
+     ngx_resolver_ctx_t   *w, **p;
+-    struct sockaddr_in   *sin;
+     ngx_resolver_node_t  *rn;
+-#if (NGX_HAVE_INET6)
+-    uint32_t              hash;
+-    struct sockaddr_in6  *sin6;
+-#endif
+ 
+     r = ctx->resolver;
+ 
+@@ -959,23 +999,9 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t
+ 
+     /* lock addr mutex */
+ 
+-    if (ctx->state == NGX_AGAIN) {
+-
+-        switch (ctx->addr.sockaddr->sa_family) {
+-
+-#if (NGX_HAVE_INET6)
+-        case AF_INET6:
+-            sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
+-            hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
+-            rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
+-            break;
+-#endif
++    if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
+ 
+-        default: /* AF_INET */
+-            sin = (struct sockaddr_in *) ctx->addr.sockaddr;
+-            addr = ntohl(sin->sin_addr.s_addr);
+-            rn = ngx_resolver_lookup_addr(r, addr);
+-        }
++        rn = ctx->node;
+ 
+         if (rn) {
+             p = &rn->waiting;
+@@ -1312,7 +1338,7 @@ ngx_resolver_process_response(ngx_resolv
+         times = 0;
+ 
+         for (q = ngx_queue_head(&r->name_resend_queue);
+-             q != ngx_queue_sentinel(&r->name_resend_queue) || times++ < 100;
++             q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100;
+              q = ngx_queue_next(q))
+         {
+             rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
+@@ -1975,20 +2001,39 @@ ngx_resolver_process_a(ngx_resolver_t *r
+ 
+         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
+ 
++        ngx_resolver_free(r, rn->query);
++        rn->query = NULL;
++#if (NGX_HAVE_INET6)
++        rn->query6 = NULL;
++#endif
++
+         ctx = rn->waiting;
+         rn->waiting = NULL;
+ 
+         if (ctx) {
+-            ctx->name = name;
+ 
+-            (void) ngx_resolve_name_locked(r, ctx);
+-        }
++            if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
+ 
+-        ngx_resolver_free(r, rn->query);
+-        rn->query = NULL;
+-#if (NGX_HAVE_INET6)
+-        rn->query6 = NULL;
+-#endif
++                /* unlock name mutex */
++
++                do {
++                    ctx->state = NGX_RESOLVE_NXDOMAIN;
++                    next = ctx->next;
++
++                    ctx->handler(ctx);
++
++                    ctx = next;
++                } while (ctx);
++
++                return;
++            }
++
++            for (next = ctx; next; next = next->next) {
++                next->node = NULL;
++            }
++
++            (void) ngx_resolve_name_locked(r, ctx, &name);
++        }
+ 
+         /* unlock name mutex */
+ 
+@@ -2496,27 +2541,23 @@ ngx_resolver_rbtree_insert_addr6_value(n
+ 
+ 
+ static ngx_int_t
+-ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
++ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
++    ngx_str_t *name)
+ {
+     u_char              *p, *s;
+     size_t               len, nlen;
+     ngx_uint_t           ident;
+-#if (NGX_HAVE_INET6)
+-    ngx_resolver_t      *r;
+-#endif
+     ngx_resolver_qs_t   *qs;
+     ngx_resolver_hdr_t  *query;
+ 
+-    nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1;
++    nlen = name->len ? (1 + name->len + 1) : 1;
+ 
+     len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
+ 
+ #if (NGX_HAVE_INET6)
+-    r = ctx->resolver;
+-
+-    p = ngx_resolver_alloc(ctx->resolver, r->ipv6 ? len * 2 : len);
++    p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len);
+ #else
+-    p = ngx_resolver_alloc(ctx->resolver, len);
++    p = ngx_resolver_alloc(r, len);
+ #endif
+     if (p == NULL) {
+         return NGX_ERROR;
+@@ -2535,8 +2576,8 @@ ngx_resolver_create_name_query(ngx_resol
+ 
+     ident = ngx_random();
+ 
+-    ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
+-                   "resolve: \"%V\" A %i", &ctx->name, ident & 0xffff);
++    ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
++                   "resolve: \"%V\" A %i", name, ident & 0xffff);
+ 
+     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
+     query->ident_lo = (u_char) (ident & 0xff);
+@@ -2566,11 +2607,11 @@ ngx_resolver_create_name_query(ngx_resol
+     p--;
+     *p-- = '\0';
+ 
+-    if (ctx->name.len == 0)  {
++    if (name->len == 0)  {
+         return NGX_DECLINED;
+     }
+ 
+-    for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) {
++    for (s = name->data + name->len - 1; s >= name->data; s--) {
+         if (*s != '.') {
+             *p = *s;
+             len++;
+@@ -2606,8 +2647,8 @@ ngx_resolver_create_name_query(ngx_resol
+ 
+     ident = ngx_random();
+ 
+-    ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
+-                   "resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff);
++    ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
++                   "resolve: \"%V\" AAAA %i", name, ident & 0xffff);
+ 
+     query->ident_hi = (u_char) ((ident >> 8) & 0xff);
+     query->ident_lo = (u_char) (ident & 0xff);
+@@ -2624,11 +2665,12 @@ ngx_resolver_create_name_query(ngx_resol
+ 
+ 
+ static ngx_int_t
+-ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
++ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
++    ngx_addr_t *addr)
+ {
+     u_char               *p, *d;
+     size_t                len;
+-    in_addr_t             addr;
++    in_addr_t             inaddr;
+     ngx_int_t             n;
+     ngx_uint_t            ident;
+     ngx_resolver_hdr_t   *query;
+@@ -2637,7 +2679,7 @@ ngx_resolver_create_addr_query(ngx_resol
+     struct sockaddr_in6  *sin6;
+ #endif
+ 
+-    switch (ctx->addr.sockaddr->sa_family) {
++    switch (addr->sockaddr->sa_family) {
+ 
+ #if (NGX_HAVE_INET6)
+     case AF_INET6:
+@@ -2654,7 +2696,7 @@ ngx_resolver_create_addr_query(ngx_resol
+               + sizeof(ngx_resolver_qs_t);
+     }
+ 
+-    p = ngx_resolver_alloc(ctx->resolver, len);
++    p = ngx_resolver_alloc(r, len);
+     if (p == NULL) {
+         return NGX_ERROR;
+     }
+@@ -2678,11 +2720,11 @@ ngx_resolver_create_addr_query(ngx_resol
+ 
+     p += sizeof(ngx_resolver_hdr_t);
+ 
+-    switch (ctx->addr.sockaddr->sa_family) {
++    switch (addr->sockaddr->sa_family) {
+ 
+ #if (NGX_HAVE_INET6)
+     case AF_INET6:
+-        sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
++        sin6 = (struct sockaddr_in6 *) addr->sockaddr;
+ 
+         for (n = 15; n >= 0; n--) {
+             p = ngx_sprintf(p, "\1%xd\1%xd",
+@@ -2697,11 +2739,11 @@ ngx_resolver_create_addr_query(ngx_resol
+ 
+     default: /* AF_INET */
+ 
+-        sin = (struct sockaddr_in *) ctx->addr.sockaddr;
+-        addr = ntohl(sin->sin_addr.s_addr);
++        sin = (struct sockaddr_in *) addr->sockaddr;
++        inaddr = ntohl(sin->sin_addr.s_addr);
+ 
+         for (n = 0; n < 32; n += 8) {
+-            d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff);
++            d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff);
+             *p = (u_char) (d - &p[1]);
+             p = d;
+         }
+@@ -2815,21 +2857,13 @@ done:
+ static void
+ ngx_resolver_timeout_handler(ngx_event_t *ev)
+ {
+-    ngx_resolver_ctx_t   *ctx, *next;
+-    ngx_resolver_node_t  *rn;
++    ngx_resolver_ctx_t  *ctx;
+ 
+-    rn = ev->data;
+-    ctx = rn->waiting;
+-    rn->waiting = NULL;
++    ctx = ev->data;
+ 
+-    do {
+-        ctx->state = NGX_RESOLVE_TIMEDOUT;
+-        next = ctx->next;
+-
+-        ctx->handler(ctx);
++    ctx->state = NGX_RESOLVE_TIMEDOUT;
+ 
+-        ctx = next;
+-    } while (ctx);
++    ctx->handler(ctx);
+ }
+ 
+ 
+diff -upr nginx-1.9.7-old/src/core/ngx_resolver.h nginx-1.9.7/src/core/ngx_resolver.h
+--- nginx-1.9.7-old/src/core/ngx_resolver.h	2016-01-26 11:54:55.914404751 -0800
++++ nginx-1.9.7/src/core/ngx_resolver.h	2016-01-26 11:55:27.068784001 -0800
+@@ -51,15 +51,11 @@ typedef void (*ngx_resolver_handler_pt)(
+ 
+ 
+ typedef struct {
+-    /* PTR: resolved name, A: name to resolve */
+-    u_char                   *name;
+-
++    ngx_rbtree_node_t         node;
+     ngx_queue_t               queue;
+ 
+-    /* event ident must be after 3 pointers as in ngx_connection_t */
+-    ngx_int_t                 ident;
+-
+-    ngx_rbtree_node_t         node;
++    /* PTR: resolved name, A: name to resolve */
++    u_char                   *name;
+ 
+ #if (NGX_HAVE_INET6)
+     /* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */
+@@ -147,6 +143,9 @@ struct ngx_resolver_ctx_s {
+     ngx_resolver_t           *resolver;
+     ngx_udp_connection_t     *udp_connection;
+ 
++    /* event ident must be after 3 pointers as in ngx_connection_t */
++    ngx_int_t                 ident;
++
+     ngx_int_t                 state;
+     ngx_str_t                 name;
+ 
+@@ -162,6 +161,8 @@ struct ngx_resolver_ctx_s {
+     ngx_uint_t                quick;  /* unsigned  quick:1; */
+     ngx_uint_t                recursion;
+     ngx_event_t              *event;
++
++    ngx_resolver_node_t      *node;
+ };
+ 
+ 
diff --git a/util/mirror-tarballs b/util/mirror-tarballs
index 0889703..ef9eea9 100755
--- a/util/mirror-tarballs
+++ b/util/mirror-tarballs
@@ -293,6 +293,12 @@ if [ "$answer" = "N" ]; then
     echo
 fi
 
+if [ "$main_ver" = "1.9.7" ]; then
+    echo "$info_txt applying the resolver_security_fixes patch for nginx"
+    patch -p1 < $root/patches/nginx-$main_ver-resolver_security_fixes.patch || exit 1
+    echo
+fi
+
 rm -f *.patch || exit 1
 
 echo "$info_txt applying the always_enable_cc_feature_tests patch to nginx"
diff --git a/util/ver b/util/ver
index 9359af9..ee48471 100755
--- a/util/ver
+++ b/util/ver
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 main_ver=1.9.7
-minor_ver=2
+minor_ver=3rc1
 version=$main_ver.$minor_ver
 echo $version