+ // We have read the last network
+ if (!network)
+ goto FINISH;
+
+ const char* country_code = loc_network_get_country_code(network);
+
+ /*
+ Skip anything that does not have a country code
+
+ Even if a network is part of the routing table, and the database provides
+ an ASN, this does not mean that this is a legitimate announcement.
+ */
+ if (country_code && !*country_code) {
+ loc_network_unref(network);
+ continue;
+ }
+
+ // Determine the network family
+ int family = loc_network_address_family(network);
+
+ switch (family) {
+ case AF_INET6:
+ gap_start = &enumerator->gap6_start;
+ break;
+
+ case AF_INET:
+ gap_start = &enumerator->gap4_start;
+ break;
+
+ default:
+ ERROR(enumerator->ctx, "Unsupported network family %d\n", family);
+ errno = ENOTSUP;
+ return 1;
+ }
+
+ const struct in6_addr* first_address = loc_network_get_first_address(network);
+ const struct in6_addr* last_address = loc_network_get_last_address(network);
+
+ // Skip if this network is a subnet of a former one
+ if (loc_address_cmp(gap_start, last_address) >= 0) {
+ loc_network_unref(network);
+ continue;
+ }
+
+ // Search where the gap could end
+ gap_end = *first_address;
+ loc_address_decrement(&gap_end);
+
+ // There is a gap
+ if (loc_address_cmp(gap_start, &gap_end) <= 0) {
+ r = loc_network_list_summarize(enumerator->ctx,
+ gap_start, &gap_end, &enumerator->stack);
+ if (r) {
+ loc_network_unref(network);
+ return r;
+ }
+ }
+
+ // The gap now starts after this network
+ *gap_start = *last_address;
+ loc_address_increment(gap_start);
+
+ loc_network_unref(network);
+
+ // Try to return something
+ *bogon = loc_network_list_pop_first(enumerator->stack);
+ if (*bogon)
+ break;
+ }
+
+ return 0;
+
+FINISH:
+
+ if (!loc_address_all_zeroes(&enumerator->gap6_start)) {
+ r = loc_address_reset_last(&gap_end, AF_INET6);
+ if (r)
+ return r;
+
+ if (loc_address_cmp(&enumerator->gap6_start, &gap_end) <= 0) {
+ r = loc_network_list_summarize(enumerator->ctx,
+ &enumerator->gap6_start, &gap_end, &enumerator->stack);
+ if (r)
+ return r;
+ }
+
+ // Reset start
+ loc_address_reset(&enumerator->gap6_start, AF_INET6);
+ }
+
+ if (!loc_address_all_zeroes(&enumerator->gap4_start)) {
+ r = loc_address_reset_last(&gap_end, AF_INET);
+ if (r)
+ return r;
+
+ if (loc_address_cmp(&enumerator->gap4_start, &gap_end) <= 0) {
+ r = loc_network_list_summarize(enumerator->ctx,
+ &enumerator->gap4_start, &gap_end, &enumerator->stack);
+ if (r)
+ return r;
+ }
+
+ // Reset start
+ loc_address_reset(&enumerator->gap4_start, AF_INET);
+ }
+
+ // Try to return something
+ *bogon = loc_network_list_pop_first(enumerator->stack);