From 307399b00a42afe7607d798ec2343ea9213e2bfc Mon Sep 17 00:00:00 2001 From: wangyu Date: Mon, 7 Aug 2017 13:58:42 +0800 Subject: [PATCH] added option lower-level --- README.md | 6 +- common.cpp | 4 +- common.h | 1 + doc/README.zh-cn.md | 11 +++- doc/openvpn_guide.md | 87 ++++++++++++++++++++++++++++ main.cpp | 20 +++++++ makefile | 13 +++-- network.cpp | 131 ++++++++++++++++++++++++++++++++++--------- network.h | 5 ++ 9 files changed, 241 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index dc32111..c883087 100755 --- a/README.md +++ b/README.md @@ -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. ### 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. -### Connnection 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. +### Connnection Failure Dectection & Recover +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 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 ) 3. openvpn over icmp also becomes a choice + +more details at [openvpn+udp2raw_guide](/doc/openvpn_guide.md) ### tunneling kcptun make kcptun support tcp mode. (kcptun, https://github.com/xtaci/kcptun) diff --git a/common.cpp b/common.cpp index a6a9dfb..d6ec31e 100644 --- a/common.cpp +++ b/common.cpp @@ -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) { - mylog(log_fatal,"SO_SNDBUFFORCE fail\n"); + mylog(log_fatal,"SO_SNDBUFFORCE fail,fd %d\n",fd); myexit(1); } 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); } return 0; diff --git a/common.h b/common.h index c2e0446..66d47bf 100644 --- a/common.h +++ b/common.h @@ -42,6 +42,7 @@ #include #include #include +#include diff --git a/doc/README.zh-cn.md b/doc/README.zh-cn.md index 6039cbc..cc64d41 100644 --- a/doc/README.zh-cn.md +++ b/doc/README.zh-cn.md @@ -18,10 +18,12 @@ Udp2raw-tunnel ### 模拟TCP3次握手 模拟TCP3次握手,模拟seq ack过程。另外还模拟了一些tcp option:MSS,sackOk,TS,TS_ack,wscale,用来使流量看起来更像是由普通的linux tcp协议栈发送的。 -### 连接快速恢复 +### 连接保持,连接快速恢复 心跳机制检查连接是否中断,一旦心跳超时。client会立即换raw socket的端口重连,重连成功后会恢复之前中断的连接。虽然raw端的端口变了,但是udp端的所有连接都会继续有效。udp这边感觉不到raw端的重连,只会感觉到短暂断流,这跟普通的短暂丢包是类似的,不会导致上层应用重连。 -另一个优化是,重连只需要client发起,就可以立即被server处理,不需要等到server端的连接超时后。 +另一个优化是,重连只需要client发起,就可以立即被server处理,不需要等到server端的连接超时后。这个在单向连接失效的情况下有用。 + +另外,对于有大量client的情况,对于不同client,server发送的心跳是错开时间发送的,不会因为短时间发送大量的心跳而造成拥塞和延迟抖动。 ### 其他特性 信道复用,client的udp端支持多个连接。 @@ -32,7 +34,10 @@ NAT 穿透 ,tcp icmp udp模式都支持nat穿透。 支持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 diff --git a/doc/openvpn_guide.md b/doc/openvpn_guide.md index 8b13789..cd68c51 100644 --- a/doc/openvpn_guide.md +++ b/doc/openvpn_guide.md @@ -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 +``` diff --git a/main.cpp b/main.cpp index a2cd4e7..b09861f 100755 --- a/main.cpp +++ b/main.cpp @@ -38,6 +38,7 @@ int disable_anti_replay=0; char key_string[1000]= "secret key"; char key[16];//,key2[16]; + //uint64_t current_time_rough=0; @@ -2351,6 +2352,7 @@ void process_arg(int argc, char *argv[]) {"gen-rule", no_argument, 0, 'g'}, {"debug", no_argument, 0, 1}, {"clear", no_argument, 0, 1}, + {"lower-level", required_argument, 0, 1}, {"sock-buf", required_argument, 0, 1}, {"seq-mode", required_argument, 0, 1}, {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,"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) { //enable_log_color=0; diff --git a/makefile b/makefile index b747473..0c14a66 100755 --- a/makefile +++ b/makefile @@ -4,13 +4,18 @@ FLAGS2= -O3 all: sudo killall udp2raw||true 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} - ${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} + 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} fast: sudo killall udp2raw||true 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: - 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} + diff --git a/network.cpp b/network.cpp index 02046c7..3e7c48b 100644 --- a/network.cpp +++ b/network.cpp @@ -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; +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[] = { { 0x28, 0, 0, 0x0000000c },//0 @@ -156,20 +162,47 @@ packet_info_t::packet_info_t() int init_raw_socket() { - raw_send_fd = socket(AF_INET , SOCK_RAW , IPPROTO_TCP); + if(lower_level==0) + { + raw_send_fd = socket(AF_INET , SOCK_RAW , IPPROTO_TCP); + + if(raw_send_fd == -1) { + mylog(log_fatal,"Failed to create raw_send_fd\n"); + //perror("Failed to create raw_send_fd"); + 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); + } - if(raw_send_fd == -1) { - mylog(log_fatal,"Failed to create raw_send_fd\n"); - //perror("Failed to create raw_send_fd"); - myexit(1); - } + } + 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) { mylog(log_fatal,"SO_SNDBUFFORCE fail\n"); myexit(1); } + + + //raw_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); 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 - 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_recv_fd); @@ -258,8 +285,26 @@ void remove_filter() //exit(-1); } } +int init_ifindex(char * if_name) +{ + struct ifreq ifr; + size_t if_name_len=strlen(if_name); + if (if_name_lenihl = sizeof(iphdr)/4; //we dont use ip options,so the length is just sizeof(iphdr) iph->version = 4; iph->tos = 0; - // iph->id = htonl (ip_id++); //Id of this packet - // iph->id = 0; //Id of this packet ,kernel will auto fill this if id is zero + if(lower_level) + { + 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(0x0000); //DF set,others are zero 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; 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 - //iph->tot_len = ip_tot_len; + 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 + else + iph->tot_len = 0; + 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) { - mylog(log_debug,"sendto failed\n"); + + mylog(log_trace,"sendto failed\n"); //perror("why?"); return -1; } + else + { + //mylog(log_info,"sendto succ\n"); + } return 0; } 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) { - mylog(log_debug,"ip header error %d\n",ip_chk); + mylog(log_debug,"ip header error %x\n",ip_chk); return -1; } diff --git a/network.h b/network.h index c5ee395..ff2bbea 100644 --- a/network.h +++ b/network.h @@ -15,6 +15,10 @@ extern int filter_port; extern u32_t bind_address_uint32; extern int disable_bpf_filter; +extern int lower_level; +extern char if_name[100]; +extern unsigned char oppsite_hw_addr[]; + struct icmphdr { uint8_t type; @@ -76,6 +80,7 @@ int init_raw_socket(); void init_filter(int port); void remove_filter(); +int init_ifindex(char * if_name); int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen);