+
See above for usage of the '--family' and '--format' parameters.
+'list-bogons [--family=[ipv6|ipv4]] [--format=FORMAT]'::
+ Lists all bogons (i.e. networks that are unknown to the database).
+ +
+ See above for usage of the '--family' and '--format' parameters.
+
'lookup ADDRESS [ADDRESS...]'::
This command returns the network the given IP address has been found in
as well as its Autonomous System if that information is available.
#include <loc/database.h>
#include <loc/format.h>
#include <loc/network.h>
+#include <loc/network-list.h>
#include <loc/private.h>
#include <loc/stringpool.h>
int network_stack_depth;
unsigned int* networks_visited;
- // For subnet search
+ // For subnet search and bogons
struct loc_network_list* stack;
+ struct loc_network* last_network;
};
static int loc_database_read_magic(struct loc_database* db) {
// Free network search
free(enumerator->networks_visited);
- // Free subnet stack
+ // Free subnet/bogons stack
if (enumerator->stack)
loc_network_list_unref(enumerator->stack);
+ if (enumerator->last_network)
+ loc_network_unref(enumerator->last_network);
+
free(enumerator);
}
return __loc_database_enumerator_next_network_flattened(enumerator, network);
}
+/*
+ This function finds all bogons (i.e. gaps) between the input networks
+*/
+static int __loc_database_enumerator_find_bogons(struct loc_ctx* ctx,
+ struct loc_network* first, struct loc_network* second, struct loc_network_list* bogons) {
+ // We do not need to check if first < second because the graph is always ordered
+
+ // The last address of the first network + 1 is the start of the gap
+ struct in6_addr first_address = address_increment(loc_network_get_last_address(first));
+
+ // The first address of the second network - 1 is the end of the gap
+ struct in6_addr last_address = address_decrement(loc_network_get_first_address(second));
+
+ // If first address is now greater than last address, there is no gap
+ if (in6_addr_cmp(&first_address, &last_address) >= 0)
+ return 0;
+
+ return loc_network_list_summarize(ctx, &first_address, &last_address, &bogons);
+}
+
+static int __loc_database_enumerator_next_bogon(
+ struct loc_database_enumerator* enumerator, struct loc_network** bogon) {
+ int r;
+
+ // Return top element from the stack
+ while (1) {
+ *bogon = loc_network_list_pop_first(enumerator->stack);
+
+ // Stack is empty
+ if (!*bogon)
+ break;
+
+ // Return result
+ return 0;
+ }
+
+ struct loc_network* network = NULL;
+
+ while (1) {
+ r = __loc_database_enumerator_next_network(enumerator, &network, 1);
+ if (r)
+ goto ERROR;
+
+ if (!network)
+ break;
+
+ if (enumerator->last_network && loc_network_address_family(enumerator->last_network) == loc_network_address_family(network)) {
+ r = __loc_database_enumerator_find_bogons(enumerator->ctx,
+ enumerator->last_network, network, enumerator->stack);
+ if (r) {
+ loc_network_unref(network);
+ goto ERROR;
+ }
+ }
+
+ // Remember network for next iteration
+ enumerator->last_network = loc_network_ref(network);
+ loc_network_unref(network);
+
+ // Try to return something
+ *bogon = loc_network_list_pop_first(enumerator->stack);
+ if (*bogon)
+ break;
+ }
+
+ERROR:
+ return r;
+}
+
LOC_EXPORT int loc_database_enumerator_next_network(
struct loc_database_enumerator* enumerator, struct loc_network** network) {
- // Do not do anything if not in network mode
- if (enumerator->mode != LOC_DB_ENUMERATE_NETWORKS)
- return 0;
+ switch (enumerator->mode) {
+ case LOC_DB_ENUMERATE_NETWORKS:
+ // Flatten output?
+ if (enumerator->flatten)
+ return __loc_database_enumerator_next_network_flattened(enumerator, network);
- // Flatten output?
- if (enumerator->flatten)
- return __loc_database_enumerator_next_network_flattened(enumerator, network);
+ return __loc_database_enumerator_next_network(enumerator, network, 1);
+
+ case LOC_DB_ENUMERATE_BOGONS:
+ return __loc_database_enumerator_next_bogon(enumerator, network);
- return __loc_database_enumerator_next_network(enumerator, network, 1);
+ default:
+ return 0;
+ }
}
LOC_EXPORT int loc_database_enumerator_next_country(
LOC_DB_ENUMERATE_NETWORKS = 1,
LOC_DB_ENUMERATE_ASES = 2,
LOC_DB_ENUMERATE_COUNTRIES = 3,
+ LOC_DB_ENUMERATE_BOGONS = 4,
};
enum loc_database_enumerator_flags {
int loc_network_list_contains(struct loc_network_list* list, struct loc_network* network);
int loc_network_list_merge(struct loc_network_list* self, struct loc_network_list* other);
+#ifdef LIBLOC_PRIVATE
+
+#include <netinet/in.h>
+
+int loc_network_list_summarize(struct loc_ctx* ctx,
+ const struct in6_addr* first, const struct in6_addr* last, struct loc_network_list** list);
+
+#endif /* LOC_PRIVATE */
+
#endif
return 0;
}
+
+int loc_network_list_summarize(struct loc_ctx* ctx,
+ const struct in6_addr* first, const struct in6_addr* last, struct loc_network_list** list) {
+ int r;
+
+ if (!list) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ int family = loc_address_family(first);
+
+ // Families must match
+ if (family != loc_address_family(last)) {
+ ERROR(ctx, "Address families do not match\n");
+ errno = EINVAL;
+ return 1;
+ }
+
+ // Check if the last address is larger than the first address
+ if (in6_addr_cmp(first, last) >= 0) {
+ ERROR(ctx, "The first address must be smaller than the last address\n");
+ errno = EINVAL;
+ return 1;
+ }
+
+ struct loc_network* network = NULL;
+
+ struct in6_addr start = *first;
+ const struct in6_addr* end = NULL;
+
+ while (in6_addr_cmp(&start, last) <= 0) {
+ // Guess the prefix
+ int prefix = 128 - loc_address_count_trailing_zero_bits(&start);
+
+ while (1) {
+ // Create a new network object
+ r = loc_network_new(ctx, &network, &start, prefix);
+ if (r)
+ return r;
+
+ // Is this network within bounds?
+ end = loc_network_get_last_address(network);
+ if (in6_addr_cmp(last, end) <= 0)
+ break;
+
+ // Drop network and decrease prefix
+ loc_network_unref(network);
+ prefix--;
+ }
+
+ // Push it on the list
+ r = loc_network_list_push(*list, network);
+ if (r) {
+ loc_network_unref(network);
+ return r;
+ }
+
+ // Reset addr to the next start address
+ start = address_increment(end);
+
+ // Cleanup
+ loc_network_unref(network);
+ }
+
+ return 0;
+}
return Database_iterate_all(self, LOC_DB_ENUMERATE_COUNTRIES, AF_UNSPEC, 0);
}
+static PyObject* Database_list_bogons(DatabaseObject* self, PyObject* args, PyObject* kwargs) {
+ char* kwlist[] = { "family", NULL };
+ int family = AF_UNSPEC;
+
+ // Parse arguments
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &family))
+ return NULL;
+
+ return Database_iterate_all(self, LOC_DB_ENUMERATE_BOGONS, family, 0);
+}
+
static struct PyMethodDef Database_methods[] = {
{
"get_as",
METH_VARARGS,
NULL,
},
+ {
+ "list_bogons",
+ (PyCFunction)Database_list_bogons,
+ METH_VARARGS|METH_KEYWORDS,
+ NULL,
+ },
{
"lookup",
(PyCFunction)Database_lookup,
choices=location.export.formats.keys(), default="list")
list_networks_by_flags.set_defaults(func=self.handle_list_networks_by_flags)
+ # List bogons
+ list_bogons = subparsers.add_parser("list-bogons",
+ help=_("Lists all bogons"),
+ )
+ list_bogons.add_argument("--family", choices=("ipv6", "ipv4"))
+ list_bogons.add_argument("--format",
+ choices=location.export.formats.keys(), default="list")
+ list_bogons.set_defaults(func=self.handle_list_bogons)
+
# List countries
list_countries = subparsers.add_parser("list-countries",
help=_("Lists all countries"),
f.finish()
+ def handle_list_bogons(self, db, ns):
+ writer = self.__get_output_formatter(ns)
+ f = writer(sys.stdout, prefix="bogons")
+
+ for n in db.list_bogons(family=ns.family):
+ f.write(n)
+
+ f.finish()
+
def handle_export(self, db, ns):
countries, asns = [], []