启用tun设备开启tap虚拟网卡功能

注意:该文章中的arp应答部分是有问题的,由于作者现在已经没有实验环境无法再进行修正了,望看该文章的人注意一下

关于tun设备启用tap网卡,就是启用一个字符设备,使用open函数得到一个tun设备的文件描述符,可以使用write和read,或者pcap接口读写网卡,以下的部分为tun设备的控制代码,包括了网卡mac ip mask设置等,主要就是ioctl函数的使用

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

static char * interface_name_cut (char *buf, char **name)  
{  
    char *stat; 

    while (*buf == ' ')                                                                                                                                                                                                                     
        buf++;  
    *name = buf;  
    
    stat = strrchr (buf, ':');  
    *stat = '\0';  
    
    return *name;  
}

//check whether the network card exists.
int check_phy_name(char *interface)  
{  
    FILE *fp;  
    char buf[PROCBUFSIZ];  
    char *name;  

    fp = fopen (_PATH_PROC_NET_DEV, "r");  
    if (fp == NULL) {     
        printf("open proc file error\n");  
        goto EXIT1;
    }     

    fgets (buf, PROCBUFSIZ, fp);  
    fgets (buf, PROCBUFSIZ, fp);  

    while (fgets (buf, PROCBUFSIZ, fp) != NULL) {     
        interface_name_cut(buf, &name);  
        if(strcmp(interface,name)==0) {
            fclose(fp);
            return 1;  
        }
    } 

EXIT1:
    fclose(fp);  
    return -1;  
} 

//设置ip和mask
static int set_addr(char *dev_name, char *ip, int flag)
{
    struct ifreq ifr;
    struct sockaddr_in sin;
    int sockfd;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd == -1) {
        perror("tap");
        goto EXIT2;
    }

    snprintf(ifr.ifr_name, sizeof(dev_name), "%s", dev_name);

    /* Read interface flags */
    if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
        perror(ifr.ifr_name);
        goto EXIT2;
    }

    memset(&sin, 0, sizeof(struct sockaddr));
    sin.sin_family = AF_INET;
    inet_aton(ip, &sin.sin_addr);
    memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
   
    if (ioctl(sockfd, flag, &ifr) < 0) {
        perror(ifr.ifr_name);
        goto EXIT2;
    }
    
    close(sockfd);
    return 1;

EXIT2:
    close(sockfd);
    exit(-1);
}

static int get_tun_mac(char *dev_name, uint8_t *tun_mac)
{
    struct ifreq ifr;
    int sockfd, ret;
    uint8_t *mac;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd == -1) {
        perror("tap");
        goto EXIT1;
    }

    snprintf(ifr.ifr_name, sizeof(dev_name), "%s", dev_name);

    ret = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
    if (ret == -1) {
        printf("get tun mac error\n");
        goto EXIT1;
    }   

    mac = (uint8_t *)ifr.ifr_hwaddr.sa_data;
    memcpy(tun_mac, mac, 6);
    
    close(sockfd);
    return 1;

EXIT1:
    close(sockfd);
    exit(-1);
}

static int set_tun_mac(char *dev_name, uint8_t *tun_mac)
{
    struct ifreq ifr;
    int sockfd, ret;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd == -1) {
        perror("tap");
        goto EXIT;
    }

    snprintf(ifr.ifr_name, sizeof(dev_name), "%s", dev_name);
    
    /* Read interface flags */
    if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
        perror(ifr.ifr_name);
        goto EXIT;
    }
    
    ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
    memcpy(&ifr.ifr_hwaddr.sa_data, tun_mac, 6);

    ret = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
    if (ret == -1) {
        printf("set tun mac error\n");
        goto EXIT;
    } 

    close(sockfd);
    return 1;

EXIT:
    close(sockfd);
    return -1;
}

static int set_routing(char *dst, char *gw, char *genmask, char *dev)
{
    int sockfd;
    struct rtentry route;
    struct sockaddr_in *addr;
    int err = 0;

    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("set routing");
        close(sockfd);
        return -1;
    }

    memset(&route, 0, sizeof(route));
    
    route.rt_dev = dev;
    
    addr = (struct sockaddr_in*)&route.rt_gateway;
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = inet_addr(gw);

    addr = (struct sockaddr_in*) &route.rt_dst;
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = inet_addr(dst);

    addr = (struct sockaddr_in*) &route.rt_genmask;
    addr->sin_family = AF_INET;
    inet_aton(genmask, &addr->sin_addr);

    route.rt_flags = RTF_UP | RTF_GATEWAY;
    route.rt_metric = 0;
    if ((err = ioctl(sockfd, SIOCADDRT, &route)) != 0) 
    {
        perror("ioctl routing");
        close(sockfd);
        return -1;
    }
    
    close(sockfd);
    return 1;
}

