]>
Commit | Line | Data |
---|---|---|
46aded9a MT |
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 | ||
1a3cb1b4 MT |
20 | #ifdef LIBLOC_PRIVATE |
21 | ||
f39c751d | 22 | #include <errno.h> |
2a30e4de | 23 | #include <netinet/in.h> |
46aded9a | 24 | #include <stdbool.h> |
726f9984 | 25 | #include <stdio.h> |
46aded9a MT |
26 | #include <syslog.h> |
27 | ||
c12a1385 | 28 | #include <libloc/libloc.h> |
46aded9a MT |
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 | |
d0cef0e8 | 52 | # define secure_getenv getenv |
46aded9a MT |
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 | ||
2a30e4de | 62 | static inline int in6_addr_cmp(const struct in6_addr* a1, const struct in6_addr* a2) { |
e14564aa MT |
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; | |
2a30e4de MT |
72 | } |
73 | ||
74 | static inline int in6_addr_get_bit(const struct in6_addr* address, unsigned int i) { | |
20e3a06f | 75 | return ((address->s6_addr[i / 8] >> (7 - (i % 8))) & 1); |
2a30e4de MT |
76 | } |
77 | ||
78 | static inline void in6_addr_set_bit(struct in6_addr* address, unsigned int i, unsigned int val) { | |
20e3a06f | 79 | address->s6_addr[i / 8] ^= (-val ^ address->s6_addr[i / 8]) & (1 << (7 - (i % 8))); |
2a30e4de MT |
80 | } |
81 | ||
30f0f0ed MT |
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 | ||
b074be0b | 98 | static inline unsigned int __loc_address6_bit_length(const struct in6_addr* address) { |
f69e0c8b MT |
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 | ||
b074be0b MT |
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 | ||
9306c68d MT |
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 | ||
30f0f0ed MT |
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 | ||
f39c751d | 195 | static inline int __loc_address6_sub(struct in6_addr* result, |
d701dcfd | 196 | const struct in6_addr* address1, const struct in6_addr* address2) { |
d701dcfd MT |
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 | ||
f39c751d | 205 | result->s6_addr[octet] = x & 0xff; |
d701dcfd MT |
206 | } |
207 | ||
f39c751d MT |
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 | ||
6f060cae | 215 | for (int octet = 15; octet >= 12; octet--) { |
f39c751d MT |
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 | } | |
d701dcfd MT |
255 | } |
256 | ||
257626f5 MT |
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 | ||
356cabc1 MT |
264 | DEBUG(ctx, "Dumping %zu byte(s)\n", len); |
265 | ||
257626f5 MT |
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 | ||
46aded9a | 301 | #endif |
1a3cb1b4 | 302 | #endif |