Skip to content

Commit

Permalink
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
Browse files Browse the repository at this point in the history
  • Loading branch information
snail007 committed Oct 25, 2017
1 parent 581ff2b commit b7c2b0e
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 86 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
proxy更新日志
v3.4
1.socks5代理新增了用户名密码验证支持.
2.socks5,http(s)代理增加了kcp传输协议支持.
3.优化了内网穿透的心跳机制.

v3.3
1.修复了socks代理模式对证书文件的判断逻辑.
Expand Down
15 changes: 11 additions & 4 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ func initConfig() (err error) {
httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
httpArgs.CertFile = http.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
httpArgs.KeyFile = http.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
httpArgs.LocalType = http.Flag("local-type", "local protocol type <tls|tcp>").Default("tcp").Short('t').Enum("tls", "tcp")
httpArgs.ParentType = http.Flag("parent-type", "parent protocol type <tls|tcp|ssh>").Short('T').Enum("tls", "tcp", "ssh")
httpArgs.LocalType = http.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
httpArgs.ParentType = http.Flag("parent-type", "parent protocol type <tls|tcp|ssh|kcp>").Short('T').Enum("tls", "tcp", "ssh", "kcp")
httpArgs.Always = http.Flag("always", "always use parent proxy").Default("false").Bool()
httpArgs.Timeout = http.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int()
httpArgs.HTTPTimeout = http.Flag("http-timeout", "check domain if blocked , http request timeout milliseconds when connect to host").Default("3000").Int()
Expand All @@ -58,6 +58,8 @@ func initConfig() (err error) {
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.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()

//########tcp#########
tcp := app.Command("tcp", "proxy on tcp mode")
Expand Down Expand Up @@ -110,9 +112,11 @@ func initConfig() (err error) {
//########ssh#########
socks := app.Command("socks", "proxy on ssh mode")
socksArgs.Parent = socks.Flag("parent", "parent ssh address, such as: \"23.32.32.19:22\"").Default("").Short('P').String()
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "ssh")
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp>").Default("tcp").Short('t').Enum("tls", "tcp")
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
socksArgs.SSHUser = socks.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
Expand All @@ -126,6 +130,9 @@ func initConfig() (err error) {
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.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()

//parse args
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
flags := log.Ldate
Expand Down
7 changes: 7 additions & 0 deletions services/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
TYPE_UDP = "udp"
TYPE_HTTP = "http"
TYPE_TLS = "tls"
TYPE_KCP = "kcp"
CONN_CLIENT_CONTROL = uint8(1)
CONN_SERVER_CONTROL = uint8(2)
CONN_SERVER = uint8(3)
Expand Down Expand Up @@ -87,6 +88,8 @@ type HTTPArgs struct {
SSHUser *string
SSHKeyBytes []byte
SSHAuthMethod ssh.AuthMethod
KCPMethod *string
KCPKey *string
}
type UDPArgs struct {
Parent *string
Expand Down Expand Up @@ -122,6 +125,10 @@ type SocksArgs struct {
Direct *string
AuthFile *string
Auth *[]string
KCPMethod *string
KCPKey *string
UDPParent *string
UDPLocal *string
}

func (a *TCPArgs) Protocol() string {
Expand Down
11 changes: 8 additions & 3 deletions services/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,10 @@ func (s *HTTP) Start(args interface{}) (err error) {
sc := utils.NewServerChannel(host, p)
if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.callback)
} else {
} else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback)
}
if err != nil {
return
Expand Down Expand Up @@ -197,6 +199,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
if *s.cfg.ParentType == "ssh" {
outConn, err = s.getSSHConn(address)
} else {
//log.Printf("%v", s.outPool)
_outConn, err = s.outPool.Pool.Get()
if err == nil {
outConn = _outConn.(net.Conn)
Expand Down Expand Up @@ -303,12 +306,14 @@ func (s *HTTP) ConnectSSH() (err error) {
return
}
func (s *HTTP) InitOutConnPool() {
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP {
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
//dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool(
*s.cfg.CheckParentInterval,
*s.cfg.ParentType == TYPE_TLS,
*s.cfg.ParentType,
*s.cfg.KCPMethod,
*s.cfg.KCPKey,
s.cfg.CertBytes, s.cfg.KeyBytes,
*s.cfg.Parent,
*s.cfg.Timeout,
Expand Down
23 changes: 16 additions & 7 deletions services/socks.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ func (s *Socks) InitService() {
if *s.cfg.ParentType == "ssh" {
log.Println("warn: socks udp not suppored for ssh")
} else {
_, port, _ := net.SplitHostPort(*s.cfg.Local)
s.udpSC = utils.NewServerChannelHost(":" + port)

s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal)
err := s.udpSC.ListenUDP(s.udpCallback)
if err != nil {
log.Fatalf("init udp service fail, ERR: %s", err)
Expand All @@ -133,8 +133,10 @@ func (s *Socks) Start(args interface{}) (err error) {
sc := utils.NewServerChannelHost(*s.cfg.Local)
if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.socksConnCallback)
} else {
} else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.socksConnCallback)
} else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.socksConnCallback)
}
if err != nil {
return
Expand Down Expand Up @@ -176,7 +178,11 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
return
}
}
dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent)
parent := *s.cfg.UDPParent
if parent == "" {
parent = *s.cfg.Parent
}
dstAddr, err := net.ResolveUDPAddr("udp", parent)
if err != nil {
log.Printf("can't resolve address: %s", err)
return
Expand Down Expand Up @@ -382,7 +388,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
}
host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
_, port, _ := net.SplitHostPort(s.udpSC.UDPListener.LocalAddr().String())
// log.Printf("proxy udp on %s", net.JoinHostPort(host, port))
log.Printf("proxy udp on %s", net.JoinHostPort(host, port))
request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port))
}
func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
Expand Down Expand Up @@ -428,22 +434,25 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
inLocalAddr := (*inConn).LocalAddr().String()

