tun虚拟网络设备

TUN/TAP虚拟网络设备:https://www.cnblogs.com/oxspirt/p/12043721.html
ip头部报文 https://www.cnblogs.com/zhangbing12304/p/11016921.html

#include <string.h>
#include <assert.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <net/route.h>
#include <stdlib.h>


/*
 * 计算ip头部的checksum
 */
unsigned short GetIpCheckSum( unsigned char *ptr, int size)
{
	int cksum = 0;
	int index = 0;
	
	*(ptr + 10) = 0;
	*(ptr + 11) = 0;
	
	if(size % 2 != 0)
		return 0;
	
	while(index < size)
	{
		cksum += *(ptr + index + 1);
		cksum += *(ptr + index) << 8;
		
		index += 2;
	}
	
	while(cksum > 0xffff)
	{
		cksum = (cksum >> 16) + (cksum & 0xffff);
	}
	return ~cksum;
}

/*
 * 计算udp数据的checksum
 */
unsigned short GetUdpCheckSum( unsigned short *buf, int nword)
{
	unsigned long sum;
	for(sum=0;nword>0;nword--)
	{
		sum += *buf++;
		sum = (sum>>16) + (sum&0xffff);
	}
	return ~sum;
	
}

/*
 * 高字节和低字节对调:
 */
unsigned short change(unsigned short sum)
{
	return ( ( sum >> 8 ) & 0x00ff ) + ( ( sum << 8 ) & 0xff00 );
}

/**
 *  激活接口
 */
