diff --git a/Makefile.am b/Makefile.am
index 4310f2c..2700edc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -332,6 +332,7 @@ wireshark_LDADD = \
 	@PCAP_LIBS@			\
 	@GTK_LIBS@			\
 	@C_ARES_LIBS@			\
+	@UNBOUND_LIBS@			\
 	@ADNS_LIBS@			\
 	@KRB5_LIBS@			\
 	@FRAMEWORKS@			\
@@ -363,6 +364,7 @@ tshark_LDADD = \
 	@SOCKET_LIBS@			\
 	@NSL_LIBS@			\
 	@C_ARES_LIBS@			\
+	@UNBOUND_LIBS@			\
 	@ADNS_LIBS@			\
 	@KRB5_LIBS@			\
 	@FRAMEWORKS@			\
@@ -393,6 +395,7 @@ rawshark_LDADD = \
 	@SOCKET_LIBS@			\
 	@NSL_LIBS@			\
 	@C_ARES_LIBS@			\
+	@UNBOUND_LIBS@			\
 	@ADNS_LIBS@			\
 	@KRB5_LIBS@			\
 	@FRAMEWORKS@			\
@@ -447,6 +450,7 @@ randpkt_LDADD = \
 	@SOCKET_LIBS@			\
 	@NSL_LIBS@			\
 	@C_ARES_LIBS@			\
+	@UNBOUND_LIBS@			\
 	@ADNS_LIBS@
 randpkt_CFLAGS = $(AM_CLEAN_CFLAGS) $(py_dissectors_dir)
 
@@ -464,6 +468,7 @@ dftest_LDADD = \
 	@SOCKET_LIBS@			\
 	@NSL_LIBS@			\
 	@C_ARES_LIBS@			\
+	@UNBOUND_LIBS@			\
 	@ADNS_LIBS@			\
 	@KRB5_LIBS@			\
 	@LIBGCRYPT_LIBS@		\
diff --git a/acinclude.m4 b/acinclude.m4
index 489cd81..b91beb3 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -1295,6 +1295,36 @@ AC_DEFUN([AC_WIRESHARK_C_ARES_CHECK],
 
 
 #
+# AC_WIRESHARK_UNBOUND_CHECK
+#
+AC_DEFUN([AC_WIRESHARK_UNBOUND_CHECK],
+[
+	want_unbound=defaultyes
+
+	if test "x$want_unbound" = "xdefaultyes"; then
+		want_unbound=yes
+		if test "x$ac_cv_enable_usr_local" = "xyes" ; then
+			withval=/usr/local
+			if test -d "$withval"; then
+				AC_WIRESHARK_ADD_DASH_L(LDFLAGS, ${withval}/lib)
+			fi
+		fi
+	fi
+
+	if test "x$want_unbound" = "xyes"; then
+		AC_CHECK_LIB(unbound, ub_ctx_create,
+		  [
+		    UNBOUND_LIBS=-lunbound
+		    AC_DEFINE(HAVE_UNBOUND, 1, [Define to use unbound library])
+		have_good_unbound=yes
+		  ],, $SOCKET_LIBS $NSL_LIBS
+		)
+	else
+		AC_MSG_RESULT(not required)
+	fi
+])
+
+#
 # AC_WIRESHARK_ADNS_CHECK
 #
 AC_DEFUN([AC_WIRESHARK_ADNS_CHECK],
diff --git a/config.h.win32 b/config.h.win32
index 5b04308..60d6555 100644
--- a/config.h.win32
+++ b/config.h.win32
@@ -208,7 +208,10 @@
 /* Define if you have the z library (-lz).  */
 @HAVE_LIBZ@
 
-/* Define to use GNU ADNS library */
+/* Define to use UNBOUND library */
+@HAVE_UNBOUND@
+
+/* Define to use C-ARES library */
 @HAVE_C_ARES@
 
 /* Define to use GNU ADNS library */
diff --git a/configure.in b/configure.in
index aa235d1..4af28bd 100644
--- a/configure.in
+++ b/configure.in
@@ -1289,10 +1289,33 @@ else
 fi
 
 
+dnl unbound Check
+UNBOUND_LIBS=''
+AC_MSG_CHECKING(whether to use the unbound library if available)
+AC_ARG_WITH(unbound,
+  AC_HELP_STRING( [--with-unbound@<:@=DIR@:>@],
+                  [use unbound (located in directory DIR, if supplied). Supersedes both --with-adns and --with-c-ares.   @<:@default=yes, if present@:>@]),
+[
+if   test "x$withval" = "xno";  then
+        want_unbound=no
+elif test "x$withval" = "xyes"; then
+        want_unbound=yes
+elif test -d "$withval"; then
+        want_unbound=yes
+        AC_WIRESHARK_ADD_DASH_L(LDFLAGS, ${withval}/lib)
+fi
+])
+if test "x$want_unbound" = "xno" ; then
+        AC_MSG_RESULT(no)
+else
+        AC_MSG_RESULT(yes)
+        AC_WIRESHARK_UNBOUND_CHECK
+fi
+AC_SUBST(UNBOUND_LIBS)
+
 dnl c-ares Check
 C_ARES_LIBS=''
 AC_MSG_CHECKING(whether to use the c-ares library if available)
-
 AC_ARG_WITH(c-ares,
   AC_HELP_STRING( [--with-c-ares@<:@=DIR@:>@],
                   [use c-ares (located in directory DIR, if supplied). Supersedes --with-adns.   @<:@default=yes, if present@:>@]),
@@ -1306,7 +1329,7 @@ elif test -d "$withval"; then
 	AC_WIRESHARK_ADD_DASH_L(LDFLAGS, ${withval}/lib)
 fi
 ])
-if test "x$want_c_ares" = "xno" ; then
+if test "x$want_c_ares" = "xno" -o "x$have_good_unbound" = "xyes" ; then
 	AC_MSG_RESULT(no)
 else
 	AC_MSG_RESULT(yes)
@@ -1331,7 +1354,7 @@ elif test -d "$withval"; then
 	AC_WIRESHARK_ADD_DASH_L(LDFLAGS, ${withval}/lib)
 fi
 ])
