LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network,
struct in6_addr* address, unsigned int prefix) {
+ struct loc_network* n = NULL;
+
// Validate the prefix
if (!loc_address_valid_prefix(address, prefix)) {
ERROR(ctx, "Invalid prefix in %s: %u\n", loc_address_str(address), prefix);
return 1;
}
- struct loc_network* n = calloc(1, sizeof(*n));
+ // Allocate a new network
+ n = calloc(1, sizeof(*n));
if (!n)
return 1;
n->prefix = prefix;
// Convert the prefix into a bitmask
- struct in6_addr bitmask = loc_prefix_to_bitmask(n->prefix);
+ const struct in6_addr bitmask = loc_prefix_to_bitmask(n->prefix);
// Store the first and last address in the network
n->first_address = loc_address_and(address, &bitmask);
return 0;
}
+unsigned int loc_network_raw_prefix(struct loc_network* network) {
+ return network->prefix;
+}
+
LOC_EXPORT const struct in6_addr* loc_network_get_first_address(struct loc_network* network) {
return &network->first_address;
}
return 0;
}
+int loc_network_properties_cmp(struct loc_network* self, struct loc_network* other) {
+ int r;
+
+ // Check country code
+ r = loc_country_code_cmp(self->country_code, other->country_code);
+ if (r)
+ return r;
+
+ // Check ASN
+ if (self->asn > other->asn)
+ return 1;
+ else if (self->asn < other->asn)
+ return -1;
+
+ // Check flags
+ if (self->flags > other->flags)
+ return 1;
+ else if (self->flags < other->flags)
+ return -1;
+
+ return 0;
+}
+
LOC_EXPORT int loc_network_overlaps(struct loc_network* self, struct loc_network* other) {
// Either of the start addresses must be in the other subnet
if (loc_network_matches_address(self, &other->first_address))
return subnets;
}
+int loc_network_merge(struct loc_network** n,
+ struct loc_network* n1, struct loc_network* n2) {
+ struct loc_network* network = NULL;
+ struct in6_addr address;
+ int r;
+
+ // Reset pointer
+ *n = NULL;
+
+ DEBUG(n1->ctx, "Attempting to merge %s and %s\n", loc_network_str(n1), loc_network_str(n2));
+
+ // Family must match
+ if (n1->family != n2->family)
+ return 0;
+
+ // The prefix must match, too
+ if (n1->prefix != n2->prefix)
+ return 0;
+
+ // Cannot merge ::/0 or 0.0.0.0/0
+ if (!n1->prefix || !n2->prefix)
+ return 0;
+
+ const unsigned int prefix = loc_network_prefix(n1);
+
+ // How many bits do we need to represent this address?
+ const size_t bitlength = loc_address_bit_length(&n1->first_address);
+
+ // We cannot shorten this any more
+ if (bitlength >= prefix) {
+ DEBUG(n1->ctx, "Cannot shorten this any further because we need at least %jd bits,"
+ " but only have %d\n", bitlength, prefix);
+
+ return 0;
+ }
+
+ // Increment the last address of the first network
+ address = n1->last_address;
+ loc_address_increment(&address);
+
+ // If they don't match they are not neighbours
+ if (loc_address_cmp(&address, &n2->first_address) != 0)
+ return 0;
+
+ // All properties must match, too
+ if (loc_network_properties_cmp(n1, n2) != 0)
+ return 0;
+
+ // Create a new network object
+ r = loc_network_new(n1->ctx, &network, &n1->first_address, prefix - 1);
+ if (r)
+ return r;
+
+ // Copy everything else
+ loc_country_code_copy(network->country_code, n1->country_code);
+ network->asn = n1->asn;
+ network->flags = n1->flags;
+
+ // Return pointer
+ *n = network;
+
+ return 0;
+}
+
int loc_network_to_database_v1(struct loc_network* network, struct loc_database_network_v1* dbobj) {
// Add country code
loc_country_code_copy(dbobj->country_code, network->country_code);
return 0;
}
-struct loc_network_tree {
- struct loc_ctx* ctx;
- int refcount;
-
- struct loc_network_tree_node* root;
-};
-
-struct loc_network_tree_node {
- struct loc_ctx* ctx;
- int refcount;
-
- struct loc_network_tree_node* zero;
- struct loc_network_tree_node* one;
-
- struct loc_network* network;
-};
-
-int loc_network_tree_new(struct loc_ctx* ctx, struct loc_network_tree** tree) {
- struct loc_network_tree* t = calloc(1, sizeof(*t));
- if (!t)
- return 1;
-
- t->ctx = loc_ref(ctx);
- t->refcount = 1;
-
- // Create the root node
- int r = loc_network_tree_node_new(ctx, &t->root);
- if (r) {
- loc_network_tree_unref(t);
- return r;
- }
-
- DEBUG(t->ctx, "Network tree allocated at %p\n", t);
- *tree = t;
- return 0;
-}
-
-struct loc_network_tree_node* loc_network_tree_get_root(struct loc_network_tree* tree) {
- return loc_network_tree_node_ref(tree->root);
-}
-
-static struct loc_network_tree_node* loc_network_tree_get_node(struct loc_network_tree_node* node, int path) {
- struct loc_network_tree_node** n;
-
- if (path == 0)
- n = &node->zero;
- else
- n = &node->one;
-
- // If the desired node doesn't exist, yet, we will create it
- if (*n == NULL) {
- int r = loc_network_tree_node_new(node->ctx, n);
- if (r)
- return NULL;
- }
-
- return *n;
-}
+static char* loc_network_reverse_pointer6(struct loc_network* network, const char* suffix) {
+ char* buffer = NULL;
+ int r;
-static struct loc_network_tree_node* loc_network_tree_get_path(struct loc_network_tree* tree, const struct in6_addr* address, unsigned int prefix) {
- struct loc_network_tree_node* node = tree->root;
+ unsigned int prefix = loc_network_prefix(network);
- for (unsigned int i = 0; i < prefix; i++) {
- // Check if the ith bit is one or zero
- node = loc_network_tree_get_node(node, loc_address_get_bit(address, i));
+ // Must border on a nibble
+ if (prefix % 4) {
+ errno = ENOTSUP;
+ return NULL;
}
- return node;
-}
-
-static int __loc_network_tree_walk(struct loc_ctx* ctx, struct loc_network_tree_node* node,
- int(*filter_callback)(struct loc_network* network, void* data),
- int(*callback)(struct loc_network* network, void* data), void* data) {
- int r;
-
- // Finding a network ends the walk here
- if (node->network) {
- if (filter_callback) {
- int f = filter_callback(node->network, data);
- if (f < 0)
- return f;
-
- // Skip network if filter function returns value greater than zero
- if (f > 0)
- return 0;
- }
+ if (!suffix)
+ suffix = "ip6.arpa.";
- r = callback(node->network, data);
- if (r)
- return r;
- }
+ // Initialize the buffer
+ r = asprintf(&buffer, "%s", suffix);
+ if (r < 0)
+ goto ERROR;
- // Walk down on the left side of the tree first
- if (node->zero) {
- r = __loc_network_tree_walk(ctx, node->zero, filter_callback, callback, data);
- if (r)
- return r;
+ 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;
}
- // Then walk on the other side
- if (node->one) {
- r = __loc_network_tree_walk(ctx, node->one, filter_callback, callback, data);
- if (r)
- return r;
+ // Add the asterisk
+ if (prefix < 128) {
+ r = asprintf(&buffer, "*.%s", buffer);
+ if (r < 0)
+ goto ERROR;
}
- return 0;
-}
+ return buffer;
-int loc_network_tree_walk(struct loc_network_tree* tree,
- int(*filter_callback)(struct loc_network* network, void* data),
- int(*callback)(struct loc_network* network, void* data), void* data) {
- return __loc_network_tree_walk(tree->ctx, tree->root, filter_callback, callback, data);
-}
-
-static void loc_network_tree_free(struct loc_network_tree* tree) {
- DEBUG(tree->ctx, "Releasing network tree at %p\n", tree);
-
- loc_network_tree_node_unref(tree->root);
-
- loc_unref(tree->ctx);
- free(tree);
-}
-
-struct loc_network_tree* loc_network_tree_unref(struct loc_network_tree* tree) {
- if (--tree->refcount > 0)
- return tree;
+ERROR:
+ if (buffer)
+ free(buffer);
- loc_network_tree_free(tree);
return NULL;
}
-static int __loc_network_tree_dump(struct loc_network* network, void* data) {
- DEBUG(network->ctx, "Dumping network at %p\n", network);
-
- const char* s = loc_network_str(network);
- if (!s)
- return 1;
-
- INFO(network->ctx, "%s\n", s);
-
- return 0;
-}
-
-int loc_network_tree_dump(struct loc_network_tree* tree) {
- DEBUG(tree->ctx, "Dumping network tree at %p\n", tree);
-
- return loc_network_tree_walk(tree, NULL, __loc_network_tree_dump, NULL);
-}
+static char* loc_network_reverse_pointer4(struct loc_network* network, const char* suffix) {
+ char* buffer = NULL;
+ int r;
-int loc_network_tree_add_network(struct loc_network_tree* tree, struct loc_network* network) {
- DEBUG(tree->ctx, "Adding network %p to tree %p\n", network, tree);
+ unsigned int prefix = loc_network_prefix(network);
- struct loc_network_tree_node* node = loc_network_tree_get_path(tree,
- &network->first_address, network->prefix);
- if (!node) {
- ERROR(tree->ctx, "Could not find a node\n");
- return -ENOMEM;
+ // Must border on an octet
+ if (prefix % 8) {
+ errno = ENOTSUP;
+ return NULL;
}
- // Check if node has not been set before
- if (node->network) {
- DEBUG(tree->ctx, "There is already a network at this path\n");
- return -EBUSY;
+ 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;
}
- // Point node to the network
- node->network = loc_network_ref(network);
-
- return 0;
-}
-
-static size_t __loc_network_tree_count_nodes(struct loc_network_tree_node* node) {
- size_t counter = 1;
-
- if (node->zero)
- counter += __loc_network_tree_count_nodes(node->zero);
-
- if (node->one)
- counter += __loc_network_tree_count_nodes(node->one);
-
- return counter;
-}
-
-size_t loc_network_tree_count_nodes(struct loc_network_tree* tree) {
- return __loc_network_tree_count_nodes(tree->root);
-}
-
-int loc_network_tree_node_new(struct loc_ctx* ctx, struct loc_network_tree_node** node) {
- struct loc_network_tree_node* n = calloc(1, sizeof(*n));
- if (!n)
- return -ENOMEM;
-
- n->ctx = loc_ref(ctx);
- n->refcount = 1;
-
- n->zero = n->one = NULL;
-
- DEBUG(n->ctx, "Network node allocated at %p\n", n);
- *node = n;
- return 0;
-}
-
-struct loc_network_tree_node* loc_network_tree_node_ref(struct loc_network_tree_node* node) {
- if (node)
- node->refcount++;
+ if (r < 0)
+ return NULL;
- return node;
+ return buffer;
}
-static void loc_network_tree_node_free(struct loc_network_tree_node* node) {
- DEBUG(node->ctx, "Releasing network node at %p\n", node);
-
- if (node->network)
- loc_network_unref(node->network);
-
- if (node->zero)
- loc_network_tree_node_unref(node->zero);
-
- if (node->one)
- loc_network_tree_node_unref(node->one);
+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);
- loc_unref(node->ctx);
- free(node);
-}
+ case AF_INET:
+ return loc_network_reverse_pointer4(network, suffix);
-struct loc_network_tree_node* loc_network_tree_node_unref(struct loc_network_tree_node* node) {
- if (--node->refcount > 0)
- return node;
+ default:
+ break;
+ }
- loc_network_tree_node_free(node);
return NULL;
}
-
-struct loc_network_tree_node* loc_network_tree_node_get(struct loc_network_tree_node* node, unsigned int index) {
- if (index == 0)
- node = node->zero;
- else
- node = node->one;
-
- if (!node)
- return NULL;
-
- return loc_network_tree_node_ref(node);
-}
-
-int loc_network_tree_node_is_leaf(struct loc_network_tree_node* node) {
- return (!!node->network);
-}
-
-struct loc_network* loc_network_tree_node_get_network(struct loc_network_tree_node* node) {
- return loc_network_ref(node->network);
-}