1 /*
2 * Project : ipv6calc
3 * File : databases/lib/libipv6calc_db_wrapper_MMDB.c
4 * Version : $Id: 239da87caeecd331a6074c5f9fd07dedee2023ea $
5 * Copyright : 2019-2021 by Peter Bieringer <pb (at) bieringer.de>
6 *
7 * Information:
8 * ipv6calc MaxMindDB database wrapper
9 * - decoupling databases from main binary
10 * - optional support of dynamic library loading (based on config.h)
11 * - contains some generic wrapper functions
12 */
13
14 #include <stdio.h>
15 #include <dlfcn.h>
16 #include <string.h>
17
18 #include "config.h"
19
20 #include "libipv6calcdebug.h"
21 #include "libipv6addr.h"
22
23 #include "libipv6calc_db_wrapper.h"
24
25 #ifdef SUPPORT_MMDB
26 #include "libipv6calc_db_wrapper_MMDB.h"
27
28 #ifdef SUPPORT_MMDB_DYN
29 char mmdb_lib_file[PATH_MAX] = MMDB_DYN_LIB;
30 static const char* wrapper_mmdb_info = "dyn-load";
31
32 /* define status and dynamic load functions */
33 static int dl_status_MMDB_open = IPV6CALC_DL_STATUS_UNKNOWN;
34 typedef int (*dl_MMDB_open_t)(const char *filename, int flags, MMDB_s *const mmdb);
35 static union { dl_MMDB_open_t func; void * obj; } dl_MMDB_open;
36
37 static int dl_status_MMDB_close = IPV6CALC_DL_STATUS_UNKNOWN;
38 typedef void (*dl_MMDB_close_t)(MMDB_s *const mmdb);
39 static union { dl_MMDB_close_t func; void * obj; } dl_MMDB_close;
40
41 static int dl_status_MMDB_lib_version = IPV6CALC_DL_STATUS_UNKNOWN;
42 typedef char *(*dl_MMDB_lib_version_t)(void);
43 static union { dl_MMDB_lib_version_t func; void * obj; } dl_MMDB_lib_version;
44
45 static int dl_status_MMDB_aget_value = IPV6CALC_DL_STATUS_UNKNOWN;
46 typedef int (*dl_MMDB_aget_value_t)(MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, const char *const *const path);
47 static union { dl_MMDB_aget_value_t func; void * obj; } dl_MMDB_aget_value;
48
49 static int dl_status_MMDB_get_entry_data_list = IPV6CALC_DL_STATUS_UNKNOWN;
50 typedef int (*dl_MMDB_get_entry_data_list_t)(MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list);
51 static union { dl_MMDB_get_entry_data_list_t func; void * obj; } dl_MMDB_get_entry_data_list;
52
53 static int dl_status_MMDB_free_entry_data_list = IPV6CALC_DL_STATUS_UNKNOWN;
54 typedef int (*dl_MMDB_free_entry_data_list_t)(MMDB_entry_data_list_s *const entry_data_list);
55 static union { dl_MMDB_free_entry_data_list_t func; void * obj; } dl_MMDB_free_entry_data_list;
56
57 static int dl_status_MMDB_dump_entry_data_list = IPV6CALC_DL_STATUS_UNKNOWN;
58 typedef int (*dl_MMDB_dump_entry_data_list_t)(FILE *const stream, MMDB_entry_data_list_s *const entry_data_list, int indent);
59 static union { dl_MMDB_dump_entry_data_list_t func; void * obj; } dl_MMDB_dump_entry_data_list;
60
61 static int dl_status_MMDB_lookup_sockaddr = IPV6CALC_DL_STATUS_UNKNOWN;
62 typedef MMDB_lookup_result_s (*dl_MMDB_lookup_sockaddr_t)(MMDB_s *const mmdb, const struct sockaddr *const sockaddr, int *const mmdb_error);
63 static union { dl_MMDB_lookup_sockaddr_t func; void * obj; } dl_MMDB_lookup_sockaddr;
64
65 static int dl_status_MMDB_strerror = IPV6CALC_DL_STATUS_UNKNOWN;
66 typedef const char *(*dl_MMDB_strerror_t)(int error_code);
67 static union { dl_MMDB_strerror_t func; void * obj; } dl_MMDB_strerror;
68
69 #else // SUPPORT_MMDB_DYN
70 static const char* wrapper_mmdb_info = "built-in";
71 #endif // SUPPORT_MMDB_DYN
72
73 static void *dl_MMDB_handle = NULL;
74
75 #define CHECK_STORE(MAXLEN, STORE, DESC) \
76 if (entry_data.has_data) { \
77 if (entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) { \
78 int max = (entry_data.data_size + 1 > MAXLEN) ? MAXLEN : entry_data.data_size +1; \
79 snprintf(STORE, max , "%s", entry_data.utf8_string); \
80 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "%s: %s", DESC, STORE); \
81 } else { \
82 ERRORPRINT_WA("Lookup result from MaxMindDB has unexpected type for %s: %u", DESC, entry_data.type); \
83 }; \
84 } else { \
85 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "%s not found", DESC); \
86 };
87
88 #define CHECK_STORE_DOUBLE(STORE, DESC) \
89 if (entry_data.has_data) { \
90 if (entry_data.type == MMDB_DATA_TYPE_DOUBLE) { \
91 STORE = entry_data.double_value; \
92 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "%s: %lf", DESC, STORE); \
93 } else { \
94 ERRORPRINT_WA("Lookup result from MaxMindDB has unexpected type for %s: %u", DESC, entry_data.type); \
95 }; \
96 } else { \
97 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "%s not found", DESC); \
98 };
99
100 #define CHECK_STORE_UINT32(STORE, DESC) \
101 if (entry_data.has_data) { \
102 if (entry_data.type == MMDB_DATA_TYPE_UINT32) { \
103 STORE = entry_data.uint32; \
104 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "%s: %u", DESC, STORE); \
105 } else { \
106 ERRORPRINT_WA("Lookup result from MaxMindDB has unexpected type for %s: %u", DESC, entry_data.type); \
107 }; \
108 } else { \
109 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "%s not found", DESC); \
110 };
111
112 #define CHECK_STORE_UINT16(STORE, DESC) \
113 if (entry_data.has_data) { \
114 if (entry_data.type == MMDB_DATA_TYPE_UINT16) { \
115 STORE = entry_data.uint16; \
116 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "%s: %u", DESC, STORE); \
117 } else { \
118 ERRORPRINT_WA("Lookup result from MaxMindDB has unexpected type for %s: %u", DESC, entry_data.type); \
119 }; \
120 } else { \
121 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "%s not found", DESC); \
122 };
123
124 /*
125 * function initialise the MMDB wrapper
126 *
127 * in : (nothing)
128 * out: 0=ok, 1=error, 2=not found, 3=unknown
129 */
libipv6calc_db_wrapper_MMDB_wrapper_init(void)130 int libipv6calc_db_wrapper_MMDB_wrapper_init(void) {
131 int result = 3;
132
133 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called");
134
135 #ifdef SUPPORT_MMDB_DYN
136 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Load library: %s", mmdb_lib_file);
137
138 dlerror(); /* Clear any existing error */
139
140 dl_MMDB_handle = dlopen(mmdb_lib_file, RTLD_NOW | RTLD_LOCAL);
141
142 if (dl_MMDB_handle == NULL) {
143 const char *error = dlerror();
144 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Load of library not successful: %s (%s)", mmdb_lib_file, error);
145 if (strstr(error, "such file") != NULL) {
146 result = 2;
147 goto END_libipv6calc_db_wrapper;
148 };
149 if ((strcmp(mmdb_lib_file, MMDB_DYN_LIB) != 0) || (ipv6calc_verbose > 0)) {
150 NONQUIETPRINT_WA("MMDB dynamic library load failed by problem with specified library (disable support): %s (%s)", mmdb_lib_file, error)
151 };
152 result = 1;
153 } else {
154 result = 0;
155 };
156
157 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Loaded library successful: %s", mmdb_lib_file);
158 END_libipv6calc_db_wrapper:
159 #else // SUPPORT_MMDB_DYN
160 // todo: library version check
161 result = 0;
162 #endif // SUPPORT_MMDB_DYN
163
164 return(result);
165 };
166
167
168 /*
169 * function cleanup the MMDB wrapper
170 *
171 * in : (nothing)
172 * out: (nothing)
173 */
libipv6calc_db_wrapper_MMDB_wrapper_cleanup(void)174 void libipv6calc_db_wrapper_MMDB_wrapper_cleanup(void) {
175 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called");
176
177 #ifdef SUPPORT_MMDB
178 //libipv6calc_db_wrapper_MMDB_cleanup();
179 #endif
180
181 dl_MMDB_handle = NULL; // disable handle
182
183 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "Finished");
184 return;
185 };
186
187
188 /*
189 * function info of MMDB wrapper
190 *
191 * in : ptr and size of string to be filled
192 * out: modified string;
193 */
libipv6calc_db_wrapper_MMDB_wrapper_info(char * string,const size_t size)194 void libipv6calc_db_wrapper_MMDB_wrapper_info(char* string, const size_t size) {
195 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called");
196
197 #ifdef SUPPORT_MMDB
198 snprintf(string, size, "MMDB support active");
199 #else
200 snprintf(string, size, "No MMDB support built-in");
201 #endif
202
203 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "Finished");
204 return;
205 };
206
207
208 /***********************************************
209 * Generic wrapper functions for MMDB for alignment
210 ***********************************************/
211
212 /*
213 * function cleanup the MMDB wrapper
214 *
215 * in : (nothing)
216 * out: (nothing)
217 */
libipv6calc_db_wrapper_MMDB_cleanup(void)218 void libipv6calc_db_wrapper_MMDB_cleanup(void) {
219 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called");
220
221 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "Not required for MMDB");
222
223 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "Finished");
224 return;
225 };
226
227
228 /***********************************************
229 * Wrapper functions for MMDB library
230 * autoswitch between dynamically linked/loaded
231 ***********************************************/
232
233 /*
234 * wrapper: MMDB_lib_version
235 */
libipv6calc_db_wrapper_MMDB_lib_version(void)236 const char *libipv6calc_db_wrapper_MMDB_lib_version(void) {
237 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called: %s", wrapper_mmdb_info);
238
239 #ifdef SUPPORT_MMDB_DYN
240 char *result_MMDB_lib_version = "unknown";
241 const char *dl_symbol = "MMDB_lib_version";
242 char *error;
243
244 if (dl_MMDB_handle == NULL) {
245 result_MMDB_lib_version = "LIBRARY-NOT-LOADED";
246 goto END_libipv6calc_db_wrapper;
247 };
248
249 if (dl_status_MMDB_lib_version == IPV6CALC_DL_STATUS_UNKNOWN) {
250 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Call dlsym: %s", dl_symbol);
251
252 dlerror(); /* Clear any existing error */
253
254 *(void **) (&dl_MMDB_lib_version.obj) = dlsym(dl_MMDB_handle, dl_symbol);
255
256 if ((error = dlerror()) != NULL) {
257 dl_status_MMDB_lib_version = IPV6CALC_DL_STATUS_ERROR;
258 fprintf(stderr, "%s\n", error);
259 goto END_libipv6calc_db_wrapper;
260 };
261
262 dl_status_MMDB_lib_version = IPV6CALC_DL_STATUS_OK;
263 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called dlsym successful: %s", dl_symbol);
264 } else if (dl_status_MMDB_lib_version == IPV6CALC_DL_STATUS_ERROR) {
265 /* already known issue */
266 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already failed: %s", dl_symbol);
267 goto END_libipv6calc_db_wrapper;
268 } else {
269 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already successful: %s", dl_symbol);
270 };
271
272 dlerror(); /* Clear any existing error */
273
274 result_MMDB_lib_version = (*dl_MMDB_lib_version.func)();
275
276 if ((error = dlerror()) != NULL) {
277 fprintf(stderr, "%s\n", error);
278 goto END_libipv6calc_db_wrapper;
279 };
280
281 END_libipv6calc_db_wrapper:
282 return(result_MMDB_lib_version);
283 #else // SUPPORT_MMDB_DYN
284 return(MMDB_lib_version());
285 #endif
286 };
287
288
289 /*
290 * wrapper: MMDB_open
291 */
libipv6calc_db_wrapper_MMDB_open(const char * const filename,uint32_t flags,MMDB_s * const mmdb)292 int libipv6calc_db_wrapper_MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) {
293 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called: %s filename=%s", wrapper_mmdb_info, filename);
294
295 #ifdef SUPPORT_MMDB_DYN
296 int r = MMDB_FILE_OPEN_ERROR;
297 const char *dl_symbol = "MMDB_open";
298 char *error;
299
300 if (dl_MMDB_handle == NULL) {
301 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "dl_MMDB_handle not defined");
302 goto END_libipv6calc_db_wrapper;
303 };
304
305 if (dl_status_MMDB_open == IPV6CALC_DL_STATUS_UNKNOWN) {
306 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Call dlsym: %s", dl_symbol);
307
308 dlerror(); /* Clear any existing error */
309
310 *(void **) (&dl_MMDB_open.obj) = dlsym(dl_MMDB_handle, dl_symbol);
311
312 if ((error = dlerror()) != NULL) {
313 dl_status_MMDB_open = IPV6CALC_DL_STATUS_ERROR;
314 fprintf(stderr, "%s\n", error);
315 goto END_libipv6calc_db_wrapper;
316 };
317
318 dl_status_MMDB_open = IPV6CALC_DL_STATUS_OK;
319 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called dlsym successful: %s", dl_symbol);
320 } else if (dl_status_MMDB_open == IPV6CALC_DL_STATUS_ERROR) {
321 /* already known issue */
322 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already failed: %s", dl_symbol);
323 goto END_libipv6calc_db_wrapper;
324 } else {
325 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already successful: %s", dl_symbol);
326 };
327
328 dlerror(); /* Clear any existing error */
329
330 r = (*dl_MMDB_open.func)(filename, flags, mmdb);
331
332 if ((error = dlerror()) != NULL) {
333 fprintf(stderr, "%s\n", error);
334 goto END_libipv6calc_db_wrapper;
335 };
336
337 END_libipv6calc_db_wrapper:
338 return(r);
339 #else
340 return(MMDB_open(filename, flags, mmdb));
341 #endif
342 };
343
344
345 /*
346 * wrapper: MMDB_close
347 */
libipv6calc_db_wrapper_MMDB_close(MMDB_s * mmdb)348 void libipv6calc_db_wrapper_MMDB_close(MMDB_s* mmdb) {
349 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called: %s", wrapper_mmdb_info);
350
351 if (mmdb == NULL) {
352 return;
353 };
354
355 #ifdef SUPPORT_MMDB_DYN
356 const char *dl_symbol = "MMDB_close";
357 char *error;
358
359 if (dl_MMDB_handle == NULL) {
360 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "dl_MMDB_handle not defined");
361 goto END_libipv6calc_db_wrapper;
362 };
363
364 if (dl_status_MMDB_close == IPV6CALC_DL_STATUS_UNKNOWN) {
365 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Call dlsym: %s", dl_symbol);
366
367 dlerror(); /* Clear any existing error */
368
369 *(void **) (&dl_MMDB_close) = dlsym(dl_MMDB_handle, dl_symbol);
370
371 if ((error = dlerror()) != NULL) {
372 dl_status_MMDB_close = IPV6CALC_DL_STATUS_ERROR;
373 fprintf(stderr, "%s\n", error);
374 goto END_libipv6calc_db_wrapper;
375 };
376
377 dl_status_MMDB_close = IPV6CALC_DL_STATUS_OK;
378 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called dlsym successful: %s", dl_symbol);
379 } else if (dl_status_MMDB_close == IPV6CALC_DL_STATUS_ERROR) {
380 /* already known issue */
381 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already failed: %s", dl_symbol);
382 goto END_libipv6calc_db_wrapper;
383 } else {
384 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already successful: %s", dl_symbol);
385 };
386
387 dlerror(); /* Clear any existing error */
388
389 (*dl_MMDB_close.func)(mmdb);
390
391 if ((error = dlerror()) != NULL) {
392 fprintf(stderr, "%s\n", error);
393 goto END_libipv6calc_db_wrapper;
394 };
395
396 END_libipv6calc_db_wrapper:
397 #else
398 MMDB_close(mmdb);
399 #endif
400
401 return;
402 };
403
404
405 /*
406 * wrapper: MMDB_aget_value
407 */
libipv6calc_db_wrapper_MMDB_aget_value(MMDB_entry_s * const start,MMDB_entry_data_s * const entry_data,const char * const * const path)408 int libipv6calc_db_wrapper_MMDB_aget_value (MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, const char *const *const path) {
409 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called: %s", wrapper_mmdb_info);
410
411 #ifdef SUPPORT_MMDB_DYN
412 int result_MMDB_aget_value = 0;
413 const char *dl_symbol = "MMDB_aget_value";
414 char *error;
415
416 if (dl_MMDB_handle == NULL) {
417 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "dl_MMDB_handle not defined");
418 goto END_libipv6calc_db_wrapper;
419 };
420
421 if (dl_status_MMDB_aget_value == IPV6CALC_DL_STATUS_UNKNOWN) {
422 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Call dlsym: %s", dl_symbol);
423
424 dlerror(); /* Clear any existing error */
425
426 *(void **) (&dl_MMDB_aget_value.obj) = dlsym(dl_MMDB_handle, dl_symbol);
427
428 if ((error = dlerror()) != NULL) {
429 dl_status_MMDB_aget_value = IPV6CALC_DL_STATUS_ERROR;
430 fprintf(stderr, "%s\n", error);
431 goto END_libipv6calc_db_wrapper;
432 };
433
434 dl_status_MMDB_aget_value = IPV6CALC_DL_STATUS_OK;
435 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called dlsym successful: %s", dl_symbol);
436 } else if (dl_status_MMDB_aget_value == IPV6CALC_DL_STATUS_ERROR) {
437 /* already known issue */
438 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already failed: %s", dl_symbol);
439 goto END_libipv6calc_db_wrapper;
440 } else {
441 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already successful: %s", dl_symbol);
442 };
443
444 dlerror(); /* Clear any existing error */
445
446 result_MMDB_aget_value = (*dl_MMDB_aget_value.func)(start, entry_data, path);
447
448 if ((error = dlerror()) != NULL) {
449 fprintf(stderr, "%s\n", error);
450 goto END_libipv6calc_db_wrapper;
451 };
452
453 END_libipv6calc_db_wrapper:
454 return(result_MMDB_aget_value);
455 #else
456 return(MMDB_aget_value(start, entry_data, path));
457 #endif
458 };
459
460
461 /*
462 * wrapper: MMDB_get_entry_data_list
463 */
libipv6calc_db_wrapper_MMDB_get_entry_data_list(MMDB_entry_s * start,MMDB_entry_data_list_s ** const entry_data_list)464 int libipv6calc_db_wrapper_MMDB_get_entry_data_list (MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list) {
465 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called: %s", wrapper_mmdb_info);
466
467 #ifdef SUPPORT_MMDB_DYN
468 int result_MMDB_get_entry_data_list = 0;
469 const char *dl_symbol = "MMDB_get_entry_data_list";
470 char *error;
471
472 if (dl_MMDB_handle == NULL) {
473 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "dl_MMDB_handle not defined");
474 goto END_libipv6calc_db_wrapper;
475 };
476
477 if (dl_status_MMDB_get_entry_data_list == IPV6CALC_DL_STATUS_UNKNOWN) {
478 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Call dlsym: %s", dl_symbol);
479
480 dlerror(); /* Clear any existing error */
481
482 *(void **) (&dl_MMDB_get_entry_data_list.obj) = dlsym(dl_MMDB_handle, dl_symbol);
483
484 if ((error = dlerror()) != NULL) {
485 dl_status_MMDB_get_entry_data_list = IPV6CALC_DL_STATUS_ERROR;
486 fprintf(stderr, "%s\n", error);
487 goto END_libipv6calc_db_wrapper;
488 };
489
490 dl_status_MMDB_get_entry_data_list = IPV6CALC_DL_STATUS_OK;
491 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called dlsym successful: %s", dl_symbol);
492 } else if (dl_status_MMDB_get_entry_data_list == IPV6CALC_DL_STATUS_ERROR) {
493 /* already known issue */
494 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already failed: %s", dl_symbol);
495 goto END_libipv6calc_db_wrapper;
496 } else {
497 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already successful: %s", dl_symbol);
498 };
499
500 dlerror(); /* Clear any existing error */
501
502 result_MMDB_get_entry_data_list = (*dl_MMDB_get_entry_data_list.func)(start, entry_data_list);
503
504 if ((error = dlerror()) != NULL) {
505 fprintf(stderr, "%s\n", error);
506 goto END_libipv6calc_db_wrapper;
507 };
508
509 END_libipv6calc_db_wrapper:
510 return(result_MMDB_get_entry_data_list);
511 #else
512 return(MMDB_get_entry_data_list(start, entry_data_list));
513 #endif
514 };
515
516
517 /*
518 * wrapper: MMDB_free_entry_data_list
519 */
libipv6calc_db_wrapper_MMDB_free_entry_data_list(MMDB_entry_data_list_s * const entry_data_list)520 void libipv6calc_db_wrapper_MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list) {
521 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called: %s", wrapper_mmdb_info);
522
523 #ifdef SUPPORT_MMDB_DYN
524 const char *dl_symbol = "MMDB_free_entry_data_list";
525 char *error;
526
527 if (dl_MMDB_handle == NULL) {
528 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "dl_MMDB_handle not defined");
529 goto END_libipv6calc_db_wrapper;
530 };
531
532 if (dl_status_MMDB_free_entry_data_list == IPV6CALC_DL_STATUS_UNKNOWN) {
533 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Call dlsym: %s", dl_symbol);
534
535 dlerror(); /* Clear any existing error */
536
537 *(void **) (&dl_MMDB_free_entry_data_list.obj) = dlsym(dl_MMDB_handle, dl_symbol);
538
539 if ((error = dlerror()) != NULL) {
540 dl_status_MMDB_free_entry_data_list = IPV6CALC_DL_STATUS_ERROR;
541 fprintf(stderr, "%s\n", error);
542 goto END_libipv6calc_db_wrapper;
543 };
544
545 dl_status_MMDB_free_entry_data_list = IPV6CALC_DL_STATUS_OK;
546 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called dlsym successful: %s", dl_symbol);
547 } else if (dl_status_MMDB_free_entry_data_list == IPV6CALC_DL_STATUS_ERROR) {
548 /* already known issue */
549 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already failed: %s", dl_symbol);
550 goto END_libipv6calc_db_wrapper;
551 } else {
552 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already successful: %s", dl_symbol);
553 };
554
555 dlerror(); /* Clear any existing error */
556
557 (*dl_MMDB_free_entry_data_list.func)(entry_data_list);
558
559 if ((error = dlerror()) != NULL) {
560 fprintf(stderr, "%s\n", error);
561 goto END_libipv6calc_db_wrapper;
562 };
563
564 END_libipv6calc_db_wrapper:
565 return;
566 #else
567 MMDB_free_entry_data_list(entry_data_list);
568 #endif
569 };
570
571
572 /*
573 * wrapper: MMDB_dump_entry_data_list
574 */
libipv6calc_db_wrapper_MMDB_dump_entry_data_list(FILE * const stream,MMDB_entry_data_list_s * const entry_data_list,int indent)575 int libipv6calc_db_wrapper_MMDB_dump_entry_data_list(FILE *const stream, MMDB_entry_data_list_s *const entry_data_list, int indent) {
576 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called: %s", wrapper_mmdb_info);
577
578 #ifdef SUPPORT_MMDB_DYN
579 const char *dl_symbol = "MMDB_dump_entry_data_list";
580 char *error;
581 int result_MMDB_dump_entry_data_list = 0;
582
583 if (dl_MMDB_handle == NULL) {
584 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "dl_MMDB_handle not defined");
585 goto END_libipv6calc_db_wrapper;
586 };
587
588 if (dl_status_MMDB_dump_entry_data_list == IPV6CALC_DL_STATUS_UNKNOWN) {
589 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Call dlsym: %s", dl_symbol);
590
591 dlerror(); /* Clear any existing error */
592
593 *(void **) (&dl_MMDB_dump_entry_data_list.obj) = dlsym(dl_MMDB_handle, dl_symbol);
594
595 if ((error = dlerror()) != NULL) {
596 dl_status_MMDB_dump_entry_data_list = IPV6CALC_DL_STATUS_ERROR;
597 fprintf(stderr, "%s\n", error);
598 goto END_libipv6calc_db_wrapper;
599 };
600
601 dl_status_MMDB_dump_entry_data_list = IPV6CALC_DL_STATUS_OK;
602 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called dlsym successful: %s", dl_symbol);
603 } else if (dl_status_MMDB_dump_entry_data_list == IPV6CALC_DL_STATUS_ERROR) {
604 /* already known issue */
605 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already failed: %s", dl_symbol);
606 goto END_libipv6calc_db_wrapper;
607 } else {
608 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already successful: %s", dl_symbol);
609 };
610
611 dlerror(); /* Clear any existing error */
612
613 result_MMDB_dump_entry_data_list = (*dl_MMDB_dump_entry_data_list.func)(stream, entry_data_list, indent);
614
615 if ((error = dlerror()) != NULL) {
616 fprintf(stderr, "%s\n", error);
617 goto END_libipv6calc_db_wrapper;
618 };
619
620 END_libipv6calc_db_wrapper:
621 return(result_MMDB_dump_entry_data_list);
622 #else
623 return MMDB_dump_entry_data_list(stream, entry_data_list, indent);
624 #endif
625 };
626
627
628 /*
629 * wrapper: MMDB_lookup_sockaddr
630 */
libipv6calc_db_wrapper_MMDB_lookup_sockaddr(MMDB_s * const mmdb,const struct sockaddr * const sockaddr,int * const mmdb_error)631 MMDB_lookup_result_s libipv6calc_db_wrapper_MMDB_lookup_sockaddr (MMDB_s *const mmdb, const struct sockaddr *const sockaddr, int *const mmdb_error) {
632 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called: %s", wrapper_mmdb_info);
633
634 #ifdef SUPPORT_MMDB_DYN
635 MMDB_lookup_result_s result_MMDB_lookup_sockaddr = {false, { NULL, 0}, 0};
636 const char *dl_symbol = "MMDB_lookup_sockaddr";
637 char *error;
638
639 if (dl_MMDB_handle == NULL) {
640 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "dl_MMDB_handle not defined");
641 goto END_libipv6calc_db_wrapper;
642 };
643
644 if (dl_status_MMDB_lookup_sockaddr == IPV6CALC_DL_STATUS_UNKNOWN) {
645 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Call dlsym: %s", dl_symbol);
646
647 dlerror(); /* Clear any existing error */
648
649 *(void **) (&dl_MMDB_lookup_sockaddr.obj) = dlsym(dl_MMDB_handle, "MMDB_lookup_sockaddr");
650
651 if ((error = dlerror()) != NULL) {
652 dl_status_MMDB_lookup_sockaddr = IPV6CALC_DL_STATUS_ERROR;
653 fprintf(stderr, "%s\n", error);
654 goto END_libipv6calc_db_wrapper;
655 };
656
657 dl_status_MMDB_lookup_sockaddr = IPV6CALC_DL_STATUS_OK;
658 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called dlsym successful: %s", dl_symbol);
659 } else if (dl_status_MMDB_lookup_sockaddr == IPV6CALC_DL_STATUS_ERROR) {
660 /* already known issue */
661 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already failed: %s", dl_symbol);
662 goto END_libipv6calc_db_wrapper;
663 } else {
664 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already successful: %s", dl_symbol);
665 };
666
667 dlerror(); /* Clear any existing error */
668
669 result_MMDB_lookup_sockaddr = (*dl_MMDB_lookup_sockaddr.func)(mmdb, sockaddr, mmdb_error);
670
671 if ((error = dlerror()) != NULL) {
672 fprintf(stderr, "%s\n", error);
673 goto END_libipv6calc_db_wrapper;
674 };
675
676 END_libipv6calc_db_wrapper:
677 return(result_MMDB_lookup_sockaddr);
678 #else
679 return(MMDB_lookup_sockaddr(mmdb, sockaddr, mmdb_error));
680 #endif
681 };
682
683
684 /*
685 * wrapper: MMDB_strerror
686 */
libipv6calc_db_wrapper_MMDB_strerror(int error_code)687 const char *libipv6calc_db_wrapper_MMDB_strerror (int error_code) {
688 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called: %s", wrapper_mmdb_info);
689
690 #ifdef SUPPORT_MMDB_DYN
691 const char *result_MMDB_strerror = "";
692 const char *dl_symbol = "MMDB_strerror";
693 char *error;
694
695 if (dl_MMDB_handle == NULL) {
696 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "dl_MMDB_handle not defined");
697 goto END_libipv6calc_db_wrapper;
698 };
699
700 if (dl_status_MMDB_strerror == IPV6CALC_DL_STATUS_UNKNOWN) {
701 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Call dlsym: %s", dl_symbol);
702
703 dlerror(); /* Clear any existing error */
704
705 *(void **) (&dl_MMDB_strerror.obj) = dlsym(dl_MMDB_handle, "MMDB_strerror");
706
707 if ((error = dlerror()) != NULL) {
708 dl_status_MMDB_strerror = IPV6CALC_DL_STATUS_ERROR;
709 fprintf(stderr, "%s\n", error);
710 goto END_libipv6calc_db_wrapper;
711 };
712
713 dl_status_MMDB_strerror = IPV6CALC_DL_STATUS_OK;
714 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Called dlsym successful: %s", dl_symbol);
715 } else if (dl_status_MMDB_strerror == IPV6CALC_DL_STATUS_ERROR) {
716 /* already known issue */
717 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already failed: %s", dl_symbol);
718 goto END_libipv6calc_db_wrapper;
719 } else {
720 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "Previous call of dlsym already successful: %s", dl_symbol);
721 };
722
723 dlerror(); /* Clear any existing error */
724
725 result_MMDB_strerror = (*dl_MMDB_strerror.func)(error_code);
726
727 if ((error = dlerror()) != NULL) {
728 fprintf(stderr, "%s\n", error);
729 goto END_libipv6calc_db_wrapper;
730 };
731
732 END_libipv6calc_db_wrapper:
733 return(result_MMDB_strerror);
734 #else
735 return(MMDB_strerror(error_code));
736 #endif
737 };
738
739
740 /***********************************************
741 * Special wrapper functions for MMDB to avoid duplicate code
742 ***********************************************/
743
744 /* Lookup By Addr
745 * in : ipaddrp, mmdb
746 * mod: mmdb_error
747 * out: MMDB_lookup_result_s
748 */
libipv6calc_db_wrapper_MMDB_wrapper_lookup_by_addr(const ipv6calc_ipaddr * ipaddrp,MMDB_s * const mmdb,int * const mmdb_error)749 MMDB_lookup_result_s libipv6calc_db_wrapper_MMDB_wrapper_lookup_by_addr (const ipv6calc_ipaddr *ipaddrp, MMDB_s *const mmdb, int *const mmdb_error) {
750 MMDB_lookup_result_s lookup_result;
751 lookup_result.found_entry = false;
752
753 // convert ipaddrp into sockaddr
754 union sockaddr_u {
755 struct sockaddr_in in;
756 struct sockaddr_in6 in6;
757 struct sockaddr sockaddr;
758 } su;
759
760 if (ipaddrp->proto == 4) {
761 su.sockaddr.sa_family = AF_INET;
762 su.in.sin_addr.s_addr = htonl(ipaddrp->addr[0]);
763 } else if (ipaddrp->proto == 6) {
764 su.sockaddr.sa_family = AF_INET6;
765 #ifdef __KAME__ // FreeBSD misses s6_addr8/16/32 in non-kernel include, also union has different name in glibc (__in6_u vs. __u6_addr) :-(
766 su.in6.sin6_addr.__u6_addr.__u6_addr32[0] = htonl(ipaddrp->addr[0]);
767 su.in6.sin6_addr.__u6_addr.__u6_addr32[1] = htonl(ipaddrp->addr[1]);
768 su.in6.sin6_addr.__u6_addr.__u6_addr32[2] = htonl(ipaddrp->addr[2]);
769 su.in6.sin6_addr.__u6_addr.__u6_addr32[3] = htonl(ipaddrp->addr[3]);
770 #else
771 su.in6.sin6_addr.s6_addr32[0] = htonl(ipaddrp->addr[0]);
772 su.in6.sin6_addr.s6_addr32[1] = htonl(ipaddrp->addr[1]);
773 su.in6.sin6_addr.s6_addr32[2] = htonl(ipaddrp->addr[2]);
774 su.in6.sin6_addr.s6_addr32[3] = htonl(ipaddrp->addr[3]);
775 #endif
776 } else {
777 *mmdb_error = MMDB_INVALID_DATA_ERROR;
778 goto END_libipv6calc_db_wrapper;
779 };
780
781 lookup_result = libipv6calc_db_wrapper_MMDB_lookup_sockaddr(mmdb, &su.sockaddr, mmdb_error);
782
783 END_libipv6calc_db_wrapper:
784 return(lookup_result);
785 };
786
787
788 /* Country Code By Addr
789 * in : ipaddrp, country_len, country, mmdb
790 * mod: country
791 * out: mmdb_error
792 */
libipv6calc_db_wrapper_MMDB_country_code_by_addr(const ipv6calc_ipaddr * ipaddrp,char * country,const size_t country_len,MMDB_s * const mmdb)793 int libipv6calc_db_wrapper_MMDB_country_code_by_addr(const ipv6calc_ipaddr *ipaddrp, char *country, const size_t country_len, MMDB_s *const mmdb) {
794 MMDB_lookup_result_s lookup_result;
795 MMDB_entry_data_s entry_data;
796 int mmdb_error = MMDB_INVALID_DATA_ERROR;
797
798 lookup_result = libipv6calc_db_wrapper_MMDB_wrapper_lookup_by_addr(ipaddrp, mmdb, &mmdb_error);
799
800 if (mmdb_error != MMDB_SUCCESS) {
801 goto END_libipv6calc_db_wrapper;
802 };
803
804 // fetch CountryCode
805 const char *lookup_path_country_code[] = { "country", "iso_code", NULL };
806 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_country_code);
807 if (entry_data.has_data) {
808 if (entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
809 int max = (entry_data.data_size + 1 > country_len) ? country_len : entry_data.data_size +1;
810 snprintf(country, max , "%s", entry_data.utf8_string);
811 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "CountryCode: %s", country);
812 } else {
813 ERRORPRINT_WA("Lookup result from MaxMindDB has unexpected type for CountryCode: %u", entry_data.type);
814 };
815 } else {
816 // fetch CountryCode from fallback (registered_country)
817 const char *lookup_path_registered_country_code[] = { "registered_country", "iso_code", NULL };
818 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_registered_country_code);
819 if (entry_data.has_data) {
820 if (entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
821 int max = (entry_data.data_size + 1 > country_len) ? country_len : entry_data.data_size +1;
822 snprintf(country, max , "%s", entry_data.utf8_string);
823 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "CountryCode(Registered): %s", country);
824 } else {
825 ERRORPRINT_WA("Lookup result from MaxMindDB has unexpected type for CountryCode(Registered): %u", entry_data.type);
826 };
827 } else {
828 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "CountryCode not found");
829 mmdb_error = MMDB_INVALID_DATA_ERROR;
830 };
831 };
832
833 END_libipv6calc_db_wrapper:
834 return(mmdb_error);
835 };
836
837
838 /* ASN By Addr
839 * in : ipaddrp, mmdb
840 * out: asn
841 */
libipv6calc_db_wrapper_MMDB_asn_by_addr(const ipv6calc_ipaddr * ipaddrp,MMDB_s * const mmdb)842 uint32_t libipv6calc_db_wrapper_MMDB_asn_by_addr(const ipv6calc_ipaddr *ipaddrp, MMDB_s *const mmdb) {
843 MMDB_lookup_result_s lookup_result;
844 MMDB_entry_data_s entry_data;
845 int mmdb_error = MMDB_INVALID_DATA_ERROR;
846 uint32_t result = ASNUM_AS_UNKNOWN;
847
848 lookup_result = libipv6calc_db_wrapper_MMDB_wrapper_lookup_by_addr(ipaddrp, mmdb, &mmdb_error);
849
850 if (mmdb_error != MMDB_SUCCESS) {
851 goto END_libipv6calc_db_wrapper;
852 };
853
854 // fetch ASN
855 if(strstr(mmdb->metadata.database_type, "ASN")) {
856 // GeoLite2-ASN
857 const char *lookup_path_asn[] = { "autonomous_system_number", NULL };
858 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_asn);
859 } else {
860 const char *lookup_path_asn[] = { "traits", "autonomous_system_number", NULL };
861 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_asn);
862 };
863 if (entry_data.has_data) {
864 if (entry_data.type == MMDB_DATA_TYPE_UINT32) {
865 result = entry_data.uint32;
866 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "ASN: %u", result);
867 } else {
868 ERRORPRINT_WA("Lookup result from MaxMindDB has unexpected type for ASN: %u", entry_data.type);
869 };
870 } else {
871 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_MMDB, "ASN not found");
872 mmdb_error = MMDB_INVALID_DATA_ERROR;
873 };
874
875 END_libipv6calc_db_wrapper:
876 return(result);
877 };
878
879
880 /* GeonameID By Addr
881 * in : ipaddrp, mmdb
882 * mod: source
883 * out: GeonameID
884 */
libipv6calc_db_wrapper_MMDB_GeonameID_by_addr(const ipv6calc_ipaddr * ipaddrp,MMDB_s * const mmdb,int * source_ptr)885 uint32_t libipv6calc_db_wrapper_MMDB_GeonameID_by_addr(const ipv6calc_ipaddr *ipaddrp, MMDB_s *const mmdb, int *source_ptr) {
886 MMDB_lookup_result_s lookup_result;
887 MMDB_entry_data_s entry_data;
888 int mmdb_error = MMDB_INVALID_DATA_ERROR;
889 uint32_t result = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN;
890 int source = IPV6CALC_DB_GEO_GEONAMEID_TYPE_UNKNOWN;
891
892 int limit_24bit = 0;
893
894 if ((source_ptr != NULL) \
895 && ((*source_ptr & IPV6CALC_DB_GEO_GEONAMEID_TYPE_FLAG_MASK) == IPV6CALC_DB_GEO_GEONAMEID_TYPE_FLAG_24BIT)) {
896 limit_24bit = 1;
897 };
898
899 lookup_result = libipv6calc_db_wrapper_MMDB_wrapper_lookup_by_addr(ipaddrp, mmdb, &mmdb_error);
900
901 if (mmdb_error != MMDB_SUCCESS) {
902 goto END_libipv6calc_db_wrapper;
903 };
904
905 // fetch GeonameID (nearest to global)
906 // city
907 const char *lookup_path_city_geonameid[] = { "city", "geoname_id", NULL };
908 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_city_geonameid);
909 CHECK_STORE_UINT32(result, "City/GeonameId")
910 source = IPV6CALC_DB_GEO_GEONAMEID_TYPE_CITY;
911 if ((result != IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) && ((limit_24bit == 0) || (source < 0x1000000))) { goto END_libipv6calc_db_wrapper; };
912
913 // district
914 const char *lookup_path_district_geonameid[] = { "subdivisions", "1", "geoname_id", NULL };
915 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_district_geonameid);
916 CHECK_STORE_UINT32(result, "District(subdivision#1)/GeonameId")
917 source = IPV6CALC_DB_GEO_GEONAMEID_TYPE_DISTRICT;
918 if ((result != IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) && ((limit_24bit == 0) || (source < 0x1000000))) { goto END_libipv6calc_db_wrapper; };
919
920 // stateprov
921 const char *lookup_path_stateprov_geonameid[] = { "subdivisions", "0", "geoname_id", NULL };
922 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_stateprov_geonameid);
923 CHECK_STORE_UINT32(result, "State/Prov(subdivsion#0)/GeonameId")
924 source = IPV6CALC_DB_GEO_GEONAMEID_TYPE_STATEPROV;
925 if ((result != IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) && ((limit_24bit == 0) || (source < 0x1000000))) { goto END_libipv6calc_db_wrapper; };
926
927 // country
928 const char *lookup_path_country_geonameid[] = { "country", "geoname_id", NULL };
929 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_country_geonameid);
930 CHECK_STORE_UINT32(result, "Country/GeonameId")
931 source = IPV6CALC_DB_GEO_GEONAMEID_TYPE_COUNTRY;
932 if ((result != IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) && ((limit_24bit == 0) || (source < 0x1000000))) { goto END_libipv6calc_db_wrapper; };
933
934 // registered country (fallback)
935 const char *lookup_path_registered_country_geonameid[] = { "registered_country", "geoname_id", NULL };
936 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_registered_country_geonameid);
937 CHECK_STORE_UINT32(result, "RegisteredCountry/GeonameId")
938 source = IPV6CALC_DB_GEO_GEONAMEID_TYPE_COUNTRY;
939 if ((result != IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) && ((limit_24bit == 0) || (source < 0x1000000))) { goto END_libipv6calc_db_wrapper; };
940
941 // continent
942 const char *lookup_path_continent_geonameid[] = { "continent", "geoname_id", NULL };
943 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_continent_geonameid);
944 CHECK_STORE_UINT32(result, "Continent/GeonameId")
945 source = IPV6CALC_DB_GEO_GEONAMEID_TYPE_CONTINENT;
946 if ((result != IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) && ((limit_24bit == 0) || (source < 0x1000000))) { goto END_libipv6calc_db_wrapper; };
947
948 source = IPV6CALC_DB_GEO_GEONAMEID_TYPE_UNKNOWN;
949
950 END_libipv6calc_db_wrapper:
951 if (source_ptr != NULL) {
952 *source_ptr = source;
953 };
954 return(result);
955 };
956
957
958 /* all information by addr
959 * in : ipaddrp, recordp
960 * mod: recordp
961 * out: mmdb_error
962 */
libipv6calc_db_wrapper_MMDB_all_by_addr(const ipv6calc_ipaddr * ipaddrp,libipv6calc_db_wrapper_geolocation_record * recordp,MMDB_s * const mmdb)963 int libipv6calc_db_wrapper_MMDB_all_by_addr(const ipv6calc_ipaddr *ipaddrp, libipv6calc_db_wrapper_geolocation_record *recordp, MMDB_s *const mmdb) {
964 MMDB_lookup_result_s lookup_result;
965 MMDB_entry_data_s entry_data;
966 int mmdb_error;
967
968 static char resultstring[IPV6CALC_STRING_MAX];
969
970 libipv6calc_db_wrapper_geolocation_record_clear(recordp);
971
972 // convert ipaddrp into sockaddr
973 union sockaddr_u {
974 struct sockaddr_in in;
975 struct sockaddr_in6 in6;
976 struct sockaddr sockaddr;
977 } su;
978
979 if (ipaddrp->proto == 4) {
980 su.sockaddr.sa_family = AF_INET;
981 su.in.sin_addr.s_addr = htonl(ipaddrp->addr[0]);
982 } else if (ipaddrp->proto == 6) {
983 su.sockaddr.sa_family = AF_INET6;
984 #ifdef __KAME__ // FreeBSD misses s6_addr8/16/32 in non-kernel include, also union has different name in glibc (__in6_u vs. __u6_addr) :-(
985 su.in6.sin6_addr.__u6_addr.__u6_addr32[0] = htonl(ipaddrp->addr[0]);
986 su.in6.sin6_addr.__u6_addr.__u6_addr32[1] = htonl(ipaddrp->addr[1]);
987 su.in6.sin6_addr.__u6_addr.__u6_addr32[2] = htonl(ipaddrp->addr[2]);
988 su.in6.sin6_addr.__u6_addr.__u6_addr32[3] = htonl(ipaddrp->addr[3]);
989 #else
990 su.in6.sin6_addr.s6_addr32[0] = htonl(ipaddrp->addr[0]);
991 su.in6.sin6_addr.s6_addr32[1] = htonl(ipaddrp->addr[1]);
992 su.in6.sin6_addr.s6_addr32[2] = htonl(ipaddrp->addr[2]);
993 su.in6.sin6_addr.s6_addr32[3] = htonl(ipaddrp->addr[3]);
994 #endif
995 } else {
996 mmdb_error = MMDB_INVALID_DATA_ERROR;
997 goto END_libipv6calc_db_wrapper;
998 };
999
1000 lookup_result = libipv6calc_db_wrapper_MMDB_lookup_sockaddr(mmdb, &su.sockaddr, &mmdb_error);
1001
1002 if (mmdb_error != MMDB_SUCCESS) {
1003 ERRORPRINT_WA("Lookup results in error from MaxMindDB library: %s", libipv6calc_db_wrapper_MMDB_strerror(mmdb_error));
1004 goto END_libipv6calc_db_wrapper;
1005 };
1006
1007 // dump contents for debug
1008 DEBUGSECTION_BEGIN(DEBUG_libipv6calc_db_wrapper_MMDB)
1009 MMDB_entry_data_list_s *entry_data_list = NULL;
1010 int status = libipv6calc_db_wrapper_MMDB_get_entry_data_list(&lookup_result.entry, &entry_data_list);
1011
1012 if (status == MMDB_SUCCESS) {
1013 libipv6calc_db_wrapper_MMDB_dump_entry_data_list(stderr, entry_data_list, 2);
1014 };
1015 libipv6calc_db_wrapper_MMDB_free_entry_data_list(entry_data_list);
1016 DEBUGSECTION_END
1017
1018 // fetch CountryCode
1019 const char *lookup_path_country_code[] = { "country", "iso_code", NULL };
1020 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_country_code);
1021 if (!entry_data.has_data) {
1022 // fetch CountryCode (fallback)
1023 const char *lookup_path_registered_country_code[] = { "registered_country", "iso_code", NULL };
1024 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_registered_country_code);
1025 };
1026 CHECK_STORE(IPV6CALC_DB_SIZE_COUNTRY_CODE, recordp->country_code, "CountryCode")
1027
1028 // fetch CountryName
1029 const char *lookup_path_country_name[] = { "country", "names", "en", NULL };
1030 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_country_name);
1031 if (!entry_data.has_data) {
1032 // fetch CountryName (fallback)
1033 const char *lookup_path_registered_country_name[] = { "registered_country", "names", "en", NULL };
1034 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_registered_country_name);
1035 }
1036 CHECK_STORE(IPV6CALC_DB_SIZE_COUNTRY_LONG, recordp->country_long, "CountryName")
1037
1038 // fetch ContinentCode
1039 const char *lookup_path_continent_code[] = { "continent", "code", NULL };
1040 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_continent_code);
1041 CHECK_STORE(IPV6CALC_DB_SIZE_CONTINENT_CODE, recordp->continent_code, "ContinentCode")
1042
1043 // fetch ContinentName
1044 const char *lookup_path_continent_name[] = { "continent", "names", "en", NULL };
1045 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_continent_name);
1046 CHECK_STORE(IPV6CALC_DB_SIZE_CONTINENT_LONG, recordp->continent_long, "ContinentName")
1047
1048 // fetch Location Latitude/Longitude
1049 const char *lookup_path_location_latitude[] = { "location", "latitude", NULL };
1050 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_location_latitude);
1051 CHECK_STORE_DOUBLE(recordp->latitude, "Latitude")
1052
1053 const char *lookup_path_location_longitude[] = { "location", "longitude", NULL };
1054 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_location_longitude);
1055 CHECK_STORE_DOUBLE(recordp->longitude, "Longitude")
1056
1057 // fetch accuracy_radius
1058 const char *lookup_path_location_radius[] = { "location", "accuracy_radius", NULL };
1059 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_location_radius);
1060 CHECK_STORE_UINT16(recordp->accuracy_radius, "Radius")
1061
1062 // weather_code
1063 const char *lookup_path_location_weather_code[] = { "location", "weather_code", NULL };
1064 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_location_weather_code);
1065 CHECK_STORE(IPV6CALC_DB_SIZE_WEATHERSTATIONCODE, recordp->weatherstationcode, "WeatherStationCode")
1066
1067 // fetch City
1068 const char *lookup_path_city_name[] = { "city", "names", "en", NULL };
1069 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_city_name);
1070 CHECK_STORE(IPV6CALC_DB_SIZE_CITY, recordp->city, "City")
1071
1072 // fetch GeonameId of Continent
1073 const char *lookup_path_continent_geonameid[] = { "continent", "geoname_id", NULL };
1074 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_continent_geonameid);
1075 CHECK_STORE_UINT32(recordp->continent_geoname_id, "Continent/GeonameId")
1076
1077 // fetch GeonameId of Country
1078 const char *lookup_path_country_geonameid[] = { "country", "geoname_id", NULL };
1079 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_country_geonameid);
1080 if (!entry_data.has_data) {
1081 // fetch GeonameId of Country (fallback)
1082 const char *lookup_path_registered_country_geonameid[] = { "registered_country", "geoname_id", NULL };
1083 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_registered_country_geonameid);
1084 };
1085 CHECK_STORE_UINT32(recordp->country_geoname_id, "Country/GeonameId")
1086
1087 // fetch GeonameId of City
1088 const char *lookup_path_city_geonameid[] = { "city", "geoname_id", NULL };
1089 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_city_geonameid);
1090 CHECK_STORE_UINT32(recordp->geoname_id, "City/GeonameId")
1091
1092 // fetch postal code
1093 const char *lookup_path_zipcode[] = { "postal", "code", NULL };
1094 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_zipcode);
1095 CHECK_STORE(IPV6CALC_DB_SIZE_ZIPCODE, recordp->zipcode, "PostalCode")
1096
1097 // time zone
1098 const char *lookup_path_timezone[] = { "location", "time_zone", NULL };
1099 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_timezone);
1100 CHECK_STORE(IPV6CALC_DB_SIZE_TIMEZONE_NAME, recordp->timezone_name, "TimeZoneName")
1101
1102 // ISP
1103 const char *lookup_path_isp[] = { "traits", "isp", NULL };
1104 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_isp);
1105 CHECK_STORE(IPV6CALC_DB_SIZE_ISP_NAME, recordp->isp_name, "ISP")
1106
1107 // connection type
1108 const char *lookup_path_connection_type[] = { "traits", "connection_type", NULL };
1109 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_connection_type);
1110 CHECK_STORE(IPV6CALC_DB_SIZE_CONN_TYPE, recordp->connection_type, "ConnectionType")
1111
1112 // fetch ASN
1113 if(strstr(mmdb->metadata.database_type, "ASN")) {
1114 // GeoLite2-ASN
1115 const char *lookup_path_asn[] = { "autonomous_system_number", NULL };
1116 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_asn);
1117 } else {
1118 const char *lookup_path_asn[] = { "traits", "autonomous_system_number", NULL };
1119 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_asn);
1120 };
1121 CHECK_STORE_UINT32(recordp->asn, "Autonomous System Number");
1122
1123 // organization name
1124 if(strstr(mmdb->metadata.database_type, "ASN")) {
1125 // GeoLite2-ASN
1126 const char *lookup_path_organization_name[] = { "autonomous_system_organization", NULL };
1127 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_organization_name);
1128 } else {
1129 const char *lookup_path_organization_name[] = { "traits", "autonomous_system_organization", NULL };
1130 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_organization_name);
1131 };
1132 CHECK_STORE(IPV6CALC_DB_SIZE_ORG_NAME, recordp->organization_name, "AutonomousSystemOrganization")
1133
1134 // fetch StateProv / District (Subdivision) - which is a list
1135 const char *lookup_path_stateprov[] = { "subdivisions", "0", "names", "en", NULL };
1136 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_stateprov);
1137 CHECK_STORE(IPV6CALC_DB_SIZE_STATEPROV, recordp->stateprov, "State/Province(subdivision#0)")
1138
1139 const char *lookup_path_stateprov_geonameid[] = { "subdivisions", "0", "geoname_id", NULL };
1140 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_stateprov_geonameid);
1141 CHECK_STORE_UINT32(recordp->stateprov_geoname_id, "State/Prov(subdivsion#0)/GeonameId")
1142
1143 const char *lookup_path_distinct[] = { "subdivisions", "1", "names", "en", NULL };
1144 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_distinct);
1145 CHECK_STORE(IPV6CALC_DB_SIZE_DISTRICT, recordp->district, "District(subdivsion#1)")
1146
1147 const char *lookup_path_district_geonameid[] = { "subdivisions", "1", "geoname_id", NULL };
1148 libipv6calc_db_wrapper_MMDB_aget_value(&lookup_result.entry, &entry_data, lookup_path_district_geonameid);
1149 CHECK_STORE_UINT32(recordp->district_geoname_id, "District(subdivision#1)/GeonameId")
1150
1151 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_MMDB, "resultstring=%s", resultstring);
1152
1153 END_libipv6calc_db_wrapper:
1154 return(mmdb_error);
1155 };
1156
1157 #endif // MMDB
1158