BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
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