]> git.ipfire.org Git - people/ms/libloc.git/commitdiff
network: Add function to return a reverse pointer for networks
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 6 Apr 2024 10:49:41 +0000 (10:49 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 6 Apr 2024 10:49:41 +0000 (10:49 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libloc.sym
src/libloc/network.h
src/lua/network.c
src/network.c
src/python/network.c
src/test-network.c
tests/lua/main.lua

index 29e17f0caad20a54206cf7721d2bd9eaff006b79..50734b3b26bc6dc12b5f4cf7acbff0a490593b18 100644 (file)
@@ -146,3 +146,10 @@ global:
 local:
        *;
 };
+
+LIBLOC_2 {
+global:
+       loc_network_reverse_pointer;
+local:
+       *;
+} LIBLOC_1;
index 62334acd3999d0274db2ef58d40ce2caa49d7c8c..6f2dad2285b37a008646ec3ce8fd2e78a0526d23 100644 (file)
@@ -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);
index a25166e23b8946f895c15f0c77be10adb0925c07..15936f78e6ac18a364ef3e81abd7690f2b1a33ad 100644 (file)
@@ -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 },
index d658709f9dba3eae5be2ec38a0895327f2f45528..69306a91f4b18ed0be8f4280373b34bbb7496c81 100644 (file)
@@ -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;
+}
index 3400721271b39e34b7245f2e48d4d11932eee7d6..4bae918f3f06997fd4bde05eacd636eb489c30a3 100644 (file)
@@ -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,
index f6ccb626a9e9c75192f2867365c42110f51c232f..69544e29628bc32febc981ba3fa1f9dbc8dd2a24 100644 (file)
 #include <libloc/private.h>
 #include <libloc/writer.h>
 
+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);
 
index a824513ee83d2af202155632d8bce0c5a66865a8..b45ab1c41474cdc83b288d55d40d149ea17fd048 100755 (executable)
@@ -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