mirror of
https://github.com/xtaci/kcptun.git
synced 2024-04-21 12:32:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8ca7afa22 | ||
|
|
baf532e1b1 | ||
|
|
c5cdc30250 | ||
|
|
d0eafa4cce | ||
|
|
3ac0c05756 | ||
|
|
1bcb40d3fe | ||
|
|
962f8c4a31 | ||
|
|
cba4bbefd4 | ||
|
|
a3f60e5781 | ||
|
|
e31a6cfca3 | ||
|
|
79deb2ab86 | ||
|
|
6cc274e01e | ||
|
|
b0620ab7a2 | ||
|
|
b4e4d747e7 | ||
|
|
f430afcd99 | ||
|
|
88e3c64aed | ||
|
|
22893775cc | ||
|
|
aae950de2d | ||
|
|
43a68a68f5 | ||
|
|
c0077c2043 | ||
|
|
adae725995 | ||
|
|
c59479c7c4 | ||
|
|
561ee05818 | ||
|
|
65d8945050 | ||
|
|
cdaff1bd72 | ||
|
|
cb451a3a88 | ||
|
|
8f8d762742 | ||
|
|
e3ab00cf5b | ||
|
|
42bf13fb7a | ||
|
|
03f27ec53d | ||
|
|
b2390a5dd3 | ||
|
|
bf1d0d6419 | ||
|
|
834cc5d596 | ||
|
|
825ccca6ac | ||
|
|
2845af3911 | ||
|
|
31a9d13871 | ||
|
|
43761f486c | ||
|
|
030e39bf74 | ||
|
|
e6a1d00758 | ||
|
|
9d5a5b9c0d | ||
|
|
4aaf974a0b | ||
|
|
1600d4d26f | ||
|
|
c612e5e153 | ||
|
|
2fef48ce71 | ||
|
|
1d492accd6 | ||
|
|
d1beaf8383 | ||
|
|
ded53a9229 | ||
|
|
65751d535b | ||
|
|
4b5f7c1405 | ||
|
|
25bad3c03c | ||
|
|
d2c4d04600 | ||
|
|
0cb075b061 | ||
|
|
ab7a8321a6 | ||
|
|
6496672b61 | ||
|
|
ae513e9af1 | ||
|
|
36763feca4 | ||
|
|
acf7a01922 | ||
|
|
ee01d61266 | ||
|
|
fd7ed8532e | ||
|
|
ff9e3d699b | ||
|
|
e667b74b35 | ||
|
|
9a162e7008 | ||
|
|
bf4170ddff | ||
|
|
915db867bd | ||
|
|
e32fa78db6 | ||
|
|
12b8cdb366 | ||
|
|
87120a019b | ||
|
|
2ab1e3fb26 | ||
|
|
b3c4ec9483 | ||
|
|
91335c3db6 | ||
|
|
7df2c447db | ||
|
|
ad8683d46c | ||
|
|
ca4800f298 | ||
|
|
a25c9eb3a9 | ||
|
|
a0e8b2592e | ||
|
|
dc6b61ded3 | ||
|
|
298b4a0795 | ||
|
|
1334ce5a9a | ||
|
|
6efb6008e5 | ||
|
|
53d4bbfe4c | ||
|
|
2f0783f81d | ||
|
|
64e141430e | ||
|
|
bf543cfd63 | ||
|
|
751fb5f8cd | ||
|
|
e074076db5 | ||
|
|
417c602cc5 | ||
|
|
23e3782dc4 | ||
|
|
532d9e56ce | ||
|
|
203a626528 | ||
|
|
338bc5befc | ||
|
|
4051938931 | ||
|
|
c2489808cc | ||
|
|
a9ea222f24 | ||
|
|
aa85dc9ada | ||
|
|
ec5cb958b7 | ||
|
|
490c40eb44 | ||
|
|
76e7818b45 | ||
|
|
f2363702bc | ||
|
|
beddab04fe | ||
|
|
12a39bebb8 | ||
|
|
c0d6104594 | ||
|
|
2fe88a1c46 | ||
|
|
22c2314eee | ||
|
|
e7ee96cb1c | ||
|
|
a5f5d64fd9 | ||
|
|
ac0d3aa954 | ||
|
|
16c8c2daa5 | ||
|
|
69b1ee3e30 | ||
|
|
87ee41833b | ||
|
|
d3d2cd271d | ||
|
|
1a2c3559a2 | ||
|
|
844dc17ab7 | ||
|
|
7eee949682 | ||
|
|
06b63b6fdd | ||
|
|
5f950feed8 | ||
|
|
8ee3fce2ff | ||
|
|
190f82f064 | ||
|
|
534708138c | ||
|
|
e58e3e66d0 | ||
|
|
3bee8ca6e9 | ||
|
|
cfabba001d | ||
|
|
d4b07015ab | ||
|
|
f70beed964 | ||
|
|
0ba3cfb0a2 | ||
|
|
ee8e1be581 | ||
|
|
ae2e3be73d | ||
|
|
356bb7615e | ||
|
|
b870c588ae | ||
|
|
f31a5e6b61 | ||
|
|
3972a6faa1 | ||
|
|
20211352e7 | ||
|
|
608c598cbf | ||
|
|
e26d19da09 | ||
|
|
9f63ea2362 | ||
|
|
81c9f91f44 | ||
|
|
8d8ee15381 | ||
|
|
dc730d8501 | ||
|
|
8ae01cd92f | ||
|
|
3000a611cc | ||
|
|
f09f1c9b2d | ||
|
|
cc12ada5a7 | ||
|
|
074f4d54d5 | ||
|
|
c4253493b4 | ||
|
|
7b4c8967d6 | ||
|
|
a1befb4763 | ||
|
|
9b31b71cb5 | ||
|
|
0ffe2cd369 | ||
|
|
42535dff05 | ||
|
|
52a3e0f7ff | ||
|
|
b643d63bad | ||
|
|
b7f0cb8408 | ||
|
|
dc4d42007b |
+3
-1
@@ -1,6 +1,8 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.6
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 636 B |
+5
-2
@@ -1,8 +1,11 @@
|
||||
FROM golang:alpine
|
||||
FROM golang:alpine as builder
|
||||
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 -ldflags "-X main.VERSION=$(date -u +%Y%m%d) -s -w" github.com/xtaci/kcptun/client && go get -ldflags "-X main.VERSION=$(date -u +%Y%m%d) -s -w" github.com/xtaci/kcptun/server
|
||||
|
||||
FROM alpine:3.6
|
||||
COPY --from=builder /go/bin /bin
|
||||
EXPOSE 29900/udp
|
||||
EXPOSE 12948
|
||||
|
||||
-250
@@ -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 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 1:Increase client rcvwnd & server sndwnd simultaneously & gradually。
|
||||
> Step 2:Try 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 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.
|
||||
|
||||
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. Furthermore, Reed–Solomon 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.
|
||||
|
||||

