From 2b9338eadc23e3a983ec9d9c9c2f63a6d633ec5a Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Fri, 18 Sep 2020 13:46:58 +0000 Subject: [PATCH] network: Export family, first_address and last_address in Python We can use this to avoid formatting the network in a string representation which is then parsed again later to determine the first and last addresses. Signed-off-by: Michael Tremer --- src/libloc.sym | 2 ++ src/loc/network.h | 3 +++ src/network.c | 41 ++++++++++++++++++++++++++++++++++++++++ src/python/export.py | 8 +++----- src/python/network.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ src/test-network.c | 25 +++++++++++++++++++++++- 6 files changed, 118 insertions(+), 6 deletions(-) diff --git a/src/libloc.sym b/src/libloc.sym index 222a4cf..b8296eb 100644 --- a/src/libloc.sym +++ b/src/libloc.sym @@ -80,6 +80,8 @@ global: # Network loc_network_address_family; + loc_network_format_first_address; + loc_network_format_last_address; loc_network_get_asn; loc_network_get_country_code; loc_network_has_flag; diff --git a/src/loc/network.h b/src/loc/network.h index 6bc498f..70c3803 100644 --- a/src/loc/network.h +++ b/src/loc/network.h @@ -37,6 +37,9 @@ struct loc_network* loc_network_ref(struct loc_network* network); struct loc_network* loc_network_unref(struct loc_network* network); char* loc_network_str(struct loc_network* network); int loc_network_address_family(struct loc_network* network); + +char* loc_network_format_first_address(struct loc_network* network); +char* loc_network_format_last_address(struct loc_network* network); int loc_network_match_address(struct loc_network* network, const struct in6_addr* address); const char* loc_network_get_country_code(struct loc_network* network); diff --git a/src/network.c b/src/network.c index a4c7646..dc976e9 100644 --- a/src/network.c +++ b/src/network.c @@ -278,6 +278,47 @@ LOC_EXPORT int loc_network_address_family(struct loc_network* network) { return AF_INET6; } +static char* loc_network_format_address(struct loc_network* network, const struct in6_addr* address) { + const size_t length = INET6_ADDRSTRLEN; + + char* string = malloc(length); + if (!string) + return NULL; + + int r = 0; + + switch (loc_network_address_family(network)) { + case AF_INET6: + r = format_ipv6_address(address, string, length); + break; + + case AF_INET: + r = format_ipv4_address(address, string, length); + break; + + default: + r = -1; + break; + } + + if (r) { + ERROR(network->ctx, "Could not format IP address to string: %s\n", strerror(errno)); + free(string); + + return NULL; + } + + return string; +} + +LOC_EXPORT char* loc_network_format_first_address(struct loc_network* network) { + return loc_network_format_address(network, &network->first_address); +} + +LOC_EXPORT char* loc_network_format_last_address(struct loc_network* network) { + return loc_network_format_address(network, &network->last_address); +} + LOC_EXPORT int loc_network_match_address(struct loc_network* network, const struct in6_addr* address) { // Address must be larger than the start address if (in6_addr_cmp(&network->first_address, address) > 0) diff --git a/src/python/export.py b/src/python/export.py index 180d462..d15c6f0 100644 --- a/src/python/export.py +++ b/src/python/export.py @@ -143,12 +143,10 @@ class XTGeoIPOutputWriter(OutputWriter): mode = "wb" def _write_network(self, network): - n = ipaddress.ip_network("%s" % network) - - for address in (n.network_address, n.broadcast_address): + for address in (network.first_address, network.last_address): + # Convert this into a string of bits bytes = socket.inet_pton( - socket.AF_INET6 if address.version == 6 else socket.AF_INET, - "%s" % address, + network.family, address, ) self.f.write(bytes) diff --git a/src/python/network.c b/src/python/network.c index 5fbb17d..5496d1e 100644 --- a/src/python/network.c +++ b/src/python/network.c @@ -166,6 +166,30 @@ static PyObject* Network_is_subnet_of(NetworkObject* self, PyObject* args) { Py_RETURN_FALSE; } +static PyObject* Network_get_family(NetworkObject* self) { + int family = loc_network_address_family(self->network); + + return PyLong_FromLong(family); +} + +static PyObject* Network_get_first_address(NetworkObject* self) { + char* address = loc_network_format_first_address(self->network); + + PyObject* obj = PyUnicode_FromString(address); + free(address); + + return obj; +} + +static PyObject* Network_get_last_address(NetworkObject* self) { + char* address = loc_network_format_last_address(self->network); + + PyObject* obj = PyUnicode_FromString(address); + free(address); + + return obj; +} + static struct PyMethodDef Network_methods[] = { { "has_flag", @@ -203,6 +227,27 @@ static struct PyGetSetDef Network_getsetters[] = { NULL, NULL, }, + { + "family", + (getter)Network_get_family, + NULL, + NULL, + NULL, + }, + { + "first_address", + (getter)Network_get_first_address, + NULL, + NULL, + NULL, + }, + { + "last_address", + (getter)Network_get_last_address, + NULL, + NULL, + NULL, + }, { NULL }, }; diff --git a/src/test-network.c b/src/test-network.c index c49c3ef..d38f13d 100644 --- a/src/test-network.c +++ b/src/test-network.c @@ -46,7 +46,7 @@ int main(int argc, char** argv) { // Create a network struct loc_network* network1; - err = loc_network_new_from_string(ctx, &network1, "2001:db8::/32"); + err = loc_network_new_from_string(ctx, &network1, "2001:db8::1/32"); if (err) { fprintf(stderr, "Could not create the network\n"); exit(EXIT_FAILURE); @@ -65,6 +65,29 @@ int main(int argc, char** argv) { exit(EXIT_FAILURE); } + // Check if the first and last addresses are correct + char* string = loc_network_format_first_address(network1); + if (!string) { + fprintf(stderr, "Did get NULL instead of a string for the first address\n"); + exit(EXIT_FAILURE); + } + + if (strcmp(string, "2001:db8::") != 0) { + fprintf(stderr, "Got an incorrect first address: %s\n", string); + exit(EXIT_FAILURE); + } + + string = loc_network_format_last_address(network1); + if (!string) { + fprintf(stderr, "Did get NULL instead of a string for the last address\n"); + exit(EXIT_FAILURE); + } + + if (strcmp(string, "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff") != 0) { + fprintf(stderr, "Got an incorrect last address: %s\n", string); + exit(EXIT_FAILURE); + } + struct loc_network* network2; err = loc_network_new_from_string(ctx, &network2, "2001:db8:ffff::/48"); if (err) { -- 2.39.2