C语言 IPv6 十六进制 转 十进制
1 #include <stdio.h> 2 #include <string.h> 3 #include <math.h> 4 5 //ipv4地址转换 6 int ipv4_to_i(const char *ip, unsigned int *ipv4_addr) 7 { 8 char str_ip_index[4] = {'\0'}; 9 unsigned int ip_int, ip_add = 0; 10 unsigned int j = 0, a = 3, i = 0; 11 12 for(i = 0; i <= strlen(ip); i++) { 13 if (ip[i] == '\0' || ip[i] == '.') { 14 ip_int = atoi(str_ip_index); 15 if (ip_int > 255) 16 return 0; 17 18 ip_add += (ip_int * pow(256, a)); 19 a--; 20 memset(str_ip_index, 0, sizeof(str_ip_index)); 21 22 j = 0; 23 continue; 24 } 25 26 str_ip_index[j] = ip[i]; 27 j++; 28 } 29 30 *ipv4_addr = ip_add; 31 32 return 1; 33 } 34 35 /* ipv6 无符号整型数组转化为字符串 */ 36 void ipv6_to_str(char *addr_str, unsigned int ipv6_addr[]) 37 { 38 /* ipv6地址128位,数组ip维数默认为4 */ 39 /* 输出格式为: A:B:C:D:E:F:G:H. */ 40 int i; 41 unsigned short msw, lsw; 42 char *addr_str_end_ptr; 43 44 addr_str[0] = '\0'; 45 addr_str_end_ptr = addr_str; 46 for (i = 0; i < 4; i++) 47 { 48 msw = ipv6_addr[i] >> 16; 49 lsw = ipv6_addr[i] & 0x0000ffff; 50 addr_str_end_ptr += sprintf(addr_str_end_ptr, "%X:%X:", msw, lsw); 51 } 52 *(addr_str_end_ptr - 1) = '\0'; 53 } 54 55 char * string_white_space_trim(char *str) 56 { 57 /* 移除字符串中空格 */ 58 int index; 59 int new_index; 60 int str_length; 61 62 str_length = strlen(str); 63 64 for (index = 0, new_index = 0; index < str_length; index++) 65 { 66 if (!isspace((unsigned char)str[index])) 67 { 68 str[new_index] = str[index]; 69 new_index++; 70 } 71 } 72 73 str[new_index] = '\0'; 74 75 return str; 76 } 77 78 int string_char_count(const char *string, char character) 79 { 80 /* 计算字符串中,给定字符的数量 */ 81 int i; 82 int str_length; 83 int count = 0; 84 85 str_length = strlen(string); 86 for (i = 0; i < str_length; i++) 87 if (string[i] == character) 88 count++; 89 90 return count; 91 } 92 93 int ipv6_address_field_type_get(const char * field_str) 94 { 95 /* 判断ipv6地址域类型 */ 96 int i = 0; 97 int length; 98 int type; 99 unsigned int ipv4_addr; 100 101 /* 通过长度判断 */ 102 /* 16进制数字域: 1-4 */ 103 /* "::"域:0 */ 104 /* ipv4地址域: 7-15 */ 105 106 length = strlen(field_str); 107 108 if (0 == length) 109 { 110 type = 1; 111 } 112 else if (length <= 4) 113 { 114 // 确保每个数字为16进制 115 for (i = 0; i < length; i++) 116 if (!isxdigit((unsigned char)field_str[i])) 117 return -1; 118 type = 0; 119 } 120 else if((length >= 7) && (length <= 15)) 121 { 122 //确保是有效的ipv4地址 123 if (ipv4_to_i(field_str, &ipv4_addr)) 124 type = 2; 125 else 126 type = -1; 127 } 128 else 129 { 130 type = -1; 131 } 132 133 return type; 134 } 135 136 int ipv6_to_i(const char *addr_str, int length, unsigned int ipv6_addr_ptr[]) 137 { 138 /***************************************************************************/ 139 /* 功能:解析ipv6地址字符串,转换为无符号整形,存入4个无符号整形的一维数组 */ 140 /* ipv6地址 128位,prefix length: */ 141 /* - 64 for EUI-64 addresses */ 142 /* - 128 for non-EUI-64 addresses */ 143 /* 输入:ipv6地址字符串,地址位数,默认为128位 */ 144 /* 输出:返回解析成功或失败;指向4个无符号整形的一维数组的指针 */ 145 /****************************************************************************/ 146 147 char addr_str_copy[256]; 148 int i, num_fields; 149 //unsigned int *ret_addr_ptr; 150 unsigned short int addr_field_arr[8]; 151 int addr_index; 152 char *ith_field; // 指向地址当前域 153 int ith_field_type; // 地址域类型 154 char *next_field; 155 int double_colon_field_index = -1; // 字符串地址中"::"的位置 156 unsigned int ipv4_address; // ipv6地址中的ipv4部分 157 unsigned int msw, lsw; 158 int error = 0; 159 160 //复制一份,以便操作 161 strcpy(addr_str_copy, addr_str); 162 163 // 移除字符串中的空格字符 164 string_white_space_trim(addr_str_copy); 165 166 /* IPv6地址可能几种格式: */ 167 /* 1) 2006:DB8:2A0:2F3B:34:E35:45:1 用16进制表示每个域的值(16位) */ 168 /* 2) 2006:DB8::E34:1 , "::" 代表0,且只能出现一次 */ 169 /* 3) 2002:9D36:1:2:0:5EFE:192.168.12.9 带有ipv4地址 */ 170 171 // 计算字符串中冒号,字符串中地址域数比冒号多一个 172 num_fields = string_char_count(addr_str_copy, ':') + 1; 173 174 // 域最大数量为length/16 + 2 175 // 如 ::0:0:0:0:0:0:0:0. 176 if (num_fields > ((length >> 4) + 2)) 177 { 178 ipv6_addr_ptr = NULL; 179 return 0; 180 } 181 182 // 初始化 183 ith_field = addr_str_copy; 184 185 for (i = 0, addr_index = 0; i < num_fields; i++) 186 { 187 // 获得下一个域的指针 188 next_field = strchr(ith_field, ':'); 189 190 /* 若当前是最后一个域, next_field 是 NULL */ 191 /* 否则,替换':'为'\0', 字符串可以结束,从而ith_field指向当前域 */ 192 /* next_field指向下一个域头部 */ 193 if (NULL != next_field) 194 { 195 *next_field = '\0'; 196 ++next_field; 197 } 198 199 // 发现这个域的类型 200 ith_field_type = ipv6_address_field_type_get(ith_field); 201 202 switch (ith_field_type) 203 { 204 case 0: 205 // 域类型为16进制表示 206 207 if (addr_index >= (length >> 4)) 208 { 209 error = 1; 210 break; 211 } 212 // 字符串转换为16进制 213 addr_field_arr[addr_index] = (unsigned short)strtoul(ith_field, NULL, 16); 214 ++addr_index; 215 break; 216 217 case 1: 218 // 域类型为 "::" 219 220 // 若出现在字符串的开头或结尾,忽略 221 if ((0 == i) || (i == num_fields - 1)) 222 { 223 break; 224 } 225 226 // 若出现大于一次,错误 227 if (double_colon_field_index != -1) 228 { 229 error = 1; 230 break; 231 } 232 233 // 记下位置 234 double_colon_field_index = addr_index; 235 236 break; 237 238 case 2: 239 // 域类型为ipv4地址 240 241 // 确保在地址中还有两个未设置的域 242 if (addr_index >= 7) 243 { 244 error = 1; 245 break; 246 } 247 248 // ipv4地址解析 249 ipv4_to_i(ith_field, &ipv4_address); 250 251 // 存储高16位 252 addr_field_arr[addr_index] = (unsigned short)(ipv4_address >> 16); 253 254 // 存储低16位 255 addr_field_arr[addr_index + 1] = (unsigned short)(ipv4_address & 0x0000ffff); 256 257 addr_index += 2; 258 259 break; 260 default: 261 error = 1; 262 break; 263 } 264 265 if (error) 266 { 267 ipv6_addr_ptr = NULL; 268 return 0; 269 } 270 271 ith_field = next_field; 272 } 273 274 // 计算的域不是8,并且没有"::",错误 275 if ((addr_index != (length >> 4)) && (-1 == double_colon_field_index)) 276 { 277 ipv6_addr_ptr = NULL; 278 return 0; 279 } 280 281 if ((addr_index != (length >> 4)) && (-1 != double_colon_field_index)) 282 { 283 // 设置相应"::"对应addr_field_arr中位置为0 284 memmove(addr_field_arr + (double_colon_field_index + (length >> 4) - addr_index), 285 addr_field_arr + double_colon_field_index, (addr_index - double_colon_field_index) * 2); 286 memset(addr_field_arr + double_colon_field_index, 0, ((length >> 4) - addr_index) * 2); 287 } 288 289 for (i = 0; i < 4; i++) 290 { 291 msw = addr_field_arr[2 * i]; 292 lsw = addr_field_arr[2 * i + 1]; 293 294 (ipv6_addr_ptr)[i] = (msw << 16 | lsw); 295 } 296 297 return 1; 298 } 299 300 int main(void) 301 { 302 char addr[256] = {"0"}; 303 unsigned int ip_v4 = 3356567252; 304 unsigned int ipv6[4] = {3356567252, 3356567253, 3356567254, 3356567255}; 305 unsigned int ipv61[4] = {65538, 196612, 327686, 458760}; 306 307 char *ipv6_str1 = "1:2:3:4:5:6:7:8"; 308 char *ipv6_str2 = "1:2:3:4:5:6:7:8::"; 309 char *ipv6_str3 = "::1:2:3:4:5:6:7:8"; 310 char *ipv6_str4 = "1:2:3:4:5:6:192.168.1.100"; 311 char *ipv6_str5 = "1:2::5:6:7:8"; 312 char *ipv6_str6 = "1::3:4:5:6:7:8"; 313 char *ipv6_str7 = "1::4:5:6:7:8"; 314 char *ipv6_str8 = "1::8"; 315 316 unsigned int ipv6_addr[4]; 317 unsigned int ipv4_addr; 318 unsigned int ipv6_addr_sum = 1; 319 int flag; 320 int i; 321 322 ipv6_to_str(addr, ipv61); 323 printf("ipv6: %s\n", addr); 324 325 flag = ipv4_to_i("192.168.1.100", &ipv4_addr); 326 if (flag) 327 { 328 printf("ipv4_addr: %u\n", ipv4_addr); 329 } 330 331 flag = ipv6_to_i(ipv6_str1, 128, ipv6_addr); 332 if (flag) 333 { 334 for (i = 0; i < 4; i++) 335 { 336 printf("ipv6_addr: %u\n", ipv6_addr[i]); 337 ipv6_addr_sum += ipv6_addr[i]; 338 } 339 340 printf("ipv6_addr_sum: %u\n", ipv6_addr_sum); 341 } 342 343 return 0; 344 }
编译运行:
[root@node1 ~]# gcc ddd.c -lm
[root@node1 ~]# ./a.out
ipv6: 1:2:3:4:5:6:7:8
ipv4_addr: 3232235876
ipv6_addr: 65538
ipv6_addr: 196612
ipv6_addr: 327686
ipv6_addr: 458760
ipv6_addr_sum: 1048597