2 libloc - A library to determine the location of someone on the Internet
4 Copyright (C) 2022 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>
18 #include <netinet/in.h>
24 #include <libloc/address.h>
25 #include <libloc/compat.h>
27 #define LOC_ADDRESS_BUFFERS 6
28 #define LOC_ADDRESS_BUFFER_LENGTH INET6_ADDRSTRLEN
30 static char __loc_address_buffers
[LOC_ADDRESS_BUFFERS
][LOC_ADDRESS_BUFFER_LENGTH
+ 1];
31 static int __loc_address_buffer_idx
= 0;
33 static const char* __loc_address6_str(const struct in6_addr
* address
, char* buffer
, size_t length
) {
34 return inet_ntop(AF_INET6
, address
, buffer
, length
);
37 static const char* __loc_address4_str(const struct in6_addr
* address
, char* buffer
, size_t length
) {
38 struct in_addr address4
= {
39 .s_addr
= address
->s6_addr32
[3],
42 return inet_ntop(AF_INET
, &address4
, buffer
, length
);
45 const char* loc_address_str(const struct in6_addr
* address
) {
50 char* buffer
= __loc_address_buffers
[__loc_address_buffer_idx
++];
52 // Prevent index from overflow
53 __loc_address_buffer_idx
%= LOC_ADDRESS_BUFFERS
;
55 if (IN6_IS_ADDR_V4MAPPED(address
))
56 return __loc_address4_str(address
, buffer
, LOC_ADDRESS_BUFFER_LENGTH
);
58 return __loc_address6_str(address
, buffer
, LOC_ADDRESS_BUFFER_LENGTH
);
61 static void loc_address_from_address4(struct in6_addr
* address
,
62 const struct in_addr
* address4
) {
63 address
->s6_addr32
[0] = 0;
64 address
->s6_addr32
[1] = 0;
65 address
->s6_addr32
[2] = htonl(0xffff);
66 address
->s6_addr32
[3] = address4
->s_addr
;
69 int loc_address_parse(struct in6_addr
* address
, unsigned int* prefix
, const char* string
) {
70 char buffer
[INET6_ADDRSTRLEN
+ 4];
73 if (!address
|| !string
) {
78 // Copy the string into the buffer
79 r
= snprintf(buffer
, sizeof(buffer
) - 1, "%s", string
);
84 char* p
= strchr(buffer
, '/');
86 // Terminate the IP address
90 int family
= AF_UNSPEC
;
92 // Try parsing as an IPv6 address
93 r
= inet_pton(AF_INET6
, buffer
, address
);
95 // This is not a valid IPv6 address
99 // This is a valid IPv6 address
109 // Try parsing as an IPv4 address
111 struct in_addr address4
;
113 r
= inet_pton(AF_INET
, buffer
, &address4
);
115 // This was not a valid IPv4 address
119 // This was a valid IPv4 address
124 loc_address_from_address4(address
, &address4
);
134 if (family
== AF_UNSPEC
) {
139 // Did the user request a prefix?
141 // Set the prefix to the default value
142 const unsigned int max_prefix
= loc_address_family_bit_length(family
);
144 // Parse the actual string
146 *prefix
= strtol(p
, NULL
, 10);
148 // Check if prefix is within bounds
149 if (*prefix
> max_prefix
) {
154 // If the string didn't contain a prefix, we set the maximum
156 *prefix
= max_prefix
;