Compare commits
31 Commits
20170805.1
...
20170809.0
Author | SHA1 | Date | |
---|---|---|---|
|
2251947278 | ||
|
c48c619002 | ||
|
0cac945a26 | ||
|
97738ab3ce | ||
|
a6bb0b50cf | ||
|
e7530fa7f9 | ||
|
cec1257474 | ||
|
c97f09f534 | ||
|
92581be9a1 | ||
|
58ab1f6b15 | ||
|
1b0d4f6d08 | ||
|
91a015b8a8 | ||
|
ce2e6a094d | ||
|
59af4a0135 | ||
|
b5c6176079 | ||
|
83abc1def4 | ||
|
307399b00a | ||
|
44852270ef | ||
|
ae153ceacc | ||
|
da6aafba12 | ||
|
e50d368440 | ||
|
801ecfd0ee | ||
|
45b7ab6285 | ||
|
8271cce383 | ||
|
00dcec9896 | ||
|
6be7034bcb | ||
|
9593528dd4 | ||
|
9884544e34 | ||
|
858928a17f | ||
|
dc6c328d57 | ||
|
716c183886 |
151
README.md
@@ -1,14 +1,147 @@
|
||||
# udp2raw-tunnel
|
||||
udp2raw tunnel (udp to tcp with fake tcp header)
|
||||
# Udp2raw-tunnel
|
||||

|
||||
|
||||
#usage
|
||||
An Encrpyted,Anti-Replay,Multiplexed Udp Tunnel,tunnels udp traffic through raw socket
|
||||
|
||||
client:
|
||||
-A INPUT -s 44.55.66.77/32 -p tcp -m tcp --sport 9999 -j DROP
|
||||
[简体中文](/doc/README.zh-cn.md)
|
||||
### Send/Recv Udp Packet as Raw Packet with TCP header,ICMP header
|
||||
Which can help you bypass udp blocking or udp QOS or just poorly supported udp NAT behavior by some ISP. Raw packet with UDP header is also supported,in this way you can just make use of the encrpyting and anti-replay feature.
|
||||
### Encrpytion and Anti-Replay
|
||||
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 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
|
||||
|
||||
./raw -l 127.0.0.1:6666 -r44.55.66.77:9999 -c --source-ip 192.168.1.100
|
||||
Multiple Clients Support,one server supports multiple clients.
|
||||
|
||||
server:
|
||||
-A INPUT -p tcp -m tcp --dport 9999 -j DROP
|
||||
NAT Supported,all 3 modes work in NAT environment
|
||||
|
||||
OpenVZ Supported,tested on bandwagonhost
|
||||
|
||||
Openwrt Supported,no dependence package,easy to compile,ar71xx binary included in release.
|
||||
### Key Words
|
||||
bypass udp qos,bypass udp blocking,openvpn tcp over tcp problem,openvpn over icmp,udp to icmp tunnel,udp to tcp tunnel,udp via icmp,udp via tcp
|
||||
# Getting Started
|
||||
### Prerequisites
|
||||
linux host,root access. if you want to use it on window,you can use VMware in bridged mode.
|
||||
### Installing
|
||||
download binary release from https://github.com/wangyu-/udp2raw-tunnel/releases
|
||||
### Running
|
||||
assume your udp is blocked or being QOS-ed or just poorly supported.assume your server ip is 44.55.66.77, you have a service listening on udp port 7777.
|
||||
```
|
||||
run at client side:
|
||||
./udp2raw_amd64 -c -l0.0.0.0:3333 -r44.55.66.77:4096 -a -k "passwd" --raw-mode faketcp
|
||||
|
||||
run at server side:
|
||||
./udp2raw_amd64 -s -l0.0.0.0:4096 -r 127.0.0.1:7777 -a -k "passwd" --raw-mode faketcp
|
||||
|
||||
```
|
||||
Now,your client and server established a tunnel thorough tcp port 4096. Connecting to udp port 3333 at client side is equivalent with connecting to port 7777 at server side. No udp traffic will be exposed to outside.
|
||||
# Advanced Topic
|
||||
### Usage
|
||||
```
|
||||
udp2raw-tunnel
|
||||
version: Aug 5 2017 21:03:54
|
||||
repository: https://github.com/wangyu-/udp2raw-tunnel
|
||||
|
||||
usage:
|
||||
run as client : ./this_program -c -l local_listen_ip:local_port -r server_ip:server_port [options]
|
||||
run as server : ./this_program -s -l server_listen_ip:server_port -r remote_ip:remote_port [options]
|
||||
|
||||
common options,these options must be same on both side:
|
||||
--raw-mode <string> avaliable values:faketcp(default),udp,icmp
|
||||
-k,--key <string> password to gen symetric key,default:"secret key"
|
||||
--auth-mode <string> avaliable values:aes128cbc(default),xor,none
|
||||
--cipher-mode <string> avaliable values:md5(default),crc32,simple,none
|
||||
-a,--auto-rule auto add (and delete) iptables rule
|
||||
-g,--gen-rule generate iptables rule then exit
|
||||
--disable-anti-replay disable anti-replay,not suggested
|
||||
client options:
|
||||
--source-ip <ip> force source-ip for raw socket
|
||||
--source-port <port> force source-port for raw socket,tcp/udp only
|
||||
this option disables port changing while re-connecting
|
||||
other options:
|
||||
--log-level <number> 0:never 1:fatal 2:error 3:warn
|
||||
4:info (default) 5:debug 6:trace
|
||||
--log-position enable file name,function name,line number in log
|
||||
--disable-color disable log color
|
||||
--disable-bpf disable the kernel space filter,most time its not necessary
|
||||
unless you suspect there is a bug
|
||||
--sock-buf <number> buf size for socket,>=10 and <=10240,unit:kbyte,default:1024
|
||||
--seqmode <number> seq increase mode for faketcp:
|
||||
0:dont increase
|
||||
1:increase every packet
|
||||
2:increase randomly, about every 3 packets (default)
|
||||
-h,--help print this help message
|
||||
```
|
||||
### iptables rule
|
||||
this programs sends packet via raw socket.In faketcp mode,Linux Kernel TCP packet processing has to be blocked by a iptables rule on both sides,otherwise Kernel will automatically send RST for unrecongized TCP packet and you will sustain from stability/peformance problem.You can use -a option to let the program automatically add/del iptables rule on start/exit.You can also use the -g option to generate iptables rule and add it manually.
|
||||
### cipher-mode and auth-mode
|
||||
Its suggested to use aes128cbc + md5 to obtain maxmized security.If you want to run the program on a router,you can try xor+simple,it can fool Packet Inspection by firewalls most time, but it cant protect you from serious attackers. Mode none is only for debug,its not suggest to set cipher-mode or auth-mode to none.
|
||||
### seq-mode
|
||||
the faketcp mode doest not behave 100% like a real tcp connection.ISP may be able to distinguish the simulated tcp traffic from real tcp traffic(though its costly). seq-mode can help you changed the seq increase behavior a bit. If you experienced problems,try to change the value.
|
||||
# Peformance Test
|
||||
#### test method:
|
||||
iperf3 tcp via openvpn + udp2raw
|
||||
(iperf3 udp mode is not used bc of bug mentioned in this issue: https://github.com/esnet/iperf/issues/296 ,instead,we turn iperf3 's tcp traffic into udp by using openvpn,to test udp2raw 's peformance. Read [Application](https://github.com/wangyu-/udp2raw-tunnel#application) for detail )
|
||||
#### iperf3 command:
|
||||
```
|
||||
iperf3 -c 10.222.2.1 -P40
|
||||
iperf3 -c 10.222.2.1 -P40 -R
|
||||
```
|
||||
#### client host
|
||||
vultr $2.5/monthly plan(single core 2.4ghz cpu,512m ram,location:Tokyo,Japan),
|
||||
#### server host
|
||||
bandwagonhost $3.99/annually(single core 2.0ghz cpu,128m ram,location:Los Angeles,USA)
|
||||
### Test1
|
||||
raw_mode: faketcp cipher_mode: xor auth_mode: simple
|
||||
|
||||

|
||||
|
||||
(reverse speed is simliar and not uploaded)
|
||||
|
||||
### Test2
|
||||
raw_mode: faketcp cipher_mode: aes128cbc auth_mode: md5
|
||||
|
||||

|
||||
|
||||
(reverse speed is simliar and not uploaded)
|
||||
|
||||
# Application
|
||||
### tunneling any traffic via raw traffic by using udp2raw +openvpn
|
||||

|
||||
1. bypasses UDP block/UDP QOS
|
||||
|
||||
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)
|
||||
|
||||
### tunneling finalspeed
|
||||
finalspeed 's tcp mode doesnt work on openvz VPS.you can use finalspeed 's udp mode,and tunnel udp through tcp with this tunnel.
|
||||
|
||||
# Related work
|
||||
### kcptun-raw
|
||||
this project was inspired by kcptun-raw,which modified kcptun to support tcp mode.
|
||||
|
||||
https://github.com/Chion82/kcptun-raw
|
||||
### kcpraw
|
||||
another project of kcptun with tcp mode
|
||||
|
||||
https://github.com/ccsexyz/kcpraw
|
||||
### relayRawSocket
|
||||
a simple udp to raw tunnel without simluated 3-way handshake ,wrote in python
|
||||
|
||||
https://github.com/linhua55/some_kcptun_tools/tree/master/relayRawSocket
|
||||
### icmptunnel
|
||||
Transparently tunnel your IP traffic through ICMP echo and reply packets.
|
||||
|
||||
https://github.com/DhavalKapil/icmptunnel
|
||||
|
||||
./raw -l44.55.66.77:9999 -r 127.0.0.1:5555 -s
|
||||
|
@@ -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;
|
||||
|
2
common.h
@@ -42,6 +42,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
|
||||
|
||||
@@ -88,6 +89,7 @@ const u32_t timer_interval=400;//this should be smaller than heartbeat_interval
|
||||
const u32_t conv_timeout=30000; //for test
|
||||
|
||||
const u32_t client_conn_timeout=10000;
|
||||
const u32_t client_conn_uplink_timeout=client_conn_timeout+2000;
|
||||
|
||||
//const uint32_t server_conn_timeout=conv_timeout+60000;//this should be 60s+ longer than conv_timeout,so that conv_manager can destruct convs gradually,to avoid latency glicth
|
||||
const u32_t server_conn_timeout=conv_timeout+10000;//for test
|
||||
|
174
doc/README.zh-cn.md
Normal file
@@ -0,0 +1,174 @@
|
||||
Udp2raw-tunnel
|
||||