-if test "x$want_adns" = "xno" -o "x$have_good_c_ares" = "xyes" ; then
+if test "x$want_adns" = "xno" -o "x$have_good_c_ares" = "xyes" -o "x$have_good_unbound" = "xyes" ; then
 	AC_MSG_RESULT(no)
 else
 	AC_MSG_RESULT(yes)
@@ -1813,6 +1836,12 @@ else
 	krb5_message="yes ($ac_krb5_version)"
 fi
 
+if test "x$have_good_unbound" = "xyes" ; then
+	unbound_message="yes"
+else
+	unbound_message="no"
+fi
+
 if test "x$have_good_c_ares" = "xyes" ; then
 	c_ares_message="yes"
 else
@@ -1862,6 +1891,7 @@ echo "                   Use pcap library : $want_pcap"
 echo "                   Use zlib library : $zlib_message"
 echo "                   Use pcre library : $pcre_message"
 echo "               Use kerberos library : $krb5_message"
+echo "                Use unbound library : $unbound_message"
 echo "                 Use c-ares library : $c_ares_message"
 echo "               Use GNU ADNS library : $adns_message"
 echo "                Use SMI MIB library : $libsmi_message"
diff --git a/epan/Makefile.am b/epan/Makefile.am
index 68fbc1a..738806b 100644
--- a/epan/Makefile.am
+++ b/epan/Makefile.am
@@ -140,7 +140,7 @@ libwireshark_la_LIBADD = \
 	ftypes/libftypes.la dfilter/libdfilter.la dissectors/libdissectors.la \
 	dissectors/libdirtydissectors.la $(wslua_lib) $(wspython_lib) @SOCKET_LIBS@ @NSL_LIBS@ \
 	@C_ARES_LIBS@ @ADNS_LIBS@ @LIBGCRYPT_LIBS@ @LIBGNUTLS_LIBS@ \
-	@KRB5_LIBS@ @SSL_LIBS@ @LIBSMI_LDFLAGS@ @GEOIP_LIBS@ \
+	@KRB5_LIBS@ @SSL_LIBS@ @LIBSMI_LDFLAGS@ @GEOIP_LIBS@ @UNBOUND_LIBS@ \
 	${top_builddir}/wiretap/libwiretap.la @GLIB_LIBS@ \
 	${top_builddir}/wsutil/libwsutil.la -lm
 
