如何从C程序为接口设置ipv6地址

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何从C程序为接口设置ipv6地址相关的知识,希望对你有一定的参考价值。

我正在编写一个程序,需要设置一个接口的IP地址,并设置它UPRUNNING。我可以使用ioctl(SIOCSIFADDR)为ipv4地址执行此操作,但ipv6地址的相同内容会出错。

以下是代码段:

 329     memset(&ifr, 0, sizeof(ifr));
 330     strncpy(ifr.ifr_name, in.dev.device, IFNAMSIZ);
 331 
 332     /* we need a socket descriptor for ioctl(). Cant use tun descriptor */
 333     s = socket(in.over_n, SOCK_DGRAM, 0);
 334     /* Now check if socket we got is ok */
 335     if (s < 0)
 336         raise_error("socket()");
 337         
 338 
 339 
 340     switch (in.over_n) {
 341     
 342     case AF_INET:   memset(&addr4, 0, sizeof(addr4));
 343                     addr4.sin_family = AF_INET;
 344                     /* Convert ip to network binary */
 345                     stat = inet_pton(addr4.sin_family, in.dev.ip_addr, &addr4.sin_addr);
 346                     ifr.ifr_addr = *(struct sockaddr *) &addr4;
 347                     break;
 348                     
 349     case AF_INET6:  memset(&addr6, 0, sizeof(addr6));
 350                     addr6.sin6_family = AF_INET6;
 351                     /* Convert ip to network binary */
 352                     stat = inet_pton(addr6.sin6_family, in.dev.ip_addr, &addr6.sin6_addr);
 353                     ifr.ifr_addr = *(struct sockaddr *) &addr6.sin6_addr;
 354                     break; 
 355     default:        raise_error("invalid network prot");
 356     }               
 357                     
 358     /* Check if conversion happened properly */
 359     if (stat == 0)
 360         raise_error("inet_pton() - invalid ip");
 361     if (stat == -1)
 362         raise_error("inet_pton() - invalid family");
 363         
 364     if (stat != 1)
 365         raise_error("inet_pton()");
 366         
 367     char dum[BUFF_SIZE];
 368     if (inet_ntop(in.over_n, &ifr.ifr_addr, dum, BUFF_SIZE) != NULL)
 369         printf("name = %s, ip = %s
",ifr.ifr_name,dum);
 370     
 371     /* Set ip */
 372     if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) == -1) 
 373         raise_error("ioctl() - SIOCSIFADDR");

这适用于ipv4地址,但ipv6地址给我错误:

name = tun9, ip = aaaa::bbbb
ioctl() - SIOCSIFADDR: Invalid argument

如果我将第353行更改为

 353                     ifr.ifr_addr = *(struct sockaddr *) &addr6;

然后错误变为

name = tun9, ip = a00::aaaa:0:0:0
ioctl() - SIOCSIFADDR: No such device

我注意到struct ifreq有一个成员struct sockaddr,我认为它比struct sockaddr_in6小但是和sockaddr_in一样大。我想知道这是否是问题,struct ifreq无法保存ipv6地址。如果这是真的,那么我们对涉及ipv6地址的ioctl()使用了什么?

我试图设置的输入IP地址是aaaa::bbbbin.over_nAF_INETAF_INET6

任何帮助都感激不尽。如果我需要发布更多代码,输出等,请告诉我。

非常感谢。

答案

对于IPv6,您应该使用rtnetlink API。这是ip等工具使用的API,ifconfig也可能在现代版本中使用它。

rtnetlink的优势在于它支持每个设备多个地址,并且可以提供更多信息,因为它更具动态性,可以做许多奇特的事情。

但是rtnetlink API最初工作也很棘手,因为它需要一些结构来正确填充和解析,包括需要填充正确sizeof()的一些奇怪的成员组合。

以上是关于如何从C程序为接口设置ipv6地址的主要内容,如果未能解决你的问题,请参考以下文章

c语言如何输出ipv6header

IPV6怎么设置?(本地路由)

华三交换机打了ipv6但是没显示

ipv4 ipv6哪个上网速度快

潘多拉的系统怎么配置ipv6

将 IPv4/IPv6 地址和端口设置为 sockaddr_storage 结构