added option lower-level

This commit is contained in:
wangyu 2017-08-07 13:58:42 +08:00
parent 44852270ef
commit 307399b00a
9 changed files with 241 additions and 37 deletions

@ -10,8 +10,8 @@ Which can help you bypass udp blocking or udp QOS or just poorly supported udp N
encrypt your traffic with aes128cbc,protects data integrity by md5 or crc32,protect replay attack with an anti-replay window smiliar to ipsec/openvpn. encrypt your traffic with aes128cbc,protects data integrity by md5 or crc32,protect replay attack with an anti-replay window smiliar to ipsec/openvpn.
### Simulated TCP Handshake ### Simulated TCP Handshake
simulated 3-way handshake,simluated seq ack_seq. Simluated tcp options:MSS,sackOk,TS,TS_ack,wscale. Provides real-time delivery ,no tcp over tcp problem when using openvpn. simulated 3-way handshake,simluated seq ack_seq. Simluated tcp options:MSS,sackOk,TS,TS_ack,wscale. Provides real-time delivery ,no tcp over tcp problem when using openvpn.
### Connnection Recover ### Connnection Failure Dectection & Recover
After connection timeouts,the client will re-connect.if re-connection is successful,the previous connection will be recovered,and all existed udp conversations will stay vaild. Conection failure detection by hearbeat. After hearbeat timeouts,client will auto change port and re-connect.if re-connection is successful,the previous connection will be recovered,and all existed udp conversations will stay vaild.
### Other Features ### Other Features
Multiplexing ,one client supports multi udp connections,all of those traffic will share one raw connection Multiplexing ,one client supports multi udp connections,all of those traffic will share one raw connection
@ -118,6 +118,8 @@ raw_mode: faketcp cipher_mode: aes128cbc  auth_mode: md5
2. no TCP ovr tcp problem (tcp over tcp problem http://sites.inka.de/bigred/devel/tcp-tcp.html ,https://community.openvpn.net/openvpn/ticket/2 ) 2. no TCP ovr tcp problem (tcp over tcp problem http://sites.inka.de/bigred/devel/tcp-tcp.html ,https://community.openvpn.net/openvpn/ticket/2 )
3. openvpn over icmp also becomes a choice 3. openvpn over icmp also becomes a choice
more details at [openvpn+udp2raw_guide](/doc/openvpn_guide.md)
### tunneling kcptun ### tunneling kcptun
make kcptun support tcp mode. make kcptun support tcp mode.
(kcptun, https://github.com/xtaci/kcptun) (kcptun, https://github.com/xtaci/kcptun)

@ -198,12 +198,12 @@ int set_buf_size(int fd)
{ {
if(setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0) if(setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0)
{ {
mylog(log_fatal,"SO_SNDBUFFORCE fail\n"); mylog(log_fatal,"SO_SNDBUFFORCE fail,fd %d\n",fd);
myexit(1); myexit(1);
} }
if(setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0) if(setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0)
{ {
mylog(log_fatal,"SO_RCVBUFFORCE fail\n"); mylog(log_fatal,"SO_RCVBUFFORCE fail,fd %d\n",fd);
myexit(1); myexit(1);
} }
return 0; return 0;

@ -42,6 +42,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h> #include <assert.h>
#include <linux/if_packet.h>

@ -18,10 +18,12 @@ Udp2raw-tunnel
### 模拟TCP3次握手 ### 模拟TCP3次握手
模拟TCP3次握手模拟seq ack过程。另外还模拟了一些tcp optionMSS,sackOk,TS,TS_ack,wscale用来使流量看起来更像是由普通的linux tcp协议栈发送的。 模拟TCP3次握手模拟seq ack过程。另外还模拟了一些tcp optionMSS,sackOk,TS,TS_ack,wscale用来使流量看起来更像是由普通的linux tcp协议栈发送的。
### 连接快速恢复 ### 连接保持,连接快速恢复
心跳机制检查连接是否中断一旦心跳超时。client会立即换raw socket的端口重连重连成功后会恢复之前中断的连接。虽然raw端的端口变了但是udp端的所有连接都会继续有效。udp这边感觉不到raw端的重连只会感觉到短暂断流,这跟普通的短暂丢包是类似的,不会导致上层应用重连。 心跳机制检查连接是否中断一旦心跳超时。client会立即换raw socket的端口重连重连成功后会恢复之前中断的连接。虽然raw端的端口变了但是udp端的所有连接都会继续有效。udp这边感觉不到raw端的重连只会感觉到短暂断流,这跟普通的短暂丢包是类似的,不会导致上层应用重连。
另一个优化是重连只需要client发起就可以立即被server处理不需要等到server端的连接超时后。 另一个优化是重连只需要client发起就可以立即被server处理不需要等到server端的连接超时后。这个在单向连接失效的情况下有用。
另外对于有大量client的情况对于不同client,server发送的心跳是错开时间发送的不会因为短时间发送大量的心跳而造成拥塞和延迟抖动。
### 其他特性 ### 其他特性
信道复用client的udp端支持多个连接。 信道复用client的udp端支持多个连接。
@ -32,7 +34,10 @@ NAT 穿透 tcp icmp udp模式都支持nat穿透。
支持Openvz配合finalspeed使用可以在openvz上用tcp模式的finalspeed 支持Openvz配合finalspeed使用可以在openvz上用tcp模式的finalspeed
支持Openwrt,没有编译以来容易编译到任何平台上。release中提供了ar71xx版本的binary 支持Openwrt,没有编译依赖容易编译到任何平台上。release中提供了ar71xx版本的binary
单进程纯异步无锁高并发除了回收过期连接外所有操作的时间复杂度都跟连接数无关。回收过期连接这个操作是个批量操作会定期进行但是会保证一次回收的数量不超过总数的1/10可配置不会造成延迟抖动。
### 关键词 ### 关键词
突破udp qos,突破udp屏蔽openvpn tcp over tcp problem,openvpn over icmp,udp to icmp tunnel,udp to tcp tunnel,udp via icmp,udp via tcp 突破udp qos,突破udp屏蔽openvpn tcp over tcp problem,openvpn over icmp,udp to icmp tunnel,udp to tcp tunnel,udp via icmp,udp via tcp

@ -1 +1,88 @@
# udp2raw+openvpn config guide
![image_vpn](/images/openvpn.PNG)
![image4](/images/image4.PNG)
# udp2raw command
#### run at server side
```
./udp2raw_amd64 -s -l0.0.0.0:8855 -r 127.0.0.1:7777 -k "passwd" --raw-mode faketcp -a
```
#### run at client side
assume server ip is 45.66.77.88
```
./udp2raw_amd64 -s -l0.0.0.0:3333 -r 45.66.77.88:8855 -k "passwd" --raw-mode faketcp -a
```
# openvpn config
#### client side config
```
remote 127.0.0.1 3333
resolv-retry infinite
nobind
persist-key
persist-tun
ca /root/add-on/openvpn/ca.crt
cert /root/add-on/openvpn/client.crt
key /root/add-on/openvpn/client.key
keepalive 3 20
verb 3
mute 20
comp-lzo no
cipher none ##### disable openvpn 's cipher and auth for maxmized peformance.
auth none ##### you can enable openvpn's cipher and auth,if you dont care about peformance,oryou dont trust udp2raw 's encryption
fragment 1200 ##### very important you can turn it up a bit. but,the lower the safer
mssfix 1200 ##### very important
sndbuf 2000000 ##### important
rcvbuf 2000000 ##### important
txqueuelen 4000 ##### suggested
```
#### server side config
```
local 0.0.0.0
port 7777
proto udp
dev tun
ca /etc/openvpn/easy-rsa/2.0/keys/ca.crt
cert /etc/openvpn/easy-rsa/2.0/keys/server.crt
key /etc/openvpn/easy-rsa/2.0/keys/server.key
dh /etc/openvpn/easy-rsa/2.0/keys/dh1024.pem
server 10.222.2.0 255.255.255.0
ifconfig 10.222.2.1 10.222.2.6
client-to-client
duplicate-cn
keepalive 10 60
max-clients 50
persist-key
persist-tun
status /etc/openvpn/openvpn-status.log
verb 3
mute 20
comp-lzo no
cipher none ##### disable openvpn 's cipher and auth for maxmized peformance.
auth none ##### you can enable openvpn's cipher and auth,if you dont care about peformance,oryou dont trust udp2raw 's encryption
fragment 1200 ##### very important you can turn it up a bit. but,the lower the safer
mssfix 1200 ##### very important
sndbuf 2000000 ##### important
rcvbuf 2000000 ##### important
txqueuelen 4000 ##### suggested
```

@ -38,6 +38,7 @@ int disable_anti_replay=0;
char key_string[1000]= "secret key"; char key_string[1000]= "secret key";
char key[16];//,key2[16]; char key[16];//,key2[16];
//uint64_t current_time_rough=0; //uint64_t current_time_rough=0;
@ -2351,6 +2352,7 @@ void process_arg(int argc, char *argv[])
{"gen-rule", no_argument, 0, 'g'}, {"gen-rule", no_argument, 0, 'g'},
{"debug", no_argument, 0, 1}, {"debug", no_argument, 0, 1},
{"clear", no_argument, 0, 1}, {"clear", no_argument, 0, 1},
{"lower-level", required_argument, 0, 1},
{"sock-buf", required_argument, 0, 1}, {"sock-buf", required_argument, 0, 1},
{"seq-mode", required_argument, 0, 1}, {"seq-mode", required_argument, 0, 1},
{NULL, 0, 0, 0} {NULL, 0, 0, 0}
@ -2544,6 +2546,24 @@ void process_arg(int argc, char *argv[])
else if(strcmp(long_options[option_index].name,"log-level")==0) else if(strcmp(long_options[option_index].name,"log-level")==0)
{ {
} }
else if(strcmp(long_options[option_index].name,"lower-level")==0)
{
if(strchr(optarg,'#')==0)
{
mylog(log_fatal,"lower-level parameter invaild,should be if_name#mac_adress ,ie eth0#00:23:45:67:89:b9\n");
myexit(-1);
}
lower_level=1;
u32_t hw[6];
memset(hw,0,sizeof(hw));
sscanf(optarg,"%[^#]#%x:%x:%x:%x:%x:%x",if_name,&hw[0],&hw[1],&hw[2],&hw[3],&hw[4],&hw[5]);
mylog(log_warn,"make sure this is correct: ifname=<%s> gateway_hw_hd=<%x:%x:%x:%x:%x:%x> \n",if_name,hw[0],hw[1],hw[2],hw[3],hw[4],hw[5]);
for(int i=0;i<6;i++)
{
oppsite_hw_addr[i]=uint8_t(hw[i]);
}
}
else if(strcmp(long_options[option_index].name,"disable-color")==0) else if(strcmp(long_options[option_index].name,"disable-color")==0)
{ {
//enable_log_color=0; //enable_log_color=0;

@ -4,13 +4,18 @@ FLAGS2= -O3
all: all:
sudo killall udp2raw||true sudo killall udp2raw||true
sleep 0.2 sleep 0.2
g++ main.cpp -o udp2raw_amd64 -static -ggdb -I. lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -lrt -std=c++11 ${FLAGS} ${FLAGS2} g++ main.cpp -o udp2raw -static -ggdb -I. lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -lrt -std=c++11 ${FLAGS} ${FLAGS2}
${ccmips} main.cpp -o udp2raw_ar71xx -lrt -I. lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -std=c++11 ${FLAGS} ${FLAGS2} # ${ccmips} main.cpp -o udp2raw_ar71xx -lrt -I. lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -std=c++11 ${FLAGS} ${FLAGS2}
fast: fast:
sudo killall udp2raw||true sudo killall udp2raw||true
sleep 0.2 sleep 0.2
g++ main.cpp -o udp2raw_amd64 -ggdb -I. lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -lrt -std=c++11 ${FLAGS} g++ main.cpp -o udp2raw -ggdb -I. lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -lrt -std=c++11 ${FLAGS}
debug: debug:
g++ main.cpp -o udp2raw_amd64 -static -ggdb -I. -Ilib lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -lrt -std=c++11 ${FLAGS} -Wformat-nonliteral -D MY_DEBUG g++ main.cpp -o udp2raw -static -ggdb -I. -Ilib lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -lrt -std=c++11 ${FLAGS} -Wformat-nonliteral -D MY_DEBUG
release:
g++ main.cpp -o udp2raw_amd64 -static -ggdb -I. lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -lrt -std=c++11 ${FLAGS} ${FLAGS2}
${ccmips} main.cpp -o udp2raw_ar71xx -lrt -I. lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -std=c++11 ${FLAGS} ${FLAGS2}

@ -20,7 +20,13 @@ int disable_bpf_filter=0; //for test only,most time no need to disable this
u32_t bind_address_uint32=0; u32_t bind_address_uint32=0;
int lower_level=0;
int ifindex=-1;
char if_name[100]="";
unsigned char oppsite_hw_addr[6]=
{0xff,0xff,0xff,0xff,0xff,0xff};
//{0x00,0x23,0x45,0x67,0x89,0xb9};
struct sock_filter code_tcp_old[] = { struct sock_filter code_tcp_old[] = {
{ 0x28, 0, 0, 0x0000000c },//0 { 0x28, 0, 0, 0x0000000c },//0
@ -156,20 +162,47 @@ packet_info_t::packet_info_t()
int init_raw_socket() int init_raw_socket()
{ {
if(lower_level==0)
{
raw_send_fd = socket(AF_INET , SOCK_RAW , IPPROTO_TCP); raw_send_fd = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
if(raw_send_fd == -1) { if(raw_send_fd == -1) {
mylog(log_fatal,"Failed to create raw_send_fd\n"); mylog(log_fatal,"Failed to create raw_send_fd\n");
//perror("Failed to create raw_send_fd"); //perror("Failed to create raw_send_fd");
myexit(1); myexit(1);
} }
int one = 1;
const int *val = &one;
if (setsockopt (raw_send_fd, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) {
mylog(log_fatal,"Error setting IP_HDRINCL %d\n",errno);
//perror("Error setting IP_HDRINCL");
myexit(2);
}
}
else
{
raw_send_fd = socket(PF_PACKET , SOCK_DGRAM , htons(ETH_P_IP));
if(raw_send_fd == -1) {
mylog(log_fatal,"Failed to create raw_send_fd\n");
//perror("Failed to create raw_send_fd");
myexit(1);
}
init_ifindex(if_name);
}
if(setsockopt(raw_send_fd, SOL_SOCKET, SO_SNDBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0) if(setsockopt(raw_send_fd, SOL_SOCKET, SO_SNDBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0)
{ {
mylog(log_fatal,"SO_SNDBUFFORCE fail\n"); mylog(log_fatal,"SO_SNDBUFFORCE fail\n");
myexit(1); myexit(1);
} }
//raw_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); //raw_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
raw_recv_fd= socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); raw_recv_fd= socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
@ -188,13 +221,7 @@ int init_raw_socket()
//IP_HDRINCL to tell the kernel that headers are included in the packet //IP_HDRINCL to tell the kernel that headers are included in the packet
int one = 1;
const int *val = &one;
if (setsockopt (raw_send_fd, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) {
mylog(log_fatal,"Error setting IP_HDRINCL %d\n",errno);
//perror("Error setting IP_HDRINCL");
myexit(2);
}
setnonblocking(raw_send_fd); //not really necessary setnonblocking(raw_send_fd); //not really necessary
setnonblocking(raw_recv_fd); setnonblocking(raw_recv_fd);
@ -258,8 +285,26 @@ void remove_filter()
//exit(-1); //exit(-1);
} }
} }
int init_ifindex(char * if_name)
{
struct ifreq ifr;
size_t if_name_len=strlen(if_name);
if (if_name_len<sizeof(ifr.ifr_name)) {
memcpy(ifr.ifr_name,if_name,if_name_len);
ifr.ifr_name[if_name_len]=0;
} else {
mylog(log_fatal,"interface name is too long\n");
myexit(-1);
}
if (ioctl(raw_send_fd,SIOCGIFINDEX,&ifr)==-1) {
mylog(log_fatal,"SIOCGIFINDEX fail ,%s\n",strerror(errno));
myexit(-1);
}
ifindex=ifr.ifr_ifindex;
mylog(log_info,"ifname:%s ifindex:%d\n",if_name,ifindex);
return 0;
}
int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen) int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen)
@ -271,17 +316,20 @@ int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen)
struct iphdr *iph = (struct iphdr *) send_raw_ip_buf; struct iphdr *iph = (struct iphdr *) send_raw_ip_buf;
memset(iph,0,sizeof(iphdr)); memset(iph,0,sizeof(iphdr));
struct sockaddr_in sin; static unsigned short ip_id=1;
sin.sin_family = AF_INET;
//sin.sin_port = htons(info.dst_port); //dont need this
sin.sin_addr.s_addr = send_info.dst_ip;
iph->ihl = sizeof(iphdr)/4; //we dont use ip options,so the length is just sizeof(iphdr) iph->ihl = sizeof(iphdr)/4; //we dont use ip options,so the length is just sizeof(iphdr)
iph->version = 4; iph->version = 4;
iph->tos = 0; iph->tos = 0;
// iph->id = htonl (ip_id++); //Id of this packet if(lower_level)
// iph->id = 0; //Id of this packet ,kernel will auto fill this if id is zero {
iph->id=0;
//iph->id = htons (ip_id++); //Id of this packet
}
else
iph->id = 0; //Id of this packet ,kernel will auto fill this if id is zero ,or really?????// todo //seems like there is a problem
iph->frag_off = htons(0x4000); //DF set,others are zero iph->frag_off = htons(0x4000); //DF set,others are zero
// iph->frag_off = htons(0x0000); //DF set,others are zero // iph->frag_off = htons(0x0000); //DF set,others are zero
iph->ttl = 64; iph->ttl = 64;
@ -291,20 +339,51 @@ int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen)
iph->daddr = send_info.dst_ip; iph->daddr = send_info.dst_ip;
uint16_t ip_tot_len=sizeof (struct iphdr)+payloadlen; uint16_t ip_tot_len=sizeof (struct iphdr)+payloadlen;
// iph->tot_len = htons(ip_tot_len); //this is not necessary ,kernel will always auto fill this //http://man7.org/linux/man-pages/man7/raw.7.html if(lower_level)iph->tot_len = htons(ip_tot_len); //this is not necessary ,kernel will always auto fill this //http://man7.org/linux/man-pages/man7/raw.7.html
//iph->tot_len = ip_tot_len; else
iph->tot_len = 0;
memcpy(send_raw_ip_buf+sizeof(iphdr) , payload, payloadlen); memcpy(send_raw_ip_buf+sizeof(iphdr) , payload, payloadlen);
//iph->check = csum ((unsigned short *) send_raw_ip_buf, ip_tot_len); //this is not necessary ,kernel will always auto fill this if(lower_level) iph->check =
csum ((unsigned short *) send_raw_ip_buf, iph->ihl*4); //this is not necessary ,kernel will always auto fill this
else
iph->check=0;
int ret = sendto(raw_send_fd, send_raw_ip_buf, ip_tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)); int ret;
if(lower_level==0)
{
struct sockaddr_in sin;
sin.sin_family = AF_INET;
//sin.sin_port = htons(info.dst_port); //dont need this
sin.sin_addr.s_addr = send_info.dst_ip;
ret = sendto(raw_send_fd, send_raw_ip_buf, ip_tot_len , 0, (struct sockaddr *) &sin, sizeof (sin));
}
else
{
struct sockaddr_ll addr;
memset(&addr,0,sizeof(addr));
addr.sll_family=AF_PACKET;
addr.sll_ifindex=ifindex;
addr.sll_halen=ETHER_ADDR_LEN;
addr.sll_protocol=htons(ETH_P_IP);
memcpy(addr.sll_addr,oppsite_hw_addr,ETHER_ADDR_LEN);
ret = sendto(raw_send_fd, send_raw_ip_buf, ip_tot_len , 0, (struct sockaddr *) &addr, sizeof (addr));
}
if(ret==-1) if(ret==-1)
{ {
mylog(log_debug,"sendto failed\n");
mylog(log_trace,"sendto failed\n");
//perror("why?"); //perror("why?");
return -1; return -1;
} }
else
{
//mylog(log_info,"sendto succ\n");
}
return 0; return 0;
} }
int peek_raw(packet_info_t &peek_info) int peek_raw(packet_info_t &peek_info)
@ -426,7 +505,7 @@ int recv_raw_ip(raw_info_t &raw_info,char * &payload,int &payloadlen)
if(ip_chk!=0) if(ip_chk!=0)
{ {
mylog(log_debug,"ip header error %d\n",ip_chk); mylog(log_debug,"ip header error %x\n",ip_chk);
return -1; return -1;
} }

@ -15,6 +15,10 @@ extern int filter_port;
extern u32_t bind_address_uint32; extern u32_t bind_address_uint32;
extern int disable_bpf_filter; extern int disable_bpf_filter;
extern int lower_level;
extern char if_name[100];
extern unsigned char oppsite_hw_addr[];
struct icmphdr struct icmphdr
{ {
uint8_t type; uint8_t type;
@ -76,6 +80,7 @@ int init_raw_socket();
void init_filter(int port); void init_filter(int port);
void remove_filter(); void remove_filter();
int init_ifindex(char * if_name);
int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen); int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen);