1 /*
2 * Project : ipv6calc
3 * File : libeui64.c
4 * Version : $Id: ac04b718a59935f2d7430dc1deed00c86386bb68 $
5 * Copyright : 2001-2019 by Peter Bieringer <pb (at) bieringer.de>
6 *
7 * Information:
8 * Function library EUI-64 identifier handling
9 */
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14
15 #include "libeui64.h"
16 #include "libieee.h"
17
18 #include "libipv6calc.h"
19 #include "libipv6calcdebug.h"
20 #include "libipv6addr.h"
21
22 static char ChSet[] = "0123456789abcdefABCDEF:- ";
23
24
25 /* function MAC address to EUI format
26 *
27 * in : macaddrp
28 * out: ipv6addrp
29 * ret: ==0: ok, !=0: error
30 */
create_eui64_from_mac(ipv6calc_ipv6addr * ipv6addrp,ipv6calc_macaddr * macaddrp)31 int create_eui64_from_mac(ipv6calc_ipv6addr *ipv6addrp, ipv6calc_macaddr *macaddrp) {
32 int retval = 1;
33
34 DEBUGPRINT_NA(DEBUG_libeui64, "called");
35
36 /* clear IPv6 structure */
37 ipv6addr_clear(ipv6addrp);
38
39 /* create EUI-64 from MAC-48 */
40 ipv6addrp->in6_addr.s6_addr[ 8] = macaddrp->addr[0] ^ 0x02;
41 ipv6addrp->in6_addr.s6_addr[ 9] = macaddrp->addr[1];
42 ipv6addrp->in6_addr.s6_addr[10] = macaddrp->addr[2];
43 ipv6addrp->in6_addr.s6_addr[11] = 0xff;
44 ipv6addrp->in6_addr.s6_addr[12] = 0xfe;
45 ipv6addrp->in6_addr.s6_addr[13] = macaddrp->addr[3];
46 ipv6addrp->in6_addr.s6_addr[14] = macaddrp->addr[4];
47 ipv6addrp->in6_addr.s6_addr[15] = macaddrp->addr[5];
48
49 ipv6addrp->prefixlength = 64;
50 ipv6addrp->flag_prefixuse = 0;
51
52 ipv6addrp->flag_valid = 1;
53
54 retval = 0;
55 return (retval);
56 };
57
58
59 /*
60 * stores the EUI-64 structure in a string
61 *
62 * in: eui64addr_p = EUI-64 address structure ptr
63 * out: *resultstring = EUI-64 address string
64 * ret: ==0: ok, !=0: error
65 */
libeui64_eui64addrstruct_to_string(const ipv6calc_eui64addr * eui64addr_p,char * resultstring,const size_t resultstring_length,const uint32_t formatoptions)66 int libeui64_eui64addrstruct_to_string(const ipv6calc_eui64addr *eui64addr_p, char *resultstring, const size_t resultstring_length, const uint32_t formatoptions) {
67 char tempstring[IPV6CALC_STRING_MAX];
68
69 /* address */
70 snprintf(tempstring, sizeof(tempstring), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", \
71 (unsigned int) eui64addr_p->addr[0], \
72 (unsigned int) eui64addr_p->addr[1], \
73 (unsigned int) eui64addr_p->addr[2], \
74 (unsigned int) eui64addr_p->addr[3], \
75 (unsigned int) eui64addr_p->addr[4], \
76 (unsigned int) eui64addr_p->addr[5], \
77 (unsigned int) eui64addr_p->addr[6], \
78 (unsigned int) eui64addr_p->addr[7]);
79
80 if ( (formatoptions & FORMATOPTION_machinereadable) != 0 ) {
81 snprintf(resultstring, resultstring_length, "EUI64=%s", tempstring);
82 } else {
83 snprintf(resultstring, resultstring_length, "%s", tempstring);
84 };
85
86 return(0);
87 };
88
89
90 /* function 48-bit EUI-64 address to eui64addr_structure
91 *
92 * in : *addrstring = EUI-64 address
93 * out: *resultstring = result
94 * ret: ==0: ok, !=0: error
95 */
libeui64_addr_to_eui64addrstruct(const char * addrstring,char * resultstring,const size_t resultstring_length,ipv6calc_eui64addr * eui64addrp)96 int libeui64_addr_to_eui64addrstruct(const char *addrstring, char *resultstring, const size_t resultstring_length, ipv6calc_eui64addr *eui64addrp) {
97 int retval = 1, result, i, ccolons = 0, cdashes = 0, cspaces = 0;
98 size_t cnt;
99 int temp[8];
100
101 DEBUGPRINT_NA(DEBUG_libeui64, "called");
102
103 /* check length */
104 if ( ( strlen(addrstring) < 15 ) || ( strlen(addrstring) > 23 ) ) {
105 snprintf(resultstring, resultstring_length, "Error in given 64-bit EUI-64 address, has not 15 to 23 chars!");
106 retval = 1;
107 return (retval);
108 };
109
110 /* check for hex chars and ":"/"-"/" " only content */
111 cnt = strspn(addrstring, ChSet);
112 if ( cnt < strlen(addrstring) ) {
113 snprintf(resultstring, resultstring_length, "Error in given EUI-64 address, '%s' has illegal char on position %d (%c)!", addrstring, (int) cnt+1, addrstring[cnt]);
114 retval = 1;
115 return (retval);
116
117 };
118
119 /* count ":" or "-" or " " must be 7 x "-" */
120 for (i = 0; i < (int) strlen(addrstring); i++) {
121 if (addrstring[i] == ':') {
122 ccolons++;
123 } else if (addrstring[i] == '-') {
124 cdashes++;
125 } else if (addrstring[i] == ' ') {
126 cspaces++;
127 };
128 };
129
130 if ( ! ( (ccolons == 7 && cdashes == 0 && cspaces == 0) || (ccolons == 0 && cdashes == 7 && cspaces == 0) || (ccolons == 0 && cdashes == 0 && cspaces == 7) || (ccolons == 0 && cdashes == 0 && cspaces == 0 && strlen(addrstring) == 16)) ) {
131 snprintf(resultstring, resultstring_length, "Error in given EUI-64 address, '%s' is not valid (number of colons/dashes/spaces is not 7)!", addrstring);
132 retval = 1;
133 return (retval);
134 };
135
136 /* scan address into array */
137 if ( ccolons == 7 ) {
138 result = sscanf(addrstring, "%x:%x:%x:%x:%x:%x:%x:%x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5], &temp[6], &temp[7]);
139 } else if ( cdashes == 7 ) {
140 result = sscanf(addrstring, "%x-%x-%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5], &temp[6], &temp[7]);
141 } else if ( cspaces == 7 ) {
142 result = sscanf(addrstring, "%x %x %x %x %x %x %x %x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5], &temp[6], &temp[7]);
143 } else if ( cdashes == 0 ) {
144 result = sscanf(addrstring, "%2x%2x%2x%2x%2x%2x%2x%2x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5], &temp[6], &temp[7]);
145 } else {
146 snprintf(resultstring, resultstring_length, "Error in given EUI-64 address, unexpected failure on scanning '%s'!", addrstring);
147 retval = 1;
148 return (retval);
149 };
150
151 if ( result != 8 ) {
152 snprintf(resultstring, resultstring_length, "Error in given EUI-64 address, splitting of '%s' return %d items instead of 8!", addrstring, result);
153 retval = 1;
154 return (retval);
155 };
156
157 /* check address words range */
158 for ( i = 0; i <= 7; i++ ) {
159 if ( ( temp[i] < 0x0 ) || ( temp[i] > 0xff ) ) {
160 snprintf(resultstring, resultstring_length, "Error in given EUI-64 address, '%s' is not valid on position %d!", addrstring, i);
161 retval = 1;
162 return (retval);
163 };
164 };
165
166 /* copy address */
167 for ( i = 0; i <= 7; i++ ) {
168 eui64addrp->addr[i] = (uint8_t) temp[i];
169 };
170
171 eui64addrp->flag_valid = 1;
172
173 retval = 0;
174 return (retval);
175 };
176
177
178 /*
179 * clear EUI-64 addr
180 *
181 * mod: *addrstring = EUI-64 address
182 */
libeui64_clear(ipv6calc_eui64addr * eui64addrp)183 void libeui64_clear(ipv6calc_eui64addr *eui64addrp) {
184 int i;
185
186 DEBUGPRINT_NA(DEBUG_libeui64, "called");
187
188 for ( i = 0; i <= 7; i++ ) {
189 eui64addrp->addr[i] = 0;
190 };
191
192 return;
193 };
194
195
196 /*
197 * clear EUI64 addr_structure
198 *
199 * mod: *addrstring = EUI64 address
200 */
libeui64_clearall(ipv6calc_eui64addr * eui64addrp)201 void libeui64_clearall(ipv6calc_eui64addr *eui64addrp) {
202 libeui64_clear(eui64addrp);
203
204 DEBUGPRINT_NA(DEBUG_libeui64, "called");
205
206 /* Clear valid flag */
207 eui64addrp->flag_valid = 0;
208
209 return;
210 };
211
212
213 /*
214 * anonymize EUI-64 addr
215 *
216 * mod: *addrstring = EUI-64 address
217 */
libeui64_anonymize(ipv6calc_eui64addr * eui64addrp,const s_ipv6calc_anon_set * ipv6calc_anon_set_p)218 void libeui64_anonymize(ipv6calc_eui64addr *eui64addrp, const s_ipv6calc_anon_set *ipv6calc_anon_set_p) {
219 int mask = 0, i, j;
220 uint8_t bit_ul = 0;
221
222 DEBUGPRINT_WA(DEBUG_libeui64, "called: EUI-64=%08x%08x method=%d", EUI64_00_31(eui64addrp->addr), EUI64_32_63(eui64addrp->addr), ipv6calc_anon_set_p->method);
223
224 // if (ipv6calc_anon_set_p->method == ANON_METHOD_ZEROIZE) { TODO: different implementations
225 if (ipv6calc_anon_set_p->mask_autoadjust == 1) {
226 DEBUGPRINT_NA(DEBUG_libeui64, "mask-autoadjust is set, autoselect proper mask");
227
228 if ((eui64addrp->addr[0] & 0x2) == 0) {
229 // global address
230 if ((eui64addrp->addr[3] == 0xff) && (eui64addrp->addr[4] == 0xfe)) {
231 // expanded EUI-48
232 mask = 40; // 24 + 16 bits
233 DEBUGPRINT_WA(DEBUG_libeui64, "EUI-64 is a expanded EUI-48, change mask: %d", mask);
234 } else {
235 mask = 24;
236 };
237
238 if (libieee_check_oui36_iab(EUI64_00_23(eui64addrp->addr)) == 1) {
239 // OUI-36/IAB
240 mask += 12; // increase by 12 bits
241 DEBUGPRINT_WA(DEBUG_libeui64, "EUI-64 contains OUI-36/IAB, change mask: %d", mask);
242 } else if (libieee_check_oui28(EUI64_00_23(eui64addrp->addr)) == 1) {
243 // OUI-28
244 mask += 4; // increase by 4 bits
245 DEBUGPRINT_WA(DEBUG_libeui64, "EUI-64 contains OUI-28, change mask: %d", mask);
246 };
247
248 DEBUGPRINT_WA(DEBUG_libeui64, "EUI-64 is a global one, source of mask: automagic: %d", mask);
249 } else {
250 // local address, honor mask_eui64
251 mask = ipv6calc_anon_set_p->mask_eui64;
252 DEBUGPRINT_WA(DEBUG_libeui64, "EUI-64 is a local one, source of mask: mask-iid option: %d", mask);
253 };
254
255 if (ipv6calc_anon_set_p->mask_eui64 > mask) {
256 mask = ipv6calc_anon_set_p->mask_eui64;
257 DEBUGPRINT_WA(DEBUG_libeui64, "specified mask is higher than autoselected one, change to specified: %d", mask);
258 };
259 } else {
260 DEBUGPRINT_WA(DEBUG_libeui64, "mask-autoadjust is not set, use always given mask: %d", mask);
261 mask = ipv6calc_anon_set_p->mask_eui64;
262 };
263
264 // save universal/local bit
265 bit_ul = eui64addrp->addr[0] & 0x02;
266
267 DEBUGPRINT_WA(DEBUG_libeui64, "zeroize EUI-64 with masked bits: %d (u/l=%s)", mask, (bit_ul == 2) ? "local" : "universal");
268
269 if (mask == 64) {
270 // nothing to do
271 } else if (mask > 0) {
272 j = mask >> 3;
273
274 for (i = 7; i >= 0; i--) {
275 DEBUGPRINT_WA(DEBUG_libeui64, "zeroize EUI-64: mask=%02d i=%d j=%d", mask, i, j);
276 if (j < i) {
277 DEBUGPRINT_WA(DEBUG_libeui64, "zeroize EUI-64: byte %d", i);
278 eui64addrp->addr[i] = 0x00;
279 } else if (j == i) {
280 DEBUGPRINT_WA(DEBUG_libeui64, "zeroize EUI-64: mask byte %d with %02x (offset: %d)", i, (0xff00 >> (mask % 0x8)) & 0xff, (mask % 0x8));
281 eui64addrp->addr[i] &= (0xff00 >> (mask % 0x8)) & 0xff;
282 } else {
283 DEBUGPRINT_NA(DEBUG_libeui64, "zeroize EUI-64: finished");
284 break;
285 };
286 };
287 } else {
288 libeui64_clear(eui64addrp);
289 };
290
291 // restore universal/local bit
292 eui64addrp->addr[0] = (eui64addrp->addr[0] & 0xfd) | bit_ul;
293 // };
294
295 DEBUGPRINT_WA(DEBUG_libeui64, "anonymization finished, return: %08x%08x", EUI64_00_31(eui64addrp->addr), EUI64_32_63(eui64addrp->addr));
296
297 return;
298 };
299