4

我正在编写一个程序,需要设置接口的 ip 地址并将其设置UPRUNNING. 我可以使用 ipv4 地址执行此操作ioctl(SIOCSIFADDR),但 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\n",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 地址。如果这是真的,我们用什么来ioctl()涉及 ipv6 地址?

我要设置的输入 IP 地址是aaaa::bbbb、或。in.over_nAF_INETAF_INET6

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

非常感谢。

4

1 回答 1

0

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

rtnetlink 的优点是它支持每个设备多个地址,并且可以提供更多信息,因为它更具动态性,并且可以做很多花哨的事情。

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

于 2018-05-03T08:56:08.323 回答