]> git.ipfire.org Git - people/ms/libloc.git/blame - src/database.c
importer: Drop EDROP as it has been merged into DROP
[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;
82 off_t length;
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
MT
151 const char* p, const size_t length) {
152 size_t offset = p - db->data;
18638ad2 153
975f280f
MT
154 // Return if everything is within the boundary
155 if (offset <= db->length - length)
156 return 1;
18638ad2 157
975f280f
MT
158 DEBUG(db->ctx, "Database read check failed at %p for %zu byte(s)\n", p, length);
159 DEBUG(db->ctx, " p = %p (offset = %jd, length = %zu)\n", p, offset, length);
160 DEBUG(db->ctx, " data = %p (length = %zu)\n", db->data, db->length);
161 DEBUG(db->ctx, " end = %p\n", db->data + db->length);
162 DEBUG(db->ctx, " overflow of %zu byte(s)\n", 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
261 DEBUG(db->ctx, "Mapped database of %zu byte(s) at %p\n", db->length, db->data);
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);
406 if (!fd) {
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
412 db->f = fdopen(fd, "r");
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:
621 ERROR(db->ctx, "Cannot compute hash for database with format %d\n",
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);
2a30e4de 910
9086d2b1
MT
911 // End here if a result was found
912 if (r == 0)
913 return r;
2a30e4de 914
9086d2b1
MT
915 // Raise any errors
916 else if (r < 0)
917 return r;
ec1d9681
MT
918
919 DEBUG(db->ctx, "No match found below level %u\n", level);
920 } else {
921 DEBUG(db->ctx, "Tree ended at level %u\n", level);
9086d2b1 922 }
2a30e4de 923
9086d2b1 924 // If this node has a leaf, we will check if it matches
975f280f
MT
925 if (__loc_database_node_is_leaf(node_v1)) {
926 r = __loc_database_lookup_handle_leaf(db, address, network, network_address, level, node_v1);
9086d2b1
MT
927 if (r <= 0)
928 return r;
929 }
2a30e4de 930
ec1d9681 931 return 1;
2a30e4de
MT
932}
933
934LOC_EXPORT int loc_database_lookup(struct loc_database* db,
a178efea 935 const struct in6_addr* address, struct loc_network** network) {
2a30e4de
MT
936 struct in6_addr network_address;
937 memset(&network_address, 0, sizeof(network_address));
938
939 *network = NULL;
940
6661692f 941#ifdef ENABLE_DEBUG
2a30e4de
MT
942 // Save start time
943 clock_t start = clock();
6661692f 944#endif
2a30e4de 945
18638ad2 946 int r = __loc_database_lookup(db, address, network, &network_address, 0, 0);
2a30e4de 947
6661692f 948#ifdef ENABLE_DEBUG
2a30e4de
MT
949 clock_t end = clock();
950
951 // Log how fast this has been
e16c943b
MT
952 DEBUG(db->ctx, "Executed network search in %.4fms\n",
953 (double)(end - start) / CLOCKS_PER_SEC * 1000);
6661692f 954#endif
2a30e4de
MT
955
956 return r;
957}
958
959LOC_EXPORT int loc_database_lookup_from_string(struct loc_database* db,
960 const char* string, struct loc_network** network) {
961 struct in6_addr address;
962
95b6a8e4 963 int r = loc_address_parse(&address, NULL, string);
2a30e4de
MT
964 if (r)
965 return r;
966
967 return loc_database_lookup(db, &address, network);
968}
7e13db74 969
ec684c1a
MT
970// Returns the country at position pos
971static int loc_database_fetch_country(struct loc_database* db,
972 struct loc_country** country, off_t pos) {
975f280f 973 struct loc_database_country_v1* country_v1 = NULL;
18638ad2
MT
974 int r;
975
976 // Check if the country is within range
977 if ((size_t)pos >= db->country_objects.count) {
978 errno = ERANGE;
979 return 1;
980 }
ec684c1a 981
2e2325a9 982 DEBUG(db->ctx, "Fetching country at position %jd\n", (intmax_t)pos);
ec684c1a 983
ec684c1a 984 switch (db->version) {
22c7b98b 985 case LOC_DATABASE_VERSION_1:
18638ad2 986 // Read the object
975f280f
MT
987 country_v1 = (struct loc_database_country_v1*)loc_database_object(db,
988 &db->country_objects, sizeof(*country_v1), pos);
989 if (!country_v1)
18638ad2
MT
990 return 1;
991
975f280f 992 r = loc_country_new_from_database_v1(db->ctx, db->pool, country, country_v1);
ec684c1a
MT
993 break;
994
995 default:
18638ad2
MT
996 errno = ENOTSUP;
997 return 1;
ec684c1a
MT
998 }
999
18638ad2 1000 if (r == 0)
ec684c1a 1001 DEBUG(db->ctx, "Got country %s\n", loc_country_get_code(*country));
ec684c1a
MT
1002
1003 return r;
1004}
1005
1006// Performs a binary search to find the country in the list
1007LOC_EXPORT int loc_database_get_country(struct loc_database* db,
1008 struct loc_country** country, const char* code) {
1009 off_t lo = 0;
18638ad2 1010 off_t hi = db->country_objects.count - 1;
ec684c1a 1011
8fcb5bc7
MT
1012 // Check if the country code is valid
1013 if (!loc_country_code_is_valid(code)) {
1014 errno = EINVAL;
1015 return 1;
1016 }
1017
6661692f 1018#ifdef ENABLE_DEBUG
ec684c1a
MT
1019 // Save start time
1020 clock_t start = clock();
6661692f 1021#endif
ec684c1a
MT
1022
1023 while (lo <= hi) {
1024 off_t i = (lo + hi) / 2;
1025
1026 // Fetch country in the middle between lo and hi
1027 int r = loc_database_fetch_country(db, country, i);
1028 if (r)
1029 return r;
1030
1031 // Check if this is a match
1032 const char* cc = loc_country_get_code(*country);
1033 int result = strcmp(code, cc);
1034
1035 if (result == 0) {
6661692f 1036#ifdef ENABLE_DEBUG
ec684c1a
MT
1037 clock_t end = clock();
1038
1039 // Log how fast this has been
1040 DEBUG(db->ctx, "Found country %s in %.4fms\n", cc,
1041 (double)(end - start) / CLOCKS_PER_SEC * 1000);
6661692f 1042#endif
ec684c1a
MT
1043
1044 return 0;
1045 }
1046
1047 // If it wasn't, we release the country and
1048 // adjust our search pointers
1049 loc_country_unref(*country);
1050
191830da 1051 if (result > 0) {
ec684c1a
MT
1052 lo = i + 1;
1053 } else
1054 hi = i - 1;
1055 }
1056
1057 // Nothing found
1058 *country = NULL;
1059
8fcb5bc7 1060 return 0;
ec684c1a
MT
1061}
1062
7e13db74
MT
1063// Enumerator
1064
d87fd7a3
MT
1065static void loc_database_enumerator_free(struct loc_database_enumerator* enumerator) {
1066 DEBUG(enumerator->ctx, "Releasing database enumerator %p\n", enumerator);
1067
1068 // Release all references
1069 loc_database_unref(enumerator->db);
1070 loc_unref(enumerator->ctx);
1071
1072 if (enumerator->string)
1073 free(enumerator->string);
1074
5470d06c
MT
1075 if (enumerator->countries)
1076 loc_country_list_unref(enumerator->countries);
1077
1078 if (enumerator->asns)
1079 loc_as_list_unref(enumerator->asns);
1080
d87fd7a3 1081 // Free network search
18638ad2
MT
1082 if (enumerator->networks_visited)
1083 free(enumerator->networks_visited);
d87fd7a3 1084
8c37d8a7 1085 // Free subnet/bogons stack
d87fd7a3
MT
1086 if (enumerator->stack)
1087 loc_network_list_unref(enumerator->stack);
1088
065b3496
MT
1089 if (enumerator->subnets)
1090 loc_network_list_unref(enumerator->subnets);
1091
d87fd7a3
MT
1092 free(enumerator);
1093}
1094
ccc7ab4e 1095LOC_EXPORT int loc_database_enumerator_new(struct loc_database_enumerator** enumerator,
681ff05c 1096 struct loc_database* db, enum loc_database_enumerator_mode mode, int flags) {
18638ad2
MT
1097 int r;
1098
7e13db74 1099 struct loc_database_enumerator* e = calloc(1, sizeof(*e));
18638ad2 1100 if (!e) {
7e13db74 1101 return -ENOMEM;
18638ad2 1102 }
7e13db74
MT
1103
1104 // Reference context
1105 e->ctx = loc_ref(db->ctx);
1106 e->db = loc_database_ref(db);
ccc7ab4e 1107 e->mode = mode;
7e13db74
MT
1108 e->refcount = 1;
1109
681ff05c
MT
1110 // Flatten output?
1111 e->flatten = (flags & LOC_DB_ENUMERATOR_FLAGS_FLATTEN);
1112
e3f696c1 1113 // Initialise graph search
e3f696c1 1114 e->network_stack_depth = 1;
18638ad2 1115 e->networks_visited = calloc(db->network_node_objects.count, sizeof(*e->networks_visited));
18638ad2
MT
1116 if (!e->networks_visited) {
1117 ERROR(db->ctx, "Could not allocated visited networks: %m\n");
1118 r = 1;
1119 goto ERROR;
1120 }
e3f696c1 1121
d87fd7a3 1122 // Allocate stack
18638ad2
MT
1123 r = loc_network_list_new(e->ctx, &e->stack);
1124 if (r)
1125 goto ERROR;
d87fd7a3 1126
9306c68d
MT
1127 // Initialize bogon search
1128 loc_address_reset(&e->gap6_start, AF_INET6);
1129 loc_address_reset(&e->gap4_start, AF_INET);
1130
7e13db74
MT
1131 DEBUG(e->ctx, "Database enumerator object allocated at %p\n", e);
1132
1133 *enumerator = e;
1134 return 0;
18638ad2
MT
1135
1136ERROR:
1137 if (e)
1138 loc_database_enumerator_free(e);
1139
1140 return r;
7e13db74
MT
1141}
1142
1143LOC_EXPORT struct loc_database_enumerator* loc_database_enumerator_ref(struct loc_database_enumerator* enumerator) {
1144 enumerator->refcount++;
1145
1146 return enumerator;
1147}
1148
7e13db74
MT
1149LOC_EXPORT struct loc_database_enumerator* loc_database_enumerator_unref(struct loc_database_enumerator* enumerator) {
1150 if (!enumerator)
1151 return NULL;
1152
1153 if (--enumerator->refcount > 0)
1154 return enumerator;
1155
1156 loc_database_enumerator_free(enumerator);
1157 return NULL;
1158}
d3d8ede6
MT
1159
1160LOC_EXPORT int loc_database_enumerator_set_string(struct loc_database_enumerator* enumerator, const char* string) {
1161 enumerator->string = strdup(string);
1162
1163 // Make the string lowercase
1164 for (char *p = enumerator->string; *p; p++)
1165 *p = tolower(*p);
1166
1167 return 0;
1168}
1169
e646a8f3
MT
1170LOC_EXPORT struct loc_country_list* loc_database_enumerator_get_countries(
1171 struct loc_database_enumerator* enumerator) {
1172 if (!enumerator->countries)
1173 return NULL;
35bb3a32 1174
e646a8f3
MT
1175 return loc_country_list_ref(enumerator->countries);
1176}
4ef1761f 1177
e646a8f3
MT
1178LOC_EXPORT int loc_database_enumerator_set_countries(
1179 struct loc_database_enumerator* enumerator, struct loc_country_list* countries) {
1180 if (enumerator->countries)
1181 loc_country_list_unref(enumerator->countries);
57146963 1182
e646a8f3 1183 enumerator->countries = loc_country_list_ref(countries);
35bb3a32
MT
1184
1185 return 0;
1186}
1187
84a2f0c2
MT
1188LOC_EXPORT struct loc_as_list* loc_database_enumerator_get_asns(
1189 struct loc_database_enumerator* enumerator) {
1190 if (!enumerator->asns)
1191 return NULL;
1192
1193 return loc_as_list_ref(enumerator->asns);
1194}
1195
1196LOC_EXPORT int loc_database_enumerator_set_asns(
1197 struct loc_database_enumerator* enumerator, struct loc_as_list* asns) {
1198 if (enumerator->asns)
1199 loc_as_list_unref(enumerator->asns);
1200
1201 enumerator->asns = loc_as_list_ref(asns);
82910b95
MT
1202
1203 return 0;
1204}
1205
9268db5a
MT
1206LOC_EXPORT int loc_database_enumerator_set_flag(
1207 struct loc_database_enumerator* enumerator, enum loc_network_flags flag) {
1208 enumerator->flags |= flag;
1209
1210 return 0;
1211}
1212
44e5ef71
MT
1213LOC_EXPORT int loc_database_enumerator_set_family(
1214 struct loc_database_enumerator* enumerator, int family) {
1215 enumerator->family = family;
1216
1217 return 0;
1218}
1219
15f79e2d
MT
1220LOC_EXPORT int loc_database_enumerator_next_as(
1221 struct loc_database_enumerator* enumerator, struct loc_as** as) {
1222 *as = NULL;
1223
ccc7ab4e
MT
1224 // Do not do anything if not in AS mode
1225 if (enumerator->mode != LOC_DB_ENUMERATE_ASES)
15f79e2d 1226 return 0;
ccc7ab4e 1227
d3d8ede6 1228 struct loc_database* db = enumerator->db;
d3d8ede6 1229
18638ad2 1230 while (enumerator->as_index < db->as_objects.count) {
d3d8ede6 1231 // Fetch the next AS
15f79e2d 1232 int r = loc_database_fetch_as(db, as, enumerator->as_index++);
d3d8ede6 1233 if (r)
15f79e2d 1234 return r;
d3d8ede6 1235
15f79e2d 1236 r = loc_as_match_string(*as, enumerator->string);
273948cf 1237 if (r == 1) {
d3d8ede6 1238 DEBUG(enumerator->ctx, "AS%d (%s) matches %s\n",
15f79e2d 1239 loc_as_get_number(*as), loc_as_get_name(*as), enumerator->string);
d3d8ede6 1240
15f79e2d 1241 return 0;
d3d8ede6
MT
1242 }
1243
1244 // No match
15f79e2d 1245 loc_as_unref(*as);
74f218f0 1246 *as = NULL;
d3d8ede6
MT
1247 }
1248
1249 // Reset the index
1250 enumerator->as_index = 0;
1251
1252 // We have searched through all of them
15f79e2d 1253 return 0;
d3d8ede6 1254}
e3f696c1
MT
1255
1256static int loc_database_enumerator_stack_push_node(
1257 struct loc_database_enumerator* e, off_t offset, int i, int depth) {
1258 // Do not add empty nodes
1259 if (!offset)
1260 return 0;
1261
1262 // Check if there is any space left on the stack
1263 if (e->network_stack_depth >= MAX_STACK_DEPTH) {
1264 ERROR(e->ctx, "Maximum stack size reached: %d\n", e->network_stack_depth);
18638ad2
MT
1265 return 1;
1266 }
1267
1268 // Check if the node is in range
1269 if (offset >= (off_t)e->db->network_node_objects.count) {
1270 ERROR(e->ctx, "Trying to add invalid node with offset %jd/%zu\n",
1271 offset, e->db->network_node_objects.count);
1272 errno = ERANGE;
1273 return 1;
e3f696c1
MT
1274 }
1275
1276 // Increase stack size
1277 int s = ++e->network_stack_depth;
1278
2e2325a9 1279 DEBUG(e->ctx, "Added node %jd to stack (%d)\n", (intmax_t)offset, depth);
e3f696c1
MT
1280
1281 e->network_stack[s].offset = offset;
1282 e->network_stack[s].i = i;
1283 e->network_stack[s].depth = depth;
1284
1285 return 0;
1286}
1287
964633d9 1288static int loc_database_enumerator_match_network(
69248038 1289 struct loc_database_enumerator* enumerator, struct loc_network* network) {
964633d9 1290 // If family is set, it must match
e0e96878
MT
1291 if (enumerator->family && loc_network_address_family(network) != enumerator->family) {
1292 DEBUG(enumerator->ctx, "Filtered network %p because of family not matching\n", network);
964633d9 1293 return 0;
e0e96878 1294 }
69248038 1295
098d871b
MT
1296 // Match if no filter criteria is configured
1297 if (!enumerator->countries && !enumerator->asns && !enumerator->flags)
1298 return 1;
1299
964633d9 1300 // Check if the country code matches
e0e96878
MT
1301 if (enumerator->countries && !loc_country_list_empty(enumerator->countries)) {
1302 const char* country_code = loc_network_get_country_code(network);
50120b99 1303
964633d9
MT
1304 if (loc_country_list_contains_code(enumerator->countries, country_code)) {
1305 DEBUG(enumerator->ctx, "Matched network %p because of its country code\n", network);
e0e96878 1306 return 1;
50120b99
MT
1307 }
1308 }
69248038 1309
964633d9 1310 // Check if the ASN matches
e0e96878
MT
1311 if (enumerator->asns && !loc_as_list_empty(enumerator->asns)) {
1312 uint32_t asn = loc_network_get_asn(network);
c1a36c94 1313
964633d9
MT
1314 if (loc_as_list_contains_number(enumerator->asns, asn)) {
1315 DEBUG(enumerator->ctx, "Matched network %p because of its ASN\n", network);
e0e96878 1316 return 1;
c1a36c94
MT
1317 }
1318 }
69248038 1319
964633d9
MT
1320 // Check if flags match
1321 if (enumerator->flags && loc_network_has_flag(network, enumerator->flags)) {
1322 DEBUG(enumerator->ctx, "Matched network %p because of its flags\n", network);
69248038 1323 return 1;
e0e96878 1324 }
69248038 1325
964633d9 1326 // Not a match
69248038
MT
1327 return 0;
1328}
1329
d87fd7a3
MT
1330static int __loc_database_enumerator_next_network(
1331 struct loc_database_enumerator* enumerator, struct loc_network** network, int filter) {
1332 // Return top element from the stack
2113e71b 1333 while (1) {
04cbd2bf 1334 *network = loc_network_list_pop_first(enumerator->stack);
2113e71b
MT
1335
1336 // Stack is empty
1337 if (!*network)
1338 break;
1339
964633d9
MT
1340 // Return everything if filter isn't enabled, or only return matches
1341 if (!filter || loc_database_enumerator_match_network(enumerator, *network))
1342 return 0;
2113e71b 1343
964633d9
MT
1344 // Throw away anything that doesn't match
1345 loc_network_unref(*network);
1346 *network = NULL;
2113e71b 1347 }
15f79e2d 1348
15f79e2d
MT
1349 DEBUG(enumerator->ctx, "Called with a stack of %u nodes\n",
1350 enumerator->network_stack_depth);
e3f696c1
MT
1351
1352 // Perform DFS
15f79e2d
MT
1353 while (enumerator->network_stack_depth > 0) {
1354 DEBUG(enumerator->ctx, "Stack depth: %u\n", enumerator->network_stack_depth);
e3f696c1
MT
1355
1356 // Get object from top of the stack
15f79e2d 1357 struct loc_node_stack* node = &enumerator->network_stack[enumerator->network_stack_depth];
e3f696c1 1358
18638ad2
MT
1359 DEBUG(enumerator->ctx, " Got node: %jd\n", node->offset);
1360
e3f696c1 1361 // Remove the node from the stack if we have already visited it
15f79e2d
MT
1362 if (enumerator->networks_visited[node->offset]) {
1363 enumerator->network_stack_depth--;
e3f696c1
MT
1364 continue;
1365 }
1366
74fb733a 1367 // Mark the bits on the path correctly
d698ca09 1368 loc_address_set_bit(&enumerator->network_address,
e3f696c1
MT
1369 (node->depth > 0) ? node->depth - 1 : 0, node->i);
1370
2e2325a9 1371 DEBUG(enumerator->ctx, "Looking at node %jd\n", (intmax_t)node->offset);
15f79e2d 1372 enumerator->networks_visited[node->offset]++;
e3f696c1
MT
1373
1374 // Pop node from top of the stack
975f280f
MT
1375 struct loc_database_network_node_v1* n =
1376 (struct loc_database_network_node_v1*)loc_database_object(enumerator->db,
1377 &enumerator->db->network_node_objects, sizeof(*n), node->offset);
18638ad2
MT
1378 if (!n)
1379 return 1;
e3f696c1
MT
1380
1381 // Add edges to stack
d87fd7a3 1382 int r = loc_database_enumerator_stack_push_node(enumerator,
e3f696c1 1383 be32toh(n->one), 1, node->depth + 1);
e3f696c1
MT
1384 if (r)
1385 return r;
1386
15f79e2d 1387 r = loc_database_enumerator_stack_push_node(enumerator,
e3f696c1 1388 be32toh(n->zero), 0, node->depth + 1);
e3f696c1
MT
1389 if (r)
1390 return r;
1391
1392 // Check if this node is a leaf and has a network object
1393 if (__loc_database_node_is_leaf(n)) {
1394 off_t network_index = be32toh(n->network);
1395
2e2325a9 1396 DEBUG(enumerator->ctx, "Node has a network at %jd\n", (intmax_t)network_index);
e3f696c1
MT
1397
1398 // Fetch the network object
15f79e2d
MT
1399 r = loc_database_fetch_network(enumerator->db, network,
1400 &enumerator->network_address, node->depth, network_index);
e3f696c1
MT
1401
1402 // Break on any errors
1403 if (r)
1404 return r;
1405
964633d9
MT
1406 // Return all networks when the filter is disabled, or check for match
1407 if (!filter || loc_database_enumerator_match_network(enumerator, *network))
d87fd7a3
MT
1408 return 0;
1409
964633d9
MT
1410 // Does not seem to be a match, so we cleanup and move on
1411 loc_network_unref(*network);
1412 *network = NULL;
e3f696c1
MT
1413 }
1414 }
1415
1416 // Reached the end of the search
d87fd7a3
MT
1417 return 0;
1418}
fe483cdc 1419
d87fd7a3
MT
1420static int __loc_database_enumerator_next_network_flattened(
1421 struct loc_database_enumerator* enumerator, struct loc_network** network) {
1422 // Fetch the next network
1423 int r = __loc_database_enumerator_next_network(enumerator, network, 1);
1424 if (r)
1425 return r;
e3f696c1 1426
d87fd7a3
MT
1427 // End if we could not read another network
1428 if (!*network)
1429 return 0;
1430
1431 struct loc_network* subnet = NULL;
d87fd7a3
MT
1432
1433 // Create a list with all subnets
065b3496
MT
1434 if (!enumerator->subnets) {
1435 r = loc_network_list_new(enumerator->ctx, &enumerator->subnets);
1436 if (r)
1437 return r;
1438 }
d87fd7a3
MT
1439
1440 // Search all subnets from the database
1441 while (1) {
1442 // Fetch the next network in line
1443 r = __loc_database_enumerator_next_network(enumerator, &subnet, 0);
ed0f53df
MT
1444 if (r) {
1445 loc_network_unref(subnet);
065b3496 1446 loc_network_list_clear(enumerator->subnets);
ed0f53df
MT
1447
1448 return r;
1449 }
d87fd7a3
MT
1450
1451 // End if we did not receive another subnet
1452 if (!subnet)
1453 break;
1454
1455 // Collect all subnets in a list
1456 if (loc_network_is_subnet(*network, subnet)) {
065b3496 1457 r = loc_network_list_push(enumerator->subnets, subnet);
ed0f53df
MT
1458 if (r) {
1459 loc_network_unref(subnet);
065b3496 1460 loc_network_list_clear(enumerator->subnets);
ed0f53df
MT
1461
1462 return r;
1463 }
d87fd7a3
MT
1464
1465 loc_network_unref(subnet);
1466 continue;
1467 }
1468
1469 // If this is not a subnet, we push it back onto the stack and break
1470 r = loc_network_list_push(enumerator->stack, subnet);
ed0f53df
MT
1471 if (r) {
1472 loc_network_unref(subnet);
065b3496 1473 loc_network_list_clear(enumerator->subnets);
ed0f53df
MT
1474
1475 return r;
1476 }
d87fd7a3
MT
1477
1478 loc_network_unref(subnet);
1479 break;
1480 }
1481
065b3496
MT
1482 DEBUG(enumerator->ctx, "Found %zu subnet(s)\n",
1483 loc_network_list_size(enumerator->subnets));
d87fd7a3
MT
1484
1485 // We can abort here if the network has no subnets
065b3496
MT
1486 if (loc_network_list_empty(enumerator->subnets)) {
1487 loc_network_list_clear(enumerator->subnets);
d87fd7a3
MT
1488
1489 return 0;
1490 }
1491
1492 // If the network has any subnets, we will break it into smaller parts
1493 // without the subnets.
065b3496 1494 struct loc_network_list* excluded = loc_network_exclude_list(*network, enumerator->subnets);
ed0f53df 1495 if (!excluded) {
065b3496 1496 loc_network_list_clear(enumerator->subnets);
725718e1 1497 return 1;
ed0f53df
MT
1498 }
1499
5dacb45a 1500 // Merge subnets onto the stack
065b3496 1501 r = loc_network_list_merge(enumerator->stack, enumerator->subnets);
ed0f53df 1502 if (r) {
065b3496 1503 loc_network_list_clear(enumerator->subnets);
ed0f53df
MT
1504 loc_network_list_unref(excluded);
1505
1506 return r;
d87fd7a3
MT
1507 }
1508
5dacb45a
MT
1509 // Push excluded list onto the stack
1510 r = loc_network_list_merge(enumerator->stack, excluded);
1511 if (r) {
065b3496 1512 loc_network_list_clear(enumerator->subnets);
5dacb45a 1513 loc_network_list_unref(excluded);
d87fd7a3 1514
5dacb45a
MT
1515 return r;
1516 }
d87fd7a3 1517
065b3496 1518 loc_network_list_clear(enumerator->subnets);
5dacb45a
MT
1519 loc_network_list_unref(excluded);
1520
6bd9cd76 1521 // Drop the network and restart the whole process again to pick the next network
5dacb45a 1522 loc_network_unref(*network);
d87fd7a3 1523
6bd9cd76 1524 return __loc_database_enumerator_next_network_flattened(enumerator, network);
d87fd7a3
MT
1525}
1526
8c37d8a7
MT
1527/*
1528 This function finds all bogons (i.e. gaps) between the input networks
1529*/
8c37d8a7
MT
1530static int __loc_database_enumerator_next_bogon(
1531 struct loc_database_enumerator* enumerator, struct loc_network** bogon) {
1532 int r;
1533
1534 // Return top element from the stack
1535 while (1) {
1536 *bogon = loc_network_list_pop_first(enumerator->stack);
1537
1538 // Stack is empty
1539 if (!*bogon)
1540 break;
1541
1542 // Return result
1543 return 0;
1544 }
1545
1546 struct loc_network* network = NULL;
9306c68d
MT
1547 struct in6_addr* gap_start = NULL;
1548 struct in6_addr gap_end = IN6ADDR_ANY_INIT;
8c37d8a7
MT
1549
1550 while (1) {
1551 r = __loc_database_enumerator_next_network(enumerator, &network, 1);
1552 if (r)
9306c68d 1553 return r;
8c37d8a7 1554
9306c68d 1555 // We have read the last network
8c37d8a7 1556 if (!network)
9306c68d
MT
1557 goto FINISH;
1558
5a01e11e
MT
1559 const char* country_code = loc_network_get_country_code(network);
1560
1561 /*
1562 Skip anything that does not have a country code
1563
1564 Even if a network is part of the routing table, and the database provides
1565 an ASN, this does not mean that this is a legitimate announcement.
1566 */
1567 if (country_code && !*country_code) {
1568 loc_network_unref(network);
1569 continue;
1570 }
1571
9306c68d
MT
1572 // Determine the network family
1573 int family = loc_network_address_family(network);
1574
1575 switch (family) {
1576 case AF_INET6:
1577 gap_start = &enumerator->gap6_start;
1578 break;
1579
1580 case AF_INET:
1581 gap_start = &enumerator->gap4_start;
1582 break;
1583
1584 default:
1585 ERROR(enumerator->ctx, "Unsupported network family %d\n", family);
1586 errno = ENOTSUP;
1587 return 1;
1588 }
1589
8649c654
MT
1590 const struct in6_addr* first_address = loc_network_get_first_address(network);
1591 const struct in6_addr* last_address = loc_network_get_last_address(network);
1592
1593 // Skip if this network is a subnet of a former one
1594 if (loc_address_cmp(gap_start, last_address) >= 0) {
1595 loc_network_unref(network);
1596 continue;
1597 }
1598
9306c68d 1599 // Search where the gap could end
8649c654 1600 gap_end = *first_address;
5b72642c 1601 loc_address_decrement(&gap_end);
8c37d8a7 1602
9306c68d 1603 // There is a gap
c833e45e 1604 if (loc_address_cmp(gap_start, &gap_end) <= 0) {
9306c68d
MT
1605 r = loc_network_list_summarize(enumerator->ctx,
1606 gap_start, &gap_end, &enumerator->stack);
8c37d8a7
MT
1607 if (r) {
1608 loc_network_unref(network);
9306c68d 1609 return r;
8c37d8a7
MT
1610 }
1611 }
1612
9306c68d 1613 // The gap now starts after this network
8649c654 1614 *gap_start = *last_address;
5b72642c 1615 loc_address_increment(gap_start);
9306c68d 1616
8c37d8a7
MT
1617 loc_network_unref(network);
1618
1619 // Try to return something
1620 *bogon = loc_network_list_pop_first(enumerator->stack);
1621 if (*bogon)
1622 break;
1623 }
1624
9306c68d
MT
1625 return 0;
1626
1627FINISH:
1628
1629 if (!loc_address_all_zeroes(&enumerator->gap6_start)) {
1630 r = loc_address_reset_last(&gap_end, AF_INET6);
1631 if (r)
1632 return r;
1633
c833e45e 1634 if (loc_address_cmp(&enumerator->gap6_start, &gap_end) <= 0) {
9306c68d
MT
1635 r = loc_network_list_summarize(enumerator->ctx,
1636 &enumerator->gap6_start, &gap_end, &enumerator->stack);
1637 if (r)
1638 return r;
1639 }
c0b1f64f
MT
1640
1641 // Reset start
1642 loc_address_reset(&enumerator->gap6_start, AF_INET6);
9306c68d
MT
1643 }
1644
1645 if (!loc_address_all_zeroes(&enumerator->gap4_start)) {
1646 r = loc_address_reset_last(&gap_end, AF_INET);
1647 if (r)
1648 return r;
1649
c833e45e 1650 if (loc_address_cmp(&enumerator->gap4_start, &gap_end) <= 0) {
9306c68d
MT
1651 r = loc_network_list_summarize(enumerator->ctx,
1652 &enumerator->gap4_start, &gap_end, &enumerator->stack);
1653 if (r)
1654 return r;
1655 }
c0b1f64f
MT
1656
1657 // Reset start
1658 loc_address_reset(&enumerator->gap4_start, AF_INET);
9306c68d
MT
1659 }
1660
1661 // Try to return something
1662 *bogon = loc_network_list_pop_first(enumerator->stack);
1663
1664 return 0;
8c37d8a7
MT
1665}
1666
d87fd7a3
MT
1667LOC_EXPORT int loc_database_enumerator_next_network(
1668 struct loc_database_enumerator* enumerator, struct loc_network** network) {
8c37d8a7
MT
1669 switch (enumerator->mode) {
1670 case LOC_DB_ENUMERATE_NETWORKS:
1671 // Flatten output?
1672 if (enumerator->flatten)
1673 return __loc_database_enumerator_next_network_flattened(enumerator, network);
d87fd7a3 1674
8c37d8a7
MT
1675 return __loc_database_enumerator_next_network(enumerator, network, 1);
1676
1677 case LOC_DB_ENUMERATE_BOGONS:
1678 return __loc_database_enumerator_next_bogon(enumerator, network);
d87fd7a3 1679
8c37d8a7
MT
1680 default:
1681 return 0;
1682 }
e3f696c1 1683}
fa9a3663
MT
1684
1685LOC_EXPORT int loc_database_enumerator_next_country(
1686 struct loc_database_enumerator* enumerator, struct loc_country** country) {
1687 *country = NULL;
1688
1689 // Do not do anything if not in country mode
1690 if (enumerator->mode != LOC_DB_ENUMERATE_COUNTRIES)
1691 return 0;
1692
1693 struct loc_database* db = enumerator->db;
1694
18638ad2 1695 while (enumerator->country_index < db->country_objects.count) {
fa9a3663
MT
1696 // Fetch the next country
1697 int r = loc_database_fetch_country(db, country, enumerator->country_index++);
1698 if (r)
1699 return r;
1700
1701 // We do not filter here, so it always is a match
1702 return 0;
1703 }
1704
1705 // Reset the index
1706 enumerator->country_index = 0;
1707
1708 // We have searched through all of them
1709 return 0;
1710}