src_libloc_la_SOURCES = \
src/libloc.c \
+ src/address.c \
src/as.c \
src/as-list.c \
src/country.c \
--- /dev/null
+/*
+ libloc - A library to determine the location of someone on the Internet
+
+ Copyright (C) 2022 IPFire Development Team <info@ipfire.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stddef.h>
+
+#include <libloc/address.h>
+
+#define LOC_ADDRESS_BUFFERS 6
+#define LOC_ADDRESS_BUFFER_LENGTH INET6_ADDRSTRLEN
+
+static char __loc_address_buffers[LOC_ADDRESS_BUFFER_LENGTH + 1][LOC_ADDRESS_BUFFERS];
+static int __loc_address_buffer_idx = 0;
+
+static const char* __loc_address6_str(const struct in6_addr* address, char* buffer, size_t length) {
+ return inet_ntop(AF_INET6, address, buffer, length);
+}
+
+static const char* __loc_address4_str(const struct in6_addr* address, char* buffer, size_t length) {
+ struct in_addr address4 = {
+ .s_addr = address->s6_addr32[3],
+ };
+
+ return inet_ntop(AF_INET, &address4, buffer, length);
+}
+
+const char* loc_address_str(const struct in6_addr* address) {
+ if (!address)
+ return NULL;
+
+ // Select buffer
+ char* buffer = __loc_address_buffers[__loc_address_buffer_idx++];
+
+ // Prevent index from overflow
+ __loc_address_buffer_idx %= LOC_ADDRESS_BUFFERS;
+
+ if (IN6_IS_ADDR_V4MAPPED(address))
+ return __loc_address4_str(address, buffer, LOC_ADDRESS_BUFFER_LENGTH);
+ else
+ return __loc_address6_str(address, buffer, LOC_ADDRESS_BUFFER_LENGTH);
+}
return -1;
}
-#ifdef ENABLE_DEBUG
- if (r == 0) {
- char* string = loc_network_str(*network);
- DEBUG(db->ctx, "Got network %s\n", string);
- free(string);
- }
-#endif
+ if (r == 0)
+ DEBUG(db->ctx, "Got network %s\n", loc_network_str(*network));
return r;
}
All of these functions are private and for internal use only
*/
+const char* loc_address_str(const struct in6_addr* address);
+
static inline int loc_address_family(const struct in6_addr* address) {
if (IN6_IS_ADDR_V4MAPPED(address))
return AF_INET;
const char* address_string);
struct loc_network* loc_network_ref(struct loc_network* network);
struct loc_network* loc_network_unref(struct loc_network* network);
-char* loc_network_str(struct loc_network* network);
+const char* loc_network_str(struct loc_network* network);
int loc_network_address_family(struct loc_network* network);
unsigned int loc_network_prefix(struct loc_network* network);
const struct in6_addr* loc_network_get_first_address(struct loc_network* network);
-char* loc_network_format_first_address(struct loc_network* network);
+const char* loc_network_format_first_address(struct loc_network* network);
const struct in6_addr* loc_network_get_last_address(struct loc_network* network);
-char* loc_network_format_last_address(struct loc_network* network);
+const char* loc_network_format_last_address(struct loc_network* network);
int loc_network_matches_address(struct loc_network* network, const struct in6_addr* address);
const char* loc_network_get_country_code(struct loc_network* network);
LOC_EXPORT void loc_network_list_dump(struct loc_network_list* list) {
struct loc_network* network;
- char* s;
for (unsigned int i = 0; i < list->size; i++) {
network = list->elements[i];
- s = loc_network_str(network);
-
- INFO(list->ctx, "%4d: %s\n", i, s);
- free(s);
+ INFO(list->ctx, "%4d: %s\n",
+ i, loc_network_str(network));
}
}
return 1;
}
+ DEBUG(ctx, "Summarizing %s - %s\n", loc_address_str(first), loc_address_str(last));
+
const int family1 = loc_address_family(first);
const int family2 = loc_address_family(last);
// Select the smaller one
int bits = (bits1 > bits2) ? bits2 : bits1;
+ printf("prefix = %d, bits1 = %d, bits2 = %d\n", family_bit_length, bits1, bits2);
+
// Create a network
r = loc_network_new(ctx, &network, &start, family_bit_length - bits);
if (r)
return r;
#ifdef ENABLE_DEBUG
- char* n = loc_network_str(network);
+ const char* n = loc_network_str(network);
if (n) {
DEBUG(ctx, "Found network %s\n", n);
- free(n);
}
#endif
char country_code[3];
uint32_t asn;
enum loc_network_flags flags;
+
+ char string[INET6_ADDRSTRLEN + 4];
};
LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network,
return NULL;
}
-static int format_ipv6_address(const struct in6_addr* address, char* string, size_t length) {
- const char* ret = inet_ntop(AF_INET6, address, string, length);
- if (!ret)
- return -1;
-
- return 0;
-}
-
-static int format_ipv4_address(const struct in6_addr* address, char* string, size_t length) {
- struct in_addr ipv4_address;
- ipv4_address.s_addr = address->s6_addr32[3];
-
- const char* ret = inet_ntop(AF_INET, &ipv4_address, string, length);
- if (!ret)
- return -1;
-
- return 0;
-}
-
-LOC_EXPORT char* loc_network_str(struct loc_network* network) {
- int r;
- const size_t length = INET6_ADDRSTRLEN + 4;
-
- char* string = malloc(length);
- if (!string)
- return NULL;
-
- unsigned int prefix = network->prefix;
-
- switch (network->family) {
- case AF_INET6:
- r = format_ipv6_address(&network->first_address, string, length);
- break;
-
- case AF_INET:
- r = format_ipv4_address(&network->first_address, string, length);
- prefix -= 96;
- break;
-
- default:
- r = -1;
- break;
- }
+LOC_EXPORT const char* loc_network_str(struct loc_network* network) {
+ if (!*network->string) {
+ // Format the address
+ const char* address = loc_address_str(&network->first_address);
+ if (!address)
+ return NULL;
- if (r) {
- ERROR(network->ctx, "Could not convert network to string: %s\n", strerror(errno));
- free(string);
+ // Fetch the prefix
+ unsigned int prefix = loc_network_prefix(network);
- return NULL;
+ // Format the string
+ int r = snprintf(network->string, sizeof(network->string) - 1,
+ "%s/%u", address, prefix);
+ if (r < 0) {
+ ERROR(network->ctx, "Could not format network string: %m\n");
+ *network->string = '\0';
+ return NULL;
+ }
}
- // Append prefix
- sprintf(string + strlen(string), "/%u", prefix);
-
- return string;
+ return network->string;
}
LOC_EXPORT int loc_network_address_family(struct loc_network* network) {
return 0;
}
-static char* loc_network_format_address(struct loc_network* network, const struct in6_addr* address) {
- const size_t length = INET6_ADDRSTRLEN;
-
- char* string = malloc(length);
- if (!string)
- return NULL;
-
- int r = 0;
-
- switch (network->family) {
- case AF_INET6:
- r = format_ipv6_address(address, string, length);
- break;
-
- case AF_INET:
- r = format_ipv4_address(address, string, length);
- break;
-
- default:
- r = -1;
- break;
- }
-
- if (r) {
- ERROR(network->ctx, "Could not format IP address to string: %s\n", strerror(errno));
- free(string);
-
- return NULL;
- }
-
- return string;
-}
-
LOC_EXPORT const struct in6_addr* loc_network_get_first_address(struct loc_network* network) {
return &network->first_address;
}
-LOC_EXPORT char* loc_network_format_first_address(struct loc_network* network) {
- return loc_network_format_address(network, &network->first_address);
+LOC_EXPORT const char* loc_network_format_first_address(struct loc_network* network) {
+ return loc_address_str(&network->first_address);
}
LOC_EXPORT const struct in6_addr* loc_network_get_last_address(struct loc_network* network) {
return &network->last_address;
}
-LOC_EXPORT char* loc_network_format_last_address(struct loc_network* network) {
- return loc_network_format_address(network, &network->last_address);
+LOC_EXPORT const char* loc_network_format_last_address(struct loc_network* network) {
+ return loc_address_str(&network->last_address);
}
LOC_EXPORT int loc_network_matches_address(struct loc_network* network, const struct in6_addr* address) {
struct loc_network* self, struct loc_network* other) {
struct loc_network_list* list;
-#ifdef ENABLE_DEBUG
- char* n1 = loc_network_str(self);
- char* n2 = loc_network_str(other);
-
- DEBUG(self->ctx, "Returning %s excluding %s...\n", n1, n2);
-
- free(n1);
- free(n2);
-#endif
+ DEBUG(self->ctx, "Returning %s excluding %s...\n",
+ loc_network_str(self), loc_network_str(other));
// Create a new list with the result
int r = loc_network_list_new(self->ctx, &list);
static int __loc_network_tree_dump(struct loc_network* network, void* data) {
DEBUG(network->ctx, "Dumping network at %p\n", network);
- char* s = loc_network_str(network);
+ const char* s = loc_network_str(network);
if (!s)
return 1;
INFO(network->ctx, "%s\n", s);
- free(s);
return 0;
}
}
static PyObject* Network_repr(NetworkObject* self) {
- char* network = loc_network_str(self->network);
+ const char* network = loc_network_str(self->network);
- PyObject* obj = PyUnicode_FromFormat("<location.Network %s>", network);
- free(network);
-
- return obj;
+ return PyUnicode_FromFormat("<location.Network %s>", network);
}
static PyObject* Network_str(NetworkObject* self) {
- char* network = loc_network_str(self->network);
+ const char* network = loc_network_str(self->network);
- PyObject* obj = PyUnicode_FromString(network);
- free(network);
-
- return obj;
+ return PyUnicode_FromString(network);
}
static PyObject* Network_get_country_code(NetworkObject* self) {
}
static PyObject* Network_get_first_address(NetworkObject* self) {
- char* address = loc_network_format_first_address(self->network);
+ const char* address = loc_network_format_first_address(self->network);
- PyObject* obj = PyUnicode_FromString(address);
- free(address);
-
- return obj;
+ return PyUnicode_FromString(address);
}
static PyObject* PyBytes_FromAddress(const struct in6_addr* address6) {
}
static PyObject* Network_get_last_address(NetworkObject* self) {
- char* address = loc_network_format_last_address(self->network);
+ const char* address = loc_network_format_last_address(self->network);
- PyObject* obj = PyUnicode_FromString(address);
- free(address);
-
- return obj;
+ return PyUnicode_FromString(address);
}
static PyObject* Network_get__last_address(NetworkObject* self) {
if (!network)
break;
- char* s = loc_network_str(network);
+ const char* s = loc_network_str(network);
printf("Got network: %s\n", s);
- free(s);
}
// Free the enumerator
#endif
// Check if the first and last addresses are correct
- char* string = loc_network_format_first_address(network1);
+ const char* string = loc_network_format_first_address(network1);
if (!string) {
fprintf(stderr, "Did get NULL instead of a string for the first address\n");
exit(EXIT_FAILURE);
exit(EXIT_FAILURE);
}
- char* s = loc_network_str(subnet1);
+ const char* s = loc_network_str(subnet1);
printf("Received subnet1 = %s\n", s);
- free(s);
s = loc_network_str(subnet2);
printf("Received subnet2 = %s\n", s);
- free(s);
if (!loc_network_is_subnet(network1, subnet1)) {
fprintf(stderr, "Subnet1 is not a subnet\n");