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

 

posted @ 2019-02-18 14:29  salami_china  阅读(2306)  评论(0编辑  收藏  举报