├── .clang-format ├── .gitmodules ├── CMakeLists.txt ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── README.md ├── doc └── README.zh-cn.md ├── images ├── FEC.PNG ├── en │ ├── init │ ├── ping_compare.PNG │ ├── ping_compare2.PNG │ ├── rs.png │ ├── scp_compare.PNG │ └── scp_compare2.PNG ├── init ├── peformance.PNG ├── performance2.PNG ├── restriction.PNG ├── tinyFecVPN.PNG ├── tinyFecVPN2.PNG ├── tinyFecVPN3.PNG ├── tinyFecVPNcn.PNG └── tinyFecVPNcn2.PNG ├── main.cpp ├── makefile ├── tun_dev.cpp ├── tun_dev.h ├── tun_dev_client.cpp └── tun_dev_server.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | SortIncludes: false 2 | BasedOnStyle: Google 3 | ColumnLimit: 0 4 | IndentWidth: 4 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "UDPspeeder"] 2 | path = UDPspeeder 3 | url = https://github.com/wangyu-/UDPspeeder.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #note: experimental 2 | # currently only used for generating `compile_commands.json` for clangd 3 | # to build this project, it's suggested to use `makefile` instead 4 | 5 | cmake_minimum_required(VERSION 3.7) 6 | project(tinyvpn) 7 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 8 | 9 | set(CMAKE_CXX_STANDARD 11) 10 | 11 | set(SOURCE_FILES 12 | UDPspeeder/log.cpp 13 | UDPspeeder/common.cpp 14 | UDPspeeder/lib/fec.cpp 15 | UDPspeeder/lib/rs.cpp 16 | UDPspeeder/packet.cpp 17 | UDPspeeder/delay_manager.cpp 18 | UDPspeeder/fd_manager.cpp 19 | UDPspeeder/connection.cpp 20 | UDPspeeder/fec_manager.cpp 21 | UDPspeeder/misc.cpp 22 | UDPspeeder/my_ev.cpp 23 | main.cpp 24 | tun_dev_client.cpp 25 | tun_dev_server.cpp 26 | tun_dev.cpp 27 | ) 28 | set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers -O2 -g -fsanitize=address,undefined") 29 | 30 | #target_include_directories(speederv2 PRIVATE .) 31 | #set(CMAKE_LINK_LIBRARY_FLAG "-lrt") 32 | add_executable(tinyvpn ${SOURCE_FILES}) 33 | target_link_libraries(tinyvpn rt) 34 | target_link_libraries(tinyvpn pthread) 35 | include_directories(SYSTEM "UDPspeeder/libev") 36 | include_directories("UDPspeeder") 37 | include_directories(".") 38 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | English Only. 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Yu Wang (wangyucn at gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tinyfecVPN 2 | 3 | A Lightweight VPN with Build-in Forward Error Correction Support(or A Network Improving Tool which works at VPN mode). Improves your Network Quality on a High-latency Lossy Link. 4 | 5 | ![image](/images/tinyFecVPN3.PNG) 6 | 7 | tinyfecVPN uses Forward Error Correction(Reed-Solomon code) to reduce packet loss rate, at the cost of additional bandwidth usage. 8 | 9 | Assume your local network to your server is lossy. Just establish a VPN connection to your server with tinyfecVPN, access your server via this VPN connection, then your connection quality will be significantly improved. With well-tuned parameters , you can easily reduce IP or UDP/ICMP packet-loss-rate to less than 0.01% . Besides reducing packet-loss-rate, tinyfecVPN can also significantly improve your TCP latency and TCP single-thread download speed. 10 | 11 | tinyfecVPN uses same lib as [UDPspeeder](https://github.com/wangyu-/UDPspeeder), supports all FEC features of UDPspeeder. tinyfecVPN works at VPN mode,while UDPspeeder works at UDP tunnel mode. 12 | 13 | [tinyfecVPN wiki](https://github.com/wangyu-/tinyfecVPN/wiki) 14 | 15 | [简体中文](/doc/README.zh-cn.md) 16 | 17 | ##### Note 18 | UDPspeeder's repo: 19 | 20 | https://github.com/wangyu-/UDPspeeder 21 | 22 | # Efficacy 23 | Tested on a link with 100ms roundtrip and 10% packet loss at both direction. You can easily reproduce the test result by yourself. 24 | 25 | ### Ping Packet Loss 26 | ![](/images/en/ping_compare2.PNG) 27 | 28 | ### SCP Copy Speed 29 | ![](/images/en/scp_compare2.PNG) 30 | 31 | # Supported Platforms 32 | Linux host (including desktop Linux,Android phone/tablet, OpenWRT router, or Raspberry PI).Binaries for `amd64` `x86` `mips_be` `mips_le` `arm` are provided. 33 | 34 | For Windows and MacOS, You can run tinyfecVPN 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. 35 | 36 | Need root or at least CAP_NET_ADMIN permission to run, for creating tun device. 37 | 38 | # How does it work 39 | 40 | tinyfecVPN uses FEC(Forward Error Correction) to reduce packet loss rate, at the cost of additional bandwidth usage. The algorithm for FEC is called Reed-Solomon. 41 | 42 | ![](/images/FEC.PNG) 43 | 44 | ### Reed-Solomon 45 | 46 | ` 47 | In coding theory, the Reed–Solomon code belongs to the class of non-binary cyclic error-correcting codes. The Reed–Solomon code is based on univariate polynomials over finite fields. 48 | ` 49 | 50 | ` 51 | It is able to detect and correct multiple symbol errors. By adding t check symbols to the data, a Reed–Solomon code can detect any combination of up to t erroneous symbols, or correct up to ⌊t/2⌋ symbols. As an erasure code, it can correct up to t known erasures, or it can detect and correct combinations of errors and erasures. Reed–Solomon codes are also suitable as multiple-burst bit-error correcting codes, since a sequence of b + 1 consecutive bit errors can affect at most two symbols of size b. The choice of t is up to the designer of the code, and may be selected within wide limits. 52 | ` 53 | 54 | ![](/images/en/rs.png) 55 | 56 | Check wikipedia for more info, https://en.wikipedia.org/wiki/Reed–Solomon_error_correction 57 | 58 | 59 | # Getting Started 60 | 61 | ### Installing 62 | 63 | Download binary release from https://github.com/wangyu-/tinyfecVPN/releases 64 | 65 | ### Running 66 | 67 | Assume your server ip is `44.55.66.77`, you have a service listening on udp/tcp port `0.0.0.0:7777`. 68 | 69 | ``` 70 | # Run at server side: 71 | ./tinyvpn -s -l0.0.0.0:4096 -f20:10 -k "passwd" --sub-net 10.22.22.0 72 | 73 | # Run at client side 74 | ./tinyvpn -c -r44.55.66.77:4096 -f20:10 -k "passwd" --sub-net 10.22.22.0 75 | ``` 76 | 77 | Now, use `10.22.22.1:7777` to connect to your service,all traffic will be improved by FEC. If you ping `10.22.22.1`, you will get ping reply. 78 | 79 | ##### Note 80 | 81 | `-f20:10` means sending 10 redundant packets for every 20 original packets. 82 | 83 | `-k` enables simple XOR encryption 84 | 85 | To create tun device, you need root or cap_net_admin permission. Its suggested to run tinyfecVPN as non-root, check [this link](https://github.com/wangyu-/tinyfecVPN/wiki/run-tinyfecVPN-as-non-root) for more info. 86 | 87 | Currently one server supports only one client. For multiple clients, start multiple servers. 88 | 89 | ##### Note2 90 | 91 | You can use udp2raw with tinyfecVPN together to get better speed on some ISP with UDP QoS(UDP throttling). 92 | 93 | udp2raw's repo: 94 | 95 | https://github.com/wangyu-/udp2raw-tunnel 96 | 97 | # Advanced Topic 98 | 99 | ### Usage 100 | ``` 101 | tinyfecVPN 102 | git version: b03df1b586 build date: Oct 31 2017 19:46:50 103 | repository: https://github.com/wangyu-/tinyfecVPN/ 104 | 105 | usage: 106 | run as client: ./this_program -c -r server_ip:server_port [options] 107 | run as server: ./this_program -s -l server_listen_ip:server_port [options] 108 | 109 | common options, must be same on both sides: 110 | -k,--key key for simple xor encryption. if not set, xor is disabled 111 | main options: 112 | --sub-net specify sub-net, for example: 192.168.1.0 , default: 10.22.22.0 113 | --tun-dev sepcify tun device name, for example: tun10, default: a random name such as tun987 114 | -f,--fec x:y forward error correction, send y redundant packets for every x packets 115 | --timeout how long could a packet be held in queue before doing fec, unit: ms, default: 8ms 116 | --mode fec-mode,available values: 0, 1; 0 cost less bandwidth, 1 cost less latency;default: 0) 117 | --report turn on send/recv report, and set a period for reporting, unit: s 118 | --keep-reconnect re-connect after lost connection,only for client. 119 | advanced options: 120 | --mtu mtu. for mode 0, the program will split packet to segment smaller than mtu_value. 121 | for mode 1, no packet will be split, the program just check if the mtu is exceed. 122 | default value: 1250 123 | -j,--jitter simulated jitter. randomly delay first packet for 0~ ms, default value: 0. 124 | do not use if you dont know what it means. 125 | -i,--interval scatter each fec group to a interval of ms, to protect burst packet loss. 126 | default value: 0. do not use if you dont know what it means. 127 | --random-drop simulate packet loss, unit: 0.01%. default value: 0 128 | --disable-obscure disable obscure, to save a bit bandwidth and cpu 129 | developer options: 130 | --tun-mtu mtu of the tun interface,most time you shouldnt change this 131 | --disable-mssfix disable mssfix for tcp connection 132 | --fifo use a fifo(named pipe) for sending commands to the running program, so that you 133 | can change fec encode parameters dynamically, check readme.md in repository for 134 | supported commands. 135 | -j ,--jitter jmin:jmax similiar to -j above, but create jitter randomly between jmin and jmax 136 | -i,--interval imin:imax similiar to -i above, but scatter randomly between imin and imax 137 | -q,--queue-len max fec queue len, only for mode 0 138 | --decode-buf size of buffer of fec decoder,u nit: packet, default: 2000 139 | --fix-latency try to stabilize latency, only for mode 0 140 | --delay-capacity max number of delayed packets 141 | --disable-fec completely disable fec, turn the program into a normal udp tunnel 142 | --sock-buf buf size for socket, >=10 and <=10240, unit: kbyte, default: 1024 143 | log and help options: 144 | --log-level 0: never 1: fatal 2: error 3: warn 145 | 4: info (default) 5: debug 6: trace 146 | --log-position enable file name, function name, line number in log 147 | --disable-color disable log color 148 | -h,--help print this help message 149 | 150 | ``` 151 | ### FEC Options 152 | 153 | The program supports all options of UDPspeeder,check UDPspeeder repo for details: 154 | 155 | https://github.com/wangyu-/UDPspeeder 156 | 157 | ### Addtional Options 158 | 159 | ##### `--tun-dev` 160 | 161 | Specify a tun device name to use. Example: `--tun-dev tun100`. 162 | 163 | If not set,tinyfecVPN will randomly chose a name,such as `tun987`. 164 | 165 | ##### `--sub-net` 166 | 167 | Specify the sub-net of VPN. Example: `--sub-net 10.10.10.0`, in this way,server IP will be `10.10.10.1`,client IP will be `10.10.10.2`. 168 | 169 | The last number of option should be zero, for exmaple `10.10.10.123` is invalild, and will be corrected automatically to `10.10.10.0`. 170 | 171 | ##### `--keep-reconnect` 172 | 173 | Only works at client side. 174 | 175 | tinyfecVPN server only handles one client at same time,the connection of a new client will kick old client,after being kicked,old client will just exit by default. 176 | 177 | If `--keep-reconnect` is enabled , client will try to get connection back after lost connection or being kicked. 178 | 179 | # Performance Test(throughput) 180 | 181 | Server is a Vulr VPS in japan,CPU: single core 2.4GHz,ram: 512mb. Client is a Bandwagonhost VPS in USA,CPU: single core 2.0GHZ,ram: 96mb. To put pressure on the FEC algorithm, an additional 10% packet-loss rate was introduced at both direction. 182 | 183 | ### Test command 184 | 185 | ``` 186 | Server side: 187 | ./tinyvpn_amd64 -s -l 0.0.0.0:5533 --mode 0 -f20:10 188 | iperf3 -s 189 | 190 | Client side: 191 | ./tinyvpn_amd64 -c -r 44.55.66.77:5533 --mode 0 -f20:10 192 | iperf3 -c 10.22.22.1 -P10 193 | ``` 194 | 195 | ### Test result 196 | 197 | ![image](/images/performance2.PNG) 198 | 199 | Note: the performance is mainly limited by the RS code lib. 200 | 201 | # Other 202 | 203 | As a VPN software may contradict with local regulations, I had to introduce an intended restriction in the pre-released binaries: you can only use tinyfecVPN to access your own server. 204 | 205 | You can easily get rid of this restriction by compiling the source code by yourself (take a look at the makefile). This restriction exits only at server side, only the server side binary needs to be compiled by yourself. 206 | 207 | (If you want to compile by yourself, use `git clone --recursive` instead of `git clone`, otherwise the submodule wont be cloned) 208 | -------------------------------------------------------------------------------- /doc/README.zh-cn.md: -------------------------------------------------------------------------------- 1 | # tinyfecVPN 2 | 3 | 工作在VPN方式的双边网络加速工具,可以加速全流量(TCP/UDP/ICMP)。 4 | 5 | ![image](/images/tinyFecVPNcn2.PNG) 6 | 7 | 假设你的本地主机到某个服务器的丢包很高,你只需要用tinyfecVPN建立一条VPN连接,然后透过此VPN来访问server,你的网路质量会得到显著改善。通过合理设置参数,可以轻易把网络丢包率降低到万分之一以下。除了可以降低丢包,还可以显著改善TCP的响应速度,提高TCP的单线程传输速度。 8 | 9 | tinyfecVPN使用了和UDPSpeeder相同的lib,功能和UDPspeeder类似,只不过tinyfecVPN工作方式是VPN,UDPspeeder工作方式是UDP tunnel. 10 | 11 | tinyfecVPN是无状态的点对点VPN, 收到包即连接建立成功;即使VPN断线重连,上层承载的连接不掉线。 12 | 13 | ##### 提示 14 | 15 | UDPspeeder的repo: 16 | 17 | https://github.com/wangyu-/UDPspeeder 18 | 19 | #### 效果 20 | 测试环境是一个有100ms RTT 和双向10%丢包的网络。 21 | 22 | ![](https://raw.githubusercontent.com/wangyu-/UDPspeeder/master/images/cn/ping_compare_cn.PNG) 23 | 24 | ![](https://github.com/wangyu-/UDPspeeder/blob/master/images/cn/scp_compare.PNG) 25 | 26 | #### 关键词 27 | 双边加速、全流量加速、开源加速器、游戏加速、网游加速器 28 | 29 | # 原理简介 30 | 31 | 主要原理是通过冗余数据来对抗网络的丢包,发送冗余数据的方式支持FEC(Forward Error Correction)和多倍发包,其中FEC算法是Reed-Solomon。 32 | 33 | 原理图: 34 | 35 | ![](/images/FEC.PNG) 36 | 37 | 细节请看UDPspeeder的repo,这里不再重复: 38 | 39 | https://github.com/wangyu-/UDPspeeder/ 40 | 41 | 42 | # 简明操作说明 43 | 44 | ### 环境要求 45 | 46 | Linux主机,可以是桌面版,可以是android手机/平板,可以是openwrt路由器,也可以是树莓派。(android暂时有问题) 47 | 48 | 在windows和mac上配合虚拟机可以稳定使用(tinyfecVPN跑在Linux里,其他应用照常跑在window里,桥接模式测试可用),可以使用[这个](https://github.com/wangyu-/udp2raw-tunnel/releases/download/20171108.0/lede-17.01.2-x86_virtual_machine_image.zip)虚拟机镜像,大小只有7.5mb,免去在虚拟机里装系统的麻烦;虚拟机自带ssh server,可以scp拷贝文件,可以ssh进去,可以复制粘贴,root密码123456。 49 | 50 | android需要通过terminal运行。 51 | 52 | 需要root或者cap_net_admin权限(因为需要创建tun设备)。 53 | 54 | ###### 注意 55 | 在使用虚拟机时,建议手动指定桥接到哪个网卡,不要设置成自动。否则可能会桥接到错误的网卡。 56 | 57 | # 简明操作说明 58 | 59 | ### 安装 60 | 61 | 下载编译好的二进制文件,解压到本地和服务器的任意目录。 62 | 63 | https://github.com/wangyu-/tinyfecVPN/releases 64 | 65 | ### 运行 66 | 67 | 假设你有一个server,ip为44.55.66.77,有一个服务监听tcp/udp 0.0.0.0:7777。 68 | 69 | ``` 70 | # 在server端运行: 71 | ./tinyvpn -s -l0.0.0.0:4096 -f20:10 -k "passwd" --sub-net 10.22.22.0 72 | 73 | # 在client端运行: 74 | ./tinyvpn -c -r44.55.66.77:4096 -f20:10 -k "passwd" --sub-net 10.22.22.0 75 | 76 | ``` 77 | 78 | 现在,只要在客户端使用10.22.22.1:7777就可以连上你的服务了,来回的流量都会被加速。执行ping 10.22.22.1也会得到回复。 79 | 80 | ###### 备注: 81 | 82 | `-f20:10`表示对每20个原始数据发送10个冗余包。`-f20:10` 和`-f 20:10`都是可以的,空格可以省略,对于所有的单字节option都是如此。对于双字节option,例如后面会提到的`--mode 0`,空格不可以省略。 83 | 84 | `-k` 指定一个字符串,开启简单的异或加密 85 | 86 | 目前一个server只能支持一个client,如果需要同时运行多个client,需要启动多个server。 87 | 88 | ##### 提示 89 | 90 | 对于某些运营商,tinyfecVPN跟udp2raw配合可以达到更好的速度,udp2raw负责把UDP伪装成TCP,来绕过运营商的UDP限速。 91 | 92 | udp2raw的repo: 93 | 94 | https://github.com/wangyu-/udp2raw-tunnel 95 | 96 | # 进阶操作说明 97 | 98 | ### 命令选项 99 | ``` 100 | tinyfecVPN 101 | git version: b03df1b586 build date: Oct 31 2017 19:46:50 102 | repository: https://github.com/wangyu-/tinyfecVPN/ 103 | 104 | usage: 105 | run as client: ./this_program -c -r server_ip:server_port [options] 106 | run as server: ./this_program -s -l server_listen_ip:server_port [options] 107 | 108 | common options, must be same on both sides: 109 | -k,--key key for simple xor encryption. if not set, xor is disabled 110 | main options: 111 | --sub-net specify sub-net, for example: 192.168.1.0 , default: 10.22.22.0 112 | --tun-dev sepcify tun device name, for example: tun10, default: a random name such as tun987 113 | -f,--fec x:y forward error correction, send y redundant packets for every x packets 114 | --timeout how long could a packet be held in queue before doing fec, unit: ms, default: 8ms 115 | --mode fec-mode,available values: 0, 1; 0 cost less bandwidth, 1 cost less latency;default: 0) 116 | --report turn on send/recv report, and set a period for reporting, unit: s 117 | --keep-reconnect re-connect after lost connection,only for client. 118 | advanced options: 119 | --mtu mtu. for mode 0, the program will split packet to segment smaller than mtu_value. 120 | for mode 1, no packet will be split, the program just check if the mtu is exceed. 121 | default value: 1250 122 | -j,--jitter simulated jitter. randomly delay first packet for 0~ ms, default value: 0. 123 | do not use if you dont know what it means. 124 | -i,--interval scatter each fec group to a interval of ms, to protect burst packet loss. 125 | default value: 0. do not use if you dont know what it means. 126 | --random-drop simulate packet loss, unit: 0.01%. default value: 0 127 | --disable-obscure disable obscure, to save a bit bandwidth and cpu 128 | developer options: 129 | --tun-mtu mtu of the tun interface,most time you shouldnt change this 130 | --disable-mssfix disable mssfix for tcp connection 131 | --fifo use a fifo(named pipe) for sending commands to the running program, so that you 132 | can change fec encode parameters dynamically, check readme.md in repository for 133 | supported commands. 134 | -j ,--jitter jmin:jmax similiar to -j above, but create jitter randomly between jmin and jmax 135 | -i,--interval imin:imax similiar to -i above, but scatter randomly between imin and imax 136 | -q,--queue-len max fec queue len, only for mode 0 137 | --decode-buf size of buffer of fec decoder,u nit: packet, default: 2000 138 | --fix-latency try to stabilize latency, only for mode 0 139 | --delay-capacity max number of delayed packets 140 | --disable-fec completely disable fec, turn the program into a normal udp tunnel 141 | --sock-buf buf size for socket, >=10 and <=10240, unit: kbyte, default: 1024 142 | log and help options: 143 | --log-level 0: never 1: fatal 2: error 3: warn 144 | 4: info (default) 5: debug 6: trace 145 | --log-position enable file name, function name, line number in log 146 | --disable-color disable log color 147 | -h,--help print this help message 148 | 149 | ``` 150 | ### 跟UDPspeeder共用的选项 151 | 152 | tinyfecVPN支持UDPspeeder的所有选项,具体请看UDPspeeder的repo: 153 | 154 | https://github.com/wangyu-/UDPspeeder/blob/master/doc/README.zh-cn.md#命令选项 155 | 156 | ### tinyfecVPN的新增选项 157 | 158 | ##### `--tun-dev` 159 | 160 | 指定tun设备的名字. 例如: --tun-dev tun100. 161 | 162 | 如果不指定,tinyfecVPN会创建一个随机名字的tun设备,比如tun987. 163 | 164 | ##### `--sub-net` 165 | 166 | 指定VPN的子网,格式为xxx.xxx.xxx.0。 例如: 对于--sub-net 10.10.10.0, server的IP会被设置成10.10.10.1,client的IP会被设置成10.10.10.2 . 167 | 168 | 子网中的最后一个数字应该是0, 比如10.10.10.123是不符合规范的, 会被程序自动纠正成10.10.10.0. 169 | 170 | ##### `--keep-reconnect` 171 | 172 | 只对client有效 173 | 174 | tinyfecVPN server只接受一个client的连接,后连接的client会把新的挤掉。 175 | 176 | 如果开启了--keep-reconnect,client在连接断开或者被挤掉以后会尝试重新获得连接。 177 | 178 | # 使用经验 179 | 180 | https://github.com/wangyu-/tinyfecVPN/wiki/使用经验 181 | 182 | # 性能测试(侧重吞吐量) 183 | 184 | server 在 vulr 日本,CPU2.4GHz,内存 512mb。client 在搬瓦工美国,CPU 2.0GHZ,内存 96mb。在网路间额外模拟了10%的丢包,用于加重FEC的负担。 185 | 186 | ### 测试命令 187 | 188 | ``` 189 | 在server端: 190 | ./tinyvpn_amd64 -s -l 0.0.0.0:5533 --mode 0 191 | iperf3 -s 192 | 在client端: 193 | ./tinyvpn_amd64 -c -r 44.55.66.77:5533 --mode 0 194 | iperf3 -c 10.22.22.1 -P10 195 | ``` 196 | 197 | ### 测试结果 198 | 199 | ![image](/images/performance2.PNG) 200 | 201 | # Wiki 202 | 203 | Wiki上有更丰富的内容: 204 | 205 | https://github.com/wangyu-/tinyfecVPN/wiki 206 | 207 | # 限制 208 | 209 | 考虑到国内的实情,为了降低风险,[releases](https://github.com/wangyu-/tinyfecVPN/releases)中的binaries存在一点人为限制:只允许透过tinyfecVPN访问server上的服务,不能(直接)访问第三方服务器;也就是只能当加速器用,不能(直接)用来科学上网。 210 | 211 | 即使开启了ipforward和MASQUERADE也不行,代码里有额外处理,直接透过tinyfecVPN访问第三方服务器的包会被丢掉,效果如图: 212 | 213 | ![image](/images/restriction.PNG) 214 | 215 | 如果你需要去掉这个限制,可以自己编译(makefile里有相应的target)。 只需要自己编译server端,因为限制只存在于server端。 216 | 217 | (自己编译请用` git clone --recursive`而不是仅`git clone`,否则submodule不会被正常clone) 218 | -------------------------------------------------------------------------------- /images/FEC.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/FEC.PNG -------------------------------------------------------------------------------- /images/en/init: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /images/en/ping_compare.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/ping_compare.PNG -------------------------------------------------------------------------------- /images/en/ping_compare2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/ping_compare2.PNG -------------------------------------------------------------------------------- /images/en/rs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/rs.png -------------------------------------------------------------------------------- /images/en/scp_compare.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/scp_compare.PNG -------------------------------------------------------------------------------- /images/en/scp_compare2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/en/scp_compare2.PNG -------------------------------------------------------------------------------- /images/init: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /images/peformance.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/peformance.PNG -------------------------------------------------------------------------------- /images/performance2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/performance2.PNG -------------------------------------------------------------------------------- /images/restriction.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/restriction.PNG -------------------------------------------------------------------------------- /images/tinyFecVPN.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPN.PNG -------------------------------------------------------------------------------- /images/tinyFecVPN2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPN2.PNG -------------------------------------------------------------------------------- /images/tinyFecVPN3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPN3.PNG -------------------------------------------------------------------------------- /images/tinyFecVPNcn.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPNcn.PNG -------------------------------------------------------------------------------- /images/tinyFecVPNcn2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangyu-/tinyfecVPN/cbdf9beed3d03558b70d54e712453293f1d824f0/images/tinyFecVPNcn2.PNG -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * tun.cpp 3 | * 4 | * Created on: Oct 26, 2017 5 | * Author: root 6 | */ 7 | 8 | #include "common.h" 9 | #include "log.h" 10 | #include "misc.h" 11 | #include "tun_dev.h" 12 | #include "git_version.h" 13 | using namespace std; 14 | 15 | static void print_help() { 16 | char git_version_buf[100] = {0}; 17 | strncpy(git_version_buf, gitversion, 10); 18 | 19 | printf("tinyFecVPN\n"); 20 | printf("git version: %s ", git_version_buf); 21 | printf("build date: %s %s\n", __DATE__, __TIME__); 22 | printf("repository: https://github.com/wangyu-/tinyFecVPN/\n"); 23 | printf("\n"); 24 | printf("usage:\n"); 25 | printf(" run as client: ./this_program -c -r server_ip:server_port [options]\n"); 26 | printf(" run as server: ./this_program -s -l server_listen_ip:server_port [options]\n"); 27 | printf("\n"); 28 | printf("common options, must be same on both sides:\n"); 29 | printf(" -k,--key key for simple xor encryption. if not set, xor is disabled\n"); 30 | 31 | printf("main options:\n"); 32 | printf(" --sub-net specify sub-net, for example: 192.168.1.0 , default: 10.22.22.0\n"); 33 | printf(" --tun-dev sepcify tun device name, for example: tun10, default: a random name such as tun987\n"); 34 | printf(" -f,--fec x:y forward error correction, send y redundant packets for every x packets\n"); 35 | printf(" --timeout how long could a packet be held in queue before doing fec, unit: ms, default: 8ms\n"); 36 | printf(" --report turn on send/recv report, and set a period for reporting, unit: s\n"); 37 | printf(" --keep-reconnect re-connect after lost connection,only for client. \n"); 38 | 39 | printf("advanced options:\n"); 40 | printf(" --mode fec-mode,available values: 0,1; mode 0(default) costs less bandwidth,no mtu problem.\n"); 41 | printf(" mode 1 usually introduces less latency, but you have to care about mtu.\n"); 42 | printf(" --mtu mtu for fec. for mode 0, the program will split packet to segment smaller than mtu.\n"); 43 | printf(" for mode 1, no packet will be split, the program just check if the mtu is exceed.\n"); 44 | printf(" default value: 1250\n"); 45 | printf(" -j,--jitter simulated jitter. randomly delay first packet for 0~ ms, default value: 0.\n"); 46 | printf(" do not use if you dont know what it means.\n"); 47 | printf(" -i,--interval scatter each fec group to a interval of ms, to defend burst packet loss.\n"); 48 | printf(" default value: 0. do not use if you dont know what it means.\n"); 49 | printf(" -f,--fec x1:y1,x2:y2,.. similiar to -f/--fec above,fine-grained fec parameters,may help save bandwidth.\n"); 50 | printf(" example: \"-f 1:3,2:4,10:6,20:10\". check repo for details\n"); 51 | printf(" --random-drop simulate packet loss, unit: 0.01%%. default value: 0\n"); 52 | printf(" --disable-obscure disable obscure, to save a bit bandwidth and cpu\n"); 53 | printf(" --disable-checksum disable checksum to save a bit bandwdith and cpu\n"); 54 | // printf(" --disable-xor disable xor\n"); 55 | printf(" --persist-tun make the tun device persistent, so that it wont be deleted after exited.\n"); 56 | printf(" --mssfix do mssfix for tcp connection, use 0 to disable. default value: 1250\n"); 57 | 58 | printf("developer options:\n"); 59 | printf(" --tun-mtu mtu of the tun interface,most time you shouldnt change this\n"); 60 | printf(" --manual-set-tun tell tinyfecvpn to not setup the tun device automatically(e.g. assign ip address),\n"); 61 | printf(" so that you can do it manually later\n"); 62 | printf(" --fifo use a fifo(named pipe) for sending commands to the running program, so that you\n"); 63 | printf(" can change fec encode parameters dynamically, check readme.md in repository for\n"); 64 | printf(" supported commands.\n"); 65 | printf(" -j ,--jitter jmin:jmax similiar to -j above, but create jitter randomly between jmin and jmax\n"); 66 | printf(" -i,--interval imin:imax similiar to -i above, but scatter randomly between imin and imax\n"); 67 | printf(" -q,--queue-len fec queue len, only for mode 0, fec will be performed immediately after queue is full.\n"); 68 | printf(" default value: 200. \n"); 69 | printf(" --decode-buf size of buffer of fec decoder,u nit: packet, default: 2000\n"); 70 | // printf(" --fix-latency try to stabilize latency, only for mode 0\n"); 71 | printf(" --delay-capacity max number of delayed packets, 0 means unlimited, default: 0\n"); 72 | printf(" --disable-fec completely disable fec, turn the program into a normal udp tunnel\n"); 73 | printf(" --sock-buf buf size for socket, >=10 and <=10240, unit: kbyte, default: 1024\n"); 74 | printf(" --out-addr ip:port force all output packets of '-r' end to go through this address, port 0 for random port.\n"); 75 | printf(" --out-interface force all output packets of '-r' end to go through this interface.\n"); 76 | 77 | printf("log and help options:\n"); 78 | printf(" --log-level 0: never 1: fatal 2: error 3: warn \n"); 79 | printf(" 4: info (default) 5: debug 6: trace\n"); 80 | printf(" --log-position enable file name, function name, line number in log\n"); 81 | printf(" --disable-color disable log color\n"); 82 | printf(" -h,--help print this help message\n"); 83 | 84 | // printf("common options,these options must be same on both side\n"); 85 | } 86 | 87 | void sigpipe_cb(struct ev_loop *l, ev_signal *w, int revents) { 88 | mylog(log_info, "got sigpipe, ignored"); 89 | } 90 | 91 | void sigterm_cb(struct ev_loop *l, ev_signal *w, int revents) { 92 | mylog(log_info, "got sigterm, exit"); 93 | myexit(0); 94 | } 95 | 96 | void sigint_cb(struct ev_loop *l, ev_signal *w, int revents) { 97 | mylog(log_info, "got sigint, exit"); 98 | myexit(0); 99 | } 100 | 101 | int main(int argc, char *argv[]) { 102 | working_mode = tun_dev_mode; 103 | struct ev_loop *loop = ev_default_loop(0); 104 | #if !defined(__MINGW32__) 105 | ev_signal signal_watcher_sigpipe; 106 | ev_signal_init(&signal_watcher_sigpipe, sigpipe_cb, SIGPIPE); 107 | ev_signal_start(loop, &signal_watcher_sigpipe); 108 | #else 109 | enable_log_color = 0; 110 | #endif 111 | 112 | ev_signal signal_watcher_sigterm; 113 | ev_signal_init(&signal_watcher_sigterm, sigterm_cb, SIGTERM); 114 | ev_signal_start(loop, &signal_watcher_sigterm); 115 | 116 | ev_signal signal_watcher_sigint; 117 | ev_signal_init(&signal_watcher_sigint, sigint_cb, SIGINT); 118 | ev_signal_start(loop, &signal_watcher_sigint); 119 | 120 | assert(sizeof(u64_t) == 8); 121 | assert(sizeof(i64_t) == 8); 122 | assert(sizeof(u32_t) == 4); 123 | assert(sizeof(i32_t) == 4); 124 | assert(sizeof(u16_t) == 2); 125 | assert(sizeof(i16_t) == 2); 126 | dup2(1, 2); // redirect stderr to stdout 127 | int i, j, k; 128 | if (argc == 1) { 129 | print_help(); 130 | myexit(-1); 131 | } 132 | for (i = 0; i < argc; i++) { 133 | if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { 134 | print_help(); 135 | myexit(0); 136 | } 137 | } 138 | 139 | // g_fec_mode=0; 140 | 141 | process_arg(argc, argv); 142 | 143 | delay_manager.set_capacity(delay_capacity); 144 | // local_ip_uint32=inet_addr(local_ip); 145 | // remote_ip_uint32=inet_addr(remote_ip); 146 | sub_net_uint32 = inet_addr(sub_net); 147 | 148 | if (strlen(tun_dev) == 0) { 149 | sprintf(tun_dev, "tun%u", get_fake_random_number() % 1000); 150 | } 151 | mylog(log_info, "using interface %s\n", tun_dev); 152 | /*if(tun_mtu==0) 153 | { 154 | tun_mtu=g_fec_mtu; 155 | }*/ 156 | if (program_mode == client_mode) { 157 | tun_dev_client_event_loop(); 158 | } else { 159 | tun_dev_server_event_loop(); 160 | } 161 | 162 | return 0; 163 | } 164 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | cc_cross=/toolchains/tmp/OpenWrt-SDK-15.05.1-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-g++ -s 2 | cc_local=g++ 3 | #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++ 4 | 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++ 5 | 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++ 6 | #cc_arm= /toolchains/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-g++ -march=armv6 -marm 7 | cc_arm= /toolchains/arm-2014.05/bin/arm-none-linux-gnueabi-g++ 8 | #cc_bcm2708=/home/wangyu/raspberry/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-g++ 9 | FLAGS= -std=c++11 -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers -ggdb -I. -IUDPspeeder -isystem UDPspeeder/libev ${OPT} 10 | 11 | SOURCES=`ls UDPspeeder/*.cpp UDPspeeder/lib/*.cpp|grep -v main.cpp|grep -v tunnel.cpp` main.cpp tun_dev.cpp tun_dev_client.cpp tun_dev_server.cpp 12 | 13 | #INCLUDE= -I. -IUDPspeeder 14 | 15 | NAME=tinyvpn 16 | 17 | TARGETS=amd64 arm mips24kc_be x86 mips24kc_le 18 | 19 | TAR=${NAME}_binaries.tar.gz `echo ${TARGETS}|sed -r 's/([^ ]+)/tinyvpn_\1/g'` version.txt 20 | 21 | export STAGING_DIR=/tmp/ #just for supress warning of staging_dir not define 22 | 23 | all:git_version 24 | rm -f ${NAME} 25 | ${cc_local} -o ${NAME} ${INCLUDE} ${SOURCES} ${FLAGS} -lrt -ggdb -static -O2 26 | 27 | debug: git_version 28 | rm -f ${NAME} 29 | ${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -Wformat-nonliteral -D MY_DEBUG 30 | debug2: git_version 31 | rm -f ${NAME} 32 | ${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -Wformat-nonliteral -ggdb 33 | 34 | init: 35 | git submodule init 36 | git submodule update 37 | 38 | mips24kc_be: git_version 39 | ${cc_mips24kc_be} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O3 40 | 41 | mips24kc_be_debug: git_version 42 | ${cc_mips24kc_be} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -ggdb 43 | 44 | mips24kc_le: git_version 45 | ${cc_mips24kc_le} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O3 46 | 47 | amd64:git_version 48 | ${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3 49 | amd64_debug:git_version 50 | ${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -ggdb 51 | x86:git_version 52 | ${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3 -m32 53 | arm:git_version 54 | ${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3 55 | 56 | arm_debug:git_version 57 | ${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -ggdb 58 | 59 | cross:git_version 60 | ${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -O3 61 | 62 | cross2:git_version 63 | ${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -static -lgcc_eh -O3 64 | 65 | cross3:git_version 66 | ${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -static -O3 67 | 68 | release: ${TARGETS} 69 | cp git_version.h version.txt 70 | tar -zcvf ${TAR} 71 | 72 | clean: 73 | rm -f ${TAR} 74 | rm -f speeder speeder_cross 75 | rm -f git_version.h 76 | 77 | git_version: 78 | echo "const char * const gitversion = \"$(shell git rev-parse HEAD)\";" > git_version.h 79 | 80 | 81 | # targets without restrictions: 82 | nolimit: 83 | make OPT=-DNOLIMIT 84 | nolimit_all: 85 | make OPT=-DNOLIMIT 86 | nolimit_cross: 87 | make cross OPT=-DNOLIMIT 88 | nolimit_cross2: 89 | make cross2 OPT=-DNOLIMIT 90 | nolimit_cross3: 91 | make cross3 OPT=-DNOLIMIT 92 | nolimit_release: 93 | make release OPT=-DNOLIMIT 94 | -------------------------------------------------------------------------------- /tun_dev.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * tun.cpp 3 | * 4 | * Created on: Oct 26, 2017 5 | * Author: root 6 | */ 7 | 8 | #include "tun_dev.h" 9 | 10 | my_time_t last_keep_alive_time = 0; 11 | 12 | int get_tun_fd(char *dev_name) { 13 | int tun_fd = open("/dev/net/tun", O_RDWR); 14 | 15 | if (tun_fd < 0) { 16 | mylog(log_fatal, "open /dev/net/tun failed"); 17 | myexit(-1); 18 | } 19 | struct ifreq ifr; 20 | memset(&ifr, 0, sizeof(ifr)); 21 | ifr.ifr_flags = IFF_TUN | IFF_NO_PI; 22 | 23 | strncpy(ifr.ifr_name, dev_name, IFNAMSIZ); 24 | 25 | if (ioctl(tun_fd, TUNSETIFF, (void *)&ifr) != 0) { 26 | mylog(log_fatal, "open /dev/net/tun failed"); 27 | myexit(-1); 28 | } 29 | 30 | if (persist_tun == 1) { 31 | if (ioctl(tun_fd, TUNSETPERSIST, 1) != 0) { 32 | mylog(log_warn, "failed to set tun persistent"); 33 | } 34 | } 35 | return tun_fd; 36 | } 37 | 38 | int set_tun(char *if_name, u32_t local_ip, u32_t remote_ip, int mtu) { 39 | if (manual_set_tun) return 0; 40 | 41 | // printf("i m here1\n"); 42 | struct ifreq ifr; 43 | struct sockaddr_in sai; 44 | memset(&ifr, 0, sizeof(ifr)); 45 | memset(&sai, 0, sizeof(struct sockaddr)); 46 | 47 | int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 48 | strncpy(ifr.ifr_name, if_name, IFNAMSIZ); 49 | 50 | sai.sin_family = AF_INET; 51 | sai.sin_port = 0; 52 | 53 | sai.sin_addr.s_addr = local_ip; 54 | memcpy(&ifr.ifr_addr, &sai, sizeof(struct sockaddr)); 55 | assert(ioctl(sockfd, SIOCSIFADDR, &ifr) == 0); // set source ip 56 | 57 | sai.sin_addr.s_addr = remote_ip; 58 | memcpy(&ifr.ifr_addr, &sai, sizeof(struct sockaddr)); 59 | assert(ioctl(sockfd, SIOCSIFDSTADDR, &ifr) == 0); // set dest ip 60 | 61 | ifr.ifr_mtu = mtu; 62 | assert(ioctl(sockfd, SIOCSIFMTU, &ifr) == 0); // set mtu 63 | 64 | assert(ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0); 65 | // ifr.ifr_flags |= ( IFF_UP|IFF_POINTOPOINT|IFF_RUNNING|IFF_NOARP|IFF_MULTICAST ); 66 | ifr.ifr_flags = (IFF_UP | IFF_POINTOPOINT | IFF_RUNNING | IFF_NOARP | IFF_MULTICAST); // set interface flags 67 | assert(ioctl(sockfd, SIOCSIFFLAGS, &ifr) == 0); 68 | 69 | // printf("i m here2\n"); 70 | return 0; 71 | } 72 | 73 | int put_header(char header, char *data, int &len) { 74 | assert(len >= 0); 75 | data[len] = header; 76 | len += 1; 77 | return 0; 78 | } 79 | int get_header(char &header, char *data, int &len) { 80 | assert(len >= 0); 81 | if (len < 1) return -1; 82 | len -= 1; 83 | header = data[len]; 84 | 85 | return 0; 86 | } 87 | int from_normal_to_fec2(conn_info_t &conn_info, dest_t &dest, char *data, int len, char header) { 88 | int out_n; 89 | char **out_arr; 90 | int *out_len; 91 | my_time_t *out_delay; 92 | 93 | from_normal_to_fec(conn_info, data, len, out_n, out_arr, out_len, out_delay); 94 | 95 | for (int i = 0; i < out_n; i++) { 96 | char tmp_buf[buf_len]; 97 | int tmp_len = out_len[i]; 98 | memcpy(tmp_buf, out_arr[i], out_len[i]); 99 | put_header(header, tmp_buf, tmp_len); 100 | delay_send(out_delay[i], dest, tmp_buf, tmp_len); // this is slow but safer.just use this one 101 | 102 | // put_header(header,out_arr[i],out_len[i]);//modify in place 103 | // delay_send(out_delay[i],dest,out_arr[i],out_len[i]);//warning this is currently okay,but if you modified fec encoder,you may have to use the above code 104 | } 105 | return 0; 106 | } 107 | 108 | int from_fec_to_normal2(conn_info_t &conn_info, dest_t &dest, char *data, int len) { 109 | int out_n; 110 | char **out_arr; 111 | int *out_len; 112 | my_time_t *out_delay; 113 | 114 | from_fec_to_normal(conn_info, data, len, out_n, out_arr, out_len, out_delay); 115 | 116 | for (int i = 0; i < out_n; i++) { 117 | #if 0 118 | if (program_mode == server_mode) { 119 | char *tmp_data = out_arr[i]; 120 | int tmp_len = out_len[i]; 121 | iphdr *iph; 122 | iph = (struct iphdr *)tmp_data; 123 | if (tmp_len >= int(sizeof(iphdr)) && iph->version == 4) { 124 | u32_t dest_ip = iph->daddr; 125 | // printf("%s\n",my_ntoa(dest_ip)); 126 | if ((ntohl(sub_net_uint32) & 0xFFFFFF00) != (ntohl(dest_ip) & 0xFFFFFF00)) { 127 | string sub = my_ntoa(dest_ip); 128 | string dst = my_ntoa(htonl(ntohl(sub_net_uint32) & 0xFFFFFF00)); 129 | mylog(log_warn, "[restriction]packet's dest ip [%s] not in subnet [%s],dropped, maybe you need to compile an un-restricted server\n", sub.c_str(), dst.c_str()); 130 | continue; 131 | } 132 | } 133 | } 134 | #endif 135 | delay_send(out_delay[i], dest, out_arr[i], out_len[i]); 136 | } 137 | 138 | return 0; 139 | } 140 | int do_mssfix(char *s, int len) // currently only for ipv4 141 | { 142 | if (mssfix == 0) { 143 | return 0; 144 | } 145 | 146 | if (len < int(sizeof(iphdr))) { 147 | mylog(log_debug, "packet from tun len=%d <20\n", len); 148 | return -1; 149 | } 150 | iphdr *iph; 151 | iph = (struct iphdr *)s; 152 | if (iph->version != 4) { 153 | // mylog(log_trace,"not ipv4"); 154 | return 0; 155 | } 156 | 157 | if (iph->protocol != IPPROTO_TCP) { 158 | // mylog(log_trace,"not tcp"); 159 | return 0; 160 | } 161 | 162 | int ip_len = ntohs(iph->tot_len); 163 | int ip_hdr_len = iph->ihl * 4; 164 | 165 | if (len < ip_hdr_len) { 166 | mylog(log_debug, "len ip_len) { 174 | mylog(log_debug, "ip_hdr_lenfrag_off) & (short)(0x1FFF)) != 0) { 179 | // not first segment 180 | 181 | // printf("line=%d %x %x \n",__LINE__,(u32_t)ntohs(iph->frag_off),u32_t( ntohs(iph->frag_off) &0xFFF8)); 182 | return 0; 183 | } 184 | if ((ntohs(iph->frag_off) & (short)(0x80FF)) != 0) { 185 | // not whole segment 186 | // printf("line=%d \n",__LINE__); 187 | return 0; 188 | } 189 | 190 | char *tcp_begin = s + ip_hdr_len; 191 | int tcp_len = ip_len - ip_hdr_len; 192 | 193 | if (tcp_len < 20) { 194 | mylog(log_debug, "tcp_len<20,%d\n", tcp_len); 195 | return -1; 196 | } 197 | 198 | tcphdr *tcph = (struct tcphdr *)tcp_begin; 199 | 200 | if (int(tcph->syn) == 0) // fast fail 201 | { 202 | mylog(log_trace, "tcph->syn==0\n"); 203 | return 0; 204 | } 205 | 206 | int tcp_hdr_len = tcph->doff * 4; 207 | 208 | if (tcp_len < tcp_hdr_len) { 209 | mylog(log_debug, "tcp_len = option_end) { 230 | mylog(log_debug, "invaild option ptr+1==option_end,for mss\n"); 231 | return -1; 232 | } 233 | if (*(ptr + 1) != 4) { 234 | mylog(log_debug, "invaild mss len\n"); 235 | return -1; 236 | } 237 | if (ptr + 3 >= option_end) { 238 | mylog(log_debug, "ptr+4>option_end for mss\n"); 239 | return -1; 240 | } 241 | int mss = read_u16(ptr + 2); // uint8_t(ptr[2])*256+uint8_t(ptr[3]); 242 | int new_mss = mss; 243 | if (new_mss > ::mssfix - 40 - 10) // minus extra 10 for safe 244 | { 245 | new_mss = ::mssfix - 40 - 10; 246 | } 247 | write_u16(ptr + 2, (unsigned short)new_mss); 248 | 249 | pseudo_header psh; 250 | 251 | psh.source_address = iph->saddr; 252 | psh.dest_address = iph->daddr; 253 | psh.placeholder = 0; 254 | psh.protocol = iph->protocol; 255 | psh.tcp_length = htons(tcp_len); 256 | 257 | tcph->check = 0; 258 | tcph->check = tcp_csum(psh, (unsigned short *)tcph, tcp_len); 259 | 260 | mylog(log_trace, "mss=%d syn=%d ack=%d, changed mss to %d \n", mss, (int)tcph->syn, (int)tcph->ack, new_mss); 261 | 262 | // printf("test=%x\n",u32_t(1)); 263 | // printf("frag=%x\n",u32_t( ntohs(iph->frag_off) )); 264 | 265 | return 0; 266 | } else { 267 | if (ptr + 1 >= option_end) { 268 | mylog(log_debug, "invaild option ptr+1==option_end\n"); 269 | return -1; 270 | } else { 271 | int len = (unsigned char)*(ptr + 1); 272 | if (len <= 1) { 273 | mylog(log_debug, "invaild option len %d\n", len); 274 | return -1; 275 | } 276 | ptr += len; 277 | } 278 | } 279 | } 280 | 281 | return 0; 282 | } 283 | int do_keep_alive(dest_t &dest) { 284 | if (get_current_time() - last_keep_alive_time > u64_t(keep_alive_interval)) { 285 | last_keep_alive_time = get_current_time(); 286 | char data[buf_len]; 287 | int len; 288 | data[0] = header_keep_alive; 289 | len = 1; 290 | 291 | assert(dest.cook == 1); 292 | // do_cook(data,len); 293 | 294 | delay_send(0, dest, data, len); 295 | } 296 | return 0; 297 | } 298 | -------------------------------------------------------------------------------- /tun_dev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tun.h 3 | * 4 | * Created on: Oct 26, 2017 5 | * Author: root 6 | */ 7 | 8 | #ifndef TUN_DEV_H_ 9 | #define TUN_DEV_H_ 10 | 11 | #include "common.h" 12 | #include "log.h" 13 | #include "misc.h" 14 | 15 | #include //Provides declarations for tcp header 16 | #include 17 | #include //Provides declarations for ip header 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | extern my_time_t last_keep_alive_time; 24 | 25 | const int keep_alive_interval = 3000; // 3000ms 26 | 27 | const char header_normal = 1; 28 | const char header_new_connect = 2; 29 | const char header_reject = 3; 30 | const char header_keep_alive = 4; 31 | 32 | int set_tun(char *if_name, u32_t local_ip, u32_t remote_ip, int mtu); 33 | 34 | int get_tun_fd(char *dev_name); 35 | 36 | int put_header(char header, char *data, int &len); 37 | 38 | int get_header(char &header, char *data, int &len); 39 | int from_normal_to_fec2(conn_info_t &conn_info, dest_t &dest, char *data, int len, char header); 40 | 41 | int from_fec_to_normal2(conn_info_t &conn_info, dest_t &dest, char *data, int len); 42 | int do_mssfix(char *s, int len); 43 | int do_keep_alive(dest_t &dest); 44 | 45 | int tun_dev_client_event_loop(); 46 | 47 | int tun_dev_server_event_loop(); 48 | 49 | #endif /* TUN_H_ */ 50 | -------------------------------------------------------------------------------- /tun_dev_client.cpp: -------------------------------------------------------------------------------- 1 | #include "tun_dev.h" 2 | 3 | static int got_feed_back = 0; 4 | 5 | static dest_t udp_dest; 6 | static dest_t tun_dest; 7 | 8 | static void remote_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { 9 | assert(!(revents & EV_ERROR)); 10 | 11 | conn_info_t &conn_info = *((conn_info_t *)watcher->data); 12 | 13 | char data[buf_len]; 14 | int len; 15 | 16 | fd64_t fd64 = watcher->u64; 17 | int fd = fd_manager.to_fd(fd64); 18 | 19 | len = recv(fd, data, max_data_len + 1, 0); 20 | 21 | if (len == max_data_len + 1) { 22 | mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len); 23 | return; 24 | } 25 | 26 | if (len < 0) { 27 | mylog(log_warn, "recv return %d,errno=%s\n", len, strerror(errno)); 28 | return; 29 | } 30 | 31 | if (de_cook(data, len) < 0) { 32 | mylog(log_warn, "de_cook(data,len)failed \n"); 33 | return; 34 | } 35 | 36 | char header = 0; 37 | if (get_header(header, data, len) != 0) { 38 | mylog(log_warn, "get_header failed\n"); 39 | return; 40 | } 41 | 42 | if (header == header_keep_alive) { 43 | mylog(log_trace, "got keep_alive packet\n"); 44 | return; 45 | } 46 | 47 | if (header == header_reject) { 48 | if (keep_reconnect == 0) { 49 | mylog(log_fatal, "server restarted or switched to handle another client,exited. maybe you need --keep-reconnect\n"); 50 | myexit(-1); 51 | } else { 52 | if (got_feed_back == 1) 53 | mylog(log_warn, "server restarted or switched to handle another client,but keep-reconnect enabled,trying to reconnect\n"); 54 | got_feed_back = 0; 55 | } 56 | return; 57 | } else if (header == header_normal) { 58 | if (got_feed_back == 0) 59 | mylog(log_info, "connection accepted by server\n"); 60 | got_feed_back = 1; 61 | } else { 62 | mylog(log_warn, "invalid header %d %d\n", int(header), len); 63 | return; 64 | } 65 | 66 | mylog(log_trace, "Received packet from udp,len: %d\n", len); 67 | 68 | from_fec_to_normal2(conn_info, tun_dest, data, len); 69 | } 70 | 71 | static void tun_fd_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { 72 | assert(!(revents & EV_ERROR)); 73 | 74 | conn_info_t &conn_info = *((conn_info_t *)watcher->data); 75 | 76 | char data[buf_len]; 77 | int len; 78 | int tun_fd = watcher->fd; 79 | 80 | len = read(tun_fd, data, max_data_len + 1); 81 | 82 | if (len == max_data_len + 1) { 83 | mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len); 84 | return; 85 | } 86 | 87 | if (len < 0) { 88 | mylog(log_warn, "read from tun_fd return %d,errno=%s\n", len, strerror(errno)); 89 | return; 90 | } 91 | 92 | do_mssfix(data, len); 93 | 94 | mylog(log_trace, "Received packet from tun,len: %d\n", len); 95 | 96 | char header = (got_feed_back == 0 ? header_new_connect : header_normal); 97 | from_normal_to_fec2(conn_info, udp_dest, data, len, header); 98 | } 99 | 100 | static void delay_manager_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) { 101 | assert(!(revents & EV_ERROR)); 102 | 103 | // do nothing 104 | } 105 | 106 | static void fec_encode_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) { 107 | assert(!(revents & EV_ERROR)); 108 | 109 | mylog(log_trace, "fec_encode_cb() called\n"); 110 | 111 | conn_info_t &conn_info = *((conn_info_t *)watcher->data); 112 | 113 | /// int ret; 114 | /// fd64_t fd64=watcher->u64; 115 | /// mylog(log_trace,"events[idx].data.u64 == conn_info.fec_encode_manager.get_timer_fd64()\n"); 116 | 117 | /// uint64_t value; 118 | /// if(!fd_manager.exist(fd64)) //fd64 has been closed 119 | ///{ 120 | /// mylog(log_trace,"!fd_manager.exist(fd64)"); 121 | /// return; 122 | /// } 123 | /// if((ret=read(fd_manager.to_fd(fd64), &value, 8))!=8) 124 | ///{ 125 | /// mylog(log_trace,"(ret=read(fd_manager.to_fd(fd64), &value, 8))!=8,ret=%d\n",ret); 126 | /// return; 127 | /// } 128 | /// if(value==0) 129 | ///{ 130 | /// mylog(log_debug,"value==0\n"); 131 | /// return; 132 | /// } 133 | /// assert(value==1); 134 | 135 | char header = (got_feed_back == 0 ? header_new_connect : header_normal); 136 | from_normal_to_fec2(conn_info, udp_dest, 0, 0, header); 137 | } 138 | 139 | static void conn_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) { 140 | assert(!(revents & EV_ERROR)); 141 | 142 | conn_info_t &conn_info = *((conn_info_t *)watcher->data); 143 | 144 | /// uint64_t value; 145 | /// read(conn_info.timer.get_timer_fd(), &value, 8); 146 | /// mylog(log_trace,"events[idx].data.u64==(u64_t)conn_info.timer.get_timer_fd()\n"); 147 | 148 | mylog(log_trace, "conn_timer_cb() called\n"); 149 | conn_info.stat.report_as_client(); 150 | if (got_feed_back) do_keep_alive(udp_dest); 151 | } 152 | 153 | static void fifo_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { 154 | assert(!(revents & EV_ERROR)); 155 | int fifo_fd = watcher->fd; 156 | 157 | char buf[buf_len]; 158 | int len = read(fifo_fd, buf, sizeof(buf)); 159 | if (len < 0) { 160 | mylog(log_warn, "fifo read failed len=%d,errno=%s\n", len, strerror(errno)); 161 | return; 162 | } 163 | buf[len] = 0; 164 | handle_command(buf); 165 | } 166 | 167 | static void prepare_cb(struct ev_loop *loop, struct ev_prepare *watcher, int revents) { 168 | assert(!(revents & EV_ERROR)); 169 | 170 | delay_manager.check(); 171 | } 172 | 173 | int tun_dev_client_event_loop() { 174 | // char data[buf_len]; 175 | // int len; 176 | int i, j, k, ret; 177 | int tun_fd; 178 | 179 | int remote_fd; 180 | fd64_t remote_fd64; 181 | 182 | conn_info_t *conn_info_p = new conn_info_t; 183 | conn_info_t &conn_info = *conn_info_p; // huge size of conn_info,do not allocate on stack 184 | 185 | tun_fd = get_tun_fd(tun_dev); 186 | assert(tun_fd > 0); 187 | 188 | assert(new_connected_socket2(remote_fd, remote_addr, out_addr, out_interface) == 0); 189 | remote_fd64 = fd_manager.create(remote_fd); 190 | 191 | assert(set_tun(tun_dev, htonl((ntohl(sub_net_uint32) & 0xFFFFFF00) | 2), htonl((ntohl(sub_net_uint32) & 0xFFFFFF00) | 1), tun_mtu) == 0); 192 | 193 | tun_dest.type = type_write_fd; 194 | tun_dest.inner.fd = tun_fd; 195 | 196 | udp_dest.cook = 1; 197 | udp_dest.type = type_fd64; 198 | udp_dest.inner.fd64 = remote_fd64; 199 | 200 | /// epoll_fd = epoll_create1(0); 201 | /// assert(epoll_fd>0); 202 | 203 | /// const int max_events = 4096; 204 | /// struct epoll_event ev, events[max_events]; 205 | /// if (epoll_fd < 0) { 206 | /// mylog(log_fatal,"epoll return %d\n", epoll_fd); 207 | /// myexit(-1); 208 | /// } 209 | 210 | struct ev_loop *loop = ev_default_loop(0); 211 | assert(loop != NULL); 212 | conn_info.loop = loop; 213 | 214 | /// ev.events = EPOLLIN; 215 | /// ev.data.u64 = remote_fd64; 216 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, remote_fd, &ev); 217 | /// if (ret!=0) { 218 | /// mylog(log_fatal,"add remote_fd64 error\n"); 219 | /// myexit(-1); 220 | /// } 221 | 222 | struct ev_io remote_watcher; 223 | remote_watcher.data = &conn_info; 224 | remote_watcher.u64 = remote_fd64; 225 | 226 | ev_io_init(&remote_watcher, remote_cb, remote_fd, EV_READ); 227 | ev_io_start(loop, &remote_watcher); 228 | 229 | /// ev.events = EPOLLIN; 230 | /// ev.data.u64 = tun_fd; 231 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tun_fd, &ev); 232 | /// if (ret!=0) { 233 | /// mylog(log_fatal,"add tun_fd error\n"); 234 | /// myexit(-1); 235 | /// } 236 | 237 | struct ev_io tun_fd_watcher; 238 | tun_fd_watcher.data = &conn_info; 239 | 240 | ev_io_init(&tun_fd_watcher, tun_fd_cb, tun_fd, EV_READ); 241 | ev_io_start(loop, &tun_fd_watcher); 242 | 243 | /// ev.events = EPOLLIN; 244 | /// ev.data.u64 = delay_manager.get_timer_fd(); 245 | 246 | /// mylog(log_debug,"delay_manager.get_timer_fd()=%d\n",delay_manager.get_timer_fd()); 247 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, delay_manager.get_timer_fd(), &ev); 248 | /// if (ret!= 0) { 249 | /// mylog(log_fatal,"add delay_manager.get_timer_fd() error\n"); 250 | /// myexit(-1); 251 | /// } 252 | 253 | delay_manager.set_loop_and_cb(loop, delay_manager_cb); 254 | 255 | /// u64_t tmp_timer_fd64=conn_info.fec_encode_manager.get_timer_fd64(); 256 | /// ev.events = EPOLLIN; 257 | /// ev.data.u64 = tmp_timer_fd64; 258 | 259 | /// mylog(log_debug,"conn_info.fec_encode_manager.get_timer_fd64()=%llu\n",conn_info.fec_encode_manager.get_timer_fd64()); 260 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd_manager.to_fd(tmp_timer_fd64), &ev); 261 | /// if (ret!= 0) { 262 | /// mylog(log_fatal,"add fec_encode_manager.get_timer_fd64() error\n"); 263 | /// myexit(-1); 264 | /// } 265 | 266 | conn_info.fec_encode_manager.set_data(&conn_info); 267 | conn_info.fec_encode_manager.set_loop_and_cb(loop, fec_encode_cb); 268 | 269 | // conn_info.timer.add_fd_to_epoll(epoll_fd); 270 | // conn_info.timer.data=&conn_info; 271 | 272 | conn_info.timer.data = &conn_info; 273 | ev_init(&conn_info.timer, conn_timer_cb); 274 | ev_timer_set(&conn_info.timer, 0, timer_interval / 1000.0); 275 | ev_timer_start(loop, &conn_info.timer); 276 | 277 | struct ev_io fifo_watcher; 278 | 279 | int fifo_fd = -1; 280 | 281 | if (fifo_file[0] != 0) { 282 | fifo_fd = create_fifo(fifo_file); 283 | /// ev.events = EPOLLIN; 284 | /// ev.data.u64 = fifo_fd; 285 | 286 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fifo_fd, &ev); 287 | /// if (ret!= 0) { 288 | /// mylog(log_fatal,"add fifo_fd to epoll error %s\n",strerror(errno)); 289 | /// myexit(-1); 290 | /// } 291 | ev_io_init(&fifo_watcher, fifo_cb, fifo_fd, EV_READ); 292 | ev_io_start(loop, &fifo_watcher); 293 | 294 | mylog(log_info, "fifo_file=%s\n", fifo_file); 295 | } 296 | 297 | ev_prepare prepare_watcher; 298 | ev_init(&prepare_watcher, prepare_cb); 299 | ev_prepare_start(loop, &prepare_watcher); 300 | 301 | ev_run(loop, 0); 302 | 303 | mylog(log_warn, "ev_run returned\n"); 304 | myexit(0); 305 | 306 | return 0; 307 | } 308 | -------------------------------------------------------------------------------- /tun_dev_server.cpp: -------------------------------------------------------------------------------- 1 | #include "tun_dev.h" 2 | 3 | static dest_t udp_dest; 4 | static dest_t tun_dest; 5 | 6 | static void local_listen_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { 7 | char data[buf_len]; 8 | int len; 9 | 10 | assert(!(revents & EV_ERROR)); 11 | 12 | conn_info_t &conn_info = *((conn_info_t *)watcher->data); 13 | 14 | int local_listen_fd = watcher->fd; 15 | 16 | // struct sockaddr_in udp_new_addr_in={0}; 17 | // socklen_t udp_new_addr_len = sizeof(sockaddr_in); 18 | address_t::storage_t udp_new_addr_in = {0}; 19 | socklen_t udp_new_addr_len = sizeof(address_t::storage_t); 20 | 21 | if ((len = recvfrom(local_listen_fd, data, max_data_len + 1, 0, 22 | (struct sockaddr *)&udp_new_addr_in, &udp_new_addr_len)) < 0) { 23 | mylog(log_error, "recv_from error,this shouldnt happen,err=%s,but we can try to continue\n", strerror(errno)); 24 | return; 25 | // myexit(1); 26 | }; 27 | 28 | address_t new_addr; 29 | new_addr.from_sockaddr((struct sockaddr *)&udp_new_addr_in, udp_new_addr_len); 30 | 31 | if (len == max_data_len + 1) { 32 | mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len); 33 | return; 34 | } 35 | 36 | if (de_cook(data, len) < 0) { 37 | mylog(log_warn, "de_cook(data,len)failed \n"); 38 | return; 39 | } 40 | 41 | char header = 0; 42 | if (get_header(header, data, len) != 0) { 43 | mylog(log_warn, "get_header() failed\n"); 44 | return; 45 | } 46 | 47 | if (udp_dest.inner.fd_addr.addr == new_addr) { 48 | if (header == header_keep_alive) { 49 | mylog(log_trace, "got keep_alive packet\n"); 50 | return; 51 | } 52 | 53 | if (header != header_new_connect && header != header_normal) { 54 | mylog(log_warn, "invalid header\n"); 55 | return; 56 | } 57 | } else { 58 | if (header == header_keep_alive) { 59 | mylog(log_debug, "got keep_alive packet from unexpected client\n"); 60 | return; 61 | } 62 | 63 | if (header == header_new_connect) { 64 | mylog(log_info, "new connection from %s\n", new_addr.get_str()); 65 | udp_dest.inner.fd_addr.addr = new_addr; 66 | // udp_dest.inner.fd_ip_port.ip_port.ip=udp_new_addr_in.sin_addr.s_addr; 67 | // udp_dest.inner.fd_ip_port.ip_port.port=ntohs(udp_new_addr_in.sin_port); 68 | conn_info.fec_decode_manager.clear(); 69 | conn_info.fec_encode_manager.clear_data(); 70 | conn_info.stat.clear(); 71 | } else if (header == header_normal) { 72 | mylog(log_debug, "rejected connection from %s\n", new_addr.get_str()); 73 | 74 | len = 1; 75 | data[0] = header_reject; 76 | do_cook(data, len); 77 | 78 | dest_t tmp_dest; 79 | tmp_dest.type = type_fd_addr; 80 | 81 | tmp_dest.inner.fd_addr.fd = local_listen_fd; 82 | tmp_dest.inner.fd_addr.addr = new_addr; 83 | 84 | delay_manager.add(0, tmp_dest, data, len); 85 | ; 86 | return; 87 | } else { 88 | mylog(log_warn, "invalid header\n"); 89 | } 90 | } 91 | 92 | mylog(log_trace, "Received packet from %s,len: %d\n", new_addr.get_str(), len); 93 | 94 | from_fec_to_normal2(conn_info, tun_dest, data, len); 95 | } 96 | static void tun_fd_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { 97 | char data[buf_len]; 98 | int len; 99 | 100 | assert(!(revents & EV_ERROR)); 101 | 102 | conn_info_t &conn_info = *((conn_info_t *)watcher->data); 103 | int tun_fd = watcher->fd; 104 | 105 | len = read(tun_fd, data, max_data_len + 1); 106 | 107 | if (len == max_data_len + 1) { 108 | mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len); 109 | return; 110 | } 111 | 112 | if (len < 0) { 113 | mylog(log_warn, "read from tun_fd return %d,errno=%s\n", len, strerror(errno)); 114 | return; 115 | } 116 | 117 | do_mssfix(data, len); 118 | 119 | mylog(log_trace, "Received packet from tun,len: %d\n", len); 120 | 121 | if (udp_dest.inner.fd_addr.addr.is_vaild() == 0) { 122 | mylog(log_debug, "received packet from tun,but there is no client yet,dropped packet\n"); 123 | return; 124 | } 125 | 126 | from_normal_to_fec2(conn_info, udp_dest, data, len, header_normal); 127 | } 128 | 129 | static void delay_manager_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) { 130 | assert(!(revents & EV_ERROR)); 131 | 132 | // do nothing 133 | } 134 | 135 | static void fec_encode_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) { 136 | assert(!(revents & EV_ERROR)); 137 | 138 | mylog(log_trace, "fec_encode_cb() called\n"); 139 | 140 | conn_info_t &conn_info = *((conn_info_t *)watcher->data); 141 | 142 | assert(udp_dest.inner.fd_addr.addr.is_vaild() != 0); 143 | /// mylog(log_trace,"events[idx].data.u64 == conn_info.fec_encode_manager.get_timer_fd64()\n"); 144 | /// uint64_t fd64=events[idx].data.u64; 145 | /// uint64_t value; 146 | /// if(!fd_manager.exist(fd64)) //fd64 has been closed 147 | ///{ 148 | /// mylog(log_trace,"!fd_manager.exist(fd64)"); 149 | /// continue; 150 | /// } 151 | /// if((ret=read(fd_manager.to_fd(fd64), &value, 8))!=8) 152 | ///{ 153 | /// mylog(log_trace,"(ret=read(fd_manager.to_fd(fd64), &value, 8))!=8,ret=%d\n",ret); 154 | /// continue; 155 | /// } 156 | /// if(value==0) 157 | ///{ 158 | /// mylog(log_debug,"value==0\n"); 159 | /// continue; 160 | /// } 161 | /// assert(value==1); 162 | 163 | from_normal_to_fec2(conn_info, udp_dest, 0, 0, header_normal); 164 | } 165 | 166 | static void fifo_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { 167 | assert(!(revents & EV_ERROR)); 168 | int fifo_fd = watcher->fd; 169 | 170 | char buf[buf_len]; 171 | int len = read(fifo_fd, buf, sizeof(buf)); 172 | if (len < 0) { 173 | mylog(log_warn, "fifo read failed len=%d,errno=%s\n", len, strerror(errno)); 174 | return; 175 | } 176 | buf[len] = 0; 177 | handle_command(buf); 178 | } 179 | 180 | static void conn_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) { 181 | assert(!(revents & EV_ERROR)); 182 | 183 | conn_info_t &conn_info = *((conn_info_t *)watcher->data); 184 | 185 | mylog(log_trace, "conn_timer_cb() called\n"); 186 | 187 | // uint64_t value; 188 | // read(conn_info.timer.get_timer_fd(), &value, 8); 189 | 190 | if (udp_dest.inner.fd_addr.addr.is_vaild() == 0) { 191 | return; 192 | } 193 | conn_info.stat.report_as_server(udp_dest.inner.fd_addr.addr); 194 | do_keep_alive(udp_dest); 195 | } 196 | 197 | static void prepare_cb(struct ev_loop *loop, struct ev_prepare *watcher, int revents) { 198 | assert(!(revents & EV_ERROR)); 199 | 200 | delay_manager.check(); 201 | } 202 | 203 | int tun_dev_server_event_loop() { 204 | int i, j, k, ret; 205 | int tun_fd; 206 | int local_listen_fd; 207 | 208 | conn_info_t *conn_info_p = new conn_info_t; 209 | conn_info_t &conn_info = *conn_info_p; // huge size of conn_info,do not allocate on stack 210 | 211 | tun_fd = get_tun_fd(tun_dev); 212 | assert(tun_fd > 0); 213 | 214 | assert(new_listen_socket2(local_listen_fd, local_addr) == 0); 215 | assert(set_tun(tun_dev, htonl((ntohl(sub_net_uint32) & 0xFFFFFF00) | 1), htonl((ntohl(sub_net_uint32) & 0xFFFFFF00) | 2), tun_mtu) == 0); 216 | 217 | udp_dest.cook = 1; 218 | udp_dest.type = type_fd_addr; 219 | 220 | udp_dest.inner.fd_addr.fd = local_listen_fd; 221 | udp_dest.inner.fd_addr.addr.clear(); 222 | 223 | tun_dest.type = type_write_fd; 224 | tun_dest.inner.fd = tun_fd; 225 | 226 | /// epoll_fd = epoll_create1(0); 227 | /// assert(epoll_fd>0); 228 | 229 | /// const int max_events = 4096; 230 | /// struct epoll_event ev, events[max_events]; 231 | /// if (epoll_fd < 0) { 232 | /// mylog(log_fatal,"epoll return %d\n", epoll_fd); 233 | /// myexit(-1); 234 | /// } 235 | 236 | struct ev_loop *loop = ev_default_loop(0); 237 | assert(loop != NULL); 238 | conn_info.loop = loop; 239 | 240 | /// ev.events = EPOLLIN; 241 | /// ev.data.u64 = local_listen_fd; 242 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, local_listen_fd, &ev); 243 | /// if (ret!=0) { 244 | /// mylog(log_fatal,"add udp_listen_fd error\n"); 245 | /// myexit(-1); 246 | /// } 247 | 248 | struct ev_io local_listen_watcher; 249 | local_listen_watcher.data = &conn_info; 250 | ev_io_init(&local_listen_watcher, local_listen_cb, local_listen_fd, EV_READ); 251 | ev_io_start(loop, &local_listen_watcher); 252 | 253 | /// ev.events = EPOLLIN; 254 | /// ev.data.u64 = tun_fd; 255 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tun_fd, &ev); 256 | /// if (ret!=0) { 257 | /// mylog(log_fatal,"add tun_fd error\n"); 258 | /// myexit(-1); 259 | /// } 260 | 261 | struct ev_io tun_fd_watcher; 262 | tun_fd_watcher.data = &conn_info; 263 | 264 | ev_io_init(&tun_fd_watcher, tun_fd_cb, tun_fd, EV_READ); 265 | ev_io_start(loop, &tun_fd_watcher); 266 | 267 | /// ev.events = EPOLLIN; 268 | /// ev.data.u64 = delay_manager.get_timer_fd(); 269 | 270 | /// mylog(log_debug,"delay_manager.get_timer_fd()=%d\n",delay_manager.get_timer_fd()); 271 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, delay_manager.get_timer_fd(), &ev); 272 | /// if (ret!= 0) { 273 | /// mylog(log_fatal,"add delay_manager.get_timer_fd() error\n"); 274 | /// myexit(-1); 275 | /// } 276 | 277 | delay_manager.set_loop_and_cb(loop, delay_manager_cb); 278 | 279 | /// u64_t tmp_timer_fd64=conn_info.fec_encode_manager.get_timer_fd64(); 280 | /// ev.events = EPOLLIN; 281 | /// ev.data.u64 = tmp_timer_fd64; 282 | 283 | /// mylog(log_debug,"conn_info.fec_encode_manager.get_timer_fd64()=%llu\n",conn_info.fec_encode_manager.get_timer_fd64()); 284 | /// ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd_manager.to_fd(tmp_timer_fd64), &ev); 285 | /// if (ret!= 0) { 286 | /// mylog(log_fatal,"add fec_encode_manager.get_timer_fd64() error\n"); 287 | /// myexit(-1); 288 | /// } 289 | 290 | conn_info.fec_encode_manager.set_data(&conn_info); 291 | conn_info.fec_encode_manager.set_loop_and_cb(loop, fec_encode_cb); 292 | 293 | /// conn_info.timer.add_fd_to_epoll(epoll_fd); 294 | /// conn_info.timer.set_timer_repeat_us(timer_interval*1000); 295 | 296 | conn_info.timer.data = &conn_info; 297 | ev_init(&conn_info.timer, conn_timer_cb); 298 | ev_timer_set(&conn_info.timer, 0, timer_interval / 1000.0); 299 | ev_timer_start(loop, &conn_info.timer); 300 | 301 | struct ev_io fifo_watcher; 302 | int fifo_fd = -1; 303 | 304 | if (fifo_file[0] != 0) { 305 | fifo_fd = create_fifo(fifo_file); 306 | 307 | ev_io_init(&fifo_watcher, fifo_cb, fifo_fd, EV_READ); 308 | ev_io_start(loop, &fifo_watcher); 309 | 310 | mylog(log_info, "fifo_file=%s\n", fifo_file); 311 | } 312 | 313 | ev_prepare prepare_watcher; 314 | ev_init(&prepare_watcher, prepare_cb); 315 | ev_prepare_start(loop, &prepare_watcher); 316 | 317 | mylog(log_info, "now listening at %s\n", local_addr.get_str()); 318 | 319 | ev_run(loop, 0); 320 | 321 | mylog(log_warn, "ev_run returned\n"); 322 | myexit(0); 323 | 324 | return 0; 325 | } 326 | --------------------------------------------------------------------------------