在C中设置TUN的IP地址

qfe3c7zg  于 2023-02-03  发布在  其他
关注(0)|答案(1)|浏览(281)

我正在尝试在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接口。

mo49yndu

mo49yndu1#

SIOCSIFADDRSIOCSIFFLAGS(以及其他SIOwhateverioctl调用应该针对任何AF_INET套接字,而不是针对tun接口本身。设计的目的是让您可以使用它们配置 * 任何 * 接口,而不仅仅是您创建的接口。您必须创建一个AF_INET套接字,然后在该套接字上调用ioctl
如果您认为必须创建套接字有点奇怪,那么您是对的。ioctl用于对文件进行“特殊请求”,readwrite以外的其他文件。请求的解释取决于文件类型。使用套接字可确保IP网络系统将其解释为与IP套接字相关的请求。它 * 将 *从逻辑上讲,您也可以在tun接口上发出与IP相关的特殊请求,但显然内核开发人员没有想到这一点,而且它们也没有必要工作,因为您只需创建一个套接字即可。
还有另一种方法可以使用名为“rtnetlink”的系统来设置IP地址,但对于像这样简单的场景来说,它更复杂,也没有必要。

相关问题