]> git.ipfire.org Git - location/libloc.git/blob - src/libloc/address.h
Refactor parsing IP addresses
[location/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 int loc_address_parse(struct in6_addr* address, unsigned int* prefix, const char* string);
31
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
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
67 static inline int loc_address_cmp(const struct in6_addr* a1, const struct in6_addr* a2) {
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
79 #define foreach_octet_in_address(octet, address) \
80 for (octet = (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet <= 15; octet++)
81
82 #define foreach_octet_in_address_reverse(octet, address) \
83 for (octet = 15; octet >= (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet--)
84
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
107 static inline int loc_address_get_bit(const struct in6_addr* address, unsigned int i) {
108 return ((address->s6_addr[i / 8] >> (7 - (i % 8))) & 1);
109 }
110
111 static inline void loc_address_set_bit(struct in6_addr* address, unsigned int i, unsigned int val) {
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
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]);
136 }
137
138 return 0;
139 }
140
141 static inline int loc_address_reset(struct in6_addr* address, int family) {
142 switch (family) {
143 case AF_INET6:
144 address->s6_addr32[0] = 0x00000000;
145 address->s6_addr32[1] = 0x00000000;
146 address->s6_addr32[2] = 0x00000000;
147 address->s6_addr32[3] = 0x00000000;
148 return 0;
149
150 case AF_INET:
151 address->s6_addr32[0] = 0x00000000;
152 address->s6_addr32[1] = 0x00000000;
153 address->s6_addr32[2] = htonl(0xffff);
154 address->s6_addr32[3] = 0x00000000;
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:
164 address->s6_addr32[0] = 0xffffffff;
165 address->s6_addr32[1] = 0xffffffff;
166 address->s6_addr32[2] = 0xffffffff;
167 address->s6_addr32[3] = 0xffffffff;
168 return 0;
169
170 case AF_INET:
171 address->s6_addr32[0] = 0x00000000;
172 address->s6_addr32[1] = 0x00000000;
173 address->s6_addr32[2] = htonl(0xffff);
174 address->s6_addr32[3] = 0xffffffff;
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
203 static inline int loc_address_sub(struct in6_addr* result,
204 const struct in6_addr* address1, const struct in6_addr* address2) {
205 int family1 = loc_address_family(address1);
206 int family2 = loc_address_family(address2);
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
219 int octet = 0;
220 int remainder = 0;
221
222 foreach_octet_in_address_reverse(octet, address1) {
223 int x = address1->s6_addr[octet] - address2->s6_addr[octet] + remainder;
224
225 // Store remainder for the next iteration
226 remainder = (x >> 8);
227
228 result->s6_addr[octet] = x & 0xff;
229 }
230
231 return 0;
232 }
233
234 static inline void loc_address_increment(struct in6_addr* address) {
235 // Prevent overflow when everything is ones
236 if (loc_address_all_ones(address))
237 return;
238
239 int octet = 0;
240 foreach_octet_in_address_reverse(octet, address) {
241 if (address->s6_addr[octet] < 255) {
242 address->s6_addr[octet]++;
243 break;
244 } else {
245 address->s6_addr[octet] = 0;
246 }
247 }
248 }
249
250 static inline void loc_address_decrement(struct in6_addr* address) {
251 // Prevent underflow when everything is ones
252 if (loc_address_all_zeroes(address))
253 return;
254
255 int octet = 0;
256 foreach_octet_in_address_reverse(octet, address) {
257 if (address->s6_addr[octet] > 0) {
258 address->s6_addr[octet]--;
259 break;
260 } else {
261 address->s6_addr[octet] = 255;
262 }
263 }
264 }
265
266 static inline int loc_address_count_trailing_zero_bits(const struct in6_addr* address) {
267 int zeroes = 0;
268
269 int octet = 0;
270 foreach_octet_in_address_reverse(octet, address) {
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 */