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