]>
git.ipfire.org Git - people/ms/libloc.git/blob - src/libloc/address.h
2 libloc - A library to determine the location of someone on the Internet
4 Copyright (C) 2022 IPFire Development Team <info@ipfire.org>
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.
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.
17 #ifndef LIBLOC_ADDRESS_H
18 #define LIBLOC_ADDRESS_H
23 #include <netinet/in.h>
26 All of these functions are private and for internal use only
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
);
32 static inline int loc_address_family(const struct in6_addr
* address
) {
33 if (IN6_IS_ADDR_V4MAPPED(address
))
39 static inline unsigned int loc_address_family_bit_length(const int family
) {
53 Checks whether prefix is valid for the given address
55 static inline int loc_address_valid_prefix(const struct in6_addr
* address
, unsigned int prefix
) {
56 const int family
= loc_address_family(address
);
58 // What is the largest possible prefix?
59 const unsigned int bit_length
= loc_address_family_bit_length(family
);
61 if (prefix
<= bit_length
)
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
])
72 else if (a1
->s6_addr
[i
] < a2
->s6_addr
[i
])
79 #define foreach_octet_in_address(octet, address) \
80 for (octet = (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet <= 15; octet++)
82 #define foreach_octet_in_address_reverse(octet, address) \
83 for (octet = 15; octet >= (IN6_IS_ADDR_V4MAPPED(address) ? 12 : 0); octet--)
85 static inline int loc_address_all_zeroes(const struct in6_addr
* address
) {
88 foreach_octet_in_address(octet
, address
) {
89 if (address
->s6_addr
[octet
])
96 static inline int loc_address_all_ones(const struct in6_addr
* address
) {
99 foreach_octet_in_address(octet
, address
) {
100 if (address
->s6_addr
[octet
] < 255)
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);
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)));
115 static inline struct in6_addr
loc_prefix_to_bitmask(const unsigned int prefix
) {
116 struct in6_addr bitmask
;
118 for (unsigned int i
= 0; i
< 16; i
++)
119 bitmask
.s6_addr
[i
] = 0;
121 for (int i
= prefix
, j
= 0; i
> 0; i
-= 8, j
++) {
123 bitmask
.s6_addr
[j
] = 0xff;
125 bitmask
.s6_addr
[j
] = 0xff << (8 - i
);
131 static inline unsigned int loc_address_bit_length(const struct in6_addr
* address
) {
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
]);
141 static inline int loc_address_reset(struct in6_addr
* address
, int family
) {
144 address
->s6_addr32
[0] = 0x00000000;
145 address
->s6_addr32
[1] = 0x00000000;
146 address
->s6_addr32
[2] = 0x00000000;
147 address
->s6_addr32
[3] = 0x00000000;
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;
161 static inline int loc_address_reset_last(struct in6_addr
* address
, int family
) {
164 address
->s6_addr32
[0] = 0xffffffff;
165 address
->s6_addr32
[1] = 0xffffffff;
166 address
->s6_addr32
[2] = 0xffffffff;
167 address
->s6_addr32
[3] = 0xffffffff;
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;
181 static inline struct in6_addr
loc_address_and(
182 const struct in6_addr
* address
, const struct in6_addr
* bitmask
) {
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
];
192 static inline struct in6_addr
loc_address_or(
193 const struct in6_addr
* address
, const struct in6_addr
* bitmask
) {
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
];
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
);
208 // Address family must match
209 if (family1
!= family2
) {
215 int r
= loc_address_reset(result
, family1
);
222 foreach_octet_in_address_reverse(octet
, address1
) {
223 int x
= address1
->s6_addr
[octet
] - address2
->s6_addr
[octet
] + remainder
;
225 // Store remainder for the next iteration
226 remainder
= (x
>> 8);
228 result
->s6_addr
[octet
] = x
& 0xff;
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
))
240 foreach_octet_in_address_reverse(octet
, address
) {
241 if (address
->s6_addr
[octet
] < 255) {
242 address
->s6_addr
[octet
]++;
245 address
->s6_addr
[octet
] = 0;
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
))
256 foreach_octet_in_address_reverse(octet
, address
) {
257 if (address
->s6_addr
[octet
] > 0) {
258 address
->s6_addr
[octet
]--;
261 address
->s6_addr
[octet
] = 255;
266 static inline int loc_address_count_trailing_zero_bits(const struct in6_addr
* address
) {
270 foreach_octet_in_address_reverse(octet
, address
) {
271 if (address
->s6_addr
[octet
]) {
272 zeroes
+= __builtin_ctz(address
->s6_addr
[octet
]);
281 #endif /* LIBLOC_PRIVATE */
283 #endif /* LIBLOC_ADDRESS_H */