static int set_gateway(char ip[16])
{
    int sockfd;
    struct sockaddr_in sockaddr;
    struct rtentry rt;
    
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("set gateway");
        close(sockfd);
        exit(-1);
    } 

    memset(&rt, 0, sizeof(struct rtentry));
    memset(&sockaddr, 0, sizeof(struct sockaddr_in));
    sockaddr.sin_family = AF_INET;
    sockaddr.sin_port = 0;
    inet_aton(ip, &sockaddr.sin_addr);

    memcpy (&rt.rt_gateway, &sockaddr, sizeof(struct sockaddr_in));
    ((struct sockaddr_in *)&rt.rt_dst)->sin_family = AF_INET;
    ((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
    rt.rt_flags = RTF_GATEWAY;

    if (ioctl(sockfd, SIOCADDRT, &rt) < 0)
    {
        perror("ioctl(SIOCADDRT) error in set_default_route\n");
        close(sockfd);
        exit(-1);
    }
    
    close(sockfd);
    return 1;
}

int interface_up(char *name)
{
    int fd;
    struct ifreq ifr;
    
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0)
    {
        fprintf(stderr, "tun : interface sokcet open failed!\n");
        return -1;
    }

    strcpy(ifr.ifr_name, name);
    
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        exit(-1);
    }

    ifr.ifr_flags |= IFF_UP;

    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        exit(-1);
    }

    return 1;
}

int interface_down(char *name)
{
    int fd;
    struct ifreq ifr;
    
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0)
    {
        fprintf(stderr, "tun : interface sokcet open failed!\n");
        return -1;
    }

    strcpy(ifr.ifr_name, name);
    
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        return -1;
    }

    ifr.ifr_flags &= ~IFF_UP;

    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        return -1;
    }

    return 1;
}

//arp应答就是填充一个mac地址然后对换mac,将数据包发出
static int build_arp_response(int tunfd, char *origin_pkts,int pkts_len)
{
    char buf[128]={0};
    unsigned char mymac[6] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
    struct ethhdr *eth_request = (struct ethhdr *)origin_pkts;
    struct ethhdr *eth_reply = (struct ethhdr *)buf;

    //原本的代码部分存在问题,所以删除了,如果有需要的自行添加,
    //arp的应答只需要修改下行流量的目标mac即可,将ff:ff:ff:ff:ff:ff换成mymac
    //调换ip和mac然后write写数据到tunfd即可
    return 0;
}

int main(int argc, char *argv[])
{
    struct ifreq ifr;
	int tunfd;

    //检测主网卡是否存在 -1 no exist
    if (check_phy_name("tap") == -1)  
    {
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_flags |= (IFF_TAP | IFF_NO_PI);
        strncpy(ifr.ifr_name, "tap", IFNAMSIZ);

        tunfd = open("/dev/net/tun", O_RDWR|O_NONBLOCK);
        if (tunfd == -1)
        {
            fprintf(stderr, "tun : /dev/net/tun open failed\n");
            return -1;
        }

        int ior;
        ior = ioctl(tunfd, TUNSETIFF, (void *)&ifr);
        if (ior < 0)
        {
            fprintf(stderr, "tun : virtual network create failed\n");
            return -1;
        }
    }

	unsigned char mac[6] = {0x43, 0x42, 0x15, 0x57, 0x45, 0x65};
	char ip[] = "192.168.0.1"
	char mask[] = "255.255.255.0";
    set_tap_mac("tap", mac);

    if (set_addr("tap", ip, SIOCSIFADDR) == -1)                       //set ip
        return -1;
    if (set_addr("tap", mask, SIOCSIFNETMASK) == -1)  //set netmask
        return -1;

    if (interface_up("tap") == -1)
    {
        fprintf(stderr, "virtual network up failed!\n");
        return -1;
    }

    if (set_routing("0.0.0.0", ip, "0.0.0.0", "tap") == -1)
    {
        fprintf(stderr, "virtual network set routing failed!\n");
        return -1;
    }
  
    get_tap_mac("tap", mac);
    printf("tun mac : %x:%x:%x:%x:%x:%x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
 
    return 1;
}

 

你可能感兴趣的:(tcp/ip网络,c/c++)