BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file ipaddr6.h |
||
3 | * @author Ambroz Bizjak <ambrop7@gmail.com> |
||
4 | * |
||
5 | * @section LICENSE |
||
6 | * |
||
7 | * Redistribution and use in source and binary forms, with or without |
||
8 | * modification, are permitted provided that the following conditions are met: |
||
9 | * 1. Redistributions of source code must retain the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer. |
||
11 | * 2. Redistributions in binary form must reproduce the above copyright |
||
12 | * notice, this list of conditions and the following disclaimer in the |
||
13 | * documentation and/or other materials provided with the distribution. |
||
14 | * 3. Neither the name of the author nor the |
||
15 | * names of its contributors may be used to endorse or promote products |
||
16 | * derived from this software without specific prior written permission. |
||
17 | * |
||
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
21 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||
22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
28 | * |
||
29 | * @section DESCRIPTION |
||
30 | * |
||
31 | * IPv6 address parsing functions. |
||
32 | */ |
||
33 | |||
34 | #ifndef BADVPN_MISC_IPADDR6_H |
||
35 | #define BADVPN_MISC_IPADDR6_H |
||
36 | |||
37 | #include <stdio.h> |
||
38 | #include <string.h> |
||
39 | #include <stdlib.h> |
||
40 | #include <limits.h> |
||
41 | |||
42 | #include <misc/debug.h> |
||
43 | #include <misc/byteorder.h> |
||
44 | #include <misc/parse_number.h> |
||
45 | #include <misc/find_char.h> |
||
46 | #include <misc/print_macros.h> |
||
47 | #include <misc/memref.h> |
||
48 | |||
49 | struct ipv6_addr { |
||
50 | uint8_t bytes[16]; |
||
51 | }; |
||
52 | |||
53 | struct ipv6_ifaddr { |
||
54 | struct ipv6_addr addr; |
||
55 | int prefix; |
||
56 | }; |
||
57 | |||
58 | static int ipaddr6_parse_ipv6_addr (MemRef name, struct ipv6_addr *out_addr); |
||
59 | static int ipaddr6_parse_ipv6_prefix (MemRef str, int *out_num); |
||
60 | static int ipaddr6_parse_ipv6_ifaddr (MemRef str, struct ipv6_ifaddr *out); |
||
61 | static int ipaddr6_ipv6_ifaddr_from_addr_mask (struct ipv6_addr addr, struct ipv6_addr mask, struct ipv6_ifaddr *out); |
||
62 | static void ipaddr6_ipv6_mask_from_prefix (int prefix, struct ipv6_addr *out_mask); |
||
63 | static int ipaddr6_ipv6_prefix_from_mask (struct ipv6_addr mask, int *out_prefix); |
||
64 | static int ipaddr6_ipv6_addrs_in_network (struct ipv6_addr addr1, struct ipv6_addr addr2, int netprefix); |
||
65 | |||
66 | #define IPADDR6_PRINT_MAX 44 |
||
67 | |||
68 | static void ipaddr6_print_addr (struct ipv6_addr addr, char *out_buf); |
||
69 | static void ipaddr6_print_ifaddr (struct ipv6_ifaddr addr, char *out_buf); |
||
70 | |||
71 | int ipaddr6_parse_ipv6_addr (MemRef name, struct ipv6_addr *out_addr) |
||
72 | { |
||
73 | int num_blocks = 0; |
||
74 | int compress_pos = -1; |
||
75 | uint16_t block = 0; |
||
76 | int empty = 1; |
||
77 | |||
78 | size_t i = 0; |
||
79 | |||
80 | while (i < name.len) { |
||
81 | if (name.ptr[i] == '.') { |
||
82 | goto ipv4_ending; |
||
83 | } else if (name.ptr[i] == ':') { |
||
84 | int is_double = (i + 1 < name.len && name.ptr[i + 1] == ':'); |
||
85 | |||
86 | if (i > 0) { |
||
87 | if (empty || num_blocks == 7) { |
||
88 | return 0; |
||
89 | } |
||
90 | out_addr->bytes[2 * num_blocks + 0] = block >> 8; |
||
91 | out_addr->bytes[2 * num_blocks + 1] = block & 0xFF; |
||
92 | num_blocks++; |
||
93 | block = 0; |
||
94 | empty = 1; |
||
95 | } |
||
96 | else if (!is_double) { |
||
97 | return 0; |
||
98 | } |
||
99 | |||
100 | if (is_double) { |
||
101 | if (compress_pos != -1) { |
||
102 | return 0; |
||
103 | } |
||
104 | compress_pos = num_blocks; |
||
105 | } |
||
106 | |||
107 | i += 1 + is_double; |
||
108 | } else { |
||
109 | int digit = decode_hex_digit(name.ptr[i]); |
||
110 | if (digit < 0) { |
||
111 | return 0; |
||
112 | } |
||
113 | if (block > UINT16_MAX / 16) { |
||
114 | return 0; |
||
115 | } |
||
116 | block *= 16; |
||
117 | if (digit > UINT16_MAX - block) { |
||
118 | return 0; |
||
119 | } |
||
120 | block += digit; |
||
121 | empty = 0; |
||
122 | i += 1; |
||
123 | } |
||
124 | } |
||
125 | |||
126 | if (!empty) { |
||
127 | out_addr->bytes[2 * num_blocks + 0] = block >> 8; |
||
128 | out_addr->bytes[2 * num_blocks + 1] = block & 0xFF; |
||
129 | num_blocks++; |
||
130 | } |
||
131 | else if (num_blocks != compress_pos) { |
||
132 | return 0; |
||
133 | } |
||
134 | |||
135 | ipv4_done: |
||
136 | if (compress_pos == -1) { |
||
137 | if (num_blocks != 8) { |
||
138 | return 0; |
||
139 | } |
||
140 | compress_pos = 0; |
||
141 | } |
||
142 | |||
143 | int num_rear = num_blocks - compress_pos; |
||
144 | memmove(out_addr->bytes + 2 * (8 - num_rear), out_addr->bytes + 2 * compress_pos, 2 * num_rear); |
||
145 | memset(out_addr->bytes + 2 * compress_pos, 0, 2 * (8 - num_rear - compress_pos)); |
||
146 | |||
147 | return 1; |
||
148 | |||
149 | ipv4_ending: |
||
150 | if (empty || (num_blocks == 0 && compress_pos == -1)) { |
||
151 | return 0; |
||
152 | } |
||
153 | |||
154 | while (name.ptr[i - 1] != ':') { |
||
155 | i--; |
||
156 | } |
||
157 | |||
158 | uint8_t bytes[4]; |
||
159 | int cur_byte = 0; |
||
160 | uint8_t byte = 0; |
||
161 | empty = 1; |
||
162 | |||
163 | while (i < name.len) { |
||
164 | if (name.ptr[i] == '.') { |
||
165 | if (empty || cur_byte == 3) { |
||
166 | return 0; |
||
167 | } |
||
168 | bytes[cur_byte] = byte; |
||
169 | cur_byte++; |
||
170 | byte = 0; |
||
171 | empty = 1; |
||
172 | } else { |
||
173 | if (!empty && byte == 0) { |
||
174 | return 0; |
||
175 | } |
||
176 | int digit = decode_decimal_digit(name.ptr[i]); |
||
177 | if (digit < 0) { |
||
178 | return 0; |
||
179 | } |
||
180 | if (byte > UINT8_MAX / 10) { |
||
181 | return 0; |
||
182 | } |
||
183 | byte *= 10; |
||
184 | if (digit > UINT8_MAX - byte) { |
||
185 | return 0; |
||
186 | } |
||
187 | byte += digit; |
||
188 | empty = 0; |
||
189 | } |
||
190 | i++; |
||
191 | } |
||
192 | |||
193 | if (cur_byte != 3 || empty) { |
||
194 | return 0; |
||
195 | } |
||
196 | bytes[cur_byte] = byte; |
||
197 | |||
198 | if (8 - num_blocks < 2) { |
||
199 | return 0; |
||
200 | } |
||
201 | memcpy(out_addr->bytes + 2 * num_blocks, bytes, 4); |
||
202 | num_blocks += 2; |
||
203 | |||
204 | goto ipv4_done; |
||
205 | } |
||
206 | |||
207 | int ipaddr6_parse_ipv6_prefix (MemRef str, int *out_num) |
||
208 | { |
||
209 | uintmax_t d; |
||
210 | if (!parse_unsigned_integer(str, &d)) { |
||
211 | return 0; |
||
212 | } |
||
213 | if (d > 128) { |
||
214 | return 0; |
||
215 | } |
||
216 | |||
217 | *out_num = d; |
||
218 | return 1; |
||
219 | } |
||
220 | |||
221 | int ipaddr6_parse_ipv6_ifaddr (MemRef str, struct ipv6_ifaddr *out) |
||
222 | { |
||
223 | size_t slash_pos; |
||
224 | if (!MemRef_FindChar(str, '/', &slash_pos)) { |
||
225 | return 0; |
||
226 | } |
||
227 | |||
228 | return (ipaddr6_parse_ipv6_addr(MemRef_SubTo(str, slash_pos), &out->addr) && |
||
229 | ipaddr6_parse_ipv6_prefix(MemRef_SubFrom(str, slash_pos + 1), &out->prefix)); |
||
230 | } |
||
231 | |||
232 | int ipaddr6_ipv6_ifaddr_from_addr_mask (struct ipv6_addr addr, struct ipv6_addr mask, struct ipv6_ifaddr *out) |
||
233 | { |
||
234 | int prefix; |
||
235 | if (!ipaddr6_ipv6_prefix_from_mask(mask, &prefix)) { |
||
236 | return 0; |
||
237 | } |
||
238 | |||
239 | out->addr = addr; |
||
240 | out->prefix = prefix; |
||
241 | return 1; |
||
242 | } |
||
243 | |||
244 | void ipaddr6_ipv6_mask_from_prefix (int prefix, struct ipv6_addr *out_mask) |
||
245 | { |
||
246 | ASSERT(prefix >= 0) |
||
247 | ASSERT(prefix <= 128) |
||
248 | |||
249 | int quot = prefix / 8; |
||
250 | int rem = prefix % 8; |
||
251 | |||
252 | if (quot > 0) { |
||
253 | memset(out_mask->bytes, UINT8_MAX, quot); |
||
254 | } |
||
255 | if (16 - quot > 0) { |
||
256 | memset(out_mask->bytes + quot, 0, 16 - quot); |
||
257 | } |
||
258 | |||
259 | for (int i = 0; i < rem; i++) { |
||
260 | out_mask->bytes[quot] |= (uint8_t)1 << (8 - i - 1); |
||
261 | } |
||
262 | } |
||
263 | |||
264 | int ipaddr6_ipv6_prefix_from_mask (struct ipv6_addr mask, int *out_prefix) |
||
265 | { |
||
266 | int prefix = 0; |
||
267 | int i = 0; |
||
268 | |||
269 | while (i < 16 && mask.bytes[i] == UINT8_MAX) { |
||
270 | prefix += 8; |
||
271 | i++; |
||
272 | } |
||
273 | |||
274 | if (i < 16) { |
||
275 | uint8_t t = 0; |
||
276 | int j; |
||
277 | for (j = 0; j <= 8; j++) { |
||
278 | if (mask.bytes[i] == t) { |
||
279 | break; |
||
280 | } |
||
281 | if (j < 8) { |
||
282 | t |= ((uint8_t)1 << (8 - j - 1)); |
||
283 | } |
||
284 | } |
||
285 | if (!(j <= 8)) { |
||
286 | return 0; |
||
287 | } |
||
288 | |||
289 | prefix += j; |
||
290 | i++; |
||
291 | |||
292 | while (i < 16) { |
||
293 | if (mask.bytes[i] != 0) { |
||
294 | return 0; |
||
295 | } |
||
296 | i++; |
||
297 | } |
||
298 | } |
||
299 | |||
300 | *out_prefix = prefix; |
||
301 | return 1; |
||
302 | } |
||
303 | |||
304 | int ipaddr6_ipv6_addrs_in_network (struct ipv6_addr addr1, struct ipv6_addr addr2, int netprefix) |
||
305 | { |
||
306 | ASSERT(netprefix >= 0) |
||
307 | ASSERT(netprefix <= 128) |
||
308 | |||
309 | int quot = netprefix / 8; |
||
310 | int rem = netprefix % 8; |
||
311 | |||
312 | if (memcmp(addr1.bytes, addr2.bytes, quot)) { |
||
313 | return 0; |
||
314 | } |
||
315 | |||
316 | if (rem == 0) { |
||
317 | return 1; |
||
318 | } |
||
319 | |||
320 | uint8_t t = 0; |
||
321 | for (int i = 0; i < rem; i++) { |
||
322 | t |= (uint8_t)1 << (8 - i - 1); |
||
323 | } |
||
324 | |||
325 | return ((addr1.bytes[quot] & t) == (addr2.bytes[quot] & t)); |
||
326 | } |
||
327 | |||
328 | void ipaddr6_print_addr (struct ipv6_addr addr, char *out_buf) |
||
329 | { |
||
330 | int largest_start = 0; |
||
331 | int largest_len = 0; |
||
332 | int current_start = 0; |
||
333 | int current_len = 0; |
||
334 | |||
335 | for (int i = 0; i < 8; i++) { |
||
336 | if (addr.bytes[2 * i] == 0 && addr.bytes[2 * i + 1] == 0) { |
||
337 | current_len++; |
||
338 | if (current_len > largest_len) { |
||
339 | largest_start = current_start; |
||
340 | largest_len = current_len; |
||
341 | } |
||
342 | } else { |
||
343 | current_start = i + 1; |
||
344 | current_len = 0; |
||
345 | } |
||
346 | } |
||
347 | |||
348 | if (largest_len > 1) { |
||
349 | for (int i = 0; i < largest_start; i++) { |
||
350 | uint16_t block = ((uint16_t)addr.bytes[2 * i] << 8) | addr.bytes[2 * i + 1]; |
||
351 | out_buf += sprintf(out_buf, "%"PRIx16":", block); |
||
352 | } |
||
353 | if (largest_start == 0) { |
||
354 | out_buf += sprintf(out_buf, ":"); |
||
355 | } |
||
356 | |||
357 | for (int i = largest_start + largest_len; i < 8; i++) { |
||
358 | uint16_t block = ((uint16_t)addr.bytes[2 * i] << 8) | addr.bytes[2 * i + 1]; |
||
359 | out_buf += sprintf(out_buf, ":%"PRIx16, block); |
||
360 | } |
||
361 | if (largest_start + largest_len == 8) { |
||
362 | out_buf += sprintf(out_buf, ":"); |
||
363 | } |
||
364 | } else { |
||
365 | const char *prefix = ""; |
||
366 | for (int i = 0; i < 8; i++) { |
||
367 | uint16_t block = ((uint16_t)addr.bytes[2 * i] << 8) | addr.bytes[2 * i + 1]; |
||
368 | out_buf += sprintf(out_buf, "%s%"PRIx16, prefix, block); |
||
369 | prefix = ":"; |
||
370 | } |
||
371 | } |
||
372 | } |
||
373 | |||
374 | void ipaddr6_print_ifaddr (struct ipv6_ifaddr addr, char *out_buf) |
||
375 | { |
||
376 | ASSERT(addr.prefix >= 0) |
||
377 | ASSERT(addr.prefix <= 128) |
||
378 | |||
379 | ipaddr6_print_addr(addr.addr, out_buf); |
||
380 | sprintf(out_buf + strlen(out_buf), "/%d", addr.prefix); |
||
381 | } |
||
382 | |||
383 | #endif |