mirror of
https://github.com/xtaci/kcptun.git
synced 2024-04-21 12:32:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f8d762742 | ||
|
|
e3ab00cf5b | ||
|
|
42bf13fb7a | ||
|
|
03f27ec53d | ||
|
|
b2390a5dd3 | ||
|
|
bf1d0d6419 | ||
|
|
834cc5d596 | ||
|
|
825ccca6ac | ||
|
|
2845af3911 | ||
|
|
31a9d13871 | ||
|
|
43761f486c | ||
|
|
030e39bf74 | ||
|
|
e6a1d00758 | ||
|
|
9d5a5b9c0d | ||
|
|
4aaf974a0b | ||
|
|
1600d4d26f | ||
|
|
c612e5e153 | ||
|
|
2fef48ce71 | ||
|
|
1d492accd6 | ||
|
|
d1beaf8383 | ||
|
|
ded53a9229 | ||
|
|
65751d535b | ||
|
|
4b5f7c1405 | ||
|
|
25bad3c03c | ||
|
|
d2c4d04600 | ||
|
|
0cb075b061 | ||
|
|
ab7a8321a6 | ||
|
|
6496672b61 | ||
|
|
ae513e9af1 | ||
|
|
36763feca4 |
+1
-1
@@ -1,6 +1,6 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.6
|
||||
- 1.9
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 636 B |
+5
-2
@@ -1,8 +1,11 @@
|
||||
FROM golang:alpine
|
||||
FROM golang:alpine as builder
|
||||
MAINTAINER xtaci <daniel820313@gmail.com>
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add git
|
||||
RUN go get github.com/xtaci/kcptun/client && go get github.com/xtaci/kcptun/server
|
||||
RUN go get -ldflags "-X main.VERSION=$(date -u +%Y%m%d) -s -w" github.com/xtaci/kcptun/client && go get -ldflags "-X main.VERSION=$(date -u +%Y%m%d) -s -w" github.com/xtaci/kcptun/server
|
||||
|
||||
FROM alpine:3.6
|
||||
COPY --from=builder /go/bin /bin
|
||||
EXPOSE 29900/udp
|
||||
EXPOSE 12948
|
||||
|
||||
@@ -21,8 +21,16 @@
|
||||
|
||||
<img src="kcptun.png" alt="kcptun" height="300px"/>
|
||||
|
||||
> *kcptun maintains a single website — [github.com/xtaci/kcptun](https://github.com/xtaci/kcptun). Any websites other than [github.com/xtaci/kcptun](https://github.com/xtaci/kcptun) are not endorsed by xtaci. kcptun won't publish anything on any social media.*
|
||||
|
||||
> *KCP communication group: 364933586 (QQ group number), KCP integration, tuning, network transmission and related technical discussions.*
|
||||
|
||||
### QuickStart
|
||||
|
||||
Increase number of open files on your server, as:
|
||||
|
||||
`ulimit -n 65535`, or write it in `~/.bashrc`.
|
||||
|
||||
Download precompiled [Releases](https://github.com/xtaci/kcptun/releases).
|
||||
|
||||
```
|
||||
@@ -31,7 +39,11 @@ KCP Server: ./server_linux_amd64 -t "TARGET_IP:8388" -l ":4000" -mode fast2
|
||||
```
|
||||
The above commands will establish port forwarding for 8388/tcp as:
|
||||
|
||||
Application -> KCP Client(8388/tcp) -> KCP Server(4000/udp) -> Server(8388/tcp)
|
||||
> Application -> **KCP Client(8388/tcp) -> KCP Server(4000/udp)** -> Target Server(8388/tcp)
|
||||
|
||||
Tunnels the original connection:
|
||||
|
||||
> Application -> Target Server(8388/tcp)
|
||||
|
||||
### Install from source
|
||||
|
||||
@@ -52,7 +64,8 @@ All precompiled releases are genereated from `build-release.sh` script.
|
||||
|
||||
> **Q: I have a high speed network link, how to reach the maximum bandwidth?**
|
||||
|
||||
> **A:** Increase `-rcvwnd` on KCP Client and `-sndwnd` on KCP Server **simultaneously & gradually**, the mininum one decides the maximum transfer rate of the link, as `wnd * mtu / rtt`; Then try downloading something and to see if it meets your requirements.
|
||||
> **A:** Increase `-rcvwnd` on KCP Client and `-sndwnd` on KCP Server **simultaneously & gradually**, the mininum one decides the maximum transfer rate of the link, as `wnd * mtu / rtt`; Then try downloading something and to see if it meets your requirements.
|
||||
(mtu is adjustable by `-mtu`)
|
||||
|
||||
#### Improving Latency
|
||||
|
||||
@@ -154,7 +167,7 @@ It is able to detect and correct multiple symbol errors. By adding t check symbo
|
||||
|
||||

|
||||
|
||||
Setting parameters of RS-Code with ```-datashard m -parityshard n``` on both KCP Client & KCP Server.
|
||||
Setting parameters of RS-Code with ```-datashard m -parityshard n``` on **BOTH** KCP Client & KCP Server **MUST** be **IDENTICAL**.
|
||||
|
||||
#### DSCP
|
||||
|
||||
@@ -212,7 +225,7 @@ kcptun has builtin snappy algorithms for compressing streams:
|
||||
|
||||
Compression may save bandwidth for **PLAINTEXT** data, such as HTTP data.
|
||||
|
||||
Compression is enabled by default, you can disable it by setting ```-nocomp``` on both KCP Client & KCP Server.
|
||||
Compression is enabled by default, you can disable it by setting ```-nocomp``` on **BOTH** KCP Client & KCP Server **MUST** be **IDENTICAL**.
|
||||
|
||||
#### SNMP
|
||||
|
||||
@@ -254,6 +267,17 @@ https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configurati
|
||||
|
||||
Low-level KCP configuration can be altered by using manual mode like above, make sure you really **UNDERSTAND** what these means before doing **ANY** manual settings.
|
||||
|
||||
|
||||
### Identical Parmeters
|
||||
|
||||
The parameters below **MUST** be **IDENTICAL** on **BOTH** side:
|
||||
|
||||
1. -key
|
||||
1. -crypt
|
||||
1. -nocomp
|
||||
1. -datashard
|
||||
1. -parityshard
|
||||
|
||||
### References
|
||||
|
||||
1. https://github.com/skywind3000/kcp -- KCP - A Fast and Reliable ARQ Protocol.
|
||||
@@ -271,3 +295,10 @@ Low-level KCP configuration can be altered by using manual mode like above, make
|
||||
1. http://http2.github.io/ -- What is HTTP/2?
|
||||
1. http://www.lartc.org/ -- Linux Advanced Routing & Traffic Control
|
||||
1. https://en.wikipedia.org/wiki/Noisy-channel_coding_theorem -- Noisy channel coding theorem
|
||||
1. https://play.google.com/store/apps/details?id=com.k17game.k3 -- Battle Zone - Earth 2048, an online strategy game using kcp.
|
||||
|
||||
### Donate via Ethereum(ETH)
|
||||
|
||||
Address: 0x2e4b43ab3d0983da282592571eef61ae5e60f726 , Or scan here:
|
||||
|
||||
<img src="0x2e4b43ab3d0983da282592571eef61ae5e60f726.png" alt="kcptun" height="100px" />
|
||||
|
||||
@@ -32,6 +32,7 @@ type Config struct {
|
||||
Log string `json:"log"`
|
||||
SnmpLog string `json:"snmplog"`
|
||||
SnmpPeriod int `json:"snmpperiod"`
|
||||
Quiet bool `json:"quiet"`
|
||||
}
|
||||
|
||||
func parseJSONConfig(config *Config, path string) error {
|
||||
|
||||
+25
-27
@@ -9,7 +9,6 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
@@ -19,6 +18,8 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
"github.com/xtaci/smux"
|
||||
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -28,11 +29,6 @@ var (
|
||||
SALT = "kcp-go"
|
||||
)
|
||||
|
||||
// global recycle buffer
|
||||
var copyBuf sync.Pool
|
||||
|
||||
const bufSize = 4096
|
||||
|
||||
type compStream struct {
|
||||
conn net.Conn
|
||||
w *snappy.Writer
|
||||
@@ -61,9 +57,12 @@ func newCompStream(conn net.Conn) *compStream {
|
||||
return c
|
||||
}
|
||||
|
||||
func handleClient(sess *smux.Session, p1 io.ReadWriteCloser) {
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
func handleClient(sess *smux.Session, p1 io.ReadWriteCloser, quiet bool) {
|
||||
if !quiet {
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
}
|
||||
|
||||
defer p1.Close()
|
||||
p2, err := sess.OpenStream()
|
||||
if err != nil {
|
||||
@@ -73,20 +72,10 @@ func handleClient(sess *smux.Session, p1 io.ReadWriteCloser) {
|
||||
|
||||
// start tunnel
|
||||
p1die := make(chan struct{})
|
||||
go func() {
|
||||
buf := copyBuf.Get().([]byte)
|
||||
io.CopyBuffer(p1, p2, buf)
|
||||
close(p1die)
|
||||
copyBuf.Put(buf)
|
||||
}()
|
||||
go func() { io.Copy(p1, p2); close(p1die) }()
|
||||
|
||||
p2die := make(chan struct{})
|
||||
go func() {
|
||||
buf := copyBuf.Get().([]byte)
|
||||
io.CopyBuffer(p2, p1, buf)
|
||||
close(p2die)
|
||||
copyBuf.Put(buf)
|
||||
}()
|
||||
go func() { io.Copy(p2, p1); close(p2die) }()
|
||||
|
||||
// wait for tunnel termination
|
||||
select {
|
||||
@@ -104,9 +93,6 @@ func checkError(err error) {
|
||||
|
||||
func main() {
|
||||
rand.Seed(int64(time.Now().Nanosecond()))
|
||||
copyBuf.New = func() interface{} {
|
||||
return make([]byte, bufSize)
|
||||
}
|
||||
if VERSION == "SELFBUILD" {
|
||||
// add more log flags for debugging
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
@@ -135,7 +121,7 @@ func main() {
|
||||
cli.StringFlag{
|
||||
Name: "crypt",
|
||||
Value: "aes",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "mode",
|
||||
@@ -241,6 +227,10 @@ func main() {
|
||||
Value: "",
|
||||
Usage: "specify a log file to output, default goes to stderr",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "to suppress the 'stream open/close' messages",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "c",
|
||||
Value: "", // when the value is not empty, the config path must exists
|
||||
@@ -274,6 +264,7 @@ func main() {
|
||||
config.Log = c.String("log")
|
||||
config.SnmpLog = c.String("snmplog")
|
||||
config.SnmpPeriod = c.Int("snmpperiod")
|
||||
config.Quiet = c.Bool("quiet")
|
||||
|
||||
if c.String("c") != "" {
|
||||
err := parseJSONConfig(&config, c.String("c"))
|
||||
@@ -308,6 +299,8 @@ func main() {
|
||||
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
|
||||
var block kcp.BlockCrypt
|
||||
switch config.Crypt {
|
||||
case "sm4":
|
||||
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
|
||||
case "tea":
|
||||
block, _ = kcp.NewTEABlockCrypt(pass[:16])
|
||||
case "xor":
|
||||
@@ -352,6 +345,7 @@ func main() {
|
||||
log.Println("scavengettl:", config.ScavengeTTL)
|
||||
log.Println("snmplog:", config.SnmpLog)
|
||||
log.Println("snmpperiod:", config.SnmpPeriod)
|
||||
log.Println("quiet:", config.Quiet)
|
||||
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.MaxReceiveBuffer = config.SockBuf
|
||||
@@ -399,6 +393,7 @@ func main() {
|
||||
if session, err := createConn(); err == nil {
|
||||
return session
|
||||
} else {
|
||||
log.Println("re-connecting:", err)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
@@ -434,7 +429,7 @@ func main() {
|
||||
muxes[idx].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
}
|
||||
|
||||
go handleClient(muxes[idx].session, p1)
|
||||
go handleClient(muxes[idx].session, p1, config.Quiet)
|
||||
rr++
|
||||
}
|
||||
}
|
||||
@@ -483,7 +478,10 @@ func snmpLogger(path string, interval int) {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
f, err := os.OpenFile(time.Now().Format(path), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
// split path into dirname and filename
|
||||
logdir, logfile := filepath.Split(path)
|
||||
// only format logfile
|
||||
f, err := os.OpenFile(logdir+time.Now().Format(logfile), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
|
||||
@@ -18,6 +18,7 @@ func init() {
|
||||
func sigHandler() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGUSR1)
|
||||
signal.Ignore(syscall.SIGPIPE)
|
||||
|
||||
for {
|
||||
switch <-ch {
|
||||
|
||||
@@ -30,6 +30,7 @@ type Config struct {
|
||||
SnmpLog string `json:"snmplog"`
|
||||
SnmpPeriod int `json:"snmpperiod"`
|
||||
Pprof bool `json:"pprof"`
|
||||
Quiet bool `json:"quiet"`
|
||||
}
|
||||
|
||||
func parseJSONConfig(config *Config, path string) error {
|
||||
|
||||
+23
-27
@@ -11,11 +11,12 @@ 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"
|
||||
@@ -29,11 +30,6 @@ var (
|
||||
SALT = "kcp-go"
|
||||
)
|
||||
|
||||
// global recycle buffer
|
||||
var copyBuf sync.Pool
|
||||
|
||||
const bufSize = 4096
|
||||
|
||||
type compStream struct {
|
||||
conn net.Conn
|
||||
w *snappy.Writer
|
||||
@@ -87,32 +83,24 @@ func handleMux(conn io.ReadWriteCloser, config *Config) {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
go handleClient(p1, p2)
|
||||
go handleClient(p1, p2, config.Quiet)
|
||||
}
|
||||
}
|
||||
|
||||
func handleClient(p1, p2 io.ReadWriteCloser) {
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
func handleClient(p1, p2 io.ReadWriteCloser, quiet bool) {
|
||||
if !quiet {
|
||||
log.Println("stream opened")
|
||||
defer log.Println("stream closed")
|
||||
}
|
||||
defer p1.Close()
|
||||
defer p2.Close()
|
||||
|
||||
// start tunnel
|
||||
p1die := make(chan struct{})
|
||||
go func() {
|
||||
buf := copyBuf.Get().([]byte)
|
||||
io.CopyBuffer(p1, p2, buf)
|
||||
close(p1die)
|
||||
copyBuf.Put(buf)
|
||||
}()
|
||||
go func() { io.Copy(p1, p2); close(p1die) }()
|
||||
|
||||
p2die := make(chan struct{})
|
||||
go func() {
|
||||
buf := copyBuf.Get().([]byte)
|
||||
io.CopyBuffer(p2, p1, buf)
|
||||
close(p2die)
|
||||
copyBuf.Put(buf)
|
||||
}()
|
||||
go func() { io.Copy(p2, p1); close(p2die) }()
|
||||
|
||||
// wait for tunnel termination
|
||||
select {
|
||||
@@ -130,9 +118,6 @@ func checkError(err error) {
|
||||
|
||||
func main() {
|
||||
rand.Seed(int64(time.Now().Nanosecond()))
|
||||
copyBuf.New = func() interface{} {
|
||||
return make([]byte, bufSize)
|
||||
}
|
||||
if VERSION == "SELFBUILD" {
|
||||
// add more log flags for debugging
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
@@ -161,7 +146,7 @@ func main() {
|
||||
cli.StringFlag{
|
||||
Name: "crypt",
|
||||
Value: "aes",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, none",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "mode",
|
||||
@@ -256,6 +241,10 @@ func main() {
|
||||
Value: "",
|
||||
Usage: "specify a log file to output, default goes to stderr",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "to suppress the 'stream open/close' messages",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "c",
|
||||
Value: "", // when the value is not empty, the config path must exists
|
||||
@@ -287,6 +276,7 @@ func main() {
|
||||
config.SnmpLog = c.String("snmplog")
|
||||
config.SnmpPeriod = c.Int("snmpperiod")
|
||||
config.Pprof = c.Bool("pprof")
|
||||
config.Quiet = c.Bool("quiet")
|
||||
|
||||
if c.String("c") != "" {
|
||||
//Now only support json config file
|
||||
@@ -317,6 +307,8 @@ func main() {
|
||||
pass := pbkdf2.Key([]byte(config.Key), []byte(SALT), 4096, 32, sha1.New)
|
||||
var block kcp.BlockCrypt
|
||||
switch config.Crypt {
|
||||
case "sm4":
|
||||
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
|
||||
case "tea":
|
||||
block, _ = kcp.NewTEABlockCrypt(pass[:16])
|
||||
case "xor":
|
||||
@@ -361,6 +353,7 @@ func main() {
|
||||
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)
|
||||
@@ -409,7 +402,10 @@ func snmpLogger(path string, interval int) {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
f, err := os.OpenFile(time.Now().Format(path), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
// split path into dirname and filename
|
||||
logdir, logfile := filepath.Split(path)
|
||||
// only format logfile
|
||||
f, err := os.OpenFile(logdir+time.Now().Format(logfile), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
|
||||
@@ -18,6 +18,7 @@ func init() {
|
||||
func sigHandler() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGUSR1)
|
||||
signal.Ignore(syscall.SIGPIPE)
|
||||
|
||||
for {
|
||||
switch <-ch {
|
||||
|
||||
Reference in New Issue
Block a user