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