]> git.ipfire.org Git - location/libloc.git/blame - src/libloc/private.h
address: Correctly subtract IPv4 addresses
[location/libloc.git] / src / libloc / private.h
CommitLineData
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
30static inline void __attribute__((always_inline, format(printf, 2, 3)))
31loc_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
58void 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 62static 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
74static 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
78static 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
82static 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 98static 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
112static 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
126static 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
133static 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
153static 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
173static 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
184static 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 195static 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
211static 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
227static 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
257static 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