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