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