|
||||
加密、防重放攻击的、信道复用的udp tunnel,利用raw socket中转udp流量
|
||||
|
||||
[English](/README.md)
|
||||
|
||||
[udp2raw+kcptun step_by_step教程](kcptun_step_by_step.md)
|
||||
|
||||
[udp2raw+finalspeed step_by_step教程](finalspeed_step_by_step.md)
|
||||
|
||||
如果你需要加速跨国网游、网页浏览,解决方案在另一个repo:
|
||||
|
||||
https://github.com/wangyu-/UDPspeeder
|
||||
### 把udp流量伪装成tcp /icmp
|
||||
用raw socket给udp包加上tcp/icmp包头,可以突破udp流量限制或Udp QOS。或者在udp nat有问题的环境下,提升稳定性。 另外也支持用raw 发udp包,这样流量不会被伪装,只会被加密。
|
||||
|
||||
### 加密 防重放攻击
|
||||
用aes128cbc加密,md5/crc32做数据完整校验。用类似ipsec/openvpn的 replay windows机制来防止重放攻击。
|
||||
|
||||
设计目标是,即使攻击者可以监听到tunnel的所有包,可以选择性丢弃tunnel的任意包,可以重放任意包;攻击者也没办法获得tunnel承载的任何数据,也没办法向tunnel的数据流中通过包构造/包重放插入任何数据。
|
||||
|
||||
### 模拟TCP3次握手
|
||||
模拟TCP3次握手,模拟seq ack过程。另外还模拟了一些tcp option:MSS,sackOk,TS,TS_ack,wscale,用来使流量看起来更像是由普通的linux tcp协议栈发送的。
|
||||
|
||||
### 连接保持,连接快速恢复,单向链路失效检测
|
||||
心跳机制检查连接是否中断,一旦心跳超时。client会立即换raw socket的端口重连,重连成功后会恢复之前中断的连接。虽然raw端的端口变了,但是udp端的所有连接都会继续有效。udp这边感觉不到raw端的重连,只会感觉到短暂断流,这跟普通的短暂丢包是类似的,不会导致上层应用重连。
|
||||
|
||||
Client能用单倍的超时时间检测到单向链路的失效,不管是上行还是下行,只要有一端失效就能被client检测到。重连只需要client发起,就可以立即被server处理,不需要等到server端的连接超时后。
|
||||
|
||||
对于有大量client的情况,对于不同client,server发送的心跳是错开时间发送的,不会因为短时间发送大量的心跳而造成拥塞和延迟抖动。
|
||||
|
||||
|
||||
|
||||
### 其他特性
|
||||
信道复用,client的udp端支持多个连接。
|
||||
|
||||
server支持多个client,也能正确处理多个连接的重连和连接恢复。
|
||||
|
||||
NAT 穿透 ,tcp icmp udp模式都支持nat穿透。
|
||||
|
||||
支持Openvz,配合finalspeed使用,可以在openvz上用tcp模式的finalspeed
|
||||
|
||||
支持Openwrt,没有编译依赖,容易编译到任何平台上。release中提供了ar71xx版本的binary
|
||||
|
||||
epoll纯异步,高并发,除了回收过期连接外,所有操作的时间复杂度都跟连接数无关。回收过期连接的操做也是一点一点进行的,不会因为消耗太多cpu时间造成延迟抖动。
|
||||
|
||||
### 关键词
|
||||
突破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
|
||||
|
||||
# 简明操作说明
|
||||
|
||||
### 环境要求
|
||||
Linux主机,有root权限。主机上最好安装了iptables命令(apt/yum很容易安装)。在windows和mac上可以开虚拟机(桥接模式测试可用)。
|
||||
|
||||
### 安装
|
||||
下载编译好的二进制文件,解压到任意目录。
|
||||
|
||||
https://github.com/wangyu-/udp2raw-tunnel/releases
|
||||
|
||||
### 运行
|
||||
假设你有一个server,ip为44.55.66.77,有一个服务监听在udp 7777端口。 假设你本地的主机到44.55.66.77的UDP流量被屏蔽了,或者被qos了
|
||||
|
||||
```
|
||||
在client端运行:
|
||||
./udp2raw_amd64 -c -l0.0.0.0:3333 -r44.55.66.77:4096 -a -k "passwd" --raw-mode faketcp
|
||||
|
||||
在server端运行:
|
||||
./udp2raw_amd64 -s -l0.0.0.0:4096 -r 127.0.0.1:7777 -a -k "passwd" --raw-mode faketcp
|
||||
|
||||
```
|
||||
|
||||
现在client和server之间建立起了,tunnel。想要在本地连接44.55.66.77:7777,只需要连接 127.0.0.1:3333。来回的所有的udp流量会被经过tunneling发送。在外界看起来是tcp流量,不会有udp流量暴露到公网。
|
||||
|
||||
# 进阶操作说明
|
||||
|
||||
### 命令选项
|
||||
```
|
||||
udp2raw-tunnel
|
||||
version: Aug 5 2017 21:03:54
|
||||
repository: https://github.com/wangyu-/udp2raw-tunnel
|
||||
|
||||
usage:
|
||||
run as client : ./this_program -c -l local_listen_ip:local_port -r server_ip:server_port [options]
|
||||
run as server : ./this_program -s -l server_listen_ip:server_port -r remote_ip:remote_port [options]
|
||||
|
||||
common options,these options must be same on both side:
|
||||
--raw-mode <string> avaliable values:faketcp(default),udp,icmp
|
||||
-k,--key <string> password to gen symetric key,default:"secret key"
|
||||
--auth-mode <string> avaliable values:aes128cbc(default),xor,none
|
||||
--cipher-mode <string> avaliable values:md5(default),crc32,simple,none
|
||||
-a,--auto-rule auto add (and delete) iptables rule
|
||||
-g,--gen-rule generate iptables rule then exit
|
||||
--disable-anti-replay disable anti-replay,not suggested
|
||||
client options:
|
||||
--source-ip <ip> force source-ip for raw socket
|
||||
--source-port <port> force source-port for raw socket,tcp/udp only
|
||||
this option disables port changing while re-connecting
|
||||
other options:
|
||||
--log-level <number> 0:never 1:fatal 2:error 3:warn
|
||||
4:info (default) 5:debug 6:trace
|
||||
--log-position enable file name,function name,line number in log
|
||||
--disable-color disable log color
|
||||
--disable-bpf disable the kernel space filter,most time its not necessary
|
||||
unless you suspect there is a bug
|
||||
--sock-buf <number> buf size for socket,>=10 and <=10240,unit:kbyte,default:1024
|
||||
--seqmode <number> seq increase mode for faketcp:
|
||||
0:dont increase
|
||||
1:increase every packet
|
||||
2:increase randomly, about every 3 packets (default)
|
||||
-h,--help print this help message
|
||||
```
|
||||
### iptables 规则
|
||||
用raw收发tcp包本质上绕过了linux内核的tcp协议栈。linux碰到raw socket发来的包会不认识,如果一直收到不认识的包,会回复大量RST,造成不稳定或性能问题。所以强烈建议添加iptables规则屏蔽Linux内核的对指定端口的处理。用-a选项,udp2raw会在启动的时候自动帮你加上Iptables规则,退出的时候再自动删掉。如果你不信任-a选项的可靠性,可以用-g选项来生成相应的Ip规则再自己手动添加。
|
||||
|
||||
用raw收发udp包也类似,只是内核回复的是icmp unreachable。而用raw 收发icmp,内核会自动回复icmp echo。都需要相应的iptables规则。
|
||||
### cipher-mode 和 auth-mode
|
||||
如果要最大的安全性建议用aes128cbc+md5。如果要运行再路由器上,建议xor+simple。但是注意xor+simple只能骗过防火墙的包检测,不能防止真正的攻击者。
|
||||
|
||||
### seq-mode
|
||||
facktcp模式并没有模拟tcp的全部。所以理论上有办法把faketcp和真正的tcp流量区分开来(虽然大部分ISP不太可能做这种程度的包检测)。seq-mode可以改变一些seq ack的行为。如果遇到了连接问题,可以尝试更改。在我这边的移动线路用3种模式都没问题。
|
||||
|
||||
# 性能测试
|
||||
iperf3 的UDP模式有BUG,所以,这里用iperf3的tcp模式,配合Openvpn,测试udp2raw的性能。(iperf3 udp issue ,https://github.com/esnet/iperf/issues/296 )
|
||||
|
||||
openvpn关掉了自带的加密。
|
||||
#### iperf3 命令:
|
||||
```
|
||||
iperf3 -c 10.222.2.1 -P40
|
||||
iperf3 -c 10.222.2.1 -P40 -R
|
||||
```
|
||||
#### client主机
|
||||
vultr 2.5美元每月套餐(single core 2.4ghz cpu,512m ram,日本东京机房),
|
||||
#### server主机
|
||||
bandwagonhost 3.99美元每年套餐(single core 2.0ghz cpu,128m ram,美国洛杉矶机房)
|
||||
### 测试1
|
||||
raw_mode: faketcp cipher_mode: xor auth_mode: simple
|
||||
|
||||

|
||||
|
||||
(反向的速度几乎一样,所以只发正向测试的图)
|
||||
|
||||
测试中cpu被打满。其中有30%的cpu是被openvpn占的。 如果不用Openvpn中转,实际达到100+Mb/S 应该没问题。
|
||||
|
||||
### 测试2
|
||||
raw_mode: faketcp cipher_mode: aes128cbc auth_mode: md5
|
||||
|
||||

|
||||
|
||||
(反向的速度几乎一样,所以只发正向测试的图)
|
||||
|
||||
测试中cpu被打满。绝大多数cpu都是被udp2raw占用的(主要消耗在aes加密)。即使不用Openvpn,速度也不会快很多了。
|
||||
# 应用
|
||||
### 中转 kcptun
|
||||
[udp2raw+kcptun step_by_step教程](kcptun_step_by_step.md)
|
||||
### 中转 finalspeed
|
||||
[udp2raw+finalspeed step_by_step教程](finalspeed_step_by_step.md)
|
||||
# 相关repo
|
||||
### kcptun-raw
|
||||
this project was inspired by kcptun-raw,which modified kcptun to support tcp mode.
|
||||
|
||||
https://github.com/Chion82/kcptun-raw
|
||||
### kcpraw
|
||||
another project of kcptun with tcp mode
|
||||
|
||||
https://github.com/ccsexyz/kcpraw
|
||||
### relayRawSocket
|
||||
a simple udp to raw tunnel without simluated 3-way handshake ,wrote in python
|
||||
|
||||
https://github.com/linhua55/some_kcptun_tools/tree/master/relayRawSocket
|
||||
### icmptunnel
|
||||
Transparently tunnel your IP traffic through ICMP echo and reply packets.
|
||||
|
||||
https://github.com/DhavalKapil/icmptunnel
|
||||
|
69
doc/finalspeed_step_by_step.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# udp2raw+finalspeed 加速tcp流量 Step by Step 教程
|
||||

|
||||
|
||||
##### 背景
|
||||
国内有些ISP会对UDP做QOS或屏蔽,这时候加速协议对TCP发包模式的支持就很重要。finalspeed虽然本身支持在底层用TCP发包,但是其依赖的libpcap不支持openvz架构,即使不是openvz架构的主机,也存在不稳定的问题。
|
||||
|
||||
|
||||
##### 摘要
|
||||
udp2raw是一个把udp流量通过raw socket包装成tcp流量的工具。通过用udp2raw配合udp模式的 finalspeed一样可以达到在底层发tcp包,绕过QOS的效果。支持openvz,稳定性也好很多。原理上相当于在finalspeed外面再包了一层tunnel。
|
||||
|
||||
本教程会一步一步演示用udp2raw+kcptun加速http流量的过程。加速任何其他tcp流量也一样。
|
||||
|
||||
udp2raw也支持把udp流量包装成Icmp发送,本教程不做演示。
|
||||
|
||||
### 环境要求
|
||||
服务器主机是linux,有root权限。 可以是openvz架构的vps。 也可以是openwrt路由器。
|
||||
|
||||
本地主机是windows,本地有openwrt路由器或树莓派或安装了linux虚拟机(网卡设置为桥接模式)。
|
||||
|
||||
(如果嫌给虚拟机安装linux麻烦,可以下载别人提供好的linux虚拟机镜像,比如https://www.kali.org/downloads/ ,不过我没有测试过这个镜像,我用的是debian 7)
|
||||
|
||||
### 安装
|
||||
下载好udp2raw的压缩包,解压分别解压到服务器和本地的虚拟机。
|
||||
|
||||
https://github.com/xtaci/kcptun/releases
|
||||
|
||||
在服务器端安装好finalspeed服务端,在本地windows安装好finalspeed的客户端。服务端我以前是用91yun的一键安装脚本安装的,没装过的可以去网上搜一键安装脚本。
|
||||
|
||||
### 运行
|
||||
1.先在服务器主机运行如下命令,确定finalspeed服务端已经正常启动了。
|
||||
|
||||
```
|
||||
netstat -nlp|grep java
|
||||
```
|
||||

|
||||
|
||||
如果显示了150端口,就表示服务端启动好了。
|
||||
|
||||
2.在服务器启动udp2raw server
|
||||
```
|
||||
./udp2raw_amd64 -s -l0.0.0.0:8855 -r 127.0.0.1:150 -a -k "passwd" --raw-mode faketcp
|
||||
```
|
||||

|
||||
|
||||
3.在本地的虚拟机上启动udp2raw client ,假设服务器ip是45.66.77.88
|
||||
```
|
||||
./udp2raw_amd64 -c -r45.66.77.88:8855 -l0.0.0.0:150 --raw-mode faketcp -a -k"passwd"
|
||||
```
|
||||
如果一切正常,client端会显示client_ready:
|
||||
|
||||

|
||||
|
||||
记下红框中的ip,这是虚拟机的网卡ip
|
||||
|
||||
在server端也会显示server_reay
|
||||

|
||||
|
||||
4.在本地windows,按图配置好finalspeed的客户端。注意,192.168.205.8改成你刚才记下来的IP,带宽也要按实际的填。传输协议要选UDP.
|
||||

|
||||
|
||||
5.所有准备工作已经完成了,在本地访问本地的8012端口,相当于访问服务器的80端口。
|
||||
|
||||
来试一下通过http://127.0.0.1:8012/ 下载文件 ,1.5M/s:
|
||||

|
||||
|
||||
再试一下直接通过服务器的ip访问,http://45.66.77.88:80/ ,速度只有600K/s
|
||||

|
||||
|
||||
教程就到这里了,用来加速其他的tcp服务也是一样的,只要再第三步那里设置其他的端口。
|
1
doc/finalspeed_step_by_step/11
Normal file
@@ -0,0 +1 @@
|
||||
11
|
BIN
doc/finalspeed_step_by_step/Capture.PNG
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
doc/finalspeed_step_by_step/Capture0.PNG
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
doc/finalspeed_step_by_step/Capture2.PNG
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
doc/finalspeed_step_by_step/Capture3.PNG
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
doc/finalspeed_step_by_step/Capture4.PNG
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
doc/finalspeed_step_by_step/Capture5.PNG
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
doc/finalspeed_step_by_step/Capture6.PNG
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
doc/finalspeed_step_by_step/Capture7.PNG
Normal file
After Width: | Height: | Size: 69 KiB |
59
doc/kcptun_step_by_step.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# udp2raw+kcptun 加速tcp流量 Step by Step 教程
|
||||

|
||||
|
||||
本教程会一步一步演示用udp2raw+kcptun加速SSH流量的过程。加速任何其他tcp流量也一样。
|
||||
|
||||
### 环境要求
|
||||
两边的主机都是linux,有root权限。 可以是openwrt路由器或树莓派,windows上桥接模式的虚拟机也可用
|
||||
|
||||
|
||||
### 安装
|
||||
下载好kcptun和udp2raw的压缩包,解压分别解压到client端和server端。
|
||||
|
||||
https://github.com/xtaci/kcptun/releases
|
||||
https://github.com/wangyu-/udp2raw-tunnel/releases
|
||||
|
||||
解压好后,如图:
|
||||

|
||||
|
||||
### 运行
|
||||
1.在远程服务器运行 udp2raw_amd64 server模式:
|
||||
```
|
||||
./udp2raw_amd64 -s -l0.0.0.0:8855 -r 127.0.0.1:4000 -k "passwd" --raw-mode faketcp -a
|
||||
```
|
||||

|
||||
|
||||
2.在本地运行udp2raw_amd64 client模式,假设server ip是45.66.77.88:
|
||||
```
|
||||
./udp2raw_amd64 -c -r45.66.77.88:8855 -l0.0.0.0:4000 --raw-mode faketcp -a -k"passwd"
|
||||
```
|
||||
如果一切正常client端输出如下,显示client_ready:
|
||||

|
||||
|
||||
server端也会有类似输出,显示server_ready:
|
||||

|
||||
|
||||
3.在远程服务器运行 kcp server
|
||||
|
||||
|
||||
```
|
||||
./server_linux_amd64 -t "127.0.0.1:22" -l ":4000" -mode fast2 -mtu 1300
|
||||
```
|
||||
-mtu 1300很重要,或者设置成更小。
|
||||

|
||||
|
||||
4.在本地运行
|
||||
|
||||
|
||||
```
|
||||
./client_linux_amd64 -r "127.0.0.1:4000" -l ":3322" -mode fast2 -mtu 1300
|
||||
```
|
||||
-mtu 1300很重要,或者设置成更小。
|
||||

|
||||
|
||||
5.所有准备工作已经做好,在本地运行
|
||||
```
|
||||
ssh -p 3322 root@127.0.0.1
|
||||
```
|
||||
已经连进去了,而且是经过kcptun加速的:
|
||||

|
BIN
doc/kcptun_step_by_step/Capture.PNG
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
doc/kcptun_step_by_step/Capture0.PNG
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
doc/kcptun_step_by_step/Capture00.PNG
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
doc/kcptun_step_by_step/Capture2.PNG
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
doc/kcptun_step_by_step/Capture3.PNG
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
doc/kcptun_step_by_step/Capture6.PNG
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
doc/kcptun_step_by_step/Capture7.PNG
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
doc/kcptun_step_by_step/Capture8.PNG
Normal file
After Width: | Height: | Size: 14 KiB |
88
doc/openvpn_guide.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# udp2raw+openvpn config guide
|
||||

|
||||
|
||||

|
||||
# 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
|
||||
```
|
BIN
images/image0.PNG
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
images/image1.PNG
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
images/image2.PNG
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
images/image4.PNG
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
images/image5.PNG
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
images/openvpn.PNG
Normal file
After Width: | Height: | Size: 44 KiB |
151
main.cpp
@@ -38,6 +38,8 @@ int disable_anti_replay=0;
|
||||
char key_string[1000]= "secret key";
|
||||
char key[16];//,key2[16];
|
||||
|
||||
int mtu_warn=1375;
|
||||
|
||||
//uint64_t current_time_rough=0;
|
||||
|
||||
|
||||
@@ -291,6 +293,11 @@ struct conn_info_t
|
||||
id_t oppsite_const_id;
|
||||
|
||||
blob_t *blob;
|
||||
|
||||
uint8_t my_roller;
|
||||
uint8_t oppsite_roller;
|
||||
u64_t last_oppsite_roller_time;
|
||||
|
||||
/*
|
||||
const uint32_t &ip=raw_info.recv_info.src_ip;
|
||||
const uint16_t &port=raw_info.recv_info.src_port;
|
||||
@@ -305,8 +312,13 @@ struct conn_info_t
|
||||
my_id=conn_info.my_id;
|
||||
oppsite_id=conn_info.oppsite_id;
|
||||
blob->anti_replay.re_init();
|
||||
|
||||
my_roller=0;//no need to set,but for easier debug,set it to zero
|
||||
oppsite_roller=0;//same as above
|
||||
last_oppsite_roller_time=0;
|
||||
}
|
||||
conn_info_t()
|
||||
|
||||
void re_init()
|
||||
{
|
||||
//send_packet_info.protocol=g_packet_info_send.protocol;
|
||||
if(program_mode==server_mode)
|
||||
@@ -315,8 +327,17 @@ struct conn_info_t
|
||||
state.client_current_state=client_idle;
|
||||
last_state_time=0;
|
||||
oppsite_const_id=0;
|
||||
blob=0;
|
||||
|
||||
timer_fd=0;
|
||||
|
||||
my_roller=0;
|
||||
oppsite_roller=0;
|
||||
last_oppsite_roller_time=0;
|
||||
}
|
||||
conn_info_t()
|
||||
{
|
||||
blob=0;
|
||||
re_init();
|
||||
}
|
||||
void prepare()
|
||||
{
|
||||
@@ -537,7 +558,7 @@ int TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
|
||||
////////==========================type divider=======================================================
|
||||
|
||||
int server_on_raw_recv_pre_ready(conn_info_t &conn_info,char * ip_port,u32_t tmp_oppsite_const_id);
|
||||
int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char *data,int data_len);
|
||||
int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char type,char *data,int data_len);
|
||||
int server_on_raw_recv_handshake1(conn_info_t &conn_info,char * ip_port,char * data, int data_len);
|
||||
|
||||
int DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD;
|
||||
@@ -676,15 +697,15 @@ int recv_handshake(packet_info_t &info,id_t &id1,id_t &id2,id_t &id3)
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
int send_safer(conn_info_t &conn_info,const char* data,int len)
|
||||
int send_safer(conn_info_t &conn_info,char type,const char* data,int len)
|
||||
{
|
||||
|
||||
packet_info_t &send_info=conn_info.raw_info.send_info;
|
||||
packet_info_t &recv_info=conn_info.raw_info.recv_info;
|
||||
|
||||
if(data[0]!='h'&&data[0]!='d')
|
||||
if(type!='h'&&type!='d')
|
||||
{
|
||||
mylog(log_warn,"first byte is not h or d ,%x\n",data[0]);
|
||||
mylog(log_warn,"first byte is not h or d ,%x\n",type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -693,6 +714,8 @@ int send_safer(conn_info_t &conn_info,const char* data,int len)
|
||||
char send_data_buf[buf_len]; //buf for send data and send hb
|
||||
char send_data_buf2[buf_len];
|
||||
|
||||
|
||||
|
||||
id_t n_tmp_id=htonl(conn_info.my_id);
|
||||
|
||||
memcpy(send_data_buf,&n_tmp_id,sizeof(n_tmp_id));
|
||||
@@ -706,9 +729,12 @@ int send_safer(conn_info_t &conn_info,const char* data,int len)
|
||||
memcpy(send_data_buf+sizeof(n_tmp_id)*2,&n_seq,sizeof(n_seq));
|
||||
|
||||
|
||||
memcpy(send_data_buf+sizeof(n_tmp_id)*2+sizeof(n_seq),data,len);//data;
|
||||
send_data_buf[sizeof(n_tmp_id)*2+sizeof(n_seq)]=type;
|
||||
send_data_buf[sizeof(n_tmp_id)*2+sizeof(n_seq)+1]=conn_info.my_roller;
|
||||
|
||||
int new_len=len+sizeof(n_seq)+sizeof(n_tmp_id)*2;
|
||||
memcpy(send_data_buf+2+sizeof(n_tmp_id)*2+sizeof(n_seq),data,len);//data;
|
||||
|
||||
int new_len=len+sizeof(n_seq)+sizeof(n_tmp_id)*2+2;
|
||||
|
||||
if(my_encrypt(send_data_buf,send_data_buf2,new_len,key)!=0)
|
||||
{
|
||||
@@ -727,17 +753,17 @@ int send_data_safer(conn_info_t &conn_info,const char* data,int len,u32_t conv_n
|
||||
packet_info_t &recv_info=conn_info.raw_info.recv_info;
|
||||
|
||||
char send_data_buf[buf_len];
|
||||
send_data_buf[0]='d';
|
||||
//send_data_buf[0]='d';
|
||||
u32_t n_conv_num=htonl(conv_num);
|
||||
memcpy(send_data_buf+1,&n_conv_num,sizeof(n_conv_num));
|
||||
memcpy(send_data_buf,&n_conv_num,sizeof(n_conv_num));
|
||||
|
||||
memcpy(send_data_buf+1+sizeof(n_conv_num),data,len);
|
||||
int new_len=len+1+sizeof(n_conv_num);
|
||||
send_safer(conn_info,send_data_buf,new_len);
|
||||
memcpy(send_data_buf+sizeof(n_conv_num),data,len);
|
||||
int new_len=len+sizeof(n_conv_num);
|
||||
send_safer(conn_info,'d',send_data_buf,new_len);
|
||||
return 0;
|
||||
|
||||
}
|
||||
int parse_safer(conn_info_t &conn_info,const char * input,int input_len,char* &data,int &len)//allow overlap
|
||||
int parse_safer(conn_info_t &conn_info,const char * input,int input_len,char &type,char* &data,int &len)//allow overlap
|
||||
{
|
||||
static char recv_data_buf0[buf_len];
|
||||
|
||||
@@ -779,17 +805,32 @@ int parse_safer(conn_info_t &conn_info,const char * input,int input_len,char* &d
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t roller=data[1];
|
||||
|
||||
|
||||
type=data[0];
|
||||
data+=2;
|
||||
len-=2;
|
||||
|
||||
if(len<0)
|
||||
{
|
||||
mylog(log_debug,"len <0 ,%d\n",len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(roller!=conn_info.oppsite_roller)
|
||||
{
|
||||
conn_info.oppsite_roller=roller;
|
||||
conn_info.last_oppsite_roller_time=get_current_time();
|
||||
}
|
||||
conn_info.my_roller++;//increase on a successful recv
|
||||
|
||||
|
||||
if(after_recv_raw0(conn_info.raw_info)!=0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
int recv_safer(conn_info_t &conn_info,char* &data,int &len)
|
||||
int recv_safer(conn_info_t &conn_info,char &type,char* &data,int &len)
|
||||
{
|
||||
packet_info_t &send_info=conn_info.raw_info.send_info;
|
||||
packet_info_t &recv_info=conn_info.raw_info.recv_info;
|
||||
@@ -799,7 +840,7 @@ int recv_safer(conn_info_t &conn_info,char* &data,int &len)
|
||||
|
||||
if(recv_raw0(conn_info.raw_info,recv_data,recv_len)!=0) return -1;
|
||||
|
||||
return parse_safer(conn_info,recv_data,recv_len,data,len);
|
||||
return parse_safer(conn_info,recv_data,recv_len,type,data,len);
|
||||
}
|
||||
|
||||
int try_to_list_and_bind(int port)
|
||||
@@ -928,6 +969,8 @@ int client_on_timer(conn_info_t &conn_info) //for client
|
||||
conn_info.blob->conv_manager.clear_inactive();
|
||||
mylog(log_trace,"timer!\n");
|
||||
|
||||
mylog(log_trace,"roller my %d,oppsite %d,%lld\n",int(conn_info.my_roller),int(conn_info.oppsite_roller),conn_info.last_oppsite_roller_time);
|
||||
|
||||
mylog(log_trace,"<client_on_timer,send_info.ts_ack= %u>\n",send_info.ts_ack);
|
||||
|
||||
if(conn_info.state.client_current_state==client_idle)
|
||||
@@ -1112,7 +1155,7 @@ int client_on_timer(conn_info_t &conn_info) //for client
|
||||
{
|
||||
conn_info.state.client_current_state=client_idle;
|
||||
conn_info.my_id=get_true_random_number_nz();
|
||||
mylog(log_info,"state back to client_idle from client_ready\n");
|
||||
mylog(log_info,"state back to client_idle from client_ready bc of recv-direction timeout\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1121,9 +1164,16 @@ int client_on_timer(conn_info_t &conn_info) //for client
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(get_current_time()- conn_info.last_oppsite_roller_time>client_conn_uplink_timeout)
|
||||
{
|
||||
conn_info.state.client_current_state=client_idle;
|
||||
conn_info.my_id=get_true_random_number_nz();
|
||||
mylog(log_info,"state back to client_idle from client_ready bc of send-direction timeout\n");
|
||||
}
|
||||
|
||||
mylog(log_debug,"heartbeat sent <%x,%x>\n",conn_info.oppsite_id,conn_info.my_id);
|
||||
|
||||
send_safer(conn_info,(char *)"h",1);/////////////send
|
||||
send_safer(conn_info,'h',"",0);/////////////send
|
||||
|
||||
conn_info.last_hb_sent_time=get_current_time();
|
||||
return 0;
|
||||
@@ -1164,7 +1214,7 @@ int server_on_timer_multi(conn_info_t &conn_info,char * ip_port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
send_safer(conn_info,(char *)"h",1); /////////////send
|
||||
send_safer(conn_info,'h',"",0); /////////////send
|
||||
|
||||
conn_info.last_hb_sent_time=get_current_time();
|
||||
|
||||
@@ -1280,7 +1330,8 @@ int client_on_raw_recv(conn_info_t &conn_info)
|
||||
}
|
||||
else if(conn_info.state.client_current_state==client_handshake2||conn_info.state.client_current_state==client_ready)//received heartbeat or data
|
||||
{
|
||||
if(recv_safer(conn_info,data,data_len)!=0)
|
||||
char type;
|
||||
if(recv_safer(conn_info,type,data,data_len)!=0)
|
||||
{
|
||||
mylog(log_debug,"recv_safer failed!\n");
|
||||
return -1;
|
||||
@@ -1296,21 +1347,22 @@ int client_on_raw_recv(conn_info_t &conn_info)
|
||||
conn_info.state.client_current_state=client_ready;
|
||||
conn_info.last_hb_sent_time=0;
|
||||
conn_info.last_hb_recv_time=get_current_time();
|
||||
conn_info.last_oppsite_roller_time=conn_info.last_hb_recv_time;
|
||||
client_on_timer(conn_info);
|
||||
}
|
||||
if(data_len==1&&data[0]=='h')
|
||||
if(data_len==0&&type=='h')
|
||||
{
|
||||
mylog(log_debug,"[hb]heart beat received\n");
|
||||
conn_info.last_hb_recv_time=get_current_time();
|
||||
return 0;
|
||||
}
|
||||
else if(data_len>= int( sizeof(u32_t)+1 )&&data[0]=='d')
|
||||
else if(data_len>= int( sizeof(u32_t))&&type=='d')
|
||||
{
|
||||
mylog(log_trace,"received a data from fake tcp,len:%d\n",data_len);
|
||||
|
||||
conn_info.last_hb_recv_time=get_current_time();
|
||||
|
||||
u32_t tmp_conv_id= ntohl(* ((u32_t *)&data[1]));
|
||||
u32_t tmp_conv_id= ntohl(* ((u32_t *)&data[0]));
|
||||
|
||||
if(!conn_info.blob->conv_manager.is_conv_used(tmp_conv_id))
|
||||
{
|
||||
@@ -1331,7 +1383,7 @@ int client_on_raw_recv(conn_info_t &conn_info)
|
||||
tmp_sockaddr.sin_port= htons(uint16_t((u64<<32u)>>32u));
|
||||
|
||||
|
||||
int ret=sendto(udp_fd,data+1+sizeof(u32_t),data_len -(1+sizeof(u32_t)),0,(struct sockaddr *)&tmp_sockaddr,sizeof(tmp_sockaddr));
|
||||
int ret=sendto(udp_fd,data+sizeof(u32_t),data_len -(sizeof(u32_t)),0,(struct sockaddr *)&tmp_sockaddr,sizeof(tmp_sockaddr));
|
||||
|
||||
if(ret<0)
|
||||
{
|
||||
@@ -1491,10 +1543,11 @@ int server_on_raw_recv_multi()
|
||||
}
|
||||
if(conn_info.state.server_current_state==server_ready)
|
||||
{
|
||||
if (recv_safer(conn_info, data, data_len) != 0) {
|
||||
char type;
|
||||
if (recv_safer(conn_info,type, data, data_len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return server_on_raw_recv_ready(conn_info,ip_port,data,data_len);
|
||||
return server_on_raw_recv_ready(conn_info,ip_port,type,data,data_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1572,7 +1625,7 @@ int server_on_raw_recv_handshake1(conn_info_t &conn_info,char * ip_port,char * d
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char *data,int data_len)
|
||||
int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char type,char *data,int data_len)
|
||||
{
|
||||
|
||||
raw_info_t &raw_info = conn_info.raw_info;
|
||||
@@ -1590,15 +1643,15 @@ int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char *data,in
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
if (data[0] == 'h' && data_len == 1) {
|
||||
u32_t tmp = ntohl(*((u32_t *) &data[1 + sizeof(u32_t)]));
|
||||
if (type == 'h' && data_len == 0) {
|
||||
//u32_t tmp = ntohl(*((u32_t *) &data[sizeof(u32_t)]));
|
||||
mylog(log_debug,"[%s][hb]received hb \n",ip_port);
|
||||
conn_info.last_hb_recv_time = get_current_time();
|
||||
return 0;
|
||||
} else if (data[0] == 'd' && data_len >=int( sizeof(u32_t) + 1))
|
||||
} else if (type== 'd' && data_len >=int( sizeof(u32_t) ))
|
||||
{
|
||||
|
||||
u32_t tmp_conv_id = ntohl(*((u32_t *) &data[1]));
|
||||
u32_t tmp_conv_id = ntohl(*((u32_t *) &data[0]));
|
||||
|
||||
conn_info.last_hb_recv_time = get_current_time();
|
||||
|
||||
@@ -1671,8 +1724,8 @@ int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char *data,in
|
||||
int fd = int((u64 << 32u) >> 32u);
|
||||
|
||||
mylog(log_trace, "[%s]received a data from fake tcp,len:%d\n",ip_port, data_len);
|
||||
int ret = send(fd, data + 1 + sizeof(u32_t),
|
||||
data_len - (1 + sizeof(u32_t)), 0);
|
||||
int ret = send(fd, data + sizeof(u32_t),
|
||||
data_len - ( sizeof(u32_t)), 0);
|
||||
|
||||
mylog(log_trace, "[%s]%d byte sent ,fd :%d\n ",ip_port, ret, fd);
|
||||
if (ret < 0) {
|
||||
@@ -1724,7 +1777,7 @@ int server_on_raw_recv_pre_ready(conn_info_t &conn_info,char * ip_port,u32_t tmp
|
||||
conn_info.last_hb_recv_time = get_current_time();
|
||||
conn_info.last_hb_sent_time = conn_info.last_hb_recv_time;//=get_current_time()
|
||||
|
||||
send_safer(conn_info, (char *) "h", 1); /////////////send
|
||||
send_safer(conn_info, 'h',"", 0); /////////////send
|
||||
|
||||
mylog(log_info, "[%s]changed state to server_ready\n",ip_port);
|
||||
conn_info.blob->anti_replay.re_init();
|
||||
@@ -1783,7 +1836,7 @@ int server_on_raw_recv_pre_ready(conn_info_t &conn_info,char * ip_port,u32_t tmp
|
||||
//ori_conn_info.state.server_current_state=server_ready;
|
||||
ori_conn_info.recover(conn_info);
|
||||
|
||||
send_safer(ori_conn_info, (char *) "h", 1);
|
||||
send_safer(ori_conn_info, 'h',"", 0);
|
||||
//ori_conn_info.blob->anti_replay.re_init();
|
||||
|
||||
|
||||
@@ -1987,6 +2040,10 @@ int client_event_loop()
|
||||
myexit(1);
|
||||
};
|
||||
|
||||
if(recv_len>=mtu_warn)
|
||||
{
|
||||
mylog(log_warn,"huge packet,data len=%d (>=%d).strongly suggested to set a smaller mtu at upper level,to get rid of this warn\n ",recv_len,mtu_warn);
|
||||
}
|
||||
mylog(log_trace,"Received packet from %s:%d,len: %d\n", inet_ntoa(udp_new_addr_in.sin_addr),
|
||||
ntohs(udp_new_addr_in.sin_port),recv_len);
|
||||
|
||||
@@ -2260,6 +2317,11 @@ int server_event_loop()
|
||||
continue;
|
||||
}
|
||||
|
||||
if(recv_len>=mtu_warn)
|
||||
{
|
||||
mylog(log_warn,"huge packet,data len=%d (>=%d).strongly suggested to set a smaller mtu at upper level,to get rid of this warn\n ",recv_len,mtu_warn);
|
||||
}
|
||||
|
||||
//conn_info.conv_manager->update_active_time(conv_id); server dosnt update from upd side,only update from raw side. (client updates at both side)
|
||||
|
||||
if(conn_info.state.server_current_state==server_ready)
|
||||
@@ -2351,6 +2413,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 +2607,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;
|
||||
|
15
makefile
@@ -4,13 +4,20 @@ FLAGS2= -O3
|
||||
all:
|
||||
sudo killall udp2raw||true
|
||||
sleep 0.2
|
||||
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} ${FLAGS2}
|
||||
${ccmips} main.cpp -o udp2raw_ar71xx -lrt -I. -Ilib 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. -Ilib 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}
|
||||
g++ main.cpp -o udp2raw_x86 -static -ggdb -I. lib/aes.c lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp -lrt -std=c++11 ${FLAGS} ${FLAGS2} -m32
|
||||
${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}
|
||||
tar -zcvf udp2raw_binaries.tar.gz udp2raw_amd64 udp2raw_x86 udp2raw_ar71xx
|
||||
|
||||
|
131
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_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)
|
||||
@@ -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;
|
||||
memset(iph,0,sizeof(iphdr));
|
||||
|
||||
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;
|
||||
static unsigned short ip_id=1;
|
||||
|
||||
iph->ihl = 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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|