]> git.ipfire.org Git - people/ms/libloc.git/blob - src/libloc/address.h
f4c0ee330bc0df62b1dfcc4a2476800d081d2bc2
[people/ms/libloc.git] / src / libloc / address.h
1 /*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2022 IPFire Development Team <info@ipfire.org>
5
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.
10
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.
15 */
16
17 #ifndef LIBLOC_ADDRESS_H
18 #define LIBLOC_ADDRESS_H
19
20 #ifdef LIBLOC_PRIVATE
21
22 #include <errno.h>
23 #include <netinet/in.h>
24
25 #include <libloc/compat.h>
26
27 /*
28 All of these functions are private and for internal use only
29 */
30
31 const char* loc_address_str(const struct in6_addr* address);
32 int loc_address_parse(struct in6_addr* address, unsigned int* prefix, const char* string);
33
34 static inline int loc_address_family(const struct in6_addr* address) {
35 if (IN6_IS_ADDR_V4MAPPED(address))
36 return AF_INET;
37 else
38 return AF_INET6;
39 }
40
41 static inline unsigned int loc_address_family_bit_length(const int family) {
42 switch (family) {
43 case AF_INET6:
44 return 128;
45
46 case AF_INET:
47 return 32;
48
49 default:
50 return 0;
51 }
52 }
53
54 /*
55 Checks whether prefix is valid for the given address
56 */
57 static inline int loc_address_valid_prefix(const struct in6_addr* address, unsigned int prefix) {
58 const int family = loc_address_family(address);
59
60 // What is the largest possible prefix?
61 const unsigned int bit_length = loc_address_family_bit_length(family);
62
63 if (prefix <= bit_length)
64 return 1;
65
66 return 0;
67 }
68
69 static inline int loc_address_cmp(const struct in6_addr* a1, const struct in6_addr* a2) {
70 for (unsigned int i = 0; i < 16; i++) {
71 if (a1->s6_addr[i] > a2->s6_addr[i])
72 return 1;
73
74 else if (a1->s6_addr[i] < a2->s6_addr[i])
75 return -1;
76 }
77
78 return 0;
79 }
80
81 #define foreach_octet_in_address(octet, address) \
82 for (octet = (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet <= 15; octet++)
83
84 #define foreach_octet_in_address_reverse(octet, address) \
85 for (octet = 15; octet >= (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet--)
86
87 static inline int loc_address_all_zeroes(const struct in6_addr* address) {
88 int octet = 0;
89
90 foreach_octet_in_address(octet, address) {
91 if (address->s6_addr[octet])
92 return 0;
93 }
94
95 return 1;
96 }
97
98 static inline int loc_address_all_ones(const struct in6_addr* address) {
99 int octet = 0;
100
101 foreach_octet_in_address(octet, address) {
102 if (address->s6_addr[octet] < 255)
103 return 0;
104 }
105
106 return 1;
107 }
108
109 static inline int loc_address_get_bit(const struct in6_addr* address, unsigned int i) {
110 return ((address->s6_addr[i / 8] >> (7 - (i % 8))) & 1);
111 }
112
113 static inline void loc_address_set_bit(struct in6_addr* address, unsigned int i, unsigned int val) {
114 address->s6_addr[i / 8] ^= (-val ^ address->s6_addr[i / 8]) & (1 << (7 - (i % 8)));
115 }
116
117 static inline struct in6_addr loc_prefix_to_bitmask(const unsigned int prefix) {
118 struct in6_addr bitmask;
119
120 for (unsigned int i = 0; i < 16; i++)
121 bitmask.s6_addr[i] = 0;
122
123 for (int i = prefix, j = 0; i > 0; i -= 8, j++) {
124 if (i >= 8)
125 bitmask.s6_addr[j] = 0xff;
126 else
127 bitmask.s6_addr[j] = 0xff << (8 - i);
128 }
129
130 return bitmask;
131 }
132
133 static inline unsigned int loc_address_bit_length(const struct in6_addr* address) {
134 int octet = 0;
135 foreach_octet_in_address(octet, address) {
136 if (address->s6_addr[octet])
137 return (15 - octet) * 8 + 32 - __builtin_clz(address->s6_addr[octet]);
138 }
139
140 return 0;
141 }
142
143 static inline int loc_address_reset(struct in6_addr* address, int family) {
144 switch (family) {
145 case AF_INET6:
146 address->s6_addr32[0] = 0x00000000;
147 address->s6_addr32[1] = 0x00000000;
148 address->s6_addr32[2] = 0x00000000;
149 address->s6_addr32[3] = 0x00000000;
150 return 0;
151
152 case AF_INET:
153 address->s6_addr32[0] = 0x00000000;
154 address->s6_addr32[1] = 0x00000000;
155 address->s6_addr32[2] = htonl(0xffff);
156 address->s6_addr32[3] = 0x00000000;
157 return 0;
158 }
159
160 return -1;
161 }
162
163 static inline int loc_address_reset_last(struct in6_addr* address, int family) {
164 switch (family) {
165 case AF_INET6:
166 address->s6_addr32[0] = 0xffffffff;
167 address->s6_addr32[1] = 0xffffffff;
168 address->s6_addr32[2] = 0xffffffff;
169 address->s6_addr32[3] = 0xffffffff;
170 return 0;
171
172 case AF_INET:
173 address->s6_addr32[0] = 0x00000000;
174 address->s6_addr32[1] = 0x00000000;
175 address->s6_addr32[2] = htonl(0xffff);
176 address->s6_addr32[3] = 0xffffffff;
177 return 0;
178 }
179
180 return -1;
181 }
182
183 static inline struct in6_addr loc_address_and(
184 const struct in6_addr* address, const struct in6_addr* bitmask) {
185 struct in6_addr a;
186
187 // Perform bitwise AND
188 for (unsigned int i = 0; i < 4; i++)
189 a.s6_addr32[i] = address->s6_addr32[i] & bitmask->s6_addr32[i];
190
191 return a;
192 }
193
194 static inline struct in6_addr loc_address_or(
195 const struct in6_addr* address, const struct in6_addr* bitmask) {
196 struct in6_addr a;
197
198 // Perform bitwise OR
199 for (unsigned int i = 0; i < 4; i++)
200 a.s6_addr32[i] = address->s6_addr32[i] | ~bitmask->s6_addr32[i];
201
202 return a;
203 }
204
205 static inline int loc_address_sub(struct in6_addr* result,
206 const struct in6_addr* address1, const struct in6_addr* address2) {
207 int family1 = loc_address_family(address1);
208 int family2 = loc_address_family(address2);
209
210 // Address family must match
211 if (family1 != family2) {
212 errno = EINVAL;
213 return 1;
214 }
215
216 // Clear result
217 int r = loc_address_reset(result, family1);
218 if (r)
219 return r;
220
221 int octet = 0;
222 int remainder = 0;
223
224 foreach_octet_in_address_reverse(octet, address1) {
225 int x = address1->s6_addr[octet] - address2->s6_addr[octet] + remainder;
226
227 // Store remainder for the next iteration
228 remainder = (x >> 8);
229
230 result->s6_addr[octet] = x & 0xff;
231 }
232
233 return 0;
234 }
235
236 static inline void loc_address_increment(struct in6_addr* address) {
237 // Prevent overflow when everything is ones
238 if (loc_address_all_ones(address))
239 return;
240
241 int octet = 0;
242 foreach_octet_in_address_reverse(octet, address) {
243 if (address->s6_addr[octet] < 255) {
244 address->s6_addr[octet]++;
245 break;
246 } else {
247 address->s6_addr[octet] = 0;
248 }
249 }
250 }
251
252 static inline void loc_address_decrement(struct in6_addr* address) {
253 // Prevent underflow when everything is ones
254 if (loc_address_all_zeroes(address))
255 return;
256
257 int octet = 0;
258 foreach_octet_in_address_reverse(octet, address) {
259 if (address->s6_addr[octet] > 0) {
260 address->s6_addr[octet]--;
261 break;
262 } else {
263 address->s6_addr[octet] = 255;
264 }
265 }
266 }
267
268 static inline int loc_address_count_trailing_zero_bits(const struct in6_addr* address) {
269 int zeroes = 0;
270
271 int octet = 0;
272 foreach_octet_in_address_reverse(octet, address) {
273 if (address->s6_addr[octet]) {
274 zeroes += __builtin_ctz(address->s6_addr[octet]);
275 break;
276 } else
277 zeroes += 8;
278 }
279
280 return zeroes;
281 }
282
283 #endif /* LIBLOC_PRIVATE */
284
285 #endif /* LIBLOC_ADDRESS_H */