local:
*;
};
+
+LIBLOC_2 {
+global:
+ loc_network_reverse_pointer;
+local:
+ *;
+} LIBLOC_1;
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);
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 },
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;
+}
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",
METH_VARARGS,
NULL,
},
+ {
+ "reverse_pointer",
+ (PyCFunction)Network_reverse_pointer,
+ METH_VARARGS|METH_KEYWORDS,
+ NULL,
+ },
{
"set_flag",
(PyCFunction)Network_set_flag,
#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;
loc_network_unref(network1);
}
+ // Test reverse pointers
+ err = test_reverse_pointers(ctx);
+ if (err)
+ exit(err);
+
loc_unref(ctx);
fclose(f);
db = location.Database.open(ENV_TEST_DATABASE)
for network in db:list_networks() do
- print(network)
+ print(network, network:reverse_pointer())
end
end