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