diff --git a/epan/Makefile.nmake b/epan/Makefile.nmake
index 17b1432..e53ac47 100644
--- a/epan/Makefile.nmake
+++ b/epan/Makefile.nmake
@@ -13,8 +13,8 @@ LINK= link
 
 # We use GENERATED_CFLAGS to get around flex's non-LLP64-compliant output
 GENERATED_CFLAGS=-DHAVE_CONFIG_H /I. /I.. /I../wiretap $(GLIB_CFLAGS) \
-	$(ZLIB_CFLAGS) $(C_ARES_CFLAGS) $(ADNS_CFLAGS) $(PCRE_CFLAGS) \
-	$(GNUTLS_CFLAGS) /I$(PCAP_DIR)\include \
+	$(ZLIB_CFLAGS) $(UNBOUND_CFLAGS) $(C_ARES_CFLAGS) $(ADNS_CFLAGS) \
+	$(PCRE_CFLAGS) $(GNUTLS_CFLAGS) /I$(PCAP_DIR)\include \
 	$(SMI_CFLAGS) $(GEOIP_CFLAGS) -D_U_="" $(LOCAL_CFLAGS)
 CFLAGS=-WX $(GENERATED_CFLAGS)
 
@@ -31,6 +31,7 @@ WSLUA_DIR=
 # For use when making libwireshark.dll
 libwireshark_LIBS = \
 	$(GLIB_LIBS)	\
+	$(UNBOUND_LIBS) \
 	$(C_ARES_LIBS) \
 	$(ADNS_LIBS) \
 	$(PCRE_LIBS) \
diff --git a/epan/addr_resolv.c b/epan/addr_resolv.c
index e1ea4c1..0906609 100644
--- a/epan/addr_resolv.c
+++ b/epan/addr_resolv.c
@@ -118,6 +118,11 @@
 #  if defined(inet_aton) && defined(_WIN32)
 #   undef inet_aton
 #  endif
+#else
+# ifdef HAVE_UNBOUND
+#  include <unbound.h>
+#  include <arpa/nameser.h>
+# endif	/* HAVE_UNBOUND */
 # endif	/* HAVE_GNU_ADNS */
 #endif	/* HAVE_C_ARES */
 
@@ -341,6 +346,24 @@ typedef struct _adns_queue_msg
 #endif /* HAVE_GNU_ADNS */
 #endif /* HAVE_C_ARES */
 
+#ifdef HAVE_UNBOUND
+
+static gboolean unbound_initialized = FALSE;
+struct ub_ctx* context;
+int unbound_in_flight = 0;
+GList *unbound_queue_head = NULL;
+
+typedef struct _unbound_queue_msg
+{
+  union {
+    guint32           ip4;
+    struct e_in6_addr ip6;
+  } addr;
+  int                 family;
+} unbound_queue_msg_t;
+
+#endif /* HAVE_UNBOUND */
+
 typedef struct {
     guint32 mask;
     gsize mask_length;
@@ -717,6 +740,9 @@ static gchar *host_name_lookup(guint addr, gboolean *found)
   adns_queue_msg_t *qmsg;
 #endif /* HAVE_GNU_ADNS */
 #endif /* HAVE_C_ARES */
+#ifdef HAVE_UNBOUND
+  unbound_queue_msg_t *qmsg;
+#endif /* HAVE_UNBOUND */
 
   *found = TRUE;
 
@@ -781,6 +807,23 @@ static gchar *host_name_lookup(guint addr, gboolean *found)
 #endif /* HAVE_GNU_ADNS */
 #endif /* HAVE_C_ARES */
 
+#ifdef HAVE_UNBOUND
+  if ((g_resolv_flags & RESOLV_CONCURRENT) &&
+      prefs.name_resolve_concurrency > 0 &&
+      unbound_initialized) {
+    qmsg = g_malloc(sizeof(unbound_queue_msg_t));
+    qmsg->family = AF_INET;
+    qmsg->addr.ip4 = addr;
+    unbound_queue_head = g_list_append(unbound_queue_head, (gpointer) qmsg);
+
+    /* XXX found is set to TRUE, which seems a bit odd, but I'm not
+     * going to risk changing the semantics.
+     */
+    fill_dummy_ip4(addr, tp);
+    return tp->name;
+  }
+#endif /* HAVE_UNBOUND */
+
   /*
    * The Windows "gethostbyaddr()" insists on translating 0.0.0.0 to
    * the name of the host on which it's running; to work around that
@@ -834,6 +877,9 @@ static gchar *host_name_lookup6(struct e_in6_addr *addr, gboolean *found)
 #ifdef HAVE_C_ARES
   c_ares_queue_msg_t *caqm;
 #endif /* HAVE_C_ARES */
+#ifdef HAVE_UNBOUND
+  unbound_queue_msg_t *ubqm;
+#endif /* HAVE_UNBOUND */
 #ifdef INET6
   struct hostent *hostp;
 #endif
@@ -883,6 +929,23 @@ static gchar *host_name_lookup6(struct e_in6_addr *addr, gboolean *found)
     return tp->name;
   }
 #endif /* HAVE_C_ARES */
