mirror of
https://github.com/xtaci/kcptun.git
synced 2024-04-21 12:32:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
556de3055b | ||
|
|
9d84f40720 | ||
|
|
f70791fc61 | ||
|
|
8f2fcb7026 | ||
|
|
2eec01d9c0 | ||
|
|
047895f088 | ||
|
|
b93460fb27 | ||
|
|
8ab062621e | ||
|
|
c380abfc75 | ||
|
|
029af29881 | ||
|
|
b2720342c4 | ||
|
|
b51ef20d30 | ||
|
|
a95a000cad | ||
|
|
c251f2c3b4 | ||
|
|
ffb7f8aeaf | ||
|
|
265dd7eb1d | ||
|
|
c21ba84b05 | ||
|
|
7d06c5f2d7 | ||
|
|
7e648ff260 | ||
|
|
00db8d26ec | ||
|
|
f45e756fca | ||
|
|
3530c325ba | ||
|
|
6d6114bf26 | ||
|
|
cda9de7d8d | ||
|
|
9004bf3170 | ||
|
|
903cb9f9f1 | ||
|
|
6c46285010 | ||
|
|
1b72bf39d8 | ||
|
|
112870d870 | ||
|
|
a859f419f6 | ||
|
|
fa728236d4 | ||
|
|
ade7ee06a0 | ||
|
|
30cca4d7db | ||
|
|
0f18b17a8a | ||
|
|
1b756aeb3d | ||
|
|
a69b0a90ed | ||
|
|
8778495915 | ||
|
|
13deb22077 | ||
|
|
1635649aa5 | ||
|
|
3425d6288b | ||
|
|
fe3227db22 | ||
|
|
2684e47946 | ||
|
|
fcb6a5e141 | ||
|
|
ff9a67e931 | ||
|
|
f288fe9ea6 | ||
|
|
7a42a51643 | ||
|
|
bd4051bd02 | ||
|
|
bab23e05b0 | ||
|
|
4200cc7ef6 | ||
|
|
d9df85de52 | ||
|
|
379ce89334 | ||
|
|
34aaf35425 | ||
|
|
375d7bff86 | ||
|
|
4e9d289d7a | ||
|
|
b5f98ed351 | ||
|
|
4cc3e083d8 | ||
|
|
adae541dd9 | ||
|
|
0734e23cf3 | ||
|
|
6a8b0f70e7 | ||
|
|
f8454de6b6 | ||
|
|
e97e49498e | ||
|
|
9f2ff06ec8 | ||
|
|
6715764c4f | ||
|
|
62f2ffe2d8 | ||
|
|
90b9f85617 | ||
|
|
e619848985 | ||
|
|
7f93fb5858 | ||
|
|
7b8a4646fc | ||
|
|
b5487cd0ce | ||
|
|
acfe430810 | ||
|
|
9285b162b7 | ||
|
|
8d13f9be89 | ||
|
|
4ba9028985 | ||
|
|
b4473a5413 | ||
|
|
3b01e69ba2 | ||
|
|
76b658917a | ||
|
|
b260423213 | ||
|
|
72fbf47844 | ||
|
|
8daf4edd0a | ||
|
|
c8d917f400 | ||
|
|
db88c47847 | ||
|
|
32ecbcdc34 | ||
|
|
3f8089807e | ||
|
|
bdd293f180 | ||
|
|
bd4a02a193 | ||
|
|
bb6bf9985c | ||
|
|
3923bba92c | ||
|
|
d6f97d1f4a | ||
|
|
255bb85640 | ||
|
|
d5104ec4f1 | ||
|
|
addeb3b2df | ||
|
|
2feb1129f2 | ||
|
|
efff54a699 | ||
|
|
6a84007ab0 | ||
|
|
468cafff85 | ||
|
|
002827cbaa | ||
|
|
3260e4d346 | ||
|
|
60bee85c51 | ||
|
|
3a649e369c | ||
|
|
7cc7454c7c | ||
|
|
9ba6c75eff | ||
|
|
1a28b61d45 | ||
|
|
5bf748b8b5 | ||
|
|
04602bfb9f | ||
|
|
9dee7cb401 | ||
|
|
7e53f045d2 | ||
|
|
951521a0a6 | ||
|
|
d0b4365909 | ||
|
|
51192afeba | ||
|
|
1ab630df33 | ||
|
|
18113ed797 | ||
|
|
770f5c00da | ||
|
|
bf635db2f9 | ||
|
|
b31a9d01af | ||
|
|
440e490204 | ||
|
|
45e58e6500 | ||
|
|
7382d41489 | ||
|
|
22966661c4 | ||
|
|
a704f60ee3 | ||
|
|
0db71f7d0c | ||
|
|
76c88158c8 | ||
|
|
af3185d2e9 | ||
|
|
76f62b0dd1 | ||
|
|
9f5d2a278a | ||
|
|
af88878dd9 | ||
|
|
ec9ace1de0 | ||
|
|
e93a1908c1 | ||
|
|
e7c6eb17d2 | ||
|
|
26f6688da3 | ||
|
|
dbaefc35a7 | ||
|
|
5da363682e | ||
|
|
116c1e7668 | ||
|
|
86cc46f437 | ||
|
|
e54a648576 | ||
|
|
49f701be26 | ||
|
|
6e0b2077ea | ||
|
|
873351361a | ||
|
|
f33e913f73 | ||
|
|
5c77ac3c60 | ||
|
|
5d015f0616 | ||
|
|
2a9fb0b908 | ||
|
|
2f36a43223 |
+16
-14
@@ -1,27 +1,29 @@
|
||||
问问题前先搜索ISSUE,并搞清楚下面的问题:
|
||||
|
||||
1. 检查 ```-key xxx``` 至少三遍, ***保证***两边一致。
|
||||
2. 保证```-nocomp, -datashard, -parityshard, -key, -crypt```两边一致。
|
||||
2. 保证```-nocomp, -datashard, -parityshard, -key, -crypt, -smuxver```两边一致。
|
||||
3. 是否在服务器端,正确设定了转发的目标服务器地址 ***--target***。
|
||||
4. 如果第3条不确定,尝试在服务器上telnet target port试试。
|
||||
5. 防火墙是否关闭了UDP通信。
|
||||
6. 两端的版本是否一致?
|
||||
7. 是不是最新版本?
|
||||
8. 两端分别是什么操作系统?
|
||||
9. 两端的输出日志是什么?
|
||||
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``` ***must be the same*** on both side.
|
||||
2. ```-nocomp, -datashard, -parityshard, -key, -crypt, -smuxver``` ***must be the same*** on both side.
|
||||
3. Did you correctly set the ***-target*** on the server side?
|
||||
4. ***MAKE SURE*** ```telnet target port``` on your server successful(don't ask me why couldn't).
|
||||
5. Does your ***firewall allows UDP*** communications? (including your ISP Cable-Modem)
|
||||
6. Are you using the **same version** for both client & server
|
||||
7. Are you using the **latest release**?
|
||||
8. Which **OS** do you use?
|
||||
9. Which end for this issue related to, **client or server**?
|
||||
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**?
|
||||
|
||||
|
||||
|
||||
@@ -24,3 +24,5 @@ _testmain.go
|
||||
*.prof
|
||||
client/client
|
||||
server/server
|
||||
build/*
|
||||
.DS_Store
|
||||
|
||||
+6
-6
@@ -1,18 +1,18 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
install:
|
||||
- go get github.com/xtaci/kcptun/client
|
||||
- go get github.com/xtaci/kcptun/server
|
||||
- env GO111MODULE=on go get github.com/xtaci/kcptun/client
|
||||
- env GO111MODULE=on go get github.com/xtaci/kcptun/server
|
||||
before_script:
|
||||
script:
|
||||
- cd $HOME/gopath/src/github.com/xtaci/kcptun/client
|
||||
- $HOME/gopath/bin/goveralls -service=travis-ci
|
||||
- env GO111MODULE=on $HOME/gopath/bin/goveralls -service=travis-ci
|
||||
- cd $HOME/gopath/src/github.com/xtaci/kcptun/server
|
||||
- $HOME/gopath/bin/goveralls -service=travis-ci
|
||||
- env GO111MODULE=on $HOME/gopath/bin/goveralls -service=travis-ci
|
||||
- exit 0
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
FROM golang:alpine as builder
|
||||
MAINTAINER xtaci <daniel820313@gmail.com>
|
||||
ENV GO111MODULE=on
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add git
|
||||
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
|
||||
|
||||
@@ -62,19 +62,24 @@ which tunnels the original connection:
|
||||
### Install from source
|
||||
|
||||
```
|
||||
$go get -u github.com/xtaci/kcptun/...
|
||||
$ export GO111MODULE=on
|
||||
$ go get -u github.com/xtaci/kcptun/...
|
||||
```
|
||||
|
||||
All precompiled releases are genereated from `build-release.sh` script.
|
||||
|
||||
### Performance
|
||||
|
||||
<img src="fast.png" alt="fast.com" height="256px" />
|
||||
<img src="fast.png" alt="fast.com" height="256px" />
|
||||
|
||||
<img src="bw.png" alt="bandwidth usage graph" height="256px" />
|
||||

|
||||
|
||||

|
||||
|
||||
> Practical bandwidth graph with parameters: -mode fast3 -ds 10 -ps 3
|
||||
|
||||
|
||||
|
||||
### Basic Tuning Guide
|
||||
|
||||
#### Improving Thoughput
|
||||
@@ -101,6 +106,8 @@ All precompiled releases are genereated from `build-release.sh` script.
|
||||
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.
|
||||
@@ -115,7 +122,7 @@ If you insist on running under some ARM routers, you'd better turn off `FEC` and
|
||||
#### Usage
|
||||
|
||||
```
|
||||
xtaci@gw:~$ ./client_linux_amd64 -h
|
||||
➜ ~ ./client_linux_amd64 -h
|
||||
NAME:
|
||||
kcptun - client(with SMUX)
|
||||
|
||||
@@ -123,10 +130,10 @@ USAGE:
|
||||
client_linux_amd64 [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
20190409
|
||||
20190924
|
||||
|
||||
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")
|
||||
@@ -145,17 +152,20 @@ GLOBAL OPTIONS:
|
||||
--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
|
||||
|
||||
xtaci@gw:~$ ./server_linux_amd64 -h
|
||||
➜ ~ ./server_linux_amd64 -h
|
||||
NAME:
|
||||
kcptun - server(with SMUX)
|
||||
|
||||
@@ -163,14 +173,14 @@ USAGE:
|
||||
server_linux_amd64 [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
20190409
|
||||
20190924
|
||||
|
||||
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 (default: "127.0.0.1:12948")
|
||||
--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")
|
||||
@@ -182,13 +192,16 @@ GLOBAL OPTIONS:
|
||||
--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
|
||||
@@ -294,29 +307,30 @@ Compression is enabled by default, you can disable it by setting ```-nocomp``` o
|
||||
#### SNMP
|
||||
|
||||
```go
|
||||
// Snmp defines network statistics indicator
|
||||
type Snmp struct {
|
||||
BytesSent uint64 // raw bytes sent
|
||||
BytesReceived uint64
|
||||
MaxConn uint64
|
||||
ActiveOpens uint64
|
||||
PassiveOpens uint64
|
||||
CurrEstab uint64 // count of connections for now
|
||||
InErrs uint64 // udp read errors
|
||||
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 from kcp
|
||||
InSegs uint64
|
||||
OutSegs uint64
|
||||
InBytes uint64 // udp bytes received
|
||||
OutBytes uint64 // udp bytes sent
|
||||
RetransSegs uint64
|
||||
FastRetransSegs uint64
|
||||
EarlyRetransSegs uint64
|
||||
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
|
||||
FECSegs uint64 // FEC segments received
|
||||
FECParityShards uint64 // FEC segments received
|
||||
FECShortShards uint64 // number of data shards that's not enough for recovery
|
||||
}
|
||||
```
|
||||
@@ -341,6 +355,7 @@ The parameters below **MUST** be **IDENTICAL** on **BOTH** side:
|
||||
1. -nocomp
|
||||
1. -datashard
|
||||
1. -parityshard
|
||||
1. -smuxver
|
||||
|
||||
### References
|
||||
|
||||
@@ -359,15 +374,7 @@ The parameters below **MUST** be **IDENTICAL** on **BOTH** side:
|
||||
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开发小记
|
||||
|
||||
### Donate
|
||||
|
||||
via Ethereum(ETH): Address: 0x2e4b43ab3d0983da282592571eef61ae5e60f726 , Or scan here:
|
||||
|
||||
<img src="0x2e4b43ab3d0983da282592571eef61ae5e60f726.png" alt="kcptun" height="120px" />
|
||||
|
||||
via WeChat
|
||||
|
||||
<img src="wechat_donate.jpg" alt="kcptun" height="120px" />
|
||||
|
||||
(注意:我没有任何社交网站的账号,请小心骗子。)
|
||||
|
||||
Executable
+139
@@ -0,0 +1,139 @@
|
||||
#!/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 ==="
|
||||
@@ -1,7 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
BUILD_DIR=$(dirname "$0")/build
|
||||
mkdir -p $BUILD_DIR
|
||||
cd $BUILD_DIR
|
||||
|
||||
sum="sha1sum"
|
||||
|
||||
echo "If you need reproducible build, export GO111MODULE=on first"
|
||||
if [ "$GO111MODULE" != "on" ]; then
|
||||
echo "GO111MODULE is off"
|
||||
else
|
||||
echo "GO111MODULE is on"
|
||||
fi
|
||||
|
||||
if ! hash sha1sum 2>/dev/null; then
|
||||
if ! hash shasum 2>/dev/null; then
|
||||
@@ -28,12 +28,15 @@ type Config struct {
|
||||
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 {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
"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)
|
||||
}
|
||||
+131
-124
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -14,71 +13,67 @@ import (
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
"github.com/xtaci/kcptun/generic"
|
||||
"github.com/xtaci/smux"
|
||||
|
||||
"path/filepath"
|
||||
smuxv2 "github.com/xtaci/smux/v2"
|
||||
)
|
||||
|
||||
// SALT is use for pbkdf2 key expansion
|
||||
const SALT = "kcp-go"
|
||||
|
||||
// maximum supported smux version
|
||||
const maxSmuxVer = 2
|
||||
|
||||
// VERSION is injected by buildflags
|
||||
var VERSION = "SELFBUILD"
|
||||
|
||||
// A pool for stream copying
|
||||
var xmitBuf sync.Pool
|
||||
|
||||
type compStream struct {
|
||||
conn net.Conn
|
||||
w *snappy.Writer
|
||||
r *snappy.Reader
|
||||
}
|
||||
|
||||
func (c *compStream) Read(p []byte) (n int, err error) {
|
||||
return c.r.Read(p)
|
||||
}
|
||||
|
||||
func (c *compStream) Write(p []byte) (n int, err error) {
|
||||
n, err = c.w.Write(p)
|
||||
err = c.w.Flush()
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *compStream) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func newCompStream(conn net.Conn) *compStream {
|
||||
c := new(compStream)
|
||||
c.conn = conn
|
||||
c.w = snappy.NewBufferedWriter(conn)
|
||||
c.r = snappy.NewReader(conn)
|
||||
return c
|
||||
}
|
||||
|
||||
func handleClient(sess *smux.Session, p1 io.ReadWriteCloser, quiet bool) {
|
||||
if !quiet {
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
func handleClient(mux generic.Mux, p1 net.Conn, quiet bool) {
|
||||
logln := func(v ...interface{}) {
|
||||
if !quiet {
|
||||
log.Println(v...)
|
||||
}
|
||||
}
|
||||
|
||||
defer p1.Close()
|
||||
p2, err := sess.OpenStream()
|
||||
p2, err := mux.Open()
|
||||
if err != nil {
|
||||
logln(err)
|
||||
return
|
||||
}
|
||||
|
||||
defer p2.Close()
|
||||
|
||||
if s2, ok := p2.(generic.Stream); ok {
|
||||
logln("stream opened", "in:", p1.RemoteAddr(), "out:", fmt.Sprint(s2.RemoteAddr(), "(", s2.ID(), ")"))
|
||||
defer logln("stream closed", "in:", p1.RemoteAddr(), "out:", fmt.Sprint(s2.RemoteAddr(), "(", s2.ID(), ")"))
|
||||
}
|
||||
|
||||
// start tunnel & wait for tunnel termination
|
||||
streamCopy := func(dst io.Writer, src io.Reader) chan struct{} {
|
||||
streamCopy := func(dst io.Writer, src io.ReadCloser) chan struct{} {
|
||||
die := make(chan struct{})
|
||||
go func() {
|
||||
buf := xmitBuf.Get().([]byte)
|
||||
io.CopyBuffer(dst, src, buf)
|
||||
if _, err := generic.CopyBuffer(dst, src, buf); err != nil {
|
||||
if s2, ok := p2.(generic.Stream); ok {
|
||||
// verbose error handling
|
||||
cause := err
|
||||
if e, ok := err.(interface{ Cause() error }); ok {
|
||||
cause = e.Cause()
|
||||
}
|
||||
|
||||
switch cause {
|
||||
case smux.ErrInvalidProtocol:
|
||||
log.Println("smux version:1", err, "in:", p1.RemoteAddr(), "out:", fmt.Sprint(s2.RemoteAddr(), "(", s2.ID(), ")"))
|
||||
case smuxv2.ErrInvalidProtocol:
|
||||
log.Println("smux version:2", err, "in:", p1.RemoteAddr(), "out:", fmt.Sprint(s2.RemoteAddr(), "(", s2.ID(), ")"))
|
||||
}
|
||||
}
|
||||
}
|
||||
xmitBuf.Put(buf)
|
||||
close(die)
|
||||
}()
|
||||
@@ -105,7 +100,7 @@ func main() {
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
}
|
||||
xmitBuf.New = func() interface{} {
|
||||
return make([]byte, 65535)
|
||||
return make([]byte, 32768)
|
||||
}
|
||||
|
||||
myApp := cli.NewApp()
|
||||
@@ -218,11 +213,21 @@ func main() {
|
||||
Value: 4194304, // socket buffer size in bytes
|
||||
Usage: "per-socket buffer in bytes",
|
||||
},
|
||||
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
|
||||
@@ -247,6 +252,10 @@ func main() {
|
||||
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
|
||||
@@ -277,11 +286,14 @@ func main() {
|
||||
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"))
|
||||
@@ -313,8 +325,37 @@ func main() {
|
||||
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)
|
||||
|
||||
// parameters check
|
||||
if config.SmuxVer > maxSmuxVer {
|
||||
log.Fatal("unsupported smux version:", config.SmuxVer)
|
||||
}
|
||||
|
||||
log.Println("initiating key derivation")
|
||||
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
|
||||
log.Println("key derivation done")
|
||||
var block kcp.BlockCrypt
|
||||
switch config.Crypt {
|
||||
case "sm4":
|
||||
@@ -346,34 +387,10 @@ func main() {
|
||||
block, _ = kcp.NewAESBlockCrypt(pass)
|
||||
}
|
||||
|
||||
log.Println("listening on:", listener.Addr())
|
||||
log.Println("encryption:", config.Crypt)
|
||||
log.Println("nodelay parameters:", config.NoDelay, config.Interval, config.Resend, config.NoCongestion)
|
||||
log.Println("remote address:", config.RemoteAddr)
|
||||
log.Println("sndwnd:", config.SndWnd, "rcvwnd:", config.RcvWnd)
|
||||
log.Println("compression:", !config.NoComp)
|
||||
log.Println("mtu:", config.MTU)
|
||||
log.Println("datashard:", config.DataShard, "parityshard:", config.ParityShard)
|
||||
log.Println("acknodelay:", config.AckNodelay)
|
||||
log.Println("dscp:", config.DSCP)
|
||||
log.Println("sockbuf:", config.SockBuf)
|
||||
log.Println("smuxbuf:", config.SmuxBuf)
|
||||
log.Println("keepalive:", config.KeepAlive)
|
||||
log.Println("conn:", config.Conn)
|
||||
log.Println("autoexpire:", config.AutoExpire)
|
||||
log.Println("scavengettl:", config.ScavengeTTL)
|
||||
log.Println("snmplog:", config.SnmpLog)
|
||||
log.Println("snmpperiod:", config.SnmpPeriod)
|
||||
log.Println("quiet:", config.Quiet)
|
||||
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||
|
||||
createConn := func() (*smux.Session, error) {
|
||||
kcpconn, err := kcp.DialWithOptions(config.RemoteAddr, block, config.DataShard, config.ParityShard)
|
||||
createConn := func() (generic.Mux, error) {
|
||||
kcpconn, err := dial(&config, block)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "createConn()")
|
||||
return nil, errors.Wrap(err, "dial()")
|
||||
}
|
||||
kcpconn.SetStreamMode(true)
|
||||
kcpconn.SetWriteDelay(false)
|
||||
@@ -391,23 +408,48 @@ func main() {
|
||||
if err := kcpconn.SetWriteBuffer(config.SockBuf); err != nil {
|
||||
log.Println("SetWriteBuffer:", err)
|
||||
}
|
||||
log.Println("smux version:", config.SmuxVer, "on connection:", kcpconn.LocalAddr(), "->", kcpconn.RemoteAddr())
|
||||
switch config.SmuxVer {
|
||||
case 1:
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||
|
||||
// stream multiplex
|
||||
var session *smux.Session
|
||||
if config.NoComp {
|
||||
session, err = smux.Client(kcpconn, smuxConfig)
|
||||
} else {
|
||||
session, err = smux.Client(newCompStream(kcpconn), smuxConfig)
|
||||
// stream multiplex
|
||||
var session *smux.Session
|
||||
if config.NoComp {
|
||||
session, err = smux.Client(kcpconn, smuxConfig)
|
||||
} else {
|
||||
session, err = smux.Client(generic.NewCompStream(kcpconn), smuxConfig)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "createConn()")
|
||||
}
|
||||
return session, nil
|
||||
case 2:
|
||||
smuxConfig := smuxv2.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
|
||||
smuxConfig.MaxStreamBuffer = config.StreamBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||
|
||||
// stream multiplex
|
||||
var session *smuxv2.Session
|
||||
if config.NoComp {
|
||||
session, err = smuxv2.Client(kcpconn, smuxConfig)
|
||||
} else {
|
||||
session, err = smuxv2.Client(generic.NewCompStream(kcpconn), smuxConfig)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "createConn()")
|
||||
}
|
||||
return session, nil
|
||||
default:
|
||||
panic("incorrect smux version")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "createConn()")
|
||||
}
|
||||
log.Println("connection:", kcpconn.LocalAddr(), "->", kcpconn.RemoteAddr())
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// wait until a connection is ready
|
||||
waitConn := func() *smux.Session {
|
||||
waitConn := func() generic.Mux {
|
||||
for {
|
||||
if session, err := createConn(); err == nil {
|
||||
return session
|
||||
@@ -420,7 +462,7 @@ func main() {
|
||||
|
||||
numconn := uint16(config.Conn)
|
||||
muxes := make([]struct {
|
||||
session *smux.Session
|
||||
session generic.Mux
|
||||
ttl time.Time
|
||||
}, numconn)
|
||||
|
||||
@@ -429,16 +471,15 @@ func main() {
|
||||
muxes[k].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
}
|
||||
|
||||
chScavenger := make(chan *smux.Session, 128)
|
||||
chScavenger := make(chan generic.Mux, 128)
|
||||
go scavenger(chScavenger, config.ScavengeTTL)
|
||||
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
go generic.SnmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
rr := uint16(0)
|
||||
for {
|
||||
p1, err := listener.AcceptTCP()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Fatalf("%+v", err)
|
||||
}
|
||||
checkError(err)
|
||||
idx := rr % numconn
|
||||
|
||||
// do auto expiration && reconnection
|
||||
@@ -456,11 +497,11 @@ func main() {
|
||||
}
|
||||
|
||||
type scavengeSession struct {
|
||||
session *smux.Session
|
||||
session generic.Mux
|
||||
ts time.Time
|
||||
}
|
||||
|
||||
func scavenger(ch chan *smux.Session, ttl int) {
|
||||
func scavenger(ch chan generic.Mux, ttl int) {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
var sessionList []scavengeSession
|
||||
@@ -468,16 +509,16 @@ func scavenger(ch chan *smux.Session, ttl int) {
|
||||
select {
|
||||
case sess := <-ch:
|
||||
sessionList = append(sessionList, scavengeSession{sess, time.Now()})
|
||||
log.Println("session marked as expired")
|
||||
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")
|
||||
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")
|
||||
log.Println("session reached scavenge ttl", s.session.RemoteAddr())
|
||||
s.session.Close()
|
||||
} else {
|
||||
newList = append(newList, sessionList[k])
|
||||
@@ -487,37 +528,3 @@ func scavenger(ch chan *smux.Session, ttl int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package generic
|
||||
|
||||
import "io"
|
||||
|
||||
// io.CopyBuffer has extra tests for interface like io.ReaderFrom and io.WriterTo
|
||||
// which is not efficient in memory management from tests
|
||||
func CopyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
|
||||
if buf != nil && len(buf) == 0 {
|
||||
panic("empty buffer in copyBuffer")
|
||||
}
|
||||
|
||||
for {
|
||||
nr, er := src.Read(buf)
|
||||
if nr > 0 {
|
||||
nw, ew := dst.Write(buf[0:nr])
|
||||
if nw > 0 {
|
||||
written += int64(nw)
|
||||
}
|
||||
if ew != nil {
|
||||
err = ew
|
||||
break
|
||||
}
|
||||
if nr != nw {
|
||||
err = io.ErrShortWrite
|
||||
break
|
||||
}
|
||||
}
|
||||
if er != nil {
|
||||
if er != io.EOF {
|
||||
err = er
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return written, err
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Mux interface {
|
||||
Open() (io.ReadWriteCloser, error)
|
||||
Accept() (io.ReadWriteCloser, error)
|
||||
IsClosed() bool
|
||||
NumStreams() int
|
||||
RemoteAddr() net.Addr
|
||||
Close() error
|
||||
}
|
||||
|
||||
type Stream interface {
|
||||
io.ReadWriteCloser
|
||||
ID() uint32
|
||||
RemoteAddr() net.Addr
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/kcp-go"
|
||||
)
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,24 @@
|
||||
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/klauspost/cpuid v1.2.1 // indirect
|
||||
github.com/klauspost/reedsolomon v1.9.1 // indirect
|
||||
github.com/klauspost/reedsolomon v1.9.2 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
|
||||
github.com/tjfoc/gmsm v1.0.1 // indirect
|
||||
github.com/urfave/cli v1.20.0
|
||||
github.com/xtaci/kcp-go v5.2.7+incompatible
|
||||
github.com/xtaci/smux v1.2.10
|
||||
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 // indirect
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 // indirect
|
||||
golang.org/x/text v0.3.1 // indirect
|
||||
golang.org/x/tools v0.0.0-20190424031103-cb2dda6eabdf // indirect
|
||||
github.com/urfave/cli v1.21.0
|
||||
github.com/xtaci/kcp-go v5.4.19+incompatible
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
|
||||
github.com/xtaci/smux v1.4.4
|
||||
github.com/xtaci/smux/v2 v2.0.11
|
||||
github.com/xtaci/tcpraw v1.2.25
|
||||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83
|
||||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b // indirect
|
||||
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b // indirect
|
||||
)
|
||||
|
||||
go 1.13
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
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/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
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.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/reedsolomon v1.9.1 h1:kYrT1MlR4JH6PqOpC+okdb9CDTcwEC/BqpzK4WFyXL8=
|
||||
github.com/klauspost/reedsolomon v1.9.1/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
|
||||
github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18=
|
||||
github.com/klauspost/reedsolomon v1.9.2/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/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||
@@ -14,93 +17,41 @@ github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkB
|
||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
||||
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.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/xtaci/kcp-go v5.0.7+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.1.1+incompatible h1:A6zXUGblo98vosfEdaHcy0cTBZKY2dByJxICuaV+L5g=
|
||||
github.com/xtaci/kcp-go v5.1.1+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.1.2+incompatible h1:UafCgw2Yk3QOf8MRm8jYEWJt1l4J61BgLpMsROkJQxo=
|
||||
github.com/xtaci/kcp-go v5.1.2+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.1.3+incompatible h1:s96+ulBrZlxk4DPRPgEGPBV8o55kYKKFVivDwVgZNcA=
|
||||
github.com/xtaci/kcp-go v5.1.3+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.1.4+incompatible h1:GHIUAicdHMKwTys8sx2ZnZbFaK8lvmwDniQlFa2BOo4=
|
||||
github.com/xtaci/kcp-go v5.1.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.2.1+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.2.3+incompatible h1:LD/Go8xYxtcyvOvFzeo387BV3UNPcwJvMY+8H+JDhfk=
|
||||
github.com/xtaci/kcp-go v5.2.3+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.2.4+incompatible h1:96bjdOFrUFfU4wYXqGwPJkEOdvnVwciGlAGOHEDpgy8=
|
||||
github.com/xtaci/kcp-go v5.2.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.2.5+incompatible h1:9C3xCFYCw6HUMN1/DQhLlUcbx1DmFiLbpiNA/moLYPM=
|
||||
github.com/xtaci/kcp-go v5.2.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.2.6+incompatible h1:WokjD7IJJopwivFVIleBjmuHYlhGTlR/JAhCsapl1dk=
|
||||
github.com/xtaci/kcp-go v5.2.6+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.2.7+incompatible h1:NkJrwfMj3K6lRHfppR8H+oayahPS6GkGGF4BKiRAiFg=
|
||||
github.com/xtaci/kcp-go v5.2.7+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/smux v1.1.1 h1:ZyIo9XHuHkAeENzHR8yGWC+6xUSCTeP2tPTRE8mnLvc=
|
||||
github.com/xtaci/smux v1.1.1/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.1.2 h1:AeAzHKqvDeFEcicL9Q06LTjIVW2I55iooUbpDRGHth4=
|
||||
github.com/xtaci/smux v1.1.2/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.1/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.2 h1:pF/P78jvAXNG3yddhxKYTXMmNLzxXxdGKKjUBvxF8lk=
|
||||
github.com/xtaci/smux v1.2.2/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.3/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.4 h1:l+peIfF3MUC5OmA93nKlezj8Nhejjv76BvnTyQEB2RI=
|
||||
github.com/xtaci/smux v1.2.4/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.5 h1:p5K13hQEKeMo/H0XwO7jNxuT2G4/guo7Z7blfxBWBpI=
|
||||
github.com/xtaci/smux v1.2.5/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.6 h1:lcooP+CKdWf1IE0d35eJ4MuUt7+kA3hwtQN0uPdd5lo=
|
||||
github.com/xtaci/smux v1.2.6/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.7 h1:h7m7UL5zNZRaqEAtFXReqAVuStI3Al85zvJSGxqDqF0=
|
||||
github.com/xtaci/smux v1.2.7/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.8 h1:mNFGEdnACCih1aER/JF4JVJIcOl7Mkf5yrQNzdDY6jg=
|
||||
github.com/xtaci/smux v1.2.8/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.9 h1:aLBpFdORtDMzFJnrktW5hhe6UScbiS9inicP01KWR7M=
|
||||
github.com/xtaci/smux v1.2.9/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
github.com/xtaci/smux v1.2.10 h1:DQiH08XfO+33X7l5XOGV5urQHrgK8PRFWYxT/z9Hrnw=
|
||||
github.com/xtaci/smux v1.2.10/go.mod h1:f+nYm6SpuHMy/SH0zpbvAFHT1QoMcgLOsWcFip5KfPw=
|
||||
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.13+incompatible h1:s6ba2XTw8lAj+s6AQNob25dCvWDgwE+U1QpEVBUoYy8=
|
||||
github.com/xtaci/kcp-go v5.4.13+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.4.14+incompatible h1:kQZr/ngKQtYrgXSUxwF4A59mTMzUp0BDmtWIRuXYoqg=
|
||||
github.com/xtaci/kcp-go v5.4.14+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.4.15+incompatible h1:QLDulPaKjT4k4cGeviyC1mt00gwJ3r5epx8yCw6ACEc=
|
||||
github.com/xtaci/kcp-go v5.4.15+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.4.16+incompatible h1:/L7UP4P4H/oXpMnrb2W9oOxCMVpjPi3FJeMJmgN+SUE=
|
||||
github.com/xtaci/kcp-go v5.4.16+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.4.17+incompatible h1:RudP76JCx062JSxPxSjBl+457+fS0M7T8zEZPLpC0o8=
|
||||
github.com/xtaci/kcp-go v5.4.17+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.4.18+incompatible h1:zxzRP8V54vhJ8QAKEjf1b9g96R01prybCRchx6rEmtg=
|
||||
github.com/xtaci/kcp-go v5.4.18+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/kcp-go v5.4.19+incompatible h1:vv7Ar1D9WZGiv6deIOluxrC26Oin/2jFtx8sFU5tlvw=
|
||||
github.com/xtaci/kcp-go v5.4.19+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
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.4.4 h1:FukIfahko+KHhS9Gxppkp6756opZymvPOLNmpny1is4=
|
||||
github.com/xtaci/smux v1.4.4/go.mod h1:LuA3S0xssf4fmGRJ7ow3EehgmDUzib4EcobaFNKvlMA=
|
||||
github.com/xtaci/smux/v2 v2.0.11 h1:thVWmgGRciZ8iaATwpY2B/51aHzmMI6wrF7DfcJSckU=
|
||||
github.com/xtaci/smux/v2 v2.0.11/go.mod h1:Iqy5a3Gax2p7WCKHOHkSNo/COthNFXd3/vqrcKNtzqI=
|
||||
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-20190320223903-b7391e95e576 h1:aUX/1G2gFSs4AsJJg2cL3HuoRhCSCz733FE5GUSuaT4=
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a h1:Igim7XhdOpBnWPuYJ70XcNpq8q3BCACtVgNfoJxOV7g=
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190417174047-f416ebab96af h1:6qGQw30u837TXZbCmLFR9AVA+RjJU1LIbvk0oIkDZGY=
|
||||
golang.org/x/crypto v0.0.0-20190417174047-f416ebab96af/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h7zlCWCcH4RHyPVReBmhzk=
|
||||
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd h1:sMHc2rZHuzQmrbVoSpt9HgerkXPyIeCSO6k0zUMGfFk=
|
||||
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 h1:kcXqo9vE6fsZY5X5Rd7R1l7fTgnWaDCVmln65REefiE=
|
||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190324223953-e3b2ff56ed87 h1:yh5/K199RObPR6zqVBYf+AyJuweAqx+fOe9s3cekn1Y=
|
||||
golang.org/x/net v0.0.0-20190324223953-e3b2ff56ed87/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190328230028-74de082e2cca h1:hyA6yiAgbUwuWqtscNvWAI7U1CtlaD1KilQ6iudt1aI=
|
||||
golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83 h1:mgAKeshyNqWKdENOnQsg+8dRTwZFIwFaO3HNl52sweA=
|
||||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190415214537-1da14a5a36f2 h1:iC0Y6EDq+rhnAePxGvJs2kzUAYcwESqdcGRPzEUfzTU=
|
||||
golang.org/x/net v0.0.0-20190415214537-1da14a5a36f2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190420063019-afa5a82059c6 h1:HdqqaWmYAUI7/dmByKKEw+yxDksGSo+9GjkUc9Zp34E=
|
||||
golang.org/x/net v0.0.0-20190420063019-afa5a82059c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190424024845-afe8014c977f h1:uALRiwYevCJtciRa4mKKFkrs5jY4F2OTf1D2sfi1swY=
|
||||
golang.org/x/net v0.0.0-20190424024845-afe8014c977f/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 h1:FP8hkuE6yUEaJnK7O2eTuejKWwW+Rhfj80dQ2JcKxCU=
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc=
|
||||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/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-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190329044733-9eb1bfa1ce65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20190415145633-3fd5a3612ccd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190416152802-12500544f89f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b h1:3S2h5FadpNr0zUUCVZjlKIEYF+KaX/OBplTGo89CYHI=
|
||||
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190424031103-cb2dda6eabdf/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
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=
|
||||
|
||||
@@ -26,12 +26,15 @@ type Config struct {
|
||||
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 {
|
||||
|
||||
+179
-134
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -16,76 +15,86 @@ import (
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/urfave/cli"
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
"github.com/xtaci/kcptun/generic"
|
||||
"github.com/xtaci/smux"
|
||||
smuxv2 "github.com/xtaci/smux/v2"
|
||||
"github.com/xtaci/tcpraw"
|
||||
)
|
||||
|
||||
// SALT is use for pbkdf2 key expansion
|
||||
const SALT = "kcp-go"
|
||||
|
||||
// maximum supported smux version
|
||||
const maxSmuxVer = 2
|
||||
|
||||
// VERSION is injected by buildflags
|
||||
var VERSION = "SELFBUILD"
|
||||
|
||||
// A pool for stream copying
|
||||
var xmitBuf sync.Pool
|
||||
|
||||
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 io.ReadWriteCloser, config *Config) {
|
||||
// stream multiplex
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||
|
||||
mux, err := smux.Server(conn, smuxConfig)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
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
|
||||
}
|
||||
defer mux.Close()
|
||||
log.Println("smux version:", config.SmuxVer, "on connection:", conn.LocalAddr(), "->", conn.RemoteAddr())
|
||||
|
||||
// stream multiplex
|
||||
var muxer generic.Mux
|
||||
switch config.SmuxVer {
|
||||
case 1:
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||
|
||||
mux, err := smux.Server(conn, smuxConfig)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer mux.Close()
|
||||
muxer = mux
|
||||
case 2:
|
||||
smuxConfig := smuxv2.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
|
||||
smuxConfig.MaxStreamBuffer = config.StreamBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||
|
||||
mux, err := smuxv2.Server(conn, smuxConfig)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer mux.Close()
|
||||
muxer = mux
|
||||
default:
|
||||
panic("incorrect smux version")
|
||||
}
|
||||
|
||||
for {
|
||||
stream, err := mux.AcceptStream()
|
||||
stream, err := muxer.Accept()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
go func(p1 *smux.Stream) {
|
||||
p2, err := net.Dial("tcp", config.Target)
|
||||
go func(p1 io.ReadWriteCloser) {
|
||||
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 {
|
||||
p1.Close()
|
||||
log.Println(err)
|
||||
p1.Close()
|
||||
return
|
||||
}
|
||||
handleClient(p1, p2, config.Quiet)
|
||||
@@ -93,20 +102,42 @@ func handleMux(conn io.ReadWriteCloser, config *Config) {
|
||||
}
|
||||
}
|
||||
|
||||
func handleClient(p1, p2 io.ReadWriteCloser, quiet bool) {
|
||||
if !quiet {
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
func handleClient(p1 io.ReadWriteCloser, p2 net.Conn, quiet bool) {
|
||||
logln := func(v ...interface{}) {
|
||||
if !quiet {
|
||||
log.Println(v...)
|
||||
}
|
||||
}
|
||||
|
||||
defer p1.Close()
|
||||
defer p2.Close()
|
||||
|
||||
if s1, ok := p1.(generic.Stream); ok {
|
||||
logln("stream opened", "in:", fmt.Sprint(s1.RemoteAddr(), "(", s1.ID(), ")"), "out:", p2.RemoteAddr())
|
||||
defer logln("stream closed", "in:", fmt.Sprint(s1.RemoteAddr(), "(", s1.ID(), ")"), "out:", p2.RemoteAddr())
|
||||
}
|
||||
|
||||
// start tunnel & wait for tunnel termination
|
||||
streamCopy := func(dst io.Writer, src io.Reader) chan struct{} {
|
||||
streamCopy := func(dst io.Writer, src io.ReadCloser) chan struct{} {
|
||||
die := make(chan struct{})
|
||||
go func() {
|
||||
buf := xmitBuf.Get().([]byte)
|
||||
io.CopyBuffer(dst, src, buf)
|
||||
if _, err := generic.CopyBuffer(dst, src, buf); err != nil {
|
||||
if s1, ok := p1.(generic.Stream); ok {
|
||||
// verbose error handling
|
||||
cause := err
|
||||
if e, ok := err.(interface{ Cause() error }); ok {
|
||||
cause = e.Cause()
|
||||
}
|
||||
|
||||
switch cause {
|
||||
case smux.ErrInvalidProtocol:
|
||||
log.Println("smux version:1", err, "in:", fmt.Sprint(s1.RemoteAddr(), "(", s1.ID(), ")"), "out:", p2.RemoteAddr())
|
||||
case smuxv2.ErrInvalidProtocol:
|
||||
log.Println("smux version:2", err, "in:", fmt.Sprint(s1.RemoteAddr(), "(", s1.ID(), ")"), "out:", p2.RemoteAddr())
|
||||
}
|
||||
}
|
||||
}
|
||||
xmitBuf.Put(buf)
|
||||
close(die)
|
||||
}()
|
||||
@@ -133,7 +164,7 @@ func main() {
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
}
|
||||
xmitBuf.New = func() interface{} {
|
||||
return make([]byte, 65535)
|
||||
return make([]byte, 32768)
|
||||
}
|
||||
|
||||
myApp := cli.NewApp()
|
||||
@@ -149,7 +180,7 @@ func main() {
|
||||
cli.StringFlag{
|
||||
Name: "target, t",
|
||||
Value: "127.0.0.1:12948",
|
||||
Usage: "target server address",
|
||||
Usage: "target server address, or path/to/unix_socket",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "key",
|
||||
@@ -231,11 +262,21 @@ func main() {
|
||||
Value: 4194304, // socket buffer size in bytes
|
||||
Usage: "per-socket buffer in bytes",
|
||||
},
|
||||
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
|
||||
@@ -264,6 +305,10 @@ func main() {
|
||||
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
|
||||
@@ -291,12 +336,15 @@ func main() {
|
||||
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
|
||||
@@ -324,8 +372,35 @@ func main() {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
log.Println("initiating key derivation")
|
||||
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
|
||||
log.Println("key derivation done")
|
||||
var block kcp.BlockCrypt
|
||||
switch config.Crypt {
|
||||
case "sm4":
|
||||
@@ -357,94 +432,64 @@ func main() {
|
||||
block, _ = kcp.NewAESBlockCrypt(pass)
|
||||
}
|
||||
|
||||
lis, err := kcp.ListenWithOptions(config.Listen, block, config.DataShard, config.ParityShard)
|
||||
checkError(err)
|
||||
log.Println("listening on:", lis.Addr())
|
||||
log.Println("target:", config.Target)
|
||||
log.Println("encryption:", config.Crypt)
|
||||
log.Println("nodelay parameters:", config.NoDelay, config.Interval, config.Resend, config.NoCongestion)
|
||||
log.Println("sndwnd:", config.SndWnd, "rcvwnd:", config.RcvWnd)
|
||||
log.Println("compression:", !config.NoComp)
|
||||
log.Println("mtu:", config.MTU)
|
||||
log.Println("datashard:", config.DataShard, "parityshard:", config.ParityShard)
|
||||
log.Println("acknodelay:", config.AckNodelay)
|
||||
log.Println("dscp:", config.DSCP)
|
||||
log.Println("sockbuf:", config.SockBuf)
|
||||
log.Println("smuxbuf:", config.SmuxBuf)
|
||||
log.Println("keepalive:", config.KeepAlive)
|
||||
log.Println("snmplog:", config.SnmpLog)
|
||||
log.Println("snmpperiod:", config.SnmpPeriod)
|
||||
log.Println("pprof:", config.Pprof)
|
||||
log.Println("quiet:", config.Quiet)
|
||||
|
||||
if err := lis.SetDSCP(config.DSCP); err != nil {
|
||||
log.Println("SetDSCP:", err)
|
||||
}
|
||||
if err := lis.SetReadBuffer(config.SockBuf); err != nil {
|
||||
log.Println("SetReadBuffer:", err)
|
||||
}
|
||||
if err := lis.SetWriteBuffer(config.SockBuf); err != nil {
|
||||
log.Println("SetWriteBuffer:", err)
|
||||
}
|
||||
|
||||
go snmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
go generic.SnmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
if config.Pprof {
|
||||
go http.ListenAndServe(":6060", nil)
|
||||
}
|
||||
|
||||
for {
|
||||
if conn, err := lis.AcceptKCP(); err == nil {
|
||||
log.Println("remote address:", conn.RemoteAddr())
|
||||
conn.SetStreamMode(true)
|
||||
conn.SetWriteDelay(false)
|
||||
conn.SetNoDelay(config.NoDelay, config.Interval, config.Resend, config.NoCongestion)
|
||||
conn.SetMtu(config.MTU)
|
||||
conn.SetWindowSize(config.SndWnd, config.RcvWnd)
|
||||
conn.SetACKNoDelay(config.AckNodelay)
|
||||
// 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)
|
||||
}
|
||||
|
||||
if config.NoComp {
|
||||
go handleMux(conn, &config)
|
||||
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)
|
||||
|
||||
if config.NoComp {
|
||||
go handleMux(conn, &config)
|
||||
} else {
|
||||
go handleMux(generic.NewCompStream(conn), &config)
|
||||
}
|
||||
} else {
|
||||
go handleMux(newCompStream(conn), &config)
|
||||
log.Printf("%+v", err)
|
||||
}
|
||||
} else {
|
||||
log.Printf("%+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
Reference in New Issue
Block a user