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