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;
}