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