如何通过C程序设置tun设备的IP地址并设置link UP

Posted

技术标签:

【中文标题】如何通过C程序设置tun设备的IP地址并设置link UP【英文标题】:How to set IP address of tun device and set link UP through C program 【发布时间】:2013-07-27 17:16:10 【问题描述】:

我正在编写一个使用 Linux tun 设备进行隧道传输的 C 程序。我正在创建一个 tun 设备,使用 ioctl() 调用设置它的所有者、组和持久性。但是,为了进行隧道,我需要为设备设置 IP 地址并设置链接。我目前正在使用

# ip addr add
# ip link set

我想设置地址、掩码并将链接设置为up。有没有什么方法可以通过程序做到这一点而不调用ip 命令?

我尝试将ioctl()SIOCSIFADDR 命令一起使用,但它不适用于tun 设备,并且适用于eth0。我收到错误 ioctl() - Invalid argument

以下是适用于eth0 但不适用于tun2 之类的代码:

280 void setip (int fd) 
281 
282     struct ifreq ifr;
283     struct sockaddr_in addr;
284     int stat;
285     
286     memset(&ifr, 0, sizeof(ifr));
287     memset(&addr, 0, sizeof(addr));
288     strncpy(ifr.ifr_name, in.dev.device, IFNAMSIZ);     // device name: eg. tun2
289     
290     addr.sin_family = AF_INET;
291     stat = inet_pton(addr.sin_family, in.dev.ip_addr, &addr.sin_addr); // ip string
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     ifr.ifr_addr = *(struct sockaddr *) &addr;
302     /* This is just to test if address conversion happened properly */
303     char buff[BUFF_SIZE];
304     char * foo;
305     foo = inet_ntop(AF_INET, &addr.sin_addr, buff, BUFF_SIZE);
306     if (foo == NULL)
307         raise_error("inet_ntop()");
308     else
309         printf("main = %s, addr = %s\n",in.dev.ip_addr, buff);
310         
311     if (ioctl(fd, SIOCSIFADDR, (caddr_t) &ifr) == -1)
312         raise_error("ioctl() - SIOCSIFADDR"); 
313 

我搜索了为 tun 设备执行此操作的方法,但找不到任何方法。我必须使用ipifconfig 之类的所有帖子。

有没有办法通过程序做到这一点? 谢谢

【问题讨论】:

实现此目的的正确方法是使用 IOCTL。如文档man7.org/linux/man-pages/man7/netdevice.7.html 中所述,IOCTL 允许配置任何套接字设备。您确定,此代码适用于 eth0 吗?你是如何创建 tun0 设备的?抱歉,我无法测试代码。 您好,感谢您的回复。我测试了 eth0 的代码,它运行良好。 (我对函数做了一些修改,因为这是更大程序的一部分)。我必须添加一个socket() 调用来获取文件描述符fd。此代码中的fd 是tun 设备描述符。我使用与Linux documentation page 第 3.1 节中给出的代码几乎相同的代码来创建 tun 设备。 【参考方案1】:

我发现了问题所在。对于eth0,我使用套接字描述符作为ioctl() 的参数,对于tun 设备,我使用tun 设备描述符。我也为 tun 设备创建了一个套接字,并且 ioctl() 工作。以下是代码:

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

感谢 Giuseppe Pes 的回复 :)

【讨论】:

这个程序和你的方法一样:linuxgazette.net/149/misc/melinte/udptun.c

以上是关于如何通过C程序设置tun设备的IP地址并设置link UP的主要内容,如果未能解决你的问题,请参考以下文章

C 激活网卡并配置IP与子网掩码

TUN/TAP设备浅析(一) -- 原理浅析

如何使用 C 程序为计算机设置 IP 地址?

如何在同一网络上以编程方式获取其他支持Wifi的设备的IP地址?

Linux 网络工具详解之 ip tuntap 和 tunctl 创建 tap/tun 设备

如何设置CentOS 7获取动态及静态IP地址