Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Kenny Lam 2018-04-25 23:06:08 +08:00
commit 8fe8653331
33 changed files with 752 additions and 246 deletions

6
ISSUE_TEMPLATE.md Normal file

@ -0,0 +1,6 @@
For English speaking user
https://github.com/wangyu-/UDPspeeder/wiki/Issue-Guide
中文用户请看:
https://github.com/wangyu-/UDPspeeder/wiki/发Issue前请看
(否则Issue可能被忽略或被直接关掉)

@ -1,16 +1,23 @@
# Udp2raw-tunnel
![image0](images/image0.PNG)
A Tunnel which turns UDP Traffic into Encrypted FakeTCP/UDP/ICMP Traffic by using Raw Socket, helps you Bypass UDP FireWalls(or Unstable UDP Environment). It can defend Replay-Attack and supports Multiplexing. It also acts as a Connection Stabilizer.
It can tunnel any traffic when used together with a UDP-based VPN(such as OpenVPN).Check [this link](https://github.com/wangyu-/udp2raw-tunnel#tunneling-any-traffic-via-raw-traffic-by-using-udp2raw-openvpn) for more info.
![image0](images/image0.PNG)
[简体中文](/doc/README.zh-cn.md)
When used alone,udp2raw tunnels only UDP traffic. Nevertheless,if you used udp2raw + any UDP-based VPN together,you can tunnel any traffic(include TCP/UDP/ICMP),currently OpenVPN/L2TP/ShadowVPN and [tinyfecVPN](https://github.com/wangyu-/tinyfecVPN) are confirmed to be supported.
![image_vpn](images/udp2rawopenvpn.PNG)
[简体中文](/doc/README.zh-cn.md)(内容更丰富)
[udp2raw wiki](https://github.com/wangyu-/udp2raw-tunnel/wiki)
# Support Platforms
Linux host (including desktop Linux,Android phone/tablet,OpenWRT router,or Raspberry PI) with root access.
For Winodws/MacOS,the 4.4mb virtual image with udp2raw pre-installed has been released,you can load it with Vmware/VirtualBox.The virtual image has been set to auto obtain ip,udp2raw can be run imidiately after boot finished(make sure network mode of virtual machine has been set to bridged)(only udp2raw has to be run under virtual machine,all other programs runs under Windows/MacOS as usual).
For Windows and MacOS You can run udp2raw inside [this](https://github.com/wangyu-/udp2raw-tunnel/releases/download/20171108.0/lede-17.01.2-x86_virtual_machine_image.zip) 7.5mb virtual machine image(make sure network adapter runs at bridged mode).
# Features
@ -46,22 +53,6 @@ For example, if you use udp2raw + OpenVPN, OpenVPN won't lose connection after a
### Keywords
`Bypass UDP QoS` `Bypass UDP Blocking` `Bypass OpenVPN TCP over TCP problem` `OpenVPN over ICMP` `UDP to ICMP tunnel` `UDP to TCP tunnel` `UDP over ICMP` `UDP over TCP`
# Frequently Asked Questions
### Q: What is the advantage of using udp2raw FakeTCP mode,why not use a TCP-based VPN(such as OpenVPN TCP mode)?
Answer: **TCP doesnt allow real-time/out-of-order delivery**. **If you use OpenVPN TCP mode to turn UDP traffic into TCP,there will be latency issue**:the loss of a single packet blocks all following packet until re-transmission is done. This will cause unacceptable delay for gaming and voice chatting.
**TCP also has re-transmission and congestion control which cant be disabled.** UDP programs usualy want to control packet sending rate by themselves. If you use OpenVPN TCP mode this cant be done because of the congestion control of underlying TCP protocol. Further more,with the re-transmission of underlying TCP,**if you send too many udp packets via an OpenVPN TCP connection,the connection will become completely unusable for a while**(It will eventually recover as most of the re-transmission is done,but it wont be very soon).
Those issues exist for almost all TCP-based VPNs.
For udp2raw there is no underlying TCP protocol,udp2raw just add TCP headers to UDP packets directly by using raw socket. It supports real-time/out-of-order delivery,there is no re-transmission and congestion control. **Udp2raw doesnt have all above issues**.
### Q: Is udp2raw designed for replacing VPN?
Answer: No. Udp2raw is designed for bypassing UDP restrictions. It doesnt have all of the features a VPN has(such as transparently redirect all traffic).
Instead of replacing VPN,udp2raw can be used with any UDP-based VPN together to grant UDP-based VPN the ablity of bypassing UDP restrictions,while not having the performance issue involved by a TCP-based VPN. Check [this link](https://github.com/wangyu-/udp2raw-tunnel#tunneling-any-traffic-via-raw-traffic-by-using-udp2raw-openvpn) for more info.
# Getting Started
### Installing
Download binary release from https://github.com/wangyu-/udp2raw-tunnel/releases
@ -76,6 +67,8 @@ Assume your UDP is blocked or being QOS-ed or just poorly supported. Assume your
# Run at client side
./udp2raw_amd64 -c -l0.0.0.0:3333 -r44.55.66.77:4096 -a -k "passwd" --raw-mode faketcp
```
(The above commands need to be run as root. For better security, with some extra steps, you can run udp2raw as non-root. Check [this link](https://github.com/wangyu-/udp2raw-tunnel/wiki/run-udp2raw-as-non-root) for more info )
###### Server Output:
![](images/output_server.PNG)
###### Client Output:
@ -86,9 +79,9 @@ Now,an encrypted raw tunnel has been established between client and server throu
### Note
To run on Android, check [Android_Guide](/doc/android_guide.md)
If you have connection problems.Take a look at `--seq-mode` option.
If you have connection problems. Take a look at `--seq-mode` option.
You can run udp2raw with a non-root account(for better security).Take a look at [#26](https://github.com/wangyu-/udp2raw-tunnel/issues/26) for more info.
# Advanced Topic
### Usage
@ -191,6 +184,10 @@ Then start the server with
./udp2raw_amd64 --conf-file server.conf
```
### `--fifo`
Use a fifo(named pipe) for sending commands to the running program. For example `--fifo fifo.file`.
At client side,you can use `echo reconnect >fifo.file` to force client to reconnect.Currently no command has been implemented for server.
# Peformance Test
#### Test method:
@ -222,7 +219,7 @@ raw_mode: faketcp cipher_mode: aes128cbc  auth_mode: md5
# Application
## Tunneling any traffic via raw traffic by using udp2raw +openvpn
![image_vpn](images/openvpn.PNG)
![image_vpn](images/udp2rawopenvpn.PNG)
1. Bypasses UDP block/UDP QOS
2. No TCP over TCP problem (TCP over TCP problem http://sites.inka.de/bigred/devel/tcp-tcp.html ,https://community.openvpn.net/openvpn/ticket/2 )
@ -231,7 +228,7 @@ raw_mode: faketcp cipher_mode: aes128cbc  auth_mode: md5
4. Supports almost any UDP-based VPN
More details at [openvpn+udp2raw_guide](/doc/openvpn_guide.md)
More details at [openvpn+udp2raw_guide](https://github.com/wangyu-/udp2raw-tunnel/wiki/udp2raw-openvpn-config-guide)
## Speed-up tcp connection via raw traffic by using udp2raw+kcptun
kcptun is a tcp connection speed-up program,it speeds-up tcp connection by using kcp protocol on-top of udp.by using udp2raw,you can use kcptun while udp is QoSed or blocked.
(kcptun, https://github.com/xtaci/kcptun)
@ -276,3 +273,9 @@ https://arxiv.org/abs/1103.0463
http://korz.cs.yale.edu/2009/tng/papers/pfldnet10.pdf
https://pdfs.semanticscholar.org/9e6f/e2306f4385b4eb5416d1fcab16e9361d6ba3.pdf
# wiki
Check wiki for more info:
https://github.com/wangyu-/udp2raw-tunnel/wiki

@ -16,7 +16,7 @@ u64_t get_current_time()
{
timespec tmp_time;
clock_gettime(CLOCK_MONOTONIC, &tmp_time);
return tmp_time.tv_sec*1000+tmp_time.tv_nsec/(1000*1000l);
return ((u64_t)tmp_time.tv_sec)*1000llu+((u64_t)tmp_time.tv_nsec)/(1000*1000llu);
}
u64_t pack_u64(u32_t a,u32_t b)
@ -593,7 +593,21 @@ int create_fifo(char * file)
return fifo_fd;
}
void ip_port_t::from_u64(u64_t u64)
{
ip=get_u64_h(u64);
port=get_u64_l(u64);
}
u64_t ip_port_t::to_u64()
{
return pack_u64(ip,port);
}
char * ip_port_t::to_s()
{
static char res[40];
sprintf(res,"%s:%d",my_ntoa(ip),port);
return res;
}

@ -71,7 +71,22 @@ typedef u64_t padding_t;
typedef u64_t anti_replay_seq_t;
const int max_data_len=1600;
struct ip_port_t
{
u32_t ip;
int port;
void from_u64(u64_t u64);
u64_t to_u64();
char * to_s();
};
typedef u64_t fd64_t;
const int max_data_len=1800;
const int buf_len=max_data_len+400;
u64_t get_current_time();

@ -7,6 +7,7 @@
#include "connection.h"
#include "encrypt.h"
#include "fd_manager.h"
int disable_anti_replay=0;//if anti_replay windows is diabled
@ -227,6 +228,10 @@ conv_manager_t::~conv_manager_t()
void conn_info_t::recover(const conn_info_t &conn_info)
{
raw_info=conn_info.raw_info;
raw_info.rst_received=0;
raw_info.disabled=0;
last_state_time=conn_info.last_state_time;
last_hb_recv_time=conn_info.last_hb_recv_time;
last_hb_sent_time=conn_info.last_hb_sent_time;
@ -237,6 +242,7 @@ conv_manager_t::~conv_manager_t()
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;
}
void conn_info_t::re_init()
@ -249,7 +255,7 @@ conv_manager_t::~conv_manager_t()
last_state_time=0;
oppsite_const_id=0;
timer_fd=0;
timer_fd64=0;
my_roller=0;
oppsite_roller=0;
@ -296,6 +302,7 @@ conv_manager_t::~conv_manager_t()
assert(oppsite_const_id==0);
}
}
assert(timer_fd64==0);
//if(oppsite_const_id!=0) //do this at conn_manager 's deconstuction function
//conn_manager.const_id_mp.erase(oppsite_const_id);
if(blob!=0)
@ -310,9 +317,9 @@ conv_manager_t::~conv_manager_t()
ready_num=0;
mp.reserve(10007);
clear_it=mp.begin();
timer_fd_mp.reserve(10007);
// timer_fd_mp.reserve(10007);
const_id_mp.reserve(10007);
udp_fd_mp.reserve(100007);
// udp_fd_mp.reserve(100007);
last_clear_time=0;
//current_ready_ip=0;
// current_ready_port=0;
@ -372,21 +379,33 @@ conv_manager_t::~conv_manager_t()
ready_num--;
assert(i32_t(ready_num)!=-1);
assert(erase_it->second!=0);
assert(erase_it->second->timer_fd !=0);
assert(erase_it->second->timer_fd64 !=0);
assert(fd_manager.exist(erase_it->second->timer_fd64));
assert(erase_it->second->oppsite_const_id!=0);
assert(const_id_mp.find(erase_it->second->oppsite_const_id)!=const_id_mp.end());
assert(timer_fd_mp.find(erase_it->second->timer_fd)!=timer_fd_mp.end());
//assert(timer_fd_mp.find(erase_it->second->timer_fd)!=timer_fd_mp.end());
const_id_mp.erase(erase_it->second->oppsite_const_id);
timer_fd_mp.erase(erase_it->second->timer_fd);
close(erase_it->second->timer_fd);// close will auto delte it from epoll
fd_manager.fd64_close(erase_it->second->timer_fd64);
erase_it->second->timer_fd64=0;
//timer_fd_mp.erase(erase_it->second->timer_fd);
//close(erase_it->second->timer_fd);// close will auto delte it from epoll
delete(erase_it->second);
mp.erase(erase_it->first);
}
else
{
assert(erase_it->second->blob==0);
assert(erase_it->second->timer_fd ==0);
assert(erase_it->second->timer_fd64 ==0);
assert(erase_it->second->oppsite_const_id==0);
delete(erase_it->second);
mp.erase(erase_it->first);
@ -628,7 +647,7 @@ int send_data_safer(conn_info_t &conn_info,const char* data,int len,u32_t conv_n
return 0;
}
int parse_safer(conn_info_t &conn_info,const char * input,int input_len,char &type,char* &data,int &len)//subfunction for recv_safer,allow overlap
int reserved_parse_safer(conn_info_t &conn_info,const char * input,int input_len,char &type,char* &data,int &len)//subfunction for recv_safer,allow overlap
{
static char recv_data_buf[buf_len];
@ -697,7 +716,17 @@ int parse_safer(conn_info_t &conn_info,const char * input,int input_len,char &ty
conn_info.oppsite_roller=roller;
conn_info.last_oppsite_roller_time=get_current_time();
}
conn_info.my_roller++;//increase on a successful recv
if(hb_mode==0)
conn_info.my_roller++;//increase on a successful recv
else if(hb_mode==1)
{
if(type=='h')
conn_info.my_roller++;
}
else
{
assert(0==1);
}
if(after_recv_raw0(conn_info.raw_info)!=0) return -1;
@ -714,15 +743,15 @@ int recv_safer(conn_info_t &conn_info,char &type,char* &data,int &len)///safer t
if(recv_raw0(conn_info.raw_info,recv_data,recv_len)!=0) return -1;
return parse_safer(conn_info,recv_data,recv_len,type,data,len);
return reserved_parse_safer(conn_info,recv_data,recv_len,type,data,len);
}
void server_clear_function(u64_t u64)//used in conv_manager in server mode.for server we have to use one udp fd for one conv(udp connection),
//so we have to close the fd when conv expires
{
int fd=int(u64);
int ret;
assert(fd!=0);
//int fd=int(u64);
// int ret;
//assert(fd!=0);
/*
epoll_event ev;
@ -735,14 +764,19 @@ void server_clear_function(u64_t u64)//used in conv_manager in server mode.for s
mylog(log_fatal,"fd:%d epoll delete failed!!!!\n",fd);
myexit(-1); //this shouldnt happen
}*/ //no need
ret= close(fd); //closed fd should be auto removed from epoll
/*ret= close(fd); //closed fd should be auto removed from epoll
if (ret!=0)
{
mylog(log_fatal,"close fd %d failed !!!!\n",fd);
myexit(-1); //this shouldnt happen
}
}*/
//mylog(log_fatal,"size:%d !!!!\n",conn_manager.udp_fd_mp.size());
assert(conn_manager.udp_fd_mp.find(fd)!=conn_manager.udp_fd_mp.end());
conn_manager.udp_fd_mp.erase(fd);
fd64_t fd64=u64;
assert(fd_manager.exist(fd64));
fd_manager.fd64_close(fd64);
//assert(conn_manager.udp_fd_mp.find(fd)!=conn_manager.udp_fd_mp.end());
//conn_manager.udp_fd_mp.erase(fd);
}

@ -85,7 +85,8 @@ struct conn_info_t //stores info for a raw connection.for client ,there is o
id_t oppsite_id;
int timer_fd;
fd64_t timer_fd64;
id_t oppsite_const_id;
blob_t *blob;
@ -94,6 +95,8 @@ struct conn_info_t //stores info for a raw connection.for client ,there is o
uint8_t oppsite_roller;
u64_t last_oppsite_roller_time;
// ip_port_t ip_port;
/*
const uint32_t &ip=raw_info.recv_info.src_ip;
const uint16_t &port=raw_info.recv_info.src_port;
@ -113,8 +116,8 @@ struct conn_manager_t //manager for connections. for client,we dont need conn_m
u32_t ready_num;
unordered_map<int,conn_info_t *> udp_fd_mp; //a bit dirty to used pointer,but can void unordered_map search
unordered_map<int,conn_info_t *> timer_fd_mp;//we can use pointer here since unordered_map.rehash() uses shallow copy
//unordered_map<int,conn_info_t *> udp_fd_mp; //a bit dirty to used pointer,but can void unordered_map search
//unordered_map<int,conn_info_t *> timer_fd_mp;//we can use pointer here since unordered_map.rehash() uses shallow copy
unordered_map<id_t,conn_info_t *> const_id_mp;
@ -151,12 +154,12 @@ void server_clear_function(u64_t u64);
int send_bare(raw_info_t &raw_info,const char* data,int len);//send function with encryption but no anti replay,this is used when client and server verifys each other
//you have to design the protocol carefully, so that you wont be affect by relay attack
int reserved_parse_bare(const char *input,int input_len,char* & data,int & len); // a sub function used in recv_bare
//int reserved_parse_bare(const char *input,int input_len,char* & data,int & len); // a sub function used in recv_bare
int recv_bare(raw_info_t &raw_info,char* & data,int & len);//recv function with encryption but no anti replay,this is used when client and server verifys each other
//you have to design the protocol carefully, so that you wont be affect by relay attack
int send_handshake(raw_info_t &raw_info,id_t id1,id_t id2,id_t id3);// a warp for send_bare for sending handshake(this is not tcp handshake) easily
int send_safer(conn_info_t &conn_info,char type,const char* data,int len); //safer transfer function with anti-replay,when mutually verification is done.
int send_data_safer(conn_info_t &conn_info,const char* data,int len,u32_t conv_num);//a wrap for send_safer for transfer data.
int parse_safer(conn_info_t &conn_info,const char * input,int input_len,char &type,char* &data,int &len);//subfunction for recv_safer,allow overlap
//int reserved_parse_safer(conn_info_t &conn_info,const char * input,int input_len,char &type,char* &data,int &len);//subfunction for recv_safer,allow overlap
int recv_safer(conn_info_t &conn_info,char &type,char* &data,int &len);///safer transfer function with anti-replay,when mutually verification is done.
#endif /* CONNECTION_H_ */

@ -1,25 +1,40 @@
Udp2raw-tunnel
![image2](/images/image2.PNG)
# Udp2raw-tunnel
![image2](/images/image0.PNG)
udp2raw tunnel通过raw socket给UDP包加上TCP或ICMP header进而绕过UDP屏蔽或QoS或在UDP不稳定的环境下提升稳定性。可以有效防止在使用kcptun或者finalspeed的情况下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
[udp2raw wiki](https://github.com/wangyu-/udp2raw-tunnel/wiki)
**提示:**
udp2raw不是加速器只是一个帮助你绕过UDP限制的工具。如果你需要UDP加速器请看UDPspeeder。
UDPspeeder的repo:
https://github.com/wangyu-/UDPspeeder
# 支持的平台
Linux主机有root权限。可以是PC、android手机/平板、openwrt路由器、树莓派。主机上最好安装了iptables命令(apt/yum很容易安装)。
在windows和mac上预装了udp2raw的虚拟机镜像已发布可以用Vmware或VirtualBox加载容量4.4mb已经配置好了自动获取网卡ip开机即用稳定性能很好。
udp2raw跑在虚拟机里其他应用照常跑在windows上确保虚拟机网卡工作在桥接模式Vmware player 75mb,VirtualBox 118mb,很容易安装)。
Release中提供了`amd64`、`x86`、`arm`、`mips_be`、`mips_le`的预编译binary.
##### 对于windows和mac用户
可以把udp2raw运行在虚拟机上(网络必须是桥接模式)。
另外可以参考:
https://github.com/wangyu-/udp2raw-tunnel/wiki/在windows-mac上运行udp2raw客户端带图形界面
##### 对于ios和游戏主机用户
可以把udp2raw运行在局域网的其他机器/虚拟机上。最好的办法是买个能刷OpenWrt/LEDE/梅林的路由器把udp2raw运行在路由器上。
# 功能特性
### 把udp流量伪装成tcp /icmp
@ -49,9 +64,9 @@ NAT 穿透 tcp icmp udp模式都支持nat穿透。
支持Openvz配合finalspeed使用可以在openvz上用tcp模式的finalspeed
支持Openwrt没有编译依赖容易编译到任何平台上。release中提供了ar71xx版本的binary
支持Openwrt没有编译依赖容易编译到任何平台上。
epoll纯异步高并发除了回收过期连接外所有操作的时间复杂度都跟连接数无关。回收过期连接的操做也是柔和进行的不会因为消耗太多cpu时间造成延迟抖动。
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
@ -68,11 +83,13 @@ https://github.com/wangyu-/udp2raw-tunnel/releases
```
在server端运行:
./udp2raw_amd64 -s -l0.0.0.0:4096 -r 127.0.0.1:7777 -a -k "passwd" --raw-mode faketcp
./udp2raw_amd64 -s -l0.0.0.0:4096 -r127.0.0.1:7777 -a -k "passwd" --raw-mode faketcp --cipher-mode xor
在client端运行:
./udp2raw_amd64 -c -l0.0.0.0:3333 -r44.55.66.77:4096 -a -k "passwd" --raw-mode faketcp
./udp2raw_amd64 -c -l0.0.0.0:3333 -r44.55.66.77:4096 -a -k "passwd" --raw-mode faketcp --cipher-mode xor
```
(以上例子需要用root账号运行。 用非root运行udp2raw需要一些额外的步骤具体方法请看 [这个](https://github.com/wangyu-/udp2raw-tunnel/wiki/run-udp2raw-as-non-root) 链接。用非root运行更安全)
###### Server端输出:
![](/images/output_server.PNG)
###### Client端输出:
@ -85,20 +102,20 @@ https://github.com/wangyu-/udp2raw-tunnel/releases
不论你用udp2raw来加速kcptun还是vpn,为了稳定使用,都需要设置合理的MTU在kcptun/vpn里设置而不是在udp2raw里建议把MTU设置成1200。client和server端都要设置。
### 提醒
`--cipher-mode xor`表示仅使用简单的XOR加密这样可以节省CPU占用以免CPU成为速度瓶颈。如果你需要更强的加密可以去掉此选项使用默认的AES加密。加密相关的选项见后文的`--cipher-mode`和`--auth-mode`。
如果要在anroid上运行请看[Android简明教程](/doc/android_guide.md)
如果要在梅林固件的路由器上使用,添加`--lower-level auto` `--keep-rule`
如果client和server无法连接或者连接经常断开请看一下`--seq-mode`的用法尝试不同的seq-mode。
udp2raw可以用非root账号运行这样更安全。具体方法见[#26](https://github.com/wangyu-/udp2raw-tunnel/issues/26)
# 进阶操作说明
### 命令选项
```
udp2raw-tunnel
git version:adbe7d110f build date:Sep 6 2017 05:37:45
git version:6e1df4b39f build date:Oct 24 2017 09:21:15
repository: https://github.com/wangyu-/udp2raw-tunnel
usage:
@ -121,7 +138,9 @@ client options:
other options:
--conf-file <string> read options from a configuration file instead of command line.
check example.conf in repo for format
--log-level <number> 0:never 1:fatal 2:error 3:warn
--fifo <string> use a fifo(named pipe) for sending commands to the running program,
check readme.md in repository for supported commands.
--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
@ -135,7 +154,7 @@ other options:
2:increase seq randomly, about every 3 packets,simply ack last seq
3:simulate an almost real seq/ack procedure(default)
4:similiar to 3,but do not consider TCP Option Window_Scale,
maybe useful when firewall doesnt support TCP Option
maybe useful when firewall doesnt support TCP Option
--lower-level <string> send packets at OSI level 2, format:'if_name#dest_mac_adress'
ie:'eth0#00:23:45:67:89:b9'.or try '--lower-level auto' to obtain
the parameter automatically,specify it manually if 'auto' failed
@ -151,7 +170,7 @@ other options:
用raw收发udp包也类似只是内核回复的是icmp unreachable。而用raw 收发icmp内核会自动回复icmp echo。都需要相应的iptables规则。
### `--cipher-mode``--auth-mode`
如果要最大的安全性建议用aes128cbc+md5。如果要运行再路由器上建议xor+simple。但是注意xor+simple只能骗过防火墙的包检测不能防止真正的攻击者。
如果要最大的安全性建议用aes128cbc+md5。如果要运行在路由器上建议用xor+simple可以节省CPU。但是注意xor+simple只能骗过防火墙的包检测不能防止真正的攻击者。
### `--seq-mode`
facktcp模式并没有模拟tcp的全部。所以理论上有办法把faketcp和真正的tcp流量区分开来虽然大部分ISP不太可能做这种程度的包检测。seq-mode可以改变一些seq ack的行为。如果遇到了连接问题可以尝试更改。在我这边的移动线路用3种模式都没问题。
@ -159,6 +178,11 @@ facktcp模式并没有模拟tcp的全部。所以理论上有办法把faketcp和
### `--keep-rule`
定期主动检查iptables如果udp2raw添加的iptables规则丢了就重新添加。在一些iptables可能会被其他程序清空的情况下(比如梅林固件和openwrt的路由器)格外有用。
### `--fifo`
指定一个fifo(named pipe)来向运行中的程序发送命令,例如`--fifo fifo.file`
在client端,可以用`echo reconnect >fifo.file`来强制client换端口重连上层不断线.对Server目前没有效果。
### `--lower-level`
大部分udp2raw不能连通的情况都是设置了不兼容的iptables造成的。--lower-level选项允许绕过本地iptables。在一些iptables不好改动的情况下尤其有效比如你用的是梅林固件iptables全是固件自己生成的
@ -270,3 +294,9 @@ Transparently tunnel your IP traffic through ICMP echo and reply packets.
https://github.com/DhavalKapil/icmptunnel
# wiki
更多内容请看 wiki:
https://github.com/wangyu-/udp2raw-tunnel/wiki

@ -1,8 +1,10 @@
# udp2raw build guide
the guide on how to build udp2raw to you own platform
the guide on how to build udp2raw
## linux platform which supports local compile
## Build udp2raw for a specific platform
### linux platform which supports local compile
such as PC,raspberry pi
##### install git
@ -36,7 +38,7 @@ sudo yum groupinstall 'Development Tools'
run 'make'compilation done. the udp2raw file is the just compiled binary
## platform which needs cross-compile
### platform which needs cross-compile
such as openwrt router,run following instructions on your PC
##### install git
@ -74,3 +76,17 @@ cc_cross=/home/wangyu/Desktop/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uC
run `make cross`the just generated `udp2raw_cross` is the binary,compile done. copy it to your router to run.
`make cross` generates non-static binary. If you have any problem on running it,try to compile a static binary by using `make cross2` or `make cross3`.If your toolchain supports static compiling, usually one of them will succeed. The generated file is still named `udp2raw_cross`.
## Build a full release (include all binaries supported in the makefile)
1. make sure your linux is amd64 version
2. clone the repo
3. make sure you have g++ , make sure your g++ support the `-m32` option; make your your have installed libraries for `-m32` option
4. download https://github.com/wangyu-/files/releases/download/files/toolchains.tar.gz , and extract it to the right position (according to the makefile)
5. run `make release` inside udp2raw's directory

@ -6,7 +6,9 @@
### 环境要求
两边的主机都是linux有root权限。 可以是openwrt路由器或树莓派也可以是root了的android。
(windows和mac可以用release里发布的预装了udp2raw的openwrt_x86虚拟机镜像容量4.4mb,开机即用)
在windows/mac上运行udp2raw可以参考这个教程
https://github.com/wangyu-/udp2raw-tunnel/wiki/在windows-mac上运行udp2raw客户端带图形界面
### 安装

@ -17,23 +17,13 @@ static int8_t zero_iv[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0};//this prog
****/
char key[16];//generated from key_string by md5.
/*
TODO
Change md5 to HMAC-md5 if necessary.Change padding to PKCS#7 style if necessary.
Need someone with cryptography knowledge to help review the encryption method.
Change them if necessary(I can do this by myself,if it turns out to be necessary).
github issue:
https://github.com/wangyu-/udp2raw-tunnel/issues/17
*/
//TODO key derive function
unordered_map<int, const char *> auth_mode_tostring = {{auth_none, "none"}, {auth_md5, "md5"}, {auth_crc32, "crc32"},{auth_simple,"simple"}};
//TODO HMAC-md5 ,HMAC-sha1
unordered_map<int, const char *> cipher_mode_tostring={{cipher_none,"none"},{cipher_aes128cbc,"aes128cbc"},{cipher_xor,"xor"}};
//TODO aes-gcm
auth_mode_t auth_mode=auth_md5;
cipher_mode_t cipher_mode=cipher_aes128cbc;
@ -356,13 +346,28 @@ int my_decrypt(const char *data,char *output,int &len,char * key)
return 0;
}
int my_encrypt_pesudo_header(uint8_t *data,uint8_t *output,int &len,uint8_t * key,uint8_t *header,int hlen)
int encrypt_AE(const char *data,char *output,int &len,char * key)
{
return 0;
}
int my_decrypt_pesudo_header(uint8_t *data,uint8_t *output,int &len,uint8_t * key,uint8_t *header,int hlen)
{
return 0;
//TODO
//use encrypt-then-MAC scheme
return -1;
}
int decrypt_AE(const char *data,char *output,int &len,char * key)
{
//TODO
return -1;
}
int encrypt_AEAD(uint8_t *data,uint8_t *output,int &len,uint8_t * key,uint8_t *header,int hlen)
{
//TODO
return -1;
}
int decrypt_AEAD(uint8_t *data,uint8_t *output,int &len,uint8_t * key,uint8_t *header,int hlen)
{
//TODO
return -1;
}

@ -17,9 +17,6 @@ extern char key[16];
int my_encrypt(const char *data,char *output,int &len,char * key);
int my_decrypt(const char *data,char *output,int &len,char * key);
int my_encrypt_pesudo_header(uint8_t *data,uint8_t *output,int &len,uint8_t * key,uint8_t *header,int hlen);
int my_decrypt_pesudo_header(uint8_t *data,uint8_t *output,int &len,uint8_t * key,uint8_t *header,int hlen);
unsigned short csum(const unsigned short *ptr,int nbytes) ;

63
fd_manager.cpp Normal file

@ -0,0 +1,63 @@
/*
* fd_manager.cpp
*
* Created on: Sep 25, 2017
* Author: root
*/
#include "fd_manager.h"
int fd_manager_t::fd_exist(int fd)
{
return fd_to_fd64_mp.find(fd)!=fd_to_fd64_mp.end();
}
int fd_manager_t::exist(fd64_t fd64)
{
return fd64_to_fd_mp.find(fd64)!=fd64_to_fd_mp.end();
}
int fd_manager_t::to_fd(fd64_t fd64)
{
assert(exist(fd64));
return fd64_to_fd_mp[fd64];
}
void fd_manager_t::fd64_close(fd64_t fd64)
{
assert(exist(fd64));
int fd=fd64_to_fd_mp[fd64];
fd64_to_fd_mp.erase(fd64);
fd_to_fd64_mp.erase(fd);
if(exist_info(fd64))
{
fd_info_mp.erase(fd64);
}
assert(close(fd)==0);
}
void fd_manager_t::reserve(int n)
{
fd_to_fd64_mp.reserve(n);
fd64_to_fd_mp.reserve(n);
fd_info_mp.reserve(n);
}
u64_t fd_manager_t::create(int fd)
{
assert(!fd_exist(fd));
fd64_t fd64=counter++;
fd_to_fd64_mp[fd]=fd64;
fd64_to_fd_mp[fd64]=fd;
return fd64;
}
fd_manager_t::fd_manager_t()
{
counter=u32_t(-1);
counter+=100;
reserve(10007);
}
fd_info_t & fd_manager_t::get_info(fd64_t fd64)
{
assert(exist(fd64));
return fd_info_mp[fd64];
}
int fd_manager_t::exist_info(fd64_t fd64)
{
return fd_info_mp.find(fd64)!=fd_info_mp.end();
}

43
fd_manager.h Normal file

@ -0,0 +1,43 @@
/*
* fd_manager.h
*
* Created on: Sep 25, 2017
* Author: root
*/
#ifndef FD_MANAGER_H_
#define FD_MANAGER_H_
#include "common.h"
//#include "packet.h"
#include "connection.h"
struct fd_info_t
{
//ip_port_t ip_port;
conn_info_t *p_conn_info;
};
struct fd_manager_t //conver fd to a uniq 64bit number,avoid fd value conflict caused by close and re-create
//this class is not strictly necessary,it just makes epoll fd handling easier
{
fd_info_t & get_info(fd64_t fd64);
int exist_info(fd64_t);
int exist(fd64_t fd64);
int to_fd(fd64_t);
void fd64_close(fd64_t fd64);
void reserve(int n);
u64_t create(int fd);
fd_manager_t();
private:
u64_t counter;
unordered_map<int,fd64_t> fd_to_fd64_mp;
unordered_map<fd64_t,int> fd64_to_fd_mp;
unordered_map<fd64_t,fd_info_t> fd_info_mp;
int fd_exist(int fd);
//void remove_fd(int fd);
//fd64_t fd_to_fd64(int fd);
};
extern fd_manager_t fd_manager;
#endif /* FD_MANAGER_H_ */

BIN
images/udp2rawopenvpn.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

1
images/wiki/111 Normal file

@ -0,0 +1 @@

BIN
images/wiki/mac_nat_vb1.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
images/wiki/mac_nat_vb2.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
images/wiki/mac_nat_vb3.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
images/wiki/mac_nat_vb4.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
images/wiki/windows_nat.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

295
main.cpp

@ -5,13 +5,18 @@
#include "log.h"
#include "lib/md5.h"
#include "encrypt.h"
#include "fd_manager.h"
int mtu_warn=1375;//if a packet larger than mtu warn is receviced,there will be a warning
char hb_buf[buf_len];
int on_epoll_recv_event=0; //TODO, just a flag to help detect epoll infinite shoot
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 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 client_on_timer(conn_info_t &conn_info) //for client. called when a timer is ready in epoll
{
//keep_iptables_rule();
@ -25,11 +30,19 @@ int client_on_timer(conn_info_t &conn_info) //for client. called when a timer is
mylog(log_trace,"<client_on_timer,send_info.ts_ack= %u>\n",send_info.ts_ack);
if(raw_info.disabled)
{
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\n");
}
if(conn_info.state.client_current_state==client_idle)
{
raw_info.rst_received=0;
raw_info.disabled=0;
fail_time_counter++;
if(max_fail_time>0&&fail_time_counter>max_fail_time)
{
@ -51,6 +64,8 @@ int client_on_timer(conn_info_t &conn_info) //for client. called when a timer is
conn_info.blob->anti_replay.re_init();
conn_info.my_id = get_true_random_number_nz(); ///todo no need to do this everytime
u32_t new_ip=0;
if(!force_source_ip&&get_src_adress(new_ip,remote_ip_uint32,remote_port)==0)
{
@ -237,11 +252,6 @@ int client_on_timer(conn_info_t &conn_info) //for client. called when a timer is
return 0;
}
if(get_current_time()-conn_info.last_hb_sent_time<heartbeat_interval)
{
return 0;
}
if(get_current_time()- conn_info.last_oppsite_roller_time>client_conn_uplink_timeout)
{
conn_info.state.client_current_state=client_idle;
@ -249,10 +259,20 @@ int client_on_timer(conn_info_t &conn_info) //for client. called when a timer is
mylog(log_info,"state back to client_idle from client_ready bc of client-->server direction timeout\n");
}
if(get_current_time()-conn_info.last_hb_sent_time<heartbeat_interval)
{
return 0;
}
mylog(log_debug,"heartbeat sent <%x,%x>\n",conn_info.oppsite_id,conn_info.my_id);
send_safer(conn_info,'h',"",0);/////////////send
if(hb_mode==0)
send_safer(conn_info,'h',hb_buf,0);/////////////send
else
send_safer(conn_info,'h',hb_buf,hb_len);
conn_info.last_hb_sent_time=get_current_time();
return 0;
}
@ -294,8 +314,10 @@ int server_on_timer_multi(conn_info_t &conn_info,char * ip_port) //for server.
return 0;
}
send_safer(conn_info,'h',"",0); /////////////send
if(hb_mode==0)
send_safer(conn_info,'h',hb_buf,0); /////////////send
else
send_safer(conn_info,'h',hb_buf,hb_len);
conn_info.last_hb_sent_time=get_current_time();
mylog(log_debug,"heart beat sent<%x,%x>\n",conn_info.my_id,conn_info.oppsite_id);
@ -441,9 +463,9 @@ int client_on_raw_recv(conn_info_t &conn_info) //called when raw fd received a p
conn_info.last_oppsite_roller_time=conn_info.last_hb_recv_time;
client_on_timer(conn_info);
}
if(data_len==0&&type=='h')
if(data_len>=0&&type=='h')
{
mylog(log_debug,"[hb]heart beat received\n");
mylog(log_debug,"[hb]heart beat received,oppsite_roller=%d\n",int(conn_info.oppsite_roller));
conn_info.last_hb_recv_time=get_current_time();
return 0;
}
@ -451,7 +473,8 @@ int client_on_raw_recv(conn_info_t &conn_info) //called when raw fd received a p
{
mylog(log_trace,"received a data from fake tcp,len:%d\n",data_len);
conn_info.last_hb_recv_time=get_current_time();
if(hb_mode==0)
conn_info.last_hb_recv_time=get_current_time();
//u32_t tmp_conv_id= ntohl(* ((u32_t *)&data[0]));
u32_t tmp_conv_id;
@ -612,10 +635,15 @@ int server_on_raw_recv_multi() //called when server received an raw packet
conn_info_t &conn_info=conn_manager.find_insert(ip,port);
conn_info.raw_info=tmp_raw_info;
raw_info_t &raw_info=conn_info.raw_info;
packet_info_t &send_info=conn_info.raw_info.send_info;
packet_info_t &recv_info=conn_info.raw_info.recv_info;
raw_info_t &raw_info=conn_info.raw_info;
//conn_info.ip_port.ip=ip;
//conn_info.ip_port.port=port;
send_info.src_ip=recv_info.dst_ip;
send_info.src_port=recv_info.dst_port;
@ -644,6 +672,8 @@ int server_on_raw_recv_multi() //called when server received an raw packet
}
conn_info_t & conn_info=conn_manager.find_insert(ip,port);//insert if not exist
packet_info_t &send_info=conn_info.raw_info.send_info;
packet_info_t &recv_info=conn_info.raw_info.recv_info;
@ -782,7 +812,7 @@ int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char type,cha
return 0;
}*/
if (type == 'h' && data_len == 0) {
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();
@ -796,7 +826,8 @@ int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char type,cha
tmp_conv_id=ntohl(tmp_conv_id);
conn_info.last_hb_recv_time = get_current_time();
if(hb_mode==0)
conn_info.last_hb_recv_time = get_current_time();
mylog(log_trace, "conv:%u\n", tmp_conv_id);
if (!conn_info.blob->conv_manager.is_conv_used(tmp_conv_id)) {
@ -843,11 +874,13 @@ int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char type,cha
}
struct epoll_event ev;
u64_t u64 = (u32_t(new_udp_fd))+(1llu<<32u);
mylog(log_trace, "[%s]u64: %lld\n",ip_port, u64);
fd64_t new_udp_fd64 = fd_manager.create(new_udp_fd);
fd_manager.get_info(new_udp_fd64).p_conn_info=&conn_info;
mylog(log_trace, "[%s]u64: %lld\n",ip_port, new_udp_fd64);
ev.events = EPOLLIN;
ev.data.u64 = u64;
ev.data.u64 = new_udp_fd64;
ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, new_udp_fd, &ev);
@ -857,10 +890,13 @@ int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char type,cha
return -1;
}
conn_info.blob->conv_manager.insert_conv(tmp_conv_id, new_udp_fd);
assert(conn_manager.udp_fd_mp.find(new_udp_fd)==conn_manager.udp_fd_mp.end());
conn_info.blob->conv_manager.insert_conv(tmp_conv_id, new_udp_fd64);
conn_manager.udp_fd_mp[new_udp_fd] = &conn_info;
//assert(conn_manager.udp_fd_mp.find(new_udp_fd)==conn_manager.udp_fd_mp.end());
//conn_manager.udp_fd_mp[new_udp_fd] = &conn_info;
//pack_u64(conn_info.raw_info.recv_info.src_ip,conn_info.raw_info.recv_info.src_port);
@ -871,11 +907,11 @@ int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char type,cha
}
u64_t u64 = conn_info.blob->conv_manager.find_u64_by_conv(tmp_conv_id);
fd64_t fd64 = conn_info.blob->conv_manager.find_u64_by_conv(tmp_conv_id);
conn_info.blob->conv_manager.update_active_time(tmp_conv_id);
int fd = int((u64 << 32u) >> 32u);
int fd = fd_manager.to_fd(fd64);
mylog(log_trace, "[%s]received a data from fake tcp,len:%d\n",ip_port, data_len);
int ret = send(fd, data + sizeof(u32_t),
@ -928,21 +964,25 @@ int server_on_raw_recv_pre_ready(conn_info_t &conn_info,char * ip_port,u32_t tmp
//my_id=conn_info.my_id;
//oppsite_id=conn_info.oppsite_id;
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, 'h',"", 0); /////////////send
if(hb_mode==0)
send_safer(conn_info,'h',hb_buf,0);/////////////send
else
send_safer(conn_info,'h',hb_buf,hb_len);
mylog(log_info, "[%s]changed state to server_ready\n",ip_port);
conn_info.blob->anti_replay.re_init();
//g_conn_info=conn_info;
int new_timer_fd;
set_timer_server(epollfd, new_timer_fd);
conn_info.timer_fd=new_timer_fd;
assert(conn_manager.timer_fd_mp.find(new_timer_fd)==conn_manager.timer_fd_mp.end());
conn_manager.timer_fd_mp[new_timer_fd] = &conn_info;//pack_u64(ip,port);
set_timer_server(epollfd, new_timer_fd,conn_info.timer_fd64);
fd_manager.get_info(conn_info.timer_fd64).p_conn_info=&conn_info;
//assert(conn_manager.timer_fd_mp.find(new_timer_fd)==conn_manager.timer_fd_mp.end());
//conn_manager.timer_fd_mp[new_timer_fd] = &conn_info;//pack_u64(ip,port);
//timer_fd_mp[new_timer_fd]
@ -991,8 +1031,14 @@ 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, 'h',"", 0);
//send_safer(ori_conn_info, 'h',hb_buf, hb_len);
//ori_conn_info.blob->anti_replay.re_init();
if(hb_mode==0)
send_safer(ori_conn_info,'h',hb_buf,0);/////////////send
else
send_safer(ori_conn_info,'h',hb_buf,hb_len);
ori_conn_info.last_hb_recv_time=get_current_time();
@ -1043,10 +1089,36 @@ int client_event_loop()
u32_t dest_ip;
string if_name_string;
string hw_string;
if(find_lower_level_info(remote_ip_uint32,dest_ip,if_name_string,hw_string)!=0)
if(retry_on_error==0)
{
<<<<<<< HEAD
mylog(log_fatal,"auto detect lower-level info failed for %s,specific it manually\n",remote_host);
myexit(-1);
=======
if(find_lower_level_info(remote_ip_uint32,dest_ip,if_name_string,hw_string)!=0)
{
mylog(log_fatal,"auto detect lower-level info failed for %s,specific it manually\n",remote_ip);
myexit(-1);
}
}
else
{
int ok=0;
while(!ok)
{
if(find_lower_level_info(remote_ip_uint32,dest_ip,if_name_string,hw_string)!=0)
{
mylog(log_warn,"auto detect lower-level info failed for %s,retry in %d seconds\n",remote_ip,retry_on_error_interval);
sleep(retry_on_error_interval);
}
else
{
ok=1;
}
}
>>>>>>> upstream/master
}
mylog(log_info,"we are running at lower-level (auto) mode,%s %s %s\n",my_ntoa(dest_ip),if_name_string.c_str(),hw_string.c_str());
@ -1080,11 +1152,32 @@ int client_event_loop()
if(source_ip_uint32==0)
{
mylog(log_info,"get_src_adress called\n");
if(get_src_adress(source_ip_uint32,remote_ip_uint32,remote_port)!=0)
if(retry_on_error==0)
{
mylog(log_fatal,"the trick to auto get source ip failed,you should specific an ip by --source-ip\n");
myexit(-1);
if(get_src_adress(source_ip_uint32,remote_ip_uint32,remote_port)!=0)
{
mylog(log_fatal,"the trick to auto get source ip failed, maybe you dont have internet access\n");
myexit(-1);
}
}
else
{
int ok=0;
while(!ok)
{
if(get_src_adress(source_ip_uint32,remote_ip_uint32,remote_port)!=0)
{
mylog(log_warn,"the trick to auto get source ip failed, maybe you dont have internet access, retry in %d seconds\n",retry_on_error_interval);
sleep(retry_on_error_interval);
}
else
{
ok=1;
}
}
}
}
in_addr tmp;
tmp.s_addr=source_ip_uint32;
@ -1190,13 +1283,13 @@ int client_event_loop()
if (nfds < 0) { //allow zero
if(errno==EINTR )
{
mylog(log_info,"epoll interrupted by signal\n");
mylog(log_info,"epoll interrupted by signal,continue\n");
//close(fifo_fd);
myexit(0);
//myexit(0);
}
else
{
mylog(log_fatal,"epoll_wait return %d\n", nfds);
mylog(log_fatal,"epoll_wait return %d,%s\n", nfds,strerror(errno));
myexit(-1);
}
}
@ -1218,7 +1311,12 @@ int client_event_loop()
else if (events[idx].data.u64 == (u64_t)fifo_fd)
{
int len=read (fifo_fd, buf, sizeof (buf));
assert(len>=0);
//assert(len>=0);
if(len<0)
{
mylog(log_warn,"fifo read failed len=%d,errno=%s\n",len,strerror(errno));
continue;
}
buf[len]=0;
while(len>=1&&buf[len-1]=='\n')
buf[len-1]=0;
@ -1241,12 +1339,18 @@ int client_event_loop()
int recv_len;
struct sockaddr_in udp_new_addr_in={0};
socklen_t udp_new_addr_len = sizeof(sockaddr_in);
if ((recv_len = recvfrom(udp_fd, buf, max_data_len, 0,
if ((recv_len = recvfrom(udp_fd, buf, max_data_len+1, 0,
(struct sockaddr *) &udp_new_addr_in, &udp_new_addr_len)) == -1) {
mylog(log_error,"recv_from error,this shouldnt happen at client\n");
myexit(1);
};
if(recv_len==max_data_len+1)
{
mylog(log_warn,"huge packet, data_len > %d,dropped\n",max_data_len);
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);
@ -1420,6 +1524,8 @@ int server_event_loop()
}
mylog(log_info,"fifo_file=%s\n",fifo_file);
}
while(1)////////////////////////
{
@ -1429,12 +1535,12 @@ int server_event_loop()
if (nfds < 0) { //allow zero
if(errno==EINTR )
{
mylog(log_info,"epoll interrupted by signal\n");
myexit(0);
mylog(log_info,"epoll interrupted by signal,continue\n");
//myexit(0);
}
else
{
mylog(log_fatal,"epoll_wait return %d\n", nfds);
mylog(log_fatal,"epoll_wait return %d,%s\n", nfds,strerror(errno));
myexit(-1);
}
}
@ -1474,29 +1580,58 @@ int server_event_loop()
else if (events[idx].data.u64 == (u64_t)fifo_fd)
{
int len=read (fifo_fd, buf, sizeof (buf));
assert(len>=0);
if(len<0)
{
mylog(log_warn,"fifo read failed len=%d,errno=%s\n",len,strerror(errno));
continue;
}
//assert(len>=0);
buf[len]=0;
while(len>=1&&buf[len-1]=='\n')
buf[len-1]=0;
mylog(log_info,"got data from fifo,len=%d,s=[%s]\n",len,buf);
mylog(log_info,"unknown command\n");
}
else if ((events[idx].data.u64 >>32u) == 2u)
else if (events[idx].data.u64>u32_t(-1) )
{
fd64_t fd64=events[idx].data.u64;
if(!fd_manager.exist(fd64))
{
mylog(log_trace ,"fd64 no longer exist\n");
continue;
}
assert(fd_manager.exist_info(fd64));
conn_info_t* p_conn_info=fd_manager.get_info(fd64).p_conn_info;
u32_t ip=p_conn_info->raw_info.send_info.dst_ip;
u32_t port=p_conn_info->raw_info.send_info.dst_port;
//assert(conn_manager.exist(ip,port));
///conn_info_t* p_conn_info=conn_manager.find_insert_p(ip,port);
if(fd64==p_conn_info->timer_fd64)//////////timer_fd64
{
if(debug_flag)begin_time=get_current_time();
int fd=get_u64_l(events[idx].data.u64);
//int fd=get_u64_l(events[idx].data.u64);
int fd=fd_manager.to_fd(fd64);
u64_t dummy;
read(fd, &dummy, 8);
if(conn_manager.timer_fd_mp.find(fd)==conn_manager.timer_fd_mp.end()) //this can happen,when fd is a just closed fd
/*if(conn_manager.timer_fd_mp.find(fd)==conn_manager.timer_fd_mp.end()) //this can happen,when fd is a just closed fd
{
mylog(log_info,"timer_fd no longer exits\n");
continue;
}
conn_info_t* p_conn_info=conn_manager.timer_fd_mp[fd];
u32_t ip=p_conn_info->raw_info.recv_info.src_ip;
u32_t port=p_conn_info->raw_info.recv_info.src_port;
assert(conn_manager.exist(ip,port));//TODO remove this for peformance
}*/
//conn_info_t* p_conn_info=conn_manager.timer_fd_mp[fd];
//u32_t ip=p_conn_info->raw_info.recv_info.src_ip;
//u32_t port=p_conn_info->raw_info.recv_info.src_port;
//assert(conn_manager.exist(ip,port));//TODO remove this for peformance
assert(p_conn_info->state.server_current_state == server_ready); //TODO remove this for peformance
@ -1512,30 +1647,36 @@ int server_event_loop()
end_time=get_current_time();
mylog(log_debug,"(events[idx].data.u64 >>32u) == 2u ,%llu,%llu,%llu \n",begin_time,end_time,end_time-begin_time);
}
}
else if ((events[idx].data.u64 >>32u) == 1u)
{
}
else//udp_fd64
{
//}
//else if ((events[idx].data.u64 >>32u) == 1u)
//{
//uint32_t conv_id=events[n].data.u64>>32u;
if(debug_flag)begin_time=get_current_time();
int fd=int((events[idx].data.u64<<32u)>>32u);
//int fd=int((events[idx].data.u64<<32u)>>32u);
/*
if(conn_manager.udp_fd_mp.find(fd)==conn_manager.udp_fd_mp.end()) //this can happen,when fd is a just closed fd
{
mylog(log_debug,"fd no longer exists in udp_fd_mp,udp fd %d\n",fd);
recv(fd,0,0,0);
continue;
}
conn_info_t* p_conn_info=conn_manager.udp_fd_mp[fd];
}*/
//conn_info_t* p_conn_info=conn_manager.udp_fd_mp[fd];
u32_t ip=p_conn_info->raw_info.recv_info.src_ip;
u32_t port=p_conn_info->raw_info.recv_info.src_port;
if(!conn_manager.exist(ip,port))//TODO remove this for peformance
//u32_t ip=p_conn_info->raw_info.recv_info.src_ip;
//u32_t port=p_conn_info->raw_info.recv_info.src_port;
/*if(!conn_manager.exist(ip,port))//TODO remove this for peformance
{
mylog(log_fatal,"ip port no longer exits 2!!!this shouldnt happen\n");
myexit(-1);
}
}*/
if(p_conn_info->state.server_current_state!=server_ready)//TODO remove this for peformance
{
@ -1545,19 +1686,22 @@ int server_event_loop()
conn_info_t &conn_info=*p_conn_info;
if(!conn_info.blob->conv_manager.is_u64_used(fd))
{
mylog(log_debug,"conv no longer exists,udp fd %d\n",fd);
int recv_len=recv(fd,0,0,0); ///////////TODO ,delete this
continue;
}
assert(conn_info.blob->conv_manager.is_u64_used(fd64));
u32_t conv_id=conn_info.blob->conv_manager.find_conv_by_u64(fd);
u32_t conv_id=conn_info.blob->conv_manager.find_conv_by_u64(fd64);
int recv_len=recv(fd,buf,max_data_len,0);
int fd=fd_manager.to_fd(fd64);
int recv_len=recv(fd,buf,max_data_len+1,0);
mylog(log_trace,"received a packet from udp_fd,len:%d\n",recv_len);
if(recv_len==max_data_len+1)
{
mylog(log_warn,"huge packet, data_len > %d,dropped\n",max_data_len);
continue;
}
if(recv_len<0)
{
mylog(log_debug,"udp fd,recv_len<0 continue,%s\n",strerror(errno));
@ -1584,6 +1728,9 @@ int server_event_loop()
end_time=get_current_time();
mylog(log_debug,"(events[idx].data.u64 >>32u) == 1u,%lld,%lld,%lld \n",begin_time,end_time,end_time-begin_time);
}
}
}
else
{
@ -1630,7 +1777,11 @@ int main(int argc, char *argv[])
if(geteuid() != 0)
{
mylog(log_error,"root check failed,make sure you run this program with root,we can try to continue,but it will likely fail\n");
mylog(log_warn,"root check failed, it seems like you are using a non-root account. we can try to continue, but it may fail. If you want to run udp2raw as non-root, you have to add iptables rule manually, and grant udp2raw CAP_NET_RAW capability, check README.md in repo for more info.\n");
}
else
{
mylog(log_warn,"you can run udp2raw with non-root account for better security. check README.md in repo for more info.\n");
}

@ -1,21 +1,23 @@
cc_cross=/home/wangyu/Desktop/arm-2014.05/bin/arm-none-linux-gnueabi-g++
cc_local=g++
#cc_local=/opt/cross/x86_64-linux-musl/bin/x86_64-linux-musl-g++
#cc_mips34kc=/toolchains/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-g++
cc_mips24kc_be=/toolchains/lede-sdk-17.01.2-ar71xx-generic_gcc-5.4.0_musl-1.1.16.Linux-x86_64/staging_dir/toolchain-mips_24kc_gcc-5.4.0_musl-1.1.16/bin/mips-openwrt-linux-musl-g++
cc_mips24kc_le=/toolchains/lede-sdk-17.01.2-ramips-mt7621_gcc-5.4.0_musl-1.1.16.Linux-x86_64/staging_dir/toolchain-mipsel_24kc_gcc-5.4.0_musl-1.1.16/bin/mipsel-openwrt-linux-musl-g++
#cc_arm= /toolchains/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-g++ -march=armv6 -marm
cc_arm= /toolchains/arm-2014.05/bin/arm-none-linux-gnueabi-g++
#cc_arm=/toolchains/lede-sdk-17.01.2-brcm2708-bcm2708_gcc-5.4.0_musl-1.1.16_eabi.Linux-x86_64/staging_dir/toolchain-arm_arm1176jzf-s+vfp_gcc-5.4.0_musl-1.1.16_eabi/bin/arm-openwrt-linux-muslgnueabi-g++
#cc_bcm2708=/home/wangyu/raspberry/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-g++
FLAGS= -std=c++11 -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers
COMMON=main.cpp lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp connection.cpp misc.cpp -lpthread
COMMON=main.cpp lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp connection.cpp misc.cpp fd_manager.cpp -lpthread
SOURCES= $(COMMON) lib/aes_faster_c/aes.c lib/aes_faster_c/wrapper.c
SOURCES_TINY_AES= $(COMMON) lib/aes.c
SOURCES_AES_ACC=$(COMMON) $(wildcard lib/aes_acc/aes*.c)
NAME=udp2raw
TARGETS=amd64 arm amd64_hw_aes arm_asm_aes mips24kc_be mips24kc_be_asm_aes x86 x86_asm_aes mips24kc_le mips24kc_le_asm_aes
TAR=${NAME}_binaries.tar.gz `echo ${TARGETS}|sed -r 's/([^ ]+)/udp2raw_\1/g'`
TAR=${NAME}_binaries.tar.gz `echo ${TARGETS}|sed -r 's/([^ ]+)/udp2raw_\1/g'` version.txt
all:git_version
rm -f ${NAME}
@ -47,6 +49,10 @@ mips24kc_le_asm_aes: git_version
# ${cc_bcm2708} -o ${NAME}_bcm2708 -I. ${SOURCES} ${FLAGS} -lrt -static -O3
amd64:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3
amd64_perf:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O0 -fno-omit-frame-pointer -g
amd64_hw_aes:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -static -O3 lib/aes_acc/asm/x64.S
x86:git_version
@ -56,6 +62,9 @@ x86_asm_aes:git_version
arm:git_version
${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3
arm_perf:git_version
${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -mapcs-frame -fno-omit-frame-pointer -g -O0 -lgcc_eh
arm_asm_aes:git_version
${cc_arm} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -static -O3 lib/aes_acc/asm/arm.S
@ -69,6 +78,7 @@ cross3:git_version
${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -static -O3
release: ${TARGETS}
cp git_version.h version.txt
tar -zcvf ${TAR}
clean:

171
misc.cpp

@ -10,8 +10,21 @@
#include "misc.h"
#include "network.h"
#include "connection.h"
#include "fd_manager.h"
int hb_mode=1;
int hb_len=1200;
int mtu_warn=1375;//if a packet larger than mtu warn is receviced,there will be a warning
int max_rst_to_show=15;
int max_rst_allowed=-1;
fd_manager_t fd_manager;
char local_ip[100]="0.0.0.0", remote_host[100]="255.255.255.255",source_ip[100]="0.0.0.0";//local_ip is for -l option,remote_host for -r option,source for --source-ip
u32_t local_ip_uint32,remote_ip_uint32,source_ip_uint32;//convert from last line.
int local_port = -1, remote_port=-1,source_port=0;//similiar to local_ip remote_host,buf for port.source_port=0 indicates --source-port is not enabled
@ -35,12 +48,18 @@ int auto_add_iptables_rule=0;//if -a is set
int generate_iptables_rule=0;//if -g is set
int generate_iptables_rule_add=0;// if --gen-add is set
int retry_on_error=0;
int debug_resend=0; // debug only
char key_string[1000]= "secret key";// -k option
char fifo_file[1000]="";
int clear_iptables=0;
int wait_xtables_lock=0;
string iptables_command0="iptables ";
string iptables_command="";
string iptables_pattern="";
int iptables_rule_added=0;
int iptables_rule_keeped=0;
@ -144,9 +163,13 @@ void print_help()
printf(" --lower-level <string> send packets at OSI level 2, format:'if_name#dest_mac_adress'\n");
printf(" ie:'eth0#00:23:45:67:89:b9'.or try '--lower-level auto' to obtain\n");
printf(" the parameter automatically,specify it manually if 'auto' failed\n");
printf(" --wait-lock wait for xtables lock while invoking iptables, need iptables v1.4.20+\n");
printf(" --gen-add generate iptables rule and add it permanently,then exit.overrides -g\n");
printf(" --keep-rule monitor iptables and auto re-add if necessary.implys -a\n");
printf(" --hb-len <number> length of heart-beat packet, >=0 and <=1500\n");
printf(" --mtu-warn <number> mtu warning threshold, unit:byte, default:1375\n");
printf(" --clear clear any iptables rules added by this program.overrides everything\n");
printf(" --retry-on-error retry on error, allow to start udp2raw before network is initialized\n");
printf(" -h,--help print this help message\n");
//printf("common options,these options must be same on both side\n");
@ -234,6 +257,7 @@ void process_arg(int argc, char *argv[]) //process all options
{"gen-rule", no_argument, 0, 'g'},
{"gen-add", no_argument, 0, 1},
{"debug", no_argument, 0, 1},
{"retry-on-error", no_argument, 0, 1},
{"clear", no_argument, 0, 1},
{"simple-rule", no_argument, 0, 1},
{"keep-rule", no_argument, 0, 1},
@ -242,8 +266,14 @@ void process_arg(int argc, char *argv[]) //process all options
{"seq-mode", required_argument, 0, 1},
{"conf-file", required_argument, 0, 1},
{"force-sock-buf", no_argument, 0, 1},
{"wait-lock", no_argument, 0, 1},
{"random-drop", required_argument, 0, 1},
{"fifo", required_argument, 0, 1},
{"hb-mode", required_argument, 0, 1},
{"hb-len", required_argument, 0, 1},
{"mtu-warn", required_argument, 0, 1},
{"max-rst-to-show", required_argument, 0, 1},
{"max-rst-allowed", required_argument, 0, 1},
{NULL, 0, 0, 0}
};
@ -412,15 +442,7 @@ void process_arg(int argc, char *argv[]) //process all options
mylog(log_debug,"option_index: %d\n",option_index);
if(strcmp(long_options[option_index].name,"clear")==0)
{
char *output;
//int ret =system("iptables-save |grep udp2raw_dWRwMnJhdw|sed -n 's/^-A/iptables -D/p'|sh");
int ret =run_command("iptables -S|sed -n '/udp2rawDwrW/p'|sed -n 's/^-A/iptables -D/p'|sh",output);
int ret2 =run_command("iptables -S|sed -n '/udp2rawDwrW/p'|sed -n 's/^-N/iptables -X/p'|sh",output);
//system("iptables-save |grep udp2raw_dWRwMnJhdw|sed 's/^-A/iptables -D/'|sh");
//system("iptables-save|grep -v udp2raw_dWRwMnJhdw|iptables-restore");
mylog(log_info,"tried to clear all iptables rule created previously,return value %d %d\n",ret,ret2);
myexit(-1);
clear_iptables=1;
}
else if(strcmp(long_options[option_index].name,"source-ip")==0)
{
@ -532,6 +554,14 @@ void process_arg(int argc, char *argv[]) //process all options
{
force_socket_buf=1;
}
else if(strcmp(long_options[option_index].name,"retry-on-error")==0)
{
retry_on_error=1;
}
else if(strcmp(long_options[option_index].name,"wait-lock")==0)
{
wait_xtables_lock=1;
}
else if(strcmp(long_options[option_index].name,"disable-bpf")==0)
{
disable_bpf_filter=1;
@ -586,7 +616,36 @@ void process_arg(int argc, char *argv[]) //process all options
{
mylog(log_info,"configuration loaded from %s\n",optarg);
}
else if(strcmp(long_options[option_index].name,"hb-mode")==0)
{
sscanf(optarg,"%d",&hb_mode);
assert(hb_mode==0||hb_mode==1);
mylog(log_info,"hb_mode =%d \n",hb_mode);
}
else if(strcmp(long_options[option_index].name,"hb-len")==0)
{
sscanf(optarg,"%d",&hb_len);
assert(hb_len>=0&&hb_len<=1500);
mylog(log_info,"hb_len =%d \n",hb_len);
}
else if(strcmp(long_options[option_index].name,"mtu-warn")==0)
{
sscanf(optarg,"%d",&mtu_warn);
assert(mtu_warn>0);
mylog(log_info,"mtu_warn=%d \n",mtu_warn);
}
else if(strcmp(long_options[option_index].name,"max-rst-to-show")==0)
{
sscanf(optarg,"%d",&max_rst_to_show);
assert(max_rst_to_show>=-1);
mylog(log_info,"max_rst_to_show=%d \n",max_rst_to_show);
}
else if(strcmp(long_options[option_index].name,"max-rst-allowed")==0)
{
sscanf(optarg,"%d",&max_rst_allowed);
assert(max_rst_allowed>=-1);
mylog(log_info,"max_rst_allowed=%d \n",max_rst_allowed);
}
else
{
mylog(log_warn,"ignored unknown long option ,option_index:%d code:<%x>\n",option_index, optopt);
@ -609,6 +668,7 @@ void process_arg(int argc, char *argv[]) //process all options
print_help();
myexit(-1);
}
//if(lower_level)
//process_lower_level_arg();
@ -737,8 +797,30 @@ void *run_keep(void *none) //called in a new thread for --keep-rule option
return NULL;
}
void iptables_rule() // handles -a -g --gen-add --keep-rule
void iptables_rule() // handles -a -g --gen-add --keep-rule --clear --wait-lock
{
if(!wait_xtables_lock)
{
iptables_command=iptables_command0;
}
else
{
iptables_command=iptables_command0+"-w ";
}
if(clear_iptables)
{
char *output;
//int ret =system("iptables-save |grep udp2raw_dWRwMnJhdw|sed -n 's/^-A/iptables -D/p'|sh");
int ret =run_command(iptables_command+"-S|sed -n '/udp2rawDwrW/p'|sed -n 's/^-A/"+iptables_command+"-D/p'|sh",output);
int ret2 =run_command(iptables_command+"-S|sed -n '/udp2rawDwrW/p'|sed -n 's/^-N/"+iptables_command+"-X/p'|sh",output);
//system("iptables-save |grep udp2raw_dWRwMnJhdw|sed 's/^-A/iptables -D/'|sh");
//system("iptables-save|grep -v udp2raw_dWRwMnJhdw|iptables-restore");
mylog(log_info,"tried to clear all iptables rule created previously,return value %d %d\n",ret,ret2);
myexit(-1);
}
if(auto_add_iptables_rule&&generate_iptables_rule)
{
mylog(log_warn," -g overrides -a\n");
@ -841,7 +923,7 @@ void iptables_rule() // handles -a -g --gen-add --keep-rule
}
if(generate_iptables_rule)
{
string rule="iptables -I INPUT ";
string rule=iptables_command+"-I INPUT ";
rule+=pattern;
rule+=" -j DROP";
@ -948,7 +1030,7 @@ int set_timer(int epollfd,int &timer_fd)//put a timer_fd into epoll,general func
}
int set_timer_server(int epollfd,int &timer_fd)//only for server
int set_timer_server(int epollfd,int &timer_fd,fd64_t &fd64)//only for server
{
int ret;
epoll_event ev;
@ -966,9 +1048,11 @@ int set_timer_server(int epollfd,int &timer_fd)//only for server
its.it_value.tv_nsec=1; //imidiately
timerfd_settime(timer_fd,0,&its,0);
fd64=fd_manager.create(timer_fd);
ev.events = EPOLLIN;
ev.data.u64 = pack_u64(2,timer_fd);////difference
ev.data.u64 = fd64;////difference
ret=epoll_ctl(epollfd, EPOLL_CTL_ADD, timer_fd, &ev);
if (ret < 0) {
@ -1009,31 +1093,6 @@ int handle_lower_level(raw_info_t &raw_info)//fill lower_level info,when --lower
}
/*
int add_iptables_rule(const char * s)
{
iptables_pattern=s;
string rule="iptables -I INPUT ";
rule+=iptables_pattern;
rule+=" -j DROP";
char *output;
if(run_command(rule.c_str(),output)==0)
{
mylog(log_warn,"auto added iptables rule by: %s\n",rule.c_str());
}
else
{
mylog(log_fatal,"auto added iptables failed by: %s\n",rule.c_str());
//mylog(log_fatal,"reason : %s\n",strerror(errno));
myexit(-1);
}
iptables_rule_added=1;
return 0;
}*/
string chain[2];
string rule_keep[2];
string rule_keep_add[2];
@ -1048,14 +1107,14 @@ int iptables_gen_add(const char * s,u32_t const_id)
iptables_pattern=s;
chain[0] =dummy+ "udp2rawDwrW_C";
rule_keep[0]=dummy+ iptables_pattern+" -j " +chain[0];
rule_keep_add[0]=dummy+"iptables -I INPUT "+rule_keep[0];
rule_keep_add[0]=iptables_command+"-I INPUT "+rule_keep[0];
char *output;
run_command(dummy+"iptables -N "+chain[0],output,show_none);
run_command(dummy+"iptables -F "+chain[0],output);
run_command(dummy+"iptables -I "+chain[0] + " -j DROP",output);
run_command(iptables_command+"-N "+chain[0],output,show_none);
run_command(iptables_command+"-F "+chain[0],output);
run_command(iptables_command+"-I "+chain[0] + " -j DROP",output);
rule_keep_del[0]=dummy+"iptables -D INPUT "+rule_keep[0];
rule_keep_del[0]=iptables_command+"-D INPUT "+rule_keep[0];
run_command(rule_keep_del[0],output,show_none);
run_command(rule_keep_del[0],output,show_none);
@ -1083,11 +1142,11 @@ int iptables_rule_init(const char * s,u32_t const_id,int keep)
rule_keep[0]=dummy+ iptables_pattern+" -j " +chain[0];
rule_keep[1]=dummy+ iptables_pattern+" -j " +chain[1];
rule_keep_add[0]=dummy+"iptables -I INPUT "+rule_keep[0];
rule_keep_add[1]=dummy+"iptables -I INPUT "+rule_keep[1];
rule_keep_add[0]=iptables_command+"-I INPUT "+rule_keep[0];
rule_keep_add[1]=iptables_command+"-I INPUT "+rule_keep[1];
rule_keep_del[0]=dummy+"iptables -D INPUT "+rule_keep[0];
rule_keep_del[1]=dummy+"iptables -D INPUT "+rule_keep[1];
rule_keep_del[0]=iptables_command+"-D INPUT "+rule_keep[0];
rule_keep_del[1]=iptables_command+"-D INPUT "+rule_keep[1];
keep_rule_last_time=get_current_time();
@ -1095,9 +1154,9 @@ int iptables_rule_init(const char * s,u32_t const_id,int keep)
for(int i=0;i<=iptables_rule_keeped;i++)
{
run_command(dummy+"iptables -N "+chain[i],output);
run_command(dummy+"iptables -F "+chain[i],output);
run_command(dummy+"iptables -I "+chain[i] + " -j DROP",output);
run_command(iptables_command+"-N "+chain[i],output);
run_command(iptables_command+"-F "+chain[i],output);
run_command(iptables_command+"-I "+chain[i] + " -j DROP",output);
if(run_command(rule_keep_add[i],output)!=0)
{
@ -1134,12 +1193,12 @@ int keep_iptables_rule() //magic to work on a machine without grep/iptables --c
int i=iptables_rule_keep_index;
run_command(dummy + "iptables -N " + chain[i], output,show_none);
run_command(iptables_command + "-N " + chain[i], output,show_none);
if (run_command(dummy + "iptables -F " + chain[i], output,show_none) != 0)
if (run_command(iptables_command + "-F " + chain[i], output,show_none) != 0)
mylog(log_warn, "iptables -F failed %d\n",i);
if (run_command(dummy + "iptables -I " + chain[i] + " -j DROP",output,show_none) != 0)
if (run_command(iptables_command + "-I " + chain[i] + " -j DROP",output,show_none) != 0)
mylog(log_warn, "iptables -I failed %d\n",i);
if (run_command(rule_keep_del[i], output,show_none) != 0)
@ -1163,8 +1222,8 @@ int clear_iptables_rule()
for(int i=0;i<=iptables_rule_keeped;i++ )
{
run_command(rule_keep_del[i],output);
run_command(dummy+"iptables -F "+chain[i],output);
run_command(dummy+"iptables -X "+chain[i],output);
run_command(iptables_command+"-F "+chain[i],output);
run_command(iptables_command+"-X "+chain[i],output);
}
return 0;
}

24
misc.h

@ -13,6 +13,12 @@
#include "log.h"
#include "network.h"
extern int hb_mode;
extern int hb_len;
extern int mtu_warn;
extern int max_rst_allowed;
extern int max_rst_to_show;
const u32_t max_handshake_conn_num=10000;
@ -25,22 +31,22 @@ const u32_t client_retry_interval=1000;//ms
const u32_t server_handshake_timeout=client_handshake_timeout+5000;// this should be longer than clients. client retry initially ,server retry passtively
const int conv_clear_ratio=10; //conv grabage collecter check 1/10 of all conv one time
const int conn_clear_ratio=30;
const int conv_clear_ratio=30; //conv grabage collecter check 1/30 of all conv one time
const int conn_clear_ratio=50;
const int conv_clear_min=1;
const int conn_clear_min=1;
const u32_t conv_clear_interval=3000;//ms
const u32_t conn_clear_interval=3000;//ms
const u32_t conv_clear_interval=1000;//ms
const u32_t conn_clear_interval=1000;//ms
const i32_t max_fail_time=0;//disable
const u32_t heartbeat_interval=1000;//ms
const u32_t heartbeat_interval=600;//ms
const u32_t timer_interval=400;//ms. this should be smaller than heartbeat_interval and retry interval;
const uint32_t conv_timeout=120000; //ms. 120 second
const uint32_t conv_timeout=180000; //ms. 120 second
//const u32_t conv_timeout=30000; //for test
const u32_t client_conn_timeout=10000;//ms.
@ -49,7 +55,7 @@ const u32_t client_conn_uplink_timeout=client_conn_timeout+2000;//ms
const uint32_t server_conn_timeout=conv_timeout+60000;//ms. 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
const u32_t iptables_rule_keep_interval=15;//unit: second;
const u32_t iptables_rule_keep_interval=20;//unit: second;
enum server_current_state_t {server_idle=0,server_handshake1,server_ready}; //server state machine
enum client_current_state_t {client_idle=0,client_tcp_handshake,client_handshake1,client_handshake2,client_ready};//client state machine
@ -85,6 +91,8 @@ extern int keep_rule; //whether to monitor the iptables rule periodly,re-add if
extern int auto_add_iptables_rule;//if -a is set
extern int generate_iptables_rule;//if -g is set
extern int generate_iptables_rule_add;// if --gen-add is set
extern int retry_on_error;
const int retry_on_error_interval=10;
extern int debug_resend; // debug only
@ -112,7 +120,7 @@ void iptables_rule();
void pre_process_arg(int argc, char *argv[]);//mainly for load conf file;
int unit_test();
int set_timer(int epollfd,int &timer_fd);
int set_timer_server(int epollfd,int &timer_fd);
int set_timer_server(int epollfd,int &timer_fd,fd64_t &fd64);
int handle_lower_level(raw_info_t &raw_info);
int add_iptables_rule(const char *);

@ -566,6 +566,13 @@ int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen)
const packet_info_t &recv_info=raw_info.recv_info;
char send_raw_ip_buf[buf_len];
if(raw_info.disabled)
{
mylog(log_debug,"[%s,%d]connection disabled, no packet will be sent\n",my_ntoa(recv_info.src_ip),recv_info.src_port);
assert(max_rst_allowed>=0);
return 0;
}
struct iphdr *iph = (struct iphdr *) send_raw_ip_buf;
memset(iph,0,sizeof(iphdr));
@ -704,7 +711,13 @@ int recv_raw_ip(raw_info_t &raw_info,char * &payload,int &payloadlen)
struct sockaddr_ll saddr={0};
socklen_t saddr_size = sizeof(saddr);
int flag=0;
int recv_len = recvfrom(raw_recv_fd, recv_raw_ip_buf, max_data_len, flag ,(sockaddr*)&saddr , &saddr_size);
int recv_len = recvfrom(raw_recv_fd, recv_raw_ip_buf, max_data_len+1, flag ,(sockaddr*)&saddr , &saddr_size);
if(recv_len==max_data_len+1)
{
mylog(log_warn,"huge packet, data_len > %d,dropped\n",max_data_len);
return -1;
}
if(recv_len<0)
{
@ -1439,7 +1452,37 @@ int recv_raw_tcp(raw_info_t &raw_info,char * &payload,int &payloadlen)
if(tcph->rst==1)
{
mylog(log_error,"[%s,%d]rst==1\n",my_ntoa(recv_info.src_ip),recv_info.src_port);
raw_info.rst_received++;
if(max_rst_to_show>0)
{
if(raw_info.rst_received < max_rst_to_show)
{
mylog(log_warn,"[%s,%d]rst==1,cnt=%d\n",my_ntoa(recv_info.src_ip),recv_info.src_port,(int)raw_info.rst_received);
}
else if(raw_info.rst_received == max_rst_to_show)
{
mylog(log_warn,"[%s,%d]rst==1,cnt=%d >=max_rst_to_show, this log will be muted for current connection\n",my_ntoa(recv_info.src_ip),recv_info.src_port,(int)raw_info.rst_received);
}
else
{
mylog(log_debug,"[%s,%d]rst==1,cnt=%d\n",my_ntoa(recv_info.src_ip),recv_info.src_port,(int)raw_info.rst_received);
}
}
else if(max_rst_to_show==0)
{
mylog(log_debug,"[%s,%d]rst==1,cnt=%d\n",my_ntoa(recv_info.src_ip),recv_info.src_port,(int)raw_info.rst_received);
}
else
{
mylog(log_warn,"[%s,%d]rst==1,cnt=%d\n",my_ntoa(recv_info.src_ip),recv_info.src_port,(int)raw_info.rst_received);
}
if(max_rst_allowed>=0 && raw_info.rst_received==max_rst_allowed+1 )
{
mylog(log_warn,"[%s,%d]connection disabled because of rst_received=%d > max_rst_allow=%d\n",my_ntoa(recv_info.src_ip),recv_info.src_port,(int)raw_info.rst_received,(int)max_rst_allowed );
raw_info.disabled=1;
}
}
/* if(recv_info.has_ts)
@ -1820,17 +1863,17 @@ int get_src_adress(u32_t &ip,u32_t remote_ip_uint32,int remote_port) //a trick
return 0;
}
int try_to_list_and_bind(int bind_fd,u32_t local_ip_uint32,int port) //try to bind to a port,may fail.
int try_to_list_and_bind(int &fd,u32_t local_ip_uint32,int port) //try to bind to a port,may fail.
{
int old_bind_fd=bind_fd;
int old_bind_fd=fd;
if(raw_mode==mode_faketcp)
{
bind_fd=socket(AF_INET,SOCK_STREAM,0);
fd=socket(AF_INET,SOCK_STREAM,0);
}
else if(raw_mode==mode_udp||raw_mode==mode_icmp)
{
bind_fd=socket(AF_INET,SOCK_DGRAM,0);
fd=socket(AF_INET,SOCK_DGRAM,0);
}
if(old_bind_fd!=-1)
{
@ -1844,7 +1887,7 @@ int try_to_list_and_bind(int bind_fd,u32_t local_ip_uint32,int port) //try to b
temp_bind_addr.sin_port = htons(port);
temp_bind_addr.sin_addr.s_addr = local_ip_uint32;
if (bind(bind_fd, (struct sockaddr*)&temp_bind_addr, sizeof(temp_bind_addr)) !=0)
if (bind(fd, (struct sockaddr*)&temp_bind_addr, sizeof(temp_bind_addr)) !=0)
{
mylog(log_debug,"bind fail\n");
return -1;
@ -1852,19 +1895,19 @@ int try_to_list_and_bind(int bind_fd,u32_t local_ip_uint32,int port) //try to b
if(raw_mode==mode_faketcp)
{
if (listen(bind_fd, SOMAXCONN) != 0) {
if (listen(fd, SOMAXCONN) != 0) {
mylog(log_warn,"listen fail\n");
return -1;
}
}
return 0;
}
int client_bind_to_a_new_port(int bind_fd,u32_t local_ip_uint32)//find a free port and bind to it.
int client_bind_to_a_new_port(int &fd,u32_t local_ip_uint32)//find a free port and bind to it.
{
int raw_send_port=10000+get_true_random_number()%(65535-10000);
for(int i=0;i<1000;i++)//try 1000 times at max,this should be enough
{
if (try_to_list_and_bind(bind_fd,local_ip_uint32,raw_send_port)==0)
if (try_to_list_and_bind(fd,local_ip_uint32,raw_send_port)==0)
{
return raw_send_port;
}

@ -77,12 +77,13 @@ struct raw_info_t
{
packet_info_t send_info;
packet_info_t recv_info;
//int last_send_len;
//int last_recv_len;
u32_t reserved_send_seq;
//uint32_t first_seq,first_ack_seq;
int rst_received=0;
bool disabled=0;
};//g_raw_info;
@ -99,9 +100,9 @@ int find_lower_level_info(u32_t ip,u32_t &dest_ip,string &if_name,string &hw);
int get_src_adress(u32_t &ip,u32_t remote_ip_uint32,int remote_port); //a trick to get src adress for a dest adress,so that we can use the src address in raw socket as source ip
int try_to_list_and_bind(int bind_fd,u32_t local_ip_uint32,int port); //try to bind to a port,may fail.
int try_to_list_and_bind(int & bind_fd,u32_t local_ip_uint32,int port); //try to bind to a port,may fail.
int client_bind_to_a_new_port(int bind_fd,u32_t local_ip_uint32);//find a free port and bind to it.
int client_bind_to_a_new_port(int & bind_fd,u32_t local_ip_uint32);//find a free port and bind to it.
int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen);

@ -0,0 +1 @@
https://github.com/sensec/luci-app-udp2raw

@ -0,0 +1 @@
https://github.com/sensec/openwrt-udp2raw