]> git.ipfire.org Git - location/libloc.git/blob - src/libloc/private.h
address: Correctly subtract IPv4 addresses
[location/libloc.git] / src / libloc / private.h
1 /*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2017 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_PRIVATE_H
18 #define LIBLOC_PRIVATE_H
19
20 #ifdef LIBLOC_PRIVATE
21
22 #include <errno.h>
23 #include <netinet/in.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <syslog.h>
27
28 #include <libloc/libloc.h>
29
30 static inline void __attribute__((always_inline, format(printf, 2, 3)))
31 loc_log_null(struct loc_ctx *ctx, const char *format, ...) {}
32
33 #define loc_log_cond(ctx, prio, arg...) \
34 do { \
35 if (loc_get_log_priority(ctx) >= prio) \
36 loc_log(ctx, prio, __FILE__, __LINE__, __FUNCTION__, ## arg); \
37 } while (0)
38
39 #ifdef ENABLE_DEBUG
40 # define DEBUG(ctx, arg...) loc_log_cond(ctx, LOG_DEBUG, ## arg)
41 #else
42 # define DEBUG(ctx, arg...) loc_log_null(ctx, ## arg)
43 #endif
44
45 #define INFO(ctx, arg...) loc_log_cond(ctx, LOG_INFO, ## arg)
46 #define ERROR(ctx, arg...) loc_log_cond(ctx, LOG_ERR, ## arg)
47
48 #ifndef HAVE_SECURE_GETENV
49 # ifdef HAVE___SECURE_GETENV
50 # define secure_getenv __secure_getenv
51 # else
52 # define secure_getenv getenv
53 # endif
54 #endif
55
56 #define LOC_EXPORT __attribute__ ((visibility("default")))
57
58 void loc_log(struct loc_ctx *ctx,
59 int priority, const char *file, int line, const char *fn,
60 const char *format, ...) __attribute__((format(printf, 6, 7)));
61
62 static inline int in6_addr_cmp(const struct in6_addr* a1, const struct in6_addr* a2) {
63 for (unsigned int i = 0; i < 16; i++) {
64 if (a1->s6_addr[i] > a2->s6_addr[i])
65 return 1;
66
67 else if (a1->s6_addr[i] < a2->s6_addr[i])
68 return -1;
69 }
70
71 return 0;
72 }
73
74 static inline int in6_addr_get_bit(const struct in6_addr* address, unsigned int i) {
75 return ((address->s6_addr[i / 8] >> (7 - (i % 8))) & 1);
76 }
77
78 static inline void in6_addr_set_bit(struct in6_addr* address, unsigned int i, unsigned int val) {
79 address->s6_addr[i / 8] ^= (-val ^ address->s6_addr[i / 8]) & (1 << (7 - (i % 8)));
80 }
81
82 static inline struct in6_addr loc_prefix_to_bitmask(const unsigned int prefix) {
83 struct in6_addr bitmask;
84
85 for (unsigned int i = 0; i < 16; i++)
86 bitmask.s6_addr[i] = 0;
87
88 for (int i = prefix, j = 0; i > 0; i -= 8, j++) {
89 if (i >= 8)
90 bitmask.s6_addr[j] = 0xff;
91 else
92 bitmask.s6_addr[j] = 0xff << (8 - i);
93 }
94
95 return bitmask;
96 }
97
98 static inline unsigned int __loc_address6_bit_length(const struct in6_addr* address) {
99 unsigned int length = 128;
100
101 for (int octet = 0; octet <= 15; octet++) {
102 if (address->s6_addr[octet]) {
103 length -= __builtin_clz(address->s6_addr[octet]) - 24;
104 break;
105 } else
106 length -= 8;
107 }
108
109 return length;
110 }
111
112 static inline unsigned int __loc_address4_bit_length(const struct in6_addr* address) {
113 unsigned int length = 32;
114
115 for (int octet = 12; octet <= 15; octet++) {
116 if (address->s6_addr[octet]) {
117 length -= __builtin_clz(address->s6_addr[octet]) - 24;
118 break;
119 } else
120 length -= 8;
121 }
122
123 return length;
124 }
125
126 static inline unsigned int loc_address_bit_length(const struct in6_addr* address) {
127 if (IN6_IS_ADDR_V4MAPPED(address))
128 return __loc_address4_bit_length(address);
129 else
130 return __loc_address6_bit_length(address);
131 }
132
133 static inline int loc_address_reset(struct in6_addr* address, int family) {
134 switch (family) {
135 case AF_INET6:
136 address->s6_addr32[0] = 0x0000;
137 address->s6_addr32[1] = 0x0000;
138 address->s6_addr32[2] = 0x0000;
139 address->s6_addr32[3] = 0x0000;
140 return 0;
141
142 case AF_INET:
143 address->s6_addr32[0] = 0x0000;
144 address->s6_addr32[1] = 0x0000;
145 address->s6_addr32[2] = htonl(0xffff);
146 address->s6_addr32[3] = 0x0000;
147 return 0;
148 }
149
150 return -1;
151 }
152
153 static inline int loc_address_reset_last(struct in6_addr* address, int family) {
154 switch (family) {
155 case AF_INET6:
156 address->s6_addr32[0] = 0xffff;
157 address->s6_addr32[1] = 0xffff;
158 address->s6_addr32[2] = 0xffff;
159 address->s6_addr32[3] = 0xffff;
160 return 0;
161
162 case AF_INET:
163 address->s6_addr32[0] = 0x0000;
164 address->s6_addr32[1] = 0x0000;
165 address->s6_addr32[2] = htonl(0xffff);
166 address->s6_addr32[3] = 0xffff;
167 return 0;
168 }
169
170 return -1;
171 }
172
173 static inline struct in6_addr loc_address_and(
174 const struct in6_addr* address, const struct in6_addr* bitmask) {
175 struct in6_addr a;
176
177 // Perform bitwise AND
178 for (unsigned int i = 0; i < 4; i++)
179 a.s6_addr32[i] = address->s6_addr32[i] & bitmask->s6_addr32[i];
180
181 return a;
182 }
183
184 static inline struct in6_addr loc_address_or(
185 const struct in6_addr* address, const struct in6_addr* bitmask) {
186 struct in6_addr a;
187
188 // Perform bitwise OR
189 for (unsigned int i = 0; i < 4; i++)
190 a.s6_addr32[i] = address->s6_addr32[i] | ~bitmask->s6_addr32[i];
191
192 return a;
193 }
194
195 static inline int __loc_address6_sub(struct in6_addr* result,
196 const struct in6_addr* address1, const struct in6_addr* address2) {
197 int remainder = 0;
198
199 for (int octet = 15; octet >= 0; octet--) {
200 int x = address1->s6_addr[octet] - address2->s6_addr[octet] + remainder;
201
202 // Store remainder for the next iteration
203 remainder = (x >> 8);
204
205 result->s6_addr[octet] = x & 0xff;
206 }
207
208 return 0;
209 }
210
211 static inline int __loc_address4_sub(struct in6_addr* result,
212 const struct in6_addr* address1, const struct in6_addr* address2) {
213 int remainder = 0;
214
215 for (int octet = 15; octet >= 12; octet--) {
216 int x = address1->s6_addr[octet] - address2->s6_addr[octet] + remainder;
217
218 // Store remainder for the next iteration
219 remainder = (x >> 8);
220
221 result->s6_addr[octet] = x & 0xff;
222 }
223
224 return 0;
225 }
226
227 static inline int loc_address_sub(struct in6_addr* result,
228 const struct in6_addr* address1, const struct in6_addr* address2) {
229 // XXX should be using loc_address_family
230 int family1 = IN6_IS_ADDR_V4MAPPED(address1) ? AF_INET : AF_INET6;
231 int family2 = IN6_IS_ADDR_V4MAPPED(address2) ? AF_INET : AF_INET6;
232
233 // Address family must match
234 if (family1 != family2) {
235 errno = EINVAL;
236 return 1;
237 }
238
239 // Clear result
240 int r = loc_address_reset(result, family1);
241 if (r)
242 return r;
243
244 switch (family1) {
245 case AF_INET6:
246 return __loc_address6_sub(result, address1, address2);
247
248 case AF_INET:
249 return __loc_address4_sub(result, address1, address2);
250
251 default:
252 errno = ENOTSUP;
253 return 1;
254 }
255 }
256
257 static inline void hexdump(struct loc_ctx* ctx, const void* addr, size_t len) {
258 char buffer_hex[16 * 3 + 6];
259 char buffer_ascii[17];
260
261 unsigned int i = 0;
262 unsigned char* p = (unsigned char*)addr;
263
264 DEBUG(ctx, "Dumping %zu byte(s)\n", len);
265
266 // Process every byte in the data
267 for (i = 0; i < len; i++) {
268 // Multiple of 16 means new line (with line offset)
269 if ((i % 16) == 0) {
270 // Just don't print ASCII for the zeroth line
271 if (i != 0)
272 DEBUG(ctx, " %s %s\n", buffer_hex, buffer_ascii);
273
274 // Output the offset.
275 sprintf(buffer_hex, "%04x ", i);
276 }
277
278 // Now the hex code for the specific character
279 sprintf(buffer_hex + 5 + ((i % 16) * 3), " %02x", p[i]);
280
281 // And store a printable ASCII character for later
282 if ((p[i] < 0x20) || (p[i] > 0x7e))
283 buffer_ascii[i % 16] = '.';
284 else
285 buffer_ascii[i % 16] = p[i];
286
287 // Terminate string
288 buffer_ascii[(i % 16) + 1] = '\0';
289 }
290
291 // Pad out last line if not exactly 16 characters
292 while ((i % 16) != 0) {
293 sprintf(buffer_hex + 5 + ((i % 16) * 3), " ");
294 i++;
295 }
296
297 // And print the final bit
298 DEBUG(ctx, " %s %s\n", buffer_hex, buffer_ascii);
299 }
300
301 #endif
302 #endif