1/* $NetBSD: geoip.c,v 1.7 2024/02/21 22:51:05 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/print.h> 24#include <isc/string.h> 25#include <isc/util.h> 26 27#include <dns/geoip.h> 28 29#include <named/geoip.h> 30#include <named/log.h> 31 32static dns_geoip_databases_t geoip_table; 33 34#if defined(HAVE_GEOIP2) 35static MMDB_s geoip_country, geoip_city, geoip_as, geoip_isp, geoip_domain; 36 37static MMDB_s * 38open_geoip2(const char *dir, const char *dbfile, MMDB_s *mmdb) { 39 char pathbuf[PATH_MAX]; 40 unsigned int n; 41 int ret; 42 43 n = snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dir, dbfile); 44 if (n >= sizeof(pathbuf)) { 45 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 46 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, 47 "GeoIP2 database '%s/%s': path too long", dir, 48 dbfile); 49 return (NULL); 50 } 51 52 ret = MMDB_open(pathbuf, MMDB_MODE_MMAP, mmdb); 53 if (ret == MMDB_SUCCESS) { 54 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 55 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, 56 "opened GeoIP2 database '%s'", pathbuf); 57 return (mmdb); 58 } 59 60 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 61 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), 62 "unable to open GeoIP2 database '%s' (status %d)", 63 pathbuf, ret); 64 65 return (NULL); 66} 67#endif /* HAVE_GEOIP2 */ 68 69void 70named_geoip_init(void) { 71#if defined(HAVE_GEOIP2) 72 if (named_g_geoip == NULL) { 73 named_g_geoip = &geoip_table; 74 } 75#else /* if defined(HAVE_GEOIP2) */ 76 return; 77#endif /* if defined(HAVE_GEOIP2) */ 78} 79 80void 81named_geoip_load(char *dir) { 82#if defined(HAVE_GEOIP2) 83 REQUIRE(dir != NULL); 84 85 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, 86 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO, 87 "looking for GeoIP2 databases in '%s'", dir); 88 89 named_g_geoip->country = open_geoip2(dir, "GeoIP2-Country.mmdb", 90 &geoip_country); 91 if (named_g_geoip->country == NULL) { 92 named_g_geoip->country = open_geoip2( 93 dir, "GeoLite2-Country.mmdb", &geoip_country); 94 } 95 96 named_g_geoip->city = open_geoip2(dir, "GeoIP2-City.mmdb", &geoip_city); 97 if (named_g_geoip->city == NULL) { 98 named_g_geoip->city = open_geoip2(dir, "GeoLite2-City.mmdb", 99 &geoip_city); 100 } 101 102 named_g_geoip->as = open_geoip2(dir, "GeoIP2-ASN.mmdb", &geoip_as); 103 if (named_g_geoip->as == NULL) { 104 named_g_geoip->as = open_geoip2(dir, "GeoLite2-ASN.mmdb", 105 &geoip_as); 106 } 107 108 named_g_geoip->isp = open_geoip2(dir, "GeoIP2-ISP.mmdb", &geoip_isp); 109 named_g_geoip->domain = open_geoip2(dir, "GeoIP2-Domain.mmdb", 110 &geoip_domain); 111#else /* if defined(HAVE_GEOIP2) */ 112 UNUSED(dir); 113 114 return; 115#endif /* if defined(HAVE_GEOIP2) */ 116} 117 118void 119named_geoip_unload(void) { 120#ifdef HAVE_GEOIP2 121 if (named_g_geoip->country != NULL) { 122 MMDB_close(named_g_geoip->country); 123 named_g_geoip->country = NULL; 124 } 125 if (named_g_geoip->city != NULL) { 126 MMDB_close(named_g_geoip->city); 127 named_g_geoip->city = NULL; 128 } 129 if (named_g_geoip->as != NULL) { 130 MMDB_close(named_g_geoip->as); 131 named_g_geoip->as = NULL; 132 } 133 if (named_g_geoip->isp != NULL) { 134 MMDB_close(named_g_geoip->isp); 135 named_g_geoip->isp = NULL; 136 } 137 if (named_g_geoip->domain != NULL) { 138 MMDB_close(named_g_geoip->domain); 139 named_g_geoip->domain = NULL; 140 } 141#endif /* ifdef HAVE_GEOIP2 */ 142} 143 144void 145named_geoip_shutdown(void) { 146#ifdef HAVE_GEOIP2 147 named_geoip_unload(); 148#endif /* HAVE_GEOIP2 */ 149} 150