Add compress and encryt support on (tcp|tls|kcp) transport layer
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
This commit is contained in:
@ -8,6 +8,11 @@ v4.7
|
||||
5.优化了所有服务代码,方便对sdk提供支持.
|
||||
6.增加了SDK手册.
|
||||
7.增加了GUI客户端(windows/web/android/ios)介绍主页.
|
||||
8.SPS\HTTP(s)\Socks代理增加了自定义加密传输,只需要通过参数-z和-Z设置一个密码即可.
|
||||
9.SPS\HTTP(s)\Socks代理增加了压缩传输,只需要通过参数-m和-M设置即可.
|
||||
10.手册增加了SPS\HTTP(s)\Socks自定义加密的使用示例.
|
||||
11.手册增加了SPS\HTTP(s)\Socks压缩传输的使用示例.
|
||||
|
||||
|
||||
v4.6
|
||||
1.sps,http(s),socks5,内网穿透都做了大量的超时优化处理,更加稳定.
|
||||
|
||||
14
config.go
14
config.go
@ -99,6 +99,10 @@ func initConfig() (err error) {
|
||||
httpArgs.AuthURLRetry = http.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("1").Int()
|
||||
httpArgs.DNSAddress = http.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
httpArgs.DNSTTL = http.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
httpArgs.LocalKey = http.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//########tcp#########
|
||||
tcp := app.Command("tcp", "proxy on tcp mode")
|
||||
@ -207,6 +211,11 @@ func initConfig() (err error) {
|
||||
socksArgs.AuthURLRetry = socks.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||
socksArgs.DNSAddress = socks.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
socksArgs.DNSTTL = socks.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
socksArgs.LocalKey = socks.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//########socks+http(s)#########
|
||||
sps := app.Command("sps", "proxy on socks+http(s) mode")
|
||||
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
@ -228,6 +237,11 @@ func initConfig() (err error) {
|
||||
spsArgs.AuthURLOkCode = sps.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||
spsArgs.AuthURLRetry = sps.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||
spsArgs.ParentAuth = sps.Flag("parent-auth", "parent socks auth username and password, such as: -A user1:pass1").Short('A').String()
|
||||
spsArgs.LocalKey = sps.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//parse args
|
||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||
|
||||
|
||||
14
sdk/sdk.go
14
sdk/sdk.go
@ -94,6 +94,10 @@ func Start(argsStr string) (errStr string) {
|
||||
httpArgs.AuthURLRetry = http.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("1").Int()
|
||||
httpArgs.DNSAddress = http.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
httpArgs.DNSTTL = http.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
httpArgs.LocalKey = http.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//########tcp#########
|
||||
tcp := app.Command("tcp", "proxy on tcp mode")
|
||||
@ -202,6 +206,11 @@ func Start(argsStr string) (errStr string) {
|
||||
socksArgs.AuthURLRetry = socks.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||
socksArgs.DNSAddress = socks.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||
socksArgs.DNSTTL = socks.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||
socksArgs.LocalKey = socks.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//########socks+http(s)#########
|
||||
sps := app.Command("sps", "proxy on socks+http(s) mode")
|
||||
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
@ -223,6 +232,11 @@ func Start(argsStr string) (errStr string) {
|
||||
spsArgs.AuthURLOkCode = sps.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||
spsArgs.AuthURLRetry = sps.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||
spsArgs.ParentAuth = sps.Flag("parent-auth", "parent socks auth username and password, such as: -A user1:pass1").Short('A').String()
|
||||
spsArgs.LocalKey = sps.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||
|
||||
//parse args
|
||||
_args := strings.Fields(strings.Trim(argsStr, " "))
|
||||
args := []string{}
|
||||
|
||||
@ -149,6 +149,10 @@ type HTTPArgs struct {
|
||||
LocalIPS *[]string
|
||||
DNSAddress *string
|
||||
DNSTTL *int
|
||||
LocalKey *string
|
||||
ParentKey *string
|
||||
LocalCompress *bool
|
||||
ParentCompress *bool
|
||||
}
|
||||
type UDPArgs struct {
|
||||
Parent *string
|
||||
@ -195,6 +199,10 @@ type SocksArgs struct {
|
||||
LocalIPS *[]string
|
||||
DNSAddress *string
|
||||
DNSTTL *int
|
||||
LocalKey *string
|
||||
ParentKey *string
|
||||
LocalCompress *bool
|
||||
ParentCompress *bool
|
||||
}
|
||||
type SPSArgs struct {
|
||||
Parent *string
|
||||
@ -220,6 +228,10 @@ type SPSArgs struct {
|
||||
AuthURLRetry *int
|
||||
LocalIPS *[]string
|
||||
ParentAuth *string
|
||||
LocalKey *string
|
||||
ParentKey *string
|
||||
LocalCompress *bool
|
||||
ParentCompress *bool
|
||||
}
|
||||
|
||||
func (a *SPSArgs) Protocol() string {
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"snail007/proxy/utils"
|
||||
"snail007/proxy/utils/conncrypt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -201,6 +202,14 @@ func (s *HTTP) callback(inConn net.Conn) {
|
||||
log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
if *s.cfg.LocalCompress {
|
||||
inConn = utils.NewCompConn(inConn)
|
||||
}
|
||||
if *s.cfg.LocalKey != "" {
|
||||
inConn = conncrypt.New(inConn, &conncrypt.Config{
|
||||
Password: *s.cfg.LocalKey,
|
||||
})
|
||||
}
|
||||
var err interface{}
|
||||
var req utils.HTTPRequest
|
||||
req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth)
|
||||
@ -280,6 +289,15 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentCompress {
|
||||
outConn = utils.NewCompConn(outConn)
|
||||
}
|
||||
if *s.cfg.ParentKey != "" {
|
||||
outConn = conncrypt.New(outConn, &conncrypt.Config{
|
||||
Password: *s.cfg.ParentKey,
|
||||
})
|
||||
}
|
||||
|
||||
outAddr := outConn.RemoteAddr().String()
|
||||
//outLocalAddr := outConn.LocalAddr().String()
|
||||
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"runtime/debug"
|
||||
"snail007/proxy/utils"
|
||||
"snail007/proxy/utils/aes"
|
||||
"snail007/proxy/utils/conncrypt"
|
||||
"snail007/proxy/utils/socks"
|
||||
"strings"
|
||||
"time"
|
||||
@ -361,6 +362,14 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
inConn.Close()
|
||||
}
|
||||
}()
|
||||
if *s.cfg.LocalCompress {
|
||||
inConn = utils.NewCompConn(inConn)
|
||||
}
|
||||
if *s.cfg.LocalKey != "" {
|
||||
inConn = conncrypt.New(inConn, &conncrypt.Config{
|
||||
Password: *s.cfg.LocalKey,
|
||||
})
|
||||
}
|
||||
//协商开始
|
||||
|
||||
//method select request
|
||||
@ -521,6 +530,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
||||
request.TCPReply(socks.REP_NETWOR_UNREACHABLE)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("use proxy %v : %s", useProxy, request.Addr())
|
||||
|
||||
request.TCPReply(socks.REP_SUCCESS)
|
||||
@ -557,6 +567,14 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
err = fmt.Errorf("connect fail,%s", err)
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentCompress {
|
||||
outConn = utils.NewCompConn(outConn)
|
||||
}
|
||||
if *s.cfg.ParentKey != "" {
|
||||
outConn = conncrypt.New(outConn, &conncrypt.Config{
|
||||
Password: *s.cfg.ParentKey,
|
||||
})
|
||||
}
|
||||
var buf = make([]byte, 1024)
|
||||
//var n int
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"snail007/proxy/utils"
|
||||
"snail007/proxy/utils/conncrypt"
|
||||
"snail007/proxy/utils/socks"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -142,6 +143,14 @@ func (s *SPS) callback(inConn net.Conn) {
|
||||
log.Printf("%s conn handler crashed with err : %s \nstack: %s", s.cfg.Protocol(), err, string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
if *s.cfg.LocalCompress {
|
||||
inConn = utils.NewCompConn(inConn)
|
||||
}
|
||||
if *s.cfg.LocalKey != "" {
|
||||
inConn = conncrypt.New(inConn, &conncrypt.Config{
|
||||
Password: *s.cfg.LocalKey,
|
||||
})
|
||||
}
|
||||
var err error
|
||||
switch *s.cfg.ParentType {
|
||||
case TYPE_KCP:
|
||||
@ -232,7 +241,14 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
|
||||
if *s.cfg.ParentCompress {
|
||||
outConn = utils.NewCompConn(outConn)
|
||||
}
|
||||
if *s.cfg.ParentKey != "" {
|
||||
outConn = conncrypt.New(outConn, &conncrypt.Config{
|
||||
Password: *s.cfg.ParentKey,
|
||||
})
|
||||
}
|
||||
//ask parent for connect to target address
|
||||
if *s.cfg.ParentServiceType == "http" {
|
||||
//http parent
|
||||
|
||||
95
utils/conncrypt/conncrypt.go
Normal file
95
utils/conncrypt/conncrypt.go
Normal file
@ -0,0 +1,95 @@
|
||||
package conncrypt
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/sha256"
|
||||
"hash"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
//Confg defaults
|
||||
const DefaultIterations = 2048
|
||||
const DefaultKeySize = 32 //256bits
|
||||
var DefaultHashFunc = sha256.New
|
||||
var DefaultSalt = []byte(`
|
||||
(;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T}
|
||||
Ao<:>SOd,6acYKY_ec+(x"R";\'4&fTAVu92GVA-wxBptOTM^2,iP5%)wnhW
|
||||
hwk=]Snsgymt!3gbP2pe=J//}1a?lp9ej=&TB!C_V(cT2?z8wyoL_-13fd[]
|
||||
`) //salt must be predefined in order to derive the same key
|
||||
|
||||
//Config stores the PBKDF2 key generation parameters
|
||||
type Config struct {
|
||||
Password string
|
||||
Salt []byte
|
||||
Iterations int
|
||||
KeySize int
|
||||
HashFunc func() hash.Hash
|
||||
}
|
||||
|
||||
//New creates an AES encrypted net.Conn by generating
|
||||
//a key using PBKDF2 with the provided configuration
|
||||
func New(conn net.Conn, c *Config) net.Conn {
|
||||
//set defaults
|
||||
if len(c.Salt) == 0 {
|
||||
c.Salt = DefaultSalt
|
||||
}
|
||||
if c.Iterations == 0 {
|
||||
c.Iterations = DefaultIterations
|
||||
}
|
||||
if c.KeySize != 16 && c.KeySize != 24 && c.KeySize != 32 {
|
||||
c.KeySize = DefaultKeySize
|
||||
}
|
||||
if c.HashFunc == nil {
|
||||
c.HashFunc = DefaultHashFunc
|
||||
}
|
||||
|
||||
//generate key
|
||||
key := pbkdf2.Key([]byte(c.Password), c.Salt, c.Iterations, c.KeySize, c.HashFunc)
|
||||
|
||||
// could use scrypt, but it's a bit slow...
|
||||
// dk, err := scrypt.Key([]byte(c.Password), c.Salt, 16384, 8, 1, 32)
|
||||
|
||||
//key will be always be the correct size so this will never error
|
||||
conn, _ = NewFromKey(conn, key)
|
||||
return conn
|
||||
}
|
||||
|
||||
//NewFromKey creates an AES encrypted net.Conn using the provided key
|
||||
func NewFromKey(conn net.Conn, key []byte) (net.Conn, error) {
|
||||
block, err := aes.NewCipher([]byte(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//hash(key) -> read IV
|
||||
riv := DefaultHashFunc().Sum(key)
|
||||
rstream := cipher.NewCFBDecrypter(block, riv[:aes.BlockSize])
|
||||
reader := &cipher.StreamReader{S: rstream, R: conn}
|
||||
//hash(read IV) -> write IV
|
||||
wiv := DefaultHashFunc().Sum(riv)
|
||||
wstream := cipher.NewCFBEncrypter(block, wiv[:aes.BlockSize])
|
||||
writer := &cipher.StreamWriter{S: wstream, W: conn}
|
||||
|
||||
return &cryptoConn{
|
||||
Conn: conn,
|
||||
r: reader,
|
||||
w: writer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type cryptoConn struct {
|
||||
net.Conn
|
||||
r io.Reader
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
//replace read and write methods
|
||||
func (c *cryptoConn) Read(p []byte) (int, error) {
|
||||
return c.r.Read(p)
|
||||
}
|
||||
func (c *cryptoConn) Write(p []byte) (int, error) {
|
||||
return c.w.Write(p)
|
||||
}
|
||||
@ -749,8 +749,16 @@ func NewCompStream(conn net.Conn) *CompStream {
|
||||
c.r = snappy.NewReader(conn)
|
||||
return c
|
||||
}
|
||||
func NewCompConn(conn net.Conn) net.Conn {
|
||||
c := CompStream{}
|
||||
c.conn = conn
|
||||
c.w = snappy.NewBufferedWriter(conn)
|
||||
c.r = snappy.NewReader(conn)
|
||||
return &c
|
||||
}
|
||||
|
||||
type CompStream struct {
|
||||
net.Conn
|
||||
conn net.Conn
|
||||
w *snappy.Writer
|
||||
r *snappy.Reader
|
||||
|
||||
Reference in New Issue
Block a user