diff --git a/.gitignore b/.gitignore
index 1cd99dfd3815b114382f7ade57b63c81210fbbad..cedff8fb37cda019e0cbabef6477bc8bf077066d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -173,6 +173,8 @@ uptime-*.json
 /src/lib/libtor-fdio-testing.a
 /src/lib/libtor-fs.a
 /src/lib/libtor-fs-testing.a
+/src/lib/libtor-geoip.a
+/src/lib/libtor-geoip-testing.a
 /src/lib/libtor-intmath.a
 /src/lib/libtor-intmath-testing.a
 /src/lib/libtor-lock.a
diff --git a/Makefile.am b/Makefile.am
index 36a5dd2e9e9aecd2dc57b059f4c14104b0a1262d..a0f513c75ef55cc31597c79dae913cae2cb17f05 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -40,6 +40,7 @@ endif
 
 # "Common" libraries used to link tor's utility code.
 TOR_UTIL_LIBS = \
+        src/lib/libtor-geoip.a \
 	src/lib/libtor-process.a \
 	src/lib/libtor-time.a \
 	src/lib/libtor-fs.a \
@@ -68,6 +69,7 @@ TOR_UTIL_LIBS = \
 # and tests)
 if UNITTESTS_ENABLED
 TOR_UTIL_TESTING_LIBS = \
+        src/lib/libtor-geoip-testing.a \
 	src/lib/libtor-process-testing.a \
 	src/lib/libtor-time-testing.a \
 	src/lib/libtor-fs-testing.a \
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 53cc9c0acf11dedff95358cbd9f9fc3e3aaa9b41..d44b17ce657c14e81cda001cf1271c5085f067a1 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -103,7 +103,7 @@
 #include "feature/relay/routermode.h"
 #include "feature/rend/rendclient.h"
 #include "feature/rend/rendservice.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "feature/stats/geoip_stats.h"
 #include "feature/stats/predict_ports.h"
 #include "feature/stats/rephist.h"
diff --git a/src/app/main/main.c b/src/app/main/main.c
index 2266a5ff7f501a55013331af8c9bc36a11c81762..8a24df21058b186cbd481534e969fe0626321cd1 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -61,7 +61,7 @@
 #include "feature/rend/rendcache.h"
 #include "feature/rend/rendclient.h"
 #include "feature/rend/rendservice.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "feature/stats/geoip_stats.h"
 #include "feature/stats/predict_ports.h"
 #include "feature/stats/rephist.h"
diff --git a/src/core/include.am b/src/core/include.am
index 1a26a65c278a79b71e1af30c1a20ed5fa3ec196e..e51819fa208ab86ab801c1a1a9f2fc4e33a0ec96 100644
--- a/src/core/include.am
+++ b/src/core/include.am
@@ -117,7 +117,6 @@ LIBTOR_APP_A_SOURCES = 				\
 	src/feature/rend/rendcommon.c		\
 	src/feature/rend/rendmid.c		\
 	src/feature/rend/rendservice.c		\
-	src/feature/stats/geoip.c		\
 	src/feature/stats/geoip_stats.c		\
 	src/feature/stats/rephist.c		\
 	src/feature/stats/predict_ports.c
@@ -350,7 +349,6 @@ noinst_HEADERS +=					\
 	src/feature/rend/rendcommon.h			\
 	src/feature/rend/rendmid.h			\
 	src/feature/rend/rendservice.h			\
