1 /* $NetBSD: geoip.c,v 1.8 2025/01/26 16:24:33 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #if defined(HAVE_GEOIP2) 19 #include <maxminddb.h> 20 #endif /* if defined(HAVE_GEOIP2) */ 21 22 #include <isc/dir.h> 23 #include <isc/string.h> 24 #include <isc/util.h> 25 26 #include <dns/geoip.h> 27 28 #include <named/geoip.h> 29 #include <named/log.h> 30 31 static dns_geoip_databases_t geoip_table; 32 33 #if defined(HAVE_GEOIP2) 34 static MMDB_s geoip_country, geoip_city, geoip_as, geoip_isp, geoip_domain; 35 36 static MMDB_s * 37 open_geoip2(const char *dir, const char *dbfile, MMDB_s *mmdb) { 38 char pathbuf[PATH_MAX]; 39 unsigned int n; 40 int ret; 41 42 n = snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dir, dbfile); 43 if (n >= sizeof(pathbuf)) { 44 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 45 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 46 "GeoIP2 database '%s/%s': path too long", dir, 47 dbfile); 48 return NULL; 49 } 50 51 ret = MMDB_open(pathbuf, MMDB_MODE_MMAP, mmdb); 52 if (ret == MMDB_SUCCESS) { 53 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 54 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, 55 "opened GeoIP2 database '%s'", pathbuf); 56 return mmdb; 57 } 58 59 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 60 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), 61 "unable to open GeoIP2 database '%s' (status %d)", 62 pathbuf, ret); 63 64 return NULL; 65 } 66 #endif /* HAVE_GEOIP2 */ 67 68 void 69 named_geoip_init(void) { 70 #if defined(HAVE_GEOIP2) 71 if (named_g_geoip == NULL) { 72 named_g_geoip = &geoip_table; 73 } 74 #else /* if defined(HAVE_GEOIP2) */ 75 return; 76 #endif /* if defined(HAVE_GEOIP2) */ 77 } 78 79 void 80 named_geoip_load(char *dir) { 81 #if defined(HAVE_GEOIP2) 82 REQUIRE(dir != NULL); 83 84 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 85 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, 86 "looking for GeoIP2 databases in '%s'", dir); 87 88 named_g_geoip->country = open_geoip2(dir, "GeoIP2-Country.mmdb", 89 &geoip_country); 90 if (named_g_geoip->country == NULL) { 91 named_g_geoip->country = open_geoip2( 92 dir, "GeoLite2-Country.mmdb", &geoip_country); 93 } 94 95 named_g_geoip->city = open_geoip2(dir, "GeoIP2-City.mmdb", &geoip_city); 96 if (named_g_geoip->city == NULL) { 97 named_g_geoip->city = open_geoip2(dir, "GeoLite2-City.mmdb", 98 &geoip_city); 99 } 100 101 named_g_geoip->as = open_geoip2(dir, "GeoIP2-ASN.mmdb", &geoip_as); 102 if (named_g_geoip->as == NULL) { 103 named_g_geoip->as = open_geoip2(dir, "GeoLite2-ASN.mmdb", 104 &geoip_as); 105 } 106 107 named_g_geoip->isp = open_geoip2(dir, "GeoIP2-ISP.mmdb", &geoip_isp); 108 named_g_geoip->domain = open_geoip2(dir, "GeoIP2-Domain.mmdb", 109 &geoip_domain); 110 #else /* if defined(HAVE_GEOIP2) */ 111 UNUSED(dir); 112 113 return; 114 #endif /* if defined(HAVE_GEOIP2) */ 115 } 116 117 void 118 named_geoip_unload(void) { 119 #ifdef HAVE_GEOIP2 120 if (named_g_geoip->country != NULL) { 121 MMDB_close(named_g_geoip->country); 122 named_g_geoip->country = NULL; 123 } 124 if (named_g_geoip->city != NULL) { 125 MMDB_close(named_g_geoip->city); 126 named_g_geoip->city = NULL; 127 } 128 if (named_g_geoip->as != NULL) { 129 MMDB_close(named_g_geoip->as); 130 named_g_geoip->as = NULL; 131 } 132 if (named_g_geoip->isp != NULL) { 133 MMDB_close(named_g_geoip->isp); 134 named_g_geoip->isp = NULL; 135 } 136 if (named_g_geoip->domain != NULL) { 137 MMDB_close(named_g_geoip->domain); 138 named_g_geoip->domain = NULL; 139 } 140 #endif /* ifdef HAVE_GEOIP2 */ 141 } 142 143 void 144 named_geoip_shutdown(void) { 145 #ifdef HAVE_GEOIP2 146 named_geoip_unload(); 147 #endif /* HAVE_GEOIP2 */ 148 } 149