geoip.c revision 1.8 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