-	src/feature/stats/geoip.h			\
 	src/feature/stats/geoip_stats.h			\
 	src/feature/stats/rephist.h			\
 	src/feature/stats/predict_ports.h
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index 18863fc04f6d5d49cca34e116fe5d5ad6bf3cf6d..d8326a5be83ccb22b203c3c6c774ac7325128bcd 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -102,7 +102,7 @@
 #include "feature/relay/routermode.h"
 #include "feature/rend/rendclient.h"
 #include "feature/rend/rendcommon.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "feature/stats/rephist.h"
 #include "lib/crypt_ops/crypto_util.h"
 
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index 4a724a24d37faf15b9fafa72ec8499a824b0f302..65f4e28c92867904ea6d09b3b798b6fc7cbf9b64 100644
--- a/src/core/or/connection_or.c
+++ b/src/core/or/connection_or.c
@@ -43,7 +43,7 @@
 #include "lib/crypt_ops/crypto_util.h"
 #include "feature/dirauth/reachability.h"
 #include "feature/client/entrynodes.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "core/mainloop/mainloop.h"
 #include "trunnel/link_handshake.h"
 #include "feature/nodelist/microdesc.h"
diff --git a/src/core/or/or.h b/src/core/or/or.h
index 7557c1321ed6857cb4f438f53a4a024bf00de162..acf092c8dc872f1d1adfe24c86f443564ec3e79b 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -41,6 +41,7 @@
 #include "lib/fs/mmap.h"
 #include "lib/fs/path.h"
 #include "lib/fs/userdb.h"
+#include "lib/geoip/country.h"
 #include "lib/intmath/addsub.h"
 #include "lib/intmath/bits.h"
 #include "lib/intmath/cmp.h"
@@ -798,9 +799,6 @@ typedef struct download_status_t download_status_t;
 
 typedef struct signed_descriptor_t signed_descriptor_t;
 
