Compare commits

..
136 Commits
Author SHA1 Message Date
xtaci e26ab6729f spelling 2016-08-22 14:46:57 +08:00
xtaci 583fe3ba24 simple layer 2016-08-21 19:09:08 +08:00
xtaci 7fd6442284 refer to my fork 2016-08-20 21:15:05 +08:00
xtaci 81f4643830 Revert "refer to fork"
This reverts commit 744a6407e7.
2016-08-20 20:49:44 +08:00
xtaci 744a6407e7 refer to fork 2016-08-20 20:23:04 +08:00
xtaci 2cf5292ac1 revert yamux config 2016-08-20 18:37:52 +08:00
xtaci b3a8b631b4 upd README 2016-08-20 16:48:10 +08:00
xtaci 1167419210 add salsa20, xtea crypto 2016-08-20 15:02:25 +08:00
xtaci 56f9f0d01a Merge branch 'master' of https://github.com/xtaci/kcptun 2016-08-20 13:39:01 +08:00
xtaci 96888f1cac pisces 2016-08-20 13:35:27 +08:00
xtaciandGitHub e752d70c79 Update README.en.md 2016-08-20 10:47:59 +08:00
xtaciandGitHub a882b94e5b Update README.md 2016-08-20 10:46:34 +08:00
xtaciandGitHub 790a6d5352 Update README.en.md 2016-08-19 21:21:03 +08:00
xtaciandGitHub 603c2db5ab Update README.md 2016-08-19 21:20:15 +08:00
xtaci 581df3a34d update README.md 2016-08-19 15:00:25 +08:00
xtaci 6113d2b497 update README.md 2016-08-19 14:27:13 +08:00
xtaci d3b8a4d71d keep compatiability 2016-08-19 13:17:02 +08:00
xtaci 1f0a4a2c2f change default settings 2016-08-19 12:31:51 +08:00
xtaci 75923fb08f adjust -help 2016-08-19 12:22:36 +08:00
xtaci 0243422885 add supports for blowfish, cast5, 3des 2016-08-19 11:15:13 +08:00
xtaci 6374cb0d36 Merge branch 'master' of https://github.com/xtaci/kcptun 2016-08-18 23:44:25 +08:00
xtaci 0aedc21c50 Revert "change default resend from 2 -> 3"
This reverts commit 003617186b.
2016-08-18 23:40:51 +08:00
xtaciandGitHub 727887517f Update README.en.md 2016-08-18 10:56:46 +08:00
xtaciandGitHub 7b81b24e8d Update README.md 2016-08-18 10:55:55 +08:00
xtaci ba22434379 experimental Bounds Checking Elimination 2016-08-18 09:51:17 +08:00
xtaci 003617186b change default resend from 2 -> 3 2016-08-17 21:07:27 +08:00
xtaciandGitHub b9ce27cb3e Update README.en.md 2016-08-17 11:33:53 +08:00
xtaciandGitHub c93a199823 Update README.md 2016-08-17 11:32:58 +08:00
xtaci bb34894947 upd issue 2016-08-17 11:26:35 +08:00
xtaci f743a075c5 upd 2016-08-17 11:22:09 +08:00
xtaci a04c959c9c add aes-128 aes-192 cipher 2016-08-16 16:46:27 +08:00
xtaci 4a79d26d35 upd README.md 2016-08-16 10:31:37 +08:00
xtaci 8104d18959 Revert "add manual GC support"
This reverts commit ae699f498c.
2016-08-15 21:34:43 +08:00
xtaci ae699f498c add manual GC support 2016-08-15 20:28:15 +08:00
xtaci dbdd79f1d6 upd 2016-08-15 14:04:45 +08:00
xtaciandGitHub 51bdedb1b3 Update README.md 2016-08-15 14:03:48 +08:00
xtaci 8ea071fa03 upd README 2016-08-15 10:23:47 +08:00
xtaciandGitHub f74201a410 Update ISSUE_TEMPLATE 2016-08-14 18:34:32 +08:00
xtaci 96622bcfc0 add issue template 2016-08-12 10:27:17 +08:00
xtaciandGitHub 29328b375a Update README.md 2016-08-11 21:02:21 +08:00
xtaciandGitHub db7f1def1b Update README.en.md 2016-08-11 20:50:48 +08:00
xtaciandGitHub 628e723167 Update README.md 2016-08-11 20:48:48 +08:00
xtaci ff393ccacb revert part of the PR 2016-08-11 14:47:43 +08:00
xtaciandGitHub 1bb61dbcfc Merge pull request #113 from buaazp/yamux-optimize
*: some optimizes for yamux cache and config
2016-08-11 14:38:05 +08:00
招牌疯子 0b1598d09f *: yamux optimizes for cache and config
and debug log flags when selfbuild.
2016-08-11 14:23:44 +08:00
xtaci 0552bebe46 upd 2016-08-11 13:29:01 +08:00
xtaci d158e6df3f set stream max windows size to sockbuff 2016-08-11 13:20:03 +08:00
xtaciandGitHub cf7bca5cb7 Update README.md 2016-08-11 10:05:05 +08:00
xtaciandGitHub 99a2b60c7d Update README.md 2016-08-11 10:04:25 +08:00
xtaciandGitHub 4a5024b361 Update README.md 2016-08-11 10:04:02 +08:00
xtaciandGitHub 12bd3853d5 Update README.en.md 2016-08-10 10:31:05 +08:00
xtaciandGitHub 7992b87889 Update README.md 2016-08-10 10:30:17 +08:00
xtaciandGitHub cfcc2e0676 Update README.en.md 2016-08-09 15:52:45 +08:00
xtaciandGitHub 1e870f02af Update README.md 2016-08-09 14:08:22 +08:00
xtaci bf2abf14e7 change default socket buffer to 4MB(macOS default limit) 2016-08-08 10:50:46 +08:00
xtaci 2df3e6c438 optimize API 2016-08-08 10:41:42 +08:00
xtaciandGitHub ba4c93c3f5 Update README.md 2016-08-07 21:00:52 +08:00
xtaciandGitHub bc22f46065 Merge pull request #97 from buaazp/master
optmize cli flags for accept callback
2016-08-07 19:45:01 +08:00
招牌疯子 3fc15de95d optmize cli flags for accept callback
And use custom kcp package name for godef.
2016-08-07 14:09:58 +08:00
xtaci 6f9449bb10 rename api 2016-08-06 11:21:20 +08:00
xtaci c6cbfd307e change ping -> keepalive for nat keep-alive 2016-08-06 10:19:13 +08:00
xtaci d68792cb1a add hidden parameters -- ping 2016-08-05 22:46:11 +08:00
xtaci 117edce137 upd kcp-go api 2016-08-05 17:06:57 +08:00
xtaciandGitHub 990a5f7f87 Update README.md 2016-08-02 14:24:42 +08:00
xtaciandGitHub 19d7d74d59 Add files via upload 2016-08-01 12:44:41 +08:00
xtaci 31afe325ad Merge branch 'master' of https://github.com/xtaci/kcptun 2016-07-29 10:17:33 +08:00
xtaci ab7519c2d6 remove one unnecessary line 2016-07-29 10:17:14 +08:00
xtaciandGitHub d6da2e1ead Update README.en.md 2016-07-27 13:51:13 +08:00
xtaciandGitHub 4d5a3dd791 Update README.md 2016-07-27 13:49:01 +08:00
xtaciandGitHub 4a46d696b6 Update README.md 2016-07-27 13:41:31 +08:00
xtaciandGitHub 33d50dcd45 Update README.en.md 2016-07-26 23:26:23 +08:00
xtaciandGitHub 2b3f6dbabe Update README.md 2016-07-26 23:25:15 +08:00
xtaciandGitHub 448717fa1c Update README.md 2016-07-26 21:40:17 +08:00
xtaciandGitHub 887fba3381 Update README.md 2016-07-26 21:33:52 +08:00
xtaciandGitHub fb62d45df8 Update README.en.md 2016-07-26 16:10:29 +08:00
xtaciandGitHub cd1e2b4ff7 Update README.md 2016-07-26 16:09:08 +08:00
xtaci 5ee659dd41 improve network latency by introducing stream mode 2016-07-25 20:14:12 +08:00
xtaciandGitHub 1a596f55f4 Update README.en.md 2016-07-24 16:18:28 +08:00
xtaciandGitHub 889a904dca Update README.md 2016-07-24 16:18:09 +08:00
xtaciandGitHub 172dcf6481 Update README.en.md 2016-07-24 16:16:34 +08:00
xtaciandGitHub ff92c70b40 Add files via upload 2016-07-24 16:15:22 +08:00
xtaciandGitHub af1d28ae5a Update README.md 2016-07-24 16:09:06 +08:00
xtaciandGitHub 4a7d143c69 Update README.en.md 2016-07-24 16:04:58 +08:00
xtaciandGitHub 7ff69f16d5 Update README.md 2016-07-24 16:03:48 +08:00
xtaciandGitHub 7eb037c4dd Update README.md 2016-07-24 16:00:53 +08:00
xtaciandGitHub a87f6af812 Add files via upload 2016-07-24 15:58:35 +08:00
xtaciandGitHub 7574f9bfd3 Update README.md 2016-07-24 09:23:47 +08:00
xtaci d5b5cf683b update Dockerfile 2016-07-23 11:30:37 +08:00
xtaci fded353b68 update Dockerfile 2016-07-23 11:23:18 +08:00
xtaci 832dbed064 Merge branch 'master' of https://github.com/xtaci/kcptun 2016-07-23 11:18:48 +08:00
xtaci 4b660fa02c update 2016-07-23 11:18:29 +08:00
xtaciandGitHub 59e6ebee05 Update README.md 2016-07-23 11:10:55 +08:00
xtaciandGitHub c1a895426d Update README.md 2016-07-23 10:49:21 +08:00
xtaci ebdcc9ae8a Merge branch 'master' of https://github.com/xtaci/kcptun 2016-07-22 21:41:24 +08:00
xtaci 2c076f7a34 update Dockerfile to alpine 2016-07-22 21:25:29 +08:00
Daniel FuandGitHub a1a0fbd060 Update README.md 2016-07-21 20:25:43 +08:00
Daniel FuandGitHub bc4214e4a8 Update README.md 2016-07-21 12:27:00 +08:00
Daniel FuandGitHub 61e6dfe87b Update README.md 2016-07-21 12:26:00 +08:00
Daniel FuandGitHub 4448a2658d Add files via upload 2016-07-20 14:53:01 +08:00
Daniel FuandGitHub c9a312f12b Update README.md 2016-07-18 11:04:47 +08:00
Daniel FuandGitHub 2bb48495d3 Update README.md 2016-07-18 11:03:30 +08:00
Daniel FuandGitHub 06f0a6f80b Update README.md 2016-07-18 11:01:21 +08:00
Daniel FuandGitHub ea895ad824 Update README.md 2016-07-18 10:52:37 +08:00
Daniel FuandGitHub a72bf0c9b5 Update README.md 2016-07-18 10:32:22 +08:00
xtaci 2b83dbda07 hide acknodelay parameters 2016-07-16 22:57:03 +08:00
xtaci c35ef339af fix urfave deprecated action signature 2016-07-14 10:01:35 +08:00
xtaci c96d4b534e Merge branch 'master' of https://github.com/xtaci/kcptun 2016-07-12 12:35:54 +08:00
xtaci 6216049c14 force CGO_ENABLED=0 2016-07-12 12:35:23 +08:00
Daniel FuandGitHub 0d98020e59 Update README.md 2016-07-12 11:32:42 +08:00
Daniel FuandGitHub 14ea6f8a71 Update README.md 2016-07-11 17:23:00 +08:00
Daniel FuandGitHub 214669eaf9 Update README.md 2016-07-11 17:15:15 +08:00
Daniel FuandGitHub 48d2cad6ac Update README.en.md 2016-07-11 17:14:04 +08:00
Daniel FuandGitHub 67cd5a4e22 Update README.md 2016-07-11 17:06:34 +08:00
Daniel FuandGitHub f49392c95e Update README.md 2016-07-11 17:03:18 +08:00
Daniel FuandGitHub 4c9370a252 Update README.en.md 2016-07-07 11:07:42 +08:00
Daniel FuandGitHub ef3cf3d982 Update README.en.md 2016-07-07 11:03:49 +08:00
Daniel FuandGitHub 8e5f405336 Update README.md 2016-07-07 10:52:50 +08:00
Daniel FuandGitHub 2aa6887860 Update README.md 2016-07-07 10:37:27 +08:00
Daniel FuandGitHub 9d13ec9350 Update README.md 2016-07-06 21:31:55 +08:00
Daniel FuandGitHub ef9d08567f Update README.md 2016-07-06 21:26:30 +08:00
Daniel FuandGitHub 66ebcf2773 Update README.md 2016-07-06 21:18:52 +08:00
Daniel FuandGitHub 67a08b43ed Update README.md 2016-07-06 21:15:36 +08:00
Daniel FuandGitHub 46ce8a2e51 Update README.md 2016-07-06 21:12:34 +08:00
Daniel FuandGitHub fd6a6e4a64 Update README.md 2016-07-06 19:18:55 +08:00
Daniel FuandGitHub 1de3c1fa8a Update README.md 2016-07-05 22:31:08 +08:00
Daniel FuandGitHub cc821b6eaf Update README.en.md 2016-07-05 22:30:25 +08:00
xtaci 6f8ce90c23 add english readme 2016-07-05 22:25:36 +08:00
Daniel FuandGitHub 32be3e836b Update README.md 2016-07-05 21:46:37 +08:00
Daniel FuandGitHub 664a79e488 Update README.md 2016-07-05 14:12:33 +08:00
Daniel FuandGitHub 74d874b0db Update README.md 2016-07-04 11:37:58 +08:00
Daniel FuandGitHub 58874784f3 Add files via upload 2016-07-04 11:36:24 +08:00
Daniel FuandGitHub f92bae1d03 Update README.md 2016-07-04 11:35:35 +08:00
Daniel FuandGitHub a1aa89ea1c Update README.md 2016-07-02 17:04:35 +08:00
Daniel FuandGitHub 52c75f68ba Update README.md 2016-07-02 11:11:35 +08:00
Daniel FuandGitHub 57fce73ca6 Update README.md 2016-07-02 09:52:18 +08:00
xtaci 13e980cdff lint 2016-06-30 14:45:26 +08:00
31 changed files with 760 additions and 1523 deletions
+7 -23
View File
@@ -1,29 +1,13 @@
问问题前先搜索ISSUE,并搞清楚下面的问题:
1. 检查 ```-key xxx``` 至少三遍, ***保证***两边一致。
2. 保证```-nocomp, -datashard, -parityshard, -key, -crypt, -smuxver```两边一致。
3. 是否在服务器端,正确设定了转发的目标服务器地址 ***--target***。
4. 是否在客户端,正确的连接到了 client的监听端口。
5. 如果第3条不确定,尝试在服务器上telnet target port试试。
6. 防火墙是否关闭了UDP通信,或者设置了UDP的最大发包速率?
7. 两端的版本是否一致?
8. 是不是最新版本?
9. 两端分别是什么操作系统?
10. 两端的输出日志是什么?
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, -smuxver``` ***must be the same*** on both side.
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. Did you correctly connected to the listening port on client side?
5. ***MAKE SURE*** ```telnet target port``` on your server successful(don't ask me why couldn't).
6. Does your ***firewall allows UDP*** communications? (including your ISP Cable-Modem)
7. Are you using the **same version** for both client & server
8. Are you using the **latest release**?
9. Which **OS** do you use?
10. Which end for this issue related to, **client or server**?
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**?
-2
View File
@@ -24,5 +24,3 @@ _testmain.go
*.prof
client/client
server/server
build/*
.DS_Store
+5 -7
View File
@@ -1,18 +1,16 @@
language: go
go:
- 1.11.x
- 1.12.x
- 1.13.x
- 1.6
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
install:
- env GO111MODULE=on go get github.com/xtaci/kcptun/client
- env GO111MODULE=on go get github.com/xtaci/kcptun/server
- 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
- env GO111MODULE=on $HOME/gopath/bin/goveralls -service=travis-ci
- $HOME/gopath/bin/goveralls -service=travis-ci
- cd $HOME/gopath/src/github.com/xtaci/kcptun/server
- env GO111MODULE=on $HOME/gopath/bin/goveralls -service=travis-ci
- $HOME/gopath/bin/goveralls -service=travis-ci
- exit 0
Binary file not shown.

Before

Width:  |  Height:  |  Size: 636 B

+3 -7
View File
@@ -1,12 +1,8 @@
FROM golang:alpine as builder
FROM golang:alpine
MAINTAINER xtaci <daniel820313@gmail.com>
ENV GO111MODULE=on
RUN apk update && \
apk upgrade && \
apk add git gcc libc-dev linux-headers
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.9
COPY --from=builder /go/bin /bin
apk add git
RUN go get github.com/xtaci/kcptun/client && go get github.com/xtaci/kcptun/server
EXPOSE 29900/udp
EXPOSE 12948
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

+240
View File
@@ -0,0 +1,240 @@
# <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:
```
Server Side: ./server_linux_amd64 -t "127.0.0.1:1080" -l ":4000" -mode fast2 // forwarding to local port 1080
Client Side: ./client_darwin_amd64 -r "SERVERIP:4000" -l ":1080" -mode fast2 // listening on port 1080
```
### *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 - kcptun client
USAGE:
client_darwin_amd64 [global options] command [command options] [arguments...]
VERSION:
20160820
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 for 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)
--mtu value set maximum transmission unit of 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
--help, -h show help
--version, -v print the version
$ ./server_darwin_amd64 -h
NAME:
kcptun - kcptun server
USAGE:
server_darwin_amd64 [global options] command [command options] [arguments...]
VERSION:
20160820
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 for 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 of 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
--help, -h show help
--version, -v print the version
```
### *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 10 -parityshard 3```
### *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)
All donations to this project will be used on the R&D of [gonet/2](http://gonet2.github.io/).
### *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
+194 -309
View File
@@ -1,305 +1,188 @@
# <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]
# <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
[11]: https://img.shields.io/github/license/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/v/release/xtaci/kcptun?color=orange
[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&color=red
[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
<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.*
### Requirements
| Target | Minimum | Recommended |
| --- | --- | --- |
| System | aix darwin dragonfly freebsd linux netbsd openbsd solaris windows | linux |
| Memory | >20MB | >32MB |
| CPU | ANY | amd64 with AES-NI & AVX2 |
### 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:
***[kcp-go](https://github.com/xtaci/kcp-go)协议测试小工具 :zap: [官方下载地址](https://github.com/xtaci/kcptun/releases/latest):zap:***
![kcptun](kcptun.png)
[English Readme](README.en.md)
### *快速设定* :lollipop:
```
net.core.rmem_max=26214400 // BDP - bandwidth delay product
net.core.rmem_default=26214400
net.core.wmem_max=26214400
net.core.wmem_default=26214400
net.core.netdev_max_backlog=2048 // proportional to -rcvwnd
服务器: ./server_linux_amd64 -t "127.0.0.1:8388" -l ":4000" -mode fast2 // 转发到服务器的本地8388端口
客户端: ./client_darwin_amd64 -r "服务器IP地址:4000" -l ":8388" -mode fast2 // 监听客户端的本地8388端口
注: 服务器端需要有服务监听8388端口
```
You can also increase the per-socket buffer by adding parameter(default 4MB):
### *速度对比* :lollipop:
<img src="fast.png" alt="fast.com" height="256px" />
* 测速网站: https://fast.com
* 接入: 100M ADSL
* WIFI: 5GHz TL-WDR3320
### *使用方法* :lollipop:
在Mac OS X El Capitan下的帮助输出:
```
-sockbuf 16777217
```
for **slow processors**, increasing this buffer is **CRITICAL** to receive packets properly.
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 fast3 -nocomp -autoexpire 900 -sockbuf 16777217 -dscp 46
KCP Server: ./server_linux_amd64 -t "TARGET_IP:8388" -l ":4000" -mode fast3 -nocomp -sockbuf 16777217 -dscp 46
```
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)
### Build from source
```
$ git clone https://github.com/xtaci/kcptun.git
$ cd kcptun
$ ./build-release.sh
$ cd build
```
All precompiled releases are genereated from `build-release.sh` script.
### Performance
<img src="fast.png" alt="fast.com" height="256px" />
![bandwidth](bw.png)
![flame](flame.png)
> Practical bandwidth graph with parameters: -mode fast3 -ds 10 -ps 3
### 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*
#### HOLB
Since streams are multiplexed into a single physical channel, head of line blocking may appear under certain circumstances, by
increasing `-smuxbuf` to a larger value (default 4MB) may mitigate this problem, obviously this will costs more memory.
For versions >= v20190924, you can switch to smux version 2, smux v2 has options to limit per-stream memory usage, now set `-smuxver 2` to enable smux v2, and adjust `-streambuf` to limit per-stream memory usage, eg: `-streambuf 2097152` can limit per-stream memory usage to 2MB. By limiting stream buffer on the receiver side, a back-pressure will be conducted to the sender and limits reading, and finally prevent source from sending too much data to occupy every bits of buffer along the link. (Setting -smuxver **MUST** be **IDENTICAL** on both side, default is 1. )
#### Slow Devices
kcptun made use of **ReedSolomon-Codes** to recover lost packets, which requires massive amount of computation, a low-end ARM device cannot satisfy kcptun well. To unleash the full potential of kcptun, a multi-core x86 homeserver CPU like AMD Opteron is recommended.
If you insist on running under some ARM routers, you'd better turn off `FEC` and use `salsa20` as the encryption method.
### Expert Tuning Guide
#### Overview
<p align="left"><img src="layeredparams.png" alt="params" height="450px"/></p>
#### Usage
```
➜ ~ ./client_linux_amd64 -h
$ ./client_darwin_amd64 -h
NAME:
kcptun - client(with SMUX)
kcptun - kcptun client
USAGE:
client_linux_amd64 [global options] command [command options] [arguments...]
client_darwin_amd64 [global options] command [command options] [arguments...]
VERSION:
20190924
20160820
COMMANDS:
help, h Shows a list of commands or help for one command
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, 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 per-socket buffer in bytes (default: 4194304)
--smuxver value specify smux version, available 1,2 (default: 1)
--smuxbuf value the overall de-mux buffer in bytes (default: 4194304)
--streambuf value per stream receive buffer in bytes, smux v2+ (default: 2097152)
--keepalive value seconds between heartbeats (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
--tcp to emulate a TCP connection(linux)
-c value config from json file, which will override the command from shell
--help, -h show help
--version, -v print the version
➜ ~ ./server_linux_amd64 -h
--localaddr value, -l value local listen address (default: ":12948")
--remoteaddr value, -r value kcp server address (default: "vps:29900")
--key value pre-shared secret for 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)
--mtu value set maximum transmission unit of 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
--help, -h show help
--version, -v print the version
$ ./server_darwin_amd64 -h
NAME:
kcptun - server(with SMUX)
kcptun - kcptun server
USAGE:
server_linux_amd64 [global options] command [command options] [arguments...]
server_darwin_amd64 [global options] command [command options] [arguments...]
VERSION:
20190924
20160820
COMMANDS:
help, h Shows a list of commands or help for one command
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, or path/to/unix_socket (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 per-socket buffer in bytes (default: 4194304)
--smuxver value specify smux version, available 1,2 (default: 1)
--smuxbuf value the overall de-mux buffer in bytes (default: 4194304)
--streambuf value per stream receive buffer in bytes, smux v2+ (default: 2097152)
--keepalive value seconds between heartbeats (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
--tcp to emulate a TCP connection(linux)
-c value config from json file, which will override the command from shell
--help, -h show help
--version, -v print the version
--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 for 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 of 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
--help, -h show help
--version, -v print the version
```
#### Forward Error Correction
### *参数调整* :lollipop:
***两端参数必须一致的有:***
* datashard
* parityshard
* nocomp
* key
* crypt
In coding theory, the [ReedSolomon code](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction) 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.
*简易自我调优方法*
> 第一步:同时在两端逐步增大client rcvwnd和server sndwnd;
> 第二步:尝试下载,观察如果带宽利用率(服务器+客户端两端都要观察)接近物理带宽则停止,否则跳转到第一步。
![FED](FEC.png)
Setting parameters of RS-Code with ```-datashard m -parityshard n``` on **BOTH** KCP Client & KCP Server **MUST** be **IDENTICAL**.
#### DSCP
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.
setting each side with ```-dscp value```, Here are some [Commonly used DSCP values](https://en.wikipedia.org/wiki/Differentiated_services#Commonly_used_DSCP_values).
#### 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).
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.
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*)
Benchmarks for crypto algorithms supported by kcptun:
***注意:产生大量重传时,一定是窗口偏大了***
*带宽计算公式*
```
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
在不丢包的情况下,有最大-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
```
Benchmark result from openssl
### *安全* :lollipop:
无论你上层如何加密,如果```-crypt none```,那么协议头部都是***明文***的,建议至少采用```-crypt aes-128```加密。
注意: ```-crypt xor``` 也是不安全的,除非你知道你在做什么。
### *内存控制* :lollipop:
路由器,手机等嵌入式设备通常对内存用量敏感,通过调节环境变量GOGC(例如GOGC=20)后启动client,可以降低内存使用。
参考:https://blog.golang.org/go15gc
### *流量控制* :lollipop:
***必要性: 针对流量敏感的服务器,做双保险。***
> 基本原则: SERVER的发送速率不能超过ADSL下行带宽,否则只会浪费您的服务器带宽。
在server通过linux tc,可以限制服务器发送带宽。
举例: 用linux tc限制server发送带宽为32mbit/s:
```
$ 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
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:~#
```
The encrytion performance in kcptun is as fast as in openssl library(if not faster).
其中eth0为网卡,有些服务器为ens3,有些为p2p1,通过ifconfig查询修改。
#### Memory Control
### *DSCP* :lollipop:
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),至于有没有用,完全取决于数据包经过的设备。
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值,两端可分别设定。
Primary memory allocation are done from a global buffer pool *xmit.Buf*, in kcp-go, when we need to allocate some bytes, we can get from that pool, and a *fixed-capacity* 1500 bytes(mtuLimit) will be returned, the *rx queue*, *tx queue* and *fec queue* all receive bytes from there, and they will return the bytes to the pool after using to prevent *unnecessary zer0ing* of bytes.
The pool mechanism maintained a *high watermark* for slice objects, these *in-flight* objects from the pool will survive from the perodical garbage collection, meanwhile the pool kept the ability to return the memory to runtime if in idle, `-sndwnd`,`-rcvwnd`,`-ds`, `-ps`, these parameters affect this *high watermark*, the larger the value, the bigger the memory consumption will be.
### *前向纠错* :lollipop:
前向纠错采用Reed Solomon纠删码, 它的基本原理如下: 给定n个数据块d1, d2,…, dn,n和一个正整数m, RS根据n个数据块生成m个校验块, c1, c2,…, cm。 对于任意的n和m, 从n个原始数据块和m 个校验块中任取n块就能解码出原始数据, 即RS最多容忍m个数据块或者校验块同时丢失。
`-smuxbuf` also affects the maximum memory consumption, this parameter maintains a subtle balance between *concurrency* and *resource*, you can increase this value(default 4MB) to boost concurrency if you have many clients to serve and you get a powerful server at the same time, and also you can decrease this value to serve only 1 or 2 clients and hope this program can run under some embeded SoC system with limited memory and only you can access. (Notice that the `-smuxbuf` value is not proprotional to concurrency, you need to test.)
![reed-solomon](rs.png)
通过参数```-datashard 10 -parityshard 3``` 在两端同时设定。
#### Compression
kcptun has builtin snappy algorithms for compressing streams:
### *Snappy数据流压缩* :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,
@@ -309,81 +192,83 @@ kcptun has builtin snappy algorithms for compressing streams:
> Reference: http://google.github.io/snappy/
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**.
#### SNMP
### *内置模式* :lollipop:
响应速度:
*fast3 >* ***[fast2]*** *> fast > normal > default*
有效载荷比:
*default > normal > fast >* ***[fast2]*** *> fast3*
中间mode参数比较均衡,总之就是越快越浪费带宽,推荐模式 ***fast2***
更高级的 ***手动档*** 需要理解KCP协议,并通过 ***隐藏参数*** 调整,例如:
```
-mode manual -nodelay 1 -resend 2 -nc 1 -interval 20
```
高丢包率的网络建议采用fast2, 低丢包率的网络,建议采用normal。
### *SNMP* :lollipop:
```go
// Snmp defines network statistics indicator
type Snmp struct {
BytesSent uint64 // bytes sent from upper level
BytesReceived uint64 // bytes received to upper level
MaxConn uint64 // max number of connections ever reached
ActiveOpens uint64 // accumulated active open connections
PassiveOpens uint64 // accumulated passive open connections
CurrEstab uint64 // current number of established connections
InErrs uint64 // UDP read errors reported from net.PacketConn
InCsumErrors uint64 // checksum errors from CRC32
KCPInErrors uint64 // packet iput errors reported from KCP
InPkts uint64 // incoming packets count
OutPkts uint64 // outgoing packets count
InSegs uint64 // incoming KCP segments
OutSegs uint64 // outgoing KCP segments
InBytes uint64 // UDP bytes received
OutBytes uint64 // UDP bytes sent
RetransSegs uint64 // accmulated retransmited segments
FastRetransSegs uint64 // accmulated fast retransmitted segments
EarlyRetransSegs uint64 // accmulated early retransmitted segments
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
FECParityShards uint64 // FEC segments received
FECShortShards uint64 // number of data shards that's not enough for recovery
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 `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.
使用```kill -SIGUSR1 pid``` 可以在控制台打印出SNMP信息,通常用于精细调整***当前链路的有效载荷比***。
观察```RetransSegs,FastRetransSegs,LostSegs,OutSegs```这几者的数值比例,用于参考调整```-mode manual,fec```的参数。
### Manual Control
### *故障排除* :lollipop:
> Q: 客户端和服务器端***皆无*** ```stream opened```信息。
> A: 连接客户端程序的端口设置错误。
https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configuration
> Q: 客户端有 ```stream opened```信息,服务器端没有。
> A: 连接服务器的端口设置错误,或者被防火墙拦截。
`-mode manual -nodelay 1 -interval 20 -resend 2 -nc 1`
> Q: 客户端服务器***皆有*** ```stream opened```信息,但无法通信。
> A: 上层软件的设定错误。
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.
### *免责申明* :warning:
用户以各种方式使用本软件(包括但不限于修改使用、直接使用、通过第三方使用)的过程中,不得以任何方式利用本软件直接或间接从事违反中国法律、以及社会公德的行为。软件的使用者需对自身行为负责,因使用软件引发的一切纠纷,由使用者承担全部法律及连带责任。作者不承担任何法律及连带责任。
对免责声明的解释、修改及更新权均属于作者本人所有。
### Identical Parmeters
### *捐赠* :dollar:
![donate](donate.png)
The parameters below **MUST** be **IDENTICAL** on **BOTH** side:
对该项目的捐款将用于[gonet/2](http://gonet2.github.io/)游戏服务器框架的研发。
1. -key
1. -crypt
1. -nocomp
1. -datashard
1. -parityshard
1. -smuxver
### References
```特别感谢: 郑H立, 南D风, Li, 七q, 凌J,昶,Les*ables, Ky*n, 噼**啦, 等,名字已做特殊处理。```
### *参考资料* :paperclip:
1. https://github.com/skywind3000/kcp -- KCP - A Fast and Reliable ARQ Protocol.
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://zhuanlan.zhihu.com/p/53849089 -- kcptun开发小记
(注意:我没有任何社交网站的账号,请小心骗子。)
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
-139
View File
@@ -1,139 +0,0 @@
#!/bin/bash
BUILD_DIR=$(dirname "$0")/build
mkdir -p $BUILD_DIR
cd $BUILD_DIR
sum="sha1sum"
if [ "$GO111MODULE" != "on" ]; then
echo "GO111MODULE is off"
else
echo "GO111MODULE is on"
fi
echo "Prerequisites for cross-compiling were written in build-release.sh"
# required library for cross-compiling
# sudo apt-get install -y automake autogen build-essential ca-certificates gcc-5-arm-linux-gnueabi g++-5-arm-linux-gnueabi libc6-dev-armel-cross gcc-5-arm-linux-gnueabihf g++-5-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-5-aarch64-linux-gnu g++-5-aarch64-linux-gnu libc6-dev-arm64-cross gcc-5-mips-linux-gnu g++-5-mips-linux-gnu libc6-dev-mips-cross gcc-5-mipsel-linux-gnu g++-5-mipsel-linux-gnu libc6-dev-mipsel-cross gcc-5-mips64-linux-gnuabi64 g++-5-mips64-linux-gnuabi64 libc6-dev-mips64-cross gcc-5-mips64el-linux-gnuabi64 g++-5-mips64el-linux-gnuabi64 libc6-dev-mips64el-cross gcc-5-multilib g++-5-multilib gcc-mingw-w64 g++-mingw-w64 clang llvm-dev libtool libxml2-dev uuid-dev libssl-dev swig openjdk-8-jdk pkg-config patch make xz-utils cpio wget zip unzip p7zip git mercurial bzr texinfo help2man --no-install-recommends
# if error message:
# /usr/include/linux/errno.h:1:23: fatal error: asm/errno.h: No such file or directory
# try:
# ln -s /usr/include/asm-generic /usr/include/asm
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
if hash upx 2>/dev/null; then
UPX=true
fi
VERSION=`date -u +%Y%m%d`
LDFLAGS="-X main.VERSION=$VERSION -s -w"
LDFLAGS_LINUX='-X main.VERSION='$VERSION' -s -w -linkmode "external" -extldflags "-static"'
LDFLAGS_LINUX32='-X main.VERSION='$VERSION' -s -w -linkmode "external" -extldflags "-static -m32 -L/usr/lib32"'
echo "-ldflag for linux/amd64:" $LDFLAGS_LINUX
echo "-ldflag for linux/386:" $LDFLAGS_LINUX32
echo "-ldflag for other:" $LDFLAGS
echo "=== Building ==="
# 386
OSES=(linux windows)
for os in ${OSES[@]}; do
suffix=""
if [ "$os" == "windows" ]
then
suffix=".exe"
fi
if [ "$os" == "linux" ];then
CC=gcc-5 CGO_ENABLED=1 GOOS=$os GOARCH=386 CGO_CFLAGS="-m32 -L/usr/lib32" CGO_CXXFLAGS="-m32 -L/usr/lib32" go build -ldflags "$LDFLAGS_LINUX32" -o client_${os}_386${suffix} github.com/xtaci/kcptun/client
CC=gcc-5 CGO_ENABLED=1 GOOS=$os GOARCH=386 CGO_CFLAGS="-m32 -L/usr/lib32" CGO_CXXFLAGS="-m32 -L/usr/lib32" go build -ldflags "$LDFLAGS_LINUX32" -o server_${os}_386${suffix} github.com/xtaci/kcptun/server
else
CGO_ENABLED=0 GOOS=$os GOARCH=386 go build -ldflags "$LDFLAGS" -o client_${os}_386${suffix} github.com/xtaci/kcptun/client
CGO_ENABLED=0 GOOS=$os GOARCH=386 go build -ldflags "$LDFLAGS" -o server_${os}_386${suffix} github.com/xtaci/kcptun/server
fi
if $UPX; then upx -9 client_${os}_386${suffix} server_${os}_386${suffix};fi
tar -zcf kcptun-${os}-386-$VERSION.tar.gz client_${os}_386${suffix} server_${os}_386${suffix}
$sum kcptun-${os}-386-$VERSION.tar.gz
done
# AMD64
OSES=(linux darwin windows freebsd)
for os in ${OSES[@]}; do
suffix=""
if [ "$os" == "windows" ]
then
suffix=".exe"
fi
if [ "$os" == "linux" ];then
CC=gcc-5 CGO_ENABLED=1 GOOS=$os GOARCH=amd64 go build -ldflags "$LDFLAGS_LINUX" -o client_${os}_amd64${suffix} github.com/xtaci/kcptun/client
CC=gcc-5 CGO_ENABLED=1 GOOS=$os GOARCH=amd64 go build -ldflags "$LDFLAGS_LINUX" -o server_${os}_amd64${suffix} github.com/xtaci/kcptun/server
else
CGO_ENABLED=0 GOOS=$os GOARCH=amd64 go build -ldflags "$LDFLAGS" -o client_${os}_amd64${suffix} github.com/xtaci/kcptun/client
CGO_ENABLED=0 GOOS=$os GOARCH=amd64 go build -ldflags "$LDFLAGS" -o server_${os}_amd64${suffix} github.com/xtaci/kcptun/server
fi
if $UPX; then upx -9 client_${os}_amd64${suffix} server_${os}_amd64${suffix};fi
tar -zcf kcptun-${os}-amd64-$VERSION.tar.gz client_${os}_amd64${suffix} server_${os}_amd64${suffix}
$sum kcptun-${os}-amd64-$VERSION.tar.gz
done
# ARM-5
#CC=arm-linux-gnueabi-gcc-5 GOOS=linux GOARCH=arm GOARM=5 CGO_ENABLED=1 CGO_CFLAGS="-march=armv5" CGO_CXXFLAGS="-march=armv5" go install std
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 GOOS=linux GOARCH=arm GOARM=5 CGO_ENABLED=1 CGO_CFLAGS="-march=armv5" CGO_CXXFLAGS="-march=armv5" go build -ldflags "$LDFLAGS_LINUX" -o client_linux_arm5 github.com/xtaci/kcptun/client
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 GOOS=linux GOARCH=arm GOARM=5 CGO_ENABLED=1 CGO_CFLAGS="-march=armv5" CGO_CXXFLAGS="-march=armv5" go build -ldflags "$LDFLAGS_LINUX" -o server_linux_arm5 github.com/xtaci/kcptun/server
if $UPX; then upx -9 client_linux_arm5 server_linux_arm5;fi
tar -zcf kcptun-linux-arm5-$VERSION.tar.gz client_linux_arm5 server_linux_arm5
$sum kcptun-linux-arm5-$VERSION.tar.gz
# ARM-6
#CC=arm-linux-gnueabi-gcc-5 GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=1 CGO_CFLAGS="-march=armv6" CGO_CXXFLAGS="-march=armv6" go install std
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=1 CGO_CFLAGS="-march=armv6" CGO_CXXFLAGS="-march=armv6" go build -ldflags "$LDFLAGS_LINUX" -o client_linux_arm6 github.com/xtaci/kcptun/client
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=1 CGO_CFLAGS="-march=armv6" CGO_CXXFLAGS="-march=armv6" go build -ldflags "$LDFLAGS_LINUX" -o server_linux_arm6 github.com/xtaci/kcptun/server
if $UPX; then upx -9 client_linux_arm6 server_linux_arm6;fi
tar -zcf kcptun-linux-arm6-$VERSION.tar.gz client_linux_arm6 server_linux_arm6
$sum kcptun-linux-arm6-$VERSION.tar.gz
# ARM-7
ARMS=(7)
#CC=arm-linux-gnueabihf-gcc-5 GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="-march=armv7-a" CGO_CXXFLAGS="-march=armv7-a" go install std
CC=arm-linux-gnueabihf-gcc-5 CXX=arm-linux-gnueabihf-g++-5 GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="-march=armv7-a -fPIC" CGO_CXXFLAGS="-march=armv7-a -fPIC" go build -ldflags "$LDFLAGS_LINUX" -o client_linux_arm7 github.com/xtaci/kcptun/client
CC=arm-linux-gnueabihf-gcc-5 CXX=arm-linux-gnueabihf-g++-5 GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="-march=armv7-a -fPIC" CGO_CXXFLAGS="-march=armv7-a -fPIC" go build -ldflags "$LDFLAGS_LINUX" -o server_linux_arm7 github.com/xtaci/kcptun/server
if $UPX; then upx -9 client_linux_arm7 server_linux_arm7;fi
tar -zcf kcptun-linux-arm7-$VERSION.tar.gz client_linux_arm7 server_linux_arm7
$sum kcptun-linux-arm7-$VERSION.tar.gz
# ARM64
CC=aarch64-linux-gnu-gcc-5 CXX=aarch64-linux-gnu-g++-5 GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go build -ldflags "$LDFLAGS_LINUX" -o client_linux_arm64 github.com/xtaci/kcptun/client
CC=aarch64-linux-gnu-gcc-5 CXX=aarch64-linux-gnu-g++-5 GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go build -ldflags "$LDFLAGS_LINUX" -o server_linux_arm64 github.com/xtaci/kcptun/server
if $UPX; then upx -9 client_linux_arm64 server_linux_arm64*;fi
tar -zcf kcptun-linux-arm64-$VERSION.tar.gz client_linux_arm64 server_linux_arm64
$sum kcptun-linux-arm64-$VERSION.tar.gz
#MIPS32LE
CC=mipsel-linux-gnu-gcc-5 CXX=mipsel-linux-gnu-g++-5 GOOS=linux GOARCH=mipsle CGO_ENABLED=1 GOMIPS=softfloat go build -ldflags "$LDFLAGS_LINUX" -o client_linux_mipsle github.com/xtaci/kcptun/client
CC=mipsel-linux-gnu-gcc-5 CXX=mipsel-linux-gnu-g++-5 GOOS=linux GOARCH=mipsle CGO_ENABLED=1 GOMIPS=softfloat go build -ldflags "$LDFLAGS_LINUX" -o server_linux_mipsle github.com/xtaci/kcptun/server
#MIPS32
CC=mips-linux-gnu-gcc-5 CXX=mips-linux-gnu-g++-5 GOOS=linux GOARCH=mips CGO_ENABLED=1 GOMIPS=softfloat go build -ldflags "$LDFLAGS_LINUX" -o client_linux_mips github.com/xtaci/kcptun/client
CC=mips-linux-gnu-gcc-5 CXX=mips-linux-gnu-g++-5 GOOS=linux GOARCH=mips CGO_ENABLED=1 GOMIPS=softfloat go build -ldflags "$LDFLAGS_LINUX" -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
$sum kcptun-linux-mipsle-$VERSION.tar.gz
$sum kcptun-linux-mips-$VERSION.tar.gz
echo "=== Building Completed ==="
+21 -66
View File
@@ -1,21 +1,8 @@
#!/bin/bash
BUILD_DIR=$(dirname "$0")/build
mkdir -p $BUILD_DIR
cd $BUILD_DIR
sum="sha1sum"
export GO111MODULE=on
echo "Setting GO111MODULE to" $GO111MODULE
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"
MD5='md5sum'
unamestr=`uname`
if [[ "$unamestr" == 'Darwin' ]]; then
MD5='md5'
fi
UPX=false
@@ -25,36 +12,23 @@ fi
VERSION=`date -u +%Y%m%d`
LDFLAGS="-X main.VERSION=$VERSION -s -w"
GCFLAGS=""
GCFLAGS="-B"
# AMD64
OSES=(linux darwin windows freebsd)
ARCHS=(amd64 386)
for os in ${OSES[@]}; do
suffix=""
if [ "$os" == "windows" ]
then
suffix=".exe"
fi
env CGO_ENABLED=0 GOOS=$os GOARCH=amd64 go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_${os}_amd64${suffix} github.com/xtaci/kcptun/client
env CGO_ENABLED=0 GOOS=$os GOARCH=amd64 go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_${os}_amd64${suffix} github.com/xtaci/kcptun/server
if $UPX; then upx -9 client_${os}_amd64${suffix} server_${os}_amd64${suffix};fi
tar -zcf kcptun-${os}-amd64-$VERSION.tar.gz client_${os}_amd64${suffix} server_${os}_amd64${suffix}
$sum kcptun-${os}-amd64-$VERSION.tar.gz
done
# 386
OSES=(linux windows)
for os in ${OSES[@]}; do
suffix=""
if [ "$os" == "windows" ]
then
suffix=".exe"
fi
env CGO_ENABLED=0 GOOS=$os GOARCH=386 go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_${os}_386${suffix} github.com/xtaci/kcptun/client
env CGO_ENABLED=0 GOOS=$os GOARCH=386 go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_${os}_386${suffix} github.com/xtaci/kcptun/server
if $UPX; then upx -9 client_${os}_386${suffix} server_${os}_386${suffix};fi
tar -zcf kcptun-${os}-386-$VERSION.tar.gz client_${os}_386${suffix} server_${os}_386${suffix}
$sum kcptun-${os}-386-$VERSION.tar.gz
for arch in ${ARCHS[@]}; do
suffix=""
if [ "$os" == "windows" ]
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
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
done
done
# ARM
@@ -62,26 +36,7 @@ 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
if $UPX; then upx -9 client_linux_arm$v server_linux_arm$v;fi
tar -zcf kcptun-linux-arm$v-$VERSION.tar.gz client_linux_arm$v server_linux_arm$v
$sum kcptun-linux-arm$v-$VERSION.tar.gz
done
# ARM64
env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_linux_arm64 github.com/xtaci/kcptun/client
env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_linux_arm64 github.com/xtaci/kcptun/server
if $UPX; then upx -9 client_linux_arm64 server_linux_arm64*;fi
tar -zcf kcptun-linux-arm64-$VERSION.tar.gz client_linux_arm64 server_linux_arm64
$sum kcptun-linux-arm64-$VERSION.tar.gz
#MIPS32LE
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
$sum kcptun-linux-mipsle-$VERSION.tar.gz
$sum kcptun-linux-mips-$VERSION.tar.gz
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
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

-50
View File
@@ -1,50 +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"`
ScavengeTTL int `json:"scavengettl"`
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"`
SmuxVer int `json:"smuxver"`
SmuxBuf int `json:"smuxbuf"`
StreamBuf int `json:"streambuf"`
KeepAlive int `json:"keepalive"`
Log string `json:"log"`
SnmpLog string `json:"snmplog"`
SnmpPeriod int `json:"snmpperiod"`
Quiet bool `json:"quiet"`
TCP bool `json:"tcp"`
}
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)
}
-18
View File
@@ -1,18 +0,0 @@
package main
import (
"github.com/pkg/errors"
kcp "github.com/xtaci/kcp-go/v5"
"github.com/xtaci/tcpraw"
)
func dial(config *Config, block kcp.BlockCrypt) (*kcp.UDPSession, error) {
if config.TCP {
conn, err := tcpraw.Dial("tcp", config.RemoteAddr)
if err != nil {
return nil, errors.Wrap(err, "tcpraw.Dial()")
}
return kcp.NewConn(config.RemoteAddr, block, config.DataShard, config.ParityShard, conn)
}
return kcp.DialWithOptions(config.RemoteAddr, block, config.DataShard, config.ParityShard)
}
+147 -303
View File
@@ -2,7 +2,6 @@ package main
import (
"crypto/sha1"
"fmt"
"io"
"log"
"math/rand"
@@ -12,63 +11,76 @@ import (
"golang.org/x/crypto/pbkdf2"
"github.com/pkg/errors"
"github.com/golang/snappy"
"github.com/urfave/cli"
kcp "github.com/xtaci/kcp-go/v5"
"github.com/xtaci/kcptun/generic"
"github.com/xtaci/smux"
kcp "github.com/xtaci/kcp-go"
"github.com/xtaci/yamux"
)
const (
var (
// VERSION is injected by buildflags
VERSION = "SELFBUILD"
// SALT is use for pbkdf2 key expansion
SALT = "kcp-go"
// maximum supported smux version
maxSmuxVer = 2
// stream copy buffer size
bufSize = 4096
)
// VERSION is injected by buildflags
var VERSION = "SELFBUILD"
type compStream struct {
conn net.Conn
w *snappy.Writer
r *snappy.Reader
}
// handleClient aggregates connection p1 on mux with 'writeLock'
func handleClient(session *smux.Session, p1 net.Conn, quiet bool) {
logln := func(v ...interface{}) {
if !quiet {
log.Println(v...)
}
}
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(p1, p2 io.ReadWriteCloser) {
log.Println("stream opened")
defer log.Println("stream closed")
defer p1.Close()
p2, err := session.OpenStream()
if err != nil {
logln(err)
return
}
defer p2.Close()
logln("stream opened", "in:", p1.RemoteAddr(), "out:", fmt.Sprint(p2.RemoteAddr(), "(", p2.ID(), ")"))
defer logln("stream closed", "in:", p1.RemoteAddr(), "out:", fmt.Sprint(p2.RemoteAddr(), "(", p2.ID(), ")"))
// start tunnel
p1die := make(chan struct{})
go func() {
io.Copy(p1, p2)
close(p1die)
}()
// start tunnel & wait for tunnel termination
streamCopy := func(dst io.Writer, src io.ReadCloser) {
if _, err := generic.Copy(dst, src); err != nil {
// report protocol error
if err == smux.ErrInvalidProtocol {
log.Println("smux", err, "in:", p1.RemoteAddr(), "out:", fmt.Sprint(p2.RemoteAddr(), "(", p2.ID(), ")"))
}
}
p1.Close()
p2.Close()
p2die := make(chan struct{})
go func() {
io.Copy(p2, p1)
close(p2die)
}()
// wait for tunnel termination
select {
case <-p1die:
case <-p2die:
}
go streamCopy(p1, p2)
streamCopy(p2, p1)
}
func checkError(err error) {
if err != nil {
log.Printf("%+v\n", err)
log.Println(err)
os.Exit(-1)
}
}
@@ -79,10 +91,9 @@ func main() {
// 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{
@@ -104,28 +115,18 @@ func main() {
cli.StringFlag{
Name: "crypt",
Value: "aes",
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none",
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, manual",
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",
},
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,
@@ -138,19 +139,24 @@ func main() {
},
cli.IntFlag{
Name: "rcvwnd",
Value: 512,
Value: 1024,
Usage: "set receive window size(num of packets)",
},
cli.IntFlag{
Name: "datashard,ds",
Name: "datashard",
Value: 10,
Usage: "set reed-solomon erasure coding - datashard",
},
cli.IntFlag{
Name: "parityshard,ps",
Name: "parityshard",
Value: 3,
Usage: "set reed-solomon erasure coding - parityshard",
},
cli.BoolFlag{
Name: "acknodelay",
Usage: "flush ack immediately when a packet is received",
Hidden: true,
},
cli.IntFlag{
Name: "dscp",
Value: 0,
@@ -160,11 +166,6 @@ func main() {
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,
@@ -172,7 +173,7 @@ func main() {
},
cli.IntFlag{
Name: "interval",
Value: 50,
Value: 40,
Hidden: true,
},
cli.IntFlag{
@@ -186,157 +187,41 @@ func main() {
Hidden: true,
},
cli.IntFlag{
Name: "sockbuf",
Value: 4194304, // socket buffer size in bytes
Usage: "per-socket buffer in bytes",
Name: "sockbuf",
Value: 4194304, // socket buffer size in bytes
Hidden: true,
},
cli.IntFlag{
Name: "smuxver",
Value: 1,
Usage: "specify smux version, available 1,2",
},
cli.IntFlag{
Name: "smuxbuf",
Value: 4194304,
Usage: "the overall de-mux buffer in bytes",
},
cli.IntFlag{
Name: "streambuf",
Value: 2097152,
Usage: "per stream receive buffer in bytes, smux v2+",
},
cli.IntFlag{
Name: "keepalive",
Value: 10, // nat keepalive interval in seconds
Usage: "seconds between heartbeats",
},
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.BoolFlag{
Name: "quiet",
Usage: "to suppress the 'stream open/close' messages",
},
cli.BoolFlag{
Name: "tcp",
Usage: "to emulate a TCP connection(linux)",
},
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",
Name: "keepalive",
Value: 10, // nat keepalive interval in seconds
Hidden: true,
},
}
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.ScavengeTTL = c.Int("scavengettl")
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.SmuxBuf = c.Int("smuxbuf")
config.StreamBuf = c.Int("streambuf")
config.SmuxVer = c.Int("smuxver")
config.KeepAlive = c.Int("keepalive")
config.Log = c.String("log")
config.SnmpLog = c.String("snmplog")
config.SnmpPeriod = c.Int("snmpperiod")
config.Quiet = c.Bool("quiet")
config.TCP = c.Bool("tcp")
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, 40, 2, 1
case "fast":
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":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 1, 10, 2, 1
}
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)
log.Println("smux version:", config.SmuxVer)
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("smuxbuf:", config.SmuxBuf)
log.Println("streambuf:", config.StreamBuf)
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)
log.Println("tcp:", config.TCP)
// kcp server
nodelay, interval, resend, nc := c.Int("nodelay"), c.Int("interval"), c.Int("resend"), c.Int("nc")
// parameters check
if config.SmuxVer > maxSmuxVer {
log.Fatal("unsupported smux version:", config.SmuxVer)
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
}
log.Println("initiating key derivation")
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
log.Println("key derivation done")
crypt := c.String("crypt")
pass := pbkdf2.Key([]byte(c.String("key")), []byte(SALT), 4096, 32, sha1.New)
var block kcp.BlockCrypt
switch config.Crypt {
case "sm4":
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
switch c.String("crypt") {
case "tea":
block, _ = kcp.NewTEABlockCrypt(pass[:16])
case "xor":
@@ -360,132 +245,91 @@ func main() {
case "salsa20":
block, _ = kcp.NewSalsa20BlockCrypt(pass)
default:
config.Crypt = "aes"
crypt = "aes"
block, _ = kcp.NewAESBlockCrypt(pass)
}
createConn := func() (*smux.Session, error) {
kcpconn, err := dial(&config, block)
if err != nil {
return nil, errors.Wrap(err, "dial()")
}
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)
remoteaddr := c.String("remoteaddr")
datashard, parityshard := c.Int("datashard"), c.Int("parityshard")
mtu, sndwnd, rcvwnd := c.Int("mtu"), c.Int("sndwnd"), c.Int("rcvwnd")
nocomp, acknodelay := c.Bool("nocomp"), c.Bool("acknodelay")
dscp, sockbuf, keepalive, conn := c.Int("dscp"), c.Int("sockbuf"), c.Int("keepalive"), c.Int("conn")
if err := kcpconn.SetDSCP(config.DSCP); err != nil {
log.Println("listening on:", listener.Addr())
log.Println("encryption:", crypt)
log.Println("nodelay parameters:", nodelay, interval, resend, nc)
log.Println("remote address:", remoteaddr)
log.Println("sndwnd:", sndwnd, "rcvwnd:", rcvwnd)
log.Println("compression:", !nocomp)
log.Println("mtu:", mtu)
log.Println("datashard:", datashard, "parityshard:", parityshard)
log.Println("acknodelay:", acknodelay)
log.Println("dscp:", dscp)
log.Println("sockbuf:", sockbuf)
log.Println("keepalive:", keepalive)
log.Println("conn:", conn)
config := &yamux.Config{
AcceptBacklog: 256,
EnableKeepAlive: true,
KeepAliveInterval: 30 * time.Second,
ConnectionWriteTimeout: 30 * time.Second,
MaxStreamWindowSize: uint32(sockbuf),
LogOutput: os.Stderr,
}
createConn := func() *yamux.Session {
kcpconn, err := kcp.DialWithOptions(remoteaddr, block, datashard, parityshard)
checkError(err)
kcpconn.SetStreamMode(true)
kcpconn.SetNoDelay(nodelay, interval, resend, nc)
kcpconn.SetWindowSize(sndwnd, rcvwnd)
kcpconn.SetMtu(mtu)
kcpconn.SetACKNoDelay(acknodelay)
kcpconn.SetKeepAlive(keepalive)
if err := kcpconn.SetDSCP(dscp); err != nil {
log.Println("SetDSCP:", err)
}
if err := kcpconn.SetReadBuffer(config.SockBuf); err != nil {
if err := kcpconn.SetReadBuffer(sockbuf); err != nil {
log.Println("SetReadBuffer:", err)
}
if err := kcpconn.SetWriteBuffer(config.SockBuf); err != nil {
if err := kcpconn.SetWriteBuffer(sockbuf); err != nil {
log.Println("SetWriteBuffer:", err)
}
log.Println("smux version:", config.SmuxVer, "on connection:", kcpconn.LocalAddr(), "->", kcpconn.RemoteAddr())
smuxConfig := smux.DefaultConfig()
smuxConfig.Version = config.SmuxVer
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
smuxConfig.MaxStreamBuffer = config.StreamBuf
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
if err := smux.VerifyConfig(smuxConfig); err != nil {
log.Fatalf("%+v", err)
}
// stream multiplex
var session *smux.Session
if config.NoComp {
session, err = smux.Client(kcpconn, smuxConfig)
var session *yamux.Session
if nocomp {
session, err = yamux.Client(kcpconn, config)
} else {
session, err = smux.Client(generic.NewCompStream(kcpconn), smuxConfig)
session, err = yamux.Client(newCompStream(kcpconn), config)
}
if err != nil {
return nil, errors.Wrap(err, "createConn()")
}
return session, nil
checkError(err)
return session
}
// wait until a connection is ready
waitConn := func() *smux.Session {
for {
if session, err := createConn(); err == nil {
return session
} else {
log.Println("re-connecting:", err)
time.Sleep(time.Second)
}
}
numconn := uint16(conn)
var muxes []*yamux.Session
for i := uint16(0); i < numconn; i++ {
muxes = append(muxes, createConn())
}
numconn := uint16(config.Conn)
muxes := make([]struct {
session *smux.Session
ttl time.Time
}, numconn)
for k := range muxes {
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, config.ScavengeTTL)
go generic.SnmpLogger(config.SnmpLog, config.SnmpPeriod)
rr := uint16(0)
for {
p1, err := listener.AcceptTCP()
if err != nil {
log.Fatalf("%+v", err)
checkError(err)
mux := muxes[rr%numconn]
p2, err := mux.Open()
if err != nil { // yamux failure
log.Println(err)
p1.Close()
muxes[rr%numconn] = createConn()
mux.Close()
continue
}
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, config.Quiet)
go handleClient(p1, p2)
rr++
}
}
myApp.Run(os.Args)
}
type scavengeSession struct {
session *smux.Session
ts time.Time
}
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", sess.RemoteAddr())
case <-ticker.C:
var newList []scavengeSession
for k := range sessionList {
s := sessionList[k]
if s.session.NumStreams() == 0 || s.session.IsClosed() {
log.Println("session normally closed", s.session.RemoteAddr())
s.session.Close()
} else if ttl >= 0 && time.Since(s.ts) >= time.Duration(ttl)*time.Second {
log.Println("session reached scavenge ttl", s.session.RemoteAddr())
s.session.Close()
} else {
newList = append(newList, sessionList[k])
}
}
sessionList = newList
}
}
}
+1 -2
View File
@@ -8,7 +8,7 @@ import (
"os/signal"
"syscall"
kcp "github.com/xtaci/kcp-go/v5"
kcp "github.com/xtaci/kcp-go"
)
func init() {
@@ -18,7 +18,6 @@ func init() {
func sigHandler() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGUSR1)
signal.Ignore(syscall.SIGPIPE)
for {
switch <-ch {
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

-16
View File
@@ -1,16 +0,0 @@
Description=kcptun
Wants=network.target
After=syslog.target network-online.target
[Service]
Type=simple
Environment=GOGC=20
ExecStart=/home/user/client_linux_amd64 -c /home/user/local.json
Restart=on-failure
RestartSec=10
KillMode=process
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
-27
View File
@@ -1,27 +0,0 @@
{
"localaddr": ":2000",
"remoteaddr": "11.22.33.44:2000",
"key": "PASSWORD",
"crypt": "aes-128",
"mode": "fast3",
"mtu": 1400,
"sndwnd": 128,
"rcvwnd": 1024,
"datashard": 10,
"parityshard": 3,
"dscp": 46,
"nocomp": true,
"acknodelay": false,
"nodelay": 1,
"interval": 40,
"resend": 2,
"nc": 1,
"sockbuf": 16777217,
"smuxver": 1,
"smuxbuf": 16777217,
"streambuf": 2097152,
"keepalive": 10,
"autoexpire": 1800,
"quiet": false,
"tcp": false
}
-27
View File
@@ -1,27 +0,0 @@
{
"listen": ":2000",
"target": "127.0.0.1:9999",
"key": "PASSWORD",
"crypt": "aes-128",
"mode": "fast3",
"mtu": 1400,
"sndwnd": 2048,
"rcvwnd": 2048,
"datashard": 10,
"parityshard": 3,
"dscp": 46,
"nocomp": true,
"acknodelay": false,
"nodelay": 1,
"interval": 40,
"resend": 2,
"nc": 1,
"sockbuf": 16777217,
"smuxver": 1,
"smuxbuf": 16777217,
"streambuf": 2097152,
"keepalive": 10,
"pprof":false,
"quiet":false,
"tcp":false
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

-62
View File
@@ -1,62 +0,0 @@
package generic
import (
"net"
"time"
"github.com/golang/snappy"
"github.com/pkg/errors"
)
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) {
if _, err := c.w.Write(p); err != nil {
return 0, errors.WithStack(err)
}
if err := c.w.Flush(); err != nil {
return 0, errors.WithStack(err)
}
return len(p), err
}
func (c *CompStream) Close() error {
return c.conn.Close()
}
func (c *CompStream) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *CompStream) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
func (c *CompStream) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *CompStream) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *CompStream) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
func NewCompStream(conn net.Conn) *CompStream {
c := new(CompStream)
c.conn = conn
c.w = snappy.NewBufferedWriter(conn)
c.r = snappy.NewReader(conn)
return c
}
-24
View File
@@ -1,24 +0,0 @@
package generic
import (
"io"
)
const bufSize = 4096
// Memory optimized io.Copy function specified for this library
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
// If the reader has a WriteTo method, use it to do the copy.
// Avoids an allocation and a copy.
if wt, ok := src.(io.WriterTo); ok {
return wt.WriteTo(dst)
}
// Similarly, if the writer has a ReadFrom method, use it to do the copy.
if rt, ok := dst.(io.ReaderFrom); ok {
return rt.ReadFrom(src)
}
// fallback to standard io.CopyBuffer
buf := make([]byte, bufSize)
return io.CopyBuffer(dst, src, buf)
}
-46
View File
@@ -1,46 +0,0 @@
package generic
import (
"encoding/csv"
"fmt"
"log"
"os"
"path/filepath"
"time"
kcp "github.com/xtaci/kcp-go/v5"
)
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:
// 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
}
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()
}
}
}
-15
View File
@@ -1,15 +0,0 @@
module github.com/xtaci/kcptun
require (
github.com/coreos/go-iptables v0.4.2 // indirect
github.com/golang/snappy v0.0.1
github.com/google/gopacket v1.1.17 // indirect
github.com/pkg/errors v0.8.1
github.com/urfave/cli v1.21.0
github.com/xtaci/kcp-go/v5 v5.4.26
github.com/xtaci/smux v1.5.7
github.com/xtaci/tcpraw v1.2.25
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413
)
go 1.13
-55
View File
@@ -1,55 +0,0 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/coreos/go-iptables v0.4.2 h1:KH0EwId05JwWIfb96gWvkiT2cbuOu8ygqUaB+yPAwIg=
github.com/coreos/go-iptables v0.4.2/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/klauspost/cpuid v1.2.2 h1:1xAgYebNnsb9LKCdLOvFWtAxGU/33mjJtyOVbmUa0Us=
github.com/klauspost/cpuid v1.2.2/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/reedsolomon v1.9.3 h1:N/VzgeMfHmLc+KHMD1UL/tNkfXAt8FnUqlgXGIduwAY=
github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/templexxx/cpu v0.0.1 h1:hY4WdLOgKdc8y13EYklu9OUTXik80BkxHoWvTO6MQQY=
github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
github.com/templexxx/xorsimd v0.3.1 h1:K6aBXKOSPgs0Pz/VXDy0pQK/RlwvtI1Cf9sOm3dPDrU=
github.com/templexxx/xorsimd v0.3.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
github.com/templexxx/xorsimd v0.4.1 h1:iUZcywbOYDRAZUasAs2eSCUW8eobuZDy0I9FJiORkVg=
github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=
github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE=
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go/v5 v5.4.23 h1:fQG2rrEYWRKyq/PRtUZdBZ+RSr3S/3QQFuScA/KzjxU=
github.com/xtaci/kcp-go/v5 v5.4.23/go.mod h1:kaRUj0x4HWAdtA32VaDNGGY8AZTRsFIOSCJQOWYcDc0=
github.com/xtaci/kcp-go/v5 v5.4.25 h1:hD2bpx3R92TXvXoYGQ844heHekXNmXafnpKUE/uxGbc=
github.com/xtaci/kcp-go/v5 v5.4.25/go.mod h1:kaRUj0x4HWAdtA32VaDNGGY8AZTRsFIOSCJQOWYcDc0=
github.com/xtaci/kcp-go/v5 v5.4.26 h1:4NhV2D9c8IMUzhxI8eS0QVRR4MPqjhxoPGoh7Za3lQU=
github.com/xtaci/kcp-go/v5 v5.4.26/go.mod h1:Oyw+zrBrO58urX1AaWV+2RynthEKcs+qrRAh0Q8YpdU=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
github.com/xtaci/smux v1.5.7 h1:fVOjux34i112nzp5BIF7yg4WvVKLj1pUMqEgSdiBho4=
github.com/xtaci/smux v1.5.7/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
github.com/xtaci/tcpraw v1.2.25 h1:VDlqo0op17JeXBM6e2G9ocCNLOJcw9mZbobMbJjo0vk=
github.com/xtaci/tcpraw v1.2.25/go.mod h1:dKyZ2V75s0cZ7cbgJYdxPvms7af0joIeOyx1GgJQbLk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 h1:JA8d3MPx/IToSyXZG/RhwYEtfrKO1Fxrqe8KrkiLXKM=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 20 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

-48
View File
@@ -1,48 +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"`
SmuxBuf int `json:"smuxbuf"`
StreamBuf int `json:"streambuf"`
SmuxVer int `json:"smuxver"`
KeepAlive int `json:"keepalive"`
Log string `json:"log"`
SnmpLog string `json:"snmplog"`
SnmpPeriod int `json:"snmpperiod"`
Pprof bool `json:"pprof"`
Quiet bool `json:"quiet"`
TCP bool `json:"tcp"`
}
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)
}
+141 -275
View File
@@ -2,55 +2,60 @@ package main
import (
"crypto/sha1"
"fmt"
"io"
"log"
"math/rand"
"net"
"net/http"
_ "net/http/pprof"
"os"
"sync"
"time"
"golang.org/x/crypto/pbkdf2"
"github.com/golang/snappy"
"github.com/urfave/cli"
kcp "github.com/xtaci/kcp-go/v5"
"github.com/xtaci/kcptun/generic"
"github.com/xtaci/smux"
"github.com/xtaci/tcpraw"
kcp "github.com/xtaci/kcp-go"
"github.com/xtaci/yamux"
)
const (
var (
// VERSION is injected by buildflags
VERSION = "SELFBUILD"
// SALT is use for pbkdf2 key expansion
SALT = "kcp-go"
// maximum supported smux version
maxSmuxVer = 2
// stream copy buffer size
bufSize = 4096
)
// VERSION is injected by buildflags
var VERSION = "SELFBUILD"
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
}
// handle multiplex-ed connection
func handleMux(conn net.Conn, config *Config) {
// check if target is unix domain socket
var isUnix bool
if _, _, err := net.SplitHostPort(config.Target); err != nil {
isUnix = true
}
log.Println("smux version:", config.SmuxVer, "on connection:", conn.LocalAddr(), "->", conn.RemoteAddr())
func handleMux(conn io.ReadWriteCloser, target string, config *yamux.Config) {
// stream multiplex
smuxConfig := smux.DefaultConfig()
smuxConfig.Version = config.SmuxVer
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
smuxConfig.MaxStreamBuffer = config.StreamBuf
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
mux, err := smux.Server(conn, smuxConfig)
mux, err := yamux.Server(conn, config)
if err != nil {
log.Println(err)
return
@@ -58,63 +63,43 @@ func handleMux(conn net.Conn, config *Config) {
defer mux.Close()
for {
stream, err := mux.AcceptStream()
p1, err := mux.Accept()
if err != nil {
log.Println(err)
return
}
go func(p1 *smux.Stream) {
var p2 net.Conn
var err error
if !isUnix {
p2, err = net.Dial("tcp", config.Target)
} else {
p2, err = net.Dial("unix", config.Target)
}
if err != nil {
log.Println(err)
p1.Close()
return
}
handleClient(p1, p2, config.Quiet)
}(stream)
p2, err := net.DialTimeout("tcp", target, 5*time.Second)
if err != nil {
log.Println(err)
return
}
go handleClient(p1, p2)
}
}
func handleClient(p1 *smux.Stream, p2 net.Conn, quiet bool) {
logln := func(v ...interface{}) {
if !quiet {
log.Println(v...)
}
}
func handleClient(p1, p2 io.ReadWriteCloser) {
log.Println("stream opened")
defer log.Println("stream closed")
defer p1.Close()
defer p2.Close()
logln("stream opened", "in:", fmt.Sprint(p1.RemoteAddr(), "(", p1.ID(), ")"), "out:", p2.RemoteAddr())
defer logln("stream closed", "in:", fmt.Sprint(p1.RemoteAddr(), "(", p1.ID(), ")"), "out:", p2.RemoteAddr())
// start tunnel
p1die := make(chan struct{})
go func() {
io.Copy(p1, p2)
close(p1die)
}()
// start tunnel & wait for tunnel termination
streamCopy := func(dst io.Writer, src io.ReadCloser) {
if _, err := generic.Copy(dst, src); err != nil {
if err == smux.ErrInvalidProtocol {
log.Println("smux", err, "in:", fmt.Sprint(p1.RemoteAddr(), "(", p1.ID(), ")"), "out:", p2.RemoteAddr())
}
}
p1.Close()
p2.Close()
}
p2die := make(chan struct{})
go func() {
io.Copy(p2, p1)
close(p2die)
}()
go streamCopy(p2, p1)
streamCopy(p1, p2)
}
func checkError(err error) {
if err != nil {
log.Printf("%+v\n", err)
os.Exit(-1)
// wait for tunnel termination
select {
case <-p1die:
case <-p2die:
}
}
@@ -124,10 +109,9 @@ func main() {
// 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,7 +122,7 @@ func main() {
cli.StringFlag{
Name: "target, t",
Value: "127.0.0.1:12948",
Usage: "target server address, or path/to/unix_socket",
Usage: "target server address",
},
cli.StringFlag{
Name: "key",
@@ -149,12 +133,12 @@ func main() {
cli.StringFlag{
Name: "crypt",
Value: "aes",
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none",
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, manual",
Usage: "profiles: fast3, fast2, fast, normal",
},
cli.IntFlag{
Name: "mtu",
@@ -172,15 +156,20 @@ func main() {
Usage: "set receive window size(num of packets)",
},
cli.IntFlag{
Name: "datashard,ds",
Name: "datashard",
Value: 10,
Usage: "set reed-solomon erasure coding - datashard",
},
cli.IntFlag{
Name: "parityshard,ps",
Name: "parityshard",
Value: 3,
Usage: "set reed-solomon erasure coding - parityshard",
},
cli.BoolFlag{
Name: "acknodelay",
Usage: "flush ack immediately when a packet is received",
Hidden: true,
},
cli.IntFlag{
Name: "dscp",
Value: 0,
@@ -190,11 +179,6 @@ func main() {
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,
@@ -202,7 +186,7 @@ func main() {
},
cli.IntFlag{
Name: "interval",
Value: 50,
Value: 40,
Hidden: true,
},
cli.IntFlag{
@@ -216,153 +200,34 @@ func main() {
Hidden: true,
},
cli.IntFlag{
Name: "sockbuf",
Value: 4194304, // socket buffer size in bytes
Usage: "per-socket buffer in bytes",
Name: "sockbuf",
Value: 4194304, // socket buffer size in bytes
Hidden: true,
},
cli.IntFlag{
Name: "smuxver",
Value: 1,
Usage: "specify smux version, available 1,2",
},
cli.IntFlag{
Name: "smuxbuf",
Value: 4194304,
Usage: "the overall de-mux buffer in bytes",
},
cli.IntFlag{
Name: "streambuf",
Value: 2097152,
Usage: "per stream receive buffer in bytes, smux v2+",
},
cli.IntFlag{
Name: "keepalive",
Value: 10, // nat keepalive interval in seconds
Usage: "seconds between heartbeats",
},
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.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.BoolFlag{
Name: "tcp",
Usage: "to emulate a TCP connection(linux)",
},
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",
Name: "keepalive",
Value: 10, // nat keepalive interval in seconds
Hidden: true,
},
}
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.SmuxBuf = c.Int("smuxbuf")
config.StreamBuf = c.Int("streambuf")
config.SmuxVer = c.Int("smuxver")
config.KeepAlive = c.Int("keepalive")
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")
config.TCP = c.Bool("tcp")
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, 40, 2, 1
case "fast":
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":
config.NoDelay, config.Interval, config.Resend, config.NoCongestion = 1, 10, 2, 1
}
log.Println("version:", VERSION)
log.Println("smux version:", config.SmuxVer)
log.Println("listening on:", config.Listen)
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("smuxbuf:", config.SmuxBuf)
log.Println("streambuf:", config.StreamBuf)
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)
log.Println("tcp:", config.TCP)
// parameters check
if config.SmuxVer > maxSmuxVer {
log.Fatal("unsupported smux version:", config.SmuxVer)
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
}
log.Println("initiating key derivation")
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
log.Println("key derivation done")
crypt := c.String("crypt")
pass := pbkdf2.Key([]byte(c.String("key")), []byte(SALT), 4096, 32, sha1.New)
var block kcp.BlockCrypt
switch config.Crypt {
case "sm4":
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
switch crypt {
case "tea":
block, _ = kcp.NewTEABlockCrypt(pass[:16])
case "xor":
@@ -386,68 +251,69 @@ func main() {
case "salsa20":
block, _ = kcp.NewSalsa20BlockCrypt(pass)
default:
config.Crypt = "aes"
crypt = "aes"
block, _ = kcp.NewAESBlockCrypt(pass)
}
go generic.SnmpLogger(config.SnmpLog, config.SnmpPeriod)
if config.Pprof {
go http.ListenAndServe(":6060", nil)
datashard, parityshard := c.Int("datashard"), c.Int("parityshard")
lis, err := kcp.ListenWithOptions(c.String("listen"), block, datashard, parityshard)
if err != nil {
log.Fatal(err)
}
// main loop
var wg sync.WaitGroup
loop := func(lis *kcp.Listener) {
defer wg.Done()
if err := lis.SetDSCP(config.DSCP); err != nil {
log.Println("SetDSCP:", 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)
}
mtu, sndwnd, rcvwnd := c.Int("mtu"), c.Int("sndwnd"), c.Int("rcvwnd")
nocomp, acknodelay := c.Bool("nocomp"), c.Bool("acknodelay")
dscp, sockbuf, keepalive := c.Int("dscp"), c.Int("sockbuf"), c.Int("keepalive")
target := c.String("target")
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)
log.Println("listening on ", lis.Addr())
log.Println("encryption:", crypt)
log.Println("nodelay parameters:", nodelay, interval, resend, nc)
log.Println("sndwnd:", sndwnd, "rcvwnd:", rcvwnd)
log.Println("compression:", !nocomp)
log.Println("mtu:", mtu)
log.Println("datashard:", datashard, "parityshard:", parityshard)
log.Println("acknodelay:", acknodelay)
log.Println("dscp:", dscp)
log.Println("sockbuf:", sockbuf)
log.Println("keepalive:", keepalive)
if config.NoComp {
go handleMux(conn, &config)
} else {
go handleMux(generic.NewCompStream(conn), &config)
}
if err := lis.SetDSCP(dscp); err != nil {
log.Println("SetDSCP:", err)
}
if err := lis.SetReadBuffer(sockbuf); err != nil {
log.Println("SetReadBuffer:", err)
}
if err := lis.SetWriteBuffer(sockbuf); err != nil {
log.Println("SetWriteBuffer:", err)
}
config := &yamux.Config{
AcceptBacklog: 256,
EnableKeepAlive: true,
KeepAliveInterval: 30 * time.Second,
ConnectionWriteTimeout: 30 * time.Second,
MaxStreamWindowSize: uint32(sockbuf),
LogOutput: os.Stderr,
}
for {
if conn, err := lis.Accept(); err == nil {
log.Println("remote address:", conn.RemoteAddr())
conn.SetStreamMode(true)
conn.SetNoDelay(nodelay, interval, resend, nc)
conn.SetMtu(mtu)
conn.SetWindowSize(sndwnd, rcvwnd)
conn.SetACKNoDelay(acknodelay)
conn.SetKeepAlive(keepalive)
if nocomp {
go handleMux(conn, target, config)
} else {
log.Printf("%+v", err)
go handleMux(newCompStream(conn), target, config)
}
}
}
if config.TCP { // tcp dual stack
if conn, err := tcpraw.Listen("tcp", config.Listen); err == nil {
lis, err := kcp.ServeConn(block, config.DataShard, config.ParityShard, conn)
checkError(err)
wg.Add(1)
go loop(lis)
} else {
log.Println(err)
}
}
// udp stack
lis, err := kcp.ListenWithOptions(config.Listen, block, config.DataShard, config.ParityShard)
checkError(err)
wg.Add(1)
go loop(lis)
wg.Wait()
return nil
}
myApp.Run(os.Args)
}
+1 -2
View File
@@ -8,7 +8,7 @@ import (
"os/signal"
"syscall"
kcp "github.com/xtaci/kcp-go/v5"
kcp "github.com/xtaci/kcp-go"
)
func init() {
@@ -18,7 +18,6 @@ func init() {
func sigHandler() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGUSR1)
signal.Ignore(syscall.SIGPIPE)
for {
switch <-ch {