From 3aba428b76146da39d4a506cae445be5e109622a Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Mon, 9 Apr 2018 16:16:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0gomobile=20sdk=E5=AF=B9androi?= =?UTF-8?q?d/ios=E8=BF=9B=E8=A1=8C=E6=94=AF=E6=8C=81.=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: arraykeys@gmail.com --- sdk/release.sh | 41 +++++ sdk/sdk.go | 325 ++++++++++++++++++++++++++++++++++++++ services/http.go | 43 +++-- services/mux_bridge.go | 25 ++- services/mux_client.go | 27 ++-- services/mux_server.go | 42 +++-- services/service.go | 30 ++-- services/socks.go | 63 ++++---- services/sps.go | 32 ++-- services/tcp.go | 26 ++- services/tunnel_bridge.go | 117 ++------------ services/tunnel_client.go | 81 ++-------- services/tunnel_server.go | 94 ++++------- services/udp.go | 26 ++- utils/functions.go | 8 +- 15 files changed, 626 insertions(+), 354 deletions(-) create mode 100755 sdk/release.sh create mode 100644 sdk/sdk.go diff --git a/sdk/release.sh b/sdk/release.sh new file mode 100755 index 0000000..09b7b00 --- /dev/null +++ b/sdk/release.sh @@ -0,0 +1,41 @@ +#/bin/bash +VER="v4.7" +rm -rf release-* +#arm +gomobile bind -v -target=android/arm +mkdir proxy-sdk-arm +mv sdk.aar proxy-sdk-arm/proxy-sdk-arm.aar +mv sdk-sources.jar proxy-sdk-arm/proxy-sdk-arm-sources.jar +tar zcfv proxy-sdk-arm-${VER}.tar.gz proxy-sdk-arm +rm -rf proxy-sdk-arm +#arm64 +gomobile bind -v -target=android/arm64 +mkdir proxy-sdk-arm64 +mv sdk.aar proxy-sdk-arm64/proxy-sdk-arm64.aar +mv sdk-sources.jar proxy-sdk-arm64/proxy-sdk-arm64-sources.jar +tar zcfv proxy-sdk-arm64-${VER}.tar.gz proxy-sdk-arm64 +rm -rf proxy-sdk-arm64 +#386 +gomobile bind -v -target=android/386 +mkdir proxy-sdk-386 +mv sdk.aar proxy-sdk-386/proxy-sdk-386.aar +mv sdk-sources.jar proxy-sdk-386/proxy-sdk-386-sources.jar +tar zcfv proxy-sdk-386-${VER}.tar.gz proxy-sdk-386 +rm -rf proxy-sdk-386 +#amd64 +gomobile bind -v -target=android/amd64 +mkdir proxy-sdk-amd64 +mv sdk.aar proxy-sdk-amd64/proxy-sdk-amd64.aar +mv sdk-sources.jar proxy-sdk-amd64/proxy-sdk-amd64-sources.jar +tar zcfv proxy-sdk-amd64-${VER}.tar.gz proxy-sdk-amd64 +rm -rf proxy-sdk-amd64 +#all-in-one +gomobile bind -v -target=android +mkdir proxy-sdk-all +mv sdk.aar proxy-sdk-all/proxy-sdk-all.aar +mv sdk-sources.jar proxy-sdk-all/proxy-sdk-all-sources.jar +tar zcfv proxy-sdk-all-${VER}.tar.gz proxy-sdk-all +rm -rf proxy-sdk-all +mkdir proxy-sdk-release-${VER} +mv *.tar.gz proxy-sdk-release-${VER} +echo "done." \ No newline at end of file diff --git a/sdk/sdk.go b/sdk/sdk.go new file mode 100644 index 0000000..cb37165 --- /dev/null +++ b/sdk/sdk.go @@ -0,0 +1,325 @@ +package sdk + +import ( + "crypto/sha1" + "fmt" + "log" + "os" + "snail007/proxy/services" + "snail007/proxy/services/kcpcfg" + "strings" + + kcp "github.com/xtaci/kcp-go" + "golang.org/x/crypto/pbkdf2" + kingpin "gopkg.in/alecthomas/kingpin.v2" +) + +var ( + app *kingpin.Application + service *services.ServiceItem +) + +//Start argsStr: is the whole command line args string +//such as : +//1."http -t tcp -p :8989" +//2."socks -t tcp -p :8989" +//and so on. +//if an error occured , errStr will be the error reason +//if start success, errStr is empty. +func Start(argsStr string) (errStr string) { + //define args + tcpArgs := services.TCPArgs{} + httpArgs := services.HTTPArgs{} + tunnelServerArgs := services.TunnelServerArgs{} + tunnelClientArgs := services.TunnelClientArgs{} + tunnelBridgeArgs := services.TunnelBridgeArgs{} + muxServerArgs := services.MuxServerArgs{} + muxClientArgs := services.MuxClientArgs{} + muxBridgeArgs := services.MuxBridgeArgs{} + udpArgs := services.UDPArgs{} + socksArgs := services.SocksArgs{} + spsArgs := services.SPSArgs{} + kcpArgs := kcpcfg.KCPConfigArgs{} + //build srvice args + app = kingpin.New("proxy", "happy with proxy") + app.Author("snail").Version("4.7") + debug := app.Flag("debug", "debug log output").Default("false").Bool() + 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").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none") + kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast").Enum("fast3", "fast2", "fast", "normal", "manual") + 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 := app.Command("http", "proxy on http mode") + httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() + httpArgs.CaCertFile = http.Flag("ca", "ca cert file for tls").Default("").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 ").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") + httpArgs.ParentType = http.Flag("parent-type", "parent protocol type ").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() + httpArgs.Interval = http.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int() + httpArgs.Blocked = http.Flag("blocked", "blocked domain file , one domain each line").Default("blocked").Short('b').String() + httpArgs.Direct = http.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String() + httpArgs.AuthFile = http.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String() + httpArgs.Auth = http.Flag("auth", "http basic auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings() + httpArgs.PoolSize = http.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() + httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() + httpArgs.Local = http.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() + httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').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.SSHPassword = http.Flag("ssh-password", "password for ssh").Short('A').Default("").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.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.AuthURLOkCode = http.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int() + 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() + + //########tcp######### + tcp := app.Command("tcp", "proxy on tcp mode") + tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() + tcpArgs.CertFile = tcp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() + tcpArgs.KeyFile = tcp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() + tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int() + tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type ").Short('T').Enum("tls", "tcp", "udp", "kcp") + tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type ").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") + 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.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() + + //########udp######### + udp := app.Command("udp", "proxy on udp mode") + udpArgs.Parent = udp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() + udpArgs.CertFile = udp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() + udpArgs.KeyFile = udp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() + udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int() + udpArgs.ParentType = udp.Flag("parent-type", "parent protocol type ").Short('T').Enum("tls", "tcp", "udp") + udpArgs.PoolSize = udp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() + udpArgs.CheckParentInterval = udp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() + udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() + + //########mux-server######### + muxServer := app.Command("server", "proxy on mux server mode") + muxServerArgs.Parent = muxServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() + muxServerArgs.ParentType = muxServer.Flag("parent-type", "parent protocol type ").Default("tls").Short('T').Enum("tls", "tcp", "kcp") + muxServerArgs.CertFile = muxServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() + muxServerArgs.KeyFile = muxServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() + muxServerArgs.Timeout = muxServer.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int() + muxServerArgs.IsUDP = muxServer.Flag("udp", "proxy on udp mux server mode").Default("false").Bool() + muxServerArgs.Key = muxServer.Flag("k", "client key").Default("default").String() + muxServerArgs.Route = muxServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings() + muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool() + muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int() + + //########mux-client######### + muxClient := app.Command("client", "proxy on mux client mode") + muxClientArgs.Parent = muxClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() + muxClientArgs.ParentType = muxClient.Flag("parent-type", "parent protocol type ").Default("tls").Short('T').Enum("tls", "tcp", "kcp") + muxClientArgs.CertFile = muxClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() + muxClientArgs.KeyFile = muxClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() + muxClientArgs.Timeout = muxClient.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int() + muxClientArgs.Key = muxClient.Flag("k", "key same with server").Default("default").String() + muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool() + muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int() + + //########mux-bridge######### + muxBridge := app.Command("bridge", "proxy on mux bridge mode") + muxBridgeArgs.CertFile = muxBridge.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() + muxBridgeArgs.KeyFile = muxBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() + muxBridgeArgs.Timeout = muxBridge.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int() + muxBridgeArgs.Local = muxBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() + muxBridgeArgs.LocalType = muxBridge.Flag("local-type", "local protocol type ").Default("tls").Short('t').Enum("tls", "tcp", "kcp") + + //########tunnel-server######### + tunnelServer := app.Command("tserver", "proxy on tunnel server mode") + tunnelServerArgs.Parent = tunnelServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() + tunnelServerArgs.CertFile = tunnelServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() + tunnelServerArgs.KeyFile = tunnelServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() + tunnelServerArgs.Timeout = tunnelServer.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int() + tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool() + tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String() + tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings() + + //########tunnel-client######### + tunnelClient := app.Command("tclient", "proxy on tunnel client mode") + tunnelClientArgs.Parent = tunnelClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() + tunnelClientArgs.CertFile = tunnelClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() + tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() + tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int() + tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String() + + //########tunnel-bridge######### + tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode") + tunnelBridgeArgs.CertFile = tunnelBridge.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() + tunnelBridgeArgs.KeyFile = tunnelBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() + tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int() + tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() + + //########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 ").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh") + socksArgs.LocalType = socks.Flag("local-type", "local protocol type ").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.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").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() + socksArgs.SSHKeyFile = socks.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String() + socksArgs.SSHKeyFileSalt = socks.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String() + socksArgs.SSHPassword = socks.Flag("ssh-password", "password for ssh").Short('A').Default("").String() + socksArgs.Always = socks.Flag("always", "always use parent proxy").Default("false").Bool() + socksArgs.Timeout = socks.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("5000").Int() + socksArgs.Interval = socks.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int() + socksArgs.Blocked = socks.Flag("blocked", "blocked domain file , one domain each line").Default("blocked").Short('b').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.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.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.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int() + socksArgs.AuthURLOkCode = socks.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int() + 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() + //########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() + spsArgs.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() + spsArgs.KeyFile = sps.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() + spsArgs.CaCertFile = sps.Flag("ca", "ca cert file for tls").Default("").String() + spsArgs.Timeout = sps.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('i').Default("2000").Int() + spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type ").Short('T').Enum("tls", "tcp", "kcp") + spsArgs.LocalType = sps.Flag("local-type", "local protocol type ").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.ParentServiceType = sps.Flag("parent-service-type", "parent service type ").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.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int() + spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String() + spsArgs.Auth = sps.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings() + spsArgs.LocalIPS = sps.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings() + spsArgs.AuthURL = sps.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() + spsArgs.AuthURLTimeout = sps.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int() + 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() + //parse args + args := strings.Fields(strings.Trim(argsStr, " ")) + serviceName, err := app.Parse(args) + if err != nil { + return fmt.Sprintf("parse args fail,err: %s", err) + } + //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) + } + //attach kcp config + tcpArgs.KCP = kcpArgs + httpArgs.KCP = kcpArgs + socksArgs.KCP = kcpArgs + spsArgs.KCP = kcpArgs + muxBridgeArgs.KCP = kcpArgs + muxServerArgs.KCP = kcpArgs + muxClientArgs.KCP = kcpArgs + + flags := log.Ldate + if *debug { + flags |= log.Lshortfile | log.Lmicroseconds + } else { + flags |= log.Ltime + } + log.SetFlags(flags) + + if *logfile != "" { + f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + if e != nil { + log.Fatal(e) + } + log.SetOutput(f) + } + + //regist services and run service + services.Regist("http", services.NewHTTP(), httpArgs) + services.Regist("tcp", services.NewTCP(), tcpArgs) + services.Regist("udp", services.NewUDP(), udpArgs) + services.Regist("tserver", services.NewTunnelServerManager(), tunnelServerArgs) + services.Regist("tclient", services.NewTunnelClient(), tunnelClientArgs) + services.Regist("tbridge", services.NewTunnelBridge(), tunnelBridgeArgs) + services.Regist("server", services.NewMuxServerManager(), muxServerArgs) + services.Regist("client", services.NewMuxClient(), muxClientArgs) + services.Regist("bridge", services.NewMuxBridge(), muxBridgeArgs) + services.Regist("socks", services.NewSocks(), socksArgs) + services.Regist("sps", services.NewSPS(), spsArgs) + + service, err = services.Run(serviceName) + if err != nil { + return fmt.Sprintf("run service [%s] fail, ERR:%s", serviceName, err) + } + return +} + +func Stop() { + if service != nil && service.S != nil { + service.S.Clean() + } +} diff --git a/services/http.go b/services/http.go index 37993ab..62fb269 100644 --- a/services/http.go +++ b/services/http.go @@ -34,26 +34,32 @@ func NewHTTP() Service { lockChn: make(chan bool, 1), } } -func (s *HTTP) CheckArgs() { - var err error +func (s *HTTP) CheckArgs() (err error) { if *s.cfg.Parent != "" && *s.cfg.ParentType == "" { - log.Fatalf("parent type unkown,use -T ") + err = fmt.Errorf("parent type unkown,use -T ") + return } if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" { - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + if err != nil { + return + } if *s.cfg.CaCertFile != "" { s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile) if err != nil { - log.Fatalf("read ca file error,ERR:%s", err) + err = fmt.Errorf("read ca file error,ERR:%s", err) + return } } } if *s.cfg.ParentType == "ssh" { if *s.cfg.SSHUser == "" { - log.Fatalf("ssh user required") + err = fmt.Errorf("ssh user required") + return } if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" { - log.Fatalf("ssh password or key required") + err = fmt.Errorf("ssh password or key required") + return } if *s.cfg.SSHPassword != "" { @@ -62,7 +68,8 @@ func (s *HTTP) CheckArgs() { var SSHSigner ssh.Signer s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile) if err != nil { - log.Fatalf("read key file ERR: %s", err) + err = fmt.Errorf("read key file ERR: %s", err) + return } if *s.cfg.SSHKeyFileSalt != "" { SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt)) @@ -70,13 +77,15 @@ func (s *HTTP) CheckArgs() { SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes) } if err != nil { - log.Fatalf("parse ssh private key fail,ERR: %s", err) + err = fmt.Errorf("parse ssh private key fail,ERR: %s", err) + return } s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner) } } + return } -func (s *HTTP) InitService() { +func (s *HTTP) InitService() (err error) { s.InitBasicAuth() if *s.cfg.Parent != "" { s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct) @@ -85,9 +94,10 @@ func (s *HTTP) InitService() { (*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL) } if *s.cfg.ParentType == "ssh" { - err := s.ConnectSSH() + err = s.ConnectSSH() if err != nil { - log.Fatalf("init service fail, ERR: %s", err) + err = fmt.Errorf("init service fail, ERR: %s", err) + return } go func() { //循环检查ssh网络连通性 @@ -114,6 +124,7 @@ func (s *HTTP) InitService() { } }() } + return } func (s *HTTP) StopService() { if s.outPool.Pool != nil { @@ -122,12 +133,16 @@ func (s *HTTP) StopService() { } func (s *HTTP) Start(args interface{}) (err error) { s.cfg = args.(HTTPArgs) - s.CheckArgs() + if err = s.CheckArgs(); err != nil { + return + } if *s.cfg.Parent != "" { log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) s.InitOutConnPool() } - s.InitService() + if err = s.InitService(); err != nil { + return + } for _, addr := range strings.Split(*s.cfg.Local, ",") { if addr != "" { host, port, _ := net.SplitHostPort(addr) diff --git a/services/mux_bridge.go b/services/mux_bridge.go index c2d51fd..ee4afa6 100644 --- a/services/mux_bridge.go +++ b/services/mux_bridge.go @@ -2,6 +2,7 @@ package services import ( "bufio" + "fmt" "io" "log" "math/rand" @@ -32,24 +33,34 @@ func NewMuxBridge() Service { return b } -func (s *MuxBridge) InitService() { - +func (s *MuxBridge) InitService() (err error) { + return } -func (s *MuxBridge) CheckArgs() { +func (s *MuxBridge) CheckArgs() (err error) { if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" { - log.Fatalf("cert and key file required") + err = fmt.Errorf("cert and key file required") + return } if *s.cfg.LocalType == TYPE_TLS { - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + if err != nil { + return + } } + return } func (s *MuxBridge) StopService() { } func (s *MuxBridge) Start(args interface{}) (err error) { s.cfg = args.(MuxBridgeArgs) - s.CheckArgs() - s.InitService() + if err = s.CheckArgs(); err != nil { + return + } + if err = s.InitService(); err != nil { + return + } + host, port, _ := net.SplitHostPort(*s.cfg.Local) p, _ := strconv.Atoi(port) sc := utils.NewServerChannel(host, p) diff --git a/services/mux_client.go b/services/mux_client.go index 398744a..2ea91ed 100644 --- a/services/mux_client.go +++ b/services/mux_client.go @@ -23,30 +23,40 @@ func NewMuxClient() Service { } } -func (s *MuxClient) InitService() { - +func (s *MuxClient) InitService() (err error) { + return } -func (s *MuxClient) CheckArgs() { +func (s *MuxClient) CheckArgs() (err error) { if *s.cfg.Parent != "" { log.Printf("use tls parent %s", *s.cfg.Parent) } else { - log.Fatalf("parent required") + err = fmt.Errorf("parent required") + return } if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" { - log.Fatalf("cert and key file required") + err = fmt.Errorf("cert and key file required") + return } if *s.cfg.ParentType == "tls" { - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + if err != nil { + return + } } + return } func (s *MuxClient) StopService() { } func (s *MuxClient) Start(args interface{}) (err error) { s.cfg = args.(MuxClientArgs) - s.CheckArgs() - s.InitService() + if err = s.CheckArgs(); err != nil { + return + } + if err = s.InitService(); err != nil { + return + } log.Printf("client started") count := 1 if *s.cfg.SessionCount > 0 { @@ -119,7 +129,6 @@ func (s *MuxClient) Start(args interface{}) (err error) { }() } } - }(i) } return diff --git a/services/mux_server.go b/services/mux_server.go index 9e1fc65..2ffc6b7 100644 --- a/services/mux_server.go +++ b/services/mux_server.go @@ -41,14 +41,19 @@ func NewMuxServerManager() Service { } func (s *MuxServerManager) Start(args interface{}) (err error) { s.cfg = args.(MuxServerArgs) - s.CheckArgs() + if err = s.CheckArgs(); err != nil { + return + } if *s.cfg.Parent != "" { log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) } else { - log.Fatalf("parent required") + err = fmt.Errorf("parent required") + return } - s.InitService() + if err = s.InitService(); err != nil { + return + } log.Printf("server id: %s", s.serverID) //log.Printf("route:%v", *s.cfg.Route) @@ -103,15 +108,21 @@ func (s *MuxServerManager) Clean() { } func (s *MuxServerManager) StopService() { } -func (s *MuxServerManager) CheckArgs() { +func (s *MuxServerManager) CheckArgs() (err error) { if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" { - log.Fatalf("cert and key file required") + err = fmt.Errorf("cert and key file required") + return } if *s.cfg.ParentType == "tls" { - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + if err != nil { + return + } } + return } -func (s *MuxServerManager) InitService() { +func (s *MuxServerManager) InitService() (err error) { + return } func NewMuxServer() Service { @@ -129,19 +140,26 @@ type MuxUDPItem struct { srcAddr *net.UDPAddr } -func (s *MuxServer) InitService() { +func (s *MuxServer) InitService() (err error) { s.UDPConnDeamon() + return } -func (s *MuxServer) CheckArgs() { +func (s *MuxServer) CheckArgs() (err error) { if *s.cfg.Remote == "" { - log.Fatalf("remote required") + err = fmt.Errorf("remote required") + return } + return } func (s *MuxServer) Start(args interface{}) (err error) { s.cfg = args.(MuxServerArgs) - s.CheckArgs() - s.InitService() + if err = s.CheckArgs(); err != nil { + return + } + if err = s.InitService(); err != nil { + return + } host, port, _ := net.SplitHostPort(*s.cfg.Local) p, _ := strconv.Atoi(port) s.sc = utils.NewServerChannel(host, p) diff --git a/services/service.go b/services/service.go index de280af..b133210 100644 --- a/services/service.go +++ b/services/service.go @@ -2,7 +2,6 @@ package services import ( "fmt" - "log" "runtime/debug" ) @@ -28,24 +27,21 @@ func Regist(name string, s Service, args interface{}) { func Run(name string, args ...interface{}) (service *ServiceItem, err error) { service, ok := servicesMap[name] if ok { - go func() { - defer func() { - err := recover() - if err != nil { - log.Fatalf("%s servcie crashed, ERR: %s\ntrace:%s", name, err, string(debug.Stack())) - } - }() - if len(args) == 1 { - err = service.S.Start(args[0]) - } else { - err = service.S.Start(service.Args) - } - if err != nil { - log.Fatalf("%s servcie fail, ERR: %s", name, err) + defer func() { + e := recover() + if e != nil { + err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack())) } }() - } - if !ok { + if len(args) == 1 { + err = service.S.Start(args[0]) + } else { + err = service.S.Start(service.Args) + } + if err != nil { + err = fmt.Errorf("%s servcie fail, ERR: %s", name, err) + } + } else { err = fmt.Errorf("service %s not found", name) } return diff --git a/services/socks.go b/services/socks.go index 9828733..02fcaa6 100644 --- a/services/socks.go +++ b/services/socks.go @@ -35,36 +35,34 @@ func NewSocks() Service { } } -func (s *Socks) CheckArgs() { - var err error +func (s *Socks) CheckArgs() (err error) { + if *s.cfg.LocalType == "tls" || (*s.cfg.Parent != "" && *s.cfg.ParentType == "tls") { - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + if err != nil { + return + } if *s.cfg.CaCertFile != "" { s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile) if err != nil { - log.Fatalf("read ca file error,ERR:%s", err) + err = fmt.Errorf("read ca file error,ERR:%s", err) + return } } } if *s.cfg.Parent != "" { if *s.cfg.ParentType == "" { - log.Fatalf("parent type unkown,use -T ") + err = fmt.Errorf("parent type unkown,use -T ") + return } - // if *s.cfg.ParentType == "tls" { - // s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) - // if *s.cfg.CaCertFile != "" { - // s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile) - // if err != nil { - // log.Fatalf("read ca file error,ERR:%s", err) - // } - // } - // } if *s.cfg.ParentType == "ssh" { if *s.cfg.SSHUser == "" { - log.Fatalf("ssh user required") + err = fmt.Errorf("ssh user required") + return } if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" { - log.Fatalf("ssh password or key required") + err = fmt.Errorf("ssh password or key required") + return } if *s.cfg.SSHPassword != "" { s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword) @@ -72,7 +70,8 @@ func (s *Socks) CheckArgs() { var SSHSigner ssh.Signer s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile) if err != nil { - log.Fatalf("read key file ERR: %s", err) + err = fmt.Errorf("read key file ERR: %s", err) + return } if *s.cfg.SSHKeyFileSalt != "" { SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt)) @@ -80,24 +79,26 @@ func (s *Socks) CheckArgs() { SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes) } if err != nil { - log.Fatalf("parse ssh private key fail,ERR: %s", err) + err = fmt.Errorf("parse ssh private key fail,ERR: %s", err) + return } s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner) } } } - + return } -func (s *Socks) InitService() { +func (s *Socks) InitService() (err error) { s.InitBasicAuth() if *s.cfg.DNSAddress != "" { (*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL) } s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct) if *s.cfg.ParentType == "ssh" { - err := s.ConnectSSH() - if err != nil { - log.Fatalf("init service fail, ERR: %s", err) + e := s.ConnectSSH() + if e != nil { + err = fmt.Errorf("init service fail, ERR: %s", e) + return } go func() { //循环检查ssh网络连通性 @@ -125,12 +126,14 @@ func (s *Socks) InitService() { log.Println("warn: socks udp not suppored for ssh") } else { 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) + e := s.udpSC.ListenUDP(s.udpCallback) + if e != nil { + err = fmt.Errorf("init udp service fail, ERR: %s", e) + return } log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr()) } + return } func (s *Socks) StopService() { if s.sshClient != nil { @@ -143,8 +146,12 @@ func (s *Socks) StopService() { func (s *Socks) Start(args interface{}) (err error) { //start() s.cfg = args.(SocksArgs) - s.CheckArgs() - s.InitService() + if err = s.CheckArgs(); err != nil { + return + } + if err = s.InitService(); err != nil { + s.InitService() + } if *s.cfg.Parent != "" { log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) } diff --git a/services/sps.go b/services/sps.go index 8d687cc..a169aaa 100644 --- a/services/sps.go +++ b/services/sps.go @@ -30,30 +30,37 @@ func NewSPS() Service { basicAuth: utils.BasicAuth{}, } } -func (s *SPS) CheckArgs() { +func (s *SPS) CheckArgs() (err error) { if *s.cfg.Parent == "" { - log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local) + err = fmt.Errorf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local) + return } if *s.cfg.ParentType == "" { - log.Fatalf("parent type unkown,use -T ") + err = fmt.Errorf("parent type unkown,use -T ") + return } if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS { - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + if err != nil { + return + } if *s.cfg.CaCertFile != "" { - var err error s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile) if err != nil { - log.Fatalf("read ca file error,ERR:%s", err) + err = fmt.Errorf("read ca file error,ERR:%s", err) + return } } } + return } -func (s *SPS) InitService() { +func (s *SPS) InitService() (err error) { s.InitOutConnPool() if *s.cfg.DNSAddress != "" { (*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL) } - s.InitBasicAuth() + err = s.InitBasicAuth() + return } func (s *SPS) InitOutConnPool() { if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP { @@ -79,10 +86,13 @@ func (s *SPS) StopService() { } func (s *SPS) Start(args interface{}) (err error) { s.cfg = args.(SPSArgs) - s.CheckArgs() + if err = s.CheckArgs(); err != nil { + return + } + if err = s.InitService(); err != nil { + return + } log.Printf("use %s %s parent %s", *s.cfg.ParentType, *s.cfg.ParentServiceType, *s.cfg.Parent) - s.InitService() - for _, addr := range strings.Split(*s.cfg.Local, ",") { if addr != "" { host, port, _ := net.SplitHostPort(*s.cfg.Local) diff --git a/services/tcp.go b/services/tcp.go index 34df8ee..edf0689 100644 --- a/services/tcp.go +++ b/services/tcp.go @@ -24,19 +24,26 @@ func NewTCP() Service { cfg: TCPArgs{}, } } -func (s *TCP) CheckArgs() { +func (s *TCP) CheckArgs() (err error) { if *s.cfg.Parent == "" { - log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local) + err = fmt.Errorf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local) + return } if *s.cfg.ParentType == "" { - log.Fatalf("parent type unkown,use -T ") + err = fmt.Errorf("parent type unkown,use -T ") + return } if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS { - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + if err != nil { + return + } } + return } -func (s *TCP) InitService() { +func (s *TCP) InitService() (err error) { s.InitOutConnPool() + return } func (s *TCP) StopService() { if s.outPool.Pool != nil { @@ -45,10 +52,13 @@ func (s *TCP) StopService() { } func (s *TCP) Start(args interface{}) (err error) { s.cfg = args.(TCPArgs) - s.CheckArgs() + if err = s.CheckArgs(); err != nil { + return + } + if err = s.InitService(); err != nil { + return + } log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) - s.InitService() - host, port, _ := net.SplitHostPort(*s.cfg.Local) p, _ := strconv.Atoi(port) sc := utils.NewServerChannel(host, p) diff --git a/services/tunnel_bridge.go b/services/tunnel_bridge.go index ddae0a7..f7122b3 100644 --- a/services/tunnel_bridge.go +++ b/services/tunnel_bridge.go @@ -2,6 +2,7 @@ package services import ( "bufio" + "fmt" "log" "net" "snail007/proxy/utils" @@ -31,22 +32,28 @@ func NewTunnelBridge() Service { } } -func (s *TunnelBridge) InitService() { - +func (s *TunnelBridge) InitService() (err error) { + return } -func (s *TunnelBridge) CheckArgs() { +func (s *TunnelBridge) CheckArgs() (err error) { if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" { - log.Fatalf("cert and key file required") + err = fmt.Errorf("cert and key file required") + return } - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + return } func (s *TunnelBridge) StopService() { } func (s *TunnelBridge) Start(args interface{}) (err error) { s.cfg = args.(TunnelBridgeArgs) - s.CheckArgs() - s.InitService() + if err = s.CheckArgs(); err != nil { + return + } + if err = s.InitService(); err != nil { + return + } host, port, _ := net.SplitHostPort(*s.cfg.Local) p, _ := strconv.Atoi(port) sc := utils.NewServerChannel(host, p) @@ -135,102 +142,6 @@ func (s *TunnelBridge) Start(args interface{}) (err error) { } s.clientControlConns.Set(key, &inConn) log.Printf("set client %s control conn", key) - - // case CONN_SERVER_HEARBEAT: - // var serverID string - // err = utils.ReadPacketData(reader, &serverID) - // if err != nil { - // log.Printf("read error,ERR:%s", err) - // return - // } - // log.Printf("server heartbeat connection, id: %s", serverID) - // writeDie := make(chan bool) - // readDie := make(chan bool) - // go func() { - // for { - // inConn.SetWriteDeadline(time.Now().Add(time.Second * 3)) - // _, err = inConn.Write([]byte{0x00}) - // inConn.SetWriteDeadline(time.Time{}) - // if err != nil { - // log.Printf("server heartbeat connection write err %s", err) - // break - // } - // time.Sleep(time.Second * 3) - // } - // close(writeDie) - // }() - // go func() { - // for { - // signal := make([]byte, 1) - // inConn.SetReadDeadline(time.Now().Add(time.Second * 6)) - // _, err := inConn.Read(signal) - // inConn.SetReadDeadline(time.Time{}) - // if err != nil { - // log.Printf("server heartbeat connection read err: %s", err) - // break - // } else { - // // log.Printf("heartbeat from server ,id:%s", serverID) - // } - // } - // close(readDie) - // }() - // select { - // case <-readDie: - // case <-writeDie: - // } - // utils.CloseConn(&inConn) - // s.cmServer.Remove(serverID) - // log.Printf("server heartbeat conn %s released", serverID) - // case CONN_CLIENT_HEARBEAT: - // var clientID string - // err = utils.ReadPacketData(reader, &clientID) - // if err != nil { - // log.Printf("read error,ERR:%s", err) - // return - // } - // log.Printf("client heartbeat connection, id: %s", clientID) - // writeDie := make(chan bool) - // readDie := make(chan bool) - // go func() { - // for { - // inConn.SetWriteDeadline(time.Now().Add(time.Second * 3)) - // _, err = inConn.Write([]byte{0x00}) - // inConn.SetWriteDeadline(time.Time{}) - // if err != nil { - // log.Printf("client heartbeat connection write err %s", err) - // break - // } - // time.Sleep(time.Second * 3) - // } - // close(writeDie) - // }() - // go func() { - // for { - // signal := make([]byte, 1) - // inConn.SetReadDeadline(time.Now().Add(time.Second * 6)) - // _, err := inConn.Read(signal) - // inConn.SetReadDeadline(time.Time{}) - // if err != nil { - // log.Printf("client control connection read err: %s", err) - // break - // } else { - // // log.Printf("heartbeat from client ,id:%s", clientID) - // } - // } - // close(readDie) - // }() - // select { - // case <-readDie: - // case <-writeDie: - // } - // utils.CloseConn(&inConn) - // s.cmClient.Remove(clientID) - // if s.clientControlConns.Has(clientID) { - // item, _ := s.clientControlConns.Get(clientID) - // (*item.(*net.Conn)).Close() - // } - // s.clientControlConns.Remove(clientID) - // log.Printf("client heartbeat conn %s released", clientID) } }) if err != nil { diff --git a/services/tunnel_client.go b/services/tunnel_client.go index 0d93483..012756f 100644 --- a/services/tunnel_client.go +++ b/services/tunnel_client.go @@ -23,86 +23,35 @@ func NewTunnelClient() Service { } } -func (s *TunnelClient) InitService() { - // s.InitHeartbeatDeamon() +func (s *TunnelClient) InitService() (err error) { + return } -// func (s *TunnelClient) InitHeartbeatDeamon() { -// log.Printf("heartbeat started") -// go func() { -// var heartbeatConn net.Conn -// var ID = *s.cfg.Key -// for { - -// //close all connection -// s.cm.RemoveAll() -// if s.ctrlConn != nil { -// s.ctrlConn.Close() -// } -// utils.CloseConn(&heartbeatConn) -// heartbeatConn, err := s.GetInConn(CONN_CLIENT_HEARBEAT, ID) -// if err != nil { -// log.Printf("heartbeat connection err: %s, retrying...", err) -// time.Sleep(time.Second * 3) -// utils.CloseConn(&heartbeatConn) -// continue -// } -// log.Printf("heartbeat connection created,id:%s", ID) -// writeDie := make(chan bool) -// readDie := make(chan bool) -// go func() { -// for { -// heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3)) -// _, err = heartbeatConn.Write([]byte{0x00}) -// heartbeatConn.SetWriteDeadline(time.Time{}) -// if err != nil { -// log.Printf("heartbeat connection write err %s", err) -// break -// } -// time.Sleep(time.Second * 3) -// } -// close(writeDie) -// }() -// go func() { -// for { -// signal := make([]byte, 1) -// heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6)) -// _, err := heartbeatConn.Read(signal) -// heartbeatConn.SetReadDeadline(time.Time{}) -// if err != nil { -// log.Printf("heartbeat connection read err: %s", err) -// break -// } else { -// //log.Printf("heartbeat from bridge") -// } -// } -// close(readDie) -// }() -// select { -// case <-readDie: -// case <-writeDie: -// } -// } -// }() -// } -func (s *TunnelClient) CheckArgs() { +func (s *TunnelClient) CheckArgs() (err error) { if *s.cfg.Parent != "" { log.Printf("use tls parent %s", *s.cfg.Parent) } else { - log.Fatalf("parent required") + err = fmt.Errorf("parent required") + return } if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" { - log.Fatalf("cert and key file required") + err = fmt.Errorf("cert and key file required") + return } - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + return } func (s *TunnelClient) StopService() { // s.cm.RemoveAll() } func (s *TunnelClient) Start(args interface{}) (err error) { s.cfg = args.(TunnelClientArgs) - s.CheckArgs() - s.InitService() + if err = s.CheckArgs(); err != nil { + return + } + if err = s.InitService(); err != nil { + return + } log.Printf("proxy on tunnel client mode") for { diff --git a/services/tunnel_server.go b/services/tunnel_server.go index b4fbfa0..e3ed0cf 100644 --- a/services/tunnel_server.go +++ b/services/tunnel_server.go @@ -37,14 +37,19 @@ func NewTunnelServerManager() Service { } func (s *TunnelServerManager) Start(args interface{}) (err error) { s.cfg = args.(TunnelServerArgs) - s.CheckArgs() + if err = s.CheckArgs(); err != nil { + return + } if *s.cfg.Parent != "" { log.Printf("use tls parent %s", *s.cfg.Parent) } else { - log.Fatalf("parent required") + err = fmt.Errorf("parent required") + return } - s.InitService() + if err = s.InitService(); err != nil { + return + } log.Printf("server id: %s", s.serverID) //log.Printf("route:%v", *s.cfg.Route) @@ -93,70 +98,18 @@ func (s *TunnelServerManager) Clean() { func (s *TunnelServerManager) StopService() { // s.cm.RemoveAll() } -func (s *TunnelServerManager) CheckArgs() { +func (s *TunnelServerManager) CheckArgs() (err error) { if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" { - log.Fatalf("cert and key file required") + err = fmt.Errorf("cert and key file required") + return } - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + return } -func (s *TunnelServerManager) InitService() { - // s.InitHeartbeatDeamon() +func (s *TunnelServerManager) InitService() (err error) { + return } -// func (s *TunnelServerManager) InitHeartbeatDeamon() { -// log.Printf("heartbeat started") -// go func() { -// var heartbeatConn net.Conn -// var ID string -// for { -// //close all connection -// s.cm.Remove(ID) -// utils.CloseConn(&heartbeatConn) -// heartbeatConn, ID, err := s.GetOutConn(CONN_SERVER_HEARBEAT) -// if err != nil { -// log.Printf("heartbeat connection err: %s, retrying...", err) -// time.Sleep(time.Second * 3) -// utils.CloseConn(&heartbeatConn) -// continue -// } -// log.Printf("heartbeat connection created,id:%s", ID) -// writeDie := make(chan bool) -// readDie := make(chan bool) -// go func() { -// for { -// heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3)) -// _, err = heartbeatConn.Write([]byte{0x00}) -// heartbeatConn.SetWriteDeadline(time.Time{}) -// if err != nil { -// log.Printf("heartbeat connection write err %s", err) -// break -// } -// time.Sleep(time.Second * 3) -// } -// close(writeDie) -// }() -// go func() { -// for { -// signal := make([]byte, 1) -// heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6)) -// _, err := heartbeatConn.Read(signal) -// heartbeatConn.SetReadDeadline(time.Time{}) -// if err != nil { -// log.Printf("heartbeat connection read err: %s", err) -// break -// } else { -// // log.Printf("heartbeat from bridge") -// } -// } -// close(readDie) -// }() -// select { -// case <-readDie: -// case <-writeDie: -// } -// } -// }() -// } func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) { outConn, err = s.GetConn() if err != nil { @@ -193,19 +146,26 @@ type UDPItem struct { srcAddr *net.UDPAddr } -func (s *TunnelServer) InitService() { +func (s *TunnelServer) InitService() (err error) { s.UDPConnDeamon() + return } -func (s *TunnelServer) CheckArgs() { +func (s *TunnelServer) CheckArgs() (err error) { if *s.cfg.Remote == "" { - log.Fatalf("remote required") + err = fmt.Errorf("remote required") + return } + return } func (s *TunnelServer) Start(args interface{}) (err error) { s.cfg = args.(TunnelServerArgs) - s.CheckArgs() - s.InitService() + if err = s.CheckArgs(); err != nil { + return + } + if err = s.InitService(); err != nil { + return + } host, port, _ := net.SplitHostPort(*s.cfg.Local) p, _ := strconv.Atoi(port) s.sc = utils.NewServerChannel(host, p) diff --git a/services/udp.go b/services/udp.go index 74951fb..400b252 100644 --- a/services/udp.go +++ b/services/udp.go @@ -28,21 +28,28 @@ func NewUDP() Service { p: utils.NewConcurrentMap(), } } -func (s *UDP) CheckArgs() { +func (s *UDP) CheckArgs() (err error) { if *s.cfg.Parent == "" { - log.Fatalf("parent required for udp %s", *s.cfg.Local) + err = fmt.Errorf("parent required for udp %s", *s.cfg.Local) + return } if *s.cfg.ParentType == "" { - log.Fatalf("parent type unkown,use -T ") + err = fmt.Errorf("parent type unkown,use -T ") + return } if *s.cfg.ParentType == "tls" { - s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) + if err != nil { + return + } } + return } -func (s *UDP) InitService() { +func (s *UDP) InitService() (err error) { if *s.cfg.ParentType != TYPE_UDP { s.InitOutConnPool() } + return } func (s *UDP) StopService() { if s.outPool.Pool != nil { @@ -51,10 +58,13 @@ func (s *UDP) StopService() { } func (s *UDP) Start(args interface{}) (err error) { s.cfg = args.(UDPArgs) - s.CheckArgs() + if err = s.CheckArgs(); err != nil { + return + } log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) - s.InitService() - + if err = s.InitService(); err != nil { + return + } host, port, _ := net.SplitHostPort(*s.cfg.Local) p, _ := strconv.Atoi(port) sc := utils.NewServerChannel(host, p) diff --git a/utils/functions.go b/utils/functions.go index cc30c33..9429a40 100755 --- a/utils/functions.go +++ b/utils/functions.go @@ -524,15 +524,15 @@ func SubBytes(bytes []byte, start, end int) []byte { } return bytes[start:end] } -func TlsBytes(cert, key string) (certBytes, keyBytes []byte) { - certBytes, err := ioutil.ReadFile(cert) +func TlsBytes(cert, key string) (certBytes, keyBytes []byte, err error) { + certBytes, err = ioutil.ReadFile(cert) if err != nil { - log.Fatalf("err : %s", err) + err = fmt.Errorf("err : %s", err) return } keyBytes, err = ioutil.ReadFile(key) if err != nil { - log.Fatalf("err : %s", err) + err = fmt.Errorf("err : %s", err) return } return