diff --git a/.bind.metadata b/.bind.metadata
index 5e29fe2..9cfc411 100644
--- a/.bind.metadata
+++ b/.bind.metadata
@@ -1,2 +1,3 @@
 d7be390e6c2546f37a7280e1975e1cd134565f62 SOURCES/bind-9.9.4.tar.gz
-3320c2bd77776079111603b7d266cc7ce7dcbd28 SOURCES/config-13.tar.bz2
+096a128b9272f1f2bb22ad0dfe62df24455f6f67 SOURCES/config-14.tar.bz2
+d3c4943f2f2aa1f7c51487af02ff3a52ca51a6d9 SOURCES/geoip-testing-data.tar.xz
diff --git a/.gitignore b/.gitignore
index 800c33e..4a26baf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 SOURCES/bind-9.9.4.tar.gz
-SOURCES/config-13.tar.bz2
+SOURCES/config-14.tar.bz2
+SOURCES/geoip-testing-data.tar.xz
diff --git a/SOURCES/bind-9.5-sdb.patch b/SOURCES/bind-9.5-sdb.patch
index 99475e6..6af9818 100644
--- a/SOURCES/bind-9.5-sdb.patch
+++ b/SOURCES/bind-9.5-sdb.patch
@@ -1,6 +1,7 @@
-diff -up bind-9.9.4-P2/bin/Makefile.in.sdb bind-9.9.4-P2/bin/Makefile.in
---- bind-9.9.4-P2/bin/Makefile.in.sdb	2013-12-20 01:28:28.000000000 +0100
-+++ bind-9.9.4-P2/bin/Makefile.in	2014-07-22 10:29:23.940233449 +0200
+diff --git a/bin/Makefile.in b/bin/Makefile.in
+index 187ec23..e6179e7 100644
+--- a/bin/Makefile.in
++++ b/bin/Makefile.in
 @@ -19,8 +19,8 @@ srcdir =	@srcdir@
  VPATH =		@srcdir@
  top_srcdir =	@top_srcdir@
@@ -12,64 +13,66 @@ diff -up bind-9.9.4-P2/bin/Makefile.in.sdb bind-9.9.4-P2/bin/Makefile.in
  TARGETS =
  
  @BIND9_MAKE_RULES@
