Compare commits

..
133 Commits
Author SHA1 Message Date
xtaci 7e648ff260 upgrade to kcp-go@5.4.10 2019-09-24 13:28:31 +08:00
xtaci 00db8d26ec upgrade to kcp-go@5.4.9 2019-09-23 22:02:38 +08:00
xtaci f45e756fca upgrade to kcp-go@5.4.8 2019-09-23 21:32:37 +08:00
xtaci 3530c325ba upgrade smux@v2.0.10 -> smux@v2.0.11 2019-09-22 21:59:51 +08:00
xtaci 6d6114bf26 update example json for smux v2 2019-09-22 20:51:39 +08:00
xtaci cda9de7d8d go mod tidy 2019-09-22 18:41:19 +08:00
xtaci 9004bf3170 update Dockerfile to support GO111MODULE 2019-09-22 18:06:09 +08:00
xtaci 903cb9f9f1 update .travis.yml 2019-09-22 17:45:40 +08:00
xtaci 6c46285010 upd to kcp-go@5.4.7 2019-09-22 17:42:01 +08:00
xtaci 1b72bf39d8 verbose logging on smux establishment 2019-09-22 16:41:23 +08:00
xtaci 112870d870 1->2 2019-09-22 16:31:02 +08:00
xtaci a859f419f6 verbose error handling for smux protocol 2019-09-22 14:47:38 +08:00
xtaci fa728236d4 only output protocol error in streamCopy 2019-09-22 14:40:14 +08:00
xtaci ade7ee06a0 stream copy print high-level error 2019-09-22 13:47:11 +08:00
xtaci 30cca4d7db half default streambuf to 2097152 bytes 2019-09-22 12:43:54 +08:00
xtaci 0f18b17a8a fix spelling 2019-09-22 12:32:07 +08:00
xtaci 1b756aeb3d adjust sequence of startup log 2019-09-22 11:12:55 +08:00
xtaci a69b0a90ed fix generic.Stream interface type error 2019-09-22 11:03:16 +08:00
xtaci 8778495915 upd deps smuxv2 2019-09-22 10:54:30 +08:00
xtaci 13deb22077 upd deps 2019-09-22 00:18:30 +08:00
xtaci 1635649aa5 upd deps 2019-09-22 00:02:21 +08:00
xtaci 3425d6288b upd deps 2019-09-21 23:56:05 +08:00
xtaci fe3227db22 update smux deps 2019-09-21 23:43:22 +08:00
xtaci 2684e47946 upd default value for streambuf 2019-09-21 22:30:26 +08:00
xtaci fcb6a5e141 add -smuxver to support smux version 2 2019-09-21 20:59:41 +08:00
xtaci ff9a67e931 upgrade kcp-go to v5.4.5 2019-09-10 22:14:24 +08:00
xtaci f288fe9ea6 upd deps 2019-09-10 20:57:21 +08:00
xtaci 7a42a51643 remove obsolete file 2019-09-06 14:18:02 +08:00
xtaci bd4051bd02 make server listen dual stack on tcp & udp if -tcp is specified 2019-09-06 14:15:18 +08:00
xtaci bab23e05b0 upd deps 2019-09-05 13:54:25 +08:00
xtaciandGitHub 4200cc7ef6 Update README.md 2019-08-13 18:14:24 +08:00
xtaci d9df85de52 upd deps 2019-08-08 12:53:24 +00:00
xtaci 379ce89334 upd deps 2019-08-08 09:33:05 +00:00
xtaci 34aaf35425 upd deps 2019-07-25 16:30:34 +08:00
xtaci 375d7bff86 support unix domain socket 2019-07-23 09:13:37 +00:00
xtaci 4e9d289d7a fix 2019-07-23 09:00:16 +00:00
xtaci b5f98ed351 support unix domain socket 2019-07-23 08:57:58 +00:00
xtaci 4cc3e083d8 Merge branch 'master' of https://github.com/xtaci/kcptun 2019-07-23 06:57:19 +00:00
xtaci adae541dd9 upd deps 2019-07-23 06:56:25 +00:00
xtaci 0734e23cf3 fix build issue 2019-07-23 11:08:45 +08:00
xtaci 6a8b0f70e7 upd deps 2019-07-22 11:13:27 +00:00
xtaci f8454de6b6 upd deps 2019-07-18 05:46:46 +00:00
xtaci e97e49498e upd deps 2019-07-17 07:47:41 +00:00
xtaci 9f2ff06ec8 upd deps 2019-07-16 08:47:36 +00:00
xtaci 6715764c4f upd deps 2019-07-15 13:57:07 +08:00
xtaci 62f2ffe2d8 Merge branch 'master' of https://github.com/xtaci/kcptun 2019-07-14 10:29:56 +00:00
xtaci 90b9f85617 upd 2019-07-14 10:28:59 +00:00
xtaci e619848985 upd 2019-07-14 12:17:40 +08:00
xtaci 7f93fb5858 upd deps 2019-07-13 07:22:04 +00:00
xtaci 7b8a4646fc upd deps 2019-07-13 05:01:55 +00:00
xtaci b5487cd0ce upd deps 2019-07-12 16:38:16 +00:00
xtaci acfe430810 upd deps 2019-07-12 16:16:29 +00:00
xtaci 9285b162b7 upd deps 2019-07-12 16:02:00 +00:00
xtaci 8d13f9be89 upd deps 2019-07-12 15:22:09 +00:00
xtaci 4ba9028985 upd deps 2019-07-12 06:25:06 +00:00
xtaci b4473a5413 print address on compressed connection 2019-07-11 15:24:54 +00:00
xtaci 3b01e69ba2 upd deps 2019-07-11 13:47:45 +00:00
xtaci 76b658917a add example config json file 2019-07-11 13:38:47 +00:00
xtaci b260423213 upd deps 2019-07-11 10:17:15 +00:00
xtaci 72fbf47844 upd deps 2019-07-11 08:01:44 +00:00
xtaci 8daf4edd0a upd deps 2019-07-11 04:30:12 +00:00
xtaci c8d917f400 upd desp 2019-07-10 05:38:28 +00:00
xtaci db88c47847 upd deps 2019-07-09 08:22:09 +00:00
xtaci 32ecbcdc34 upd deps 2019-07-09 07:45:25 +00:00
xtaci 3f8089807e upd 2019-07-08 13:22:39 +00:00
xtaci bdd293f180 upd 2019-07-08 12:45:33 +00:00
xtaci bd4a02a193 upd deps 2019-07-08 09:54:37 +00:00
xtaci bb6bf9985c simplify dial/listen 2019-07-08 07:13:28 +00:00
xtaci 3923bba92c upd deps 2019-07-08 06:33:51 +00:00
xtaci d6f97d1f4a upd deps 2019-07-05 08:11:38 +00:00
xtaci 255bb85640 upd 2019-07-04 23:06:02 +08:00
xtaci d5104ec4f1 upd script 2019-07-04 07:01:02 +00:00
xtaci addeb3b2df upd deps 2019-07-04 06:58:29 +00:00
xtaci 2feb1129f2 upd deps 2019-07-04 06:37:00 +00:00
xtaci efff54a699 upd build-release.sh 2019-07-04 05:19:43 +00:00
xtaci 6a84007ab0 fix dockerfile 2019-07-04 12:38:36 +08:00
xtaci 468cafff85 fix version 2019-07-03 14:08:10 +00:00
xtaci 002827cbaa add comment 2019-07-03 13:36:58 +00:00
xtaci 3260e4d346 Squashed commit of the following:
commit f3022926ae0c0d176088c299f40df47b472b7a52
Author: xtaci <daniel820313@gmail.com>
Date:   Wed Jul 3 13:18:04 2019 +0000

    enable tcp option

