]> git.ipfire.org Git - people/ms/libloc.git/blame - src/database.c
jenkins: Explicitely install gettext/autopoint
[people/ms/libloc.git] / src / database.c
CommitLineData
2601e83e
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15*/
16
2a30e4de 17#include <arpa/inet.h>
d3d8ede6 18#include <ctype.h>
2601e83e 19#include <errno.h>
10778041 20#include <netinet/in.h>
2601e83e
MT
21#include <stddef.h>
22#include <stdint.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
c182393f 26#include <sys/mman.h>
2601e83e 27#include <sys/types.h>
96ea74a5 28#include <time.h>
3f35869a 29#include <unistd.h>
2601e83e 30
42f3ccd7
MT
31#ifdef HAVE_ENDIAN_H
32# include <endian.h>
33#endif
34
726f9984 35#include <openssl/err.h>
b1720435 36#include <openssl/evp.h>
726f9984 37#include <openssl/pem.h>
b1720435 38
c12a1385 39#include <libloc/libloc.h>
0b1fef38 40#include <libloc/address.h>
c12a1385
MT
41#include <libloc/as.h>
42#include <libloc/as-list.h>
43#include <libloc/compat.h>
44#include <libloc/country.h>
45#include <libloc/country-list.h>
46#include <libloc/database.h>
47#include <libloc/format.h>
48#include <libloc/network.h>
49#include <libloc/network-list.h>
50#include <libloc/private.h>
51#include <libloc/stringpool.h>
2601e83e 52
18638ad2 53struct loc_database_objects {
866ae435 54 char* data;
18638ad2
MT
55 size_t length;
56 size_t count;
57};
58
866ae435
MT
59struct loc_database_signature {
60 const char* data;
61 size_t length;
62};
63
2601e83e
MT
64struct loc_database {
65 struct loc_ctx* ctx;
66 int refcount;
67
b1720435
MT
68 FILE* f;
69
22c7b98b 70 enum loc_database_version version;
96ea74a5 71 time_t created_at;
2601e83e
MT
72 off_t vendor;
73 off_t description;
4bf49d00 74 off_t license;
2601e83e 75
5ce881d4 76 // Signatures
866ae435
MT
77 struct loc_database_signature signature1;
78 struct loc_database_signature signature2;
726f9984 79
3496a16c
MT
80 // Data mapped into memory
81 char* data;
d1c5e1c1 82 ssize_t length;
3496a16c 83
18638ad2
MT
84 struct loc_stringpool* pool;
85
a5db3e49 86 // ASes in the database
18638ad2 87 struct loc_database_objects as_objects;
a5db3e49 88
f66b7b09 89 // Network tree
18638ad2 90 struct loc_database_objects network_node_objects;
f66b7b09 91
a735a563 92 // Networks
18638ad2 93 struct loc_database_objects network_objects;
a735a563 94
ec684c1a 95 // Countries
18638ad2 96 struct loc_database_objects country_objects;
2601e83e
MT
97};
98
e3f696c1
MT
99#define MAX_STACK_DEPTH 256
100
101struct loc_node_stack {
102 off_t offset;
103 int i; // Is this node 0 or 1?
104 int depth;
105};
106
7e13db74
MT
107struct loc_database_enumerator {
108 struct loc_ctx* ctx;
109 struct loc_database* db;
ccc7ab4e 110 enum loc_database_enumerator_mode mode;
7e13db74 111 int refcount;
d3d8ede6
MT
112
113 // Search string
114 char* string;
e646a8f3 115 struct loc_country_list* countries;
84a2f0c2 116 struct loc_as_list* asns;
9268db5a 117 enum loc_network_flags flags;
44e5ef71 118 int family;
d3d8ede6 119
681ff05c
MT
120 // Flatten output?
121 int flatten;
122
d3d8ede6
MT
123 // Index of the AS we are looking at
124 unsigned int as_index;
e3f696c1 125
fa9a3663
MT
126 // Index of the country we are looking at
127 unsigned int country_index;
128
e3f696c1
MT
129 // Network state
130 struct in6_addr network_address;
131 struct loc_node_stack network_stack[MAX_STACK_DEPTH];
132 int network_stack_depth;
133 unsigned int* networks_visited;
d87fd7a3 134
8c37d8a7 135 // For subnet search and bogons
d87fd7a3 136 struct loc_network_list* stack;
065b3496 137 struct loc_network_list* subnets;
9306c68d
MT
138
139 // For bogons
140 struct in6_addr gap6_start;
141 struct in6_addr gap4_start;
7e13db74
MT
142};
143
18638ad2 144/*
975f280f 145 Checks if it is safe to read the buffer of size length starting at p.
18638ad2 146*/
975f280f
MT
147#define loc_database_check_boundaries(db, p) \
148 __loc_database_check_boundaries(db, (const char*)p, sizeof(*p))
18638ad2 149
0e0be76c 150static inline int __loc_database_check_boundaries(struct loc_database* db,
975f280f 151 const char* p, const size_t length) {
d1c5e1c1 152 ssize_t offset = p - db->data;
18638ad2 153
975f280f 154 // Return if everything is within the boundary
d1c5e1c1 155 if (offset <= (ssize_t)(db->length - length))
975f280f 156 return 1;
18638ad2 157
975f280f 158 DEBUG(db->ctx, "Database read check failed at %p for %zu byte(s)\n", p, length);
d1c5e1c1 159 DEBUG(db->ctx, " p = %p (offset = %zd, length = %zu)\n", p, offset, length);
64c01ef0 160 DEBUG(db->ctx, " data = %p (length = %zd)\n", db->data, db->length);
975f280f 161 DEBUG(db->ctx, " end = %p\n", db->data + db->length);
d1c5e1c1 162 DEBUG(db->ctx, " overflow of %zd byte(s)\n", (ssize_t)(offset + length - db->length));
18638ad2 163
975f280f
MT
164 // Otherwise raise EFAULT
165 errno = EFAULT;
166 return 0;
167}
168
169/*
170 Returns a pointer to the n-th object
171*/
0e0be76c 172static inline char* loc_database_object(struct loc_database* db,
975f280f 173 const struct loc_database_objects* objects, const size_t length, const off_t n) {
975f280f
MT
174 // Calculate offset
175 const off_t offset = n * length;
176
177 // Return a pointer to where the object lies
178 char* object = objects->data + offset;
179
180 // Check if the object is part of the memory
181 if (!__loc_database_check_boundaries(db, object, length))
182 return NULL;
183
184 return object;
18638ad2
MT
185}
186
5acc1d5f
MT
187static int loc_database_version_supported(struct loc_database* db, uint8_t version) {
188 switch (version) {
189 // Supported versions
190 case LOC_DATABASE_VERSION_1:
191 return 1;
192
193 default:
194 ERROR(db->ctx, "Database version %d is not supported\n", version);
195 errno = ENOTSUP;
196 return 0;
197 }
198}
199
546c0ac0 200static int loc_database_check_magic(struct loc_database* db) {
2601e83e
MT
201 struct loc_database_magic magic;
202
203 // Read from file
b1720435 204 size_t bytes_read = fread(&magic, 1, sizeof(magic), db->f);
2601e83e
MT
205
206 // Check if we have been able to read enough data
207 if (bytes_read < sizeof(magic)) {
208 ERROR(db->ctx, "Could not read enough data to validate magic bytes\n");
209 DEBUG(db->ctx, "Read %zu bytes, but needed %zu\n", bytes_read, sizeof(magic));
808d6ac8 210 goto ERROR;
2601e83e
MT
211 }
212
213 // Compare magic bytes
546c0ac0 214 if (memcmp(magic.magic, LOC_DATABASE_MAGIC, sizeof(magic.magic)) == 0) {
2601e83e
MT
215 DEBUG(db->ctx, "Magic value matches\n");
216
5acc1d5f
MT
217 // Do we support this version?
218 if (!loc_database_version_supported(db, magic.version))
219 return 1;
220
2601e83e 221 // Parse version
22c7b98b 222 db->version = magic.version;
2601e83e
MT
223
224 return 0;
225 }
226
808d6ac8 227ERROR:
22c7b98b 228 ERROR(db->ctx, "Unrecognized file type\n");
808d6ac8 229 errno = ENOMSG;
2601e83e
MT
230
231 // Return an error
232 return 1;
233}
234
3496a16c
MT
235/*
236 Maps the entire database into memory
237*/
238static int loc_database_mmap(struct loc_database* db) {
e63d76be
MT
239 int r;
240
241 // Get file descriptor
3496a16c
MT
242 int fd = fileno(db->f);
243
244 // Determine the length of the database
245 db->length = lseek(fd, 0, SEEK_END);
246 if (db->length < 0) {
247 ERROR(db->ctx, "Could not determine the length of the database: %m\n");
248 return 1;
249 }
250
251 rewind(db->f);
252
253 // Map all data
254 db->data = mmap(NULL, db->length, PROT_READ, MAP_SHARED, fd, 0);
255 if (db->data == MAP_FAILED) {
256 ERROR(db->ctx, "Could not map the database: %m\n");
257 db->data = NULL;
258 return 1;
259 }
260
64c01ef0 261 DEBUG(db->ctx, "Mapped database of %zd byte(s) at %p\n", db->length, db->data);
3496a16c 262
e63d76be
MT
263 // Tell the system that we expect to read data randomly
264 r = madvise(db->data, db->length, MADV_RANDOM);
265 if (r) {
266 ERROR(db->ctx, "madvise() failed: %m\n");
267 return r;
268 }
269
3496a16c
MT
270 return 0;
271}
272
18638ad2
MT
273/*
274 Maps arbitrary objects from the database into memory.
275*/
ff59db8e
MT
276static int loc_database_map_objects(struct loc_database* db, struct loc_database_objects* objects,
277 const size_t size, const off_t offset, const size_t length) {
18638ad2 278 // Store parameters
866ae435 279 objects->data = db->data + offset;
18638ad2
MT
280 objects->length = length;
281 objects->count = objects->length / size;
a5db3e49 282
866ae435
MT
283 return 0;
284}
a735a563 285
866ae435
MT
286static int loc_database_read_signature(struct loc_database* db,
287 struct loc_database_signature* signature, const char* data, const size_t length) {
288 // Check for a plausible signature length
289 if (length > LOC_SIGNATURE_MAX_LENGTH) {
290 ERROR(db->ctx, "Signature too long: %zu\n", length);
291 errno = EINVAL;
18638ad2 292 return 1;
a735a563
MT
293 }
294
866ae435
MT
295 // Store data & length
296 signature->data = data;
297 signature->length = length;
a735a563 298
866ae435
MT
299 DEBUG(db->ctx, "Read signature of %zu byte(s) at %p\n",
300 signature->length, signature->data);
ec684c1a 301
866ae435 302 hexdump(db->ctx, signature->data, signature->length);
ec684c1a 303
ec684c1a
MT
304 return 0;
305}
306
b904896a 307static int loc_database_read_header_v1(struct loc_database* db) {
866ae435
MT
308 const struct loc_database_header_v1* header =
309 (const struct loc_database_header_v1*)(db->data + LOC_DATABASE_MAGIC_SIZE);
5ce881d4 310 int r;
2601e83e 311
866ae435 312 DEBUG(db->ctx, "Reading header at %p\n", header);
2601e83e 313
866ae435
MT
314 // Check if we can read the header
315 if (!loc_database_check_boundaries(db, header)) {
2601e83e 316 ERROR(db->ctx, "Could not read enough data for header\n");
18638ad2 317 return 1;
2601e83e
MT
318 }
319
866ae435
MT
320 // Dump the entire header
321 hexdump(db->ctx, header, sizeof(*header));
2601e83e 322
866ae435
MT
323 // Copy over data
324 db->created_at = be64toh(header->created_at);
325 db->vendor = be32toh(header->vendor);
326 db->description = be32toh(header->description);
327 db->license = be32toh(header->license);
726f9984 328
5ce881d4 329 // Read signatures
866ae435
MT
330 r = loc_database_read_signature(db, &db->signature1,
331 header->signature1, be16toh(header->signature1_length));
332 if (r)
333 return r;
726f9984 334
866ae435
MT
335 r = loc_database_read_signature(db, &db->signature2,
336 header->signature2, be16toh(header->signature2_length));
337 if (r)
338 return r;
726f9984 339
975f280f
MT
340 const char* stringpool_start = db->data + be32toh(header->pool_offset);
341 size_t stringpool_length = be32toh(header->pool_length);
342
343 // Check if the stringpool is part of the mapped area
344 if (!__loc_database_check_boundaries(db, stringpool_start, stringpool_length))
345 return 1;
346
18638ad2 347 // Open the stringpool
975f280f 348 r = loc_stringpool_open(db->ctx, &db->pool, stringpool_start, stringpool_length);
2601e83e
MT
349 if (r)
350 return r;
351
18638ad2
MT
352 // Map AS objects
353 r = loc_database_map_objects(db, &db->as_objects,
354 sizeof(struct loc_database_as_v1),
866ae435
MT
355 be32toh(header->as_offset),
356 be32toh(header->as_length));
a5db3e49
MT
357 if (r)
358 return r;
359
18638ad2
MT
360 // Map Network Nodes
361 r = loc_database_map_objects(db, &db->network_node_objects,
362 sizeof(struct loc_database_network_node_v1),
866ae435
MT
363 be32toh(header->network_tree_offset),
364 be32toh(header->network_tree_length));
f66b7b09
MT
365 if (r)
366 return r;
367
18638ad2
MT
368 // Map Networks
369 r = loc_database_map_objects(db, &db->network_objects,
370 sizeof(struct loc_database_network_v1),
866ae435
MT
371 be32toh(header->network_data_offset),
372 be32toh(header->network_data_length));
a735a563
MT
373 if (r)
374 return r;
375
18638ad2
MT
376 // Map countries
377 r = loc_database_map_objects(db, &db->country_objects,
378 sizeof(struct loc_database_country_v1),
866ae435
MT
379 be32toh(header->countries_offset),
380 be32toh(header->countries_length));
ec684c1a
MT
381 if (r)
382 return r;
383
2601e83e
MT
384 return 0;
385}
386
b1720435 387static int loc_database_read_header(struct loc_database* db) {
22c7b98b
MT
388 DEBUG(db->ctx, "Database version is %u\n", db->version);
389
2601e83e 390 switch (db->version) {
22c7b98b 391 case LOC_DATABASE_VERSION_1:
b904896a 392 return loc_database_read_header_v1(db);
2601e83e
MT
393
394 default:
395 ERROR(db->ctx, "Incompatible database version: %u\n", db->version);
396 return 1;
397 }
398}
399
1642ccea
MT
400static int loc_database_clone_handle(struct loc_database* db, FILE* f) {
401 // Fetch the FD of the original handle
b1720435
MT
402 int fd = fileno(f);
403
404 // Clone file descriptor
405 fd = dup(fd);
c852a284 406 if (fd < 0) {
b1720435 407 ERROR(db->ctx, "Could not duplicate file descriptor\n");
1642ccea 408 return 1;
b1720435
MT
409 }
410
411 // Reopen the file so that we can keep our own file handle
3a661db2 412 db->f = fdopen(fd, "r");
b1720435
MT
413 if (!db->f) {
414 ERROR(db->ctx, "Could not re-open database file\n");
1642ccea 415 return 1;
b1720435
MT
416 }
417
418 // Rewind to the start of the file
419 rewind(db->f);
420
1642ccea
MT
421 return 0;
422}
423
424static int loc_database_open(struct loc_database* db, FILE* f) {
425 int r;
426
427 clock_t start = clock();
428
429 // Clone the file handle
430 r = loc_database_clone_handle(db, f);
431 if (r)
432 return r;
433
02879100 434 // Read magic bytes
546c0ac0 435 r = loc_database_check_magic(db);
02879100
MT
436 if (r)
437 return r;
438
3496a16c
MT
439 // Map the database into memory
440 r = loc_database_mmap(db);
441 if (r)
442 return r;
443
02879100 444 // Read the header
b1720435 445 r = loc_database_read_header(db);
02879100
MT
446 if (r)
447 return r;
448
449 clock_t end = clock();
450
e16c943b
MT
451 INFO(db->ctx, "Opened database in %.4fms\n",
452 (double)(end - start) / CLOCKS_PER_SEC * 1000);
02879100
MT
453
454 return 0;
455}
456
c182393f 457static void loc_database_free(struct loc_database* db) {
3496a16c
MT
458 int r;
459
c182393f 460 DEBUG(db->ctx, "Releasing database %p\n", db);
c34e76f1 461
3496a16c
MT
462 // Unmap the entire database
463 if (db->data) {
464 r = munmap(db->data, db->length);
465 if (r)
466 ERROR(db->ctx, "Could not unmap the database: %m\n");
467 }
468
18638ad2 469 // Free the stringpool
414d8958
MT
470 if (db->pool)
471 loc_stringpool_unref(db->pool);
c34e76f1 472
b1720435
MT
473 // Close database file
474 if (db->f)
475 fclose(db->f);
476
c182393f
MT
477 loc_unref(db->ctx);
478 free(db);
c34e76f1
MT
479}
480
50c0fbcd
MT
481LOC_EXPORT int loc_database_new(struct loc_ctx* ctx, struct loc_database** database, FILE* f) {
482 struct loc_database* db = NULL;
8ee057fd 483 int r = 1;
50c0fbcd
MT
484
485 // Fail on invalid file handle
486 if (!f) {
487 errno = EINVAL;
488 return 1;
489 }
490
491 // Allocate the database object
492 db = calloc(1, sizeof(*db));
493 if (!db)
494 goto ERROR;
495
496 // Reference context
497 db->ctx = loc_ref(ctx);
498 db->refcount = 1;
499
500 DEBUG(db->ctx, "Database object allocated at %p\n", db);
501
502 // Try to open the database
1642ccea 503 r = loc_database_open(db, f);
50c0fbcd
MT
504 if (r)
505 goto ERROR;
506
507 *database = db;
508 return 0;
509
510ERROR:
511 if (db)
512 loc_database_free(db);
513
514 return r;
515}
516
517LOC_EXPORT struct loc_database* loc_database_ref(struct loc_database* db) {
518 db->refcount++;
519
520 return db;
521}
522
c182393f
MT
523LOC_EXPORT struct loc_database* loc_database_unref(struct loc_database* db) {
524 if (--db->refcount > 0)
525 return NULL;
78ace4ed 526
c182393f
MT
527 loc_database_free(db);
528 return NULL;
529}
78ace4ed 530
726f9984 531LOC_EXPORT int loc_database_verify(struct loc_database* db, FILE* f) {
98b2876e
MT
532 size_t bytes_read = 0;
533
726f9984 534 // Cannot do this when no signature is available
866ae435 535 if (!db->signature1.data && !db->signature2.data) {
726f9984
MT
536 DEBUG(db->ctx, "No signature available to verify\n");
537 return 1;
538 }
539
c81205a5
MT
540 // Start the stopwatch
541 clock_t start = clock();
542
726f9984
MT
543 // Load public key
544 EVP_PKEY* pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
545 if (!pkey) {
6cd02f1d
MT
546 ERROR(db->ctx, "Could not parse public key: %s\n",
547 ERR_error_string(ERR_get_error(), NULL));
726f9984
MT
548
549 return -1;
550 }
551
b1720435
MT
552 int r = 0;
553
554 EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
555
b1720435 556 // Initialise hash function
e7f4b2ce
MT
557 r = EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey);
558 if (r != 1) {
559 ERROR(db->ctx, "Error initializing signature validation: %s\n",
560 ERR_error_string(ERR_get_error(), NULL));
561 r = 1;
562
563 goto CLEANUP;
564 }
b1720435
MT
565
566 // Reset file to start
567 rewind(db->f);
568
569 // Read magic
570 struct loc_database_magic magic;
98b2876e
MT
571 bytes_read = fread(&magic, 1, sizeof(magic), db->f);
572 if (bytes_read < sizeof(magic)) {
573 ERROR(db->ctx, "Could not read header: %m\n");
574 r = 1;
575 goto CLEANUP;
576 }
b1720435 577
a0cff45d
MT
578 hexdump(db->ctx, &magic, sizeof(magic));
579
b1720435 580 // Feed magic into the hash
e7f4b2ce
MT
581 r = EVP_DigestVerifyUpdate(mdctx, &magic, sizeof(magic));
582 if (r != 1) {
583 ERROR(db->ctx, "%s\n", ERR_error_string(ERR_get_error(), NULL));
584 r = 1;
585
586 goto CLEANUP;
587 }
b1720435
MT
588
589 // Read the header
b904896a 590 struct loc_database_header_v1 header_v1;
b1720435
MT
591
592 switch (db->version) {
22c7b98b 593 case LOC_DATABASE_VERSION_1:
54f0649f
MT
594 bytes_read = fread(&header_v1, 1, sizeof(header_v1), db->f);
595 if (bytes_read < sizeof(header_v1)) {
596 ERROR(db->ctx, "Could not read header\n");
597 r = 1;
598
599 goto CLEANUP;
600 }
b1720435 601
5ce881d4
MT
602 // Clear signatures
603 memset(header_v1.signature1, '\0', sizeof(header_v1.signature1));
604 header_v1.signature1_length = 0;
605 memset(header_v1.signature2, '\0', sizeof(header_v1.signature2));
606 header_v1.signature2_length = 0;
b1720435 607
b904896a 608 hexdump(db->ctx, &header_v1, sizeof(header_v1));
a0cff45d 609
b1720435 610 // Feed header into the hash
b904896a 611 r = EVP_DigestVerifyUpdate(mdctx, &header_v1, sizeof(header_v1));
e7f4b2ce
MT
612 if (r != 1) {
613 ERROR(db->ctx, "%s\n", ERR_error_string(ERR_get_error(), NULL));
614 r = 1;
615
616 goto CLEANUP;
617 }
b1720435
MT
618 break;
619
620 default:
64c01ef0 621 ERROR(db->ctx, "Cannot compute hash for database with format %u\n",
b1720435
MT
622 db->version);
623 r = -EINVAL;
624 goto CLEANUP;
625 }
626
726f9984
MT
627 // Walk through the file in chunks of 64kB
628 char buffer[64 * 1024];
b1720435
MT
629
630 while (!feof(db->f)) {
54f0649f 631 bytes_read = fread(buffer, 1, sizeof(buffer), db->f);
b1720435 632
a0cff45d
MT
633 hexdump(db->ctx, buffer, bytes_read);
634
e7f4b2ce
MT
635 r = EVP_DigestVerifyUpdate(mdctx, buffer, bytes_read);
636 if (r != 1) {
637 ERROR(db->ctx, "%s\n", ERR_error_string(ERR_get_error(), NULL));
638 r = 1;
639
640 goto CLEANUP;
641 }
b1720435
MT
642 }
643
fa4898d0
MT
644 int sig1_valid = 0;
645 int sig2_valid = 0;
646
5ce881d4 647 // Check first signature
a6445b74 648 if (db->signature1.length) {
866ae435 649 hexdump(db->ctx, db->signature1.data, db->signature1.length);
726f9984 650
5ce881d4 651 r = EVP_DigestVerifyFinal(mdctx,
866ae435 652 (unsigned char*)db->signature1.data, db->signature1.length);
5ce881d4
MT
653
654 if (r == 0) {
655 DEBUG(db->ctx, "The first signature is invalid\n");
5ce881d4
MT
656 } else if (r == 1) {
657 DEBUG(db->ctx, "The first signature is valid\n");
fa4898d0 658 sig1_valid = 1;
5ce881d4
MT
659 } else {
660 ERROR(db->ctx, "Error verifying the first signature: %s\n",
661 ERR_error_string(ERR_get_error(), NULL));
662 r = -1;
fa4898d0 663 goto CLEANUP;
5ce881d4 664 }
b1720435
MT
665 }
666
5ce881d4 667 // Check second signature only when the first one was invalid
a6445b74 668 if (db->signature2.length) {
866ae435 669 hexdump(db->ctx, db->signature2.data, db->signature2.length);
5ce881d4
MT
670
671 r = EVP_DigestVerifyFinal(mdctx,
866ae435 672 (unsigned char*)db->signature2.data, db->signature2.length);
5ce881d4
MT
673
674 if (r == 0) {
675 DEBUG(db->ctx, "The second signature is invalid\n");
5ce881d4
MT
676 } else if (r == 1) {
677 DEBUG(db->ctx, "The second signature is valid\n");
fa4898d0 678 sig2_valid = 1;
5ce881d4
MT
679 } else {
680 ERROR(db->ctx, "Error verifying the second signature: %s\n",
681 ERR_error_string(ERR_get_error(), NULL));
682 r = -1;
fa4898d0 683 goto CLEANUP;
5ce881d4
MT
684 }
685 }
257626f5 686
c81205a5 687 clock_t end = clock();
6661692f 688 INFO(db->ctx, "Signature checked in %.4fms\n",
c81205a5
MT
689 (double)(end - start) / CLOCKS_PER_SEC * 1000);
690
fa4898d0
MT
691 // Check if at least one signature as okay
692 if (sig1_valid || sig2_valid)
693 r = 0;
694 else
695 r = 1;
696
b1720435
MT
697CLEANUP:
698 // Cleanup
699 EVP_MD_CTX_free(mdctx);
726f9984 700 EVP_PKEY_free(pkey);
b1720435
MT
701
702 return r;
703}
704
c182393f
MT
705LOC_EXPORT time_t loc_database_created_at(struct loc_database* db) {
706 return db->created_at;
707}
78ace4ed 708
c182393f
MT
709LOC_EXPORT const char* loc_database_get_vendor(struct loc_database* db) {
710 return loc_stringpool_get(db->pool, db->vendor);
711}
78ace4ed 712
c182393f
MT
713LOC_EXPORT const char* loc_database_get_description(struct loc_database* db) {
714 return loc_stringpool_get(db->pool, db->description);
715}
78ace4ed 716
4bf49d00
MT
717LOC_EXPORT const char* loc_database_get_license(struct loc_database* db) {
718 return loc_stringpool_get(db->pool, db->license);
719}
720
c182393f 721LOC_EXPORT size_t loc_database_count_as(struct loc_database* db) {
18638ad2 722 return db->as_objects.count;
78ace4ed
MT
723}
724
c182393f
MT
725// Returns the AS at position pos
726static int loc_database_fetch_as(struct loc_database* db, struct loc_as** as, off_t pos) {
975f280f 727 struct loc_database_as_v1* as_v1 = NULL;
18638ad2
MT
728 int r;
729
730 if ((size_t)pos >= db->as_objects.count) {
731 errno = ERANGE;
732 return 1;
733 }
2601e83e 734
5c57de03 735 DEBUG(db->ctx, "Fetching AS at position %jd\n", (intmax_t)pos);
2601e83e 736
c182393f 737 switch (db->version) {
22c7b98b 738 case LOC_DATABASE_VERSION_1:
975f280f
MT
739 // Find the object
740 as_v1 = (struct loc_database_as_v1*)loc_database_object(db,
741 &db->as_objects, sizeof(*as_v1), pos);
742 if (!as_v1)
18638ad2
MT
743 return 1;
744
975f280f 745 r = loc_as_new_from_database_v1(db->ctx, db->pool, as, as_v1);
c182393f 746 break;
2601e83e 747
c182393f 748 default:
18638ad2
MT
749 errno = ENOTSUP;
750 return 1;
c182393f 751 }
2601e83e 752
18638ad2 753 if (r == 0)
c182393f 754 DEBUG(db->ctx, "Got AS%u\n", loc_as_get_number(*as));
2601e83e 755
c182393f
MT
756 return r;
757}
c34e76f1 758
c182393f
MT
759// Performs a binary search to find the AS in the list
760LOC_EXPORT int loc_database_get_as(struct loc_database* db, struct loc_as** as, uint32_t number) {
761 off_t lo = 0;
18638ad2 762 off_t hi = db->as_objects.count - 1;
c34e76f1 763
6661692f 764#ifdef ENABLE_DEBUG
8f3e2a06
MT
765 // Save start time
766 clock_t start = clock();
6661692f 767#endif
8f3e2a06 768
c182393f
MT
769 while (lo <= hi) {
770 off_t i = (lo + hi) / 2;
8f5b676a 771
c182393f
MT
772 // Fetch AS in the middle between lo and hi
773 int r = loc_database_fetch_as(db, as, i);
774 if (r)
775 return r;
a5db3e49 776
c182393f
MT
777 // Check if this is a match
778 uint32_t as_number = loc_as_get_number(*as);
8f3e2a06 779 if (as_number == number) {
6661692f 780#ifdef ENABLE_DEBUG
8f3e2a06
MT
781 clock_t end = clock();
782
783 // Log how fast this has been
e16c943b
MT
784 DEBUG(db->ctx, "Found AS%u in %.4fms\n", as_number,
785 (double)(end - start) / CLOCKS_PER_SEC * 1000);
6661692f 786#endif
8f3e2a06 787
c182393f 788 return 0;
8f3e2a06 789 }
c182393f
MT
790
791 // If it wasn't, we release the AS and
792 // adjust our search pointers
793 loc_as_unref(*as);
794
795 if (as_number < number) {
796 lo = i + 1;
797 } else
798 hi = i - 1;
799 }
2601e83e 800
c182393f
MT
801 // Nothing found
802 *as = NULL;
2601e83e 803
8f3e2a06 804 return 1;
2601e83e 805}
10778041
MT
806
807// Returns the network at position pos
39a55353
MT
808static int loc_database_fetch_network(struct loc_database* db, struct loc_network** network,
809 struct in6_addr* address, unsigned int prefix, off_t pos) {
975f280f 810 struct loc_database_network_v1* network_v1 = NULL;
18638ad2
MT
811 int r;
812
813 if ((size_t)pos >= db->network_objects.count) {
9b9e5faf 814 DEBUG(db->ctx, "Network ID out of range: %jd/%jd\n",
18638ad2
MT
815 (intmax_t)pos, (intmax_t)db->network_objects.count);
816 errno = ERANGE;
817 return 1;
9b9e5faf
MT
818 }
819
5c57de03 820 DEBUG(db->ctx, "Fetching network at position %jd\n", (intmax_t)pos);
10778041 821
10778041 822 switch (db->version) {
22c7b98b 823 case LOC_DATABASE_VERSION_1:
18638ad2 824 // Read the object
975f280f
MT
825 network_v1 = (struct loc_database_network_v1*)loc_database_object(db,
826 &db->network_objects, sizeof(*network_v1), pos);
827 if (!network_v1)
18638ad2
MT
828 return 1;
829
975f280f 830 r = loc_network_new_from_database_v1(db->ctx, network, address, prefix, network_v1);
10778041
MT
831 break;
832
833 default:
18638ad2
MT
834 errno = ENOTSUP;
835 return 1;
10778041
MT
836 }
837
0a0a289a
MT
838 if (r == 0)
839 DEBUG(db->ctx, "Got network %s\n", loc_network_str(*network));
10778041
MT
840
841 return r;
842}
2a30e4de 843
b904896a 844static int __loc_database_node_is_leaf(const struct loc_database_network_node_v1* node) {
39a55353 845 return (node->network != htobe32(0xffffffff));
025ef489
MT
846}
847
848static int __loc_database_lookup_handle_leaf(struct loc_database* db, const struct in6_addr* address,
39a55353 849 struct loc_network** network, struct in6_addr* network_address, unsigned int prefix,
b904896a 850 const struct loc_database_network_node_v1* node) {
39a55353
MT
851 off_t network_index = be32toh(node->network);
852
18638ad2 853 DEBUG(db->ctx, "Handling leaf node at %jd\n", (intmax_t)network_index);
2a30e4de
MT
854
855 // Fetch the network
18638ad2 856 int r = loc_database_fetch_network(db, network, network_address, prefix, network_index);
e85e2b0b 857 if (r) {
18638ad2
MT
858 ERROR(db->ctx, "Could not fetch network %jd from database: %m\n",
859 (intmax_t)network_index);
2a30e4de 860 return r;
e85e2b0b 861 }
39a55353 862
2a30e4de 863 // Check if the given IP address is inside the network
0258d3c9 864 if (!loc_network_matches_address(*network, address)) {
2a30e4de
MT
865 DEBUG(db->ctx, "Searched address is not part of the network\n");
866
867 loc_network_unref(*network);
868 *network = NULL;
869 return 1;
870 }
871
872 // A network was found and the IP address matches
873 return 0;
874}
875
2a30e4de
MT
876// Searches for an exact match along the path
877static int __loc_database_lookup(struct loc_database* db, const struct in6_addr* address,
878 struct loc_network** network, struct in6_addr* network_address,
18638ad2 879 off_t node_index, unsigned int level) {
975f280f 880 struct loc_database_network_node_v1* node_v1 = NULL;
18638ad2 881
025ef489 882 int r;
18638ad2
MT
883
884 // Fetch the next node
975f280f
MT
885 node_v1 = (struct loc_database_network_node_v1*)loc_database_object(db,
886 &db->network_node_objects, sizeof(*node_v1), node_index);
887 if (!node_v1)
18638ad2 888 return 1;
2a30e4de
MT
889
890 // Follow the path
d698ca09
MT
891 int bit = loc_address_get_bit(address, level);
892 loc_address_set_bit(network_address, level, bit);
2a30e4de
MT
893
894 if (bit == 0)
975f280f 895 node_index = be32toh(node_v1->zero);
2a30e4de 896 else
975f280f 897 node_index = be32toh(node_v1->one);
2a30e4de 898
9086d2b1
MT
899 // If the node index is zero, the tree ends here
900 // and we cannot descend any further
901 if (node_index > 0) {
902 // Check boundaries
18638ad2
MT
903 if ((size_t)node_index >= db->network_node_objects.count) {
904 errno = ERANGE;
905 return 1;
906 }
2a30e4de 907
9086d2b1 908 // Move on to the next node
18638ad2 909 r = __loc_database_lookup(db, address, network, network_address, node_index, level + 1);
95d271bb 910 if (r < 0)
9086d2b1 911 return r;
ec1d9681
MT
912
913 DEBUG(db->ctx, "No match found below level %u\n", level);
914 } else {
915 DEBUG(db->ctx, "Tree ended at level %u\n", level);
9086d2b1 916 }
2a30e4de 917
9086d2b1 918 // If this node has a leaf, we will check if it matches
95d271bb 919 if (!*network && __loc_database_node_is_leaf(node_v1)) {
975f280f 920 r = __loc_database_lookup_handle_leaf(db, address, network, network_address, level, node_v1);
9e72b8a0 921 if (r < 0)
9086d2b1
MT
922 return r;
923 }
2a30e4de 924
9e72b8a0
MT
925 // Return no error - even if nothing was found
926 return 0;
2a30e4de
MT
927}
928
929LOC_EXPORT int loc_database_lookup(struct loc_database* db,
a178efea 930 const struct in6_addr* address, struct loc_network** network) {
2a30e4de
MT
931 struct in6_addr network_address;
932 memset(&network_address, 0, sizeof(network_address));
933
934 *network = NULL;
935
6661692f 936#ifdef ENABLE_DEBUG
2a30e4de
MT
937 // Save start time
938 clock_t start = clock();
6661692f 939#endif
2a30e4de 940
18638ad2 941 int r = __loc_database_lookup(db, address, network, &network_address, 0, 0);
2a30e4de 942
6661692f 943#ifdef ENABLE_DEBUG
2a30e4de
MT
944 clock_t end = clock();
945
946 // Log how fast this has been
e16c943b
MT
947 DEBUG(db->ctx, "Executed network search in %.4fms\n",
948 (double)(end - start) / CLOCKS_PER_SEC * 1000);
6661692f 949#endif
2a30e4de
MT
950
951 return r;
952}
953
954LOC_EXPORT int loc_database_lookup_from_string(struct loc_database* db,
955 const char* string, struct loc_network** network) {
956 struct in6_addr address;
957
95b6a8e4 958 int r = loc_address_parse(&address, NULL, string);
2a30e4de
MT
959 if (r)
960 return r;
961
962 return loc_database_lookup(db, &address, network);
963}
7e13db74 964
ec684c1a
MT
965// Returns the country at position pos
966static int loc_database_fetch_country(struct loc_database* db,
967 struct loc_country** country, off_t pos) {
975f280f 968 struct loc_database_country_v1* country_v1 = NULL;
18638ad2
MT
969 int r;
970
971 // Check if the country is within range
972 if ((size_t)pos >= db->country_objects.count) {
973 errno = ERANGE;
974 return 1;
975 }
ec684c1a 976
2e2325a9 977 DEBUG(db->ctx, "Fetching country at position %jd\n", (intmax_t)pos);
ec684c1a 978
ec684c1a 979 switch (db->version) {
22c7b98b 980 case LOC_DATABASE_VERSION_1:
18638ad2 981 // Read the object
975f280f
MT
982 country_v1 = (struct loc_database_country_v1*)loc_database_object(db,
983 &db->country_objects, sizeof(*country_v1), pos);
984 if (!country_v1)
18638ad2
MT
985 return 1;
986
975f280f 987 r = loc_country_new_from_database_v1(db->ctx, db->pool, country, country_v1);
ec684c1a
MT
988 break;
989
990 default:
18638ad2
MT
991 errno = ENOTSUP;
992 return 1;
ec684c1a
MT
993 }
994
18638ad2 995 if (r == 0)
ec684c1a 996 DEBUG(db->ctx, "Got country %s\n", loc_country_get_code(*country));
ec684c1a
MT
997
998 return r;
999}
1000
1001// Performs a binary search to find the country in the list
1002LOC_EXPORT int loc_database_get_country(struct loc_database* db,
1003 struct loc_country** country, const char* code) {
1004 off_t lo = 0;
18638ad2 1005 off_t hi = db->country_objects.count - 1;
ec684c1a 1006
8fcb5bc7
MT
1007 // Check if the country code is valid
1008 if (!loc_country_code_is_valid(code)) {
1009 errno = EINVAL;
1010 return 1;
1011 }
1012
6661692f 1013#ifdef ENABLE_DEBUG
ec684c1a
MT
1014 // Save start time
1015 clock_t start = clock();
6661692f 1016#endif
ec684c1a
MT
1017
1018 while (lo <= hi) {
1019 off_t i = (lo + hi) / 2;
1020
1021 // Fetch country in the middle between lo and hi
1022 int r = loc_database_fetch_country(db, country, i);
1023 if (r)
1024 return r;
1025
1026 // Check if this is a match
1027 const char* cc = loc_country_get_code(*country);
1028 int result = strcmp(code, cc);
1029
1030 if (result == 0) {
6661692f 1031#ifdef ENABLE_DEBUG
ec684c1a
MT
1032 clock_t end = clock();
1033
1034 // Log how fast this has been
1035 DEBUG(db->ctx, "Found country %s in %.4fms\n", cc,
1036 (double)(end - start) / CLOCKS_PER_SEC * 1000);
6661692f 1037#endif
ec684c1a
MT
1038
1039 return 0;
1040 }
1041
1042 // If it wasn't, we release the country and
1043 // adjust our search pointers
1044 loc_country_unref(*country);
1045
191830da 1046 if (result > 0) {
ec684c1a
MT
1047 lo = i + 1;
1048 } else
1049 hi = i - 1;
1050 }
1051
1052 // Nothing found
1053 *country = NULL;
1054
8fcb5bc7 1055 return 0;
ec684c1a
MT
1056}
1057
7e13db74
MT
1058// Enumerator
1059
d87fd7a3
MT
1060static void loc_database_enumerator_free(struct loc_database_enumerator* enumerator) {
1061 DEBUG(enumerator->ctx, "Releasing database enumerator %p\n", enumerator);
1062
1063 // Release all references
1064 loc_database_unref(enumerator->db);
1065 loc_unref(enumerator->ctx);
1066
1067 if (enumerator->string)
1068 free(enumerator->string);
1069
5470d06c
MT
1070 if (enumerator->countries)
1071 loc_country_list_unref(enumerator->countries);
1072
1073 if (enumerator->asns)
1074 loc_as_list_unref(enumerator->asns);
1075
d87fd7a3 1076 // Free network search
18638ad2
MT
1077 if (enumerator->networks_visited)
1078 free(enumerator->networks_visited);
d87fd7a3 1079
8c37d8a7 1080 // Free subnet/bogons stack
d87fd7a3
MT
1081 if (enumerator->stack)
1082 loc_network_list_unref(enumerator->stack);
1083
065b3496
MT
1084 if (enumerator->subnets)
1085 loc_network_list_unref(enumerator->subnets);
1086
d87fd7a3
MT
1087 free(enumerator);
1088}
1089
ccc7ab4e 1090LOC_EXPORT int loc_database_enumerator_new(struct loc_database_enumerator** enumerator,
681ff05c 1091 struct loc_database* db, enum loc_database_enumerator_mode mode, int flags) {
18638ad2
MT
1092 int r;
1093
7e13db74 1094 struct loc_database_enumerator* e = calloc(1, sizeof(*e));
18638ad2 1095 if (!e) {
7e13db74 1096 return -ENOMEM;
18638ad2 1097 }
7e13db74
MT
1098
1099 // Reference context
1100 e->ctx = loc_ref(db->ctx);
1101 e->db = loc_database_ref(db);
ccc7ab4e 1102 e->mode = mode;
7e13db74
MT
1103 e->refcount = 1;
1104
681ff05c
MT
1105 // Flatten output?
1106 e->flatten = (flags & LOC_DB_ENUMERATOR_FLAGS_FLATTEN);
1107
e3f696c1 1108 // Initialise graph search
e3f696c1 1109 e->network_stack_depth = 1;
18638ad2 1110 e->networks_visited = calloc(db->network_node_objects.count, sizeof(*e->networks_visited));
18638ad2
MT
1111 if (!e->networks_visited) {
1112 ERROR(db->ctx, "Could not allocated visited networks: %m\n");
1113 r = 1;
1114 goto ERROR;
1115 }
e3f696c1 1116
d87fd7a3 1117 // Allocate stack
18638ad2
MT
1118 r = loc_network_list_new(e->ctx, &e->stack);
1119 if (r)
1120 goto ERROR;
d87fd7a3 1121
9306c68d
MT
1122 // Initialize bogon search
1123 loc_address_reset(&e->gap6_start, AF_INET6);
1124 loc_address_reset(&e->gap4_start, AF_INET);
1125
7e13db74
MT
1126 DEBUG(e->ctx, "Database enumerator object allocated at %p\n", e);
1127
1128 *enumerator = e;
1129 return 0;
18638ad2
MT
1130
1131ERROR:
1132 if (e)
1133 loc_database_enumerator_free(e);
1134
1135 return r;
7e13db74
MT
1136}
1137
1138LOC_EXPORT struct loc_database_enumerator* loc_database_enumerator_ref(struct loc_database_enumerator* enumerator) {
1139 enumerator->refcount++;
1140
1141 return enumerator;
1142}
1143
7e13db74
MT
1144LOC_EXPORT struct loc_database_enumerator* loc_database_enumerator_unref(struct loc_database_enumerator* enumerator) {
1145 if (!enumerator)
1146 return NULL;
1147
1148 if (--enumerator->refcount > 0)
1149 return enumerator;
1150
1151 loc_database_enumerator_free(enumerator);
1152 return NULL;
1153}
d3d8ede6
MT
1154
1155LOC_EXPORT int loc_database_enumerator_set_string(struct loc_database_enumerator* enumerator, const char* string) {
1156 enumerator->string = strdup(string);
1157
1158 // Make the string lowercase
1159 for (char *p = enumerator->string; *p; p++)
1160 *p = tolower(*p);
1161
1162 return 0;
1163}
1164
e646a8f3
MT
1165LOC_EXPORT struct loc_country_list* loc_database_enumerator_get_countries(
1166 struct loc_database_enumerator* enumerator) {
1167 if (!enumerator->countries)
1168 return NULL;
35bb3a32 1169
e646a8f3
MT
1170 return loc_country_list_ref(enumerator->countries);
1171}
4ef1761f 1172
e646a8f3
MT
1173LOC_EXPORT int loc_database_enumerator_set_countries(
1174 struct loc_database_enumerator* enumerator, struct loc_country_list* countries) {
1175 if (enumerator->countries)
1176 loc_country_list_unref(enumerator->countries);
57146963 1177
e646a8f3 1178 enumerator->countries = loc_country_list_ref(countries);
35bb3a32
MT
1179
1180 return 0;
1181}
1182
84a2f0c2
MT
1183LOC_EXPORT struct loc_as_list* loc_database_enumerator_get_asns(
1184 struct loc_database_enumerator* enumerator) {
1185 if (!enumerator->asns)
1186 return NULL;
1187
1188 return loc_as_list_ref(enumerator->asns);
1189}
1190
1191LOC_EXPORT int loc_database_enumerator_set_asns(
1192 struct loc_database_enumerator* enumerator, struct loc_as_list* asns) {
1193 if (enumerator->asns)
1194 loc_as_list_unref(enumerator->asns);
1195
1196 enumerator->asns = loc_as_list_ref(asns);
82910b95
MT
1197
1198 return 0;
1199}
1200
9268db5a
MT
1201LOC_EXPORT int loc_database_enumerator_set_flag(
1202 struct loc_database_enumerator* enumerator, enum loc_network_flags flag) {
1203 enumerator->flags |= flag;
1204
1205 return 0;
1206}
1207
44e5ef71
MT
1208LOC_EXPORT int loc_database_enumerator_set_family(
1209 struct loc_database_enumerator* enumerator, int family) {
1210 enumerator->family = family;
1211
1212 return 0;
1213}
1214
15f79e2d
MT
1215LOC_EXPORT int loc_database_enumerator_next_as(
1216 struct loc_database_enumerator* enumerator, struct loc_as** as) {
1217 *as = NULL;
1218
ccc7ab4e
MT
1219 // Do not do anything if not in AS mode
1220 if (enumerator->mode != LOC_DB_ENUMERATE_ASES)
15f79e2d 1221 return 0;
ccc7ab4e 1222
d3d8ede6 1223 struct loc_database* db = enumerator->db;
d3d8ede6 1224
18638ad2 1225 while (enumerator->as_index < db->as_objects.count) {
d3d8ede6 1226 // Fetch the next AS
15f79e2d 1227 int r = loc_database_fetch_as(db, as, enumerator->as_index++);
d3d8ede6 1228 if (r)
15f79e2d 1229 return r;
d3d8ede6 1230
15f79e2d 1231 r = loc_as_match_string(*as, enumerator->string);
273948cf 1232 if (r == 1) {
64c01ef0 1233 DEBUG(enumerator->ctx, "AS%u (%s) matches %s\n",
15f79e2d 1234 loc_as_get_number(*as), loc_as_get_name(*as), enumerator->string);
d3d8ede6 1235
15f79e2d 1236 return 0;
d3d8ede6
MT
1237 }
1238
1239 // No match
15f79e2d 1240 loc_as_unref(*as);
74f218f0 1241 *as = NULL;
d3d8ede6
MT
1242 }
1243
1244 // Reset the index
1245 enumerator->as_index = 0;
1246
1247 // We have searched through all of them
15f79e2d 1248 return 0;
d3d8ede6 1249}
e3f696c1
MT
1250
1251static int loc_database_enumerator_stack_push_node(
1252 struct loc_database_enumerator* e, off_t offset, int i, int depth) {
1253 // Do not add empty nodes
1254 if (!offset)
1255 return 0;
1256
1257 // Check if there is any space left on the stack
1258 if (e->network_stack_depth >= MAX_STACK_DEPTH) {
1259 ERROR(e->ctx, "Maximum stack size reached: %d\n", e->network_stack_depth);
18638ad2
MT
1260 return 1;
1261 }
1262
1263 // Check if the node is in range
1264 if (offset >= (off_t)e->db->network_node_objects.count) {
1265 ERROR(e->ctx, "Trying to add invalid node with offset %jd/%zu\n",
1266 offset, e->db->network_node_objects.count);
1267 errno = ERANGE;
1268 return 1;
e3f696c1
MT
1269 }
1270
1271 // Increase stack size
1272 int s = ++e->network_stack_depth;
1273
2e2325a9 1274 DEBUG(e->ctx, "Added node %jd to stack (%d)\n", (intmax_t)offset, depth);
e3f696c1
MT
1275
1276 e->network_stack[s].offset = offset;
1277 e->network_stack[s].i = i;
1278 e->network_stack[s].depth = depth;
1279
1280 return 0;
1281}
1282
964633d9 1283static int loc_database_enumerator_match_network(
69248038 1284 struct loc_database_enumerator* enumerator, struct loc_network* network) {
964633d9 1285 // If family is set, it must match
e0e96878
MT
1286 if (enumerator->family && loc_network_address_family(network) != enumerator->family) {
1287 DEBUG(enumerator->ctx, "Filtered network %p because of family not matching\n", network);
964633d9 1288 return 0;
e0e96878 1289 }
69248038 1290
098d871b
MT
1291 // Match if no filter criteria is configured
1292 if (!enumerator->countries && !enumerator->asns && !enumerator->flags)
1293 return 1;
1294
964633d9 1295 // Check if the country code matches
e0e96878
MT
1296 if (enumerator->countries && !loc_country_list_empty(enumerator->countries)) {
1297 const char* country_code = loc_network_get_country_code(network);
50120b99 1298
964633d9
MT
1299 if (loc_country_list_contains_code(enumerator->countries, country_code)) {
1300 DEBUG(enumerator->ctx, "Matched network %p because of its country code\n", network);
e0e96878 1301 return 1;
50120b99
MT
1302 }
1303 }
69248038 1304
964633d9 1305 // Check if the ASN matches
e0e96878
MT
1306 if (enumerator->asns && !loc_as_list_empty(enumerator->asns)) {
1307 uint32_t asn = loc_network_get_asn(network);
c1a36c94 1308
964633d9
MT
1309 if (loc_as_list_contains_number(enumerator->asns, asn)) {
1310 DEBUG(enumerator->ctx, "Matched network %p because of its ASN\n", network);
e0e96878 1311 return 1;
c1a36c94
MT
1312 }
1313 }
69248038 1314
964633d9
MT
1315 // Check if flags match
1316 if (enumerator->flags && loc_network_has_flag(network, enumerator->flags)) {
1317 DEBUG(enumerator->ctx, "Matched network %p because of its flags\n", network);
69248038 1318 return 1;
e0e96878 1319 }
69248038 1320
964633d9 1321 // Not a match
69248038
MT
1322 return 0;
1323}
1324
d87fd7a3
MT
1325static int __loc_database_enumerator_next_network(
1326 struct loc_database_enumerator* enumerator, struct loc_network** network, int filter) {
1327 // Return top element from the stack
2113e71b 1328 while (1) {
04cbd2bf 1329 *network = loc_network_list_pop_first(enumerator->stack);
2113e71b
MT
1330
1331 // Stack is empty
1332 if (!*network)
1333 break;
1334
964633d9
MT
1335 // Return everything if filter isn't enabled, or only return matches
1336 if (!filter || loc_database_enumerator_match_network(enumerator, *network))
1337 return 0;
2113e71b 1338
964633d9
MT
1339 // Throw away anything that doesn't match
1340 loc_network_unref(*network);
1341 *network = NULL;
2113e71b 1342 }
15f79e2d 1343
64c01ef0 1344 DEBUG(enumerator->ctx, "Called with a stack of %d nodes\n",
15f79e2d 1345 enumerator->network_stack_depth);
e3f696c1
MT
1346
1347 // Perform DFS
15f79e2d 1348 while (enumerator->network_stack_depth > 0) {
64c01ef0 1349 DEBUG(enumerator->ctx, "Stack depth: %d\n", enumerator->network_stack_depth);
e3f696c1
MT
1350
1351 // Get object from top of the stack
15f79e2d 1352 struct loc_node_stack* node = &enumerator->network_stack[enumerator->network_stack_depth];
e3f696c1 1353
18638ad2
MT
1354 DEBUG(enumerator->ctx, " Got node: %jd\n", node->offset);
1355
e3f696c1 1356 // Remove the node from the stack if we have already visited it
15f79e2d
MT
1357 if (enumerator->networks_visited[node->offset]) {
1358 enumerator->network_stack_depth--;
e3f696c1
MT
1359 continue;
1360 }
1361
74fb733a 1362 // Mark the bits on the path correctly
d698ca09 1363 loc_address_set_bit(&enumerator->network_address,
e3f696c1
MT
1364 (node->depth > 0) ? node->depth - 1 : 0, node->i);
1365
2e2325a9 1366 DEBUG(enumerator->ctx, "Looking at node %jd\n", (intmax_t)node->offset);
15f79e2d 1367 enumerator->networks_visited[node->offset]++;
e3f696c1
MT
1368
1369 // Pop node from top of the stack
975f280f
MT
1370 struct loc_database_network_node_v1* n =
1371 (struct loc_database_network_node_v1*)loc_database_object(enumerator->db,
1372 &enumerator->db->network_node_objects, sizeof(*n), node->offset);
18638ad2
MT
1373 if (!n)
1374 return 1;
e3f696c1
MT
1375
1376 // Add edges to stack
d87fd7a3 1377 int r = loc_database_enumerator_stack_push_node(enumerator,
e3f696c1 1378 be32toh(n->one), 1, node->depth + 1);
e3f696c1
MT
1379 if (r)
1380 return r;
1381
15f79e2d 1382 r = loc_database_enumerator_stack_push_node(enumerator,
e3f696c1 1383 be32toh(n->zero), 0, node->depth + 1);
e3f696c1
MT
1384 if (r)
1385 return r;
1386
1387 // Check if this node is a leaf and has a network object
1388 if (__loc_database_node_is_leaf(n)) {
1389 off_t network_index = be32toh(n->network);
1390
2e2325a9 1391 DEBUG(enumerator->ctx, "Node has a network at %jd\n", (intmax_t)network_index);
e3f696c1
MT
1392
1393 // Fetch the network object
15f79e2d
MT
1394 r = loc_database_fetch_network(enumerator->db, network,
1395 &enumerator->network_address, node->depth, network_index);
e3f696c1
MT
1396
1397 // Break on any errors
1398 if (r)
1399 return r;
1400
964633d9
MT
1401 // Return all networks when the filter is disabled, or check for match
1402 if (!filter || loc_database_enumerator_match_network(enumerator, *network))
d87fd7a3
MT
1403 return 0;
1404
964633d9
MT
1405 // Does not seem to be a match, so we cleanup and move on
1406 loc_network_unref(*network);
1407 *network = NULL;
e3f696c1
MT
1408 }
1409 }
1410
1411 // Reached the end of the search
d87fd7a3
MT
1412 return 0;
1413}
fe483cdc 1414
d87fd7a3
MT
1415static int __loc_database_enumerator_next_network_flattened(
1416 struct loc_database_enumerator* enumerator, struct loc_network** network) {
1417 // Fetch the next network
1418 int r = __loc_database_enumerator_next_network(enumerator, network, 1);
1419 if (r)
1420 return r;
e3f696c1 1421
d87fd7a3
MT
1422 // End if we could not read another network
1423 if (!*network)
1424 return 0;
1425
1426 struct loc_network* subnet = NULL;
d87fd7a3
MT
1427
1428 // Create a list with all subnets
065b3496
MT
1429 if (!enumerator->subnets) {
1430 r = loc_network_list_new(enumerator->ctx, &enumerator->subnets);
1431 if (r)
1432 return r;
1433 }
d87fd7a3
MT
1434
1435 // Search all subnets from the database
1436 while (1) {
1437 // Fetch the next network in line
1438 r = __loc_database_enumerator_next_network(enumerator, &subnet, 0);
ed0f53df
MT
1439 if (r) {
1440 loc_network_unref(subnet);
065b3496 1441 loc_network_list_clear(enumerator->subnets);
ed0f53df
MT
1442
1443 return r;
1444 }
d87fd7a3
MT
1445
1446 // End if we did not receive another subnet
1447 if (!subnet)
1448 break;
1449
1450 // Collect all subnets in a list
1451 if (loc_network_is_subnet(*network, subnet)) {
065b3496 1452 r = loc_network_list_push(enumerator->subnets, subnet);
ed0f53df
MT
1453 if (r) {
1454 loc_network_unref(subnet);
065b3496 1455 loc_network_list_clear(enumerator->subnets);
ed0f53df
MT
1456
1457 return r;
1458 }
d87fd7a3
MT
1459
1460 loc_network_unref(subnet);
1461 continue;
1462 }
1463
1464 // If this is not a subnet, we push it back onto the stack and break
1465 r = loc_network_list_push(enumerator->stack, subnet);
ed0f53df
MT
1466 if (r) {
1467 loc_network_unref(subnet);
065b3496 1468 loc_network_list_clear(enumerator->subnets);
ed0f53df
MT
1469
1470 return r;
1471 }
d87fd7a3
MT
1472
1473 loc_network_unref(subnet);
1474 break;
1475 }
1476
065b3496
MT
1477 DEBUG(enumerator->ctx, "Found %zu subnet(s)\n",
1478 loc_network_list_size(enumerator->subnets));
d87fd7a3
MT
1479
1480 // We can abort here if the network has no subnets
065b3496
MT
1481 if (loc_network_list_empty(enumerator->subnets)) {
1482 loc_network_list_clear(enumerator->subnets);
d87fd7a3
MT
1483
1484 return 0;
1485 }
1486
1487 // If the network has any subnets, we will break it into smaller parts
1488 // without the subnets.
065b3496 1489 struct loc_network_list* excluded = loc_network_exclude_list(*network, enumerator->subnets);
ed0f53df 1490 if (!excluded) {
065b3496 1491 loc_network_list_clear(enumerator->subnets);
725718e1 1492 return 1;
ed0f53df
MT
1493 }
1494
5dacb45a 1495 // Merge subnets onto the stack
065b3496 1496 r = loc_network_list_merge(enumerator->stack, enumerator->subnets);
ed0f53df 1497 if (r) {
065b3496 1498 loc_network_list_clear(enumerator->subnets);
ed0f53df
MT
1499 loc_network_list_unref(excluded);
1500
1501 return r;
d87fd7a3
MT
1502 }
1503
5dacb45a
MT
1504 // Push excluded list onto the stack
1505 r = loc_network_list_merge(enumerator->stack, excluded);
1506 if (r) {
065b3496 1507 loc_network_list_clear(enumerator->subnets);
5dacb45a 1508 loc_network_list_unref(excluded);
d87fd7a3 1509
5dacb45a
MT
1510 return r;
1511 }
d87fd7a3 1512
065b3496 1513 loc_network_list_clear(enumerator->subnets);
5dacb45a
MT
1514 loc_network_list_unref(excluded);
1515
6bd9cd76 1516 // Drop the network and restart the whole process again to pick the next network
5dacb45a 1517 loc_network_unref(*network);
d87fd7a3 1518
6bd9cd76 1519 return __loc_database_enumerator_next_network_flattened(enumerator, network);
d87fd7a3
MT
1520}
1521
8c37d8a7
MT
1522/*
1523 This function finds all bogons (i.e. gaps) between the input networks
1524*/
8c37d8a7
MT
1525static int __loc_database_enumerator_next_bogon(
1526 struct loc_database_enumerator* enumerator, struct loc_network** bogon) {
1527 int r;
1528
1529 // Return top element from the stack
1530 while (1) {
1531 *bogon = loc_network_list_pop_first(enumerator->stack);
1532
1533 // Stack is empty
1534 if (!*bogon)
1535 break;
1536
1537 // Return result
1538 return 0;
1539 }
1540
1541 struct loc_network* network = NULL;
9306c68d
MT
1542 struct in6_addr* gap_start = NULL;
1543 struct in6_addr gap_end = IN6ADDR_ANY_INIT;
8c37d8a7
MT
1544
1545 while (1) {
1546 r = __loc_database_enumerator_next_network(enumerator, &network, 1);
1547 if (r)
9306c68d 1548 return r;
8c37d8a7 1549
9306c68d 1550 // We have read the last network
8c37d8a7 1551 if (!network)
9306c68d
MT
1552 goto FINISH;
1553
5a01e11e
MT
1554 const char* country_code = loc_network_get_country_code(network);
1555
1556 /*
1557 Skip anything that does not have a country code
1558
1559 Even if a network is part of the routing table, and the database provides
1560 an ASN, this does not mean that this is a legitimate announcement.
1561 */
1562 if (country_code && !*country_code) {
1563 loc_network_unref(network);
1564 continue;
1565 }
1566
9306c68d
MT
1567 // Determine the network family
1568 int family = loc_network_address_family(network);
1569
1570 switch (family) {
1571 case AF_INET6:
1572 gap_start = &enumerator->gap6_start;
1573 break;
1574
1575 case AF_INET:
1576 gap_start = &enumerator->gap4_start;
1577 break;
1578
1579 default:
1580 ERROR(enumerator->ctx, "Unsupported network family %d\n", family);
1581 errno = ENOTSUP;
1582 return 1;
1583 }
1584
8649c654
MT
1585 const struct in6_addr* first_address = loc_network_get_first_address(network);
1586 const struct in6_addr* last_address = loc_network_get_last_address(network);
1587
1588 // Skip if this network is a subnet of a former one
1589 if (loc_address_cmp(gap_start, last_address) >= 0) {
1590 loc_network_unref(network);
1591 continue;
1592 }
1593
9306c68d 1594 // Search where the gap could end
8649c654 1595 gap_end = *first_address;
5b72642c 1596 loc_address_decrement(&gap_end);
8c37d8a7 1597
9306c68d 1598 // There is a gap
c833e45e 1599 if (loc_address_cmp(gap_start, &gap_end) <= 0) {
9306c68d
MT
1600 r = loc_network_list_summarize(enumerator->ctx,
1601 gap_start, &gap_end, &enumerator->stack);
8c37d8a7
MT
1602 if (r) {
1603 loc_network_unref(network);
9306c68d 1604 return r;
8c37d8a7
MT
1605 }
1606 }
1607
9306c68d 1608 // The gap now starts after this network
8649c654 1609 *gap_start = *last_address;
5b72642c 1610 loc_address_increment(gap_start);
9306c68d 1611
8c37d8a7
MT
1612 loc_network_unref(network);
1613
1614 // Try to return something
1615 *bogon = loc_network_list_pop_first(enumerator->stack);
1616 if (*bogon)
1617 break;
1618 }
1619
9306c68d
MT
1620 return 0;
1621
1622FINISH:
9306c68d
MT
1623 if (!loc_address_all_zeroes(&enumerator->gap6_start)) {
1624 r = loc_address_reset_last(&gap_end, AF_INET6);
1625 if (r)
1626 return r;
1627
c833e45e 1628 if (loc_address_cmp(&enumerator->gap6_start, &gap_end) <= 0) {
9306c68d
MT
1629 r = loc_network_list_summarize(enumerator->ctx,
1630 &enumerator->gap6_start, &gap_end, &enumerator->stack);
1631 if (r)
1632 return r;
1633 }
c0b1f64f
MT
1634
1635 // Reset start
1636 loc_address_reset(&enumerator->gap6_start, AF_INET6);
9306c68d
MT
1637 }
1638
1639 if (!loc_address_all_zeroes(&enumerator->gap4_start)) {
1640 r = loc_address_reset_last(&gap_end, AF_INET);
1641 if (r)
1642 return r;
1643
c833e45e 1644 if (loc_address_cmp(&enumerator->gap4_start, &gap_end) <= 0) {
9306c68d
MT
1645 r = loc_network_list_summarize(enumerator->ctx,
1646 &enumerator->gap4_start, &gap_end, &enumerator->stack);
1647 if (r)
1648 return r;
1649 }
c0b1f64f
MT
1650
1651 // Reset start
1652 loc_address_reset(&enumerator->gap4_start, AF_INET);
9306c68d
MT
1653 }
1654
1655 // Try to return something
1656 *bogon = loc_network_list_pop_first(enumerator->stack);
1657
1658 return 0;
8c37d8a7
MT
1659}
1660
d87fd7a3
MT
1661LOC_EXPORT int loc_database_enumerator_next_network(
1662 struct loc_database_enumerator* enumerator, struct loc_network** network) {
8c37d8a7
MT
1663 switch (enumerator->mode) {
1664 case LOC_DB_ENUMERATE_NETWORKS:
1665 // Flatten output?
1666 if (enumerator->flatten)
1667 return __loc_database_enumerator_next_network_flattened(enumerator, network);
d87fd7a3 1668
8c37d8a7
MT
1669 return __loc_database_enumerator_next_network(enumerator, network, 1);
1670
1671 case LOC_DB_ENUMERATE_BOGONS:
1672 return __loc_database_enumerator_next_bogon(enumerator, network);
d87fd7a3 1673
8c37d8a7
MT
1674 default:
1675 return 0;
1676 }
e3f696c1 1677}
fa9a3663
MT
1678
1679LOC_EXPORT int loc_database_enumerator_next_country(
1680 struct loc_database_enumerator* enumerator, struct loc_country** country) {
1681 *country = NULL;
1682
1683 // Do not do anything if not in country mode
1684 if (enumerator->mode != LOC_DB_ENUMERATE_COUNTRIES)
1685 return 0;
1686
1687 struct loc_database* db = enumerator->db;
1688
18638ad2 1689 while (enumerator->country_index < db->country_objects.count) {
fa9a3663
MT
1690 // Fetch the next country
1691 int r = loc_database_fetch_country(db, country, enumerator->country_index++);
1692 if (r)
1693 return r;
1694
1695 // We do not filter here, so it always is a match
1696 return 0;
1697 }
1698
1699 // Reset the index
1700 enumerator->country_index = 0;
1701
1702 // We have searched through all of them
1703 return 0;
1704}