From 84a2f0c2d9cbf8ae4225802c29ccba86561c77ed Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Tue, 17 Nov 2020 16:46:48 +0000 Subject: [PATCH] as: Add list for easier processing Signed-off-by: Michael Tremer --- Makefile.am | 2 + src/as-list.c | 138 ++++++++++++++++++++++++++++++++++++++++++ src/database.c | 29 +++++++-- src/libloc.sym | 15 ++++- src/loc/as-list.h | 41 +++++++++++++ src/loc/database.h | 5 +- src/python/database.c | 58 ++++++++++++++++-- src/python/export.py | 2 +- 8 files changed, 275 insertions(+), 15 deletions(-) create mode 100644 src/as-list.c create mode 100644 src/loc/as-list.h diff --git a/Makefile.am b/Makefile.am index f4ca3c8..d0cc793 100644 --- a/Makefile.am +++ b/Makefile.am @@ -91,6 +91,7 @@ EXTRA_DIST += \ pkginclude_HEADERS = \ src/loc/libloc.h \ src/loc/as.h \ + src/loc/as-list.h \ src/loc/compat.h \ src/loc/country.h \ src/loc/country-list.h \ @@ -109,6 +110,7 @@ lib_LTLIBRARIES = \ src_libloc_la_SOURCES = \ src/libloc.c \ src/as.c \ + src/as-list.c \ src/country.c \ src/country-list.c \ src/database.c \ diff --git a/src/as-list.c b/src/as-list.c new file mode 100644 index 0000000..7c69eb0 --- /dev/null +++ b/src/as-list.c @@ -0,0 +1,138 @@ +/* + libloc - A library to determine the location of someone on the Internet + + Copyright (C) 2020 IPFire Development Team + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#include +#include + +#include +#include +#include + +struct loc_as_list { + struct loc_ctx* ctx; + int refcount; + + struct loc_as* list[1024]; + size_t size; + size_t max_size; +}; + +LOC_EXPORT int loc_as_list_new(struct loc_ctx* ctx, + struct loc_as_list** list) { + struct loc_as_list* l = calloc(1, sizeof(*l)); + if (!l) + return -ENOMEM; + + l->ctx = loc_ref(ctx); + l->refcount = 1; + + // Do not allow this list to grow larger than this + l->max_size = 1024; + + DEBUG(l->ctx, "AS list allocated at %p\n", l); + *list = l; + + return 0; +} + +LOC_EXPORT struct loc_as_list* loc_as_list_ref(struct loc_as_list* list) { + list->refcount++; + + return list; +} + +static void loc_as_list_free(struct loc_as_list* list) { + DEBUG(list->ctx, "Releasing AS list at %p\n", list); + + loc_as_list_clear(list); + + loc_unref(list->ctx); + free(list); +} + +LOC_EXPORT struct loc_as_list* loc_as_list_unref(struct loc_as_list* list) { + if (!list) + return NULL; + + if (--list->refcount > 0) + return list; + + loc_as_list_free(list); + return NULL; +} + +LOC_EXPORT size_t loc_as_list_size(struct loc_as_list* list) { + return list->size; +} + +LOC_EXPORT int loc_as_list_empty(struct loc_as_list* list) { + return list->size == 0; +} + +LOC_EXPORT void loc_as_list_clear(struct loc_as_list* list) { + for (unsigned int i = 0; i < list->size; i++) + loc_as_unref(list->list[i]); +} + +LOC_EXPORT struct loc_as* loc_as_list_get(struct loc_as_list* list, size_t index) { + // Check index + if (index >= list->size) + return NULL; + + return loc_as_ref(list->list[index]); +} + +LOC_EXPORT int loc_as_list_append( + struct loc_as_list* list, struct loc_as* as) { + if (loc_as_list_contains(list, as)) + return 0; + + // Check if we have space left + if (list->size == list->max_size) { + ERROR(list->ctx, "%p: Could not append AS to the list. List full\n", list); + return -ENOMEM; + } + + DEBUG(list->ctx, "%p: Appending AS %p to list\n", list, as); + + list->list[list->size++] = loc_as_ref(as); + + return 0; +} + +LOC_EXPORT int loc_as_list_contains( + struct loc_as_list* list, struct loc_as* as) { + for (unsigned int i = 0; i < list->size; i++) { + if (loc_as_cmp(as, list->list[i]) == 0) + return 1; + } + + return 0; +} + +LOC_EXPORT int loc_as_list_contains_number( + struct loc_as_list* list, uint32_t number) { + struct loc_as* as; + + int r = loc_as_new(list->ctx, &as, number); + if (r) + return -1; + + r = loc_as_list_contains(list, as); + loc_as_unref(as); + + return r; +} diff --git a/src/database.c b/src/database.c index 29823b2..51cb5cd 100644 --- a/src/database.c +++ b/src/database.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -101,7 +102,7 @@ struct loc_database_enumerator { // Search string char* string; struct loc_country_list* countries; - uint32_t asn; + struct loc_as_list* asns; enum loc_network_flags flags; int family; @@ -1036,9 +1037,20 @@ LOC_EXPORT int loc_database_enumerator_set_countries( return 0; } -LOC_EXPORT int loc_database_enumerator_set_asn( - struct loc_database_enumerator* enumerator, unsigned int asn) { - enumerator->asn = asn; +LOC_EXPORT struct loc_as_list* loc_database_enumerator_get_asns( + struct loc_database_enumerator* enumerator) { + if (!enumerator->asns) + return NULL; + + return loc_as_list_ref(enumerator->asns); +} + +LOC_EXPORT int loc_database_enumerator_set_asns( + struct loc_database_enumerator* enumerator, struct loc_as_list* asns) { + if (enumerator->asns) + loc_as_list_unref(enumerator->asns); + + enumerator->asns = loc_as_list_ref(asns); return 0; } @@ -1123,6 +1135,12 @@ static int loc_network_match_countries(struct loc_network* network, struct loc_c return loc_country_list_contains_code(countries, country_code); } +static int loc_network_match_asns(struct loc_network* network, struct loc_as_list* asns) { + uint32_t asn = loc_network_get_asn(network); + + return loc_as_list_contains_number(asns, asn); +} + static int loc_database_enumerator_filter_network( struct loc_database_enumerator* enumerator, struct loc_network* network) { // Skip if the family does not match @@ -1134,8 +1152,7 @@ static int loc_database_enumerator_filter_network( return 1; // Skip if the ASN does not match - if (enumerator->asn && - !loc_network_match_asn(network, enumerator->asn)) + if (enumerator->asns && !loc_network_match_asns(network, enumerator->asns)) return 1; // Skip if flags do not match diff --git a/src/libloc.sym b/src/libloc.sym index 40e9f88..53273cd 100644 --- a/src/libloc.sym +++ b/src/libloc.sym @@ -37,6 +37,18 @@ global: loc_as_set_name; loc_as_unref; + # AS List + loc_as_list_append; + loc_as_list_clear; + loc_as_list_contains; + loc_as_list_contains_number; + loc_as_list_empty; + loc_as_list_get; + loc_as_list_new; + loc_as_list_ref; + loc_as_list_size; + loc_as_list_unref; + # Country loc_country_cmp; loc_country_code_is_valid; @@ -78,13 +90,14 @@ global: loc_database_verify; # Database Enumerator + loc_database_enumerator_get_asns; loc_database_enumerator_get_countries; loc_database_enumerator_new; loc_database_enumerator_next_as; loc_database_enumerator_next_country; loc_database_enumerator_next_network; loc_database_enumerator_ref; - loc_database_enumerator_set_asn; + loc_database_enumerator_set_asns; loc_database_enumerator_set_countries; loc_database_enumerator_set_family; loc_database_enumerator_set_flag; diff --git a/src/loc/as-list.h b/src/loc/as-list.h new file mode 100644 index 0000000..7b5c4e8 --- /dev/null +++ b/src/loc/as-list.h @@ -0,0 +1,41 @@ +/* + libloc - A library to determine the location of someone on the Internet + + Copyright (C) 2017 IPFire Development Team + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +#ifndef LIBLOC_AS_LIST_H +#define LIBLOC_AS_LIST_H + +#include +#include + +struct loc_as_list; + +int loc_as_list_new(struct loc_ctx* ctx, struct loc_as_list** list); +struct loc_as_list* loc_as_list_ref(struct loc_as_list* list); +struct loc_as_list* loc_as_list_unref(struct loc_as_list* list); + +size_t loc_as_list_size(struct loc_as_list* list); +int loc_as_list_empty(struct loc_as_list* list); +void loc_as_list_clear(struct loc_as_list* list); + +struct loc_as* loc_as_list_get(struct loc_as_list* list, size_t index); +int loc_as_list_append(struct loc_as_list* list, struct loc_as* as); + +int loc_as_list_contains( + struct loc_as_list* list, struct loc_as* as); +int loc_as_list_contains_number( + struct loc_as_list* list, uint32_t number); + +#endif diff --git a/src/loc/database.h b/src/loc/database.h index 246e5c5..70801f0 100644 --- a/src/loc/database.h +++ b/src/loc/database.h @@ -70,7 +70,10 @@ int loc_database_enumerator_set_string(struct loc_database_enumerator* enumerato struct loc_country_list* loc_database_enumerator_get_countries(struct loc_database_enumerator* enumerator); int loc_database_enumerator_set_countries( struct loc_database_enumerator* enumerator, struct loc_country_list* countries); -int loc_database_enumerator_set_asn(struct loc_database_enumerator* enumerator, unsigned int asn); +struct loc_as_list* loc_database_enumerator_get_asns( + struct loc_database_enumerator* enumerator); +int loc_database_enumerator_set_asns( + struct loc_database_enumerator* enumerator, struct loc_as_list* asns); int loc_database_enumerator_set_flag(struct loc_database_enumerator* enumerator, enum loc_network_flags flag); int loc_database_enumerator_set_family(struct loc_database_enumerator* enumerator, int family); int loc_database_enumerator_next_as( diff --git a/src/python/database.c b/src/python/database.c index e6f6f37..38a804c 100644 --- a/src/python/database.c +++ b/src/python/database.c @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include "locationmodule.h" @@ -258,15 +260,15 @@ static PyObject* Database_networks_flattened(DatabaseObject *self) { } static PyObject* Database_search_networks(DatabaseObject* self, PyObject* args, PyObject* kwargs) { - char* kwlist[] = { "country_codes", "asn", "flags", "family", "flatten", NULL }; + char* kwlist[] = { "country_codes", "asns", "flags", "family", "flatten", NULL }; PyObject* country_codes = NULL; - unsigned int asn = 0; + PyObject* asn_list = NULL; int flags = 0; int family = 0; int flatten = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O!iiip", kwlist, - &PyList_Type, &country_codes, &asn, &flags, &family, &flatten)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O!O!iip", kwlist, + &PyList_Type, &country_codes, &PyList_Type, &asn_list, &flags, &family, &flatten)) return NULL; struct loc_database_enumerator* enumerator; @@ -330,13 +332,57 @@ static PyObject* Database_search_networks(DatabaseObject* self, PyObject* args, } // Set the ASN we are searching for - if (asn) { - r = loc_database_enumerator_set_asn(enumerator, asn); + if (asn_list) { + struct loc_as_list* asns; + r = loc_as_list_new(loc_ctx, &asns); + if (r) { + PyErr_SetString(PyExc_SystemError, "Could not create AS list"); + return NULL; + } + + for (unsigned int i = 0; i < PyList_Size(asn_list); i++) { + PyObject* item = PyList_GetItem(asn_list, i); + + if (!PyLong_Check(item)) { + PyErr_SetString(PyExc_TypeError, "ASNs must be numbers"); + + loc_as_list_unref(asns); + return NULL; + } + + unsigned long number = PyLong_AsLong(item); + struct loc_as* as; + r = loc_as_new(loc_ctx, &as, number); + if (r) { + PyErr_SetString(PyExc_SystemError, "Could not create AS"); + + loc_as_list_unref(asns); + loc_as_unref(as); + return NULL; + } + + r = loc_as_list_append(asns, as); + if (r) { + PyErr_SetString(PyExc_SystemError, "Could not append AS to the list"); + + loc_as_list_unref(asns); + loc_as_unref(as); + return NULL; + } + + loc_as_unref(as); + } + + r = loc_database_enumerator_set_asns(enumerator, asns); if (r) { PyErr_SetFromErrno(PyExc_SystemError); + + loc_as_list_unref(asns); return NULL; } + + loc_as_list_unref(asns); } // Set the flags we are searching for diff --git a/src/python/export.py b/src/python/export.py index 739742f..f675eb3 100644 --- a/src/python/export.py +++ b/src/python/export.py @@ -197,7 +197,7 @@ class Exporter(object): # Get all networks that match the family networks = self.db.search_networks(family=family, - country_codes=country_codes, flags=flags, flatten=True) + country_codes=country_codes, asns=asns, flags=flags, flatten=True) # Walk through all networks for network in networks: -- 2.39.2