如何使用 inet_pton 和 struct ifreq 从 C 程序设置 IP 地址

Posted

技术标签:

【中文标题】如何使用 inet_pton 和 struct ifreq 从 C 程序设置 IP 地址【英文标题】:How to use inet_pton and struct ifreq for setting up ip address from C program 【发布时间】:2013-07-27 02:35:35 【问题描述】:

我正在尝试从 C 程序设置网络接口的 IP 地址。我环顾四周,发现我可以使用ioctl()inet_pton() 来做到这一点。我的问题是,我无法弄清楚我应该在struct ifreq 的哪个位置存储转换后的地址。我不断收到ioctl() - invalid argument 错误。

我特别看过How to set the IP address from C in linux这个例子。这表示我们可以将ifr.ifr_addr 转换为struct sockaddr_in。但是,在进行地址转换后,ioctl() 失败并出现无效参数错误。

以下是代码:

280 void setip (int fd) 
281 
282     struct ifreq ifr;
283     struct sockaddr_in * addr;
284     int stat;
285 
286     strcpy(ifr.ifr_name, in.dev.device);          // in.dev.device = tun2
287     addr = (struct sockaddr_in *) &ifr.ifr_addr;
288 
289     addr->sin_family = AF_INET;
290 
291     stat = inet_pton(addr->sin_family, in.dev.ip_addr, &addr->sin_addr); // in.dev.ip_addr = "100.0.0.10"
292     if (stat == 0)
293         raise_error("inet_pton() - invalid ip");
294     if (stat == -1)
295         raise_error("inet_pton() - invalid family");
296 
297     if (stat == 1);
298     else
299         raise_error("inet_pton()");
300 
301     /* This is just to test if address conversion happened properly */
302     char buff[BUFF_SIZE];
303     char * foo;
304     foo = inet_ntop(AF_INET, &addr->sin_addr, buff, BUFF_SIZE);
305     if (foo == NULL)
306         raise_error("inet_ntop()");
307     else
308         printf("main = %s, addr = %s\n",in.dev.ip_addr, buff);
309     
310     if (ioctl(fd, SIOCSIFADDR, &ifr, sizeof(ifr)) == -1)
311         raise_error("ioctl() - SIOCSIFADDR");
312 

编辑:raise_error 函数是:

void raise_error (const char * msg) 

    perror(msg);
    exit(1);

我得到的输出是:

main = 100.0.0.10, addr = 100.0.0.10
ioctl() - SIOCSIFADDR: Invalid argument

我猜测转换后的地址被放置在 struct ifreq 中的错误位置,但我无法确定应该放置的确切位置。 我也尝试使用ifr.ifr_addr 进行地址转换,但也没有用。

编辑:我以 root 身份运行程序。

任何帮助将不胜感激。如果我需要发布更多代码或调试输出,请告诉我。

谢谢

【问题讨论】:

【参考方案1】:

我认为您看到了错误的错误消息,因为 raise_errorperror 之前调用了另一个函数,而您看到的是该调用的结果而不是 ioctl.. 您应该始终在之后立即调用 perror您要测试的功能。我尝试了您的代码,ioctl() 失败并显示“ioctl(): Permission denied”,您需要以 root 身份运行它(另请注意,您不需要传递 ifreq 的大小)

【讨论】:

您好,感谢您的回复,我正在以 root 身份运行该程序,并且 raise_error 在其他情况下工作正常。我已经通过检查 raise_error 打印的错误以及手册中给出的相应 errno 错误来确认这一点。如果我在这里遗漏了什么,请告诉我。 我可以设置 eth0 的 IP 地址,但不能设置 tun 设备。关于如何为 tun 设备做到这一点的任何想法?谢谢【参考方案2】:

根据 mux 的评论,我在 eth0 上尝试了相同的代码,它有效。因此,我猜 tun 设备是不同的,我们不能使用相同的 ioctl() 调用它们。 所以使用inet_ptonstruct ifreqioctl()设置ip地址的方式是对的,但是在tun设备上不行。

【讨论】:

以上是关于如何使用 inet_pton 和 struct ifreq 从 C 程序设置 IP 地址的主要内容,如果未能解决你的问题,请参考以下文章

网络编程函数inet_pton()

网络编程之inet_pton函数

何时在directx11 中为STRUCTS 和类使用前缀“I”?

解决“‘inet_addr‘: Use inet_pton() or InetPton() instead “问题

C结构体struct 和 共用体union的使用测试

解决“‘inet_addr‘: Use inet_pton() or InetPton() instead “问题