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