]> git.ipfire.org Git - location/libloc.git/blame - src/network.c
network-list: Set elements pointer to NULL so that we know it is empty
[location/libloc.git] / src / network.c
CommitLineData
3b5f4af2
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
17#include <arpa/inet.h>
18#include <assert.h>
19#include <errno.h>
71ff3e69 20#include <stdio.h>
3b5f4af2
MT
21#include <stdlib.h>
22#include <string.h>
23
42f3ccd7
MT
24#ifdef HAVE_ENDIAN_H
25# include <endian.h>
26#endif
27
3b5f4af2 28#include <loc/libloc.h>
42f3ccd7 29#include <loc/compat.h>
57146963 30#include <loc/country.h>
3b5f4af2 31#include <loc/network.h>
e0b9ff5f 32#include <loc/network-list.h>
9fc7f001 33#include <loc/private.h>
3b5f4af2
MT
34
35struct loc_network {
36 struct loc_ctx* ctx;
37 int refcount;
38
c3068be1 39 int family;
ce4f5752 40 struct in6_addr first_address;
b43edb61 41 struct in6_addr last_address;
3b5f4af2
MT
42 unsigned int prefix;
43
44 char country_code[3];
71ff3e69 45 uint32_t asn;
a293f829 46 enum loc_network_flags flags;
3b5f4af2
MT
47};
48
6183c0f2
MT
49static int valid_prefix(struct in6_addr* address, unsigned int prefix) {
50 // The prefix cannot be larger than 128 bits
51 if (prefix > 128)
52 return 1;
53
54 // And the prefix cannot be zero
55 if (prefix == 0)
56 return 1;
57
aa37232a
MT
58 // For IPv4-mapped addresses the prefix has to be 96 or lager
59 if (IN6_IS_ADDR_V4MAPPED(address) && prefix <= 96)
60 return 1;
61
6183c0f2
MT
62 return 0;
63}
64
a82ce8bc
MT
65static struct in6_addr prefix_to_bitmask(unsigned int prefix) {
66 struct in6_addr bitmask;
67
68 for (unsigned int i = 0; i < 16; i++)
69 bitmask.s6_addr[i] = 0;
70
364a2a37 71 for (int i = prefix, j = 0; i > 0; i -= 8, j++) {
a82ce8bc
MT
72 if (i >= 8)
73 bitmask.s6_addr[j] = 0xff;
74 else
75 bitmask.s6_addr[j] = 0xff << (8 - i);
76 }
77
78 return bitmask;
79}
80
b43edb61 81static struct in6_addr make_first_address(const struct in6_addr* address, const struct in6_addr* bitmask) {
a82ce8bc 82 struct in6_addr a;
a82ce8bc
MT
83
84 // Perform bitwise AND
85 for (unsigned int i = 0; i < 4; i++)
b43edb61 86 a.s6_addr32[i] = address->s6_addr32[i] & bitmask->s6_addr32[i];
a82ce8bc
MT
87
88 return a;
89}
90
b43edb61 91static struct in6_addr make_last_address(const struct in6_addr* address, const struct in6_addr* bitmask) {
2a30e4de 92 struct in6_addr a;
2a30e4de
MT
93
94 // Perform bitwise OR
95 for (unsigned int i = 0; i < 4; i++)
b43edb61 96 a.s6_addr32[i] = address->s6_addr32[i] | ~bitmask->s6_addr32[i];
2a30e4de
MT
97
98 return a;
99}
100
850e7516
MT
101static struct in6_addr address_increment(const struct in6_addr* address) {
102 struct in6_addr a = *address;
103
104 for (int octet = 15; octet >= 0; octet--) {
105 if (a.s6_addr[octet] < 255) {
106 a.s6_addr[octet]++;
107 break;
108 } else {
109 a.s6_addr[octet] = 0;
110 }
111 }
112
113 return a;
114}
115
3b5f4af2 116LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network,
10778041 117 struct in6_addr* address, unsigned int prefix) {
3b5f4af2 118 // Address cannot be unspecified
bca87342 119 if (IN6_IS_ADDR_UNSPECIFIED(address)) {
3b5f4af2
MT
120 DEBUG(ctx, "Start address is unspecified\n");
121 return -EINVAL;
122 }
123
124 // Address cannot be loopback
bca87342 125 if (IN6_IS_ADDR_LOOPBACK(address)) {
3b5f4af2
MT
126 DEBUG(ctx, "Start address is loopback address\n");
127 return -EINVAL;
128 }
129
130 // Address cannot be link-local
bca87342 131 if (IN6_IS_ADDR_LINKLOCAL(address)) {
3b5f4af2
MT
132 DEBUG(ctx, "Start address cannot be link-local\n");
133 return -EINVAL;
134 }
135
136 // Address cannot be site-local
bca87342 137 if (IN6_IS_ADDR_SITELOCAL(address)) {
3b5f4af2
MT
138 DEBUG(ctx, "Start address cannot be site-local\n");
139 return -EINVAL;
140 }
141
6183c0f2 142 // Validate the prefix
10778041 143 if (valid_prefix(address, prefix) != 0) {
6183c0f2
MT
144 DEBUG(ctx, "Invalid prefix: %u\n", prefix);
145 return -EINVAL;
146 }
147
3b5f4af2
MT
148 struct loc_network* n = calloc(1, sizeof(*n));
149 if (!n)
150 return -ENOMEM;
151
152 n->ctx = loc_ref(ctx);
153 n->refcount = 1;
154
b43edb61 155 // Store the prefix
3b5f4af2
MT
156 n->prefix = prefix;
157
b43edb61
MT
158 // Convert the prefix into a bitmask
159 struct in6_addr bitmask = prefix_to_bitmask(n->prefix);
160
161 // Store the first and last address in the network
162 n->first_address = make_first_address(address, &bitmask);
163 n->last_address = make_last_address(&n->first_address, &bitmask);
164
c3068be1
MT
165 // Set family
166 if (IN6_IS_ADDR_V4MAPPED(&n->first_address))
167 n->family = AF_INET;
168 else
169 n->family = AF_INET6;
170
3b5f4af2
MT
171 DEBUG(n->ctx, "Network allocated at %p\n", n);
172 *network = n;
173 return 0;
174}
175
176LOC_EXPORT int loc_network_new_from_string(struct loc_ctx* ctx, struct loc_network** network,
177 const char* address_string) {
ce4f5752 178 struct in6_addr first_address;
3b5f4af2 179 char* prefix_string;
26ab419b 180 unsigned int prefix = 128;
13ad6e69
MT
181 int r = -EINVAL;
182
183 DEBUG(ctx, "Attempting to parse network %s\n", address_string);
3b5f4af2
MT
184
185 // Make a copy of the string to work on it
186 char* buffer = strdup(address_string);
187 address_string = prefix_string = buffer;
188
189 // Split address and prefix
190 address_string = strsep(&prefix_string, "/");
191
13ad6e69
MT
192 DEBUG(ctx, " Split into address = %s, prefix = %s\n", address_string, prefix_string);
193
13ad6e69
MT
194 // Parse the address
195 r = loc_parse_address(ctx, address_string, &first_address);
196 if (r) {
197 DEBUG(ctx, "The address could not be parsed\n");
198 goto FAIL;
b61f14fc 199 }
3b5f4af2 200
26ab419b
MT
201 // If a prefix was given, we will try to parse it
202 if (prefix_string) {
203 // Convert prefix to integer
204 prefix = strtol(prefix_string, NULL, 10);
205
206 if (!prefix) {
207 DEBUG(ctx, "The prefix was not parsable: %s\n", prefix_string);
208 goto FAIL;
209 }
210
211 // Map the prefix to IPv6 if needed
212 if (IN6_IS_ADDR_V4MAPPED(&first_address))
213 prefix += 96;
214 }
13ad6e69
MT
215
216FAIL:
3b5f4af2
MT
217 // Free temporary buffer
218 free(buffer);
219
13ad6e69
MT
220 // Exit if the parsing was unsuccessful
221 if (r)
222 return r;
223
13ad6e69
MT
224 // Create a new network
225 return loc_network_new(ctx, network, &first_address, prefix);
3b5f4af2
MT
226}
227
228LOC_EXPORT struct loc_network* loc_network_ref(struct loc_network* network) {
229 network->refcount++;
230
231 return network;
232}
233
234static void loc_network_free(struct loc_network* network) {
235 DEBUG(network->ctx, "Releasing network at %p\n", network);
236
3b5f4af2
MT
237 loc_unref(network->ctx);
238 free(network);
239}
240
241LOC_EXPORT struct loc_network* loc_network_unref(struct loc_network* network) {
2a30e4de
MT
242 if (!network)
243 return NULL;
244
3b5f4af2
MT
245 if (--network->refcount > 0)
246 return network;
247
248 loc_network_free(network);
249 return NULL;
250}
251
8fb874e9
MT
252static int format_ipv6_address(const struct in6_addr* address, char* string, size_t length) {
253 const char* ret = inet_ntop(AF_INET6, address, string, length);
d3409788
MT
254 if (!ret)
255 return -1;
256
257 return 0;
258}
259
8fb874e9 260static int format_ipv4_address(const struct in6_addr* address, char* string, size_t length) {
d3409788 261 struct in_addr ipv4_address;
8fb874e9 262 ipv4_address.s_addr = address->s6_addr32[3];
d3409788
MT
263
264 const char* ret = inet_ntop(AF_INET, &ipv4_address, string, length);
265 if (!ret)
266 return -1;
267
268 return 0;
269}
270
3b5f4af2 271LOC_EXPORT char* loc_network_str(struct loc_network* network) {
d3409788
MT
272 int r;
273 const size_t length = INET6_ADDRSTRLEN + 4;
3b5f4af2 274
d3409788 275 char* string = malloc(length);
3b5f4af2
MT
276 if (!string)
277 return NULL;
278
aa37232a
MT
279 unsigned int prefix = network->prefix;
280
c3068be1 281 switch (network->family) {
d3409788 282 case AF_INET6:
ce4f5752 283 r = format_ipv6_address(&network->first_address, string, length);
d3409788 284 break;
3b5f4af2 285
d3409788 286 case AF_INET:
ce4f5752 287 r = format_ipv4_address(&network->first_address, string, length);
aa37232a 288 prefix -= 96;
d3409788
MT
289 break;
290
291 default:
292 r = -1;
293 break;
294 }
295
296 if (r) {
297 ERROR(network->ctx, "Could not convert network to string: %s\n", strerror(errno));
3b5f4af2 298 free(string);
d3409788 299
3b5f4af2
MT
300 return NULL;
301 }
302
303 // Append prefix
aa37232a 304 sprintf(string + strlen(string), "/%u", prefix);
3b5f4af2
MT
305
306 return string;
307}
308
44e5ef71 309LOC_EXPORT int loc_network_address_family(struct loc_network* network) {
c3068be1 310 return network->family;
44e5ef71
MT
311}
312
7fe6a218
MT
313LOC_EXPORT unsigned int loc_network_prefix(struct loc_network* network) {
314 switch (network->family) {
315 case AF_INET6:
316 return network->prefix;
317
318 case AF_INET:
319 return network->prefix - 96;
320 }
321
322 return 0;
323}
324
2b9338ea
MT
325static char* loc_network_format_address(struct loc_network* network, const struct in6_addr* address) {
326 const size_t length = INET6_ADDRSTRLEN;
327
328 char* string = malloc(length);
329 if (!string)
330 return NULL;
331
332 int r = 0;
333
c3068be1 334 switch (network->family) {
2b9338ea
MT
335 case AF_INET6:
336 r = format_ipv6_address(address, string, length);
337 break;
338
339 case AF_INET:
340 r = format_ipv4_address(address, string, length);
341 break;
342
343 default:
344 r = -1;
345 break;
346 }
347
348 if (r) {
349 ERROR(network->ctx, "Could not format IP address to string: %s\n", strerror(errno));
350 free(string);
351
352 return NULL;
353 }
354
355 return string;
356}
357
a1a00053
MT
358LOC_EXPORT const struct in6_addr* loc_network_get_first_address(struct loc_network* network) {
359 return &network->first_address;
360}
361
2b9338ea
MT
362LOC_EXPORT char* loc_network_format_first_address(struct loc_network* network) {
363 return loc_network_format_address(network, &network->first_address);
364}
365
a1a00053
MT
366LOC_EXPORT const struct in6_addr* loc_network_get_last_address(struct loc_network* network) {
367 return &network->last_address;
368}
369
2b9338ea
MT
370LOC_EXPORT char* loc_network_format_last_address(struct loc_network* network) {
371 return loc_network_format_address(network, &network->last_address);
372}
373
2a30e4de 374LOC_EXPORT int loc_network_match_address(struct loc_network* network, const struct in6_addr* address) {
f50adb09 375 // Address must be larger than the start address
ce4f5752 376 if (in6_addr_cmp(&network->first_address, address) > 0)
fc692a58 377 return 0;
2a30e4de 378
2a30e4de 379 // Address must be smaller than the last address
b43edb61 380 if (in6_addr_cmp(&network->last_address, address) < 0)
fc692a58 381 return 0;
2a30e4de
MT
382
383 // The address is inside this network
fc692a58 384 return 1;
2a30e4de
MT
385}
386
3b5f4af2
MT
387LOC_EXPORT const char* loc_network_get_country_code(struct loc_network* network) {
388 return network->country_code;
389}
390
391LOC_EXPORT int loc_network_set_country_code(struct loc_network* network, const char* country_code) {
901ef882
MT
392 // Set empty country code
393 if (!country_code || !*country_code) {
394 *network->country_code = '\0';
395 return 0;
396 }
397
57146963
MT
398 // Check country code
399 if (!loc_country_code_is_valid(country_code))
3b5f4af2
MT
400 return -EINVAL;
401
a7a3d958 402 loc_country_code_copy(network->country_code, country_code);
3b5f4af2
MT
403
404 return 0;
405}
406
e3f696c1 407LOC_EXPORT int loc_network_match_country_code(struct loc_network* network, const char* country_code) {
57146963
MT
408 // Check country code
409 if (!loc_country_code_is_valid(country_code))
e3f696c1
MT
410 return -EINVAL;
411
412 return (network->country_code[0] == country_code[0])
413 && (network->country_code[1] == country_code[1]);
414}
415
71ff3e69
MT
416LOC_EXPORT uint32_t loc_network_get_asn(struct loc_network* network) {
417 return network->asn;
418}
419
420LOC_EXPORT int loc_network_set_asn(struct loc_network* network, uint32_t asn) {
421 network->asn = asn;
422
423 return 0;
424}
425
82910b95
MT
426LOC_EXPORT int loc_network_match_asn(struct loc_network* network, uint32_t asn) {
427 return network->asn == asn;
428}
429
a99e7c2b
MT
430LOC_EXPORT int loc_network_has_flag(struct loc_network* network, uint32_t flag) {
431 return network->flags & flag;
432}
433
434LOC_EXPORT int loc_network_set_flag(struct loc_network* network, uint32_t flag) {
435 network->flags |= flag;
436
437 return 0;
438}
439
440LOC_EXPORT int loc_network_match_flag(struct loc_network* network, uint32_t flag) {
441 return loc_network_has_flag(network, flag);
442}
443
af4689bf
MT
444LOC_EXPORT int loc_network_cmp(struct loc_network* self, struct loc_network* other) {
445 // Compare family
446 if (self->family > other->family)
447 return 1;
448 else if (self->family < other->family)
449 return -1;
450
451 // Compare address
452 int r = in6_addr_cmp(&self->first_address, &other->first_address);
453 if (r)
454 return r;
455
456 // Compare prefix
457 if (self->prefix > other->prefix)
458 return 1;
459 else if (self->prefix < other->prefix)
460 return -1;
461
462 // Both networks are equal
463 return 0;
464}
465
6159d384 466LOC_EXPORT int loc_network_overlaps(struct loc_network* self, struct loc_network* other) {
fc692a58
MT
467 // Either of the start addresses must be in the other subnet
468 if (loc_network_match_address(self, &other->first_address))
6159d384
MT
469 return 1;
470
fc692a58 471 if (loc_network_match_address(other, &self->first_address))
6159d384
MT
472 return 1;
473
fc692a58
MT
474 // Or either of the end addresses is in the other subnet
475 if (loc_network_match_address(self, &other->last_address))
6159d384
MT
476 return 1;
477
fc692a58 478 if (loc_network_match_address(other, &self->last_address))
6159d384
MT
479 return 1;
480
481 return 0;
482}
483
33a051e0 484LOC_EXPORT int loc_network_is_subnet(struct loc_network* self, struct loc_network* other) {
cf8d3c64
MT
485 // Check family
486 if (self->family != other->family)
487 return 0;
488
489 // The prefix must be smaller (this avoids the more complex comparisons later)
490 if (self->prefix > other->prefix)
491 return 0;
492
33a051e0
MT
493 // If the start address of the other network is smaller than this network,
494 // it cannot be a subnet.
1209ff0c 495 if (in6_addr_cmp(&self->first_address, &other->first_address) > 0)
33a051e0
MT
496 return 0;
497
498 // If the end address of the other network is greater than this network,
499 // it cannot be a subnet.
1209ff0c 500 if (in6_addr_cmp(&self->last_address, &other->last_address) < 0)
33a051e0
MT
501 return 0;
502
503 return 1;
504}
505
a5967330
MT
506LOC_EXPORT int loc_network_subnets(struct loc_network* network,
507 struct loc_network** subnet1, struct loc_network** subnet2) {
508 int r;
509 *subnet1 = NULL;
510 *subnet2 = NULL;
850e7516
MT
511
512 // New prefix length
513 unsigned int prefix = network->prefix + 1;
514
515 // Check if the new prefix is valid
516 if (valid_prefix(&network->first_address, prefix))
a5967330 517 return -1;
850e7516
MT
518
519 // Create the first half of the network
a5967330 520 r = loc_network_new(network->ctx, subnet1, &network->first_address, prefix);
850e7516 521 if (r)
a5967330 522 return r;
850e7516
MT
523
524 // The next subnet starts after the first one
a5967330 525 struct in6_addr first_address = address_increment(&(*subnet1)->last_address);
850e7516
MT
526
527 // Create the second half of the network
a5967330 528 r = loc_network_new(network->ctx, subnet2, &first_address, prefix);
850e7516 529 if (r)
a5967330 530 return r;
850e7516 531
594ca328
MT
532 // Copy country code
533 const char* country_code = loc_network_get_country_code(network);
534 if (country_code) {
a5967330
MT
535 loc_network_set_country_code(*subnet1, country_code);
536 loc_network_set_country_code(*subnet2, country_code);
594ca328
MT
537 }
538
539 // Copy ASN
540 uint32_t asn = loc_network_get_asn(network);
541 if (asn) {
a5967330
MT
542 loc_network_set_asn(*subnet1, asn);
543 loc_network_set_asn(*subnet2, asn);
594ca328
MT
544 }
545
a5967330
MT
546 return 0;
547}
850e7516 548
a5967330
MT
549static int __loc_network_exclude(struct loc_network* network,
550 struct loc_network* other, struct loc_network_list* list) {
551 struct loc_network* subnet1 = NULL;
552 struct loc_network* subnet2 = NULL;
553
554 int r = loc_network_subnets(network, &subnet1, &subnet2);
555 if (r)
556 goto ERROR;
557
da101d55 558 if (loc_network_cmp(other, subnet1) == 0) {
a5967330
MT
559 r = loc_network_list_push(list, subnet2);
560 if (r)
561 goto ERROR;
562
da101d55 563 } else if (loc_network_cmp(other, subnet2) == 0) {
a5967330
MT
564 r = loc_network_list_push(list, subnet1);
565 if (r)
566 goto ERROR;
567
d6a5092f 568 } else if (loc_network_is_subnet(subnet1, other)) {
a5967330
MT
569 r = loc_network_list_push(list, subnet2);
570 if (r)
571 goto ERROR;
572
573 r = __loc_network_exclude(subnet1, other, list);
574 if (r)
575 goto ERROR;
576
d6a5092f 577 } else if (loc_network_is_subnet(subnet2, other)) {
a5967330
MT
578 r = loc_network_list_push(list, subnet1);
579 if (r)
580 goto ERROR;
581
582 r = __loc_network_exclude(subnet2, other, list);
583 if (r)
584 goto ERROR;
585
586 } else {
587 ERROR(network->ctx, "We should never get here\n");
588 r = 1;
589 goto ERROR;
590 }
850e7516
MT
591
592ERROR:
593 if (subnet1)
594 loc_network_unref(subnet1);
595
596 if (subnet2)
597 loc_network_unref(subnet2);
598
a5967330 599 return r;
850e7516
MT
600}
601
c650008e
MT
602static int __loc_network_exclude_to_list(struct loc_network* self,
603 struct loc_network* other, struct loc_network_list* list) {
850e7516
MT
604 // Family must match
605 if (self->family != other->family) {
606 DEBUG(self->ctx, "Family mismatch\n");
607
c650008e 608 return 1;
850e7516
MT
609 }
610
611 // Other must be a subnet of self
d6a5092f 612 if (!loc_network_is_subnet(self, other)) {
850e7516
MT
613 DEBUG(self->ctx, "Network %p is not contained in network %p\n", other, self);
614
c650008e 615 return 1;
850e7516
MT
616 }
617
618 // We cannot perform this operation if both networks equal
da101d55 619 if (loc_network_cmp(self, other) == 0) {
850e7516
MT
620 DEBUG(self->ctx, "Networks %p and %p are equal\n", self, other);
621
c650008e 622 return 1;
850e7516
MT
623 }
624
c650008e
MT
625 return __loc_network_exclude(self, other, list);
626}
627
628LOC_EXPORT struct loc_network_list* loc_network_exclude(
629 struct loc_network* self, struct loc_network* other) {
630 struct loc_network_list* list;
631
632#ifdef ENABLE_DEBUG
633 char* n1 = loc_network_str(self);
634 char* n2 = loc_network_str(other);
635
636 DEBUG(self->ctx, "Returning %s excluding %s...\n", n1, n2);
637
638 free(n1);
639 free(n2);
640#endif
641
850e7516
MT
642 // Create a new list with the result
643 int r = loc_network_list_new(self->ctx, &list);
644 if (r) {
645 ERROR(self->ctx, "Could not create network list: %d\n", r);
c650008e 646
850e7516
MT
647 return NULL;
648 }
649
c650008e 650 r = __loc_network_exclude_to_list(self, other, list);
a5967330
MT
651 if (r) {
652 loc_network_list_unref(list);
850e7516 653
a5967330 654 return NULL;
850e7516
MT
655 }
656
850e7516
MT
657 // Return the result
658 return list;
850e7516
MT
659}
660
add5bb65
MT
661LOC_EXPORT struct loc_network_list* loc_network_exclude_list(
662 struct loc_network* network, struct loc_network_list* list) {
663 struct loc_network_list* to_check;
664
665 // Create a new list with all networks to look at
666 int r = loc_network_list_new(network->ctx, &to_check);
667 if (r)
668 return NULL;
669
670 struct loc_network* subnet = NULL;
671 struct loc_network_list* subnets = NULL;
672
673 for (unsigned int i = 0; i < loc_network_list_size(list); i++) {
674 subnet = loc_network_list_get(list, i);
675
676 // Find all excluded networks
c650008e
MT
677 if (!loc_network_list_contains(to_check, subnet)) {
678 r = __loc_network_exclude_to_list(network, subnet, to_check);
679 if (r) {
680 loc_network_list_unref(to_check);
681 loc_network_unref(subnet);
682
683 return NULL;
684 }
add5bb65
MT
685 }
686
687 // Cleanup
688 loc_network_unref(subnet);
689 }
690
691 r = loc_network_list_new(network->ctx, &subnets);
692 if (r) {
693 loc_network_list_unref(to_check);
694 return NULL;
695 }
696
697 while (!loc_network_list_empty(to_check)) {
698 struct loc_network* subnet_to_check = loc_network_list_pop(to_check);
699
06177d8c
MT
700 // Check whether the subnet to check is part of the input list
701 if (loc_network_list_contains(list, subnet_to_check)) {
702 loc_network_unref(subnet_to_check);
703 continue;
704 }
705
add5bb65
MT
706 // Marks whether this subnet passed all checks
707 int passed = 1;
708
709 for (unsigned int i = 0; i < loc_network_list_size(list); i++) {
710 subnet = loc_network_list_get(list, i);
711
add5bb65 712 // Drop this subnet if is a subnet of another subnet
d6a5092f 713 if (loc_network_is_subnet(subnet_to_check, subnet)) {
add5bb65
MT
714 passed = 0;
715 loc_network_unref(subnet);
716 break;
717 }
718
719 // Break it down if it overlaps
720 if (loc_network_overlaps(subnet_to_check, subnet)) {
721 passed = 0;
722
723 struct loc_network_list* excluded = loc_network_exclude(subnet_to_check, subnet);
724 if (excluded) {
725 loc_network_list_merge(to_check, excluded);
726 loc_network_list_unref(excluded);
727 }
728
729 loc_network_unref(subnet);
730 break;
731 }
732
733 loc_network_unref(subnet);
734 }
735
736 if (passed) {
737 r = loc_network_list_push(subnets, subnet_to_check);
738 }
739
740 loc_network_unref(subnet_to_check);
741 }
742
743 loc_network_list_unref(to_check);
744
d3375368
MT
745 // Sort the result
746 loc_network_list_sort(subnets);
747
add5bb65
MT
748 return subnets;
749}
750
b904896a 751LOC_EXPORT int loc_network_to_database_v1(struct loc_network* network, struct loc_database_network_v1* dbobj) {
f3e02bc5 752 // Add country code
a7a3d958 753 loc_country_code_copy(dbobj->country_code, network->country_code);
f3e02bc5
MT
754
755 // Add ASN
71ff3e69 756 dbobj->asn = htobe32(network->asn);
f3e02bc5 757
a99e7c2b 758 // Flags
eee6346d 759 dbobj->flags = htobe16(network->flags);
a99e7c2b 760
f3e02bc5
MT
761 return 0;
762}
763
b904896a
MT
764LOC_EXPORT int loc_network_new_from_database_v1(struct loc_ctx* ctx, struct loc_network** network,
765 struct in6_addr* address, unsigned int prefix, const struct loc_database_network_v1* dbobj) {
3dc8adfb 766 char country_code[3] = "\0\0";
a7a3d958 767
39a55353 768 int r = loc_network_new(ctx, network, address, prefix);
94a3f329
MT
769 if (r) {
770 ERROR(ctx, "Could not allocate a new network: %s", strerror(-r));
10778041 771 return r;
94a3f329 772 }
10778041
MT
773
774 // Import country code
a7a3d958 775 loc_country_code_copy(country_code, dbobj->country_code);
10778041
MT
776
777 r = loc_network_set_country_code(*network, country_code);
94a3f329
MT
778 if (r) {
779 ERROR(ctx, "Could not set country code: %s\n", country_code);
10778041 780 return r;
94a3f329 781 }
10778041
MT
782
783 // Import ASN
94a3f329
MT
784 uint32_t asn = be32toh(dbobj->asn);
785 r = loc_network_set_asn(*network, asn);
786 if (r) {
787 ERROR(ctx, "Could not set ASN: %d\n", asn);
10778041 788 return r;
94a3f329 789 }
10778041 790
a99e7c2b 791 // Import flags
94a3f329
MT
792 int flags = be16toh(dbobj->flags);
793 r = loc_network_set_flag(*network, flags);
794 if (r) {
795 ERROR(ctx, "Could not set flags: %d\n", flags);
a99e7c2b 796 return r;
94a3f329 797 }
a99e7c2b 798
10778041
MT
799 return 0;
800}
801
3b5f4af2
MT
802struct loc_network_tree {
803 struct loc_ctx* ctx;
804 int refcount;
805
806 struct loc_network_tree_node* root;
807};
808
809struct loc_network_tree_node {
438db08c
MT
810 struct loc_ctx* ctx;
811 int refcount;
812
3b5f4af2
MT
813 struct loc_network_tree_node* zero;
814 struct loc_network_tree_node* one;
815
816 struct loc_network* network;
817};
818
7933f5bf 819int loc_network_tree_new(struct loc_ctx* ctx, struct loc_network_tree** tree) {
3b5f4af2
MT
820 struct loc_network_tree* t = calloc(1, sizeof(*t));
821 if (!t)
822 return -ENOMEM;
823
824 t->ctx = loc_ref(ctx);
825 t->refcount = 1;
826
827 // Create the root node
438db08c
MT
828 int r = loc_network_tree_node_new(ctx, &t->root);
829 if (r) {
830 loc_network_tree_unref(t);
831 return r;
832 }
3b5f4af2
MT
833
834 DEBUG(t->ctx, "Network tree allocated at %p\n", t);
835 *tree = t;
836 return 0;
837}
838
7933f5bf 839struct loc_network_tree_node* loc_network_tree_get_root(struct loc_network_tree* tree) {
438db08c 840 return loc_network_tree_node_ref(tree->root);
3b5f4af2
MT
841}
842
843static struct loc_network_tree_node* loc_network_tree_get_node(struct loc_network_tree_node* node, int path) {
844 struct loc_network_tree_node** n;
845
2a30e4de 846 if (path == 0)
3b5f4af2 847 n = &node->zero;
3eda9cab
MT
848 else
849 n = &node->one;
3b5f4af2
MT
850
851 // If the desired node doesn't exist, yet, we will create it
852 if (*n == NULL) {
438db08c 853 int r = loc_network_tree_node_new(node->ctx, n);
3b5f4af2
MT
854 if (r)
855 return NULL;
856 }
857
858 return *n;
859}
860
39a55353 861static struct loc_network_tree_node* loc_network_tree_get_path(struct loc_network_tree* tree, const struct in6_addr* address, unsigned int prefix) {
3b5f4af2
MT
862 struct loc_network_tree_node* node = tree->root;
863
39a55353 864 for (unsigned int i = 0; i < prefix; i++) {
3b5f4af2 865 // Check if the ith bit is one or zero
2a30e4de 866 node = loc_network_tree_get_node(node, in6_addr_get_bit(address, i));
3b5f4af2
MT
867 }
868
869 return node;
870}
871
872static int __loc_network_tree_walk(struct loc_ctx* ctx, struct loc_network_tree_node* node,
f3e02bc5
MT
873 int(*filter_callback)(struct loc_network* network, void* data),
874 int(*callback)(struct loc_network* network, void* data), void* data) {
3b5f4af2
MT
875 int r;
876
877 // Finding a network ends the walk here
878 if (node->network) {
879 if (filter_callback) {
f3e02bc5 880 int f = filter_callback(node->network, data);
3b5f4af2
MT
881 if (f < 0)
882 return f;
883
884 // Skip network if filter function returns value greater than zero
885 if (f > 0)
886 return 0;
887 }
888
f3e02bc5 889 r = callback(node->network, data);
3b5f4af2
MT
890 if (r)
891 return r;
892 }
893
894 // Walk down on the left side of the tree first
895 if (node->zero) {
f3e02bc5 896 r = __loc_network_tree_walk(ctx, node->zero, filter_callback, callback, data);
3b5f4af2
MT
897 if (r)
898 return r;
899 }
900
901 // Then walk on the other side
902 if (node->one) {
f3e02bc5 903 r = __loc_network_tree_walk(ctx, node->one, filter_callback, callback, data);
3b5f4af2
MT
904 if (r)
905 return r;
906 }
907
908 return 0;
909}
910
7933f5bf 911int loc_network_tree_walk(struct loc_network_tree* tree,
f3e02bc5
MT
912 int(*filter_callback)(struct loc_network* network, void* data),
913 int(*callback)(struct loc_network* network, void* data), void* data) {
914 return __loc_network_tree_walk(tree->ctx, tree->root, filter_callback, callback, data);
915}
916
3b5f4af2
MT
917static void loc_network_tree_free(struct loc_network_tree* tree) {
918 DEBUG(tree->ctx, "Releasing network tree at %p\n", tree);
919
438db08c 920 loc_network_tree_node_unref(tree->root);
3b5f4af2
MT
921
922 loc_unref(tree->ctx);
923 free(tree);
924}
925
7933f5bf 926struct loc_network_tree* loc_network_tree_unref(struct loc_network_tree* tree) {
3b5f4af2
MT
927 if (--tree->refcount > 0)
928 return tree;
929
930 loc_network_tree_free(tree);
931 return NULL;
932}
933
e9b4e2a8 934static int __loc_network_tree_dump(struct loc_network* network, void* data) {
3b5f4af2
MT
935 DEBUG(network->ctx, "Dumping network at %p\n", network);
936
937 char* s = loc_network_str(network);
938 if (!s)
939 return 1;
940
941 INFO(network->ctx, "%s\n", s);
942 free(s);
943
944 return 0;
945}
946
7933f5bf 947int loc_network_tree_dump(struct loc_network_tree* tree) {
3b5f4af2
MT
948 DEBUG(tree->ctx, "Dumping network tree at %p\n", tree);
949
f3e02bc5 950 return loc_network_tree_walk(tree, NULL, __loc_network_tree_dump, NULL);
3b5f4af2
MT
951}
952
7933f5bf 953int loc_network_tree_add_network(struct loc_network_tree* tree, struct loc_network* network) {
3b5f4af2
MT
954 DEBUG(tree->ctx, "Adding network %p to tree %p\n", network, tree);
955
39a55353 956 struct loc_network_tree_node* node = loc_network_tree_get_path(tree,
ce4f5752 957 &network->first_address, network->prefix);
3b5f4af2
MT
958 if (!node) {
959 ERROR(tree->ctx, "Could not find a node\n");
960 return -ENOMEM;
961 }
962
963 // Check if node has not been set before
964 if (node->network) {
965 DEBUG(tree->ctx, "There is already a network at this path\n");
c04005bb 966 return -EBUSY;
3b5f4af2
MT
967 }
968
969 // Point node to the network
970 node->network = loc_network_ref(network);
971
972 return 0;
973}
f3e02bc5
MT
974
975static int __loc_network_tree_count(struct loc_network* network, void* data) {
976 size_t* counter = (size_t*)data;
977
978 // Increase the counter for each network
979 counter++;
980
981 return 0;
982}
983
7933f5bf 984size_t loc_network_tree_count_networks(struct loc_network_tree* tree) {
f3e02bc5
MT
985 size_t counter = 0;
986
987 int r = loc_network_tree_walk(tree, NULL, __loc_network_tree_count, &counter);
988 if (r)
989 return r;
990
991 return counter;
992}
940f9c2b
MT
993
994static size_t __loc_network_tree_count_nodes(struct loc_network_tree_node* node) {
995 size_t counter = 1;
996
997 if (node->zero)
998 counter += __loc_network_tree_count_nodes(node->zero);
999
1000 if (node->one)
1001 counter += __loc_network_tree_count_nodes(node->one);
1002
1003 return counter;
1004}
1005
7933f5bf 1006size_t loc_network_tree_count_nodes(struct loc_network_tree* tree) {
940f9c2b
MT
1007 return __loc_network_tree_count_nodes(tree->root);
1008}
438db08c 1009
7933f5bf 1010int loc_network_tree_node_new(struct loc_ctx* ctx, struct loc_network_tree_node** node) {
438db08c
MT
1011 struct loc_network_tree_node* n = calloc(1, sizeof(*n));
1012 if (!n)
1013 return -ENOMEM;
1014
1015 n->ctx = loc_ref(ctx);
1016 n->refcount = 1;
1017
1018 n->zero = n->one = NULL;
1019
1020 DEBUG(n->ctx, "Network node allocated at %p\n", n);
1021 *node = n;
1022 return 0;
1023}
1024
7933f5bf 1025struct loc_network_tree_node* loc_network_tree_node_ref(struct loc_network_tree_node* node) {
438db08c
MT
1026 if (node)
1027 node->refcount++;
1028
1029 return node;
1030}
1031
1032static void loc_network_tree_node_free(struct loc_network_tree_node* node) {
1033 DEBUG(node->ctx, "Releasing network node at %p\n", node);
1034
1035 if (node->network)
1036 loc_network_unref(node->network);
1037
1038 if (node->zero)
1039 loc_network_tree_node_unref(node->zero);
1040
1041 if (node->one)
1042 loc_network_tree_node_unref(node->one);
1043
1044 loc_unref(node->ctx);
1045 free(node);
1046}
1047
7933f5bf 1048struct loc_network_tree_node* loc_network_tree_node_unref(struct loc_network_tree_node* node) {
438db08c
MT
1049 if (!node)
1050 return NULL;
1051
1052 if (--node->refcount > 0)
1053 return node;
1054
1055 loc_network_tree_node_free(node);
1056 return NULL;
1057}
1058
7933f5bf 1059struct loc_network_tree_node* loc_network_tree_node_get(struct loc_network_tree_node* node, unsigned int index) {
438db08c
MT
1060 if (index == 0)
1061 node = node->zero;
1062 else
1063 node = node->one;
1064
1065 if (!node)
1066 return NULL;
1067
1068 return loc_network_tree_node_ref(node);
1069}
1070
7933f5bf 1071int loc_network_tree_node_is_leaf(struct loc_network_tree_node* node) {
438db08c
MT
1072 return (!!node->network);
1073}
1074
7933f5bf 1075struct loc_network* loc_network_tree_node_get_network(struct loc_network_tree_node* node) {
438db08c
MT
1076 return loc_network_ref(node->network);
1077}