]>
git.ipfire.org Git - people/ms/libloc.git/blob - src/network.c
bf11f2a68b46c360ed1ed5caf4404309c086f20c
2 libloc - A library to determine the location of someone on the Internet
4 Copyright (C) 2017 IPFire Development Team <info@ipfire.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
17 #include <arpa/inet.h>
23 #include <loc/libloc.h>
24 #include <loc/network.h>
26 #include "libloc-private.h"
33 struct in6_addr start_address
;
41 LOC_EXPORT
int loc_network_new(struct loc_ctx
* ctx
, struct loc_network
** network
,
42 struct in6_addr start_address
, unsigned int prefix
) {
43 // Address cannot be unspecified
44 if (IN6_IS_ADDR_UNSPECIFIED(&start_address
)) {
45 DEBUG(ctx
, "Start address is unspecified\n");
49 // Address cannot be loopback
50 if (IN6_IS_ADDR_LOOPBACK(&start_address
)) {
51 DEBUG(ctx
, "Start address is loopback address\n");
55 // Address cannot be link-local
56 if (IN6_IS_ADDR_LINKLOCAL(&start_address
)) {
57 DEBUG(ctx
, "Start address cannot be link-local\n");
61 // Address cannot be site-local
62 if (IN6_IS_ADDR_SITELOCAL(&start_address
)) {
63 DEBUG(ctx
, "Start address cannot be site-local\n");
67 struct loc_network
* n
= calloc(1, sizeof(*n
));
71 n
->ctx
= loc_ref(ctx
);
74 n
->start_address
= start_address
;
77 DEBUG(n
->ctx
, "Network allocated at %p\n", n
);
82 LOC_EXPORT
int loc_network_new_from_string(struct loc_ctx
* ctx
, struct loc_network
** network
,
83 const char* address_string
) {
84 struct in6_addr start_address
;
87 // Make a copy of the string to work on it
88 char* buffer
= strdup(address_string
);
89 address_string
= prefix_string
= buffer
;
91 // Split address and prefix
92 address_string
= strsep(&prefix_string
, "/");
94 // Convert prefix to integer
95 unsigned int prefix
= strtol(prefix_string
, NULL
, 10);
98 int r
= inet_pton(AF_INET6
, address_string
, &start_address
);
100 // Free temporary buffer
104 r
= loc_network_new(ctx
, network
, start_address
, prefix
);
110 LOC_EXPORT
struct loc_network
* loc_network_ref(struct loc_network
* network
) {
116 static void loc_network_free(struct loc_network
* network
) {
117 DEBUG(network
->ctx
, "Releasing network at %p\n", network
);
120 loc_as_unref(network
->as
);
122 loc_unref(network
->ctx
);
126 LOC_EXPORT
struct loc_network
* loc_network_unref(struct loc_network
* network
) {
127 if (--network
->refcount
> 0)
130 loc_network_free(network
);
134 LOC_EXPORT
char* loc_network_str(struct loc_network
* network
) {
135 const size_t l
= INET6_ADDRSTRLEN
+ 3;
137 char* string
= malloc(l
);
141 const char* ret
= inet_ntop(AF_INET6
, &network
->start_address
, string
, l
);
143 ERROR(network
->ctx
, "Could not convert network to string: %s\n", strerror(errno
));
150 sprintf(string
+ strlen(string
), "/%u", network
->prefix
);
155 LOC_EXPORT
const char* loc_network_get_country_code(struct loc_network
* network
) {
156 return network
->country_code
;
159 LOC_EXPORT
int loc_network_set_country_code(struct loc_network
* network
, const char* country_code
) {
160 // Country codes must be two characters
161 if (strlen(country_code
) != 2)
164 for (unsigned int i
= 0; i
< 3; i
++) {
165 network
->country_code
[i
] = country_code
[i
];
171 struct loc_network_tree
{
175 struct loc_network_tree_node
* root
;
178 struct loc_network_tree_node
{
179 struct loc_network_tree_node
* zero
;
180 struct loc_network_tree_node
* one
;
182 struct loc_network
* network
;
185 LOC_EXPORT
int loc_network_tree_new(struct loc_ctx
* ctx
, struct loc_network_tree
** tree
) {
186 struct loc_network_tree
* t
= calloc(1, sizeof(*t
));
190 t
->ctx
= loc_ref(ctx
);
193 // Create the root node
194 t
->root
= calloc(1, sizeof(*t
->root
));
196 DEBUG(t
->ctx
, "Network tree allocated at %p\n", t
);
201 static int loc_network_tree_node_new(struct loc_network_tree_node
** node
) {
202 struct loc_network_tree_node
* n
= calloc(1, sizeof(*n
));
206 n
->zero
= n
->one
= NULL
;
212 static struct loc_network_tree_node
* loc_network_tree_get_node(struct loc_network_tree_node
* node
, int path
) {
213 struct loc_network_tree_node
** n
;
220 // If the desired node doesn't exist, yet, we will create it
222 int r
= loc_network_tree_node_new(n
);
230 static struct loc_network_tree_node
* loc_network_tree_get_path(struct loc_network_tree
* tree
, const struct in6_addr
* address
) {
231 struct loc_network_tree_node
* node
= tree
->root
;
233 for (unsigned int i
= 127; i
> 0; i
--) {
234 // Check if the ith bit is one or zero
235 node
= loc_network_tree_get_node(node
, ((address
->s6_addr32
[i
/ 32] & (1 << (i
% 32))) == 0));
241 static int __loc_network_tree_walk(struct loc_ctx
* ctx
, struct loc_network_tree_node
* node
,
242 int(*filter_callback
)(struct loc_network
* network
), int(*callback
)(struct loc_network
* network
)) {
245 // Finding a network ends the walk here
247 if (filter_callback
) {
248 int f
= filter_callback(node
->network
);
252 // Skip network if filter function returns value greater than zero
257 r
= callback(node
->network
);
262 // Walk down on the left side of the tree first
264 r
= __loc_network_tree_walk(ctx
, node
->zero
, filter_callback
, callback
);
269 // Then walk on the other side
271 r
= __loc_network_tree_walk(ctx
, node
->one
, filter_callback
, callback
);
279 static void loc_network_tree_free_subtree(struct loc_network_tree_node
* node
) {
281 loc_network_unref(node
->network
);
284 loc_network_tree_free_subtree(node
->zero
);
287 loc_network_tree_free_subtree(node
->one
);
292 static void loc_network_tree_free(struct loc_network_tree
* tree
) {
293 DEBUG(tree
->ctx
, "Releasing network tree at %p\n", tree
);
295 loc_network_tree_free_subtree(tree
->root
);
297 loc_unref(tree
->ctx
);
301 LOC_EXPORT
struct loc_network_tree
* loc_network_tree_unref(struct loc_network_tree
* tree
) {
302 if (--tree
->refcount
> 0)
305 loc_network_tree_free(tree
);
309 int __loc_network_tree_dump(struct loc_network
* network
) {
310 DEBUG(network
->ctx
, "Dumping network at %p\n", network
);
312 char* s
= loc_network_str(network
);
316 INFO(network
->ctx
, "%s\n", s
);
322 LOC_EXPORT
int loc_network_tree_dump(struct loc_network_tree
* tree
) {
323 DEBUG(tree
->ctx
, "Dumping network tree at %p\n", tree
);
325 return __loc_network_tree_walk(tree
->ctx
, tree
->root
, NULL
, __loc_network_tree_dump
);
328 LOC_EXPORT
int loc_network_tree_add_network(struct loc_network_tree
* tree
, struct loc_network
* network
) {
329 DEBUG(tree
->ctx
, "Adding network %p to tree %p\n", network
, tree
);
331 struct loc_network_tree_node
* node
= loc_network_tree_get_path(tree
, &network
->start_address
);
333 ERROR(tree
->ctx
, "Could not find a node\n");
337 // Check if node has not been set before
339 DEBUG(tree
->ctx
, "There is already a network at this path\n");
343 // Point node to the network
344 node
->network
= loc_network_ref(network
);