1 /*
2 * Project : ipv6calc
3 * File : databases/lib/libipv6calc_db_wrapper_External.c
4 * Version : $Id: afd04f01f138a78ccc19870e078208e13ec1a8e7 $
5 * Copyright : 2013-2021 by Peter Bieringer <pb (at) bieringer.de>
6 *
7 * Information:
8 * ipv6calc External (superseeding BuiltIn) database wrapper
9 */
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <dlfcn.h>
14 #include <unistd.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <time.h>
18
19 #include "config.h"
20
21 #include "libipv6calcdebug.h"
22 #include "libipv6calc.h"
23
24 #include "libipv6calc_db_wrapper.h"
25
26
27 #ifdef SUPPORT_EXTERNAL
28
29 #include <db.h>
30
31 #include "libipv6calc_db_wrapper_External.h"
32
33 char external_db_dir[PATH_MAX] = EXTERNAL_DB;
34
35 static const char* wrapper_external_info = "External";
36
37
38 /* database usage map */
39 #define EXTERNAL_DB_MAX_BLOCKS_32 2 // 0-63
40 static uint32_t external_db_usage_map[EXTERNAL_DB_MAX_BLOCKS_32];
41
42 #define EXTERNAL_DB_USAGE_MAP_TAG(db) if (db < (32 * EXTERNAL_DB_MAX_BLOCKS_32)) { \
43 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Tag usage for db: %d", db); \
44 external_db_usage_map[db / 32] |= 1 << (db % 32); \
45 } else { \
46 fprintf(stderr, "FIXME: unsupported db value (exceed limit): %d (%d)\n", db, 32 * EXTERNAL_DB_MAX_BLOCKS_32 - 1); \
47 exit(1); \
48 };
49
50 char external_db_usage_string[IPV6CALC_STRING_MAX] = "";
51
52 // local cache
53 #define IPV6CALC_DBD_SUBDB_MAX 3
54 static DB *db_ptr_cache[MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc)][IPV6CALC_DBD_SUBDB_MAX];
55 static db_recno_t db_recno_max_cache[MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc)][IPV6CALC_DBD_SUBDB_MAX];
56
57 // creation time of databases
58 time_t wrapper_db_unixtime_External[MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc)];
59
60
61 // local prototyping
62 static char *libipv6calc_db_wrapper_External_dbfilename(unsigned int type);
63 static char *libipv6calc_db_wrapper_External_database_info(unsigned int type);
64
65
66 /*
67 * function initialise the External wrapper
68 *
69 * in : (nothing)
70 * out: 0=ok, 1=error
71 */
libipv6calc_db_wrapper_External_wrapper_init(void)72 int libipv6calc_db_wrapper_External_wrapper_init(void) {
73 int i, j;
74 char *result;
75 DB *dbp;
76 long int recno_max;
77
78 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Called");
79
80 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Check for External databases in directory: %s", external_db_dir);
81
82 /* check available databases for resolution */
83 for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc); i++) {
84 // clean local cache
85 for (j = 0; j < IPV6CALC_DBD_SUBDB_MAX; j++) {
86 db_ptr_cache[i][j] = NULL;
87 db_recno_max_cache[i][j] = -1;
88 };
89 wrapper_db_unixtime_External[i] = 0;
90
91 // add features to implemented
92 wrapper_features_by_source_implemented[IPV6CALC_DB_SOURCE_EXTERNAL] |= libipv6calc_db_wrapper_External_db_file_desc[i].features;
93
94 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "External database test for availability: %s", libipv6calc_db_wrapper_External_db_file_desc[i].filename);
95
96 if (libipv6calc_db_wrapper_External_db_avail(libipv6calc_db_wrapper_External_db_file_desc[i].number) != 1) {
97 // no file found
98 continue;
99 };
100
101 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "External database available: %s type=%d", libipv6calc_db_wrapper_External_db_file_desc[i].description, libipv6calc_db_wrapper_External_db_file_desc[i].number);
102
103 result = libipv6calc_db_wrapper_External_database_info(libipv6calc_db_wrapper_External_db_file_desc[i].number);
104
105 if (strlen(result) == 0) {
106 // no proper database
107 continue;
108 };
109
110 if (wrapper_db_unixtime_External[i] == 0) {
111 // no proper database
112 continue;
113 };
114
115 // finally mark database features as available
116 wrapper_features_by_source[IPV6CALC_DB_SOURCE_EXTERNAL] |= libipv6calc_db_wrapper_External_db_file_desc[i].features;
117
118 // more sophisticated check for "data-info"
119 if (libipv6calc_db_wrapper_External_db_file_desc[i].number == EXTERNAL_DB_IPV4_REGISTRY) {
120 dbp = libipv6calc_db_wrapper_External_open_type(EXTERNAL_DB_IPV4_REGISTRY | 0x40000, &recno_max);
121 if (dbp == NULL) {
122 // disable feature
123 wrapper_features_by_source[IPV6CALC_DB_SOURCE_EXTERNAL] &= ~IPV6CALC_DB_IPV4_TO_INFO;
124 };
125 } else if (libipv6calc_db_wrapper_External_db_file_desc[i].number == EXTERNAL_DB_IPV6_REGISTRY) {
126 dbp = libipv6calc_db_wrapper_External_open_type(EXTERNAL_DB_IPV6_REGISTRY | 0x40000, &recno_max);
127 if (dbp == NULL) {
128 // disable feature
129 wrapper_features_by_source[IPV6CALC_DB_SOURCE_EXTERNAL] &= ~IPV6CALC_DB_IPV6_TO_INFO;
130 };
131 };
132 };
133
134 wrapper_features |= wrapper_features_by_source[IPV6CALC_DB_SOURCE_EXTERNAL];
135
136 return 0;
137 };
138
139
140 /*
141 * wrapper: External_close
142 */
libipv6calc_db_wrapper_External_close(DB * dbp)143 static int libipv6calc_db_wrapper_External_close(DB *dbp) {
144 int i, j;
145
146 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Called");
147
148 if (dbp != NULL) {
149 /* cleanup cache entry */
150 for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc); i++) {
151 for (j = 0; j < IPV6CALC_DBD_SUBDB_MAX; j++) {
152 if (db_ptr_cache[i][j] == dbp) {
153 db_ptr_cache[i][j] = NULL;
154 db_recno_max_cache[i][j] = -1;
155 };
156 };
157 };
158
159 dbp->close(dbp, 0);
160 };
161
162 return(0);
163 };
164
165
166 /*
167 * function cleanup the External wrapper
168 *
169 * in : (nothing)
170 * out: 0=ok, 1=error
171 */
libipv6calc_db_wrapper_External_wrapper_cleanup(void)172 int libipv6calc_db_wrapper_External_wrapper_cleanup(void) {
173 int i, j;
174
175 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Called");
176
177 for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc); i++) {
178 if (db_ptr_cache[i] != NULL) {
179 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Close External: type=%d desc='%s'", libipv6calc_db_wrapper_External_db_file_desc[i].number, libipv6calc_db_wrapper_External_db_file_desc[i].description);
180 for (j = 0; j < IPV6CALC_DBD_SUBDB_MAX; j++) {
181 libipv6calc_db_wrapper_External_close(db_ptr_cache[i][j]);
182 };
183 };
184 };
185
186 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Finished");
187 return 0;
188 };
189
190
191 /*
192 * function info of External wrapper
193 *
194 * in : ptr and size of string to be filled
195 * out: modified string;
196 */
libipv6calc_db_wrapper_External_wrapper_info(char * string,const size_t size)197 void libipv6calc_db_wrapper_External_wrapper_info(char* string, const size_t size) {
198 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Called");
199
200 snprintf(string, size, "External available databases: Country4=%d Country6=%d IPV4_REG=%d IPV6_REG=%d", \
201 (wrapper_features & IPV6CALC_DB_IPV4_TO_CC) ? 1 : 0, \
202 (wrapper_features & IPV6CALC_DB_IPV6_TO_CC) ? 1 : 0, \
203 (wrapper_features & IPV6CALC_DB_IPV4_TO_REGISTRY) ? 1 : 0, \
204 (wrapper_features & IPV6CALC_DB_IPV6_TO_REGISTRY) ? 1 : 0 \
205 );
206
207 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Finished");
208 return;
209 };
210
211 /*
212 * function print database info of External wrapper
213 *
214 * in : (void)
215 * out: (void)
216 */
libipv6calc_db_wrapper_External_wrapper_print_db_info(const int level_verbose,const char * prefix_string)217 void libipv6calc_db_wrapper_External_wrapper_print_db_info(const int level_verbose, const char *prefix_string) {
218 int i, type, count = 0;
219
220 const char *prefix = "\0";
221 if (prefix_string != NULL) {
222 prefix = prefix_string;
223 };
224
225 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Called");
226
227 IPV6CALC_DB_FEATURE_INFO(prefix, IPV6CALC_DB_SOURCE_EXTERNAL)
228
229 fprintf(stderr, "%sExternal: info of available databases in directory: %s\n", prefix, external_db_dir);
230
231 for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc); i++) {
232 type = libipv6calc_db_wrapper_External_db_file_desc[i].number;
233
234 if (libipv6calc_db_wrapper_External_db_avail(type)) {
235 fprintf(stderr, "%sExternal: %-20s: %-40s (%s)\n", prefix, libipv6calc_db_wrapper_External_db_file_desc[i].description, libipv6calc_db_wrapper_External_db_file_desc[i].filename, libipv6calc_db_wrapper_External_database_info(type));
236 count++;
237 } else {
238 if (level_verbose == LEVEL_VERBOSE2) {
239 fprintf(stderr, "%sExternal: %-20s: %-40s (%s)\n", prefix, libipv6calc_db_wrapper_External_db_file_desc[i].description, libipv6calc_db_wrapper_External_dbfilename(type), strerror(errno));
240 };
241 continue;
242 };
243 };
244
245 if (count == 0) {
246 fprintf(stderr, "%sExternal: NO available databases found in directory: %s\n", prefix, external_db_dir);
247 };
248
249 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Finished");
250 return;
251 };
252
253
254 /*
255 * wrapper: string regarding used database infos
256 */
libipv6calc_db_wrapper_External_wrapper_db_info_used(void)257 char *libipv6calc_db_wrapper_External_wrapper_db_info_used(void) {
258 int type, i;
259 char tempstring[IPV6CALC_STRING_MAX];
260 char *info;
261
262 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Called");
263
264 for (i = 0; i < EXTERNAL_DB_MAX_BLOCKS_32; i++) {
265 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "external_db_usage_map[%d]=%08x", i, (unsigned int) external_db_usage_map[i]);
266 };
267
268 for (type = 0; type < 32 * EXTERNAL_DB_MAX_BLOCKS_32; type++) {
269 if ((external_db_usage_map[type / 32] & (1 << (type % 32))) != 0) {
270 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "DB type used: %d", type);
271
272 info = libipv6calc_db_wrapper_External_database_info(type);
273
274 if (info == NULL) { continue; }; // NULL pointer returned
275
276 if (strlen(info) == 0) { continue; }; // empty string returned
277
278 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "type=%d info=%s", type, info);
279
280 if (strlen(external_db_usage_string) > 0) {
281 if (strstr(external_db_usage_string, info) != NULL) {
282 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "type=%d info=%s (skip, already displayed)", type, info);
283 continue;
284 }; // string already included
285
286 snprintf(tempstring, sizeof(tempstring), "%s / %s", external_db_usage_string, info);
287 } else {
288 snprintf(tempstring, sizeof(tempstring), "%s", info);
289 };
290
291 snprintf(external_db_usage_string, sizeof(external_db_usage_string), "%s", tempstring);
292 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "type=%d external_db_usage_string=%s", type, external_db_usage_string);
293 };
294 };
295
296 return(external_db_usage_string);
297 };
298
299
300 /*******************************
301 * Wrapper extension functions for External
302 *******************************/
303
304 /*
305 * wrapper extension: External_dbfilename
306 */
libipv6calc_db_wrapper_External_dbfilename(unsigned int type)307 static char *libipv6calc_db_wrapper_External_dbfilename(unsigned int type) {
308 static char tempstring[IPV6CALC_STRING_MAX];
309 int entry = -1, i;
310
311 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Called: %s type=%d", wrapper_external_info, type);
312
313 for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc); i++) {
314 if (libipv6calc_db_wrapper_External_db_file_desc[i].number == type) {
315 entry = i;
316 break;
317 };
318 };
319
320 if (entry < 0) {
321 return(NULL);
322 };
323
324 snprintf(tempstring, sizeof(tempstring), "%s/%s", external_db_dir, libipv6calc_db_wrapper_External_db_file_desc[i].filename);
325
326 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Finished: %s type=%d has filename=%s", wrapper_external_info, type, tempstring);
327
328 return(tempstring);
329 };
330
331
332 /*
333 * wrapper extension: External_dbdescription
334 */
libipv6calc_db_wrapper_External_dbdescription(const unsigned int type)335 const char *libipv6calc_db_wrapper_External_dbdescription(const unsigned int type) {
336 int entry = -1;
337 unsigned int i;
338
339 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Called: %s type=%d", wrapper_external_info, type);
340
341 for (i = 0; i < sizeof(libipv6calc_db_wrapper_External_db_file_desc) / sizeof(libipv6calc_db_wrapper_External_db_file_desc[0]); i++) {
342 if (libipv6calc_db_wrapper_External_db_file_desc[i].number == type) {
343 entry = i;
344 break;
345 };
346 };
347
348 if (entry < 0) {
349 return("unknown");
350 };
351
352 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Finished: %s type=%d has description=%s", wrapper_external_info, type, libipv6calc_db_wrapper_External_db_file_desc[i].description);
353
354 return(libipv6calc_db_wrapper_External_db_file_desc[i].description);
355 };
356
357
358 /*
359 * wrapper extension: External_db_avail
360 * ret: 1=avail 0=not-avail
361 */
libipv6calc_db_wrapper_External_db_avail(const unsigned int type)362 int libipv6calc_db_wrapper_External_db_avail(const unsigned int type) {
363 char *filename;
364 int r = 0;
365
366 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Called: %s type=%d", wrapper_external_info, type);
367
368 filename = libipv6calc_db_wrapper_External_dbfilename(type);
369
370 if (filename == NULL) {
371 goto END_libipv6calc_db_wrapper;
372 };
373
374 r = (access(filename, R_OK) == 0) ? 1:0;
375
376 if (r == 0) {
377 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Finished: %s type=%d (still unknown) (r=%d: %s)", wrapper_external_info, type, r, strerror(errno));
378 } else {
379 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Finished: %s type=%d (%s) (r=%d)", wrapper_external_info, type, filename, r);
380 };
381
382 END_libipv6calc_db_wrapper:
383 return(r);
384 };
385
386
387 /*
388 * wrapper extension: External_open_type
389 * input:
390 * type (mandatory)
391 * if | 0x10000 -> info is opened and ptr is not cached
392 * if | 0x20000 -> data-iana is opened
393 * if | 0x40000 -> data-info is opened
394 * db_recno_max_ptr (set if not NULL)
395 */
libipv6calc_db_wrapper_External_open_type(const unsigned int type_flag,long int * db_recno_max_ptr)396 DB *libipv6calc_db_wrapper_External_open_type(const unsigned int type_flag, long int *db_recno_max_ptr) {
397 DB *dbp = NULL;
398 DBC *dbcp;
399 DBT key, data;
400
401 int type = (type_flag & 0xffff);
402 int info_selector = ((type_flag & 0x10000) != 0) ? 1 : 0;
403 int data_iana_selector = ((type_flag & 0x20000) != 0) ? 1 : 0;
404 int data_info_selector = ((type_flag & 0x40000) != 0) ? 1 : 0;
405 int subdb = 0; // data
406
407 char *filename;
408 int entry = -1, i;
409 int ret;
410
411 const char *type_text;
412 if (info_selector != 0) {
413 type_text = "info";
414 } else if (data_iana_selector != 0) {
415 type_text = "data-iana";
416 subdb = 1;
417 } else if (data_info_selector != 0) {
418 type_text = "data-info";
419 subdb = 2;
420 } else {
421 type_text = "data";
422 };
423
424 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Called: %s type=%d (%s)", wrapper_external_info, type, type_text);
425
426 // check for valid type
427 for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc); i++) {
428 if (libipv6calc_db_wrapper_External_db_file_desc[i].number == (type & 0xffff)) {
429 entry = i;
430 break;
431 };
432 };
433
434 if (entry < 0) {
435 return(NULL);
436 };
437
438 if ((info_selector == 0) && (db_ptr_cache[entry][subdb] != NULL)) {
439 // already open
440 dbp = db_ptr_cache[entry][subdb];
441
442 if (db_recno_max_ptr != NULL) {
443 *db_recno_max_ptr = db_recno_max_cache[entry][subdb];
444 };
445
446 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Database already opened (cached) dbp=%p type=%d subdb=%d recno_max: %u", dbp, type, subdb, db_recno_max_cache[entry][subdb]);
447
448 goto END_libipv6calc_db_wrapper;
449 };
450
451 // retrieve filename
452 filename = libipv6calc_db_wrapper_External_dbfilename(type);
453
454 if (filename == NULL) {
455 return(NULL);
456 };
457
458 if (libipv6calc_db_wrapper_External_db_avail(type) != 1) {
459 return(NULL);
460
461 };
462
463 if ((ret = db_create(&dbp, NULL, 0)) != 0) {
464 if (ipv6calc_quiet == 0) {
465 fprintf(stderr, "db_create: %s\n", db_strerror(ret));
466 };
467 return(NULL);
468 };
469
470 if ((ret = dbp->open(dbp, NULL, filename, type_text, (info_selector == 0) ? DB_RECNO : DB_BTREE, DB_RDONLY, 0444)) != 0) {
471 if ((ipv6calc_quiet == 0) && (data_info_selector == 0)) {
472 fprintf(stderr, "db->open failed: %s (%s) subdb=%s\n", db_strerror(ret), filename, type_text);
473 };
474 return(NULL);
475 };
476
477 if (info_selector == 0) {
478 // cache entry
479 db_ptr_cache[entry][subdb] = dbp;
480
481 // get amount of entries in database
482 memset(&key, 0, sizeof(key));
483 memset(&data, 0, sizeof(data));
484
485 /* Acquire a cursor for the database. */
486 if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
487 dbp->err(dbp, ret, "DB->cursor");
488 goto END_libipv6calc_db_wrapper_close_error;
489 };
490
491 /* Walk through the database and print out the key/data pairs. */
492 if ((ret = dbcp->c_get(dbcp, &key, &data, DB_LAST)) != 0) {
493 dbp->err(dbp, ret, "DB->cursor/DB_LAST");
494 goto END_libipv6calc_db_wrapper_close_error;
495 };
496
497 /* Close the cursor. */
498 if ((ret = dbcp->c_close(dbcp)) != 0) {
499 dbp->err(dbp, ret, "DBcursor->close");
500 goto END_libipv6calc_db_wrapper_close_error;
501 };
502
503 db_recno_max_cache[entry][subdb] = *(db_recno_t *)key.data;
504
505 if (db_recno_max_cache[entry][subdb] < 2) {
506 goto END_libipv6calc_db_wrapper_close_error;
507 };
508
509 if (db_recno_max_ptr != NULL) {
510 *db_recno_max_ptr = db_recno_max_cache[entry][subdb];
511 };
512
513 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Database successfully opened (fill-cache), dbp=%p type=%d subdb=%d recno_max=%u", dbp, type, subdb, db_recno_max_cache[entry][subdb]);
514 } else {
515 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Database successfully opened, dbp=%p type=%d (info)", dbp, type);
516 };
517
518 // jump to "good end"
519 goto END_libipv6calc_db_wrapper;
520
521 END_libipv6calc_db_wrapper_close_error:
522 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "error opening database, close now");
523 libipv6calc_db_wrapper_External_close(dbp);
524 dbp = NULL;
525
526 END_libipv6calc_db_wrapper:
527 return(dbp);
528 };
529
530
531 /*******************************
532 * Wrapper functions for External
533 *******************************/
534
535 /*
536 * wrapper: External_database_info
537 */
libipv6calc_db_wrapper_External_database_info(const unsigned int type)538 char *libipv6calc_db_wrapper_External_database_info(const unsigned int type) {
539 static char resultstring[IPV6CALC_STRING_MAX] = ""; // has to be static because pointer is returned
540 char datastring[IPV6CALC_STRING_MAX];
541 char tempstring[IPV6CALC_STRING_MAX];
542 int ret, i, entry = -1;
543 DB *dbp;
544
545 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Called: %s", wrapper_external_info);
546
547 // check for valid type
548 for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc); i++) {
549 if (libipv6calc_db_wrapper_External_db_file_desc[i].number == (type & 0xffff)) {
550 entry = i;
551 break;
552 };
553 };
554
555 if (entry < 0) {
556 ERRORPRINT_WA("Invalid type (FIX CODE): %d", type);
557 goto END_libipv6calc_db_wrapper;
558 };
559
560 dbp = libipv6calc_db_wrapper_External_open_type(type | 0x10000, NULL);
561
562 if (dbp == NULL) {
563 snprintf(resultstring, sizeof(resultstring), "%s", "(CAN'T OPEN database information)");
564 goto END_libipv6calc_db_wrapper;
565 };
566
567 // get dbusage
568 ret = libipv6calc_db_wrapper_bdb_get_data_by_key(dbp, "dbusage", datastring, sizeof(datastring));
569 if (ret != 0) {
570 snprintf(resultstring, sizeof(resultstring), "%s", "can't retrieve 'dbusage', unsupported db file");
571 goto END_libipv6calc_db_wrapper_close;
572 };
573 if (strcmp(datastring, "ipv6calc") != 0) {
574 snprintf(resultstring, sizeof(resultstring), "%s", "dbusage!=ipv6calc, unsupported db file");
575 goto END_libipv6calc_db_wrapper_close;
576 };
577
578 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Database dbusage string: %s", datastring);
579
580 // get dbdate
581 ret = libipv6calc_db_wrapper_bdb_get_data_by_key(dbp, "dbdate", datastring, sizeof(datastring));
582 if (ret != 0) {
583 snprintf(resultstring, sizeof(resultstring), "%s", "can't retrieve 'dbdate', unsupported db file");
584 goto END_libipv6calc_db_wrapper_close;
585 };
586
587 snprintf(resultstring, sizeof(resultstring), "EXTDB-%d/%s", type, datastring);
588
589 // get dbcreated_unixtime
590 ret = libipv6calc_db_wrapper_bdb_get_data_by_key(dbp, "dbcreated_unixtime", datastring, sizeof(datastring));
591 if (ret != 0) {
592 snprintf(resultstring, sizeof(resultstring), "%s", "can't retrieve 'dbcreated_unixtime', unsupported db file");
593 goto END_libipv6calc_db_wrapper_close;
594 };
595
596 wrapper_db_unixtime_External[entry] = atoi(datastring);
597
598 if (wrapper_db_unixtime_External[entry] == 0) {
599 snprintf(resultstring, sizeof(resultstring), "%s", "'dbcreated_unixtime' is not proper, unsupported db file");
600 goto END_libipv6calc_db_wrapper_close;
601 };
602
603 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "wrapper_db_unixtime_External=%ld", (long int) wrapper_db_unixtime_External[entry]);
604
605 strftime(datastring, sizeof(datastring), "%Y%m%d-%H%M%S UTC", gmtime(&wrapper_db_unixtime_External[entry]));
606 snprintf(tempstring, sizeof(tempstring), "%s, created: %s", resultstring, datastring);
607 snprintf(resultstring, sizeof(resultstring), "%s", tempstring);
608
609 END_libipv6calc_db_wrapper_close:
610 libipv6calc_db_wrapper_External_close(dbp);
611
612 END_libipv6calc_db_wrapper:
613 return(resultstring);
614 };
615
616
617 /*********************************************
618 * Abstract functions
619 * *******************************************/
620
621 /* query for available features
622 * ret=-1: unknown
623 * 0 : not matching
624 * 1 : ok
625 */
libipv6calc_db_wrapper_External_has_features(uint32_t features)626 int libipv6calc_db_wrapper_External_has_features(uint32_t features) {
627 int result = -1;
628
629 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Called with feature value to test: 0x%08x", features);
630
631 if ((wrapper_features_by_source[IPV6CALC_DB_SOURCE_EXTERNAL] & features) == features) {
632 result = 1;
633 } else {
634 result = 0;
635 };
636
637 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Return with result: %d", result);
638 return(result);
639 };
640
641
642 /* query db_unixtime by feature
643 * ret=-1: unknown
644 * 0 : not matching
645 * 1 : ok
646 */
libipv6calc_db_wrapper_External_db_unixtime_by_feature(uint32_t feature)647 time_t libipv6calc_db_wrapper_External_db_unixtime_by_feature(uint32_t feature) {
648 time_t result = 0;
649 int i;
650
651 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Called with feature value to get db_unixtime: 0x%08x", feature);
652
653 // run through entries
654 for (i = 0; i < MAXENTRIES_ARRAY(libipv6calc_db_wrapper_External_db_file_desc); i++) {
655 if ((libipv6calc_db_wrapper_External_db_file_desc[i].features & feature) == feature) {
656 // found
657 if (wrapper_db_unixtime_External[i] > result) {
658 result = wrapper_db_unixtime_External[i];
659 };
660 };
661 };
662
663 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Return for feature=0x08x db_unixtime=%ld", (long int) result);
664 return(result);
665 };
666
667
668 /*
669 * get registry number of an IPv4/IPv6 address
670 *
671 * in: ipaddr
672 * out: assignment number (-1 = no result)
673 */
libipv6calc_db_wrapper_External_registry_num_by_addr(const ipv6calc_ipaddr * ipaddrp)674 int libipv6calc_db_wrapper_External_registry_num_by_addr(const ipv6calc_ipaddr *ipaddrp) {
675 DB *dbp, *dbp_iana;
676 long int recno_max;
677 char resultstring[IPV6CALC_STRING_MAX];
678 int i, result;
679 int retval = REGISTRY_UNKNOWN;
680
681 int External_type;
682
683 switch (ipaddrp->proto) {
684 case IPV6CALC_PROTO_IPV4:
685 External_type = EXTERNAL_DB_IPV4_REGISTRY;
686 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Given IPv4 address: %08x", (unsigned int) ipaddrp->addr[0]);
687 break;
688
689 case IPV6CALC_PROTO_IPV6:
690 External_type = EXTERNAL_DB_IPV6_REGISTRY;
691 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Given IPv6 address prefix (0-63): %08x%08x", (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
692 break;
693
694 default:
695 ERRORPRINT_WA("unsupported protocol: %d (FIX CODE)", ipaddrp->proto);
696 exit(EXIT_FAILURE);
697 break;
698 };
699
700
701 // data (standard)
702 dbp = libipv6calc_db_wrapper_External_open_type(External_type, &recno_max);
703
704 if (dbp == NULL) {
705 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Error opening External by type");
706 goto END_libipv6calc_db_wrapper;
707 };
708
709 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "database opened type=%d recno_max=%ld dbp=%p", External_type, recno_max, dbp);
710
711 result = libipv6calc_db_wrapper_get_entry_generic(
712 (void *) dbp, // pointer to database
713 IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB, // type of data_ptr
714 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
715 ? IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_FIRST_LAST \
716 : IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_BASE_MASK, // key type
717 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
718 ? IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x2 \
719 : IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_WITH_VALUE_32x4 , // key format
720 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
721 ? 32 \
722 : 64, // key length
723 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
724 ? IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY \
725 : IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_SEQLONGEST, // search type
726 recno_max, // number of rows
727 ipaddrp->addr[0], // lookup key MSB
728 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
729 ? 0 \
730 : ipaddrp->addr[1], // lookup key LSB
731 resultstring, // data ptr
732 NULL // function pointer
733 );
734
735 if (result >= 0 ) {
736 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "found match in database type=%d", External_type);
737 goto END_libipv6calc_db_wrapper_match;
738 };
739
740 if (ipaddrp->proto != IPV6CALC_PROTO_IPV4) {
741 goto END_libipv6calc_db_wrapper;
742 };
743
744 // data-iana (fallback for IPv4 only)
745 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "no found match in database type=%d, fallback to IANA data now for: %08x", External_type, ipaddrp->addr[0]);
746 dbp_iana = libipv6calc_db_wrapper_External_open_type(External_type | 0x20000, &recno_max);
747
748 if (dbp == NULL) {
749 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Error opening External by type");
750 goto END_libipv6calc_db_wrapper;
751 };
752
753 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "database opened type=%d (data-iana) recno_max=%ld", External_type, recno_max);
754
755 result = libipv6calc_db_wrapper_get_entry_generic(
756 (void *) dbp_iana, // pointer to database
757 IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB, // type of data_ptr
758 IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_FIRST_LAST, // key type
759 IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x2, // key format
760 32, // key length
761 IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY, // search type
762 recno_max, // number of rows
763 ipaddrp->addr[0], // lookup key MSB
764 0, // lookup key LSB
765 resultstring, // data ptr
766 NULL // function pointer
767 );
768
769 libipv6calc_db_wrapper_External_close(dbp_iana);
770
771 if (result >= 0 ) {
772 goto END_libipv6calc_db_wrapper_match;
773 };
774
775 goto END_libipv6calc_db_wrapper;
776
777 END_libipv6calc_db_wrapper_match:
778 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "resultstring=%s", resultstring);
779
780 char datastring[IPV6CALC_STRING_MAX];
781 snprintf(datastring, sizeof(datastring), "%s", resultstring); // copy string for strtok
782
783 char *token, *cptr, **ptrptr;
784 ptrptr = &cptr;
785
786 int token_count = 0;
787
788 // split result string
789 token = strtok_r(datastring, ";", ptrptr);
790 while (token != NULL) {
791 token_count++;
792
793 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Database entry found %d: %s", token_count, token);
794
795 if (token_count == 1) {
796 for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_registries); i++) {
797 if (strcmp(token, ipv6calc_registries[i].tokensimple) == 0) {
798 retval = ipv6calc_registries[i].number;
799 break;
800 };
801 };
802 };
803
804 /* get next token */
805 token = strtok_r(NULL, ";", ptrptr);
806 };
807
808 if (token_count != 1) {
809 ERRORPRINT_WA("data has more entries than expected, corrupt database: %d (resultstring='%s' prefix=%08x%08x)", token_count, resultstring, (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
810 goto END_libipv6calc_db_wrapper;
811 };
812
813 if (retval == REGISTRY_UNKNOWN) {
814 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "did not return a record for 'registry'");
815 goto END_libipv6calc_db_wrapper;
816 };
817
818 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "result registry=%d", retval);
819
820 EXTERNAL_DB_USAGE_MAP_TAG(External_type);
821
822 END_libipv6calc_db_wrapper:
823 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "retval=%d", retval);
824 return(retval);
825 };
826
827
828 /*
829 * get country code of an IPv4/IPv6 address
830 *
831 * in: ipaddr
832 * mod: country code
833 * out: status of retrievment (0=success, -1=problem)
834 */
libipv6calc_db_wrapper_External_country_code_by_addr(const ipv6calc_ipaddr * ipaddrp,char * country,const size_t country_len)835 int libipv6calc_db_wrapper_External_country_code_by_addr(const ipv6calc_ipaddr *ipaddrp, char *country, const size_t country_len) {
836 DB *dbp;
837 long int recno_max;
838 static char resultstring[IPV6CALC_STRING_MAX];
839 int result;
840 int retval = -1;
841
842 int External_type;
843
844 switch (ipaddrp->proto) {
845 case IPV6CALC_PROTO_IPV4:
846 External_type = EXTERNAL_DB_IPV4_COUNTRYCODE;
847 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Given IPv4 address: %08x", (unsigned int) ipaddrp->addr[0]);
848 break;
849
850 case IPV6CALC_PROTO_IPV6:
851 External_type = EXTERNAL_DB_IPV6_COUNTRYCODE;
852 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Given IPv6 address prefix (0-63): %08x%08x", (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
853 break;
854
855 default:
856 ERRORPRINT_WA("unsupported protocol: %d (FIX CODE)", ipaddrp->proto);
857 exit(EXIT_FAILURE);
858 break;
859 };
860
861
862 // data (standard)
863 dbp = libipv6calc_db_wrapper_External_open_type(External_type, &recno_max);
864
865 if (dbp == NULL) {
866 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Error opening External by type");
867 goto END_libipv6calc_db_wrapper;
868 };
869
870 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "database opened type=%d recno_max=%ld dbp=%p", External_type, recno_max, dbp);
871
872 result = libipv6calc_db_wrapper_get_entry_generic(
873 (void *) dbp, // pointer to database
874 IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB, // type of data_ptr
875 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
876 ? IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_FIRST_LAST \
877 : IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_BASE_MASK, // key type
878 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
879 ? IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x2 \
880 : IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x4 , // key format
881 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
882 ? 32 \
883 : 64, // key length
884 IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY, // search type
885 recno_max, // number of rows
886 ipaddrp->addr[0], // lookup key MSB
887 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
888 ? 0 \
889 : ipaddrp->addr[1], // lookup key LSB
890 resultstring, // data ptr
891 NULL // function pointer
892 );
893
894 if (result < 0) {
895 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "no match found");
896 goto END_libipv6calc_db_wrapper;
897 };
898
899 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "resultstring=%s", resultstring);
900
901 char datastring[IPV6CALC_STRING_MAX];
902 snprintf(datastring, sizeof(datastring), "%s", resultstring); // copy string for strtok
903
904 char *token, *cptr, **ptrptr;
905 ptrptr = &cptr;
906
907 int token_count = 0;
908
909 // split result string
910 token = strtok_r(datastring, ";", ptrptr);
911 while (token != NULL) {
912 token_count++;
913
914 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Database entry found %d: %s", token_count, token);
915
916 if (token_count == 1) {
917 /* country */
918 snprintf(country, country_len, "%s", token);
919 };
920
921 /* get next token */
922 token = strtok_r(NULL, ";", ptrptr);
923 };
924
925 if (token_count != 1) {
926 ERRORPRINT_WA("data has more entries than expected, corrupt database: %d (resultstring='%s' prefix=%08x%08x)", token_count, resultstring, (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
927 goto END_libipv6calc_db_wrapper;
928 };
929
930 if (strlen(country) != 2) {
931 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "did not return a record for 'CountryCode'");
932 goto END_libipv6calc_db_wrapper;
933 };
934
935 retval = 0;
936
937 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "result CountryCode=%s", country);
938
939 EXTERNAL_DB_USAGE_MAP_TAG(External_type);
940
941 END_libipv6calc_db_wrapper:
942 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "retval=%d", retval);
943 return(retval);
944 };
945
946
947 /*
948 * get info of an IPv4/IPv6 address
949 * stored in REGISTRY db in dedicated table
950 *
951 * in: ipaddr
952 * mod: string
953 * out: 0=OK
954 */
libipv6calc_db_wrapper_External_info_by_ipaddr(const ipv6calc_ipaddr * ipaddrp,char * string,const size_t string_len)955 int libipv6calc_db_wrapper_External_info_by_ipaddr(const ipv6calc_ipaddr *ipaddrp, char *string, const size_t string_len) {
956 DB *dbp;
957 long int recno_max;
958 char resultstring[IPV6CALC_STRING_MAX];
959 int result;
960 int retval = -1;
961
962 int External_type;
963
964 switch (ipaddrp->proto) {
965 case IPV6CALC_PROTO_IPV4:
966 External_type = EXTERNAL_DB_IPV4_REGISTRY;
967 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Given IPv4 address: %08x", (unsigned int) ipaddrp->addr[0]);
968 break;
969
970 case IPV6CALC_PROTO_IPV6:
971 External_type = EXTERNAL_DB_IPV6_REGISTRY;
972 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Given IPv6 address prefix (0-63): %08x%08x", (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
973 break;
974
975 default:
976 ERRORPRINT_WA("unsupported protocol: %d (FIX CODE)", ipaddrp->proto);
977 exit(EXIT_FAILURE);
978 break;
979 };
980
981
982 // data-info
983 dbp = libipv6calc_db_wrapper_External_open_type(External_type | 0x40000, &recno_max);
984
985 if (dbp == NULL) {
986 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "Error opening External by type");
987 goto END_libipv6calc_db_wrapper;
988 };
989
990 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "database opened type=%x recno_max=%ld dbp=%p", External_type | 0x40000, recno_max, dbp);
991
992 result = libipv6calc_db_wrapper_get_entry_generic(
993 (void *) dbp, // pointer to database
994 IPV6CALC_DB_LOOKUP_DATA_PTR_TYPE_BDB, // type of data_ptr
995 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
996 ? IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_FIRST_LAST \
997 : IPV6CALC_DB_LOOKUP_DATA_KEY_TYPE_BASE_MASK, // key type
998 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
999 ? IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x2 \
1000 : IPV6CALC_DB_LOOKUP_DATA_DBD_FORMAT_SEMICOLON_SEP_HEX_32x4 , // key format
1001 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
1002 ? 32 \
1003 : 64, // key length
1004 IPV6CALC_DB_LOOKUP_DATA_SEARCH_TYPE_BINARY, // search type
1005 recno_max, // number of rows
1006 ipaddrp->addr[0], // lookup key MSB
1007 (ipaddrp->proto == IPV6CALC_PROTO_IPV4) \
1008 ? 0 \
1009 : ipaddrp->addr[1], // lookup key LSB
1010 resultstring, // data ptr
1011 NULL // function pointer
1012 );
1013
1014 if (result < 0) {
1015 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "no match found");
1016 goto END_libipv6calc_db_wrapper;
1017 };
1018
1019 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "resultstring=%s", resultstring);
1020
1021 char datastring[IPV6CALC_STRING_MAX];
1022 snprintf(datastring, sizeof(datastring), "%s", resultstring); // copy string for strtok
1023
1024 char *token, *cptr, **ptrptr;
1025 ptrptr = &cptr;
1026
1027 int token_count = 0;
1028
1029 // split result string
1030 token = strtok_r(datastring, ";", ptrptr);
1031 while (token != NULL) {
1032 token_count++;
1033
1034 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "Database entry found %d: %s", token_count, token);
1035
1036 if (token_count == 1) {
1037 /* info */
1038 snprintf(string, string_len, "%s", token);
1039 };
1040
1041 /* get next token */
1042 token = strtok_r(NULL, ";", ptrptr);
1043 };
1044
1045 if (token_count != 1) {
1046 ERRORPRINT_WA("data has more entries than expected, corrupt database: %d (resultstring='%s' prefix=%08x%08x)", token_count, resultstring, (unsigned int) ipaddrp->addr[0], (unsigned int) ipaddrp->addr[1]);
1047 goto END_libipv6calc_db_wrapper;
1048 };
1049
1050 if (strlen(string) == 0) {
1051 DEBUGPRINT_NA(DEBUG_libipv6calc_db_wrapper_External, "did not return a record for 'Info'");
1052 goto END_libipv6calc_db_wrapper;
1053 };
1054
1055 retval = 0;
1056
1057 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "result Info=%s", string);
1058
1059 EXTERNAL_DB_USAGE_MAP_TAG(External_type);
1060
1061 END_libipv6calc_db_wrapper:
1062 DEBUGPRINT_WA(DEBUG_libipv6calc_db_wrapper_External, "retval=%d", retval);
1063 return(retval);
1064 };
1065
1066
1067 #endif //SUPPORT_EXTERNAL
1068