-/** A signed integer representing a country code. */
-typedef int16_t country_t;
-
 /** Flags used to summarize the declared protocol versions of a relay,
  * so we don't need to parse them again and again. */
 typedef struct protover_summary_flags_t {
diff --git a/src/core/or/policies.c b/src/core/or/policies.c
index fc359627b929179eebe0d8b44f0a168f2fd15c58..c3fded1fbd72559d086ad174df6e92328c72186f 100644
--- a/src/core/or/policies.c
+++ b/src/core/or/policies.c
@@ -27,7 +27,7 @@
 #include "feature/relay/router.h"
 #include "feature/relay/routermode.h"
 #include "feature/nodelist/routerparse.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "ht.h"
 #include "lib/encoding/confline.h"
 
diff --git a/src/feature/control/getinfo_geoip.c b/src/feature/control/getinfo_geoip.c
index 35eb3f6aed9672ae20ef36ba7fe593d9d345d5d0..d188725fa3aa5728ae1941d427c74a33cb33ec0b 100644
--- a/src/feature/control/getinfo_geoip.c
+++ b/src/feature/control/getinfo_geoip.c
@@ -3,7 +3,7 @@
 #include "core/mainloop/connection.h"
 #include "feature/control/control.h"
 #include "feature/control/getinfo_geoip.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 
 /** Helper used to implement GETINFO ip-to-country/... controller command. */
 int
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index e3b77d562c6a2d0a42803a66b0e14d018d86c5fd..90ca579b7d7f71369a288eeac952437a1a8ffadb 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -65,7 +65,7 @@
 #include "feature/nodelist/routerset.h"
 #include "feature/nodelist/torcert.h"
 #include "feature/rend/rendservice.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "lib/net/address.h"
 
 #include <string.h>
diff --git a/src/feature/nodelist/routerset.c b/src/feature/nodelist/routerset.c
index 08124835aef34a12f52ffbaa2498cb6b423b218d..cb07a436d1c2f9d36350f3ac729a4214b087af2d 100644
--- a/src/feature/nodelist/routerset.c
+++ b/src/feature/nodelist/routerset.c
@@ -34,7 +34,7 @@ n * Copyright (c) 2001-2004, Roger Dingledine.
 #include "feature/nodelist/nodelist.h"
 #include "feature/nodelist/routerparse.h"
 #include "feature/nodelist/routerset.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 
 #include "core/or/addr_policy_st.h"
 #include "core/or/extend_info_st.h"
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 494634845166ab62e58add72478388a20108af07..fdaadb205bdd8e73968637cb2f06e0d2a36a73b8 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -36,7 +36,7 @@
 #include "feature/relay/routerkeys.h"
 #include "feature/relay/routermode.h"
 #include "feature/relay/selftest.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "feature/stats/geoip_stats.h"
 #include "feature/stats/rephist.h"
 #include "lib/crypt_ops/crypto_ed25519.h"
diff --git a/src/feature/stats/geoip_stats.c b/src/feature/stats/geoip_stats.c
index 4af2ff0ec069826fe6264a26a53b05b10cbbb5cb..d1a5dd79ba14efd3eb331bef2a2a571a7217798b 100644
--- a/src/feature/stats/geoip_stats.c
+++ b/src/feature/stats/geoip_stats.c
@@ -35,7 +35,7 @@
 #include "feature/control/control.h"
 #include "feature/client/dnsserv.h"
 #include "core/or/dos.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "feature/stats/geoip_stats.h"
 #include "feature/nodelist/routerlist.h"
 
diff --git a/src/include.am b/src/include.am
index b5cca7e30ae58b3c24f2934acf5ea29ce5f79030..d2f83da814606012074b93c8fddde1f3d14503c6 100644
--- a/src/include.am
+++ b/src/include.am
@@ -11,6 +11,7 @@ include src/lib/encoding/include.am
 include src/lib/evloop/include.am
 include src/lib/fdio/include.am
 include src/lib/fs/include.am
+include src/lib/geoip/include.am
 include src/lib/include.libdonna.am
 include src/lib/intmath/include.am
 include src/lib/lock/include.am
diff --git a/src/lib/geoip/.may_include b/src/lib/geoip/.may_include
new file mode 100644
index 0000000000000000000000000000000000000000..63207125bc7d1996d60041d932f18831d4bc0bdd
--- /dev/null
+++ b/src/lib/geoip/.may_include
@@ -0,0 +1,12 @@
+lib/cc/*.h
+lib/container/*.h
+lib/crypt_ops/*.h
+lib/ctime/*.h
+lib/encoding/*.h
+lib/fs/*.h
+lib/geoip/*.h
+lib/log/*.h
+lib/malloc/*.h
+lib/net/*.h
+lib/string/*.h
+lib/testsupport/*.h
diff --git a/src/lib/geoip/country.h b/src/lib/geoip/country.h
new file mode 100644
index 0000000000000000000000000000000000000000..e4ad0752b3a968d80757d3c9f088541845846081
--- /dev/null
+++ b/src/lib/geoip/country.h
@@ -0,0 +1,14 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_COUNTRY_H
+#define TOR_COUNTRY_H
+
+#include "lib/cc/torint.h"
+/** A signed integer representing a country code. */
+typedef int16_t country_t;
+
+#endif
diff --git a/src/feature/stats/geoip.c b/src/lib/geoip/geoip.c
similarity index 98%
rename from src/feature/stats/geoip.c
rename to src/lib/geoip/geoip.c
index 496615080240b0e46f7d90316e88b350138155ab..b1c0973d037001faeeb17e4038df31f1dcc1be06 100644
--- a/src/feature/stats/geoip.c
+++ b/src/lib/geoip/geoip.c
@@ -28,12 +28,7 @@
  */
 
 #define GEOIP_PRIVATE
-
-#include "lib/cc/torint.h"
-/** A signed integer representing a country code. */
-typedef int16_t country_t; // XXXX duplicate in or.h
-
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "lib/container/map.h"
 #include "lib/container/order.h"
 #include "lib/container/smartlist.h"
@@ -49,7 +44,6 @@ typedef int16_t country_t; // XXXX duplicate in or.h
 #include "lib/string/compat_string.h"
 #include "lib/string/scanf.h"
 #include "lib/string/util_string.h"
-#include "lib/time/tvdiff.h"
 
 #include <stdio.h>
 #include <string.h>
diff --git a/src/feature/stats/geoip.h b/src/lib/geoip/geoip.h
similarity index 97%
rename from src/feature/stats/geoip.h
rename to src/lib/geoip/geoip.h
index 1ca04cdff6201e5eb495c8b42e53fb6ef9396982..3c1238c319d75e5474d81f8a5d14552b5c703163 100644
--- a/src/feature/stats/geoip.h
+++ b/src/lib/geoip/geoip.h
@@ -14,7 +14,7 @@
 
 #include "lib/net/nettypes.h"
 #include "lib/testsupport/testsupport.h"
-#include "lib/cc/torint.h"
+#include "lib/geoip/country.h"
 
 #ifdef GEOIP_PRIVATE
 STATIC int geoip_parse_entry(const char *line, sa_family_t family);
diff --git a/src/lib/geoip/include.am b/src/lib/geoip/include.am
new file mode 100644
index 0000000000000000000000000000000000000000..9710d75ac7427ca79781b08385fbb2a3ff1b9d84
--- /dev/null
+++ b/src/lib/geoip/include.am
@@ -0,0 +1,17 @@
+noinst_LIBRARIES += src/lib/libtor-geoip.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/lib/libtor-geoip-testing.a
+endif
+
+src_lib_libtor_geoip_a_SOURCES =			\
+	src/lib/geoip/geoip.c
+
+src_lib_libtor_geoip_testing_a_SOURCES = \
+	$(src_lib_libtor_geoip_a_SOURCES)
+src_lib_libtor_geoip_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
+src_lib_libtor_geoip_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+noinst_HEADERS +=					\
+	src/lib/geoip/geoip.h   			\
+	src/lib/geoip/country.h
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 77c0d248c277d275c061e40a458abcef6f59b877..dae4d8376694704d5ee909ea969b379f912a9bc4 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -29,7 +29,7 @@
 #include "feature/client/entrynodes.h"
 #include "feature/client/transports.h"
 #include "feature/relay/ext_orport.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "feature/hibernate/hibernate.h"
 #include "core/mainloop/mainloop.h"
 #include "feature/nodelist/networkstatus.h"
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index 7f7a00abde37301d462e6975243f2c88a7274a7c..623d9e9b9d3ef3bdf20ff9f473d11f0b5f9551db 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -32,7 +32,7 @@
 #include "feature/nodelist/routerparse.h"
 #include "feature/nodelist/networkstatus.h"
 #include "core/proto/proto_http.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "feature/stats/geoip_stats.h"
 #include "feature/dircache/dirserv.h"
 #include "feature/dirauth/dirvote.h"
diff --git a/src/test/test_geoip.c b/src/test/test_geoip.c
index 5e2849147be667b6aa4be66e7ddf91aecd8bd879..6f9c39063b924faec80772dd5ccf2ecfcb0563c4 100644
--- a/src/test/test_geoip.c
+++ b/src/test/test_geoip.c
@@ -10,7 +10,7 @@
 #define GEOIP_PRIVATE
 #include "core/or/or.h"
 #include "app/config/config.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "feature/stats/geoip_stats.h"
 #include "test/test.h"
 
diff --git a/src/test/test_options.c b/src/test/test_options.c
index a4de0e992a818845a25dcba0ba9b7ab15a0f2f80..f14e620eeb21791a186e23b919ad6a595ebb4853 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -8,7 +8,7 @@
 #include "app/config/confparse.h"
 #include "app/config/config.h"
 #include "test/test.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 
 #define ROUTERSET_PRIVATE
 #include "feature/nodelist/routerset.h"
diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c
index 2017ef00508388dc57ecfc4edc47ea120e21c0a1..fede419f0b53a961fcfa8139db8f93c851d66fb9 100644
--- a/src/test/test_routerset.c
+++ b/src/test/test_routerset.c
@@ -4,7 +4,7 @@
 #define ROUTERSET_PRIVATE
 
 #include "core/or/or.h"
-#include "feature/stats/geoip.h"
+#include "lib/geoip/geoip.h"
 #include "feature/nodelist/routerset.h"
 #include "feature/nodelist/routerparse.h"
 #include "core/or/policies.h"