我正在尝试在C中创建一个隧道,IM设置它的IP地址时遇到了困难。我在ioctl中使用SIOCSIFADDR参数时遇到了“invalid argument”错误。如果此函数不能与tun一起使用,有人能解释一下如何设置IP地址吗?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if_tun.h>
#include <linux/if.h>
#include <fcntl.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#define IP_DEST "127.0.0.1"
#define IP_SOURCE "127.0.0.1"
int tun_alloc(char* dev) {
//dev will store the name of the tun created
struct ifreq ifr;
int fd, err;
char *clonedev = "/dev/net/tun";
//open the clone device
if( (fd = open(clonedev, O_RDWR)) < 0 ) {
printf("Error opening directory");
return fd;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN;
if (*dev) {
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
//Create the TUN
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
close(fd);
printf("Error creating the tun");
return err;
}
strcpy(dev, ifr.ifr_name);
return fd;
}
int main(int argc, char* argv[]) {
//Creating the TUN interface
char tun_name[IFNAMSIZ];
strncpy(tun_name, "tun3", IFNAMSIZ);
int tunfd = tun_alloc(tun_name);
if (tunfd < 0) {
perror("tun_create");
return 1;
}
printf("TUN interface %s created\n", tun_name);
//Setting its IP Adress
struct ifreq ifr;
struct sockaddr_in addr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, tun_name, IFNAMSIZ);
addr.sin_family = AF_INET;
if(inet_pton(AF_INET,IP_DEST,&(addr.sin_addr))<0){
fprintf(stderr,"ERROR with the IP address");
return 1;
};
memcpy(&(ifr.ifr_addr), &addr, sizeof (struct sockaddr));
if (ioctl(tunfd, SIOCSIFADDR, &ifr) < 0) {
perror("ioctl");
exit(1);
}
printf("TUN interface %s set IP address to %s\n", tun_name, IP_DEST);
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if(ioctl(tunfd, SIOCSIFFLAGS, &ifr)<0){
perror("ioctl");
exit(1);
};
printf("TUN running");
return 0;
}
我并不真正理解iotcl是如何工作的,文档也没有帮助我理解tun接口。
1条答案
按热度按时间mo49yndu1#
SIOCSIFADDR
和SIOCSIFFLAGS
(以及其他SIOwhatever
)ioctl
调用应该针对任何AF_INET
套接字,而不是针对tun
接口本身。设计的目的是让您可以使用它们配置 * 任何 * 接口,而不仅仅是您创建的接口。您必须创建一个AF_INET
套接字,然后在该套接字上调用ioctl
。如果您认为必须创建套接字有点奇怪,那么您是对的。
ioctl
用于对文件进行“特殊请求”,read
或write
以外的其他文件。请求的解释取决于文件类型。使用套接字可确保IP网络系统将其解释为与IP套接字相关的请求。它 * 将 *从逻辑上讲,您也可以在tun
接口上发出与IP相关的特殊请求,但显然内核开发人员没有想到这一点,而且它们也没有必要工作,因为您只需创建一个套接字即可。还有另一种方法可以使用名为“rtnetlink”的系统来设置IP地址,但对于像这样简单的场景来说,它更复杂,也没有必要。