启用tun设备开启tap虚拟网卡功能-爱代码爱编程
注意:该文章中的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和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;
}