1 /*
2  * Project    : ipv6calc
3  * File       : databases/lib/libipv6calc_db_wrapper_GeoIP2.c
4  * Version    : $Id: c3531f8e3bbf483d49332a0c7b6e391497268f77 $
5  * Copyright  : 2019-2021 by Peter Bieringer <pb (at) bieringer.de>
6  *
7  * Information:
8  *  ipv6calc DB-IP.com database wrapper for MaxMindDB databases
9  */
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <dlfcn.h>
14 #include <unistd.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <time.h>
18 
19 #include "config.h"
20 
21 #include "libipv6calcdebug.h"
22 #include "libipv6calc.h"
23 
24 #include "libipv6calc_db_wrapper.h"
25 
26 
27 #ifdef SUPPORT_GEOIP2
28 
29 #include "libipv6calc_db_wrapper_GeoIP2.h"
30 
31 char geoip2_db_dir[PATH_MAX] = GEOIP2_DB;
32 
33 static const char* wrapper_geoip2_info = "GeoIP2";
34 
35 
36 // DB used for resolution after automatic election, which is currently done by checking for DB files and the sequence in the header file
37 static int geoip2_db_country_v4 = 0;
38 static int geoip2_db_country_v6 = 0;
39 static int geoip2_db_region_city_v4 = 0;
40 static int geoip2_db_region_city_v6 = 0;
41 static int geoip2_db_asn_v4 = 0;
42 static int geoip2_db_asn_v6 = 0;
43 
44 typedef struct {
45 	unsigned int num;
46 	int dbtype;
47 	int dbym;
48 } s_ipv6calc_geoip2_db;
49 
50 #define GeoIP2_FREE	0
51 #define GeoIP2_COMM	1
52 #define	GeoIP2_MAX	2
53 
54 static s_ipv6calc_geoip2_db geoip2_db_country_v4_best[GeoIP2_MAX];
55 static s_ipv6calc_geoip2_db geoip2_db_country_v6_best[GeoIP2_MAX];
56 static s_ipv6calc_geoip2_db geoip2_db_region_city_v4_best[GeoIP2_MAX];
57 static s_ipv6calc_geoip2_db geoip2_db_region_city_v6_best[GeoIP2_MAX];
58 static s_ipv6calc_geoip2_db geoip2_db_asn_v4_best[GeoIP2_MAX];
59 static s_ipv6calc_geoip2_db geoip2_db_asn_v6_best[GeoIP2_MAX];
60 
61 static int type2index[GeoIP2_DB_MAX+1];
62 
63 // select FREE database if COMM is older than given months
64 int geoip2_db_comm_to_free_switch_min_delta_months = 12;
65 
66 // select better database of same product (COMM/FREE) only if not older than given months
67 int geoip2_db_better_max_delta_months = 1;
68 
69 // select only a specific GeoIP2 db type
70 int geoip2_db_only_type = 0;
71 
72 
73 #define GeoIP2_UNPACK_YM(dbym) ((dbym > 0) ? ((dbym % 12) + ((dbym / 12)) * 100) : 0)
74 
75 
76 /* database usage map */
77 #define GeoIP2_DB_MAX_BLOCKS_32	2	// 0-63
78 static uint32_t geoip2_db_usage_map[GeoIP2_DB_MAX_BLOCKS_32];
79 
80 #define GeoIP2_DB_USAGE_MAP_TAG(db)	if (db < (32 * GeoIP2_DB_MAX_BLOCKS_32)) { \
81 							DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Tag usage for db: %d", db); \
82 							geoip2_db_usage_map[db / 32] |= 1 << (db % 32); \
83 						} else { \
84 							fprintf(stderr, "FIXME: unsupported db value (exceed limit): %d (%d)\n", db, 32 * GeoIP2_DB_MAX_BLOCKS_32 - 1); \
85 							exit(1); \
86 						};
87 
88 char geoip2_db_usage_string[IPV6CALC_STRING_MAX] = "";
89 
90 // local cache
91 static MMDB_s mmdb_cache[GeoIP2_DB_MAX+1];
92 
93 // local prototyping
94 static char *libipv6calc_db_wrapper_GeoIP2_dbfilename(const unsigned int type);
95 static void libipv6calc_db_wrapper_GeoIP2_close(const int type);
96 
97 
98 /*
99  * function initialise the GeoIP2 wrapper
100  *
101  * in : (nothing)
102  * out: 0=ok, 1=error
103  */
libipv6calc_db_wrapper_GeoIP2_wrapper_init(void)104 int libipv6calc_db_wrapper_GeoIP2_wrapper_init(void) {
105 	int i, dbym, dbtype, ret, product;
106 
107 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called");
108 
109 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Check for standard GeoIP2 databases");
110 
111 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "custom directory: %s", geoip2_db_dir);
112 
113 	/* check available databases for resolution */
114 	for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_GeoIP2_db_file_desc); i++) {
115 		// add entry to mapping
116 		type2index[libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number] = i;
117 
118 		// clean local cache
119 		mmdb_cache[libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number].file_size = 0;
120 		mmdb_cache[libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number].flags = 0;
121 
122 		// add features to implemented
123 		wrapper_features_by_source_implemented[IPV6CALC_DB_SOURCE_GEOIP2] |= libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].features;
124 
125 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "GeoIP2 database test for availability: %s", libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].filename);
126 		if (libipv6calc_db_wrapper_GeoIP2_db_avail(libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number) == 1) {
127 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "GeoIP2 database available: %s", libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].description);
128 			wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2] |= libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].features;
129 		} else {
130 			// db not available
131 			continue;
132 		};
133 
134 		ret = libipv6calc_db_wrapper_GeoIP2_open_type(libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number);
135 		if (ret != MMDB_SUCCESS) {
136 			DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Error opening GeoIP2 by type");
137 			continue;
138 		};
139 
140 		dbtype = libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number;
141 
142 		if ((geoip2_db_only_type > 0) && (geoip2_db_only_type != dbtype)) {
143 			// not selected
144 			continue;
145 		};
146 
147 		if ((libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].internal & IPV6CALC_DB_GEOIP2_INTERNAL_FREE) != 0) {
148 			product = GeoIP2_FREE;
149 		} else {
150 			product = GeoIP2_COMM;
151 		};
152 
153 		time_t db_time = mmdb_cache[dbtype].metadata.build_epoch;
154 		struct tm *db_gmtime = gmtime(&db_time);
155 
156 		dbym = (db_gmtime->tm_year + 1900) * 12 + (db_gmtime->tm_mon + 1);
157 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "GEOIP2 type=%d dbym=%d Year/Month=%d unixtime=%llu", dbtype, dbym, GeoIP2_UNPACK_YM(dbym), (long long unsigned int) mmdb_cache[dbtype].metadata.build_epoch);
158 
159 #define GeoIP2_DB_SELECT_BETTER(best) \
160 			if ( \
161 			  (best.num == 0) \
162 			  || ( \
163 				(best.dbym > 0) \
164 				  && ((best.dbym - dbym) <= geoip2_db_better_max_delta_months) \
165 			     ) \
166 			) { \
167 				best.num = libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number; \
168 				best.dbym = dbym; \
169 				best.dbtype = dbtype; \
170 			};
171 
172 
173 		// note: databases are listed in sequence "less data" before "more data"
174 		if ((libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].features & IPV6CALC_DB_IPV4_TO_CC) != 0) {
175 			GeoIP2_DB_SELECT_BETTER(geoip2_db_country_v4_best[product])
176 		};
177 
178 		if ((libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].features & IPV6CALC_DB_IPV6_TO_CC) != 0) {
179 			GeoIP2_DB_SELECT_BETTER(geoip2_db_country_v6_best[product])
180 		};
181 
182 		if ((libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].features & (IPV6CALC_DB_IPV4_TO_REGION | IPV6CALC_DB_IPV4_TO_CITY)) != 0) {
183 			GeoIP2_DB_SELECT_BETTER(geoip2_db_region_city_v4_best[product])
184 		};
185 
186 		if ((libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].features & (IPV6CALC_DB_IPV6_TO_REGION | IPV6CALC_DB_IPV6_TO_CITY)) != 0) {
187 			GeoIP2_DB_SELECT_BETTER(geoip2_db_region_city_v6_best[product])
188 		};
189 
190 		if ((libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].features & IPV6CALC_DB_IPV4_TO_AS) != 0) {
191 			GeoIP2_DB_SELECT_BETTER(geoip2_db_asn_v4_best[product])
192 		};
193 
194 		if ((libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].features & IPV6CALC_DB_IPV6_TO_AS) != 0) {
195 			GeoIP2_DB_SELECT_BETTER(geoip2_db_asn_v6_best[product])
196 		};
197 
198 		wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2] |= libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].features;
199 	};
200 
201 	// select free instead of comm, if comm is outdated and free available
202 	if (geoip2_db_comm_to_free_switch_min_delta_months > 0) {
203 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "GeoIP2 database priority check (comm->free) after months: %d", geoip2_db_comm_to_free_switch_min_delta_months);
204 #define SELECT_FREE_INSTEAD_OF_COMM(free, comm, final) \
205 	if ((free.num > 0) && (comm.num > 0)) { \
206 		if (free.dbym - comm.dbym > geoip2_db_comm_to_free_switch_min_delta_months) { \
207 			final = free.num; \
208 		}; \
209 	};
210 		SELECT_FREE_INSTEAD_OF_COMM(geoip2_db_country_v4_best[GeoIP2_FREE], geoip2_db_country_v4_best[GeoIP2_COMM], geoip2_db_country_v4)
211 		SELECT_FREE_INSTEAD_OF_COMM(geoip2_db_country_v6_best[GeoIP2_FREE], geoip2_db_country_v6_best[GeoIP2_COMM], geoip2_db_country_v6)
212 		SELECT_FREE_INSTEAD_OF_COMM(geoip2_db_region_city_v4_best[GeoIP2_FREE], geoip2_db_region_city_v4_best[GeoIP2_COMM], geoip2_db_region_city_v4)
213 		SELECT_FREE_INSTEAD_OF_COMM(geoip2_db_region_city_v6_best[GeoIP2_FREE], geoip2_db_region_city_v6_best[GeoIP2_COMM], geoip2_db_region_city_v6)
214 		SELECT_FREE_INSTEAD_OF_COMM(geoip2_db_asn_v4_best[GeoIP2_FREE], geoip2_db_asn_v4_best[GeoIP2_COMM], geoip2_db_asn_v4)
215 		SELECT_FREE_INSTEAD_OF_COMM(geoip2_db_asn_v6_best[GeoIP2_FREE], geoip2_db_asn_v6_best[GeoIP2_COMM], geoip2_db_asn_v6)
216 	};
217 
218 #define FILL_EMPTY(product, final) \
219 	if ((product.num > 0) && (final == 0)) { \
220 		final = product.num; \
221 	};
222 
223 	// fill empty ones with comm
224 	FILL_EMPTY(geoip2_db_country_v4_best[GeoIP2_COMM], geoip2_db_country_v4)
225 	FILL_EMPTY(geoip2_db_country_v6_best[GeoIP2_COMM], geoip2_db_country_v6)
226 	FILL_EMPTY(geoip2_db_region_city_v4_best[GeoIP2_COMM], geoip2_db_region_city_v4)
227 	FILL_EMPTY(geoip2_db_region_city_v6_best[GeoIP2_COMM], geoip2_db_region_city_v6)
228 	FILL_EMPTY(geoip2_db_asn_v4_best[GeoIP2_COMM], geoip2_db_asn_v4)
229 	FILL_EMPTY(geoip2_db_asn_v6_best[GeoIP2_COMM], geoip2_db_asn_v6)
230 
231 	// fill empty ones with free
232 	FILL_EMPTY(geoip2_db_country_v4_best[GeoIP2_FREE], geoip2_db_country_v4)
233 	FILL_EMPTY(geoip2_db_country_v6_best[GeoIP2_FREE], geoip2_db_country_v6)
234 	FILL_EMPTY(geoip2_db_region_city_v4_best[GeoIP2_FREE], geoip2_db_region_city_v4)
235 	FILL_EMPTY(geoip2_db_region_city_v6_best[GeoIP2_FREE], geoip2_db_region_city_v6)
236 	FILL_EMPTY(geoip2_db_asn_v4_best[GeoIP2_FREE], geoip2_db_asn_v4)
237 	FILL_EMPTY(geoip2_db_asn_v6_best[GeoIP2_FREE], geoip2_db_asn_v6)
238 
239 	/* close handles which are not necessary further on */
240 	for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_GeoIP2_db_file_desc); i++) {
241 		if (mmdb_cache[libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number].file_size > 0) {
242 			if (
243 				(libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number == geoip2_db_country_v4_best[GeoIP2_FREE].num)
244 			    ||	(libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number == geoip2_db_country_v4_best[GeoIP2_COMM].num)
245 			    ||	(libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number == geoip2_db_country_v6_best[GeoIP2_FREE].num)
246 			    ||	(libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number == geoip2_db_country_v6_best[GeoIP2_COMM].num)
247 			) {
248 				// database is in use
249 				continue;
250 			};
251 
252 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Close further unused GeoIP2: type=%d desc='%s'", libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number, libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].description);
253 			libipv6calc_db_wrapper_GeoIP2_close(libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number);
254 		};
255 	};
256 
257 	wrapper_features |= wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2];
258 
259 	return 0;
260 };
261 
262 
263 /*
264  * wrapper: GeoIP2_close
265  */
libipv6calc_db_wrapper_GeoIP2_close(const int type)266 static void libipv6calc_db_wrapper_GeoIP2_close(const int type) {
267 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called type=%u", type);
268 
269 	if (mmdb_cache[type].file_size > 0) {
270 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Close GeoIP2: type=%d desc='%s'", type, libipv6calc_db_wrapper_GeoIP2_db_file_desc[type2index[type]].description);
271 		libipv6calc_db_wrapper_MMDB_close(&mmdb_cache[type]);
272 		/* cleanup cache entry */
273 		mmdb_cache[type].file_size = 0;
274 	} else if (mmdb_cache[type].flags > 0) {
275 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Already closed GeoIP2: type=%d desc='%s'", type, libipv6calc_db_wrapper_GeoIP2_db_file_desc[type2index[type]].description);
276 	};
277 };
278 
279 
280 /*
281  * function cleanup the GeoIP2 wrapper
282  *
283  * in : (nothing)
284  * out: 0=ok, 1=error
285  */
libipv6calc_db_wrapper_GeoIP2_wrapper_cleanup(void)286 int libipv6calc_db_wrapper_GeoIP2_wrapper_cleanup(void) {
287 	int i;
288 
289 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called");
290 
291 	for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_GeoIP2_db_file_desc); i++) {
292 		libipv6calc_db_wrapper_GeoIP2_close(i);
293 	};
294 
295 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Finished");
296 	return 0;
297 };
298 
299 
300 /*
301  * function info of GeoIP2 wrapper
302  *
303  * in : ptr and size of string to be filled
304  * out: modified string;
305  */
libipv6calc_db_wrapper_GeoIP2_wrapper_info(char * string,const size_t size)306 void libipv6calc_db_wrapper_GeoIP2_wrapper_info(char* string, const size_t size) {
307 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called");
308 
309 	snprintf(string, size, "GeoIP2 available databases: Country4=%d Country6=%d ASN4=%d ASN6=%d City4=%d City6=%d", \
310 		(wrapper_features & IPV6CALC_DB_IPV4_TO_CC) ? 1 : 0, \
311 		(wrapper_features & IPV6CALC_DB_IPV6_TO_CC) ? 1 : 0, \
312 		(wrapper_features & IPV6CALC_DB_IPV4_TO_AS) ? 1 : 0, \
313 		(wrapper_features & IPV6CALC_DB_IPV6_TO_AS) ? 1 : 0, \
314 		(wrapper_features & IPV6CALC_DB_IPV4_TO_CITY) ? 1 : 0, \
315 		(wrapper_features & IPV6CALC_DB_IPV6_TO_CITY) ? 1 : 0 \
316 	);
317 
318 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Finished");
319 	return;
320 };
321 
322 /*
323  * function print database info of GeoIP2 wrapper
324  *
325  * in : (void)
326  * out: (void)
327  */
libipv6calc_db_wrapper_GeoIP2_wrapper_print_db_info(const int level_verbose,const char * prefix_string)328 void libipv6calc_db_wrapper_GeoIP2_wrapper_print_db_info(const int level_verbose, const char *prefix_string) {
329 	int ret, i, type, count = 0;
330 
331 	const char *prefix = "\0";
332 	if (prefix_string != NULL) {
333 		prefix = prefix_string;
334 	};
335 
336 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called");
337 
338 	IPV6CALC_DB_FEATURE_INFO(prefix, IPV6CALC_DB_SOURCE_GEOIP2)
339 
340 	fprintf(stderr, "%sGeoIP2: info of available databases in directory: %s\n", prefix, geoip2_db_dir);
341 
342 	for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_GeoIP2_db_file_desc); i++) {
343 		type = libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number;
344 
345 		if (libipv6calc_db_wrapper_GeoIP2_db_avail(type)) {
346 			// GeoIP2 returned that database is available
347 			ret = libipv6calc_db_wrapper_GeoIP2_open_type(type);
348 			if (ret != MMDB_SUCCESS) {
349 				fprintf(stderr, "%sGeoIP2: %-30s: [%1d] %-30s (CAN'T OPEN database information)\n", prefix, libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].description, type, libipv6calc_db_wrapper_GeoIP2_dbfilename(type));
350 			} else {
351 				fprintf(stderr, "%sGeoIP2: %-30s: [%1d] %-30s (%s)\n", prefix, libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].description, type, libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].filename, libipv6calc_db_wrapper_GeoIP2_database_info(type));
352 				libipv6calc_db_wrapper_GeoIP2_close(type);
353 				count++;
354 			};
355 		} else {
356 			if (level_verbose == LEVEL_VERBOSE2) {
357 				fprintf(stderr, "%sGeoIP2: %-30s: [%1d] %-30s (%s)\n", prefix, libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].description, type, libipv6calc_db_wrapper_GeoIP2_dbfilename(type), strerror(errno));
358 			};
359 			continue;
360 		};
361 	};
362 
363 	if (count == 0) {
364 		fprintf(stderr, "%sGeoIP2: NO available databases found in directory: %s\n", prefix, geoip2_db_dir);
365 	} else {
366 		if (level_verbose >= LEVEL_VERBOSE2) {
367 			fprintf(stderr, "%sGeoIP2: detected best databases FREE    Country4=%-3d DB%-2d %6d  Country6=%-3d DB%-2d %6d  City4=%-3d DB%-2d %6d  City6=%-3d DB%-2d %6d\n"
368 				, prefix
369 				, geoip2_db_country_v4_best[GeoIP2_FREE].num
370 				, geoip2_db_country_v4_best[GeoIP2_FREE].dbtype
371 				, GeoIP2_UNPACK_YM(geoip2_db_country_v4_best[GeoIP2_FREE].dbym)
372 				, geoip2_db_country_v6_best[GeoIP2_FREE].num
373 				, geoip2_db_country_v6_best[GeoIP2_FREE].dbtype
374 				, GeoIP2_UNPACK_YM(geoip2_db_country_v6_best[GeoIP2_FREE].dbym)
375 				, geoip2_db_region_city_v4_best[GeoIP2_FREE].num
376 				, geoip2_db_region_city_v4_best[GeoIP2_FREE].dbtype
377 				, GeoIP2_UNPACK_YM(geoip2_db_region_city_v4_best[GeoIP2_FREE].dbym)
378 				, geoip2_db_region_city_v6_best[GeoIP2_FREE].num
379 				, geoip2_db_region_city_v6_best[GeoIP2_FREE].dbtype
380 				, GeoIP2_UNPACK_YM(geoip2_db_region_city_v6_best[GeoIP2_FREE].dbym)
381 			);
382 
383 			fprintf(stderr, "%sGeoIP2: detected best databases COMM    Country4=%-3d DB%-2d %6d  Country6=%-3d DB%-2d %6d  City4=%-3d DB%-2d %6d  City6=%-3d DB%-2d %6d\n"
384 				, prefix
385 				, geoip2_db_country_v4_best[GeoIP2_COMM].num
386 				, geoip2_db_country_v4_best[GeoIP2_COMM].dbtype
387 				, GeoIP2_UNPACK_YM(geoip2_db_country_v4_best[GeoIP2_COMM].dbym)
388 				, geoip2_db_country_v6_best[GeoIP2_COMM].num
389 				, geoip2_db_country_v6_best[GeoIP2_COMM].dbtype
390 				, GeoIP2_UNPACK_YM(geoip2_db_country_v6_best[GeoIP2_COMM].dbym)
391 				, geoip2_db_region_city_v4_best[GeoIP2_COMM].num
392 				, geoip2_db_region_city_v4_best[GeoIP2_COMM].dbtype
393 				, GeoIP2_UNPACK_YM(geoip2_db_region_city_v4_best[GeoIP2_COMM].dbym)
394 				, geoip2_db_region_city_v6_best[GeoIP2_COMM].num
395 				, geoip2_db_region_city_v6_best[GeoIP2_COMM].dbtype
396 				, GeoIP2_UNPACK_YM(geoip2_db_region_city_v6_best[GeoIP2_COMM].dbym)
397 			);
398 		} else if (level_verbose >= LEVEL_VERBOSE) {
399 			fprintf(stderr, "%sGeoIP2: detected best databases FREE    Country4=%-3d  Country6=%-3d  City4=%-3d  City6=%-3d\n"
400 				, prefix
401 				, geoip2_db_country_v4_best[GeoIP2_FREE].num
402 				, geoip2_db_country_v6_best[GeoIP2_FREE].num
403 				, geoip2_db_region_city_v4_best[GeoIP2_FREE].num
404 				, geoip2_db_region_city_v6_best[GeoIP2_FREE].num
405 			);
406 
407 			fprintf(stderr, "%sGeoIP2: detected best databases COMM    Country4=%-3d  Country6=%-3d  City4=%-3d  City6=%-3d\n"
408 				, prefix
409 				, geoip2_db_country_v4_best[GeoIP2_COMM].num
410 				, geoip2_db_country_v6_best[GeoIP2_COMM].num
411 				, geoip2_db_region_city_v4_best[GeoIP2_COMM].num
412 				, geoip2_db_region_city_v6_best[GeoIP2_COMM].num
413 			);
414 
415 		};
416 
417 		if (level_verbose >= LEVEL_VERBOSE) {
418 			fprintf(stderr, "%sGeoIP2: selected best databases normal  Country4=%-3d%s  Country6=%-3d%s  City4=%-3d%s  City6=%-3d\n"
419 				, prefix
420 				, geoip2_db_country_v4
421 				, (level_verbose >= LEVEL_VERBOSE2) ? "            " : ""
422 				, geoip2_db_country_v6
423 				, (level_verbose >= LEVEL_VERBOSE2) ? "            " : ""
424 				, geoip2_db_region_city_v4
425 				, (level_verbose >= LEVEL_VERBOSE2) ? "            " : ""
426 				, geoip2_db_region_city_v6
427 			);
428 
429 			if (geoip2_db_comm_to_free_switch_min_delta_months > 0) {
430 				fprintf(stderr, "%sGeoIP2: selected best databases method: COMM older than %d months are deselected in case of FREE is available\n"
431 					, prefix
432 					, geoip2_db_comm_to_free_switch_min_delta_months
433 				);
434 			};
435 
436 			if (geoip2_db_better_max_delta_months > 0) {
437 				fprintf(stderr, "%sGeoIP2: selected best databases method: COMM/FREE with more features are only selected in case not older than %d months of already found COMM/FREE\n"
438 					, prefix
439 					, geoip2_db_better_max_delta_months
440 				);
441 			};
442 
443 			if (geoip2_db_only_type > 0) {
444 				fprintf(stderr, "%sGeoIP2: selected best databases method: by applying given DB type filter: %d\n"
445 					, prefix
446 					, geoip2_db_only_type
447 				);
448 			};
449 		};
450 	};
451 
452 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Finished");
453 	return;
454 };
455 
456 
457 /*
458  * wrapper: string regarding used database infos
459  */
libipv6calc_db_wrapper_GeoIP2_wrapper_db_info_used(void)460 char *libipv6calc_db_wrapper_GeoIP2_wrapper_db_info_used(void) {
461 	int type, i;
462 	char tempstring[IPV6CALC_STRING_MAX];
463 	char *info;
464 
465 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called");
466 
467 	for (i = 0; i < GeoIP2_DB_MAX_BLOCKS_32; i++) {
468 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "geoip2_db_usage_map[%d]=%08x", i, (unsigned int) geoip2_db_usage_map[i]);
469 	};
470 
471 	for (type = 0; type < 32 * GeoIP2_DB_MAX_BLOCKS_32; type++) {
472 		if ((geoip2_db_usage_map[type / 32] & (1 << (type % 32))) != 0) {
473 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "DB type used: %d", type);
474 
475 			info = libipv6calc_db_wrapper_GeoIP2_database_info(type);
476 
477 			if (info == NULL) { continue; }; // NULL pointer returned
478 
479 			if (strlen(info) == 0) { continue; }; // empty string returned
480 
481 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "type=%d info=%s", type, info);
482 
483 			if (strlen(geoip2_db_usage_string) > 0) {
484 				if (strstr(geoip2_db_usage_string, info) != NULL) {
485 					DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "type=%d info=%s (skip, already displayed)", type, info);
486 					continue;
487 				}; // string already included
488 
489 				snprintf(tempstring, sizeof(tempstring), "%s / %s", geoip2_db_usage_string, info);
490 			} else {
491 				snprintf(tempstring, sizeof(tempstring), "%s", info);
492 			};
493 
494 			snprintf(geoip2_db_usage_string, sizeof(geoip2_db_usage_string), "%s", tempstring);
495 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "type=%d geoip2_db_usage_string=%s", type, geoip2_db_usage_string);
496 		};
497 	};
498 
499 	return(geoip2_db_usage_string);
500 };
501 
502 
503 /*******************************
504  * Wrapper extension functions for GeoIP2
505  *******************************/
506 
507 /*
508  * wrapper extension: GeoIP2_dbfilename
509  */
libipv6calc_db_wrapper_GeoIP2_dbfilename(const unsigned int type)510 static char *libipv6calc_db_wrapper_GeoIP2_dbfilename(const unsigned int type) {
511 	static char tempstring[IPV6CALC_STRING_MAX];
512 	int  entry = -1, i;
513 
514 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called: %s type=%d", wrapper_geoip2_info, type);
515 
516 	for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_GeoIP2_db_file_desc); i++) {
517 		if (libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number == type) {
518 			entry = i;
519 			break;
520 		};
521 	};
522 
523 	if (entry < 0) {
524 		return(NULL);
525 	};
526 
527 	snprintf(tempstring, sizeof(tempstring), "%s/%s", geoip2_db_dir, libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].filename);
528 
529 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Finished: %s type=%d has filename=%s", wrapper_geoip2_info, type, tempstring);
530 
531 	return(tempstring);
532 };
533 
534 
535 /*
536  * wrapper extension: GeoIP2_dbdescription
537  */
libipv6calc_db_wrapper_GeoIP2_dbdescription(const unsigned int type)538 const char *libipv6calc_db_wrapper_GeoIP2_dbdescription(const unsigned int type) {
539 	int  entry = -1, i;
540 
541 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called: %s type=%d", wrapper_geoip2_info, type);
542 
543 	for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_GeoIP2_db_file_desc); i++) {
544 		if (libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number == type) {
545 			entry = i;
546 			break;
547 		};
548 	};
549 
550 	if (entry < 0) {
551 		return("unknown");
552 	};
553 
554 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Finished: %s type=%d has description=%s", wrapper_geoip2_info, type, libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].description);
555 
556 	return(libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].description);
557 };
558 
559 
560 /*
561  * wrapper extension: GeoIP2_db_avail
562  * ret: 1=avail  0=not-avail
563  */
libipv6calc_db_wrapper_GeoIP2_db_avail(const unsigned int type)564 int libipv6calc_db_wrapper_GeoIP2_db_avail(const unsigned int type) {
565 	char *filename;
566 	int r = 0;
567 
568 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called: %s type=%d", wrapper_geoip2_info, type);
569 
570 	filename = libipv6calc_db_wrapper_GeoIP2_dbfilename(type);
571 
572 	if (filename == NULL) {
573 		goto END_libipv6calc_db_wrapper;
574 	};
575 
576 	r = (access(filename, R_OK) == 0) ? 1:0;
577 
578 	if (r == 0) {
579 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Finished: %s type=%d (still unknown) (r=%d: %s)", wrapper_geoip2_info, type, r, strerror(errno));
580 	} else {
581 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Finished: %s type=%d (%s) (r=%d)", wrapper_geoip2_info, type, filename, r);
582 	};
583 
584 END_libipv6calc_db_wrapper:
585 	return(r);
586 };
587 
588 
589 /*
590  * wrapper extension: GeoIP2_open_type
591  * input:
592  * 	type (mandatory)
593  * modified:
594  * 	mmdb_cache
595  * output:
596  * 	result
597  */
libipv6calc_db_wrapper_GeoIP2_open_type(const unsigned int type)598 int libipv6calc_db_wrapper_GeoIP2_open_type(const unsigned int type) {
599 	char *filename;
600 	int  entry = -1, i;
601 	int ret;
602 
603 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called: %s type=%d", wrapper_geoip2_info, type);
604 
605 	// check for valid type
606 	for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_GeoIP2_db_file_desc); i++) {
607 		if (libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number == type) {
608 			entry = i;
609 			break;
610 		};
611 	};
612 
613 	if (entry < 0) {
614 		mmdb_cache[type].file_size = 0;
615 		mmdb_cache[type].flags = 0;
616 		ret = MMDB_FILE_OPEN_ERROR;
617 		goto END_libipv6calc_db_wrapper;
618 	};
619 
620 	if (mmdb_cache[type].file_size > 0) {
621 		// already open
622 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Database already opened (cached) type=%d", type);
623 		ret = MMDB_SUCCESS;
624 		goto END_libipv6calc_db_wrapper;
625 	};
626 
627 	// retrieve filename
628 	filename = libipv6calc_db_wrapper_GeoIP2_dbfilename(type);
629 
630 	if (filename == NULL) {
631 		mmdb_cache[type].file_size = 0;
632 		mmdb_cache[type].flags = 0;
633 		ret = MMDB_FILE_OPEN_ERROR;
634 		goto END_libipv6calc_db_wrapper;
635 	};
636 
637 	ret = libipv6calc_db_wrapper_MMDB_open(filename, MMDB_MODE_MMAP, &mmdb_cache[type]);
638 
639 	if (ret != MMDB_SUCCESS) {
640 		if (ipv6calc_quiet == 0) {
641 			fprintf(stderr, "MMDB_open failed: %s (%s)\n", libipv6calc_db_wrapper_MMDB_strerror(ret), filename);
642 			if (ret == MMDB_IO_ERROR) {
643 				fprintf(stderr, "MMDB_open IO error: %s (%s)\n", strerror(errno), filename);
644 			};
645 		};
646 		mmdb_cache[type].file_size = 0;
647 		mmdb_cache[type].flags = 0;
648 		ret = MMDB_FILE_OPEN_ERROR;
649 		goto END_libipv6calc_db_wrapper;
650 	};
651 
652 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Database successfully opened (fill-cache), type=%d", type);
653 
654 END_libipv6calc_db_wrapper:
655 	return(ret);
656 };
657 
658 
659 /*******************************
660  * Wrapper functions for GeoIP2
661  *******************************/
662 
663 
664 /*
665  * wrapper: GeoIP2_database_info
666  */
libipv6calc_db_wrapper_GeoIP2_database_info(const unsigned int type)667 char *libipv6calc_db_wrapper_GeoIP2_database_info(const unsigned int type) {
668 	static char resultstring[IPV6CALC_STRING_MAX];
669 	char datastring[IPV6CALC_STRING_MAX];
670 	char tempstring[IPV6CALC_STRING_MAX];
671 
672 	MMDB_s mmdb;
673 	int ret, i, entry = -1;
674 
675 
676 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called: %s", wrapper_geoip2_info);
677 
678 	// check for valid type
679 	for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_GeoIP2_db_file_desc); i++) {
680 		if (libipv6calc_db_wrapper_GeoIP2_db_file_desc[i].number == (type & 0xffff)) {
681 			entry = i;
682 			break;
683 		};
684 	};
685 
686 	if (entry < 0) {
687 		ERRORPRINT_WA("Invalid type (FIX CODE): %d", type);
688 		goto END_libipv6calc_db_wrapper;
689 	};
690 
691 
692 	ret = libipv6calc_db_wrapper_GeoIP2_open_type(type);
693 
694 	if (ret != MMDB_SUCCESS) {
695 		snprintf(resultstring, sizeof(resultstring), "%s", "(CAN'T OPEN database information)");
696 		goto END_libipv6calc_db_wrapper;
697 	};
698 
699 	// get metadata
700 	//
701 /*
702  const char *meta_dump = "\n"
703                             "  Database metadata\n"
704                             "    Node count:    %i\n"
705                             "    Record size:   %i bits\n"
706                             "    IP version:    IPv%i\n"
707                             "    Binary format: %i.%i\n"
708                             "    Build epoch:   %llu (%s)\n"
709                             "    Type:          %s\n"
710                             "    Languages:     ";
711 
712     fprintf(stdout, meta_dump,
713 */
714 
715 	mmdb = mmdb_cache[type];
716 
717 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "meta: NodeCount=%i RecordSize=%i IpVersion=%i BinaryFormat=%i.%i BuildTime=%llu Type=%s", \
718             mmdb.metadata.node_count,
719             mmdb.metadata.record_size,
720             mmdb.metadata.ip_version,
721             mmdb.metadata.binary_format_major_version,
722             mmdb.metadata.binary_format_minor_version,
723             (long long unsigned int) mmdb.metadata.build_epoch,
724             mmdb.metadata.database_type);
725 
726 	const time_t epoch = (const time_t)mmdb.metadata.build_epoch;
727 
728 	char year[5];
729 	strftime(year, sizeof(year), "%Y", gmtime(&epoch));
730 	snprintf(resultstring, sizeof(resultstring), "%s Copyright (c) %s MaxMind All Rights Reserved"
731 		, mmdb.metadata.database_type
732 		, year
733 	);
734 
735 	strftime(datastring, sizeof(datastring), "%Y%m%d-%H%M%S UTC", gmtime(&epoch));
736 	snprintf(tempstring, sizeof(tempstring), "%s, created: %s", resultstring, datastring);
737 	snprintf(resultstring, sizeof(resultstring), "%s", tempstring);
738 
739 END_libipv6calc_db_wrapper:
740 	return(resultstring);
741 };
742 
743 
744 /*********************************************
745  * Abstract functions
746  * *******************************************/
747 
748 /* function query for feature set
749  * ret=-1: unknown
750  * 0 : not matching
751  * 1 : ok
752  */
libipv6calc_db_wrapper_GeoIP2_has_features(uint32_t features)753 int libipv6calc_db_wrapper_GeoIP2_has_features(uint32_t features) {
754 	int result = -1;
755 
756 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Called with feature value to test: 0x%08x", features);
757 
758 	if ((wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2] & features) == features) {
759 		result = 1;
760 	} else {
761 		result = 0;
762 	};
763 
764 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Return with result: %d", result);
765 	return(result);
766 };
767 
768 
769 /* country code */
libipv6calc_db_wrapper_GeoIP2_wrapper_country_code_by_addr(const ipv6calc_ipaddr * ipaddrp,char * country,const size_t country_len)770 int libipv6calc_db_wrapper_GeoIP2_wrapper_country_code_by_addr(const ipv6calc_ipaddr *ipaddrp, char *country, const size_t country_len) {
771 	int result = MMDB_INVALID_DATA_ERROR;
772 
773 	int GeoIP2_type = 0;
774 
775 	if (ipaddrp->proto == IPV6CALC_PROTO_IPV4) {
776 		GeoIP2_type = geoip2_db_country_v4;
777 
778 		if ((wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2] & IPV6CALC_DB_IPV4_TO_CC) == 0) {
779 			DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "No GeoIP2 database supporting IPv4 country available");
780 			goto END_libipv6calc_db_wrapper;
781 		};
782 	} else if (ipaddrp->proto == IPV6CALC_PROTO_IPV6) {
783 		GeoIP2_type = geoip2_db_country_v6;
784 
785 		if ((wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2] & IPV6CALC_DB_IPV6_TO_CC) == 0) {
786 			DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "No GeoIP2 database supporting IPv6 country available");
787 			goto END_libipv6calc_db_wrapper;
788 		};
789 	} else {
790 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Unsupported proto: %d", ipaddrp->proto);
791 		goto END_libipv6calc_db_wrapper;
792 	};
793 
794 	result = libipv6calc_db_wrapper_GeoIP2_open_type(GeoIP2_type);
795 
796 	if (result != MMDB_SUCCESS) {
797 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Error opening GeoIP2 by type");
798 		goto END_libipv6calc_db_wrapper;
799 	};
800 
801 	result = libipv6calc_db_wrapper_MMDB_country_code_by_addr(ipaddrp, country, country_len, &mmdb_cache[GeoIP2_type]);
802 
803 	if (result != MMDB_SUCCESS) {
804 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "no match found");
805 		goto END_libipv6calc_db_wrapper;
806 	};
807 
808 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "result country=%s", country);
809 
810 	GeoIP2_DB_USAGE_MAP_TAG(GeoIP2_type);
811 
812 	goto END_libipv6calc_db_wrapper; // keep db open
813 
814 END_libipv6calc_db_wrapper:
815 	return(result);
816 };
817 
818 
819 /* ASN */
libipv6calc_db_wrapper_GeoIP2_wrapper_asn_by_addr(const ipv6calc_ipaddr * ipaddrp)820 uint32_t libipv6calc_db_wrapper_GeoIP2_wrapper_asn_by_addr(const ipv6calc_ipaddr *ipaddrp) {
821 	uint32_t result = ASNUM_AS_UNKNOWN;
822 
823 	int GEOIP2_type = 0;
824 
825 	if (ipaddrp->proto == IPV6CALC_PROTO_IPV4) {
826 		GEOIP2_type = geoip2_db_asn_v4;
827 
828 		if ((wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2] & IPV6CALC_DB_IPV4_TO_AS) == 0) {
829 			DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "No GeoIP2 database supporting IPv4 ASN");
830 			goto END_libipv6calc_db_wrapper;
831 		};
832 	} else if (ipaddrp->proto == IPV6CALC_PROTO_IPV6) {
833 		GEOIP2_type = geoip2_db_asn_v6;
834 
835 		if ((wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2] & IPV6CALC_DB_IPV6_TO_AS) == 0) {
836 			DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "No GeoIP2 database supporting IPv6 ASN");
837 			goto END_libipv6calc_db_wrapper;
838 		};
839 	} else {
840 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Unsupported proto: %d", ipaddrp->proto);
841 		goto END_libipv6calc_db_wrapper;
842 	};
843 
844 	result = libipv6calc_db_wrapper_GeoIP2_open_type(GEOIP2_type);
845 
846 	if (result != MMDB_SUCCESS) {
847 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Error opening GeoIP2 by type");
848 		goto END_libipv6calc_db_wrapper;
849 	};
850 
851 	result = libipv6calc_db_wrapper_MMDB_asn_by_addr(ipaddrp, &mmdb_cache[GEOIP2_type]);
852 
853 	if (result == ASNUM_AS_UNKNOWN) {
854 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "no match found");
855 		goto END_libipv6calc_db_wrapper;
856 	};
857 
858 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "result ASN=%u", result);
859 
860 	GeoIP2_DB_USAGE_MAP_TAG(GEOIP2_type);
861 
862 	goto END_libipv6calc_db_wrapper;
863 
864 END_libipv6calc_db_wrapper:
865 	return(result);
866 };
867 
868 
869 /* GeonameID */
libipv6calc_db_wrapper_GeoIP2_wrapper_GeonameID_by_addr(const ipv6calc_ipaddr * ipaddrp,int * source_ptr)870 uint32_t libipv6calc_db_wrapper_GeoIP2_wrapper_GeonameID_by_addr(const ipv6calc_ipaddr *ipaddrp, int *source_ptr) {
871 	uint32_t result = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN;
872 
873 	int GEOIP2_type = 0;
874 
875 	if (ipaddrp->proto == IPV6CALC_PROTO_IPV4) {
876 		GEOIP2_type = geoip2_db_region_city_v4;
877 
878 		if ((wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2] & IPV6CALC_DB_IPV4_TO_GEONAMEID) == 0) {
879 			DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "No GeoIP2 database supporting IPv4 GeonameID");
880 			goto END_libipv6calc_db_wrapper;
881 		};
882 	} else if (ipaddrp->proto == IPV6CALC_PROTO_IPV6) {
883 		GEOIP2_type = geoip2_db_region_city_v6;
884 
885 		if ((wrapper_features_by_source[IPV6CALC_DB_SOURCE_GEOIP2] & IPV6CALC_DB_IPV6_TO_GEONAMEID) == 0) {
886 			DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "No GeoIP2 database supporting IPv6 GeonameID");
887 			goto END_libipv6calc_db_wrapper;
888 		};
889 	} else {
890 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Unsupported proto: %d", ipaddrp->proto);
891 		goto END_libipv6calc_db_wrapper;
892 	};
893 
894 	result = libipv6calc_db_wrapper_GeoIP2_open_type(GEOIP2_type);
895 
896 	if (result != MMDB_SUCCESS) {
897 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Error opening GeoIP2 by type");
898 		goto END_libipv6calc_db_wrapper;
899 	};
900 
901 	result = libipv6calc_db_wrapper_MMDB_GeonameID_by_addr(ipaddrp, &mmdb_cache[GEOIP2_type], source_ptr);
902 
903 	if (result == IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) {
904 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "no match found");
905 		goto END_libipv6calc_db_wrapper;
906 	};
907 
908 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "result GeonameID=%u", result);
909 
910 	GeoIP2_DB_USAGE_MAP_TAG(GEOIP2_type);
911 
912 	goto END_libipv6calc_db_wrapper;
913 
914 END_libipv6calc_db_wrapper:
915 	return(result);
916 };
917 
918 
919 /* all information */
libipv6calc_db_wrapper_GeoIP2_all_by_addr(const ipv6calc_ipaddr * ipaddrp,libipv6calc_db_wrapper_geolocation_record * recordp)920 int libipv6calc_db_wrapper_GeoIP2_all_by_addr(const ipv6calc_ipaddr *ipaddrp, libipv6calc_db_wrapper_geolocation_record *recordp) {
921 	int result = -1;
922 
923 	int GeoIP2_type = 0;
924 	int GeoIP2_type_asn = 0;
925 
926 	libipv6calc_db_wrapper_geolocation_record record_asn;
927 
928 	if (ipaddrp->proto == IPV6CALC_PROTO_IPV4) {
929 		GeoIP2_type = geoip2_db_region_city_v4;
930 		GeoIP2_type_asn = geoip2_db_asn_v4;
931 
932 		if (GeoIP2_type == 0) {
933 			// fallback
934 			GeoIP2_type = geoip2_db_country_v4;
935 		};
936 	} else if (ipaddrp->proto == IPV6CALC_PROTO_IPV6) {
937 		GeoIP2_type = geoip2_db_region_city_v6;
938 		GeoIP2_type_asn = geoip2_db_asn_v6;
939 
940 		if (GeoIP2_type == 0) {
941 			// fallback
942 			GeoIP2_type = geoip2_db_country_v6;
943 		};
944 	} else {
945 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Unsupported proto: %d", ipaddrp->proto);
946 		goto END_libipv6calc_db_wrapper;
947 	};
948 
949 	result = libipv6calc_db_wrapper_GeoIP2_open_type(GeoIP2_type);
950 
951 	if (result != MMDB_SUCCESS) {
952 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Error opening GeoIP2 by type");
953 		goto END_libipv6calc_db_wrapper;
954 	};
955 
956 	result = libipv6calc_db_wrapper_MMDB_all_by_addr(ipaddrp, recordp, &mmdb_cache[GeoIP2_type]);
957 
958 	if (result != MMDB_SUCCESS) {
959 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "no match found");
960 		goto END_libipv6calc_db_wrapper;
961 	};
962 
963 	// ASN is stored in a different database
964 	if (GeoIP2_type_asn > 0) {
965 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "fetch ASN information from dedicated database");
966 		result = libipv6calc_db_wrapper_GeoIP2_open_type(GeoIP2_type_asn);
967 
968 		if (result != MMDB_SUCCESS) {
969 			DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "Error opening GeoIP2 by type");
970 			goto END_libipv6calc_db_wrapper;
971 		};
972 
973 		result = libipv6calc_db_wrapper_MMDB_all_by_addr(ipaddrp, &record_asn, &mmdb_cache[GeoIP2_type_asn]);
974 
975 		if (result != MMDB_SUCCESS) {
976 			DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_GeoIP2, "no match found");
977 			goto END_libipv6calc_db_wrapper;
978 		};
979 
980 		// copy information
981 		recordp->asn = record_asn.asn;
982                 snprintf(recordp->organization_name, IPV6CALC_DB_SIZE_ORG_NAME, "%s", record_asn.organization_name);
983 	};
984 
985 END_libipv6calc_db_wrapper:
986 	return(result);
987 };
988 
989 #endif
990