1102644Snectar/*	$NetBSD: geoip.c,v 1.7 2024/02/21 22:51:05 christos Exp $	*/
2102644Snectar
355682Smarkm/*
4102644Snectar * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
578527Sassar *
655682Smarkm * SPDX-License-Identifier: MPL-2.0
755682Smarkm *
855682Smarkm * This Source Code Form is subject to the terms of the Mozilla Public
955682Smarkm * License, v. 2.0. If a copy of the MPL was not distributed with this
1055682Smarkm * file, you can obtain one at https://mozilla.org/MPL/2.0/.
1155682Smarkm *
1255682Smarkm * See the COPYRIGHT file distributed with this work for additional
1355682Smarkm * information regarding copyright ownership.
1455682Smarkm */
1590926Snectar
1690926Snectar/*! \file */
1790926Snectar
1890926Snectar#if defined(HAVE_GEOIP2)
19102644Snectar#include <maxminddb.h>
2090926Snectar#endif /* if defined(HAVE_GEOIP2) */
21102644Snectar
2255682Smarkm#include <isc/dir.h>
2355682Smarkm#include <isc/print.h>
2455682Smarkm#include <isc/string.h>
2555682Smarkm#include <isc/util.h>
2655682Smarkm
2755682Smarkm#include <dns/geoip.h>
2855682Smarkm
2955682Smarkm#include <named/geoip.h>
3055682Smarkm#include <named/log.h>
3155682Smarkm
3255682Smarkmstatic dns_geoip_databases_t geoip_table;
3355682Smarkm
3455682Smarkm#if defined(HAVE_GEOIP2)
3555682Smarkmstatic MMDB_s geoip_country, geoip_city, geoip_as, geoip_isp, geoip_domain;
3655682Smarkm
3755682Smarkmstatic MMDB_s *
3855682Smarkmopen_geoip2(const char *dir, const char *dbfile, MMDB_s *mmdb) {
3955682Smarkm	char pathbuf[PATH_MAX];
4055682Smarkm	unsigned int n;
4155682Smarkm	int ret;
4255682Smarkm
4355682Smarkm	n = snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dir, dbfile);
4455682Smarkm	if (n >= sizeof(pathbuf)) {
4555682Smarkm		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4655682Smarkm			      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4755682Smarkm			      "GeoIP2 database '%s/%s': path too long", dir,
4855682Smarkm			      dbfile);
4955682Smarkm		return (NULL);
5055682Smarkm	}
5155682Smarkm
52102644Snectar	ret = MMDB_open(pathbuf, MMDB_MODE_MMAP, mmdb);
5355682Smarkm	if (ret == MMDB_SUCCESS) {
5472445Sassar		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
5555682Smarkm			      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
56102644Snectar			      "opened GeoIP2 database '%s'", pathbuf);
57102644Snectar		return (mmdb);
58102644Snectar	}
5955682Smarkm
6090926Snectar	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6155682Smarkm		      NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
6255682Smarkm		      "unable to open GeoIP2 database '%s' (status %d)",
6355682Smarkm		      pathbuf, ret);
6455682Smarkm
6555682Smarkm	return (NULL);
6655682Smarkm}
6755682Smarkm#endif /* HAVE_GEOIP2 */
6855682Smarkm
6955682Smarkmvoid
70102644Snectarnamed_geoip_init(void) {
71102644Snectar#if defined(HAVE_GEOIP2)
72102644Snectar	if (named_g_geoip == NULL) {
73102644Snectar		named_g_geoip = &geoip_table;
7455682Smarkm	}
7572445Sassar#else  /* if defined(HAVE_GEOIP2) */
7672445Sassar	return;
7755682Smarkm#endif /* if defined(HAVE_GEOIP2) */
7855682Smarkm}
7955682Smarkm
8055682Smarkmvoid
8155682Smarkmnamed_geoip_load(char *dir) {
8290926Snectar#if defined(HAVE_GEOIP2)
8372445Sassar	REQUIRE(dir != NULL);
8455682Smarkm
8572445Sassar	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8690926Snectar		      NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8772445Sassar		      "looking for GeoIP2 databases in '%s'", dir);
8872445Sassar
8972445Sassar	named_g_geoip->country = open_geoip2(dir, "GeoIP2-Country.mmdb",
90102644Snectar					     &geoip_country);
9155682Smarkm	if (named_g_geoip->country == NULL) {
9255682Smarkm		named_g_geoip->country = open_geoip2(
9372445Sassar			dir, "GeoLite2-Country.mmdb", &geoip_country);
9455682Smarkm	}
9590926Snectar
9690926Snectar	named_g_geoip->city = open_geoip2(dir, "GeoIP2-City.mmdb", &geoip_city);
9755682Smarkm	if (named_g_geoip->city == NULL) {
98102644Snectar		named_g_geoip->city = open_geoip2(dir, "GeoLite2-City.mmdb",
99102644Snectar						  &geoip_city);
100102644Snectar	}
10155682Smarkm
10255682Smarkm	named_g_geoip->as = open_geoip2(dir, "GeoIP2-ASN.mmdb", &geoip_as);
10355682Smarkm	if (named_g_geoip->as == NULL) {
10490926Snectar		named_g_geoip->as = open_geoip2(dir, "GeoLite2-ASN.mmdb",
10590926Snectar						&geoip_as);
10690926Snectar	}
10790926Snectar
10872445Sassar	named_g_geoip->isp = open_geoip2(dir, "GeoIP2-ISP.mmdb", &geoip_isp);
10990926Snectar	named_g_geoip->domain = open_geoip2(dir, "GeoIP2-Domain.mmdb",
11072445Sassar					    &geoip_domain);
11190926Snectar#else  /* if defined(HAVE_GEOIP2) */
11255682Smarkm	UNUSED(dir);
11355682Smarkm
11455682Smarkm	return;
11555682Smarkm#endif /* if defined(HAVE_GEOIP2) */
11655682Smarkm}
11755682Smarkm
11855682Smarkmvoid
11955682Smarkmnamed_geoip_unload(void) {
12055682Smarkm#ifdef HAVE_GEOIP2
12172445Sassar	if (named_g_geoip->country != NULL) {
12255682Smarkm		MMDB_close(named_g_geoip->country);
12355682Smarkm		named_g_geoip->country = NULL;
124102644Snectar	}
12555682Smarkm	if (named_g_geoip->city != NULL) {
12655682Smarkm		MMDB_close(named_g_geoip->city);
12755682Smarkm		named_g_geoip->city = NULL;
12855682Smarkm	}
12955682Smarkm	if (named_g_geoip->as != NULL) {
13090926Snectar		MMDB_close(named_g_geoip->as);
13190926Snectar		named_g_geoip->as = NULL;
13290926Snectar	}
13390926Snectar	if (named_g_geoip->isp != NULL) {
13455682Smarkm		MMDB_close(named_g_geoip->isp);
13590926Snectar		named_g_geoip->isp = NULL;
13690926Snectar	}
137102644Snectar	if (named_g_geoip->domain != NULL) {
138102644Snectar		MMDB_close(named_g_geoip->domain);
139102644Snectar		named_g_geoip->domain = NULL;
14072445Sassar	}
14155682Smarkm#endif /* ifdef HAVE_GEOIP2 */
142102644Snectar}
14372445Sassar
144102644Snectarvoid
14555682Smarkmnamed_geoip_shutdown(void) {
14672445Sassar#ifdef HAVE_GEOIP2
14755682Smarkm	named_geoip_unload();
148102644Snectar#endif /* HAVE_GEOIP2 */
149102644Snectar}
15090926Snectar