Compare commits

..
Author SHA1 Message Date
xtaci 4c3c41f8d4 set default dscp value to 0 2016-06-04 18:05:33 +08:00
Daniel Fu 873ae40da8 Update README.md 2016-06-04 11:10:31 +08:00
Daniel Fu 2609d75729 Update README.md 2016-06-04 11:08:10 +08:00
Daniel Fu 2ca0d39306 Update README.md 2016-06-04 11:07:22 +08:00
Daniel Fu 3f53280c84 Update README.md 2016-06-04 10:46:40 +08:00
Daniel Fu 9a5a3a2d8c Update README.md 2016-06-04 10:11:58 +08:00
Daniel Fu 2e989b4869 Update README.md 2016-06-04 10:02:48 +08:00
Daniel Fu 2aececab60 Update README.md 2016-06-04 09:56:32 +08:00
Daniel Fu c12f4fef0b Update README.md 2016-06-04 09:53:13 +08:00
Daniel Fu 096b889e57 Update README.md 2016-06-04 08:54:10 +08:00
Daniel Fu ad11f03a5c Add files via upload 2016-06-03 16:23:33 +08:00
xtaci 026c862226 update 2016-06-03 14:16:06 +08:00
Daniel Fu e56788c401 Add files via upload 2016-06-03 14:14:44 +08:00
Daniel Fu b64545e874 Add files via upload 2016-06-03 14:14:10 +08:00
Daniel Fu 3052d2a617 Add files via upload 2016-06-03 14:12:48 +08:00
xtaci 3243a14113 add hidden manual control of SetNoDelay parameters 2016-06-03 09:44:02 +08:00
xtaci c40cf88112 Merge branch 'master' of https://github.com/xtaci/kcptun 2016-06-02 21:59:27 +08:00
xtaci 2e7a709727 update upper limit of yamux window for 4k video 2016-06-02 21:58:49 +08:00
Daniel Fu 1278597aa2 Update README.md 2016-06-02 17:26:11 +08:00
Daniel Fu 12b7f2c41b Update README.md 2016-06-02 15:45:34 +08:00
xtaci d3d1148c05 use DialTimeout 2016-06-02 10:32:01 +08:00
Daniel Fu 02d48968e1 Add files via upload 2016-06-01 22:30:41 +08:00
xtaci 16b4eec5aa rollback 2016-06-01 15:01:04 +08:00
xtaci 2df5992b4f adjust param 2016-06-01 14:13:33 +08:00
xtaci 41358f41cc cond +build signal 2016-06-01 11:12:48 +08:00
xtaci 400993f22e send -SIGUSR1 to dump KCP snmp 2016-06-01 10:52:12 +08:00
xtaci 4d935d26a2 update default param 2016-05-31 21:39:31 +08:00
xtaci 99c4cb92b9 expose SetNoDelay 2016-05-31 21:37:17 +08:00
xtaci 444533d7ff add freebsd compile 2016-05-31 13:22:06 +08:00
xtaci dc2fb504be api rename 2016-05-31 10:27:20 +08:00
Daniel Fu 33fc58594c Add files via upload 2016-05-30 14:11:57 +08:00
Daniel Fu 79e61bbd64 Add files via upload 2016-05-30 14:10:57 +08:00
Daniel Fu d98981fe2e Add files via upload 2016-05-30 14:07:59 +08:00
Daniel Fu 703467772e Delete kcptun.jpg 2016-05-30 13:49:21 +08:00
Daniel Fu 9e93e6513b Update README.md 2016-05-30 13:49:00 +08:00
Daniel Fu 1f50278b92 Add files via upload 2016-05-30 13:48:19 +08:00
Daniel Fu b4c32d780d Update README.md 2016-05-29 17:22:08 +08:00
Daniel Fu 64fe3280cd Update README.md 2016-05-29 17:14:52 +08:00
Daniel Fu 0b5ac4a446 Update README.md 2016-05-29 17:14:04 +08:00
Daniel Fu 1ebb4b6b01 Update README.md 2016-05-29 17:11:06 +08:00
Daniel Fu 661b1d75dd Add files via upload 2016-05-29 17:10:07 +08:00
Daniel Fu fb8a855bd9 Delete kitty.jpg 2016-05-29 17:00:39 +08:00
Daniel Fu 9062d4c96f Update README.md 2016-05-29 16:59:23 +08:00
Daniel Fu a831e341e3 Update README.md 2016-05-29 16:58:07 +08:00
Daniel Fu d7b268557a Add files via upload 2016-05-29 16:57:23 +08:00
xtaci 0629ab556e update import path 2016-05-27 14:15:53 +08:00
xtaci 4d3aa0b43a update build script 2016-05-26 15:51:43 +08:00
xtaci 715b1e8ddb update build-release.sh 2016-05-26 15:37:01 +08:00
Daniel Fu 63582adb78 Add files via upload 2016-05-26 13:35:37 +08:00
Daniel Fu 3b63a66b5c Update README.md 2016-05-26 13:34:03 +08:00
Daniel Fu ddd1300622 Add files via upload 2016-05-26 13:32:19 +08:00
xtaci 0eab8c2c04 既定値改正-DSCP 2016-05-26 13:15:07 +08:00
xtaci 3677cbc254 Merge branch 'master' of https://github.com/xtaci/kcptun 2016-05-26 13:13:04 +08:00
xtaci e048af8217 既定値改正 2016-05-26 13:12:47 +08:00
Daniel Fu b09c06d702 Update README.md 2016-05-26 11:29:41 +08:00
Daniel Fu 0be724cb99 Update README.md 2016-05-26 11:24:09 +08:00
xtaci ed7a0273c8 optional -dscp 2016-05-25 11:17:43 +08:00
xtaci b24b5db01c expose acknodelay option 2016-05-24 21:03:48 +08:00
xtaci 81d959cf85 update 2016-05-23 15:05:08 +08:00
xtaci b4749f5f77 update 2016-05-23 14:53:15 +08:00
xtaci b3be11c6fd update para 2016-05-23 14:19:49 +08:00
xtaci 37861c401e disable yamux ping 2016-05-23 12:25:07 +08:00
xtaci 3a335ac6db lower ping interval for NAT 2016-05-23 11:33:05 +08:00
xtaci 1c1f229cf8 reduce window 2016-05-21 23:31:45 +08:00
xtaci 43cf6d79f0 adjust ping to keep udp nat 2016-05-21 21:39:06 +08:00
xtaci 034d0f1b45 Merge branch 'master' of https://github.com/xtaci/kcptun 2016-05-21 14:54:43 +08:00
xtaci e8779394a6 update keepalive interval 2016-05-21 14:54:17 +08:00
Daniel Fu 1bd2a2ed23 Update README.md 2016-05-21 10:30:47 +08:00
xtaci 674a89f14f fully remove tuncrypt option, implement your own TLS instead 2016-05-21 10:15:54 +08:00
xtaci 89569c2f77 print fec 2016-05-20 22:40:02 +08:00
xtaci 7a89fcf55b update 2016-05-20 20:44:05 +08:00
xtaci dc1c71fbe3 Merge branch 'master' of https://github.com/xtaci/kcptun 2016-05-20 18:25:14 +08:00
xtaci 311e8c12e6 add fec support 2016-05-20 18:24:50 +08:00
Daniel Fu 76ab196896 Update README.md 2016-05-19 13:03:47 +08:00
Daniel Fu 24301b3439 Update README.md 2016-05-19 13:02:45 +08:00
Daniel Fu fac523783a Update README.md 2016-05-19 12:37:13 +08:00
Daniel Fu 6c5f0e69f5 Update README.md 2016-05-19 12:33:02 +08:00
Daniel Fu 7c0c8585a7 Add files via upload 2016-05-19 11:25:39 +08:00
xtaci 10b9086cc5 update init param 2016-05-18 12:21:40 +08:00
xtaci a79537f9c6 adjust rcvwnd to relatively *SAFE* download bandwidth 2016-05-17 16:49:26 +08:00
Daniel Fu caeba21983 Update README.md 2016-05-17 14:18:17 +08:00
Daniel Fu dc55b833e1 Update README.md 2016-05-17 10:47:16 +08:00
xtaci 212475da5f update parameters 2016-05-17 10:28:16 +08:00
xtaci 2f1f2e2420 Merge branch 'master' of https://github.com/xtaci/kcptun 2016-05-15 20:19:26 +08:00
xtaci 37f9a54d47 update -h 2016-05-15 20:18:48 +08:00
Daniel Fu 415762db23 Update README.md 2016-05-15 00:09:04 +08:00
Daniel Fu 924af51f5d Update README.md 2016-05-15 00:05:22 +08:00
Daniel Fu eab6b2fae6 Update README.md 2016-05-14 23:44:36 +08:00
Daniel Fu 85bda086c9 Update README.md 2016-05-14 18:11:43 +08:00
xtaci 2d0feed5dc modify ldflags to reduce executable size 2016-05-14 17:17:42 +08:00
Daniel Fu 1769371b7d Update README.md 2016-05-14 16:13:04 +08:00
Daniel Fu 6c0e9b3b91 Update README.md 2016-05-14 16:06:46 +08:00
Daniel Fu 60e4201d2a Update README.md 2016-05-14 16:00:47 +08:00
xtaci 8b61a91ef0 commit message 2016-05-14 15:54:59 +08:00
21 changed files with 207 additions and 1385 deletions
-27
View File
@@ -1,27 +0,0 @@
问问题前先搜索ISSUE,并搞清楚下面的问题:
1. 检查 ```-key xxx``` 至少三遍, ***保证***两边一致。
2. 保证```-nocomp, -datashard, -parityshard, -key, -crypt```两边一致。
3. 是否在服务器端,正确设定了转发的目标服务器地址 ***--target***。
4. 如果第3条不确定,尝试在服务器上telnet target port试试。
5. 防火墙是否关闭了UDP通信。
6. 两端的版本是否一致?
7. 是不是最新版本?
8. 两端分别是什么操作系统?
9. 两端的输出日志是什么?
Before firing issue, make sure you figured out the following common questions.
PLEASE DO SEARCH FIRST.
1. Check your ```-key xxx``` for at least 3 times, ***MAKE SURE*** both sides share the same secret.
2. ```-nocomp, -datashard, -parityshard, -key, -crypt``` ***must be the same*** on both side.
3. Did you correctly set the ***-target*** on the server side?
4. ***MAKE SURE*** ```telnet target port``` on your server successful(don't ask me why couldn't).
5. Does your ***firewall allows UDP*** communications? (including your ISP Cable-Modem)
6. Are you using the **same version** for both client & server
7. Are you using the **latest release**?
8. Which **OS** do you use?
9. Which end for this issue related to, **client or server**?
-16
View File
@@ -1,16 +0,0 @@
language: go
go:
- 1.6
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
install:
- go get github.com/xtaci/kcptun/client
- go get github.com/xtaci/kcptun/server
before_script:
script:
- cd $HOME/gopath/src/github.com/xtaci/kcptun/client
- $HOME/gopath/bin/goveralls -service=travis-ci
- cd $HOME/gopath/src/github.com/xtaci/kcptun/server
- $HOME/gopath/bin/goveralls -service=travis-ci
- exit 0
+3 -5
View File
@@ -1,8 +1,6 @@
FROM golang:alpine
FROM golang:latest
MAINTAINER xtaci <daniel820313@gmail.com>
RUN apk update && \
apk upgrade && \
apk add git
RUN go get github.com/xtaci/kcptun/client && go get github.com/xtaci/kcptun/server
RUN go get github.com/xtaci/kcptun/client
RUN go get github.com/xtaci/kcptun/server
EXPOSE 29900/udp
EXPOSE 12948
-250
View File
@@ -1,250 +0,0 @@
# <img src="logo.png" alt="kcptun" height="60px" />
[![Release][13]][14] [![Powered][17]][18] [![MIT licensed][11]][12] [![Build Status][3]][4] [![Go Report Card][5]][6] [![Downloads][15]][16] [![Gitter][19]][20] [![Docker][1]][2]
[1]: https://images.microbadger.com/badges/image/xtaci/kcptun.svg
[2]: https://microbadger.com/images/xtaci/kcptun
[3]: https://travis-ci.org/xtaci/kcptun.svg?branch=master
[4]: https://travis-ci.org/xtaci/kcptun
[5]: https://goreportcard.com/badge/github.com/xtaci/kcptun
[6]: https://goreportcard.com/report/github.com/xtaci/kcptun
[7]: https://img.shields.io/badge/license-MIT-blue.svg
[8]: https://raw.githubusercontent.com/xtaci/kcptun/master/LICENSE.md
[9]: https://img.shields.io/github/stars/xtaci/kcptun.svg
[10]: https://github.com/xtaci/kcptun/stargazers
[11]: https://img.shields.io/badge/license-MIT-blue.svg
[12]: LICENSE.md
[13]: https://img.shields.io/github/release/xtaci/kcptun.svg
[14]: https://github.com/xtaci/kcptun/releases/latest
[15]: https://img.shields.io/github/downloads/xtaci/kcptun/total.svg?maxAge=1800
[16]: https://github.com/xtaci/kcptun/releases
[17]: https://img.shields.io/badge/KCP-Powered-blue.svg
[18]: https://github.com/skywind3000/kcp
[19]: https://badges.gitter.im/xtaci/kcptun.svg
[20]: https://gitter.im/xtaci/kcptun?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
A tool for converting tcp stream into kcp+udp stream, :zap: ***[download address](https://github.com/xtaci/kcptun/releases/latest)***:zap:
![kcptun](kcptun.png)
***kcptun is based on [kcp-go](https://github.com/xtaci/kcp-go)***
### *QuickStart* :lollipop:
Client, server, respectively, download the corresponding platform binary compression package, and extract, through the following command to start port forwarding.
```
Server: ./server_linux_amd64 -t "SERVER_IP:8388" -l ":4000" -mode fast2
Client: ./client_darwin_amd64 -r "SERVER_IP:4000" -l ":8388" -mode fast2
```
The above command can establish 8388/tcp port forwarding (through 4000/udp port).
### *Performance* :lollipop:
<img src="fast.png" alt="fast.com" height="256px" />
* Speed tested with: https://fast.com
* WAN Link Speed: 100M ADSL
* WIFI: 5GHz TL-WDR3320
### *Usage* :lollipop:
Help output under MacOS X:
```
$ ./client_darwin_amd64 -h
NAME:
kcptun - client(with SMUX)
USAGE:
client_darwin_amd64 [global options] command [command options] [arguments...]
VERSION:
20160922
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--localaddr value, -l value local listen address (default: ":12948")
--remoteaddr value, -r value kcp server address (default: "vps:29900")
--key value pre-shared secret between client and server (default: "it's a secrect") [$KCPTUN_KEY]
--crypt value aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none (default: "aes")
--mode value profiles: fast3, fast2, fast, normal (default: "fast")
--conn value set num of UDP connections to server (default: 1)
--autoexpire value set auto expiration time(in seconds) for a single UDP connection, 0 to disable (default: 0)
--mtu value set maximum transmission unit for UDP packets (default: 1350)
--sndwnd value set send window size(num of packets) (default: 128)
--rcvwnd value set receive window size(num of packets) (default: 1024)
--datashard value set reed-solomon erasure coding - datashard (default: 10)
--parityshard value set reed-solomon erasure coding - parityshard (default: 3)
--dscp value set DSCP(6bit) (default: 0)
--nocomp disable compression
--log value specify a log file to output, default goes to stderr
-c value config from json file, which will override the command from shell
--help, -h show help
--version, -v print the version
$ ./server_darwin_amd64 -h
NAME:
kcptun - server(with SMUX)
USAGE:
server_darwin_amd64 [global options] command [command options] [arguments...]
VERSION:
20160922
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--listen value, -l value kcp server listen address (default: ":29900")
--target value, -t value target server address (default: "127.0.0.1:12948")
--key value pre-shared secret between client and server (default: "it's a secrect") [$KCPTUN_KEY]
--crypt value aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none (default: "aes")
--mode value profiles: fast3, fast2, fast, normal (default: "fast")
--mtu value set maximum transmission unit for UDP packets (default: 1350)
--sndwnd value set send window size(num of packets) (default: 1024)
--rcvwnd value set receive window size(num of packets) (default: 1024)
--datashard value set reed-solomon erasure coding - datashard (default: 10)
--parityshard value set reed-solomon erasure coding - parityshard (default: 3)
--dscp value set DSCP(6bit) (default: 0)
--nocomp disable compression
--log value specify a log file to output, default goes to stderr
-c value config from json file, which will override the command from shell
--help, -h show help
--version, -v print the version
```
#### *Parameters by Layers* :lollipop:
<p align="left"><img src="layeredparams.png" alt="params" height="450px"/></p>
### *Applications* :lollipop:
1. Real-time gaming.
2. Cross-ISP data exchange in PRC.
3. Other lossy network.
### *Parameters* :lollipop:
***Both sides must agree on the following parameters:***
* datashard
* parityshard
* nocomp
* key
* crypt
other parameters can be set independently.
*How to optimize*
> Step 1Increase client rcvwnd & server sndwnd simultaneously & gradually。
> Step 2Try download something and observer, if the bandwidth usage is close the limit then stop, otherwise goto step 1.
***NOTICE: if too much retranmission happens, it's quite possible the windows are too large***
### *Security* :lollipop:
No matter what encryption you are using for application layer, if you specify ```-crypt none``` to kcptun,
the header will be ***PLAINTEXT*** to everyone; I suggest ```-crypt aes-128``` for encryption at least .
NOTICE: ```-crypt xor``` is also insecure, do not use this unless you know what you are doing.
### *Memory Control* :lollipop:
Routers, mobile devices are sensitive to memory consumption; by setting GOGC environment(eg: GOGC=20) will lower memory consumption.
Reference: https://blog.golang.org/go15gc
### *Traffic Control* :lollipop:
***Intended audience : for those server's bandwidth is quite limited.***
Example: To limit outgoing bandwidth to 32mbit/s on server.
```
root@kcptun:~# cat tc.sh
tc qdisc del dev eth0 root
tc qdisc add dev eth0 root handle 1: htb
tc class add dev eth0 parent 1: classid 1:1 htb rate 32mbit
tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 10 fw flowid 1:1
iptables -t mangle -A POSTROUTING -o eth0 -j MARK --set-mark 10
root@kcptun:~#
```
### *DSCP* :lollipop:
Differentiated services or DiffServ is a computer networking architecture that specifies a simple, scalable and coarse-grained mechanism for classifying and managing network traffic and providing quality of service (QoS) on modern IP networks. DiffServ can, for example, be used to provide low-latency to critical network traffic such as voice or streaming media while providing simple best-effort service to non-critical services such as web traffic or file transfers.
DiffServ uses a 6-bit differentiated services code point (DSCP) in the 8-bit differentiated services field (DS field) in the IP header for packet classification purposes. The DS field and ECN field replace the outdated IPv4 TOS field.[1]
setting each side with ```-dscp value```.
### *Embeded Mode* :lollipop:
Latency:
*fast3 >* ***[fast2]*** *> fast > normal > default*
Payload Ratio:
*default > normal > fast >* ***[fast2]*** *> fast3*
Parameters in middle is balanced for latency & payload ratio, the faster you get the more wasteful you are.
Manual control is supported with hidden parameters, you must understand KCP protocol before doing this.
```
-mode manual -nodelay 1 -resend 2 -nc 1 -interval 20
```
I suggest fast2 for high-loss network, normal for low-loss network.
### *Forward Error Correction* :lollipop:
In coding theory, the ReedSolomon code belongs to the class of non-binary cyclic error-correcting codes. The ReedSolomon code is based on univariate polynomials over finite fields.
It is able to detect and correct multiple symbol errors. By adding t check symbols to the data, a ReedSolomon 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. Furthermore, ReedSolomon codes are 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.
![reed-solomon](rs.png)
Setting parameters of RS-Code with ```-datashard m -parityshard n```
### *Snappy Stream Compression* :lollipop:
> Snappy is a compression/decompression library. It does not aim for maximum
> compression, or compatibility with any other compression library; instead,
> it aims for very high speeds and reasonable compression. For instance,
> compared to the fastest mode of zlib, Snappy is an order of magnitude faster
> for most inputs, but the resulting compressed files are anywhere from 20% to
> 100% bigger.
> Reference: http://google.github.io/snappy/
disable compression by setting ```-nocomp``` on both side.
> Tips: Turning off compression may reduce latency.
### *SNMP* :lollipop:
```go
// Snmp defines network statistics indicator
type Snmp struct {
BytesSent uint64 // payload bytes sent
BytesReceived uint64
MaxConn uint64
ActiveOpens uint64
PassiveOpens uint64
CurrEstab uint64
InErrs uint64
InCsumErrors uint64 // checksum errors
InSegs uint64
OutSegs uint64
OutBytes uint64 // udp bytes sent
RetransSegs uint64
FastRetransSegs uint64
EarlyRetransSegs uint64
LostSegs uint64
RepeatSegs uint64
FECRecovered uint64
FECErrs uint64
FECSegs uint64 // fec segments received
}
```
Sending a signal by ```kill -SIGUSR1 pid``` will give SNMP information for KCPuseful for fine-grained adjustment.
Of which ```RetransSegs,FastRetransSegs,LostSegs,OutSegs``` is the most useful.
### *Donations* :dollar:
![donate](donate.png)
Best wishes to you all.
### *References* :paperclip:
1. https://github.com/skywind3000/kcp -- KCP - A Fast and Reliable ARQ Protocol.
2. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go.
3. https://en.wikipedia.org/wiki/Differentiated_services -- DSCP.
4. http://google.github.io/snappy/ -- A fast compressor/decompressor.
5. https://www.backblaze.com/blog/reed-solomon/ -- Reed-Solomon Explained.
6. http://www.qualcomm.cn/products/raptorq -- RaptorQ Forward Error Correction Scheme for Object Delivery.
7. https://en.wikipedia.org/wiki/PBKDF2 -- Key stretching.
8. http://blog.appcanary.com/2016/encrypt-or-compress.html -- Should you encrypt or compress first?
9. https://github.com/hashicorp/yamux -- Connection multiplexing library.
10. https://tools.ietf.org/html/rfc6937 -- Proportional Rate Reduction for TCP.
11. https://tools.ietf.org/html/rfc5827 -- Early Retransmit for TCP and Stream Control Transmission Protocol (SCTP).
12. http://http2.github.io/ -- What is HTTP/2?
13. http://www.lartc.org/ -- Linux Advanced Routing & Traffic Control
+52 -341
View File
@@ -1,362 +1,73 @@
<p align="center"><img src="logo.png" alt="kcptun" height="60px" /></p>
<p align="center"><em>A Simple UDP Tunnel Based On KCP</em></p>
# *kcptun*
TCP流转换为KCP+UDP流,:zap:***[下载地址](https://github.com/xtaci/kcptun/releases/latest)***:zap:工作示意图:
-
![kcptun](kcptun.png)
[![Release][13]][14] [![Powered][17]][18] [![MIT licensed][11]][12] [![Build Status][3]][4] [![Go Report Card][5]][6] [![Downloads][15]][16] [![Gitter][19]][20] [![Docker][1]][2]
[1]: https://images.microbadger.com/badges/image/xtaci/kcptun.svg
[2]: https://microbadger.com/images/xtaci/kcptun
[3]: https://travis-ci.org/xtaci/kcptun.svg?branch=master
[4]: https://travis-ci.org/xtaci/kcptun
[5]: https://goreportcard.com/badge/github.com/xtaci/kcptun
[6]: https://goreportcard.com/report/github.com/xtaci/kcptun
[7]: https://img.shields.io/badge/license-MIT-blue.svg
[8]: https://raw.githubusercontent.com/xtaci/kcptun/master/LICENSE.md
[11]: https://img.shields.io/badge/license-MIT-blue.svg
[12]: LICENSE.md
[13]: https://img.shields.io/github/release/xtaci/kcptun.svg
[14]: https://github.com/xtaci/kcptun/releases/latest
[15]: https://img.shields.io/github/downloads/xtaci/kcptun/total.svg?maxAge=1800
[16]: https://github.com/xtaci/kcptun/releases
[17]: https://img.shields.io/badge/KCP-Powered-blue.svg
[18]: https://github.com/skywind3000/kcp
[19]: https://badges.gitter.im/xtaci/kcptun.svg
[20]: https://gitter.im/xtaci/kcptun?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
***kcptun是[kcp](https://github.com/xtaci/kcp-go)协议的一个简单应用,可以用于任意tcp网络程序的传输承载,以提高网络流畅度,降低掉线情况。***
<p align="center"><img src="kcptun.png" alt="kcptun" height="200px"/></p>
<p align="center"><a href="https://github.com/xtaci/kcptun/releases/latest">立即安装</a></p>
<p align="center"><em>支持macOS/Linux/Windows/FreeBSD/ARM/Raspberry Pi/OpenWrt</em></p>
<p align="right"><a href="https://github.com/xtaci/kcptun/blob/master/README.en.md">ENGLISH VERSION</a></p>
### *使用の方法* :lollipop:
![client](client.png)
![server](server.png)
-
### 手动编译
```
$go get -u github.com/xtaci/kcptun/client
$go get -u github.com/xtaci/kcptun/server
```
注意: 如果出现错误提示,请确保依赖库能正确访问到。
Release中的所有二进制版本,是通过 `build-release.sh` 脚本生成并优化。
### 快速设定
客户端、服务器分别**下载**对应平台的二进制压缩包,并**解压**,通过下面的命令**启动**端口转发。
```
服务器: ./server_linux_amd64 -t "服务器IP地址:8388" -l ":4000" -mode fast2
客户端: ./client_darwin_amd64 -r "服务器IP地址:4000" -l ":8388" -mode fast2
```
以上命令可以实现8388/tcp端口的转发(通过4000/udp端口)。
### 速度对比
<img src="fast.png" alt="fast.com" height="256px" />
* 测速网站: https://fast.com
* 接入速度: 100Mbps
* WIFI: 5GHz TL-WDR3320
### 使用方法
在Mac OS X El Capitan下的帮助输出,注意默认值:
```
$ ./client_darwin_amd64 -h
NAME:
kcptun - client(with SMUX)
USAGE:
client_darwin_amd64 [global options] command [command options] [arguments...]
VERSION:
20161025
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--localaddr value, -l value local listen address (default: ":12948")
--remoteaddr value, -r value kcp server address (default: "vps:29900")
--key value pre-shared secret between client and server (default: "it's a secrect") [$KCPTUN_KEY]
--crypt value aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none (default: "aes")
--mode value profiles: fast3, fast2, fast, normal (default: "fast")
--conn value set num of UDP connections to server (default: 1)
--autoexpire value set auto expiration time(in seconds) for a single UDP connection, 0 to disable (default: 0)
--mtu value set maximum transmission unit for UDP packets (default: 1350)
--sndwnd value set send window size(num of packets) (default: 128)
--rcvwnd value set receive window size(num of packets) (default: 1024)
--datashard value set reed-solomon erasure coding - datashard (default: 10)
--parityshard value set reed-solomon erasure coding - parityshard (default: 3)
--dscp value set DSCP(6bit) (default: 0)
--nocomp disable compression
--log value specify a log file to output, default goes to stderr
-c value config from json file, which will override the command from shell
--help, -h show help
--version, -v print the version
$ ./server_darwin_amd64 -h
NAME:
kcptun - server(with SMUX)
USAGE:
server_darwin_amd64 [global options] command [command options] [arguments...]
VERSION:
20161025
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--listen value, -l value kcp server listen address (default: ":29900")
--target value, -t value target server address (default: "127.0.0.1:12948")
--key value pre-shared secret between client and server (default: "it's a secrect") [$KCPTUN_KEY]
--crypt value aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none (default: "aes")
--mode value profiles: fast3, fast2, fast, normal (default: "fast")
--mtu value set maximum transmission unit for UDP packets (default: 1350)
--sndwnd value set send window size(num of packets) (default: 1024)
--rcvwnd value set receive window size(num of packets) (default: 1024)
--datashard value set reed-solomon erasure coding - datashard (default: 10)
--parityshard value set reed-solomon erasure coding - parityshard (default: 3)
--dscp value set DSCP(6bit) (default: 0)
--nocomp disable compression
--log value specify a log file to output, default goes to stderr
-c value config from json file, which will override the command from shell
--help, -h show help
--version, -v print the version
```
#### 分层参数图
<p align="left"><img src="layeredparams.png" alt="params" height="450px"/></p>
**两端参数必须一致的有**:
* datashard --前向纠错
* parityshard --前向纠错
* nocomp --压缩
* key --密钥
* crypt --加密算法
其余为两边可独立设定的参数
### 内置模式
### *适用范围限定* :lollipop:
1. 实时网络游戏的数据传输
2. 跨运营商的流量传输
3. 其他高丢包通信链路的TCP承载
### *内置模式* :lollipop:
响应速度:
*fast3 > fast2 >* **[fast]** *> normal > default*
*fast3 >* ***[fast2]*** *> fast > normal > default*
有效载荷比:
*default > normal >* **[fast]** *> fast2 > fast3*
中间-mode参数比较均衡,总之就是越快,包重传越激进。
更高级的 **手动档** 需要理解KCP协议,并通过 **隐藏参数** 调整,例如:
*default > normal > fast >* ***[fast2]*** *> fast3*
中间mode参数比较均衡,总之就是越快越浪费带宽,推荐模式 ***fast2***
更高级的 ***手动档*** 需要理解KCP协议,并通过 ***隐藏参数*** 调整,例如:
```
-mode manual -nodelay 1 -resend 2 -nc 1 -interval 20
-mode manual -nodelay 1 -resend 4 -nc 1 -interval 20 -fec 4
```
* 搭配1. fast + FEC(5,5)
* 搭配2. fast2 + FEC(10,3)
* 搭配3. fast2 + FEC(0,0)
默认profile参考: https://github.com/xtaci/kcptun/blob/master/client/main.go#L248
### 前向纠错
前向纠错采用Reed Solomon纠删码, 它的基本原理如下: 给定n个数据块d1, d2,…, dn,n和一个正整数m, RS根据n个数据块生成m个校验块, c1, c2,…, cm。 对于任意的n和m, 从n个原始数据块和m 个校验块中任取n块就能解码出原始数据, 即RS最多**容忍m个数据块或者校验块同时丢失**。
![reed-solomon](rs.png)
通过参数```-datashard n -parityshard m``` 在两端同时设定。
数据包发送顺序严格遵循: n个datashard紧接m个parityshard,重复。
注意:为了发挥FEC最佳效果,设置 parityshard/(parity+datashard) > packet loss,比如5/(5+5) > 30%
### 窗口调整
**简易窗口自我调优方法**
> 第一步:同时在两端逐步增大client rcvwnd和server sndwnd;
> 第二步:尝试下载,观察如果带宽利用率(服务器+客户端两端都要观察)到达预期则停止,否则跳转到第一步。
**注意:产生大量重传时,一定是窗口偏大了**
### 安全
无论你上层如何加密,如果```-crypt none```,那么**协议头部**都是**明文**的,建议至少采用```-crypt aes-128```加密,并修改密码。
密码可以通过`-key`指定,也可以通过环境变量`KCPTUN_KEY`指定。
注意: ```-crypt xor``` 也是不安全的,除非你知道你在做什么。
附加密速度Benchmark
```
BenchmarkAES128-4 200000 11182 ns/op
BenchmarkAES192-4 200000 12699 ns/op
BenchmarkAES256-4 100000 13757 ns/op
BenchmarkTEA-4 50000 26441 ns/op
BenchmarkSimpleXOR-4 3000000 441 ns/op
BenchmarkBlowfish-4 30000 48036 ns/op
BenchmarkNone-4 20000000 106 ns/op
BenchmarkCast5-4 20000 60222 ns/op
BenchmarkTripleDES-4 2000 878759 ns/op
BenchmarkTwofish-4 20000 68501 ns/op
BenchmarkXTEA-4 20000 77417 ns/op
BenchmarkSalsa20-4 300000 4998 ns/op
```
### 内存控制
路由器,手机等嵌入式设备通常对**内存用量敏感**,通过调节环境变量GOGC(例如GOGC=20)后启动client,可以降低内存使用。
参考:https://blog.golang.org/go15gc
### DSCP
DSCP差分服务代码点(Differentiated Services Code Point),IETF于1998年12月发布了Diff-ServDifferentiated Service)的QoS分类标准。它在每个数据包IP头部的服务类别TOS标识字节中,利用已使用的**6比特**和未使用的2比特,通过编码值来区分优先级。
常用DSCP值可以参考[Wikipedia DSCP](https://en.wikipedia.org/wiki/Differentiated_services#Commonly_used_DSCP_values),至于有没有用,完全取决于数据包经过的设备。
通过 ```-dscp ``` 参数指定dscp值,两端可分别设定。
注意:设置dscp不一定会更好,需要尝试。
### Snappy数据流压缩
> Snappy is a compression/decompression library. It does not aim for maximum
> compression, or compatibility with any other compression library; instead,
> it aims for very high speeds and reasonable compression. For instance,
> compared to the fastest mode of zlib, Snappy is an order of magnitude faster
> for most inputs, but the resulting compressed files are anywhere from 20% to
> 100% bigger.
> Reference: http://google.github.io/snappy/
压缩对于非加密,非压缩的数据能降低传输数据量,比如点对点的HTTP数据转发。
通过参数 ```-nocomp``` 在两端同时设定以关闭压缩。
> 提示: 关闭压缩可能会降低延迟。
### 流量控制
**必要性: 针对流量敏感的服务器,做双保险。**
> 基本原则: SERVER的发送速率不能超过ADSL下行带宽,否则只会浪费您的服务器带宽。
在server通过linux tc,可以限制服务器发送带宽。
举例: 用linux tc限制server发送带宽为32mbit/s:
```
root@kcptun:~# cat tc.sh
tc qdisc del dev eth0 root
tc qdisc add dev eth0 root handle 1: htb
tc class add dev eth0 parent 1: classid 1:1 htb rate 32mbit
tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 10 fw flowid 1:1
iptables -t mangle -A POSTROUTING -o eth0 -j MARK --set-mark 10
root@kcptun:~#
```
其中eth0为网卡,有些服务器为ens3,有些为p2p1,通过ifconfig查询修改。
### SNMP
### *SNMP* :lollipop:
```go
// Snmp defines network statistics indicator
type Snmp struct {
BytesSent uint64 // payload bytes sent
BytesReceived uint64
MaxConn uint64
ActiveOpens uint64
PassiveOpens uint64
CurrEstab uint64
InErrs uint64
InCsumErrors uint64 // checksum errors
InSegs uint64
OutSegs uint64
OutBytes uint64 // udp bytes sent
RetransSegs uint64
FastRetransSegs uint64
EarlyRetransSegs uint64
LostSegs uint64
RepeatSegs uint64
FECRecovered uint64
FECErrs uint64
FECSegs uint64 // fec segments received
BytesSent uint64 // payload bytes sent
BytesReceived uint64
MaxConn uint64
ActiveOpens uint64
PassiveOpens uint64
CurrEstab uint64
InErrs uint64
InCsumErrors uint64 // checksum errors
InSegs uint64
OutSegs uint64
OutBytes uint64 // udp bytes sent
RetransSegs uint64
FastRetransSegs uint64
LostSegs uint64
RepeatSegs uint64
FECRecovered uint64
FECErrs uint64
FECSegs uint64 // fec segments received
}
```
使用```kill -SIGUSR1 pid``` 可以在控制台打印出SNMP信息,通常用于精细调整**当前链路的有效载荷比**。
观察```RetransSegs,FastRetransSegs,LostSegs,OutSegs```这几者的数值比例,用于参考调整```-mode manual,fec```的参数。
#### 带宽计算公式
使用```kill -SIGUSR1 pid``` 可以在控制台打印出SNMP信息,通常用于精细调整***当前链路的有效载荷比***
观察```RetransSegs,FastRetransSegs,LostSegs,OutSegs```这几者的数值比例,用于参考调整```-mode manual,fec```的参数。
### *性能对比* :lollipop:
```
在不丢包的情况下,有最大-rcvwnd 个数据包在网络上正在向你传输,以平均数据包大小avgsize计算,在任意时刻,有:
network_cap = rcvwnd*avgsize
数据流向你,这个值再除以ping值(rtt),等于最大带宽使用量。
max_bandwidth = network_cap/rtt = rcvwnd*avgsize/rtt
举例,设rcvwnd = 1024, avgsize = 1KB, rtt = 400ms,则:
max_bandwidth = 1024 * 1KB / 400ms = 2.5MB/s ~= 25Mbps
(注:以上计算不包括前向纠错的数据量)
前向纠错是最大带宽量的一个固定比例增加:
max_bandwidth_fec = max_bandwidth*(datashard+parityshard)/datashard
举例,设datashard = 10 , partiyshard = 3,则:
max_bandwidth_fec = max_bandwidth * (10 + 3) /10 = 1.3*max_bandwidth 1.3 * 25Mbps = 32.5Mbps
root@vultr:~# iperf -s
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 4.00 MByte (default)
------------------------------------------------------------
[ 4] local 172.7.7.1 port 5001 connected with 172.7.7.2 port 55453
[ ID] Interval Transfer Bandwidth
[ 4] 0.0-18.0 sec 5.50 MBytes 2.56 Mbits/sec <-- connection via kcptun
[ 5] local 45.32.xxx.xxx port 5001 connected with 218.88.xxx.xxx port 17220
[ 5] 0.0-17.9 sec 2.12 MBytes 997 Kbits/sec <-- direct connnection via tcp
```
### 故障排除
### *免责申明* :warning:
用户以各种方式使用本软件(包括但不限于修改使用、直接使用、通过第三方使用)的过程中,不得以任何方式利用本软件直接或间接从事违反中国法律、以及社会公德的行为。软件的使用者需对自身行为负责,因使用软件引发的一切纠纷,由使用者承担全部法律及连带责任。作者不承担任何法律及连带责任。
> Q: 客户端和服务器端**皆无** ```stream opened```信息。
> A: 连接客户端程序的端口设置错误。
> Q: 客户端有 ```stream opened```信息,服务器端没有。
> A: 连接服务器的端口设置错误,或者被防火墙拦截。
> Q: 客户端服务器**皆有** ```stream opened```信息,但无法通信。
> A: 上层软件的设定错误。
### 免责申明
**用户以各种方式使用本软件(包括但不限于修改使用、直接使用、通过第三方使用)的过程中,不得以任何方式利用本软件直接或间接从事违反中国法律、以及社会公德的行为。软件的使用者需对自身行为负责,因使用软件引发的一切纠纷,由使用者承担全部法律及连带责任。作者不承担任何法律及连带责任。**
**对免责声明的解释、修改及更新权均属于作者本人所有。**
### 捐赠
![donate](donate.png)
### 特别鸣谢
> 郑H立, 南东风, Li, 七七, 凌君, 昶,LesMiserables, KyOn, 噼里啪啦, 继斌, 小苍辛苦, **Ken**,
> 乔槁, 佳晨, 猪肉佬, lcx, 昊文, 冰峰, 凡, alex, **海豹叔叔**, 奥姐, 张冰, 司成,
> 武子, **慎**Alex43211**Coxxs**,荣,NeroNg,吴骁,定一,我不是林JPatrick, 超, 陈,windfarer, 宇,
> 今晶,斌,晓东,最后一缕阳光,亮,Ethan,一心不乱,allenm,冬卯,GELATO,用户1Butterfly,光子曲面,
> 丞佳,捉鱼,TalonBiny,李勇,***阿彪******rinex20***Fabre,路过发光体,池子,kk
好人一生平安!
### 相关软件
1. https://github.com/bettermanbao/openwrt-kcptun
2. https://github.com/EasyPi/openwrt-kcptun
3. https://github.com/kuoruan/luci-app-kcptun
4. https://github.com/dfdragon/kcptun_gclient
5. https://github.com/dfdragon/kcptun_xclient
### 参考资料
1. https://github.com/skywind3000/kcp -- KCP - A Fast and Reliable ARQ Protocol.
2. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go.
3. https://en.wikipedia.org/wiki/Differentiated_services -- DSCP.
4. http://google.github.io/snappy/ -- A fast compressor/decompressor.
5. https://www.backblaze.com/blog/reed-solomon/ -- Reed-Solomon Explained.
6. http://www.qualcomm.cn/products/raptorq -- RaptorQ Forward Error Correction Scheme for Object Delivery.
7. https://en.wikipedia.org/wiki/PBKDF2 -- Key stretching.
8. http://blog.appcanary.com/2016/encrypt-or-compress.html -- Should you encrypt or compress first?
9. https://github.com/hashicorp/yamux -- Connection multiplexing library.
10. https://tools.ietf.org/html/rfc6937 -- Proportional Rate Reduction for TCP.
11. https://tools.ietf.org/html/rfc5827 -- Early Retransmit for TCP and Stream Control Transmission Protocol (SCTP).
12. http://http2.github.io/ -- What is HTTP/2?
13. http://www.lartc.org/LARTC-zh_CN.GB2312.pdf -- Linux Advanced Routing & Traffic Control
14. https://en.wikipedia.org/wiki/Noisy-channel_coding_theorem -- Noisy channel coding theorem
对免责声明的解释、修改及更新权均属于作者本人所有。
+4 -17
View File
@@ -12,7 +12,6 @@ fi
VERSION=`date -u +%Y%m%d`
LDFLAGS="-X main.VERSION=$VERSION -s -w"
GCFLAGS=""
OSES=(linux darwin windows freebsd)
ARCHS=(amd64 386)
@@ -23,8 +22,8 @@ for os in ${OSES[@]}; do
then
suffix=".exe"
fi
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_${os}_${arch}${suffix} github.com/xtaci/kcptun/client
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_${os}_${arch}${suffix} github.com/xtaci/kcptun/server
env GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -o client_${os}_${arch}${suffix} github.com/xtaci/kcptun/client
env GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -o server_${os}_${arch}${suffix} github.com/xtaci/kcptun/server
if $UPX; then upx -9 client_${os}_${arch}${suffix} server_${os}_${arch}${suffix};fi
tar -zcf kcptun-${os}-${arch}-$VERSION.tar.gz client_${os}_${arch}${suffix} server_${os}_${arch}${suffix}
$MD5 kcptun-${os}-${arch}-$VERSION.tar.gz
@@ -34,21 +33,9 @@ done
# ARM
ARMS=(5 6 7)
for v in ${ARMS[@]}; do
env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=$v go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_linux_arm$v github.com/xtaci/kcptun/client
env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=$v go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_linux_arm$v github.com/xtaci/kcptun/server
env GOOS=linux GOARCH=arm GOARM=$v go build -ldflags "$LDFLAGS" -o client_linux_arm$v github.com/xtaci/kcptun/client
env GOOS=linux GOARCH=arm GOARM=$v go build -ldflags "$LDFLAGS" -o server_linux_arm$v github.com/xtaci/kcptun/server
done
if $UPX; then upx -9 client_linux_arm* server_linux_arm*;fi
tar -zcf kcptun-linux-arm-$VERSION.tar.gz client_linux_arm* server_linux_arm*
$MD5 kcptun-linux-arm-$VERSION.tar.gz
#MIPS32LE
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_linux_mipsle github.com/xtaci/kcptun/client
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_linux_mipsle github.com/xtaci/kcptun/server
env CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_linux_mips github.com/xtaci/kcptun/client
env CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_linux_mips github.com/xtaci/kcptun/server
if $UPX; then upx -9 client_linux_mips* server_linux_mips*;fi
tar -zcf kcptun-linux-mipsle-$VERSION.tar.gz client_linux_mipsle server_linux_mipsle
tar -zcf kcptun-linux-mips-$VERSION.tar.gz client_linux_mips server_linux_mips
$MD5 kcptun-linux-mipsle-$VERSION.tar.gz
$MD5 kcptun-linux-mips-$VERSION.tar.gz
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

-44
View File
@@ -1,44 +0,0 @@
package main
import (
"encoding/json"
"os"
)
// Config for client
type Config struct {
LocalAddr string `json:"localaddr"`
RemoteAddr string `json:"remoteaddr"`
Key string `json:"key"`
Crypt string `json:"crypt"`
Mode string `json:"mode"`
Conn int `json:"conn"`
AutoExpire int `json:"autoexpire"`
MTU int `json:"mtu"`
SndWnd int `json:"sndwnd"`
RcvWnd int `json:"rcvwnd"`
DataShard int `json:"datashard"`
ParityShard int `json:"parityshard"`
DSCP int `json:"dscp"`
NoComp bool `json:"nocomp"`
AckNodelay bool `json:"acknodelay"`
NoDelay int `json:"nodelay"`
Interval int `json:"interval"`
Resend int `json:"resend"`
NoCongestion int `json:"nc"`
SockBuf int `json:"sockbuf"`
KeepAlive int `json:"keepalive"`
Log string `json:"log"`
SnmpLog string `json:"snmplog"`
SnmpPeriod int `json:"snmpperiod"`
}
func parseJSONConfig(config *Config, path string) error {
file, err := os.Open(path) // For read access.
if err != nil {
return err
}
defer file.Close()
return json.NewDecoder(file).Decode(config)
}
+75 -362
View File
@@ -1,9 +1,6 @@
package main
import (
"crypto/sha1"
"encoding/csv"
"fmt"
"io"
"log"
"math/rand"
@@ -11,56 +8,14 @@ import (
"os"
"time"
"golang.org/x/crypto/pbkdf2"
"github.com/golang/snappy"
"github.com/pkg/errors"
"github.com/hashicorp/yamux"
"github.com/urfave/cli"
kcp "github.com/xtaci/kcp-go"
"github.com/xtaci/smux"
"github.com/xtaci/kcp-go"
)
var (
// VERSION is injected by buildflags
VERSION = "SELFBUILD"
// SALT is use for pbkdf2 key expansion
SALT = "kcp-go"
)
type compStream struct {
conn net.Conn
w *snappy.Writer
r *snappy.Reader
}
func (c *compStream) Read(p []byte) (n int, err error) {
return c.r.Read(p)
}
func (c *compStream) Write(p []byte) (n int, err error) {
n, err = c.w.Write(p)
err = c.w.Flush()
return n, err
}
func (c *compStream) Close() error {
return c.conn.Close()
}
func newCompStream(conn net.Conn) *compStream {
c := new(compStream)
c.conn = conn
c.w = snappy.NewBufferedWriter(conn)
c.r = snappy.NewReader(conn)
return c
}
func handleClient(sess *smux.Session, p1 io.ReadWriteCloser) {
p2, err := sess.OpenStream()
if err != nil {
return
}
var VERSION = "SELFBUILD"
func handleClient(p1, p2 net.Conn) {
log.Println("stream opened")
defer log.Println("stream closed")
defer p1.Close()
@@ -68,10 +23,16 @@ func handleClient(sess *smux.Session, p1 io.ReadWriteCloser) {
// start tunnel
p1die := make(chan struct{})
go func() { io.Copy(p1, p2); close(p1die) }()
go func() {
io.Copy(p1, p2)
close(p1die)
}()
p2die := make(chan struct{})
go func() { io.Copy(p2, p1); close(p2die) }()
go func() {
io.Copy(p2, p1)
close(p2die)
}()
// wait for tunnel termination
select {
@@ -82,20 +43,16 @@ func handleClient(sess *smux.Session, p1 io.ReadWriteCloser) {
func checkError(err error) {
if err != nil {
log.Printf("%+v\n", err)
log.Println(err)
os.Exit(-1)
}
}
func main() {
rand.Seed(int64(time.Now().Nanosecond()))
if VERSION == "SELFBUILD" {
// add more log flags for debugging
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
myApp := cli.NewApp()
myApp.Name = "kcptun"
myApp.Usage = "client(with SMUX)"
myApp.Usage = "kcptun client"
myApp.Version = VERSION
myApp.Flags = []cli.Flag{
cli.StringFlag{
@@ -111,33 +68,18 @@ func main() {
cli.StringFlag{
Name: "key",
Value: "it's a secrect",
Usage: "pre-shared secret between client and server",
Usage: "key for communcation, must be the same as kcptun server",
EnvVar: "KCPTUN_KEY",
},
cli.StringFlag{
Name: "crypt",
Value: "aes",
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none",
},
cli.StringFlag{
Name: "mode",
Value: "fast",
Usage: "profiles: fast3, fast2, fast, normal",
},
cli.IntFlag{
Name: "conn",
Value: 1,
Usage: "set num of UDP connections to server",
},
cli.IntFlag{
Name: "autoexpire",
Value: 0,
Usage: "set auto expiration time(in seconds) for a single UDP connection, 0 to disable",
Usage: "mode for communication: fast3, fast2, fast, normal",
},
cli.IntFlag{
Name: "mtu",
Value: 1350,
Usage: "set maximum transmission unit for UDP packets",
Usage: "set MTU of UDP packets, suggest 'tracepath' to discover path mtu",
},
cli.IntFlag{
Name: "sndwnd",
@@ -146,33 +88,23 @@ func main() {
},
cli.IntFlag{
Name: "rcvwnd",
Value: 512,
Value: 1024,
Usage: "set receive window size(num of packets)",
},
cli.IntFlag{
Name: "datashard",
Value: 10,
Usage: "set reed-solomon erasure coding - datashard",
Name: "fec",
Value: 4,
Usage: "set FEC group size, must be the same as server",
},
cli.IntFlag{
Name: "parityshard",
Value: 3,
Usage: "set reed-solomon erasure coding - parityshard",
cli.BoolFlag{
Name: "acknodelay",
Usage: "flush ack immediately when a packet is received",
},
cli.IntFlag{
Name: "dscp",
Value: 0,
Usage: "set DSCP(6bit)",
},
cli.BoolFlag{
Name: "nocomp",
Usage: "disable compression",
},
cli.BoolFlag{
Name: "acknodelay",
Usage: "flush ack immediately when a packet is received",
Hidden: true,
},
cli.IntFlag{
Name: "nodelay",
Value: 0,
@@ -193,295 +125,76 @@ func main() {
Value: 0,
Hidden: true,
},
cli.IntFlag{
Name: "sockbuf",
Value: 4194304, // socket buffer size in bytes
Hidden: true,
},
cli.IntFlag{
Name: "keepalive",
Value: 10, // nat keepalive interval in seconds
Hidden: true,
},
cli.StringFlag{
Name: "snmplog",
Value: "",
Usage: "collect snmp to file, aware of timeformat in golang, like: ./snmp-20060102.log",
},
cli.IntFlag{
Name: "snmpperiod",
Value: 60,
Usage: "snmp collect period, in seconds",
},
cli.StringFlag{
Name: "log",
Value: "",
Usage: "specify a log file to output, default goes to stderr",
},
cli.StringFlag{
Name: "c",
Value: "", // when the value is not empty, the config path must exists
Usage: "config from json file, which will override the command from shell",
},
}
myApp.Action = func(c *cli.Context) error {
config := Config{}
config.LocalAddr = c.String("localaddr")
config.RemoteAddr = c.String("remoteaddr")
config.Key = c.String("key")
config.Crypt = c.String("crypt")
config.Mode = c.String("mode")
config.Conn = c.Int("conn")
config.AutoExpire = c.Int("autoexpire")
config.MTU = c.Int("mtu")
config.SndWnd = c.Int("sndwnd")
config.RcvWnd = c.Int("rcvwnd")
config.DataShard = c.Int("datashard")
config.ParityShard = c.Int("parityshard")
config.DSCP = c.Int("dscp")
config.NoComp = c.Bool("nocomp")
config.AckNodelay = c.Bool("acknodelay")
config.NoDelay = c.Int("nodelay")
config.Interval = c.Int("interval")
config.Resend = c.Int("resend")
config.NoCongestion = c.Int("nc")
config.SockBuf = c.Int("sockbuf")
config.KeepAlive = c.Int("keepalive")
config.Log = c.String("log")
config.SnmpLog = c.String("snmplog")
config.SnmpPeriod = c.Int("snmpperiod")
if c.String("c") != "" {
err := parseJSONConfig(&config, c.String("c"))
checkError(err)
}
// log redirect
if config.Log != "" {
f, err := os.OpenFile(config.Log, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
checkError(err)
defer f.Close()
log.SetOutput(f)
}
switch config.Mode {
case "normal":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 30, 2, 1
case "fast":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 20, 2, 1
case "fast2":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 1, 20, 2, 1
case "fast3":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 1, 10, 2, 1
}
myApp.Action = func(c *cli.Context) {
log.Println("version:", VERSION)
addr, err := net.ResolveTCPAddr("tcp", config.LocalAddr)
addr, err := net.ResolveTCPAddr("tcp", c.String("localaddr"))
checkError(err)
listener, err := net.ListenTCP("tcp", addr)
checkError(err)
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
var block kcp.BlockCrypt
switch config.Crypt {
case "tea":
block, _ = kcp.NewTEABlockCrypt(pass[:16])
case "xor":
block, _ = kcp.NewSimpleXORBlockCrypt(pass)
case "none":
block, _ = kcp.NewNoneBlockCrypt(pass)
case "aes-128":
block, _ = kcp.NewAESBlockCrypt(pass[:16])
case "aes-192":
block, _ = kcp.NewAESBlockCrypt(pass[:24])
case "blowfish":
block, _ = kcp.NewBlowfishBlockCrypt(pass)
case "twofish":
block, _ = kcp.NewTwofishBlockCrypt(pass)
case "cast5":
block, _ = kcp.NewCast5BlockCrypt(pass[:16])
case "3des":
block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
case "xtea":
block, _ = kcp.NewXTEABlockCrypt(pass[:16])
case "salsa20":
block, _ = kcp.NewSalsa20BlockCrypt(pass)
default:
config.Crypt = "aes"
block, _ = kcp.NewAESBlockCrypt(pass)
}
log.Println("listening on:", listener.Addr())
log.Println("encryption:", config.Crypt)
log.Println("nodelay parameters:", config.NoDelay, config.Interval, config.Resend, config.NoCongestion)
log.Println("remote address:", config.RemoteAddr)
log.Println("sndwnd:", config.SndWnd, "rcvwnd:", config.RcvWnd)
log.Println("compression:", !config.NoComp)
log.Println("mtu:", config.MTU)
log.Println("datashard:", config.DataShard, "parityshard:", config.ParityShard)
log.Println("acknodelay:", config.AckNodelay)
log.Println("dscp:", config.DSCP)
log.Println("sockbuf:", config.SockBuf)
log.Println("keepalive:", config.KeepAlive)
log.Println("conn:", config.Conn)
log.Println("autoexpire:", config.AutoExpire)
log.Println("snmplog:", config.SnmpLog)
log.Println("snmpperiod:", config.SnmpPeriod)
smuxConfig := smux.DefaultConfig()
smuxConfig.MaxReceiveBuffer = config.SockBuf
START_KCP:
createConn := func() (*smux.Session, error) {
kcpconn, err := kcp.DialWithOptions(config.RemoteAddr, block, config.DataShard, config.ParityShard)
if err != nil {
return nil, errors.Wrap(err, "createConn()")
}
kcpconn.SetStreamMode(true)
kcpconn.SetNoDelay(config.NoDelay, config.Interval, config.Resend, config.NoCongestion)
kcpconn.SetWindowSize(config.SndWnd, config.RcvWnd)
kcpconn.SetMtu(config.MTU)
kcpconn.SetACKNoDelay(config.AckNodelay)
kcpconn.SetKeepAlive(config.KeepAlive)
// kcp server
kcpconn, err := kcp.DialWithOptions(c.Int("fec"), c.String("remoteaddr"), []byte(c.String("key")))
checkError(err)
nodelay, interval, resend, nc := c.Int("nodelay"), c.Int("interval"), c.Int("resend"), c.Int("nc")
if err := kcpconn.SetDSCP(config.DSCP); err != nil {
log.Println("SetDSCP:", err)
}
if err := kcpconn.SetReadBuffer(config.SockBuf); err != nil {
log.Println("SetReadBuffer:", err)
}
if err := kcpconn.SetWriteBuffer(config.SockBuf); err != nil {
log.Println("SetWriteBuffer:", err)
}
// stream multiplex
var session *smux.Session
if config.NoComp {
session, err = smux.Client(kcpconn, smuxConfig)
} else {
session, err = smux.Client(newCompStream(kcpconn), smuxConfig)
}
if err != nil {
return nil, errors.Wrap(err, "createConn()")
}
return session, nil
switch c.String("mode") {
case "normal":
nodelay, interval, resend, nc = 0, 30, 2, 1
case "fast":
nodelay, interval, resend, nc = 0, 20, 2, 1
case "fast2":
nodelay, interval, resend, nc = 1, 20, 2, 1
case "fast3":
nodelay, interval, resend, nc = 1, 10, 2, 1
}
// wait until a connection is ready
waitConn := func() *smux.Session {
for {
if session, err := createConn(); err == nil {
return session
} else {
time.Sleep(time.Second)
}
}
log.Println("nodelay parameters:", nodelay, interval, resend, nc)
log.Println("remote address:", c.String("remoteaddr"))
log.Println("sndwnd:", c.Int("sndwnd"), "rcvwnd:", c.Int("rcvwnd"))
log.Println("mtu:", c.Int("mtu"))
log.Println("fec:", c.Int("fec"))
log.Println("acknodelay:", c.Bool("acknodelay"))
log.Println("dscp:", c.Int("dscp"))
kcpconn.SetNoDelay(nodelay, interval, resend, nc)
kcpconn.SetWindowSize(c.Int("sndwnd"), c.Int("rcvwnd"))
kcpconn.SetMtu(c.Int("mtu"))
kcpconn.SetACKNoDelay(c.Bool("acknodelay"))
kcpconn.SetDSCP(c.Int("dscp"))
// stream multiplex
var mux *yamux.Session
config := &yamux.Config{
AcceptBacklog: 256,
EnableKeepAlive: true,
KeepAliveInterval: 30 * time.Second,
ConnectionWriteTimeout: 30 * time.Second,
MaxStreamWindowSize: 16777216,
LogOutput: os.Stderr,
}
session, err := yamux.Client(kcpconn, config)
checkError(err)
mux = session
numconn := uint16(config.Conn)
muxes := make([]struct {
session *smux.Session
ttl time.Time
}, numconn)
for k := range muxes {
sess, err := createConn()
checkError(err)
muxes[k].session = sess
muxes[k].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
}
chScavenger := make(chan *smux.Session, 128)
go scavenger(chScavenger)
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
rr := uint16(0)
for {
p1, err := listener.AcceptTCP()
if err != nil {
log.Fatalln(err)
log.Println(err)
continue
}
if err := p1.SetReadBuffer(config.SockBuf); err != nil {
log.Println("TCP SetReadBuffer:", err)
p2, err := mux.Open()
if err != nil { // yamux failure
log.Println(err)
kcpconn.Close()
p1.Close()
goto START_KCP
}
if err := p1.SetWriteBuffer(config.SockBuf); err != nil {
log.Println("TCP SetWriteBuffer:", err)
}
checkError(err)
idx := rr % numconn
// do auto expiration && reconnection
if muxes[idx].session.IsClosed() || (config.AutoExpire > 0 && time.Now().After(muxes[idx].ttl)) {
chScavenger <- muxes[idx].session
muxes[idx].session = waitConn()
muxes[idx].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
}
go handleClient(muxes[idx].session, p1)
rr++
go handleClient(p1, p2)
}
}
myApp.Run(os.Args)
}
type scavengeSession struct {
session *smux.Session
ttl time.Time
}
const (
maxScavengeTTL = 10 * time.Minute
)
func scavenger(ch chan *smux.Session) {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
var sessionList []scavengeSession
for {
select {
case sess := <-ch:
sessionList = append(sessionList, scavengeSession{sess, time.Now()})
case <-ticker.C:
var newList []scavengeSession
for k := range sessionList {
s := sessionList[k]
if s.session.NumStreams() == 0 || s.session.IsClosed() || time.Since(s.ttl) > maxScavengeTTL {
log.Println("session scavenged")
s.session.Close()
} else {
newList = append(newList, sessionList[k])
}
}
sessionList = newList
}
}
}
func snmpLogger(path string, interval int) {
if path == "" || interval == 0 {
return
}
ticker := time.NewTicker(time.Duration(interval) * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
f, err := os.OpenFile(time.Now().Format(path), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Println(err)
return
}
w := csv.NewWriter(f)
// write header in empty file
if stat, err := f.Stat(); err == nil && stat.Size() == 0 {
if err := w.Write(append([]string{"Unix"}, kcp.DefaultSnmp.Header()...)); err != nil {
log.Println(err)
}
}
if err := w.Write(append([]string{fmt.Sprint(time.Now().Unix())}, kcp.DefaultSnmp.ToSlice()...)); err != nil {
log.Println(err)
}
kcp.DefaultSnmp.Reset()
w.Flush()
f.Close()
}
}
}
+3 -3
View File
@@ -8,14 +8,14 @@ import (
"os/signal"
"syscall"
kcp "github.com/xtaci/kcp-go"
"github.com/xtaci/kcp-go"
)
func init() {
go sigHandler()
go sig_handler()
}
func sigHandler() {
func sig_handler() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGUSR1)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 22 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

-42
View File
@@ -1,42 +0,0 @@
package main
import (
"encoding/json"
"os"
)
// Config for server
type Config struct {
Listen string `json:"listen"`
Target string `json:"target"`
Key string `json:"key"`
Crypt string `json:"crypt"`
Mode string `json:"mode"`
MTU int `json:"mtu"`
SndWnd int `json:"sndwnd"`
RcvWnd int `json:"rcvwnd"`
DataShard int `json:"datashard"`
ParityShard int `json:"parityshard"`
DSCP int `json:"dscp"`
NoComp bool `json:"nocomp"`
AckNodelay bool `json:"acknodelay"`
NoDelay int `json:"nodelay"`
Interval int `json:"interval"`
Resend int `json:"resend"`
NoCongestion int `json:"nc"`
SockBuf int `json:"sockbuf"`
KeepAlive int `json:"keepalive"`
Log string `json:"log"`
SnmpLog string `json:"snmplog"`
SnmpPeriod int `json:"snmpperiod"`
}
func parseJSONConfig(config *Config, path string) error {
file, err := os.Open(path) // For read access.
if err != nil {
return err
}
defer file.Close()
return json.NewDecoder(file).Decode(config)
}
+67 -275
View File
@@ -1,9 +1,6 @@
package main
import (
"crypto/sha1"
"encoding/csv"
"fmt"
"io"
"log"
"math/rand"
@@ -11,83 +8,49 @@ import (
"os"
"time"
"golang.org/x/crypto/pbkdf2"
"github.com/golang/snappy"
"github.com/hashicorp/yamux"
"github.com/urfave/cli"
kcp "github.com/xtaci/kcp-go"
"github.com/xtaci/smux"
"github.com/xtaci/kcp-go"
)
var (
// VERSION is injected by buildflags
VERSION = "SELFBUILD"
// SALT is use for pbkdf2 key expansion
SALT = "kcp-go"
)
type compStream struct {
conn net.Conn
w *snappy.Writer
r *snappy.Reader
}
func (c *compStream) Read(p []byte) (n int, err error) {
return c.r.Read(p)
}
func (c *compStream) Write(p []byte) (n int, err error) {
n, err = c.w.Write(p)
err = c.w.Flush()
return n, err
}
func (c *compStream) Close() error {
return c.conn.Close()
}
func newCompStream(conn net.Conn) *compStream {
c := new(compStream)
c.conn = conn
c.w = snappy.NewBufferedWriter(conn)
c.r = snappy.NewReader(conn)
return c
}
var VERSION = "SELFBUILD"
// handle multiplex-ed connection
func handleMux(conn io.ReadWriteCloser, config *Config) {
func handleMux(conn *kcp.UDPSession, target string) {
// stream multiplex
smuxConfig := smux.DefaultConfig()
smuxConfig.MaxReceiveBuffer = config.SockBuf
mux, err := smux.Server(conn, smuxConfig)
var mux *yamux.Session
config := &yamux.Config{
AcceptBacklog: 256,
EnableKeepAlive: true,
KeepAliveInterval: 30 * time.Second,
ConnectionWriteTimeout: 30 * time.Second,
MaxStreamWindowSize: 16777216,
LogOutput: os.Stderr,
}
m, err := yamux.Server(conn, config)
if err != nil {
log.Println(err)
return
}
mux = m
defer mux.Close()
for {
p1, err := mux.AcceptStream()
p1, err := mux.Accept()
if err != nil {
log.Println(err)
return
}
p2, err := net.DialTimeout("tcp", config.Target, 5*time.Second)
p2, err := net.DialTimeout("tcp", target, 5*time.Second)
if err != nil {
p1.Close()
log.Println(err)
continue
}
if err := p2.(*net.TCPConn).SetReadBuffer(config.SockBuf); err != nil {
log.Println("TCP SetReadBuffer:", err)
}
if err := p2.(*net.TCPConn).SetWriteBuffer(config.SockBuf); err != nil {
log.Println("TCP SetWriteBuffer:", err)
return
}
go handleClient(p1, p2)
}
}
func handleClient(p1, p2 io.ReadWriteCloser) {
func handleClient(p1, p2 net.Conn) {
log.Println("stream opened")
defer log.Println("stream closed")
defer p1.Close()
@@ -95,10 +58,16 @@ func handleClient(p1, p2 io.ReadWriteCloser) {
// start tunnel
p1die := make(chan struct{})
go func() { io.Copy(p1, p2); close(p1die) }()
go func() {
io.Copy(p1, p2)
close(p1die)
}()
p2die := make(chan struct{})
go func() { io.Copy(p2, p1); close(p2die) }()
go func() {
io.Copy(p2, p1)
close(p2die)
}()
// wait for tunnel termination
select {
@@ -107,22 +76,11 @@ func handleClient(p1, p2 io.ReadWriteCloser) {
}
}
func checkError(err error) {
if err != nil {
log.Printf("%+v\n", err)
os.Exit(-1)
}
}
func main() {
rand.Seed(int64(time.Now().Nanosecond()))
if VERSION == "SELFBUILD" {
// add more log flags for debugging
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
myApp := cli.NewApp()
myApp.Name = "kcptun"
myApp.Usage = "server(with SMUX)"
myApp.Usage = "kcptun server"
myApp.Version = VERSION
myApp.Flags = []cli.Flag{
cli.StringFlag{
@@ -138,23 +96,18 @@ func main() {
cli.StringFlag{
Name: "key",
Value: "it's a secrect",
Usage: "pre-shared secret between client and server",
Usage: "key for communcation, must be the same as kcptun client",
EnvVar: "KCPTUN_KEY",
},
cli.StringFlag{
Name: "crypt",
Value: "aes",
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none",
},
cli.StringFlag{
Name: "mode",
Value: "fast",
Usage: "profiles: fast3, fast2, fast, normal",
Usage: "mode for communication: fast3, fast2, fast, normal",
},
cli.IntFlag{
Name: "mtu",
Value: 1350,
Usage: "set maximum transmission unit for UDP packets",
Usage: "set MTU of UDP packets, suggest 'tracepath' to discover path mtu",
},
cli.IntFlag{
Name: "sndwnd",
@@ -167,29 +120,19 @@ func main() {
Usage: "set receive window size(num of packets)",
},
cli.IntFlag{
Name: "datashard",
Value: 10,
Usage: "set reed-solomon erasure coding - datashard",
Name: "fec",
Value: 4,
Usage: "set FEC group size, must be the same as client",
},
cli.IntFlag{
Name: "parityshard",
Value: 3,
Usage: "set reed-solomon erasure coding - parityshard",
cli.BoolFlag{
Name: "acknodelay",
Usage: "flush ack immediately when a packet is received",
},
cli.IntFlag{
Name: "dscp",
Value: 0,
Usage: "set DSCP(6bit)",
},
cli.BoolFlag{
Name: "nocomp",
Usage: "disable compression",
},
cli.BoolFlag{
Name: "acknodelay",
Usage: "flush ack immediately when a packet is received",
Hidden: true,
},
cli.IntFlag{
Name: "nodelay",
Value: 0,
@@ -210,196 +153,45 @@ func main() {
Value: 0,
Hidden: true,
},
cli.IntFlag{
Name: "sockbuf",
Value: 4194304, // socket buffer size in bytes
Hidden: true,
},
cli.IntFlag{
Name: "keepalive",
Value: 10, // nat keepalive interval in seconds
Hidden: true,
},
cli.StringFlag{
Name: "snmplog",
Value: "",
Usage: "collect snmp to file, aware of timeformat in golang, like: ./snmp-20060102.log",
},
cli.IntFlag{
Name: "snmpperiod",
Value: 60,
Usage: "snmp collect period, in seconds",
},
cli.StringFlag{
Name: "log",
Value: "",
Usage: "specify a log file to output, default goes to stderr",
},
cli.StringFlag{
Name: "c",
Value: "", // when the value is not empty, the config path must exists
Usage: "config from json file, which will override the command from shell",
},
}
myApp.Action = func(c *cli.Context) error {
config := Config{}
config.Listen = c.String("listen")
config.Target = c.String("target")
config.Key = c.String("key")
config.Crypt = c.String("crypt")
config.Mode = c.String("mode")
config.MTU = c.Int("mtu")
config.SndWnd = c.Int("sndwnd")
config.RcvWnd = c.Int("rcvwnd")
config.DataShard = c.Int("datashard")
config.ParityShard = c.Int("parityshard")
config.DSCP = c.Int("dscp")
config.NoComp = c.Bool("nocomp")
config.AckNodelay = c.Bool("acknodelay")
config.NoDelay = c.Int("nodelay")
config.Interval = c.Int("interval")
config.Resend = c.Int("resend")
config.NoCongestion = c.Int("nc")
config.SockBuf = c.Int("sockbuf")
config.KeepAlive = c.Int("keepalive")
config.Log = c.String("log")
config.SnmpLog = c.String("snmplog")
config.SnmpPeriod = c.Int("snmpperiod")
if c.String("c") != "" {
//Now only support json config file
err := parseJSONConfig(&config, c.String("c"))
checkError(err)
}
// log redirect
if config.Log != "" {
f, err := os.OpenFile(config.Log, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
checkError(err)
defer f.Close()
log.SetOutput(f)
}
switch config.Mode {
case "normal":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 30, 2, 1
case "fast":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 20, 2, 1
case "fast2":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 1, 20, 2, 1
case "fast3":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 1, 10, 2, 1
}
myApp.Action = func(c *cli.Context) {
log.Println("version:", VERSION)
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
var block kcp.BlockCrypt
switch config.Crypt {
case "tea":
block, _ = kcp.NewTEABlockCrypt(pass[:16])
case "xor":
block, _ = kcp.NewSimpleXORBlockCrypt(pass)
case "none":
block, _ = kcp.NewNoneBlockCrypt(pass)
case "aes-128":
block, _ = kcp.NewAESBlockCrypt(pass[:16])
case "aes-192":
block, _ = kcp.NewAESBlockCrypt(pass[:24])
case "blowfish":
block, _ = kcp.NewBlowfishBlockCrypt(pass)
case "twofish":
block, _ = kcp.NewTwofishBlockCrypt(pass)
case "cast5":
block, _ = kcp.NewCast5BlockCrypt(pass[:16])
case "3des":
block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
case "xtea":
block, _ = kcp.NewXTEABlockCrypt(pass[:16])
case "salsa20":
block, _ = kcp.NewSalsa20BlockCrypt(pass)
default:
config.Crypt = "aes"
block, _ = kcp.NewAESBlockCrypt(pass)
nodelay, interval, resend, nc := c.Int("nodelay"), c.Int("interval"), c.Int("resend"), c.Int("nc")
switch c.String("mode") {
case "normal":
nodelay, interval, resend, nc = 0, 30, 2, 1
case "fast":
nodelay, interval, resend, nc = 0, 20, 2, 1
case "fast2":
nodelay, interval, resend, nc = 1, 20, 2, 1
case "fast3":
nodelay, interval, resend, nc = 1, 10, 2, 1
}
lis, err := kcp.ListenWithOptions(config.Listen, block, config.DataShard, config.ParityShard)
checkError(err)
log.Println("listening on:", lis.Addr())
log.Println("target:", config.Target)
log.Println("encryption:", config.Crypt)
log.Println("nodelay parameters:", config.NoDelay, config.Interval, config.Resend, config.NoCongestion)
log.Println("sndwnd:", config.SndWnd, "rcvwnd:", config.RcvWnd)
log.Println("compression:", !config.NoComp)
log.Println("mtu:", config.MTU)
log.Println("datashard:", config.DataShard, "parityshard:", config.ParityShard)
log.Println("acknodelay:", config.AckNodelay)
log.Println("dscp:", config.DSCP)
log.Println("sockbuf:", config.SockBuf)
log.Println("keepalive:", config.KeepAlive)
log.Println("snmplog:", config.SnmpLog)
log.Println("snmpperiod:", config.SnmpPeriod)
if err := lis.SetDSCP(config.DSCP); err != nil {
log.Println("SetDSCP:", err)
lis, err := kcp.ListenWithOptions(c.Int("fec"), c.String("listen"), []byte(c.String("key")))
if err != nil {
log.Fatal(err)
}
if err := lis.SetReadBuffer(config.SockBuf); err != nil {
log.Println("SetReadBuffer:", err)
}
if err := lis.SetWriteBuffer(config.SockBuf); err != nil {
log.Println("SetWriteBuffer:", err)
}
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
log.Println("listening on ", lis.Addr())
log.Println("nodelay parameters:", nodelay, interval, resend, nc)
log.Println("sndwnd:", c.Int("sndwnd"), "rcvwnd:", c.Int("rcvwnd"))
log.Println("mtu:", c.Int("mtu"))
log.Println("fec:", c.Int("fec"))
log.Println("acknodelay:", c.Bool("acknodelay"))
log.Println("dscp:", c.Int("dscp"))
for {
if conn, err := lis.AcceptKCP(); err == nil {
if conn, err := lis.Accept(); err == nil {
log.Println("remote address:", conn.RemoteAddr())
conn.SetStreamMode(true)
conn.SetNoDelay(config.NoDelay, config.Interval, config.Resend, config.NoCongestion)
conn.SetMtu(config.MTU)
conn.SetWindowSize(config.SndWnd, config.RcvWnd)
conn.SetACKNoDelay(config.AckNodelay)
conn.SetKeepAlive(config.KeepAlive)
if config.NoComp {
go handleMux(conn, &config)
} else {
go handleMux(newCompStream(conn), &config)
}
conn.SetNoDelay(nodelay, interval, resend, nc)
conn.SetMtu(c.Int("mtu"))
conn.SetWindowSize(c.Int("sndwnd"), c.Int("rcvwnd"))
conn.SetACKNoDelay(c.Bool("acknodelay"))
conn.SetDSCP(c.Int("dscp"))
go handleMux(conn, c.String("target"))
} else {
log.Printf("%+v", err)
log.Println(err)
}
}
}
myApp.Run(os.Args)
}
func snmpLogger(path string, interval int) {
if path == "" || interval == 0 {
return
}
ticker := time.NewTicker(time.Duration(interval) * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
f, err := os.OpenFile(time.Now().Format(path), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Println(err)
return
}
w := csv.NewWriter(f)
// write header in empty file
if stat, err := f.Stat(); err == nil && stat.Size() == 0 {
if err := w.Write(append([]string{"Unix"}, kcp.DefaultSnmp.Header()...)); err != nil {
log.Println(err)
}
}
if err := w.Write(append([]string{fmt.Sprint(time.Now().Unix())}, kcp.DefaultSnmp.ToSlice()...)); err != nil {
log.Println(err)
}
kcp.DefaultSnmp.Reset()
w.Flush()
f.Close()
}
}
}
+3 -3
View File
@@ -8,14 +8,14 @@ import (
"os/signal"
"syscall"
kcp "github.com/xtaci/kcp-go"
"github.com/xtaci/kcp-go"
)
func init() {
go sigHandler()
go sig_handler()
}
func sigHandler() {
func sig_handler() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGUSR1)