+#ifdef HAVE_UNBOUND
+  if ((g_resolv_flags & RESOLV_CONCURRENT) &&
+      prefs.name_resolve_concurrency > 0 &&
+      unbound_initialized) {
+    ubqm = g_malloc(sizeof(unbound_queue_msg_t));
+    ubqm->family = AF_INET6;
+    memcpy(&ubqm->addr.ip6, addr, sizeof(ubqm->addr.ip6));
+    unbound_queue_head = g_list_append(unbound_queue_head, (gpointer) ubqm);
+
+    /* XXX found is set to TRUE, which seems a bit odd, but I'm not
+     * going to risk changing the semantics.
+     */
+    ip6_to_str_buf(addr, tp->name);
+    tp->is_dummy_entry = TRUE;
+    return tp->name;
+  }
+#endif /* HAVE_UNBOUND */
 
 #ifdef INET6
   if (g_resolv_flags & RESOLV_NETWORK) {
@@ -2244,6 +2307,22 @@ host_name_lookup_init(void) {
   }
   g_free(hostspath);
 
+#ifdef HAVE_UNBOUND
+  if ((context=ub_ctx_create())!=NULL) 
+    {
+    int retval=0;
+    unbound_initialized = TRUE;
+    if((retval=ub_ctx_resolvconf(context, NULL))!=0)
+      report_failure("Unbound failure: %s\n", ub_strerror(retval));
+    if((retval=ub_ctx_hosts(context, NULL))!=0)
+      report_failure("Unbound failure: %s\n", ub_strerror(retval));
+    if((retval=ub_ctx_async(context, TRUE))!=0)
+      report_failure("Unbound async context failure: %s\n", ub_strerror(retval));
+    } else
+    unbound_initialized = FALSE;
+
+#endif /* HAVE_UNBOUND */
+
 #ifdef HAVE_C_ARES
   if (ares_init(&alchan) == ARES_SUCCESS) {
     c_ares_initialized = TRUE;
@@ -2366,8 +2445,6 @@ gboolean
 host_name_lookup_process(gpointer data _U_) {
   adns_queue_msg_t *almsg;
   GList *cur;
-  char addr_str[] = "111.222.333.444.in-addr.arpa.";
-  guint8 *addr_bytes;
   adns_answer *ans;
   int ret;
   gboolean dequeue;
@@ -2378,11 +2455,9 @@ host_name_lookup_process(gpointer data _U_) {
   while (cur && adns_in_flight <= prefs.name_resolve_concurrency) {
     almsg = (adns_queue_msg_t *) cur->data;
     if (! almsg->submitted && almsg->type == AF_INET) {
-      addr_bytes = (guint8 *) &almsg->ip4_addr;
-      g_snprintf(addr_str, sizeof addr_str, "%u.%u.%u.%u.in-addr.arpa.", addr_bytes[3],
-          addr_bytes[2], addr_bytes[1], addr_bytes[0]);
-      /* XXX - what if it fails? */
-      adns_submit (ads, addr_str, adns_r_ptr, 0, NULL, &almsg->query);
+      /* XXX - ip_to_ptr_str not assumed to safely success */
+      adns_submit (ads, (char *) ip_to_ptr_str((guint8 *) &(almsg->ip4_addr)),
+		    adns_r_ptr, 0, NULL, &almsg->query);
       almsg->submitted = TRUE;
       adns_in_flight++;
     }
@@ -2430,8 +2505,9 @@ host_name_lookup_cleanup(void) {
   gnu_adns_initialized = FALSE;
 }
 
-#else /* HAVE_GNU_ADNS */
+#endif /* HAVE_C_ARES */
 
+#ifndef HAVE_UNBOUND
 gboolean
 host_name_lookup_process(gpointer data _U_) {
   /* Kill the timeout, as there's nothing for it to do */
@@ -2442,7 +2518,89 @@ void
 host_name_lookup_cleanup(void) {
 }
 
-#endif /* HAVE_C_ARES */
+#endif /* HAVE_UNBOUND */
+
+
+#ifdef HAVE_UNBOUND
+
+static void unbound_cb(void* ubqm, int err,
+                                struct ub_result* result)
+{
+  unbound_queue_msg_t * query = ubqm;
+  
+  if(err != 0) 
+    {
+    report_failure("Unbound resolve error: %s\n", ub_strerror(err));
+    return;
+    }
+
+  if(result->havedata)
+    {
+    char dst[NS_MAXDNAME];
+    ns_name_ntop((u_char *) result->data[0], dst, sizeof(dst));
+    if(query->family == AF_INET)
+      add_ipv4_name(query->addr.ip4, (const gchar *) dst);
+    else if(query->family == AF_INET6)
+      add_ipv6_name(&(query->addr.ip6), (const gchar *) dst);
+    }
+      
+  unbound_queue_head = g_list_remove(unbound_queue_head, ubqm);
+  unbound_in_flight--;
+  return;
+}
+
+gboolean
+host_name_lookup_process(gpointer data _U_) {
+  unbound_queue_msg_t *ubqm;
+
+  if (!unbound_initialized || !context)
+    /* unbound not initialized. Bail out and cancel timers. */
+    return FALSE;
+  else
+    ub_process(context);
+  
+  unbound_queue_head = g_list_first(unbound_queue_head);
+  while (unbound_queue_head && unbound_in_flight <= prefs.name_resolve_concurrency) {
+    ubqm = (unbound_queue_msg_t *) unbound_queue_head->data;
+    unbound_queue_head = g_list_remove(unbound_queue_head, (void *) ubqm);
+    if (ubqm->family == AF_INET) {
+	ub_resolve_async(context, 
+			(char *) ip_to_ptr_str((guint8 *) &(ubqm->addr.ip4)),
+                        12, /* type PTR */
+			1, /* class IN (Internet) */
+                        (void*) ubqm, unbound_cb, NULL);
+      unbound_in_flight++;
+    } else if (ubqm->family == AF_INET6) {
+	ub_resolve_async(context, (char *) ip6_to_ptr_str(&(ubqm->addr.ip6)),
+                        12, /* type PTR */
+			1, /* class IN (Internet) */
+                        (void*) ubqm, unbound_cb, NULL);
+      unbound_in_flight++;
+    }
+  }
+
+  /* Keep the timeout in place */
+  return TRUE;
+}
+
+void
+host_name_lookup_cleanup(void) {
+  GList *cur;
+
+  cur = g_list_first(unbound_queue_head);
+  while (cur) {
+    g_free(cur->data);
+    cur = g_list_next (cur);
+  }
+
+  g_list_free(unbound_queue_head);
+
+  if (unbound_initialized)
+    ub_ctx_delete(context);
+  unbound_initialized = FALSE;
+}
+
+#endif /* HAVE_UNBOUND */
 
 extern const gchar *get_hostname(guint addr)
 {
diff --git a/epan/to_str.c b/epan/to_str.c
index 3769fb1..0e529ad 100644
--- a/epan/to_str.c
+++ b/epan/to_str.c
@@ -149,6 +149,22 @@ ip_to_str(const guint8 *ad) {
 }
 
 /*
+ Given an IPv4 address, return the PTR to be used for reverse DNS
+ queries, eg. 111.222.333.444 -> 444.333.222.111.in-addr.arpa.
+*/
+const gchar *
+ip_to_ptr_str(const guint8 *ad) {
+/* IPV4LEN + SUFFIX = 29 */
+#define MAXIP4RNAME 29
+  gchar *buf;
+  buf=ep_alloc(MAXIP4RNAME+1);
+  g_snprintf(buf, MAXIP4RNAME+1, "%u.%u.%u.%u.in-addr.arpa.", ad[3],
+          ad[2], ad[1], ad[0]);
+
+  return buf;
+}
+
+/*
  This function is very fast and this function is called a lot.
  XXX update the address_to_str stuff to use this function.
 */
@@ -249,6 +265,30 @@ ip6_to_str_buf(const struct e_in6_addr *ad, gchar *buf)
   inet_ntop(AF_INET6, (const guchar*)ad, buf, INET6_ADDRSTRLEN);
 }
 
+gchar *
+ip6_to_ptr_str(const struct e_in6_addr *ad) {
+#ifndef IN6ADDRSZ
+#define IN6ADDRSZ 16
+#endif
+/* IP6DOTTED + SUFFIX = 73 */
+#define MAXIP6RNAME 73
+  static gchar *str, *buf;
+  int n;
+
+  str=ep_alloc(MAXIP6RNAME+1);
+  buf=str;
+  for (n = IN6ADDRSZ - 1; n >= 0; n--)
+    {
+    buf += sprintf(buf, "%x.%x.",
+			ad->bytes[n] & 0xf,
+			(ad->bytes[n] >> 4) & 0xf);
+    }
+  strcpy(buf, "ip6.arpa.\0");
+
+  return str;
+}
+
+
 gchar*
 ipx_addr_to_str(guint32 net, const guint8 *ad)
 {
diff --git a/epan/to_str.h b/epan/to_str.h
index 9b054c8..a53e931 100644
--- a/epan/to_str.h
+++ b/epan/to_str.h
@@ -59,10 +59,12 @@ extern void     address_to_str_buf(const address *addr, gchar *buf, int buf_len)
 extern gchar*   bytestring_to_str(const guint8 *, guint32, char);
 extern gchar*	ether_to_str(const guint8 *);
 extern const gchar*	ip_to_str(const guint8 *);
+extern const gchar*	ip_to_ptr_str(const guint8 *);
 extern void	ip_to_str_buf(const guint8 *ad, gchar *buf, int buf_len);
 extern gchar*	fc_to_str(const guint8 *);
 extern gchar*	fcwwn_to_str (const guint8 *);
 extern gchar*	ip6_to_str(const struct e_in6_addr *);
+extern gchar*	ip6_to_ptr_str(const struct e_in6_addr *);
 extern void	ip6_to_str_buf(const struct e_in6_addr *, gchar *);
 extern gchar*	ipx_addr_to_str(guint32, const guint8 *);
 extern gchar*	ipxnet_to_string(const guint8 *ad);
diff --git a/gtk/main.c b/gtk/main.c
index 1ac1b68..86dbeea 100644
--- a/gtk/main.c
+++ b/gtk/main.c
@@ -2182,7 +2182,7 @@ main(int argc, char *argv[])
   tap_update_timer_id = g_timeout_add(prefs->tap_update_interval, update_cb, NULL);
 #endif /* !_WIN32 && G_THREADS_ENABLED && USE_THREADS */
 
-#if HAVE_GNU_ADNS || HAVE_C_ARES
+#if HAVE_GNU_ADNS || HAVE_C_ARES || HAVE_UNBOUND
   g_timeout_add(750, host_name_lookup_process, NULL);
 #endif
 
diff --git a/version_info.c b/version_info.c
index ef7adda..09ad896 100644
--- a/version_info.c
+++ b/version_info.c
@@ -239,7 +239,11 @@ get_epan_compiled_version_info(GString *str)
 #ifdef HAVE_GNU_ADNS
 	g_string_append(str, "with ADNS");
 #else
-	g_string_append(str, "without ADNS");
+#ifdef HAVE_UNBOUND
+	g_string_append(str, "with Unbound");
+#else
+	g_string_append(str, "without ADNS and Unbound");
+#endif /* HAVE_UNBOUND */
 #endif /* HAVE_GNU_ADNS */
 #endif /* HAVE_C_ARES */
 
