注意:该文章中的arp应答部分是有问题的,由于作者现在已经没有实验环境无法再进行修正了,望看该文章的人注意一下
关于tun设备启用tap网卡,就是启用一个字符设备,使用open函数得到一个tun设备的文件描述符,可以使用write和read,或者pcap接口读写网卡,以下的部分为tun设备的控制代码,包括了网卡mac ip mask设置等,主要就是ioctl函数的使用
#include <stdio.h>#include <string.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <fcntl.h>#include <linux/if_tun.h>#include <linux/if.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <netinet/ip.h>#include <arpa/inet.h>#include <stdlib.h>#include <unistd.h>#include <linux/if_ether.h>#include <netinet/if_ether.h>#include <net/if_arp.h>#include <net/ethernet.h>#include <net/route.h>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和maskstatic 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 existif (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 ipreturn -1;if (set_addr("tap", mask, SIOCSIFNETMASK) == -1) //set netmaskreturn -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;}