-diff -up bind-9.9.4-P2/bin/named/Makefile.in.sdb bind-9.9.4-P2/bin/named/Makefile.in
---- bind-9.9.4-P2/bin/named/Makefile.in.sdb	2014-07-22 10:29:23.873233351 +0200
-+++ bind-9.9.4-P2/bin/named/Makefile.in	2014-07-22 10:30:43.247348398 +0200
-@@ -52,7 +52,7 @@ CINCLUDES =	-I${srcdir}/include -I${srcd
- 		${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \
- 		${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@
- 
--CDEFINES =      @CONTRIB_DLZ@ @CRYPTO@
-+CDEFINES =      @CRYPTO@
- 
- CWARNINGS =
- 
-@@ -79,11 +79,11 @@ DEPLIBS =	${LWRESDEPLIBS} ${DNSDEPLIBS}
+diff --git a/bin/named-sdb/Makefile.in b/bin/named-sdb/Makefile.in
+index bc5be2a..71324d9 100644
+--- a/bin/named-sdb/Makefile.in
++++ b/bin/named-sdb/Makefile.in
+@@ -34,10 +34,10 @@ top_srcdir =	@top_srcdir@
+ #
+ # Add database drivers here.
+ #
+-DBDRIVER_OBJS =
+-DBDRIVER_SRCS =
++DBDRIVER_OBJS =	ldapdb.@O@ pgsqldb.@O@ dirdb.@O@
++DBDRIVER_SRCS =	ldapdb.c pgsqldb.c dirdb.c
+ DBDRIVER_INCLUDES =
+-DBDRIVER_LIBS =
++DBDRIVER_LIBS =	-lldap -llber -lpq
  
- LIBS =		${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
- 		${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \
--		${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@
-+		@LIBS@
+ DLZ_DRIVER_DIR =	${top_srcdir}/contrib/dlz/drivers
  
- NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
- 		${ISCCFGLIBS} ${ISCCCLIBS} ${ISCNOSYMLIBS} \
--		${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@
-+		@LIBS@
+@@ -83,7 +83,7 @@ NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
  
  SUBDIRS =	unix
  
-@@ -96,8 +96,7 @@ OBJS =		builtin.@O@ client.@O@ config.@O
- 		tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \
- 		zoneconf.@O@ \
- 		lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \
--		lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ \
--		${DLZDRIVER_OBJS} ${DBDRIVER_OBJS}
-+		lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@
- 
- UOBJS =		unix/os.@O@ unix/dlz_dlopen_driver.@O@
+-TARGETS =	named@EXEEXT@ lwresd@EXEEXT@
++TARGETS =	named-sdb@EXEEXT@
  
-@@ -110,8 +109,7 @@ SRCS =		builtin.c client.c config.c cont
- 		tkeyconf.c tsigconf.c update.c xfrout.c \
- 		zoneconf.c \
- 		lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \
--		lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c \
--		${DLZDRIVER_SRCS} ${DBDRIVER_SRCS}
-+		lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c
+ GEOIPLINKOBJS = geoip.@O@
  
- MANPAGES =	named.8 lwresd.8 named.conf.5
+@@ -146,7 +146,7 @@ config.@O@: config.c bind.keys.h
+ 		-DNS_SYSCONFDIR=\"${sysconfdir}\" \
+ 		-c ${srcdir}/config.c
  
-@@ -187,7 +185,5 @@ install:: named@EXEEXT@ lwresd@EXEEXT@ i
- 	${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8
- 	${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5
+-named@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS}
++named-sdb@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS}
+ 	export MAKE_SYMTABLE="yes"; \
+ 	export BASEOBJS="${OBJS} ${UOBJS}"; \
+ 	${FINALBUILDCMD}
+@@ -177,15 +177,9 @@ statschannel.@O@: bind9.xsl.h bind9.ver3.xsl.h
  
--@DLZ_DRIVER_RULES@
+ installdirs:
+ 	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir}
+-	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man5
+-	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8
 -
- named-symtbl.@O@: named-symtbl.c
- 	${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c named-symtbl.c
-diff -up bind-9.9.4-P2/bin/named-sdb/main.c.sdb bind-9.9.4-P2/bin/named-sdb/main.c
---- bind-9.9.4-P2/bin/named-sdb/main.c.sdb	2014-07-22 10:29:23.919233417 +0200
-+++ bind-9.9.4-P2/bin/named-sdb/main.c	2014-07-22 10:29:23.940233449 +0200
-@@ -83,6 +83,9 @@
+-install:: named@EXEEXT@ lwresd@EXEEXT@ installdirs
+-	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named@EXEEXT@ ${DESTDIR}${sbindir}
+-	(cd ${DESTDIR}${sbindir}; rm -f lwresd@EXEEXT@; @LN@ named@EXEEXT@ lwresd@EXEEXT@)
+-	${INSTALL_DATA} ${srcdir}/named.8 ${DESTDIR}${mandir}/man8
+-	${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8
+-	${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5
++
++install:: named-sdb@EXEEXT@ installdirs
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-sdb@EXEEXT@ ${DESTDIR}${sbindir}
+ 
+ @DLZ_DRIVER_RULES@
+ 
+diff --git a/bin/named-sdb/main.c b/bin/named-sdb/main.c
+index a00687f..4fba625 100644
+--- a/bin/named-sdb/main.c
++++ b/bin/named-sdb/main.c
+@@ -86,6 +86,9 @@
   * Include header files for database drivers here.
   */
  /* #include "xxdb.h" */
@@ -79,7 +82,7 @@ diff -up bind-9.9.4-P2/bin/named-sdb/main.c.sdb bind-9.9.4-P2/bin/named-sdb/main
  
  #ifdef CONTRIB_DLZ
  /*
-@@ -814,6 +817,10 @@ setup(void) {
+@@ -817,6 +820,10 @@ setup(void) {
  		ns_main_earlyfatal("isc_app_start() failed: %s",
  				   isc_result_totext(result));
  
@@ -90,7 +93,7 @@ diff -up bind-9.9.4-P2/bin/named-sdb/main.c.sdb bind-9.9.4-P2/bin/named-sdb/main
  	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
  		      ISC_LOG_NOTICE, "starting %s %s%s", ns_g_product,
  		      ns_g_version, saved_command_line);
-@@ -926,6 +933,57 @@ setup(void) {
+@@ -929,6 +936,57 @@ setup(void) {
  				   isc_result_totext(result));
  #endif
  
@@ -148,7 +151,7 @@ diff -up bind-9.9.4-P2/bin/named-sdb/main.c.sdb bind-9.9.4-P2/bin/named-sdb/main
  	ns_server_create(ns_g_mctx, &ns_g_server);
  }
  
-@@ -957,6 +1015,10 @@ cleanup(void) {
+@@ -960,6 +1018,10 @@ cleanup(void) {
  
  	dns_name_destroy();
  
@@ -159,63 +162,66 @@ diff -up bind-9.9.4-P2/bin/named-sdb/main.c.sdb bind-9.9.4-P2/bin/named-sdb/main
  	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
  		      ISC_LOG_NOTICE, "exiting");
  	ns_log_shutdown();
-diff -up bind-9.9.4-P2/bin/named-sdb/Makefile.in.sdb bind-9.9.4-P2/bin/named-sdb/Makefile.in
---- bind-9.9.4-P2/bin/named-sdb/Makefile.in.sdb	2014-07-22 10:29:23.917233415 +0200
-+++ bind-9.9.4-P2/bin/named-sdb/Makefile.in	2014-07-22 10:29:23.941233449 +0200
-@@ -34,10 +34,10 @@ top_srcdir =	@top_srcdir@
- #
- # Add database drivers here.
- #
--DBDRIVER_OBJS =
--DBDRIVER_SRCS =
-+DBDRIVER_OBJS =	ldapdb.@O@ pgsqldb.@O@ dirdb.@O@
-+DBDRIVER_SRCS =	ldapdb.c pgsqldb.c dirdb.c
- DBDRIVER_INCLUDES =
--DBDRIVER_LIBS =
-+DBDRIVER_LIBS =	-lldap -llber -lpq
+diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in
+index bc5be2a..3c69c9b 100644
+--- a/bin/named/Makefile.in
++++ b/bin/named/Makefile.in
+@@ -51,7 +51,7 @@ CINCLUDES =	-I${srcdir}/include -I${srcdir}/unix/include -I. \
+ 		${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \
+ 		${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@
  
- DLZ_DRIVER_DIR =	${top_srcdir}/contrib/dlz/drivers
+-CDEFINES =      @CONTRIB_DLZ@ @CRYPTO@
++CDEFINES =      @CRYPTO@
  
-@@ -87,7 +87,7 @@ NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BI
+ CWARNINGS =
  
- SUBDIRS =	unix
+@@ -75,11 +75,11 @@ DEPLIBS =	${LWRESDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \
  
--TARGETS =	named@EXEEXT@ lwresd@EXEEXT@
-+TARGETS =	named-sdb@EXEEXT@
+ LIBS =		${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
+ 		${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \
+-		${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@
++		@LIBS@
  
- OBJS =		builtin.@O@ client.@O@ config.@O@ control.@O@ \
- 		controlconf.@O@ interfacemgr.@O@ \
-@@ -146,7 +146,7 @@ config.@O@: config.c bind.keys.h
- 		-DNS_SYSCONFDIR=\"${sysconfdir}\" \
- 		-c ${srcdir}/config.c
+ NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
+ 		${ISCCFGLIBS} ${ISCCCLIBS} ${ISCNOSYMLIBS} \
+-		${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@
++		@LIBS@
  
--named@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS}
-+named-sdb@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS}
- 	export MAKE_SYMTABLE="yes"; \
- 	export BASEOBJS="${OBJS} ${UOBJS}"; \
- 	${FINALBUILDCMD}
-@@ -177,15 +177,9 @@ statschannel.@O@: bind9.xsl.h bind9.ver3
+ SUBDIRS =	unix
  
- installdirs:
- 	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir}
--	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man5
--	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8
+@@ -94,8 +94,7 @@ OBJS =		builtin.@O@ client.@O@ config.@O@ control.@O@ \
+ 		tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \
+ 		zoneconf.@O@ \
+ 		lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \
+-		lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ \
+-		${DLZDRIVER_OBJS} ${DBDRIVER_OBJS}
++		lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@
  
--install:: named@EXEEXT@ lwresd@EXEEXT@ installdirs
--	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named@EXEEXT@ ${DESTDIR}${sbindir}
--	(cd ${DESTDIR}${sbindir}; rm -f lwresd@EXEEXT@; @LN@ named@EXEEXT@ lwresd@EXEEXT@)
--	${INSTALL_DATA} ${srcdir}/named.8 ${DESTDIR}${mandir}/man8
--	${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8
--	${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5
-+install:: named-sdb@EXEEXT@ installdirs
-+	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-sdb@EXEEXT@ ${DESTDIR}${sbindir}
+ UOBJS =		unix/os.@O@ unix/dlz_dlopen_driver.@O@
  
- @DLZ_DRIVER_RULES@
+@@ -110,8 +109,7 @@ SRCS =		builtin.c client.c config.c control.c \
+ 		tkeyconf.c tsigconf.c update.c xfrout.c \
+ 		zoneconf.c \
+ 		lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \
+-		lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c \
+-		${DLZDRIVER_SRCS} ${DBDRIVER_SRCS}
++		lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c
  
-diff -up bind-9.9.4-P2/configure.in.sdb bind-9.9.4-P2/configure.in
---- bind-9.9.4-P2/configure.in.sdb	2014-07-22 10:29:23.909233403 +0200
-+++ bind-9.9.4-P2/configure.in	2014-07-22 10:29:23.942233450 +0200
-@@ -3900,12 +3900,15 @@ AC_CONFIG_FILES([
+ MANPAGES =	named.8 lwresd.8 named.conf.5
+ 
+@@ -187,7 +185,5 @@ install:: named@EXEEXT@ lwresd@EXEEXT@ installdirs
+ 	${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8
+ 	${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5
+ 
+-@DLZ_DRIVER_RULES@
+-
+ named-symtbl.@O@: named-symtbl.c
+ 	${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c named-symtbl.c
+diff --git a/configure.in b/configure.in
+index 9bb9a2a..d72093f 100644
+--- a/configure.in
++++ b/configure.in
+@@ -4018,12 +4018,15 @@ AC_CONFIG_FILES([
  	bin/named-pkcs11/Makefile
  	bin/named-pkcs11/unix/Makefile
  	bin/named/unix/Makefile
diff --git a/SOURCES/bind-9.9-dist-native-pkcs11.patch b/SOURCES/bind-9.9-dist-native-pkcs11.patch
index f12312b..9e6f846 100644
--- a/SOURCES/bind-9.9-dist-native-pkcs11.patch
+++ b/SOURCES/bind-9.9-dist-native-pkcs11.patch
@@ -1,26 +1,3 @@
-From 28f61b8a12da4a8dd10dccaefe8e50fc8605b87e Mon Sep 17 00:00:00 2001
-From: Tomas Hozza <thozza@redhat.com>
-Date: Mon, 22 Sep 2014 16:44:29 +0200
-Subject: [PATCH] Distributing native PKCS#11 BIND and utils
-
-Signed-off-by: Tomas Hozza <thozza@redhat.com>
----
- bin/Makefile.in                   |  2 +-
- bin/dnssec-pkcs11/Makefile.in     | 40 +++++++++++------------
- bin/dnssec/Makefile.in            |  2 +-
- bin/named-pkcs11/Makefile.in      | 40 +++++++++--------------
- bin/named/Makefile.in             |  2 +-
- bin/pkcs11/Makefile.in            |  6 ++--
- configure.in                      | 68 +++++++++++++++++++++++++++++++--------
- lib/Makefile.in                   |  2 +-
- lib/dns-pkcs11/Makefile.in        | 24 +++++++-------
- lib/export/Makefile.in            |  2 +-
- lib/export/dns-pkcs11/Makefile.in | 26 +++++++--------
- lib/export/isc-pkcs11/Makefile.in | 18 +++++------
- lib/isc-pkcs11/Makefile.in        | 24 +++++++-------
- make/includes.in                  | 10 ++++++
- 14 files changed, 154 insertions(+), 112 deletions(-)
-
 diff --git a/bin/Makefile.in b/bin/Makefile.in
 index 87ca5b2..187ec23 100644
 --- a/bin/Makefile.in
@@ -157,7 +134,7 @@ index 64e1846..cfb5628 100644
  CWARNINGS =
  
 diff --git a/bin/named-pkcs11/Makefile.in b/bin/named-pkcs11/Makefile.in
-index cd65777..be791ca 100644
+index 3a54437..32c5242 100644
 --- a/bin/named-pkcs11/Makefile.in
 +++ b/bin/named-pkcs11/Makefile.in
 @@ -47,26 +47,26 @@ DLZDRIVER_INCLUDES =	@DLZ_DRIVER_INCLUDES@
@@ -211,9 +188,9 @@ index cd65777..be791ca 100644
 -TARGETS =	named@EXEEXT@ lwresd@EXEEXT@
 +TARGETS =	named-pkcs11@EXEEXT@
  
- OBJS =		builtin.@O@ client.@O@ config.@O@ control.@O@ \
- 		controlconf.@O@ interfacemgr.@O@ \
-@@ -92,8 +92,7 @@ OBJS =		builtin.@O@ client.@O@ config.@O@ control.@O@ \
+ GEOIPLINKOBJS = geoip.@O@
+ 
+@@ -94,8 +94,7 @@ OBJS =		builtin.@O@ client.@O@ config.@O@ control.@O@ \
  		tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \
  		zoneconf.@O@ \
  		lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \
@@ -223,7 +200,7 @@ index cd65777..be791ca 100644
  
  UOBJS =		unix/os.@O@ unix/dlz_dlopen_driver.@O@
  
-@@ -106,8 +105,7 @@ SRCS =		builtin.c client.c config.c control.c \
+@@ -110,8 +109,7 @@ SRCS =		builtin.c client.c config.c control.c \
  		tkeyconf.c tsigconf.c update.c xfrout.c \
  		zoneconf.c \
  		lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \
@@ -233,7 +210,7 @@ index cd65777..be791ca 100644
  
  MANPAGES =	named.8 lwresd.8 named.conf.5
  
-@@ -142,7 +140,7 @@ config.@O@: config.c bind.keys.h
+@@ -146,7 +144,7 @@ config.@O@: config.c bind.keys.h
  		-DNS_SYSCONFDIR=\"${sysconfdir}\" \
  		-c ${srcdir}/config.c
  
@@ -242,7 +219,7 @@ index cd65777..be791ca 100644
  	export MAKE_SYMTABLE="yes"; \
  	export BASEOBJS="${OBJS} ${UOBJS}"; \
  	${FINALBUILDCMD}
-@@ -173,15 +171,9 @@ statschannel.@O@: bind9.xsl.h bind9.ver3.xsl.h
+@@ -177,15 +175,9 @@ statschannel.@O@: bind9.xsl.h bind9.ver3.xsl.h
  
  installdirs:
  	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir}
@@ -262,7 +239,7 @@ index cd65777..be791ca 100644
  @DLZ_DRIVER_RULES@
  
 diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in
-index cd65777..a5d46b6 100644
+index 3a54437..bc5be2a 100644
 --- a/bin/named/Makefile.in
 +++ b/bin/named/Makefile.in
 @@ -51,7 +51,7 @@ CINCLUDES =	-I${srcdir}/include -I${srcdir}/unix/include -I. \
@@ -296,7 +273,7 @@ index 15d3fb5..32cc753 100644
  DEPLIBS =	${ISCDEPLIBS}
  
 diff --git a/configure.in b/configure.in
-index d4dc6fd..2fbcfcb 100644
+index 5b56172..9bb9a2a 100644
 --- a/configure.in
 +++ b/configure.in
 @@ -656,10 +656,10 @@ AC_ARG_WITH(pkcs11,
@@ -374,7 +351,7 @@ index d4dc6fd..2fbcfcb 100644
  AC_SUBST(PKCS11_ECDSA)
  AC_SUBST(PKCS11_GOST)
  AC_SUBST(PKCS11_TEST)
-@@ -1435,12 +1437,13 @@ AC_SUBST(USE_GSSAPI)
+@@ -1528,12 +1530,13 @@ AC_SUBST(USE_GSSAPI)
  AC_SUBST(DST_GSSAPI_INC)
  AC_SUBST(DNS_GSSAPI_LIBS)
  DNS_CRYPTO_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_LIBS"
@@ -389,7 +366,7 @@ index d4dc6fd..2fbcfcb 100644
  
  #
  # was --with-randomdev specified?
-@@ -3918,7 +3921,10 @@ AC_CONFIG_FILES([
+@@ -4010,7 +4013,10 @@ AC_CONFIG_FILES([
  	bin/confgen/unix/Makefile
  	bin/dig/Makefile
  	bin/dnssec/Makefile
@@ -400,7 +377,7 @@ index d4dc6fd..2fbcfcb 100644
  	bin/named/unix/Makefile
  	bin/nsupdate/Makefile
  	bin/pkcs11/Makefile
-@@ -3998,11 +4004,19 @@ AC_CONFIG_FILES([
+@@ -4091,11 +4097,19 @@ AC_CONFIG_FILES([
  	lib/dns/include/dns/Makefile
  	lib/dns/include/dst/Makefile
  	lib/dns/tests/Makefile
@@ -420,7 +397,7 @@ index d4dc6fd..2fbcfcb 100644
  	lib/export/irs/Makefile
  	lib/export/irs/include/Makefile
  	lib/export/irs/include/irs/Makefile
-@@ -4016,6 +4030,16 @@ AC_CONFIG_FILES([
+@@ -4109,6 +4123,16 @@ AC_CONFIG_FILES([
  	lib/export/isc/unix/Makefile
  	lib/export/isc/unix/include/Makefile
  	lib/export/isc/unix/include/isc/Makefile
@@ -437,7 +414,7 @@ index d4dc6fd..2fbcfcb 100644
  	lib/export/isccfg/Makefile
  	lib/export/isccfg/include/Makefile
  	lib/export/isccfg/include/isccfg/Makefile
-@@ -4044,6 +4068,24 @@ AC_CONFIG_FILES([
+@@ -4137,6 +4161,24 @@ AC_CONFIG_FILES([
  	lib/isc/unix/include/Makefile
  	lib/isc/unix/include/isc/Makefile
  	lib/isc/unix/include/pkcs11/Makefile
@@ -476,7 +453,7 @@ index 8dc1d38..8e48d5e 100644
  
  @BIND9_MAKE_RULES@
 diff --git a/lib/dns-pkcs11/Makefile.in b/lib/dns-pkcs11/Makefile.in
-index 41fac95..7d88424 100644
+index 0cc82f1..cb830db 100644
 --- a/lib/dns-pkcs11/Makefile.in
 +++ b/lib/dns-pkcs11/Makefile.in
 @@ -27,16 +27,16 @@ top_srcdir =	@top_srcdir@
@@ -500,7 +477,7 @@ index 41fac95..7d88424 100644
  
  LIBS =		@LIBS@
  
-@@ -132,27 +132,27 @@ dynamic_db.@O@: dynamic_db.c
+@@ -136,27 +136,27 @@ dynamic_db.@O@: dynamic_db.c
  	-DDYNDB_LIBDIR=\"@libdir@/bind/\" \
  	-c ${srcdir}/dynamic_db.c
  
@@ -535,7 +512,7 @@ index 41fac95..7d88424 100644
  	rm -f gen code.h include/dns/enumtype.h include/dns/enumclass.h
  	rm -f include/dns/rdatastruct.h
  
-@@ -182,7 +182,7 @@ code.h:	gen
+@@ -186,7 +186,7 @@ code.h:	gen
  	./gen -s ${srcdir} > code.h
  
  gen: gen.c
@@ -558,7 +535,7 @@ index 1fd7216..a8a1342 100644
  
  @BIND9_MAKE_RULES@
 diff --git a/lib/export/dns-pkcs11/Makefile.in b/lib/export/dns-pkcs11/Makefile.in
-index e10bf59..669509f 100644
+index 54e4e39..71c6b25 100644
 --- a/lib/export/dns-pkcs11/Makefile.in
 +++ b/lib/export/dns-pkcs11/Makefile.in
 @@ -15,7 +15,7 @@
@@ -592,7 +569,7 @@ index e10bf59..669509f 100644
  
  LIBS =		@LIBS@
  
-@@ -116,29 +116,29 @@ version.@O@: ${srcdir}/version.c
+@@ -114,29 +114,29 @@ version.@O@: ${srcdir}/version.c
  		-DLIBAGE=${LIBAGE} \
  		-c ${srcdir}/version.c
  
@@ -630,7 +607,7 @@ index e10bf59..669509f 100644
  	rm -f include/dns/rdatastruct.h
  
 diff --git a/lib/export/isc-pkcs11/Makefile.in b/lib/export/isc-pkcs11/Makefile.in
-index e12dffb..926e000 100644
+index a5f8bd0..7655a9b 100644
 --- a/lib/export/isc-pkcs11/Makefile.in
 +++ b/lib/export/isc-pkcs11/Makefile.in
 @@ -15,7 +15,7 @@
@@ -688,7 +665,7 @@ index e12dffb..926e000 100644
 -	rm -f libisc-export.@A@ libisc-export.la timestamp
 +	rm -f libisc-pkcs11-export.@A@ libisc-pkcs11-export.la timestamp
 diff --git a/lib/isc-pkcs11/Makefile.in b/lib/isc-pkcs11/Makefile.in
-index 801ab35..d326786 100644
+index df62ec9..d9f0107 100644
 --- a/lib/isc-pkcs11/Makefile.in
 +++ b/lib/isc-pkcs11/Makefile.in
 @@ -31,8 +31,8 @@ CINCLUDES =	-I${srcdir}/unix/include \
@@ -766,6 +743,3 @@ index f2f1b3f..639477c 100644
 +
 +DNS_PKCS11_INCLUDES = @BIND9_DNS_BUILDINCLUDE@ \
 +	-I${top_srcdir}/lib/dns-pkcs11/include
--- 
-1.9.3
-
diff --git a/SOURCES/bind99-automatic-interface-scanning-rh1294506.patch b/SOURCES/bind99-automatic-interface-scanning-rh1294506.patch
new file mode 100644
index 0000000..0aec0c5
--- /dev/null
+++ b/SOURCES/bind99-automatic-interface-scanning-rh1294506.patch
@@ -0,0 +1,685 @@
+From 5013230b31da1d94ce5682e5c5c38011da744971 Mon Sep 17 00:00:00 2001
+From: Tomas Hozza <thozza@redhat.com>
+Date: Wed, 11 May 2016 15:17:55 +0200
+Subject: [PATCH] Added support for automatic interface scan when new address
+ is assigned to any interface
+
+Signed-off-by: Tomas Hozza <thozza@redhat.com>
+---
+ bin/named/config.c                |   1 +
+ bin/named/control.c               |   3 +
+ bin/named/include/named/control.h |   1 +
+ bin/named/include/named/server.h  |   8 +++
+ bin/named/interfacemgr.c          | 144 ++++++++++++++++++++++++++++++++++++++
+ bin/named/named.conf.docbook      |   1 +
+ bin/named/server.c                |  31 +++++++-
+ bin/named/statschannel.c          |   5 ++
+ bin/rndc/rndc.c                   |   1 +
+ bin/rndc/rndc.docbook             |  12 ++++
+ config.h.in                       |  12 ++++
+ configure.in                      |   5 +-
+ doc/arm/Bv9ARM-book.xml           |  22 +++++-
+ lib/isc/include/isc/socket.h      |  10 ++-
+ lib/isc/unix/socket.c             |  59 ++++++++++++++++
+ lib/isccfg/namedconf.c            |   1 +
+ 16 files changed, 310 insertions(+), 6 deletions(-)
+
+diff --git a/bin/named/config.c b/bin/named/config.c
+index f6d0263..b43c0fc 100644
+--- a/bin/named/config.c
++++ b/bin/named/config.c
+@@ -52,6 +52,7 @@
+ /*% default configuration */
+ static char defaultconf[] = "\
+ options {\n\
++	automatic-interface-scan yes;\n\
+ #	blackhole {none;};\n"
+ #ifndef WIN32
+ "	coresize default;\n\
+diff --git a/bin/named/control.c b/bin/named/control.c
+index 06eadce..86fa691 100644
+--- a/bin/named/control.c
++++ b/bin/named/control.c
+@@ -185,6 +185,9 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
+ 		   command_compare(command, NS_COMMAND_THAW)) {
+ 		result = ns_server_freeze(ns_g_server, ISC_FALSE, command,
+ 					  text);
++	} else if (command_compare(command, NS_COMMAND_SCAN)) {
++		result = ISC_R_SUCCESS;
++		ns_server_scan_interfaces(ns_g_server);
+ 	} else if (command_compare(command, NS_COMMAND_SYNC)) {
+ 		result = ns_server_sync(ns_g_server, command, text);
+ 	} else if (command_compare(command, NS_COMMAND_RECURSING)) {
+diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h
+index d730a83..52ed583 100644
+--- a/bin/named/include/named/control.h
++++ b/bin/named/include/named/control.h
+@@ -59,6 +59,7 @@
+ #define NS_COMMAND_NULL		"null"
+ #define NS_COMMAND_NOTIFY	"notify"
+ #define NS_COMMAND_VALIDATION	"validation"
++#define NS_COMMAND_SCAN 	"scan"
+ #define NS_COMMAND_SIGN 	"sign"
+ #define NS_COMMAND_LOADKEYS 	"loadkeys"
+ #define NS_COMMAND_ADDZONE	"addzone"
+diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h
+index ff0bfd3..83622f4 100644
+--- a/bin/named/include/named/server.h
++++ b/bin/named/include/named/server.h
+@@ -37,6 +37,7 @@
+ #define NS_EVENTCLASS		ISC_EVENTCLASS(0x4E43)
+ #define NS_EVENT_RELOAD		(NS_EVENTCLASS + 0)
+ #define NS_EVENT_CLIENTCONTROL	(NS_EVENTCLASS + 1)
++#define NS_EVENT_IFSCAN		(NS_EVENTCLASS + 2)
+ 
+ /*%
+  * Name server state.  Better here than in lots of separate global variables.
+@@ -114,6 +115,7 @@ struct ns_server {
+ 	dns_name_t		*session_keyname;
+ 	unsigned int		session_keyalg;
+ 	isc_uint16_t		session_keybits;
++	isc_boolean_t		interface_auto;
+ };
+ 
+ #define NS_SERVER_MAGIC			ISC_MAGIC('S','V','E','R')
+@@ -201,6 +203,12 @@ ns_server_reloadwanted(ns_server_t *server);
+  */
+ 
+ void
++ns_server_scan_interfaces(ns_server_t *server);
++/*%<
++ * Trigger a interface scan.
++ */
++
++void
+ ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush);
+ /*%<
+  * Inform the server that the zones should be flushed to disk on shutdown.
+diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c
+index 4f6b0f3..a9aa4a4 100644
+--- a/bin/named/interfacemgr.c
++++ b/bin/named/interfacemgr.c
+@@ -33,6 +33,28 @@
+ #include <named/client.h>
+ #include <named/log.h>
+ #include <named/interfacemgr.h>
++#include <named/server.h>
++
++#ifdef HAVE_NET_ROUTE_H
++#include <net/route.h>
++#if defined(RTM_VERSION) && defined(RTM_NEWADDR) && defined(RTM_DELADDR)
++#define USE_ROUTE_SOCKET 1
++#define ROUTE_SOCKET_PROTOCOL PF_ROUTE
++#define MSGHDR rt_msghdr
++#define MSGTYPE rtm_type
++#endif
++#endif
++
++#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
++#include <linux/netlink.h>
++#include <linux/rtnetlink.h>
++#if defined(RTM_NEWADDR) && defined(RTM_DELADDR)
++#define USE_ROUTE_SOCKET 1
++#define ROUTE_SOCKET_PROTOCOL PF_NETLINK
++#define MSGHDR nlmsghdr
++#define MSGTYPE nlmsg_type
++#endif
++#endif
+ 
+ #define IFMGR_MAGIC			ISC_MAGIC('I', 'F', 'M', 'G')
+ #define NS_INTERFACEMGR_VALID(t)	ISC_MAGIC_VALID(t, IFMGR_MAGIC)
+@@ -55,6 +77,11 @@ struct ns_interfacemgr {
+ 	dns_aclenv_t		aclenv;		/*%< Localhost/localnets ACLs */
+ 	ISC_LIST(ns_interface_t) interfaces;	/*%< List of interfaces. */
+ 	ISC_LIST(isc_sockaddr_t) listenon;
++#ifdef USE_ROUTE_SOCKET
++	isc_task_t *		task;
++	isc_socket_t *		route;
++	unsigned char		buf[2048];
++#endif
+ };
+ 
+ static void
+@@ -63,6 +90,71 @@ purge_old_interfaces(ns_interfacemgr_t *mgr);
+ static void
+ clearlistenon(ns_interfacemgr_t *mgr);
+ 
++#ifdef USE_ROUTE_SOCKET
++static void
++route_event(isc_task_t *task, isc_event_t *event) {
++	isc_socketevent_t *sevent = NULL;
++	ns_interfacemgr_t *mgr = NULL;
++	isc_region_t r;
++	isc_result_t result;
++	struct MSGHDR *rtm;
++
++	UNUSED(task);
++
++	REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
++	mgr = event->ev_arg;
++	sevent = (isc_socketevent_t *)event;
++
++	if (sevent->result != ISC_R_SUCCESS) {
++		if (sevent->result != ISC_R_CANCELED)
++			isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
++				      "automatic interface scanning "
++				      "terminated: %s",
++				      isc_result_totext(sevent->result));
++		ns_interfacemgr_detach(&mgr);
++		isc_event_free(&event);
++		return;
++	}
++
++	rtm = (struct MSGHDR *)mgr->buf;
++#ifdef RTM_VERSION
++	if (rtm->rtm_version != RTM_VERSION) {
++		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
++			      "automatic interface rescanning disabled: "
++			      "rtm->rtm_version mismatch (%u != %u) "
++			      "recompile required", rtm->rtm_version,
++			      RTM_VERSION);
++		isc_task_detach(&mgr->task);
++		isc_socket_detach(&mgr->route);
++		ns_interfacemgr_detach(&mgr);
++		isc_event_free(&event);
++		return;
++	}
++#endif
++
++	switch (rtm->MSGTYPE) {
++	case RTM_NEWADDR:
++	case RTM_DELADDR:
++		if (ns_g_server->interface_auto)
++			ns_server_scan_interfaces(ns_g_server);
++		break;
++	default:
++		break;
++	}
++
++	/*
++	 * Look for next route event.
++	 */
++	r.base = mgr->buf;
++	r.length = sizeof(mgr->buf);
++	result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
++				 route_event, mgr);
++	if (result != ISC_R_SUCCESS)
++		ns_interfacemgr_detach(&mgr);
++	isc_event_free(&event);
++}
++#endif
++
+ isc_result_t
+ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+ 		       isc_socketmgr_t *socketmgr,
+@@ -112,11 +204,52 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+ 	mgr->aclenv.geoip = ns_g_geoip;
+ #endif
+ 
++#ifdef USE_ROUTE_SOCKET
++	mgr->route = NULL;
++	result = isc_socket_create(mgr->socketmgr, ROUTE_SOCKET_PROTOCOL,
++				   isc_sockettype_raw, &mgr->route);
++	switch (result) {
++	case ISC_R_NOPERM:
++	case ISC_R_SUCCESS:
++	case ISC_R_NOTIMPLEMENTED:
++	case ISC_R_FAMILYNOSUPPORT:
++	    break;
++	default:
++		goto cleanup_aclenv;
++	}
++
++	mgr->task = NULL;
++	if (mgr->route != NULL) {
++		result = isc_task_create(taskmgr, 0, &mgr->task);
++		if (result != ISC_R_SUCCESS)
++			goto cleanup_route;
++	}
++	mgr->references = (mgr->route != NULL) ? 2 : 1;
++#else
+ 	mgr->references = 1;
++#endif
+ 	mgr->magic = IFMGR_MAGIC;
+ 	*mgrp = mgr;
++
++#ifdef USE_ROUTE_SOCKET
++	if (mgr->route != NULL) {
++		isc_region_t r = { mgr->buf, sizeof(mgr->buf) };
++
++		result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
++					 route_event, mgr);
++		if (result != ISC_R_SUCCESS)
++			ns_interfacemgr_detach(&mgr);
++	}
++#endif
+ 	return (ISC_R_SUCCESS);
+ 
++#ifdef USE_ROUTE_SOCKET
++ cleanup_route:
++	if (mgr->route != NULL)
++		isc_socket_detach(&mgr->route);
++ cleanup_aclenv:
++	dns_aclenv_destroy(&mgr->aclenv);
++#endif
+  cleanup_listenon:
+ 	ns_listenlist_detach(&mgr->listenon4);
+ 	ns_listenlist_detach(&mgr->listenon6);
+@@ -128,6 +261,13 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+ static void
+ ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
+ 	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
++
++#ifdef USE_ROUTE_SOCKET
++	if (mgr->route != NULL)
++		isc_socket_detach(&mgr->route);
++	if (mgr->task != NULL)
++		isc_task_detach(&mgr->task);
++#endif
+ 	dns_aclenv_destroy(&mgr->aclenv);
+ 	ns_listenlist_detach(&mgr->listenon4);
+ 	ns_listenlist_detach(&mgr->listenon6);
+@@ -179,6 +319,10 @@ ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
+ 	 * consider all interfaces "old".
+ 	 */
+ 	mgr->generation++;
++#ifdef USE_ROUTE_SOCKET
++	if (mgr->route != NULL)
++		isc_socket_cancel(mgr->route, mgr->task, ISC_SOCKCANCEL_RECV);
++#endif
+ 	purge_old_interfaces(mgr);
+ }
+ 
+diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook
+index 8c23e52..a8cd31e 100644
+--- a/bin/named/named.conf.docbook
++++ b/bin/named/named.conf.docbook
+@@ -373,6 +373,7 @@ options {
+ 	zero-no-soa-ttl <replaceable>boolean</replaceable>;
+ 	zero-no-soa-ttl-cache <replaceable>boolean</replaceable>;
+ 	dnssec-secure-to-insecure <replaceable>boolean</replaceable>;
++	automatic-interface-scan <replaceable>boolean</replaceable>;
+ 	deny-answer-addresses {
+ 		<replaceable>address_match_list</replaceable>
+ 	} <optional> except-from { <replaceable>namelist</replaceable> } </optional>;
+diff --git a/bin/named/server.c b/bin/named/server.c
+index 24b31c3..942bab6 100644
+--- a/bin/named/server.c
++++ b/bin/named/server.c
+@@ -4485,8 +4485,9 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
+ }
+ 
+ /*
+- * This event callback is invoked to do periodic network
+- * interface scanning.
++ * This event callback is invoked to do periodic network interface
++ * scanning.  It is also called by ns_server_scan_interfaces(),
++ * invoked by "rndc scan"
+  */
+ static void
+ interface_timer_tick(isc_task_t *task, isc_event_t *event) {
+@@ -4494,7 +4495,14 @@ interface_timer_tick(isc_task_t *task, isc_event_t *event) {
+ 	ns_server_t *server = (ns_server_t *) event->ev_arg;
+ 	INSIST(task == server->task);
+ 	UNUSED(task);
++
++	if (event->ev_type == NS_EVENT_IFSCAN)
++		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
++			      NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
++			      "automatic interface rescan");
++
+ 	isc_event_free(&event);
++
+ 	/*
+ 	 * XXX should scan interfaces unlocked and get exclusive access
+ 	 * only to replace ACLs.
+@@ -5419,6 +5427,14 @@ load_configuration(const char *filename, ns_server_t *server,
+ 	server->interface_interval = interface_interval;
+ 
+ 	/*
++	 * Enable automatic interface scans.
++	 */
++	obj = NULL;
++	result = ns_config_get(maps, "automatic-interface-scan", &obj);
++	INSIST(result == ISC_R_SUCCESS);
++	server->interface_auto = cfg_obj_asboolean(obj);
++
++	/*
+ 	 * Configure the dialup heartbeat timer.
+ 	 */
+ 	obj = NULL;
+@@ -6637,6 +6653,17 @@ ns_server_reloadwanted(ns_server_t *server) {
+ 	UNLOCK(&server->reload_event_lock);
+ }
+ 
++void
++ns_server_scan_interfaces(ns_server_t *server) {
++	isc_event_t *event;
++
++	event = isc_event_allocate(ns_g_mctx, server, NS_EVENT_IFSCAN,
++				   interface_timer_tick, server,
++				   sizeof(isc_event_t));
++	if (event != NULL)
++		isc_task_send(server->task, &event);
++}
++
+ static char *
+ next_token(char **stringp, const char *delim) {
+ 	char *res;
+diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c
+index 37e98a8..b985f62 100644
+--- a/bin/named/statschannel.c
++++ b/bin/named/statschannel.c
+@@ -341,6 +341,7 @@ init_desc(void) {
+ 	SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open");
+ 	SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open");
+ 	SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen");
++	SET_SOCKSTATDESC(rawopen, "Raw sockets opened", "RawOpen");
+ 	SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures",
+ 			 "UDP4OpenFail");
+ 	SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures",
+@@ -351,6 +352,8 @@ init_desc(void) {
+ 			 "TCP6OpenFail");
+ 	SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures",
+ 			 "UnixOpenFail");
++	SET_SOCKSTATDESC(rawopenfail, "Raw socket open failures",
++			 "RawOpenFail");
+ 	SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close");
+ 	SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close");
+ 	SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close");
+@@ -358,6 +361,7 @@ init_desc(void) {
+ 	SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose");
+ 	SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed",
+ 			 "FDWatchClose");
++	SET_SOCKSTATDESC(rawclose, "Raw sockets closed", "RawClose");
+ 	SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures",
+ 			 "UDP4BindFail");
+ 	SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures",
+@@ -424,6 +428,7 @@ init_desc(void) {
+ 			 "UnixRecvErr");
+ 	SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors",
+ 			 "FDwatchRecvErr");
++	SET_SOCKSTATDESC(rawrecvfail, "Raw recv errors", "RawRecvErr");
+ 	INSIST(i == isc_sockstatscounter_max);
+ 
+ 	/* Initialize DNSSEC statistics */
+diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c
+index 9a007e2..be198b1 100644
+--- a/bin/rndc/rndc.c
++++ b/bin/rndc/rndc.c
+@@ -160,6 +160,7 @@ command is one of the following:\n\
+ 		Add zone to given view. Requires new-zone-file option.\n\
+   delzone [\"file\"] zone [class [view]]\n\
+ 		Removes zone from given view. Requires new-zone-file option.\n\
++  scan		Scan available network interfaces for changes.\n\
+   signing -list zone [class [view]]\n\
+ 		List the private records showing the state of DNSSEC\n\
+ 		signing in the given zone.\n\
+diff --git a/bin/rndc/rndc.docbook b/bin/rndc/rndc.docbook
+index 1789aaa..5b37b7f 100644
+--- a/bin/rndc/rndc.docbook
++++ b/bin/rndc/rndc.docbook
+@@ -330,6 +330,18 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term><userinput>scan</userinput></term>
++        <listitem>
++          <para>
++             Scan the list of available network interfaces
++             for changes, without performing a full
++             <command>reconfig</command> or waiting for the
++             <command>interface-interval</command> timer.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term><userinput>sync <optional>-clean</optional> <optional><replaceable>zone</replaceable> <optional><replaceable>class</replaceable> <optional><replaceable>view</replaceable></optional></optional></optional></userinput></term>
+         <listitem>
+           <para>
+diff --git a/config.h.in b/config.h.in
+index 6ed8381..3515f69 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -280,6 +280,12 @@ int sigwait(const unsigned int *set, int *sig);
+ /* Define to 1 if you have the <linux/capability.h> header file. */
+ #undef HAVE_LINUX_CAPABILITY_H
+ 
++/* Define to 1 if you have the <linux/netlink.h> header file. */
++#undef HAVE_LINUX_NETLINK_H
++
++/* Define to 1 if you have the <linux/rtnetlink.h> header file. */
++#undef HAVE_LINUX_RTNETLINK_H
++
+ /* Define to 1 if you have the <linux/types.h> header file. */
+ #undef HAVE_LINUX_TYPES_H
+ 
+@@ -295,6 +301,9 @@ int sigwait(const unsigned int *set, int *sig);
+ /* Define to 1 if you have the <net/if6.h> header file. */
+ #undef HAVE_NET_IF6_H
+ 
++/* Define to 1 if you have the <net/route.h> header file. */
++#undef HAVE_NET_ROUTE_H
++
+ /* Define if your OpenSSL version supports ECDSA. */
+ #undef HAVE_OPENSSL_ECDSA
+ 
+@@ -358,6 +367,9 @@ int sigwait(const unsigned int *set, int *sig);
+ /* Define to 1 if you have the <sys/select.h> header file. */
+ #undef HAVE_SYS_SELECT_H
+ 
++/* Define to 1 if you have the <sys/socket.h> header file. */
++#undef HAVE_SYS_SOCKET_H
++
+ /* Define to 1 if you have the <sys/sockio.h> header file. */
+ #undef HAVE_SYS_SOCKIO_H
+ 
+diff --git a/configure.in b/configure.in
+index d72093f..38e626d 100644
+--- a/configure.in
++++ b/configure.in
+@@ -375,11 +375,14 @@ fi
+ 
+ AC_HEADER_STDC
+ 
+-AC_CHECK_HEADERS(fcntl.h regex.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h,,,
++AC_CHECK_HEADERS(fcntl.h regex.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h sys/socket.h net/route.h linux/netlink.h linux/rtnetlink.h,,,
+ [$ac_includes_default
+ #ifdef HAVE_SYS_PARAM_H
+ # include <sys/param.h>
+ #endif
++#ifdef HAVE_SYS_SOCKET_H
++# include <sys/socket.h>
++#endif
+ ])
+ 
+ AC_C_CONST
+diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
+index 92c7b72..4c47d92 100644
+--- a/doc/arm/Bv9ARM-book.xml
++++ b/doc/arm/Bv9ARM-book.xml
+@@ -4964,7 +4964,9 @@ badresp:1,adberr:0,findfail:0,valfail:0]
+ 	<optional> policy given | disabled | passthru | nxdomain | nodata | cname <replaceable>domain</replaceable> </optional>
+ 	<optional> recursive-only <replaceable>yes_or_no</replaceable> </optional> <optional> max-policy-ttl <replaceable>number</replaceable> </optional> ;
+     } <optional> recursive-only <replaceable>yes_or_no</replaceable> </optional> <optional> max-policy-ttl <replaceable>number</replaceable> </optional>
+-	<optional> break-dnssec <replaceable>yes_or_no</replaceable> </optional> <optional> min-ns-dots <replaceable>number</replaceable> </optional> ; </optional>
++    <optional> break-dnssec <replaceable>yes_or_no</replaceable> </optional> <optional> min-ns-dots <replaceable>number</replaceable> </optional>
++      <optional> automatic-interface-scan <replaceable>yes_or_no</replaceable> </optional>
++    ; </optional>
+ };
+ </programlisting>
+ 
+@@ -5726,6 +5728,23 @@ options {
+           <variablelist>
+ 
+             <varlistentry>
++	      <term><command>automatic-interface-scan</command></term>
++	      <listitem>
++		<para>
++		  If <userinput>yes</userinput> and supported by the OS,
++		  automatically rescan network interfaces when the interface
++		  addresses are added or removed.  The default is
++		  <userinput>yes</userinput>.
++		</para>
++		<para>
++		  Currently the OS needs to support routing sockets for
++		  <command>automatic-interface-scan</command> to be
++		  supported.
++		</para>
++	      </listitem>
++	    </varlistentry>
++
++	    <varlistentry>
+               <term><command>allow-new-zones</command></term>
+               <listitem>
+                 <para>
+@@ -10494,6 +10513,7 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
+     <optional> allow-query-on { <replaceable>address_match_list</replaceable> }; </optional>
+     <optional> allow-transfer { <replaceable>address_match_list</replaceable> }; </optional>
+     <optional> allow-update-forwarding { <replaceable>address_match_list</replaceable> }; </optional>
++    <optional> automatic-interface-scan { <replaceable>yes_or_no</replaceable> }; </optional>
+     <optional> dnssec-update-mode ( <replaceable>maintain</replaceable> | <replaceable>no-resign</replaceable> ); </optional>
+     <optional> update-check-ksk <replaceable>yes_or_no</replaceable>; </optional>
+     <optional> dnssec-dnskey-kskonly <replaceable>yes_or_no</replaceable>; </optional>
+diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h
+index c5a753a..1cd90bb 100644
+--- a/lib/isc/include/isc/socket.h
++++ b/lib/isc/include/isc/socket.h
+@@ -150,7 +150,12 @@ enum {
+ 	isc_sockstatscounter_unixrecvfail = 50,
+ 	isc_sockstatscounter_fdwatchrecvfail = 51,
+ 
+-	isc_sockstatscounter_max = 52
++	isc_sockstatscounter_rawopen = 52,
++	isc_sockstatscounter_rawopenfail = 53,
++	isc_sockstatscounter_rawclose = 54,
++	isc_sockstatscounter_rawrecvfail = 55,
++
++	isc_sockstatscounter_max = 56
+ };
+ 
+ /***
+@@ -221,7 +226,8 @@ typedef enum {
+ 	isc_sockettype_udp = 1,
+ 	isc_sockettype_tcp = 2,
+ 	isc_sockettype_unix = 3,
+-	isc_sockettype_fdwatch = 4
++	isc_sockettype_fdwatch = 4,
++	isc_sockettype_raw = 5
+ } isc_sockettype_t;
+ 
+ /*@{*/
+diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c
+index 82d0d16..cbc506b 100644
+--- a/lib/isc/unix/socket.c
++++ b/lib/isc/unix/socket.c
+@@ -28,6 +28,11 @@
+ #include <sys/time.h>
+ #include <sys/uio.h>
+ 
++#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
++#include <linux/netlink.h>
++#include <linux/rtnetlink.h>
++#endif
++
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <stddef.h>
+@@ -708,6 +713,18 @@ static const isc_statscounter_t fdwatchstatsindex[] = {
+ 	isc_sockstatscounter_fdwatchsendfail,
+ 	isc_sockstatscounter_fdwatchrecvfail
+ };
++static const isc_statscounter_t rawstatsindex[] = {
++	isc_sockstatscounter_rawopen,
++	isc_sockstatscounter_rawopenfail,
++	isc_sockstatscounter_rawclose,
++	-1,
++	-1,
++	-1,
++	-1,
++	-1,
++	-1,
++	isc_sockstatscounter_rawrecvfail,
++};
+ 
+ #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) || \
+     defined(USE_WATCHER_THREAD)
+@@ -1744,6 +1761,7 @@ doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) {
+ 			return (DOIO_EOF);
+ 		break;
+ 	case isc_sockettype_udp:
++	case isc_sockettype_raw:
+ 		break;
+ 	case isc_sockettype_fdwatch:
+ 	default:
+@@ -2306,6 +2324,44 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock,
+ 		case isc_sockettype_unix:
+ 			sock->fd = socket(sock->pf, SOCK_STREAM, 0);
+ 			break;
++		case isc_sockettype_raw:
++			errno = EPFNOSUPPORT;
++			/*
++			 * PF_ROUTE is a alias for PF_NETLINK on linux.
++			 */
++#if defined(PF_ROUTE)
++			if (sock->fd == -1 && sock->pf == PF_ROUTE) {
++#ifdef NETLINK_ROUTE
++				sock->fd = socket(sock->pf, SOCK_RAW,
++						  NETLINK_ROUTE);
++#else
++				sock->fd = socket(sock->pf, SOCK_RAW, 0);
++#endif
++				if (sock->fd != -1) {
++#ifdef NETLINK_ROUTE
++					struct sockaddr_nl sa;
++					int n;
++
++					/*
++					 * Do an implicit bind.
++					 */
++					memset(&sa, 0, sizeof(sa));
++					sa.nl_family = AF_NETLINK;
++					sa.nl_groups = RTMGRP_IPV4_IFADDR |
++						       RTMGRP_IPV6_IFADDR;
++					n = bind(sock->fd,
++						 (struct sockaddr *) &sa,
++						 sizeof(sa));
++					if (n < 0) {
++						close(sock->fd);
++						sock->fd = -1;
++					}
++#endif
++					sock->bound = 1;
++				}
++			}
++ #endif
++			break;
+ 		case isc_sockettype_fdwatch:
+ 			/*
+ 			 * We should not be called for isc_sockettype_fdwatch
+@@ -2602,6 +2658,9 @@ socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type,
+ 	case isc_sockettype_unix:
+ 		sock->statsindex = unixstatsindex;
+ 		break;
++	case isc_sockettype_raw:
++		sock->statsindex = rawstatsindex;
++		break;
+ 	default:
+ 		INSIST(0);
+ 	}
+diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
+index f5ff8e3..f49ff70 100644
+--- a/lib/isccfg/namedconf.c
++++ b/lib/isccfg/namedconf.c
+@@ -931,6 +931,7 @@ bindkeys_clauses[] = {
+  */
+ static cfg_clausedef_t
+ options_clauses[] = {
++	{ "automatic-interface-scan", &cfg_type_boolean, 0 },
+ 	{ "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
+ 	{ "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
+ 	{ "bindkeys-file", &cfg_type_qstring, 0 },
+-- 
+2.5.5
+
diff --git a/SOURCES/bind99-rh1220594-geoip.patch b/SOURCES/bind99-rh1220594-geoip.patch
new file mode 100644
index 0000000..a6c3d08
--- /dev/null
+++ b/SOURCES/bind99-rh1220594-geoip.patch
@@ -0,0 +1,5536 @@
+From 7af058d28da052c9fb03083f6c4de1f9af564d08 Mon Sep 17 00:00:00 2001
+From: Tomas Hozza <thozza@redhat.com>
+Date: Wed, 13 Apr 2016 09:57:31 +0200
+Subject: [PATCH] Added support for GeoIP
+
+Signed-off-by: Tomas Hozza <thozza@redhat.com>
+---
+ bin/named/Makefile.in                         |   8 +-
+ bin/named/geoip.c                             | 148 +++++
+ bin/named/include/named/geoip.h               |  31 +
+ bin/named/include/named/globals.h             |   5 +
+ bin/named/interfacemgr.c                      |   3 +
+ bin/named/server.c                            |  38 +-
+ bin/tests/system/Makefile.in                  |   3 +-
+ bin/tests/system/conf.sh.in                   |   2 +-
+ bin/tests/system/geoip/Makefile.in            |  55 ++
+ bin/tests/system/geoip/clean.sh               |  23 +
+ bin/tests/system/geoip/data/GeoIP.csv         |   7 +
+ bin/tests/system/geoip/data/GeoIPASNum.csv    |   7 +
+ bin/tests/system/geoip/data/GeoIPASNumv6.csv  |   7 +
+ bin/tests/system/geoip/data/GeoIPCity.csv     |   7 +
+ bin/tests/system/geoip/data/GeoIPCityv6.csv   |   7 +
+ bin/tests/system/geoip/data/GeoIPDomain.csv   |   7 +
+ bin/tests/system/geoip/data/GeoIPISP.csv      |   7 +
+ bin/tests/system/geoip/data/GeoIPNetSpeed.csv |   7 +
+ bin/tests/system/geoip/data/GeoIPOrg.csv      |   7 +
+ bin/tests/system/geoip/data/GeoIPRegion.csv   |   7 +
+ bin/tests/system/geoip/data/GeoIPv6.csv       |   7 +
+ bin/tests/system/geoip/data/README            |  29 +
+ bin/tests/system/geoip/geoip.c                |  31 +
+ bin/tests/system/geoip/ns2/example.db.in      |  24 +
+ bin/tests/system/geoip/ns2/named1.conf        | 104 ++++
+ bin/tests/system/geoip/ns2/named10.conf       | 104 ++++
+ bin/tests/system/geoip/ns2/named11.conf       | 104 ++++
+ bin/tests/system/geoip/ns2/named12.conf       |  80 +++
+ bin/tests/system/geoip/ns2/named13.conf       |  45 ++
+ bin/tests/system/geoip/ns2/named14.conf       | 112 ++++
+ bin/tests/system/geoip/ns2/named15.conf       |  55 ++
+ bin/tests/system/geoip/ns2/named2.conf        | 104 ++++
+ bin/tests/system/geoip/ns2/named3.conf        | 104 ++++
+ bin/tests/system/geoip/ns2/named4.conf        |  96 +++
+ bin/tests/system/geoip/ns2/named5.conf        | 104 ++++
+ bin/tests/system/geoip/ns2/named6.conf        | 104 ++++
+ bin/tests/system/geoip/ns2/named7.conf        | 104 ++++
+ bin/tests/system/geoip/ns2/named8.conf        | 104 ++++
+ bin/tests/system/geoip/ns2/named9.conf        | 104 ++++
+ bin/tests/system/geoip/options.conf           |  42 ++
+ bin/tests/system/geoip/prereq.sh              |  23 +
+ bin/tests/system/geoip/setup.sh               |  27 +
+ bin/tests/system/geoip/tests.sh               | 328 +++++++++++
+ config.h.in                                   |   9 +
+ configure.in                                  |  94 +++
+ doc/arm/Bv9ARM-book.xml                       |  72 +++
+ lib/dns/Makefile.in                           |   8 +-
+ lib/dns/acl.c                                 |  23 +-
+ lib/dns/geoip.c                               | 820 ++++++++++++++++++++++++++
+ lib/dns/include/dns/Makefile.in               |   2 +-
+ lib/dns/include/dns/acl.h                     |  24 +-
+ lib/dns/include/dns/geoip.h                   | 119 ++++
+ lib/dns/tests/Makefile.in                     |   9 +-
+ lib/dns/tests/geoip_test.c                    | 694 ++++++++++++++++++++++
+ lib/export/dns/Makefile.in                    |  18 +-
+ lib/isccfg/aclconf.c                          | 361 +++++++++++-
+ lib/isccfg/include/isccfg/aclconf.h           |   6 +
+ lib/isccfg/namedconf.c                        | 129 +++-
+ 58 files changed, 4673 insertions(+), 40 deletions(-)
+ create mode 100644 bin/named/geoip.c
+ create mode 100644 bin/named/include/named/geoip.h
+ create mode 100644 bin/tests/system/geoip/Makefile.in
+ create mode 100644 bin/tests/system/geoip/clean.sh
+ create mode 100644 bin/tests/system/geoip/data/GeoIP.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPASNum.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPASNumv6.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPCity.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPCityv6.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPDomain.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPISP.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPNetSpeed.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPOrg.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPRegion.csv
+ create mode 100644 bin/tests/system/geoip/data/GeoIPv6.csv
+ create mode 100644 bin/tests/system/geoip/data/README
+ create mode 100644 bin/tests/system/geoip/geoip.c
+ create mode 100644 bin/tests/system/geoip/ns2/example.db.in
+ create mode 100644 bin/tests/system/geoip/ns2/named1.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named10.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named11.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named12.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named13.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named14.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named15.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named2.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named3.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named4.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named5.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named6.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named7.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named8.conf
+ create mode 100644 bin/tests/system/geoip/ns2/named9.conf
+ create mode 100644 bin/tests/system/geoip/options.conf
+ create mode 100644 bin/tests/system/geoip/prereq.sh
+ create mode 100644 bin/tests/system/geoip/setup.sh
+ create mode 100644 bin/tests/system/geoip/tests.sh
+ create mode 100644 lib/dns/geoip.c
+ create mode 100644 lib/dns/include/dns/geoip.h
+ create mode 100644 lib/dns/tests/geoip_test.c
+
+diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in
+index cd65777..3a54437 100644
+--- a/bin/named/Makefile.in
++++ b/bin/named/Makefile.in
+@@ -85,8 +85,10 @@ SUBDIRS =	unix
+ 
+ TARGETS =	named@EXEEXT@ lwresd@EXEEXT@
+ 
++GEOIPLINKOBJS = geoip.@O@
++
+ OBJS =		builtin.@O@ client.@O@ config.@O@ control.@O@ \
+-		controlconf.@O@ interfacemgr.@O@ \
++		controlconf.@O@ @GEOIPLINKOBJS@ interfacemgr.@O@ \
+ 		listenlist.@O@ log.@O@ logconf.@O@ main.@O@ notify.@O@ \
+ 		query.@O@ server.@O@ sortlist.@O@ statschannel.@O@ \
+ 		tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \
+@@ -99,8 +101,10 @@ UOBJS =		unix/os.@O@ unix/dlz_dlopen_driver.@O@
+ 
+ SYMOBJS =	symtbl.@O@
+ 
++GEOIPLINKSRCS = geoip.c
++
+ SRCS =		builtin.c client.c config.c control.c \
+-		controlconf.c interfacemgr.c \
++		controlconf.c @GEOIPLINKSRCS@ interfacemgr.c \
+ 		listenlist.c log.c logconf.c main.c notify.c \
+ 		query.c server.c sortlist.c statschannel.c symtbl.c symtbl-empty.c \
+ 		tkeyconf.c tsigconf.c update.c xfrout.c \
+diff --git a/bin/named/geoip.c b/bin/named/geoip.c
+new file mode 100644
+index 0000000..c8f0c62
+--- /dev/null
++++ b/bin/named/geoip.c
+@@ -0,0 +1,148 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*! \file */
++
++#include <config.h>
++
++#include <isc/util.h>
++
++#include <named/log.h>
++#include <named/geoip.h>
++
++#include <dns/geoip.h>
++
++#ifdef HAVE_GEOIP
++static dns_geoip_databases_t geoip_table = {
++	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
++};
++
++static void
++init_geoip_db(GeoIP **dbp, GeoIPDBTypes edition, GeoIPDBTypes fallback,
++	      GeoIPOptions method, const char *name)
++{
++	char *info;
++	GeoIP *db;
++
++	REQUIRE(dbp != NULL);
++
++	db = *dbp;
++
++	if (db != NULL) {
++		GeoIP_delete(db);
++		db = *dbp = NULL;
++	}
++
++	if (! GeoIP_db_avail(edition)) {
++		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
++			NS_LOGMODULE_SERVER, ISC_LOG_INFO,
++			"GeoIP %s (type %d) DB not available", name, edition);
++		goto fail;
++	}
++
++	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
++		NS_LOGMODULE_SERVER, ISC_LOG_INFO,
++		"initializing GeoIP %s (type %d) DB", name, edition);
++
++	db = GeoIP_open_type(edition, method);
++	if (db == NULL) {
++		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
++			NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
++			"failed to initialize GeoIP %s (type %d) DB%s",
++			name, edition, fallback == 0
++			 ? "geoip matches using this database will fail" : "");
++		goto fail;
++	}
++
++	info = GeoIP_database_info(db);
++	if (info != NULL)
++		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
++			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
++			      "%s", info);
++
++	*dbp = db;
++	return;
++ fail:
++	if (fallback != 0)
++		init_geoip_db(dbp, fallback, 0, method, name);
++
++}
++#endif /* HAVE_GEOIP */
++
++void
++ns_geoip_init(void) {
++#ifndef HAVE_GEOIP
++	return;
++#else
++	GeoIP_cleanup();
++	if (ns_g_geoip == NULL)
++		ns_g_geoip = &geoip_table;
++#endif
++}
++
++void
++ns_geoip_load(char *dir) {
++#ifndef HAVE_GEOIP
++
++	UNUSED(dir);
++
++	return;
++#else
++	GeoIPOptions method;
++
++#ifdef _WIN32
++	method = GEOIP_STANDARD;
++#else
++	method = GEOIP_MMAP_CACHE;
++#endif
++
++	ns_geoip_init();
++	if (dir != NULL) {
++		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
++			      NS_LOGMODULE_SERVER, ISC_LOG_INFO,
++			      "using \"%s\" as GeoIP directory", dir);
++		GeoIP_setup_custom_directory(dir);
++	}
++
++	init_geoip_db(&ns_g_geoip->country_v4, GEOIP_COUNTRY_EDITION, 0,
++		      method, "Country (IPv4)");
++#ifdef HAVE_GEOIP_V6
++	init_geoip_db(&ns_g_geoip->country_v6, GEOIP_COUNTRY_EDITION_V6, 0,
++		      method, "Country (IPv6)");
++#endif
++
++	init_geoip_db(&ns_g_geoip->city_v4, GEOIP_CITY_EDITION_REV1,
++		      GEOIP_CITY_EDITION_REV0, method, "City (IPv4)");
++#if defined(HAVE_GEOIP_V6) && defined(HAVE_GEOIP_CITY_V6)
++	init_geoip_db(&ns_g_geoip->city_v6, GEOIP_CITY_EDITION_REV1_V6,
++		      GEOIP_CITY_EDITION_REV0_V6, method, "City (IPv6)");
++#endif
++
++	init_geoip_db(&ns_g_geoip->region, GEOIP_REGION_EDITION_REV1,
++		      GEOIP_REGION_EDITION_REV0, method, "Region");
++
++	init_geoip_db(&ns_g_geoip->isp, GEOIP_ISP_EDITION, 0,
++		      method, "ISP");
++	init_geoip_db(&ns_g_geoip->org, GEOIP_ORG_EDITION, 0,
++		      method, "Org");
++	init_geoip_db(&ns_g_geoip->as, GEOIP_ASNUM_EDITION, 0,
++		      method, "AS");
++	init_geoip_db(&ns_g_geoip->domain, GEOIP_DOMAIN_EDITION, 0,
++		      method, "Domain");
++	init_geoip_db(&ns_g_geoip->netspeed, GEOIP_NETSPEED_EDITION, 0,
++		      method, "NetSpeed");
++#endif /* HAVE_GEOIP */
++}
+diff --git a/bin/named/include/named/geoip.h b/bin/named/include/named/geoip.h
+new file mode 100644
+index 0000000..e1a66a7
+--- /dev/null
++++ b/bin/named/include/named/geoip.h
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef _GEOIP_H
++#define _GEOIP_H
++
++#ifdef HAVE_GEOIP
++#include <GeoIP.h>
++#include <GeoIPCity.h>
++#endif /* HAVE_GEOIP */
++
++void ns_geoip_init(void);
++void ns_geoip_load(char *dir);
++
++#ifdef HAVE_GEOIP
++extern dns_geoip_databases_t *ns_g_geoip;
++#endif /* HAVE_GEOIP */
++#endif
+diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h
+index aad462d..412b3a7 100644
+--- a/bin/named/include/named/globals.h
++++ b/bin/named/include/named/globals.h
+@@ -29,6 +29,7 @@
+ #include <isccfg/aclconf.h>
+ #include <isccfg/cfg.h>
+ 
++#include <dns/acl.h>
+ #include <dns/zone.h>
+ 
+ #include <dst/dst.h>
+@@ -160,6 +161,10 @@ EXTERN isc_boolean_t		ns_g_nosoa		INIT(ISC_FALSE);
+ EXTERN isc_boolean_t		ns_g_noaa		INIT(ISC_FALSE);
+ EXTERN isc_boolean_t		ns_g_nonearest		INIT(ISC_FALSE);
+ 
++#ifdef HAVE_GEOIP
++EXTERN dns_geoip_databases_t	*ns_g_geoip		INIT(NULL);
++#endif
++
+ #undef EXTERN
+ #undef INIT
+ 
+diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c
+index 9206ebb..4f6b0f3 100644
+--- a/bin/named/interfacemgr.c
++++ b/bin/named/interfacemgr.c
+@@ -108,6 +108,9 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+ 	result = dns_aclenv_init(mctx, &mgr->aclenv);
+ 	if (result != ISC_R_SUCCESS)
+ 		goto cleanup_listenon;
++#ifdef HAVE_GEOIP
++	mgr->aclenv.geoip = ns_g_geoip;
++#endif
+ 
+ 	mgr->references = 1;
+ 	mgr->magic = IFMGR_MAGIC;
+diff --git a/bin/named/server.c b/bin/named/server.c
+index 5e94660..24b31c3 100644
+--- a/bin/named/server.c
++++ b/bin/named/server.c
+@@ -98,6 +98,7 @@
+ #include <named/client.h>
+ #include <named/config.h>
+ #include <named/control.h>
++#include <named/geoip.h>
+ #include <named/interfacemgr.h>
+ #include <named/log.h>
+ #include <named/logconf.h>
+@@ -113,6 +114,9 @@
+ #include <named/ns_smf_globals.h>
+ #include <stdlib.h>
+ #endif
++#ifdef HAVE_GEOIP
++#include <named/geoip.h>
++#endif /* HAVE_GEOIP */
+ 
+ #ifndef PATH_MAX
+ #define PATH_MAX 1024
+@@ -3841,6 +3845,10 @@ create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
+ 	if (result != ISC_R_SUCCESS)
+ 		return (result);
+ 
++#ifdef HAVE_GEOIP
++	view->aclenv.geoip = ns_g_geoip;
++#endif
++
+ 	ISC_LIST_APPEND(*viewlist, view, link);
+ 	dns_view_attach(view, viewp);
+ 	return (ISC_R_SUCCESS);
+@@ -5164,6 +5172,24 @@ load_configuration(const char *filename, ns_server_t *server,
+ 	}
+ 	isc__socketmgr_setreserved(ns_g_socketmgr, reserved);
+ 
++#ifdef HAVE_GEOIP
++	/*
++	 * Initialize GeoIP databases from the configured location.
++	 * This should happen before configuring any ACLs, so that we
++	 * know what databases are available and can reject any GeoIP
++	 * ACLs that can't work.
++	 */
++	obj = NULL;
++	result = ns_config_get(maps, "geoip-directory", &obj);
++	if (result == ISC_R_SUCCESS && cfg_obj_isstring(obj)) {
++		char *dir;
++		DE_CONST(cfg_obj_asstring(obj), dir);
++		ns_geoip_load(dir);
++	} else
++		ns_geoip_load(NULL);
++	ns_g_aclconfctx->geoip = ns_g_geoip;
++#endif /* HAVE_GEOIP */
++
+ 	/*
+ 	 * Configure various server options.
+ 	 */
+@@ -6176,6 +6202,10 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
+ 	if (server->blackholeacl != NULL)
+ 		dns_acl_detach(&server->blackholeacl);
+ 
++#ifdef HAVE_GEOIP
++	dns_geoip_shutdown();
++#endif
++
+ 	dns_db_detach(&server->in_roothints);
+ 
+ 	isc_task_endexclusive(server->task);
+@@ -6197,7 +6227,6 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
+ 	server->task = NULL;
+ 
+ 	/* Initialize configuration data with default values. */
+-
+ 	result = isc_quota_init(&server->xfroutquota, 10);
+ 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ 	result = isc_quota_init(&server->tcpquota, 10);
+@@ -6205,9 +6234,16 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
+ 	result = isc_quota_init(&server->recursionquota, 100);
+ 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ 
++
+ 	result = dns_aclenv_init(mctx, &server->aclenv);
+ 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ 
++#ifdef HAVE_GEOIP
++	/* Initialize GeoIP before using ACL environment */
++	ns_geoip_init();
++	server->aclenv.geoip = ns_g_geoip;
++#endif
++
+ 	/* Initialize server data structures. */
+ 	server->zonemgr = NULL;
+ 	server->interfacemgr = NULL;
+diff --git a/bin/tests/system/Makefile.in b/bin/tests/system/Makefile.in
+index 1479824..5e3c63e 100644
+--- a/bin/tests/system/Makefile.in
++++ b/bin/tests/system/Makefile.in
+@@ -21,8 +21,7 @@ top_srcdir =	@top_srcdir@
+ 
+ @BIND9_MAKE_INCLUDES@
+ 
+-SUBDIRS =	filter-aaaa lwresd rpz rrl \
+-		rsabigexponent tkey tsiggss
++SUBDIRS =	filter-aaaa geoip lwresd rpz rrl rsabigexponent tkey tsiggss
+ TARGETS =
+ 
+ @BIND9_MAKE_RULES@
+diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in
+index c40e8f1..c3beac1 100644
+--- a/bin/tests/system/conf.sh.in
++++ b/bin/tests/system/conf.sh.in
+@@ -65,7 +65,7 @@ SUBDIRS="acl additional allow_query addzone autosign builtin
+          lwresd masterfile masterformat metadata notify nsupdate pending
+ 	 @PKCS11_TEST@ redirect resolver rndc rpz rrl rrsetorder rsabigexponent
+ 	 smartsign sortlist spf staticstub stub tkey tsig tsiggss unknown
+-	 upforwd verify views wildcard xfer xferquota zero zonechecks"
++	 upforwd verify views wildcard xfer xferquota zero zonechecks geoip filter-aaaa"
+ 
+ # PERL will be an empty string if no perl interpreter was found.
+ PERL=@PERL@
+diff --git a/bin/tests/system/geoip/Makefile.in b/bin/tests/system/geoip/Makefile.in
+new file mode 100644
+index 0000000..ab48003
+--- /dev/null
++++ b/bin/tests/system/geoip/Makefile.in
+@@ -0,0 +1,55 @@
++# Copyright (C) 2010-2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++# $Id: Makefile.in,v 1.4 2011/07/28 23:47:58 tbox Exp $
++
++srcdir =	@srcdir@
++VPATH =		@srcdir@
++top_srcdir =	@top_srcdir@
++
++@BIND9_VERSION@
++
++@BIND9_MAKE_INCLUDES@
++
++CINCLUDES =	${ISC_INCLUDES}
++
++CDEFINES =
++CWARNINGS =
++
++DNSLIBS =
++ISCLIBS =	.
++
++DNSDEPLIBS =
++ISCDEPLIBS =
++
++DEPLIBS =
++
++LIBS =		@LIBS@
++
++TARGETS =	geoip@EXEEXT@
++
++FILTEROBJS =	geoip.@O@
++
++SRCS =		geoip.c
++
++@BIND9_MAKE_RULES@
++
++all: geoip@EXEEXT@
++
++geoip@EXEEXT@: ${FILTEROBJS}
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${FILTEROBJS} ${LIBS}
++
++clean distclean::
++	rm -f ${TARGETS}
++
+diff --git a/bin/tests/system/geoip/clean.sh b/bin/tests/system/geoip/clean.sh
+new file mode 100644
+index 0000000..b04ca2d
+--- /dev/null
++++ b/bin/tests/system/geoip/clean.sh
+@@ -0,0 +1,23 @@
++#!/bin/sh
++#
++# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++rm -f ns2/named.conf
++rm -f ns2/example*.db
++rm -f dig.out.* rndc.out.*
++rm -f data2/*dat
++[ -d data2 ] && rmdir data2
++rm -f ns?/named.run
++rm -f ns?/named.memstats
+diff --git a/bin/tests/system/geoip/data/GeoIP.csv b/bin/tests/system/geoip/data/GeoIP.csv
+new file mode 100644
+index 0000000..f158a5b
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIP.csv
+@@ -0,0 +1,7 @@
++10.53.0.1/32 AU
++10.53.0.2/32 US
++10.53.0.3/32 GB
++10.53.0.4/32 CA
++10.53.0.5/32 CL
++10.53.0.6/32 DE
++10.53.0.7/32 EH
+diff --git a/bin/tests/system/geoip/data/GeoIPASNum.csv b/bin/tests/system/geoip/data/GeoIPASNum.csv
+new file mode 100644
+index 0000000..774edd1
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPASNum.csv
+@@ -0,0 +1,7 @@
++10.53.0.1/32 AS100001 One Systems, Inc.
++10.53.0.2/32 AS100002 Two Technology Ltd.
++10.53.0.3/32 AS100003 Three Network Labs
++10.53.0.4/32 AS100004 Four University
++10.53.0.5/32 AS100005 Five Telecom
++10.53.0.6/32 AS100006 Six Company
++10.53.0.7/32 AS100007 Seven Communications
+diff --git a/bin/tests/system/geoip/data/GeoIPASNumv6.csv b/bin/tests/system/geoip/data/GeoIPASNumv6.csv
+new file mode 100644
+index 0000000..4074289
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPASNumv6.csv
+@@ -0,0 +1,7 @@
++fd92:7065:b8e:ffff::1/128,AS100001 One Systems, Inc.
++fd92:7065:b8e:ffff::2/128,AS100002 Two Technology Ltd.
++fd92:7065:b8e:ffff::3/128,AS100003 Three Network Labs
++fd92:7065:b8e:ffff::4/128,AS100004 Four University
++fd92:7065:b8e:ffff::5/128,AS100005 Five Telecom
++fd92:7065:b8e:ffff::6/128,AS100006 Six Company
++fd92:7065:b8e:ffff::7/128,AS100007 Seven Communications
+diff --git a/bin/tests/system/geoip/data/GeoIPCity.csv b/bin/tests/system/geoip/data/GeoIPCity.csv
+new file mode 100644
+index 0000000..14900d5
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPCity.csv
+@@ -0,0 +1,7 @@
++10.53.0.1/32,US,CA,"Redwood City",94063,37.4914,-122.2110,807,650
++10.53.0.2/32,US,CA,"Santa Cruz",95060,37.0448,-122.1021,828,831
++10.53.0.3/32,US,OK,"Oklahoma City",73120,35.5798,-97.5731,650,405
++10.53.0.4/32,US,VA,Ashland,23005,37.7563,-77.4888,556,804
++10.53.0.5/32,US,GA,Atlanta,30345,33.8477,-84.2814,524,404
++10.53.0.6/32,US,CO,Morrison,80465,39.6081,-105.2072,751,303
++10.53.0.7/32,US,AK,Ketchikan,99901,55.6153,-131.5848,747,907
+diff --git a/bin/tests/system/geoip/data/GeoIPCityv6.csv b/bin/tests/system/geoip/data/GeoIPCityv6.csv
+new file mode 100644
+index 0000000..5f09e62
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPCityv6.csv
+@@ -0,0 +1,7 @@
++"fd92:7065:b8e:ffff::1","fd92:7065:b8e:ffff::1","US","CA","Redwood City","94063",37.4914,-122.2110,807,650
++"fd92:7065:b8e:ffff::2","fd92:7065:b8e:ffff::2","US","CA","Santa Cruz","95060",37.0448,-122.1021,828,831
++"fd92:7065:b8e:ffff::3","fd92:7065:b8e:ffff::3","US","OK","Oklahoma City","73120",35.5798,-97.5731,650,405
++"fd92:7065:b8e:ffff::4","fd92:7065:b8e:ffff::4","DE","07","Lotte","",52.2833,7.9167,0,0
++"fd92:7065:b8e:ffff::5","fd92:7065:b8e:ffff::5","US","GA","Atlanta","30345",33.8477,-84.2814,524,404
++"fd92:7065:b8e:ffff::6","fd92:7065:b8e:ffff::6","US","CO","Morrison","80465",39.6081,-105.2072,751,303
++"fd92:7065:b8e:ffff::7","fd92:7065:b8e:ffff::7","US","AK","Ketchikan","99901",55.6153,-131.5848,747,907
+diff --git a/bin/tests/system/geoip/data/GeoIPDomain.csv b/bin/tests/system/geoip/data/GeoIPDomain.csv
+new file mode 100644
+index 0000000..8611d65
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPDomain.csv
+@@ -0,0 +1,7 @@
++10.53.0.1/32 one.de
++10.53.0.2/32 two.com
++10.53.0.3/32 three.com
++10.53.0.4/32 four.com
++10.53.0.5/32 five.es
++10.53.0.6/32 six.it
++10.53.0.7/32 seven.org
+diff --git a/bin/tests/system/geoip/data/GeoIPISP.csv b/bin/tests/system/geoip/data/GeoIPISP.csv
+new file mode 100644
+index 0000000..3d5b4fa
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPISP.csv
+@@ -0,0 +1,7 @@
++10.53.0.1/32 One Systems, Inc.
++10.53.0.2/32 Two Technology Ltd.
++10.53.0.3/32 Three Network Labs
++10.53.0.4/32 Four University
++10.53.0.5/32 Five Telecom
++10.53.0.6/32 Six Company
++10.53.0.7/32 Seven Communications
+diff --git a/bin/tests/system/geoip/data/GeoIPNetSpeed.csv b/bin/tests/system/geoip/data/GeoIPNetSpeed.csv
+new file mode 100644
+index 0000000..4ede137
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPNetSpeed.csv
+@@ -0,0 +1,7 @@
++10.53.0.1/32 0
++10.53.0.2/32 1
++10.53.0.3/32 2
++10.53.0.4/32 3
++10.53.0.5/32 0
++10.53.0.6/32 1
++10.53.0.7/32 2
+diff --git a/bin/tests/system/geoip/data/GeoIPOrg.csv b/bin/tests/system/geoip/data/GeoIPOrg.csv
+new file mode 100644
+index 0000000..3d5b4fa
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPOrg.csv
+@@ -0,0 +1,7 @@
++10.53.0.1/32 One Systems, Inc.
++10.53.0.2/32 Two Technology Ltd.
++10.53.0.3/32 Three Network Labs
++10.53.0.4/32 Four University
++10.53.0.5/32 Five Telecom
++10.53.0.6/32 Six Company
++10.53.0.7/32 Seven Communications
+diff --git a/bin/tests/system/geoip/data/GeoIPRegion.csv b/bin/tests/system/geoip/data/GeoIPRegion.csv
+new file mode 100644
+index 0000000..0bcd872
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPRegion.csv
+@@ -0,0 +1,7 @@
++10.53.0.1/32 US CA
++10.53.0.2/32 CA BC
++10.53.0.3/32 US OK
++10.53.0.4/32 AU
++10.53.0.5/32 US CO
++10.53.0.6/32 CA ON
++10.53.0.7/32 NL
+diff --git a/bin/tests/system/geoip/data/GeoIPv6.csv b/bin/tests/system/geoip/data/GeoIPv6.csv
+new file mode 100644
+index 0000000..919bf86
+--- /dev/null
++++ b/bin/tests/system/geoip/data/GeoIPv6.csv
+@@ -0,0 +1,7 @@
++"fd92:7065:b8e:ffff::1/128",AU
++"fd92:7065:b8e:ffff::2/128",US
++"fd92:7065:b8e:ffff::3/128",GB
++"fd92:7065:b8e:ffff::4/128",CA
++"fd92:7065:b8e:ffff::5/128",CL
++"fd92:7065:b8e:ffff::6/128",DE
++"fd92:7065:b8e:ffff::7/128",EH
+diff --git a/bin/tests/system/geoip/data/README b/bin/tests/system/geoip/data/README
+new file mode 100644
+index 0000000..0711cde
+--- /dev/null
++++ b/bin/tests/system/geoip/data/README
+@@ -0,0 +1,29 @@
++The data data files in this directory are sample GeoIP databases,
++generated from the corresponding CSV files.  Thanks to MaxMind, Inc.
++for assistance with producing these files.
++
++Unless otherwise noted, the databases only support IPv4:
++
++GeoIP.dat: Country (IPv4)
++GeoIPv6.dat: Country (IPv6)
++GeoIPCity.dat: City (IPv4)
++GeoIPCityv6.dat: City (IPv6)
++GeoIPRegion.dat: Region
++GeoIPISP.dat: ISP
++GeoIPOrg.dat: Organization
++GeoIPDoain.dat: Domain Name
++GeoIPASNum.dat: AS Number
++GeoIPNetSpeed.dat: Net Speed
++
++GeoIP.dat can also be generated using the open source 'geoip-csv-to-dat'
++utility:
++
++$ geoip-csv-to-dat -i "BIND9 geoip test data v1" -o GeoIP.dat << EOF
++"10.53.0.1","10.53.0.1","171245569","171245569","AU","Australia"
++"10.53.0.2","10.53.0.2","171245570","171245570","US","United States"
++"10.53.0.3","10.53.0.3","171245571","171245571","GB","United Kingdom"
++"10.53.0.4","10.53.0.4","171245572","171245572","CA","Canada"
++"10.53.0.5","10.53.0.5","171245573","171245573","CL","Chile"
++"10.53.0.6","10.53.0.6","171245574","171245574","DE","Germany"
++"10.53.0.7","10.53.0.7","171245575","171245575","EH","Western Sahara"
++EOF
+diff --git a/bin/tests/system/geoip/geoip.c b/bin/tests/system/geoip/geoip.c
+new file mode 100644
+index 0000000..e0dadad
+--- /dev/null
++++ b/bin/tests/system/geoip/geoip.c
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#include <config.h>
++#include <isc/util.h>
++
++int
++main(int argc, char **argv) {
++
++	UNUSED(argc);
++	UNUSED(argv);
++
++#ifdef HAVE_GEOIP
++	return (0);
++#else
++	return (1);
++#endif
++}
+diff --git a/bin/tests/system/geoip/ns2/example.db.in b/bin/tests/system/geoip/ns2/example.db.in
+new file mode 100644
+index 0000000..52a233b
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/example.db.in
+@@ -0,0 +1,24 @@
++; Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
++;
++; Permission to use, copy, modify, and/or distribute this software for any
++; purpose with or without fee is hereby granted, provided that the above
++; copyright notice and this permission notice appear in all copies.
++;
++; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++; PERFORMANCE OF THIS SOFTWARE.
++
++$TTL 300	; 5 minutes
++@			IN SOA	mname1. . (
++				2000042407 ; serial
++				20         ; refresh (20 seconds)
++				20         ; retry (20 seconds)
++				1814400    ; expire (3 weeks)
++				3600       ; minimum (1 hour)
++				)
++			NS	ns2
++ns2			A	10.53.0.2
+diff --git a/bin/tests/system/geoip/ns2/named1.conf b/bin/tests/system/geoip/ns2/named1.conf
+new file mode 100644
+index 0000000..66aca6f
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named1.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip db country country AU; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip db country country US; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip db country country GB; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip db country country CA; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip db country country CL; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip db country country DE; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip db country country EH; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named10.conf b/bin/tests/system/geoip/ns2/named10.conf
+new file mode 100644
+index 0000000..2dd52ae
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named10.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip asnum "AS100001"; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip asnum "AS100002"; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip asnum "AS100003"; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip asnum "AS100004"; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip asnum "AS100005"; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip asnum "AS100006"; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip asnum "AS100007"; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named11.conf b/bin/tests/system/geoip/ns2/named11.conf
+new file mode 100644
+index 0000000..af87edf
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named11.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip domain one.de; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip domain two.com; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip domain three.com; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip domain four.com; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip domain five.es; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip domain six.it; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip domain seven.org; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named12.conf b/bin/tests/system/geoip/ns2/named12.conf
+new file mode 100644
+index 0000000..85c0d32
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named12.conf
+@@ -0,0 +1,80 @@
++/*
++ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-sha256;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip netspeed 0; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip netspeed 1; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip netspeed 2; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip netspeed 3; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named13.conf b/bin/tests/system/geoip/ns2/named13.conf
+new file mode 100644
+index 0000000..a650a63
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named13.conf
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++acl blocking {
++	geoip db country country AU;
++};
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++	blackhole { blocking; };
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-sha256;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
+diff --git a/bin/tests/system/geoip/ns2/named14.conf b/bin/tests/system/geoip/ns2/named14.conf
+new file mode 100644
+index 0000000..f92d252
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named14.conf
+@@ -0,0 +1,112 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-sha256;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++acl gAU { geoip db country country AU; };
++acl gUS { geoip db country country US; };
++acl gGB { geoip db country country GB; };
++acl gCA { geoip db country country CA; };
++acl gCL { geoip db country country CL; };
++acl gDE { geoip db country country DE; };
++acl gEH { geoip db country country EH; };
++
++view one {
++	match-clients { gAU; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { gUS; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { gGB; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { gCA; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { gCL; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { gDE; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { gEH; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named15.conf b/bin/tests/system/geoip/ns2/named15.conf
+new file mode 100644
+index 0000000..6ac837b
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named15.conf
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { fd92:7065:b8e:ffff::2; };
++	recursion no;
++	geoip-directory "../data2";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-sha256;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view two {
++	match-clients { geoip country US; };
++	zone "example" {
++		type master;
++		file "../ns2/example2.db";
++	};
++};
++
++view none {
++	zone "example" {
++		type master;
++		file "examplebogus.db";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named2.conf b/bin/tests/system/geoip/ns2/named2.conf
+new file mode 100644
+index 0000000..67a5155
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named2.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip db country country AUS; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip db country country USA; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip db country country GBR; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip db country country CAN; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip db country country CHL; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip db country country DEU; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip db country country ESH; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named3.conf b/bin/tests/system/geoip/ns2/named3.conf
+new file mode 100644
+index 0000000..65113a6
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named3.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip db country country Australia; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip db country country "United States"; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip db country country "United Kingdom"; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip db country country Canada; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip db country country Chile; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip db country country Germany; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip db country country "Western Sahara"; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named4.conf b/bin/tests/system/geoip/ns2/named4.conf
+new file mode 100644
+index 0000000..d2393d5
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named4.conf
+@@ -0,0 +1,96 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip region CA; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view three {
++	match-clients { geoip region OK; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip region VA; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip region GA; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip region CO; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip region AK; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named5.conf b/bin/tests/system/geoip/ns2/named5.conf
+new file mode 100644
+index 0000000..011e310
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named5.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip db region region "California"; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip db region region "British Columbia"; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip db region region "Oklahoma"; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip db region country AU; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip db region region "Colorado"; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip db region region "Ontario"; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip db region country NL; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named6.conf b/bin/tests/system/geoip/ns2/named6.conf
+new file mode 100644
+index 0000000..7ef7b19
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named6.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { fd92:7065:b8e:ffff::1; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip city "Redwood City"; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip city "Santa Cruz"; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip city "Oklahoma City"; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip city "Ashland"; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip city "Atlanta"; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip city "Morrison"; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip city "Ketchikan"; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named7.conf b/bin/tests/system/geoip/ns2/named7.conf
+new file mode 100644
+index 0000000..118bdbe
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named7.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip isp "One Systems, Inc."; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip isp "Two Technology Ltd."; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip isp "Three Network Labs"; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip isp "Four University"; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip isp "Five Telecom"; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip isp "Six Company"; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip isp "Seven Communications"; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named8.conf b/bin/tests/system/geoip/ns2/named8.conf
+new file mode 100644
+index 0000000..9cb5c0a
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named8.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip org "One Systems, Inc."; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip org "Two Technology Ltd."; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip org "Three Network Labs"; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip org "Four University"; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip org "Five Telecom"; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip org "Six Company"; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip org "Seven Communications"; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/ns2/named9.conf b/bin/tests/system/geoip/ns2/named9.conf
+new file mode 100644
+index 0000000..af2f7ff
+--- /dev/null
++++ b/bin/tests/system/geoip/ns2/named9.conf
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "../data";
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
++};
++
++view one {
++	match-clients { geoip asnum "AS100001 One Systems, Inc."; };
++	zone "example" {
++		type master;
++		file "example1.db";
++	};
++};
++
++view two {
++	match-clients { geoip asnum "AS100002 Two Technology Ltd."; };
++	zone "example" {
++		type master;
++		file "example2.db";
++	};
++};
++
++view three {
++	match-clients { geoip asnum "AS100003 Three Network Labs"; };
++	zone "example" {
++		type master;
++		file "example3.db";
++	};
++};
++
++view four {
++	match-clients { geoip asnum "AS100004 Four University"; };
++	zone "example" {
++		type master;
++		file "example4.db";
++	};
++};
++
++view five {
++	match-clients { geoip asnum "AS100005 Five Telecom"; };
++	zone "example" {
++		type master;
++		file "example5.db";
++	};
++};
++
++view six {
++	match-clients { geoip asnum "AS100006 Six Company"; };
++	zone "example" {
++		type master;
++		file "example6.db";
++	};
++};
++
++view seven {
++	match-clients { geoip asnum "AS100007 Seven Communications"; };
++	zone "example" {
++		type master;
++		file "example7.db";
++	};
++};
++
++view none {
++	match-clients { any; };
++	zone "example" {
++		type master;
++		file "example.db.in";
++	};
++};
+diff --git a/bin/tests/system/geoip/options.conf b/bin/tests/system/geoip/options.conf
+new file mode 100644
+index 0000000..b4d46cb
+--- /dev/null
++++ b/bin/tests/system/geoip/options.conf
+@@ -0,0 +1,42 @@
++/*
++ * Copyright (C) 2015  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++// NS2
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.2;
++	notify-source 10.53.0.2;
++	transfer-source 10.53.0.2;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.2; };
++	listen-on-v6 { none; };
++	recursion no;
++	geoip-directory "data";
++	allow-query {
++		geoip area 831;
++		geoip areacode 831;
++		geoip metro 828;
++		geoip metrocode 828;
++		geoip tz PST;
++		geoip timezone PST;
++		geoip postal 95060;
++		geoip postalcode 95060;
++	};
++};
++
+diff --git a/bin/tests/system/geoip/prereq.sh b/bin/tests/system/geoip/prereq.sh
+new file mode 100644
+index 0000000..b78be41
+--- /dev/null
++++ b/bin/tests/system/geoip/prereq.sh
+@@ -0,0 +1,23 @@
++#!/bin/sh
++#
++# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++if ./geoip
++then
++    :
++else
++    echo "I:This test requires GeoIP support." >&2
++    exit 1
++fi
+diff --git a/bin/tests/system/geoip/setup.sh b/bin/tests/system/geoip/setup.sh
+new file mode 100644
+index 0000000..5c5e2ca
+--- /dev/null
++++ b/bin/tests/system/geoip/setup.sh
+@@ -0,0 +1,27 @@
++#!/bin/sh
++#
++# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++sh clean.sh
++
++cp ns2/named1.conf ns2/named.conf
++
++for i in 1 2 3 4 5 6 7 other bogus; do
++        cp ns2/example.db.in ns2/example${i}.db
++        echo "@ IN TXT \"$i\"" >> ns2/example$i.db
++done
++
++mkdir -p data2
++cp data/GeoIPv6.dat data2/
+diff --git a/bin/tests/system/geoip/tests.sh b/bin/tests/system/geoip/tests.sh
+new file mode 100644
+index 0000000..07635b1
+--- /dev/null
++++ b/bin/tests/system/geoip/tests.sh
+@@ -0,0 +1,328 @@
++#!/bin/sh
++#
++# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++SYSTEMTESTTOP=..
++. $SYSTEMTESTTOP/conf.sh
++
++status=0
++n=0
++
++rm -f dig.out.*
++
++DIGOPTS="+tcp +short -p 5300 @10.53.0.2"
++DIGOPTS6="+tcp +short -p 5300 @fd92:7065:b8e:ffff::2"
++
++n=`expr $n + 1`
++echo "I:checking GeoIP country database by code ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named2.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP country database by three-letter code ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named3.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP country database by name ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named4.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP region code, no specified database ($n)"
++ret=0
++lret=0
++# skipping 2 on purpose here; it has the same region code as 1
++for i in 1 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named5.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP region database by region name and country code ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named6.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++if $TESTSOCK6 fd92:7065:b8e:ffff::3
++then
++  n=`expr $n + 1`
++  echo "I:checking GeoIP city database by city name using IPv6 ($n)"
++  ret=0
++  $DIG +tcp +short -p 5300 @fd92:7065:b8e:ffff::1 -6 txt example -b fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
++  [ $ret -eq 0 ] || echo "I:failed"
++  status=`expr $status + $ret`
++else
++  echo "I:IPv6 unavailable; skipping"
++fi
++
++n=`expr $n + 1`
++echo "I:checking GeoIP city database by city name ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named7.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP isp database ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named8.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP org database ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named9.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP asnum database ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named10.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP asnum database - ASNNNN only ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named11.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP domain database ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named12.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP netspeed database ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named13.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP blackhole ACL ($n)"
++ret=0
++$DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n || ret=1
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 status 2>&1 > rndc.out.ns2.test$n || ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:reloading server"
++cp -f ns2/named14.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++
++n=`expr $n + 1`
++echo "I:checking GeoIP country database by code (using nested ACLs) ($n)"
++ret=0
++lret=0
++for i in 1 2 3 4 5 6 7; do
++    $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1
++    j=`cat dig.out.ns2.test$n.$i | tr -d '"'`
++    [ "$i" = "$j" ] || lret=1
++    [ $lret -eq 1 ] && break
++done
++[ $lret -eq 1 ] && ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++n=`expr $n + 1`
++echo "I:reloading server with different geoip-directory ($n)"
++ret=0
++cp -f ns2/named15.conf ns2/named.conf
++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
++sleep 3
++awk '/using "..\/data2" as GeoIP directory/ {m=1} ; { if (m>0) { print } }' ns2/named.run | grep "GeoIP City .* DB not available" > /dev/null || ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++n=`expr $n + 1`
++echo "I:checking GeoIP v4/v6 when only IPv6 database is available ($n)"
++ret=0
++$DIG $DIGOPTS -4 txt example -b 10.53.0.2 > dig.out.ns2.test$n.1 || ret=1
++j=`cat dig.out.ns2.test$n.1 | tr -d '"'`
++[ "$j" = "bogus" ] || ret=1
++if $TESTSOCK6 fd92:7065:b8e:ffff::2; then
++    $DIG $DIGOPTS6 txt example -b fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n.2 || ret=1
++    j=`cat dig.out.ns2.test$n.2 | tr -d '"'`
++    [ "$j" = "2" ] || ret=1
++fi
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++n=`expr $n + 1`
++echo "I:checking other GeoIP options are parsed correctly ($n)"
++ret=0
++$CHECKCONF options.conf || ret=1
++[ $ret -eq 0 ] || echo "I:failed"
++status=`expr $status + $ret`
++
++echo "I:exit status: $status"
++exit $status
+diff --git a/config.h.in b/config.h.in
+index f2eb59a..6ed8381 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -214,6 +214,15 @@ int sigwait(const unsigned int *set, int *sig);
+ /* Define to 1 if you have the <fcntl.h> header file. */
+ #undef HAVE_FCNTL_H
+ 
++/* Build with GeoIP support */
++#undef HAVE_GEOIP
++
++/* Build with GeoIP City IPv6 support */
++#undef HAVE_GEOIP_CITY_V6
++
++/* Build with GeoIP Country IPv6 support */
++#undef HAVE_GEOIP_V6
++
+ /* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+ #undef HAVE_GSSAPI_GSSAPI_H
+ 
+diff --git a/configure.in b/configure.in
+index 24eafb7..5b56172 100644
+--- a/configure.in
++++ b/configure.in
+@@ -1252,6 +1252,99 @@ if test "$have_clock_gt" = "yes"; then
+ fi
+ 
+ 
++GEOIPLINKSRCS=
++GEOIPLINKOBJS=
++AC_ARG_WITH(geoip,
++[  --with-geoip=PATH       Build with GeoIP support (yes|no|path)],
++    use_geoip="$withval", use_geoip="no")
++
++if test "$use_geoip" = "yes"
++then
++	for d in /usr /usr/local /opt/local
++	do
++		if test -f $d/include/GeoIP.h
++		then
++			use_geoip=$d
++			break
++		fi
++	done
++fi
++
++case "$use_geoip" in
++	no|'')
++		AC_MSG_CHECKING([for GeoIP support])
++		AC_MSG_RESULT([disabled])
++		;;
++	*)
++		if test -d "$use_geoip" -o -L "$use_geoip"
++		then
++			CFLAGS="$CFLAGS -I$use_geoip/include"
++			CPPFLAGS="$CPPFLAGS -I$use_geoip/include"
++			LIBS="$LIBS -L$use_geoip/lib"
++			case "$host_os" in
++				netbsd*|openbsd*|solaris*)
++					LIBS="$LIBS -Wl,-rpath=$use_geoip/lib"
++					;;
++			esac
++		elif test "$use_geoip" = "yes"
++                then
++			AC_MSG_ERROR([GeoIP path not found])
++		else
++			AC_MSG_ERROR([GeoIP path $use_geoip does not exist])
++		fi
++		AC_CHECK_HEADER(GeoIP.h, [],
++			[AC_MSG_ERROR([GeoIP header file not found])]
++		)
++		AC_SEARCH_LIBS(GeoIP_open, GeoIP, [],
++			[AC_MSG_ERROR([GeoIP library not found])]
++		)
++		AC_SEARCH_LIBS(fabsf, m, [],
++			[AC_MSG_ERROR([Math library not found])]
++		)
++                AC_DEFINE(HAVE_GEOIP, 1, Build with GeoIP support)
++		GEOIPLINKSRCS='${GEOIPLINKSRCS}'
++		GEOIPLINKOBJS='${GEOIPLINKOBJS}'
++		AC_MSG_CHECKING([for GeoIP support])
++		AC_MSG_RESULT([yes])
++
++		AC_MSG_CHECKING([for GeoIP Country IPv6 support])
++		AC_COMPILE_IFELSE(
++			[AC_LANG_PROGRAM([
++				#include <GeoIP.h>
++				#include <netinet/in.h>
++			], [
++				struct in6_addr in6;
++				GeoIP_country_name_by_ipnum_v6(NULL, in6);
++			])],
++			[
++				AC_MSG_RESULT([yes])
++                                AC_DEFINE(HAVE_GEOIP_V6, 1, Build with GeoIP Country IPv6 support)
++			],
++			[AC_MSG_RESULT([no])]
++		)
++
++		AC_MSG_CHECKING([for GeoIP City IPv6 support])
++		AC_COMPILE_IFELSE(
++			[AC_LANG_PROGRAM([
++				#include <GeoIP.h>
++				#include <GeoIPCity.h>
++				#include <netinet/in.h>
++			], [
++				struct in6_addr in6;
++                                int i = GEOIP_CITY_EDITION_REV0_V6;
++				GeoIP_record_by_ipnum_v6(NULL, in6);
++			])],
++			[
++				AC_MSG_RESULT([yes])
++                                AC_DEFINE(HAVE_GEOIP_CITY_V6, 1, Build with GeoIP City IPv6 support)
++			],
++			[AC_MSG_RESULT([no])]
++		)
++		;;
++esac
++AC_SUBST(GEOIPLINKSRCS)
++AC_SUBST(GEOIPLINKOBJS)
++
+ AC_MSG_CHECKING(for GSSAPI library)
+ AC_ARG_WITH(gssapi,
+ [  --with-gssapi=PATH      Specify path for system-supplied GSSAPI [[default=yes]]],
+@@ -3962,6 +4055,7 @@ AC_CONFIG_FILES([
+ 	bin/tests/system/dlzexternal/ns1/named.conf
+ 	bin/tests/system/ecdsa/prereq.sh
+ 	bin/tests/system/filter-aaaa/Makefile
++	bin/tests/system/geoip/Makefile
+ 	bin/tests/system/gost/prereq.sh
+ 	bin/tests/system/lwresd/Makefile
+ 	bin/tests/system/rpz/Makefile
+diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
+index bd42e11..92c7b72 100644
+--- a/doc/arm/Bv9ARM-book.xml
++++ b/doc/arm/Bv9ARM-book.xml
+@@ -3410,6 +3410,62 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
+           </tgroup>
+         </informaltable>
+ 
++        <para>
++          When <acronym>BIND</acronym> 9 is built with GeoIP support,
++          ACLs can also be used for geographic access restrictions.
++          This is done by specifying an ACL element of the form:
++          <command>geoip <optional>db <replaceable>database</replaceable></optional> <replaceable>field</replaceable> <replaceable>value</replaceable></command>
++        </para>
++        <para>
++          The <replaceable>field</replaceable> indicates which field
++          to search for a match.  Available fields are "country",
++          "region", "city", "continent", "postal" (postal code),
++          "metro" (metro code), "area" (area code), "tz" (timezone),
++          "isp", "org", "asnum", "domain" and "netspeed".
++        </para>
++        <para>
++          <replaceable>value</replaceable> is the value to searched for
++          within the database.  A string may be quoted if it contains
++          spaces or other special characters.  If this is a "country"
++          search and the string is two characters long, then it must be a
++          standard ISO-3166-1 two-letter country code, and if it is three
++          characters long then it must be an ISO-3166-1 three-letter
++          country code; otherwise it is the full name of the country.
++          Similarly, if this is a "region" search and the string is
++          two characters long, then it must be a standard two-letter state
++          or province abbreviation; otherwise it is the full name of the
++          state or province.
++        </para>
++        <para>
++          The <replaceable>database</replaceable> field indicates which
++          GeoIP database to search for a match.  In most cases this is
++          unnecessary, because most search fields can only be found in
++          a single database.  However, searches for country can be
++          answered from the "city", "region", or "country" databases,
++          and searches for region (i.e., state or provice) can be
++          answered from the "city" or "region" databases.  For these
++          search types, specifying a <replaceable>database</replaceable>
++          will force the query to be answered from that database and no
++          other.  If <replaceable>database</replaceable> is not
++          specified, then these queries will be answered from the "city",
++          database if it is installed, or the "region" database if it is
++          installed, or the "country" database, in that order.
++        </para>
++        <para>
++          Some example GeoIP ACLs:
++        </para>
++        <programlisting>geoip country US;
++geoip country JAP;
++geoip db country country Canada;
++geoip db region region WA;
++geoip city "San Francisco";
++geoip region Oklahoma;
++geoip postal 95062;
++geoip tz "America/Los_Angeles";
++geoip org "Internet Systems Consortium";
++</programlisting>
++
++
+       </sect2>
+       <sect2>
+         <title><command>controls</command> Statement Grammar</title>
+@@ -4690,6 +4746,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
+     <optional> hostname <replaceable>hostname_string</replaceable>; </optional>
+     <optional> server-id <replaceable>server_id_string</replaceable>; </optional>
+     <optional> directory <replaceable>path_name</replaceable>; </optional>
++    <optional> geoip-directory <replaceable>path_name</replaceable>; </optional>
+     <optional> key-directory <replaceable>path_name</replaceable>; </optional>
+     <optional> managed-keys-directory <replaceable>path_name</replaceable>; </optional>
+     <optional> named-xfer <replaceable>path_name</replaceable>; </optional>
+@@ -5046,6 +5103,21 @@ badresp:1,adberr:0,findfail:0,valfail:0]
+           </varlistentry>
+ 
+           <varlistentry>
++	    <term><command>geoip-directory</command></term>
++	    <listitem>
++	      <para>
++		Specifies the directory containing GeoIP
++		<filename>.dat</filename> database files for GeoIP
++		initialization.  By default, this option is unset
++		and the GeoIP support will use libGeoIP's
++		built-in directory.
++		(For details, see <xref linkend="acl"/> about the
++		<command>geoip</command> ACL.)
++	      </para>
++	    </listitem>
++	  </varlistentry>
++
++	  <varlistentry>
+             <term><command>key-directory</command></term>
+             <listitem>
+               <para>
+diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in
+index 41fac95..0cc82f1 100644
+--- a/lib/dns/Makefile.in
++++ b/lib/dns/Makefile.in
+@@ -56,6 +56,8 @@ DSTOBJS =	@DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ @PKCS11LINKOBJS@ \
+ 
+ RRLOBJS =	rrl.@O@
+ 
++GEOIPLINKOBJS = geoip.@O@
++
+ # Alphabetically
+ DNSOBJS =	acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
+ 		cache.@O@ callbacks.@O@ clientinfo.@O@ compress.@O@ \
+@@ -75,7 +77,7 @@ DNSOBJS =	acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
+ 		tsec.@O@ tsig.@O@ ttl.@O@ update.@O@ validator.@O@ \
+ 		version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ zt.@O@
+ 
+-OBJS=		${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} @RRLLINKOBJS@
++OBJS=		${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} @RRLLINKOBJS@ @GEOIPLINKOBJS@
+ 
+ # Alphabetically
+ OPENSSLGOSTLINKSRCS = opensslgost_link.c
+@@ -90,6 +92,8 @@ DSTSRCS =	@DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ @PKCS11LINKSRCS@ \
+ 		dst_result.c gssapi_link.c gssapictx.c \
+ 		hmac_link.c key.c
+ 
++GEOIOLINKSRCS = geoip.c
++
+ DNSSRCS =	acache.c acl.c adb.c byaddr.c \
+ 		cache.c callbacks.c clientinfo.c compress.c \
+ 		db.c dbiterator.c dbtable.c diff.c dispatch.c \
+@@ -107,7 +111,7 @@ DNSSRCS =	acache.c acl.c adb.c byaddr.c \
+ 
+ RRLSRCS =	rrl.c
+ 
+-SRCS = ${DSTSRCS} ${DNSSRCS} @RRLLINKSRCS@
++SRCS = ${DSTSRCS} ${DNSSRCS} @RRLLINKSRCS@ @GEOIPLINKSRCS@
+ 
+ SUBDIRS =	include
+ TARGETS =	include/dns/enumtype.h include/dns/enumclass.h \
+diff --git a/lib/dns/acl.c b/lib/dns/acl.c
+index 3221d30..aad9aa5 100644
+--- a/lib/dns/acl.c
++++ b/lib/dns/acl.c
+@@ -29,6 +29,7 @@
+ #include <dns/acl.h>
+ #include <dns/iptable.h>
+ 
++
+ /*
+  * Create a new ACL, including an IP table and an array with room
+  * for 'n' ACL elements.  The elements are uninitialized and the
+@@ -336,6 +337,14 @@ dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos)
+ 				return result;
+ 		}
+ 
++#ifdef HAVE_GEOIP
++		/* Duplicate GeoIP data */
++		if (source->elements[i].type == dns_aclelementtype_geoip) {
++			dest->elements[nelem + i].geoip_elem =
++				source->elements[i].geoip_elem;
++		}
++#endif
++
+ 		/* reverse sense of positives if this is a negative acl */
+ 		if (!pos && source->elements[i].negative == ISC_FALSE) {
+ 			dest->elements[nelem + i].negative = ISC_TRUE;
+@@ -386,9 +395,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
+ 			if (matchelt != NULL)
+ 				*matchelt = e;
+ 			return (ISC_TRUE);
+-		} else {
++		} else
+ 			return (ISC_FALSE);
+-		}
+ 
+ 	case dns_aclelementtype_nestedacl:
+ 		inner = e->nestedacl;
+@@ -406,6 +414,12 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr,
+ 		inner = env->localnets;
+ 		break;
+ 
++#ifdef HAVE_GEOIP
++	case dns_aclelementtype_geoip:
++		if (env == NULL || env->geoip == NULL) 
++			return (ISC_FALSE);
++		return (dns_geoip_match(reqaddr, env->geoip, &e->geoip_elem));
++#endif
+ 	default:
+ 		/* Should be impossible. */
+ 		INSIST(0);
+@@ -560,7 +574,7 @@ dns_acl_isinsecure(const dns_acl_t *a) {
+ 	insecure = insecure_prefix_found;
+ 	UNLOCK(&insecure_prefix_lock);
+ 	if (insecure)
+-		return(ISC_TRUE);
++		return (ISC_TRUE);
+ 
+ 	/* Now check non-radix elements */
+ 	for (i = 0; i < a->length; i++) {
+@@ -609,6 +623,9 @@ dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) {
+ 	if (result != ISC_R_SUCCESS)
+ 		goto cleanup_localhost;
+ 	env->match_mapped = ISC_FALSE;
++#ifdef HAVE_GEOIP
++	env->geoip = NULL;
++#endif
+ 	return (ISC_R_SUCCESS);
+ 
+  cleanup_localhost:
+diff --git a/lib/dns/geoip.c b/lib/dns/geoip.c
+new file mode 100644
+index 0000000..5387ebb
+--- /dev/null
++++ b/lib/dns/geoip.c
+@@ -0,0 +1,820 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*! \file */
++
++#include <config.h>
++
++#include <isc/util.h>
++
++#include <isc/mem.h>
++#include <isc/once.h>
++#include <isc/string.h>
++
++#include <dns/acl.h>
++#include <dns/geoip.h>
++
++#include <isc/thread.h>
++#include <math.h>
++#include <netinet/in.h>
++#include <dns/log.h>
++
++#ifdef HAVE_GEOIP
++#include <GeoIP.h>
++#include <GeoIPCity.h>
++
++/*
++ * This structure preserves state from the previous GeoIP lookup,
++ * so that successive lookups for the same data from the same IP
++ * address will not require repeated calls into the GeoIP library
++ * to look up data in the database. This should improve performance
++ * somewhat.
++ *
++ * For lookups in the City and Region databases, we preserve pointers
++ * to the GeoIPRecord and GeoIPregion structures; these will need to be
++ * freed by GeoIPRecord_delete() and GeoIPRegion_delete().
++ *
++ * for lookups in ISP, AS, Org and Domain we prserve a pointer to
++ * the returned name; these must be freed by free().
++ *
++ * For lookups in Country we preserve a pointer to the text of
++ * the country code, name, etc (we use a different pointer for this
++ * than for the names returned by Org, ISP, etc, because those need
++ * to be freed but country lookups do not).
++ *
++ * For lookups in Netspeed we preserve the returned ID.
++ *
++ * XXX: Currently this mechanism is only used for IPv4 lookups; the
++ * family and addr6 fields are to be used IPv6 is added.
++ */
++typedef struct geoip_state {
++	isc_uint16_t subtype;
++	unsigned int family;
++	isc_uint32_t ipnum;
++	geoipv6_t ipnum6;
++	GeoIPRecord *record;
++	GeoIPRegion *region;
++	const char *text;
++	char *name;
++	int id;
++	isc_mem_t *mctx;
++} geoip_state_t;
++
++#ifdef ISC_PLATFORM_USETHREADS
++static isc_mutex_t key_mutex;
++static isc_boolean_t state_key_initialized = ISC_FALSE;
++static isc_thread_key_t state_key;
++static isc_once_t mutex_once = ISC_ONCE_INIT;
++static isc_mem_t *state_mctx = NULL;
++
++static void
++key_mutex_init(void) {
++	RUNTIME_CHECK(isc_mutex_init(&key_mutex) == ISC_R_SUCCESS);
++}
++
++static void
++free_state(void *arg) {
++	geoip_state_t *state = arg;
++	if (state != NULL && state->record != NULL)
++		GeoIPRecord_delete(state->record);
++	if (state != NULL)
++		isc_mem_putanddetach(&state->mctx,
++				     state, sizeof(geoip_state_t));
++	isc_thread_key_setspecific(state_key, NULL);
++}
++
++static isc_result_t
++state_key_init(void) {
++	isc_result_t result;
++
++	result = isc_once_do(&mutex_once, key_mutex_init);
++	if (result != ISC_R_SUCCESS)
++		return (result);
++
++	if (!state_key_initialized) {
++		LOCK(&key_mutex);
++		if (!state_key_initialized) {
++			int ret;
++
++			if (state_mctx == NULL)
++				result = isc_mem_create2(0, 0, &state_mctx, 0);
++			if (result != ISC_R_SUCCESS)
++				goto unlock;
++			isc_mem_setname(state_mctx, "geoip_state", NULL);
++			isc_mem_setdestroycheck(state_mctx, ISC_FALSE);
++
++			ret = isc_thread_key_create(&state_key, free_state);
++			if (ret == 0)
++				state_key_initialized = ISC_TRUE;
++			else
++				result = ISC_R_FAILURE;
++		}
++ unlock:
++		UNLOCK(&key_mutex);
++	}
++
++	return (result);
++}
++#else
++static geoip_state_t saved_state;
++#endif
++
++static void
++clean_state(geoip_state_t *state) {
++	if (state == NULL)
++		return;
++
++	if (state->record != NULL) {
++		GeoIPRecord_delete(state->record);
++		state->record = NULL;
++	}
++	if (state->region != NULL) {
++		GeoIPRegion_delete(state->region);
++		state->region = NULL;
++	}
++	if (state->name != NULL) {
++		free (state->name);
++		state->name = NULL;
++	}
++	state->ipnum = 0;
++	state->text = NULL;
++	state->id = 0;
++}
++
++static isc_result_t
++set_state(unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6,
++	  dns_geoip_subtype_t subtype, GeoIPRecord *record,
++	  GeoIPRegion *region, char *name, const char *text, int id)
++{
++	geoip_state_t *state = NULL;
++#ifdef ISC_PLATFORM_USETHREADS
++	isc_result_t result;
++
++	result = state_key_init();
++	if (result != ISC_R_SUCCESS)
++		return (result);
++
++	state = (geoip_state_t *) isc_thread_key_getspecific(state_key);
++	if (state == NULL) {
++		state = (geoip_state_t *) isc_mem_get(state_mctx,
++						      sizeof(geoip_state_t));
++		if (state == NULL)
++			return (ISC_R_NOMEMORY);
++		memset(state, 0, sizeof(*state));
++
++		result = isc_thread_key_setspecific(state_key, state);
++		if (result != ISC_R_SUCCESS) {
++			isc_mem_put(state_mctx, state, sizeof(geoip_state_t));
++			return (result);
++		}
++
++		isc_mem_attach(state_mctx, &state->mctx);
++	} else
++		clean_state(state);
++#else
++	state = &saved_state;
++	clean_state(state);
++#endif
++
++	if (family == AF_INET)
++		state->ipnum = ipnum;
++	else
++		state->ipnum6 = *ipnum6;
++
++	state->family = family;
++	state->subtype = subtype;
++	state->record = record;
++	state->region = region;
++	state->name = name;
++	state->text = text;
++	state->id = id;
++
++	return (ISC_R_SUCCESS);
++}
++
++static geoip_state_t *
++get_state_for(unsigned int family, isc_uint32_t ipnum,
++	      const geoipv6_t *ipnum6)
++{
++	geoip_state_t *state;
++
++#ifdef ISC_PLATFORM_USETHREADS
++	isc_result_t result;
++
++	result = state_key_init();
++	if (result != ISC_R_SUCCESS)
++		return (NULL);
++
++	state = (geoip_state_t *) isc_thread_key_getspecific(state_key);
++	if (state == NULL)
++		return (NULL);
++#else
++	state = &saved_state;
++#endif
++
++	if (state->family == family &&
++	    ((state->family == AF_INET && state->ipnum == ipnum) ||
++	     (state->family == AF_INET6 && ipnum6 != NULL &&
++	      memcmp(state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0)))
++		return (state);
++
++	return (NULL);
++}
++
++/*
++ * Country lookups are performed if the previous lookup was from a
++ * different IP address than the current, or was for a search of a
++ * different subtype.
++ */
++static const char *
++country_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
++	       unsigned int family,
++	       isc_uint32_t ipnum, const geoipv6_t *ipnum6)
++{
++	geoip_state_t *prev_state = NULL;
++	const char *text = NULL;
++
++	REQUIRE(db != NULL);
++
++#ifndef HAVE_GEOIP_V6
++	/* no IPv6 support? give up now */
++	if (family == AF_INET6)
++		return (NULL);
++#endif
++
++	prev_state = get_state_for(family, ipnum, ipnum6);
++	if (prev_state != NULL && prev_state->subtype == subtype)
++		text = prev_state->text;
++
++	if (text == NULL) {
++		switch (subtype) {
++		case dns_geoip_country_code:
++			if (family == AF_INET)
++				text = GeoIP_country_code_by_ipnum(db, ipnum);
++#ifdef HAVE_GEOIP_V6
++			else
++				text = GeoIP_country_code_by_ipnum_v6(db,
++								      *ipnum6);
++#endif
++			break;
++		case dns_geoip_country_code3:
++			if (family == AF_INET)
++				text = GeoIP_country_code3_by_ipnum(db, ipnum);
++#ifdef HAVE_GEOIP_V6
++			else
++				text = GeoIP_country_code3_by_ipnum_v6(db,
++								       *ipnum6);
++#endif
++			break;
++		case dns_geoip_country_name:
++			if (family == AF_INET)
++				text = GeoIP_country_name_by_ipnum(db, ipnum);
++#ifdef HAVE_GEOIP_V6
++			else
++				text = GeoIP_country_name_by_ipnum_v6(db,
++								      *ipnum6);
++#endif
++			break;
++		default:
++			INSIST(0);
++		}
++
++		set_state(family, ipnum, ipnum6, subtype,
++			  NULL, NULL, NULL, text, 0);
++	}
++
++	return (text);
++}
++
++static char *
++city_string(GeoIPRecord *record, dns_geoip_subtype_t subtype, int *maxlen) {
++	const char *s;
++	char *deconst;
++
++	REQUIRE(record != NULL);
++	REQUIRE(maxlen != NULL);
++
++	/* Set '*maxlen' to the maximum length of this subtype, if any */
++	switch (subtype) {
++	case dns_geoip_city_countrycode:
++	case dns_geoip_city_region:
++	case dns_geoip_city_continentcode:
++		*maxlen = 2;
++		break;
++
++	case dns_geoip_city_countrycode3:
++		*maxlen = 3;
++		break;
++
++	default:
++		/* No fixed length; just use strcasecmp() for comparison */
++		*maxlen = 255;
++	}
++
++	switch (subtype) {
++	case dns_geoip_city_countrycode:
++		return (record->country_code);
++	case dns_geoip_city_countrycode3:
++		return (record->country_code3);
++	case dns_geoip_city_countryname:
++		return (record->country_name);
++	case dns_geoip_city_region:
++		return (record->region);
++	case dns_geoip_city_regionname:
++		s = GeoIP_region_name_by_code(record->country_code,
++					      record->region);
++		DE_CONST(s, deconst);
++		return (deconst);
++	case dns_geoip_city_name:
++		return (record->city);
++	case dns_geoip_city_postalcode:
++		return (record->postal_code);
++	case dns_geoip_city_continentcode:
++		return (record->continent_code);
++	case dns_geoip_city_timezonecode:
++		s = GeoIP_time_zone_by_country_and_region(record->country_code,
++							  record->region);
++		DE_CONST(s, deconst);
++		return (deconst);
++	default:
++		INSIST(0);
++	}
++}
++
++static isc_boolean_t
++is_city(dns_geoip_subtype_t subtype) {
++	switch (subtype) {
++	case dns_geoip_city_countrycode:
++	case dns_geoip_city_countrycode3:
++	case dns_geoip_city_countryname:
++	case dns_geoip_city_region:
++	case dns_geoip_city_regionname:
++	case dns_geoip_city_name:
++	case dns_geoip_city_postalcode:
++	case dns_geoip_city_continentcode:
++	case dns_geoip_city_timezonecode:
++	case dns_geoip_city_metrocode:
++	case dns_geoip_city_areacode:
++		return (ISC_TRUE);
++	default:
++		return (ISC_FALSE);
++	}
++}
++
++/*
++ * GeoIPRecord lookups are performed if the previous lookup was
++ * from a different IP address than the current, or was for a search
++ * outside the City database.
++ */
++static GeoIPRecord *
++city_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
++	    unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6)
++{
++	GeoIPRecord *record = NULL;
++	geoip_state_t *prev_state = NULL;
++
++	REQUIRE(db != NULL);
++
++#ifndef HAVE_GEOIP_V6
++	/* no IPv6 support? give up now */
++	if (family == AF_INET6)
++		return (NULL);
++#endif
++
++	prev_state = get_state_for(family, ipnum, ipnum6);
++	if (prev_state != NULL && is_city(prev_state->subtype))
++		record = prev_state->record;
++
++	if (record == NULL) {
++		if (family == AF_INET)
++			record = GeoIP_record_by_ipnum(db, ipnum);
++#ifdef HAVE_GEOIP_V6
++		else
++			record = GeoIP_record_by_ipnum_v6(db, *ipnum6);
++#endif
++		if (record == NULL)
++			return (NULL);
++
++		set_state(family, ipnum, ipnum6, subtype,
++			  record, NULL, NULL, NULL, 0);
++	}
++
++	return (record);
++}
++
++static char *
++region_string(GeoIPRegion *region, dns_geoip_subtype_t subtype, int *maxlen) {
++	const char *s;
++	char *deconst;
++
++	REQUIRE(region != NULL);
++	REQUIRE(maxlen != NULL);
++
++	switch (subtype) {
++	case dns_geoip_region_countrycode:
++		*maxlen = 2;
++		return (region->country_code);
++	case dns_geoip_region_code:
++		*maxlen = 2;
++		return (region->region);
++	case dns_geoip_region_name:
++		*maxlen = 255;
++		s = GeoIP_region_name_by_code(region->country_code,
++					      region->region);
++		DE_CONST(s, deconst);
++		return (deconst);
++	default:
++		INSIST(0);
++	}
++}
++
++static isc_boolean_t
++is_region(dns_geoip_subtype_t subtype) {
++	switch (subtype) {
++	case dns_geoip_region_countrycode:
++	case dns_geoip_region_code:
++		return (ISC_TRUE);
++	default:
++		return (ISC_FALSE);
++	}
++}
++
++/*
++ * GeoIPRegion lookups are performed if the previous lookup was
++ * from a different IP address than the current, or was for a search
++ * outside the Region database.
++ */
++static GeoIPRegion *
++region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
++	GeoIPRegion *region = NULL;
++	geoip_state_t *prev_state = NULL;
++
++	REQUIRE(db != NULL);
++
++	prev_state = get_state_for(AF_INET, ipnum, NULL);
++	if (prev_state != NULL && is_region(prev_state->subtype))
++		region = prev_state->region;
++
++	if (region == NULL) {
++		region = GeoIP_region_by_ipnum(db, ipnum);
++		if (region == NULL)
++			return (NULL);
++
++		set_state(AF_INET, ipnum, NULL,
++			  subtype, NULL, region, NULL, NULL, 0);
++	}
++
++	return (region);
++}
++
++/*
++ * ISP, Organization, AS Number and Domain lookups are performed if
++ * the previous lookup was from a different IP address than the current,
++ * or was for a search of a different subtype.
++ */
++static char *
++name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
++	char *name = NULL;
++	geoip_state_t *prev_state = NULL;
++
++	REQUIRE(db != NULL);
++
++	prev_state = get_state_for(AF_INET, ipnum, NULL);
++	if (prev_state != NULL && prev_state->subtype == subtype)
++		name = prev_state->name;
++
++	if (name == NULL) {
++		name = GeoIP_name_by_ipnum(db, ipnum);
++		if (name == NULL)
++			return (NULL);
++
++		set_state(AF_INET, ipnum, NULL,
++			  subtype, NULL, NULL, name, NULL, 0);
++	}
++
++	return (name);
++}
++
++/*
++ * Netspeed lookups are performed if the previous lookup was from a
++ * different IP address than the current, or was for a search of a
++ * different subtype.
++ */
++static int
++netspeed_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
++	geoip_state_t *prev_state = NULL;
++	isc_boolean_t found = ISC_FALSE;
++	int id = -1;
++
++	REQUIRE(db != NULL);
++
++	prev_state = get_state_for(AF_INET, ipnum, NULL);
++	if (prev_state != NULL && prev_state->subtype == subtype) {
++		id = prev_state->id;
++		found = ISC_TRUE;
++	}
++
++	if (!found) {
++		id = GeoIP_id_by_ipnum(db, ipnum);
++		set_state(AF_INET, ipnum, NULL,
++			  subtype, NULL, NULL, NULL, NULL, id);
++	}
++
++	return (id);
++}
++#endif /* HAVE_GEOIP */
++
++#define DB46(addr, geoip, name) \
++	((addr->family == AF_INET) ? (geoip->name##_v4) : (geoip->name##_v6))
++
++#ifdef HAVE_GEOIP
++/*
++ * Find the best database to answer a generic subtype
++ */
++static dns_geoip_subtype_t
++fix_subtype(const isc_netaddr_t *reqaddr, const dns_geoip_databases_t *geoip,
++	    dns_geoip_subtype_t subtype)
++{
++	dns_geoip_subtype_t ret = subtype;
++
++	switch (subtype) {
++	case dns_geoip_countrycode:
++		if (DB46(reqaddr, geoip, city) != NULL)
++			ret = dns_geoip_city_countrycode;
++		else if (reqaddr->family == AF_INET && geoip->region != NULL)
++			ret = dns_geoip_region_countrycode;
++		else if (DB46(reqaddr, geoip, country) != NULL)
++			ret = dns_geoip_country_code;
++		break;
++	case dns_geoip_countrycode3:
++		if (DB46(reqaddr, geoip, city) != NULL)
++			ret = dns_geoip_city_countrycode3;
++		else if (DB46(reqaddr, geoip, country) != NULL)
++			ret = dns_geoip_country_code3;
++		break;
++	case dns_geoip_countryname:
++		if (DB46(reqaddr, geoip, city) != NULL)
++			ret = dns_geoip_city_countryname;
++		else if (DB46(reqaddr, geoip, country) != NULL)
++			ret = dns_geoip_country_name;
++		break;
++	case dns_geoip_region:
++		if (DB46(reqaddr, geoip, city) != NULL)
++			ret = dns_geoip_city_region;
++		else if (reqaddr->family == AF_INET && geoip->region != NULL)
++			ret = dns_geoip_region_code;
++		break;
++	case dns_geoip_regionname:
++		if (DB46(reqaddr, geoip, city) != NULL)
++			ret = dns_geoip_city_regionname;
++		else if (reqaddr->family == AF_INET && geoip->region != NULL)
++			ret = dns_geoip_region_name;
++		break;
++	default:
++		break;
++	}
++
++	return (ret);
++}
++#endif /* HAVE_GEOIP */
++
++isc_boolean_t
++dns_geoip_match(const isc_netaddr_t *reqaddr,
++		const dns_geoip_databases_t *geoip,
++		const dns_geoip_elem_t *elt)
++{
++#ifndef HAVE_GEOIP
++	UNUSED(reqaddr);
++	UNUSED(geoip);
++	UNUSED(elt);
++
++	return (ISC_FALSE);
++#else
++	GeoIP *db;
++	GeoIPRecord *record;
++	GeoIPRegion *region;
++	dns_geoip_subtype_t subtype;
++	isc_uint32_t ipnum = 0;
++	int maxlen = 0, id, family;
++	const char *cs;
++	char *s;
++#ifdef HAVE_GEOIP_V6
++	const geoipv6_t *ipnum6 = NULL;
++#else
++	const void *ipnum6 = NULL;
++#endif
++
++	INSIST(geoip != NULL);
++
++	family = reqaddr->family;
++	switch (family) {
++	case AF_INET:
++		ipnum = ntohl(reqaddr->type.in.s_addr);
++		break;
++	case AF_INET6:
++#ifdef HAVE_GEOIP_V6
++		ipnum6 = &reqaddr->type.in6;
++		break;
++#else
++		return (ISC_FALSE);
++#endif
++	default:
++		return (ISC_FALSE);
++	}
++
++	subtype = fix_subtype(reqaddr, geoip, elt->subtype);
++
++	switch (subtype) {
++	case dns_geoip_country_code:
++		maxlen = 2;
++		goto getcountry;
++
++	case dns_geoip_country_code3:
++		maxlen = 3;
++		goto getcountry;
++
++	case dns_geoip_country_name:
++		maxlen = 255;
++ getcountry:
++		db = DB46(reqaddr, geoip, country);
++		if (db == NULL)
++			return (ISC_FALSE);
++
++		INSIST(elt->as_string != NULL);
++
++		cs = country_lookup(db, subtype, family, ipnum, ipnum6);
++		if (cs != NULL && strncasecmp(elt->as_string, cs, maxlen) == 0)
++			return (ISC_TRUE);
++		break;
++
++	case dns_geoip_city_countrycode:
++	case dns_geoip_city_countrycode3:
++	case dns_geoip_city_countryname:
++	case dns_geoip_city_region:
++	case dns_geoip_city_regionname:
++	case dns_geoip_city_name:
++	case dns_geoip_city_postalcode:
++	case dns_geoip_city_continentcode:
++	case dns_geoip_city_timezonecode:
++		INSIST(elt->as_string != NULL);
++
++		db = DB46(reqaddr, geoip, city);
++		if (db == NULL)
++			return (ISC_FALSE);
++
++		record = city_lookup(db, subtype, family, ipnum, ipnum6);
++		if (record == NULL)
++			break;
++
++		s = city_string(record, subtype, &maxlen);
++		INSIST(maxlen != 0);
++		if (s != NULL && strncasecmp(elt->as_string, s, maxlen) == 0)
++			return (ISC_TRUE);
++		break;
++
++	case dns_geoip_city_metrocode:
++		db = DB46(reqaddr, geoip, city);
++		if (db == NULL)
++			return (ISC_FALSE);
++
++		record = city_lookup(db, subtype, family, ipnum, ipnum6);
++		if (record == NULL)
++			break;
++
++		if (elt->as_int == record->metro_code)
++			return (ISC_TRUE);
++		break;
++
++	case dns_geoip_city_areacode:
++		db = DB46(reqaddr, geoip, city);
++		if (db == NULL)
++			return (ISC_FALSE);
++
++		record = city_lookup(db, subtype, family, ipnum, ipnum6);
++		if (record == NULL)
++			break;
++
++		if (elt->as_int == record->area_code)
++			return (ISC_TRUE);
++		break;
++
++	case dns_geoip_region_countrycode:
++	case dns_geoip_region_code:
++	case dns_geoip_region_name:
++	case dns_geoip_region:
++		if (geoip->region == NULL)
++			return (ISC_FALSE);
++
++		INSIST(elt->as_string != NULL);
++
++		/* Region DB is not supported for IPv6 */
++		if (family == AF_INET6)
++			return (ISC_FALSE);
++
++		region = region_lookup(geoip->region, subtype, ipnum);
++		if (region == NULL)
++			break;
++
++		s = region_string(region, subtype, &maxlen);
++		INSIST(maxlen != 0);
++		if (s != NULL && strncasecmp(elt->as_string, s, maxlen) == 0)
++			return (ISC_TRUE);
++		break;
++
++	case dns_geoip_isp_name:
++		db = geoip->isp;
++		goto getname;
++
++	case dns_geoip_org_name:
++		db = geoip->org;
++		goto getname;
++
++	case dns_geoip_as_asnum:
++		db = geoip->as;
++		goto getname;
++
++	case dns_geoip_domain_name:
++		db = geoip->domain;
++
++ getname:
++		if (db == NULL)
++			return (ISC_FALSE);
++
++		INSIST(elt->as_string != NULL);
++		/* ISP, Org, AS, and Domain are not supported for IPv6 */
++		if (family == AF_INET6)
++			return (ISC_FALSE);
++
++		s = name_lookup(db, subtype, ipnum);
++		if (s != NULL) {
++			size_t l;
++			if (strcasecmp(elt->as_string, s) == 0)
++				return (ISC_TRUE);
++			if (subtype != dns_geoip_as_asnum)
++				break;
++			/*
++			 * Just check if the ASNNNN value matches.
++			 */
++			l = strlen(elt->as_string);
++			if (l > 0U && strchr(elt->as_string, ' ') == NULL &&
++			    strncasecmp(elt->as_string, s, l) == 0 &&
++			    s[l] == ' ')
++				return (ISC_TRUE);
++		}
++		break;
++
++	case dns_geoip_netspeed_id:
++		INSIST(geoip->netspeed != NULL);
++
++		/* Netspeed DB is not supported for IPv6 */
++		if (family == AF_INET6)
++			return (ISC_FALSE);
++
++		id = netspeed_lookup(geoip->netspeed, subtype, ipnum);
++		if (id == elt->as_int)
++			return (ISC_TRUE);
++		break;
++
++	case dns_geoip_countrycode:
++	case dns_geoip_countrycode3:
++	case dns_geoip_countryname:
++	case dns_geoip_regionname:
++		/*
++		 * If these were not remapped by fix_subtype(),
++		 * the database was unavailable. Always return false.
++		 */
++		break;
++
++	default:
++		INSIST(0);
++	}
++
++	return (ISC_FALSE);
++#endif
++}
++
++void
++dns_geoip_shutdown(void) {
++#ifdef HAVE_GEOIP
++	GeoIP_cleanup();
++#ifdef ISC_PLATFORM_USETHREADS
++	if (state_mctx != NULL)
++		isc_mem_detach(&state_mctx);
++#endif
++#else
++	return;
++#endif
++}
+diff --git a/lib/dns/include/dns/Makefile.in b/lib/dns/include/dns/Makefile.in
+index 56172e9..1836fa3 100644
+--- a/lib/dns/include/dns/Makefile.in
++++ b/lib/dns/include/dns/Makefile.in
+@@ -23,7 +23,7 @@ top_srcdir =	@top_srcdir@
+ 
+ HEADERS =	acl.h adb.h byaddr.h cache.h callbacks.h cert.h compress.h \
+ 		clientinfo.h db.h dbiterator.h dbtable.h diff.h dispatch.h dynamic_db.h \
+-		dlz.h dnssec.h ds.h events.h fixedname.h iptable.h journal.h \
++		dlz.h dnssec.h ds.h events.h fixedname.h geoip.h iptable.h journal.h \
+ 		keyflags.h keytable.h keyvalues.h lib.h log.h \
+ 		master.h masterdump.h message.h name.h ncache.h nsec.h \
+ 		peer.h portlist.h private.h rbt.h rcode.h \
+diff --git a/lib/dns/include/dns/acl.h b/lib/dns/include/dns/acl.h
+index f4fc4a3..2c3bb37 100644
+--- a/lib/dns/include/dns/acl.h
++++ b/lib/dns/include/dns/acl.h
+@@ -38,10 +38,17 @@
+ #include <isc/netaddr.h>
+ #include <isc/refcount.h>
+ 
++#ifdef HAVE_GEOIP
++#include <dns/geoip.h>
++#endif
+ #include <dns/name.h>
+ #include <dns/types.h>
+ #include <dns/iptable.h>
+ 
++#ifdef HAVE_GEOIP
++#include <GeoIP.h>
++#endif
++
+ /***
+  *** Types
+  ***/
+@@ -52,8 +59,11 @@ typedef enum {
+ 	dns_aclelementtype_nestedacl,
+ 	dns_aclelementtype_localhost,
+ 	dns_aclelementtype_localnets,
++#ifdef HAVE_GEOIP
++	dns_aclelementtype_geoip,
++#endif /* HAVE_GEOIP */
+ 	dns_aclelementtype_any
+-} dns_aclelemettype_t;
++} dns_aclelementtype_t;
+ 
+ typedef struct dns_aclipprefix dns_aclipprefix_t;
+ 
+@@ -63,9 +73,12 @@ struct dns_aclipprefix {
+ };
+ 
+ struct dns_aclelement {
+-	dns_aclelemettype_t	type;
++	dns_aclelementtype_t	type;
+ 	isc_boolean_t		negative;
+ 	dns_name_t		keyname;
++#ifdef HAVE_GEOIP
++	dns_geoip_elem_t	geoip_elem;
++#endif /* HAVE_GEOIP */
+ 	dns_acl_t		*nestedacl;
+ 	int			node_num;
+ };
+@@ -88,6 +101,9 @@ struct dns_aclenv {
+ 	dns_acl_t *localhost;
+ 	dns_acl_t *localnets;
+ 	isc_boolean_t match_mapped;
++#ifdef HAVE_GEOIP
++	dns_geoip_databases_t *geoip;
++#endif
+ };
+ 
+ #define DNS_ACL_MAGIC		ISC_MAGIC('D','a','c','l')
+@@ -214,6 +230,10 @@ dns_acl_match(const isc_netaddr_t *reqaddr,
+  * and 'matchelt' is non-NULL, *matchelt will be pointed to the matching
+  * element.
+  *
++ * 'env' points to the current ACL environment, including the
++ * current values of localhost and localnets and (if applicable)
++ * the GeoIP context.
++ *
+  * Returns:
+  *\li	#ISC_R_SUCCESS		Always succeeds.
+  */
+diff --git a/lib/dns/include/dns/geoip.h b/lib/dns/include/dns/geoip.h
+new file mode 100644
+index 0000000..bad9485
+--- /dev/null
++++ b/lib/dns/include/dns/geoip.h
+@@ -0,0 +1,119 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef DNS_GEOIP_H
++#define DNS_GEOIP_H 1
++
++/*****
++ ***** Module Info
++ *****/
++
++/*! \file dns/acl.h
++ * \brief
++ * Address match list handling.
++ */
++
++/***
++ *** Imports
++ ***/
++
++#include <isc/lang.h>
++#include <isc/magic.h>
++#include <isc/netaddr.h>
++#include <isc/refcount.h>
++
++#include <dns/name.h>
++#include <dns/types.h>
++#include <dns/iptable.h>
++
++#ifdef HAVE_GEOIP
++#include <GeoIP.h>
++#else
++typedef void GeoIP;
++#endif
++
++/***
++ *** Types
++ ***/
++
++typedef enum {
++	dns_geoip_countrycode,
++	dns_geoip_countrycode3,
++	dns_geoip_countryname,
++	dns_geoip_region,
++	dns_geoip_regionname,
++	dns_geoip_country_code,
++	dns_geoip_country_code3,
++	dns_geoip_country_name,
++	dns_geoip_region_countrycode,
++	dns_geoip_region_code,
++	dns_geoip_region_name,
++	dns_geoip_city_countrycode,
++	dns_geoip_city_countrycode3,
++	dns_geoip_city_countryname,
++	dns_geoip_city_region,
++	dns_geoip_city_regionname,
++	dns_geoip_city_name,
++	dns_geoip_city_postalcode,
++	dns_geoip_city_metrocode,
++	dns_geoip_city_areacode,
++	dns_geoip_city_continentcode,
++	dns_geoip_city_timezonecode,
++	dns_geoip_isp_name,
++	dns_geoip_org_name,
++	dns_geoip_as_asnum,
++	dns_geoip_domain_name,
++	dns_geoip_netspeed_id
++} dns_geoip_subtype_t;
++
++typedef struct dns_geoip_elem {
++	dns_geoip_subtype_t subtype;
++	GeoIP *db;
++	union {
++		char as_string[256];
++		int as_int;
++	};
++} dns_geoip_elem_t;
++
++typedef struct dns_geoip_databases {
++	GeoIP *country_v4;			/* DB 1        */
++	GeoIP *city_v4;				/* DB 2 or 6   */
++	GeoIP *region;				/* DB 3 or 7   */
++	GeoIP *isp;				/* DB 4        */
++	GeoIP *org;				/* DB 5        */
++	GeoIP *as;				/* DB 9        */
++	GeoIP *netspeed;			/* DB 10       */
++	GeoIP *domain;				/* DB 11       */
++	GeoIP *country_v6;			/* DB 12       */
++	GeoIP *city_v6;				/* DB 30 or 31 */
++} dns_geoip_databases_t;
++
++/***
++ *** Functions
++ ***/
++
++ISC_LANG_BEGINDECLS
++
++isc_boolean_t
++dns_geoip_match(const isc_netaddr_t *reqaddr,
++		const dns_geoip_databases_t *geoip,
++		const dns_geoip_elem_t *elt);
++
++void
++dns_geoip_shutdown(void);
++
++ISC_LANG_ENDDECLS
++#endif /* DNS_GEOIP_H */
+diff --git a/lib/dns/tests/Makefile.in b/lib/dns/tests/Makefile.in
+index 3b19784..8d1b83e 100644
+--- a/lib/dns/tests/Makefile.in
++++ b/lib/dns/tests/Makefile.in
+@@ -40,13 +40,13 @@ LIBS =		@LIBS@ @ATFLIBS@
+ OBJS =		dnstest.@O@
+ SRCS =		dnstest.c gost_test.c master_test.c dbiterator_test.c time_test.c \
+ 		private_test.c update_test.c zonemgr_test.c zt_test.c \
+-		dbdiff_test.c dispatch_test.c nsec3_test.c \
++		dbdiff_test.c geoip_test.c dispatch_test.c nsec3_test.c \
+ 		rdataset_test.c rdata_test.c
+ 
+ SUBDIRS =
+ TARGETS =	gost_test@EXEEXT@ master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \
+ 		private_test@EXEEXT@ update_test@EXEEXT@ zonemgr_test@EXEEXT@ \
+-		zt_test@EXEEXT@ dbversion_test@EXEEXT@ dbdiff_test@EXEEXT@ \
++		zt_test@EXEEXT@ dbversion_test@EXEEXT@ dbdiff_test@EXEEXT@ geoip_test@EXEEXT@ \
+ 		dispatch_test@EXEEXT@ nsec3_test@EXEEXT@ \
+ 		rdataset_test@EXEEXT@ rdata_test@EXEEXT@
+ 
+@@ -129,6 +129,11 @@ gost_test@EXEEXT@: gost_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 			gost_test.@O@ dnstest.@O@ ${DNSLIBS} \
+ 			${ISCLIBS} ${LIBS}
+ 
++geoip_test@EXEEXT@: geoip_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
++			geoip_test.@O@ dnstest.@O@ ${DNSLIBS} \
++			${ISCLIBS} ${LIBS}
++
+ unit::
+ 	sh ${top_srcdir}/unit/unittest.sh
+ 
+diff --git a/lib/dns/tests/geoip_test.c b/lib/dns/tests/geoip_test.c
+new file mode 100644
+index 0000000..ad983b0
+--- /dev/null
++++ b/lib/dns/tests/geoip_test.c
+@@ -0,0 +1,694 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++/*! \file */
++
++#include <config.h>
++
++#include <atf-c.h>
++
++#include <unistd.h>
++
++#include <isc/types.h>
++
++#include <dns/geoip.h>
++
++#include "dnstest.h"
++
++#ifdef HAVE_GEOIP
++#include <GeoIP.h>
++
++/* We use GeoIP databases from the 'geoip' system test */
++#define TEST_GEOIP_DATA "../../../bin/tests/system/geoip/data"
++
++/*
++ * Helper functions
++ * (Mostly copied from bin/named/geoip.c)
++ */
++static dns_geoip_databases_t geoip = {
++	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
++};
++
++static void
++init_geoip_db(GeoIP **dbp, GeoIPDBTypes edition, GeoIPDBTypes fallback,
++	      GeoIPOptions method, const char *name)
++{
++	char *info;
++	GeoIP *db;
++
++	REQUIRE(dbp != NULL);
++
++	db = *dbp;
++
++	if (db != NULL) {
++		GeoIP_delete(db);
++		db = *dbp = NULL;
++	}
++
++	if (! GeoIP_db_avail(edition)) {
++		fprintf(stderr, "GeoIP %s (type %d) DB not available\n",
++			name, edition);
++		goto fail;
++	}
++
++	fprintf(stderr, "initializing GeoIP %s (type %d) DB\n",
++		name, edition);
++
++	db = GeoIP_open_type(edition, method);
++	if (db == NULL) {
++		fprintf(stderr,
++			"failed to initialize GeoIP %s (type %d) DB%s\n",
++			name, edition, fallback == 0
++		 	 ? "; geoip matches using this database will fail"
++			 : "");
++		goto fail;
++	}
++
++	info = GeoIP_database_info(db);
++	if (info != NULL)
++		fprintf(stderr, "%s\n", info);
++
++	*dbp = db;
++	return;
++
++ fail:
++	if (fallback != 0)
++		init_geoip_db(dbp, fallback, 0, method, name);
++}
++
++static void
++load_geoip(const char *dir) {
++	GeoIPOptions method;
++
++#ifdef _WIN32
++	method = GEOIP_STANDARD;
++#else
++	method = GEOIP_MMAP_CACHE;
++#endif
++
++	if (dir != NULL) {
++		char *p;
++		DE_CONST(dir, p);
++		GeoIP_setup_custom_directory(p);
++	}
++
++	init_geoip_db(&geoip.country_v4, GEOIP_COUNTRY_EDITION, 0,
++		      method, "Country (IPv4)");
++#ifdef HAVE_GEOIP_V6
++	init_geoip_db(&geoip.country_v6, GEOIP_COUNTRY_EDITION_V6, 0,
++		      method, "Country (IPv6)");
++#endif
++
++	init_geoip_db(&geoip.city_v4, GEOIP_CITY_EDITION_REV1,
++		      GEOIP_CITY_EDITION_REV0, method, "City (IPv4)");
++#if defined(HAVE_GEOIP_V6) && defined(HAVE_GEOIP_CITY_V6)
++	init_geoip_db(&geoip.city_v6, GEOIP_CITY_EDITION_REV1_V6,
++		      GEOIP_CITY_EDITION_REV0_V6, method, "City (IPv6)");
++#endif
++
++	init_geoip_db(&geoip.region, GEOIP_REGION_EDITION_REV1,
++		      GEOIP_REGION_EDITION_REV0, method, "Region");
++	init_geoip_db(&geoip.isp, GEOIP_ISP_EDITION, 0,
++		      method, "ISP");
++	init_geoip_db(&geoip.org, GEOIP_ORG_EDITION, 0,
++		      method, "Org");
++	init_geoip_db(&geoip.as, GEOIP_ASNUM_EDITION, 0,
++		      method, "AS");
++	init_geoip_db(&geoip.domain, GEOIP_DOMAIN_EDITION, 0,
++		      method, "Domain");
++	init_geoip_db(&geoip.netspeed, GEOIP_NETSPEED_EDITION, 0,
++		      method, "NetSpeed");
++}
++
++static isc_boolean_t
++do_lookup_string(const char *addr, dns_geoip_subtype_t subtype,
++		 const char *string)
++{
++	dns_geoip_elem_t elt;
++	struct in_addr in4;
++	isc_netaddr_t na;
++
++	inet_pton(AF_INET, addr, &in4);
++	isc_netaddr_fromin(&na, &in4);
++
++	elt.subtype = subtype;
++	strcpy(elt.as_string, string);
++
++	return (dns_geoip_match(&na, &geoip, &elt));
++}
++
++static isc_boolean_t
++do_lookup_string_v6(const char *addr, dns_geoip_subtype_t subtype,
++		    const char *string)
++{
++	dns_geoip_elem_t elt;
++	struct in6_addr in6;
++	isc_netaddr_t na;
++
++	inet_pton(AF_INET6, addr, &in6);
++	isc_netaddr_fromin6(&na, &in6);
++
++	elt.subtype = subtype;
++	strcpy(elt.as_string, string);
++
++	return (dns_geoip_match(&na, &geoip, &elt));
++}
++
++static isc_boolean_t
++do_lookup_int(const char *addr, dns_geoip_subtype_t subtype, int id) {
++	dns_geoip_elem_t elt;
++	struct in_addr in4;
++	isc_netaddr_t na;
++
++	inet_pton(AF_INET, addr, &in4);
++	isc_netaddr_fromin(&na, &in4);
++
++	elt.subtype = subtype;
++	elt.as_int = id;
++
++	return (dns_geoip_match(&na, &geoip, &elt));
++}
++
++/*
++ * Individual unit tests
++ */
++
++/* GeoIP country matching */
++ATF_TC(country);
++ATF_TC_HEAD(country, tc) {
++	atf_tc_set_md_var(tc, "descr", "test country database matching");
++}
++ATF_TC_BODY(country, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.country_v4 == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_string("10.53.0.1", dns_geoip_country_code, "AU");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_country_code3, "AUS");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_country_name, "Australia");
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++/* GeoIP country (ipv6) matching */
++ATF_TC(country_v6);
++ATF_TC_HEAD(country_v6, tc) {
++	atf_tc_set_md_var(tc, "descr", "test country (ipv6) database matching");
++}
++ATF_TC_BODY(country_v6, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.country_v6 == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_country_code, "AU");
++	ATF_CHECK(match);
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_country_code3, "AUS");
++	ATF_CHECK(match);
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_country_name, "Australia");
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++/* GeoIP city (ipv4) matching */
++ATF_TC(city);
++ATF_TC_HEAD(city, tc) {
++	atf_tc_set_md_var(tc, "descr", "test city database matching");
++}
++ATF_TC_BODY(city, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.city_v4 == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_city_continentcode, "NA");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_city_countrycode, "US");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_city_countrycode3, "USA");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_city_countryname, "United States");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_city_region, "CA");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_city_regionname, "California");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_city_name, "Redwood City");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_city_postalcode, "94063");
++	ATF_CHECK(match);
++
++	match = do_lookup_int("10.53.0.1", dns_geoip_city_areacode, 650);
++	ATF_CHECK(match);
++
++	match = do_lookup_int("10.53.0.1", dns_geoip_city_metrocode, 807);
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++/* GeoIP city (ipv6) matching */
++ATF_TC(city_v6);
++ATF_TC_HEAD(city_v6, tc) {
++	atf_tc_set_md_var(tc, "descr", "test city (ipv6) database matching");
++}
++ATF_TC_BODY(city_v6, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.city_v6 == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_city_continentcode, "NA");
++	ATF_CHECK(match);
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_city_countrycode, "US");
++	ATF_CHECK(match);
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_city_countrycode3, "USA");
++	ATF_CHECK(match);
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_city_countryname,
++				    "United States");
++	ATF_CHECK(match);
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_city_region, "CA");
++	ATF_CHECK(match);
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_city_regionname, "California");
++	ATF_CHECK(match);
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_city_name, "Redwood City");
++	ATF_CHECK(match);
++
++	match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
++				    dns_geoip_city_postalcode, "94063");
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++
++/* GeoIP region matching */
++ATF_TC(region);
++ATF_TC_HEAD(region, tc) {
++	atf_tc_set_md_var(tc, "descr", "test region database matching");
++}
++ATF_TC_BODY(region, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.region == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_region_code, "CA");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_region_name, "California");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.1",
++				 dns_geoip_region_countrycode, "US");
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++/*
++ * GeoIP best-database matching
++ * (With no specified databse and a city database available, answers
++ * should come from city database.  With city database unavailable, region
++ * database.  Region database unavailable, country database.)
++ */
++ATF_TC(best);
++ATF_TC_HEAD(best, tc) {
++	atf_tc_set_md_var(tc, "descr", "test best database matching");
++}
++ATF_TC_BODY(best, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.region == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_countrycode, "US");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_countrycode3, "USA");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_countryname, "United States");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_regionname, "Virginia");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_region, "VA");
++	ATF_CHECK(match);
++
++	GeoIP_delete(geoip.city_v4);
++	geoip.city_v4 = NULL;
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_countrycode, "AU");
++	ATF_CHECK(match);
++
++	/*
++	 * Note, region doesn't support code3 or countryname, so
++	 * the next two would be answered from the country database instead
++	 */
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_countrycode3, "CAN");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_countryname, "Canada");
++	ATF_CHECK(match);
++
++	GeoIP_delete(geoip.region);
++	geoip.region = NULL;
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_countrycode, "CA");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_countrycode3, "CAN");
++	ATF_CHECK(match);
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_countryname, "Canada");
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++
++/* GeoIP asnum matching */
++ATF_TC(asnum);
++ATF_TC_HEAD(asnum, tc) {
++	atf_tc_set_md_var(tc, "descr", "test asnum database matching");
++}
++ATF_TC_BODY(asnum, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.as == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++
++	match = do_lookup_string("10.53.0.3", dns_geoip_as_asnum,
++				 "AS100003 Three Network Labs");
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++/* GeoIP isp matching */
++ATF_TC(isp);
++ATF_TC_HEAD(isp, tc) {
++	atf_tc_set_md_var(tc, "descr", "test isp database matching");
++}
++ATF_TC_BODY(isp, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.isp == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_string("10.53.0.1", dns_geoip_isp_name,
++				 "One Systems, Inc.");
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++/* GeoIP org matching */
++ATF_TC(org);
++ATF_TC_HEAD(org, tc) {
++	atf_tc_set_md_var(tc, "descr", "test org database matching");
++}
++ATF_TC_BODY(org, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.org == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_string("10.53.0.2", dns_geoip_org_name,
++				 "Two Technology Ltd.");
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++/* GeoIP domain matching */
++ATF_TC(domain);
++ATF_TC_HEAD(domain, tc) {
++	atf_tc_set_md_var(tc, "descr", "test domain database matching");
++}
++ATF_TC_BODY(domain, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.domain == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_string("10.53.0.4",
++				 dns_geoip_domain_name, "four.com");
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++
++/* GeoIP netspeed matching */
++ATF_TC(netspeed);
++ATF_TC_HEAD(netspeed, tc) {
++	atf_tc_set_md_var(tc, "descr", "test netspeed database matching");
++}
++ATF_TC_BODY(netspeed, tc) {
++	isc_result_t result;
++	isc_boolean_t match;
++
++	UNUSED(tc);
++
++	result = dns_test_begin(NULL, ISC_TRUE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	/* Use databases from the geoip system test */
++	load_geoip(TEST_GEOIP_DATA);
++
++	if (geoip.netspeed == NULL) {
++		dns_test_end();
++		atf_tc_skip("Database not available");
++	}
++
++	match = do_lookup_int("10.53.0.1", dns_geoip_netspeed_id, 0);
++	ATF_CHECK(match);
++
++	match = do_lookup_int("10.53.0.2", dns_geoip_netspeed_id, 1);
++	ATF_CHECK(match);
++
++	match = do_lookup_int("10.53.0.3", dns_geoip_netspeed_id, 2);
++	ATF_CHECK(match);
++
++	match = do_lookup_int("10.53.0.4", dns_geoip_netspeed_id, 3);
++	ATF_CHECK(match);
++
++	dns_test_end();
++}
++#else
++ATF_TC(untested);
++ATF_TC_HEAD(untested, tc) {
++	atf_tc_set_md_var(tc, "descr", "skipping geoip test");
++}
++ATF_TC_BODY(untested, tc) {
++	UNUSED(tc);
++	atf_tc_skip("GeoIP not available");
++}
++#endif
++
++/*
++ * Main
++ */
++ATF_TP_ADD_TCS(tp) {
++#ifdef HAVE_GEOIP
++	ATF_TP_ADD_TC(tp, country);
++	ATF_TP_ADD_TC(tp, country_v6);
++	ATF_TP_ADD_TC(tp, city);
++	ATF_TP_ADD_TC(tp, city_v6);
++	ATF_TP_ADD_TC(tp, region);
++	ATF_TP_ADD_TC(tp, best);
++	ATF_TP_ADD_TC(tp, asnum);
++	ATF_TP_ADD_TC(tp, isp);
++	ATF_TP_ADD_TC(tp, org);
++	ATF_TP_ADD_TC(tp, domain);
++	ATF_TP_ADD_TC(tp, netspeed);
++#else
++	ATF_TP_ADD_TC(tp, untested);
++#endif
++
++	return (atf_no_error());
++}
++
+diff --git a/lib/export/dns/Makefile.in b/lib/export/dns/Makefile.in
+index e10bf59..54e4e39 100644
+--- a/lib/export/dns/Makefile.in
++++ b/lib/export/dns/Makefile.in
+@@ -67,8 +65,9 @@ DNSOBJS =	acl.@O@ adb.@O@ byaddr.@O@ \
+ 		tcpmsg.@O@ time.@O@ tsec.@O@ tsig.@O@ ttl.@O@ \
+ 		validator.@O@ version.@O@ view.@O@
+ PORTDNSOBJS =	ecdb.@O@
++GEOIPLINKOBJS = geoip.@O@
+ 
+-OBJS=		${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} ${PORTDNSOBJS}
++OBJS=		${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} ${PORTDNSOBJS} @GEOIPLINKOBJS@
+ 
+ # Alphabetically
+ 
+@@ -96,8 +93,9 @@ DNSSRCS =	acl.c adb.c byaddr.c \
+ 		tcpmsg.c time.c tsec.c tsig.c ttl.c \
+ 		validator.c version.c view.c
+ PORTDNSSRCS =	ecdb.c
++GEOIPLINKSRCS = geoip.c
+ 
+-SRCS = ${DSTSRCS} ${DNSSRCS} ${PORTDNSSRCS}
++SRCS = ${DSTSRCS} ${DNSSRCS} ${PORTDNSSRCS} @GEOIPLINKSRCS@
+ 
+ SUBDIRS =	include
+ TARGETS =	include/dns/enumtype.h include/dns/enumclass.h \
+diff --git a/lib/isccfg/aclconf.c b/lib/isccfg/aclconf.c
+index af56599..c415a98 100644
+--- a/lib/isccfg/aclconf.c
++++ b/lib/isccfg/aclconf.c
+@@ -31,6 +31,11 @@
+ #include <dns/fixedname.h>
+ #include <dns/log.h>
+ 
++#ifdef HAVE_GEOIP
++#include <stdlib.h>
++#include <math.h>
++#endif /* HAVE_GEOIP */
++
+ #define LOOP_MAGIC ISC_MAGIC('L','O','O','P')
+ 
+ isc_result_t
+@@ -53,6 +58,10 @@ cfg_aclconfctx_create(isc_mem_t *mctx, cfg_aclconfctx_t **ret) {
+ 	isc_mem_attach(mctx, &actx->mctx);
+ 	ISC_LIST_INIT(actx->named_acl_cache);
+ 
++#ifdef HAVE_GEOIP
++	actx->geoip = NULL;
++#endif
++
+ 	*ret = actx;
+ 	return (ISC_R_SUCCESS);
+ 
+@@ -230,11 +239,15 @@ count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx,
+ 	     elt = cfg_list_next(elt)) {
+ 		const cfg_obj_t *ce = cfg_listelt_value(elt);
+ 
+-		/* negated element; just get the value. */
++		/* might be a negated element, in which case get the value. */
+ 		if (cfg_obj_istuple(ce)) {
+-			ce = cfg_tuple_get(ce, "value");
+-			if (has_negative != NULL)
+-				*has_negative = ISC_TRUE;
++			const cfg_obj_t *negated =
++				cfg_tuple_get(ce, "negated");
++			if (! cfg_obj_isvoid(negated)) {
++				ce = negated;
++				if (has_negative != NULL)
++					*has_negative = ISC_TRUE;
++			}
+ 		}
+ 
+ 		if (cfg_obj_istype(ce, &cfg_type_keyref)) {
+@@ -244,6 +257,12 @@ count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx,
+ 			n += count_acl_elements(ce, cctx, &negative);
+ 			if (negative)
+ 				n++;
++#ifdef HAVE_GEOIP
++		} else if (cfg_obj_istuple(ce) &&
++			   cfg_obj_isvoid(cfg_tuple_get(ce, "negated")))
++		{
++				n++;
++#endif /* HAVE_GEOIP */
+ 		} else if (cfg_obj_isstring(ce)) {
+ 			const char *name = cfg_obj_asstring(ce);
+ 			if (strcasecmp(name, "localhost") == 0 ||
+@@ -262,6 +281,313 @@ count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx,
+ 	return n;
+ }
+ 
++#ifdef HAVE_GEOIP
++static dns_geoip_subtype_t
++get_subtype(const cfg_obj_t *obj, isc_log_t *lctx,
++	    dns_geoip_subtype_t subtype, const char *dbname)
++{
++	if (dbname == NULL)
++		return (subtype);
++
++	switch (subtype) {
++	case dns_geoip_countrycode:
++		if (strcasecmp(dbname, "city") == 0)
++			return (dns_geoip_city_countrycode);
++		else if (strcasecmp(dbname, "region") == 0)
++			return (dns_geoip_region_countrycode);
++		else if (strcasecmp(dbname, "country") == 0)
++			return (dns_geoip_country_code);
++		cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
++			    "invalid GeoIP DB specified for "
++			    "country search: ignored");
++		return (subtype);
++	case dns_geoip_countrycode3:
++		if (strcasecmp(dbname, "city") == 0)
++			return (dns_geoip_city_countrycode3);
++		else if (strcasecmp(dbname, "country") == 0)
++			return (dns_geoip_country_code3);
++		cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
++			    "invalid GeoIP DB specified for "
++			    "country search: ignored");
++		return (subtype);
++	case dns_geoip_countryname:
++		if (strcasecmp(dbname, "city") == 0)
++			return (dns_geoip_city_countryname);
++		else if (strcasecmp(dbname, "country") == 0)
++			return (dns_geoip_country_name);
++		cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
++			    "invalid GeoIP DB specified for "
++			    "country search: ignored");
++		return (subtype);
++	case dns_geoip_region:
++		if (strcasecmp(dbname, "city") == 0)
++			return (dns_geoip_city_region);
++		else if (strcasecmp(dbname, "region") == 0)
++			return (dns_geoip_region_code);
++		cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
++			    "invalid GeoIP DB specified for "
++			    "region search: ignored");
++		return (subtype);
++	case dns_geoip_regionname:
++		if (strcasecmp(dbname, "city") == 0)
++			return (dns_geoip_city_region);
++		else if (strcasecmp(dbname, "region") == 0)
++			return (dns_geoip_region_name);
++		cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
++			    "invalid GeoIP DB specified for "
++			    "region search: ignored");
++		return (subtype);
++
++	/*
++	 * Log a warning if the wrong database was specified
++	 * on an unambiguous query
++	 */
++	case dns_geoip_city_name:
++	case dns_geoip_city_postalcode:
++	case dns_geoip_city_metrocode:
++	case dns_geoip_city_areacode:
++	case dns_geoip_city_continentcode:
++	case dns_geoip_city_timezonecode:
++		if (strcasecmp(dbname, "city") != 0)
++			cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
++				    "invalid GeoIP DB specified for "
++				    "a 'city'-only search type: ignoring");
++		return (subtype);
++	case dns_geoip_isp_name:
++		if (strcasecmp(dbname, "isp") != 0)
++			cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
++				    "invalid GeoIP DB specified for "
++				    "an 'isp' search: ignoring");
++		return (subtype);
++	case dns_geoip_org_name:
++		if (strcasecmp(dbname, "org") != 0)
++			cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
++				    "invalid GeoIP DB specified for "
++				    "an 'org' search: ignoring");
++		return (subtype);
++	case dns_geoip_as_asnum:
++		if (strcasecmp(dbname, "asnum") != 0)
++			cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
++				    "invalid GeoIP DB specified for "
++				    "an 'asnum' search: ignoring");
++		return (subtype);
++	case dns_geoip_domain_name:
++		if (strcasecmp(dbname, "domain") != 0)
++			cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
++				    "invalid GeoIP DB specified for "
++				    "a 'domain' search: ignoring");
++		return (subtype);
++	case dns_geoip_netspeed_id:
++		if (strcasecmp(dbname, "netspeed") != 0)
++			cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
++				    "invalid GeoIP DB specified for "
++				    "a 'netspeed' search: ignoring");
++		return (subtype);
++	default:
++		INSIST(0);
++	}
++}
++
++static isc_boolean_t
++geoip_can_answer(dns_aclelement_t *elt, cfg_aclconfctx_t *ctx) {
++	if (ctx->geoip == NULL)
++		return (ISC_TRUE);
++
++	switch (elt->geoip_elem.subtype) {
++	case dns_geoip_countrycode:
++	case dns_geoip_countrycode3:
++	case dns_geoip_countryname:
++		if (ctx->geoip->city_v4 != NULL ||
++		    ctx->geoip->city_v6 != NULL ||
++		    ctx->geoip->country_v4 != NULL ||
++		    ctx->geoip->country_v6 != NULL ||
++		    ctx->geoip->region != NULL)
++			return (ISC_TRUE);
++	case dns_geoip_region:
++	case dns_geoip_regionname:
++		if (ctx->geoip->city_v4 != NULL ||
++		    ctx->geoip->city_v6 != NULL ||
++		    ctx->geoip->region != NULL)
++			return (ISC_TRUE);
++	case dns_geoip_country_code:
++	case dns_geoip_country_code3:
++	case dns_geoip_country_name:
++		if (ctx->geoip->country_v4 != NULL ||
++		    ctx->geoip->country_v6 != NULL)
++			return (ISC_TRUE);
++	case dns_geoip_region_countrycode:
++	case dns_geoip_region_code:
++	case dns_geoip_region_name:
++		if (ctx->geoip->region != NULL)
++			return (ISC_TRUE);
++	case dns_geoip_city_countrycode:
++	case dns_geoip_city_countrycode3:
++	case dns_geoip_city_countryname:
++	case dns_geoip_city_region:
++	case dns_geoip_city_regionname:
++	case dns_geoip_city_name:
++	case dns_geoip_city_postalcode:
++	case dns_geoip_city_metrocode:
++	case dns_geoip_city_areacode:
++	case dns_geoip_city_continentcode:
++	case dns_geoip_city_timezonecode:
++		if (ctx->geoip->city_v4 != NULL ||
++		    ctx->geoip->city_v6 != NULL)
++			return (ISC_TRUE);
++	case dns_geoip_isp_name:
++		if (ctx->geoip->isp != NULL)
++			return (ISC_TRUE);
++	case dns_geoip_org_name:
++		if (ctx->geoip->org != NULL)
++			return (ISC_TRUE);
++	case dns_geoip_as_asnum:
++		if (ctx->geoip->as != NULL)
++			return (ISC_TRUE);
++	case dns_geoip_domain_name:
++		if (ctx->geoip->domain != NULL)
++			return (ISC_TRUE);
++	case dns_geoip_netspeed_id:
++		if (ctx->geoip->netspeed != NULL)
++			return (ISC_TRUE);
++	}
++
++	return (ISC_FALSE);
++}
++
++static isc_result_t
++parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx,
++		    cfg_aclconfctx_t *ctx, dns_aclelement_t *dep)
++{
++	const cfg_obj_t *ge;
++	const char *dbname = NULL;
++	const char *stype, *search;
++	dns_geoip_subtype_t subtype;
++	dns_aclelement_t de;
++	size_t len;
++
++	REQUIRE(dep != NULL);
++
++	de = *dep;
++
++	ge = cfg_tuple_get(obj, "db");
++	if (!cfg_obj_isvoid(ge))
++		dbname = cfg_obj_asstring(ge);
++
++	stype = cfg_obj_asstring(cfg_tuple_get(obj, "subtype"));
++	search = cfg_obj_asstring(cfg_tuple_get(obj, "search"));
++	len = strlen(search);
++
++	if (len == 0) {
++		cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
++			    "zero-length geoip search field");
++		return (ISC_R_FAILURE);
++	}
++
++	if (strcasecmp(stype, "country") == 0 && len == 2) {
++		/* Two-letter country code */
++		subtype = dns_geoip_countrycode;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "country") == 0 && len == 3) {
++		/* Three-letter country code */
++		subtype = dns_geoip_countrycode3;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "country") == 0) {
++		/* Country name */
++		subtype = dns_geoip_countryname;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "region") == 0 && len == 2) {
++		/* Two-letter region code */
++		subtype = dns_geoip_region;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "region") == 0) {
++		/* Region name */
++		subtype = dns_geoip_regionname;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "city") == 0) {
++		/* City name */
++		subtype = dns_geoip_city_name;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "postal") == 0 ||
++		   strcasecmp(stype, "postalcode") == 0)
++	{
++		if (len < 7) {
++			subtype = dns_geoip_city_postalcode;
++			strlcpy(de.geoip_elem.as_string, search,
++				sizeof(de.geoip_elem.as_string));
++		} else {
++			cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
++				    "geoiop postal code (%s) too long",
++				    search);
++			return (ISC_R_FAILURE);
++		}
++	} else if (strcasecmp(stype, "metro") == 0 ||
++		   strcasecmp(stype, "metrocode") == 0)
++	{
++		subtype = dns_geoip_city_metrocode;
++		de.geoip_elem.as_int = atoi(search);
++	} else if (strcasecmp(stype, "area") == 0 ||
++		   strcasecmp(stype, "areacode") == 0)
++	{
++		subtype = dns_geoip_city_areacode;
++		de.geoip_elem.as_int = atoi(search);
++	} else if (strcasecmp(stype, "tz") == 0 ||
++		   strcasecmp(stype, "timezone") == 0)
++	{
++		subtype = dns_geoip_city_timezonecode;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "continent") == 0 && len == 2) {
++		/* Two-letter continent code */
++		subtype = dns_geoip_city_continentcode;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "continent") == 0) {
++		cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
++			    "geoiop continent code (%s) too long", search);
++		return (ISC_R_FAILURE);
++	} else if (strcasecmp(stype, "isp") == 0) {
++		subtype = dns_geoip_isp_name;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "asnum") == 0) {
++		subtype = dns_geoip_as_asnum;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "org") == 0) {
++		subtype = dns_geoip_org_name;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "domain") == 0) {
++		subtype = dns_geoip_domain_name;
++		strlcpy(de.geoip_elem.as_string, search,
++			sizeof(de.geoip_elem.as_string));
++	} else if (strcasecmp(stype, "netspeed") == 0) {
++		subtype = dns_geoip_netspeed_id;
++		de.geoip_elem.as_int = atoi(search);
++	} else
++		INSIST(0);
++
++	de.geoip_elem.subtype = get_subtype(obj, lctx, subtype, dbname);
++
++	if (! geoip_can_answer(&de, ctx)) {
++		cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
++			    "no GeoIP database installed which can answer "
++			    "queries of type '%s'", stype);
++		return (ISC_R_FAILURE);
++	}
++
++	*dep = de;
++
++	return (ISC_R_SUCCESS);
++}
++#endif
++
+ isc_result_t
+ cfg_acl_fromconfig(const cfg_obj_t *caml,
+ 		   const cfg_obj_t *cctx,
+@@ -317,15 +643,18 @@ cfg_acl_fromconfig(const cfg_obj_t *caml,
+ 	     elt != NULL;
+ 	     elt = cfg_list_next(elt)) {
+ 		const cfg_obj_t *ce = cfg_listelt_value(elt);
+-		isc_boolean_t	neg;
++		isc_boolean_t neg = ISC_FALSE;
+ 
+ 		if (cfg_obj_istuple(ce)) {
+-			/* This must be a negated element. */
+-			ce = cfg_tuple_get(ce, "value");
+-			neg = ISC_TRUE;
+-			dacl->has_negatives = ISC_TRUE;
+-		} else
+-			neg = ISC_FALSE;
++			/* Might be a negated element */
++			const cfg_obj_t *negated =
++				cfg_tuple_get(ce, "negated");
++			if (! cfg_obj_isvoid(negated)) {
++				neg = ISC_TRUE;
++				dacl->has_negatives = ISC_TRUE;
++				ce = negated;
++			}
++		}
+ 
+ 		/*
+ 		 * If nest_level is nonzero, then every element is
+@@ -405,6 +734,16 @@ nested_acl:
+ 						 &de->keyname);
+ 			if (result != ISC_R_SUCCESS)
+ 				goto cleanup;
++#ifdef HAVE_GEOIP
++		} else if (cfg_obj_istuple(ce) &&
++			   cfg_obj_isvoid(cfg_tuple_get(ce, "negated")))
++		{
++			result = parse_geoip_element(ce, lctx, ctx, de);
++			if (result != ISC_R_SUCCESS)
++				goto cleanup;
++			de->type = dns_aclelementtype_geoip;
++			de->negative = neg;
++#endif /* HAVE_GEOIP */
+ 		} else if (cfg_obj_isstring(ce)) {
+ 			/* ACL name. */
+ 			const char *name = cfg_obj_asstring(ce);
+diff --git a/lib/isccfg/include/isccfg/aclconf.h b/lib/isccfg/include/isccfg/aclconf.h
+index 38ab9f6..3fb66f9 100644
+--- a/lib/isccfg/include/isccfg/aclconf.h
++++ b/lib/isccfg/include/isccfg/aclconf.h
+@@ -24,11 +24,17 @@
+ 
+ #include <isccfg/cfg.h>
+ 
++#ifdef HAVE_GEOIP
++#include <dns/geoip.h>
++#endif
+ #include <dns/types.h>
+ 
+ typedef struct cfg_aclconfctx {
+ 	ISC_LIST(dns_acl_t) named_acl_cache;
+ 	isc_mem_t *mctx;
++#ifdef HAVE_GEOIP
++	dns_geoip_databases_t *geoip;
++#endif
+ 	isc_refcount_t references;
+ } cfg_aclconfctx_t;
+ 
+diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
+index acaef2b..f5ff8e3 100644
+--- a/lib/isccfg/namedconf.c
++++ b/lib/isccfg/namedconf.c
+@@ -82,6 +82,17 @@ doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
+ static void
+ doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
+ 
++#ifdef HAVE_GEOIP
++static isc_result_t
++parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
++
++static void
++print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj);
++
++static void
++doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type);
++#endif /* HAVE_GEOIP */
++
+ static cfg_type_t cfg_type_acl;
+ static cfg_type_t cfg_type_addrmatchelt;
+ static cfg_type_t cfg_type_bracketed_aml;
+@@ -935,6 +946,9 @@ options_clauses[] = {
+ 	{ "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ 	{ "files", &cfg_type_size, 0 },
+ 	{ "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
++#ifdef HAVE_GEOIP
++	{ "geoip-directory", &cfg_type_qstringornone, 0 },
++#endif /* HAVE_GEOIP */
+ 	{ "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
+ 	{ "heartbeat-interval", &cfg_type_uint32, 0 },
+ 	{ "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
+@@ -2126,6 +2140,102 @@ static cfg_type_t cfg_type_optional_keyref = {
+ 	doc_optional_keyvalue, &cfg_rep_string, &key_kw
+ };
+ 
++#ifdef HAVE_GEOIP
++/*
++ * "geoip" ACL element:
++ * geoip [ db <database> ] search-type <string>
++ */
++static const char *geoiptype_enums[] = {
++	"country", "country3", "countryname", "region", "regionname",
++	"city", "postalcode", "postal", "metrocode", "metro",
++	"areacode", "area", "timezone", "tz", "continent", "isp",
++	"domain", "asnum", "org", "netspeed", NULL
++};
++static cfg_type_t cfg_type_geoiptype = {
++	"geoiptype", cfg_parse_enum, cfg_print_ustring,
++	cfg_doc_enum, &cfg_rep_string, &geoiptype_enums
++};
++
++static const char *geoipdb_enums[] = {
++	"country", "region", "city",
++	"isp", "domain", "asnum", "org", "netspeed", NULL
++};
++static cfg_type_t cfg_type_geoipdb = {
++	"geoipdb", cfg_parse_enum, cfg_print_ustring,
++	cfg_doc_enum, &cfg_rep_string, &geoipdb_enums
++};
++
++static cfg_tuplefielddef_t geoip_fields[] = {
++	{ "negated", &cfg_type_void, 0},
++	{ "db", &cfg_type_geoipdb, 0},
++	{ "subtype", &cfg_type_geoiptype, 0 },
++	{ "search", &cfg_type_astring, 0 },
++	{ NULL, NULL, 0 }
++};
++
++static cfg_type_t cfg_type_geoip = {
++	"geoip", parse_geoip, print_geoip, doc_geoip,
++	&cfg_rep_tuple, geoip_fields
++};
++
++static isc_result_t
++parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
++	isc_result_t result;
++	cfg_obj_t *obj = NULL;
++	const cfg_tuplefielddef_t *fields = type->of;
++
++	CHECK(cfg_create_tuple(pctx, type, &obj));
++	CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[0]));
++
++	/* Parse the optional "db" field. */
++	CHECK(cfg_peektoken(pctx, 0));
++	if (pctx->token.type == isc_tokentype_string) {
++		CHECK(cfg_gettoken(pctx, 0));
++		if (strcasecmp(TOKEN_STRING(pctx), "db") == 0 &&
++		    obj->value.tuple[1] == NULL) {
++			CHECK(cfg_parse_obj(pctx, fields[1].type,
++				    &obj->value.tuple[1]));
++		} else {
++			CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
++			cfg_ungettoken(pctx);
++		}
++	}
++
++	CHECK(cfg_parse_obj(pctx, fields[2].type, &obj->value.tuple[2]));
++	CHECK(cfg_parse_obj(pctx, fields[3].type, &obj->value.tuple[3]));
++
++	*ret = obj;
++	return (ISC_R_SUCCESS);
++
++ cleanup:
++	CLEANUP_OBJ(obj);
++	return (result);
++}
++
++static void
++print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj) {
++	if (obj->value.tuple[1]->type->print != cfg_print_void) {
++		cfg_print_cstr(pctx, " db ");
++		cfg_print_obj(pctx, obj->value.tuple[1]);
++	}
++	cfg_print_obj(pctx, obj->value.tuple[2]);
++	cfg_print_obj(pctx, obj->value.tuple[3]);
++}
++
++
++static void
++doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type) {
++	UNUSED(type);
++	cfg_print_cstr(pctx, "[ db ");
++	cfg_doc_enum(pctx, &cfg_type_geoipdb);
++	cfg_print_cstr(pctx, " ]");
++	cfg_print_chars(pctx, " ", 1);
++	cfg_doc_enum(pctx, &cfg_type_geoiptype);
++	cfg_print_chars(pctx, " ", 1);
++	cfg_print_cstr(pctx, "<quoted_string>");
++}
++#endif /* HAVE_GEOIP */
++
+ /*%
+  * A "controls" statement is represented as a map with the multivalued
+  * "inet" and "unix" clauses.
+@@ -2269,7 +2379,9 @@ static cfg_type_t cfg_type_statschannels = {
+  * An optional class, as used in view and zone statements.
+  */
+ static isc_result_t
+-parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
++parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type,
++		     cfg_obj_t **ret)
++{
+ 	isc_result_t result;
+ 	UNUSED(type);
+ 	CHECK(cfg_peektoken(pctx, 0));
+@@ -2392,6 +2504,16 @@ parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+ 		if (pctx->token.type == isc_tokentype_string &&
+ 		    (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
+ 			CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
++		} else if (pctx->token.type == isc_tokentype_string &&
++			   (strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) {
++#ifdef HAVE_GEOIP
++			CHECK(cfg_gettoken(pctx, 0));
++			CHECK(cfg_parse_obj(pctx, &cfg_type_geoip, ret));
++#else
++			cfg_parser_error(pctx, CFG_LOG_NEAR,
++					 "'geoip' not supported in this build");
++			return (ISC_R_UNEXPECTEDTOKEN);
++#endif
+ 		} else {
+ 			if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK |
+ 						  CFG_ADDR_V4PREFIXOK |
+@@ -2405,7 +2527,8 @@ parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+ 	} else if (pctx->token.type == isc_tokentype_special) {
+ 		if (pctx->token.value.as_char == '{') {
+ 			/* Nested match list. */
+-			CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_aml, ret));
++			CHECK(cfg_parse_obj(pctx,
++					    &cfg_type_bracketed_aml, ret));
+ 		} else if (pctx->token.value.as_char == '!') {
+ 			CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
+ 			CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
+@@ -2429,7 +2552,7 @@ parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
+  */
+ 
+ static cfg_tuplefielddef_t negated_fields[] = {
+-	{ "value", &cfg_type_addrmatchelt, 0 },
++	{ "negated", &cfg_type_addrmatchelt, 0 },
+ 	{ NULL, NULL, 0 }
+ };
+ 
+-- 
+2.5.5
+
diff --git a/SOURCES/bind99-rh1259514.patch b/SOURCES/bind99-rh1259514.patch
new file mode 100644
index 0000000..3b268d0
--- /dev/null
+++ b/SOURCES/bind99-rh1259514.patch
@@ -0,0 +1,12 @@
+diff --git a/bin/tests/system/tkey/ns1/named.conf.in b/bin/tests/system/tkey/ns1/named.conf.in
+index 50600b7..b0f1700 100644
+--- a/bin/tests/system/tkey/ns1/named.conf.in
++++ b/bin/tests/system/tkey/ns1/named.conf.in
+@@ -32,6 +32,7 @@ options {
+ 	tkey-domain "server";
+ 	tkey-dhkey "server" KEYID;
+ 	allow-query-cache { any; };
++	random-device "/dev/urandom";
+ };
+ 
+ key rndc_key {
diff --git a/SOURCES/bind99-rh1291185.patch b/SOURCES/bind99-rh1291185.patch
new file mode 100644
index 0000000..9f7c936
--- /dev/null
+++ b/SOURCES/bind99-rh1291185.patch
@@ -0,0 +1,58 @@
+diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
+index 8696b15..5ef2dd6 100644
+--- a/lib/dns/resolver.c
++++ b/lib/dns/resolver.c
+@@ -7373,9 +7373,12 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
+ 		 * NXDOMAIN, NXRDATASET, or referral.
+ 		 */
+ 		result = noanswer_response(fctx, NULL, 0);
+-		if (result == DNS_R_CHASEDSSERVERS) {
+-		} else if (result == DNS_R_DELEGATION) {
+-		force_referral:
++		switch (result) {
++		case ISC_R_SUCCESS:
++		case DNS_R_CHASEDSSERVERS:
++			break;
++		case DNS_R_DELEGATION:
++ force_referral:
+ 			/*
+ 			 * We don't have the answer, but we know a better
+ 			 * place to look.
+@@ -7400,7 +7403,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
+ 			fctx->adberr = 0;
+ 
+ 			result = ISC_R_SUCCESS;
+-		} else if (result != ISC_R_SUCCESS) {
++			break;
++		default:
+ 			/*
+ 			 * Something has gone wrong.
+ 			 */
+diff --git a/lib/dns/view.c b/lib/dns/view.c
+index 142b09e..35900b3 100644
+--- a/lib/dns/view.c
++++ b/lib/dns/view.c
+@@ -1216,6 +1216,7 @@ dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
+ 	dns_name_t *zfname;
+ 	dns_rdataset_t zrdataset, zsigrdataset;
+ 	dns_fixedname_t zfixedname;
++	unsigned int ztoptions = 0;
+ 
+ #ifndef BIND9
+ 	UNUSED(zone);
+@@ -1242,9 +1243,12 @@ dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
+ #ifdef BIND9
+ 	zone = NULL;
+ 	LOCK(&view->lock);
+-	if (view->zonetable != NULL)
+-		result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
+-	else
++	if (view->zonetable != NULL) {
++		if ((options & DNS_DBFIND_NOEXACT) != 0)
++			ztoptions |= DNS_ZTFIND_NOEXACT;
++		result = dns_zt_find(view->zonetable, name, ztoptions,
++				     NULL, &zone);
++	} else
+ 		result = ISC_R_NOTFOUND;
+ 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
+ 		result = dns_zone_getdb(zone, &db);
diff --git a/SOURCES/bind99-rh1306610.patch b/SOURCES/bind99-rh1306610.patch
new file mode 100644
index 0000000..cf5c8cc
--- /dev/null
+++ b/SOURCES/bind99-rh1306610.patch
@@ -0,0 +1,1847 @@
+From 620b1c9d90d0a59a0d892fef089ce4f5f6f61742 Mon Sep 17 00:00:00 2001
+From: Tomas Hozza <thozza@redhat.com>
+Date: Fri, 1 Apr 2016 15:20:27 +0200
+Subject: [PATCH] Added support for CAA records
+
+Signed-off-by: Tomas Hozza <thozza@redhat.com>
+---
+ bin/tests/rdata_test.c           |   17 +-
+ doc/rfc/rfc6844.txt              | 1011 ++++++++++++++++++++++++++++++++++++++
+ lib/dns/rdata.c                  |   95 ++--
+ lib/dns/rdata/generic/caa_257.c  |  370 ++++++++++++++
+ lib/dns/rdata/generic/caa_257.h  |   32 ++
+ lib/dns/rdata/generic/gpos_27.c  |    2 +-
+ lib/dns/rdata/generic/hinfo_13.c |    4 +-
+ lib/dns/rdata/generic/isdn_20.c  |    4 +-
+ lib/dns/rdata/generic/naptr_35.c |    6 +-
+ lib/dns/rdata/generic/spf_99.c   |    2 +-
+ lib/dns/rdata/generic/txt_16.c   |    2 +-
+ lib/dns/rdata/generic/uri_256.c  |   23 +-
+ lib/dns/rdata/generic/x25_19.c   |    2 +-
+ 13 files changed, 1478 insertions(+), 92 deletions(-)
+ create mode 100644 doc/rfc/rfc6844.txt
+ create mode 100644 lib/dns/rdata/generic/caa_257.c
+ create mode 100644 lib/dns/rdata/generic/caa_257.h
+
+diff --git a/bin/tests/rdata_test.c b/bin/tests/rdata_test.c
+index 51cc406..0f25364 100644
+--- a/bin/tests/rdata_test.c
++++ b/bin/tests/rdata_test.c
+@@ -15,8 +15,6 @@
+  * PERFORMANCE OF THIS SOFTWARE.
+  */
+ 
+-/* $Id: rdata_test.c,v 1.52 2011/08/28 09:10:41 marka Exp $ */
+-
+ #include <config.h>
+ 
+ #include <stdlib.h>
+@@ -284,6 +282,11 @@ viastruct(dns_rdata_t *rdata, isc_mem_t *mctx,
+ 		result = dns_rdata_tostruct(rdata, sp = &uri, NULL);
+ 		break;
+ 	}
++	case dns_rdatatype_caa: {
++		static dns_rdata_caa_t caa;
++		result = dns_rdata_tostruct(rdata, sp = &caa, NULL);
++		break;
++	}
+ 	case dns_rdatatype_wks: {
+ 		static dns_rdata_in_wks_t in_wks;
+ 		result = dns_rdata_tostruct(rdata, sp = &in_wks, NULL);
+@@ -551,6 +554,11 @@ viastruct(dns_rdata_t *rdata, isc_mem_t *mctx,
+ 		result = dns_rdata_tostruct(rdata, sp = &uri, mctx);
+ 		break;
+ 	}
++	case dns_rdatatype_caa: {
++		static dns_rdata_caa_t caa;
++		result = dns_rdata_tostruct(rdata, sp = &caa, mctx);
++		break;
++	}
+ 	case dns_rdatatype_wks: {
+ 		static dns_rdata_in_wks_t in_wks;
+ 		result = dns_rdata_tostruct(rdata, sp = &in_wks, mctx);
+@@ -848,6 +856,11 @@ viastruct(dns_rdata_t *rdata, isc_mem_t *mctx,
+ 		result = dns_rdata_fromstruct(rdata2, rdc, rdt, &uri, b);
+ 		break;
+ 	}
++	case dns_rdatatype_caa: {
++		dns_rdata_caa_t caa;
++		result = dns_rdata_fromstruct(rdata2, rdc, rdt, &caa, b);
++		break;
++	}
+ 	case dns_rdatatype_wks: {
+ 		dns_rdata_in_wks_t in_wks;
+ 		result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_wks, b);
+diff --git a/doc/rfc/rfc6844.txt b/doc/rfc/rfc6844.txt
+new file mode 100644
+index 0000000..d923649
+--- /dev/null
++++ b/doc/rfc/rfc6844.txt
+@@ -0,0 +1,1011 @@
++
++
++
++
++
++
++Internet Engineering Task Force (IETF)                   P. Hallam-Baker
++Request for Comments: 6844                            Comodo Group, Inc.
++Category: Standards Track                                   R. Stradling
++ISSN: 2070-1721                                          Comodo CA, Ltd.
++                                                            January 2013
++
++
++    DNS Certification Authority Authorization (CAA) Resource Record
++
++Abstract
++
++   The Certification Authority Authorization (CAA) DNS Resource Record
++   allows a DNS domain name holder to specify one or more Certification
++   Authorities (CAs) authorized to issue certificates for that domain.
++   CAA Resource Records allow a public Certification Authority to
++   implement additional controls to reduce the risk of unintended
++   certificate mis-issue.  This document defines the syntax of the CAA
++   record and rules for processing CAA records by certificate issuers.
++
++Status of This Memo
++
++   This is an Internet Standards Track document.
++
++   This document is a product of the Internet Engineering Task Force
++   (IETF).  It represents the consensus of the IETF community.  It has
++   received public review and has been approved for publication by the
++   Internet Engineering Steering Group (IESG).  Further information on
++   Internet Standards is available in Section 2 of RFC 5741.
++
++   Information about the current status of this document, any errata,
++   and how to provide feedback on it may be obtained at
++   http://www.rfc-editor.org/info/rfc6844.
++
++Copyright Notice
++
++   Copyright (c) 2013 IETF Trust and the persons identified as the
++   document authors.  All rights reserved.
++
++   This document is subject to BCP 78 and the IETF Trust's Legal
++   Provisions Relating to IETF Documents
++   (http://trustee.ietf.org/license-info) in effect on the date of
++   publication of this document.  Please review these documents
++   carefully, as they describe your rights and restrictions with respect
++   to this document.  Code Components extracted from this document must
++   include Simplified BSD License text as described in Section 4.e of
++   the Trust Legal Provisions and are provided without warranty as
++   described in the Simplified BSD License.
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                    [Page 1]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++Table of Contents
++
++   1. Introduction ....................................................2
++   2. Definitions .....................................................3
++      2.1. Requirements Language ......................................3
++      2.2. Defined Terms ..............................................3
++   3. The CAA RR Type .................................................5
++   4. Certification Authority Processing ..............................7
++      4.1. Use of DNS Security ........................................8
++   5. Mechanism .......................................................8
++      5.1. Syntax .....................................................8
++           5.1.1. Canonical Presentation Format ......................10
++      5.2. CAA issue Property ........................................10
++      5.3. CAA issuewild Property ....................................12
++      5.4. CAA iodef Property ........................................12
++   6. Security Considerations ........................................13
++      6.1. Non-Compliance by Certification Authority .................13
++      6.2. Mis-Issue by Authorized Certification Authority ...........13
++      6.3. Suppression or Spoofing of CAA Records ....................13
++      6.4. Denial of Service .........................................14
++      6.5. Abuse of the Critical Flag ................................14
++   7. IANA Considerations ............................................14
++      7.1. Registration of the CAA Resource Record Type ..............14
++      7.2. Certification Authority Restriction Properties ............15
++      7.3. Certification Authority Restriction Flags .................15
++   8. Acknowledgements ...............................................16
++   9. References .....................................................16
++      9.1. Normative References ......................................16
++      9.2. Informative References ....................................17
++
++1.  Introduction
++
++   The Certification Authority Authorization (CAA) DNS Resource Record
++   allows a DNS domain name holder to specify the Certification
++   Authorities (CAs) authorized to issue certificates for that domain.
++   Publication of CAA Resource Records allows a public Certification
++   Authority to implement additional controls to reduce the risk of
++   unintended certificate mis-issue.
++
++   Like the TLSA record defined in DNS-Based Authentication of Named
++   Entities (DANE) [RFC6698], CAA records are used as a part of a
++   mechanism for checking PKIX certificate data.  The distinction
++   between the two specifications is that CAA records specify an
++   authorization control to be performed by a certificate issuer before
++   issue of a certificate and TLSA records specify a verification
++   control to be performed by a relying party after the certificate is
++   issued.
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                    [Page 2]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   Conformance with a published CAA record is a necessary but not
++   sufficient condition for issuance of a certificate.  Before issuing a
++   certificate, a PKIX CA is required to validate the request according
++   to the policies set out in its Certificate Policy.  In the case of a
++   public CA that validates certificate requests as a third party, the
++   certificate will typically be issued under a public trust anchor
++   certificate embedded in one or more relevant Relying Applications.
++
++   Criteria for inclusion of embedded trust anchor certificates in
++   applications are outside the scope of this document.  Typically, such
++   criteria require the CA to publish a Certificate Practices Statement
++   (CPS) that specifies how the requirements of the Certificate Policy
++   (CP) are achieved.  It is also common for a CA to engage an
++   independent third-party auditor to prepare an annual audit statement
++   of its performance against its CPS.
++
++   A set of CAA records describes only current grants of authority to
++   issue certificates for the corresponding DNS domain.  Since a
++   certificate is typically valid for at least a year, it is possible
++   that a certificate that is not conformant with the CAA records
++   currently published was conformant with the CAA records published at
++   the time that the certificate was issued.  Relying Applications MUST
++   NOT use CAA records as part of certificate validation.
++
++   CAA records MAY be used by Certificate Evaluators as a possible
++   indicator of a security policy violation.  Such use SHOULD take
++   account of the possibility that published CAA records changed between
++   the time a certificate was issued and the time at which the
++   certificate was observed by the Certificate Evaluator.
++
++2.  Definitions
++
++2.1.  Requirements Language
++
++   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
++   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
++   document are to be interpreted as described in [RFC2119].
++
++2.2.  Defined Terms
++
++   The following terms are used in this document:
++
++   Authorization Entry:  An authorization assertion that grants or
++      denies a specific set of permissions to a specific group of
++      entities.
++
++   Certificate:  An X.509 Certificate, as specified in [RFC5280].
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                    [Page 3]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   Certificate Evaluator:  A party other than a relying party that
++      evaluates the trustworthiness of certificates issued by
++      Certification Authorities.
++
++   Certification Authority (CA):  An issuer that issues certificates in
++      accordance with a specified Certificate Policy.
++
++   Certificate Policy (CP):  Specifies the criteria that a Certification
++      Authority undertakes to meet in its issue of certificates.  See
++      [RFC3647].
++
++   Certification Practices Statement (CPS):  Specifies the means by
++      which the criteria of the Certificate Policy are met.  In most
++      cases, this will be the document against which the operations of
++      the Certification Authority are audited.  See [RFC3647].
++
++   Domain:  A DNS Domain Name.
++
++   Domain Name:  A DNS Domain Name as specified in [STD13].
++
++   Domain Name System (DNS):  The Internet naming system specified in
++      [STD13].
++
++   DNS Security (DNSSEC):  Extensions to the DNS that provide
++      authentication services as specified in [RFC4033], [RFC4034],
++      [RFC4035], [RFC5155], and revisions.
++
++   Issuer:  An entity that issues certificates.  See [RFC5280].
++
++   Property:  The tag-value portion of a CAA Resource Record.
++
++   Property Tag:  The tag portion of a CAA Resource Record.
++
++   Property Value:  The value portion of a CAA Resource Record.
++
++   Public Key Infrastructure X.509 (PKIX):  Standards and specifications
++      issued by the IETF that apply the [X.509] certificate standards
++      specified by the ITU to Internet applications as specified in
++      [RFC5280] and related documents.
++
++   Resource Record (RR):  A particular entry in the DNS including the
++      owner name, class, type, time to live, and data, as defined in
++      [STD13] and [RFC2181].
++
++   Resource Record Set (RRSet):  A set of Resource Records or a
++      particular owner name, class, and type.  The time to live on all
++      RRs with an RRSet is always the same, but the data may be
++      different among RRs in the RRSet.
++
++
++
++Hallam-Baker & Stradling     Standards Track                    [Page 4]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   Relying Party:  A party that makes use of an application whose
++      operation depends on use of a certificate for making a security
++      decision.  See [RFC5280].
++
++   Relying Application:  An application whose operation depends on use
++      of a certificate for making a security decision.
++
++3.  The CAA RR Type
++
++   A CAA RR consists of a flags byte and a tag-value pair referred to as
++   a property.  Multiple properties MAY be associated with the same
++   domain name by publishing multiple CAA RRs at that domain name.  The
++   following flag is defined:
++
++   Issuer Critical:  If set to '1', indicates that the corresponding
++      property tag MUST be understood if the semantics of the CAA record
++      are to be correctly interpreted by an issuer.
++
++      Issuers MUST NOT issue certificates for a domain if the relevant
++      CAA Resource Record set contains unknown property tags that have
++      the Critical bit set.
++
++   The following property tags are defined:
++
++   issue <Issuer Domain Name> [; <name>=<value> ]* :  The issue property
++      entry authorizes the holder of the domain name <Issuer Domain
++      Name> or a party acting under the explicit authority of the holder
++      of that domain name to issue certificates for the domain in which
++      the property is published.
++
++   issuewild <Issuer Domain Name> [; <name>=<value> ]* :  The issuewild
++      property entry authorizes the holder of the domain name <Issuer
++      Domain Name> or a party acting under the explicit authority of the
++      holder of that domain name to issue wildcard certificates for the
++      domain in which the property is published.
++
++   iodef <URL> :  Specifies a URL to which an issuer MAY report
++      certificate issue requests that are inconsistent with the issuer's
++      Certification Practices or Certificate Policy, or that a
++      Certificate Evaluator may use to report observation of a possible
++      policy violation.  The Incident Object Description Exchange Format
++      (IODEF) format is used [RFC5070].
++
++   The following example is a DNS zone file (see [RFC1035]) that informs
++   CAs that certificates are not to be issued except by the holder of
++   the domain name 'ca.example.net' or an authorized agent thereof.
++   This policy applies to all subordinate domains under example.com.
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                    [Page 5]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   $ORIGIN example.com
++   .       CAA 0 issue "ca.example.net"
++
++   If the domain name holder specifies one or more iodef properties, a
++   certificate issuer MAY report invalid certificate requests to that
++   address.  In the following example, the domain name holder specifies
++   that reports may be made by means of email with the IODEF data as an
++   attachment, a Web service [RFC6546], or both:
++
++   $ORIGIN example.com
++   .       CAA 0 issue "ca.example.net"
++   .       CAA 0 iodef "mailto:security@example.com"
++   .       CAA 0 iodef "http://iodef.example.com/"
++
++   A certificate issuer MAY specify additional parameters that allow
++   customers to specify additional parameters governing certificate
++   issuance.  This might be the Certificate Policy under which the
++   certificate is to be issued, the authentication process to be used
++   might be specified, or an account number specified by the CA to
++   enable these parameters to be retrieved.
++
++   For example, the CA 'ca.example.net' has requested its customer
++   'example.com' to specify the CA's account number '230123' in each of
++   the customer's CAA records.
++
++   $ORIGIN example.com
++   .       CAA 0 issue "ca.example.net; account=230123"
++
++   The syntax of additional parameters is a sequence of name-value pairs
++   as defined in Section 5.2.  The semantics of such parameters is left
++   to site policy and is outside the scope of this document.
++
++   The critical flag is intended to permit future versions CAA to
++   introduce new semantics that MUST be understood for correct
++   processing of the record, preventing conforming CAs that do not
++   recognize the new semantics from issuing certificates for the
++   indicated domains.
++
++   In the following example, the property 'tbs' is flagged as critical.
++   Neither the example.net CA nor any other issuer is authorized to
++   issue under either policy unless the processing rules for the 'tbs'
++   property tag are understood.
++
++   $ORIGIN example.com
++   .       CAA 0 issue "ca.example.net; policy=ev"
++   .       CAA 128 tbs "Unknown"
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                    [Page 6]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   Note that the above restrictions only apply at certificate issue.
++   Since the validity of an end entity certificate is typically a year
++   or more, it is quite possible that the CAA records published at a
++   domain will change between the time a certificate was issued and
++   validation by a relying party.
++
++4.  Certification Authority Processing
++
++   Before issuing a certificate, a compliant CA MUST check for
++   publication of a relevant CAA Resource Record set.  If such a record
++   set exists, a CA MUST NOT issue a certificate unless the CA
++   determines that either (1) the certificate request is consistent with
++   the applicable CAA Resource Record set or (2) an exception specified
++   in the relevant Certificate Policy or Certification Practices
++   Statement applies.
++
++   A certificate request MAY specify more than one domain name and MAY
++   specify wildcard domains.  Issuers MUST verify authorization for all
++   the domains and wildcard domains specified in the request.
++
++   The search for a CAA record climbs the DNS name tree from the
++   specified label up to but not including the DNS root '.'.
++
++   Given a request for a specific domain X, or a request for a wildcard
++   domain *.X, the relevant record set R(X) is determined as follows:
++
++   Let CAA(X) be the record set returned in response to performing a CAA
++   record query on the label X, P(X) be the DNS label immediately above
++   X in the DNS hierarchy, and A(X) be the target of a CNAME or DNAME
++   alias record specified at the label X.
++
++   o  If CAA(X) is not empty, R(X) = CAA (X), otherwise
++
++   o  If A(X) is not null, and R(A(X)) is not empty, then R(X) =
++      R(A(X)), otherwise
++
++   o  If X is not a top-level domain, then R(X) = R(P(X)), otherwise
++
++   o  R(X) is empty.
++
++   For example, if a certificate is requested for X.Y.Z the issuer will
++   search for the relevant CAA record set in the following order:
++
++      X.Y.Z
++
++      Alias (X.Y.Z)
++
++      Y.Z
++
++
++
++Hallam-Baker & Stradling     Standards Track                    [Page 7]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++      Alias (Y.Z)
++
++      Z
++
++      Alias (Z)
++
++      Return Empty
++
++4.1.  Use of DNS Security
++
++   Use of DNSSEC to authenticate CAA RRs is strongly RECOMMENDED but not
++   required.  An issuer MUST NOT issue certificates if doing so would
++   conflict with the relevant CAA Resource Record set, irrespective of
++   whether the corresponding DNS records are signed.
++
++   DNSSEC provides a proof of non-existence for both DNS domains and RR
++   set within domains.  DNSSEC verification thus enables an issuer to
++   determine if the answer to a CAA record query is empty because the RR
++   set is empty or if it is non-empty but the response has been
++   suppressed.
++
++   Use of DNSSEC allows an issuer to acquire and archive a proof that
++   they were authorized to issue certificates for the domain.
++   Verification of such archives MAY be an audit requirement to verify
++   CAA record processing compliance.  Publication of such archives MAY
++   be a transparency requirement to verify CAA record processing
++   compliance.
++
++5.  Mechanism
++
++5.1.  Syntax
++
++   A CAA RR contains a single property entry consisting of a tag-value
++   pair.  Each tag represents a property of the CAA record.  The value
++   of a CAA property is that specified in the corresponding value field.
++
++   A domain name MAY have multiple CAA RRs associated with it and a
++   given property MAY be specified more than once.
++
++   The CAA data field contains one property entry.  A property entry
++   consists of the following data fields:
++
++
++
++
++
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                    [Page 8]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   +0-1-2-3-4-5-6-7-|0-1-2-3-4-5-6-7-|
++   | Flags          | Tag Length = n |
++   +----------------+----------------+...+---------------+
++   | Tag char 0     | Tag char 1     |...| Tag char n-1  |
++   +----------------+----------------+...+---------------+
++   +----------------+----------------+.....+----------------+
++   | Value byte 0   | Value byte 1   |.....| Value byte m-1 |
++   +----------------+----------------+.....+----------------+
++
++   Where n is the length specified in the Tag length field and m is the
++   remaining octets in the Value field (m = d - n - 2) where d is the
++   length of the RDATA section.
++
++   The data fields are defined as follows:
++
++   Flags:  One octet containing the following fields:
++
++      Bit 0, Issuer Critical Flag:  If the value is set to '1', the
++         critical flag is asserted and the property MUST be understood
++         if the CAA record is to be correctly processed by a certificate
++         issuer.
++
++         A Certification Authority MUST NOT issue certificates for any
++         Domain that contains a CAA critical property for an unknown or
++         unsupported property tag that for which the issuer critical
++         flag is set.
++
++      Note that according to the conventions set out in [RFC1035], bit 0
++      is the Most Significant Bit and bit 7 is the Least Significant
++      Bit. Thus, the Flags value 1 means that bit 7 is set while a value
++      of 128 means that bit 0 is set according to this convention.
++
++      All other bit positions are reserved for future use.
++
++      To ensure compatibility with future extensions to CAA, DNS records
++      compliant with this version of the CAA specification MUST clear
++      (set to "0") all reserved flags bits.  Applications that interpret
++      CAA records MUST ignore the value of all reserved flag bits.
++
++   Tag Length:  A single octet containing an unsigned integer specifying
++      the tag length in octets.  The tag length MUST be at least 1 and
++      SHOULD be no more than 15.
++
++
++
++
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                    [Page 9]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   Tag:  The property identifier, a sequence of US-ASCII characters.
++
++      Tag values MAY contain US-ASCII characters 'a' through 'z', 'A'
++      through 'Z', and the numbers 0 through 9.  Tag values SHOULD NOT
++      contain any other characters.  Matching of tag values is case
++      insensitive.
++
++      Tag values submitted for registration by IANA MUST NOT contain any
++      characters other than the (lowercase) US-ASCII characters 'a'
++      through 'z' and the numbers 0 through 9.
++
++   Value:  A sequence of octets representing the property value.
++      Property values are encoded as binary values and MAY employ sub-
++      formats.
++
++      The length of the value field is specified implicitly as the
++      remaining length of the enclosing Resource Record data field.
++
++5.1.1.  Canonical Presentation Format
++
++   The canonical presentation format of the CAA record is:
++
++   CAA <flags> <tag> <value>
++
++   Where:
++
++   Flags:  Is an unsigned integer between 0 and 255.
++
++   Tag:  Is a non-zero sequence of US-ASCII letters and numbers in lower
++      case.
++
++   Value:  Is the <character-string> encoding of the value field as
++      specified in [RFC1035], Section 5.1.
++
++5.2.  CAA issue Property
++
++   The issue property tag is used to request that certificate issuers
++   perform CAA issue restriction processing for the domain and to grant
++   authorization to specific certificate issuers.
++
++   The CAA issue property value has the following sub-syntax (specified
++   in ABNF as per [RFC5234]).
++
++
++
++
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                   [Page 10]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   issuevalue  = space [domain] space [";" *(space parameter) space]
++
++   domain = label *("." label)
++   label = (ALPHA / DIGIT) *( *("-") (ALPHA / DIGIT))
++
++   space = *(SP / HTAB)
++
++   parameter =  tag "=" value
++
++   tag = 1*(ALPHA / DIGIT)
++
++   value = *VCHAR
++
++   For consistency with other aspects of DNS administration, domain name
++   values are specified in letter-digit-hyphen Label (LDH-Label) form.
++
++   A CAA record with an issue parameter tag that does not specify a
++   domain name is a request that certificate issuers perform CAA issue
++   restriction processing for the corresponding domain without granting
++   authorization to any certificate issuer.
++
++   This form of issue restriction would be appropriate to specify that
++   no certificates are to be issued for the domain in question.
++
++   For example, the following CAA record set requests that no
++   certificates be issued for the domain 'nocerts.example.com' by any
++   certificate issuer.
++
++   nocerts.example.com       CAA 0 issue ";"
++
++   A CAA record with an issue parameter tag that specifies a domain name
++   is a request that certificate issuers perform CAA issue restriction
++   processing for the corresponding domain and grants authorization to
++   the certificate issuer specified by the domain name.
++
++   For example, the following CAA record set requests that no
++   certificates be issued for the domain 'certs.example.com' by any
++   certificate issuer other than the example.net certificate issuer.
++
++   certs.example.com       CAA 0 issue "example.net"
++
++   CAA authorizations are additive; thus, the result of specifying both
++   the empty issuer and a specified issuer is the same as specifying
++   just the specified issuer alone.
++
++
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                   [Page 11]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   An issuer MAY choose to specify issuer-parameters that further
++   constrain the issue of certificates by that issuer, for example,
++   specifying that certificates are to be subject to specific validation
++   polices, billed to certain accounts, or issued under specific trust
++   anchors.
++
++   The semantics of issuer-parameters are determined by the issuer
++   alone.
++
++5.3.  CAA issuewild Property
++
++   The issuewild property has the same syntax and semantics as the issue
++   property except that issuewild properties only grant authorization to
++   issue certificates that specify a wildcard domain and issuewild
++   properties take precedence over issue properties when specified.
++   Specifically:
++
++      issuewild properties MUST be ignored when processing a request for
++      a domain that is not a wildcard domain.
++
++      If at least one issuewild property is specified in the relevant
++      CAA record set, all issue properties MUST be ignored when
++      processing a request for a domain that is a wildcard domain.
++
++5.4.  CAA iodef Property
++
++   The iodef property specifies a means of reporting certificate issue
++   requests or cases of certificate issue for the corresponding domain
++   that violate the security policy of the issuer or the domain name
++   holder.
++
++   The Incident Object Description Exchange Format (IODEF) [RFC5070] is
++   used to present the incident report in machine-readable form.
++
++   The iodef property takes a URL as its parameter.  The URL scheme type
++   determines the method used for reporting:
++
++   mailto:  The IODEF incident report is reported as a MIME email
++      attachment to an SMTP email that is submitted to the mail address
++      specified.  The mail message sent SHOULD contain a brief text
++      message to alert the recipient to the nature of the attachment.
++
++   http or https:  The IODEF report is submitted as a Web service
++      request to the HTTP address specified using the protocol specified
++      in [RFC6546].
++
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                   [Page 12]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++6.  Security Considerations
++
++   CAA records assert a security policy that the holder of a domain name
++   wishes to be observed by certificate issuers.  The effectiveness of
++   CAA records as an access control mechanism is thus dependent on
++   observance of CAA constraints by issuers.
++
++   The objective of the CAA record properties described in this document
++   is to reduce the risk of certificate mis-issue rather than avoid
++   reliance on a certificate that has been mis-issued.  DANE [RFC6698]
++   describes a mechanism for avoiding reliance on mis-issued
++   certificates.
++
++6.1.  Non-Compliance by Certification Authority
++
++   CAA records offer CAs a cost-effective means of mitigating the risk
++   of certificate mis-issue: the cost of implementing CAA checks is very
++   small and the potential costs of a mis-issue event include the
++   removal of an embedded trust anchor.
++
++6.2.  Mis-Issue by Authorized Certification Authority
++
++   Use of CAA records does not prevent mis-issue by an authorized
++   Certification Authority, i.e., a CA that is authorized to issue
++   certificates for the domain in question by CAA records.
++
++   Domain name holders SHOULD verify that the CAs they authorize to
++   issue certificates for their domains employ appropriate controls to
++   ensure that certificates are issued only to authorized parties within
++   their organization.
++
++   Such controls are most appropriately determined by the domain name
++   holder and the authorized CA(s) directly and are thus out of scope of
++   this document.
++
++6.3.  Suppression or Spoofing of CAA Records
++
++   Suppression of the CAA record or insertion of a bogus CAA record
++   could enable an attacker to obtain a certificate from an issuer that
++   was not authorized to issue for that domain name.
++
++   Where possible, issuers SHOULD perform DNSSEC validation to detect
++   missing or modified CAA record sets.
++
++   In cases where DNSSEC is not deployed in a corresponding domain, an
++   issuer SHOULD attempt to mitigate this risk by employing appropriate
++   DNS security controls.  For example, all portions of the DNS lookup
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                   [Page 13]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   process SHOULD be performed against the authoritative name server.
++   Data cached by third parties MUST NOT be relied on but MAY be used to
++   support additional anti-spoofing or anti-suppression controls.
++
++6.4.  Denial of Service
++
++   Introduction of a malformed or malicious CAA RR could in theory
++   enable a Denial-of-Service (DoS) attack.
++
++   This specific threat is not considered to add significantly to the
++   risk of running an insecure DNS service.
++
++   An attacker could, in principle, perform a DoS attack against an
++   issuer by requesting a certificate with a maliciously long DNS name.
++   In practice, the DNS protocol imposes a maximum name length and CAA
++   processing does not exacerbate the existing need to mitigate DoS
++   attacks to any meaningful degree.
++
++6.5.  Abuse of the Critical Flag
++
++   A Certification Authority could make use of the critical flag to
++   trick customers into publishing records that prevent competing
++   Certification Authorities from issuing certificates even though the
++   customer intends to authorize multiple providers.
++
++   In practice, such an attack would be of minimal effect since any
++   competent competitor that found itself unable to issue certificates
++   due to lack of support for a property marked critical SHOULD
++   investigate the cause and report the reason to the customer.  The
++   customer will thus discover that they had been deceived.
++
++7.  IANA Considerations
++
++7.1.  Registration of the CAA Resource Record Type
++
++   IANA has assigned Resource Record Type 257 for the CAA Resource
++   Record Type and added the line depicted below to the registry named
++   "Resource Record (RR) TYPEs" and QTYPEs as defined in BCP 42
++   [RFC6195] and located at
++   http://www.iana.org/assignments/dns-parameters.
++
++ RR Name      Value and meaning                                Reference
++ -----------  ---------------------------------------------    ---------
++ CAA          257 Certification Authority Restriction          [RFC6844]
++
++
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                   [Page 14]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++7.2.  Certification Authority Restriction Properties
++
++   IANA has created the "Certification Authority Restriction Properties"
++   registry with the following initial values:
++
++
++   Tag          Meaning                                Reference
++   -----------  -------------------------------------- ---------
++   issue        Authorization Entry by Domain          [RFC6844]
++   issuewild    Authorization Entry by Wildcard Domain [RFC6844]
++   iodef        Report incident by IODEF report        [RFC6844]
++   auth         Reserved                               [HB2011]
++   path         Reserved                               [HB2011]
++   policy       Reserved                               [HB2011]
++
++
++   Although [HB2011] has expired, deployed clients implement the CAA
++   properties specified in the document and reuse of these property tags
++   for a different purpose could cause unexpected behavior.
++
++   Addition of tag identifiers requires a public specification and
++   Expert Review as set out in [RFC6195], Section 3.1.1.
++
++   The tag space is designed to be sufficiently large that exhausting
++   the possible tag space need not be a concern.  The scope of Expert
++   Review SHOULD be limited to the question of whether the specification
++   provided is sufficiently clear to permit implementation and to avoid
++   unnecessary duplication of functionality.
++
++7.3.  Certification Authority Restriction Flags
++
++   IANA has created the "Certification Authority Restriction Flags"
++   registry with the following initial values:
++
++
++             Flag         Meaning                            Reference
++   -----------  ---------------------------------- ---------
++   0            Issuer Critical Flag               [RFC6844]
++   1-7          Reserved>                          [RFC6844]
++
++   Assignment of new flags follows the RFC Required policy set out in
++   [RFC5226], Section 4.1.
++
++
++
++
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                   [Page 15]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++8.  Acknowledgements
++
++   The authors would like to thank the following people who contributed
++   to the design and documentation of this work item: Chris Evans,
++   Stephen Farrell, Jeff Hodges, Paul Hoffman, Stephen Kent, Adam
++   Langley, Ben Laurie, James Manager, Chris Palmer, Scott Schmit, Sean
++   Turner, and Ben Wilson.
++
++9.  References
++
++9.1.  Normative References
++
++   [RFC1035]  Mockapetris, P., "Domain names - implementation and
++              specification", STD 13, RFC 1035, November 1987.
++
++   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
++              Requirement Levels", BCP 14, RFC 2119, March 1997.
++
++   [RFC2181]  Elz, R. and R. Bush, "Clarifications to the DNS
++              Specification", RFC 2181, July 1997.
++
++   [RFC4033]  Arends, R., Austein, R., Larson, M., Massey, D., and S.
++              Rose, "DNS Security Introduction and Requirements",
++              RFC 4033, March 2005.
++
++   [RFC4034]  Arends, R., Austein, R., Larson, M., Massey, D., and S.
++              Rose, "Resource Records for the DNS Security Extensions",
++              RFC 4034, March 2005.
++
++   [RFC4035]  Arends, R., Austein, R., Larson, M., Massey, D., and S.
++              Rose, "Protocol Modifications for the DNS Security
++              Extensions", RFC 4035, March 2005.
++
++   [RFC5070]  Danyliw, R., Meijer, J., and Y. Demchenko, "The Incident
++              Object Description Exchange Format", RFC 5070,
++              December 2007.
++
++   [RFC5155]  Laurie, B., Sisson, G., Arends, R., and D. Blacka, "DNS
++              Security (DNSSEC) Hashed Authenticated Denial of
++              Existence", RFC 5155, March 2008.
++
++   [RFC5226]  Narten, T. and H. Alvestrand, "Guidelines for Writing an
++              IANA Considerations Section in RFCs", BCP 26, RFC 5226,
++              May 2008.
++
++   [RFC5234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
++              Specifications: ABNF", STD 68, RFC 5234, January 2008.
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                   [Page 16]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++   [RFC5280]  Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
++              Housley, R., and W. Polk, "Internet X.509 Public Key
++              Infrastructure Certificate and Certificate Revocation List
++              (CRL) Profile", RFC 5280, May 2008.
++
++   [RFC6195]  Eastlake, D., "Domain Name System (DNS) IANA
++              Considerations", BCP 42, RFC 6195, March 2011.
++
++   [RFC6546]  Trammell, B., "Transport of Real-time Inter-network
++              Defense (RID) Messages over HTTP/TLS", RFC 6546,
++              April 2012.
++
++   [RFC6698]  Hoffman, P. and J. Schlyter, "The DNS-Based Authentication
++              of Named Entities (DANE) Transport Layer Security (TLS)
++              Protocol: TLSA", RFC 6698, August 2012.
++
++   [STD13]    Mockapetris, P., "Domain names - concepts and facilities",
++              STD 13, RFC 1034, November 1987.
++
++              Mockapetris, P., "Domain names - implementation and
++              specification", STD 13, RFC 1035, November 1987.
++
++   [X.509]    International Telecommunication Union, "ITU-T
++              Recommendation X.509 (11/2008): Information technology -
++              Open systems interconnection - The Directory: Public-key
++              and attribute certificate frameworks", ITU-T
++              Recommendation X.509, November 2008.
++
++9.2.  Informative References
++
++   [HB2011]   Hallam-Baker, P., Stradling, R., and B. Laurie, "DNS
++              Certification Authority Authorization (CAA) Resource
++              Record", Work in Progress, May 2011.
++
++   [RFC3647]  Chokhani, S., Ford, W., Sabett, R., Merrill, C., and S.
++              Wu, "Internet X.509 Public Key Infrastructure Certificate
++              Policy and Certification Practices Framework", RFC 3647,
++              November 2003.
++
++
++
++
++
++
++
++
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                   [Page 17]
++
++RFC 6844          Certification Authority Authorization     January 2013
++
++
++Authors' Addresses
++
++   Phillip Hallam-Baker
++   Comodo Group, Inc.
++
++   EMail: philliph@comodo.com
++
++
++   Rob Stradling
++   Comodo CA, Ltd.
++
++   EMail: rob.stradling@comodo.com
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++Hallam-Baker & Stradling     Standards Track                   [Page 18]
++
+diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c
+index a83dab4..9bf83a4 100644
+--- a/lib/dns/rdata.c
++++ b/lib/dns/rdata.c
+@@ -116,7 +116,7 @@ typedef struct dns_rdata_textctx {
+ } dns_rdata_textctx_t;
+ 
+ static isc_result_t
+-txt_totext(isc_region_t *source, isc_buffer_t *target);
++txt_totext(isc_region_t *source, isc_boolean_t quote, isc_buffer_t *target);
+ 
+ static isc_result_t
+ txt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
+@@ -130,9 +130,6 @@ multitxt_totext(isc_region_t *source, isc_buffer_t *target);
+ static isc_result_t
+ multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
+ 
+-static isc_result_t
+-multitxt_fromwire(isc_buffer_t *source, isc_buffer_t *target);
+-
+ static isc_boolean_t
+ name_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target);
+ 
+@@ -1131,7 +1128,7 @@ name_length(dns_name_t *name) {
+ }
+ 
+ static isc_result_t
+-txt_totext(isc_region_t *source, isc_buffer_t *target) {
++txt_totext(isc_region_t *source, isc_boolean_t quote, isc_buffer_t *target) {
+ 	unsigned int tl;
+ 	unsigned int n;
+ 	unsigned char *sp;
+@@ -1146,13 +1143,20 @@ txt_totext(isc_region_t *source, isc_buffer_t *target) {
+ 	n = *sp++;
+ 
+ 	REQUIRE(n + 1 <= source->length);
++	if (n == 0U)
++		REQUIRE(quote == ISC_TRUE);
+ 
+-	if (tl < 1)
+-		return (ISC_R_NOSPACE);
+-	*tp++ = '"';
+-	tl--;
++	if (quote) {
++		if (tl < 1)
++			return (ISC_R_NOSPACE);
++		*tp++ = '"';
++		tl--;
++	}
+ 	while (n--) {
+-		if (*sp < 0x20 || *sp >= 0x7f) {
++		/*
++		 * \DDD space (0x20) if not quoting.
++		 */
++		if (*sp < (quote ? 0x20 : 0x21) || *sp >= 0x7f) {
+ 			if (tl < 4)
+ 				return (ISC_R_NOSPACE);
+ 			*tp++ = 0x5c;
+@@ -1163,8 +1167,13 @@ txt_totext(isc_region_t *source, isc_buffer_t *target) {
+ 			tl -= 4;
+ 			continue;
+ 		}
+-		/* double quote, semi-colon, backslash */
+-		if (*sp == 0x22 || *sp == 0x3b || *sp == 0x5c) {
++		/*
++		 * Escape double quote, semi-colon, backslash.
++		 * If we are not enclosing the string in double
++		 * quotes also escape at sign.
++		 */
++		if (*sp == 0x22 || *sp == 0x3b || *sp == 0x5c ||
++		    (!quote && *sp == 0x40)) {
+ 			if (tl < 2)
+ 				return (ISC_R_NOSPACE);
+ 			*tp++ = '\\';
+@@ -1175,10 +1184,12 @@ txt_totext(isc_region_t *source, isc_buffer_t *target) {
+ 		*tp++ = *sp++;
+ 		tl--;
+ 	}
+-	if (tl < 1)
+-		return (ISC_R_NOSPACE);
+-	*tp++ = '"';
+-	tl--;
++	if (quote) {
++		if (tl < 1)
++			return (ISC_R_NOSPACE);
++		*tp++ = '"';
++		tl--;
++	}
+ 	isc_buffer_add(target, tp - (char *)region.base);
+ 	isc_region_consume(source, *source->base + 1);
+ 	return (ISC_R_SUCCESS);
+@@ -1274,6 +1285,9 @@ txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) {
+ 	return (ISC_R_SUCCESS);
+ }
+ 
++/*
++ * Conversion of TXT-like rdata fields without length limits.
++ */
+ static isc_result_t
+ multitxt_totext(isc_region_t *source, isc_buffer_t *target) {
+ 	unsigned int tl;
+@@ -1292,9 +1306,8 @@ multitxt_totext(isc_region_t *source, isc_buffer_t *target) {
+ 	*tp++ = '"';
+ 	tl--;
+ 	do {
+-		n0 = n = *sp++;
+-
+-		REQUIRE(n0 + 1 <= source->length);
++		n = source->length;
++		n0 = source->length - 1;
+ 
+ 		while (n--) {
+ 			if (*sp < 0x20 || *sp >= 0x7f) {
+@@ -1346,17 +1359,11 @@ multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
+ 
+ 	do {
+ 		isc_buffer_availableregion(target, &tregion);
+-		t0 = tregion.base;
++		t0 = t = tregion.base;
+ 		nrem = tregion.length;
+ 		if (nrem < 1)
+ 			return (ISC_R_NOSPACE);
+-		/* length byte */
+-		t = t0;
+-		nrem--;
+-		t++;
+-		/* 255 byte character-string slice */
+-		if (nrem > 255)
+-			nrem = 255;
++
+ 		while (n != 0) {
+ 			--n;
+ 			c = (*s++) & 0xff;
+@@ -1390,39 +1397,9 @@ multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
+ 		}
+ 		if (escape)
+ 			return (DNS_R_SYNTAX);
+-		*t0 = t - t0 - 1;
+-		isc_buffer_add(target, *t0 + 1);
+-	} while (n != 0);
+-	return (ISC_R_SUCCESS);
+-}
+-
+-static isc_result_t
+-multitxt_fromwire(isc_buffer_t *source, isc_buffer_t *target) {
+-	unsigned int n;
+-	isc_region_t sregion;
+-	isc_region_t tregion;
+-
+-	isc_buffer_activeregion(source, &sregion);
+-	if (sregion.length == 0)
+-		return(ISC_R_UNEXPECTEDEND);
+-	n = 256U;
+-	do {
+-		if (n != 256U)
+-			return (DNS_R_SYNTAX);
+-		n = *sregion.base + 1;
+-		if (n > sregion.length)
+-			return (ISC_R_UNEXPECTEDEND);
+ 
+-		isc_buffer_availableregion(target, &tregion);
+-		if (n > tregion.length)
+-			return (ISC_R_NOSPACE);
+-
+-		if (tregion.base != sregion.base)
+-			memcpy(tregion.base, sregion.base, n);
+-		isc_buffer_forward(source, n);
+-		isc_buffer_add(target, n);
+-		isc_buffer_activeregion(source, &sregion);
+-	} while (sregion.length != 0);
++		isc_buffer_add(target, t - t0);
++	} while (n != 0);
+ 	return (ISC_R_SUCCESS);
+ }
+ 
+diff --git a/lib/dns/rdata/generic/caa_257.c b/lib/dns/rdata/generic/caa_257.c
+new file mode 100644
+index 0000000..671f332
+--- /dev/null
++++ b/lib/dns/rdata/generic/caa_257.c
+@@ -0,0 +1,370 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef GENERIC_CAA_257_C
++#define GENERIC_CAA_257_C 1
++
++#define RRTYPE_CAA_ATTRIBUTES (0)
++
++static unsigned char const alphanumeric[256] = {
++	/* 0x00-0x0f */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0x10-0x1f */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0x20-0x2f */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0x30-0x3f */ 1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 0, 0, 0, 0, 0, 0,
++	/* 0x40-0x4f */ 0, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
++	/* 0x50-0x5f */ 1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 0, 0, 0, 0, 0,
++	/* 0x60-0x6f */ 0, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
++	/* 0x70-0x7f */ 1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 0, 0, 0, 0, 0,
++	/* 0x80-0x8f */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0x90-0x9f */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0xa0-0xaf */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0xb0-0xbf */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0xc0-0xcf */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0xd0-0xdf */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0xe0-0xef */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++	/* 0xf0-0xff */ 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
++};
++
++static inline isc_result_t
++fromtext_caa(ARGS_FROMTEXT) {
++	isc_token_t token;
++	isc_textregion_t tr;
++	isc_uint8_t flags;
++	unsigned int i;
++
++	REQUIRE(type == 257);
++
++	UNUSED(type);
++	UNUSED(rdclass);
++	UNUSED(origin);
++	UNUSED(options);
++	UNUSED(callbacks);
++
++	/* Flags. */
++	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
++				      ISC_FALSE));
++	if (token.value.as_ulong > 255U)
++		RETTOK(ISC_R_RANGE);
++	flags = token.value.as_ulong & 255U;
++	RETERR(uint8_tobuffer(flags, target));
++
++	/*
++	 * Tag
++	 */
++	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
++				      ISC_FALSE));
++	tr = token.value.as_textregion;
++	for (i = 0; i < tr.length; i++)
++		if (!alphanumeric[(unsigned char) tr.base[i]])
++			RETTOK(DNS_R_SYNTAX);
++	RETERR(uint8_tobuffer(tr.length, target));
++	RETERR(mem_tobuffer(target, tr.base, tr.length));
++
++	/*
++	 * Value
++	 */
++	RETERR(isc_lex_getmastertoken(lexer, &token,
++				      isc_tokentype_qstring, ISC_FALSE));
++	if (token.type != isc_tokentype_qstring &&
++	    token.type != isc_tokentype_string)
++		RETERR(DNS_R_SYNTAX);
++	RETERR(multitxt_fromtext(&token.value.as_textregion, target));
++	return (ISC_R_SUCCESS);
++}
++
++static inline isc_result_t
++totext_caa(ARGS_TOTEXT) {
++	isc_region_t region;
++	isc_uint8_t flags;
++	char buf[256];
++
++	UNUSED(tctx);
++
++	REQUIRE(rdata->type == 257);
++	REQUIRE(rdata->length >= 3U);
++	REQUIRE(rdata->data != NULL);
++
++	dns_rdata_toregion(rdata, &region);
++
++	/*
++	 * Flags
++	 */
++	flags = uint8_consume_fromregion(&region);
++	sprintf(buf, "%u ", flags);
++	RETERR(str_totext(buf, target));
++
++	/*
++	 * Tag
++	 */
++	RETERR(txt_totext(&region, ISC_FALSE, target));
++	RETERR(str_totext(" ", target));
++
++	/*
++	 * Value
++	 */
++	RETERR(multitxt_totext(&region, target));
++	return (ISC_R_SUCCESS);
++}
++
++static inline isc_result_t
++fromwire_caa(ARGS_FROMWIRE) {
++	isc_region_t sr;
++	unsigned int len, i;
++
++	REQUIRE(type == 257);
++
++	UNUSED(type);
++	UNUSED(rdclass);
++	UNUSED(dctx);
++	UNUSED(options);
++
++	/*
++	 * Flags
++	 */
++	isc_buffer_activeregion(source, &sr);
++	if (sr.length < 2)
++		return (ISC_R_UNEXPECTEDEND);
++
++	/*
++	 * Flags, tag length
++	 */
++	RETERR(mem_tobuffer(target, sr.base, 2));
++	len = sr.base[1];
++	isc_region_consume(&sr, 2);
++	isc_buffer_forward(source, 2);
++
++	/*
++	 * Zero length tag fields are illegal.
++	 */
++	if (sr.length < len || len == 0)
++		RETERR(DNS_R_FORMERR);
++
++	/* Check the Tag's value */
++	for (i = 0; i < len; i++)
++		if (!alphanumeric[sr.base[i]])
++			RETERR(DNS_R_FORMERR);
++	/*
++	 * Tag + Value
++	 */
++	isc_buffer_forward(source, sr.length);
++	return (mem_tobuffer(target, sr.base, sr.length));
++}
++
++static inline isc_result_t
++towire_caa(ARGS_TOWIRE) {
++	isc_region_t region;
++
++	REQUIRE(rdata->type == 257);
++	REQUIRE(rdata->length >= 3U);
++	REQUIRE(rdata->data != NULL);
++
++	UNUSED(cctx);
++
++	dns_rdata_toregion(rdata, &region);
++	return (mem_tobuffer(target, region.base, region.length));
++}
++
++static inline int
++compare_caa(ARGS_COMPARE) {
++	isc_region_t r1, r2;
++
++	REQUIRE(rdata1->type == rdata2->type);
++	REQUIRE(rdata1->rdclass == rdata2->rdclass);
++	REQUIRE(rdata1->type == 257);
++	REQUIRE(rdata1->length >= 3U);
++	REQUIRE(rdata2->length >= 3U);
++	REQUIRE(rdata1->data != NULL);
++	REQUIRE(rdata2->data != NULL);
++
++	dns_rdata_toregion(rdata1, &r1);
++	dns_rdata_toregion(rdata2, &r2);
++	return (isc_region_compare(&r1, &r2));
++}
++
++static inline isc_result_t
++fromstruct_caa(ARGS_FROMSTRUCT) {
++	dns_rdata_caa_t *caa = source;
++	isc_region_t region;
++	unsigned int i;
++
++	REQUIRE(type == 257);
++	REQUIRE(source != NULL);
++	REQUIRE(caa->common.rdtype == type);
++	REQUIRE(caa->common.rdclass == rdclass);
++	REQUIRE(caa->tag != NULL && caa->tag_len != 0);
++	REQUIRE(caa->value != NULL);
++
++	UNUSED(type);
++	UNUSED(rdclass);
++
++	/*
++	 * Flags
++	 */
++	RETERR(uint8_tobuffer(caa->flags, target));
++
++	/*
++	 * Tag length
++	 */
++	RETERR(uint8_tobuffer(caa->tag_len, target));
++
++	/*
++	 * Tag
++	 */
++	region.base = caa->tag;
++	region.length = caa->tag_len;
++	for (i = 0; i < region.length; i++)
++		if (!alphanumeric[region.base[i]])
++			RETERR(DNS_R_SYNTAX);
++	RETERR(isc_buffer_copyregion(target, &region));
++
++	/*
++	 * Value
++	 */
++	region.base = caa->value;
++	region.length = caa->value_len;
++	return (isc_buffer_copyregion(target, &region));
++}
++
++static inline isc_result_t
++tostruct_caa(ARGS_TOSTRUCT) {
++	dns_rdata_caa_t *caa = target;
++	isc_region_t sr;
++
++	REQUIRE(rdata->type == 257);
++	REQUIRE(target != NULL);
++	REQUIRE(rdata->length >= 3U);
++	REQUIRE(rdata->data != NULL);
++
++	caa->common.rdclass = rdata->rdclass;
++	caa->common.rdtype = rdata->type;
++	ISC_LINK_INIT(&caa->common, link);
++
++	dns_rdata_toregion(rdata, &sr);
++
++	/*
++	 * Flags
++	 */
++	if (sr.length < 1)
++		return (ISC_R_UNEXPECTEDEND);
++	caa->flags = uint8_fromregion(&sr);
++	isc_region_consume(&sr, 1);
++
++	/*
++	 * Tag length
++	 */
++	if (sr.length < 1)
++		return (ISC_R_UNEXPECTEDEND);
++	caa->tag_len = uint8_fromregion(&sr);
++	isc_region_consume(&sr, 1);
++
++	/*
++	 * Tag
++	 */
++	if (sr.length < caa->tag_len)
++		return (ISC_R_UNEXPECTEDEND);
++	caa->tag = mem_maybedup(mctx, sr.base, caa->tag_len);
++	if (caa->tag == NULL)
++		return (ISC_R_NOMEMORY);
++	isc_region_consume(&sr, caa->tag_len);
++
++	/*
++	 * Value
++	 */
++	caa->value_len = sr.length;
++	caa->value = mem_maybedup(mctx, sr.base, sr.length);
++	if (caa->value == NULL)
++		return (ISC_R_NOMEMORY);
++
++	caa->mctx = mctx;
++	return (ISC_R_SUCCESS);
++}
++
++static inline void
++freestruct_caa(ARGS_FREESTRUCT) {
++	dns_rdata_caa_t *caa = (dns_rdata_caa_t *) source;
++
++	REQUIRE(source != NULL);
++	REQUIRE(caa->common.rdtype == 257);
++
++	if (caa->mctx == NULL)
++		return;
++
++	if (caa->tag != NULL)
++		isc_mem_free(caa->mctx, caa->tag);
++	if (caa->value != NULL)
++		isc_mem_free(caa->mctx, caa->value);
++	caa->mctx = NULL;
++}
++
++static inline isc_result_t
++additionaldata_caa(ARGS_ADDLDATA) {
++	REQUIRE(rdata->type == 257);
++	REQUIRE(rdata->data != NULL);
++	REQUIRE(rdata->length >= 3U);
++
++	UNUSED(rdata);
++	UNUSED(add);
++	UNUSED(arg);
++
++	return (ISC_R_SUCCESS);
++}
++
++static inline isc_result_t
++digest_caa(ARGS_DIGEST) {
++	isc_region_t r;
++
++	REQUIRE(rdata->type == 257);
++	REQUIRE(rdata->data != NULL);
++	REQUIRE(rdata->length >= 3U);
++
++	dns_rdata_toregion(rdata, &r);
++
++	return ((digest)(arg, &r));
++}
++
++static inline isc_boolean_t
++checkowner_caa(ARGS_CHECKOWNER) {
++
++	REQUIRE(type == 257);
++
++	UNUSED(name);
++	UNUSED(type);
++	UNUSED(rdclass);
++	UNUSED(wildcard);
++
++	return (ISC_TRUE);
++}
++
++static inline isc_boolean_t
++checknames_caa(ARGS_CHECKNAMES) {
++
++	REQUIRE(rdata->type == 257);
++	REQUIRE(rdata->data != NULL);
++	REQUIRE(rdata->length >= 3U);
++
++	UNUSED(rdata);
++	UNUSED(owner);
++	UNUSED(bad);
++
++	return (ISC_TRUE);
++}
++
++static inline int
++casecompare_caa(ARGS_COMPARE) {
++	return (compare_caa(rdata1, rdata2));
++}
++
++#endif /* GENERIC_CAA_257_C */
+diff --git a/lib/dns/rdata/generic/caa_257.h b/lib/dns/rdata/generic/caa_257.h
+new file mode 100644
+index 0000000..79866a5
+--- /dev/null
++++ b/lib/dns/rdata/generic/caa_257.h
+@@ -0,0 +1,32 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef GENERIC_CAA_257_H
++#define GENERIC_CAA_257_H 1
++
++/* $Id$ */
++
++typedef struct dns_rdata_caa {
++	dns_rdatacommon_t	common;
++	isc_mem_t *		mctx;
++	isc_uint8_t		flags;
++	unsigned char *		tag;
++	isc_uint8_t		tag_len;
++        unsigned char		*value;
++        isc_uint8_t		value_len;
++} dns_rdata_caa_t;
++
++#endif /* GENERIC_CAA_257_H */
+diff --git a/lib/dns/rdata/generic/gpos_27.c b/lib/dns/rdata/generic/gpos_27.c
+index ce71822..5a90216 100644
+--- a/lib/dns/rdata/generic/gpos_27.c
++++ b/lib/dns/rdata/generic/gpos_27.c
+@@ -61,7 +61,7 @@ totext_gpos(ARGS_TOTEXT) {
+ 	dns_rdata_toregion(rdata, &region);
+ 
+ 	for (i = 0; i < 3; i++) {
+-		RETERR(txt_totext(&region, target));
++		RETERR(txt_totext(&region, ISC_TRUE, target));
+ 		if (i != 2)
+ 			RETERR(str_totext(" ", target));
+ 	}
+diff --git a/lib/dns/rdata/generic/hinfo_13.c b/lib/dns/rdata/generic/hinfo_13.c
+index 10b4fec..92038b7 100644
+--- a/lib/dns/rdata/generic/hinfo_13.c
++++ b/lib/dns/rdata/generic/hinfo_13.c
+@@ -58,9 +58,9 @@ totext_hinfo(ARGS_TOTEXT) {
+ 	REQUIRE(rdata->length != 0);
+ 
+ 	dns_rdata_toregion(rdata, &region);
+-	RETERR(txt_totext(&region, target));
++	RETERR(txt_totext(&region, ISC_TRUE, target));
+ 	RETERR(str_totext(" ", target));
+-	return (txt_totext(&region, target));
++	return (txt_totext(&region, ISC_TRUE, target));
+ }
+ 
+ static inline isc_result_t
+diff --git a/lib/dns/rdata/generic/isdn_20.c b/lib/dns/rdata/generic/isdn_20.c
+index 5aac73f..059c247 100644
+--- a/lib/dns/rdata/generic/isdn_20.c
++++ b/lib/dns/rdata/generic/isdn_20.c
+@@ -65,11 +65,11 @@ totext_isdn(ARGS_TOTEXT) {
+ 	UNUSED(tctx);
+ 
+ 	dns_rdata_toregion(rdata, &region);
+-	RETERR(txt_totext(&region, target));
++	RETERR(txt_totext(&region, ISC_TRUE, target));
+ 	if (region.length == 0)
+ 		return (ISC_R_SUCCESS);
+ 	RETERR(str_totext(" ", target));
+-	return (txt_totext(&region, target));
++	return (txt_totext(&region, ISC_TRUE, target));
+ }
+ 
+ static inline isc_result_t
+diff --git a/lib/dns/rdata/generic/naptr_35.c b/lib/dns/rdata/generic/naptr_35.c
+index 83439a5..be7d403 100644
+--- a/lib/dns/rdata/generic/naptr_35.c
++++ b/lib/dns/rdata/generic/naptr_35.c
+@@ -224,19 +224,19 @@ totext_naptr(ARGS_TOTEXT) {
+ 	/*
+ 	 * Flags.
+ 	 */
+-	RETERR(txt_totext(&region, target));
++	RETERR(txt_totext(&region, ISC_TRUE, target));
+ 	RETERR(str_totext(" ", target));
+ 
+ 	/*
+ 	 * Service.
+ 	 */
+-	RETERR(txt_totext(&region, target));
++	RETERR(txt_totext(&region, ISC_TRUE, target));
+ 	RETERR(str_totext(" ", target));
+ 
+ 	/*
+ 	 * Regexp.
+ 	 */
+-	RETERR(txt_totext(&region, target));
++	RETERR(txt_totext(&region, ISC_TRUE, target));
+ 	RETERR(str_totext(" ", target));
+ 
+ 	/*
+diff --git a/lib/dns/rdata/generic/spf_99.c b/lib/dns/rdata/generic/spf_99.c
+index 492e315..85594fd 100644
+--- a/lib/dns/rdata/generic/spf_99.c
++++ b/lib/dns/rdata/generic/spf_99.c
+@@ -64,7 +64,7 @@ totext_spf(ARGS_TOTEXT) {
+ 	dns_rdata_toregion(rdata, &region);
+ 
+ 	while (region.length > 0) {
+-		RETERR(txt_totext(&region, target));
++		RETERR(txt_totext(&region, ISC_TRUE, target));
+ 		if (region.length > 0)
+ 			RETERR(str_totext(" ", target));
+ 	}
+diff --git a/lib/dns/rdata/generic/txt_16.c b/lib/dns/rdata/generic/txt_16.c
+index e1bce6a..e0e8ea5 100644
+--- a/lib/dns/rdata/generic/txt_16.c
++++ b/lib/dns/rdata/generic/txt_16.c
+@@ -71,7 +71,7 @@ totext_txt(ARGS_TOTEXT) {
+ 	dns_rdata_toregion(rdata, &region);
+ 
+ 	while (region.length > 0) {
+-		RETERR(txt_totext(&region, target));
++		RETERR(txt_totext(&region, ISC_TRUE, target));
+ 		if (region.length > 0)
+ 			RETERR(str_totext(" ", target));
+ 	}
+diff --git a/lib/dns/rdata/generic/uri_256.c b/lib/dns/rdata/generic/uri_256.c
+index 799eb69..62bdd25 100644
+--- a/lib/dns/rdata/generic/uri_256.c
++++ b/lib/dns/rdata/generic/uri_256.c
+@@ -115,15 +115,12 @@ fromwire_uri(ARGS_FROMWIRE) {
+ 	isc_buffer_activeregion(source, &region);
+ 	if (region.length < 4)
+ 		return (ISC_R_UNEXPECTEDEND);
+-	RETERR(mem_tobuffer(target, region.base, 4));
+-	isc_buffer_forward(source, 4);
+ 
+ 	/*
+-	 * Target URI
++	 * Priority, weight and target URI
+ 	 */
+-	RETERR(multitxt_fromwire(source, target));
+-
+-	return (ISC_R_SUCCESS);
++	isc_buffer_forward(source, region.length);
++	return (mem_tobuffer(target, region.base, region.length));
+ }
+ 
+ static inline isc_result_t
+@@ -178,8 +175,6 @@ compare_uri(ARGS_COMPARE) {
+ static inline isc_result_t
+ fromstruct_uri(ARGS_FROMSTRUCT) {
+ 	dns_rdata_uri_t *uri = source;
+-	isc_region_t region;
+-	isc_uint8_t len;
+ 
+ 	REQUIRE(type == 256);
+ 	REQUIRE(source != NULL);
+@@ -203,18 +198,6 @@ fromstruct_uri(ARGS_FROMSTRUCT) {
+ 	/*
+ 	 * Target URI
+ 	 */
+-	len = 255U;
+-	region.base = uri->target;
+-	region.length = uri->tgt_len;
+-	while (region.length > 0) {
+-		REQUIRE(len == 255U);
+-		len = uint8_fromregion(&region);
+-		isc_region_consume(&region, 1);
+-		if (region.length < len)
+-			return (ISC_R_UNEXPECTEDEND);
+-		isc_region_consume(&region, len);
+-	}
+-
+ 	return (mem_tobuffer(target, uri->target, uri->tgt_len));
+ }
+ 
+diff --git a/lib/dns/rdata/generic/x25_19.c b/lib/dns/rdata/generic/x25_19.c
+index 6867fec..f9dfb8a 100644
+--- a/lib/dns/rdata/generic/x25_19.c
++++ b/lib/dns/rdata/generic/x25_19.c
+@@ -60,7 +60,7 @@ totext_x25(ARGS_TOTEXT) {
+ 	REQUIRE(rdata->length != 0);
+ 
+ 	dns_rdata_toregion(rdata, &region);
+-	return (txt_totext(&region, target));
++	return (txt_totext(&region, ISC_TRUE, target));
+ }
+ 
+ static inline isc_result_t
+-- 
+2.4.3
+
diff --git a/SOURCES/named-chroot.service b/SOURCES/named-chroot.service
index f8c0496..55bf507 100644
--- a/SOURCES/named-chroot.service
+++ b/SOURCES/named-chroot.service
@@ -16,7 +16,7 @@ EnvironmentFile=-/etc/sysconfig/named
 Environment=KRB5_KTNAME=/etc/named.keytab
 PIDFile=/var/named/chroot/run/named/named.pid
 
-ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -z /etc/named.conf; else echo "Checking of zone files is disabled"; fi'
+ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -t /var/named/chroot -z /etc/named.conf; else echo "Checking of zone files is disabled"; fi'
 ExecStart=/usr/sbin/named -u named -t /var/named/chroot $OPTIONS
 
 ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID'
diff --git a/SOURCES/named-pkcs11.service b/SOURCES/named-pkcs11.service
index 6ce9001..e522ec3 100644
--- a/SOURCES/named-pkcs11.service
+++ b/SOURCES/named-pkcs11.service
@@ -1,10 +1,9 @@
 [Unit]
 Description=Berkeley Internet Name Domain (DNS) with native PKCS#11
 Wants=nss-lookup.target
-Wants=network-online.target
 Wants=named-setup-rndc.service
 Before=nss-lookup.target
-After=network-online.target
+After=network.target
 After=named-setup-rndc.service
 
 [Service]
diff --git a/SOURCES/named-sdb-chroot.service b/SOURCES/named-sdb-chroot.service
index 09b7974..2e42646 100644
--- a/SOURCES/named-sdb-chroot.service
+++ b/SOURCES/named-sdb-chroot.service
@@ -16,7 +16,7 @@ EnvironmentFile=-/etc/sysconfig/named
 Environment=KRB5_KTNAME=/etc/named.keytab
 PIDFile=/var/named/chroot_sdb/run/named/named.pid
 
-ExecStartPre=/usr/sbin/named-checkconf -t /var/named/chroot_sdb -z /etc/named.conf
+ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -t /var/named/chroot_sdb -z /etc/named.conf; else echo "Checking of zone files is disabled"; fi'
 ExecStart=/usr/sbin/named-sdb -u named -t /var/named/chroot_sdb $OPTIONS
 
 ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID'
diff --git a/SOURCES/named.NetworkManager b/SOURCES/named.NetworkManager
deleted file mode 100644
index c835a00..0000000
--- a/SOURCES/named.NetworkManager
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-if [ "$2" = 'up' -o "$2" = 'down' ]; then
-	/usr/bin/systemctl reload named.service > /dev/null 2>&1 || true
-	/usr/bin/systemctl reload named-chroot.service > /dev/null 2>&1 || true
-	/usr/bin/systemctl reload named-sdb.service > /dev/null 2>&1 || true
-	/usr/bin/systemctl reload named-sdb-chroot.service > /dev/null 2>&1 || true
-fi
diff --git a/SOURCES/named.conf.sample b/SOURCES/named.conf.sample
index afae47b..f091345 100644
--- a/SOURCES/named.conf.sample
+++ b/SOURCES/named.conf.sample
@@ -2,10 +2,8 @@
  Sample named.conf BIND DNS server 'named' configuration file
  for the Red Hat BIND distribution.
 
- See the BIND Administrator's Reference Manual (ARM) for details, in:
-   file:///usr/share/doc/bind-{version}/arm/Bv9ARM.html
- Also see the BIND Configuration GUI : /usr/bin/system-config-bind and 
- its manual.
+ See the BIND Administrator's Reference Manual (ARM) for details about the
+ configuration located in /usr/share/doc/bind-{version}/Bv9ARM.html
 */
 
 options
diff --git a/SPECS/bind.spec b/SPECS/bind.spec
index 5d516b5..638582e 100644
--- a/SPECS/bind.spec
+++ b/SPECS/bind.spec
@@ -25,21 +25,20 @@ Summary:  The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv
 Name:     bind
 License:  ISC
 Version:  9.9.4
-Release:  29%{?PATCHVER}%{?PREVER}%{?dist}.4
+Release:  37%{?PATCHVER}%{?PREVER}%{?dist}
 Epoch:    32
 Url:      http://www.isc.org/products/BIND/
 Buildroot:%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 Group:    System Environment/Daemons
 #
-Source:   ftp://ftp.isc.org/isc/bind9/%{VERSION}/bind-%{VERSION}.tar.gz
+Source:   https://ftp.isc.org/isc/bind9/%{VERSION}/bind-%{VERSION}.tar.gz
 Source1:  named.sysconfig
 Source3:  named.logrotate
-Source4:  named.NetworkManager
 Source7:  bind-9.3.1rc1-sdb_tools-Makefile.in
 Source8:  dnszone.schema
 Source12: README.sdb_pgsql
 Source25: named.conf.sample
-Source28: config-13.tar.bz2
+Source28: config-14.tar.bz2
 Source30: ldap2zone.c
 Source31: ldap2zone.1
 Source32: named-sdb.8
@@ -58,6 +57,9 @@ Source44: named-chroot-setup.service
 Source45: named-sdb-chroot-setup.service
 Source46: named-setup-rndc.service
 Source47: named-pkcs11.service
+# added due to GeoIP functionality tests
+# patch tool does not support binary patches
+Source48: geoip-testing-data.tar.xz
 
 # Common patches
 Patch5:  bind-nonexec.patch
@@ -104,7 +106,12 @@ Patch159:bind99-CVE-2015-5722.patch
 Patch160:bind99-CVE-2015-8000.patch
 Patch161:bind99-CVE-2015-8704.patch
 Patch162:bind99-CVE-2016-1285-CVE-2016-1286.patch
-patch163:bind99-CVE-2016-2776.patch
+Patch163:bind99-rh1291185.patch
+Patch164:bind99-rh1259514.patch
+Patch165:bind99-rh1306610.patch
+Patch166:bind99-rh1220594-geoip.patch
+Patch167:bind99-automatic-interface-scanning-rh1294506.patch
+patch168:bind99-CVE-2016-2776.patch
 
 # Native PKCS#11 functionality from 9.10
 Patch150:bind-9.9-allow_external_dnskey.patch
@@ -144,7 +151,7 @@ Provides:       caching-nameserver = 31:9.4.1-7.fc8
 Obsoletes:      dnssec-conf < 1.27-2
 Provides:       dnssec-conf = 1.27-1
 BuildRequires:  openssl-devel, libtool, autoconf, pkgconfig, libcap-devel
-BuildRequires:  libidn-devel, libxml2-devel
+BuildRequires:  libidn-devel, libxml2-devel, GeoIP-devel
 BuildRequires:  systemd-units
 %if %{SDB}
 BuildRequires:  openldap-devel, postgresql-devel, sqlite-devel, mysql-devel
@@ -382,7 +389,17 @@ popd
 %patch160 -p1 -b .CVE-2015-8000
 %patch161 -p1 -b .CVE-2015-8704
 %patch162 -p1 -b .CVE-2016-1285-CVE-2016-1286
-%patch163 -p1 -b .CVE-2016-2776
+%patch163 -p1 -b .rh1291185
+%patch164 -p1 -b .rh1259514
+%patch165 -p1 -b .rh1306610-caa
+
+# GeoIP support
+%patch166 -p1 -b .rh1220594-geoip
+# extract the binary testing data
+tar -xf %{SOURCE48} -C bin/tests/system/geoip/data
+
+%patch167 -p1 -b .rh1294506
+%patch168 -p1 -b .CVE-2016-2776
 
 %if %{PKCS11}
 cp -r bin/named{,-pkcs11}
@@ -453,6 +470,7 @@ libtoolize -c -f; aclocal -I libtool.m4 --force; autoconf -f
   --with-libtool \
   --localstatedir=/var \
   --enable-threads \
+  --with-geoip \
   --enable-ipv6 \
   --enable-filter-aaaa \
   --enable-rrl \
@@ -519,7 +537,7 @@ else
 rm -rf ${RPM_BUILD_ROOT}
 
 # Build directory hierarchy
-mkdir -p ${RPM_BUILD_ROOT}/etc/{logrotate.d,NetworkManager/dispatcher.d}
+mkdir -p ${RPM_BUILD_ROOT}/etc/logrotate.d
 mkdir -p ${RPM_BUILD_ROOT}%{_libdir}/bind
 mkdir -p ${RPM_BUILD_ROOT}/var/named/{slaves,data,dynamic}
 mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/{man1,man5,man8}
@@ -590,7 +608,6 @@ install -m 755 %{SOURCE41} ${RPM_BUILD_ROOT}%{_libexecdir}/setup-named-chroot.sh
 install -m 755 %{SOURCE42} ${RPM_BUILD_ROOT}%{_libexecdir}/generate-rndc-key.sh
 
 install -m 644 %SOURCE3 ${RPM_BUILD_ROOT}/etc/logrotate.d/named
-install -m 755 %SOURCE4 ${RPM_BUILD_ROOT}/etc/NetworkManager/dispatcher.d/13-named
 mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig
 install -m 644 %{SOURCE1} ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/named
 %if %{SDB}
@@ -837,7 +854,6 @@ rm -rf ${RPM_BUILD_ROOT}
 %{_sysconfdir}/rwtab.d/named
 %{_unitdir}/named.service
 %{_unitdir}/named-setup-rndc.service
-%{_sysconfdir}/NetworkManager/dispatcher.d/13-named
 %{_sbindir}/arpaname
 %{_sbindir}/ddns-confgen
 %{_sbindir}/genrandom
@@ -1063,16 +1079,33 @@ rm -rf ${RPM_BUILD_ROOT}
 %endif
 
 %changelog
-* Fri Sep 23 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-29.4
+* Fri Sep 23 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-37
 - Fix CVE-2016-2776
 
-* Tue Mar 08 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-29.3
+* Wed May 11 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-36
+- Added automatic interface scan functionality (#1294506)
+- Removed NetworkManager dispatcher script since it is not needed any more (#1294506)
+
+* Wed Apr 13 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-35
+- Added GeoIP support (#1220594)
+
+* Fri Apr 01 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-34
+- Added support for CAA records (#1306610)
+- Use HTTPS URL instead of FTP for upstream sources (#1319280)
+
+* Tue Mar 22 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-33
+- Fix excessive queries caused by DS chasing with stub zones when DNSSEC is not used (#1291185)
+- Fix error in internal test suite (#1259514)
+- Fix named-checkconf call in *-chroot.service files (#1278082)
+- Fix incorrect path in BIND sample configuration and added comment to default configuration (#1247502)
+
+* Tue Mar 08 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-32
 - Fix CVE-2016-1285 and CVE-2016-1286
 
-* Mon Jan 18 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-29.2
+* Mon Jan 18 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-31
 - Fix CVE-2015-8704
 
-* Mon Dec 14 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-29.1
+* Mon Dec 14 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-30
 - Fix CVE-2015-8000
 
 * Wed Sep 02 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-29