add kcp config args

Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
This commit is contained in:
arraykeys@gmail.com
2018-03-08 11:51:34 +08:00
parent 70955878c9
commit 5ed4702b62
11 changed files with 198 additions and 49 deletions

View File

@ -2,14 +2,18 @@ package main
import ( import (
"bufio" "bufio"
"crypto/sha1"
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"snail007/proxy/services" "snail007/proxy/services"
"snail007/proxy/services/kcpcfg"
"snail007/proxy/utils" "snail007/proxy/utils"
"time" "time"
kcp "github.com/xtaci/kcp-go"
"golang.org/x/crypto/pbkdf2"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
@ -40,6 +44,7 @@ func initConfig() (err error) {
udpArgs := services.UDPArgs{} udpArgs := services.UDPArgs{}
socksArgs := services.SocksArgs{} socksArgs := services.SocksArgs{}
spsArgs := services.SPSArgs{} spsArgs := services.SPSArgs{}
kcpArgs := kcpcfg.KCPConfigArgs{}
//build srvice args //build srvice args
app = kingpin.New("proxy", "happy with proxy") app = kingpin.New("proxy", "happy with proxy")
app.Author("snail").Version(APP_VERSION) app.Author("snail").Version(APP_VERSION)
@ -47,6 +52,23 @@ func initConfig() (err error) {
daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool() daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool()
forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool() forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String() logfile := app.Flag("log", "log file path").Default("").String()
kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").String()
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast").String()
kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("1350").Int()
kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int()
kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int()
kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int()
kcpArgs.ParityShard = app.Flag("kcp-ps", "set reed-solomon erasure coding - parityshard").Default("3").Int()
kcpArgs.DSCP = app.Flag("kcp-dscp", "set DSCP(6bit)").Default("0").Int()
kcpArgs.NoComp = app.Flag("kcp-nocomp", "disable compression").Default("false").Bool()
kcpArgs.AckNodelay = app.Flag("kcp-acknodelay", "be carefull! flush ack immediately when a packet is received").Default("true").Bool()
kcpArgs.NoDelay = app.Flag("kcp-nodelay", "be carefull!").Default("0").Int()
kcpArgs.Interval = app.Flag("kcp-interval", "be carefull!").Default("50").Int()
kcpArgs.Resend = app.Flag("kcp-resend", "be carefull!").Default("0").Int()
kcpArgs.NoCongestion = app.Flag("kcp-nc", "be carefull! no congestion").Default("0").Int()
kcpArgs.SockBuf = app.Flag("kcp-sockbuf", "be carefull!").Default("4194304").Int()
kcpArgs.KeepAlive = app.Flag("kcp-keepalive", "be carefull!").Default("10").Int()
//########http######### //########http#########
http := app.Command("http", "proxy on http mode") http := app.Command("http", "proxy on http mode")
@ -70,8 +92,6 @@ func initConfig() (err error) {
httpArgs.SSHKeyFile = http.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String() httpArgs.SSHKeyFile = http.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
httpArgs.SSHKeyFileSalt = http.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String() httpArgs.SSHKeyFileSalt = http.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String()
httpArgs.SSHPassword = http.Flag("ssh-password", "password for ssh").Short('A').Default("").String() httpArgs.SSHPassword = http.Flag("ssh-password", "password for ssh").Short('A').Default("").String()
httpArgs.KCPKey = http.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
httpArgs.KCPMethod = http.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
httpArgs.LocalIPS = http.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings() httpArgs.LocalIPS = http.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
httpArgs.AuthURL = http.Flag("auth-url", "http basic auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String() httpArgs.AuthURL = http.Flag("auth-url", "http basic auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
httpArgs.AuthURLTimeout = http.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int() httpArgs.AuthURLTimeout = http.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
@ -91,8 +111,6 @@ func initConfig() (err error) {
tcpArgs.PoolSize = tcp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() tcpArgs.PoolSize = tcp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
tcpArgs.KCPKey = tcp.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
tcpArgs.KCPMethod = tcp.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
//########udp######### //########udp#########
udp := app.Command("udp", "proxy on udp mode") udp := app.Command("udp", "proxy on udp mode")
@ -178,8 +196,6 @@ func initConfig() (err error) {
socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String() socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
socksArgs.AuthFile = socks.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String() socksArgs.AuthFile = socks.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
socksArgs.Auth = socks.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings() socksArgs.Auth = socks.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
socksArgs.KCPKey = socks.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
socksArgs.KCPMethod = socks.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
socksArgs.LocalIPS = socks.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings() socksArgs.LocalIPS = socks.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
socksArgs.AuthURL = socks.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String() socksArgs.AuthURL = socks.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
socksArgs.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int() socksArgs.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
@ -196,14 +212,56 @@ func initConfig() (err error) {
spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp") spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String() spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
spsArgs.KCPKey = sps.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
spsArgs.KCPMethod = sps.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks") spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String() spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int() spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
//parse args //parse args
serviceName := kingpin.MustParse(app.Parse(os.Args[1:])) serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
//set kcp config
switch *kcpArgs.Mode {
case "normal":
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 40, 2, 1
case "fast":
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 30, 2, 1
case "fast2":
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 20, 2, 1
case "fast3":
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 10, 2, 1
}
pass := pbkdf2.Key([]byte(*kcpArgs.Key), []byte("snail007-goproxy"), 4096, 32, sha1.New)
switch *kcpArgs.Crypt {
case "sm4":
kcpArgs.Block, _ = kcp.NewSM4BlockCrypt(pass[:16])
case "tea":
kcpArgs.Block, _ = kcp.NewTEABlockCrypt(pass[:16])
case "xor":
kcpArgs.Block, _ = kcp.NewSimpleXORBlockCrypt(pass)
case "none":
kcpArgs.Block, _ = kcp.NewNoneBlockCrypt(pass)
case "aes-128":
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:16])
case "aes-192":
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:24])
case "blowfish":
kcpArgs.Block, _ = kcp.NewBlowfishBlockCrypt(pass)
case "twofish":
kcpArgs.Block, _ = kcp.NewTwofishBlockCrypt(pass)
case "cast5":
kcpArgs.Block, _ = kcp.NewCast5BlockCrypt(pass[:16])
case "3des":
kcpArgs.Block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
case "xtea":
kcpArgs.Block, _ = kcp.NewXTEABlockCrypt(pass[:16])
case "salsa20":
kcpArgs.Block, _ = kcp.NewSalsa20BlockCrypt(pass)
default:
*kcpArgs.Crypt = "aes"
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass)
}
flags := log.Ldate flags := log.Ldate
if *debug { if *debug {
flags |= log.Lshortfile | log.Lmicroseconds flags |= log.Lshortfile | log.Lmicroseconds

View File

@ -1,6 +1,10 @@
package services package services
import "golang.org/x/crypto/ssh" import (
"snail007/proxy/services/kcpcfg"
"golang.org/x/crypto/ssh"
)
// tcp := app.Command("tcp", "proxy on tcp mode") // tcp := app.Command("tcp", "proxy on tcp mode")
// t := tcp.Flag("tcp-timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int() // t := tcp.Flag("tcp-timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int()
@ -102,8 +106,7 @@ type TCPArgs struct {
Timeout *int Timeout *int
PoolSize *int PoolSize *int
CheckParentInterval *int CheckParentInterval *int
KCPMethod *string KCP kcpcfg.KCPConfigArgs
KCPKey *string
} }
type HTTPArgs struct { type HTTPArgs struct {
@ -135,8 +138,7 @@ type HTTPArgs struct {
SSHUser *string SSHUser *string
SSHKeyBytes []byte SSHKeyBytes []byte
SSHAuthMethod ssh.AuthMethod SSHAuthMethod ssh.AuthMethod
KCPMethod *string KCP kcpcfg.KCPConfigArgs
KCPKey *string
LocalIPS *[]string LocalIPS *[]string
DNSAddress *string DNSAddress *string
DNSTTL *int DNSTTL *int
@ -179,8 +181,7 @@ type SocksArgs struct {
AuthURLOkCode *int AuthURLOkCode *int
AuthURLTimeout *int AuthURLTimeout *int
AuthURLRetry *int AuthURLRetry *int
KCPMethod *string KCP kcpcfg.KCPConfigArgs
KCPKey *string
UDPParent *string UDPParent *string
UDPLocal *string UDPLocal *string
LocalIPS *[]string LocalIPS *[]string
@ -197,8 +198,7 @@ type SPSArgs struct {
ParentType *string ParentType *string
LocalType *string LocalType *string
Timeout *int Timeout *int
KCPMethod *string KCP kcpcfg.KCPConfigArgs
KCPKey *string
ParentServiceType *string ParentServiceType *string
DNSAddress *string DNSAddress *string
DNSTTL *int DNSTTL *int

View File

@ -130,7 +130,7 @@ func (s *HTTP) Start(args interface{}) (err error) {
} else if *s.cfg.LocalType == TYPE_TLS { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback) err = sc.ListenKCP(s.cfg.KCP, s.callback)
} }
if err != nil { if err != nil {
return return
@ -320,8 +320,7 @@ func (s *HTTP) InitOutConnPool() {
s.outPool = utils.NewOutPool( s.outPool = utils.NewOutPool(
*s.cfg.CheckParentInterval, *s.cfg.CheckParentInterval,
*s.cfg.ParentType, *s.cfg.ParentType,
*s.cfg.KCPMethod, s.cfg.KCP,
*s.cfg.KCPKey,
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CertBytes, s.cfg.KeyBytes,
s.Resolve(*s.cfg.Parent), s.Resolve(*s.cfg.Parent),
*s.cfg.Timeout, *s.cfg.Timeout,

24
services/kcpcfg/args.go Normal file
View File

@ -0,0 +1,24 @@
package kcpcfg
import kcp "github.com/xtaci/kcp-go"
type KCPConfigArgs struct {
Key *string
Crypt *string
Mode *string
MTU *int
SndWnd *int
RcvWnd *int
DataShard *int
ParityShard *int
DSCP *int
NoComp *bool
AckNodelay *bool
NoDelay *int
Interval *int
Resend *int
NoCongestion *int
SockBuf *int
KeepAlive *int
Block kcp.BlockCrypt
}

View File

@ -140,7 +140,7 @@ func (s *Socks) Start(args interface{}) (err error) {
} else if *s.cfg.LocalType == TYPE_TLS { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.socksConnCallback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.socksConnCallback)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.socksConnCallback) err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback)
} }
if err != nil { if err != nil {
return return
@ -474,7 +474,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
_outConn, err = utils.TlsConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes) _outConn, err = utils.TlsConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
outConn = net.Conn(&_outConn) outConn = net.Conn(&_outConn)
} else if *s.cfg.ParentType == "kcp" { } else if *s.cfg.ParentType == "kcp" {
outConn, err = utils.ConnectKCPHost(s.Resolve(*s.cfg.Parent), *s.cfg.KCPMethod, *s.cfg.KCPKey) outConn, err = utils.ConnectKCPHost(s.Resolve(*s.cfg.Parent), s.cfg.KCP)
} else { } else {
outConn, err = utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout) outConn, err = utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout)
} }

View File

@ -46,8 +46,7 @@ func (s *SPS) InitOutConnPool() {
s.outPool = utils.NewOutPool( s.outPool = utils.NewOutPool(
0, 0,
*s.cfg.ParentType, *s.cfg.ParentType,
*s.cfg.KCPMethod, s.cfg.KCP,
*s.cfg.KCPKey,
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CertBytes, s.cfg.KeyBytes,
*s.cfg.Parent, *s.cfg.Parent,
*s.cfg.Timeout, *s.cfg.Timeout,
@ -78,7 +77,7 @@ func (s *SPS) Start(args interface{}) (err error) {
} else if *s.cfg.LocalType == TYPE_TLS { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback) err = sc.ListenKCP(s.cfg.KCP, s.callback)
} }
if err != nil { if err != nil {
return return

View File

@ -58,7 +58,7 @@ func (s *TCP) Start(args interface{}) (err error) {
} else if *s.cfg.LocalType == TYPE_TLS { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback) err = sc.ListenKCP(s.cfg.KCP, s.callback)
} }
if err != nil { if err != nil {
return return
@ -171,8 +171,7 @@ func (s *TCP) InitOutConnPool() {
s.outPool = utils.NewOutPool( s.outPool = utils.NewOutPool(
*s.cfg.CheckParentInterval, *s.cfg.CheckParentInterval,
*s.cfg.ParentType, *s.cfg.ParentType,
*s.cfg.KCPMethod, s.cfg.KCP,
*s.cfg.KCPKey,
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CertBytes, s.cfg.KeyBytes,
*s.cfg.Parent, *s.cfg.Parent,
*s.cfg.Timeout, *s.cfg.Timeout,

View File

@ -8,6 +8,7 @@ import (
"log" "log"
"net" "net"
"runtime/debug" "runtime/debug"
"snail007/proxy/services/kcpcfg"
"snail007/proxy/utils" "snail007/proxy/utils"
"strconv" "strconv"
"strings" "strings"
@ -208,7 +209,7 @@ func (s *UDP) InitOutConnPool() {
s.outPool = utils.NewOutPool( s.outPool = utils.NewOutPool(
*s.cfg.CheckParentInterval, *s.cfg.CheckParentInterval,
*s.cfg.ParentType, *s.cfg.ParentType,
"", "", kcpcfg.KCPConfigArgs{},
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CertBytes, s.cfg.KeyBytes,
*s.cfg.Parent, *s.cfg.Parent,
*s.cfg.Timeout, *s.cfg.Timeout,

View File

@ -18,6 +18,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"snail007/proxy/services/kcpcfg"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
@ -147,17 +148,23 @@ func ConnectHost(hostAndPort string, timeout int) (conn net.Conn, err error) {
conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond) conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond)
return return
} }
func ConnectKCPHost(hostAndPort, method, key string) (conn net.Conn, err error) { func ConnectKCPHost(hostAndPort string, config kcpcfg.KCPConfigArgs) (conn net.Conn, err error) {
kcpconn, err := kcp.DialWithOptions(hostAndPort, GetKCPBlock(method, key), 10, 3) kcpconn, err := kcp.DialWithOptions(hostAndPort, config.Block, *config.DataShard, *config.ParityShard)
if err != nil { if err != nil {
return return
} }
kcpconn.SetNoDelay(1, 10, 2, 1) kcpconn.SetStreamMode(true)
kcpconn.SetWindowSize(1024, 1024) kcpconn.SetWriteDelay(true)
kcpconn.SetMtu(1400) kcpconn.SetNoDelay(*config.NoDelay, *config.Interval, *config.Resend, *config.NoCongestion)
kcpconn.SetACKNoDelay(false) kcpconn.SetMtu(*config.MTU)
kcpconn.SetWindowSize(*config.SndWnd, *config.RcvWnd)
kcpconn.SetACKNoDelay(*config.AckNodelay)
if *config.NoComp {
return kcpconn, err return kcpconn, err
}
return NewCompStream(kcpconn), err
} }
func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listener, err error) { func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listener, err error) {
block, _ := pem.Decode(certBytes) block, _ := pem.Decode(certBytes)
if block == nil { if block == nil {

View File

@ -5,6 +5,7 @@ import (
"log" "log"
"net" "net"
"runtime/debug" "runtime/debug"
"snail007/proxy/services/kcpcfg"
"strconv" "strconv"
kcp "github.com/xtaci/kcp-go" kcp "github.com/xtaci/kcp-go"
@ -138,11 +139,19 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
} }
return return
} }
func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (err error) { func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn)) (err error) {
var l net.Listener lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard)
l, err = kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), GetKCPBlock(method, key), 10, 3)
if err == nil { if err == nil {
sc.Listener = &l 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)
}
*sc.Listener = lis
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
@ -150,8 +159,8 @@ func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (
} }
}() }()
for { for {
var conn net.Conn //var conn net.Conn
conn, err = (*sc.Listener).Accept() conn, err := lis.AcceptKCP()
if err == nil { if err == nil {
go func() { go func() {
defer func() { defer func() {
@ -159,7 +168,18 @@ func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (
log.Printf("kcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) log.Printf("kcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
} }
}() }()
conn.SetStreamMode(true)
conn.SetWriteDelay(true)
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 {
fn(conn) fn(conn)
} else {
cconn := NewCompStream(conn)
fn(cconn)
}
}() }()
} else { } else {
sc.errAcceptHandler(err) sc.errAcceptHandler(err)

View File

@ -12,11 +12,13 @@ import (
"log" "log"
"net" "net"
"net/url" "net/url"
"snail007/proxy/services/kcpcfg"
"snail007/proxy/utils/sni" "snail007/proxy/utils/sni"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/golang/snappy"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@ -494,20 +496,18 @@ type OutPool struct {
typ string typ string
certBytes []byte certBytes []byte
keyBytes []byte keyBytes []byte
kcpMethod string kcp kcpcfg.KCPConfigArgs
kcpKey string
address string address string
timeout int timeout int
} }
func NewOutPool(dur int, typ, kcpMethod, kcpKey string, certBytes, keyBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) { func NewOutPool(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) {
op = OutPool{ op = OutPool{
dur: dur, dur: dur,
typ: typ, typ: typ,
certBytes: certBytes, certBytes: certBytes,
keyBytes: keyBytes, keyBytes: keyBytes,
kcpMethod: kcpMethod, kcp: kcp,
kcpKey: kcpKey,
address: address, address: address,
timeout: timeout, timeout: timeout,
} }
@ -548,7 +548,7 @@ func (op *OutPool) getConn() (conn interface{}, err error) {
conn = net.Conn(&_conn) conn = net.Conn(&_conn)
} }
} else if op.typ == "kcp" { } else if op.typ == "kcp" {
conn, err = ConnectKCPHost(op.address, op.kcpMethod, op.kcpKey) conn, err = ConnectKCPHost(op.address, op.kcp)
} else { } else {
conn, err = ConnectHost(op.address, op.timeout) conn, err = ConnectHost(op.address, op.timeout)
} }
@ -924,3 +924,45 @@ func (a *DomainResolver) PrintData() {
fmt.Printf("%s:ip[%s],domain[%s],expired at[%d]\n", k, (*d).ip, (*d).domain, (*d).expiredAt) fmt.Printf("%s:ip[%s],domain[%s],expired at[%d]\n", k, (*d).ip, (*d).domain, (*d).expiredAt)
} }
} }
func NewCompStream(conn net.Conn) *CompStream {
c := new(CompStream)
c.conn = conn
c.w = snappy.NewBufferedWriter(conn)
c.r = snappy.NewReader(conn)
return c
}
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 (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)
}