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>
26 #define LOC_ADDRESS_BUFFERS 6
27 #define LOC_ADDRESS_BUFFER_LENGTH INET6_ADDRSTRLEN
29 static char __loc_address_buffers
[LOC_ADDRESS_BUFFERS
][LOC_ADDRESS_BUFFER_LENGTH
+ 1];
30 static int __loc_address_buffer_idx
= 0;
32 static const char* __loc_address6_str(const struct in6_addr
* address
, char* buffer
, size_t length
) {
33 return inet_ntop(AF_INET6
, address
, buffer
, length
);
36 static const char* __loc_address4_str(const struct in6_addr
* address
, char* buffer
, size_t length
) {
37 struct in_addr address4
= {
38 .s_addr
= address
->s6_addr32
[3],
41 return inet_ntop(AF_INET
, &address4
, buffer
, length
);
44 const char* loc_address_str(const struct in6_addr
* address
) {
49 char* buffer
= __loc_address_buffers
[__loc_address_buffer_idx
++];
51 // Prevent index from overflow
52 __loc_address_buffer_idx
%= LOC_ADDRESS_BUFFERS
;
54 if (IN6_IS_ADDR_V4MAPPED(address
))
55 return __loc_address4_str(address
, buffer
, LOC_ADDRESS_BUFFER_LENGTH
);
57 return __loc_address6_str(address
, buffer
, LOC_ADDRESS_BUFFER_LENGTH
);
60 static void loc_address_from_address4(struct in6_addr
* address
,
61 const struct in_addr
* address4
) {
62 address
->s6_addr32
[0] = 0;
63 address
->s6_addr32
[1] = 0;
64 address
->s6_addr32
[2] = htonl(0xffff);
65 address
->s6_addr32
[3] = address4
->s_addr
;
68 int loc_address_parse(struct in6_addr
* address
, unsigned int* prefix
, const char* string
) {
69 char buffer
[INET6_ADDRSTRLEN
+ 4];
72 if (!address
|| !string
) {
77 // Copy the string into the buffer
78 r
= snprintf(buffer
, sizeof(buffer
) - 1, "%s", string
);
83 char* p
= strchr(buffer
, '/');
85 // Terminate the IP address
89 int family
= AF_UNSPEC
;
91 // Try parsing as an IPv6 address
92 r
= inet_pton(AF_INET6
, buffer
, address
);
94 // This is not a valid IPv6 address
98 // This is a valid IPv6 address
108 // Try parsing as an IPv4 address
110 struct in_addr address4
;
112 r
= inet_pton(AF_INET
, buffer
, &address4
);
114 // This was not a valid IPv4 address
118 // This was a valid IPv4 address
123 loc_address_from_address4(address
, &address4
);
133 if (family
== AF_UNSPEC
) {
138 // Did the user request a prefix?
140 // Set the prefix to the default value
141 *prefix
= loc_address_family_bit_length(family
);
143 // Parse the actual string
145 *prefix
= strtol(p
, NULL
, 10);