Enter MAC Address using the following format:
eg.
1.separate by : -> 0015:2BE4:9B60
2.separate by - -> 00-15-2B-E4-9B-60
MAC Address(EUI48):00-15-2B-E4-9B-60
EUI64: 02152BFFEFE49B60
Link local IPv6 Address : fe80::0215:2bff:efe4:9b60
#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
//Link local IPv6 Address [EUI-64]
typedef int errno_t;
//functions prototype
bool MAC48_Check(char* MAC48); // 检测MAC有效性
char* linklocal(char* MAC48); // 执行EUI48->EUI64转换.生成IPv6链路本地地址
char* regnext(char* content,regex_t* regex); //获取输入字符串有效部分
char* process(char* ipv6);//将对应IPv6地址转化为小写,去除尾部:
int main(void){
char* MAC48 = calloc(18,sizeof(char));
printf("Enter MAC Address using the following format:\neg. \n"
"1.separate by : -> 0015:2BE4:9B60\n"
"2.separate by - -> 00-15-2B-E4-9B-60 \n");
retry:
printf("MAC Address(EUI48):");
scanf("%s",MAC48);
if(!MAC48_Check(MAC48)){
printf("MAC: %s invalid! Retry\n",MAC48);
goto retry;
}
linklocal(MAC48);
return 0;
}
bool MAC48_Check(char* MAC48){
for(int i = 0 ; i < strlen(MAC48) ; i ++){
MAC48[i] = toupper(MAC48[i]);
}
char* pattern = "^([0-9A-F]{4}(:[0-9A-F]{4}){2}|[0-9A-F]{2}(-[0-9A-F]{2}){5})$";
regex_t regex;
errno_t state = regcomp(®ex,pattern,REG_EXTENDED);
if(state){
char* errbuf = calloc(20,sizeof(char));
regerror(state,®ex,errbuf,20);
fprintf(stderr,"Failed to compile Regex: %s\n"
"Reason:%s\n",pattern,errbuf);
free(errbuf);
regfree(®ex);
exit(EXIT_FAILURE);
}
state = regexec(®ex,MAC48,0,NULL,0);
regfree(®ex);
return state != REG_NOMATCH;
}
char* regnext(char* content,regex_t* regex){
static int position = 0;
regmatch_t matches[regex->re_nsub + 1];
errno_t state = regexec(regex,content + position,regex->re_nsub + 1,matches,0);
if(state == REG_NOMATCH){
position = 0;
return NULL;
}
char* reval = calloc(matches[0].rm_eo - matches[0].rm_so + 1,sizeof(char));
memcpy(reval,content + position + matches[0].rm_so,matches[0].rm_eo - matches[0].rm_so);
position += matches[0].rm_eo;
return reval;
}
char* linklocal(char* MAC48){
regex_t regex;
char* pattern = "[A-E0-9]+";
errno_t state = regcomp(®ex,pattern,REG_EXTENDED);
if(state){
char* errbuf = calloc(20,sizeof(char));
regerror(state,®ex,errbuf,20);
fprintf(stderr,"Failed to compile Regex:%s\n"
"Reason:%s\n",pattern,errbuf);
regfree(®ex);
free(errbuf);
exit(EXIT_FAILURE);
}
//EUI-48 和 EUI-64前24位是OUI
//EUI-64占64位,转换为十六进制用16个字符表示
//EUI-48转EUI-64分两个步骤
//1.在第25位插入11111111 11111110 即 FF FE
//2.将对应的结果第7位(ul)求异或
char* EUI64 = calloc(16 + 1,sizeof(char));
char* EUI48 = calloc(12 + 1,sizeof(char));
char* value = NULL;
while((value = regnext(MAC48,®ex)) != NULL){
strcat(EUI48,value);
free(value);
}
regfree(®ex);
//step 1.
memcpy(EUI64,EUI48,6);
memcpy(EUI64 + 6,"FFEF",4);
memcpy(EUI64 + 10,EUI48 + 6,6);
//step 2.
char ul = EUI64[1];
ul = (ul >= 'A' && ul <= 'F') ? 10 + ul - 'A' : ul - '0';
ul ^= 2;
EUI64[1] = (ul >= 0 && ul <= 9) ? ul + '0' : ul - 10 + 'A';
printf("\nEUI64: %s\n",EUI64);
char* reval = calloc(23,sizeof(char)); //返回的链路本地地址字符串最长22个字节
strcat(reval,"fe80::");
pattern = "[0-9A-F]{4}";
state = regcomp(®ex,pattern,REG_EXTENDED);
if(state){
char* errbuf = calloc(20,sizeof(char));
regerror(state,®ex,errbuf,20);
fprintf(stderr,"Failed to compile Regex:%s\n"
"Reason:%s\n",pattern,errbuf);
free(errbuf);
regfree(®ex);
exit(EXIT_FAILURE);
}
while((value = regnext(EUI64,®ex)) != NULL){
strcat(reval,value);
strcat(reval,":");
free(value);
}
regfree(®ex);
reval = process(reval);
printf("Link local IPv6 Address : %s\n",reval);
return reval;
}
char* process(char* ipv6){
ipv6[strlen(ipv6) - 1] = '\0';//去除尾部分号
for(int i = 0 ; i < strlen(ipv6) ; i ++){//将IPv6地址转化为小写
ipv6[i] = tolower(ipv6[i]);
}
return ipv6;
}