From 8da88dda6f99ca9938b81a1d75f252e42d74a2c4 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 6 Apr 2024 10:49:41 +0000 Subject: [PATCH] network: Add function to return a reverse pointer for networks Signed-off-by: Michael Tremer --- src/libloc.sym | 7 +++ src/libloc/network.h | 2 + src/lua/network.c | 31 ++++++++++++ src/network.c | 118 +++++++++++++++++++++++++++++++++++++++++++ src/python/network.c | 32 ++++++++++++ src/test-network.c | 66 ++++++++++++++++++++++++ tests/lua/main.lua | 2 +- 7 files changed, 257 insertions(+), 1 deletion(-) diff --git a/src/libloc.sym b/src/libloc.sym index 29e17f0..50734b3 100644 --- a/src/libloc.sym +++ b/src/libloc.sym @@ -146,3 +146,10 @@ global: local: *; }; + +LIBLOC_2 { +global: + loc_network_reverse_pointer; +local: + *; +} LIBLOC_1; diff --git a/src/libloc/network.h b/src/libloc/network.h index 62334ac..6f2dad2 100644 --- a/src/libloc/network.h +++ b/src/libloc/network.h @@ -66,6 +66,8 @@ struct loc_network_list* loc_network_exclude( struct loc_network_list* loc_network_exclude_list( struct loc_network* network, struct loc_network_list* list); +char* loc_network_reverse_pointer(struct loc_network* network, const char* suffix); + #ifdef LIBLOC_PRIVATE int loc_network_properties_cmp(struct loc_network* self, struct loc_network* other); diff --git a/src/lua/network.c b/src/lua/network.c index a25166e..15936f7 100644 --- a/src/lua/network.c +++ b/src/lua/network.c @@ -151,12 +151,43 @@ static int Network_has_flag(lua_State* L) { return 1; } +// Reverse Pointer + +static int Network_reverse_pointer(lua_State* L) { + char* rp = NULL; + + Network* self = luaL_checknetwork(L, 1); + + // Fetch the suffix + const char* suffix = luaL_optstring(L, 2, NULL); + + // Make the reverse pointer + rp = loc_network_reverse_pointer(self->network, suffix); + if (!rp) { + switch (errno) { + case ENOTSUP: + lua_pushnil(L); + return 1; + + default: + return luaL_error(L, "Could not create reverse pointer: %s\n", strerror(errno)); + } + } + + // Return the response + lua_pushstring(L, rp); + free(rp); + + return 1; +} + static const struct luaL_Reg Network_functions[] = { { "new", Network_new }, { "get_asn", Network_get_asn }, { "get_country_code", Network_get_country_code }, { "get_family", Network_get_family }, { "has_flag", Network_has_flag }, + { "reverse_pointer", Network_reverse_pointer }, { "__gc", Network_gc }, { "__tostring", Network_tostring }, { NULL, NULL }, diff --git a/src/network.c b/src/network.c index d658709..69306a9 100644 --- a/src/network.c +++ b/src/network.c @@ -700,3 +700,121 @@ int loc_network_new_from_database_v1(struct loc_ctx* ctx, struct loc_network** n return 0; } + +static char* loc_network_reverse_pointer6(struct loc_network* network, const char* suffix) { + char* buffer = NULL; + int r; + + unsigned int prefix = loc_network_prefix(network); + + // Must border on a nibble + if (prefix % 4) { + errno = ENOTSUP; + return NULL; + } + + if (!suffix) + suffix = "ip6.arpa."; + + // Initialize the buffer + r = asprintf(&buffer, "%s", suffix); + if (r < 0) + goto ERROR; + + for (unsigned int i = 0; i < (prefix / 4); i++) { + r = asprintf(&buffer, "%x.%s", loc_address_get_nibble(&network->first_address, i), buffer); + if (r < 0) + goto ERROR; + } + + // Add the asterisk + if (prefix < 128) { + r = asprintf(&buffer, "*.%s", buffer); + if (r < 0) + goto ERROR; + } + + return buffer; + +ERROR: + if (buffer) + free(buffer); + + return NULL; +} + +static char* loc_network_reverse_pointer4(struct loc_network* network, const char* suffix) { + char* buffer = NULL; + int r; + + unsigned int prefix = loc_network_prefix(network); + + // Must border on an octet + if (prefix % 8) { + errno = ENOTSUP; + return NULL; + } + + if (!suffix) + suffix = "in-addr.arpa."; + + switch (prefix) { + case 32: + r = asprintf(&buffer, "%d.%d.%d.%d.%s", + loc_address_get_octet(&network->first_address, 3), + loc_address_get_octet(&network->first_address, 2), + loc_address_get_octet(&network->first_address, 1), + loc_address_get_octet(&network->first_address, 0), + suffix); + break; + + case 24: + r = asprintf(&buffer, "*.%d.%d.%d.%s", + loc_address_get_octet(&network->first_address, 2), + loc_address_get_octet(&network->first_address, 1), + loc_address_get_octet(&network->first_address, 0), + suffix); + break; + + case 16: + r = asprintf(&buffer, "*.%d.%d.%s", + loc_address_get_octet(&network->first_address, 1), + loc_address_get_octet(&network->first_address, 0), + suffix); + break; + + case 8: + r = asprintf(&buffer, "*.%d.%s", + loc_address_get_octet(&network->first_address, 0), + suffix); + break; + + case 0: + r = asprintf(&buffer, "*.%s", suffix); + break; + + // To make the compiler happy + default: + return NULL; + } + + if (r < 0) + return NULL; + + return buffer; +} + +LOC_EXPORT char* loc_network_reverse_pointer(struct loc_network* network, const char* suffix) { + switch (network->family) { + case AF_INET6: + return loc_network_reverse_pointer6(network, suffix); + + case AF_INET: + return loc_network_reverse_pointer4(network, suffix); + + default: + break; + } + + return NULL; +} diff --git a/src/python/network.c b/src/python/network.c index 3400721..4bae918 100644 --- a/src/python/network.c +++ b/src/python/network.c @@ -279,6 +279,32 @@ static PyObject* Network_richcompare(NetworkObject* self, PyObject* other, int o Py_RETURN_NOTIMPLEMENTED; } +static PyObject* Network_reverse_pointer(NetworkObject* self, PyObject* args, PyObject* kwargs) { + char* kwlist[] = { "suffix", NULL }; + const char* suffix = NULL; + char* rp = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|z", kwlist, &suffix)) + return NULL; + + rp = loc_network_reverse_pointer(self->network, suffix); + if (!rp) { + switch (errno) { + case ENOTSUP: + Py_RETURN_NONE; + + default: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + } + + PyObject* ret = PyUnicode_FromString(rp); + free(rp); + + return ret; +} + static struct PyMethodDef Network_methods[] = { { "exclude", @@ -298,6 +324,12 @@ static struct PyMethodDef Network_methods[] = { METH_VARARGS, NULL, }, + { + "reverse_pointer", + (PyCFunction)Network_reverse_pointer, + METH_VARARGS|METH_KEYWORDS, + NULL, + }, { "set_flag", (PyCFunction)Network_set_flag, diff --git a/src/test-network.c b/src/test-network.c index f6ccb62..69544e2 100644 --- a/src/test-network.c +++ b/src/test-network.c @@ -29,6 +29,67 @@ #include #include +static int test_reverse_pointers(struct loc_ctx* ctx) { + const struct test { + const char* network; + const char* rp; + } tests[] = { + // IPv6 + { "::1/128", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa." }, + { "2001:db8::/32", "*.8.b.d.0.1.0.0.2.ip6.arpa." }, + + // IPv4 + { "10.0.0.0/32", "0.0.0.10.in-addr.arpa." }, + { "10.0.0.0/24", "*.0.0.10.in-addr.arpa." }, + { "10.0.0.0/16", "*.0.10.in-addr.arpa." }, + { "10.0.0.0/8", "*.10.in-addr.arpa." }, + { "10.0.0.0/0", "*.in-addr.arpa." }, + { "10.0.0.0/1", NULL, }, + { NULL, NULL }, + }; + + struct loc_network* network = NULL; + char* rp = NULL; + int r; + + for (const struct test* test = tests; test->network; test++) { + // Create a new network + r = loc_network_new_from_string(ctx, &network, test->network); + if (r) + return r; + + // Fetch the reverse pointer + rp = loc_network_reverse_pointer(network, NULL); + + // No RP expected and got none + if (!test->rp && !rp) + continue; + + // Got a result when expecting none + else if (!test->rp && rp) { + fprintf(stderr, "Got an RP for %s when expecting none\n", test->network); + return EXIT_FAILURE; + + // Got nothing when expecting a result + } else if (test->rp && !rp) { + fprintf(stderr, "Got no RP for %s when expecting one\n", test->network); + return EXIT_FAILURE; + + // Compare values + } else if (strcmp(test->rp, rp) != 0) { + fprintf(stderr, "Got an unexpected RP for %s: Got %s, expected %s\n", + test->network, rp, test->rp); + return EXIT_FAILURE; + } + + loc_network_unref(network); + if (rp) + free(rp); + } + + return 0; +} + int main(int argc, char** argv) { int err; @@ -336,6 +397,11 @@ int main(int argc, char** argv) { loc_network_unref(network1); } + // Test reverse pointers + err = test_reverse_pointers(ctx); + if (err) + exit(err); + loc_unref(ctx); fclose(f); diff --git a/tests/lua/main.lua b/tests/lua/main.lua index a824513..b45ab1c 100755 --- a/tests/lua/main.lua +++ b/tests/lua/main.lua @@ -158,7 +158,7 @@ function test_list_networks() db = location.Database.open(ENV_TEST_DATABASE) for network in db:list_networks() do - print(network) + print(network, network:reverse_pointer()) end end -- 2.39.2