1 /*
2  * Project    : ipv6calc
3  * File       : databases/lib/libipv6calc_db_wrapper.c
4  * Version    : $Id: 50e6b3f4ee6e3f28f90b5293245c24965a244062 $
5  * Copyright  : 2013-2021 by Peter Bieringer <pb (at) bieringer.de>
6  *
7  * Information:
8  *  ipv6calc database wrapper (for decoupling databases from main binary)
9  */
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <netinet/in.h>
17 
18 #include "config.h"
19 
20 #include "libipv6calcdebug.h"
21 #include "libipv6calc.h"
22 
23 #include "ipv6calcoptions.h"
24 
25 #include "libipv6calc_db_wrapper.h"
26 #include "libipv6calc_db_wrapper_MMDB.h"
27 #include "libipv6calc_db_wrapper_GeoIP2.h"
28 #include "libipv6calc_db_wrapper_IP2Location.h"
29 #include "libipv6calc_db_wrapper_DBIP2.h"
30 #include "libipv6calc_db_wrapper_External.h"
31 #include "libipv6calc_db_wrapper_BuiltIn.h"
32 
33 #ifdef DOMAIN
34 // fallback for IP2Location.h < 8.0.0 where "DOMAIN" is defined
35 // code taken from https://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c
uint64_log2(uint64_t n)36 static int uint64_log2(uint64_t n) {
37 	#define S(k) if (n >= (UINT64_C(1) << k)) { i += k; n >>= k; }
38 
39 	int i = -(n == 0); S(32); S(16); S(8); S(4); S(2); S(1); return i;
40 
41 	#undef S
42 };
43 #else
44 #include <math.h>
45 #define uint64_log2	log2
46 #endif
47 
48 #ifdef SUPPORT_IP2LOCATION
49 /*
50  * API_VERSION is defined as a bareword in IP2Location.h,
51  * we need this trick to stringify it. Blah.
52  */
53 #define makestr(x) #x
54 #define xmakestr(x) makestr(x)
55 #endif
56 
57 #ifdef SUPPORT_GEOIP2
58 static int wrapper_GeoIP2_disable      = 0;
59 static int wrapper_GeoIP2_status = 0;
60 #endif
61 
62 #ifdef SUPPORT_IP2LOCATION
63 static int wrapper_IP2Location_disable = 0;
64 static int wrapper_IP2Location_status = 0;
65 #endif
66 
67 #ifdef SUPPORT_DBIP2
68 static int wrapper_DBIP2_disable       = 0;
69 static int wrapper_DBIP2_status = 0;
70 #endif
71 
72 #ifdef SUPPORT_EXTERNAL
73 static int wrapper_External_disable    = 0;
74 static int wrapper_External_status = 0;
75 #endif
76 
77 #ifdef SUPPORT_BUILTIN
78 static int wrapper_BuiltIn_disable     = 0;
79 static int wrapper_BuiltIn_status = 0;
80 #endif
81 
82 uint32_t wrapper_features = 0;
83 uint32_t wrapper_features_by_source[IPV6CALC_DB_SOURCE_MAX + 1];
84 uint32_t wrapper_features_by_source_implemented[IPV6CALC_DB_SOURCE_MAX + 1];
85 
86 int wrapper_features_selector[IPV6CALC_DB_FEATURE_NUM_MAX + 1][IPV6CALC_DB_PRIO_MAX];
87 unsigned int wrapper_source_priority_selector[IPV6CALC_DB_SOURCE_MAX + 1];
88 int wrapper_source_priority_selector_by_option = -1; // -1: uninitialized, 0: initialized, > 0: touched by option
89 
90 
91 /*
92  * function initialise the main wrapper
93  *
94  * in : (nothing)
95  * out: 0=ok, 1=error
96  */
libipv6calc_db_wrapper_init(const char * prefix_string)97 int libipv6calc_db_wrapper_init(const char *prefix_string) {
98 	int result = 0, f, p, s, j;
99 
100 #if defined SUPPORT_IP2LOCATION || defined SUPPORT_EXTERNAL || defined SUPPORT_BUILTIN || defined SUPPORT_GEOIP2 || defined SUPPORT_DBIP2
101 	int r;
102 #endif
103 	s = strlen(prefix_string); // make compiler happy (avoid unused "...")
104 
105 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called");
106 
107 	// clear feature selector
108 	for (f = IPV6CALC_DB_FEATURE_NUM_MIN; f <= IPV6CALC_DB_FEATURE_NUM_MAX; f++) {
109 		for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
110 			wrapper_features_selector[f][p] = 0;
111 		};
112 	};
113 
114 	for (s = 0; s <= IPV6CALC_DB_SOURCE_MAX; s++) {
115 		wrapper_features_by_source[s] = 0;
116 	};
117 
118 	// initialize priority selector
119 	if (wrapper_source_priority_selector_by_option < 0) {
120 		for (s = 0; s <= IPV6CALC_DB_SOURCE_MAX; s++) {
121 			wrapper_source_priority_selector[s] = 0;
122 		};
123 		wrapper_source_priority_selector_by_option = 0;
124 	};
125 
126 	// initialize priority
127 	if (wrapper_source_priority_selector_by_option == 0) {
128 		// default
129 		for (s = IPV6CALC_DB_SOURCE_MIN; s <= IPV6CALC_DB_SOURCE_MAX; s++) {
130 			wrapper_source_priority_selector[s] = s;
131 		};
132 	} else {
133 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Database priorization already given by option, fill missing ones: %d", wrapper_source_priority_selector_by_option);
134 
135 		for (j = IPV6CALC_DB_SOURCE_MIN; j <= wrapper_source_priority_selector_by_option; j++) {
136 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Database priorization/defined by option entry %d: %s", j, libipv6calc_db_wrapper_get_data_source_name_by_number(wrapper_source_priority_selector[j]));
137 		};
138 
139 		// already touched by option, fill not mentioned ones
140 		for (j = 0; j < MAXENTRIES_ARRAY(data_sources); j++) {
141 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Database priorization/test source: %s", data_sources[j].shortname);
142 			for (s = IPV6CALC_DB_SOURCE_MIN; s <= wrapper_source_priority_selector_by_option; s++) {
143 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Database priorization/check: %s", libipv6calc_db_wrapper_get_data_source_name_by_number(wrapper_source_priority_selector[s]));
144 				if (wrapper_source_priority_selector[s] == data_sources[j].number) {
145 					DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Database priorization/source already defined: %s", data_sources[j].shortname);
146 					// already set, skip
147 					break;
148 				};
149 			};
150 
151 			if (s > wrapper_source_priority_selector_by_option) {
152 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Database priorization/source missing, add: %s", data_sources[j].shortname);
153 				wrapper_source_priority_selector_by_option++;
154 				wrapper_source_priority_selector[wrapper_source_priority_selector_by_option] = data_sources[j].number;
155 			};
156 		};
157 	};
158 
159 	for (j = IPV6CALC_DB_SOURCE_MIN; j <= wrapper_source_priority_selector_by_option; j++) {
160 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Database priorization/defined by option entry %d: %s", j, libipv6calc_db_wrapper_get_data_source_name_by_number(wrapper_source_priority_selector[j]));
161 	};
162 
163 #ifdef SUPPORT_MMDB
164 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call libipv6calc_db_wrapper_MMDB_wrapper_init");
165 	r = libipv6calc_db_wrapper_MMDB_wrapper_init();
166 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "MMDB_wrapper_init result: %d", r);
167 	if (r != 0) {
168 #ifndef SUPPORT_MMDB_DYN
169 		// only non-dynamic-load results in a problem
170 		result = 1;
171 #endif
172 		// disable support for GEOIP2 & DBIP2
173 #ifdef SUPPORT_GEOIP2
174 		wrapper_GeoIP2_disable = r;
175 #endif
176 #ifdef SUPPORT_DBIP2
177 		wrapper_DBIP2_disable = r;
178 #endif
179 	};
180 #else
181 	// disable support for GEOIP2 & DBIP2
182 #ifdef SUPPORT_GEOIP2
183 	wrapper_GeoIP2_disable = 3;
184 #endif
185 #ifdef SUPPORT_DBIP2
186 	wrapper_DBIP2_disable = 3;
187 #endif
188 #endif
189 
190 #ifdef SUPPORT_GEOIP2
191 	if (wrapper_GeoIP2_disable == 0) {
192 		// Call GeoIP2 wrapper
193 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call libipv6calc_db_wrapper_GeoIP2_wrapper_init");
194 
195 		r = libipv6calc_db_wrapper_GeoIP2_wrapper_init();
196 
197 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "GeoIP2_wrapper_init result: %d wrapper_features=0x%08x", r, wrapper_features);
198 
199 		if (r != 0) {
200 #ifndef SUPPORT_MMDB_DYN
201 			// only non-dynamic-load results in a problem
202 			result = 1;
203 #endif
204 		} else {
205 			wrapper_GeoIP2_status = 1; // ok
206 		};
207 	} else if (wrapper_GeoIP2_disable == 1) {
208 		NONQUIETPRINT_WA("%sSupport for GeoIP (MaxMindDB) disabled by option", prefix_string);
209 	} else if (wrapper_GeoIP2_disable == 2) {
210 #ifdef SUPPORT_MMDB_DYN
211 		NONQUIETPRINT_WA("%sSupport for GeoIP (MaxMindDB) disabled, no MaxMindDB library found: %s", prefix_string, mmdb_lib_file);
212 #endif
213 	} else {
214 #ifdef SUPPORT_MMDB_DYN
215 		NONQUIETPRINT_WA("%sSupport for GeoIP (MaxMindDB) disabled by MaxMindDB library problem: %s", prefix_string, mmdb_lib_file);
216 #endif
217 	};
218 #endif // SUPPORT_GEOIP2
219 
220 #ifdef SUPPORT_IP2LOCATION
221 	if (wrapper_IP2Location_disable == 0) {
222 		// Call IP2Location wrapper
223 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call libipv6calc_db_wrapper_IP2Location_wrapper_init");
224 
225 		r = libipv6calc_db_wrapper_IP2Location_wrapper_init();
226 
227 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "IP2Location_wrapper_init result: %d wrapper_features=0x%08x", r, wrapper_features);
228 
229 		if (r != 0) {
230 #ifndef SUPPORT_IP2LOCATION_DYN
231 			// only non-dynamic-load results in a problem
232 			result = 1;
233 #endif
234 		} else {
235 			wrapper_IP2Location_status = 1; // ok
236 		};
237 	} else {
238 		NONQUIETPRINT_WA("%sSupport for IP2Location disabled by option", prefix_string);
239 	};
240 #endif // SUPPORT_IP2LOCATION
241 
242 #ifdef SUPPORT_DBIP2
243 	if (wrapper_DBIP2_disable == 0) {
244 		// Call DBIP2 wrapper
245 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call libipv6calc_db_wrapper_DBIP2_wrapper_init");
246 
247 		r = libipv6calc_db_wrapper_DBIP2_wrapper_init();
248 
249 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "DBIP2_wrapper_init result: %d wrapper_features=0x%08x", r, wrapper_features);
250 
251 		if (r != 0) {
252 #ifndef SUPPORT_MMDB_DYN
253 			// only non-dynamic-load results in a problem
254 			result = 1;
255 #endif
256 		} else {
257 			wrapper_DBIP2_status = 1; // ok
258 		};
259 	} else if (wrapper_DBIP2_disable == 1) {
260 		NONQUIETPRINT_WA("%sSupport for db-ip.com (MaxMindDB) disabled by option", prefix_string);
261 	} else if (wrapper_DBIP2_disable == 2) {
262 #ifdef SUPPORT_MMDB_DYN
263 		NONQUIETPRINT_WA("%sSupport for db-ip.com (MaxMindDB) disabled, no MaxMindDB library found: %s", prefix_string, mmdb_lib_file);
264 #endif
265 	} else {
266 #ifdef SUPPORT_MMDB_DYN
267 		NONQUIETPRINT_WA("%sSupport for db-ip.com (MaxMindDB) disabled by MaxMindDB library problem: %s", prefix_string, mmdb_lib_file);
268 #endif
269 	};
270 #endif // SUPPORT_DBIP2
271 
272 #ifdef SUPPORT_EXTERNAL
273 	if (wrapper_External_disable == 0) {
274 		// Call External wrapper
275 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call libipv6calc_db_wrapper_External_wrapper_init");
276 
277 		r = libipv6calc_db_wrapper_External_wrapper_init();
278 
279 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "External_wrapper_init result: %d wrapper_features=0x%08x", r, wrapper_features);
280 
281 		if (r != 0) {
282 			result = 1;
283 		} else {
284 			wrapper_External_status = 1; // ok
285 		};
286 	} else {
287 		NONQUIETPRINT_WA("%sSupport for External disabled by option", prefix_string);
288 	};
289 #endif // SUPPORT_EXTERNAL
290 
291 #ifdef SUPPORT_BUILTIN
292 	if (wrapper_BuiltIn_disable == 0) {
293 		// Call BuiltIn wrapper
294 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call libipv6calc_db_wrapper_BuiltIn_wrapper_init");
295 
296 		r = libipv6calc_db_wrapper_BuiltIn_wrapper_init();
297 
298 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "BuiltIn_wrapper_init result: %d wrapper_features=0x%08x", r, wrapper_features);
299 
300 		if (r != 0) {
301 			result = 1;
302 		} else {
303 			wrapper_BuiltIn_status = 1; // ok
304 		};
305 	};
306 #endif // SUPPORT_BUILTIN
307 
308 	// select source for feature by standard priority (from last to first in list)
309 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "select source for feature by standard priority");
310 	// run through feature numbers
311 	for (f = IPV6CALC_DB_FEATURE_NUM_MIN; f <= IPV6CALC_DB_FEATURE_NUM_MAX; f++) {
312 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "check feature f=%d", f);
313 		// run through sources
314 		int sp;
315 		for (sp = IPV6CALC_DB_SOURCE_MIN; sp <= IPV6CALC_DB_SOURCE_MAX; sp++) {
316 			s = wrapper_source_priority_selector[sp];
317 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "check feature by source f=%d s=%d sp=%d", f, s, sp);
318 			if ((wrapper_features_by_source[s] & (1 << f)) != 0) {
319 				// supported, run through prio array
320 				for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
321 					if (wrapper_features_selector[f][p] == 0) {
322 						DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "select feature with source f=%d s=%d p=%d", f, s, p);
323 						wrapper_features_selector[f][p] = s;
324 						break;
325 					} else {
326 #if defined SUPPORT_BUILTIN && defined SUPPORT_EXTERNAL
327 						// special handling for BuiltIn/External (no subsequent calls)
328 						if ((wrapper_BuiltIn_disable == 0) && (wrapper_External_disable == 0)) {
329 							// IPv4 -> Registry
330 							if (((1 << f) == IPV6CALC_DB_IPV4_TO_REGISTRY) && \
331 								( (s == IPV6CALC_DB_SOURCE_BUILTIN && (wrapper_features_selector[f][p] == IPV6CALC_DB_SOURCE_EXTERNAL)) \
332 								  || (s == IPV6CALC_DB_SOURCE_EXTERNAL && (wrapper_features_selector[f][p] == IPV6CALC_DB_SOURCE_BUILTIN))
333 								)) {
334 									// BuiltIn & External have feature enabled and one of them is already selected for p=0
335 									time_t db_unixtime_BuiltIn  = libipv6calc_db_wrapper_BuiltIn_db_unixtime_by_feature(IPV6CALC_DB_IPV4_TO_REGISTRY);
336 									time_t db_unixtime_External = libipv6calc_db_wrapper_External_db_unixtime_by_feature(IPV6CALC_DB_IPV4_TO_REGISTRY);
337 
338 									if ((db_unixtime_BuiltIn > 0) && (db_unixtime_External > 0)) {
339 										if (db_unixtime_BuiltIn < db_unixtime_External) {
340 											wrapper_features_selector[f][p] = IPV6CALC_DB_SOURCE_EXTERNAL;
341 											DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "BuiltIn has older DB than External for IPV6CALC_DB_IPV4_TO_REGISTRY");
342 										} else {
343 											wrapper_features_selector[f][p] = IPV6CALC_DB_SOURCE_BUILTIN;
344 											DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "External has older DB than BuiltIn for IPV6CALC_DB_IPV4_TO_REGISTRY");
345 									};
346 									break; // no further extension of priority list
347 								};
348 							};
349 
350 							// IPv6 -> Registry
351 							if (((1 << f) == IPV6CALC_DB_IPV6_TO_REGISTRY) && \
352 								( (s == IPV6CALC_DB_SOURCE_BUILTIN && (wrapper_features_selector[f][p] == IPV6CALC_DB_SOURCE_EXTERNAL)) \
353 								  || (s == IPV6CALC_DB_SOURCE_EXTERNAL && (wrapper_features_selector[f][p] == IPV6CALC_DB_SOURCE_BUILTIN))
354 								)) {
355 									// BuiltIn & External have feature enabled and one of them is already selected for p=0
356 									time_t db_unixtime_BuiltIn  = libipv6calc_db_wrapper_BuiltIn_db_unixtime_by_feature(IPV6CALC_DB_IPV6_TO_REGISTRY);
357 									time_t db_unixtime_External = libipv6calc_db_wrapper_External_db_unixtime_by_feature(IPV6CALC_DB_IPV6_TO_REGISTRY);
358 
359 									if ((db_unixtime_BuiltIn > 0) && (db_unixtime_External > 0)) {
360 										if (db_unixtime_BuiltIn < db_unixtime_External) {
361 											wrapper_features_selector[f][p] = IPV6CALC_DB_SOURCE_EXTERNAL;
362 											DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "BuiltIn has older DB than External for IPV6CALC_DB_IPV6_TO_REGISTRY");
363 										} else {
364 											wrapper_features_selector[f][p] = IPV6CALC_DB_SOURCE_BUILTIN;
365 											DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "External has older DB than BuiltIn for IPV6CALC_DB_IPV6_TO_REGISTRY");
366 									};
367 									break; // no further extension of priority list
368 								};
369 							};
370 						};
371 #endif // SUPPORT_BUILTIN && SUPPORT_EXTERNAL
372 					};
373 				};
374 			};
375 		};
376 	};
377 
378 #ifdef TEST
379 #if defined SUPPORT_BUILTIN && defined SUPPORT_EXTERNAL
380 	// IPv4 -> Registry
381 	if ((wrapper_BuiltIn_status == 1) && (wrapper_External_status == 1)) {
382 		if (libipv6calc_db_wrapper_External_has_features(IPV6CALC_DB_IPV4_TO_REGISTRY) == 1 \
383 			&& libipv6calc_db_wrapper_BuiltIn_has_features(IPV6CALC_DB_IPV4_TO_REGISTRY) == 1) {
384 			// BuiltIn & External have feature enabled (both)
385 			time_t db_unixtime_BuiltIn  = libipv6calc_db_wrapper_BuiltIn_db_unixtime_by_feature(IPV6CALC_DB_IPV4_TO_REGISTRY);
386 			time_t db_unixtime_External = libipv6calc_db_wrapper_External_db_unixtime_by_feature(IPV6CALC_DB_IPV4_TO_REGISTRY);
387 
388 			if ((db_unixtime_BuiltIn > 0) && (db_unixtime_External > 0)) {
389 				if (db_unixtime_BuiltIn < db_unixtime_External) {
390 					wrapper_features_selector[IPV6CALC_DB_FEATURE_NUM_IPV4_TO_REGISTRY][0] = IPV6CALC_DB_SOURCE_EXTERNAL;
391 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "BuiltIn has older DB than External for IPV6CALC_DB_IPV4_TO_REGISTRY, disable it further");
392 				} else {
393 					wrapper_features_selector[IPV6CALC_DB_FEATURE_NUM_IPV4_TO_REGISTRY][0] = IPV6CALC_DB_SOURCE_BUILTIN;
394 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "External has older DB than BuiltIn for IPV6CALC_DB_IPV4_TO_REGISTRY, disable it further");
395 				};
396 			};
397 		};
398 	};
399 #endif // SUPPORT_BUILTIN && SUPPORT_EXTERNAL
400 #endif
401 
402 	return(result);
403 };
404 
405 
406 /*
407  * function cleanup the main wrapper
408  *
409  * in : (nothing)
410  * out: 0=ok, 1=error
411  */
libipv6calc_db_wrapper_cleanup(void)412 int libipv6calc_db_wrapper_cleanup(void) {
413 	int result = 0;
414 
415 #if defined SUPPORT_IP2LOCATION || defined SUPPORT_EXTERNAL || defined SUPPORT_BUILTIN || defined SUPPORT_GEOIP2 || defined SUPPORT_DBIP2
416 	int r;
417 #endif
418 
419 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called");
420 
421 #ifdef SUPPORT_GEOIP2
422 	if (wrapper_GeoIP2_disable == 0) {
423 		// Call GeoIP2 wrapper
424 		r = libipv6calc_db_wrapper_GeoIP2_wrapper_cleanup();
425 		if (r != 0) {
426 			result = 1;
427 		};
428 	};
429 #endif
430 
431 #ifdef SUPPORT_IP2LOCATION
432 	if (wrapper_IP2Location_disable == 0) {
433 		// Call IP2Location wrapper
434 		r = libipv6calc_db_wrapper_IP2Location_wrapper_cleanup();
435 		if (r != 0) {
436 			result = 1;
437 		};
438 	};
439 #endif
440 
441 #ifdef SUPPORT_DBIP2
442 	if (wrapper_DBIP2_disable == 0) {
443 		// Call DBIP2 wrapper
444 		r = libipv6calc_db_wrapper_DBIP2_wrapper_cleanup();
445 		if (r != 0) {
446 			result = 1;
447 		};
448 	};
449 #endif
450 
451 #ifdef SUPPORT_EXTERNAL
452 	if (wrapper_External_disable == 0) {
453 		// Call DBIP2 wrapper
454 		r = libipv6calc_db_wrapper_External_wrapper_cleanup();
455 		if (r != 0) {
456 			result = 1;
457 		};
458 	};
459 #endif
460 
461 #ifdef SUPPORT_BUILTIN
462 	if (wrapper_BuiltIn_disable == 0) {
463 		// Call BuiltIn wrapper
464 		r = libipv6calc_db_wrapper_BuiltIn_wrapper_cleanup();
465 		if (r != 0) {
466 			result = 1;
467 		};
468 	};
469 #endif
470 
471 	return(result);
472 };
473 
474 
475 /* function get info strings */
libipv6calc_db_wrapper_info(char * string,const size_t size)476 void libipv6calc_db_wrapper_info(char *string, const size_t size) {
477 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called");
478 
479 	snprintf(string, size, "%s", ""); // default empty
480 
481 #ifdef SUPPORT_GEOIP2
482 	if (wrapper_GeoIP2_disable == 0) {
483 		// Call GeoIP2 wrapper
484 		libipv6calc_db_wrapper_GeoIP2_wrapper_info(string, size);
485 	};
486 #endif
487 
488 #ifdef SUPPORT_IP2LOCATION
489 	if (wrapper_IP2Location_disable == 0) {
490 		// Call IP2Location wrapper
491 		libipv6calc_db_wrapper_IP2Location_wrapper_info(string, size);
492 	};
493 #endif
494 
495 #ifdef SUPPORT_DBIP2
496 	if (wrapper_DBIP2_disable == 0) {
497 		// Call DBIP2 wrapper
498 		libipv6calc_db_wrapper_DBIP2_wrapper_info(string, size);
499 	};
500 #endif
501 
502 #ifdef SUPPORT_EXTERNAL
503 	if (wrapper_External_disable == 0) {
504 		// Call BuiltIn wrapper
505 		libipv6calc_db_wrapper_External_wrapper_info(string, size);
506 	};
507 #endif
508 
509 #ifdef SUPPORT_BUILTIN
510 	if (wrapper_BuiltIn_disable == 0) {
511 		// Call BuiltIn wrapper
512 		libipv6calc_db_wrapper_BuiltIn_wrapper_info(string, size);
513 	};
514 #endif
515 
516 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: %s", string);
517 
518 	return;
519 };
520 
521 
522 /* function get feature string */
libipv6calc_db_wrapper_features(char * string,const size_t size)523 void libipv6calc_db_wrapper_features(char *string, const size_t size) {
524 	int i;
525 	char tempstring[IPV6CALC_STRING_MAX];
526 	char *separator;
527 
528 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called");
529 
530 	for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_db_features); i++) {
531 		if (wrapper_features & ipv6calc_db_features[i].number) {
532 			if (strlen(string) == 0) {
533 				separator = "";
534 			} else {
535 				separator = " ";
536 			};
537 			snprintf(tempstring, sizeof(tempstring), "%s%s%s", string, separator, ipv6calc_db_features[i].token);
538 			snprintf(string, size, "%s", tempstring);
539 		};
540 	};
541 
542 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Return");
543 
544 	return;
545 };
546 
547 
548 /* function get capability string */
libipv6calc_db_wrapper_capabilities(char * string,const size_t size)549 void libipv6calc_db_wrapper_capabilities(char *string, const size_t size) {
550 #if defined SUPPORT_IP2LOCATION || defined SUPPORT_EXTERNAL || defined SUPPORT_BUILTIN || defined SUPPORT_GEOIP2 || defined SUPPORT_DBIP2
551 	char tempstring[IPV6CALC_STRING_MAX];
552 #endif
553 
554 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called");
555 
556 	snprintf(string, size, "%s", ""); // default empty
557 
558 #ifdef SUPPORT_GEOIP2
559 	if (wrapper_GeoIP2_disable == 0) {
560 #ifdef SUPPORT_MMDB_DYN
561 		snprintf(tempstring, sizeof(tempstring), "%s%sGeoIP2(dyn-load/MaxMindDB)", string, strlen(string) > 0 ? " " : "");
562 #else
563 		snprintf(tempstring, sizeof(tempstring), "%s%sGeoIP2(linked/MaxMindDB)", string, strlen(string) > 0 ? " " : "");
564 #endif // SUPPORT_MMDB_DYN
565 		snprintf(string, size, "%s", tempstring);
566 	};
567 #endif // SUPPORT_GEOIP2
568 
569 #ifdef SUPPORT_IP2LOCATION
570 	if (wrapper_IP2Location_disable == 0) {
571 #ifdef SUPPORT_IP2LOCATION_DYN
572 		snprintf(tempstring, sizeof(tempstring), "%s%sIP2Location(dyn-load)", string, strlen(string) > 0 ? " " : "");
573 #else // SUPPORT_IP2LOCATION_DYN
574 #ifdef SUPPORT_IP2LOCATION_STATIC
575 		snprintf(tempstring, sizeof(tempstring), "%s%sIP2Location(static)", string, strlen(string) > 0 ? " " : "");
576 #else // SUPPORT_IP2LOCATION_STATIC
577 		snprintf(tempstring, sizeof(tempstring), "%s%sIP2Location(linked)", string, strlen(string) > 0 ? " " : "");
578 #endif // SUPPORT_IP2LOCATION_STATIC
579 #endif //SUPPORT_IP2LOCATION_DYN
580 		snprintf(string, size, "%s", tempstring);
581 	};
582 #endif // SUPPORT_IP2LOCATION
583 
584 #ifdef SUPPORT_DBIP2
585 	if (wrapper_DBIP2_disable == 0) {
586 #ifdef SUPPORT_MMDB_DYN
587 		snprintf(tempstring, sizeof(tempstring), "%s%sDBIP2(dyn-load/MaxMindDB)", string, strlen(string) > 0 ? " " : "");
588 #else
589 		snprintf(tempstring, sizeof(tempstring), "%s%sDBIP2(linked/MaxMindDB)", string, strlen(string) > 0 ? " " : "");
590 #endif
591 		snprintf(string, size, "%s", tempstring);
592 	};
593 #endif
594 
595 #ifdef SUPPORT_EXTERNAL
596 	if (wrapper_External_disable == 0) {
597 		snprintf(tempstring, sizeof(tempstring), "%s%sExternalDatabase", string, strlen(string) > 0 ? " " : "");
598 		snprintf(string, size, "%s", tempstring);
599 	};
600 #endif
601 
602 #ifdef SUPPORT_BUILTIN
603 	if (wrapper_BuiltIn_disable == 0) {
604 		snprintf(tempstring, sizeof(tempstring), "%s%sDB_AS_REG(BuiltIn)", string, strlen(string) > 0 ? " " : "");
605 		snprintf(string, size, "%s", tempstring);
606 		snprintf(tempstring, sizeof(tempstring), "%s%sDB_CC_REG(BuiltIn)", string, strlen(string) > 0 ? " " : "");
607 		snprintf(string, size, "%s", tempstring);
608 
609 #ifdef SUPPORT_DB_IPV4_REG
610 		snprintf(tempstring, sizeof(tempstring), "%s%sDB_IPV4_REG(BuiltIn)", string, strlen(string) > 0 ? " " : "");
611 		snprintf(string, size, "%s", tempstring);
612 #endif
613 
614 #ifdef SUPPORT_DB_IPV6_REG
615 		snprintf(tempstring, sizeof(tempstring), "%s%sDB_IPV6_REG(BuiltIn)", string, strlen(string) > 0 ? " " : "");
616 		snprintf(string, size, "%s", tempstring);
617 #endif
618 
619 #ifdef SUPPORT_DB_IEEE
620 		snprintf(tempstring, sizeof(tempstring), "%s%sDB_IEEE(BuiltIn)", string, strlen(string) > 0 ? " " : "");
621 		snprintf(string, size, "%s", tempstring);
622 #endif
623 	};
624 #endif // SUPPORT_BUILTIN
625 
626 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: %s", string);
627 
628 	return;
629 };
630 
631 /* function print wrapper features */
libipv6calc_db_wrapper_print_features_verbose(const int level_verbose)632 void libipv6calc_db_wrapper_print_features_verbose(const int level_verbose) {
633 #if defined SUPPORT_IP2LOCATION || defined SUPPORT_EXTERNAL || defined SUPPORT_BUILTIN || defined SUPPORT_GEOIP2 || defined SUPPORT_DBIP2
634 	char string[IPV6CALC_STRING_MAX] = "";
635 #endif
636 
637 #ifdef SUPPORT_MMDB
638 #ifdef MMDB_INCLUDE_VERSION
639 	fprintf(stderr, "MaxMindDB for GeoIP2/DBIP2 support enabled, compiled with include file version: %s\n", MMDB_INCLUDE_VERSION);
640 #else
641 	fprintf(stderr, "MaxMindDB for GeoIP2/DBIP2 support enabled\n");
642 #endif // MMDB_INCLUDE_VERSION
643 #ifndef SUPPORT_MMDB_DYN
644 	fprintf(stderr, "MaxMindDB dynamic library version (on this system): %s\n\n", libipv6calc_db_wrapper_MMDB_lib_version());
645 #else
646 	fprintf(stderr, "MaxMindDB configured dynamic library file and detected version: %s %s\n\n", mmdb_lib_file, libipv6calc_db_wrapper_MMDB_lib_version());
647 #endif // SUPPORT_MMDB_DYN
648 #endif
649 
650 #ifdef SUPPORT_GEOIP2
651 	if (wrapper_GeoIP2_disable == 0) {
652 		fprintf(stderr, "GeoIP2 (MaxMindDB) support enabled\n");
653 		libipv6calc_db_wrapper_GeoIP2_wrapper_info(string, sizeof(string));
654 		fprintf(stderr, "%s\n\n", string);
655 	} else if (wrapper_GeoIP2_disable == 1) {
656 		fprintf(stderr, "GeoIP2 (MaxMindDB) disabled by option\n\n");
657 	} else {
658 		fprintf(stderr, "GeoIP2 (MaxMindDB) disabled by MaxMindDB library problem\n\n");
659 	};
660 #else
661 	fprintf(stderr, "GeoIP2 (MaxMindDB) support not compiled-in\n\n");
662 #endif
663 
664 #ifdef SUPPORT_IP2LOCATION
665 	if (wrapper_IP2Location_disable == 0) {
666 #ifdef IP2LOCATION_INCLUDE_VERSION
667 		fprintf(stderr, "IP2Location support enabled, compiled with include file version: %s\n", IP2LOCATION_INCLUDE_VERSION);
668 #endif
669 		fprintf(stderr, "IP2Location support enabled, compiled with API version: %s, dynamically linked with version: %s\n", xmakestr(API_VERSION), libipv6calc_db_wrapper_IP2Location_lib_version());
670 #ifndef SUPPORT_IP2LOCATION_DYN
671 #else
672 		fprintf(stderr, "IP2Location support by dynamic library load\n");
673 		fprintf(stderr, "IP2Location configured dynamic library file and detected version: %s %s\n", ip2location_lib_file, libipv6calc_db_wrapper_IP2Location_lib_version());
674 #endif
675 		libipv6calc_db_wrapper_IP2Location_wrapper_info(string, sizeof(string));
676 		fprintf(stderr, "%s\n\n", string);
677 	} else {
678 		fprintf(stderr, "IP2Location disabled by option\n\n");
679 	};
680 #else
681 	fprintf(stderr, "IP2Location support not compiled-in\n\n");
682 #endif
683 
684 #ifdef SUPPORT_DBIP2
685 	if (wrapper_DBIP2_disable == 0) {
686 		fprintf(stderr, "DBIP2 (MaxMindDB) support enabled\n");
687 		libipv6calc_db_wrapper_DBIP2_wrapper_info(string, sizeof(string));
688 		fprintf(stderr, "%s\n\n", string);
689 	} else if (wrapper_DBIP2_disable == 1) {
690 		fprintf(stderr, "DBIP2 support disabled by option\n\n");
691 	} else {
692 		fprintf(stderr, "DBIP2 (MaxMindDB) disabled by MaxMindDB library problem\n\n");
693 	};
694 #else
695 	fprintf(stderr, "DBIP2 support not compiled-in\n\n");
696 #endif
697 
698 #ifdef SUPPORT_EXTERNAL
699 	if (wrapper_External_disable == 0) {
700 		libipv6calc_db_wrapper_External_wrapper_info(string, sizeof(string));
701 		fprintf(stderr, "%s\n\n", string);
702 	} else {
703 		fprintf(stderr, "External database support disabled by option\n\n");
704 	};
705 #else
706 	fprintf(stderr, "External database support not compiled-in\n\n");
707 #endif
708 
709 #ifdef SUPPORT_BUILTIN
710 	if (wrapper_BuiltIn_disable == 0) {
711 		libipv6calc_db_wrapper_BuiltIn_wrapper_info(string, sizeof(string));
712 		fprintf(stderr, "%s\n\n", string);
713 	} else {
714 		fprintf(stderr, "BuiltIn database support disabled by option\n\n");
715 	};
716 #else
717 	fprintf(stderr, "BuiltIn database support not compiled-in\n\n");
718 #endif
719 
720 	libipv6calc_db_wrapper_print_db_info(level_verbose, "");
721 };
722 
723 
724 /* function get source name by number
725  * in: source number
726  * out: source name
727  */
libipv6calc_db_wrapper_get_data_source_name_by_number(const unsigned int number)728 const char *libipv6calc_db_wrapper_get_data_source_name_by_number(const unsigned int number) {
729 	int i;
730 
731 	for (i = 0; i < MAXENTRIES_ARRAY(data_sources); i++) {
732 		if (data_sources[i].number == number) {
733 			return(data_sources[i].name);
734 		};
735 	};
736 
737 	ERRORPRINT_WA("unsupported data_source number: %d (FIX CODE)\n", number);
738 	exit(1);
739 };
740 
741 
742 /* function get feature index by number
743  * in: feature number
744  * out: index
745  */
libipv6calc_db_wrapper_get_feature_index_by_feature(const uint32_t feature)746 static int libipv6calc_db_wrapper_get_feature_index_by_feature(const uint32_t feature) {
747 	int i;
748 
749 	for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_db_features); i++) {
750 		if (ipv6calc_db_features[i].number == feature) {
751 			return(i);
752 		};
753 	};
754 
755 	ERRORPRINT_WA("unsupported feature: %d (FIX CODE)\n", feature);
756 	exit(1);
757 };
758 
759 
760 
761 /* function print feature string help */
libipv6calc_db_wrapper_features_help(void)762 void libipv6calc_db_wrapper_features_help(void) {
763 	int i, s, first;
764 
765 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called");
766 
767 	for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_db_features); i++) {
768 		fprintf(stderr, "%-25s%c %s", ipv6calc_db_features[i].token, (wrapper_features & ipv6calc_db_features[i].number) ? 'x' : 'o', ipv6calc_db_features[i].explanation);
769 
770 		first = 1;
771 		for (s = IPV6CALC_DB_SOURCE_MIN; s <= IPV6CALC_DB_SOURCE_MAX; s++) {
772 			if ((wrapper_features_by_source_implemented[s] & ipv6calc_db_features[i].number) != 0) {
773 				fprintf(stderr, "%s%s", (first == 1) ? " (provided by " : ",", libipv6calc_db_wrapper_get_data_source_name_by_number(s));
774 				first = 0;
775 			};
776 		};
777 		fprintf(stderr, "%s\n", (first == 1) ? "" : ")");
778 	};
779 
780 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Return");
781 
782 	return;
783 
784 
785 };
786 
787 
788 /* function print db info */
libipv6calc_db_wrapper_print_db_info(const int level_verbose,const char * prefix_string)789 void libipv6calc_db_wrapper_print_db_info(const int level_verbose, const char *prefix_string) {
790 	int f, p, f_index;
791 
792 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called with verbose level: %d", level_verbose);
793 
794 	fprintf(stderr, "%sDB features: 0x%08x\n\n", prefix_string, wrapper_features);
795 
796 #ifdef SUPPORT_GEOIP2
797 	if (wrapper_GeoIP2_disable == 0) {
798 		// Call GeoIP2 wrapper
799 		libipv6calc_db_wrapper_GeoIP2_wrapper_print_db_info(level_verbose, prefix_string);
800 	} else if (wrapper_GeoIP2_disable == 1) {
801 		fprintf(stderr, "%sGeoIP (MaxMindDB) support available but disabled by option\n", prefix_string);
802 	} else {
803 		fprintf(stderr, "%sGeoIP (MaxMindDB) support available but disabled by MaxMindDB library problem\n", prefix_string);
804 	};
805 	fprintf(stderr, "\n");
806 #endif
807 
808 #ifdef SUPPORT_IP2LOCATION
809 	if (wrapper_IP2Location_disable == 0) {
810 		// Call IP2Location wrapper
811 		libipv6calc_db_wrapper_IP2Location_wrapper_print_db_info(level_verbose, prefix_string);
812 	} else {
813 		fprintf(stderr, "%sIP2Location support available but disabled by option\n", prefix_string);
814 	};
815 	fprintf(stderr, "\n");
816 #endif
817 
818 #ifdef SUPPORT_DBIP2
819 	if (wrapper_DBIP2_disable == 0) {
820 		// Call DBIP2 wrapper
821 		libipv6calc_db_wrapper_DBIP2_wrapper_print_db_info(level_verbose, prefix_string);
822 	} else if (wrapper_DBIP2_disable == 1) {
823 		fprintf(stderr, "%sdb-ip.com (MaxMindDB) support available but disabled by option\n", prefix_string);
824 	} else {
825 		fprintf(stderr, "%sdb-ip.com (MaxMindDB) support available but disabled by MaxMindDB library problem\n", prefix_string);
826 	};
827 	fprintf(stderr, "\n");
828 #endif
829 
830 #ifdef SUPPORT_EXTERNAL
831 	if (wrapper_External_disable == 0) {
832 		// Call External wrapper
833 		libipv6calc_db_wrapper_External_wrapper_print_db_info(level_verbose, prefix_string);
834 	} else {
835 		fprintf(stderr, "%sExternal support available but disabled by option\n", prefix_string);
836 	};
837 	fprintf(stderr, "\n");
838 #endif
839 
840 #ifdef SUPPORT_BUILTIN
841 	if (wrapper_BuiltIn_disable == 0) {
842 		// Call BuiltIn wrapper
843 		libipv6calc_db_wrapper_BuiltIn_wrapper_print_db_info(level_verbose, prefix_string);
844 	} else {
845 		fprintf(stderr, "%sBuiltIn support available but disabled by option\n", prefix_string);
846 	};
847 	fprintf(stderr, "\n");
848 #endif
849 
850 	// summary
851 	fprintf(stderr, "%sDatabase selection or priorization ('->': subsequential calls)\n", prefix_string);
852 
853 	fprintf(stderr, "%sDatabase priorization %s: "
854 		, prefix_string
855 		, (wrapper_source_priority_selector_by_option > 0) ? "by option" : "default"
856 	);
857 
858 	int sp;
859 	for (sp = IPV6CALC_DB_SOURCE_MIN; sp <= IPV6CALC_DB_SOURCE_MAX; sp++) {
860 		fprintf(stderr, "%s%s"
861 			, (sp == IPV6CALC_DB_SOURCE_MIN) ? "" : "->"
862 			, libipv6calc_db_wrapper_get_data_source_name_by_number(wrapper_source_priority_selector[sp])
863 		);
864 	};
865 	fprintf(stderr, "\n");
866 
867 	for (f = IPV6CALC_DB_FEATURE_NUM_MIN; f <= IPV6CALC_DB_FEATURE_NUM_MAX; f++) {
868 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "f=%d", f);
869 
870 		f_index = libipv6calc_db_wrapper_get_feature_index_by_feature(1 << f);
871 
872 		fprintf(stderr, "%s%s (%s): ", prefix_string, ipv6calc_db_features[f_index].token, ipv6calc_db_features[f_index].explanation);
873 
874 		if (wrapper_features_selector[f][0] == 0) {
875 			fprintf(stderr, "NO-DATABASE");
876 		} else {
877 			for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
878 				if (wrapper_features_selector[f][p] != 0) {
879 					fprintf(stderr, "%s%s", (p == 0) ? "" : "->", libipv6calc_db_wrapper_get_data_source_name_by_number(wrapper_features_selector[f][p]));
880 				};
881 			};
882 		};
883 		fprintf(stderr, "\n");
884 	};
885 
886 	fprintf(stderr, "\n");
887 
888 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Return");
889 
890 	return;
891 };
892 
893 
894 /* function query for feature set
895  * ret=-1: unknown
896  * 0 : not matching
897  * 1 : ok
898  */
libipv6calc_db_wrapper_has_features(uint32_t features)899 int libipv6calc_db_wrapper_has_features(uint32_t features) {
900 	int result = -1;
901 
902 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called with feature value to test: 0x%08x", features);
903 
904 	if ((wrapper_features & features) == features) {
905 		result = 1;
906 	} else {
907 		result = 0;
908 	};
909 
910 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Return with result: %d", result);
911 
912 	return(result);
913 };
914 
915 
916 /*********************************************
917  * Option handling
918  * return < 0: error
919  *********************************************/
libipv6calc_db_wrapper_options(const int opt,const char * optarg,const struct option longopts[])920 int libipv6calc_db_wrapper_options(const int opt, const char *optarg, const struct option longopts[]) {
921 	int result = -1;
922 	int s;
923 
924 	// initialize priority selector
925 	if (wrapper_source_priority_selector_by_option < 0) {
926 		for (s = 0; s <= IPV6CALC_DB_SOURCE_MAX; s++) {
927 			wrapper_source_priority_selector[s] = 0;
928 		};
929 		wrapper_source_priority_selector_by_option = 0;
930 	};
931 
932 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called with option: %08x", opt);
933 
934 	switch(opt) {
935 		// GeoIP(legacy) EOS since 3.0.0, TODO remove in 4.0.0
936 		case DB_EOS_geoip_disable:
937 		case DB_EOS_geoip_ipv4:
938 		case DB_EOS_geoip_ipv6:
939 		case DB_EOS_geoip_ipv4_default:
940 		case DB_EOS_geoip_ipv6_default:
941 		case DB_EOS_geoip_dir:
942 		case DB_EOS_geoip_lib:
943 			NONQUIETPRINT_WA("Support for GeoIP(legacy) removed, ignoring option: --%s", ipv6calcoption_name(opt, longopts));
944 			result = 0;
945 			break;
946 
947 		case 'G':
948 			NONQUIETPRINT_NA("Support for GeoIP(legacy) removed, ignoring option: -G");
949 			result = 0;
950 			break;
951 
952 		// db-ip.com(BerkeleyDB) EOS since 3.0.0, TODO remove in 4.0.0
953 		case DB_EOS_dbip_disable:
954 		case DB_EOS_dbip_dir:
955 		case DB_EOS_dbip_comm_to_free_switch_min_delta_months:
956 		case DB_EOS_dbip_only_type:
957 			NONQUIETPRINT_WA("Support for db-ip.com(Berkeley-DB) removed, ignoring option: --%s", ipv6calcoption_name(opt, longopts));
958 			result = 0;
959 			break;
960 
961 		// IP2Location legacy options, EOS since longer, TODO remove in 4.0.0
962 		case DB_EOS_ip2location_ipv4:
963 		case DB_EOS_ip2location_ipv6:
964 		case DB_EOS_ip2location_ipv4_default:
965 		case DB_EOS_ip2location_ipv6_default:
966 			NONQUIETPRINT_WA("Obsolete, ignoring IP2Location option: --%s", ipv6calcoption_name(opt, longopts));
967 			result = 0;
968 			break;
969 
970 		case 'L':
971 			NONQUIETPRINT_NA("Obsolete, ignoring IP2Location option: -L");
972 			result = 0;
973 			break;
974 
975 		case DB_ip2location_disable:
976 #ifdef SUPPORT_IP2LOCATION
977 			wrapper_IP2Location_disable = 1;
978 #endif
979 			result = 0;
980 			break;
981 
982 		case DB_geoip2_disable:
983 #ifdef SUPPORT_GEOIP2
984 			wrapper_GeoIP2_disable = 1;
985 #endif
986 			result = 0;
987 			break;
988 
989 		case DB_dbip2_disable:
990 #ifdef SUPPORT_DBIP2
991 			wrapper_DBIP2_disable = 1;
992 #endif
993 			result = 0;
994 			break;
995 
996 		case DB_external_disable:
997 #ifdef SUPPORT_EXTERNAL
998 			wrapper_External_disable = 1;
999 #endif
1000 			result = 0;
1001 			break;
1002 
1003 		case DB_builtin_disable:
1004 #ifdef SUPPORT_BUILTIN
1005 			wrapper_BuiltIn_disable = 1;
1006 #endif
1007 			result = 0;
1008 			break;
1009 
1010 		case DB_mmdb_lib:
1011 #ifdef SUPPORT_MMDB_DYN
1012 			result = snprintf(mmdb_lib_file, sizeof(mmdb_lib_file), "%s", optarg);
1013 #else
1014 			NONQUIETPRINT_WA("Support for MaxMindDB dyn-load not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1015 #endif
1016 			result = 0;
1017 			break;
1018 
1019 		case DB_ip2location_lib:
1020 #ifdef SUPPORT_IP2LOCATION_DYN
1021 			result = snprintf(ip2location_lib_file, sizeof(ip2location_lib_file), "%s", optarg);
1022 #else
1023 			NONQUIETPRINT_WA("Support for IP2Location dyn-load not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1024 #endif
1025 			result = 0;
1026 			break;
1027 
1028 		case DB_ip2location_dir:
1029 #ifdef SUPPORT_IP2LOCATION
1030 			result = snprintf(ip2location_db_dir, sizeof(ip2location_db_dir), "%s", optarg);
1031 #else
1032 			NONQUIETPRINT_WA("Support for IP2Location not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1033 #endif
1034 			result = 0;
1035 			break;
1036 
1037 		case DB_geoip2_dir:
1038 #ifdef SUPPORT_GEOIP2
1039 			result = snprintf(geoip2_db_dir, sizeof(geoip2_db_dir), "%s", optarg);
1040 #else
1041 			NONQUIETPRINT_WA("Support for GeoIP(MaxMindDB) not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1042 #endif
1043 			result = 0;
1044 			break;
1045 
1046 		case DB_dbip2_dir:
1047 #ifdef SUPPORT_DBIP2
1048 			result = snprintf(dbip2_db_dir, sizeof(dbip2_db_dir), "%s", optarg);
1049 #else
1050 			NONQUIETPRINT_WA("Support for db-ip.com(MaxMindDB) not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1051 #endif
1052 			result = 0;
1053 			break;
1054 
1055 		case DB_dbip2_only_type:
1056 #ifdef SUPPORT_DBIP2
1057 			if ((atoi(optarg) >= 1) && (atoi(optarg) <= DBIP2_DB_MAX)) {
1058 				dbip2_db_only_type = atoi(optarg);
1059 			} else {
1060 				fprintf(stderr, " Argument of option 'db-dbip2-only-type' is out of range (1-%d): %d\n", DBIP2_DB_MAX, atoi(optarg));
1061 				exit(EXIT_FAILURE);
1062 			};
1063 #else
1064 			NONQUIETPRINT_WA("Support for db-ip.com(MaxMindDB) not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1065 #endif
1066 			result = 0;
1067 			break;
1068 
1069 
1070 		case DB_dbip2_comm_to_free_switch_min_delta_months:
1071 #ifdef SUPPORT_DBIP2
1072 			if ((atoi(optarg) >= 0) && (atoi(optarg) <= 99999)) {
1073 				dbip2_db_comm_to_free_switch_min_delta_months = atoi(optarg);
1074 			} else {
1075 				fprintf(stderr, " Argument of option 'db-dbip2-comm-to-free-switch-min-delta-months' is out of range (0-99999): %d\n", atoi(optarg));
1076 				exit(EXIT_FAILURE);
1077 			};
1078 #else
1079 			NONQUIETPRINT_WA("Support for db-ip.com(MaxMindDB) not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1080 #endif
1081 			result = 0;
1082 			break;
1083 
1084 		case DB_external_dir:
1085 #ifdef SUPPORT_EXTERNAL
1086 			result = snprintf(external_db_dir, sizeof(external_db_dir), "%s", optarg);
1087 #else
1088 			NONQUIETPRINT_WA("Support for external(BerkeleyDB) not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1089 #endif
1090 			result = 0;
1091 			break;
1092 
1093 		case DB_ip2location_lite_to_sample_autoswitch_max_delta_months:
1094 #ifdef SUPPORT_IP2LOCATION
1095 			if ((atoi(optarg) >= 0) && (atoi(optarg) <= 99999)) {
1096 				ip2location_db_lite_to_sample_autoswitch_max_delta_months = atoi(optarg);
1097 			} else {
1098 				fprintf(stderr, " Argument of option 'db-ip2location-lite-to-sample-autoswitch-max-delta-months' is out of range (0-99999): %d\n", atoi(optarg));
1099 				exit(EXIT_FAILURE);
1100 			};
1101 #else
1102 			NONQUIETPRINT_WA("Support for IP2Location not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1103 #endif
1104 			result = 0;
1105 			break;
1106 
1107 		case DB_ip2location_comm_to_lite_switch_min_delta_months:
1108 #ifdef SUPPORT_IP2LOCATION
1109 			if ((atoi(optarg) >= 0) && (atoi(optarg) <= 99999)) {
1110 				ip2location_db_comm_to_lite_switch_min_delta_months = atoi(optarg);
1111 			} else {
1112 				fprintf(stderr, " Argument of option 'db-ip2location-comm-to-lite-switch-min-delta-months' is out of range (0-99999): %d\n", atoi(optarg));
1113 				exit(EXIT_FAILURE);
1114 			};
1115 #else
1116 			NONQUIETPRINT_WA("Support for IP2Location not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1117 #endif
1118 			result = 0;
1119 			break;
1120 
1121 		case DB_ip2location_only_type:
1122 #ifdef SUPPORT_IP2LOCATION
1123 			if ((atoi(optarg) >= 1) && (atoi(optarg) <= IP2LOCATION_DB_MAX)) {
1124 				ip2location_db_only_type = atoi(optarg);
1125 			} else {
1126 				fprintf(stderr, " Argument of option 'db-ip2location-only-type' is out of range (1-%d): %d\n", IP2LOCATION_DB_MAX, atoi(optarg));
1127 				exit(EXIT_FAILURE);
1128 			};
1129 #else
1130 			NONQUIETPRINT_WA("Support for IP2Location not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1131 #endif
1132 			result = 0;
1133 			break;
1134 
1135 		case DB_ip2location_allow_softlinks:
1136 #ifdef SUPPORT_IP2LOCATION
1137 			ip2location_db_allow_softlinks = 1;
1138 #else
1139 			NONQUIETPRINT_WA("Support for IP2Location not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1140 #endif
1141 			result = 0;
1142 			break;
1143 
1144 		case DB_common_priorization:
1145 #if defined SUPPORT_EXTERNAL || defined SUPPORT_DBIP || defined SUPPORT_GEOIP || SUPPORT_IP2LOCATION || defined SUPPORT_GEOIP2 || defined SUPPORT_DBIP2
1146 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Parse database priorization string: %s", optarg);
1147 			char tempstring[IPV6CALC_STRING_MAX];
1148 			char *token, *cptr, **ptrptr;
1149 			ptrptr = &cptr;
1150 			int i, j;
1151 			snprintf(tempstring, sizeof(tempstring), "%s", optarg);
1152 
1153 			s = IPV6CALC_DB_SOURCE_MIN;
1154 
1155 			token = strtok_r(tempstring, ":", ptrptr);
1156 			while (token != NULL) {
1157 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Parsing of token: %s", token);
1158 				for (i = 0; i < MAXENTRIES_ARRAY(data_sources); i++) {
1159 					if (strcasecmp(data_sources[i].shortname, token) == 0) {
1160 						DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Token found: %s (%d)", token, data_sources[i].number);
1161 						break;
1162 					};
1163 				};
1164 
1165 				if (i == MAXENTRIES_ARRAY(data_sources)) {
1166 					ERRORPRINT_WA("Database priorization token not supported: %s", token);
1167 					exit(EXIT_FAILURE);
1168 				};
1169 
1170 				/* check for duplicate */
1171 				if (s > IPV6CALC_DB_SOURCE_MIN) {
1172 					DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Check for duplicate: %s", token);
1173 					for (j = IPV6CALC_DB_SOURCE_MIN; j <= s; j++) {
1174 						if (wrapper_source_priority_selector[j] == data_sources[i].number) {
1175 							ERRORPRINT_WA("Database duplicate priorization token found: %s", token);
1176 							exit(EXIT_FAILURE);
1177 						};
1178 					};
1179 				};
1180 
1181 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Set token on entry %d: %s", s, token);
1182 				wrapper_source_priority_selector[s] = data_sources[i].number;
1183 				wrapper_source_priority_selector_by_option = s;
1184 				s++;
1185 
1186 				/* get next token */
1187 				token = strtok_r(NULL, ":", ptrptr);
1188 			};
1189 
1190 			for (j = IPV6CALC_DB_SOURCE_MIN; j <= wrapper_source_priority_selector_by_option; j++) {
1191 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Database priorization/defined by option entry %d: %s", j, libipv6calc_db_wrapper_get_data_source_name_by_number(wrapper_source_priority_selector[j]));
1192 			};
1193 #else
1194 			NONQUIETPRINT_WA("Support for database priorization not compiled-in, skipping option: --%s", ipv6calcoption_name(opt, longopts));
1195 			s = strlen(optarg); // make compiler happy (avoid unused "...")
1196 #endif
1197 			result = 0;
1198 			break;
1199 	};
1200 
1201 	if (result > 0) {
1202 		result = 0;
1203 	};
1204 
1205 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Return with result: %d", result);
1206 
1207 	return(result);
1208 };
1209 
1210 /***********************************************************/
1211 /*********** geolocation support      **********************/
1212 /***********************************************************/
libipv6calc_db_wrapper_geolocation_record_clear(libipv6calc_db_wrapper_geolocation_record * recordp)1213 void libipv6calc_db_wrapper_geolocation_record_clear(libipv6calc_db_wrapper_geolocation_record *recordp) {
1214 
1215 	// clear structure
1216 	snprintf(recordp->country_code  , IPV6CALC_DB_SIZE_COUNTRY_CODE  , "%s", "");
1217 	snprintf(recordp->country_long  , IPV6CALC_DB_SIZE_COUNTRY_LONG  , "%s", "");
1218 	snprintf(recordp->continent_code, IPV6CALC_DB_SIZE_CONTINENT_CODE, "%s", "");
1219 	snprintf(recordp->continent_long, IPV6CALC_DB_SIZE_CONTINENT_LONG, "%s", "");
1220 	snprintf(recordp->stateprov     , IPV6CALC_DB_SIZE_STATEPROV     , "%s", "");
1221 	snprintf(recordp->district      , IPV6CALC_DB_SIZE_DISTRICT      , "%s", "");
1222 	snprintf(recordp->city          , IPV6CALC_DB_SIZE_CITY          , "%s", "");
1223 	snprintf(recordp->zipcode       , IPV6CALC_DB_SIZE_ZIPCODE       , "%s", "");
1224 	snprintf(recordp->weatherstationcode, IPV6CALC_DB_SIZE_WEATHERSTATIONCODE, "%s", "");
1225 	snprintf(recordp->weatherstationname, IPV6CALC_DB_SIZE_WEATHERSTATIONNAME, "%s", "");
1226 	snprintf(recordp->dma_code      , IPV6CALC_DB_SIZE_DMA_CODE      , "%s", "");
1227 	snprintf(recordp->idd_code      , IPV6CALC_DB_SIZE_IDD_CODE      , "%s", "");
1228 	snprintf(recordp->area_code     , IPV6CALC_DB_SIZE_AREA_CODE     , "%s", "");
1229 	recordp->latitude             = 0;
1230 	recordp->longitude            = 0;
1231 	recordp->accuracy_radius      = 0;
1232 	recordp->elevation            = IPV6CALC_DB_GEO_ELEVATION_UNKNOWN;
1233 	recordp->geoname_id           = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN;
1234 	recordp->continent_geoname_id = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN;
1235 	recordp->country_geoname_id   = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN;
1236 	recordp->stateprov_geoname_id = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN;
1237 	recordp->district_geoname_id  = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN;
1238 	recordp->asn                  = ASNUM_AS_UNKNOWN; // invalid/unset
1239 	recordp->timezone_offset      = IPV6CALC_DB_GEO_TIMEZONE_UNKNOWN; // invalid/unset (>= 24)
1240 	snprintf(recordp->timezone_name    , IPV6CALC_DB_SIZE_TIMEZONE_NAME, "%s", "");
1241 	snprintf(recordp->isp_name         , IPV6CALC_DB_SIZE_ISP_NAME     , "%s", "");
1242 	snprintf(recordp->connection_type  , IPV6CALC_DB_SIZE_CONN_TYPE    , "%s", "");
1243 	snprintf(recordp->organization_name, IPV6CALC_DB_SIZE_ORG_NAME     , "%s", "");
1244 	snprintf(recordp->domain           , IPV6CALC_DB_SIZE_DOMAIN       , "%s", "");
1245 	snprintf(recordp->mobile_network_code, IPV6CALC_DB_SIZE_MOBILENETWORKCODE, "%s", "");
1246 	snprintf(recordp->mobile_country_code, IPV6CALC_DB_SIZE_MOBILECOUNTRYCODE, "%s", "");
1247 	snprintf(recordp->mobile_brand       , IPV6CALC_DB_SIZE_MOBILE_BRAND     , "%s", "");
1248 	snprintf(recordp->usage_type         , IPV6CALC_DB_SIZE_USAGE_TYPE       , "%s", "");
1249 };
1250 
1251 
1252 /*********************************************
1253  * Abstract functions
1254  *********************************************/
1255 
1256 /*
1257  * get registry number by AS number
1258  */
libipv6calc_db_wrapper_registry_num_by_as_num32(const uint32_t as_num32)1259 int libipv6calc_db_wrapper_registry_num_by_as_num32(const uint32_t as_num32) {
1260 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called with as_num32: %d", as_num32);
1261 #ifdef SUPPORT_BUILTIN
1262 	// currently only supported by BuiltIn
1263 	return(libipv6calc_db_wrapper_BuiltIn_registry_num_by_as_num32(as_num32));
1264 #else
1265 	return(ASNUM_AS_UNKNOWN);
1266 #endif
1267 };
1268 
1269 
1270 /*
1271  * get registry number by CC index
1272  */
libipv6calc_db_wrapper_registry_num_by_cc_index(const uint16_t cc_index)1273 int libipv6calc_db_wrapper_registry_num_by_cc_index(const uint16_t cc_index) {
1274 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called with cc_index: %d", cc_index);
1275 #ifdef SUPPORT_BUILTIN
1276 	// currently only supported by BuiltIn
1277 	return(libipv6calc_db_wrapper_BuiltIn_registry_num_by_cc_index(cc_index));
1278 #else
1279 	return(COUNTRYCODE_INDEX_UNKNOWN);
1280 #endif
1281 };
1282 
1283 /*
1284  * get registry number by IP address
1285  */
libipv6calc_db_wrapper_registry_num_by_ipaddr(const ipv6calc_ipaddr * ipaddrp)1286 int libipv6calc_db_wrapper_registry_num_by_ipaddr(const ipv6calc_ipaddr *ipaddrp) {
1287 	ipv6calc_ipv4addr ipv4addr;
1288 	ipv6calc_ipv6addr ipv6addr;
1289 
1290 	if (ipaddrp->proto == IPV6CALC_PROTO_IPV4) {
1291 		CONVERT_IPADDRP_IPV4ADDR(ipaddrp, ipv4addr)
1292 		return(libipv6calc_db_wrapper_registry_num_by_ipv4addr(&ipv4addr));
1293 	} else if (ipaddrp->proto == IPV6CALC_PROTO_IPV6) {
1294 		CONVERT_IPADDRP_IPV6ADDR(ipaddrp, ipv6addr)
1295 		return(libipv6calc_db_wrapper_registry_num_by_ipv6addr(&ipv6addr));
1296 	} else {
1297 		ERRORPRINT_WA("unsupported proto=%d (FIX CODE)", ipaddrp->proto);
1298 		exit(EXIT_FAILURE);
1299 	};
1300 };
1301 
1302 /*
1303  * get registry string by IP address
1304  */
libipv6calc_db_wrapper_registry_string_by_ipaddr(const ipv6calc_ipaddr * ipaddrp,char * resultstring,const size_t resultstring_length)1305 int libipv6calc_db_wrapper_registry_string_by_ipaddr(const ipv6calc_ipaddr *ipaddrp, char *resultstring, const size_t resultstring_length) {
1306 	ipv6calc_ipv4addr ipv4addr;
1307 	ipv6calc_ipv6addr ipv6addr;
1308 
1309 	if (ipaddrp->proto == IPV6CALC_PROTO_IPV4) {
1310 		CONVERT_IPADDRP_IPV4ADDR(ipaddrp, ipv4addr)
1311 		return(libipv6calc_db_wrapper_registry_string_by_ipv4addr(&ipv4addr, resultstring, resultstring_length));
1312 	} else if (ipaddrp->proto == IPV6CALC_PROTO_IPV6) {
1313 		CONVERT_IPADDRP_IPV6ADDR(ipaddrp, ipv6addr)
1314 		return(libipv6calc_db_wrapper_registry_string_by_ipv6addr(&ipv6addr, resultstring, resultstring_length));
1315 	} else {
1316 		ERRORPRINT_WA("unsupported proto=%d (FIX CODE)", ipaddrp->proto);
1317 		exit(EXIT_FAILURE);
1318 	};
1319 };
1320 
1321 
1322 /*
1323  * get CountryCode in text form
1324  * in: ipaddrp, length
1325  * mod: string, data_source_ptr (if != NULL)
1326  * return: 0=ok
1327  */
libipv6calc_db_wrapper_country_code_by_addr(char * string,const int length,const ipv6calc_ipaddr * ipaddrp,unsigned int * data_source_ptr)1328 int libipv6calc_db_wrapper_country_code_by_addr(char *string, const int length, const ipv6calc_ipaddr *ipaddrp, unsigned int *data_source_ptr) {
1329 	unsigned int data_source = IPV6CALC_DB_SOURCE_UNKNOWN;
1330 	int f = 0, p, result = -1;
1331 
1332 #if defined SUPPORT_GEOIP || defined SUPPORT_IP2LOCATION
1333 	char tempstring[IPV6CALC_ADDR_STRING_MAX] = "";
1334 #endif
1335 
1336 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called");
1337 
1338 	if (string == NULL) {
1339 		ERRORPRINT_NA("given pointer 'string' is NULL (FIX CODE)");
1340 		exit(EXIT_FAILURE);
1341 	};
1342 
1343 	if (length < 3) {
1344 		ERRORPRINT_NA("given 'length' < 3 (FIX CODE)");
1345 		exit(EXIT_FAILURE);
1346 	};
1347 
1348 	if (ipaddrp->proto == IPV6CALC_PROTO_IPV4) {
1349 		f = IPV6CALC_DB_FEATURE_NUM_IPV4_TO_CC;
1350 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv4 address: %08x", (unsigned int) ipaddrp->addr[0]);
1351 		if ((ipaddrp->typeinfo1 & IPV4_ADDR_RESERVED) != 0) {
1352 			// reserved IPv4 address has no country
1353 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv4 address: %08x is reserved (skip CountryCode lookup)", (unsigned int) ipaddrp->addr[0]);
1354 			goto END_libipv6calc_db_wrapper;
1355 		};
1356 	} else if (ipaddrp->proto == IPV6CALC_PROTO_IPV6) {
1357 		f = IPV6CALC_DB_FEATURE_NUM_IPV6_TO_CC;
1358 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv6 address prefix (0-63): %08x%08x", (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
1359 		if ((ipaddrp->typeinfo1 & IPV6_ADDR_RESERVED) != 0) {
1360 			// reserved IPv4 address has no country
1361 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv6 address prefix (0-63): %08x%08x is reserved (skip CountryCode lookup)", (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
1362 			goto END_libipv6calc_db_wrapper;
1363 		};
1364 	} else {
1365 		ERRORPRINT_WA("unsupported proto=%d (FIX CODE)", ipaddrp->proto);
1366 		exit(EXIT_FAILURE);
1367 	};
1368 
1369 	// run through priorities
1370 	for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
1371 #if defined SUPPORT_GEOIP || defined SUPPORT_IP2LOCATION
1372 		switch(wrapper_features_selector[f][p]) {
1373 		    case IPV6CALC_DB_SOURCE_GEOIP:
1374 		    case IPV6CALC_DB_SOURCE_IP2LOCATION:
1375 			// need IP address as string
1376 			if (strlen(tempstring) == 0) {
1377 				libipaddr_ipaddrstruct_to_string(ipaddrp, tempstring, sizeof(tempstring), 0);
1378 			};
1379 		};
1380 #endif
1381 
1382 		switch(wrapper_features_selector[f][p]) {
1383 		    case 0:
1384 			// last
1385 			goto END_libipv6calc_db_wrapper; // ok
1386 			break;
1387 
1388 		    case IPV6CALC_DB_SOURCE_GEOIP:
1389 #ifdef SUPPORT_GEOIP
1390 			if (wrapper_GeoIP_status == 1) {
1391 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Call now GeoIP with %s", tempstring);
1392 
1393 				char *result_char_ptr = (char *) libipv6calc_db_wrapper_GeoIP_wrapper_country_code_by_addr(tempstring, ipaddrp->proto);
1394 
1395 				if ((result_char_ptr != NULL) && (strlen(result_char_ptr) > 0)) {
1396 					snprintf(string, length, "%s", result_char_ptr);
1397 					result = 0;
1398 					data_source = IPV6CALC_DB_SOURCE_GEOIP;
1399 					goto END_libipv6calc_db_wrapper; // ok
1400 				} else {
1401 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called GeoIP did not return a valid country_code");
1402 				};
1403 			};
1404 #endif
1405 			break;
1406 
1407 		    case IPV6CALC_DB_SOURCE_GEOIP2:
1408 #ifdef SUPPORT_GEOIP2
1409 			if (wrapper_GeoIP2_status == 1) {
1410 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now GEOIP2");
1411 
1412 				int ret = libipv6calc_db_wrapper_GeoIP2_wrapper_country_code_by_addr(ipaddrp, string, length);
1413 				if (ret == 0) {
1414 					result = 0;
1415 					data_source = IPV6CALC_DB_SOURCE_GEOIP2;
1416 					goto END_libipv6calc_db_wrapper; // ok
1417 				} else {
1418 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called GeoIP (MaxMindDB) did not return a valid country_code");
1419 				};
1420 			};
1421 #endif
1422 			break;
1423 
1424 		    case IPV6CALC_DB_SOURCE_IP2LOCATION:
1425 #ifdef SUPPORT_IP2LOCATION
1426 			if (wrapper_IP2Location_status == 1) {
1427 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Call now IP2Location with %s", tempstring);
1428 
1429 				int ret = libipv6calc_db_wrapper_IP2Location_wrapper_country_code_by_addr(tempstring, ipaddrp->proto, string, length);
1430 				if (ret == 0) {
1431 					result = 0;
1432 					data_source = IPV6CALC_DB_SOURCE_IP2LOCATION;
1433 					goto END_libipv6calc_db_wrapper; // ok
1434 				} else {
1435 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called IP2Location did not return a valid country_code");
1436 				};
1437 			};
1438 #endif
1439 			break;
1440 
1441 		    case IPV6CALC_DB_SOURCE_DBIP:
1442 #ifdef SUPPORT_DBIP
1443 			if (wrapper_DBIP_status == 1) {
1444 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now DBIP");
1445 
1446 				int ret = libipv6calc_db_wrapper_DBIP_wrapper_country_code_by_addr(ipaddrp, string, length);
1447 				if (ret == 0) {
1448 					result = 0;
1449 					data_source = IPV6CALC_DB_SOURCE_DBIP;
1450 					goto END_libipv6calc_db_wrapper; // ok
1451 				} else {
1452 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called db-ip.com did not return a valid country_code");
1453 				};
1454 			};
1455 #endif
1456 			break;
1457 
1458 		    case IPV6CALC_DB_SOURCE_DBIP2:
1459 #ifdef SUPPORT_DBIP2
1460 			if (wrapper_DBIP2_status == 1) {
1461 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now DBIP2");
1462 
1463 				int ret = libipv6calc_db_wrapper_DBIP2_wrapper_country_code_by_addr(ipaddrp, string, length);
1464 				if (ret == 0) {
1465 					result = 0;
1466 					data_source = IPV6CALC_DB_SOURCE_DBIP2;
1467 					goto END_libipv6calc_db_wrapper; // ok
1468 				} else {
1469 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called db-ip.com (MaxMindDB) did not return a valid country_code");
1470 				};
1471 			};
1472 #endif
1473 			break;
1474 
1475 		    case IPV6CALC_DB_SOURCE_EXTERNAL:
1476 #ifdef SUPPORT_EXTERNAL
1477 			if (wrapper_External_status == 1) {
1478 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now External");
1479 
1480 				int ret = libipv6calc_db_wrapper_External_country_code_by_addr(ipaddrp, string, length);
1481 
1482 				if (ret == 0) {
1483 					result = 0;
1484 					data_source = IPV6CALC_DB_SOURCE_EXTERNAL;
1485 					goto END_libipv6calc_db_wrapper; // ok
1486 				} else {
1487 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called External did not return a valid country_code");
1488 				};
1489 			};
1490 #endif
1491 			break;
1492 
1493 		    default:
1494 			goto END_libipv6calc_db_wrapper; // dummy goto in case no db is enabled
1495 			break;
1496 		};
1497 	};
1498 
1499 END_libipv6calc_db_wrapper:
1500 	if (result == 0) {
1501 		if (data_source_ptr != NULL) {
1502 			// set data_source if pointer not NULL
1503 			*data_source_ptr = data_source;
1504 		};
1505 	} else {
1506 		// clear string
1507 		snprintf(string, length, "%s", "");
1508 	};
1509 
1510 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: %s (data_source=%d)", string, data_source);
1511 
1512 	return(result);
1513 };
1514 
1515 
1516 /*
1517  * get CountryCode in special internal form (index) [A-Z] (26) x [0-9A-Z] (36)
1518  */
libipv6calc_db_wrapper_cc_index_by_addr(const ipv6calc_ipaddr * ipaddrp,unsigned int * data_source_ptr)1519 uint16_t libipv6calc_db_wrapper_cc_index_by_addr(const ipv6calc_ipaddr *ipaddrp, unsigned int *data_source_ptr) {
1520 	uint16_t index = COUNTRYCODE_INDEX_UNKNOWN;
1521 	char cc_text[256] = "";
1522 	uint8_t c1, c2;
1523 	int r;
1524 
1525 	int cache_hit = 0;
1526 
1527 	static ipv6calc_ipaddr ipaddr_cache_lastused;
1528 	static uint16_t cc_index_lastused;
1529 	static unsigned int data_source_lastused = IPV6CALC_DB_SOURCE_UNKNOWN;
1530 	static int ipaddr_cache_lastused_valid = 0;
1531 
1532 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called: addr=%08x%08x%08x%08x proto=%d", ipaddrp->addr[0], ipaddrp->addr[1], ipaddrp->addr[2], ipaddrp->addr[3], ipaddrp->proto);
1533 
1534 	if ((ipaddr_cache_lastused_valid == 1)
1535 	    &&	(ipaddr_cache_lastused.proto == ipaddrp->proto)
1536 	    && 	(ipaddr_cache_lastused.addr[0] == ipaddrp->addr[0])
1537 	    && 	(ipaddr_cache_lastused.addr[1] == ipaddrp->addr[1])
1538 	    && 	(ipaddr_cache_lastused.addr[2] == ipaddrp->addr[2])
1539 	    && 	(ipaddr_cache_lastused.addr[3] == ipaddrp->addr[3])
1540 	) {
1541 		index = cc_index_lastused;
1542 
1543 		// set only data_source from cache if caller request it
1544 		if (data_source_ptr != NULL) {
1545 			*data_source_ptr = data_source_lastused;
1546 		};
1547 
1548 		cache_hit = 1;
1549 		goto END_libipv6calc_db_wrapper_cached;
1550 	} else {
1551 		// retrieve always data_source for caching
1552 		r = libipv6calc_db_wrapper_country_code_by_addr(cc_text, sizeof(cc_text), ipaddrp, &data_source_lastused);
1553 		if (r != 0) {
1554 			goto END_libipv6calc_db_wrapper_cached; // something wrong
1555 		};
1556 
1557 		if (strlen(cc_text) == 2) {
1558 			if (isalpha((int) cc_text[0]) && isalnum((int) cc_text[1])) {
1559 				c1 = toupper(cc_text[0]);
1560 				if (! (c1 >= 'A' && c1 <= 'Z')) {
1561 					goto END_libipv6calc_db_wrapper_cached; // something wrong
1562 				};
1563 				c1 -= 'A';
1564 
1565 				c2 = toupper(cc_text[1]);
1566 				if (c2 >= '0' && c2 <= '9') {
1567 					c2 -= '0';
1568 				} else if (c2 >= 'A' && c2 <= 'Z') {
1569 					c2 -= 'A';
1570 					c2 += 10;
1571 				} else {
1572 					goto END_libipv6calc_db_wrapper_cached; // something wrong
1573 				};
1574 
1575 				index = c1 + c2 * COUNTRYCODE_LETTER1_MAX;
1576 
1577 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "c1=%d c2=%d index=%d (0x%03x) -> test: %c%c", c1, c2, index, index, COUNTRYCODE_INDEX_TO_CHAR1(index), COUNTRYCODE_INDEX_TO_CHAR2(index));
1578 
1579 				if (index >= COUNTRYCODE_INDEX_MAX) {
1580 					index = COUNTRYCODE_INDEX_UNKNOWN; // failsafe
1581 					ERRORPRINT_WA("unexpected index (too high): %d", index);
1582 					goto END_libipv6calc_db_wrapper_cached; // something wrong
1583 				};
1584 			};
1585 		} else {
1586 			ERRORPRINT_WA("returned cc_text has not 2 chars: %s (addr=%08x%08x%08x%08x)", cc_text, ipaddrp->addr[0], ipaddrp->addr[1], ipaddrp->addr[2], ipaddrp->addr[3]);
1587 			goto END_libipv6calc_db_wrapper_cached; // something wrong
1588 		};
1589 
1590 		// store in last used cache
1591 		ipaddr_cache_lastused_valid = 1;
1592 		cc_index_lastused = index;
1593 		ipaddr_cache_lastused = *ipaddrp;
1594 
1595 		// set only data_source from cache if caller request it
1596 		if (data_source_ptr != NULL) {
1597 			*data_source_ptr = data_source_lastused;
1598 		};
1599 	};
1600 
1601 END_libipv6calc_db_wrapper_cached:
1602 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: addr=%08x%08x%08x%08x cc_index=%d (0x%03x) %c%c%s", ipaddrp->addr[0], ipaddrp->addr[1], ipaddrp->addr[2], ipaddrp->addr[3], index, index, COUNTRYCODE_INDEX_TO_CHAR1(index), COUNTRYCODE_INDEX_TO_CHAR2(index), (cache_hit == 1 ? " (cached)" : ""));
1603 
1604 	return(index);
1605 };
1606 
1607 
1608 /*
1609  * get country code string by index
1610  */
libipv6calc_db_wrapper_country_code_by_cc_index(char * string,const int length,const uint16_t cc_index)1611 int libipv6calc_db_wrapper_country_code_by_cc_index(char *string, const int length, const uint16_t cc_index) {
1612 	int result = 0;
1613 
1614 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called with cc_index=%d", cc_index);
1615 
1616 	if (cc_index <= COUNTRYCODE_INDEX_LETTER_MAX) {
1617 		snprintf(string, length, "%c%c", COUNTRYCODE_INDEX_TO_CHAR1(cc_index), COUNTRYCODE_INDEX_TO_CHAR2(cc_index));
1618 	} else if (cc_index == COUNTRYCODE_INDEX_UNKNOWN) {
1619 		snprintf(string, length, "unknown");
1620 	} else if ((cc_index >= COUNTRYCODE_INDEX_UNKNOWN_REGISTRY_MAP_MIN) && (cc_index <= COUNTRYCODE_INDEX_UNKNOWN_REGISTRY_MAP_MAX)) {
1621 		snprintf(string, length, "unknown");
1622 	} else {
1623 		snprintf(string, length, "unsupported");
1624 	};
1625 
1626 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Return country code: %s", string);
1627 	return(result);
1628 };
1629 
1630 
1631 /*
1632  * get AS 32-bit number
1633  */
libipv6calc_db_wrapper_as_num32_by_addr(const ipv6calc_ipaddr * ipaddrp,unsigned int * data_source_ptr)1634 uint32_t libipv6calc_db_wrapper_as_num32_by_addr(const ipv6calc_ipaddr *ipaddrp, unsigned int *data_source_ptr) {
1635 	uint32_t as_num32 = ASNUM_AS_UNKNOWN; // default
1636 
1637 	int f = 0, p;
1638 
1639 	int cache_hit = 0;
1640 
1641 	static ipv6calc_ipaddr ipaddr_cache_lastused;
1642 	static uint32_t as_num32_lastused;
1643 	static unsigned int data_source_lastused = IPV6CALC_DB_SOURCE_UNKNOWN;
1644 	static int ipaddr_cache_lastused_valid = 0;
1645 
1646 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called: addr=%08x%08x%08x%08x proto=%d", ipaddrp->addr[0], ipaddrp->addr[1], ipaddrp->addr[2], ipaddrp->addr[3], ipaddrp->proto);
1647 
1648 	if (ipaddrp->proto == IPV6CALC_PROTO_IPV4) {
1649 		f = IPV6CALC_DB_FEATURE_NUM_IPV4_TO_AS;
1650 		if ((ipaddrp->typeinfo1 & IPV4_ADDR_RESERVED) != 0) {
1651 			// reserved IPv4 address has no AS
1652 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv4 address: %08x is reserved (skip AS lookup)", (unsigned int) ipaddrp->addr[0]);
1653 			goto END_libipv6calc_db_wrapper;
1654 		};
1655 	} else if (ipaddrp->proto == IPV6CALC_PROTO_IPV6) {
1656 		f = IPV6CALC_DB_FEATURE_NUM_IPV6_TO_AS;
1657 		if ((ipaddrp->typeinfo1 & IPV6_ADDR_RESERVED) != 0) {
1658 			// reserved IPv4 address has no AS
1659 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv6 address prefix (0-63): %08x%08x is reserved (skip AS lookup)", (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
1660 			goto END_libipv6calc_db_wrapper;
1661 		};
1662 	} else {
1663 		ERRORPRINT_WA("unsupported proto=%d (FIX CODE)", ipaddrp->proto);
1664 		exit(EXIT_FAILURE);
1665 	};
1666 
1667 	if ((ipaddr_cache_lastused_valid == 1)
1668 	    &&	(ipaddr_cache_lastused.proto == ipaddrp->proto)
1669 	    && 	(ipaddr_cache_lastused.addr[0] == ipaddrp->addr[0])
1670 	    && 	(ipaddr_cache_lastused.addr[1] == ipaddrp->addr[1])
1671 	    && 	(ipaddr_cache_lastused.addr[2] == ipaddrp->addr[2])
1672 	    && 	(ipaddr_cache_lastused.addr[3] == ipaddrp->addr[3])
1673 	) {
1674 		as_num32 = as_num32_lastused;
1675 
1676 		// set only data_source from cache if caller request it
1677 		if (data_source_ptr != NULL) {
1678 			*data_source_ptr = data_source_lastused;
1679 		};
1680 
1681 		cache_hit = 1;
1682 		goto END_libipv6calc_db_wrapper; // ok
1683 	};
1684 
1685 	// run through priorities
1686 	for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
1687 		switch(wrapper_features_selector[f][p]) {
1688 		    case 0:
1689 			// last
1690 			goto END_libipv6calc_db_wrapper; // ok
1691 			break;
1692 
1693 		    case IPV6CALC_DB_SOURCE_GEOIP:
1694 #ifdef SUPPORT_GEOIP
1695 			if (wrapper_GeoIP_status == 1) {
1696 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now GeoIP");
1697 
1698 				as_num32 = libipv6calc_db_wrapper_GeoIP_wrapper_asn_by_addr(ipaddrp);
1699 				if (as_num32 != ASNUM_AS_UNKNOWN) {
1700 					data_source_lastused = IPV6CALC_DB_SOURCE_GEOIP;
1701 					goto END_libipv6calc_db_wrapper; // ok
1702 				} else {
1703 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called GeoIP did not return a valid ASN");
1704 				};
1705 			};
1706 #endif
1707 			break;
1708 
1709 		    case IPV6CALC_DB_SOURCE_GEOIP2:
1710 #ifdef SUPPORT_GEOIP2
1711 			if (wrapper_GeoIP2_status == 1) {
1712 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now GeoIP2");
1713 
1714 				as_num32 = libipv6calc_db_wrapper_GeoIP2_wrapper_asn_by_addr(ipaddrp);
1715 				if (as_num32 != ASNUM_AS_UNKNOWN) {
1716 					data_source_lastused = IPV6CALC_DB_SOURCE_GEOIP2;
1717 					goto END_libipv6calc_db_wrapper; // ok
1718 				} else {
1719 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called GeoIP (MaxMindDB) did not return a valid ASN");
1720 				};
1721 			};
1722 #endif
1723 			break;
1724 
1725 		    case IPV6CALC_DB_SOURCE_DBIP2:
1726 #ifdef SUPPORT_DBIP2
1727 			if (wrapper_DBIP2_status == 1) {
1728 
1729 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now DBIP2");
1730 
1731 				as_num32 = libipv6calc_db_wrapper_DBIP2_wrapper_asn_by_addr(ipaddrp);
1732 				if (as_num32 != ASNUM_AS_UNKNOWN) {
1733 					data_source_lastused = IPV6CALC_DB_SOURCE_DBIP2;
1734 					goto END_libipv6calc_db_wrapper; // ok
1735 				} else {
1736 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called db-ip.com (MaxMindDB) did not return a valid ASN");
1737 				};
1738 			};
1739 #endif
1740 			break;
1741 
1742 		    default:
1743 			goto END_libipv6calc_db_wrapper; // dummy goto in case no db is enabled
1744 			break;
1745 		};
1746 	};
1747 
1748 END_libipv6calc_db_wrapper:
1749 	if (as_num32 != ASNUM_AS_UNKNOWN) {
1750 		// store in last used cache
1751 		ipaddr_cache_lastused_valid = 1;
1752 		as_num32_lastused = as_num32;
1753 		ipaddr_cache_lastused = *ipaddrp;
1754 
1755 		// set only data_source from cache if caller request it
1756 		if (data_source_ptr != NULL) {
1757 			*data_source_ptr = data_source_lastused;
1758 		};
1759 	};
1760 
1761 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: addr=%08x%08x%08x%08x as_num32=%u (0x%08x)%s (data_source=%d)", ipaddrp->addr[0], ipaddrp->addr[1], ipaddrp->addr[2], ipaddrp->addr[3], as_num32, as_num32, (cache_hit == 1 ? " (cached)" : ""), data_source_lastused);
1762 
1763 	return(as_num32);
1764 };
1765 
1766 
1767 /*
1768  * compress AS 32-bit number to 17 bit
1769  */
libipv6calc_db_wrapper_as_num32_comp17(const uint32_t as_num32)1770 uint32_t libipv6calc_db_wrapper_as_num32_comp17(const uint32_t as_num32) {;
1771 	uint32_t as_num32_comp17 = 0;
1772 	uint32_t as_num32_comp17_reg = 0;
1773 	uint32_t as_num32_comp17_asn = 0;
1774 
1775 	if (as_num32 <= 0xffff) {
1776 		as_num32_comp17 = as_num32;
1777 	} else {
1778 		if ((as_num32 & 0x00070000) == (as_num32 & 0xfff70000)) {
1779 			// 3 of 16 MSB bits active (which are  at least in 2013 maped 1:1 to related registry)
1780 			as_num32_comp17_reg = (as_num32 & 0x0007000) >> 3;
1781 		} else {
1782 			// map to unknown registry
1783 			as_num32_comp17_reg = 0;
1784 		};
1785 
1786 		if ((as_num32 & 0x0fff) == (as_num32 & 0xffff)) {
1787 			// only 12 of 16 LSB bits active
1788 			as_num32_comp17_asn = as_num32 & 0x0fff;
1789 		} else {
1790 			// more than 12 bits are in use, unspecified result, but keeping registry and set special flag
1791 			as_num32_comp17_asn = 0x1000;
1792 		};
1793 
1794 		// fill compressed value and set flag
1795 		as_num32_comp17 = as_num32_comp17_reg | as_num32_comp17_asn | 0x00010000;
1796 	};
1797 
1798 	return(as_num32_comp17);
1799 };
1800 
1801 
1802 /*
1803  * Decompress AS 32-bit number from 17 bit
1804  */
libipv6calc_db_wrapper_as_num32_decomp17(const uint32_t as_num32_comp17)1805 uint32_t libipv6calc_db_wrapper_as_num32_decomp17(const uint32_t as_num32_comp17) {;
1806 	uint32_t as_num32 = ASNUM_AS_UNKNOWN;
1807 
1808 	if ((as_num32_comp17 & 0x00010000) == 0x00000000) {
1809 		as_num32 = as_num32_comp17;
1810 	} else {
1811 		if ((as_num32_comp17 & 0xe000) == 0x0000) {
1812 			as_num32 = ASNUM_AS_UNKNOWN;
1813 		} else {
1814 			as_num32 |= (as_num32_comp17 & 0xe000) << 3;
1815 
1816 			if ((as_num32_comp17 & 0x1000) == 0x1000) {
1817 				// keep only ASN registry
1818 			} else {
1819 				as_num32 |= (as_num32_comp17 & 0x0fff);
1820 			};
1821 		};
1822 	};
1823 
1824 	return(as_num32);
1825 };
1826 
1827 
1828 /*
1829  * get GeonameID
1830  */
libipv6calc_db_wrapper_GeonameID_by_addr(const ipv6calc_ipaddr * ipaddrp,unsigned int * data_source_ptr,unsigned int * GeonameID_type_ptr)1831 uint32_t libipv6calc_db_wrapper_GeonameID_by_addr(const ipv6calc_ipaddr *ipaddrp, unsigned int *data_source_ptr, unsigned int *GeonameID_type_ptr) {
1832 	uint32_t GeonameID = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN; // default
1833 	int GeonameID_type = IPV6CALC_DB_GEO_GEONAMEID_TYPE_UNKNOWN;
1834 
1835 	int f = 0, p;
1836 
1837 	int cache_hit = 0;
1838 
1839 	static ipv6calc_ipaddr ipaddr_cache_lastused;
1840 	static uint32_t GeonameID_lastused;
1841 	static int GeonameID_type_lastused;
1842 	static unsigned int data_source_lastused = IPV6CALC_DB_SOURCE_UNKNOWN;
1843 	static int ipaddr_cache_lastused_valid = 0;
1844 
1845 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called: addr=%08x%08x%08x%08x proto=%d", ipaddrp->addr[0], ipaddrp->addr[1], ipaddrp->addr[2], ipaddrp->addr[3], ipaddrp->proto);
1846 
1847 	if (ipaddrp->proto == IPV6CALC_PROTO_IPV4) {
1848 		f = IPV6CALC_DB_FEATURE_NUM_IPV4_TO_GEONAMEID;
1849 		if ((ipaddrp->typeinfo1 & IPV4_ADDR_RESERVED) != 0) {
1850 			// reserved IPv4 address has no GeonameID
1851 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv4 address: %08x is reserved (skip GeonameID lookup)", (unsigned int) ipaddrp->addr[0]);
1852 			goto END_libipv6calc_db_wrapper;
1853 		};
1854 	} else if (ipaddrp->proto == IPV6CALC_PROTO_IPV6) {
1855 		f = IPV6CALC_DB_FEATURE_NUM_IPV6_TO_AS;
1856 		if ((ipaddrp->typeinfo1 & IPV6_ADDR_RESERVED) != 0) {
1857 			// reserved IPv4 address has no GeonameID
1858 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv6 address prefix (0-63): %08x%08x is reserved (skip GeonameID lookup)", (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
1859 			goto END_libipv6calc_db_wrapper;
1860 		};
1861 	} else {
1862 		ERRORPRINT_WA("unsupported proto=%d (FIX CODE)", ipaddrp->proto);
1863 		exit(EXIT_FAILURE);
1864 	};
1865 
1866 	if ((ipaddr_cache_lastused_valid == 1)
1867 	    &&	(ipaddr_cache_lastused.proto == ipaddrp->proto)
1868 	    && 	(ipaddr_cache_lastused.addr[0] == ipaddrp->addr[0])
1869 	    && 	(ipaddr_cache_lastused.addr[1] == ipaddrp->addr[1])
1870 	    && 	(ipaddr_cache_lastused.addr[2] == ipaddrp->addr[2])
1871 	    && 	(ipaddr_cache_lastused.addr[3] == ipaddrp->addr[3])
1872 	) {
1873 		GeonameID = GeonameID_lastused;
1874 
1875 		// set only data_source from cache if caller request it
1876 		if (data_source_ptr != NULL) {
1877 			*data_source_ptr = data_source_lastused;
1878 		};
1879 
1880 		// set only source from cache if caller request it
1881 		if (GeonameID_type_ptr != NULL) {
1882 			*GeonameID_type_ptr = GeonameID_type_lastused;
1883 		};
1884 
1885 		cache_hit = 1;
1886 		goto END_libipv6calc_db_wrapper; // ok
1887 	};
1888 
1889 	// run through priorities
1890 	for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
1891 		switch(wrapper_features_selector[f][p]) {
1892 		    case 0:
1893 			// last
1894 			goto END_libipv6calc_db_wrapper; // ok
1895 			break;
1896 
1897 		    case IPV6CALC_DB_SOURCE_GEOIP2:
1898 #ifdef SUPPORT_GEOIP2
1899 			if (wrapper_GeoIP2_status == 1) {
1900 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now GeoIP2");
1901 
1902 				GeonameID = libipv6calc_db_wrapper_GeoIP2_wrapper_GeonameID_by_addr(ipaddrp, &GeonameID_type);
1903 				if (GeonameID != IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) {
1904 					data_source_lastused = IPV6CALC_DB_SOURCE_GEOIP2;
1905 					goto END_libipv6calc_db_wrapper; // ok
1906 				} else {
1907 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called GeoIP (MaxMindDB) did not return a valid GeonameID");
1908 				};
1909 			};
1910 #endif
1911 			break;
1912 
1913 		    case IPV6CALC_DB_SOURCE_DBIP2:
1914 #ifdef SUPPORT_DBIP2
1915 			if (wrapper_DBIP2_status == 1) {
1916 
1917 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now DBIP2");
1918 
1919 				GeonameID = libipv6calc_db_wrapper_DBIP2_wrapper_GeonameID_by_addr(ipaddrp, &GeonameID_type);
1920 				if (GeonameID != IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) {
1921 					data_source_lastused = IPV6CALC_DB_SOURCE_DBIP2;
1922 					goto END_libipv6calc_db_wrapper; // ok
1923 				} else {
1924 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called db-ip.com (MaxMindDB) did not return a valid GeonameID");
1925 				};
1926 			};
1927 #endif
1928 			break;
1929 
1930 		    default:
1931 			goto END_libipv6calc_db_wrapper; // dummy goto in case no db is enabled
1932 			break;
1933 		};
1934 	};
1935 
1936 END_libipv6calc_db_wrapper:
1937 	if (GeonameID != IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN) {
1938 		// store in last used cache
1939 		ipaddr_cache_lastused_valid = 1;
1940 		GeonameID_lastused = GeonameID;
1941 		GeonameID_type_lastused = GeonameID_type;
1942 		ipaddr_cache_lastused = *ipaddrp;
1943 
1944 		// set only data_source from cache if caller request it
1945 		if (data_source_ptr != NULL) {
1946 			*data_source_ptr = data_source_lastused;
1947 		};
1948 
1949 		if (GeonameID_type_ptr != NULL) {
1950 			*GeonameID_type_ptr = GeonameID_type_lastused;
1951 		};
1952 	};
1953 
1954 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: addr=%08x%08x%08x%08x GeonameID=%u GeonameID_type=%d %s (data_source=%d)", ipaddrp->addr[0], ipaddrp->addr[1], ipaddrp->addr[2], ipaddrp->addr[3], GeonameID, GeonameID_type, (cache_hit == 1 ? " (cached)" : ""), data_source_lastused);
1955 
1956 	return(GeonameID);
1957 };
1958 
1959 
1960 /*
1961  * Get IEEE vendor string
1962  * in:  macaddrp
1963  * mod: resultstring
1964  * out: 0=found, 1=not found
1965  */
libipv6calc_db_wrapper_ieee_vendor_string_by_macaddr(char * resultstring,const size_t resultstring_length,const ipv6calc_macaddr * macaddrp)1966 int libipv6calc_db_wrapper_ieee_vendor_string_by_macaddr(char *resultstring, const size_t resultstring_length, const ipv6calc_macaddr *macaddrp) {
1967 	int retval = 1;
1968 
1969 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called with mp=%p", macaddrp); // avoid -Werror=unused-parameter
1970 
1971 #ifdef SUPPORT_BUILTIN
1972 	retval = libipv6calc_db_wrapper_BuiltIn_ieee_vendor_string_by_macaddr(resultstring, resultstring_length, macaddrp);
1973 #else
1974 	snprintf(resultstring, resultstring_length, "(BUILTIN databases not compiled in)");
1975 	retval = 0;
1976 #endif
1977 	return (retval);
1978 };
1979 
1980 
1981 /*
1982  * Get short IEEE vendor string
1983  * in:  macaddrp
1984  * mod: resultstring
1985  * out: 0=found, 1=not found
1986  */
libipv6calc_db_wrapper_ieee_vendor_string_short_by_macaddr(char * resultstring,const size_t resultstring_length,const ipv6calc_macaddr * macaddrp)1987 int libipv6calc_db_wrapper_ieee_vendor_string_short_by_macaddr(char *resultstring, const size_t resultstring_length, const ipv6calc_macaddr *macaddrp) {
1988 	int retval = 1;
1989 
1990 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called with mp=%p", macaddrp); // avoid -Werror=unused-parameter
1991 
1992 #ifdef SUPPORT_BUILTIN
1993 	retval = libipv6calc_db_wrapper_BuiltIn_ieee_vendor_string_short_by_macaddr(resultstring, resultstring_length, macaddrp);
1994 #else
1995 	snprintf(resultstring, resultstring_length, "(BUILTIN databases not compiled in)");
1996 	retval = 0;
1997 #endif
1998 	return (retval);
1999 };
2000 
2001 
2002 /********************************************
2003  * IPv4/IPv6 -> Registry lookup
2004  ********************************************/
2005 
2006 /*
2007  * Get reserved IPv4 address information as string
2008  * ret: NULL: not reserved, !=NULL: pointer to string
2009  */
libipv6calc_db_wrapper_reserved_string_by_ipv4addr(const ipv6calc_ipv4addr * ipv4addrp)2010 static const char *libipv6calc_db_wrapper_reserved_string_by_ipv4addr(const ipv6calc_ipv4addr *ipv4addrp) {
2011 	const char *info = NULL;
2012 
2013 	uint32_t ipv4 = ipv4addr_getdword(ipv4addrp);
2014 
2015 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv4 address: %08x", (unsigned int) ipv4);
2016 
2017 	// see also: https://en.wikipedia.org/wiki/Reserved_IP_addresses
2018 
2019 	if ((ipv4 & 0xff000000u) == 0x00000000u) {
2020 		// 0.0.0.0/8 (RFC 1122)
2021 		info = "reserved(RFC1122#3.2.1.3)";
2022 	} else if ((ipv4 & 0xff000000u) == 0x0a000000u) {
2023 		// 10.0.0.0/8 (RFC 1918)
2024 		info = "reserved(RFC1918#3)";
2025 	} else if ((ipv4 & 0xffc00000u) == 0x64400000u) {
2026 		// 100.64.0.0/10 (RFC 6598)
2027 		info = "reserved(RFC6598)";
2028 	} else if ((ipv4 & 0xff000000u) == 0x7f000000u) {
2029 		// 127.0.0.0/8 (RFC 1122)
2030 		info = "reserved(RFC1122#3.2.1.3)";
2031 	} else if ((ipv4 & 0xffff0000u) == 0xa9fe0000u) {
2032 		// 169.254.0.0/16 (RFC 1918)
2033 		info = "reserved(RFC3927#1)";
2034 	} else if ((ipv4 & 0xfff00000u) == 0xac100000u) {
2035 		// 172.16.0.0/12 (RFC 1918)
2036 		info = "reserved(RFC1918#3)";
2037 	} else if ((ipv4 & 0xffff0000u) == 0xc0a80000u) {
2038 		// 192.168.0.0/16 (RFC 1918)
2039 		info = "reserved(RFC1918#3)";
2040 	} else if ((ipv4 & 0xffffff00u) == 0xc0000000u) {
2041 		// 192.0.0.0/24 (RFC 5736)
2042 		info = "reserved(RFC5736#1)";
2043 	} else if ((ipv4 & 0xffffff00u) == 0xc0000200u) {
2044 		// 192.0.2.0/24 (RFC 3330)
2045 		info = "reserved(RFC5737#1)";
2046 	} else if ((ipv4 & 0xffffff00u) == 0xc0586300u) {
2047 		// 192.88.99.0/24 (RFC 3068)
2048 		info = "reserved(RFC3068#2.3)";
2049 	} else if ((ipv4 & 0xfffe0000u) == 0xc6120000u) {
2050 		// 198.18.0.0/15 (RFC 2544)
2051 		info = "reserved(RFC2544#C.2.2)";
2052 	} else if ((ipv4 & 0xffffff00u) == 0xc6336400u) {
2053 		// 198.51.100.0/24 (RFC 5737)
2054 		info = "reserved(RFC5737#3)";
2055 	} else if ((ipv4 & 0xffffff00u) == 0xcb007100u) {
2056 		// 203.0.113.0/24 (RFC 5737)
2057 		info = "reserved(RFC5737#3)";
2058 	} else if ((ipv4 & 0xf0000000u) == 0xe0000000u) {
2059 		// 224.0.0.0/4 (RFC 3171)
2060 		info = "reserved(RFC3171#2)";
2061 	} else if ((ipv4 & 0xffffffffu) == 0xffffffffu) {
2062 		// 255.255.255.255/32
2063 		info = "reserved(RFC919#7)";
2064 	} else if ((ipv4 & 0xf0000000u) == 0xf0000000u) {
2065 		// 240.0.0.0/4 (RFC 1112)
2066 		info = "reserved(RFC1112#4)";
2067 	};
2068 
2069 	if (info == NULL) {
2070 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv4 address is not reserved: %08x", (unsigned int) ipv4);
2071 	} else {
2072 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv4 address is reserved: %08x (%s)", (unsigned int) ipv4, info);
2073 	};
2074 
2075 	return(info);
2076 };
2077 
2078 
2079 /*
2080  * Get reserved IPv6 address information as string
2081  * ret: NULL: not reserved, !=NULL: pointer to string
2082  */
libipv6calc_db_wrapper_reserved_string_by_ipv6addr(const ipv6calc_ipv6addr * ipv6addrp)2083 static const char *libipv6calc_db_wrapper_reserved_string_by_ipv6addr(const ipv6calc_ipv6addr *ipv6addrp) {
2084 	const char *info = NULL;
2085 
2086 	uint32_t ipv6_00_31 = ipv6addr_getdword(ipv6addrp, 0);
2087 	uint32_t ipv6_32_63 = ipv6addr_getdword(ipv6addrp, 1);
2088 	uint32_t ipv6_64_95 = ipv6addr_getdword(ipv6addrp, 2);
2089 	uint32_t ipv6_96_127 = ipv6addr_getdword(ipv6addrp, 3);
2090 
2091 	uint16_t ipv6_00_15 = ipv6addr_getword(ipv6addrp, 0);
2092 
2093 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called: addr=%08x%08x%08x%08x"
2094 		, (unsigned int) ipv6_00_31
2095 		, (unsigned int) ipv6_32_63
2096 		, (unsigned int) ipv6_64_95
2097 		, (unsigned int) ipv6_96_127
2098 	);
2099 
2100 	// see also: https://en.wikipedia.org/wiki/Reserved_IP_addresses
2101 	//
2102 	if ((ipv6_00_31 == 0) && (ipv6_32_63 == 0) && (ipv6_64_95 == 0) && (ipv6_96_127 == 0)) {
2103 		// :: (RFC 4291)
2104 		info = "reserved(RFC4291#2.5.2)";
2105 	} else if ((ipv6_00_31 == 0) && (ipv6_32_63 == 0) && (ipv6_64_95 == 0) && (ipv6_96_127 == 1)) {
2106 		// ::1 (RFC 4291)
2107 		info = "reserved(RFC4291#2.5.3)";
2108 	} else if ((ipv6_00_31 == 0) && (ipv6_32_63 == 0) && (ipv6_64_95 == 0)) {
2109 		// ::x.x.x.x (RFC 4291)
2110 		info = "reserved(RFC4291#2.5.5.1)";
2111 	} else if ((ipv6_00_31 == 0) && (ipv6_32_63 == 0) && (ipv6_64_95 == 0x0000ffff)) {
2112 		// ::ffff:x.x.x.x (RFC 4291)
2113 		info = "reserved(RFC4291#2.5.5.2)";
2114 	} else if ((ipv6_00_31 == 0x01000000) && (ipv6_32_63 == 0)) {
2115 		// 0100::0/64 (RFC 6666)
2116 		info = "reserved(RFC6666)";
2117 	} else if (ipv6_00_31 == 0x20010000) {
2118 		// 2001:0000::/32 (RFC 4380)
2119 		info = "reserved(RFC4380#6)";
2120 	} else if ((ipv6_00_31 & 0xfffffff0) == 0x20010010) {
2121 		// 2001:0010::/28 (RFC 4843)
2122 		info = "reserved(RFC4843#2)";
2123 	} else if (ipv6_00_31 == 0x20010db8) {
2124 		// 2001:0db8::/32 (RFC 3849)
2125 		info = "reserved(RFC3849#4)";
2126 	} else if ((ipv6_00_15 & 0xffff) == 0x2002) {
2127 		// 2002::/16 (RFC 3056)
2128 		info = "reserved(RFC3056#2)";
2129 	} else if ((ipv6_00_15 & 0xfe00) == 0xfc00) {
2130 		// fc00::/7 (RFC 4193)
2131 		info = "reserved(RFC4193#3.1)";
2132 	} else if ((ipv6_00_15 & 0xffe0) == 0xfe80) {
2133 		// fe80::/10 (RFC 4291)
2134 		info = "reserved(RFC4291#2.5.6)";
2135 	} else if ((ipv6_00_15 & 0xffe0) == 0xfec0) {
2136 		// fec0::/10 (RFC 4291)
2137 		info = "reserved(RFC4291#2.5.7)";
2138 	} else if ((ipv6_00_15 & 0xff00) == 0xff00) {
2139 		// ffxx::/8 (RFC 4291)
2140 		info = "reserved(RFC4291#2.7)";
2141 	};
2142 
2143 	if (info == NULL) {
2144 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv6 address is not reserved: %08x%08x%08x%08x", (unsigned int) ipv6_00_31, (unsigned int) ipv6_32_63, (unsigned int) ipv6_64_95, (unsigned int) ipv6_96_127);
2145 	} else {
2146 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Given IPv6 address is reserved: %08x%08x%08x%08x (%s)", (unsigned int) ipv6_00_31, (unsigned int) ipv6_32_63, (unsigned int) ipv6_64_95, (unsigned int) ipv6_96_127, info);
2147 	};
2148 
2149 	return(info);
2150 };
2151 
2152 
2153 /*
2154  * get registry string of an IPv4 address
2155  *
2156  * in:  ipv4addr = IPv4 address structure
2157  * out: *resultstring = Registry string
2158  * ret: 0: ok, 1: unknown, 2: reserved
2159  */
libipv6calc_db_wrapper_registry_string_by_ipv4addr(const ipv6calc_ipv4addr * ipv4addrp,char * resultstring,const size_t resultstring_length)2160 int libipv6calc_db_wrapper_registry_string_by_ipv4addr(const ipv6calc_ipv4addr *ipv4addrp, char *resultstring, const size_t resultstring_length) {
2161 	int retval = 1;
2162 	int registry;
2163 
2164 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called");
2165 
2166 	const char *info = libipv6calc_db_wrapper_reserved_string_by_ipv4addr(ipv4addrp);
2167 
2168 	if (info != NULL) {
2169 		// is reserved
2170 		snprintf(resultstring, resultstring_length, "%s", info);
2171 		retval = 2;
2172 	} else {
2173 		registry = libipv6calc_db_wrapper_registry_num_by_ipv4addr(ipv4addrp);
2174 		snprintf(resultstring, resultstring_length, "%s", libipv6calc_registry_string_by_num(registry));
2175 		if (registry != REGISTRY_UNKNOWN) {
2176 			retval = 0;
2177 		} else {
2178 			retval = 1;
2179 		};
2180 	};
2181 
2182 	return (retval);
2183 };
2184 
2185 
2186 /*
2187  * get registry number of an IPv4 address
2188  *
2189  * in:  ipv4addr = IPv4 address structure
2190  * out: registry number
2191  */
libipv6calc_db_wrapper_registry_num_by_ipv4addr(const ipv6calc_ipv4addr * ipv4addrp)2192 int libipv6calc_db_wrapper_registry_num_by_ipv4addr(const ipv6calc_ipv4addr *ipv4addrp) {
2193 	int retval = REGISTRY_UNKNOWN, p, f;
2194 
2195 	int cache_hit = 0;
2196 
2197 	static ipv6calc_ipv4addr cache_lu_ipv4addr;
2198 	static uint32_t cache_lu_ipv4addr_registry_num;
2199 	static int      cache_lu_ipv4addr_valid = 0;
2200 
2201 #if defined SUPPORT_EXTERNAL
2202 	ipv6calc_ipaddr ipaddr;
2203 #endif
2204 
2205 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called: addr=%08x", ipv4addr_getdword(ipv4addrp));
2206 
2207 	if ((cache_lu_ipv4addr_valid == 1)
2208 	    &&  (&cache_lu_ipv4addr.in_addr.s_addr == &ipv4addrp->in_addr.s_addr)
2209 	) {
2210 		retval= cache_lu_ipv4addr_registry_num;
2211 		cache_hit = 1;
2212 		goto END_libipv6calc_db_wrapper_cached;
2213 	};
2214 
2215 	const char *info = libipv6calc_db_wrapper_reserved_string_by_ipv4addr(ipv4addrp);
2216 
2217 	if (info != NULL) {
2218 		retval = REGISTRY_RESERVED;
2219 		goto END_libipv6calc_db_wrapper;
2220 	};
2221 
2222 	f = IPV6CALC_DB_FEATURE_NUM_IPV4_TO_REGISTRY;
2223 
2224 	// run through priorities
2225 	for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
2226 		switch(wrapper_features_selector[f][p]) {
2227 		    case 0:
2228 			// last
2229 			goto END_libipv6calc_db_wrapper; // ok
2230 			break;
2231 
2232 		    case IPV6CALC_DB_SOURCE_BUILTIN:
2233 #ifdef SUPPORT_BUILTIN
2234 			if (wrapper_BuiltIn_status == 1) {
2235 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now BuiltIn");
2236 
2237 				retval = libipv6calc_db_wrapper_BuiltIn_registry_num_by_ipv4addr(ipv4addrp);
2238 			};
2239 #endif
2240 			break;
2241 
2242 		    case IPV6CALC_DB_SOURCE_EXTERNAL:
2243 #ifdef SUPPORT_EXTERNAL
2244 			if (wrapper_External_status == 1) {
2245 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now External");
2246 				CONVERT_IPV4ADDRP_IPADDR(ipv4addrp, ipaddr);
2247 				retval = libipv6calc_db_wrapper_External_registry_num_by_addr(&ipaddr);
2248 			};
2249 #endif
2250 			break;
2251 
2252 		    default:
2253 			goto END_libipv6calc_db_wrapper; // dummy goto in case no db is enabled
2254 			break;
2255 		};
2256 	};
2257 
2258 END_libipv6calc_db_wrapper:
2259 	// store in last used cache
2260 	cache_lu_ipv4addr_valid = 1;
2261 	cache_lu_ipv4addr_registry_num = retval;
2262 	cache_lu_ipv4addr.in_addr = ipv4addrp->in_addr;
2263 
2264 END_libipv6calc_db_wrapper_cached:
2265 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: addr=%08x reg=%d%s"
2266 		, ipv4addr_getdword(ipv4addrp)
2267 		, retval
2268 		, (cache_hit == 1 ? " (cached)" : "")
2269 	);
2270 	return (retval);
2271 };
2272 
2273 
2274 /*
2275  * get registry string of an IPv6 address
2276  *
2277  * in:  ipv6addr = IPv6 address structure
2278  * out: *resultstring = Registry string
2279  * ret: 0: ok, 1: unknown, 2: reserved
2280  */
libipv6calc_db_wrapper_registry_string_by_ipv6addr(const ipv6calc_ipv6addr * ipv6addrp,char * resultstring,const size_t resultstring_length)2281 int libipv6calc_db_wrapper_registry_string_by_ipv6addr(const ipv6calc_ipv6addr *ipv6addrp, char *resultstring, const size_t resultstring_length) {
2282 	int retval = 1;
2283 	int registry;
2284 
2285 	DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Called");
2286 
2287 	const char *info = libipv6calc_db_wrapper_reserved_string_by_ipv6addr(ipv6addrp);
2288 
2289 	if (info != NULL) {
2290 		// is reserved
2291 		snprintf(resultstring, resultstring_length, "%s", info);
2292 		retval = 2;
2293 	} else {
2294 		registry = libipv6calc_db_wrapper_registry_num_by_ipv6addr(ipv6addrp);
2295 		snprintf(resultstring, resultstring_length, "%s", libipv6calc_registry_string_by_num(registry));
2296 
2297 		if (registry != REGISTRY_UNKNOWN) {
2298 			retval = 0;
2299 		} else {
2300 			retval = 1;
2301 		};
2302 	};
2303 
2304 	return (retval);
2305 };
2306 
2307 
2308 /*
2309  * get registry number of an IPv6 address
2310  *
2311  * in:  ipv6addr = IPv6 address structure
2312  * out: assignment number (-1 = no result)
2313  */
libipv6calc_db_wrapper_registry_num_by_ipv6addr(const ipv6calc_ipv6addr * ipv6addrp)2314 int libipv6calc_db_wrapper_registry_num_by_ipv6addr(const ipv6calc_ipv6addr *ipv6addrp) {
2315 	int retval = REGISTRY_UNKNOWN, p, f;
2316 
2317 	int cache_hit = 0;
2318 
2319 	static ipv6calc_ipv6addr cache_lu_ipv6addr;
2320 	static uint32_t cache_lu_ipv6addr_registry_num;
2321 	static int      cache_lu_ipv6addr_valid = 0;
2322 
2323 #if defined SUPPORT_EXTERNAL
2324 	ipv6calc_ipaddr ipaddr;
2325 #endif
2326 
2327 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called: addr=%08x%08x%08x%08x", ipv6addr_getdword(ipv6addrp, 0), ipv6addr_getdword(ipv6addrp, 1), ipv6addr_getdword(ipv6addrp, 2), ipv6addr_getdword(ipv6addrp, 3));
2328 
2329 	if ((cache_lu_ipv6addr_valid == 1)
2330 #ifdef __KAME__ // FreeBSD misses s6_addr8/16/32 in non-kernel include, also union has different name in glibc (__in6_u vs.  __u6_addr) :-(
2331 	    &&  (&cache_lu_ipv6addr.in6_addr.__u6_addr.__u6_addr32[0] == &ipv6addrp->in6_addr.__u6_addr.__u6_addr32[0])
2332 	    &&  (&cache_lu_ipv6addr.in6_addr.__u6_addr.__u6_addr32[1] == &ipv6addrp->in6_addr.__u6_addr.__u6_addr32[1])
2333 	    &&  (&cache_lu_ipv6addr.in6_addr.__u6_addr.__u6_addr32[2] == &ipv6addrp->in6_addr.__u6_addr.__u6_addr32[2])
2334 	    &&  (&cache_lu_ipv6addr.in6_addr.__u6_addr.__u6_addr32[3] == &ipv6addrp->in6_addr.__u6_addr.__u6_addr32[3])
2335 #else
2336 	    &&  (&cache_lu_ipv6addr.in6_addr.s6_addr32[0] == &ipv6addrp->in6_addr.s6_addr32[0])
2337 	    &&  (&cache_lu_ipv6addr.in6_addr.s6_addr32[1] == &ipv6addrp->in6_addr.s6_addr32[1])
2338 	    &&  (&cache_lu_ipv6addr.in6_addr.s6_addr32[2] == &ipv6addrp->in6_addr.s6_addr32[2])
2339 	    &&  (&cache_lu_ipv6addr.in6_addr.s6_addr32[3] == &ipv6addrp->in6_addr.s6_addr32[3])
2340 #endif
2341 	) {
2342 		retval= cache_lu_ipv6addr_registry_num;
2343 		cache_hit = 1;
2344 		goto END_libipv6calc_db_wrapper_cached;
2345 	};
2346 
2347 	const char *info = libipv6calc_db_wrapper_reserved_string_by_ipv6addr(ipv6addrp);
2348 
2349 	if (info != NULL) {
2350 		retval = REGISTRY_RESERVED;
2351 		goto END_libipv6calc_db_wrapper;
2352 	};
2353 
2354 	if (ipv6addr_getword(ipv6addrp, 0) == 0x3ffe) {
2355 		// special handling of 6BONE
2356 		retval = REGISTRY_6BONE;
2357 		goto END_libipv6calc_db_wrapper;
2358 	};
2359 
2360 	f = IPV6CALC_DB_FEATURE_NUM_IPV6_TO_REGISTRY;
2361 
2362 	// run through priorities
2363 	for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
2364 		switch(wrapper_features_selector[f][p]) {
2365 		    case 0:
2366 			// last
2367 			goto END_libipv6calc_db_wrapper; // ok
2368 			break;
2369 
2370 		    case IPV6CALC_DB_SOURCE_BUILTIN:
2371 #ifdef SUPPORT_BUILTIN
2372 			if (wrapper_BuiltIn_status == 1) {
2373 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now BuiltIn");
2374 
2375 				retval = libipv6calc_db_wrapper_BuiltIn_registry_num_by_ipv6addr(ipv6addrp);
2376 			};
2377 #endif
2378 			break;
2379 
2380 		    case IPV6CALC_DB_SOURCE_EXTERNAL:
2381 #ifdef SUPPORT_EXTERNAL
2382 			if (wrapper_External_status == 1) {
2383 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now External");
2384 				CONVERT_IPV6ADDRP_IPADDR(ipv6addrp, ipaddr);
2385 				retval = libipv6calc_db_wrapper_External_registry_num_by_addr(&ipaddr);
2386 			};
2387 #endif
2388 			break;
2389 
2390 		    default:
2391 			goto END_libipv6calc_db_wrapper; // dummy goto in case no db is enabled
2392 			break;
2393 		};
2394 	};
2395 
2396 END_libipv6calc_db_wrapper:
2397 	// store in last used cache
2398 	cache_lu_ipv6addr_valid = 1;
2399 	cache_lu_ipv6addr_registry_num = retval;
2400 	cache_lu_ipv6addr.in6_addr = ipv6addrp->in6_addr;
2401 
2402 END_libipv6calc_db_wrapper_cached:
2403 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: addr=%08x%08x%08x%08x reg=%d%s"
2404 		, ipv6addr_getdword(ipv6addrp, 0)
2405 		, ipv6addr_getdword(ipv6addrp, 1)
2406 		, ipv6addr_getdword(ipv6addrp, 2)
2407 		, ipv6addr_getdword(ipv6addrp, 3)
2408 		, retval
2409 		, (cache_hit == 1 ? " (cached)" : "")
2410 	);
2411 	return (retval);
2412 };
2413 
2414 
2415 /*
2416  * get info string of an IPv4 address
2417  *
2418  * in:  ipv4addr = IPv4 address structure
2419  * out: *resultstring = Registry string
2420  * ret: 0: ok
2421  */
libipv6calc_db_wrapper_info_by_ipv4addr(const ipv6calc_ipv4addr * ipv4addrp,char * string,const size_t string_len)2422 int libipv6calc_db_wrapper_info_by_ipv4addr(const ipv6calc_ipv4addr *ipv4addrp, char *string, const size_t string_len) {
2423 	int retval = 1, f, p;
2424 
2425 #if defined SUPPORT_EXTERNAL
2426 	ipv6calc_ipaddr ipaddr;
2427 #endif
2428 
2429 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called: addr=%08x", ipv4addr_getdword(ipv4addrp));
2430 
2431 	f = IPV6CALC_DB_FEATURE_NUM_IPV4_TO_INFO;
2432 
2433 	// run through priorities
2434 	for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
2435 		switch(wrapper_features_selector[f][p]) {
2436 		    case 0:
2437 			// last
2438 			goto END_libipv6calc_db_wrapper; // ok
2439 			break;
2440 
2441 		    case IPV6CALC_DB_SOURCE_BUILTIN:
2442 #ifdef SUPPORT_BUILTIN
2443 			if (wrapper_BuiltIn_status == 1) {
2444 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now BuiltIn");
2445 
2446 				retval = libipv6calc_db_wrapper_BuiltIn_info_by_ipv4addr(ipv4addrp, string, string_len);
2447 			};
2448 #endif
2449 			break;
2450 
2451 		    case IPV6CALC_DB_SOURCE_EXTERNAL:
2452 #ifdef SUPPORT_EXTERNAL
2453 			if (wrapper_External_status == 1) {
2454 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now External");
2455 				CONVERT_IPV4ADDRP_IPADDR(ipv4addrp, ipaddr);
2456 				retval = libipv6calc_db_wrapper_External_info_by_ipaddr(&ipaddr, string, string_len);
2457 			};
2458 #endif
2459 			break;
2460 
2461 		    default:
2462 			snprintf(string, string_len, "unknown (databases not compiled in)");
2463 			retval = 0;
2464 			goto END_libipv6calc_db_wrapper; // dummy goto in case no db is enabled
2465 			break;
2466 		};
2467 	};
2468 
2469 END_libipv6calc_db_wrapper:
2470 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: %s", string);
2471 
2472 	return (retval);
2473 };
2474 
2475 
2476 /*
2477  * get info string of an IPv6 address
2478  *
2479  * in:  ipv6addr = IPv6 address structure
2480  * out: *resultstring = Registry string
2481  * ret: 0: ok
2482  */
libipv6calc_db_wrapper_info_by_ipv6addr(const ipv6calc_ipv6addr * ipv6addrp,char * string,const size_t string_len)2483 int libipv6calc_db_wrapper_info_by_ipv6addr(const ipv6calc_ipv6addr *ipv6addrp, char *string, const size_t string_len) {
2484 	int retval = 1, p, f;
2485 
2486 #if defined SUPPORT_EXTERNAL
2487 	ipv6calc_ipaddr ipaddr;
2488 #endif
2489 
2490 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called: addr=%08x%08x%08x%08x", ipv6addr_getdword(ipv6addrp, 0), ipv6addr_getdword(ipv6addrp, 1), ipv6addr_getdword(ipv6addrp, 2), ipv6addr_getdword(ipv6addrp, 3));
2491 
2492 	f = IPV6CALC_DB_FEATURE_NUM_IPV6_TO_INFO;
2493 
2494 	// run through priorities
2495 	for (p = 0; p < IPV6CALC_DB_PRIO_MAX; p++) {
2496 		switch(wrapper_features_selector[f][p]) {
2497 		    case 0:
2498 			// last
2499 			goto END_libipv6calc_db_wrapper; // ok
2500 			break;
2501 
2502 		    case IPV6CALC_DB_SOURCE_BUILTIN:
2503 #ifdef SUPPORT_BUILTIN
2504 			if (wrapper_BuiltIn_status == 1) {
2505 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now BuiltIn");
2506 
2507 				retval = libipv6calc_db_wrapper_BuiltIn_info_by_ipv6addr(ipv6addrp, string, string_len);
2508 			};
2509 #endif
2510 			break;
2511 
2512 		    case IPV6CALC_DB_SOURCE_EXTERNAL:
2513 #ifdef SUPPORT_EXTERNAL
2514 			if (wrapper_External_status == 1) {
2515 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Call now External");
2516 				CONVERT_IPV6ADDRP_IPADDR(ipv6addrp, ipaddr);
2517 				retval = libipv6calc_db_wrapper_External_info_by_ipaddr(&ipaddr, string, string_len);
2518 			};
2519 #endif
2520 			break;
2521 
2522 		    default:
2523 			snprintf(string, string_len, "unknown (databases not compiled in)");
2524 			retval = 0;
2525 			goto END_libipv6calc_db_wrapper; // dummy goto in case no db is enabled
2526 			break;
2527 		};
2528 	};
2529 
2530 END_libipv6calc_db_wrapper:
2531 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Result: %s", string);
2532 
2533 	return (retval);
2534 };
2535 
2536 
2537 
2538 #ifdef HAVE_BERKELEY_DB_SUPPORT
2539 /********************************************
2540  * some generic Berkeley DB helper functions
2541  ********************************************/
2542 
2543 /*
2544  * get value of token from Berkeley DB
2545  * in : DB pointer, token, max length of value
2546  * out: value
2547  * ret: 0=ok -1=error
2548  */
libipv6calc_db_wrapper_bdb_get_data_by_key(DB * dbp,char * token,char * value,const size_t value_size)2549 int libipv6calc_db_wrapper_bdb_get_data_by_key(DB *dbp, char *token, char *value, const size_t value_size) {
2550 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called: dbp=%p token=%s", dbp, token);
2551 
2552 	DBT key, data;
2553 	int ret;
2554 
2555 	memset(&key, 0, sizeof(key));
2556 	memset(&data, 0, sizeof(data));
2557 
2558 	key.data = token;
2559 	key.size = strlen(token);
2560 
2561 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "try to get key.data=%p key.size=%d", key.data, key.size);
2562 
2563 	if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) != 0) {
2564 		dbp->err(dbp, ret, "DB->get token=%s", token);
2565 		return(-1);
2566 	};
2567 
2568 	snprintf(value, (data.size + 1) >= value_size ? value_size : data.size + 1, "%s", (char *) data.data);
2569 
2570 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Return: dbp=%p token=%s value=%s", dbp, token, value);
2571 
2572 	return(0);
2573 };
2574 
2575 
2576 
2577 /*
2578  * generic fetch of a Berkeley DB row
2579  * in: data_ptr has to point to proper variable (not a pointer)
2580  */
libipv6calc_db_wrapper_bdb_fetch_row(DB * db_ptr,const uint8_t db_format,const long int row,uint32_t * data_1_00_31_ptr,uint32_t * data_1_32_63_ptr,uint32_t * data_2_00_31_ptr,uint32_t * data_2_32_63_ptr,void * data_ptr)2581 int libipv6calc_db_wrapper_bdb_fetch_row(
2582 	DB 			*db_ptr,		// pointer to DB
2583 	const uint8_t		db_format,		// DB format
2584 	const long int		row,			// row number
2585 	uint32_t		*data_1_00_31_ptr,	// data 1 (MSB in case of 64 bits)
2586 	uint32_t		*data_1_32_63_ptr,	// data 1 (LSB in case of 64 bits)
2587 	uint32_t		*data_2_00_31_ptr,	// data 2 (MSB in case of 64 bits)
2588 	uint32_t		*data_2_32_63_ptr,	// data 2 (LSB in case of 64 bits)
2589 	void			*data_ptr		// pointer to data
2590 	) {
2591 
2592 	int retval = -1;
2593 
2594 	const char *db_format_row[] = {
2595 		"%u;%u;%[^%]",			// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_DEC_32x2
2596 		"%u;%u;%u;%u;%[^%]",		// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_DEC_32x4
2597 		"%x;%x;%[^%]",			// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x2
2598 		"%x;%x;%x;%x;%[^%]",		// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x4
2599 		"%x;%x;%d;%[^%]",			// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_VALUE_32x2
2600 		"%x;%x;%x;%x;%d;%[^%]",		// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_VALUE_32x4
2601 		"0x%x;0x%x;%[^%]",			// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_PREF_32x2
2602 		"0x%x;0x%x;0x%x;0x%x;%[^%]",	// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_PREF_32x4
2603 	};
2604 
2605 	const int db_format_values[] = {
2606 		3,	// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_DEC_32x2
2607 		5,	// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_DEC_32x4
2608 		3,	// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x2
2609 		5,	// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x4
2610 		4,	// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_VALUE_32x2
2611 		6,	// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_VALUE_32x4
2612 		3,	// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_PREF_32x2
2613 		5,	// IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_PREF_32x4
2614 	};
2615 
2616 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called db_ptr=%p, data_ptr=%p", db_ptr, data_ptr);
2617 
2618 	if (MAXENTRIES_ARRAY(db_format_row) != MAXENTRIES_ARRAY(db_format_values)) {
2619 		ERRORPRINT_NA("inconsistent array definition (FIX CODE)");
2620 		exit(EXIT_FAILURE);
2621 	};
2622 
2623 	if (db_format >= MAXENTRIES_ARRAY(db_format_row)) {
2624 		ERRORPRINT_WA("unsupported db_format (FIX CODE): %u", db_format);
2625 		exit(EXIT_FAILURE);
2626 	};
2627 
2628 	char datastring[IPV6CALC_STRING_MAX];
2629 
2630 	DBT key, data;
2631 
2632 	db_recno_t recno = row;
2633 
2634 	memset(&key, 0, sizeof(key));
2635 	memset(&data, 0, sizeof(data));
2636 
2637 	key.data = &recno;
2638 	key.size = sizeof(recno);
2639 
2640 	int ret, value;
2641 
2642 	// DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Try to get row");
2643 
2644 	ret = db_ptr->get(db_ptr, NULL, &key, &data, 0);
2645 
2646 	// DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "get executed");
2647 
2648 	if (ret != 0) {
2649 		db_ptr->err(db_ptr, ret, "DB->get");
2650 		goto END_libipv6calc_db_wrapper_bdb_fetch_row;
2651 	};
2652 
2653 	// DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Got row");
2654 
2655 	snprintf(datastring, (data.size + 1) >= sizeof(datastring) ? sizeof(datastring) : data.size + 1, "%s", (char *) data.data);
2656 
2657 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "start parsing database row %u: %s (size=%d) data_ptr=%p values=%u format=%s", recno, datastring, data.size, data_ptr, db_format_values[db_format], db_format_row[db_format]);
2658 
2659 	if (db_format_values[db_format] == 3) {
2660 		ret = sscanf(datastring, db_format_row[db_format], data_1_00_31_ptr, data_2_00_31_ptr, (char *) data_ptr);
2661 		*data_1_32_63_ptr = 0;
2662 		*data_2_32_63_ptr = 0;
2663 	} else if (db_format_values[db_format] == 4) {
2664 		ret = sscanf(datastring, db_format_row[db_format], data_1_00_31_ptr, data_2_00_31_ptr, &value, (char *) data_ptr);
2665 		*data_1_32_63_ptr = 0;
2666 		*data_2_32_63_ptr = 0;
2667 	} else if (db_format_values[db_format] == 5) {
2668 		ret = sscanf(datastring, db_format_row[db_format], data_1_00_31_ptr, data_1_32_63_ptr, data_2_00_31_ptr, data_2_32_63_ptr, (char *) data_ptr);
2669 	} else if (db_format_values[db_format] == 6) {
2670 		ret = sscanf(datastring, db_format_row[db_format], data_1_00_31_ptr, data_1_32_63_ptr, data_2_00_31_ptr, data_2_32_63_ptr, &value, (char *) data_ptr);
2671 	} else {
2672 		ERRORPRINT_WA("unsupported db_format_values (FIX CODE): %u", db_format_values[db_format]);
2673 		exit(EXIT_FAILURE);
2674 	};
2675 
2676 	if (ret != db_format_values[db_format]) {
2677 		ERRORPRINT_WA("row parsing error, corrupted database: %s (ret=%d format=%s expectedvalues=%d)", datastring, ret, db_format_row[db_format], db_format_values[db_format]);
2678 		goto END_libipv6calc_db_wrapper_bdb_fetch_row;
2679 	};
2680 
2681 	if ((db_format == IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_VALUE_32x4) \
2682 	  || (db_format == IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_VALUE_32x4)) {
2683 		retval = value; // for Longest Match
2684 	} else {
2685 		retval = 0; // ok
2686 	};
2687 
2688 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "database row %lu parsed: data_1_00_31=%08x data_1_32_63=%08x data_2_00_31=%08x data_2_32_63=%08x value=%s)", row, *data_1_00_31_ptr, *data_1_32_63_ptr, *data_2_00_31_ptr, *data_2_32_63_ptr, (char *) data_ptr);
2689 
2690 END_libipv6calc_db_wrapper_bdb_fetch_row:
2691 	return(retval);
2692 };
2693 #endif // HAVE_BERKELEY_DB_SUPPORT
2694 
2695 
2696 /*
2697  * generic internal/external database lookup function
2698  * return:	 -1 : no lookup result
2699  * 		>= 0: matching row
2700  */
libipv6calc_db_wrapper_get_entry_generic(void * db_ptr,const uint8_t data_ptr_type,const uint8_t data_key_type,const uint8_t data_key_format,const uint8_t data_key_length,const uint8_t data_search_type,const uint32_t data_num_rows,const uint32_t lookup_key_00_31,const uint32_t lookup_key_32_63,void * data_ptr,int (* get_array_row)())2701 long int libipv6calc_db_wrapper_get_entry_generic(
2702 	void 		*db_ptr,		// pointer to database in case of IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB, otherwise NULL
2703 	const uint8_t	data_ptr_type,		// type of data_ptr
2704 	const uint8_t	data_key_type,		// key type
2705 	const uint8_t	data_key_format,	// key format
2706 	const uint8_t	data_key_length,	// key length
2707 	const uint8_t	data_search_type,	// search type
2708 	const uint32_t	data_num_rows,		// number of rows
2709 	const uint32_t	lookup_key_00_31,	// lookup key MSB
2710 	const uint32_t	lookup_key_32_63,	// lookup key LSB
2711 	void            *data_ptr,		// pointer to DB data in case of IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB, otherwise NULL
2712 	int  (*get_array_row)()			// function to get array row
2713 	) {
2714 
2715 	int retval = -1;
2716 
2717 	uint32_t value_first_00_31 = 0, value_last_00_31 = 0;
2718 	uint32_t value_first_32_63 = 0, value_last_32_63 = 0;
2719 
2720 #ifdef HAVE_BERKELEY_DB_SUPPORT
2721 	DB *dbp = NULL;
2722 #endif // HAVE_BERKELEY_DB_SUPPORT
2723 
2724 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Called with data_ptr_type=%u data_key_type=%u data_key_format=%u, data_key_length=%u data_num_rows=%u lookup_key_00_31=%08lx lookup_key_32_63=%08lx db_ptr=%p, data_ptr=%p",
2725 		data_ptr_type,
2726 		data_key_type,
2727 		data_key_format,
2728 		data_key_length,
2729 		data_num_rows,
2730 		(long unsigned int) lookup_key_00_31,
2731 		(long unsigned int) lookup_key_32_63,
2732 		db_ptr,
2733 		data_ptr
2734 	);
2735 
2736 	if (data_num_rows < 1) {
2737 		ERRORPRINT_WA("unsupported data_key_num_rows (FIX CODE): %u", data_num_rows);
2738 		exit(EXIT_FAILURE);
2739 	};
2740 
2741 	if (data_num_rows > INT32_MAX) {
2742 		ERRORPRINT_WA("unsupported data_key_num_rows (FIX CODE): %u", data_num_rows);
2743 		exit(EXIT_FAILURE);
2744 	};
2745 
2746 	/* check data_ptr_type */
2747 	switch(data_ptr_type) {
2748 	    case IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_ARRAY:
2749 		if (get_array_row == NULL) {
2750 			ERRORPRINT_NA("get_array_row function is unexpected NULL (FIX CODE)");
2751 			exit(EXIT_FAILURE);
2752 		};
2753 
2754 		if (data_ptr != NULL) {
2755 			ERRORPRINT_NA("data_ptr is unexpected NOT NULL - not supported on IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_ARRAY (FIX CODE)");
2756 			exit(EXIT_FAILURE);
2757 		};
2758 		break;
2759 
2760 #ifdef HAVE_BERKELEY_DB_SUPPORT
2761 	    case IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB:
2762 		if (get_array_row != NULL) {
2763 			ERRORPRINT_NA("get_array_row function is unexpected NOT NULL (FIX CODE)");
2764 			exit(EXIT_FAILURE);
2765 		};
2766 
2767 		if (data_ptr == NULL) {
2768 			ERRORPRINT_NA("data_ptr is unexpected NULL - not supported on IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB (FIX CODE)");
2769 			exit(EXIT_FAILURE);
2770 		};
2771 
2772 		// supported
2773 		dbp = (DB *) db_ptr; // map db_ptr to DB ptr
2774 		break;
2775 #endif // HAVE_BERKELEY_DB_SUPPORT
2776 
2777 	    default:
2778 		ERRORPRINT_WA("unsupported data_ptr_type (FIX CODE): %u", data_ptr_type);
2779 		exit(EXIT_FAILURE);
2780 		break;
2781 	};
2782 
2783 	/* check data_key_length */
2784 	switch(data_key_length) {
2785 	    case 32:
2786 	    case 64:
2787 		// supported
2788 		break;
2789 
2790 	    default:
2791 		ERRORPRINT_WA("unsupported data_key_length (FIX CODE): %d", data_key_length);
2792 		exit(EXIT_FAILURE);
2793 	};
2794 
2795 	/* check data search type */
2796 	switch(data_search_type) {
2797 	    case IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY:
2798 	    case IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_SEQLONGEST:
2799 		// supported
2800 		break;
2801 
2802 	    default:
2803 		ERRORPRINT_WA("unsupported data_search_type (FIX CODE): %d", data_search_type);
2804 		exit(EXIT_FAILURE);
2805 	};
2806 
2807 	/* check data_key_type */
2808 	switch(data_key_type) {
2809 	    case IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_FIRST_LAST:
2810 	    case IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_BASE_MASK:
2811 		// supported
2812 		break;
2813 
2814 	    default:
2815 		ERRORPRINT_WA("unsupported data_key_type (FIX CODE): %u", data_key_type);
2816 		exit(EXIT_FAILURE);
2817 	};
2818 
2819 
2820 	long int i = -1;
2821 	long int match = -1;
2822 	int seqlongest = -1;
2823 	long int i_min, i_max, i_old, i_old2;
2824 	int search_binary_count = 0;
2825 	int search_binary_count_max = (int) uint64_log2(data_num_rows) + 1;
2826 
2827 	int ret = -1;
2828 
2829 	i_min = 0; i_max = data_num_rows - 1; i_old = -1; i_old2 = -1;
2830 
2831 
2832 	if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
2833 		// binary search in provided data
2834 		i = i_max / 2;
2835 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Start binary search over entries: data_num_rows=%u", data_num_rows);
2836 	} else if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_SEQLONGEST) {
2837 		// sequential search in provided data
2838 		i_old = i_max;
2839 		i = 0;
2840 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Start sequential search over entries: data_num_rows=%u", data_num_rows);
2841 	};
2842 
2843 	while (i_old != i) {
2844 		if ((i >= (int32_t) data_num_rows) || (i < 0)) {
2845 			ERRORPRINT_WA("i out of range (FIX CODE): i=%ld data_num_rows=%u", i, data_num_rows);
2846 			exit(EXIT_FAILURE);
2847 		};
2848 
2849 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Analyze entry i=%ld", i);
2850 
2851 		if (data_ptr_type == IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_ARRAY) {
2852 			ret = get_array_row(i, &value_first_00_31, &value_first_32_63, &value_last_00_31, &value_last_32_63);
2853 			if (ret < 0) {
2854 				ERRORPRINT_WA("can't retrieve keys from array for row: %lu", i);
2855 				exit(EXIT_FAILURE);
2856 			};
2857 #ifdef HAVE_BERKELEY_DB_SUPPORT
2858 		} else if (data_ptr_type == IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB) {
2859 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Try to get row from Berkeley DB dbp=%p row=%ld", dbp, i + 1);
2860 			ret = libipv6calc_db_wrapper_bdb_fetch_row(
2861 				dbp,				// pointer to DB
2862 				data_key_format,		// DB format
2863 				(long unsigned int) i + 1,	// row number (BDB starts always with 1, so add offset)
2864 				&value_first_00_31,		// data 1 (MSB in case of 64 bits)
2865 				&value_first_32_63,		// data 1 (LSB in case of 64 bits)
2866 				&value_last_00_31,		// data 2 (MSB in case of 64 bits)
2867 				&value_last_32_63,		// data 2 (LSB in case of 64 bits)
2868 				data_ptr			// pointer to data
2869 			);
2870 
2871 			if (ret < 0) {
2872 				ERRORPRINT_WA("can't retrieve keys from data for row: %ld", i);
2873 				exit(EXIT_FAILURE);
2874 			};
2875 #endif // HAVE_BERKELEY_DB_SUPPORT
2876 		};
2877 
2878 		if (data_key_length == 32) {
2879 			if (data_key_type == IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_FIRST_LAST) {
2880 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Test %08x range %08x - %08x i=%ld i_min=%ld i_max=%ld",
2881 					(unsigned int) lookup_key_00_31,
2882 					(unsigned int) value_first_00_31,
2883 					(unsigned int) value_last_00_31,
2884 					i, i_min, i_max);
2885 			} else if (data_key_type == IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_BASE_MASK) {
2886 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Test %08x base/mask %08x/%08x i=%ld i_min=%ld i_max=%ld",
2887 					(unsigned int) lookup_key_00_31,
2888 					(unsigned int) value_first_00_31,
2889 					(unsigned int) value_last_00_31,
2890 					 i, i_min, i_max);
2891 			};
2892 		} else if (data_key_length == 64) {
2893 			if (data_key_type == IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_FIRST_LAST) {
2894 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Test %08x:%08x range %08x:%08x - %08x:%08x i=%ld i_min=%ld i_max=%ld",
2895 					(unsigned int) lookup_key_00_31,
2896 					(unsigned int) lookup_key_32_63,
2897 					(unsigned int) value_first_00_31,
2898 					(unsigned int) value_first_32_63,
2899 					(unsigned int) value_last_00_31,
2900 					(unsigned int) value_last_32_63,
2901 					 i, i_min, i_max);
2902 			} else if (data_key_type == IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_BASE_MASK) {
2903 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Test %08x:%08x base/mask %08x:%08x/%08x:%08x i=%ld i_min=%ld i_max=%ld",
2904 					(unsigned int) lookup_key_00_31,
2905 					(unsigned int) lookup_key_32_63,
2906 					(unsigned int) value_first_00_31,
2907 					(unsigned int) value_first_32_63,
2908 					(unsigned int) value_last_00_31,
2909 					(unsigned int) value_last_32_63,
2910 					 i, i_min, i_max);
2911 			};
2912 		};
2913 
2914 		if (data_key_length == 32) {
2915 			if (data_key_type == IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_FIRST_LAST) {
2916 				if (lookup_key_00_31 < value_first_00_31) {
2917 					// to high in array, jump down
2918 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to high in array, jump down");
2919 					i_max = i;
2920 				} else if (lookup_key_00_31 > value_last_00_31) {
2921 					// to low in array, jump up
2922 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to low in array, jump up");
2923 					i_min = i;
2924 				} else {
2925 					// hit
2926 					match = i;
2927 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
2928 						// binary search in provided data
2929 						DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "matching");
2930 						break;
2931 					} else if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_SEQLONGEST) {
2932 						// sequential search in provided data
2933 						if (ret > seqlongest) {
2934 							DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "matching, seqlongest old=%d new=%d", seqlongest, ret);
2935 							seqlongest = ret;
2936 						} else {
2937 							DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "matching, keep seqlongest=%d", seqlongest);
2938 						};
2939 					};
2940 				};
2941 			} else if (data_key_type == IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_BASE_MASK) {
2942 				if ((lookup_key_00_31 & value_last_00_31) < value_first_00_31) {
2943 					// to high in array, jump down
2944 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to high in array, jump down");
2945 					i_max = i;
2946 				} else if ((lookup_key_00_31 & value_last_00_31) > value_first_00_31) {
2947 					// to low in array, jump up
2948 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to low in array, jump up");
2949 					i_min = i;
2950 				} else {
2951 					// hit
2952 					match = i;
2953 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
2954 						// binary search in provided data
2955 						break;
2956 					} else if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_SEQLONGEST) {
2957 						// sequential search in provided data
2958 						if (ret > seqlongest) {
2959 							DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "matching, seqlongest old=%d new=%d", seqlongest, ret);
2960 							seqlongest = ret;
2961 						} else {
2962 							DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "matching, keep seqlongest=%d", seqlongest);
2963 						};
2964 					};
2965 				};
2966 			};
2967 		} else if (data_key_length == 64) {
2968 			if (data_key_type == IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_FIRST_LAST) {
2969 				if (lookup_key_00_31 < value_first_00_31) {
2970 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
2971 						/* to high in array, jump down */
2972 						DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to high in array, jump down");
2973 						i_max = i;
2974 					};
2975 				} else if (lookup_key_00_31 > value_last_00_31) {
2976 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
2977 						// to low in array, jump up
2978 						DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to low in array, jump up");
2979 						i_min = i;
2980 					};
2981 				} else if ((lookup_key_00_31 == value_first_00_31) && (lookup_key_32_63 < value_first_32_63)) {
2982 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
2983 						/* to high in array, jump down */
2984 						DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to high in array, jump down");
2985 						i_max = i;
2986 					};
2987 				} else if ((lookup_key_00_31 == value_last_00_31) && (lookup_key_32_63 > value_last_32_63)) {
2988 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
2989 						// to low in array, jump up
2990 						DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to low in array, jump up");
2991 						i_min = i;
2992 					};
2993 				} else {
2994 					// hit
2995 					match = i;
2996 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
2997 						// binary search in provided data
2998 						break;
2999 					} else if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_SEQLONGEST) {
3000 						// sequential search in provided data
3001 						if (ret > seqlongest) {
3002 							DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "matching, seqlongest old=%d new=%d", seqlongest, ret);
3003 							seqlongest = ret;
3004 						} else {
3005 							DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "matching, keep seqlongest=%d", seqlongest);
3006 						};
3007 					};
3008 				};
3009 			} else if (data_key_type == IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_BASE_MASK) {
3010 				if ((lookup_key_00_31 & value_last_00_31) < value_first_00_31) {
3011 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "(lookup_key_00_31 & value_last_00_31) < value_first_00_31");
3012 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
3013 						/* to high in array, jump down */
3014 						DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to high in array, jump down");
3015 						i_max = i;
3016 					};
3017 				} else if ((lookup_key_00_31 & value_last_00_31) > value_first_00_31) {
3018 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "(lookup_key_00_31 & value_last_00_31) > value_first_00_31");
3019 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
3020 						// to low in array, jump up
3021 						DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to low in array, jump up");
3022 						i_min = i;
3023 					};
3024 				} else if (((lookup_key_00_31 & value_last_00_31) == value_first_00_31) && ((lookup_key_32_63 & value_last_32_63) < value_first_32_63)) {
3025 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "(lookup_key_32_63 & value_last_32_63) < value_first_32_63");
3026 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
3027 						/* to high in array, jump down */
3028 						DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to high in array, jump down");
3029 						i_max = i;
3030 					};
3031 				} else if (((lookup_key_00_31 & value_last_00_31) == value_first_00_31) && ((lookup_key_32_63 & value_last_32_63) > value_first_32_63)) {
3032 					DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "(lookup_key_32_63 & value_last_32_63) > value_first_32_63");
3033 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
3034 						// to low in array, jump up
3035 						DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "to low in array, jump up");
3036 						i_min = i;
3037 					};
3038 				} else {
3039 					// hit
3040 					match = i;
3041 					if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
3042 						// binary search in provided data
3043 						break;
3044 					} else if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_SEQLONGEST) {
3045 						// sequential search in provided data
3046 						if (ret > seqlongest) {
3047 							DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "matching, seqlongest old=%d new=%d", seqlongest, ret);
3048 							seqlongest = ret;
3049 						} else {
3050 							DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "matching, keep seqlongest=%d", seqlongest);
3051 						};
3052 					};
3053 				};
3054 			};
3055 		};
3056 
3057 		if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
3058 			// binary search in provided data
3059 			i_old2 = i_old;
3060 			i_old = i;
3061 			i = (i_max - i_min) / 2 + i_min;
3062 			search_binary_count++;
3063 
3064 			// jump to last entry in special way if needed, otherwise it's not reachable
3065 			if ((i == i_old) && ((i + 1) == ((int32_t) data_num_rows - 1))) {
3066 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "workaround for last entry activated");
3067 				i = i_max;
3068 			};
3069 
3070 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "count=%d/%d i_old2=%ld i_old=%ld i_min=%ld i_max=%ld i=%ld", search_binary_count, search_binary_count_max, i_old2, i_old, i_min, i_max, i);
3071 
3072 			if (i_old2 == i) {
3073 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "loop in binary search detected, no match found");
3074 				break;
3075 			};
3076 
3077 			if (search_binary_count > search_binary_count_max) {
3078 				DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "limit of binary search reached, no match found");
3079 				break;
3080 			};
3081 
3082 		} else if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_SEQLONGEST) {
3083 			// sequential search in provided data
3084 			i++;
3085 		};
3086 	};
3087 
3088 	if (match != -1) {
3089 		retval = match;
3090 
3091 		if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY) {
3092 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Entry matched: %ld", i);
3093 			if (data_ptr_type == IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_ARRAY) {
3094 				// currently nothing to do
3095 #ifdef HAVE_BERKELEY_DB_SUPPORT
3096 			} else if (data_ptr_type == IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB) {
3097 				// currently nothing to do
3098 #endif // HAVE_BERKELEY_DB_SUPPORT
3099 			};
3100 		} else if (data_search_type == IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_SEQLONGEST) {
3101 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Finally entry matched: %ld", match);
3102 			if (data_ptr_type == IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_ARRAY) {
3103 				// currently nothing to do
3104 #ifdef HAVE_BERKELEY_DB_SUPPORT
3105 			} else if (data_ptr_type == IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB) {
3106 				// fetch matching row
3107 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Try to get row from Berkeley DB dbp=%p recno=%ld", dbp, match);
3108 				ret = libipv6calc_db_wrapper_bdb_fetch_row(
3109 					dbp,			// pointer to DB
3110 					data_key_format,	// DB format
3111 					match + 1,		// row number
3112 					&value_first_00_31,	// data 1 (MSB in case of 64 bits)
3113 					&value_first_32_63,	// data 1 (LSB in case of 64 bits)
3114 					&value_last_00_31,	// data 2 (MSB in case of 64 bits)
3115 					&value_last_32_63,	// data 2 (LSB in case of 64 bits)
3116 					data_ptr		// pointer to data
3117 				);
3118 
3119 				if (ret < 0) {
3120 					ERRORPRINT_WA("can't retrieve keys from data for row: %lu", match);
3121 					exit(EXIT_FAILURE);
3122 				};
3123 #endif // HAVE_BERKELEY_DB_SUPPORT
3124 			};
3125 		};
3126 
3127 		if (data_ptr != NULL) {
3128 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Finished with success result (DB): match=%ld", match);
3129 		};
3130 	} else {
3131 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "Finished with NO SUCCESS result (DB)");
3132 	};
3133 
3134 //END_libipv6calc_db_wrapper_get_entry_generic:
3135 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "Return: %d", retval);
3136 	return(retval);
3137 };
3138 
3139 
3140 /*********** generic function **********************/
libipv6calc_db_cc_to_index(const char * cc_text)3141 uint16_t libipv6calc_db_cc_to_index(const char *cc_text) {
3142 	uint16_t index = COUNTRYCODE_INDEX_UNKNOWN;
3143 	uint8_t c1, c2;
3144 
3145 	if (cc_text == NULL) {
3146 		ERRORPRINT_NA("input is NULL");
3147 		goto END_libipv6calc_db_cc_to_index; // something wrong
3148 	};
3149 
3150 	if (strlen(cc_text) != 2) {
3151 		ERRORPRINT_WA("input is not string with length 2: %s", cc_text);
3152 		goto END_libipv6calc_db_cc_to_index; // something wrong
3153 	};
3154 
3155 	if ((! isalpha((int) cc_text[0])) || (! isalnum((int) cc_text[1]))) {
3156 		ERRORPRINT_WA("input is not valid country code: %s", cc_text);
3157 		goto END_libipv6calc_db_cc_to_index; // something wrong
3158 	};
3159 
3160 	c1 = toupper(cc_text[0]);
3161 	if (! (c1 >= 'A' && c1 <= 'Z')) {
3162 		ERRORPRINT_WA("input char 1 is not part of a valid country code: %s", cc_text);
3163 		goto END_libipv6calc_db_cc_to_index; // something wrong
3164 	};
3165 	c1 -= 'A';
3166 
3167 	c2 = toupper(cc_text[1]);
3168 	if (c2 >= '0' && c2 <= '9') {
3169 		c2 -= '0';
3170 	} else if (c2 >= 'A' && c2 <= 'Z') {
3171 		c2 -= 'A';
3172 		c2 += 10;
3173 	} else {
3174 		ERRORPRINT_WA("input char 2 is not part of a valid country code: %s", cc_text);
3175 		goto END_libipv6calc_db_cc_to_index; // something wrong
3176 	};
3177 
3178 	index = c1 + c2 * COUNTRYCODE_LETTER1_MAX;
3179 
3180 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "c1=%d c2=%d index=%d (0x%03x) -> test: %c%c", c1, c2, index, index, COUNTRYCODE_INDEX_TO_CHAR1(index), COUNTRYCODE_INDEX_TO_CHAR2(index));
3181 
3182 	if (index >= COUNTRYCODE_INDEX_MAX) {
3183 		index = COUNTRYCODE_INDEX_UNKNOWN; // failsafe
3184 		ERRORPRINT_WA("unexpected index (too high): %d", index);
3185 	};
3186 
3187 END_libipv6calc_db_cc_to_index:
3188 	return(index);
3189 };
3190 
3191 
3192 
3193 /***********************************************************/
3194 /*********** filter based on database **********************/
3195 /***********************************************************/
3196 
3197 /*********** DB CC **********************/
3198 
3199 /*
3200  * parse filter DB CC
3201  *
3202  * in : *filter    = filter structure
3203  * ret: 0:found 1:skip 2:problem
3204  */
libipv6calc_db_cc_filter_parse(s_ipv6calc_filter_db_cc * filter,const char * token,const int negate_flag)3205 int libipv6calc_db_cc_filter_parse(s_ipv6calc_filter_db_cc *filter, const char *token, const int negate_flag) {
3206 	int result = 1, negate = negate_flag, offset = 0;
3207 	const char *filter_token = "cc=";
3208 	const char *prefixdot = "db.";
3209 
3210 	uint16_t cc_index;
3211 
3212 	if (token == NULL) {
3213 		return (result);
3214 	};
3215 
3216 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "input: %s", token);
3217 
3218 	if (token[0] == '^') {
3219 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "found negate prefix in token: %s", token);
3220 
3221 		negate = 1;
3222 		offset += 1;
3223 	};
3224 
3225 	if (strncmp(token + offset, prefixdot, strlen(prefixdot)) == 0) {
3226 		/* prefix with dot found */
3227 		offset += strlen(prefixdot);
3228 		result = 2; /* token with prefix, result into problem if not found */
3229 
3230 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "token with prefix, suffix: %s", token + offset);
3231 	} else {
3232 		/* prefix dot is required */
3233 		// no match
3234 		goto END_ipv6calc_db_cc_filter_parse;
3235 	};
3236 
3237 	if (strncmp(token + offset, filter_token, strlen(filter_token)) == 0) {
3238 		/* filter token found */
3239 		offset += strlen(filter_token);
3240 		result = 2; /* filter token found */
3241 
3242 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "filter token found, suffix: %s", token + offset);
3243 	} else {
3244 		// no match
3245 		goto END_ipv6calc_db_cc_filter_parse;
3246 	};
3247 
3248 	if (strcmp(token + offset, "unknown") == 0) {
3249 		cc_index = COUNTRYCODE_INDEX_UNKNOWN;
3250 	} else {
3251 		if (strlen(token + offset) != 2) {
3252 			ERRORPRINT_WA("filter token 'cc=' requires 2 char country code: %s:", token + offset);
3253 			goto END_ipv6calc_db_cc_filter_parse;
3254 		};
3255 
3256 		cc_index = libipv6calc_db_cc_to_index(token + offset);
3257 
3258 		if (cc_index == COUNTRYCODE_INDEX_UNKNOWN) {
3259 			ERRORPRINT_WA("filter token 'cc=' requires a valid country code: %s:", token + offset);
3260 			goto END_ipv6calc_db_cc_filter_parse;
3261 		};
3262 	};
3263 
3264 	if (negate == 1) {
3265 		if (filter->cc_may_not_have_max < IPV6CALC_FILTER_DB_CC_MAX) {
3266 			filter->cc_may_not_have[filter->cc_may_not_have_max] = cc_index;
3267 			filter->cc_may_not_have_max++;
3268 		} else {
3269 			ERRORPRINT_WA("filter token 'cc=' maxmimum reached for 'may not have': %d", filter->cc_may_not_have_max);
3270 			goto END_ipv6calc_db_cc_filter_parse;
3271 		};
3272 	} else {
3273 		if (filter->cc_must_have_max < IPV6CALC_FILTER_DB_CC_MAX) {
3274 			filter->cc_must_have[filter->cc_must_have_max] = cc_index;
3275 			filter->cc_must_have_max++;
3276 		} else {
3277 			ERRORPRINT_WA("filter token 'cc=' maxmimum reached for 'must have': %d", filter->cc_must_have_max);
3278 			goto END_ipv6calc_db_cc_filter_parse;
3279 		};
3280 	};
3281 	filter->active = 1;
3282 	result = 0;
3283 
3284 END_ipv6calc_db_cc_filter_parse:
3285 	return (result);
3286 };
3287 
3288 
3289 /*
3290  * check filter DB CC
3291  *
3292  * in : *filter    = filter structure
3293  * ret: 0:found 1:problem
3294  */
libipv6calc_db_cc_filter_check(const s_ipv6calc_filter_db_cc * filter,const int proto)3295 int libipv6calc_db_cc_filter_check(const s_ipv6calc_filter_db_cc *filter, const int proto) {
3296 	int result = 0, r;
3297 	char cc[IPV6CALC_COUNTRYCODE_STRING_MAX];
3298 
3299 	DEBUGSECTION_BEGIN(DEBUG_libipv6calc_db_wrapper)
3300 	char tempstring[IPV6CALC_STRING_MAX];
3301 	char tempstring2[IPV6CALC_STRING_MAX];
3302 	int i;
3303 
3304 	if (filter->cc_must_have_max > 0) {
3305 		tempstring2[0] = '\0';
3306 		for (i = 0; i < filter->cc_must_have_max; i++) {
3307 			libipv6calc_db_wrapper_country_code_by_cc_index(cc, sizeof(cc), filter->cc_must_have[i]);
3308 			snprintf(tempstring, sizeof(tempstring), "%s%s%s", tempstring2, (i > 0) ? " " : "", cc);
3309 			snprintf(tempstring2, sizeof(tempstring2), "%s", tempstring);
3310 		};
3311 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.cc filter 'must_have'   : %s", tempstring2);
3312 	} else {
3313 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.cc filter 'must_have'   : --");
3314 	};
3315 
3316 	if (filter->cc_may_not_have_max > 0) {
3317 		tempstring2[0] = '\0';
3318 		for (i = 0; i < filter->cc_may_not_have_max; i++) {
3319 			libipv6calc_db_wrapper_country_code_by_cc_index(cc, sizeof(cc), filter->cc_may_not_have[i]);
3320 			snprintf(tempstring, sizeof(tempstring), "%s%s%s", tempstring2, (i > 0) ? " " : "", cc);
3321 			snprintf(tempstring2, sizeof(tempstring2), "%s", tempstring);
3322 		};
3323 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.cc filter 'may_not_have': %s", tempstring2);
3324 	} else {
3325 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.cc filter 'may_not_have': --");
3326 	};
3327 	DEBUGSECTION_END
3328 
3329 	if (proto == IPV6CALC_PROTO_IPV4) {
3330 		r = libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV4_TO_CC);
3331 	} else if (proto == IPV6CALC_PROTO_IPV6) {
3332 		r = libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV6_TO_CC);
3333 	} else {
3334 		ERRORPRINT_WA("unsupported proto (FIX CODE): %d", proto);
3335 		result = 1;
3336 		goto END_ipv6calc_db_cc_filter_check;
3337 	};
3338 
3339 	if (r == 1) {
3340 		// ok
3341 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "database layer supports IPv%d->CountryCode", proto);
3342 	} else {
3343 		ERRORPRINT_WA("database layer don't support IPv%d->CountryCode", proto);
3344 		result = 1;
3345 	};
3346 
3347 END_ipv6calc_db_cc_filter_check:
3348 	return(result);
3349 };
3350 
3351 
3352 /*
3353  * filter for CC
3354  *
3355  * in : cc_index   = country code
3356  * in : *filter    = filter structure
3357  * ret: 0=match 1=not match -1=neutral
3358  */
libipv6calc_db_cc_filter(const uint16_t cc_index,const s_ipv6calc_filter_db_cc * filter)3359 int libipv6calc_db_cc_filter(const uint16_t cc_index, const s_ipv6calc_filter_db_cc *filter) {
3360 	int i, result = -1;
3361 
3362 	char cc1[IPV6CALC_COUNTRYCODE_STRING_MAX], cc2[IPV6CALC_COUNTRYCODE_STRING_MAX];
3363 
3364 	libipv6calc_db_wrapper_country_code_by_cc_index(cc1, sizeof(cc1), cc_index);
3365 
3366 	if (filter->cc_must_have_max > 0) {
3367 		result = 1;
3368 
3369 		for (i = 0; i < filter->cc_must_have_max; i++) {
3370 			libipv6calc_db_wrapper_country_code_by_cc_index(cc2, sizeof(cc2), filter->cc_must_have[i]);
3371 
3372 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.cc filter: check %s against must-have: %s", cc1, cc2);
3373 			if (cc_index == filter->cc_must_have[i]) {
3374 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.cc filter: %s hits must-have: %s", cc1, cc2);
3375 				// match MUST-HAVE
3376 				result = 0;
3377 				break;
3378 			};
3379 		};
3380 	} else {
3381 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.cc filter: no must-have defined");
3382 	};
3383 
3384 	if (filter->cc_may_not_have_max > 0) {
3385 		for (i = 0; i < filter->cc_may_not_have_max; i++) {
3386 			libipv6calc_db_wrapper_country_code_by_cc_index(cc2, sizeof(cc2), filter->cc_may_not_have[i]);
3387 
3388 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.cc filter: check %s against may-not-have: %s", cc1, cc2);
3389 			if (cc_index == filter->cc_may_not_have[i]) {
3390 				// match MAY-NOT-HAVE
3391 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.cc filter: %s hits may-not-have: %s", cc1, cc2);
3392 				result = 1;
3393 				break;
3394 			};
3395 		};
3396 	} else {
3397 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.cc filter: no may-not-have defined");
3398 	};
3399 
3400 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.cc filter final result: %d", result);
3401 	return (result);
3402 };
3403 
3404 
3405 /*********** DB ASN **********************/
3406 
3407 /*
3408  * parse filter DB ASN
3409  *
3410  * in : *filter    = filter structure
3411  * ret: 0:found 1:skip 2:problem
3412  */
libipv6calc_db_asn_filter_parse(s_ipv6calc_filter_db_asn * filter,const char * token,const int negate_flag)3413 int libipv6calc_db_asn_filter_parse(s_ipv6calc_filter_db_asn *filter, const char *token, const int negate_flag) {
3414 	int result = 1, negate = negate_flag, offset = 0;
3415 	const char *filter_token = "asn=";
3416 	const char *prefixdot = "db.";
3417 
3418 	uint32_t asn;
3419 
3420 	if (token == NULL) {
3421 		return (result);
3422 	};
3423 
3424 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "input: %s", token);
3425 
3426 	if (token[0] == '^') {
3427 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "found negate prefix in token: %s", token);
3428 
3429 		negate = 1;
3430 		offset += 1;
3431 	};
3432 
3433 	if (strncmp(token + offset, prefixdot, strlen(prefixdot)) == 0) {
3434 		/* prefix with dot found */
3435 		offset += strlen(prefixdot);
3436 		result = 2; /* token with prefix, result into problem if not found */
3437 
3438 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "token with prefix, suffix: %s", token + offset);
3439 	} else {
3440 		/* prefix dot is required */
3441 		// no match
3442 		goto END_ipv6calc_db_asn_filter_parse;
3443 	};
3444 
3445 	if (strncmp(token + offset, filter_token, strlen(filter_token)) == 0) {
3446 		/* filter token found */
3447 		offset += strlen(filter_token);
3448 		result = 2; /* filter token found */
3449 
3450 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "filter token found, suffix: %s", token + offset);
3451 	} else {
3452 		// no match
3453 		goto END_ipv6calc_db_asn_filter_parse;
3454 	};
3455 
3456 	if (strcmp(token + offset, "unknown") == 0) {
3457 		asn = ASNUM_AS_UNKNOWN;
3458 	} else {
3459 		asn = (uint32_t) strtol(token + offset, NULL, 10);
3460 
3461 		if (errno == ERANGE) {
3462 			ERRORPRINT_WA("filter token 'asn=' requires a valid decimal number between 0 and %lu: %s:", (long unsigned int) 0xffffffff, token + offset);
3463 			goto END_ipv6calc_db_asn_filter_parse;
3464 		};
3465 	};
3466 
3467 	if (negate == 1) {
3468 		if (filter->asn_may_not_have_max < IPV6CALC_FILTER_DB_ASN_MAX) {
3469 			filter->asn_may_not_have[filter->asn_may_not_have_max] = asn;
3470 			filter->asn_may_not_have_max++;
3471 		} else {
3472 			ERRORPRINT_WA("filter token 'asn=' maxmimum reached for 'may not have': %d", filter->asn_may_not_have_max);
3473 			goto END_ipv6calc_db_asn_filter_parse;
3474 		};
3475 	} else {
3476 		if (filter->asn_must_have_max < IPV6CALC_FILTER_DB_ASN_MAX) {
3477 			filter->asn_must_have[filter->asn_must_have_max] = asn;
3478 			filter->asn_must_have_max++;
3479 		} else {
3480 			ERRORPRINT_WA("filter token 'asn=' maxmimum reached for 'must have': %d", filter->asn_must_have_max);
3481 			goto END_ipv6calc_db_asn_filter_parse;
3482 		};
3483 	};
3484 	filter->active = 1;
3485 	result = 0;
3486 
3487 END_ipv6calc_db_asn_filter_parse:
3488 	return (result);
3489 };
3490 
3491 
3492 /*
3493  * check filter DB ASN
3494  *
3495  * in : *filter    = filter structure
3496  * ret: 0:found 1:problem
3497  */
libipv6calc_db_asn_filter_check(const s_ipv6calc_filter_db_asn * filter,const int proto)3498 int libipv6calc_db_asn_filter_check(const s_ipv6calc_filter_db_asn *filter, const int proto) {
3499 	int result = 0, r;
3500 
3501 	DEBUGSECTION_BEGIN(DEBUG_libipv6calc_db_wrapper)
3502 	char tempstring[IPV6CALC_STRING_MAX];
3503 	char tempstring2[IPV6CALC_STRING_MAX];
3504 	int i;
3505 	if (filter->asn_must_have_max > 0) {
3506 		tempstring2[0] = '\0';
3507 		for (i = 0; i < filter->asn_must_have_max; i++) {
3508 			snprintf(tempstring, sizeof(tempstring), "%s%s%u", tempstring2, (i > 0) ? " " : "", filter->asn_must_have[i]);
3509 			snprintf(tempstring2, sizeof(tempstring2), "%s", tempstring);
3510 		};
3511 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.asn filter 'must_have'   : %s", tempstring2);
3512 	} else {
3513 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.asn filter 'must_have'   : --");
3514 	};
3515 
3516 	if (filter->asn_may_not_have_max > 0) {
3517 		tempstring2[0] = '\0';
3518 		for (i = 0; i < filter->asn_may_not_have_max; i++) {
3519 			snprintf(tempstring, sizeof(tempstring), "%s%s%u", tempstring2, (i > 0) ? " " : "", filter->asn_may_not_have[i]);
3520 			snprintf(tempstring2, sizeof(tempstring2), "%s", tempstring);
3521 		};
3522 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.asn filter 'may_not_have': %s", tempstring2);
3523 	} else {
3524 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.asn filter 'may_not_have': --");
3525 	};
3526 	DEBUGSECTION_END
3527 
3528 	if (proto == IPV6CALC_PROTO_IPV4) {
3529 		r = libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV4_TO_AS);
3530 	} else if (proto == IPV6CALC_PROTO_IPV6) {
3531 		r = libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV6_TO_AS);
3532 	} else {
3533 		ERRORPRINT_WA("unsupported proto (FIX CODE): %d", proto);
3534 		result = 1;
3535 		goto END_ipv6calc_db_asn_filter_check;
3536 	};
3537 
3538 	if (r == 1) {
3539 		// ok
3540 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "database layer supports IPv%d->ASN", proto);
3541 	} else {
3542 		ERRORPRINT_WA("database layer don't support IPv%d->ASN", proto);
3543 		result = 1;
3544 	};
3545 
3546 END_ipv6calc_db_asn_filter_check:
3547 	return(result);
3548 };
3549 
3550 
3551 /*
3552  * filter ASN
3553  *
3554  * in : asn        = ASN
3555  * in : *filter    = filter structure
3556  * ret: 0=match 1=not match -1=neutral
3557  */
libipv6calc_db_asn_filter(const uint32_t asn,const s_ipv6calc_filter_db_asn * filter)3558 int libipv6calc_db_asn_filter(const uint32_t asn, const s_ipv6calc_filter_db_asn *filter) {
3559 	int i, result = -1;
3560 
3561 	if (filter->asn_must_have_max > 0) {
3562 		result = 1;
3563 
3564 		for (i = 0; i < filter->asn_must_have_max; i++) {
3565 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.asn filter: check %u against must-have: %u", asn, filter->asn_must_have[i]);
3566 			if (asn == filter->asn_must_have[i]) {
3567 				// match MUST-HAVE
3568 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.asn filter: %u hits must-have: %u", asn, filter->asn_must_have[i]);
3569 				result = 0;
3570 			};
3571 		};
3572 	} else {
3573 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.asn filter: no must-have defined");
3574 	};
3575 
3576 	if (filter->asn_may_not_have_max > 0) {
3577 		for (i = 0; i < filter->asn_may_not_have_max; i++) {
3578 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.asn filter: check %u against must-have: %u", asn, filter->asn_may_not_have[i]);
3579 			if (asn == filter->asn_may_not_have[i]) {
3580 				// match MAY-NOT-HAVE
3581 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.asn filter: %u hits may-not-have: %u", asn, filter->asn_may_not_have[i]);
3582 				result = 1;
3583 			};
3584 		};
3585 	} else {
3586 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.asn filter: no may-not-have defined");
3587 	};
3588 
3589 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.asn filter final result: %d", result);
3590 	return (result);
3591 };
3592 
3593 
3594 /*********** DB Registry **********************/
3595 
3596 /*
3597  * parse filter DB Registry
3598  *
3599  * in : *filter    = filter structure
3600  * ret: 0:found 1:skip 2:problem
3601  */
libipv6calc_db_registry_filter_parse(s_ipv6calc_filter_db_registry * filter,const char * token,const int negate_flag)3602 int libipv6calc_db_registry_filter_parse(s_ipv6calc_filter_db_registry *filter, const char *token, const int negate_flag) {
3603 	int result = 1, negate = negate_flag, offset = 0;
3604 	const char *filter_token = "reg=";
3605 	const char *prefixdot = "db.";
3606 
3607 	int registry = 0, i;
3608 
3609 	if (token == NULL) {
3610 		return (result);
3611 	};
3612 
3613 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "input: %s", token);
3614 
3615 	if (token[0] == '^') {
3616 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "found negate prefix in token: %s", token);
3617 
3618 		negate = 1;
3619 		offset += 1;
3620 	};
3621 
3622 	if (strncmp(token + offset, prefixdot, strlen(prefixdot)) == 0) {
3623 		/* prefix with dot found */
3624 		offset += strlen(prefixdot);
3625 		result = 2; /* token with prefix, result into problem if not found */
3626 
3627 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "token with prefix, suffix: %s", token + offset);
3628 	} else {
3629 		/* prefix dot is required */
3630 		// no match
3631 		goto END_ipv6calc_db_registry_filter_parse;
3632 	};
3633 
3634 	if (strncmp(token + offset, filter_token, strlen(filter_token)) == 0) {
3635 		/* filter token found */
3636 		offset += strlen(filter_token);
3637 		result = 2; /* filter token found */
3638 
3639 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "filter token found, suffix: %s", token + offset);
3640 	} else {
3641 		// no match
3642 		goto END_ipv6calc_db_registry_filter_parse;
3643 	};
3644 
3645 	if (strcmp(token + offset, "unknown") == 0) {
3646 		registry = REGISTRY_UNKNOWN;
3647 	} else {
3648 		for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_registries); i++) {
3649 			if (strcasecmp(token + offset, ipv6calc_registries[i].token) == 0) {
3650 				registry = ipv6calc_registries[i].number;
3651 				break;
3652 			};
3653 		};
3654 
3655 		if (registry == 0) {
3656 			ERRORPRINT_WA("filter token 'reg=' requires a valid registry token: %s:", token + offset);
3657 			goto END_ipv6calc_db_registry_filter_parse;
3658 		};
3659 	};
3660 
3661 	if (negate == 1) {
3662 		if (filter->registry_may_not_have_max < IPV6CALC_FILTER_DB_REGISTRY_MAX) {
3663 			filter->registry_may_not_have[filter->registry_may_not_have_max] = registry;
3664 			filter->registry_may_not_have_max++;
3665 		} else {
3666 			ERRORPRINT_WA("filter token 'reg=' maxmimum reached for 'may not have': %d", filter->registry_may_not_have_max);
3667 			goto END_ipv6calc_db_registry_filter_parse;
3668 		};
3669 	} else {
3670 		if (filter->registry_must_have_max < IPV6CALC_FILTER_DB_REGISTRY_MAX) {
3671 			filter->registry_must_have[filter->registry_must_have_max] = registry;
3672 			filter->registry_must_have_max++;
3673 		} else {
3674 			ERRORPRINT_WA("filter token 'reg=' maxmimum reached for 'must have': %d", filter->registry_must_have_max);
3675 			goto END_ipv6calc_db_registry_filter_parse;
3676 		};
3677 	};
3678 	filter->active = 1;
3679 	result = 0;
3680 
3681 END_ipv6calc_db_registry_filter_parse:
3682 	return (result);
3683 };
3684 
3685 
3686 /*
3687  * check filter DB Registry
3688  *
3689  * in : *filter    = filter structure
3690  * ret: 0:found 1:problem
3691  */
libipv6calc_db_registry_filter_check(const s_ipv6calc_filter_db_registry * filter,const int proto)3692 int libipv6calc_db_registry_filter_check(const s_ipv6calc_filter_db_registry *filter, const int proto) {
3693 	int result = 0, r;
3694 
3695 	DEBUGSECTION_BEGIN(DEBUG_libipv6calc_db_wrapper)
3696 	char tempstring[IPV6CALC_STRING_MAX];
3697 	char tempstring2[IPV6CALC_STRING_MAX];
3698 	int i;
3699 	if (filter->registry_must_have_max > 0) {
3700 		tempstring2[0] = '\0';
3701 		for (i = 0; i < filter->registry_must_have_max; i++) {
3702 			snprintf(tempstring, sizeof(tempstring), "%s%s%s", tempstring2, (i > 0) ? " " : "", libipv6calc_registry_string_by_num(filter->registry_must_have[i]));
3703 			snprintf(tempstring2, sizeof(tempstring2), "%s", tempstring);
3704 		};
3705 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.registry filter 'must_have'   : %s", tempstring2);
3706 	} else {
3707 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.registry filter 'must_have'   : --");
3708 	};
3709 
3710 	if (filter->registry_may_not_have_max > 0) {
3711 		tempstring2[0] = '\0';
3712 		for (i = 0; i < filter->registry_may_not_have_max; i++) {
3713 			snprintf(tempstring, sizeof(tempstring), "%s%s%s", tempstring2, (i > 0) ? " " : "", libipv6calc_registry_string_by_num(filter->registry_may_not_have[i]));
3714 			snprintf(tempstring2, sizeof(tempstring2), "%s", tempstring);
3715 		};
3716 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.registry filter 'may_not_have': %s", tempstring2);
3717 	} else {
3718 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.registry filter 'may_not_have': --");
3719 	};
3720 	DEBUGSECTION_END
3721 
3722 	if (proto == IPV6CALC_PROTO_IPV4) {
3723 		r = libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV4_TO_REGISTRY);
3724 	} else if (proto == IPV6CALC_PROTO_IPV6) {
3725 		r = libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV6_TO_REGISTRY);
3726 	} else {
3727 		ERRORPRINT_WA("unsupported proto (FIX CODE): %d", proto);
3728 		result = 1;
3729 		goto END_ipv6calc_db_registry_filter_check;
3730 	};
3731 
3732 	if (r == 1) {
3733 		// ok
3734 		DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "database layer supports IPv%d->Registry", proto);
3735 	} else {
3736 		ERRORPRINT_WA("database layer don't support IPv%d->Registry", proto);
3737 		result = 1;
3738 	};
3739 
3740 END_ipv6calc_db_registry_filter_check:
3741 	return(result);
3742 };
3743 
3744 
3745 
3746 /*
3747  * filter Registry
3748  *
3749  * in : registry        = Registry
3750  * in : *filter    = filter structure
3751  * ret: 0=match 1=not match -1=neutral
3752  */
libipv6calc_db_registry_filter(const uint32_t registry,const s_ipv6calc_filter_db_registry * filter)3753 int libipv6calc_db_registry_filter(const uint32_t registry, const s_ipv6calc_filter_db_registry *filter) {
3754 	int i, result = -1;
3755 
3756 	if (filter->registry_must_have_max > 0) {
3757 		result = 1;
3758 
3759 		for (i = 0; i < filter->registry_must_have_max; i++) {
3760 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.reg filter: check %s against must-have: %s", libipv6calc_registry_string_by_num(registry), libipv6calc_registry_string_by_num(filter->registry_must_have[i]));
3761 			if (registry == filter->registry_must_have[i]) {
3762 				// match MUST-HAVE
3763 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.reg filter: %s hits must-have: %s", libipv6calc_registry_string_by_num(registry), libipv6calc_registry_string_by_num(filter->registry_must_have[i]));
3764 				result = 0;
3765 			};
3766 		};
3767 	} else {
3768 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.registry filter: no must-have defined");
3769 	};
3770 
3771 	if (filter->registry_may_not_have_max > 0) {
3772 		for (i = 0; i < filter->registry_may_not_have_max; i++) {
3773 			DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.reg filter: check %s against must-have: %s", libipv6calc_registry_string_by_num(registry), libipv6calc_registry_string_by_num(filter->registry_may_not_have[i]));
3774 			if (registry == filter->registry_may_not_have[i]) {
3775 				// match MAY-NOT-HAVE
3776 				DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.reg filter: %s hits may-not-have: %s", libipv6calc_registry_string_by_num(registry), libipv6calc_registry_string_by_num(filter->registry_may_not_have[i]));
3777 				result = 1;
3778 			};
3779 		};
3780 	} else {
3781 		DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper, "db.reg filter: no may-not-have defined");
3782 	};
3783 
3784 	DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper, "db.reg filter final result: %d", result);
3785 	return (result);
3786 };
3787 
3788 
3789 /*
3790  * return library version numeric
3791  */
libipv6calc_db_lib_version_numeric(void)3792 uint32_t libipv6calc_db_lib_version_numeric(void) {
3793 	return(IPV6CALC_PACKAGE_VERSION_NUMERIC);
3794 };
3795 
3796 
3797 /*
3798  * return library version as string
3799  */
libipv6calc_db_lib_version_string(void)3800 const char *libipv6calc_db_lib_version_string(void) {
3801 	return(IPV6CALC_PACKAGE_VERSION_STRING);
3802 
3803 };
3804 
3805 
3806 /*
3807  * return API version numeric
3808  */
libipv6calc_db_api_version_numeric(void)3809 uint32_t libipv6calc_db_api_version_numeric(void) {
3810 	return(IPV6CALC_API_VERSION_NUMERIC);
3811 };
3812 
3813 
3814 /*
3815  * return API version as string
3816  */
libipv6calc_db_api_version_string(void)3817 const char *libipv6calc_db_api_version_string(void) {
3818 	return(IPV6CALC_API_VERSION_STRING);
3819 };
3820