1 /*
2  * Project    : ipv6calc
3  * File       : libipv6addr.c
4  * Version    : $Id: 19776250b0c1c3a7c3c1124674790d5507a99d4b $
5  * Copyright  : 2001-2021 by Peter Bieringer <pb (at) bieringer.de> except the parts taken from kernel source
6  * License    : GNU GPL v2
7  *
8  * Information:
9  *  Function library for IPv6 address handling
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <math.h>
17 
18 #include "config.h"
19 #include "libipv6addr.h"
20 #include "librfc1884.h"
21 #include "librfc3041.h"
22 #include "libipv6addr.h"
23 #include "libipv4addr.h"
24 #include "ipv6calctypes.h"
25 #include "libipv6calc.h"
26 #include "libipv6calcdebug.h"
27 #include "libieee.h"
28 #include "libeui64.h"
29 
30 #include "../databases/lib/libipv6calc_db_wrapper.h"
31 
32 
33 /*
34  * function returns an octet of an IPv6 address
35  *
36  * in: ipv6addrp = pointer to IPv6 address structure
37  * in: numoctet  = number of octet (0 = MSB, 15 = LSB)
38  * additional: calls exit on out of range
39  */
ipv6addr_getoctet(const ipv6calc_ipv6addr * ipv6addrp,const unsigned int numoctet)40 uint8_t ipv6addr_getoctet(const ipv6calc_ipv6addr *ipv6addrp, const unsigned int numoctet) {
41 	uint8_t retval;
42 
43 	if ( numoctet > 15 ) {
44 		ERRORPRINT_WA("given octet number '%u' is out of range!", numoctet);
45 		exit(EXIT_FAILURE);
46 	};
47 
48 	retval = ipv6addrp->in6_addr.s6_addr[numoctet];
49 
50 	return (retval);
51 };
52 
53 
54 /*
55  * function returns a word of an IPv6 address
56  *
57  * in: ipv6addrp = pointer to IPv6 address structure
58  * in: numword   = number of word (0 = MSB, 7 = LSB)
59  * additional: calls exit on out of range
60  */
ipv6addr_getword(const ipv6calc_ipv6addr * ipv6addrp,const unsigned int numword)61 uint16_t ipv6addr_getword(const ipv6calc_ipv6addr *ipv6addrp, const unsigned int numword) {
62 	uint16_t retval;
63 
64 	if ( numword > 7 ) {
65 		ERRORPRINT_WA("given word number '%u' is out of range!", numword);
66 		exit(EXIT_FAILURE);
67 	};
68 
69 	retval = ( ipv6addrp->in6_addr.s6_addr[numword * 2] << 8 ) \
70 		| ( ipv6addrp->in6_addr.s6_addr[numword * 2 + 1] );
71 
72 	return (retval);
73 };
74 
75 
76 /*
77  * function returns a dword of an IPv6 address
78  *
79  * in: ipv6addrp = pointer to IPv6 address structure
80  * in: numdword  = number of word (0 = MSB, 3 = LSB)
81  * additional: calls exit on out of range
82  */
ipv6addr_getdword(const ipv6calc_ipv6addr * ipv6addrp,const unsigned int numdword)83 uint32_t ipv6addr_getdword(const ipv6calc_ipv6addr *ipv6addrp, const unsigned int numdword) {
84 	uint32_t retval;
85 
86 	if ( numdword > 3 ) {
87 		ERRORPRINT_WA("given dword number '%u' is out of range!", numdword);
88 		exit(EXIT_FAILURE);
89 	};
90 
91 	retval = ( ipv6addrp->in6_addr.s6_addr[numdword * 4] << 24 ) \
92 		| ( ipv6addrp->in6_addr.s6_addr[numdword * 4 + 1] << 16 ) \
93 		| ( ipv6addrp->in6_addr.s6_addr[numdword * 4 + 2] << 8 ) \
94 		| ( ipv6addrp->in6_addr.s6_addr[numdword * 4 + 3] );
95 
96 	return (retval);
97 };
98 
99 
100 /*
101  * function sets an octet of an IPv6 address
102  *
103  * mod: ipv6addrp = pointer to IPv6 address structure
104  * in: numoctet   = number of word (0 = MSB, 15 = LSB)
105  * in: value     = value to set
106  * additional: calls exit on out of range
107  */
ipv6addr_setoctet(ipv6calc_ipv6addr * ipv6addrp,const unsigned int numoctet,const unsigned int value)108 void ipv6addr_setoctet(ipv6calc_ipv6addr *ipv6addrp, const unsigned int numoctet, const unsigned int value) {
109 
110 	if ( numoctet > 15 ) {
111 		ERRORPRINT_WA("given octet number '%u' is out of range!", numoctet);
112 		exit(EXIT_FAILURE);
113 	};
114 
115 	if ( value > 0x0000000ff ) {
116 		ERRORPRINT_WA("given value '%x' is out of range!", value);
117 		exit(EXIT_FAILURE);
118 	};
119 
120 	ipv6addrp->in6_addr.s6_addr[numoctet] = (uint8_t) value;
121 
122 	return;
123 };
124 
125 
126 /*
127  * function sets a word of an IPv6 address
128  *
129  * mod: ipv6addrp = pointer to IPv6 address structure
130  * in: numword   = number of word (0 = MSB, 7 = LSB)
131  * in: value     = value to set
132  * additional: calls exit on out of range
133  */
ipv6addr_setword(ipv6calc_ipv6addr * ipv6addrp,const unsigned int numword,const unsigned int value)134 void ipv6addr_setword(ipv6calc_ipv6addr *ipv6addrp, const unsigned int numword, const unsigned int value) {
135 	if ( numword > 7 ) {
136 		ERRORPRINT_WA("given word number '%u' is out of range!", numword);
137 		exit(EXIT_FAILURE);
138 	};
139 
140 	if ( value > 0x0000ffffu ) {
141 		ERRORPRINT_WA("given value '%x' is out of range!", value);
142 		exit(EXIT_FAILURE);
143 	};
144 
145 	ipv6addrp->in6_addr.s6_addr[numword * 2    ] = (uint8_t) ( ( value & 0x0000ff00 ) >>  8 );
146 	ipv6addrp->in6_addr.s6_addr[numword * 2 + 1] = (uint8_t) ( ( value & 0x000000ff )       );
147 
148 	return;
149 };
150 
151 
152 /*
153  * function sets a dword of an IPv6 address
154  *
155  * mod: ipv6addrp = pointer to IPv6 address structure
156  * in: numdword  = number of word (0 = MSB, 3 = LSB)
157  * in: value     = value to set
158  * additional: calls exit on out of range
159  */
ipv6addr_setdword(ipv6calc_ipv6addr * ipv6addrp,const unsigned int numdword,const unsigned int value)160 void ipv6addr_setdword(ipv6calc_ipv6addr *ipv6addrp, const unsigned int numdword, const unsigned int value) {
161 
162 	if ( numdword > 3 ) {
163 		ERRORPRINT_WA("given dword number '%u' is out of range!", numdword);
164 		exit(EXIT_FAILURE);
165 	};
166 
167 	if ( value > 0xffffffffu ) {
168 		ERRORPRINT_WA("given value '%x' is out of range!", value);
169 		exit(EXIT_FAILURE);
170 	};
171 
172 	ipv6addrp->in6_addr.s6_addr[numdword * 4    ] = (uint8_t) ( ( value & 0xff000000 ) >> 24 );
173 	ipv6addrp->in6_addr.s6_addr[numdword * 4 + 1] = (uint8_t) ( ( value & 0x00ff0000 ) >> 16 );
174 	ipv6addrp->in6_addr.s6_addr[numdword * 4 + 2] = (uint8_t) ( ( value & 0x0000ff00 ) >>  8 );
175 	ipv6addrp->in6_addr.s6_addr[numdword * 4 + 3] = (uint8_t) ( ( value & 0x000000ff )       );
176 
177 	return;
178 };
179 
180 
181 /*
182  * function clears the IPv6 structure
183  *
184  * mod: ipv6addrp = pointer to IPv6 address structure
185  */
ipv6addr_clear(ipv6calc_ipv6addr * ipv6addrp)186 void ipv6addr_clear(ipv6calc_ipv6addr *ipv6addrp) {
187 	int i;
188 
189 	for (i = 0; i < MAXENTRIES_ARRAY(ipv6addrp->in6_addr.s6_addr); i++) {
190 		ipv6addrp->in6_addr.s6_addr[i] = 0;
191 	};
192 
193 	/* Clear IPv6 address scope */
194 	ipv6addrp->typeinfo = 0;
195 	ipv6addrp->typeinfo2 = 0;
196 	ipv6addrp->flag_typeinfo = 0;
197 
198 	/* Clear valid flag */
199 	ipv6addrp->flag_valid = 0;
200 
201 	/* Clear test mode */
202 	ipv6addrp->test_mode = 0;
203 
204 	return;
205 };
206 
207 
208 /*
209  * function clears the IPv6 structure
210  *
211  * mod: ipv6addrp = pointer to IPv6 address structure
212  */
ipv6addr_clearall(ipv6calc_ipv6addr * ipv6addrp)213 void ipv6addr_clearall(ipv6calc_ipv6addr *ipv6addrp) {
214 	ipv6addr_clear(ipv6addrp);
215 
216 	/* Clear other field */
217 	ipv6addrp->bit_start = 1;
218 	ipv6addrp->bit_end = 128;
219 	ipv6addrp->flag_startend_use = 0;
220 	ipv6addrp->flag_prefixuse = 0;
221 	ipv6addrp->prefixlength = 0;
222 	ipv6addrp->prefix2length = 0;
223 	ipv6addrp->flag_valid = 0;
224 	ipv6addrp->flag_scopeid = 0;
225 
226 	return;
227 };
228 
229 
230 /*
231  * function copies the IPv6 structure
232  *
233  * in:  ipv6addrp  = pointer to IPv6 address structure
234  * mod: ipv6addrp2 = pointer to IPv6 address structure
235  */
ipv6addr_copy(ipv6calc_ipv6addr * ipv6addrp_dst,const ipv6calc_ipv6addr * ipv6addrp_src)236 void ipv6addr_copy(ipv6calc_ipv6addr *ipv6addrp_dst, const ipv6calc_ipv6addr *ipv6addrp_src) {
237 
238 	*(ipv6addrp_dst) = *(ipv6addrp_src);
239 
240 	return;
241 };
242 
243 
244 /*
245  * function compares the IPv6 structure
246  *
247  * in:  ipv6addrp1  = pointer to IPv6 address structure
248  * in:  ipv6addrp2  = pointer to IPv6 address structure
249  * in:  compare_flags:
250  *  0=less than/equal/greater than
251  *  1=honor prefix length on addr2
252  *
253  * returns: 0: addr1 equal with addr2, 1: addr1 > addr2, -1: addr1 < addr2 (compare_flags == 0)
254  * returns: 0: addr1 equal with addr2 or covered by addr2/prefix (compare_flags == 1)
255  */
ipv6addr_compare(const ipv6calc_ipv6addr * ipv6addrp1,const ipv6calc_ipv6addr * ipv6addrp2,const uint16_t compare_flags)256 int ipv6addr_compare(const ipv6calc_ipv6addr *ipv6addrp1, const ipv6calc_ipv6addr *ipv6addrp2, const uint16_t compare_flags) {
257 	int i;
258 	uint32_t mask;
259 
260 	DEBUGPRINT_WA(DEBUG_libipv6addr, "compare addr1 with addr2 (compare flags: %08x)", compare_flags);
261 
262 	if (compare_flags == 1) {
263 		for (i = 0; i < 4; i++) {
264 			if ((ipv6addrp2->flag_prefixuse == 0)
265 			  || ((ipv6addrp2->flag_prefixuse == 1) && (ipv6addrp2->prefixlength >= (i + 1) * 32))) {
266 				DEBUGPRINT_WA(DEBUG_libipv6addr, "compare dword %i (prefixuse=%d): %08x <-> %08x", i, ipv6addrp2->flag_prefixuse, ipv6addr_getdword(ipv6addrp2, i), ipv6addr_getdword(ipv6addrp1, i));
267 				/* compare 32 bits */
268 				if (ipv6addr_getdword(ipv6addrp2, i) != ipv6addr_getdword(ipv6addrp1, i)) {
269 					return(1);
270 				};
271 			} else if (ipv6addrp2->flag_prefixuse == 1) {
272 				mask = ~(0xffffffffu >> (ipv6addrp2->prefixlength - i * 32));
273 				DEBUGPRINT_WA(DEBUG_libipv6addr, "compare dword %i with mask 0x%08x: %08x <-> %08x", i, mask, (ipv6addr_getdword(ipv6addrp2, i) & mask), (ipv6addr_getdword(ipv6addrp1, i) & mask));
274 				if ((ipv6addr_getdword(ipv6addrp2, i) & mask) != (ipv6addr_getdword(ipv6addrp1, i) & mask)) {
275 					return(1);
276 				} else {
277 					return(0);
278 				};
279 			};
280 		};
281 	} else if (compare_flags == 0) {
282 		for (i = 0; i < 4; i++) {
283 			if (ipv6addr_getdword(ipv6addrp1, i) > ipv6addr_getdword(ipv6addrp2, i)) {
284 				return(1);
285 			} else if (ipv6addr_getdword(ipv6addrp1, i) < ipv6addr_getdword(ipv6addrp2, i)) {
286 				return(-1);
287 			};
288 		};
289 	};
290 
291 	return(0);
292 };
293 
294 
295 /*
296  * create/verify checksum for anonymized qword
297  *
298  * in:  ipv6addrp  = pointer to IPv6 address structure
299  * in:  flag       = ANON_CHECKSUM_FLAG_CREATE|ANON_CHECKSUM_FLAG_VERIFY
300  * in:  qword      = qword (64-bit selection)
301  * out: ANON_CHECKSUM_FLAG_CREATE: 4-bit checksum   ANON_CHECKSUM_FLAG_VERIFY: 0:ok/1:not-ok
302  *
303  * using same calculation as for ISAN: ISO 7064, MOD 17,16
304  * http://www.pruefziffernberechnung.de/I/ISAN.shtml
305  */
ipv6addr_checksum_anonymized_qword(const ipv6calc_ipv6addr * ipv6addrp,const int flag,const int qword)306 uint32_t ipv6addr_checksum_anonymized_qword(const ipv6calc_ipv6addr *ipv6addrp, const int flag, const int qword) {
307 	uint32_t dword[2];
308 	uint32_t checksum = 0;
309 	int i, n, index, i_max = 16;
310 	unsigned int s;
311 	uint32_t a, b, c = 0;
312 
313 	DEBUGPRINT_NA(DEBUG_libipv6addr, "Called");
314 
315 	dword[0] = ipv6addr_getdword(ipv6addrp, (qword << 1)); // 00-31 (8 nibbles)
316 	dword[1] = ipv6addr_getdword(ipv6addrp, (qword << 1) + 1); // 32-63 (8 nibbles, only 7 nibbles are used for calculation)
317 
318 	if (flag == ANON_CHECKSUM_FLAG_CREATE) {
319 		i_max = 15;
320 	};
321 
322 	for (i = 1; i <= i_max; i++) {
323 		index = (i - 1) / 8; // 0-1
324 		n = (i - 1) % 8; // 0-7
325 		s = (7 - n) * 4;
326 
327 		if (i == 1) {
328 			a = 16; // init
329 		} else {
330 			a = c * 2;
331 		};
332 
333 		b = (a % 17) + ((dword[index] & (0xf << s)) >> s);
334 		c = b % 16;
335 
336 		// DEBUGPRINT_WA(DEBUG_libipv6addr, "checksum calculation of qword: %08x %08x  i=%02d a=%02d b=%02d c=%02d", (unsigned int) dword[0], (unsigned int) dword[1], i, a, b, c);
337 	};
338 
339 	if (flag == ANON_CHECKSUM_FLAG_VERIFY) {
340 		// return code depending on result
341 		if (c == 1) {
342 			DEBUGPRINT_NA(DEBUG_libipv6addr, "checksum verification OK");
343 			return(0);
344 		};
345 
346 		DEBUGPRINT_NA(DEBUG_libipv6addr, "checksum verification FAILED");
347 		return(1);
348 	};
349 
350 	/* find checksum xdigit */
351 	a = c * 2;
352 
353 	for (checksum = 0; checksum <= 0xf; checksum++) {
354 		if ( (((a % 17) + checksum) % 16) == 1) {
355 			break;
356 		};
357 	};
358 
359 	DEBUGPRINT_WA(DEBUG_libipv6addr, "checksum of 64 bits: %08x %08x = %x", (unsigned int) dword[0], (unsigned int) dword[1], checksum);
360 
361 	return(checksum);
362 };
363 
364 
365 /*
366  * set checksum for anonymized prefix
367  *
368  * mod:  ipv6addrp  = pointer to IPv6 address structure
369  */
ipv6addr_set_checksum_anonymized_prefix(ipv6calc_ipv6addr * ipv6addrp)370 void ipv6addr_set_checksum_anonymized_prefix(ipv6calc_ipv6addr *ipv6addrp) {
371 	uint32_t checksum = ipv6addr_checksum_anonymized_qword(ipv6addrp, ANON_CHECKSUM_FLAG_CREATE, 0);
372 
373 	/* checksum is stored in rightmost nibble */
374 	ipv6addr_setoctet(ipv6addrp, 7, (ipv6addr_getoctet(ipv6addrp, 7) & 0xf0) | checksum);
375 };
376 
377 
378 /*
379  * verify checksum for anonymized prefix
380  *
381  * in:  ipv6addrp  = pointer to IPv6 address structure
382  * out: 0=ok 1=not ok
383  */
ipv6addr_verify_checksum_anonymized_prefix(const ipv6calc_ipv6addr * ipv6addrp)384 int ipv6addr_verify_checksum_anonymized_prefix(const ipv6calc_ipv6addr *ipv6addrp) {
385 	return (ipv6addr_checksum_anonymized_qword(ipv6addrp, ANON_CHECKSUM_FLAG_VERIFY, 0));
386 };
387 
388 
389 /*
390  * set checksum for anonymized IID
391  *
392  * mod:  ipv6addrp  = pointer to IPv6 address structure
393  */
ipv6addr_set_checksum_anonymized_iid(ipv6calc_ipv6addr * ipv6addrp)394 void ipv6addr_set_checksum_anonymized_iid(ipv6calc_ipv6addr *ipv6addrp) {
395 	uint32_t checksum = ipv6addr_checksum_anonymized_qword(ipv6addrp, ANON_CHECKSUM_FLAG_CREATE, 1);
396 
397 	/* checksum is stored in rightmost nibble */
398 	ipv6addr_setoctet(ipv6addrp, 15, (ipv6addr_getoctet(ipv6addrp, 15) & 0xf0) | checksum);
399 };
400 
401 
402 /*
403  * verify checksum for anonymized IID
404  *
405  * in:  ipv6addrp  = pointer to IPv6 address structure
406  * out: 0=ok 1=not ok
407  */
ipv6addr_verify_checksum_anonymized_iid(const ipv6calc_ipv6addr * ipv6addrp)408 int ipv6addr_verify_checksum_anonymized_iid(const ipv6calc_ipv6addr *ipv6addrp) {
409 	return (ipv6addr_checksum_anonymized_qword(ipv6addrp, ANON_CHECKSUM_FLAG_VERIFY, 1));
410 };
411 
412 
413 /*
414  * fuzzy detection of IID is random generated (e.g. by privacy extension)
415  *
416  * in:  ipv6addrp  = pointer to IPv6 address structure
417  * out: 0=probably random generated (e.g. by privacy extension), 1=manual set, -1=global, 2=unknown
418  */
ipv6addr_iidrandomdetection(const ipv6calc_ipv6addr * ipv6addrp,s_iid_statistics * iid_statisticsp)419 int ipv6addr_iidrandomdetection(const ipv6calc_ipv6addr *ipv6addrp, s_iid_statistics *iid_statisticsp) {
420 	uint32_t iid[2];
421 
422 	iid[0] = ipv6addr_getdword(ipv6addrp, 2); // 00-31
423 	iid[1] = ipv6addr_getdword(ipv6addrp, 3); // 32-63
424 
425 	int result = 2;
426 
427 	float m, e;
428 
429 	int iid_digit[16]; // digit of IID
430 
431 	int b, i, c, v;
432 
433 	// debug
434 	DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "given IID: %08x%08x",(unsigned int) iid[0], (unsigned int) iid[1]);
435 
436 	// blacklists
437 	if ((iid[0] & 0x02000000u) == 0x02000000u) {
438 		DEBUGPRINT_NA(DEBUG_libipv6addr_iidrandomdetection, "universal/local bit set to: universal (no further random detection)");
439 		result = -1;
440 		goto END_ipv6addr_iidrandomdetection;
441 	};
442 
443 	if (((iid[0] & 0x000000ffu) == 0x000000ffu) && ((iid[1] & 0xff000000u) == 0xfe000000u)) {
444 		DEBUGPRINT_NA(DEBUG_libipv6addr_iidrandomdetection, "expanded EUI-48 (no further random detection)");
445 		result = -1;
446 		goto END_ipv6addr_iidrandomdetection;
447 	};
448 
449 	// clear structure
450 	iid_statisticsp->hexdigit = 0;
451 	iid_statisticsp->lls_residual = 0;
452 
453 	for (c = 0; c < 16; c++) {
454 		iid_statisticsp->digit_blocks[c] = 0;
455 		iid_statisticsp->digit_blocks_hexdigit[c] = 0;
456 		iid_statisticsp->digit_amount[c] = 0;
457 	};
458 
459 	for (c = 0; c < 31; c++) {
460 		iid_statisticsp->digit_delta[c] = 0;
461 	};
462 
463 	iid_statisticsp->digit_delta_amount = 0;
464 
465 
466 	/* create statistics */
467 	for (b = 0; b < 16; b++) {
468 		v = (iid[b/8] & (0xf << ((7 - (b % 8)) * 4))) >> ((7 - (b % 8)) * 4);
469 		iid_digit[b] = v;
470 
471 		DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "analyze nibble %2d: %x", b, v);
472 
473 		iid_statisticsp->digit_amount[v]++;
474 	};
475 
476 	if ( (ipv6calc_debug & DEBUG_libipv6addr_iidrandomdetection) != 0 ) { // ipv6calc_debug usage ok
477 		DEBUGPRINT_NA(DEBUG_libipv6addr, "distribution");
478 
479 		fprintf(stderr, "%s/%s: hex distribution: digit   ", __FILE__, __func__);
480 		for (b = 0; b < 16; b++) {
481 			fprintf(stderr, "|%2x", b);
482 		};
483 		fprintf(stderr, "|\n");
484 		fprintf(stderr, "%s/%s: hex distribution: count   ", __FILE__, __func__);
485 		for (b = 0; b < 16; b++) {
486 			fprintf(stderr, "|%2d", iid_statisticsp->digit_amount[b]);
487 		};
488 		fprintf(stderr, "|\n");
489 	};
490 
491 	/* calculate variances */
492 	v = 0;
493 
494 	/* calculate variance over hexdigits */
495 	c = 0;
496 	float variance = 0.0;
497 	for (b = 0; b < 16; b++) {
498 		if (iid_statisticsp->digit_amount[b] == 0) {
499 			continue;
500 		};
501 		c++;
502 		e = iid_statisticsp->digit_amount[b];
503 
504 		m = 1.0;
505 		/* compensate universal/local bit = 0 by shifting average */
506 		if ((b & 0x02) == 0x02) {
507 			m -= 0.0625;
508 		} else {
509 			m += 0.0625;
510 		};
511 
512 		DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "hexdigit %x: amount=%.0f  exp.avg.=%.4f", b, e, m);
513 
514 		e = e - m; /* substract related average */
515 		e = e * e; /* square */
516 		variance += e;
517 	};
518 
519 	variance = sqrt(variance / c);
520 
521 	DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "variance for hexdigits: %0.5f", variance);
522 
523 	iid_statisticsp->hexdigit = variance;
524 
525 
526 	/* calculate linear least square fit to detect sequences */
527 	float xm = 0, ym = 0, x2 = 0, xy = 0, a0, a1, r, r2 = 0;
528 	for (b = 0; b < 16; b++) {
529 		DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "linear least square calc: x=%0.5f y=%0.5f", (float) b, (float) iid_digit[b]);
530 		xm += (float) b;
531 		ym += (float) iid_digit[b];
532 		xy += (float) b * (float) iid_digit[b];
533 		x2 += (float) b * (float) b;
534 	};
535 	xm /= 16.0; ym /= 16.0;
536 
537 	DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "linear least square calc: xm=%0.5f ym=%0.5f", xm, ym);
538 	DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "linear least square calc: x2=%0.5f xy=%0.5f", x2, xy);
539 
540 	a1 = (xy - 16 * xm * ym) / (x2 - 16 * xm * xm);
541 	a0 = ym - a1 * xm;
542 
543 	for (b = 0; b < 16; b++) {
544 		r = a0 + a1 * (float) b - (float) iid_digit[b];
545 		r2 += r * r;
546 	};
547 
548 	r = sqrt(r2);
549 
550 	DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "linear least square result: a0=%0.5f a1=%0.5f r=%05f", a0, a1, r);
551 
552 	iid_statisticsp->lls_residual = r;
553 
554 
555 	/* check for repeating digits (digit blocks) */
556 	c = 0;
557 	i = iid_digit[0];
558 	for (b = 1; b < 16; b++) {
559 		if (i == iid_digit[b]) {
560 			c++;
561 		} else {
562 			if (c > 0) {
563 				iid_statisticsp->digit_blocks_hexdigit[i]++;
564 			};
565 			iid_statisticsp->digit_blocks[c]++;
566 			i = iid_digit[b];
567 			c = 0;
568 		};
569 	};
570 	iid_statisticsp->digit_blocks[c]++;
571 
572 
573 	/* analyze delta of neighbor digits (digit delta) */
574 	for (b = 1; b < 16; b++) {
575 		v = iid_digit[b] - iid_digit[b-1] + 15;
576 
577 		if (iid_statisticsp->digit_delta[v] == 0) {
578 			// count, how many different digit deltas found
579 			iid_statisticsp->digit_delta_amount++;
580 		};
581 
582 		iid_statisticsp->digit_delta[v]++;
583 
584 	};
585 
586 	if ( (ipv6calc_debug & DEBUG_libipv6addr_iidrandomdetection) != 0 ) { // ipv6calc_debug usage ok
587 		fprintf(stderr, "%s/%s: digit blocks: ", __FILE__, __func__);
588 		for (c = 0; c < 16; c++) {
589 			fprintf(stderr, "%d:%d ", c+1, iid_statisticsp->digit_blocks[c]);
590 		};
591 		fprintf(stderr, "\n");
592 
593 		fprintf(stderr, "%s/%s: hex distribution in blocks: digit   ", __FILE__, __func__);
594 		for (b = 0; b < 16; b++) {
595 			fprintf(stderr, "|%2x", b);
596 		};
597 		fprintf(stderr, "|\n");
598 		fprintf(stderr, "%s/%s: hex distribution in blocks: count   ", __FILE__, __func__);
599 		for (b = 0; b < 16; b++) {
600 			fprintf(stderr, "|%2d", iid_statisticsp->digit_blocks_hexdigit[b]);
601 		};
602 		fprintf(stderr, "|\n");
603 	};
604 
605 	/* check against limits */
606 	if (iid_statisticsp->hexdigit < s_iid_statistics_ok_min.hexdigit || iid_statisticsp->hexdigit > s_iid_statistics_ok_max.hexdigit) {
607 		DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "min/max hexdigit variance limit reached: %f min=%f max=%f", iid_statisticsp->hexdigit, s_iid_statistics_ok_min.hexdigit, s_iid_statistics_ok_max.hexdigit);
608 		result = 1;
609 		goto END_ipv6addr_iidrandomdetection;
610 
611 	} else if (iid_statisticsp->lls_residual < s_iid_statistics_ok_min.lls_residual || iid_statisticsp->lls_residual > s_iid_statistics_ok_max.lls_residual) {
612 		DEBUGPRINT_NA(DEBUG_libipv6addr_iidrandomdetection, "min/max lls_residual limit reached");
613 		result = 1;
614 		goto END_ipv6addr_iidrandomdetection;
615 
616 	} else if (iid_statisticsp->digit_delta_amount < s_iid_statistics_ok_min.digit_delta_amount || iid_statisticsp->digit_delta_amount > s_iid_statistics_ok_max.digit_delta_amount) {
617 		DEBUGPRINT_NA(DEBUG_libipv6addr_iidrandomdetection, "min/max digit_delta_amount reached");
618 		result = 1;
619 		goto END_ipv6addr_iidrandomdetection;
620 
621 	} else {
622 		for (c = 0; c < 16; c++) {
623 			// digit blocks
624 			if (iid_statisticsp->digit_blocks[c] < s_iid_statistics_ok_min.digit_blocks[c] || iid_statisticsp->digit_blocks[c] > s_iid_statistics_ok_max.digit_blocks[c]) {
625 				DEBUGPRINT_NA(DEBUG_libipv6addr_iidrandomdetection, "min/max digit_blocks reached");
626 				result = 1;
627 				goto END_ipv6addr_iidrandomdetection;
628 			};
629 
630 			// digit blocks hexdigits
631 			if (iid_statisticsp->digit_blocks_hexdigit[c] < s_iid_statistics_ok_min.digit_blocks_hexdigit[c] || iid_statisticsp->digit_blocks_hexdigit[c] > s_iid_statistics_ok_max.digit_blocks_hexdigit[c]) {
632 				DEBUGPRINT_NA(DEBUG_libipv6addr_iidrandomdetection, "min/max digit_blocks_hexdigit reached");
633 				result = 1;
634 				goto END_ipv6addr_iidrandomdetection;
635 			};
636 
637 			// digit amount
638 			if (iid_statisticsp->digit_amount[c] < s_iid_statistics_ok_min.digit_amount[c] || iid_statisticsp->digit_amount[c] > s_iid_statistics_ok_max.digit_amount[c]) {
639 				DEBUGPRINT_NA(DEBUG_libipv6addr_iidrandomdetection, "min/max digit_amount reached");
640 				result = 1;
641 				goto END_ipv6addr_iidrandomdetection;
642 			};
643 		};
644 		for (c = 0; c < 31; c++) {
645 			// digit delta
646 			if (iid_statisticsp->digit_delta[c] < s_iid_statistics_ok_min.digit_delta[c] || iid_statisticsp->digit_delta[c] > s_iid_statistics_ok_max.digit_delta[c]) {
647 				DEBUGPRINT_NA(DEBUG_libipv6addr_iidrandomdetection, "min/max digit_delta reached");
648 				result = 1;
649 				goto END_ipv6addr_iidrandomdetection;
650 			};
651 		};
652 
653 	};
654 
655 	result = 0;
656 
657 END_ipv6addr_iidrandomdetection:
658 	DEBUGPRINT_WA(DEBUG_libipv6addr_iidrandomdetection, "result=%d", result);
659 	return (result);
660 };
661 
662 
663 /*
664  * Set type of an IPv6 address
665  *
666  * with credits to kernel and USAGI developer team
667  * basic code was taken from "kernel/net/ipv6/addrconf.c"
668  *
669  * in : ipv6addrp = pointer to IPv6 address structure
670  * mod: typeinfo, typeinfo2, prefix2length
671  */
ipv6addr_settype(ipv6calc_ipv6addr * ipv6addrp)672 void ipv6addr_settype(ipv6calc_ipv6addr *ipv6addrp) {
673 	uint32_t type = 0, r, type2 = 0;
674 	uint32_t st, st1, st2, st3;
675 	s_iid_statistics variances;
676 	int p;
677 	uint32_t mask_0_15, mask_16_31;
678 
679 	uint32_t as_num32, cc_index, geonameid, geonameid_type;
680 	int r1, r2, f;
681 
682 	ipv6calc_ipv4addr ipv4addr;
683 	ipv6calc_ipv6addr ipv6addr;
684 
685 	st =  ipv6addr_getdword(ipv6addrp, 0); /* 32 MSB */
686 	st1 = ipv6addr_getdword(ipv6addrp, 1);
687 	st2 = ipv6addr_getdword(ipv6addrp, 2);
688 	st3 = ipv6addr_getdword(ipv6addrp, 3); /* 32 LSB */
689 
690 	DEBUGPRINT_NA(DEBUG_libipv6addr, "Called");
691 
692 	/* unspecified address */
693 	if ( (st == 0) && (st1 == 0) && (st2 == 0) && (st3 == 0) ) {
694 		type |= IPV6_NEW_ADDR_UNSPECIFIED;
695 		goto END_ipv6addr_gettype;
696 	};
697 
698 	/* address space information  */
699 	if ((st & 0xFE000000u) == 0xFC000000u) {
700 		/* FC00::/7 -> Unique Local IPv6 Unicast Address */
701 		type |= IPV6_ADDR_ULUA;
702 	};
703 
704 	if (st == 0x261000d0) {
705 		/* 2610:00d0::/32 -> LISP (RFC 6830) */
706 		type2 |= IPV6_ADDR_TYPE2_LISP;
707 	};
708 
709 	if ((st == 0x2001067c) && ((st1 & 0xffff0000u) == 0x01980000u)) {
710 		/* 2001:67c:198::/48 -> LISP PETR (RFC 6830) */
711 		type2 |= IPV6_ADDR_TYPE2_LISP | IPV6_ADDR_TYPE2_LISP_PETR;
712 		type |= IPV6_ADDR_ANYCAST;
713 	};
714 
715 	if ((st == 0x2001067c) && ((st1 & 0xffff0000u) == 0x00280000u)) {
716 		/* 2001:67c:28::/48 -> LISP Map Resolver (RFC 6830) */
717 		type2 |= IPV6_ADDR_TYPE2_LISP | IPV6_ADDR_TYPE2_LISP_MAP_RESOLVER;
718 		type |= IPV6_ADDR_ANYCAST;
719 	};
720 
721 	if (st == 0x20010db8) {
722 		/* 2001:db8::/32 -> prefix for documentation (RFC 3849) */
723 		type |= IPV6_ADDR_RESERVED;
724 	};
725 
726 	if (UNPACK_XMS(st, ANON_PREFIX_TOKEN_XOR, ANON_PREFIX_TOKEN_MASK, ANON_PREFIX_TOKEN_SHIFT) == ANON_PREFIX_TOKEN_VALUE) {
727 		// anonymized prefix ?
728 		DEBUGPRINT_WA(DEBUG_libipv6addr, " probably anonymized prefix found: %04x:%04x:%04x:%04x", U32_MSB16(st), U32_LSB16(st), U32_MSB16(st1), U32_LSB16(st1));
729 
730 		/* verify now checksum */
731 		if (ipv6addr_verify_checksum_anonymized_prefix(ipv6addrp) == 0) {
732 			DEBUGPRINT_NA(DEBUG_libipv6addr, "checksum ok - anonymized prefix found");
733 
734 			/* extract flag */
735 			uint32_t flags;
736 			f = ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_FLAGS, &flags);
737 			if (f != 0) {
738 				ERRORPRINT_NA("'flags' payload can't be retrieved, FIX CODE");
739 				exit(EXIT_FAILURE);
740 			};
741 
742 			if (flags == 0x0) {
743 				DEBUGPRINT_NA(DEBUG_libipv6addr, "found anonymized IPv6 address with method: kp");
744 				// anon method=kp
745 				type |= IPV6_NEW_ADDR_AGU | IPV6_ADDR_UNICAST | IPV6_ADDR_ANONYMIZED_PREFIX;
746 
747 				r1 = ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_CCINDEX, &cc_index);
748 				r2 = ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_ASN32, &as_num32);
749 
750 				if ((r1 == 0) && (r2 == 0) && (cc_index == COUNTRYCODE_INDEX_UNKNOWN_REGISTRY_MAP_MIN + REGISTRY_6BONE)) {
751 					type |= IPV6_NEW_ADDR_6BONE;
752 				} else if ((r1 == 0) && (r2 == 0) && (cc_index == COUNTRYCODE_INDEX_LISP)) {
753 					type |= IPV6_NEW_ADDR_PRODUCTIVE;
754 					type2 |= IPV6_ADDR_TYPE2_LISP;
755 				} else {
756 					type |= IPV6_NEW_ADDR_PRODUCTIVE;
757 				};
758 			} else if (flags == 0x1) {
759 				DEBUGPRINT_NA(DEBUG_libipv6addr, "found anonymized IPv6 address with method: kg");
760 				// anon method=kg
761 				type |= IPV6_NEW_ADDR_AGU | IPV6_ADDR_UNICAST | IPV6_ADDR_ANONYMIZED_PREFIX;
762 				type2 |= IPV6_ADDR_TYPE2_ANONYMIZED_GEONAMEID;
763 
764 				r1 = ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_GEONAMEID, &geonameid);
765 				r2 = ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_GEONAMEID_TYPE, &geonameid_type);
766 
767 				if ((r1 == 0) && (r2 == 0) && (((geonameid_type & 0xf) == 0) && ((geonameid_type & 0xf0) >> 4) == REGISTRY_6BONE)) {
768 					type |= IPV6_NEW_ADDR_6BONE;
769 					DEBUGPRINT_NA(DEBUG_libipv6addr, "found anonymized 6bone IPv6 address with method: kg");
770 				} else if ((r1 == 0) && (r2 == 0) && (geonameid == 0x11800) && ((geonameid_type & 0xf)== 7)) {
771 					DEBUGPRINT_NA(DEBUG_libipv6addr, "found anonymized LISP IPv6 address with method: kg");
772 					type |= IPV6_NEW_ADDR_PRODUCTIVE;
773 					type2 |= IPV6_ADDR_TYPE2_LISP;
774 				} else {
775 					type |= IPV6_NEW_ADDR_PRODUCTIVE;
776 				};
777 			} else {
778 			};
779 		} else {
780 			DEBUGPRINT_NA(DEBUG_libipv6addr, "checksum NOT ok - no anonymized prefix found");
781 		};
782 	};
783 
784 	/* address space information  */
785 	if ((st & 0xE0000000u) == 0x20000000u) {
786 		/* 2000::/3 -> global unicast */
787 		type |= IPV6_NEW_ADDR_AGU;
788 	};
789 
790 	/* address space information  */
791 	if ((st & 0xFFFF0000u) == 0x3FFE0000u) {
792 		/* 3ffe::/16 -> experimental 6bone */
793 		type |= IPV6_NEW_ADDR_6BONE;
794 	};
795 
796 	if ((st & 0xFFFF0000u) == 0x20020000u) {
797 		/* 2002::/16 -> 6to4 tunneling */
798 		type |= IPV6_NEW_ADDR_6TO4;
799 
800 		if (	(ipv6addr_getword(ipv6addrp, 3) == 0) &&
801 			(ipv6addr_getword(ipv6addrp, 4) == 0) &&
802 			(ipv6addr_getword(ipv6addrp, 5) == 0) &&
803 			(ipv6addr_getword(ipv6addrp, 6) == ipv6addr_getword(ipv6addrp, 1)) &&
804 			(ipv6addr_getword(ipv6addrp, 7) == ipv6addr_getword(ipv6addrp, 2)) ) {
805 			/* 2002:<ipv4addr>::<ipv4addr> -> usually Microsoft does this */
806 			type |= IPV6_NEW_ADDR_6TO4_MICROSOFT;
807 			type |= IPV6_ADDR_IID_32_63_HAS_IPV4;
808 		};
809 	};
810 
811 	if (st == (uint32_t) 0x3FFE831Fu || st == (uint32_t) 0x20010000u) {
812 		/* 3ffe:831f::/32 -> Teredo (6bone, older draft) */
813 		/* 2001:0000::/32 -> Teredo (RFC 4380) */
814 		type |= IPV6_NEW_ADDR_TEREDO;
815 		if (ipv6addr_getword(ipv6addrp, 5) == 0xffffu) {
816 			// port=0, done by anonymization
817 			type |= IPV6_ADDR_ANONYMIZED_IID;
818 		};
819 	};
820 
821 	if (((st & 0xFFFFFFF0u) == 0x20010010u) || ((st & 0xFFFFFFF0u) == 0x20010020u)) {
822 		/* 2001:0010::/28 -> ORCHID (RFC 4843) */
823 		/* 2001:0020::/28 -> ORCHIDv2 (RFC 7343) */
824 		type |= IPV6_NEW_ADDR_ORCHID;
825 		/* ORCHID has no IID, only a 100 bit encoded hash */
826 
827 		/* check for anonymized hash */
828 		if ((st2 & ANON_TOKEN_MASK_00_31) == (ANON_TOKEN_VALUE_00_31 & ANON_TOKEN_MASK_00_31)) {
829 			DEBUGPRINT_NA(DEBUG_libipv6addr, "probably anonymized ORCHID found");
830 
831 			/* verify now checksum */
832 			if (ipv6addr_verify_checksum_anonymized_iid(ipv6addrp) == 0) {
833 				DEBUGPRINT_NA(DEBUG_libipv6addr, "checksum ok - anonymized ORCHID found");
834 
835 				type |= IPV6_ADDR_ANONYMIZED_IID;
836 
837 			} else {
838 				DEBUGPRINT_NA(DEBUG_libipv6addr, "checksum NOT ok - no anonymized ORCHID found");
839 			};
840 		};
841 		goto END_ipv6addr_gettype;
842 	};
843 
844 	if ((st == 0x0064ff9bu) && (st1 == 0) && (st2 == 0)) {
845 		/* 64:ff9b::/96 -> NAT64 (RFC 6052) */
846 		type |= IPV6_NEW_ADDR_NAT64;
847 	};
848 
849 	if (((type & (IPV6_NEW_ADDR_6BONE | IPV6_NEW_ADDR_6TO4)) == 0) && ((st & 0xE0000000u) == 0x20000000u)) {
850 		/* 2000::/3 -> productive IPv6 address space */
851 		/*  except 3ffe::/16 (6BONE) and 2002::/16 (6TO4) */
852 		type |= IPV6_NEW_ADDR_PRODUCTIVE;
853 	};
854 
855 	if ((st2 == (uint32_t) 0x00000001u) && (st3 & 0xFF000000u) == 0xFF000000u) {
856 		/* ..:0000:0001:ffxx:xxxx solicited node suffix */
857 		type |= IPV6_NEW_ADDR_SOLICITED_NODE;
858 	};
859 
860 	if (((st2 & 0xFDFFFF00u) == (uint32_t) 0x00005E00u) && ((type & IPV6_NEW_ADDR_TEREDO) == 0)) {
861 		/* ISATAP (RFC 4214/5214), but not if TEREDO */
862 		/* ..:0x00:5EFE:xx.xx.xx.xx ISATAP IID with private IPv4 address */
863 		/* ..:0x00:5EFE:xx.xx.xx.xx ISATAP IID with public IPv4 address */
864 		/* ..:0x00:5EFF:FExx:xxxx   ISATAP IID with vendor ID */
865 		/* ..:0x00:5Exx:xxxx:xxxx   ISATAP IID with extension ID */
866 		/* x & 0x2 == 0x2:global, x & 0x02 == 0:local */
867 		type |= IPV6_NEW_ADDR_IID_ISATAP;
868 
869 		if ((st2 & 0x02000000u) == 0x02000000u) {
870 			type |= IPV6_NEW_ADDR_IID_GLOBAL;
871 		} else {
872 			type |= IPV6_NEW_ADDR_IID_LOCAL;
873 		};
874 
875 		if ((st2 & 0x000000ffu) == 0x000000feu) {
876 			type |= IPV6_ADDR_IID_32_63_HAS_IPV4;
877 		};
878 	};
879 
880 	/* multicast */
881 	if ((st & 0xFF000000u) == 0xFF000000u) {
882 		type |= IPV6_ADDR_MULTICAST;
883 
884 		switch((st & 0x00FF0000u)) {
885 			case (0x00010000u):
886 				type |= IPV6_ADDR_LOOPBACK;
887 				break;
888 
889 			case (0x00020000u):
890 				type |= IPV6_ADDR_LINKLOCAL;
891 				break;
892 
893 			case (0x00050000u):
894 				type |= IPV6_ADDR_SITELOCAL;
895 				break;
896 		};
897 		goto END_ipv6addr_gettype;
898 	};
899 
900 	/* special */
901 	if ((st | st1) == 0) {
902 		if (st2 == 0) {
903 			if (st3 == 0) {
904 				type |= IPV6_ADDR_ANY;
905 				goto END_ipv6addr_gettype;
906 			};
907 
908 			if (st3 == (uint32_t) 0x00000001u) {
909 				type |= IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST;
910 				goto END_ipv6addr_gettype;
911 			};
912 
913 			type |= IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST;
914 		}
915 
916 		if (st2 == (uint32_t) 0x0000ffffu)
917 			type |= IPV6_ADDR_MAPPED;
918 	};
919 
920 	// check for included anonymized IPv4 address
921 	if ((type & (IPV6_ADDR_COMPATv4| IPV6_ADDR_MAPPED | IPV6_NEW_ADDR_NAT64 | IPV6_NEW_ADDR_6TO4)) != 0) {
922 		ipv6addr_copy(&ipv6addr, ipv6addrp);
923 		ipv6addr.typeinfo = type; // store what we already have
924 
925 		r = libipv6addr_get_included_ipv4addr(&ipv6addr, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
926 		if (r == 0) {
927 			if ((ipv4addr.typeinfo & IPV4_ADDR_ANONYMIZED) != 0) {
928 				if ((type & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_PREFIX) != 0) {
929 					type |= IPV6_ADDR_ANONYMIZED_PREFIX;
930 				};
931 				if ((type & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_IID) != 0) {
932 					type |= IPV6_ADDR_ANONYMIZED_IID;
933 				};
934 			};
935 			if ((ipv4addr.typeinfo & IPV4_ADDR_ANONYMIZED_GEONAMEID) != 0) {
936 				type2 |= IPV6_ADDR_TYPE2_ANONYMIZED_GEONAMEID;
937 			};
938 		};
939 	} else if ((type & (IPV6_NEW_ADDR_TEREDO)) != 0) {
940 		// check client IP
941 		ipv6addr_copy(&ipv6addr, ipv6addrp);
942 		ipv6addr.typeinfo = type; // store what we already have
943 
944 		r = libipv6addr_get_included_ipv4addr(&ipv6addr, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
945 		if (r == 0) {
946 			if ((ipv4addr.typeinfo & IPV4_ADDR_ANONYMIZED) != 0) {
947 				type |= IPV6_ADDR_ANONYMIZED_IID;
948 			};
949 			if ((ipv4addr.typeinfo & IPV4_ADDR_ANONYMIZED_GEONAMEID) != 0) {
950 				type2 |= IPV6_ADDR_TYPE2_ANONYMIZED_GEONAMEID;
951 			};
952 		};
953 
954 		// check server IP
955 		ipv6addr_copy(&ipv6addr, ipv6addrp);
956 		ipv6addr.typeinfo = type; // store what we already have
957 
958 		r = libipv6addr_get_included_ipv4addr(&ipv6addr, &ipv4addr, IPV6_ADDR_SELECT_IPV4_TEREDO_SERVER);
959 		if (r == 0) {
960 			if ((ipv4addr.typeinfo & IPV4_ADDR_ANONYMIZED) != 0) {
961 				type |= IPV6_ADDR_ANONYMIZED_PREFIX;
962 			};
963 		};
964 	};
965 
966 
967 	/* Consider all addresses with the first three bits different of
968 	   000 and 111 as unicasts.
969 	   also link-local,site-local,ULULA
970 	   except LISP anycast
971 	 */
972 	if ((((st & 0xE0000000u) != 0x00000000u) && ((st & 0xE0000000u) != 0xE0000000u)) || ((st & 0xFC000000u) == 0xFC000000u)) {
973 		if ((type2 & (IPV6_ADDR_TYPE2_LISP_PETR | IPV6_ADDR_TYPE2_LISP_MAP_RESOLVER)) == 0) {
974 			type |= IPV6_ADDR_UNICAST;
975 		};
976 
977 		if ((type & IPV6_NEW_ADDR_TEREDO) != 0) {
978 			/* teredo has no IID */
979 			goto END_ipv6addr_gettype;
980 		};
981 
982 		type |= IPV6_NEW_ADDR_IID;
983 
984 		if ((st & 0xFFC00000u) == 0xFE800000u) {
985 			type |=  IPV6_ADDR_LINKLOCAL;
986 			if ( ((st2 == 0x80005445u) && (st3 ==0x5245444fu)) \
987 			    || ((st2 == 0x0000FFFFu) && (st3 ==0xFFFFFFFDu)) \
988 			) {
989 				/* fe80::8000:5445:5245:444F : LSB string: "TEREDO" */
990 				/* fe80::ffff:ffff:fffd */
991 				type |= IPV6_NEW_ADDR_LINKLOCAL_TEREDO | IPV6_NEW_ADDR_IID_TEREDO;
992 			};
993 		} else if ((st & 0xFFC00000u) == 0xFEC00000u) {
994 			type |= IPV6_ADDR_SITELOCAL;
995 		};
996 
997 		if ((type & IPV6_NEW_ADDR_IID) != 0) {
998 			/* check IID */
999 			if ((st2 & 0x02000000u) == 0x02000000u) {
1000 				type |= IPV6_NEW_ADDR_IID_GLOBAL;
1001 
1002 				if ((type & IPV6_NEW_ADDR_IID_ISATAP) != 0) {
1003 					/* ISATAP is handled above */
1004 				} else {
1005 					if (((st2 & (uint32_t) 0x000000FFu) == (uint32_t) 0x000000FFu) && ((st3 & (uint32_t) 0xFE000000u) == (uint32_t) 0xFE000000u)) {
1006 						type |= IPV6_NEW_ADDR_IID_EUI48;
1007 					} else {
1008 						type |= IPV6_NEW_ADDR_IID_EUI64;
1009 					};
1010 				};
1011 			} else {
1012 				if ((type & IPV6_NEW_ADDR_IID_ISATAP) != 0) {
1013 					/* ISATAP is handled above */
1014 				} else if (((st2 & (uint32_t) 0x000000FFu) == (uint32_t) 0x000000FFu) && ((st3 & (uint32_t) 0xFE000000u) == (uint32_t) 0xFE000000u)) {
1015 					/* EUI-48 local scope based */
1016 					type |= IPV6_NEW_ADDR_IID_EUI48 | IPV6_NEW_ADDR_IID_LOCAL;
1017 				};
1018 
1019 				DEBUGPRINT_WA(DEBUG_libipv6addr, "check for anonymized IID: %04x:%04x:%04x:%04x", U32_MSB16(st2), U32_LSB16(st2), U32_MSB16(st3), U32_LSB16(st3));
1020 
1021 				/* check for anonymized IID */
1022 				if ((st2 & ANON_TOKEN_MASK_00_31) == (ANON_TOKEN_VALUE_00_31 & ANON_TOKEN_MASK_00_31)) {
1023 					DEBUGPRINT_NA(DEBUG_libipv6addr, "perhaps anonymized IID found (ANON token match)");
1024 
1025 					/* verify now checksum */
1026  					if (ipv6addr_verify_checksum_anonymized_iid(ipv6addrp) == 0) {
1027 						p = UNPACK_XMS(st2, 0, ANON_IID_PREFIX_NIBBLES_MASK, ANON_IID_PREFIX_NIBBLES_SHIFT);
1028 
1029 						DEBUGPRINT_WA(DEBUG_libipv6addr, "checksum ok - probably anonymized IID found, p=%d", p);
1030 
1031 						if (p == 0) {
1032 							// no additional check
1033 						} else if (p == 0xf) {
1034 							if ((type & IPV6_ADDR_ANONYMIZED_PREFIX) == 0) {
1035 								DEBUGPRINT_NA(DEBUG_libipv6addr, "no anonymized prefix found, but p=f -> no anonymized IID");
1036 								goto END_ANON_IID;
1037 							};
1038 						} else {
1039 							// check anonymized nibbles in prefix
1040 							DEBUGPRINT_WA(DEBUG_libipv6addr, "check now for %d anonymized nibbles in prefix: %04x:%04x:%04x:%04x", p, U32_MSB16(st), U32_LSB16(st), U32_MSB16(st1), U32_LSB16(st1));
1041 
1042 							if (p >= 8) {
1043 								mask_0_15 = 0xffffffff >> ((16 - p) * 4);
1044 								mask_16_31 = 0xffffffff;
1045 							} else {
1046 								mask_0_15 = 0x0;
1047 								mask_16_31 = 0xffffffff >> ((8 - p) * 4);
1048 							};
1049 
1050 							// check 1st 32-bit block
1051 							if ((st & mask_0_15) != ((ANON_TOKEN_VALUE_00_31 | (ANON_TOKEN_VALUE_00_31 >> 16)) & mask_0_15)) {
1052 								DEBUGPRINT_WA(DEBUG_libipv6addr, "anonymized parts of prefix doesn't match amount of given nibbles: 0-15=%08x mask=%08x", st, mask_0_15);
1053 								goto END_ANON_IID;
1054 							};
1055 
1056 							// check 2nd 32-bit block
1057 							if ((st1 & mask_16_31) != ((ANON_TOKEN_VALUE_00_31 | (ANON_TOKEN_VALUE_00_31 >> 16)) & mask_16_31)) {
1058 								DEBUGPRINT_WA(DEBUG_libipv6addr, "anonymized parts of prefix doesn't match amount of given nibbles: 16-31=%08x mask=%08x", st1, mask_16_31);
1059 								goto END_ANON_IID;
1060 							};
1061 
1062 							type2 |= IPV6_ADDR_TYPE2_ANON_MASKED_PREFIX;
1063 							ipv6addrp->prefix2length = 64 - 4 * p;
1064 							DEBUGPRINT_WA(DEBUG_libipv6addr, "anonymized masked prefix verified, usable prefix length is %u", ipv6addrp->prefix2length);
1065 						};
1066 
1067 						if (((st2 & ANON_IID_RANDOM_MASK_00_31) == ANON_IID_RANDOM_VALUE_00_31) && ((st3 & ANON_IID_RANDOM_MASK_32_63) == ANON_IID_RANDOM_VALUE_32_63)) {
1068 							type |= IPV6_NEW_ADDR_IID_RANDOM | IPV6_ADDR_ANONYMIZED_IID | IPV6_NEW_ADDR_IID_LOCAL;
1069 							goto END_ipv6addr_gettype;
1070 
1071 						} else if (((st2 & ANON_IID_STATIC_MASK_00_31) == ANON_IID_STATIC_VALUE_00_31) && ((st3 & ANON_IID_STATIC_MASK_32_63) == ANON_IID_STATIC_VALUE_32_63)) {
1072 							type |= IPV6_NEW_ADDR_IID_LOCAL | IPV6_ADDR_ANONYMIZED_IID;
1073 							goto END_ipv6addr_gettype;
1074 
1075 						} else if (((st2 & ANON_IID_EUI48_MASK_00_31) == ANON_IID_EUI48_VALUE_00_31) && ((st3 & ANON_IID_EUI48_MASK_32_63) == ANON_IID_EUI48_VALUE_32_63)) {
1076 							type |= IPV6_NEW_ADDR_IID_EUI48 | IPV6_ADDR_ANONYMIZED_IID;
1077 
1078 							/* retrieve inverted local/global bit */
1079 							if ( (st3 & ANON_IID_EUIxx_SCOPE_MASK) == ANON_IID_EUIxx_SCOPE_GLOBAL) {
1080 								type |= IPV6_NEW_ADDR_IID_GLOBAL;
1081 							} else {
1082 								type |= IPV6_NEW_ADDR_IID_LOCAL;
1083 							};
1084 							goto END_ipv6addr_gettype;
1085 
1086 						} else if (((st2 & ANON_IID_EUI64_MASK_00_31) == ANON_IID_EUI64_VALUE_00_31) && ((st3 & ANON_IID_EUI64_MASK_32_63) == ANON_IID_EUI64_VALUE_32_63)) {
1087 							type |= IPV6_NEW_ADDR_IID_EUI64 | IPV6_ADDR_ANONYMIZED_IID;
1088 
1089 							/* retrieve local/global bit */
1090 							if ( (st3 & ANON_IID_EUIxx_SCOPE_MASK) == ANON_IID_EUIxx_SCOPE_GLOBAL) {
1091 								type |= IPV6_NEW_ADDR_IID_GLOBAL;
1092 							} else {
1093 								type |= IPV6_NEW_ADDR_IID_LOCAL;
1094 							};
1095 							goto END_ipv6addr_gettype;
1096 
1097 						} else if (((st2 & ANON_IID_IPV4_MASK_00_31) == ANON_IID_IPV4_VALUE_00_31) && ((st3 & ANON_IID_IPV4_MASK_32_63) == ANON_IID_IPV4_VALUE_32_63)) {
1098 							type |= IPV6_ADDR_IID_32_63_HAS_IPV4 | IPV6_ADDR_ANONYMIZED_IID;
1099 							if ((type & IPV6_NEW_ADDR_6TO4) != 0) {
1100 								// anonymized 6to4 microsoft address
1101 								type |= IPV6_NEW_ADDR_6TO4_MICROSOFT | IPV6_NEW_ADDR_IID_LOCAL;
1102 							};
1103 							goto END_ipv6addr_gettype;
1104 
1105 						} else if (((st2 & ANON_IID_ISATAP_MASK_00_31) == ANON_IID_ISATAP_VALUE_00_31)) {
1106 							type |= IPV6_NEW_ADDR_IID_ISATAP | IPV6_ADDR_ANONYMIZED_IID;
1107 
1108 							if ((st3 & ANON_IID_ISATAP_TYPE_MASK_32_63) == ANON_IID_ISATAP_TYPE_IPV4_VALUE_32_63) {
1109 								type |= IPV6_ADDR_IID_32_63_HAS_IPV4;
1110 							};
1111 
1112 							if (((st3 & ANON_IID_ISATAP_SCOPE_MASK) == ANON_IID_ISATAP_SCOPE_GLOBAL)) {
1113 								type |= IPV6_NEW_ADDR_IID_GLOBAL;
1114 							} else {
1115 								type |= IPV6_NEW_ADDR_IID_LOCAL;
1116 							};
1117 							goto END_ipv6addr_gettype;
1118 						};
1119 
1120 
1121 						if ((ipv6calc_debug & DEBUG_libipv6addr_anonymization_unknown_break) != 0) { // ipv6calc_debug usage ok
1122 							DEBUGPRINT_WA(DEBUG_libipv6addr_anonymization_unknown_break, "unhandled probably anonymized IID found, STOP because of debug level: %08x %08x", st2, st3);
1123 							exit(1);
1124 						} else {
1125 							DEBUGPRINT_NA(DEBUG_libipv6addr, "unhandled probably anonymized IID found (this can really happen), proceed further on");
1126 						};;
1127 					} else {
1128 						DEBUGPRINT_NA(DEBUG_libipv6addr, "checksum WRONG - no anonymized IID found, proceed further on");
1129 					};
1130 				};
1131 
1132 END_ANON_IID:
1133 				type |= IPV6_NEW_ADDR_IID_LOCAL;
1134 
1135 				if ((type & (IPV6_ADDR_IID_32_63_HAS_IPV4 | IPV6_NEW_ADDR_LINKLOCAL_TEREDO | IPV6_NEW_ADDR_IID_ISATAP | IPV6_NEW_ADDR_TEREDO | IPV6_NEW_ADDR_SOLICITED_NODE)) == 0) {
1136 					DEBUGPRINT_WA(DEBUG_libipv6addr, "call IID random detection, typeinfo=%08x", type);
1137 
1138 					/* fuzzy detection of random IID (e.g. privacy extension) */
1139 					r = ipv6addr_iidrandomdetection(ipv6addrp, &variances);
1140 					if (r == 0) {
1141 						type |= IPV6_NEW_ADDR_IID_RANDOM;
1142 					} else if (r == 2) {
1143 						type |= IPV6_NEW_ADDR_IID_RANDOM | IPV6_ADDR_ANONYMIZED_IID;
1144 					} else if (r == 3) {
1145 						type |= IPV6_NEW_ADDR_IID_LOCAL | IPV6_ADDR_ANONYMIZED_IID;
1146 					};
1147 				};
1148 			};
1149 		};
1150 	} else {
1151 		type |= IPV6_ADDR_RESERVED;
1152 	};
1153 
1154 END_ipv6addr_gettype:
1155 	ipv6addrp->typeinfo  = type;
1156 	ipv6addrp->typeinfo2 = type2;
1157 	ipv6addrp->flag_typeinfo = 1;
1158 };
1159 
1160 
1161 /*
1162  * function stores an IPv6 literal address string into a structure
1163  *
1164  * in : *addrstring = IPv6 address
1165  * out: *resultstring = error message
1166  * out: ipv6addrp = changed IPv6 address structure
1167  * ret: ==0: ok, !=0: error
1168  */
addrliteral_to_ipv6addrstruct(const char * addrstring,char * resultstring,const size_t resultstring_length,ipv6calc_ipv6addr * ipv6addrp)1169 int addrliteral_to_ipv6addrstruct(const char *addrstring, char *resultstring, const size_t resultstring_length, ipv6calc_ipv6addr *ipv6addrp) {
1170 	int retval = 1;
1171 	unsigned int s;
1172 	char tempstring[IPV6CALC_STRING_MAX], tempstring2[IPV6CALC_STRING_MAX], *cptr;
1173 	const char *literalstring = ".ipv6-literal.net";
1174 
1175 	resultstring[0] = '\0'; /* clear result string */
1176 
1177 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Got input '%s'", addrstring);
1178 
1179 	/* lowercase string */
1180 	for (s = 0; s <= strlen(addrstring); s++) {
1181 		/* including trailing \0 */
1182 		tempstring2[s] = tolower(addrstring[s]);
1183 	}
1184 
1185 	/* search for literal string */
1186 	cptr = strstr(tempstring2, literalstring);
1187 
1188 	DEBUGPRINT_WA(DEBUG_libipv6addr, "String lengths addrstring=%d strstr=%d literal=%d", (unsigned int) strlen(addrstring), (unsigned int) strlen(cptr), (unsigned int) strlen(literalstring));
1189 
1190 	if (cptr == NULL) {
1191 		snprintf(resultstring, resultstring_length, "Error in given IPv6 literal address, has no 'ipv6-literal.net' included!");
1192 		return (1);
1193 	};
1194 
1195 	if (strlen(cptr) != strlen(literalstring)) {
1196 		snprintf(resultstring, resultstring_length, "Error in given IPv6 literal address, ends not with 'ipv6-literal.net'!");
1197 		return (1);
1198 	};
1199 
1200 	/* copy without literal */
1201 	snprintf(tempstring, strlen(addrstring) - strlen(literalstring) + 1, "%s", addrstring);
1202 
1203 	DEBUGPRINT_WA(DEBUG_libipv6addr, "String without literal suffix: %s", tempstring);
1204 
1205 	/* replace - with : */
1206 	for (s = 0; s < strlen(tempstring); s++) {
1207 		if (tempstring[s] == '-') {
1208 			tempstring[s] = ':';
1209 		} else if (tempstring[s] == 's') {
1210 			tempstring[s] = '%';
1211 		};
1212 	};
1213 
1214 	DEBUGPRINT_WA(DEBUG_libipv6addr, "String converted to non-literal format: %s", tempstring);
1215 
1216 	/* call normal IPv6 parsing function */
1217 	retval = addr_to_ipv6addrstruct(tempstring, resultstring, resultstring_length, ipv6addrp);
1218 
1219 	return (retval);
1220 };
1221 
1222 /*
1223  * function stores an IPv6 address string into a structure
1224  *
1225  * in : *addrstring = IPv6 address
1226  * out: *resultstring = error message
1227  * out: ipv6addrp = changed IPv6 address structure
1228  * ret: ==0: ok, !=0: error
1229  */
addr_to_ipv6addrstruct(const char * addrstring,char * resultstring,const size_t resultstring_length,ipv6calc_ipv6addr * ipv6addrp)1230 int addr_to_ipv6addrstruct(const char *addrstring, char *resultstring, const size_t resultstring_length, ipv6calc_ipv6addr *ipv6addrp) {
1231 	int retval = 1, result, i, cpoints = 0, ccolons = 0, cxdigits = 0;
1232 	char *addronlystring, *cp, tempstring[IPV6CALC_STRING_MAX], tempstring2[IPV6CALC_STRING_MAX], *cptr, **ptrptr;
1233 	int expecteditems = 0;
1234 	int temp[8];
1235 	unsigned int compat[4];
1236 
1237 	ptrptr = &cptr;
1238 
1239 	resultstring[0] = '\0'; /* clear result string */
1240 
1241 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Got input '%s' (resultstring_length=%u)", addrstring, (unsigned int) resultstring_length);
1242 
1243 	if (strlen(addrstring) < 2) {
1244 		fprintf(stderr, "Error in given IPv6 address, has less than 2 chars!\n");
1245 		return (1);
1246 	};
1247 
1248 	if (strlen(addrstring) >= sizeof(tempstring)) {
1249 		fprintf(stderr, "Error in given IPv6 address, has too much chars: %s\n", addrstring);
1250 		return (1);
1251 	};
1252 
1253 	ipv6addr_clearall(ipv6addrp);
1254 
1255 	snprintf(tempstring, sizeof(tempstring), "%s", addrstring);
1256 
1257 	/* save prefix length first, if available */
1258 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Call strtok_r, searching for / in %s", tempstring);
1259 
1260 	addronlystring = strtok_r(tempstring, "/", ptrptr);
1261 
1262 	if ( addronlystring == NULL ) {
1263 		fprintf(stderr, "Strange input (extracting prefix length): %s\n", addrstring);
1264 		return (1);
1265 	};
1266 
1267 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Got address only string: %s", addronlystring);
1268 
1269 	cp = strtok_r (NULL, "/", ptrptr);
1270 	if ( cp != NULL ) {
1271 		i = atoi(cp);
1272 		if (i < 0 || i > 128 ) {
1273 			snprintf(resultstring, resultstring_length, "Illegal prefix length: '%s'", cp);
1274 			retval = 1;
1275 			return (retval);
1276 		};
1277 		ipv6addrp->flag_prefixuse = 1;
1278 		ipv6addrp->prefixlength = (uint8_t) i;
1279 
1280 		DEBUGPRINT_WA(DEBUG_libipv6addr, "prefix length %u", (unsigned int) ipv6addrp->prefixlength);
1281 		DEBUGPRINT_WA(DEBUG_libipv6addr, "flag_prefixuse %d", ipv6addrp->flag_prefixuse);
1282 	};
1283 
1284 	snprintf(tempstring2, sizeof(tempstring2), "%s", addronlystring);
1285 
1286 	/* save scope ID, if available */
1287 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Call strtok_r, searching for %% in %s", tempstring2);
1288 
1289 	addronlystring = strtok_r(tempstring2, "%%", ptrptr);
1290 
1291 	if ( addronlystring == NULL ) {
1292 		fprintf(stderr, "Strange input (extracting scope ID): %s\n", addrstring);
1293 		return (1);
1294 	};
1295 
1296 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Got address only string: %s", addronlystring);
1297 
1298 	cp = strtok_r (NULL, "%", ptrptr);
1299 	if ( cp != NULL ) {
1300 		ipv6addrp->flag_scopeid = 1;
1301 		snprintf(ipv6addrp->scopeid, sizeof(ipv6addrp->scopeid), "%s", cp);
1302 
1303 		DEBUGPRINT_WA(DEBUG_libipv6addr, "scope ID    : %s", ipv6addrp->scopeid);
1304 		DEBUGPRINT_WA(DEBUG_libipv6addr, "flag_scopeid: %d", ipv6addrp->flag_scopeid);
1305 	};
1306 
1307 	if ((strlen(addronlystring) < 2) || (strlen(addronlystring) > 45)) {
1308 		/* min: :: */
1309 		/* max: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 */
1310 		/* max: ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123 */
1311 		snprintf(resultstring, resultstring_length, "Error in given IPv6 address, has not 2 to 45 chars!");
1312 		return (1);
1313 	};
1314 
1315 	/* uncompress string, if necessary */
1316 	if (strstr(addronlystring, "::") != NULL) {
1317 		result = compaddr_to_uncompaddr(addronlystring, tempstring, sizeof(tempstring));
1318 		DEBUGPRINT_WA(DEBUG_libipv6addr, "Result of uncompressed string: '%s'", tempstring);
1319 		if ( result != 0 ) {
1320 			snprintf(resultstring, resultstring_length, "%s", tempstring);
1321 			retval = 1;
1322 			return (retval);
1323 		};
1324 	} else {
1325 		DEBUGPRINT_WA(DEBUG_libipv6addr, "Copy string: '%s'", addronlystring);
1326 		snprintf(tempstring, sizeof(tempstring), "%s", addronlystring);
1327 	};
1328 
1329 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Check string: '%s'", tempstring);
1330 
1331 	/* count ":", "." and xdigits */
1332 	for (i = 0; i < (int) strlen(tempstring); i++) {
1333 		if (tempstring[i] == ':') {
1334 			ccolons++;
1335 		};
1336 		if (tempstring[i] == '.') {
1337 			cpoints++;
1338 		};
1339 		if (isxdigit(tempstring[i])) {
1340 			cxdigits++;
1341 		};
1342 	};
1343 
1344 	/* check amount of ":", must be 6 (compat) or 7 (other) */
1345 	if ( ! ( ( ( ccolons == 7 ) && ( cpoints == 0 ) ) ||  ( ( ccolons == 6 ) && ( cpoints == 3 ) ) ) ) {
1346 		if (strstr(addronlystring, "::")) {
1347 			snprintf(resultstring, resultstring_length, "Error in given address expanded to '%s' is not valid!", tempstring);
1348 		} else {
1349 			snprintf(resultstring, resultstring_length, "Error in given address '%s' is not valid!", addrstring);
1350 		};
1351 		retval = 1;
1352 		return (retval);
1353 	};
1354 
1355 	/* amount of ":" + "." + xdigits must be length */
1356 	if (ccolons + cpoints + cxdigits != (int) strlen(tempstring)) {
1357 		snprintf(resultstring, resultstring_length, "Error in given address '%s' is not valid!", tempstring);
1358 		retval = 1;
1359 		return (retval);
1360 	};
1361 
1362 	/* clear variables */
1363 	for ( i = 0; i <= 3; i++ ) {
1364 		compat[i] = 0;
1365 	};
1366 
1367 	ipv6addr_clear(ipv6addrp);
1368 
1369 	if ( ccolons == 6 ) {
1370 		/* compatv4/mapped format */
1371 		expecteditems = 10;
1372 		result = sscanf(tempstring, "%x:%x:%x:%x:%x:%x:%u.%u.%u.%u", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5], &compat[0], &compat[1], &compat[2], &compat[3]);
1373 		/* check compat */
1374 		for ( i = 0; i <= 3; i++ ) {
1375 			if ( compat[i] > 255 )	{
1376 				snprintf(resultstring, resultstring_length, "Error in given compatv4/mapped IPv6 address, '%s' is not valid on position %d!", addrstring, i);
1377 				retval = 1;
1378 				return (retval);
1379 			};
1380 		};
1381 		temp[6] = (int) (( compat[0] << 8 ) | compat[1]);
1382 		temp[7] = (int) (( compat[2] << 8 ) | compat[3]);
1383 	} else {
1384 		/* normal format */
1385 		expecteditems = 8;
1386 		result = sscanf(tempstring, "%x:%x:%x:%x:%x:%x:%x:%x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5], &temp[6], &temp[7]);
1387 	};
1388 
1389 	DEBUGPRINT_WA(DEBUG_libipv6addr, "reading into array, got items: %d", result);
1390 
1391 	if ( result != expecteditems ) {
1392 		snprintf(resultstring, resultstring_length, "Error in given IPv6 address, splitting of '%s' returns %d items instead of %d!", addronlystring, result, expecteditems);
1393 		retval = 1;
1394 		return (retval);
1395 	};
1396 
1397 	/* check address words range */
1398 	for ( i = 0; i <= 7; i++ ) {
1399 		if ( (temp[i] < 0) || (temp[i] > 0xffff) )	{
1400 			snprintf(resultstring, resultstring_length, "Error in given IPv6 address, '%s' is not valid on position %d!", addronlystring, i);
1401 			retval = 1;
1402 			return (retval);
1403 		};
1404 	};
1405 
1406 	/* copy into structure */
1407 	for ( i = 0; i <= 7; i++ ) {
1408 		DEBUGPRINT_WA(DEBUG_libipv6addr, "Push word %u: %04x", (unsigned int) i, (unsigned int) temp[i]);
1409 		ipv6addr_setword(ipv6addrp, (unsigned int) i, (unsigned int) temp[i]);
1410 	};
1411 
1412 	DEBUGPRINT_WA(DEBUG_libipv6addr, "In structure %08x %08x %08x %08x", (unsigned int) ipv6addr_getdword(ipv6addrp, 0), (unsigned int) ipv6addr_getdword(ipv6addrp, 1), (unsigned int) ipv6addr_getdword(ipv6addrp, 2), (unsigned int) ipv6addr_getdword(ipv6addrp, 3));
1413 	DEBUGPRINT_WA(DEBUG_libipv6addr, "In structure %04x %04x %04x %04x %04x %04x %04x %04x", (unsigned int) ipv6addr_getword(ipv6addrp, 0), (unsigned int) ipv6addr_getword(ipv6addrp, 1), (unsigned int) ipv6addr_getword(ipv6addrp, 2), (unsigned int) ipv6addr_getword(ipv6addrp, 3), (unsigned int) ipv6addr_getword(ipv6addrp, 4), (unsigned int) ipv6addr_getword(ipv6addrp, 5), (unsigned int) ipv6addr_getword(ipv6addrp, 6), (unsigned int) ipv6addr_getword(ipv6addrp, 7));
1414 
1415 	ipv6addr_settype(ipv6addrp);
1416 
1417 	DEBUGPRINT_WA(DEBUG_libipv6addr, "flag_prefixuse %d", ipv6addrp->flag_prefixuse);
1418 
1419 	ipv6addrp->flag_valid = 1;
1420 	retval = 0;
1421 	return (retval);
1422 };
1423 
1424 
1425 /*
1426  * stores the ipv6addr structure in an uncompressed IPv6 format string
1427  *
1428  * in:  ipv6addr = IPv6 address structure
1429  * out: *resultstring = IPv6 address (modified)
1430  * ret: ==0: ok, !=0: error
1431  */
ipv6addrstruct_to_uncompaddr(const ipv6calc_ipv6addr * ipv6addrp,char * resultstring,const size_t resultstring_length,const uint32_t formatoptions)1432 static int ipv6addrstruct_to_uncompaddr(const ipv6calc_ipv6addr *ipv6addrp, char *resultstring, const size_t resultstring_length, const uint32_t formatoptions) {
1433 	int retval = 1;
1434 	unsigned int s;
1435 	char tempstring[IPV6CALC_STRING_MAX], temp2string[IPV6CALC_STRING_MAX];
1436 
1437 	/* print array */
1438 	if ( ((ipv6addrp->typeinfo & (IPV6_ADDR_COMPATv4 | IPV6_ADDR_MAPPED | IPV6_ADDR_IID_32_63_HAS_IPV4)) != 0) && ((ipv6addrp->typeinfo & IPV6_ADDR_ANONYMIZED_IID) == 0)) {
1439 		if ( (formatoptions & FORMATOPTION_printfulluncompressed) != 0 ) {
1440 			snprintf(tempstring, sizeof(tempstring), "%04x:%04x:%04x:%04x:%04x:%04x:%u.%u.%u.%u", \
1441 				(unsigned int) ipv6addr_getword(ipv6addrp, 0), \
1442 				(unsigned int) ipv6addr_getword(ipv6addrp, 1), \
1443 				(unsigned int) ipv6addr_getword(ipv6addrp, 2), \
1444 				(unsigned int) ipv6addr_getword(ipv6addrp, 3), \
1445 				(unsigned int) ipv6addr_getword(ipv6addrp, 4), \
1446 				(unsigned int) ipv6addr_getword(ipv6addrp, 5), \
1447 				(unsigned int) ipv6addrp->in6_addr.s6_addr[12], \
1448 				(unsigned int) ipv6addrp->in6_addr.s6_addr[13], \
1449 				(unsigned int) ipv6addrp->in6_addr.s6_addr[14], \
1450 				(unsigned int) ipv6addrp->in6_addr.s6_addr[15]  \
1451 			);
1452 		} else {
1453 			snprintf(tempstring, sizeof(tempstring), "%x:%x:%x:%x:%x:%x:%u.%u.%u.%u", \
1454 				(unsigned int) ipv6addr_getword(ipv6addrp, 0), \
1455 				(unsigned int) ipv6addr_getword(ipv6addrp, 1), \
1456 				(unsigned int) ipv6addr_getword(ipv6addrp, 2), \
1457 				(unsigned int) ipv6addr_getword(ipv6addrp, 3), \
1458 				(unsigned int) ipv6addr_getword(ipv6addrp, 4), \
1459 				(unsigned int) ipv6addr_getword(ipv6addrp, 5), \
1460 				(unsigned int) ipv6addrp->in6_addr.s6_addr[12], \
1461 				(unsigned int) ipv6addrp->in6_addr.s6_addr[13], \
1462 				(unsigned int) ipv6addrp->in6_addr.s6_addr[14], \
1463 				(unsigned int) ipv6addrp->in6_addr.s6_addr[15]  \
1464 			);
1465 		};
1466 	} else {
1467 		if ( (formatoptions & FORMATOPTION_printfulluncompressed) != 0 ) {
1468 			snprintf(tempstring, sizeof(tempstring), "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", \
1469 				(unsigned int) ipv6addr_getword(ipv6addrp, 0), \
1470 				(unsigned int) ipv6addr_getword(ipv6addrp, 1), \
1471 				(unsigned int) ipv6addr_getword(ipv6addrp, 2), \
1472 				(unsigned int) ipv6addr_getword(ipv6addrp, 3), \
1473 				(unsigned int) ipv6addr_getword(ipv6addrp, 4), \
1474 				(unsigned int) ipv6addr_getword(ipv6addrp, 5), \
1475 				(unsigned int) ipv6addr_getword(ipv6addrp, 6), \
1476 				(unsigned int) ipv6addr_getword(ipv6addrp, 7)  \
1477 			);
1478 		} else {
1479 			snprintf(tempstring, sizeof(tempstring), "%x:%x:%x:%x:%x:%x:%x:%x", \
1480 				(unsigned int) ipv6addr_getword(ipv6addrp, 0), \
1481 				(unsigned int) ipv6addr_getword(ipv6addrp, 1), \
1482 				(unsigned int) ipv6addr_getword(ipv6addrp, 2), \
1483 				(unsigned int) ipv6addr_getword(ipv6addrp, 3), \
1484 				(unsigned int) ipv6addr_getword(ipv6addrp, 4), \
1485 				(unsigned int) ipv6addr_getword(ipv6addrp, 5), \
1486 				(unsigned int) ipv6addr_getword(ipv6addrp, 6), \
1487 				(unsigned int) ipv6addr_getword(ipv6addrp, 7)  \
1488 			);
1489 		};
1490 	};
1491 
1492 	if ((ipv6addrp->flag_prefixuse == 1) && ((formatoptions & (FORMATOPTION_literal | FORMATOPTION_no_prefixlength)) == 0))  {
1493 		/* append prefix length */
1494 		snprintf(resultstring, resultstring_length, "%s/%u", tempstring, (unsigned int) ipv6addrp->prefixlength);
1495 	} else {
1496 		if ((formatoptions & FORMATOPTION_literal) != 0) {
1497 			/* replace : by - */
1498 			for (s = 0; s < strlen(tempstring); s++) {
1499 				if (tempstring[s] == ':') {
1500 					tempstring[s] = '-';
1501 				};
1502 			};
1503 
1504 			if (ipv6addrp->flag_scopeid) {
1505 				snprintf(resultstring, resultstring_length, "%ss%s.ipv6-literal.net", tempstring, ipv6addrp->scopeid);
1506 			} else {
1507 				snprintf(resultstring, resultstring_length, "%s.ipv6-literal.net", tempstring);
1508 			}
1509 		} else {
1510 			if (ipv6addrp->flag_scopeid) {
1511 				snprintf(resultstring, resultstring_length, "%s%%%s", tempstring, ipv6addrp->scopeid);
1512 			} else {
1513 				snprintf(resultstring, resultstring_length, "%s", tempstring);
1514 			};
1515 		};
1516 	};
1517 
1518 	if ( (formatoptions & FORMATOPTION_machinereadable) != 0 ) {
1519 		snprintf(temp2string, sizeof(temp2string), "IPV6=%s", resultstring);
1520 		snprintf(resultstring, resultstring_length, "%s", temp2string);
1521 	};
1522 
1523 	retval = 0;
1524 	return (retval);
1525 };
1526 
1527 
1528 /*
1529  * stores the prefix of an ipv6addr structure in an uncompressed IPv6 format string
1530  *
1531  * in:  ipv6addr = IPv6 address structure, formatoptions
1532  * out: *resultstring = IPv6 address (modified)
1533  * ret: ==0: ok, !=0: error
1534  */
ipv6addrstruct_to_uncompaddrprefix(const ipv6calc_ipv6addr * ipv6addrp,char * resultstring,const size_t resultstring_length,const uint32_t formatoptions)1535 static int ipv6addrstruct_to_uncompaddrprefix(const ipv6calc_ipv6addr *ipv6addrp, char *resultstring, const size_t resultstring_length, const uint32_t formatoptions) {
1536 	int retval = 1;
1537 	unsigned int max, i;
1538 	char tempstring1[IPV6CALC_STRING_MAX], tempstring2[IPV6CALC_STRING_MAX];
1539 
1540 	DEBUGPRINT_NA(DEBUG_libipv6addr, "called");
1541 
1542 	/* test for misuse */
1543 	if ( ((ipv6addrp->typeinfo & (IPV6_ADDR_COMPATv4 | IPV6_ADDR_MAPPED)) != 0 ) && (ipv6addrp->prefixlength > 96) ) {
1544 		snprintf(resultstring, resultstring_length, "Error, cannot print prefix of a compatv4/mapped address with prefix length bigger than 96!");
1545 		retval = 1;
1546 		return (retval);
1547 	};
1548 	if ( ipv6addrp->prefixlength == 0 ) {
1549 		snprintf(resultstring, resultstring_length, "Error, cannot print prefix of a address with prefix length 0!");
1550 		retval = 1;
1551 		return (retval);
1552 	};
1553 
1554 	max = ( (unsigned int) ipv6addrp->prefixlength - 1 ) / 16u;
1555 	i = 0;
1556 	tempstring1[0] = '\0';
1557 	while (i <= max ) {
1558 		if ( i < max ) {
1559 			if ( (formatoptions & FORMATOPTION_printfulluncompressed) != 0 ) {
1560 				snprintf(tempstring2, sizeof(tempstring2), "%s%04x:", tempstring1, (unsigned int) ipv6addr_getword(ipv6addrp, i));
1561 			} else {
1562 				snprintf(tempstring2, sizeof(tempstring2), "%s%x:", tempstring1, (unsigned int) ipv6addr_getword(ipv6addrp, i));
1563 			};
1564 		} else {
1565 			if ( (formatoptions & FORMATOPTION_printfulluncompressed) != 0 ) {
1566 				snprintf(tempstring2, sizeof(tempstring2), "%s%04x", tempstring1, (unsigned int) ipv6addr_getword(ipv6addrp, i));
1567 			} else {
1568 				snprintf(tempstring2, sizeof(tempstring2), "%s%x", tempstring1, (unsigned int) ipv6addr_getword(ipv6addrp, i));
1569 			};
1570 		};
1571 		i++;
1572 		snprintf(tempstring1, sizeof(tempstring1), "%s", tempstring2);
1573 	};
1574 	snprintf(resultstring, resultstring_length, "%s", tempstring1);
1575 
1576 	DEBUGPRINT_WA(DEBUG_libipv6addr, "result string: %s", resultstring);
1577 
1578 	retval = 0;
1579 	return (retval);
1580 };
1581 
1582 
1583 /*
1584  * function stores the suffix of an ipv6addr structure in an uncompressed IPv6 format string
1585  *
1586  * in:  ipv6addr = IPv6 address structure
1587  * out: *resultstring = IPv6 address (modified)
1588  * ret: ==0: ok, !=0: error
1589  */
ipv6addrstruct_to_uncompaddrsuffix(const ipv6calc_ipv6addr * ipv6addrp,char * resultstring,const size_t resultstring_length,const uint32_t formatoptions)1590 static int ipv6addrstruct_to_uncompaddrsuffix(const ipv6calc_ipv6addr *ipv6addrp, char *resultstring, const size_t resultstring_length, const uint32_t formatoptions) {
1591 	int retval = 1;
1592 	unsigned int max, i;
1593 	char tempstring1[IPV6CALC_STRING_MAX], tempstring2[IPV6CALC_STRING_MAX];
1594 
1595 	DEBUGPRINT_NA(DEBUG_libipv6addr, "called");
1596 
1597 	/* test for misuse */
1598 	if ( ( (ipv6addrp->typeinfo & (IPV6_ADDR_COMPATv4 | IPV6_ADDR_MAPPED)) != 0) && ( ipv6addrp->prefixlength > 96 ) ) {
1599 		snprintf(resultstring, resultstring_length, "Error, cannot print suffix of a compatv4/mapped address with prefix length bigger than 96!");
1600 		retval = 1;
1601 		return (retval);
1602 	};
1603 	if ( ipv6addrp->prefixlength == 128 ) {
1604 		snprintf(resultstring, resultstring_length, "Error, cannot print suffix of a address with prefix length 128!");
1605 		retval = 1;
1606 		return (retval);
1607 	};
1608 
1609 	max = 7;
1610 	i = (unsigned int) ipv6addrp->prefixlength / 16u;
1611 	tempstring1[0] = '\0';
1612 	while (i <= max ) {
1613 		if ( ( ( ipv6addrp->typeinfo & (IPV6_ADDR_COMPATv4 | IPV6_ADDR_MAPPED)) != 0 ) && ( i == 6 ) ) {
1614 			snprintf(tempstring2, sizeof(tempstring2), "%s%u.%u.%u.%u", tempstring1, \
1615 				(unsigned int) ipv6addrp->in6_addr.s6_addr[12], \
1616 				(unsigned int) ipv6addrp->in6_addr.s6_addr[13], \
1617 				(unsigned int) ipv6addrp->in6_addr.s6_addr[14], \
1618 				(unsigned int) ipv6addrp->in6_addr.s6_addr[15]  \
1619 			);
1620 			i = max;
1621 		} else if ( i < max ) {
1622 			if ( (formatoptions & FORMATOPTION_printfulluncompressed) != 0 ) {
1623 				snprintf(tempstring2, sizeof(tempstring2), "%s%04x:", tempstring1, (unsigned int) ipv6addr_getword(ipv6addrp, i));
1624 			} else {
1625 				snprintf(tempstring2, sizeof(tempstring2), "%s%x:", tempstring1, (unsigned int) ipv6addr_getword(ipv6addrp, i));
1626 			};
1627 		} else {
1628 			if ( (formatoptions & FORMATOPTION_printfulluncompressed) != 0 ) {
1629 				snprintf(tempstring2, sizeof(tempstring2), "%s%04x", tempstring1, (unsigned int) ipv6addr_getword(ipv6addrp, i));
1630 			} else {
1631 				snprintf(tempstring2, sizeof(tempstring2), "%s%x", tempstring1, (unsigned int) ipv6addr_getword(ipv6addrp, i));
1632 			};
1633 		};
1634 		i++;
1635 		snprintf(tempstring1, sizeof(tempstring1), "%s", tempstring2);
1636 	};
1637 	snprintf(resultstring, resultstring_length, "%s", tempstring1);
1638 
1639 	DEBUGPRINT_WA(DEBUG_libipv6addr, "result string: %s", resultstring);
1640 
1641 	retval = 0;
1642 	return (retval);
1643 };
1644 
1645 
libipv6addr_ipv6addrstruct_to_uncompaddr(const ipv6calc_ipv6addr * ipv6addrp,char * resultstring,const size_t resultstring_length,const uint32_t formatoptions)1646 int libipv6addr_ipv6addrstruct_to_uncompaddr(const ipv6calc_ipv6addr *ipv6addrp, char *resultstring, const size_t resultstring_length, const uint32_t formatoptions) {
1647 	int retval = 1;
1648 
1649 	DEBUGPRINT_WA(DEBUG_libipv6addr, "get format option: %08x", (unsigned int) formatoptions);
1650 
1651 	if ( (formatoptions & FORMATOPTION_printprefix) != 0 ) {
1652 		retval = ipv6addrstruct_to_uncompaddrprefix(ipv6addrp, resultstring, resultstring_length, formatoptions);
1653 	} else if ( (formatoptions & FORMATOPTION_printsuffix) != 0 ) {
1654 		retval = ipv6addrstruct_to_uncompaddrsuffix(ipv6addrp, resultstring, resultstring_length, formatoptions);
1655 	} else {
1656 		retval = ipv6addrstruct_to_uncompaddr(ipv6addrp, resultstring, resultstring_length, formatoptions);
1657 	};
1658 
1659 	if (retval == 0) {
1660 		/* don't modify case on error messages */
1661 		if ( (formatoptions & FORMATOPTION_printlowercase) != 0 ) {
1662 			/* nothing to do */
1663 		} else if ( (formatoptions & FORMATOPTION_printuppercase) != 0 ) {
1664 			string_to_upcase(resultstring);
1665 		};
1666 	};
1667 
1668 	DEBUGPRINT_WA(DEBUG_libipv6addr, "result string: %s", resultstring);
1669 
1670 	retval = 0;
1671 	return (retval);
1672 };
1673 
1674 
1675 /*
1676  * mask prefix bits (set suffix bits to 0)
1677  *
1678  * in:  structure via reference
1679  * out: modified structure
1680  */
ipv6addrstruct_maskprefix(ipv6calc_ipv6addr * ipv6addrp)1681 void ipv6addrstruct_maskprefix(ipv6calc_ipv6addr *ipv6addrp) {
1682 	unsigned int nbit, nword;
1683 	uint16_t mask, newword;
1684 	int i;
1685 
1686 	DEBUGPRINT_NA(DEBUG_libipv6addr, "called");
1687 
1688 	if (ipv6addrp->flag_prefixuse != 1) {
1689 		/* hmm, no prefix specified. skip */
1690 		return;
1691 	};
1692 
1693 	for (i = 127; i >= 0; i--) {
1694 		nbit = (unsigned int) i;
1695 		if (nbit >= (unsigned int) ipv6addrp->prefixlength) {
1696 			/* set bit to zero */
1697 
1698 			/* calculate word (16 bit) - matches with addr6p[]*/
1699 			nword = (nbit & 0x70) >> 4;
1700 
1701 			/* calculate mask */
1702 			mask = ((uint16_t) 0x8000u) >> (( ((uint16_t) nbit) & ((uint16_t) 0x0fu)));
1703 			newword = ipv6addr_getword(ipv6addrp, nword) & (~ mask );
1704 
1705 			DEBUGPRINT_WA(DEBUG_libipv6addr, "bit: %u = nword: %u, mask: %04x, word: %04x newword: %04x", nbit, nword, (unsigned int) mask, (unsigned int) ipv6addr_getword(ipv6addrp, nword), (unsigned int) newword);
1706 
1707 			ipv6addr_setword(ipv6addrp, nword, (unsigned int) newword);
1708 		};
1709 	};
1710 };
1711 
1712 
1713 /*
1714  * mask suffix bits (set prefix bits to 0)
1715  *
1716  * in:  structure via reference
1717  * out: modified structure
1718  */
ipv6addrstruct_masksuffix(ipv6calc_ipv6addr * ipv6addrp)1719 void ipv6addrstruct_masksuffix(ipv6calc_ipv6addr *ipv6addrp) {
1720 	unsigned int nbit, nword;
1721 	uint16_t mask, newword;
1722 	int i;
1723 
1724 	DEBUGPRINT_NA(DEBUG_libipv6addr, "called");
1725 
1726 	if (ipv6addrp->flag_prefixuse != 1) {
1727 		/* hmm, no prefix specified. skip */
1728 		return;
1729 	};
1730 
1731 	for (i = 127; i >= 0; i--) {
1732 		nbit = (unsigned int) i;
1733 
1734 		if (nbit < (unsigned int) ipv6addrp->prefixlength) {
1735 			/* set bit to zero */
1736 
1737 			/* calculate word (16 bit) - matches with addr6p[]*/
1738 			nword = (nbit & 0x70) >> 4;
1739 
1740 			/* calculate mask */
1741 			mask = ((uint32_t) 0x8000u) >> (((uint32_t) nbit) & ((uint32_t) 0x0fu ));
1742 			newword = ipv6addr_getword(ipv6addrp, nword) & (~ mask );
1743 
1744 			DEBUGPRINT_WA(DEBUG_libipv6addr, "%u = nword: %u, mask: %04x, word: %04x newword: %04x", nbit, nword, (unsigned int) mask, (unsigned int) ipv6addr_getword(ipv6addrp, nword), (unsigned int) newword);
1745 
1746 			ipv6addr_setword(ipv6addrp, nword, (unsigned int) newword);
1747 		};
1748 	};
1749 };
1750 
1751 
1752 /*
1753  * function stores an 16 char token into a structure
1754  *
1755  * in : *addrstring = 16 char token
1756  * out: *resultstring = error message
1757  * out: ipv6addr = IPv6 address structure
1758  * ret: ==0: ok, !=0: error
1759  */
tokenlsb64_to_ipv6addrstruct(const char * addrstring,char * resultstring,const size_t resultstring_length,ipv6calc_ipv6addr * ipv6addrp)1760 int tokenlsb64_to_ipv6addrstruct(const char *addrstring, char *resultstring, const size_t resultstring_length, ipv6calc_ipv6addr *ipv6addrp) {
1761 	int retval = 1, result;
1762 	int temp[4];
1763 	char tempstring[IPV6CALC_STRING_MAX];
1764 
1765 	resultstring[0] = '\0'; /* clear result string */
1766 
1767 	DEBUGPRINT_WA(DEBUG_libipv6addr, "got input '%s'", addrstring);
1768 
1769 	if ( strlen(addrstring) != 16 ) {
1770 		snprintf(resultstring, resultstring_length, "Error in given token '%s' is not valid (length != 16)!", addrstring);
1771 		retval = 1;
1772 		return (retval);
1773 	};
1774 
1775 	/* scan address into array */
1776 	result = sscanf(addrstring, "%04x%04x%04x%04x", &temp[0], &temp[1], &temp[2], &temp[3]);
1777 	if ( result != 4 ) {
1778 		snprintf(resultstring, resultstring_length, "Error splitting address '%s', got %d items instead of 4!", addrstring, result);
1779 		retval = 1;
1780 		return (retval);
1781 	};
1782 
1783 	/* set prefix */
1784 	snprintf(tempstring, sizeof(tempstring),  "0:0:0:0:%04x:%04x:%04x:%04x", \
1785 		(unsigned int) temp[0] ,\
1786 		(unsigned int) temp[1], \
1787 		(unsigned int) temp[2], \
1788 		(unsigned int) temp[3]  \
1789 	);
1790 
1791 	/* store into structure */
1792 	retval = addr_to_ipv6addrstruct(tempstring, resultstring, sizeof(resultstring), ipv6addrp);
1793 
1794 	return (retval);
1795 };
1796 
1797 /*
1798  * function stores an interface identifier into a structure
1799  *
1800  * in : *addrstring = interface identifier
1801  * out: *resultstring = error message
1802  * out: ipv6addr = IPv6 address structure
1803  * ret: ==0: ok, !=0: error
1804  */
identifier_to_ipv6addrstruct(const char * addrstring,char * resultstring,const size_t resultstring_length,ipv6calc_ipv6addr * ipv6addrp)1805 int identifier_to_ipv6addrstruct(const char *addrstring, char *resultstring, const size_t resultstring_length, ipv6calc_ipv6addr *ipv6addrp) {
1806 	int retval = 1, i, ccolons = 0;
1807 	char tempstring[IPV6CALC_STRING_MAX];
1808 
1809 	resultstring[0] = '\0'; /* clear result string */
1810 
1811 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Got input '%s'", addrstring);
1812 
1813 	if ((strlen(addrstring) < 2) || (strlen(addrstring) > 19)) {
1814 		/* min: :: */
1815 		/* max: ffff:ffff:ffff:ffff */
1816 		snprintf(resultstring, resultstring_length, "Error in given identifier identifier, has not 2 to 19 chars!");
1817 		retval = 1;
1818 		return (retval);
1819 	};
1820 
1821 	/* count ":", must be 2 to 3 */
1822 	for (i = 0; i < (int) strlen(addrstring); i++) {
1823 		if (addrstring[i] == ':') {
1824 			ccolons++;
1825 		};
1826 	};
1827 	if ((ccolons < 2) || (ccolons > 3)) {
1828 		snprintf(resultstring, resultstring_length, "Error in given identifier '%s' is not valid!", addrstring);
1829 		retval = 1;
1830 		return (retval);
1831 	};
1832 
1833 	/* set prefix */
1834 	snprintf(tempstring, sizeof(tempstring), "0:0:0:0:%s", addrstring);
1835 
1836 	/* store into structure */
1837 	retval = addr_to_ipv6addrstruct(tempstring, resultstring, sizeof(resultstring), ipv6addrp);
1838 
1839 	DEBUGPRINT_WA(DEBUG_libipv6addr, "result string '%s'", resultstring);
1840 
1841 	return (retval);
1842 };
1843 
1844 /*
1845  * function stores the ipv6addr structure in an uncompressed IPv6 format string
1846  *
1847  * in:  ipv6addr = IPv6 address structure
1848  * out: *resultstring = IPv6 address (modified)
1849  * ret: ==0: ok, !=0: error
1850  */
libipv6addr_ipv6addrstruct_to_tokenlsb64(const ipv6calc_ipv6addr * ipv6addrp,char * resultstring,const size_t resultstring_length,uint32_t formatoptions)1851 int libipv6addr_ipv6addrstruct_to_tokenlsb64(const ipv6calc_ipv6addr *ipv6addrp, char *resultstring, const size_t resultstring_length, uint32_t formatoptions) {
1852 	int retval = 1;
1853 
1854 	/* print array */
1855 	snprintf(resultstring, resultstring_length, "%04x%04x%04x%04x", \
1856 		(unsigned int) ipv6addr_getword(ipv6addrp, 4), \
1857 		(unsigned int) ipv6addr_getword(ipv6addrp, 5), \
1858 		(unsigned int) ipv6addr_getword(ipv6addrp, 6), \
1859 		(unsigned int) ipv6addr_getword(ipv6addrp, 7)  \
1860 	);
1861 
1862 	if ( (formatoptions & FORMATOPTION_printlowercase) != 0 ) {
1863 		/* nothing to do */
1864 	} else if ( (formatoptions & FORMATOPTION_printuppercase) != 0 ) {
1865 		string_to_upcase(resultstring);
1866 	};
1867 
1868 	DEBUGPRINT_WA(DEBUG_libipv6addr, "result string '%s'", resultstring);
1869 
1870 	retval = 0;
1871 	return (retval);
1872 };
1873 
1874 
1875 /*
1876  * function prints an IPv6 address in native octal format
1877  *
1878  * in:  ipv6addr = IPv6 address structure
1879  * formatoptions
1880  * out: *resultstring = IPv6 address (modified)
1881  * ret: ==0: ok, !=0: error
1882  */
libipv6addr_to_octal(const ipv6calc_ipv6addr * ipv6addrp,char * resultstring,const size_t resultstring_length,const uint32_t formatoptions)1883 int libipv6addr_to_octal(const ipv6calc_ipv6addr *ipv6addrp, char *resultstring, const size_t resultstring_length, const uint32_t formatoptions) {
1884 	int retval = 1;
1885 	char tempstring[IPV6CALC_STRING_MAX];
1886 
1887 	if ( (formatoptions & FORMATOPTION_printfulluncompressed) != 0 ) {
1888 		snprintf(tempstring, sizeof(tempstring), "\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o\\0%03o",
1889 			(unsigned int) ipv6addrp->in6_addr.s6_addr[0],  \
1890 			(unsigned int) ipv6addrp->in6_addr.s6_addr[1],  \
1891 			(unsigned int) ipv6addrp->in6_addr.s6_addr[2],  \
1892 			(unsigned int) ipv6addrp->in6_addr.s6_addr[3],  \
1893 			(unsigned int) ipv6addrp->in6_addr.s6_addr[4],  \
1894 			(unsigned int) ipv6addrp->in6_addr.s6_addr[5],  \
1895 			(unsigned int) ipv6addrp->in6_addr.s6_addr[6],  \
1896 			(unsigned int) ipv6addrp->in6_addr.s6_addr[7],  \
1897 			(unsigned int) ipv6addrp->in6_addr.s6_addr[8],  \
1898 			(unsigned int) ipv6addrp->in6_addr.s6_addr[9],  \
1899 			(unsigned int) ipv6addrp->in6_addr.s6_addr[10], \
1900 			(unsigned int) ipv6addrp->in6_addr.s6_addr[11], \
1901 			(unsigned int) ipv6addrp->in6_addr.s6_addr[12], \
1902 			(unsigned int) ipv6addrp->in6_addr.s6_addr[13], \
1903 			(unsigned int) ipv6addrp->in6_addr.s6_addr[14], \
1904 			(unsigned int) ipv6addrp->in6_addr.s6_addr[15]  \
1905 		);
1906 	} else {
1907 		snprintf(tempstring, sizeof(tempstring), "\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o\\0%o",
1908 			(unsigned int) ipv6addrp->in6_addr.s6_addr[0],  \
1909 			(unsigned int) ipv6addrp->in6_addr.s6_addr[1],  \
1910 			(unsigned int) ipv6addrp->in6_addr.s6_addr[2],  \
1911 			(unsigned int) ipv6addrp->in6_addr.s6_addr[3],  \
1912 			(unsigned int) ipv6addrp->in6_addr.s6_addr[4],  \
1913 			(unsigned int) ipv6addrp->in6_addr.s6_addr[5],  \
1914 			(unsigned int) ipv6addrp->in6_addr.s6_addr[6],  \
1915 			(unsigned int) ipv6addrp->in6_addr.s6_addr[7],  \
1916 			(unsigned int) ipv6addrp->in6_addr.s6_addr[8],  \
1917 			(unsigned int) ipv6addrp->in6_addr.s6_addr[9],  \
1918 			(unsigned int) ipv6addrp->in6_addr.s6_addr[10], \
1919 			(unsigned int) ipv6addrp->in6_addr.s6_addr[11], \
1920 			(unsigned int) ipv6addrp->in6_addr.s6_addr[12], \
1921 			(unsigned int) ipv6addrp->in6_addr.s6_addr[13], \
1922 			(unsigned int) ipv6addrp->in6_addr.s6_addr[14], \
1923 			(unsigned int) ipv6addrp->in6_addr.s6_addr[15]  \
1924 		);
1925 	};
1926 
1927 	snprintf(resultstring, resultstring_length, "%s", tempstring);
1928 	retval = 0;
1929 	return (retval);
1930 };
1931 
1932 
1933 /*
1934  * function prints an IPv6 address in native hex format
1935  *
1936  * in:  ipv6addr = IPv6 address structure
1937  * formatoptions
1938  * out: *resultstring = IPv6 address (modified)
1939  * ret: ==0: ok, !=0: error
1940  */
libipv6addr_to_hex(const ipv6calc_ipv6addr * ipv6addrp,char * resultstring,const size_t resultstring_length,const uint32_t formatoptions)1941 int libipv6addr_to_hex(const ipv6calc_ipv6addr *ipv6addrp, char *resultstring, const size_t resultstring_length, const uint32_t formatoptions) {
1942 	int retval = 1;
1943 	int i;
1944 	unsigned int s;
1945 	char tempstring[IPV6CALC_STRING_MAX];
1946 
1947 	snprintf(tempstring, sizeof(tempstring), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
1948 			(unsigned int) ipv6addrp->in6_addr.s6_addr[0],  \
1949 			(unsigned int) ipv6addrp->in6_addr.s6_addr[1],  \
1950 			(unsigned int) ipv6addrp->in6_addr.s6_addr[2],  \
1951 			(unsigned int) ipv6addrp->in6_addr.s6_addr[3],  \
1952 			(unsigned int) ipv6addrp->in6_addr.s6_addr[4],  \
1953 			(unsigned int) ipv6addrp->in6_addr.s6_addr[5],  \
1954 			(unsigned int) ipv6addrp->in6_addr.s6_addr[6],  \
1955 			(unsigned int) ipv6addrp->in6_addr.s6_addr[7],  \
1956 			(unsigned int) ipv6addrp->in6_addr.s6_addr[8],  \
1957 			(unsigned int) ipv6addrp->in6_addr.s6_addr[9],  \
1958 			(unsigned int) ipv6addrp->in6_addr.s6_addr[10], \
1959 			(unsigned int) ipv6addrp->in6_addr.s6_addr[11], \
1960 			(unsigned int) ipv6addrp->in6_addr.s6_addr[12], \
1961 			(unsigned int) ipv6addrp->in6_addr.s6_addr[13], \
1962 			(unsigned int) ipv6addrp->in6_addr.s6_addr[14], \
1963 			(unsigned int) ipv6addrp->in6_addr.s6_addr[15]  \
1964 		);
1965 
1966 	snprintf(resultstring, resultstring_length, "%s", tempstring);
1967 
1968 	if ((formatoptions & FORMATOPTION_printprefix) && (ipv6addrp->flag_prefixuse == 1)) {
1969 		// shorten string
1970 		resultstring[ipv6addrp->prefixlength / 4] = '\0';
1971 	} else if ((formatoptions & FORMATOPTION_printsuffix) && (ipv6addrp->flag_prefixuse == 1)) {
1972 		// move string
1973 		for (i = 0; i < 32 - (ipv6addrp->prefixlength / 4); i++) {
1974 			resultstring[i] = resultstring[i + (ipv6addrp->prefixlength / 4)];
1975 		};
1976 		resultstring[32 - (ipv6addrp->prefixlength / 4)] = '\0';
1977 	};
1978 
1979 	if (formatoptions & FORMATOPTION_printuppercase) {
1980 		for (s = 0; s < strlen(resultstring); s++) {
1981 			resultstring[s] = toupper(resultstring[s]);
1982 		};
1983 	};
1984 
1985 	retval = 0;
1986 	return (retval);
1987 };
1988 
1989 
1990 /*
1991  * retrieve payload of anonymized prefix
1992  *
1993  * in:  ipv6addrp  = pointer to IPv6 address structure
1994  *      payload_selector: payload which should be retrieved
1995  *      result_ptr = pointer to a 32-bit result
1996  * out: 0 = OK, !=0: not ok
1997  */
ipv6addr_get_payload_anonymized_prefix(const ipv6calc_ipv6addr * ipv6addrp,const int payload_selector,uint32_t * result_ptr)1998 int ipv6addr_get_payload_anonymized_prefix(const ipv6calc_ipv6addr *ipv6addrp, const int payload_selector, uint32_t *result_ptr) {
1999 	uint32_t prefix[2], flags;
2000 
2001 	prefix[0] = ipv6addr_getdword(ipv6addrp, 0);
2002 	prefix[1] = ipv6addr_getdword(ipv6addrp, 1);
2003 
2004 	// retrieve flags
2005 	flags = UNPACK_XMS(prefix[ANON_PREFIX_FLAGS_DWORD], ANON_PREFIX_FLAGS_XOR, ANON_PREFIX_FLAGS_MASK, ANON_PREFIX_FLAGS_SHIFT);
2006 
2007 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Get payload %d from %08x%08x (flags=%x)", payload_selector, prefix[0], prefix[1], flags);
2008 
2009 	if (payload_selector == ANON_PREFIX_PAYLOAD_FLAGS) {
2010 		*result_ptr = flags;
2011 	} else  {
2012 		if ((flags != 0) && (flags != 1)) {
2013 			// currently only flags=0| is supported
2014 			return(1);
2015 		};
2016 
2017 		if (payload_selector == ANON_PREFIX_PAYLOAD_CCINDEX) {
2018 			*result_ptr = UNPACK_XMS(prefix[ANON_PREFIX_CCINDEX_DWORD], ANON_PREFIX_CCINDEX_XOR, ANON_PREFIX_CCINDEX_MASK, ANON_PREFIX_CCINDEX_SHIFT);
2019 		} else if (payload_selector == ANON_PREFIX_PAYLOAD_ASN32) {
2020 			*result_ptr = (UNPACK_XMS(prefix[ANON_PREFIX_ASN32_MSB_DWORD], ANON_PREFIX_ASN32_MSB_XOR, ANON_PREFIX_ASN32_MSB_MASK, ANON_PREFIX_ASN32_MSB_SHIFT) << ANON_PREFIX_ASN32_LSB_AMOUNT)| (UNPACK_XMS(prefix[ANON_PREFIX_ASN32_LSB_DWORD], ANON_PREFIX_ASN32_LSB_XOR, ANON_PREFIX_ASN32_LSB_MASK, ANON_PREFIX_ASN32_LSB_SHIFT));
2021 		} else if (payload_selector == ANON_PREFIX_PAYLOAD_GEONAMEID) {
2022 			*result_ptr = (UNPACK_XMS(prefix[ANON_PREFIX_GEONAMEID_MSB_DWORD], ANON_PREFIX_GEONAMEID_MSB_XOR, ANON_PREFIX_GEONAMEID_MSB_MASK, ANON_PREFIX_GEONAMEID_MSB_SHIFT) << ANON_PREFIX_GEONAMEID_LSB_AMOUNT)| (UNPACK_XMS(prefix[ANON_PREFIX_GEONAMEID_LSB_DWORD], ANON_PREFIX_GEONAMEID_LSB_XOR, ANON_PREFIX_GEONAMEID_LSB_MASK, ANON_PREFIX_GEONAMEID_LSB_SHIFT));
2023 		} else if (payload_selector == ANON_PREFIX_PAYLOAD_GEONAMEID_TYPE) {
2024 			*result_ptr = UNPACK_XMS(prefix[ANON_PREFIX_GEONAMEID_TYPE_DWORD], ANON_PREFIX_GEONAMEID_TYPE_XOR, ANON_PREFIX_GEONAMEID_TYPE_MASK, ANON_PREFIX_GEONAMEID_TYPE_SHIFT);
2025 		} else {
2026 			ERRORPRINT_WA("payload_selector out of range, FIX CODE: %d", payload_selector);
2027 			exit(EXIT_FAILURE);
2028 		};
2029 	};
2030 
2031 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Extracted payload %d from %08x%08x: %08x", payload_selector, prefix[0], prefix[1], *result_ptr);
2032 
2033 	return(0);
2034 };
2035 
2036 
2037 /*
2038  * retrieve payload of anonymized IID
2039  *
2040  * in:  ipv6addrp  = pointer to IPv6 address structure
2041  * out: payload (max. 32 bit)
2042  */
ipv6addr_get_payload_anonymized_iid(const ipv6calc_ipv6addr * ipv6addrp,const uint32_t typeinfo)2043 uint32_t ipv6addr_get_payload_anonymized_iid(const ipv6calc_ipv6addr *ipv6addrp, const uint32_t typeinfo) {
2044 	uint32_t iid[2];
2045 	uint32_t payload = 0;
2046 
2047 	iid[0] = ipv6addr_getdword(ipv6addrp, 2);
2048 	iid[1] = ipv6addr_getdword(ipv6addrp, 3);
2049 
2050 	DEBUGPRINT_WA(DEBUG_libipv6addr, "typeinfo=%08x iid[0]=%08x iid[1]=%08x", typeinfo, iid[0], iid[1]);
2051 
2052 	if ((typeinfo & IPV6_NEW_ADDR_IID_EUI48) != 0) {
2053 		payload = (iid[1] >> ANON_IID_EUI48_PAYLOAD_SHIFT) & ((2 << ANON_IID_EUI48_PAYLOAD_LENGTH) - 1);
2054 	} else if ((typeinfo & IPV6_NEW_ADDR_IID_EUI64) != 0) {
2055 		payload = (iid[1] >> ANON_IID_EUI64_PAYLOAD_SHIFT) & ((2 << ANON_IID_EUI64_PAYLOAD_LENGTH) - 1);
2056 	} else if ((typeinfo & (IPV6_NEW_ADDR_IID_ISATAP|IPV6_ADDR_IID_32_63_HAS_IPV4)) != 0) {
2057 		payload = (iid[1] >> ANON_IID_ISATAP_PAYLOAD_SHIFT) & ((2 << ANON_IID_ISATAP_PAYLOAD_LENGTH) - 1);
2058 	} else if ((typeinfo & IPV6_ADDR_IID_32_63_HAS_IPV4) != 0) {
2059 		payload = (iid[1] >> ANON_IID_IPV4_PAYLOAD_SHIFT) & ((2 << ANON_IID_IPV4_PAYLOAD_LENGTH) - 1);
2060 	};
2061 
2062 	DEBUGPRINT_WA(DEBUG_libipv6addr, "payload=%08x", payload);
2063 
2064 	return(payload);
2065 };
2066 
2067 
2068 /*
2069  * anonymize IPv6 address
2070  *
2071  * in : *ipv6addrp = IPv6 address structure
2072  *      *ipv6calc_anon_set = anonymization set structure
2073  * ret: 0:anonymization ok
2074  *      1:anonymization method not supported
2075  */
libipv6addr_anonymize(ipv6calc_ipv6addr * ipv6addrp,const s_ipv6calc_anon_set * ipv6calc_anon_set)2076 int libipv6addr_anonymize(ipv6calc_ipv6addr *ipv6addrp, const s_ipv6calc_anon_set *ipv6calc_anon_set) {
2077 	/* anonymize IPv4 address according to settings */
2078 	uint32_t iid[2];
2079 	char tempstring[IPV6CALC_STRING_MAX];
2080 	char helpstring[IPV6CALC_STRING_MAX];
2081 	int i, r;
2082 	int calculate_checksum = 0;
2083 	int calculate_checksum_prefix = 0;
2084 	int zeroize_prefix = 0;
2085 	int zeroize_iid = 0;
2086 	int anonymized_prefix_nibbles = 0;
2087 
2088 	ipv6calc_macaddr   macaddr;
2089 	ipv6calc_eui64addr eui64addr;
2090 	ipv6calc_ipv4addr  ipv4addr;
2091 	ipv6calc_ipaddr    ipaddr;
2092 	uint32_t map_value;
2093 
2094 	uint16_t cc_index, flags = 0;
2095 	uint32_t as_num32, ipv6_prefix[2];
2096 
2097 	int mask_eui64  = ipv6calc_anon_set->mask_eui64;
2098 	// int mask_mac  = ipv6calc_anon_set->mask_mac; // currently not used
2099 	int mask_ipv6 = ipv6calc_anon_set->mask_ipv6;
2100 	int mask_ipv4 = ipv6calc_anon_set->mask_ipv4;
2101 	int method    = ipv6calc_anon_set->method;
2102 
2103 	uint8_t bit_ul = 0;
2104 
2105 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Called: addr=%08x %08x %08x %08x", ipv6addr_getdword(ipv6addrp, 0), ipv6addr_getdword(ipv6addrp, 1), ipv6addr_getdword(ipv6addrp, 2), ipv6addr_getdword(ipv6addrp, 3));
2106 
2107 	ipv6addr_settype(ipv6addrp);
2108 
2109 	if (method == ANON_METHOD_ZEROIZE) {
2110 		zeroize_prefix = 1;
2111 	};
2112 
2113 	if ( (ipv6calc_debug & DEBUG_libipv6addr) != 0 ) {	// ipv6calc_debug usage ok
2114 		libipv6calc_anon_infostring(tempstring, sizeof(tempstring), ipv6calc_anon_set);
2115 		DEBUGPRINT_WA(DEBUG_libipv6addr, "Anonymize IPv6 address flags: %s", tempstring);
2116 	};
2117 
2118 	if ((ipv6addrp->typeinfo & (IPV6_ADDR_ANONYMIZED_IID | IPV6_ADDR_ANONYMIZED_PREFIX)) != 0) {
2119 		DEBUGPRINT_NA(DEBUG_libipv6addr, "Already anonymized IPv6 address - skip");
2120 		return(0);
2121 	};
2122 
2123 	if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_6TO4) != 0) {
2124 		DEBUGPRINT_NA(DEBUG_libipv6addr, "Embedded IPv4 address, anonymize and store back");
2125 		ipv4addr_clearall(&ipv4addr);
2126 		/* extract IPv4 address */
2127 		for (i = 0; i <= 3; i++) {
2128 			ipv4addr_setoctet(&ipv4addr, (unsigned int) i, (unsigned int) ipv6addr_getoctet(ipv6addrp, (unsigned int) 2 + i));
2129 		};
2130 
2131 		ipv4addr_settype(&ipv4addr, 1); /* Set typeinfo */
2132 		ipv4addr.flag_valid = 1;
2133 		libipv4addr_anonymize(&ipv4addr, mask_ipv4, method);
2134 
2135 		/* store back */
2136 		for (i = 0; i <= 3; i++) {
2137 			ipv6addr_setoctet(ipv6addrp, (unsigned int) 2 + i, (unsigned int) ipv4addr_getoctet(&ipv4addr, (unsigned int) i));
2138 		};
2139 
2140 	};
2141 
2142 	if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_TEREDO) != 0) {
2143 		/* extract Teredo client IPv4 address */
2144 		ipv4addr_clearall(&ipv4addr);
2145 		for (i = 0; i <= 3; i++) {
2146 			ipv4addr_setoctet(&ipv4addr, (unsigned int) i, (unsigned int) ipv6addr_getoctet(ipv6addrp, (unsigned int) 12 + i) ^ 0xff);
2147 		};
2148 
2149 		ipv4addr_settype(&ipv4addr, 1);
2150 		ipv4addr.flag_valid = 1;
2151 		libipv4addr_anonymize(&ipv4addr, mask_ipv4, method);
2152 
2153 		/* store back */
2154 		for (i = 0; i <= 3; i++) {
2155 			ipv6addr_setoctet(ipv6addrp, (unsigned int) 12 + i, (unsigned int) ipv4addr_getoctet(&ipv4addr, (unsigned int) i) ^ 0xff);
2156 		};
2157 
2158 		/* clear client port */
2159 		ipv6addr_setword(ipv6addrp, 5, 0 ^ 0xffff);
2160 	};
2161 
2162 	if ((ipv6addrp->typeinfo & (IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_NEW_ADDR_NAT64)) != 0) {
2163 		/* extract IPv4 address */
2164 		ipv4addr_clearall(&ipv4addr);
2165 		for (i = 0; i <= 3; i++) {
2166 			ipv4addr_setoctet(&ipv4addr, (unsigned int) i, (unsigned int) ipv6addr_getoctet(ipv6addrp, (unsigned int) 12 + i));
2167 		};
2168 
2169 		ipv4addr_settype(&ipv4addr, 1);
2170 		ipv4addr.flag_valid = 1;
2171 		libipv4addr_anonymize(&ipv4addr, mask_ipv4, method);
2172 
2173 		/* store back */
2174 		for (i = 0; i <= 3; i++) {
2175 			ipv6addr_setoctet(ipv6addrp, (unsigned int) 12 + i, (unsigned int) ipv4addr_getoctet(&ipv4addr, (unsigned int) i));
2176 		};
2177 	};
2178 
2179 	/* prefix handling */
2180 	if ( ((ipv6addrp->typeinfo & (IPV6_ADDR_SITELOCAL | IPV6_ADDR_ULUA | IPV6_NEW_ADDR_AGU)) != 0) && ((ipv6addrp->typeinfo & (IPV6_NEW_ADDR_TEREDO | IPV6_NEW_ADDR_ORCHID)) == 0) ) {
2181 		/* prefix included */
2182 		DEBUGPRINT_WA(DEBUG_libipv6addr, "Prefix: pref=%08x %08x", ipv6addr_getdword(ipv6addrp, 0), ipv6addr_getdword(ipv6addrp, 1));
2183 
2184 		if (((ipv6addrp->typeinfo & IPV6_NEW_ADDR_AGU) != 0) && ((ipv6addrp->typeinfo & (IPV6_NEW_ADDR_6TO4)) == 0) \
2185 		    && ((method == ANON_METHOD_KEEPTYPEASNCC) || (method == ANON_METHOD_KEEPTYPEGEONAMEID))) {
2186 			uint32_t GeonameID_type = IPV6CALC_DB_GEO_GEONAMEID_TYPE_UNKNOWN;
2187 			uint32_t GeonameID = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN;
2188 
2189 			// check whether IPv6 address is anycast
2190 			if (((ipv6addrp->typeinfo & IPV6_ADDR_ANYCAST) != 0) && ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_LISP) != 0)) {
2191 				DEBUGPRINT_NA(DEBUG_libipv6addr, "IPv6 is LISP anycast, skip prefix anonymization");
2192 				goto InterfaceIdentifier;
2193 			};
2194 
2195 			// check whether IPv6 address is reserved
2196 			r = libipv6calc_db_wrapper_registry_string_by_ipv6addr(ipv6addrp, helpstring, sizeof(helpstring));
2197 			if (r == 2) {
2198 				DEBUGPRINT_NA(DEBUG_libipv6addr, "IPv6 registry of prefix contains reserved, skip anonymization");
2199 				goto InterfaceIdentifier;
2200 			};
2201 
2202 			if (method == ANON_METHOD_KEEPTYPEASNCC) {
2203 				if (libipv6calc_db_wrapper_has_features(ANON_METHOD_KEEPTYPEASNCC_IPV6_REQ_DB) == 0) {
2204 					DEBUGPRINT_NA(DEBUG_libipv6addr, "anonymization method not supported, db_wrapper reports too less features");
2205 					return(1);
2206 				};
2207 
2208 				// switch to prefix anonymization
2209 				if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_6BONE) != 0) {
2210 					DEBUGPRINT_NA(DEBUG_libipv6addr, "IPv6 is 6bone unicast, special prefix anonymization");
2211 					cc_index = COUNTRYCODE_INDEX_UNKNOWN_REGISTRY_MAP_MIN + IPV6_ADDR_REGISTRY_6BONE;
2212 
2213 					CONVERT_IPV6ADDRP_IPADDR(ipv6addrp, ipaddr);
2214 					as_num32 = libipv6calc_db_wrapper_as_num32_by_addr(&ipaddr, NULL);
2215 				} else if ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_LISP) != 0) {
2216 					DEBUGPRINT_NA(DEBUG_libipv6addr, "IPv6 is LISP unicast, special prefix anonymization");
2217 					cc_index = COUNTRYCODE_INDEX_LISP;
2218 
2219 					CONVERT_IPV6ADDRP_IPADDR(ipv6addrp, ipaddr);
2220 					as_num32 = libipv6calc_db_wrapper_as_num32_by_addr(&ipaddr, NULL);
2221 				} else {
2222 					CONVERT_IPV6ADDRP_IPADDR(ipv6addrp, ipaddr);
2223 
2224 					cc_index = libipv6calc_db_wrapper_cc_index_by_addr(&ipaddr, NULL);
2225 					as_num32 = libipv6calc_db_wrapper_as_num32_by_addr(&ipaddr, NULL);
2226 
2227 					if (cc_index == COUNTRYCODE_INDEX_UNKNOWN) {
2228 						// on unknown country, map registry value
2229 						cc_index = COUNTRYCODE_INDEX_UNKNOWN_REGISTRY_MAP_MIN + libipv6calc_db_wrapper_registry_num_by_ipv6addr(ipv6addrp);
2230 					};
2231 				};
2232 
2233 				DEBUGPRINT_WA(DEBUG_libipv6addr, "cc_index=%d (0x%03x) as_num32=%d (0x%08x)", cc_index, cc_index, as_num32, as_num32);
2234 			} else if (method == ANON_METHOD_KEEPTYPEGEONAMEID) {
2235 				if (libipv6calc_db_wrapper_has_features(ANON_METHOD_KEEPTYPEGEONAMEID_IPV6_REQ_DB) == 0) {
2236 					DEBUGPRINT_NA(DEBUG_libipv6addr, "anonymization method not supported, db_wrapper reports too less features");
2237 					return(1);
2238 				};
2239 
2240 				CONVERT_IPV6ADDRP_IPADDR(ipv6addrp, ipaddr);
2241 
2242 				if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_6BONE) != 0) {
2243 					DEBUGPRINT_NA(DEBUG_libipv6addr, "IPv6 is 6bone unicast, special prefix anonymization");
2244 					GeonameID_type = 0x0;
2245 					GeonameID_type |= REGISTRY_6BONE << 4;
2246 				} else if (((ipv6addrp->typeinfo & IPV6_ADDR_UNICAST) != 0) && ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_LISP) != 0)) {
2247 					DEBUGPRINT_NA(DEBUG_libipv6addr, "IPv6 is LISP unicast, special prefix anonymization");
2248 					GeonameID_type = 0x7;
2249 					GeonameID = 0x11800;
2250 					GeonameID_type |= (libipv6calc_db_wrapper_registry_num_by_ipv6addr(ipv6addrp) & 0x7) << 4;
2251 					GeonameID |= 0x000; // TODO: map LISP information into 11 LSB
2252 				} else {
2253 					// get GeonameID
2254 					GeonameID = libipv6calc_db_wrapper_GeonameID_by_addr(&ipaddr, NULL, &GeonameID_type);
2255 
2256 					// get registry
2257 					int registry = libipv6addr_registry_num_by_addr(ipv6addrp);
2258 
2259 					DEBUGPRINT_WA(DEBUG_libipv6addr, "result of GeonameID retrievement: %d (0x%08x) (source: %d) (registry: %d)", GeonameID, GeonameID, GeonameID_type, registry);
2260 
2261 					if (registry > 0) {
2262 						// store registry
2263 						GeonameID_type |= registry << 4;
2264 					};
2265 				};
2266 			};
2267 
2268 			ipv6_prefix[0] = 0; ipv6_prefix[1] = 0;
2269 
2270 			// store prefix
2271 			ipv6_prefix[ANON_PREFIX_TOKEN_DWORD] |= PACK_XMS(ANON_PREFIX_TOKEN_VALUE, ANON_PREFIX_TOKEN_XOR, ANON_PREFIX_TOKEN_MASK, ANON_PREFIX_TOKEN_SHIFT);
2272 
2273 			if (method == ANON_METHOD_KEEPTYPEASNCC) {
2274 				flags = 0x0;
2275 
2276 				// store cc_index
2277 				ipv6_prefix[ANON_PREFIX_CCINDEX_DWORD] |= PACK_XMS(cc_index, ANON_PREFIX_CCINDEX_XOR, ANON_PREFIX_CCINDEX_MASK, ANON_PREFIX_CCINDEX_SHIFT);
2278 
2279 				// store as_num32
2280 				ipv6_prefix[ANON_PREFIX_ASN32_MSB_DWORD] |= PACK_XMS(as_num32 >> ANON_PREFIX_ASN32_LSB_AMOUNT, ANON_PREFIX_ASN32_MSB_XOR, ANON_PREFIX_ASN32_MSB_MASK, ANON_PREFIX_ASN32_MSB_SHIFT);
2281 				ipv6_prefix[ANON_PREFIX_ASN32_LSB_DWORD] |= PACK_XMS(as_num32 & ANON_PREFIX_ASN32_LSB_MASK, ANON_PREFIX_ASN32_LSB_XOR, ANON_PREFIX_ASN32_LSB_MASK, ANON_PREFIX_ASN32_LSB_SHIFT);
2282 
2283 			} else if (method == ANON_METHOD_KEEPTYPEGEONAMEID) {
2284 				flags = 0x1;
2285 
2286 				// store type
2287 				ipv6_prefix[ANON_PREFIX_GEONAMEID_TYPE_DWORD] |= PACK_XMS(GeonameID_type, ANON_PREFIX_GEONAMEID_TYPE_XOR, ANON_PREFIX_GEONAMEID_TYPE_MASK, ANON_PREFIX_GEONAMEID_TYPE_SHIFT);
2288 
2289 				// store GeonameID
2290 				ipv6_prefix[ANON_PREFIX_GEONAMEID_MSB_DWORD] |= PACK_XMS(GeonameID >> ANON_PREFIX_GEONAMEID_LSB_AMOUNT, ANON_PREFIX_GEONAMEID_MSB_XOR, ANON_PREFIX_GEONAMEID_MSB_MASK, ANON_PREFIX_GEONAMEID_MSB_SHIFT);
2291 				ipv6_prefix[ANON_PREFIX_GEONAMEID_LSB_DWORD] |= PACK_XMS(GeonameID & ANON_PREFIX_GEONAMEID_LSB_MASK, ANON_PREFIX_GEONAMEID_LSB_XOR, ANON_PREFIX_GEONAMEID_LSB_MASK, ANON_PREFIX_GEONAMEID_LSB_SHIFT);
2292 			};
2293 
2294 			// store flags
2295 			ipv6_prefix[ANON_PREFIX_FLAGS_DWORD] |= PACK_XMS(flags, ANON_PREFIX_FLAGS_XOR, ANON_PREFIX_FLAGS_MASK, ANON_PREFIX_FLAGS_SHIFT);
2296 
2297 			DEBUGPRINT_WA(DEBUG_libipv6addr, "anonmized prefix for method=%d: %08x%08x", method, ipv6_prefix[0], ipv6_prefix[1]);
2298 
2299 			anonymized_prefix_nibbles = 0;
2300 
2301 			ipv6addr_setdword(ipv6addrp, 0, ipv6_prefix[0]);
2302 			ipv6addr_setdword(ipv6addrp, 1, ipv6_prefix[1]);
2303 			calculate_checksum_prefix = 1;
2304 
2305 		} else if (mask_ipv6 == 64) {
2306 			/* nothing to do */
2307 		} else if (mask_ipv6 < 16 || mask_ipv6 > 64) {
2308 			/* should not happen here */
2309 			fprintf(stderr, "%s/%s: 'mask_ipv6' has an unexpected illegal value: %d\n", __FILE__, __func__, mask_ipv6);
2310 			exit(EXIT_FAILURE);
2311 		} else {
2312 			if (((ipv6addrp->typeinfo & IPV6_ADDR_ANYCAST) != 0) && ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_LISP) != 0)) {
2313 				if (mask_ipv6 < 48) {
2314 					mask_ipv6 = 48; // keeping address type
2315 				};
2316 				DEBUGPRINT_WA(DEBUG_libipv6addr, "Mask adjusted to: %d", mask_ipv6);
2317 			};
2318 
2319 			DEBUGPRINT_WA(DEBUG_libipv6addr, "Mask prefix with mask: %d", mask_ipv6);
2320 
2321 			if (mask_ipv6 < 64 && mask_ipv6 > 32) {
2322 				if (zeroize_prefix != 0) {
2323 					ipv6addr_setdword(ipv6addrp, 1, ipv6addr_getdword(ipv6addrp, 1) & (0xffffffffu << ((unsigned int) 64 - mask_ipv6)));
2324 				} else {
2325 					ipv6addr_setdword(ipv6addrp, 1, (ipv6addr_getdword(ipv6addrp, 1) & (0xffffffffu << ((unsigned int) 64 - mask_ipv6))) | ((ANON_TOKEN_VALUE_00_31 | (ANON_TOKEN_VALUE_00_31 >> 16)) & ((0xffffffffu >> ((unsigned int) mask_ipv6 - 32)))));
2326 					anonymized_prefix_nibbles = (64 - mask_ipv6) / 4;
2327 				};
2328 			} else if (mask_ipv6 == 32) {
2329 				if (zeroize_prefix != 0) {
2330 					ipv6addr_setdword(ipv6addrp, 1, 0u);
2331 				} else {
2332 					ipv6addr_setdword(ipv6addrp, 1, ANON_TOKEN_VALUE_00_31 | (ANON_TOKEN_VALUE_00_31 >> 16));
2333 					anonymized_prefix_nibbles = 8;
2334 				};
2335 			} else if (mask_ipv6 < 32 && mask_ipv6 >= 16) {
2336 				if (zeroize_prefix != 0) {
2337 					ipv6addr_setdword(ipv6addrp, 1, 0u);
2338 					ipv6addr_setdword(ipv6addrp, 0, ipv6addr_getdword(ipv6addrp, 0) & (0xffffffffu << ((unsigned int) 32 - mask_ipv6)));
2339 				} else {
2340 					ipv6addr_setdword(ipv6addrp, 1, ANON_TOKEN_VALUE_00_31 | (ANON_TOKEN_VALUE_00_31 >> 16));
2341 					ipv6addr_setdword(ipv6addrp, 0, (ipv6addr_getdword(ipv6addrp, 0) & (0xffffffffu << ((unsigned int) 32 - mask_ipv6))) | ((ANON_TOKEN_VALUE_00_31 | (ANON_TOKEN_VALUE_00_31 >> 16)) & ((0xffffffffu >> ((unsigned int) mask_ipv6)))));
2342 					anonymized_prefix_nibbles = (64 - mask_ipv6) / 4;
2343 				};
2344 			};
2345 		};
2346 
2347 		/* restore prefix in special cases */
2348 		if ( ((ipv6addrp->typeinfo & IPV6_ADDR_SITELOCAL) != 0) && (mask_ipv6 < 10) ) {
2349 			ipv6addr_setword(ipv6addrp, 0, ipv6addr_getword(ipv6addrp, 1) | 0xfec0u);
2350 		} else if ( ((ipv6addrp->typeinfo & IPV6_ADDR_ULUA) != 0) && (mask_ipv6 < 7) ) {
2351 			ipv6addr_setoctet(ipv6addrp, 0, ipv6addr_getoctet(ipv6addrp, 0) | 0xfdu);
2352 		};
2353 
2354 		DEBUGPRINT_WA(DEBUG_libipv6addr, "Prefix: pref=%08x %08x (anonymized)", ipv6addr_getdword(ipv6addrp, 0), ipv6addr_getdword(ipv6addrp, 1));
2355 	};
2356 
2357 InterfaceIdentifier:
2358 	/* interface identifier handling */
2359 	if ( ( ((ipv6addrp->typeinfo & (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_SITELOCAL | IPV6_NEW_ADDR_AGU | IPV6_ADDR_ULUA )) != 0) || ((ipv6addrp->typeinfo & (IPV6_ADDR_LOOPBACK | IPV6_NEW_ADDR_SOLICITED_NODE)) == (IPV6_ADDR_LOOPBACK | IPV6_NEW_ADDR_SOLICITED_NODE)) ) && ((ipv6addrp->typeinfo & (IPV6_NEW_ADDR_TEREDO | IPV6_NEW_ADDR_ORCHID)) == 0) ) {
2360 		/* Interface identifier included */
2361 		if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_IID_EUI48) != 0) {
2362 			/* EUI-48 */
2363 
2364 			DEBUGPRINT_NA(DEBUG_libipv6addr, "EUI-48 identifier found");
2365 
2366 			if (method == ANON_METHOD_ZEROIZE) {
2367 				zeroize_iid = 1;
2368 			} else {
2369 				/* set anon interface ID, include shifted OUI bytes */
2370 				DEBUGPRINT_WA(DEBUG_libipv6addr, "Anonymize IPv6 address: OUI=%02x:%02x:%02x", ipv6addr_getoctet(ipv6addrp, 8) & 0xfc, ipv6addr_getoctet(ipv6addrp, 9), ipv6addr_getoctet(ipv6addrp, 10));
2371 
2372 				mac_clearall(&macaddr);
2373 				macaddr.addr[0] = ipv6addr_getoctet(ipv6addrp,  8) ^ 0x2;
2374 				macaddr.addr[1] = ipv6addr_getoctet(ipv6addrp,  9);
2375 				macaddr.addr[2] = ipv6addr_getoctet(ipv6addrp, 10);
2376 				macaddr.addr[3] = ipv6addr_getoctet(ipv6addrp, 13);
2377 				macaddr.addr[4] = ipv6addr_getoctet(ipv6addrp, 14);
2378 				macaddr.addr[5] = ipv6addr_getoctet(ipv6addrp, 15);
2379 				macaddr.flag_valid = 1;
2380 
2381 				map_value = libieee_map_oui_macaddr(&macaddr) ^ 0x00020000;
2382 
2383 				iid[0] = ANON_TOKEN_VALUE_00_31 | ANON_IID_EUI48_VALUE_00_31;
2384 				iid[1] = ANON_IID_EUI48_VALUE_32_63 | ((map_value & 0x1ffffff) << ANON_IID_EUI48_PAYLOAD_SHIFT);
2385 
2386 				ipv6addr_setdword(ipv6addrp, 2, iid[0]);
2387 				ipv6addr_setdword(ipv6addrp, 3, iid[1]);
2388 				calculate_checksum = 1;
2389 			};
2390 		} else {
2391 			if ( (ipv6addrp->typeinfo & IPV6_NEW_ADDR_IID_RANDOM) != 0 ) {
2392 				if (method == ANON_METHOD_ZEROIZE) {
2393 					/* mask ID according to mask_eui64 */
2394 					zeroize_iid = 1;
2395 				} else {
2396 					/* replace IID with special value */
2397 					iid[0] = ANON_TOKEN_VALUE_00_31 | ANON_IID_RANDOM_VALUE_00_31;
2398 					iid[1] = ANON_IID_RANDOM_VALUE_32_63;
2399 
2400 					ipv6addr_setdword(ipv6addrp, 2, iid[0]);
2401 					ipv6addr_setdword(ipv6addrp, 3, iid[1]);
2402 					calculate_checksum = 1;
2403 				};
2404 			} else if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_IID_EUI64) == IPV6_NEW_ADDR_IID_EUI64) {
2405 				/* Check for global EUI-64 */
2406 				if (method == ANON_METHOD_ZEROIZE) {
2407 					/* mask ID according to mask_eui64 */
2408 					zeroize_iid = 1;
2409 				} else {
2410 					libeui64_clearall(&eui64addr);
2411 					eui64addr.addr[0] = ipv6addr_getoctet(ipv6addrp,  8) ^ 0x2;
2412 					eui64addr.addr[1] = ipv6addr_getoctet(ipv6addrp,  9);
2413 					eui64addr.addr[2] = ipv6addr_getoctet(ipv6addrp, 10);
2414 					eui64addr.addr[3] = ipv6addr_getoctet(ipv6addrp, 11);
2415 					eui64addr.addr[4] = ipv6addr_getoctet(ipv6addrp, 12);
2416 					eui64addr.addr[5] = ipv6addr_getoctet(ipv6addrp, 13);
2417 					eui64addr.addr[6] = ipv6addr_getoctet(ipv6addrp, 14);
2418 					eui64addr.addr[7] = ipv6addr_getoctet(ipv6addrp, 15);
2419 					eui64addr.flag_valid = 1;
2420 
2421 					map_value = libieee_map_oui_eui64addr(&eui64addr) ^ 0x00020000;
2422 
2423 					iid[0] = ANON_TOKEN_VALUE_00_31 | ANON_IID_EUI64_VALUE_00_31;
2424 					iid[1] = ANON_IID_EUI64_VALUE_32_63 | ((map_value & 0x1ffffff) << ANON_IID_EUI64_PAYLOAD_SHIFT);
2425 
2426 					ipv6addr_setdword(ipv6addrp, 2, iid[0]);
2427 					ipv6addr_setdword(ipv6addrp, 3, iid[1]);
2428 					calculate_checksum = 1;
2429 				};
2430 			} else {
2431 				if ( (ipv6addrp->typeinfo & IPV6_NEW_ADDR_SOLICITED_NODE) != 0 ) {
2432 					/* zero'ise unique ID */
2433 					ipv6addr_setoctet(ipv6addrp, 13, 0x0u);
2434 					ipv6addr_setoctet(ipv6addrp, 14, 0x0u);
2435 					ipv6addr_setoctet(ipv6addrp, 15, 0x0u);
2436 				} else if ( (ipv6addrp->typeinfo & IPV6_NEW_ADDR_IID_ISATAP) != 0 )  {
2437 					/* ISATAP address */
2438 					if ( (ipv6addrp->typeinfo & IPV6_ADDR_IID_32_63_HAS_IPV4) != 0 ) {
2439 						/* IPv4 address included */
2440 
2441 						for (i = 0; i <= 3; i++) {
2442 							ipv4addr_setoctet(&ipv4addr, (unsigned int) i, (unsigned int) ipv6addr_getoctet(ipv6addrp, (unsigned int) (i + 12)));
2443 						};
2444 						libipv4addr_anonymize(&ipv4addr, mask_ipv4, method);
2445 
2446 						DEBUGPRINT_WA(DEBUG_libipv6addr, "ISATAP includes IPv4 address: IPv4=%d.%d.%d.%d, anonymized: %d.%d.%d.%d", ipv6addr_getoctet(ipv6addrp, 12), ipv6addr_getoctet(ipv6addrp, 13), ipv6addr_getoctet(ipv6addrp, 14), ipv6addr_getoctet(ipv6addrp, 15), ipv4addr_getoctet(&ipv4addr, 0), ipv4addr_getoctet(&ipv4addr, 1), ipv4addr_getoctet(&ipv4addr, 2), ipv4addr_getoctet(&ipv4addr, 3));
2447 
2448 						/* store back */
2449 						for (i = 0; i <= 3; i++) {
2450 							ipv6addr_setoctet(ipv6addrp, (unsigned int) 12 + i, (unsigned int) ipv4addr_getoctet(&ipv4addr, (unsigned int) i));
2451 						};
2452 
2453 						if (method == ANON_METHOD_ZEROIZE) {
2454 							// nothing to do, IPv4 address already anonymized
2455 						} else {
2456 							iid[0] = ANON_TOKEN_VALUE_00_31 | ANON_IID_ISATAP_VALUE_00_31;
2457 							iid[1] = (ipv6addr_getoctet(ipv6addrp, 12) << (ANON_IID_ISATAP_PAYLOAD_SHIFT + 16)) | (ipv6addr_getoctet(ipv6addrp, 13) << (ANON_IID_ISATAP_PAYLOAD_SHIFT + 8)) | (ipv6addr_getoctet(ipv6addrp, 14) << (ANON_IID_ISATAP_PAYLOAD_SHIFT));
2458 							iid[1] |= ANON_IID_ISATAP_TYPE_IPV4_VALUE_32_63;
2459 							calculate_checksum = 1;
2460 						};
2461 					} else if ((ipv6addr_getoctet(ipv6addrp, 11) == 0xff) && (ipv6addr_getoctet(ipv6addrp, 12) == 0xfe)) {
2462 						/* vendor ID included */
2463 						if (method == ANON_METHOD_ZEROIZE) {
2464 							/* zero'ise unique ID */
2465 							/* TODO: honor mask_eui64 */
2466 							ipv6addr_setoctet(ipv6addrp, 13, 0x0u);
2467 							ipv6addr_setoctet(ipv6addrp, 14, 0x0u);
2468 							ipv6addr_setoctet(ipv6addrp, 15, 0x0u);
2469 						} else {
2470 							iid[0] = ANON_TOKEN_VALUE_00_31 | ANON_IID_ISATAP_VALUE_00_31;
2471 							iid[1] = (ipv6addr_getoctet(ipv6addrp, 13) << (ANON_IID_ISATAP_PAYLOAD_SHIFT + 16));
2472 							iid[1] |= ANON_IID_ISATAP_TYPE_VENDOR_VALUE_32_63;
2473 							calculate_checksum = 1;
2474 						};
2475 					} else {
2476 						/* extension ID included */
2477 						if (method == ANON_METHOD_ZEROIZE) {
2478 							/* mask ID according to mask_eui64 */
2479 							zeroize_iid = 1;
2480 						} else {
2481 							iid[0] = ANON_TOKEN_VALUE_00_31 | ANON_IID_ISATAP_VALUE_00_31;
2482 							iid[1] = (ipv6addr_getoctet(ipv6addrp, 11) << (ANON_IID_ISATAP_PAYLOAD_SHIFT + 16)) | (ipv6addr_getoctet(ipv6addrp, 12) << (ANON_IID_ISATAP_PAYLOAD_SHIFT + 8)) | (ipv6addr_getoctet(ipv6addrp, 13) << (ANON_IID_ISATAP_PAYLOAD_SHIFT));
2483 							iid[1] |= ANON_IID_ISATAP_TYPE_EXTID_VALUE_32_63;
2484 							calculate_checksum = 1;
2485 						};
2486 					};
2487 
2488 					if (calculate_checksum == 1) {
2489 						/* store local/global bit */
2490 						DEBUGPRINT_NA(DEBUG_libipv6addr, "ISATAP: store local/global bit");
2491 						if ( (ipv6addrp->typeinfo & IPV6_NEW_ADDR_IID_GLOBAL) != 0 )  {
2492 							DEBUGPRINT_NA(DEBUG_libipv6addr, "ISATAP: store global bit");
2493 							iid[1] |= ANON_IID_ISATAP_SCOPE_GLOBAL;
2494 						} else if ( (ipv6addrp->typeinfo & IPV6_NEW_ADDR_IID_LOCAL) != 0 ) {
2495 							DEBUGPRINT_NA(DEBUG_libipv6addr, "ISATAP: store local bit");
2496 							iid[1] |= ANON_IID_ISATAP_SCOPE_LOCAL;
2497 						};
2498 						ipv6addr_setdword(ipv6addrp, 2, iid[0]);
2499 						ipv6addr_setdword(ipv6addrp, 3, iid[1]);
2500 					};
2501 
2502 				} else if ( ( ( (ipv6addrp->typeinfo & IPV6_ADDR_LINKLOCAL) != 0) && (ipv6addr_getdword(ipv6addrp, 2) == 0 && ipv6addr_getword(ipv6addrp, 6) != 0)) )   {
2503 					/* fe80:: must have 0000:0000:xxxx:yyyy where xxxx > 0 */
2504 					for (i = 0; i <= 3; i++) {
2505 						ipv4addr_setoctet(&ipv4addr, (unsigned int) i, (unsigned int) ipv6addr_getoctet(ipv6addrp, (unsigned int) (i + 12)));
2506 					};
2507 
2508 					libipv4addr_anonymize(&ipv4addr, mask_ipv4, method);
2509 
2510 					/* store back */
2511 					for (i = 0; i <= 3; i++) {
2512 						ipv6addr_setoctet(ipv6addrp, (unsigned int) 12 + i, (unsigned int) ipv4addr_getoctet(&ipv4addr, (unsigned int) i));
2513 					};
2514 				} else {
2515 					if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_6TO4_MICROSOFT) != 0) {
2516 						/* extract IPv4 address */
2517 						for (i = 0; i <= 3; i++) {
2518 							ipv4addr_setoctet(&ipv4addr, (unsigned int) i, (unsigned int) ipv6addr_getoctet(ipv6addrp, (unsigned int) (i + 12)));
2519 						};
2520 
2521 						libipv4addr_anonymize(&ipv4addr, mask_ipv4, method);
2522 
2523 						if (method == ANON_METHOD_ZEROIZE) {
2524 							/* store back */
2525 							for (i = 0; i <= 3; i++) {
2526 								ipv6addr_setoctet(ipv6addrp, (unsigned int) 12 + i, (unsigned int) ipv4addr_getoctet(&ipv4addr, (unsigned int) i));
2527 							};
2528 						} else {
2529 							iid[0] = ANON_TOKEN_VALUE_00_31 | ANON_IID_IPV4_VALUE_00_31;
2530 							iid[1] = ANON_IID_IPV4_VALUE_32_63 | (ipv4addr_getoctet(&ipv4addr, 0) << (ANON_IID_IPV4_PAYLOAD_SHIFT + 16)) | (ipv4addr_getoctet(&ipv4addr, 1) << (ANON_IID_IPV4_PAYLOAD_SHIFT + 8)) | (ipv4addr_getoctet(&ipv4addr, 2) << (ANON_IID_IPV4_PAYLOAD_SHIFT));
2531 
2532 							ipv6addr_setdword(ipv6addrp, 2, iid[0]);
2533 							ipv6addr_setdword(ipv6addrp, 3, iid[1]);
2534 							calculate_checksum = 1;
2535 						};
2536 					} else {
2537 						/* Identifier has local scope */
2538 						if (method == ANON_METHOD_ZEROIZE) {
2539 							/* mask ID according to mask_eui64 */
2540 							zeroize_iid = 1;
2541 						} else {
2542 							iid[0] = ANON_TOKEN_VALUE_00_31 | ANON_IID_STATIC_VALUE_00_31;
2543 							iid[1] = ANON_IID_STATIC_VALUE_32_63;
2544 
2545 							ipv6addr_setdword(ipv6addrp, 2, iid[0]);
2546 							ipv6addr_setdword(ipv6addrp, 3, iid[1]);
2547 							calculate_checksum = 1;
2548 						};
2549 					};
2550 				};
2551 			};
2552 		};
2553 	};
2554 
2555 	/* ORCHID hash */
2556 	if ( (ipv6addrp->typeinfo & IPV6_NEW_ADDR_ORCHID) != 0 ) {
2557 		DEBUGPRINT_NA(DEBUG_libipv6addr, "ORCHID address found");
2558 
2559 		if (method == ANON_METHOD_ZEROIZE) {
2560 			/* mask 100 LSBs */
2561 			ipv6addr_setword(ipv6addrp, 7, 0x0u);
2562 			ipv6addr_setword(ipv6addrp, 6, 0x0u);
2563 			ipv6addr_setword(ipv6addrp, 5, 0x0u);
2564 			ipv6addr_setword(ipv6addrp, 4, 0x0u);
2565 		} else {
2566 			iid[0] = ANON_TOKEN_VALUE_00_31 | ANON_ORCHID_VALUE_00_31;
2567 			iid[1] = ANON_ORCHID_VALUE_32_63;
2568 			ipv6addr_setdword(ipv6addrp, 2, iid[0]);
2569 			ipv6addr_setdword(ipv6addrp, 3, iid[1]);
2570 			calculate_checksum = 1;
2571 		};
2572 
2573 		if (zeroize_prefix != 0) {
2574 			ipv6addr_setword(ipv6addrp, 3, 0x0u);
2575 			ipv6addr_setword(ipv6addrp, 2, 0x0u);
2576 			ipv6addr_setword(ipv6addrp, 1, ipv6addr_getword(ipv6addrp, 1) & 0xFFF0);
2577 		} else {
2578 			ipv6addr_setdword(ipv6addrp, 1, (ANON_TOKEN_VALUE_00_31 | (ANON_TOKEN_VALUE_00_31 >> 16)));
2579 			ipv6addr_setword(ipv6addrp, 1, (ipv6addr_getword(ipv6addrp, 1) & 0xFFF0) | ((ANON_TOKEN_VALUE_00_31 >> 16) & 0xF));
2580 			anonymized_prefix_nibbles = (64 - 28) / 4;
2581 		};
2582 	};
2583 
2584 	/* switch prefix anonymization if IID is not anonymizied in reliable way */
2585 	if (calculate_checksum == 0) {
2586 		zeroize_prefix = 1;
2587 	} else {
2588 		ipv6addrp->typeinfo |= IPV6_ADDR_ANONYMIZED_IID;
2589 	};
2590 
2591 	if (zeroize_iid == 1) {
2592 		DEBUGPRINT_WA(DEBUG_libipv6addr, "Zeroize IID with mask: %d", mask_eui64);
2593 
2594 		libeui64_clearall(&eui64addr);
2595 
2596 		eui64addr.addr[0] = ipv6addr_getoctet(ipv6addrp,  8) ^ 0x2;
2597 		eui64addr.addr[1] = ipv6addr_getoctet(ipv6addrp,  9);
2598 		eui64addr.addr[2] = ipv6addr_getoctet(ipv6addrp, 10);
2599 		eui64addr.addr[3] = ipv6addr_getoctet(ipv6addrp, 11);
2600 		eui64addr.addr[4] = ipv6addr_getoctet(ipv6addrp, 12);
2601 		eui64addr.addr[5] = ipv6addr_getoctet(ipv6addrp, 13);
2602 		eui64addr.addr[6] = ipv6addr_getoctet(ipv6addrp, 14);
2603 		eui64addr.addr[7] = ipv6addr_getoctet(ipv6addrp, 15);
2604 		eui64addr.flag_valid = 1;
2605 
2606 		bit_ul = eui64addr.addr[0] & 0x02;
2607 
2608 		libeui64_anonymize(&eui64addr, ipv6calc_anon_set); // covers also EUI-48
2609 
2610 		if ((mask_eui64 < 7) && (ipv6calc_anon_set->mask_autoadjust == 0) && (bit_ul == 0x0)) {
2611 			DEBUGPRINT_WA(DEBUG_libipv6addr, "mask_eui64 < 7 AND EUI-64 was %s AND mask_autoadjust not set, do not invert universal/local bit for IID (for backwards compatibility reason", (bit_ul == 2) ? "local" : "universal");
2612 
2613 			eui64addr.addr[0] |= 0x02; // will be inverted and therefore cleared next
2614 		};
2615 
2616 		ipv6addr_setoctet(ipv6addrp,  8, eui64addr.addr[0] ^ 0x2);
2617 		ipv6addr_setoctet(ipv6addrp,  9, eui64addr.addr[1]);
2618 		ipv6addr_setoctet(ipv6addrp, 10, eui64addr.addr[2]);
2619 		ipv6addr_setoctet(ipv6addrp, 11, eui64addr.addr[3]);
2620 		ipv6addr_setoctet(ipv6addrp, 12, eui64addr.addr[4]);
2621 		ipv6addr_setoctet(ipv6addrp, 13, eui64addr.addr[5]);
2622 		ipv6addr_setoctet(ipv6addrp, 14, eui64addr.addr[6]);
2623 		ipv6addr_setoctet(ipv6addrp, 15, eui64addr.addr[7]);
2624 	};
2625 
2626 	// checksumming
2627 	if (calculate_checksum == 1) {
2628 		if (anonymized_prefix_nibbles > 0) {
2629 			/* fill amount of nibbles into IID lead token */
2630 			DEBUGPRINT_WA(DEBUG_libipv6addr, "Store amount of anonymized nibbles to IID lead token: %d", anonymized_prefix_nibbles);
2631 
2632 			ipv6addr_setoctet(ipv6addrp, 9, ipv6addr_getoctet(ipv6addrp, 9) | (anonymized_prefix_nibbles << 4));
2633 		};
2634 
2635 		ipv6addr_set_checksum_anonymized_iid(ipv6addrp);
2636 	};
2637 
2638 	if (calculate_checksum_prefix == 1) {
2639 		ipv6addr_set_checksum_anonymized_prefix(ipv6addrp);
2640 		ipv6addrp->typeinfo |= IPV6_ADDR_ANONYMIZED_PREFIX;
2641 	};
2642 
2643 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Result: addr=%08x %08x %08x %08x (anonymized)", ipv6addr_getdword(ipv6addrp, 0), ipv6addr_getdword(ipv6addrp, 1), ipv6addr_getdword(ipv6addrp, 2), ipv6addr_getdword(ipv6addrp, 3));
2644 
2645 	return(0);
2646 };
2647 
2648 
2649 /*
2650  * clear filter IPv6 address
2651  *
2652  * in : *filter    = filter structure
2653  */
ipv6addr_filter_clear(s_ipv6calc_filter_ipv6addr * filter)2654 void ipv6addr_filter_clear(s_ipv6calc_filter_ipv6addr *filter) {
2655 	filter->active = 0;
2656 
2657 	filter->filter_typeinfo.active = 0;
2658 	filter->filter_typeinfo.typeinfo_must_have = 0;
2659 	filter->filter_typeinfo.typeinfo_may_not_have = 0;
2660 	filter->filter_typeinfo2.typeinfo_must_have = 0;
2661 	filter->filter_typeinfo2.typeinfo_may_not_have = 0;
2662 
2663 	libipv6calc_filter_clear_db_cc(&filter->filter_db_cc);
2664 	libipv6calc_filter_clear_db_asn(&filter->filter_db_asn);
2665 	libipv6calc_filter_clear_db_registry(&filter->filter_db_registry);
2666 
2667 	filter->filter_addr.active = 0;
2668 	filter->filter_addr.addr_must_have_max = 0;
2669 	filter->filter_addr.addr_may_not_have_max = 0;
2670 
2671 	return;
2672 };
2673 
2674 
2675 /*
2676  * parse filter IPv6
2677  *
2678  * in : *filter    = filter structure
2679  * ret: 0:found 1:skip 2:problem
2680  */
ipv6addr_filter_parse(s_ipv6calc_filter_ipv6addr * filter,const char * token)2681 int ipv6addr_filter_parse(s_ipv6calc_filter_ipv6addr *filter, const char *token) {
2682 	int i, result = 1, negate = 0, offset = 0, r;
2683 	const char *prefix = "ipv6";
2684 	const char *prefixdot = "ipv6.";
2685 	const char *prefixdbdot = "db.";
2686 	const char *prefixaddreq = "addr=";
2687 	const char *prefixaddreq_le = "addr<=";
2688 	const char *prefixaddreq_lt = "addr<";
2689 	const char *prefixaddreq_ge = "addr>=";
2690 	const char *prefixaddreq_gt = "addr>";
2691 	const char *prefixaddreq_le2 = "addr=le=";
2692 	const char *prefixaddreq_lt2 = "addr=lt=";
2693 	const char *prefixaddreq_ge2 = "addr=ge=";
2694 	const char *prefixaddreq_gt2 = "addr=gt=";
2695 	ipv6calc_ipv6addr ipv6addr;
2696 	char resultstring[IPV6CALC_STRING_MAX];
2697 	int db = 0;
2698 	int addr_test_method = IPV6CALC_TEST_NONE;
2699 
2700 	if (token == NULL) {
2701 		return (result);
2702 	};
2703 
2704 	DEBUGPRINT_WA(DEBUG_libipv6addr, "input: %s", token);
2705 
2706 	if (token[0] == '^') {
2707 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found negate prefix in token: %s", token);
2708 
2709 		negate = 1;
2710 		offset += 1;
2711 	};
2712 
2713 	// typeinfo
2714 	if (strcmp(token + offset, prefix) == 0) {
2715 		/* any */
2716 		if (negate == 1) {
2717 			filter->filter_typeinfo.typeinfo_may_not_have = ~IPV6_ADDR_ANY;
2718 		} else {
2719 			filter->filter_typeinfo.typeinfo_must_have = IPV6_ADDR_ANY;
2720 		};
2721 		filter->filter_typeinfo.active = 1;
2722 		filter->active = 1;
2723 		result = 0;
2724 		goto END_ipv6addr_filter_parse;
2725 
2726 	} else if (strncmp(token + offset, prefixdot, strlen(prefixdot)) == 0) {
2727 		/* prefix with dot found */
2728 		offset += strlen(prefixdot);
2729 		result = 2; /* token with prefix, result into problem if not found */
2730 
2731 		DEBUGPRINT_WA(DEBUG_libipv6addr, "token with prefix, suffix: %s", token + offset);
2732 	};
2733 
2734 	if (strncmp(token + offset, prefixaddreq_le, strlen(prefixaddreq_le)) == 0) {
2735 		/* prefixaddr with = found */
2736 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'addr<=' prefix in token: %s", token);
2737 		offset += strlen(prefixaddreq_le);
2738 		addr_test_method = IPV6CALC_TEST_LE;
2739 
2740 	} else if (strncmp(token + offset, prefixaddreq_lt, strlen(prefixaddreq_lt)) == 0) {
2741 		/* prefixaddr with = found */
2742 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'addr<' prefix in token: %s", token);
2743 		offset += strlen(prefixaddreq_lt);
2744 		addr_test_method = IPV6CALC_TEST_LT;
2745 
2746 	} else if (strncmp(token + offset, prefixaddreq_ge, strlen(prefixaddreq_ge)) == 0) {
2747 		/* prefixaddr with = found */
2748 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'addr>=' prefix in token: %s", token);
2749 		offset += strlen(prefixaddreq_ge);
2750 		addr_test_method = IPV6CALC_TEST_GE;
2751 
2752 	} else if (strncmp(token + offset, prefixaddreq_gt, strlen(prefixaddreq_gt)) == 0) {
2753 		/* prefixaddr with = found */
2754 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'addr>' prefix in token: %s", token);
2755 		offset += strlen(prefixaddreq_gt);
2756 		addr_test_method = IPV6CALC_TEST_GT;
2757 
2758 	} else if (strncmp(token + offset, prefixaddreq_le2, strlen(prefixaddreq_le2)) == 0) {
2759 		/* prefixaddr with = found */
2760 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'addr=le=' prefix in token: %s", token);
2761 		offset += strlen(prefixaddreq_le2);
2762 		addr_test_method = IPV6CALC_TEST_LE;
2763 
2764 	} else if (strncmp(token + offset, prefixaddreq_lt2, strlen(prefixaddreq_lt2)) == 0) {
2765 		/* prefixaddr with = found */
2766 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'addr=lt=' prefix in token: %s", token);
2767 		offset += strlen(prefixaddreq_lt2);
2768 		addr_test_method = IPV6CALC_TEST_LT;
2769 
2770 	} else if (strncmp(token + offset, prefixaddreq_ge2, strlen(prefixaddreq_ge2)) == 0) {
2771 		/* prefixaddr with = found */
2772 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'addr=ge=' prefix in token: %s", token);
2773 		offset += strlen(prefixaddreq_ge2);
2774 		addr_test_method = IPV6CALC_TEST_GE;
2775 
2776 	} else if (strncmp(token + offset, prefixaddreq_gt2, strlen(prefixaddreq_gt2)) == 0) {
2777 		/* prefixaddr with = found */
2778 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'addr=gt=' prefix in token: %s", token);
2779 		offset += strlen(prefixaddreq_gt2);
2780 		addr_test_method = IPV6CALC_TEST_GT;
2781 
2782 	} else if (strncmp(token + offset, prefixaddreq, strlen(prefixaddreq)) == 0) {
2783 		/* prefixaddr with = found */
2784 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'addr=' prefix in token: %s", token);
2785 		offset += strlen(prefixaddreq);
2786 		addr_test_method = IPV6CALC_TEST_PREFIX;
2787 
2788 
2789 	} else if (strncmp(token + offset, prefixdbdot, strlen(prefixdbdot)) == 0) {
2790 		/* prefixdb with dot found */
2791 		DEBUGPRINT_WA(DEBUG_libipv6addr, "found 'db.' prefix in token: %s", token);
2792 		db = 1;
2793 
2794 	} else if (strstr(token, ".") != NULL) {
2795 		/* other prefix */
2796 		DEBUGPRINT_WA(DEBUG_libipv6addr, "prefix did not match: %s", token + offset);
2797 		return(1);
2798 	};
2799 
2800 
2801 	if ((db == 0) && (addr_test_method == IPV6CALC_TEST_NONE)) {
2802 		// typeinfo token
2803 		for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_ipv6addrtypestrings); i++ ) {
2804 			DEBUGPRINT_WA(DEBUG_libipv6addr, "check token against: %s", ipv6calc_ipv6addrtypestrings[i].token);
2805 
2806 			if (strcmp(ipv6calc_ipv6addrtypestrings[i].token, token + offset) == 0) {
2807 				DEBUGPRINT_WA(DEBUG_libipv6addr, "token match: %s", ipv6calc_ipv6addrtypestrings[i].token);
2808 
2809 				if (negate == 1) {
2810 					filter->filter_typeinfo.typeinfo_may_not_have |= ipv6calc_ipv6addrtypestrings[i].number;
2811 				} else {
2812 					filter->filter_typeinfo.typeinfo_must_have |= ipv6calc_ipv6addrtypestrings[i].number;
2813 				};
2814 				filter->filter_typeinfo.active = 1;
2815 				filter->active = 1;
2816 				result = 0;
2817 				break;
2818 			};
2819 		};
2820 
2821 		// typeinfo2 token
2822 		for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_ipv6addr_type2_strings); i++ ) {
2823 			DEBUGPRINT_WA(DEBUG_libipv6addr, "check token against: %s", ipv6calc_ipv6addr_type2_strings[i].token);
2824 
2825 			if (strcmp(ipv6calc_ipv6addr_type2_strings[i].token, token + offset) == 0) {
2826 				DEBUGPRINT_WA(DEBUG_libipv6addr, "token match: %s", ipv6calc_ipv6addr_type2_strings[i].token);
2827 
2828 				if (negate == 1) {
2829 					filter->filter_typeinfo2.typeinfo_may_not_have |= ipv6calc_ipv6addr_type2_strings[i].number;
2830 				} else {
2831 					filter->filter_typeinfo2.typeinfo_must_have |= ipv6calc_ipv6addr_type2_strings[i].number;
2832 				};
2833 				filter->filter_typeinfo2.active = 1;
2834 				filter->active = 1;
2835 				result = 0;
2836 				break;
2837 			};
2838 		};
2839 	};
2840 
2841 	if (db == 1) {
2842 		// DB CC filter
2843 		r = libipv6calc_db_cc_filter_parse(&filter->filter_db_cc, token + offset, negate);
2844 		if (r == 0) {
2845 			result = 0;
2846 			filter->active = 1;
2847 		};
2848 
2849 		// DB ASN filter
2850 		r = libipv6calc_db_asn_filter_parse(&filter->filter_db_asn, token + offset, negate);
2851 		if (r == 0) {
2852 			result = 0;
2853 			filter->active = 1;
2854 		};
2855 
2856 		// DB registry filter
2857 		r = libipv6calc_db_registry_filter_parse(&filter->filter_db_registry, token + offset, negate);
2858 		if (r == 0) {
2859 			result = 0;
2860 			filter->active = 1;
2861 		};
2862 	};
2863 
2864 
2865 	if (addr_test_method != IPV6CALC_TEST_NONE) {
2866 		DEBUGPRINT_WA(DEBUG_libipv6addr, "try to parse IPv6 address: %s", token + offset);
2867 		r = addr_to_ipv6addrstruct(token + offset, resultstring, sizeof(resultstring), &ipv6addr);
2868 
2869 		if (r == 0) {
2870 			DEBUGPRINT_WA(DEBUG_libipv6addr, "successfully parsed IPv6 address: %s", token + offset);
2871 
2872 			// store address test method in 'flag_startend_use'
2873 			ipv6addr.test_mode = addr_test_method;
2874 
2875 			if (negate == 1) {
2876 				if (filter->filter_addr.addr_may_not_have_max < IPV6CALC_FILTER_IPV6ADDR) {
2877 					ipv6addr_copy(&filter->filter_addr.ipv6addr_may_not_have[filter->filter_addr.addr_may_not_have_max], &ipv6addr);
2878         				filter->filter_addr.addr_may_not_have_max++;
2879 					filter->filter_addr.active = 1;
2880 					filter->active = 1;
2881 					result = 0;
2882 				} else {
2883 					ERRORPRINT_WA("filter token 'addr=' maxmimum reached for 'may not have': %d", filter->filter_addr.addr_may_not_have_max);
2884 				};
2885 			} else {
2886 				if (filter->filter_addr.addr_must_have_max < IPV6CALC_FILTER_IPV6ADDR) {
2887 					ipv6addr_copy(&filter->filter_addr.ipv6addr_must_have[filter->filter_addr.addr_must_have_max], &ipv6addr);
2888         				filter->filter_addr.addr_must_have_max++;
2889 					filter->filter_addr.active = 1;
2890 					filter->active = 1;
2891 					result = 0;
2892 				} else {
2893 					ERRORPRINT_WA("filter token 'addr=' maxmimum reached for 'must have': %d", filter->filter_addr.addr_must_have_max);
2894 				};
2895 			};
2896 		};
2897 	};
2898 
2899 	if (result != 0) {
2900 		DEBUGPRINT_WA(DEBUG_libipv6addr, "token not supported: %s", token);
2901 		return (result);
2902 	};
2903 
2904 END_ipv6addr_filter_parse:
2905 	return (result);
2906 };
2907 
2908 
2909 /*
2910  * check filter IPv6
2911  *
2912  * in : *filter    = filter structure
2913  * ret: 0:ok 1:problem
2914  */
ipv6addr_filter_check(const s_ipv6calc_filter_ipv6addr * filter)2915 int ipv6addr_filter_check(const s_ipv6calc_filter_ipv6addr *filter) {
2916 	int result = 0, r, i;
2917 	char resultstring[IPV6CALC_STRING_MAX];
2918 
2919 	DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter general active          : %d", filter->active);
2920 
2921 	DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'typeinfo' active       : %d", filter->filter_typeinfo.active);
2922 	if (filter->filter_typeinfo.active > 0) {
2923 		DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'typeinfo/must_have'    : 0x%08x", filter->filter_typeinfo.typeinfo_must_have);
2924 		DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'typeinfo/may_not_have' : 0x%08x", filter->filter_typeinfo.typeinfo_may_not_have);
2925 	};
2926 
2927 	DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'typeinfo2' active      : %d", filter->filter_typeinfo2.active);
2928 	if (filter->filter_typeinfo2.active > 0) {
2929 		DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'typeinfo2/must_have'   : 0x%08x", filter->filter_typeinfo2.typeinfo_must_have);
2930 		DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'typeinfo2/may_not_have': 0x%08x", filter->filter_typeinfo2.typeinfo_may_not_have);
2931 	};
2932 
2933 	DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'addr' active           : %d", filter->filter_addr.active);
2934 	if (filter->filter_addr.active > 0) {
2935 		if (filter->filter_addr.addr_must_have_max > 0) {
2936 			for (i = 0; i < filter->filter_addr.addr_must_have_max; i++) {
2937 				ipv6addrstruct_to_compaddr(&filter->filter_addr.ipv6addr_must_have[i], resultstring, sizeof(resultstring));
2938 				DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'addr/must_have'        : %s", resultstring);
2939 			};
2940 		};
2941 		if (filter->filter_addr.addr_may_not_have_max > 0) {
2942 			for (i = 0; i < filter->filter_addr.addr_may_not_have_max; i++) {
2943 				ipv6addrstruct_to_compaddr(&filter->filter_addr.ipv6addr_may_not_have[i], resultstring, sizeof(resultstring));
2944 				DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'addr/may_not_have'     : %s", resultstring);
2945 			};
2946 		};
2947 	};
2948 
2949 	DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'db.cc' active          : %d", filter->filter_db_cc.active);
2950 	if (filter->filter_db_cc.active > 0) {
2951 		r = libipv6calc_db_cc_filter_check(&filter->filter_db_cc, IPV6CALC_PROTO_IPV6);
2952 		if (r > 0) { result = 1; };
2953 	};
2954 
2955 	DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'db.asn' active         : %d", filter->filter_db_asn.active);
2956 	if (filter->filter_db_asn.active > 0) {
2957 		r = libipv6calc_db_asn_filter_check(&filter->filter_db_asn, IPV6CALC_PROTO_IPV6);
2958 		if (r > 0) { result = 1; };
2959 	};
2960 
2961 	DEBUGPRINT_WA(DEBUG_libipv6addr, "ipv6 filter 'db.registry' active    : %d", filter->filter_db_registry.active);
2962 	if (filter->filter_db_registry.active > 0) {
2963 		r = libipv6calc_db_registry_filter_check(&filter->filter_db_registry, IPV6CALC_PROTO_IPV6);
2964 		if (r > 0) { result = 1; };
2965 	};
2966 
2967 //END_ipv6addr_filter_check:
2968 	return (result);
2969 };
2970 
2971 
2972 /*
2973  * filter IPv6 address
2974  *
2975  * in : *ipv6addrp = IPv6 address structure
2976  * in : *filter    = filter structure
2977  * ret: 0=match 1=not match
2978  */
ipv6addr_filter(const ipv6calc_ipv6addr * ipv6addrp,const s_ipv6calc_filter_ipv6addr * filter)2979 int ipv6addr_filter(const ipv6calc_ipv6addr *ipv6addrp, const s_ipv6calc_filter_ipv6addr *filter) {
2980 	int result = 0, r, i, t;
2981 
2982 	if (filter->active == 0) {
2983 		DEBUGPRINT_NA(DEBUG_libipv6addr, "No filter active (SKIP)");
2984 		return (1);
2985 	};
2986 
2987 	DEBUGPRINT_NA(DEBUG_libipv6addr, "start");
2988 
2989 	if ((filter->filter_typeinfo.active > 0) || (filter->filter_typeinfo2.active > 0)) {
2990 		if (ipv6addrp->flag_typeinfo == 0) {
2991 			fprintf(stderr, "FATAL error, typeinfo not valid - FIX CODE of caller\n");
2992 			exit(2);
2993 		};
2994 	};
2995 
2996 	if (filter->filter_typeinfo.active > 0) {
2997 		DEBUGPRINT_WA(DEBUG_libipv6addr, "compare typeinfo against must_have: 0x%08x/0x%08x", ipv6addrp->typeinfo, filter->filter_typeinfo.typeinfo_must_have);
2998 
2999 		if ((ipv6addrp->typeinfo & filter->filter_typeinfo.typeinfo_must_have) != filter->filter_typeinfo.typeinfo_must_have) {
3000 			/* no match */
3001 			result = 1;
3002 		} else {
3003 			if ((ipv6addrp->typeinfo & filter->filter_typeinfo.typeinfo_may_not_have) != 0) {
3004 				/* no match */
3005 				result = 1;
3006 			};
3007 		};
3008 	};
3009 
3010 	if (filter->filter_typeinfo2.active > 0) {
3011 		DEBUGPRINT_WA(DEBUG_libipv6addr, "compare typeinfo2 against must_have: 0x%08x/0x%08x", ipv6addrp->typeinfo2, filter->filter_typeinfo2.typeinfo_must_have);
3012 
3013 		if ((ipv6addrp->typeinfo2 & filter->filter_typeinfo2.typeinfo_must_have) != filter->filter_typeinfo2.typeinfo_must_have) {
3014 			/* no match */
3015 			result = 1;
3016 		} else {
3017 			if ((ipv6addrp->typeinfo & filter->filter_typeinfo2.typeinfo_may_not_have) != 0) {
3018 				/* no match */
3019 				result = 1;
3020 			};
3021 		};
3022 	};
3023 
3024 	if (filter->filter_addr.active > 0) {
3025 		if (filter->filter_addr.addr_must_have_max > 0) {
3026 			DEBUGPRINT_NA(DEBUG_libipv6addr, "compare against ipv6addr/must_have");
3027 			r = 1;
3028 			for (i = 0; i < filter->filter_addr.addr_must_have_max; i++) {
3029 				DEBUGPRINT_WA(DEBUG_libipv6addr, "compare against ipv6addr/must_have filter number: %d", i);
3030 				t = ipv6addr_compare(ipv6addrp, &filter->filter_addr.ipv6addr_must_have[i],
3031 					(filter->filter_addr.ipv6addr_must_have[i].test_mode == IPV6CALC_TEST_PREFIX) ? 1 : 0);
3032 
3033 				switch (filter->filter_addr.ipv6addr_must_have[i].test_mode) {
3034 					case IPV6CALC_TEST_PREFIX:
3035 						if (t != 0) { r = 0; }; break;
3036 
3037 					case IPV6CALC_TEST_LE:
3038 						if (t >  0) { r = 0; }; break;
3039 
3040 					case IPV6CALC_TEST_LT:
3041 						if (t >= 0) { r = 0; }; break;
3042 
3043 					case IPV6CALC_TEST_GE:
3044 						if (t <  0) { r = 0; }; break;
3045 
3046 					case IPV6CALC_TEST_GT:
3047 						if (t <= 0) { r = 0; }; break;
3048 
3049 					default:
3050 						ERRORPRINT_WA("unsupported test mode (FIX CODE): %d", filter->filter_addr.ipv6addr_must_have[i].test_mode);
3051 						break;
3052 				};
3053 
3054 				DEBUGPRINT_WA(DEBUG_libipv6addr, "compare against ipv6addr/must_have result filter number: %d r=%d", i, r);
3055 			};
3056 			if (r == 0) {
3057 				/* no match */
3058 				result = 1;
3059 			};
3060 			DEBUGPRINT_WA(DEBUG_libipv6addr, "compare against ipv6addr/must_have result: r=%d result=%d", r, result);
3061 		};
3062 		if (filter->filter_addr.addr_may_not_have_max > 0) {
3063 			DEBUGPRINT_NA(DEBUG_libipv6addr, "compare against ipv6addr/may_not_have");
3064 			r = 0;
3065 			for (i = 0; i < filter->filter_addr.addr_may_not_have_max; i++) {
3066 				DEBUGPRINT_WA(DEBUG_libipv6addr, "compare against ipv6addr/may_not_have filter number: %d", i);
3067 				t = ipv6addr_compare(ipv6addrp, &filter->filter_addr.ipv6addr_may_not_have[i],
3068 					(filter->filter_addr.ipv6addr_may_not_have[i].test_mode == IPV6CALC_TEST_PREFIX) ? 1 : 0);
3069 
3070 				switch (filter->filter_addr.ipv6addr_may_not_have[i].test_mode) {
3071 					case IPV6CALC_TEST_PREFIX:
3072 						if (t == 0) { r = 1; }; break;
3073 
3074 					case IPV6CALC_TEST_LE:
3075 						if (t <= 0) { r = 1; }; break;
3076 
3077 					case IPV6CALC_TEST_LT:
3078 						if (t <  0) { r = 1; }; break;
3079 
3080 					case IPV6CALC_TEST_GE:
3081 						if (t >= 0) { r = 1; }; break;
3082 
3083 					case IPV6CALC_TEST_GT:
3084 						if (t >  0) { r = 1; }; break;
3085 
3086 					default:
3087 						ERRORPRINT_WA("unsupported test mode (FIX CODE): %d", filter->filter_addr.ipv6addr_must_have[i].test_mode);
3088 						break;
3089 				};
3090 				DEBUGPRINT_WA(DEBUG_libipv6addr, "compare against ipv6addr/may_not_have result filter number: %d r=%d", i, r);
3091 			};
3092 			if (r == 1) {
3093 				/* match may_not_have*/
3094 				result = 1;
3095 			};
3096 		};
3097 	};
3098 
3099 	if (filter->filter_db_cc.active > 0) {
3100 		uint16_t cc_index = libipv6addr_cc_index_by_addr(ipv6addrp, NULL);
3101 
3102 		if (libipv6calc_db_cc_filter(cc_index, &filter->filter_db_cc) > 0) {
3103 			/* no match */
3104 			result = 1;
3105 		};
3106 	};
3107 
3108 	if (filter->filter_db_asn.active > 0) {
3109 		uint32_t asn = libipv6addr_as_num32_by_addr(ipv6addrp, NULL);
3110 
3111 		if (libipv6calc_db_asn_filter(asn, &filter->filter_db_asn) > 0) {
3112 			/* no match */
3113 			result = 1;
3114 		};
3115 	};
3116 
3117 	if (filter->filter_db_registry.active > 0) {
3118 		int registry = libipv6addr_registry_num_by_addr(ipv6addrp);
3119 
3120 		if (libipv6calc_db_registry_filter(registry, &filter->filter_db_registry) > 0) {
3121 			/* no match */
3122 			result = 1;
3123 		};
3124 	};
3125 
3126 	return (result);
3127 };
3128 
3129 
3130 /* get included IPv4 address from an IPv6 address */
3131 /* in:	IPv6 address pointer (ro)
3132  *	selector: in case of Teredo (otherwise ignored):
3133  *	 IPV6_ADDR_SELECT_IPV4_DEFAULT (TEREDO_CLIENT)
3134  *	 IPV6_ADDR_SELECT_IPV4_TEREDO_SERVER
3135  *	 IPV6_ADDR_SELECT_IPV4_PREFIX2_LENGTH
3136  * mod:	IPv4 address pointer (rw)
3137  * ret: 0=ok, !=0: no IPv4 adress included
3138  */
libipv6addr_get_included_ipv4addr(const ipv6calc_ipv6addr * ipv6addrp,ipv6calc_ipv4addr * ipv4addrp,const int selector)3139 int libipv6addr_get_included_ipv4addr(const ipv6calc_ipv6addr *ipv6addrp, ipv6calc_ipv4addr *ipv4addrp, const int selector) {
3140 	int result = -1;
3141 	uint32_t typeinfo, typeinfo2;
3142 	int begin = -1, shift = 0;
3143 	int i;
3144 	uint8_t xor = 0;
3145 
3146 	typeinfo = ipv6addrp->typeinfo;
3147 	typeinfo2 = ipv6addrp->typeinfo2;
3148 
3149 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Called with IPv6 address having typeinfo: 0x%08x-0x%08x", typeinfo, typeinfo2);
3150 
3151 	if (selector == IPV6_ADDR_SELECT_IPV4_PREFIX2_LENGTH) {
3152 		begin = ipv6addrp->prefix2length / 8;
3153 		shift = ipv6addrp->prefix2length % 8;
3154 	} else {
3155 		if ((typeinfo & (IPV6_ADDR_COMPATv4 | IPV6_ADDR_MAPPED | IPV6_NEW_ADDR_NAT64)) != 0) {
3156 			begin = 12;
3157 		} else if ((typeinfo & IPV6_NEW_ADDR_TEREDO) != 0) {
3158 			if (selector == IPV6_ADDR_SELECT_IPV4_DEFAULT) {
3159 				// Teredo client
3160 				begin = 12;
3161 				xor   = 0xff;
3162 			} else if (selector == IPV6_ADDR_SELECT_IPV4_TEREDO_SERVER) {
3163 				// Teredo server
3164 				begin = 4;
3165 			} else {
3166 				fprintf(stderr, "libipv6addr_get_included_ipv4addr FAILED (unsupported value of selector: %d - FIX CALLING CODE)", selector);
3167 				exit(1);
3168 			};
3169 		} else if ((typeinfo & IPV6_NEW_ADDR_6TO4) != 0) {
3170 			begin = 2;
3171 		};
3172 	};
3173 
3174 	if (begin > 0) {
3175 		if (shift > 0) {
3176 			DEBUGPRINT_WA(DEBUG_libipv6addr, "IPv6 address contains IPv4 address in octets %d-%d and shift %d", begin, begin+3, shift);
3177 		} else {
3178 			DEBUGPRINT_WA(DEBUG_libipv6addr, "IPv6 address contains IPv4 address in octets %d-%d", begin, begin+3);
3179 		};
3180 
3181 		ipv4addr_clearall(ipv4addrp);
3182 
3183 		if (shift > 0) {
3184 			for (i = 0; i <= 4; i++) {
3185 				int ipv6_p = ipv6addr_getoctet(ipv6addrp, i + begin);
3186 
3187 				DEBUGPRINT_WA(DEBUG_libipv6addr, "IPv6[%d]=%02x", i + begin, ipv6_p);
3188 				ipv6_p <<= shift;
3189 
3190 				if (ipv6_p > 0xff) {
3191 					if (i > 0) {
3192 						// update higher octet
3193 						ipv4addr_setoctet(ipv4addrp
3194 							, (unsigned int) i - 1
3195 							, (unsigned int) (ipv4addr_getoctet(ipv4addrp, i - 1) | (ipv6_p >> 8))
3196 						);
3197 					};
3198 				};
3199 
3200 				if (i <= 3) {
3201 					ipv4addr_setoctet(ipv4addrp
3202 						, (unsigned int) i
3203 						, (unsigned int) (ipv6_p & 0xff)
3204 					);
3205 				};
3206 			};
3207 		} else {
3208 			for (i = 0; i <= 3; i++) {
3209 				ipv4addr_setoctet(ipv4addrp
3210 					, (unsigned int) i
3211 					, (unsigned int) ipv6addr_getoctet(ipv6addrp, (unsigned int) (i + begin)) ^ xor
3212 				);
3213 			};
3214 		};
3215 
3216 		ipv4addr_settype(ipv4addrp, 1);
3217 		ipv4addrp->flag_valid = 1;
3218 
3219 		result = 0;
3220 	};
3221 
3222 	if (result == -1) {
3223 		// fprintf(stderr, "libipv6addr_get_included_ipv4addr FAILED (this should not happen)");
3224 	};
3225 
3226 	DEBUGPRINT_WA(DEBUG_libipv6addr, "Return with result: %d", result);
3227 
3228 	return(result);
3229 };
3230 
3231 
3232 /*
3233  * country code index of IPv6 address
3234  *
3235  * in : *ipv6addrp = IPv6 address structure
3236  * out: country code index
3237  */
libipv6addr_cc_index_by_addr(const ipv6calc_ipv6addr * ipv6addrp,unsigned int * data_source_ptr)3238 uint16_t libipv6addr_cc_index_by_addr(const ipv6calc_ipv6addr *ipv6addrp, unsigned int *data_source_ptr) {
3239 	uint32_t cc_index = COUNTRYCODE_INDEX_UNKNOWN;
3240 	ipv6calc_ipv4addr ipv4addr;
3241 	ipv6calc_ipv6addr ipv6addr;
3242 	ipv6calc_ipaddr ipaddr;
3243 	int retval;
3244 
3245 	DEBUGPRINT_NA(DEBUG_libipv6addr, "start");
3246 
3247 	if ((ipv6addrp->typeinfo & IPV6_ADDR_ANONYMIZED_PREFIX) != 0) {
3248 		DEBUGPRINT_NA(DEBUG_libipv6addr, "anonymized prefix handling");
3249 		if ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_PREFIX) == 0) {
3250 			if ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_LISP) != 0) {
3251 				// no country code included
3252 				cc_index = COUNTRYCODE_INDEX_LISP;
3253 			} else {
3254 				/* retrieve CountryCodeIndex from anonymization value */
3255 				retval = ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_CCINDEX, &cc_index);
3256 				if (retval != 0) {
3257 					fprintf(stderr, "Error getting CountryCode index from anonymized IPv6 address\n");
3258 					goto END_libipv6addr_cc_index_by_addr;
3259 				};
3260 			};
3261 		} else {
3262 			if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_6TO4) != 0) {
3263 				retval = libipv6addr_get_included_ipv4addr(ipv6addrp, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
3264 				if (retval != 0) {
3265 					fprintf(stderr, "Error getting included IPv4 address from anonymized IPv6 address\n");
3266 					goto END_libipv6addr_cc_index_by_addr;
3267 				};
3268 
3269 				cc_index = libipv4addr_cc_index_by_addr(&ipv4addr, NULL);
3270 			};
3271 		};
3272 	} else if (((ipv6addrp->typeinfo & IPV6_ADDR_ANONYMIZED_IID) != 0) && ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_IID) != 0)) {
3273 		retval = libipv6addr_get_included_ipv4addr(ipv6addrp, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
3274 		if (retval != 0) {
3275 			fprintf(stderr, "Error getting included IPv4 address from anonymized IPv6 address\n");
3276 			goto END_libipv6addr_cc_index_by_addr;
3277 		};
3278 
3279 		cc_index = libipv4addr_cc_index_by_addr(&ipv4addr, data_source_ptr);
3280 	} else {
3281 		if ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_IID) != 0) {
3282 			if (libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV4_TO_CC) == 1) {
3283 				/* retrieve CountryCodeIndex from IPv4 address inside */
3284 				retval = libipv6addr_get_included_ipv4addr(ipv6addrp, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
3285 				if (retval != 0) {
3286 					fprintf(stderr, "Error getting included IPv4 address from IPv6 address\n");
3287 					goto END_libipv6addr_cc_index_by_addr;
3288 				};
3289 
3290 				cc_index = libipv4addr_cc_index_by_addr(&ipv4addr, data_source_ptr);
3291 			} else {
3292 				DEBUGPRINT_NA(DEBUG_libipv6addr, "DB feature missing: DB_IPV4_TO_CC");
3293 			};
3294 		} else if ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_PREFIX) != 0) {
3295 			if (libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV4_TO_CC) == 1) {
3296 				retval = libipv6addr_get_included_ipv4addr(ipv6addrp, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
3297 				if (retval != 0) {
3298 					fprintf(stderr, "Error getting included IPv4 address from IPv6 address\n");
3299 					goto END_libipv6addr_cc_index_by_addr;
3300 				};
3301 
3302 				cc_index = libipv4addr_cc_index_by_addr(&ipv4addr, data_source_ptr);
3303 			} else {
3304 				DEBUGPRINT_NA(DEBUG_libipv6addr, "DB feature missing: DB_IPV4_TO_CC");
3305 			};
3306 		} else if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_6BONE) != 0) {
3307 			cc_index = COUNTRYCODE_INDEX_UNKNOWN_REGISTRY_MAP_MIN + IPV6_ADDR_REGISTRY_6BONE;
3308 		} else if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_ORCHID) != 0) {
3309 			DEBUGPRINT_NA(DEBUG_libipv6addr, "ORCHID has no country");
3310 			goto END_libipv6addr_cc_index_by_addr;
3311 		} else if ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_LISP) != 0) {
3312 			DEBUGPRINT_NA(DEBUG_libipv6addr, "LISP has no country");
3313 			goto END_libipv6addr_cc_index_by_addr;
3314 		} else if (libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV6_TO_CC) == 1) {
3315 			if ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_ANON_MASKED_PREFIX) != 0) {
3316 				if (ipv6addrp->prefix2length < 48) {
3317 					DEBUGPRINT_WA(DEBUG_libipv6addr, "anonymized prefix prefix length to low for detecting country: %u", ipv6addrp->prefix2length);
3318 					goto END_libipv6addr_cc_index_by_addr;
3319 				};
3320 				ipv6addr = *ipv6addrp;
3321 				ipv6addr.flag_prefixuse = 1;
3322 				ipv6addr.prefixlength = ipv6addrp->prefix2length;
3323 				ipv6addrstruct_maskprefix(&ipv6addr);
3324 				DEBUGPRINT_WA(DEBUG_libipv6addr, "anonymized prefix found, apply prefix length %u", ipv6addr.prefixlength);
3325 				CONVERT_IPV6ADDRP_IPADDR(&ipv6addr, ipaddr);
3326 			} else {
3327 				CONVERT_IPV6ADDRP_IPADDR(ipv6addrp, ipaddr);
3328 			};
3329 
3330 			cc_index = libipv6calc_db_wrapper_cc_index_by_addr(&ipaddr, data_source_ptr);
3331 		} else {
3332 			DEBUGPRINT_NA(DEBUG_libipv6addr, "DB feature missing: DB_IPV6_TO_CC");
3333 		};
3334 	};
3335 
3336 END_libipv6addr_cc_index_by_addr:
3337 	DEBUGPRINT_WA(DEBUG_libipv6addr, "cc_index=%d (0x%03x)", cc_index, cc_index);
3338 	return(cc_index);
3339 };
3340 
3341 
3342 /*
3343  * 32-bit AS number of IPv6 address
3344  *
3345  * in : *ipv6addrp = IPv6 address structure
3346  * out: 32-bit AS number
3347  */
libipv6addr_as_num32_by_addr(const ipv6calc_ipv6addr * ipv6addrp,unsigned int * data_source_ptr)3348 uint32_t libipv6addr_as_num32_by_addr(const ipv6calc_ipv6addr *ipv6addrp, unsigned int *data_source_ptr) {
3349 	uint32_t as_num32 = ASNUM_AS_UNKNOWN;
3350 	ipv6calc_ipv4addr ipv4addr;
3351 	ipv6calc_ipv6addr ipv6addr;
3352 	ipv6calc_ipaddr ipaddr;
3353 	uint32_t payload;
3354 	int retval;
3355 
3356 	DEBUGPRINT_NA(DEBUG_libipv6addr, "start");
3357 
3358 	if ((ipv6addrp->typeinfo & IPV6_ADDR_ANONYMIZED_PREFIX) != 0) {
3359 		DEBUGPRINT_NA(DEBUG_libipv6addr, "IPv6 address has anonymized prefix");
3360 		if ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_PREFIX) == 0) {
3361 			if ((ipv6addrp->typeinfo & IPV6_ADDR_IID_32_63_HAS_IPV4) != 0) {
3362 				DEBUGPRINT_NA(DEBUG_libipv6addr, "retrieve ASN from anonymized IPv4 in IID");
3363 				payload = ipv6addr_get_payload_anonymized_iid(ipv6addrp, ipv6addrp->typeinfo);
3364 				/* IPv4 */
3365 				ipv4addr_clearall(&ipv4addr);
3366 				ipv4addr_setoctet(&ipv4addr, 0, (payload >> 16) & 0xff);
3367 				ipv4addr_setoctet(&ipv4addr, 1, (payload >>  8) & 0xff);
3368 				ipv4addr_setoctet(&ipv4addr, 2, (payload      ) & 0xff);
3369 				ipv4addr_setoctet(&ipv4addr, 3, 0);
3370 
3371 				ipv4addr_settype(&ipv4addr, 1); // set type
3372 				ipv4addr.flag_valid = 1;
3373 
3374 				as_num32 = libipv4addr_as_num32_by_addr(&ipv4addr, data_source_ptr);
3375 			} else {
3376 				/* retrieve ASN from anonymization value */
3377 				DEBUGPRINT_NA(DEBUG_libipv6addr, "retrieve ASN from anonymized prefix");
3378 				retval = ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_ASN32, &as_num32);
3379 				if (retval != 0) {
3380 					fprintf(stderr, "Error getting ASN32 from anonymized IPv6 address\n");
3381 					goto END_libipv6addr_as_num32_by_addr;
3382 				};
3383 			};
3384 		} else {
3385 			if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_6TO4) != 0) {
3386 				/* retrieve ASN from included IPv4 address */
3387 				DEBUGPRINT_NA(DEBUG_libipv6addr, "retrieve ASN from included IPv4 address (6to4)");
3388 				retval = libipv6addr_get_included_ipv4addr(ipv6addrp, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
3389 				if (retval != 0) {
3390 					fprintf(stderr, "Error getting included IPv4 address from anonymized IPv6 address\n");
3391 					goto END_libipv6addr_as_num32_by_addr;
3392 				};
3393 
3394 				as_num32 = libipv4addr_as_num32_by_addr(&ipv4addr, data_source_ptr);
3395 			};
3396 		};
3397 	} else if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_6BONE) != 0) {
3398 		as_num32 = ASNUM_AS_UNKNOWN;
3399 		goto END_libipv6addr_as_num32_by_addr;
3400 	} else {
3401 		if (libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV6_TO_AS) == 1) {
3402 			if ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_ANON_MASKED_PREFIX) != 0) {
3403 				if (ipv6addrp->prefix2length < 48) {
3404 					goto END_libipv6addr_as_num32_by_addr;
3405 				};
3406 				ipv6addr = *ipv6addrp;
3407 				ipv6addr.flag_prefixuse = 1;
3408 				ipv6addr.prefixlength = ipv6addrp->prefix2length;
3409 				ipv6addrstruct_maskprefix(&ipv6addr);
3410 				DEBUGPRINT_WA(DEBUG_libipv6addr, "anonymized prefix found, apply prefix length %u", ipv6addr.prefixlength);
3411 				CONVERT_IPV6ADDRP_IPADDR(&ipv6addr, ipaddr);
3412 			} else {
3413 				CONVERT_IPV6ADDRP_IPADDR(ipv6addrp, ipaddr);
3414 			};
3415 
3416 			as_num32 = libipv6calc_db_wrapper_as_num32_by_addr(&ipaddr, data_source_ptr);
3417 		} else {
3418 			DEBUGPRINT_NA(DEBUG_libipv6addr, "DB feature missing: DB_IPV6_TO_AS");
3419 		};
3420 	};
3421 
3422 END_libipv6addr_as_num32_by_addr:
3423 	DEBUGPRINT_WA(DEBUG_libipv6addr, "as_num32=%d (0x%08x)", as_num32, as_num32);
3424 	return(as_num32);
3425 };
3426 
3427 
3428 /*
3429  * registry number of IPv6 address
3430  *
3431  * in : *ipv6addrp = IPv6 address structure
3432  * out: registry number
3433  */
libipv6addr_registry_num_by_addr(const ipv6calc_ipv6addr * ipv6addrp)3434 int libipv6addr_registry_num_by_addr(const ipv6calc_ipv6addr *ipv6addrp) {
3435 	int registry = IPV6_ADDR_REGISTRY_UNKNOWN;
3436 	uint16_t cc_index;
3437 	uint32_t as_num32;
3438 	uint32_t geonameid_type;
3439 	ipv6calc_ipv6addr ipv6addr;
3440 
3441 	if (((ipv6addrp->typeinfo & IPV6_ADDR_ANONYMIZED_PREFIX) != 0) \
3442 	    && ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_PREFIX) == 0)) {
3443 		if ((ipv6addrp->typeinfo2 & (IPV6_ADDR_TYPE2_ANONYMIZED_GEONAMEID)) == 0) {
3444 			/* retrieve registry via cc_index from anonymized address (simple) */
3445 			cc_index = libipv6addr_cc_index_by_addr(ipv6addrp, NULL);
3446 
3447 			if (cc_index == COUNTRYCODE_INDEX_LISP) {
3448 				as_num32 = libipv6addr_as_num32_by_addr(ipv6addrp, NULL);
3449 				registry = libipv6calc_db_wrapper_registry_num_by_as_num32(as_num32);
3450 			} else {
3451 				registry = libipv6calc_db_wrapper_registry_num_by_cc_index(cc_index);
3452 			};
3453 		} else {
3454 			if (ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_GEONAMEID_TYPE, &geonameid_type) == 0) {
3455 				DEBUGPRINT_WA(DEBUG_libipv6addr, "geonameid_type/registry=%d (0x%03x)", geonameid_type, geonameid_type);
3456 				if ((geonameid_type & 0x300) == 0x000) {
3457 					registry = (geonameid_type & 0x0f0) >> 4;
3458 				};
3459 			};
3460 		};
3461 	} else {
3462 		if (libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV6_TO_REGISTRY) == 1) {
3463 			if ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_ANON_MASKED_PREFIX) != 0) {
3464 				if (ipv6addrp->prefix2length < 12) {
3465 					goto END_libipv6addr_registry_by_addr;
3466 				};
3467 				ipv6addr = *ipv6addrp;
3468 				ipv6addr.flag_prefixuse = 1;
3469 				ipv6addr.prefixlength = ipv6addrp->prefix2length;
3470 				ipv6addrstruct_maskprefix(&ipv6addr);
3471 				registry = libipv6calc_db_wrapper_registry_num_by_ipv6addr(&ipv6addr);
3472 			} else {
3473 				registry = libipv6calc_db_wrapper_registry_num_by_ipv6addr(ipv6addrp);
3474 			};
3475 		};
3476 	};
3477 
3478 END_libipv6addr_registry_by_addr:
3479 	DEBUGPRINT_WA(DEBUG_libipv6addr, "registry=%d (0x%x)", registry, registry);
3480 	return(registry);
3481 };
3482 
3483 
3484 /*
3485  * GeonameID of IPv6 address
3486  *
3487  * in : *ipv6addrp = IPv6 address structure
3488  * mod: GeonameID_type_ptr
3489  * out: GeonameID
3490  */
libipv6addr_GeonameID_by_addr(const ipv6calc_ipv6addr * ipv6addrp,unsigned int * data_source_ptr,unsigned int * GeonameID_type_ptr)3491 uint32_t libipv6addr_GeonameID_by_addr(const ipv6calc_ipv6addr *ipv6addrp, unsigned int *data_source_ptr, unsigned int *GeonameID_type_ptr) {
3492 	uint32_t GeonameID = IPV6CALC_DB_GEO_GEONAMEID_UNKNOWN;
3493 	uint32_t GeonameID_type = IPV6CALC_DB_GEO_GEONAMEID_TYPE_UNKNOWN;
3494 	unsigned int data_source = IPV6CALC_DB_SOURCE_UNKNOWN;
3495 	ipv6calc_ipaddr ipaddr;
3496 	ipv6calc_ipv4addr ipv4addr;
3497 	int retval;
3498 
3499 	if ((ipv6addrp->typeinfo & IPV6_ADDR_ANONYMIZED_PREFIX) != 0) {
3500 		if (((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_IID) != 0)
3501 		    || ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_PREFIX) != 0)) {
3502 			retval = libipv6addr_get_included_ipv4addr(ipv6addrp, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
3503 			if (retval != 0) {
3504 				fprintf(stderr, "Error getting included IPv4 address from IPv6 address\n");
3505 				goto END_libipv6addr_GeonameID_by_addr;
3506 			};
3507 			GeonameID = libipv4addr_GeonameID_by_addr(&ipv4addr, NULL, &GeonameID_type);
3508 		} else if (((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_ANONYMIZED_GEONAMEID) != 0) \
3509 		    && ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_LISP) == 0)) {
3510 			// GeonameID included
3511 			int r1 = ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_GEONAMEID, &GeonameID);
3512 			int r2 = ipv6addr_get_payload_anonymized_prefix(ipv6addrp, ANON_PREFIX_PAYLOAD_GEONAMEID_TYPE, &GeonameID_type);
3513 			GeonameID_type &= 0x00f;
3514 			DEBUGPRINT_WA(DEBUG_libipv6addr, "result of anonymized IPv6 GeonameID retrievement: %d (0x%08x) (source: %02x)", GeonameID, GeonameID, GeonameID_type);
3515 			if ((r1 == 0) && (r2 == 0)) {
3516 				// dummy
3517 			};
3518 		};
3519 	} else if (((ipv6addrp->typeinfo & IPV6_ADDR_ANONYMIZED_IID) != 0) && ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_IID) != 0)) {
3520 		retval = libipv6addr_get_included_ipv4addr(ipv6addrp, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
3521 		if (retval != 0) {
3522 			fprintf(stderr, "Error getting included IPv4 address from anonymized IPv6 address\n");
3523 			goto END_libipv6addr_GeonameID_by_addr;
3524 		};
3525 		GeonameID = libipv4addr_GeonameID_by_addr(&ipv4addr, NULL, &GeonameID_type);
3526 	} else {
3527 		if ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_IID) != 0) {
3528 			if (libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV4_TO_GEONAMEID) == 1) {
3529 				/* retrieve GeonameID from IPv4 address inside */
3530 				retval = libipv6addr_get_included_ipv4addr(ipv6addrp, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
3531 				if (retval != 0) {
3532 					fprintf(stderr, "Error getting included IPv4 address from IPv6 address\n");
3533 					goto END_libipv6addr_GeonameID_by_addr;
3534 				};
3535 				GeonameID = libipv4addr_GeonameID_by_addr(&ipv4addr, NULL, &GeonameID_type);
3536 			} else {
3537 				DEBUGPRINT_NA(DEBUG_libipv6addr, "DB feature missing: DB_IPV4_TO_GEONAMEID");
3538 			};
3539 		} else if ((ipv6addrp->typeinfo & IPV6_ADDR_HAS_PUBLIC_IPV4_IN_PREFIX) != 0) {
3540 			if (libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV4_TO_GEONAMEID) == 1) {
3541 				retval = libipv6addr_get_included_ipv4addr(ipv6addrp, &ipv4addr, IPV6_ADDR_SELECT_IPV4_DEFAULT);
3542 				if (retval != 0) {
3543 					fprintf(stderr, "Error getting included IPv4 address from IPv6 address\n");
3544 					goto END_libipv6addr_GeonameID_by_addr;
3545 				};
3546 				GeonameID = libipv4addr_GeonameID_by_addr(&ipv4addr, NULL, &GeonameID_type);
3547 			} else {
3548 				DEBUGPRINT_NA(DEBUG_libipv6addr, "DB feature missing: DB_IPV4_TO_GEONAMEID");
3549 			};
3550 		} else if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_6BONE) != 0) {
3551 			DEBUGPRINT_NA(DEBUG_libipv6addr, "6bone has no GeonameID");
3552 			goto END_libipv6addr_GeonameID_by_addr;
3553 		} else if ((ipv6addrp->typeinfo & IPV6_NEW_ADDR_ORCHID) != 0) {
3554 			DEBUGPRINT_NA(DEBUG_libipv6addr, "ORCHID has no GeonameID");
3555 			goto END_libipv6addr_GeonameID_by_addr;
3556 		} else if ((ipv6addrp->typeinfo2 & IPV6_ADDR_TYPE2_LISP) != 0) {
3557 			DEBUGPRINT_NA(DEBUG_libipv6addr, "LISP has no country");
3558 			goto END_libipv6addr_GeonameID_by_addr;
3559 		} else if (libipv6calc_db_wrapper_has_features(IPV6CALC_DB_IPV6_TO_GEONAMEID) == 1) {
3560 			// get GeonameID
3561 			CONVERT_IPV6ADDRP_IPADDR(ipv6addrp, ipaddr);
3562 			GeonameID = libipv6calc_db_wrapper_GeonameID_by_addr(&ipaddr, &data_source, &GeonameID_type);
3563 			DEBUGPRINT_WA(DEBUG_libipv6addr, "result of GeonameID retrievement: %d (0x%08x) (source: %02x)", GeonameID, GeonameID, GeonameID_type);
3564 		} else {
3565 			DEBUGPRINT_NA(DEBUG_libipv6addr, "No support available for IPV6CALC_DB_IPV6_TO_GEONAMEID");
3566 		};
3567 	};
3568 
3569 	DEBUGPRINT_WA(DEBUG_libipv6addr, "GeonameID=%d (0x%x)", GeonameID, GeonameID);
3570 
3571 	if (data_source_ptr != NULL) {
3572 		*data_source_ptr = data_source;
3573 	};
3574 
3575 	if (GeonameID_type_ptr != NULL) {
3576 		*GeonameID_type_ptr = GeonameID_type;
3577 	};
3578 
3579 END_libipv6addr_GeonameID_by_addr:
3580 	return(GeonameID);
3581 };
3582