commit e8be0df1d071a2cab0c2c3bc573af0fd836d852e
Author: xtaci <daniel820313@gmail.com>
Date:   Wed Jul 3 13:01:22 2019 +0000

    fix compile for i386

commit 03d15811558f6aedc9d58b4eeef17b563186ac4b
Author: xtaci <daniel820313@gmail.com>
Date:   Wed Jul 3 12:35:02 2019 +0000

    upd build-release.sh and simplify platformd-depedent dial/listen

commit b8240d92ea453b397a5662c19c5ffebf3356af78
Author: xtaci <daniel820313@gmail.com>
Date:   Wed Jul 3 09:49:01 2019 +0000

    simplify listening

commit e2e87b6f8dcabbd91d521f02baa00443c0ad1df3
Author: xtaci <daniel820313@gmail.com>
Date:   Wed Jul 3 09:41:43 2019 +0000

    simplify dialing
2019-07-03 13:19:16 +00:00
xtaci 60bee85c51 Squashed commit of the following:
commit e8be0df1d071a2cab0c2c3bc573af0fd836d852e
Author: xtaci <daniel820313@gmail.com>
Date:   Wed Jul 3 13:01:22 2019 +0000

    fix compile for i386

commit 03d15811558f6aedc9d58b4eeef17b563186ac4b
Author: xtaci <daniel820313@gmail.com>
Date:   Wed Jul 3 12:35:02 2019 +0000

    upd build-release.sh and simplify platformd-depedent dial/listen