int interface_up(char *interface_name)
{
	int s;
	
	if((s = socket(PF_INET,SOCK_STREAM,0)) < 0)
	{
		printf("Error create socket :%s\n", strerror(errno));
		return -1;
	}
	
	struct ifreq ifr;
	strcpy(ifr.ifr_name,interface_name);
	
	short flag;
	flag = IFF_UP;
	if(ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
	{
		printf("Error up %s :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	ifr.ifr_ifru.ifru_flags |= flag;
	
	if(ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
	{
		printf("Error up %s :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	return 0;
	
}

/**
 *  设置接口ip地址 netmask
 */
int set_ipaddr(char *interface_name, char *ip ,char *netmask)
{
	int s;
	
	if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
	{
		printf("Error up %s :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	struct ifreq ifr;
	strcpy(ifr.ifr_name, interface_name);
	
	struct sockaddr_in addr;
	bzero(&addr, sizeof(struct sockaddr_in));
	
	//设置 ip:
	addr.sin_family = PF_INET;
	inet_aton(ip, &addr.sin_addr);
	
	memcpy(&ifr.ifr_ifru.ifru_addr, &addr, sizeof(struct sockaddr_in));
	
	if(ioctl(s, SIOCSIFADDR, &ifr) < 0)
	{
		printf("Error set %s ip :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	//设置 netmask:
	addr.sin_family = PF_INET;
	inet_aton(netmask, &addr.sin_addr);
	
	memcpy(&ifr.ifr_ifru.ifru_addr, &addr, sizeof(struct sockaddr_in));
	
	if(ioctl(s, SIOCSIFNETMASK, &ifr) < 0)
	{
		printf("Error set %s netmask :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	return 0;
}


/**
 *  增加到10.0.0.0/24的路由
 *  同命令:route add -net 10.0.0.0/24 dev tun0
 */
int route_add(char * interface_name)
{
	int skfd;
	struct rtentry rt;
	
	struct sockaddr_in dst;
	//struct sockaddr_in gw;
	struct sockaddr_in genmask;
	
	memset(&rt, 0, sizeof(rt));
	
	genmask.sin_addr.s_addr = inet_addr("255.255.0.0");
	genmask.sin_family = PF_INET;
	
	bzero(&dst,sizeof(struct sockaddr_in));
	dst.sin_family = PF_INET;
	dst.sin_addr.s_addr = inet_addr("10.0.0.0");
	
	rt.rt_metric = 0;
	rt.rt_dst = *(struct sockaddr*) &dst;
	rt.rt_genmask = *(struct sockaddr*) &genmask;
	
	rt.rt_dev = interface_name;
	rt.rt_flags = RTF_UP ;
	
	skfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(ioctl(skfd, SIOCADDRT, &rt) < 0)
	{
		printf("Error route add :%s\n", strerror(errno));
		return -1;
	}
	return 0;
}

int tun_create(char *dev, int flags)
{
	struct ifreq ifr;
	int fd, err;
	
	assert(dev != NULL);
	
	if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
		return fd;
	
	memset(&ifr, 0, sizeof(ifr));
	ifr.ifr_flags |= flags;
	if (*dev != '\0')
		strncpy(ifr.ifr_name, dev, IFNAMSIZ);
	if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
		close(fd);
		return err;
	}
	strcpy(dev, ifr.ifr_name);
	
	return fd;
}

int main(int argc, char *argv[])
{
	int tun, ret;
	char tun_name[IFNAMSIZ] = "tunTX";
	unsigned char buf[4096];
	unsigned char udpbuf[4096] = {0};
	unsigned short checksum;
	unsigned short udpchecksum;
	unsigned short num = 0x1100;
	
	tun_name[0] = '\0';
	tun = tun_create(tun_name, IFF_TUN | IFF_NO_PI );
	if (tun < 0) {
		perror("tun_create");
		return 1;
	}
	printf("TUN name is %s\n", tun_name);
	interface_up(tun_name);
	set_ipaddr(tun_name, "172.16.66.1", "255.255.0.0");
	route_add(tun_name);
	in_addr_t transip = inet_addr("172.16.0.0");
	in_addr_t trandip = inet_addr("192.168.0.0");
	
	while (1) {
		unsigned char ip[4];
		unsigned char ipret[4];
		
		ret = read(tun, buf, sizeof(buf));
		if (ret < 0)
			break;
		memcpy(ip, &buf[12], 4);
		printf("------------------------------------------------\n" );
		printf("ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
		memcpy(ipret, &buf[16], 4);
		printf("ipret:%s\n", inet_ntoa( *(struct in_addr*)&ipret ) );
		memcpy((void*)&checksum, &buf[10], 2);
		printf("checksum:0x%x\n", checksum);
		checksum = GetIpCheckSum(buf, 20);
		checksum = change(checksum);
		printf("88888checksum:0x%x\n", checksum);
		memcpy((void*)&udpchecksum, &buf[26], 2);
		printf("66666udpchecksum:0x%x\n", udpchecksum);
		memset(udpbuf, 0, sizeof(udpbuf));
		memcpy(udpbuf, &buf[12], 8);
		memcpy(&udpbuf[8], (void*)&num, 2);
		memcpy(&udpbuf[10], &buf[24], 2);
		memcpy(&udpbuf[12], &buf[20], ret-20);
		memset(&udpbuf[18], 0, 2);
		udpchecksum = GetUdpCheckSum((unsigned short*)udpbuf, ((ret-8)/2) + ((ret-8)%2) );
		printf("777777udpchecksum:0x%x\n", udpchecksum);
		
		//SNAT
		
		if( !strncmp( inet_ntoa( *(struct in_addr*)&ip ) , "192.168", strlen("192.168") ) )
		{
			printf("read %d bytes\n", ret);
			memcpy(&buf[12], &transip, 2 );
			memcpy(ip, &buf[12], 4);
			printf("----ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
			memcpy(ip, &buf[16], 4);
			printf("++++ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
			checksum = GetIpCheckSum(buf, 20);
			checksum = change(checksum);
			printf("*****checksum:0x%x\n", checksum);
			memcpy(&buf[10], (void*)&checksum, 2 );
			memcpy(udpbuf, &buf[12], 8);
			udpchecksum = GetUdpCheckSum((unsigned short*)udpbuf, ((ret-8)/2) + ((ret-8)%2) );
			printf("*****udpchecksum:0x%x\n", udpchecksum);
			memcpy(&buf[26], (void*)&udpchecksum, 2);
			ret = write(tun, buf, ret);
			printf("write %d bytes\n", ret);
			memset(ip, 0, sizeof(ip));
			
		}
		
		
		if( !strncmp( inet_ntoa( *(struct in_addr*)&ipret ) , "172.16", strlen("172.16") ) )
		{
			printf("read %d bytes\n", ret);
			memcpy(&buf[16], &trandip, 2 );
			memcpy(ip, &buf[16], 4);
			printf("++++ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
			memcpy(ip, &buf[12], 4);
			printf("----ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
			memset(&buf[10], 0, 2 );
			checksum = GetIpCheckSum(buf, 20);
			checksum = change(checksum);
			printf("*****checksum:0x%x\n", checksum);
			memcpy(&buf[10], (void*)&checksum, 2 );
			memcpy(udpbuf, &buf[12], 8);
			udpchecksum = GetUdpCheckSum((unsigned short*)udpbuf, ((ret-8)/2) + ((ret-8)%2) );
			printf("*****udpchecksum:0x%x\n", udpchecksum);
			memcpy(&buf[26], (void*)&udpchecksum, 2);
			ret = write(tun, buf, ret);
			printf("write %d bytes\n", ret);
			memset(ip, 0, sizeof(ip));
			system("touch /tmp/.SYS_MARK_SUCCEED");
		}
		
		
	}
	
	return 0;
}
#include <string.h>
#include <assert.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <net/route.h>
#include <stdlib.h>


/*
 * 计算ip头部的checksum
 */
unsigned short GetIpCheckSum( unsigned char *ptr, int size)
{
	int cksum = 0;
	int index = 0;
	
	*(ptr + 10) = 0;
	*(ptr + 11) = 0;
	
	if(size % 2 != 0)
		return 0;
	
	while(index < size)
	{
		cksum += *(ptr + index + 1);
		cksum += *(ptr + index) << 8;
		
		index += 2;
	}
	
	while(cksum > 0xffff)
	{
		cksum = (cksum >> 16) + (cksum & 0xffff);
	}
	return ~cksum;
}

/*
 * 计算icmp的checksum
 */
unsigned short GetIcmpCheckSum( unsigned short *buf,int nword)
{
	unsigned long sum;
	memset(&buf[1],0,2);
	for(sum=0;nword>0;nword--)
	{
		sum += *buf++;
		sum = (sum>>16) + (sum&0xffff);
	}
	return ~sum;
}


/*
 * 计算udp数据的checksum
 */
unsigned short GetUdpCheckSum( unsigned short *buf, int nword)
{
	unsigned long sum;
	for(sum=0;nword>0;nword--)
	{
		sum += *buf++;
		sum = (sum>>16) + (sum&0xffff);
	}
	return ~sum;
	
}

/*
 * 高字节和低字节对调:
 */
unsigned short change(unsigned short sum)
{
	return ( ( sum >> 8 ) & 0x00ff ) + ( ( sum << 8 ) & 0xff00 );
}

/**
 *  激活接口
 */
int interface_up(char *interface_name)
{
	int s;
	
	if((s = socket(PF_INET,SOCK_STREAM,0)) < 0)
	{
		printf("Error create socket :%s\n", strerror(errno));
		return -1;
	}
	
	struct ifreq ifr;
	strcpy(ifr.ifr_name,interface_name);
	
	short flag;
	flag = IFF_UP;
	if(ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
	{
		printf("Error up %s :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	ifr.ifr_ifru.ifru_flags |= flag;
	
	if(ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
	{
		printf("Error up %s :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	return 0;
	
}

/**
 *  设置接口ip地址 netmask
 */
int set_ipaddr(char *interface_name, char *ip ,char *netmask)
{
	int s;
	
	if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
	{
		printf("Error up %s :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	struct ifreq ifr;
	strcpy(ifr.ifr_name, interface_name);
	
	struct sockaddr_in addr;
	bzero(&addr, sizeof(struct sockaddr_in));
	
	//设置 ip:
	addr.sin_family = PF_INET;
	inet_aton(ip, &addr.sin_addr);
	
	memcpy(&ifr.ifr_ifru.ifru_addr, &addr, sizeof(struct sockaddr_in));
	
	if(ioctl(s, SIOCSIFADDR, &ifr) < 0)
	{
		printf("Error set %s ip :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	//设置 netmask:
	addr.sin_family = PF_INET;
	inet_aton(netmask, &addr.sin_addr);
	
	memcpy(&ifr.ifr_ifru.ifru_addr, &addr, sizeof(struct sockaddr_in));
	
	if(ioctl(s, SIOCSIFNETMASK, &ifr) < 0)
	{
		printf("Error set %s netmask :%s\n",interface_name,  strerror(errno));
		return -1;
	}
	
	return 0;
}

int tun_create(char *dev, int flags)
{
	struct ifreq ifr;
	int fd, err;
	
	assert(dev != NULL);
	
	if ((fd = open("/dev/tun", O_RDWR)) < 0)
		return fd;
	
	memset(&ifr, 0, sizeof(ifr));
	ifr.ifr_flags |= flags;
	if (*dev != '\0')
		strncpy(ifr.ifr_name, dev, IFNAMSIZ);
	if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
		close(fd);
		return err;
	}
	strcpy(dev, ifr.ifr_name);
	
	return fd;
}

int main(int argc, char *argv[])
{
	int tun, ret;
	char tun_name[IFNAMSIZ] = "tunTX";
	unsigned char buf[4096];
	unsigned char udpbuf[4096] = {0};
	unsigned char icmpbuf[4096] = {0};
	unsigned short checksum;
	unsigned short udpchecksum;
	unsigned short num = 0x1100;
	unsigned char protocol = 0x00;
	
	tun_name[0] = '\0';
	tun = tun_create(tun_name, IFF_TUN | IFF_NO_PI );
	if (tun < 0) {
		perror("tun_create");
		return 1;
	}
	printf("TUN name is %s\n", tun_name);
	interface_up(tun_name);
	set_ipaddr(tun_name, "172.16.66.1", "255.255.0.0");
	in_addr_t transip = inet_addr("172.16.0.0");
	in_addr_t trandip = inet_addr("192.168.0.0");
	
	while (1) {
		unsigned char ip[4];
		unsigned char ipret[4];
		
		ret = read(tun, buf, sizeof(buf));
		if (ret < 0)
			break;
		
		memcpy(&protocol, &buf[9], 1);
		printf("-----------------------protocol:%d-------------------------\n" , protocol);
		
		
		//icmp
		if( protocol == 0x01 )
		{
			printf("-----------------------ICMP-------------------------\n" );
			printf("read %d bytes\n", ret);
			memcpy((void*)&checksum, &buf[22], 2);
			printf("checksum:0x%x\n", checksum);
			memcpy(icmpbuf, &buf[20], ret-20);
			checksum = GetIcmpCheckSum((unsigned short*)icmpbuf, ((ret-20)/2) );
			if( ((ret-20)%2) )
				checksum-=1;
			printf("88888checksum:0x%x\n", checksum);
			
			memcpy(ip, &buf[12], 4);
			printf("SIP:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
			memcpy(ipret, &buf[16], 4);
			printf("DIP:%s\n", inet_ntoa( *(struct in_addr*)&ipret ) );
			memcpy(&buf[12], ipret, 4);
			memcpy(&buf[16], ip, 4);  
			
			buf[20] = 0;
			buf[21] = 0;
			
			memcpy(icmpbuf, &buf[20], ret-20);
			checksum = GetIcmpCheckSum((unsigned short*)icmpbuf, ((ret-20)/2));
			if( ((ret-20)%2) )
				checksum-=1;
			printf("666666checksum:0x%x\n", checksum);
			memcpy(&buf[22], (void*)&checksum,  2);
			
			ret = write(tun, buf, ret);
			printf("write %d bytes\n", ret);
		}
		
		
		
		//udp
		if( protocol == 0x11 )
		{
			printf("-----------------------UDP FOR DNS-------------------------\n" );
			memcpy(ip, &buf[12], 4);
			printf("ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
			memcpy(ipret, &buf[16], 4);
			printf("ipret:%s\n", inet_ntoa( *(struct in_addr*)&ipret ) );
			memcpy((void*)&checksum, &buf[10], 2);
			printf("checksum:0x%x\n", checksum);
			checksum = GetIpCheckSum(buf, 20);
			checksum = change(checksum);
			printf("88888checksum:0x%x\n", checksum);
			memcpy((void*)&udpchecksum, &buf[26], 2);
			printf("66666udpchecksum:0x%x\n", udpchecksum);
			memset(udpbuf, 0, sizeof(udpbuf));
			memcpy(udpbuf, &buf[12], 8);
			memcpy(&udpbuf[8], (void*)&num, 2);
			memcpy(&udpbuf[10], &buf[24], 2);
			memcpy(&udpbuf[12], &buf[20], ret-20);
			memset(&udpbuf[18], 0, 2);
			udpchecksum = GetUdpCheckSum((unsigned short*)udpbuf, ((ret-8)/2) + ((ret-8)%2) );
			printf("777777udpchecksum:0x%x\n", udpchecksum);
			
			//SNAT
			
			if( !strncmp( inet_ntoa( *(struct in_addr*)&ip ) , "192.168", strlen("192.168") ) )
			{
				printf("read %d bytes\n", ret);
				memcpy(&buf[12], &transip, 2 );
				memcpy(ip, &buf[12], 4);
				printf("----ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
				memcpy(ip, &buf[16], 4);
				printf("++++ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
				checksum = GetIpCheckSum(buf, 20);
				checksum = change(checksum);
				printf("*****checksum:0x%x\n", checksum);
				memcpy(&buf[10], (void*)&checksum, 2 );
				memcpy(udpbuf, &buf[12], 8);
				udpchecksum = GetUdpCheckSum((unsigned short*)udpbuf, ((ret-8)/2) + ((ret-8)%2) );
				printf("*****udpchecksum:0x%x\n", udpchecksum);
				memcpy(&buf[26], (void*)&udpchecksum, 2);
				ret = write(tun, buf, ret);
				printf("write %d bytes\n", ret);
				memset(ip, 0, sizeof(ip));
				
			}
			
			
			if( !strncmp( inet_ntoa( *(struct in_addr*)&ipret ) , "172.16", strlen("172.16") ) )
			{
				printf("read %d bytes\n", ret);
				memcpy(&buf[16], &trandip, 2 );
				memcpy(ip, &buf[16], 4);
				printf("++++ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
				memcpy(ip, &buf[12], 4);
				printf("----ip:%s\n", inet_ntoa( *(struct in_addr*)&ip ) );
				memset(&buf[10], 0, 2 );
				checksum = GetIpCheckSum(buf, 20);
				checksum = change(checksum);
				printf("*****checksum:0x%x\n", checksum);
				memcpy(&buf[10], (void*)&checksum, 2 );
				memcpy(udpbuf, &buf[12], 8);
				udpchecksum = GetUdpCheckSum((unsigned short*)udpbuf, ((ret-8)/2) + ((ret-8)%2) );
				printf("*****udpchecksum:0x%x\n", udpchecksum);
				memcpy(&buf[26], (void*)&udpchecksum, 2);
				ret = write(tun, buf, ret);
				printf("write %d bytes\n", ret);
				memset(ip, 0, sizeof(ip));
				system("touch /tmp/.SYS_MARK_SUCCEED");
			}
			
		}
		
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值