|
||||
|
||||
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 KCP,useful for fine-grained adjustment.
|
||||
Of which ```RetransSegs,FastRetransSegs,LostSegs,OutSegs``` is the most useful.
|
||||
|
||||
### *Donations* :dollar:
|
||||

|
||||
|
||||
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
|
||||
@@ -1,9 +1,7 @@
|
||||
<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>
|
||||
# <img src="logo.png" alt="kcptun" height="54px" />
|
||||
|
||||
-
|
||||
[![Release][13]][14] [![Powered][17]][18] [![MIT licensed][11]][12] [![Build Status][3]][4] [![Go Report Card][5]][6] [![Downloads][15]][16] [![Docker][1]][2]
|
||||
|
||||
[![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
|
||||
@@ -20,43 +18,93 @@
|
||||
[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
|
||||
|
||||
<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>
|
||||
<img src="kcptun.png" alt="kcptun" height="300px"/>
|
||||
|
||||
> *Disclaimer: kcptun maintains a single website — [github.com/xtaci/kcptun](https://github.com/xtaci/kcptun). Any websites other than [github.com/xtaci/kcptun](https://github.com/xtaci/kcptun) are not endorsed by xtaci.*
|
||||
|
||||
> *KCP discussion QQ group: 364933586, KCP integration, tuning, network transmission and related technical discussions.*
|
||||
|
||||
### QuickStart
|
||||
|
||||
Increase the number of open files on your server, as:
|
||||
|
||||
`ulimit -n 65535`, or write it in `~/.bashrc`.
|
||||
|
||||
Suggested `sysctl.conf` parameters for better handling of UDP packets:
|
||||
|
||||
-
|
||||
### 手动编译
|
||||
```
|
||||
$go get -u github.com/xtaci/kcptun/client
|
||||
$go get -u github.com/xtaci/kcptun/server
|
||||
net.core.rmem_max=26214400
|
||||
net.core.rmem_default=26214400
|
||||
net.core.wmem_max=26214400
|
||||
net.core.wmem_default=26214400
|
||||
net.core.netdev_max_backlog=2048
|
||||
```
|
||||
注意: 如果出现错误提示,请确保依赖库能正确访问到。
|
||||
|
||||
Release中的所有二进制版本,是通过 `build-release.sh` 脚本生成并优化。
|
||||
|
||||
### 快速设定
|
||||
|
||||
客户端、服务器分别**下载**对应平台的二进制压缩包,并**解压**,通过下面的命令**启动**端口转发。
|
||||
You can also increase the per-socket buffer by adding parameter(default 4MB):
|
||||
```
|
||||
服务器: ./server_linux_amd64 -t "服务器IP地址:8388" -l ":4000" -mode fast2
|
||||
客户端: ./client_darwin_amd64 -r "服务器IP地址:4000" -l ":8388" -mode fast2
|
||||
-sockbuf 16777217
|
||||
```
|
||||
以上命令可以实现8388/tcp端口的转发(通过4000/udp端口)。
|
||||
increasing this would work for most of the old model CPUs.
|
||||
|
||||
### 速度对比
|
||||
|
||||
Download a corresponding one from precompiled [Releases](https://github.com/xtaci/kcptun/releases).
|
||||
|
||||
```
|
||||
KCP Client: ./client_darwin_amd64 -r "KCP_SERVER_IP:4000" -l ":8388" -mode fast2
|
||||
KCP Server: ./server_linux_amd64 -t "TARGET_IP:8388" -l ":4000" -mode fast2
|
||||
```
|
||||
The above commands will establish port forwarding channel for 8388/tcp as:
|
||||
|
||||
> Application -> **KCP Client(8388/tcp) -> KCP Server(4000/udp)** -> Target Server(8388/tcp)
|
||||
|
||||
which tunnels the original connection:
|
||||
|
||||
> Application -> Target Server(8388/tcp)
|
||||
|
||||
### Install from source
|
||||
|
||||
```
|
||||
$go get -u github.com/xtaci/kcptun/...
|
||||
```
|
||||
|
||||
All precompiled releases are genereated from `build-release.sh` script.
|
||||
|
||||
### Performance
|
||||
|
||||
<img src="fast.png" alt="fast.com" height="256px" />
|
||||
* 测速网站: https://fast.com
|
||||
* 接入速度: 100Mbps
|
||||
* WIFI: 5GHz TL-WDR3320
|
||||
|
||||
### 使用方法
|
||||
### Basic Tuning Guide
|
||||
|
||||
#### Improving Thoughput
|
||||
|
||||
> **Q: I have a high speed network link, how to reach the maximum bandwidth?**
|
||||
|
||||
> **A:** Increase `-rcvwnd` on KCP Client and `-sndwnd` on KCP Server **simultaneously & gradually**, the mininum one decides the maximum transfer rate of the link, as `wnd * mtu / rtt`; Then try downloading something and to see if it meets your requirements.
|
||||
(mtu is adjustable by `-mtu`)
|
||||
|
||||
#### Improving Latency
|
||||
|
||||
> **Q: I'm using kcptun for game, I don't want any lag happening.**
|
||||
|
||||
> **A:** Lag means packet loss for most of the time, lags can be improved by changing `-mode`.
|
||||
|
||||
> eg: `-mode fast3`
|
||||
|
||||
> Aggresiveness/Responsiveness on retransmission for embeded modes are:
|
||||
|
||||
> *fast3 > fast2 > fast > normal > default*
|
||||
|
||||
|
||||
|
||||
### Expert Tuning Guide
|
||||
|
||||
#### Overview
|
||||
|
||||
<p align="left"><img src="layeredparams.png" alt="params" height="450px"/></p>
|
||||
|
||||
#### Usage
|
||||
|
||||
在Mac OS X El Capitan下的帮助输出,注意默认值:
|
||||
```
|
||||
$ ./client_darwin_amd64 -h
|
||||
NAME:
|
||||
@@ -66,30 +114,36 @@ USAGE:
|
||||
client_darwin_amd64 [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
20161025
|
||||
20180922
|
||||
|
||||
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
|
||||
--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, sm4, none (default: "aes")
|
||||
--mode value profiles: fast3, fast2, fast, normal, manual (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)
|
||||
--scavengettl value set how long an expired connection can live(in sec), -1 to disable (default: 600)
|
||||
--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: 512)
|
||||
--datashard value, --ds value set reed-solomon erasure coding - datashard (default: 10)
|
||||
--parityshard value, --ps value set reed-solomon erasure coding - parityshard (default: 3)
|
||||
--dscp value set DSCP(6bit) (default: 0)
|
||||
--nocomp disable compression
|
||||
--sockbuf value (default: 4194304)
|
||||
--keepalive value (default: 10)
|
||||
--snmplog value collect snmp to file, aware of timeformat in golang, like: ./snmp-20060102.log
|
||||
--snmpperiod value snmp collect period, in seconds (default: 60)
|
||||
--log value specify a log file to output, default goes to stderr
|
||||
--quiet to suppress the 'stream open/close' messages
|
||||
-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:
|
||||
@@ -99,122 +153,113 @@ USAGE:
|
||||
server_darwin_amd64 [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
20161025
|
||||
20180922
|
||||
|
||||
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 --加密算法
|
||||
|
||||
其余为两边可独立设定的参数
|
||||
|
||||
### 内置模式
|
||||
|
||||
响应速度:
|
||||
*fast3 > fast2 >* **[fast]** *> normal > default*
|
||||
有效载荷比:
|
||||
*default > normal >* **[fast]** *> fast2 > fast3*
|
||||
中间-mode参数比较均衡,总之就是越快,包重传越激进。
|
||||
更高级的 **手动档** 需要理解KCP协议,并通过 **隐藏参数** 调整,例如:
|
||||
```
|
||||
-mode manual -nodelay 1 -resend 2 -nc 1 -interval 20
|
||||
--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, sm4, none (default: "aes")
|
||||
--mode value profiles: fast3, fast2, fast, normal, manual (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, --ds value set reed-solomon erasure coding - datashard (default: 10)
|
||||
--parityshard value, --ps value set reed-solomon erasure coding - parityshard (default: 3)
|
||||
--dscp value set DSCP(6bit) (default: 0)
|
||||
--nocomp disable compression
|
||||
--sockbuf value (default: 4194304)
|
||||
--keepalive value (default: 10)
|
||||
--snmplog value collect snmp to file, aware of timeformat in golang, like: ./snmp-20060102.log
|
||||
--snmpperiod value snmp collect period, in seconds (default: 60)
|
||||
--pprof start profiling server on :6060
|
||||
--log value specify a log file to output, default goes to stderr
|
||||
--quiet to suppress the 'stream open/close' messages
|
||||
-c value config from json file, which will override the command from shell
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
```
|
||||
|
||||
* 搭配1. fast + FEC(5,5)
|
||||
* 搭配2. fast2 + FEC(10,3)
|
||||
* 搭配3. fast2 + FEC(0,0)
|
||||
#### Forward Error Correction
|
||||
|
||||
默认profile参考: https://github.com/xtaci/kcptun/blob/master/client/main.go#L248
|
||||
In coding theory, the [Reed–Solomon code](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction) belongs to the class of non-binary cyclic error-correcting codes. The Reed–Solomon 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 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. Furthermore, Reed–Solomon 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纠删码, 它的基本原理如下: 给定n个数据块d1, d2,…, dn,n和一个正整数m, RS根据n个数据块生成m个校验块, c1, c2,…, cm。 对于任意的n和m, 从n个原始数据块和m 个校验块中任取n块就能解码出原始数据, 即RS最多**容忍m个数据块或者校验块同时丢失**。
|
||||

|
||||
|
||||

|
||||
Setting parameters of RS-Code with ```-datashard m -parityshard n``` on **BOTH** KCP Client & KCP Server **MUST** be **IDENTICAL**.
|
||||
|
||||
通过参数```-datashard n -parityshard m``` 在两端同时设定。
|
||||
#### DSCP
|
||||
|
||||
数据包发送顺序严格遵循: n个datashard紧接m个parityshard,重复。
|
||||
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.
|
||||
|
||||
注意:为了发挥FEC最佳效果,设置 parityshard/(parity+datashard) > packet loss,比如5/(5+5) > 30%
|
||||
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.
|
||||
|
||||
### 窗口调整
|
||||
**简易窗口自我调优方法**:
|
||||
setting each side with ```-dscp value```, Here are some [Commonly used DSCP values](https://en.wikipedia.org/wiki/Differentiated_services#Commonly_used_DSCP_values).
|
||||
|
||||
> 第一步:同时在两端逐步增大client rcvwnd和server sndwnd;
|
||||
> 第二步:尝试下载,观察如果带宽利用率(服务器+客户端两端都要观察)到达预期则停止,否则跳转到第一步。
|
||||
#### Cryptanalysis
|
||||
|
||||
**注意:产生大量重传时,一定是窗口偏大了**
|
||||
kcptun is shipped with builtin packet encryption powered by various block encryption algorithms and works in [Cipher Feedback Mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Feedback_(CFB)), for each packet to be sent, the encryption process will start from encrypting a [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) from the [system entropy](https://en.wikipedia.org/wiki//dev/random), so encryption to same plaintexts never leads to a same ciphertexts thereafter.
|
||||
|
||||
### 安全
|
||||
The contents of the packets are completely anonymous with encryption, including the headers(FEC,KCP), checksums and contents. Note that, no matter which encryption method you choose on you upper layer, if you disable encryption by specifying `-crypt none` to kcptun, the transmit will be insecure somehow, since the header is ***PLAINTEXT*** to everyone it would be susceptible to header tampering, such as jamming the *sliding window size*, *round-trip time*, *FEC property* and *checksums*. ```aes-128``` is suggested for minimal encryption since modern CPUs are shipped with [AES-NI](https://en.wikipedia.org/wiki/AES_instruction_set) instructions and performs even better than `salsa20`(check the table below).
|
||||
|
||||
无论你上层如何加密,如果```-crypt none```,那么**协议头部**都是**明文**的,建议至少采用```-crypt aes-128```加密,并修改密码。
|
||||
Other possible attacks to kcptun includes: a) [traffic analysis](https://en.wikipedia.org/wiki/Traffic_analysis), dataflow on specific websites may have pattern while interchanging data, but this type of eavesdropping has been mitigated by adapting [smux](https://github.com/xtaci/smux) to mix data streams so as to introduce noises, perfect solution to this has not appeared yet, theroretically by shuffling/mixing messages on larger scale network may mitigate this problem. b) [replay attack](https://en.wikipedia.org/wiki/Replay_attack), since the asymmetrical encryption has not been introduced into kcptun for some reason, capturing the packets and replay them on a different machine is possible, (notice: hijacking the session and decrypting the contents is still *impossible*), so upper layers should contain a asymmetrical encryption system to guarantee the authenticity of each message(to process message exactly once), such as HTTPS/OpenSSL/LibreSSL, only by signing the requests with private keys can eliminate this type of attack.
|
||||
|
||||
密码可以通过`-key`指定,也可以通过环境变量`KCPTUN_KEY`指定。
|
||||
Important:
|
||||
1. `-crypt` and `-key` must be the same on both KCP Client & KCP Server.
|
||||
2. `-crypt xor` is also insecure and vulnerable to [known-plaintext attack](https://en.wikipedia.org/wiki/Known-plaintext_attack), do not use this unless you know what you are doing. (*cryptanalysis note: any type of [counter mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR)) is insecure in packet encryption due to the shorten of counter period and leads to iv/nonce collision*)
|
||||
|
||||
注意: ```-crypt xor``` 也是不安全的,除非你知道你在做什么。
|
||||
|
||||
附加密速度Benchmark:
|
||||
Benchmarks for crypto algorithms supported by kcptun:
|
||||
|
||||
```
|
||||
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
|
||||
BenchmarkSM4-4 50000 32087 ns/op 93.49 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkAES128-4 500000 3274 ns/op 916.15 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkAES192-4 500000 3587 ns/op 836.34 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkAES256-4 300000 3828 ns/op 783.60 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkTEA-4 100000 15359 ns/op 195.32 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkXOR-4 20000000 90.2 ns/op 33249.02 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkBlowfish-4 50000 26885 ns/op 111.58 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkNone-4 30000000 45.8 ns/op 65557.11 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkCast5-4 50000 34370 ns/op 87.29 MB/s 0 B/op 0 allocs/op
|
||||
Benchmark3DES-4 10000 117893 ns/op 25.45 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkTwofish-4 50000 33477 ns/op 89.61 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkXTEA-4 30000 45825 ns/op 65.47 MB/s 0 B/op 0 allocs/op
|
||||
BenchmarkSalsa20-4 500000 3282 ns/op 913.90 MB/s 0 B/op 0 allocs/op
|
||||
```
|
||||
|
||||
### 内存控制
|
||||
Benchmark result from openssl
|
||||
|
||||
路由器,手机等嵌入式设备通常对**内存用量敏感**,通过调节环境变量GOGC(例如GOGC=20)后启动client,可以降低内存使用。
|
||||
参考:https://blog.golang.org/go15gc
|
||||
```
|
||||
$ openssl speed -evp aes-128-cfb
|
||||
Doing aes-128-cfb for 3s on 16 size blocks: 157794127 aes-128-cfb's in 2.98s
|
||||
Doing aes-128-cfb for 3s on 64 size blocks: 39614018 aes-128-cfb's in 2.98s
|
||||
Doing aes-128-cfb for 3s on 256 size blocks: 9971090 aes-128-cfb's in 2.99s
|
||||
Doing aes-128-cfb for 3s on 1024 size blocks: 2510877 aes-128-cfb's in 2.99s
|
||||
Doing aes-128-cfb for 3s on 8192 size blocks: 310865 aes-128-cfb's in 2.98s
|
||||
OpenSSL 1.0.2p 14 Aug 2018
|
||||
built on: reproducible build, date unspecified
|
||||
options:bn(64,64) rc4(ptr,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
|
||||
compiler: clang -I. -I.. -I../include -fPIC -fno-common -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -arch x86_64 -O3 -DL_ENDIAN -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
|
||||
The 'numbers' are in 1000s of bytes per second processed.
|
||||
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
|
||||
aes-128-cfb 847216.79k 850770.86k 853712.05k 859912.39k 854565.80k
|
||||
```
|
||||
|
||||
The encrytion performance in kcptun is as fast as in openssl library(if not faster).
|
||||
|
||||
|
||||
### DSCP
|
||||
#### Memory Usage Control
|
||||
|
||||
DSCP差分服务代码点(Differentiated Services Code Point),IETF于1998年12月发布了Diff-Serv(Differentiated Service)的QoS分类标准。它在每个数据包IP头部的服务类别TOS标识字节中,利用已使用的**6比特**和未使用的2比特,通过编码值来区分优先级。
|
||||
常用DSCP值可以参考[Wikipedia DSCP](https://en.wikipedia.org/wiki/Differentiated_services#Commonly_used_DSCP_values),至于有没有用,完全取决于数据包经过的设备。
|
||||
Routers, mobile devices are susceptible to memory consumption; by setting GOGC environment(eg: GOGC=20) will make the garbage collector to recycle faster.
|
||||
Reference: https://blog.golang.org/go15gc
|
||||
|
||||
通过 ```-dscp ``` 参数指定dscp值,两端可分别设定。
|
||||
#### Compression
|
||||
|
||||
注意:设置dscp不一定会更好,需要尝试。
|
||||
|
||||
### Snappy数据流压缩
|
||||
kcptun has builtin snappy algorithms for compressing streams:
|
||||
|
||||
> Snappy is a compression/decompression library. It does not aim for maximum
|
||||
> compression, or compatibility with any other compression library; instead,
|
||||
@@ -225,138 +270,86 @@ DSCP差分服务代码点(Differentiated Services Code Point),IETF于1998
|
||||
|
||||
> Reference: http://google.github.io/snappy/
|
||||
|
||||
压缩对于非加密,非压缩的数据能降低传输数据量,比如点对点的HTTP数据转发。
|
||||
Compression may save bandwidth for **PLAINTEXT** data, it's quite useful for specific scenarios as cross-datacenter replications, by compressing the redologs in dbms or kafka-like message queues and then transfer the data streams across the continent can be much faster.
|
||||
|
||||
通过参数 ```-nocomp``` 在两端同时设定以关闭压缩。
|
||||
> 提示: 关闭压缩可能会降低延迟。
|
||||
Compression is enabled by default, you can disable it by setting ```-nocomp``` on **BOTH** KCP Client & KCP Server **MUST** be **IDENTICAL**.
|
||||
|
||||
### 流量控制
|
||||
|
||||
**必要性: 针对流量敏感的服务器,做双保险。**
|
||||
|
||||
> 基本原则: 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
|
||||
|
||||
```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 // raw bytes sent
|
||||
BytesReceived uint64
|
||||
MaxConn uint64
|
||||
ActiveOpens uint64
|
||||
PassiveOpens uint64
|
||||
CurrEstab uint64 // count of connections for now
|
||||
InErrs uint64 // udp read errors
|
||||
InCsumErrors uint64 // checksum errors from CRC32
|
||||
KCPInErrors uint64 // packet iput errors from kcp
|
||||
InSegs uint64
|
||||
OutSegs uint64
|
||||
InBytes uint64 // udp bytes received
|
||||
OutBytes uint64 // udp bytes sent
|
||||
RetransSegs uint64
|
||||
FastRetransSegs uint64
|
||||
EarlyRetransSegs uint64
|
||||
LostSegs uint64 // number of segs infered as lost
|
||||
RepeatSegs uint64 // number of segs duplicated
|
||||
FECRecovered uint64 // correct packets recovered from FEC
|
||||
FECErrs uint64 // incorrect packets recovered from FEC
|
||||
FECSegs uint64 // FEC segments received
|
||||
FECShortShards uint64 // number of data shards that's not enough for recovery
|
||||
}
|
||||
```
|
||||
|
||||
使用```kill -SIGUSR1 pid``` 可以在控制台打印出SNMP信息,通常用于精细调整**当前链路的有效载荷比**。
|
||||
观察```RetransSegs,FastRetransSegs,LostSegs,OutSegs```这几者的数值比例,用于参考调整```-mode manual,fec```的参数。
|
||||
Sending a `SIGUSR1` signal to KCP Client or KCP Server will dump SNMP information to console, just like `/proc/net/snmp`. You can use this information to do fine-grained tuning.
|
||||
|
||||
#### 带宽计算公式
|
||||
### Manual Control
|
||||
|
||||
```
|
||||
在不丢包的情况下,有最大-rcvwnd 个数据包在网络上正在向你传输,以平均数据包大小avgsize计算,在任意时刻,有:
|
||||
https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configuration
|
||||
|
||||
network_cap = rcvwnd*avgsize
|
||||
`-mode manual -nodelay 1 -interval 20 -resend 2 -nc 1`
|
||||
|
||||
数据流向你,这个值再除以ping值(rtt),等于最大带宽使用量。
|
||||
Low-level KCP configuration can be altered by using manual mode like above, make sure you really **UNDERSTAND** what these means before doing **ANY** manual settings.
|
||||
|
||||
max_bandwidth = network_cap/rtt = rcvwnd*avgsize/rtt
|
||||
|
||||
举例,设rcvwnd = 1024, avgsize = 1KB, rtt = 400ms,则:
|
||||
|
||||
max_bandwidth = 1024 * 1KB / 400ms = 2.5MB/s ~= 25Mbps
|
||||
|
||||
(注:以上计算不包括前向纠错的数据量)
|
||||
### Identical Parmeters
|
||||
|
||||
前向纠错是最大带宽量的一个固定比例增加:
|
||||
The parameters below **MUST** be **IDENTICAL** on **BOTH** side:
|
||||
|
||||
max_bandwidth_fec = max_bandwidth*(datashard+parityshard)/datashard
|
||||
1. -key
|
||||
1. -crypt
|
||||
1. -nocomp
|
||||
1. -datashard
|
||||
1. -parityshard
|
||||
|
||||
举例,设datashard = 10 , partiyshard = 3,则:
|
||||
|
||||
max_bandwidth_fec = max_bandwidth * (10 + 3) /10 = 1.3*max_bandwidth = 1.3 * 25Mbps = 32.5Mbps
|
||||
```
|
||||
|
||||
### 故障排除
|
||||
|
||||
> Q: 客户端和服务器端**皆无** ```stream opened```信息。
|
||||
> A: 连接客户端程序的端口设置错误。
|
||||
|
||||
> Q: 客户端有 ```stream opened```信息,服务器端没有。
|
||||
> A: 连接服务器的端口设置错误,或者被防火墙拦截。
|
||||
|
||||
> Q: 客户端服务器**皆有** ```stream opened```信息,但无法通信。
|
||||
> A: 上层软件的设定错误。
|
||||
|
||||
### 免责申明
|
||||
|
||||
**用户以各种方式使用本软件(包括但不限于修改使用、直接使用、通过第三方使用)的过程中,不得以任何方式利用本软件直接或间接从事违反中国法律、以及社会公德的行为。软件的使用者需对自身行为负责,因使用软件引发的一切纠纷,由使用者承担全部法律及连带责任。作者不承担任何法律及连带责任。**
|
||||
|
||||
**对免责声明的解释、修改及更新权均属于作者本人所有。**
|
||||
|
||||
### 捐赠
|
||||
|
||||

|
||||
|
||||
### 特别鸣谢
|
||||
|
||||
> 郑H立, 南东风, Li, 七七, 凌君, 昶,LesMiserables, KyOn, 噼里啪啦, 继斌, 小苍辛苦, **Ken**,
|
||||
> 乔槁, 佳晨, 猪肉佬, lcx, 昊文, 冰峰, 凡, alex, **海豹叔叔**, 奥姐, 张冰, 司成,
|
||||
> 武子, **慎**,Alex43211,**Coxxs**,荣,NeroNg,吴骁,定一,我不是林J,Patrick, 超, 陈,windfarer, 宇,
|
||||
> 今晶,斌,晓东,最后一缕阳光,亮,Ethan,一心不乱,allenm,冬卯,GELATO,用户1,Butterfly,光子曲面,
|
||||
> 丞佳,捉鱼,Talon,Biny,李勇,***阿彪***,***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
|
||||
|
||||
### 参考资料
|
||||
### References
|
||||
|
||||
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
|
||||
1. https://github.com/xtaci/kcp-go/ -- A Production-Grade Reliable-UDP Library for golang
|
||||
1. https://github.com/klauspost/reedsolomon -- Reed-Solomon Erasure Coding in Go.
|
||||
1. https://en.wikipedia.org/wiki/Differentiated_services -- DSCP.
|
||||
1. http://google.github.io/snappy/ -- A fast compressor/decompressor.
|
||||
1. https://www.backblaze.com/blog/reed-solomon/ -- Reed-Solomon Explained.
|
||||
1. http://www.qualcomm.cn/products/raptorq -- RaptorQ Forward Error Correction Scheme for Object Delivery.
|
||||
1. https://en.wikipedia.org/wiki/PBKDF2 -- Key stretching.
|
||||
1. http://blog.appcanary.com/2016/encrypt-or-compress.html -- Should you encrypt or compress first?
|
||||
1. https://github.com/hashicorp/yamux -- Connection multiplexing library.
|
||||
1. https://tools.ietf.org/html/rfc6937 -- Proportional Rate Reduction for TCP.
|
||||
1. https://tools.ietf.org/html/rfc5827 -- Early Retransmit for TCP and Stream Control Transmission Protocol (SCTP).
|
||||
1. http://http2.github.io/ -- What is HTTP/2?
|
||||
1. http://www.lartc.org/ -- Linux Advanced Routing & Traffic Control
|
||||
1. https://en.wikipedia.org/wiki/Noisy-channel_coding_theorem -- Noisy channel coding theorem
|
||||
1. https://play.google.com/store/apps/details?id=com.k17game.k3 -- Battle Zone - Earth 2048, an online strategy game using kcp.
|
||||
|
||||
### Donate
|
||||
|
||||
via Ethereum(ETH): Address: 0x2e4b43ab3d0983da282592571eef61ae5e60f726 , Or scan here:
|
||||
|
||||
<img src="0x2e4b43ab3d0983da282592571eef61ae5e60f726.png" alt="kcptun" height="120px" />
|
||||
|
||||
via WeChat
|
||||
|
||||
<img src="wechat_donate.jpg" alt="kcptun" height="120px" />
|
||||
|
||||
+17
-12
@@ -1,8 +1,13 @@
|
||||
#!/bin/bash
|
||||
MD5='md5sum'
|
||||
unamestr=`uname`
|
||||
if [[ "$unamestr" == 'Darwin' ]]; then
|
||||
MD5='md5'
|
||||
sum="sha1sum"
|
||||
|
||||
if ! hash sha1sum 2>/dev/null; then
|
||||
if ! hash shasum 2>/dev/null; then
|
||||
echo "I can't see 'sha1sum' or 'shasum'"
|
||||
echo "Please install one of them!"
|
||||
exit
|
||||
fi
|
||||
sum="shasum"
|
||||
fi
|
||||
|
||||
UPX=false
|
||||
@@ -27,7 +32,7 @@ for os in ${OSES[@]}; do
|
||||
env CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -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
|
||||
$sum kcptun-${os}-${arch}-$VERSION.tar.gz
|
||||
done
|
||||
done
|
||||
|
||||
@@ -39,16 +44,16 @@ for v in ${ARMS[@]}; do
|
||||
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
|
||||
$sum 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
|
||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_linux_mipsle github.com/xtaci/kcptun/client
|
||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_linux_mipsle github.com/xtaci/kcptun/server
|
||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_linux_mips github.com/xtaci/kcptun/client
|
||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat 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
|
||||
$sum kcptun-linux-mipsle-$VERSION.tar.gz
|
||||
$sum kcptun-linux-mips-$VERSION.tar.gz
|
||||
|
||||
@@ -14,6 +14,7 @@ type Config struct {
|
||||
Mode string `json:"mode"`
|
||||
Conn int `json:"conn"`
|
||||
AutoExpire int `json:"autoexpire"`
|
||||
ScavengeTTL int `json:"scavengettl"`
|
||||
MTU int `json:"mtu"`
|
||||
SndWnd int `json:"sndwnd"`
|
||||
RcvWnd int `json:"rcvwnd"`
|
||||
@@ -31,6 +32,7 @@ type Config struct {
|
||||
Log string `json:"log"`
|
||||
SnmpLog string `json:"snmplog"`
|
||||
SnmpPeriod int `json:"snmpperiod"`
|
||||
Quiet bool `json:"quiet"`
|
||||
}
|
||||
|
||||
func parseJSONConfig(config *Config, path string) error {
|
||||
|
||||
+60
-40
@@ -18,6 +18,8 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
"github.com/xtaci/smux"
|
||||
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -55,23 +57,27 @@ func newCompStream(conn net.Conn) *compStream {
|
||||
return c
|
||||
}
|
||||
|
||||
func handleClient(sess *smux.Session, p1 io.ReadWriteCloser) {
|
||||
func handleClient(sess *smux.Session, p1 io.ReadWriteCloser, quiet bool) {
|
||||
if !quiet {
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
}
|
||||
|
||||
defer p1.Close()
|
||||
p2, err := sess.OpenStream()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
defer p1.Close()
|
||||
defer p2.Close()
|
||||
|
||||
// start tunnel
|
||||
p1die := make(chan struct{})
|
||||
go func() { io.Copy(p1, p2); close(p1die) }()
|
||||
buf1 := make([]byte, 65535)
|
||||
go func() { io.CopyBuffer(p1, p2, buf1); close(p1die) }()
|
||||
|
||||
p2die := make(chan struct{})
|
||||
go func() { io.Copy(p2, p1); close(p2die) }()
|
||||
buf2 := make([]byte, 65535)
|
||||
go func() { io.CopyBuffer(p2, p1, buf2); close(p2die) }()
|
||||
|
||||
// wait for tunnel termination
|
||||
select {
|
||||
@@ -117,12 +123,12 @@ func main() {
|
||||
cli.StringFlag{
|
||||
Name: "crypt",
|
||||
Value: "aes",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "mode",
|
||||
Value: "fast",
|
||||
Usage: "profiles: fast3, fast2, fast, normal",
|
||||
Usage: "profiles: fast3, fast2, fast, normal, manual",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "conn",
|
||||
@@ -134,6 +140,11 @@ func main() {
|
||||
Value: 0,
|
||||
Usage: "set auto expiration time(in seconds) for a single UDP connection, 0 to disable",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "scavengettl",
|
||||
Value: 600,
|
||||
Usage: "set how long an expired connection can live(in sec), -1 to disable",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "mtu",
|
||||
Value: 1350,
|
||||
@@ -180,7 +191,7 @@ func main() {
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "interval",
|
||||
Value: 40,
|
||||
Value: 50,
|
||||
Hidden: true,
|
||||
},
|
||||
cli.IntFlag{
|
||||
@@ -194,14 +205,14 @@ func main() {
|
||||
Hidden: true,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "sockbuf",
|
||||
Value: 4194304, // socket buffer size in bytes
|
||||
Hidden: true,
|
||||
Name: "sockbuf",
|
||||
Value: 4194304, // socket buffer size in bytes
|
||||
Usage: "per-socket buffer in bytes",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "keepalive",
|
||||
Value: 10, // nat keepalive interval in seconds
|
||||
Hidden: true,
|
||||
Name: "keepalive",
|
||||
Value: 10, // nat keepalive interval in seconds
|
||||
Usage: "seconds between heartbeats",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "snmplog",
|
||||
@@ -218,6 +229,10 @@ func main() {
|
||||
Value: "",
|
||||
Usage: "specify a log file to output, default goes to stderr",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "to suppress the 'stream open/close' messages",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "c",
|
||||
Value: "", // when the value is not empty, the config path must exists
|
||||
@@ -233,6 +248,7 @@ func main() {
|
||||
config.Mode = c.String("mode")
|
||||
config.Conn = c.Int("conn")
|
||||
config.AutoExpire = c.Int("autoexpire")
|
||||
config.ScavengeTTL = c.Int("scavengettl")
|
||||
config.MTU = c.Int("mtu")
|
||||
config.SndWnd = c.Int("sndwnd")
|
||||
config.RcvWnd = c.Int("rcvwnd")
|
||||
@@ -250,6 +266,7 @@ func main() {
|
||||
config.Log = c.String("log")
|
||||
config.SnmpLog = c.String("snmplog")
|
||||
config.SnmpPeriod = c.Int("snmpperiod")
|
||||
config.Quiet = c.Bool("quiet")
|
||||
|
||||
if c.String("c") != "" {
|
||||
err := parseJSONConfig(&config, c.String("c"))
|
||||
@@ -266,9 +283,9 @@ func main() {
|
||||
|
||||
switch config.Mode {
|
||||
case "normal":
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 30, 2, 1
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 40, 2, 1
|
||||
case "fast":
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 20, 2, 1
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 30, 2, 1
|
||||
case "fast2":
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 1, 20, 2, 1
|
||||
case "fast3":
|
||||
@@ -281,9 +298,12 @@ func main() {
|
||||
listener, err := net.ListenTCP("tcp", addr)
|
||||
checkError(err)
|
||||
|
||||
log.Println("initiating key derivation")
|
||||
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
|
||||
var block kcp.BlockCrypt
|
||||
switch config.Crypt {
|
||||
case "sm4":
|
||||
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
|
||||
case "tea":
|
||||
block, _ = kcp.NewTEABlockCrypt(pass[:16])
|
||||
case "xor":
|
||||
@@ -325,11 +345,14 @@ func main() {
|
||||
log.Println("keepalive:", config.KeepAlive)
|
||||
log.Println("conn:", config.Conn)
|
||||
log.Println("autoexpire:", config.AutoExpire)
|
||||
log.Println("scavengettl:", config.ScavengeTTL)
|
||||
log.Println("snmplog:", config.SnmpLog)
|
||||
log.Println("snmpperiod:", config.SnmpPeriod)
|
||||
log.Println("quiet:", config.Quiet)
|
||||
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SockBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||
|
||||
createConn := func() (*smux.Session, error) {
|
||||
kcpconn, err := kcp.DialWithOptions(config.RemoteAddr, block, config.DataShard, config.ParityShard)
|
||||
@@ -337,11 +360,11 @@ func main() {
|
||||
return nil, errors.Wrap(err, "createConn()")
|
||||
}
|
||||
kcpconn.SetStreamMode(true)
|
||||
kcpconn.SetWriteDelay(false)
|
||||
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)
|
||||
|
||||
if err := kcpconn.SetDSCP(config.DSCP); err != nil {
|
||||
log.Println("SetDSCP:", err)
|
||||
@@ -363,6 +386,7 @@ func main() {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "createConn()")
|
||||
}
|
||||
log.Println("connection:", kcpconn.LocalAddr(), "->", kcpconn.RemoteAddr())
|
||||
return session, nil
|
||||
}
|
||||
|
||||
@@ -372,6 +396,7 @@ func main() {
|
||||
if session, err := createConn(); err == nil {
|
||||
return session
|
||||
} else {
|
||||
log.Println("re-connecting:", err)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
@@ -384,14 +409,12 @@ func main() {
|
||||
}, numconn)
|
||||
|
||||
for k := range muxes {
|
||||
sess, err := createConn()
|
||||
checkError(err)
|
||||
muxes[k].session = sess
|
||||
muxes[k].session = waitConn()
|
||||
muxes[k].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
}
|
||||
|
||||
chScavenger := make(chan *smux.Session, 128)
|
||||
go scavenger(chScavenger)
|
||||
go scavenger(chScavenger, config.ScavengeTTL)
|
||||
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
rr := uint16(0)
|
||||
for {
|
||||
@@ -399,12 +422,6 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if err := p1.SetReadBuffer(config.SockBuf); err != nil {
|
||||
log.Println("TCP SetReadBuffer:", err)
|
||||
}
|
||||
if err := p1.SetWriteBuffer(config.SockBuf); err != nil {
|
||||
log.Println("TCP SetWriteBuffer:", err)
|
||||
}
|
||||
checkError(err)
|
||||
idx := rr % numconn
|
||||
|
||||
@@ -415,7 +432,7 @@ func main() {
|
||||
muxes[idx].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
}
|
||||
|
||||
go handleClient(muxes[idx].session, p1)
|
||||
go handleClient(muxes[idx].session, p1, config.Quiet)
|
||||
rr++
|
||||
}
|
||||
}
|
||||
@@ -424,27 +441,27 @@ func main() {
|
||||
|
||||
type scavengeSession struct {
|
||||
session *smux.Session
|
||||
ttl time.Time
|
||||
ts time.Time
|
||||
}
|
||||
|
||||
const (
|
||||
maxScavengeTTL = 10 * time.Minute
|
||||
)
|
||||
|
||||
func scavenger(ch chan *smux.Session) {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
func scavenger(ch chan *smux.Session, ttl int) {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
var sessionList []scavengeSession
|
||||
for {
|
||||
select {
|
||||
case sess := <-ch:
|
||||
sessionList = append(sessionList, scavengeSession{sess, time.Now()})
|
||||
log.Println("session marked as expired")
|
||||
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")
|
||||
if s.session.NumStreams() == 0 || s.session.IsClosed() {
|
||||
log.Println("session normally closed")
|
||||
s.session.Close()
|
||||
} else if ttl >= 0 && time.Since(s.ts) >= time.Duration(ttl)*time.Second {
|
||||
log.Println("session reached scavenge ttl")
|
||||
s.session.Close()
|
||||
} else {
|
||||
newList = append(newList, sessionList[k])
|
||||
@@ -464,7 +481,10 @@ func snmpLogger(path string, interval int) {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
f, err := os.OpenFile(time.Now().Format(path), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
// split path into dirname and filename
|
||||
logdir, logfile := filepath.Split(path)
|
||||
// only format logfile
|
||||
f, err := os.OpenFile(logdir+time.Now().Format(logfile), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
|
||||
@@ -18,6 +18,7 @@ func init() {
|
||||
func sigHandler() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGUSR1)
|
||||
signal.Ignore(syscall.SIGPIPE)
|
||||
|
||||
for {
|
||||
switch <-ch {
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 4.3 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 33 KiB |
@@ -29,6 +29,8 @@ type Config struct {
|
||||
Log string `json:"log"`
|
||||
SnmpLog string `json:"snmplog"`
|
||||
SnmpPeriod int `json:"snmpperiod"`
|
||||
Pprof bool `json:"pprof"`
|
||||
Quiet bool `json:"quiet"`
|
||||
}
|
||||
|
||||
func parseJSONConfig(config *Config, path string) error {
|
||||
|
||||
+51
-25
@@ -8,11 +8,15 @@ import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/urfave/cli"
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
@@ -59,6 +63,8 @@ func handleMux(conn io.ReadWriteCloser, config *Config) {
|
||||
// stream multiplex
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SockBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||
|
||||
mux, err := smux.Server(conn, smuxConfig)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -77,28 +83,26 @@ func handleMux(conn io.ReadWriteCloser, config *Config) {
|
||||
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)
|
||||
}
|
||||
go handleClient(p1, p2)
|
||||
go handleClient(p1, p2, config.Quiet)
|
||||
}
|
||||
}
|
||||
|
||||
func handleClient(p1, p2 io.ReadWriteCloser) {
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
func handleClient(p1, p2 io.ReadWriteCloser, quiet bool) {
|
||||
if !quiet {
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
}
|
||||
defer p1.Close()
|
||||
defer p2.Close()
|
||||
|
||||
// start tunnel
|
||||
p1die := make(chan struct{})
|
||||
go func() { io.Copy(p1, p2); close(p1die) }()
|
||||
buf1 := make([]byte, 65535)
|
||||
go func() { io.CopyBuffer(p1, p2, buf1); close(p1die) }()
|
||||
|
||||
p2die := make(chan struct{})
|
||||
go func() { io.Copy(p2, p1); close(p2die) }()
|
||||
buf2 := make([]byte, 65535)
|
||||
go func() { io.CopyBuffer(p2, p1, buf2); close(p2die) }()
|
||||
|
||||
// wait for tunnel termination
|
||||
select {
|
||||
@@ -144,12 +148,12 @@ func main() {
|
||||
cli.StringFlag{
|
||||
Name: "crypt",
|
||||
Value: "aes",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "mode",
|
||||
Value: "fast",
|
||||
Usage: "profiles: fast3, fast2, fast, normal",
|
||||
Usage: "profiles: fast3, fast2, fast, normal, manual",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "mtu",
|
||||
@@ -197,7 +201,7 @@ func main() {
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "interval",
|
||||
Value: 40,
|
||||
Value: 50,
|
||||
Hidden: true,
|
||||
},
|
||||
cli.IntFlag{
|
||||
@@ -211,14 +215,14 @@ func main() {
|
||||
Hidden: true,
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "sockbuf",
|
||||
Value: 4194304, // socket buffer size in bytes
|
||||
Hidden: true,
|
||||
Name: "sockbuf",
|
||||
Value: 4194304, // socket buffer size in bytes
|
||||
Usage: "per-socket buffer in bytes",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "keepalive",
|
||||
Value: 10, // nat keepalive interval in seconds
|
||||
Hidden: true,
|
||||
Name: "keepalive",
|
||||
Value: 10, // nat keepalive interval in seconds
|
||||
Usage: "seconds between heartbeats",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "snmplog",
|
||||
@@ -230,11 +234,19 @@ func main() {
|
||||
Value: 60,
|
||||
Usage: "snmp collect period, in seconds",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "pprof",
|
||||
Usage: "start profiling server on :6060",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "log",
|
||||
Value: "",
|
||||
Usage: "specify a log file to output, default goes to stderr",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "to suppress the 'stream open/close' messages",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "c",
|
||||
Value: "", // when the value is not empty, the config path must exists
|
||||
@@ -265,6 +277,8 @@ func main() {
|
||||
config.Log = c.String("log")
|
||||
config.SnmpLog = c.String("snmplog")
|
||||
config.SnmpPeriod = c.Int("snmpperiod")
|
||||
config.Pprof = c.Bool("pprof")
|
||||
config.Quiet = c.Bool("quiet")
|
||||
|
||||
if c.String("c") != "" {
|
||||
//Now only support json config file
|
||||
@@ -282,9 +296,9 @@ func main() {
|
||||
|
||||
switch config.Mode {
|
||||
case "normal":
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 30, 2, 1
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 40, 2, 1
|
||||
case "fast":
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 20, 2, 1
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 0, 30, 2, 1
|
||||
case "fast2":
|
||||
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 1, 20, 2, 1
|
||||
case "fast3":
|
||||
@@ -292,9 +306,12 @@ func main() {
|
||||
}
|
||||
|
||||
log.Println("version:", VERSION)
|
||||
log.Println("initiating key derivation")
|
||||
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
|
||||
var block kcp.BlockCrypt
|
||||
switch config.Crypt {
|
||||
case "sm4":
|
||||
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
|
||||
case "tea":
|
||||
block, _ = kcp.NewTEABlockCrypt(pass[:16])
|
||||
case "xor":
|
||||
@@ -338,6 +355,8 @@ func main() {
|
||||
log.Println("keepalive:", config.KeepAlive)
|
||||
log.Println("snmplog:", config.SnmpLog)
|
||||
log.Println("snmpperiod:", config.SnmpPeriod)
|
||||
log.Println("pprof:", config.Pprof)
|
||||
log.Println("quiet:", config.Quiet)
|
||||
|
||||
if err := lis.SetDSCP(config.DSCP); err != nil {
|
||||
log.Println("SetDSCP:", err)
|
||||
@@ -350,15 +369,19 @@ func main() {
|
||||
}
|
||||
|
||||
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
if config.Pprof {
|
||||
go http.ListenAndServe(":6060", nil)
|
||||
}
|
||||
|
||||
for {
|
||||
if conn, err := lis.AcceptKCP(); err == nil {
|
||||
log.Println("remote address:", conn.RemoteAddr())
|
||||
conn.SetStreamMode(true)
|
||||
conn.SetWriteDelay(false)
|
||||
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)
|
||||
@@ -382,7 +405,10 @@ func snmpLogger(path string, interval int) {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
f, err := os.OpenFile(time.Now().Format(path), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
// split path into dirname and filename
|
||||
logdir, logfile := filepath.Split(path)
|
||||
// only format logfile
|
||||
f, err := os.OpenFile(logdir+time.Now().Format(logfile), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
|
||||
@@ -18,6 +18,7 @@ func init() {
|
||||
func sigHandler() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGUSR1)
|
||||
signal.Ignore(syscall.SIGPIPE)
|
||||
|
||||
for {
|
||||
switch <-ch {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Reference in New Issue
Block a user