commit b8240d92ea453b397a5662c19c5ffebf3356af78
Author: xtaci <daniel820313@gmail.com>
Date:   Wed Jul 3 09:49:01 2019 +0000

    simplify listening

commit e2e87b6f8dcabbd91d521f02baa00443c0ad1df3
Author: xtaci <daniel820313@gmail.com>
Date:   Wed Jul 3 09:41:43 2019 +0000

    simplify dialing
2019-07-03 13:02:23 +00:00
xtaci 3a649e369c upd travis 2019-07-02 07:51:58 +00:00
xtaci 7cc7454c7c upd 2019-07-02 07:48:32 +00:00
xtaci 9ba6c75eff upd deps 2019-07-02 07:38:51 +00:00
xtaci 1a28b61d45 upd README.md 2019-07-01 12:19:15 +00:00
xtaci 5bf748b8b5 Revert "support -tcp", keep on tcp branch
This reverts commit 770f5c00da.
2019-06-27 21:49:44 +00:00
xtaci 04602bfb9f upd deps 2019-06-27 21:15:40 +00:00
xtaci 9dee7cb401 upd dep 2019-06-27 20:27:17 +00:00
xtaci 7e53f045d2 upd 2019-06-27 20:04:06 +00:00
xtaci 951521a0a6 upd deps 2019-06-27 16:16:58 +00:00
xtaci d0b4365909 upd 2019-06-27 15:44:30 +00:00
xtaci 51192afeba upds deps 2019-06-27 15:33:13 +00:00
xtaciandGitHub 1ab630df33 Update README.md 2019-06-27 15:17:24 +08:00
xtaciandGitHub 18113ed797 Update README.md 2019-06-27 15:13:11 +08:00
xtaci 770f5c00da support -tcp 2019-06-27 15:10:00 +08:00
xtaci bf635db2f9 upd deps 2019-06-11 15:32:03 +08:00
xtaci b31a9d01af change stream i/o log 2019-06-11 14:59:09 +08:00
xtaci 440e490204 upd deps 2019-06-11 14:22:28 +08:00
xtaci 45e58e6500 output endpoint address when stream opened 2019-06-11 14:07:17 +08:00
xtaci 7382d41489 do not reset the snmp values 2019-05-23 11:26:08 +08:00
xtaciandGitHub 22966661c4 Update README.md 2019-05-20 13:24:31 +08:00
xtaci a704f60ee3 remove one line 2019-05-16 21:35:24 +08:00
xtaci 0db71f7d0c upd readme 2019-05-16 13:10:03 +08:00
xtaci 76c88158c8 upd deps 2019-05-14 21:21:31 +08:00
xtaci af3185d2e9 log prints remoteaddr 2019-05-14 21:20:24 +08:00
xtaci 76f62b0dd1 smux 1.3.1 2019-05-14 14:07:53 +08:00
xtaci 9f5d2a278a smux v1.2.12 kcp-go v5.3.8 2019-05-14 11:29:45 +08:00
xtaci af88878dd9 kcp-go v5.3.7 2019-05-13 16:52:30 +08:00
xtaci ec9ace1de0 fix 2019-05-12 21:30:14 +08:00
xtaci e93a1908c1 upd 2019-05-12 20:34:42 +08:00
xtaci e7c6eb17d2 upd deps 2019-05-12 19:06:06 +08:00
jessandxtaci 26f6688da3 Added backers and sponsors on the README (#679) 2019-05-12 11:21:10 +08:00
xtaci dbaefc35a7 adjust bi-tun parameters 2019-05-11 18:13:48 +08:00
xtaci 5da363682e indie snmp.go 2019-05-10 21:47:23 +08:00
xtaci 116c1e7668 seperate compStream 2019-05-10 21:44:02 +08:00
xtaci 86cc46f437 a specific version of copy 2019-05-10 21:33:51 +08:00
xtaci e54a648576 half-close 2019-05-10 17:38:20 +08:00
xtaci 49f701be26 fix format 2019-05-10 15:27:04 +08:00
xtaci 6e0b2077ea add error output 2019-05-10 15:22:45 +08:00
xtaci 873351361a upd deps 2019-05-10 14:36:20 +08:00
xtaci f33e913f73 deps kcp-go to 5.3.2 2019-05-10 12:36:14 +08:00
xtaci 5c77ac3c60 upd deps 2019-04-28 14:56:10 +08:00
xtaci 5d015f0616 less memory usage 2019-04-28 14:53:40 +08:00
xtaci 2a9fb0b908 mv build-releash.sh to root dir 2019-04-28 14:35:33 +08:00
xtaciandGitHub 2f36a43223 Add files via upload (#671)
* Add files via upload

* Update README.md
2019-04-27 10:17:43 +08:00
xtaci 11681b5d73 deps 2019-04-24 23:14:17 +08:00
xtaci 4ab1085fe5 update deps 2019-04-24 13:42:52 +08:00
xtaci 60569b85fa upd deps 2019-04-23 21:10:39 +08:00
xtaci 273ca4febc upd deps 2019-04-23 21:08:03 +08:00
xtaci d129f92842 upd deps 2019-04-22 17:05:50 +08:00
xtaci 75e83adfba reuse buffer for io.copyBuffer 2019-04-22 14:10:12 +08:00
xtaciandGitHub 3f6134be00 Merge pull request #667 from imcotton/patch-1
upgrade alpine to v3.9 in docker image
2019-04-19 17:42:24 +08:00
Cotton HouandGitHub 2ea87c9c22 upgrade alpine to v3.9 in docker image 2019-04-19 17:04:06 +08:00
xtaci 0bf2b94d92 upd deps 2019-04-18 14:17:27 +08:00
20 changed files with 813 additions and 351 deletions
+2
View File
@@ -24,3 +24,5 @@ _testmain.go
*.prof
client/client
server/server
build/*
.DS_Store
+6 -6
View File
@@ -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
+3 -2
View File
@@ -1,11 +1,12 @@
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.6
FROM alpine:3.9
COPY --from=builder /go/bin /bin
EXPOSE 29900/udp
EXPOSE 12948
+25 -19
View File
@@ -69,12 +69,16 @@ 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" />
![bandwidth](bw.png)
![flame](flame.png)
> Practical bandwidth graph with parameters: -mode fast3 -ds 10 -ps 3
### Basic Tuning Guide
#### Improving Thoughput
@@ -294,29 +298,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
}
```
@@ -359,6 +364,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
+139
View File
@@ -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 ==="
+10 -1
View File
@@ -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
+3
View File
@@ -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 {
+18
View File
@@ -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)
}
+142 -126
View File
@@ -2,79 +2,79 @@ package main
import (
"crypto/sha1"
"encoding/csv"
"fmt"
"io"
"log"
"math/rand"
"net"
"os"
"sync"
"time"
"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"
)
var (
// VERSION is injected by buildflags
VERSION = "SELFBUILD"
// SALT is use for pbkdf2 key expansion
SALT = "kcp-go"
)
// SALT is use for pbkdf2 key expansion
const SALT = "kcp-go"
type compStream struct {
conn net.Conn
w *snappy.Writer
r *snappy.Reader
}
// maximum supported smux version
const maxSmuxVer = 2
func (c *compStream) Read(p []byte) (n int, err error) {
return c.r.Read(p)
}
// VERSION is injected by buildflags
var VERSION = "SELFBUILD"
func (c *compStream) Write(p []byte) (n int, err error) {
n, err = c.w.Write(p)
err = c.w.Flush()
return n, err
}
// A pool for stream copying
var xmitBuf sync.Pool
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() {
io.CopyBuffer(dst, src, make([]byte, 65535))
buf := xmitBuf.Get().([]byte)
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)
}()
return die
@@ -99,6 +99,10 @@ func main() {
// add more log flags for debugging
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
xmitBuf.New = func() interface{} {
return make([]byte, 32768)
}
myApp := cli.NewApp()
myApp.Name = "kcptun"
myApp.Usage = "client(with SMUX)"
@@ -209,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
@@ -238,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
@@ -268,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"))
@@ -304,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":
@@ -337,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)
@@ -382,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
@@ -411,7 +462,7 @@ func main() {
numconn := uint16(config.Conn)
muxes := make([]struct {
session *smux.Session
session generic.Mux
ttl time.Time
}, numconn)
@@ -420,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
@@ -447,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
@@ -459,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])
@@ -478,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()
}
}
}
+27
View File
@@ -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
}
+27
View File
@@ -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
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

+62
View File
@@ -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
}
+36
View File
@@ -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
}
+21
View File
@@ -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
}
+46
View File
@@ -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()
}
}
}
+15 -8
View File
@@ -1,17 +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/klauspost/cpuid v1.2.0 // indirect
github.com/klauspost/reedsolomon v1.9.1 // indirect
github.com/google/gopacket v1.1.17 // indirect
github.com/klauspost/cpuid v1.2.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.3+incompatible
github.com/xtaci/smux v1.2.5
golang.org/x/crypto v0.0.0-20190417174047-f416ebab96af
golang.org/x/net v0.0.0-20190415214537-1da14a5a36f2 // indirect
golang.org/x/sys v0.0.0-20190416152802-12500544f89f // indirect
github.com/urfave/cli v1.21.0
github.com/xtaci/kcp-go v5.4.10+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
+38 -53
View File
@@ -1,9 +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/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/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.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=
@@ -12,57 +17,37 @@ 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/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/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.7+incompatible h1:0WXorSb87WBIVjXWv618klAeCh8H32NcDpWq+g04x2E=
github.com/xtaci/kcp-go v5.4.7+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go v5.4.8+incompatible h1:4GnTyiiC1S7ZFBMKvsF0gMJ3MoN1BoiFRCQ7IuAeUB0=
github.com/xtaci/kcp-go v5.4.8+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go v5.4.9+incompatible h1:wrMgJXB/UFch+ERT0Qr4wO9CSqPAXWblbnH9uGK7TM4=
github.com/xtaci/kcp-go v5.4.9+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go v5.4.10+incompatible h1:FgH1ji3efEmRFaHEeyim1RYN4Q/c8BT8VqXMklBmh84=
github.com/xtaci/kcp-go v5.4.10+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.10 h1:EKYuZH06sfoId5REZXyHmKTSgIeU5Ko27JICc0YI6ys=
github.com/xtaci/smux/v2 v2.0.10/go.mod h1:Iqy5a3Gax2p7WCKHOHkSNo/COthNFXd3/vqrcKNtzqI=
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/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-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-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-20190412213103-97732733099d/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=
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=
+3
View File
@@ -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 {
+190 -136
View File
@@ -2,7 +2,6 @@ package main
import (
"crypto/sha1"
"encoding/csv"
"fmt"
"io"
"log"
@@ -11,78 +10,91 @@ import (
"net/http"
_ "net/http/pprof"
"os"
"sync"
"time"
"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"
)
var (
// VERSION is injected by buildflags
VERSION = "SELFBUILD"
// SALT is use for pbkdf2 key expansion
SALT = "kcp-go"
)
// SALT is use for pbkdf2 key expansion
const SALT = "kcp-go"
type compStream struct {
conn net.Conn
w *snappy.Writer
r *snappy.Reader
}
// maximum supported smux version
const maxSmuxVer = 2
func (c *compStream) Read(p []byte) (n int, err error) {
return c.r.Read(p)
}
// VERSION is injected by buildflags
var VERSION = "SELFBUILD"
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
}
// A pool for stream copying
var xmitBuf sync.Pool
// 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)
@@ -90,19 +102,43 @@ 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() {
io.CopyBuffer(dst, src, make([]byte, 65535))
buf := xmitBuf.Get().([]byte)
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)
}()
return die
@@ -127,6 +163,10 @@ func main() {
// add more log flags for debugging
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
xmitBuf.New = func() interface{} {
return make([]byte, 32768)
}
myApp := cli.NewApp()
myApp.Name = "kcptun"
myApp.Usage = "server(with SMUX)"
@@ -140,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",
@@ -222,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
@@ -255,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
@@ -282,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
@@ -315,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":
@@ -348,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()
}
}
}