log.Printf("conn %s - %s connected [%s]", inAddr, inLocalAddr, request.Addr())
utils.IoBind0(*inConn, outConn, func(err error) {
utils.IoBind(*inConn, outConn, func(err error) {
log.Printf("conn %s - %s released [%s]", inAddr, inLocalAddr, request.Addr())
utils.CloseConn(inConn)
utils.CloseConn(&outConn)
})
//}, func(i int, b bool) {}, 0)
}
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) {
switch *s.cfg.ParentType {
case "kcp":
fallthrough
case "tls":
fallthrough
case "tcp":
if *s.cfg.ParentType == "tls" {
var _outConn tls.Conn
_outConn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
outConn = net.Conn(&_outConn)
} else if *s.cfg.ParentType == "kcp" {
outConn, err = utils.ConnectKCPHost(*s.cfg.Parent, *s.cfg.KCPMethod, *s.cfg.KCPKey)
} else {
outConn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
}
Expand Down
3 changes: 2 additions & 1 deletion services/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ func (s *TCP) InitOutConnPool() {
//parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool(
*s.cfg.CheckParentInterval,
*s.cfg.ParentType == TYPE_TLS,
*s.cfg.ParentType,
"", "",
s.cfg.CertBytes, s.cfg.KeyBytes,
*s.cfg.Parent,
*s.cfg.Timeout,
Expand Down
4 changes: 2 additions & 2 deletions services/tunnel_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
_, err = inConn.Write([]byte{0x00})
inConn.SetWriteDeadline(time.Time{})
if err != nil {
log.Printf("control connection write err %s", err)
log.Printf("server control connection write err %s", err)
break
}
time.Sleep(time.Second * 3)
Expand All @@ -181,7 +181,7 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
_, err := inConn.Read(signal)
inConn.SetReadDeadline(time.Time{})
if err != nil {
log.Printf("control connection read err: %s", err)
log.Printf("server control connection read err: %s", err)
break
} else {
// log.Printf("heartbeat from server ,id:%s", serverID)
Expand Down
3 changes: 2 additions & 1 deletion services/udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ func (s *UDP) InitOutConnPool() {
//parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool(
*s.cfg.CheckParentInterval,
*s.cfg.ParentType == TYPE_TLS,
*s.cfg.ParentType,
"", "",
s.cfg.CertBytes, s.cfg.KeyBytes,
*s.cfg.Parent,
*s.cfg.Timeout,
Expand Down
119 changes: 57 additions & 62 deletions utils/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package utils
import (
"bufio"
"bytes"
"crypto/sha1"
"crypto/tls"
"crypto/x509"
"encoding/binary"
Expand All @@ -16,92 +17,50 @@ import (
"net/http"
"os"
"os/exec"
"sync"

"golang.org/x/crypto/pbkdf2"

"runtime/debug"
"strconv"
"strings"
"time"

kcp "github.com/xtaci/kcp-go"
)

func IoBind0(dst io.ReadWriter, src io.ReadWriter, fn func(err error)) {
func IoBind(dst io.ReadWriter, src io.ReadWriter, fn func(err error)) {
go func() {
e1 := make(chan error, 1)
e2 := make(chan error, 1)
go func() {
defer func() {
if e := recover(); e != nil {
log.Printf("IoBind0 crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
_, err := io.Copy(dst, src)
if err != nil {
fn(err)
}

_, e := io.Copy(dst, src)
e1 <- e
}()
go func() {
defer func() {
if e := recover(); e != nil {
log.Printf("IoBind0 crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
_, err := io.Copy(src, dst)
if err != nil {
fn(err)
}
}()
}()
}
func IoBind(dst io.ReadWriter, src io.ReadWriter, fn func(err error)) {
var one = &sync.Once{}
go func() {
defer func() {
if e := recover(); e != nil {
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
var err error
_, err = ioCopy(dst, src)
if err != nil {
one.Do(func() {
fn(err)
})
}
}()
go func() {
defer func() {
if e := recover(); e != nil {
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}

_, e := io.Copy(src, dst)
e2 <- e
}()
var err error
_, err = ioCopy(src, dst)
if err != nil {
one.Do(func() {
fn(err)
})
select {
case err = <-e1:
case err = <-e2:
}
fn(err)
}()
}
func ioCopy(dst io.Writer, src io.Reader) (written int64, err error) {
buf := make([]byte, 32*1024)
for {
nr, er := src.Read(buf)
if er != nil {
err = er
break
}
nw, ew := dst.Write(buf[0:nr])
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
written += int64(nw)
}
return written, err
}

func TlsConnectHost(host string, timeout int, certBytes, keyBytes []byte) (conn tls.Conn, err error) {
h := strings.Split(host, ":")
port, _ := strconv.Atoi(h[1])
Expand Down Expand Up @@ -143,6 +102,10 @@ func ConnectHost(hostAndPort string, timeout int) (conn net.Conn, err error) {
conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond)
return
}
func ConnectKCPHost(hostAndPort, method, key string) (conn net.Conn, err error) {
conn, err = kcp.DialWithOptions(hostAndPort, GetKCPBlock(method, key), 10, 3)
return
}
func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listener, err error) {
var cert tls.Certificate
cert, err = tls.X509KeyPair(certBytes, keyBytes)
Expand Down Expand Up @@ -406,6 +369,38 @@ func TlsBytes(cert, key string) (certBytes, keyBytes []byte) {
}
return
}
func GetKCPBlock(method, key string) (block kcp.BlockCrypt) {
pass := pbkdf2.Key([]byte(key), []byte(key), 4096, 32, sha1.New)
switch method {
case "sm4":
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
case "tea":
block, _ = kcp.NewTEABlockCrypt(pass[:16])
case "xor":
block, _ = kcp.NewSimpleXORBlockCrypt(pass)
case "none":
block, _ = kcp.NewNoneBlockCrypt(pass)
case "aes-128":
block, _ = kcp.NewAESBlockCrypt(pass[:16])
case "aes-192":
block, _ = kcp.NewAESBlockCrypt(pass[:24])
case "blowfish":
block, _ = kcp.NewBlowfishBlockCrypt(pass)
case "twofish":
block, _ = kcp.NewTwofishBlockCrypt(pass)
case "cast5":
block, _ = kcp.NewCast5BlockCrypt(pass[:16])
case "3des":
block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
case "xtea":
block, _ = kcp.NewXTEABlockCrypt(pass[:16])
case "salsa20":
block, _ = kcp.NewSalsa20BlockCrypt(pass)
default:
block, _ = kcp.NewAESBlockCrypt(pass)
}
return
}

// type sockaddr struct {
// family uint16
Expand Down
Loading

0 comments on commit b7c2b0e

Please sign in to comment.