package server import ( "bytes" "crypto/tls" "encoding/json" "errors" "fmt" uuid2 "github.com/google/uuid" "io" "io/ioutil" "math/rand" "net" "os" "rakshasa/cert" "rakshasa/common" "runtime" "strconv" "strings" "sync" "sync/atomic" "time" "unsafe" ) var ( currentNode = &node{uuid: uuid2.New().String()} clientLock = &lock{} nodeMap = make(map[string]*node) upLevelNode []*node //上游节点 upNodeWrite = make(chan []byte, 999) extNodeIp []string connMap sync.Map ) func InitCurrentNode() { s := unsafe.Sizeof(uintptr(1)) bit := " x32" if s == 8 { bit = " x64" } rand.Seed(time.Now().Unix()) currentNode.hostName, _ = os.Hostname() if ip, _ := common.ExternalIP(); ip != nil { currentNode.addr = ip.String() } currentNode.goos = runtime.GOOS + bit currentNode.mirrorNode = &node{ id: currentNode.id, uuid: currentNode.uuid, hostName: currentNode.hostName, goos: currentNode.goos, addr: currentNode.addr, } currentNode.mirrorNode.mirrorNode = currentNode nodeMap[currentNode.uuid] = currentNode //fmt.Println("当前节点UUID", currentNode.uuid) go func() { for b := range upNodeWrite { for { ok := func() bool { l := clientLock.Lock() defer l.Unlock() if len(upLevelNode) == 0 { return false } upLevelNode[0].conn.tlsWrite(b) return true }() if ok { break } time.Sleep(time.Second) } } }() nodeTickPing() time.AfterFunc(time.Second*10, checkUpLevelNode) } func checkUpLevelNode() { if len(currentConfig.DstNode) > 0 && len(upLevelNode) == 0 { //尝试重新连接节点 for _, addr := range currentConfig.DstNode { connectNew(addr) } if len(upLevelNode) == 0 { //尝试连接其他节点 if !currentConfig.Limit { for _, addr := range extNodeIp { if common.Debug { fmt.Println("连接extNodeIp", addr) } connectNew(addr) if len(upLevelNode) > 0 { return } } func() { l := clientLock.RLock() defer l.RUnlock() for _, n := range nodeMap { if n.uuid != currentNode.uuid { func() { l.RUnlock() defer clientLock.RLock(l) if len(n.mainIp) == 0 { if common.Debug { fmt.Println("连接n.addr", fmt.Sprintf("%s:%d", n.addr, n.port)) } connectNew(fmt.Sprintf("%s:%d", n.addr, n.port)) } }() if len(upLevelNode) > 0 { return } } } }() } } } time.AfterFunc(time.Second*5, checkUpLevelNode) } func nodeTickPing() { l := clientLock.RLock() defer l.RUnlock() now := time.Now().Unix() for _, n := range nodeMap { if n.uuid != currentNode.uuid { for _, ip := range n.mainIp { if ip != "" { addr1 := fmt.Sprintf("%s:%d", ip, n.port) find := false for _, addr2 := range extNodeIp { if addr1 == addr2 { find = true break } } if !find { extNodeIp = append(extNodeIp, addr1) } } } if n.nextPingTime == 0 { go n.ping(0) n.nextPingTime = now + 10 + rand.Int63n(10) } else if n.nextPingTime < now { go n.ping(0) n.nextPingTime = now + 30 + rand.Int63n(30) } } } time.AfterFunc(time.Second*1, nodeTickPing) } // 节点 type node struct { id int uuid string hostName string goos string addr string connMap sync.Map udpConnMap sync.Map listenMap sync.Map //client端会存入clientListen,server存入serverListen shellMap sync.Map queryMap sync.Map conn *Conn pingTime, pongTime int64 mainIp []string port int listen net.Listener nextPingTime int64 waitMsg []*common.Msg //需要等待处理的消息 mirrorNode *node //currentNode会生成一个互为mirror的node,以实现client-server功能,比如httpProxy在单节点启动 } type nodeMsg struct { UUID string HostName string Addr string MainIp []string Port int Goos string } func connectNew(addr string) (n *node, e error) { config := cert.Tlsconfig.Clone() conn, err := tls.Dial("tcp", addr, config) if err != nil { return nil, err } c := &Conn{nodeConn: conn, isClient: true, nodeaddr: addr, remoteAddr: conn.LocalAddr().String()} connMap.Store(c.remoteAddr, conn) c.regResult = make(chan error, 1) c.regResultNode = make(chan *node, 1) c.handle() c.reg() defer func() { if c.node != nil { l := clientLock.Lock() find := false for _, n := range upLevelNode { if n.uuid == c.node.uuid { find = true } } if !find { upLevelNode = append(upLevelNode, c.node) } l.Unlock() resChan := make(chan interface{}, 1) id := c.node.storeQuery(resChan) c.node.Write(common.CMD_GET_NODE, id, []byte{0}) select { case <-resChan: c.node.deleteQuery(id) c.node.broadcastNode() case <-time.After(common.CMD_TIMEOUT): c.node.deleteQuery(id) c.node.Close("") e = errors.New("time out") } } }() select { case err = <-c.regResult: return nil, err case n = <-c.regResultNode: return n, err case <-time.After(time.Second * 10): return nil, errors.New("time out") } } func (n *node) Write(option uint8, id uint32, b []byte) { msg := common.Msg{ From: currentNode.uuid, To: n.uuid, CmdOpteion: option, CmdId: id, CmdData: b, } if n.uuid == currentNode.uuid { n.mirrorNode.do(&msg) } else { if n.conn != nil { n.conn.OutChan <- msg.Marshal() } else { upNodeWrite <- msg.Marshal() } } } func (n *node) WriteMsg(msg *common.Msg) { if n.conn != nil { n.conn.OutChan <- msg.Marshal() } else { upNodeWrite <- msg.Marshal() } } func (n *node) do(msg *common.Msg) { if common.Debug { fmt.Println("client收到", common.CmdToName[msg.CmdOpteion]) } var err error //fmt.Println(common.CmdToName[msg.CmdOpteion]) switch msg.CmdOpteion { case common.CMD_CONNECT_BYIDADDR: conn := &serverConnect{} conn.node = n conn.id = msg.CmdId conn.write = make(chan *bytes.Buffer, 64) conn.close = 0 conn.windowsSize = 0 conn.wait = make(chan int) n.connMap.Store(conn.id, conn) addr := string(msg.CmdData[1:]) switch common.NetWork(msg.CmdData[0]) { case common.SOCKS5_CMD_CONNECT: conn.address = addr go conn.doConnectTcp(common.SOCKS5_CMD_CONNECT, addr) case common.SOCKS5_CMD_UDP: go conn.doHandleUdp() case common.RAW_TCP: go conn.doConnectTcp(common.RAW_TCP, addr) case common.RAW_TCP_WITH_PROXY: go conn.doConnectTcpWithHttpProxy(common.RAW_TCP_WITH_PROXY, addr) case common.SOCKS5_CMD_BIND: _l, err := net.Listen("tcp", addr) if err != nil { n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) return } l := &serverListen{listen: _l, node: n, isSocks5: true, id: common.GetID(), replayid: msg.CmdId} n.connMap.Delete(conn.id) l.socks5Replay = make([]byte, len(msg.CmdData)) copy(l.socks5Replay, msg.CmdData) n.Write(common.CMD_CONNECT_BYIDADDR_RESULT, l.replayid, l.socks5Replay) n.listenMap.Store(l.id, l) go l.Lisen() } case common.CMD_CONNECT_BYIDADDR_RESULT: if v, ok := n.connMap.Load(msg.CmdId); ok { if conn, ok := v.(common.Conn); ok { conn.Write(append([]byte{common.CMD_CONNECT_BYIDADDR_RESULT}, msg.CmdData...)) } } case common.CMD_CONN_MSG: v, ok1 := n.connMap.Load(msg.CmdId) conn, ok2 := v.(common.Conn) if !ok1 || !ok2 { n.Write(common.CMD_DELETE_CONNID, msg.CmdId, nil) return } conn.Write(append([]byte{common.CMD_CONN_MSG}, msg.CmdData...)) case common.CMD_DELETE_CONNID: v, ok := n.connMap.Load(msg.CmdId) if ok { if conn, ok2 := v.(common.Conn); ok2 { conn.Close("对方节点要求关闭") } else { n.connMap.Delete(msg.CmdId) } } case common.CMD_WINDOWS_UPDATE: v, ok := n.connMap.Load(msg.CmdId) if ok { conn := v.(*serverConnect) windows_update_size := int64(msg.CmdData[0]) | int64(msg.CmdData[1])<<8 | int64(msg.CmdData[2])<<16 | int64(msg.CmdData[3])<<24 | int64(msg.CmdData[4])<<32 | int64(msg.CmdData[5])<<40 | int64(msg.CmdData[6])<<48 | int64(msg.CmdData[7])<<56 if windows_update_size > 0 { old := atomic.AddInt64(&conn.windowsSize, windows_update_size) - windows_update_size if old < 0 { go func() { select { case conn.wait <- common.CONN_STATUS_OK: case <-time.After(time.Second): } }() } } } else { n.Write(common.CMD_DELETE_CONNID, msg.CmdId, nil) } case common.CMD_REG: func() { l := clientLock.Lock() defer l.Unlock() var regmsg common.RegMsg err = json.Unmarshal(msg.CmdData, ®msg) if err != nil { regmsg.Err = err.Error() b, _ := json.Marshal(regmsg) n.Write(common.CMD_REG_RESULT, 0, b) return } uuid := regmsg.UUID if uuid == currentNode.uuid { regmsg.Err = "不能连接自己" b, _ := json.Marshal(regmsg) n.Write(common.CMD_REG_RESULT, 0, b) return } n.addr = regmsg.Addr n.hostName = regmsg.Hostname n.mainIp = regmsg.MainIp n.port = regmsg.Port n.goos = regmsg.Goos resultMsg := regmsg resultMsg.Addr = currentNode.addr resultMsg.UUID = currentNode.uuid resultMsg.Hostname = currentNode.hostName resultMsg.MainIp = currentNode.mainIp resultMsg.Port = currentNode.port resultMsg.Goos = currentNode.goos b, _ := json.Marshal(resultMsg) //返回成功结果 n.Write(common.CMD_REG_RESULT, 0, b) //储存节点 n.uuid = uuid if v, ok := nodeMap[uuid]; !ok || v.conn.closeTag > 0 { n.conn.node = n nodeMap[regmsg.UUID] = n n.broadcastNode() } }() case common.CMD_REG_RESULT: var regmsg common.RegMsg err = json.Unmarshal(msg.CmdData, ®msg) if err != nil { select { case n.conn.regResult <- err: default: } return } if regmsg.Err != "" { select { case n.conn.regResult <- errors.New(regmsg.Err): default: } return } //fmt.Printf("connect to %s(%s) success\n", regmsg.UUID, regmsg.RegAddr) l := clientLock.Lock() n.uuid = regmsg.UUID n.addr = regmsg.Addr n.hostName = regmsg.Hostname n.goos = regmsg.Goos workconn := n.conn n.mainIp = regmsg.MainIp n.port = regmsg.Port if v, ok := nodeMap[regmsg.UUID]; ok { if v.conn.node != nil && v.conn.node.uuid == regmsg.UUID && v.conn.closeTag == 0 { n.uuid = "" //清空uuid避免正常的node被删 n.conn.Close("重复注册") //当前的连接关掉 n.conn = v.conn v.mainIp = regmsg.MainIp v.port = regmsg.Port n = v } else { n.conn.node = n } } else { n.conn.node = n } nodeMap[n.uuid] = n l.Unlock() select { case workconn.regResultNode <- n: default: } //回复节点 n.writeGetNodeResult(msg.CmdId) case common.CMD_REMOTE_REG: var regmsg common.RegMsg err = json.Unmarshal(msg.CmdData, ®msg) if currentConfig.Limit { regmsg.Err = "node is in limit mode" b, _ := json.Marshal(regmsg) n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b) return } if err == nil { var node *node node, err = connectNew(regmsg.RegAddr) if err == nil { regmsg.UUID = node.uuid regmsg.Hostname = node.hostName regmsg.ViaUUID = currentNode.uuid regmsg.MainIp = currentNode.mainIp regmsg.Port = currentNode.port regmsg.Goos = currentNode.goos b, _ := json.Marshal(regmsg) n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b) } } if err != nil { regmsg.Err = err.Error() b, _ := json.Marshal(regmsg) n.Write(common.CMD_REMOTE_REG_RESULT, msg.CmdId, b) } case common.CMD_REMOTE_REG_RESULT: var regmsg common.RegMsg err = json.Unmarshal(msg.CmdData, ®msg) v, ok := n.loadQuery(msg.CmdId) if !ok { return } if err != nil { v <- err return } if regmsg.Err != "" { v <- errors.New(regmsg.Err) return } l := clientLock.Lock() n.uuid = regmsg.UUID n.addr = regmsg.Addr n.hostName = regmsg.Hostname n.goos = regmsg.Goos n.mainIp = regmsg.MainIp n.port = regmsg.Port if v, ok := nodeMap[regmsg.UUID]; !ok { n.conn.node = n } else { if v.conn.node.uuid == regmsg.UUID && v.conn.closeTag == 0 { n.conn.close <- "" //当前的连接关掉 n.conn = v.conn v.mainIp = regmsg.MainIp v.port = regmsg.Port } else { n.conn.node = n } } nodeMap[n.uuid] = n l.Unlock() //fmt.Printf("connect to %s(%s) success\n", regmsg.UUID, regmsg.RegAddr) n.writeGetNodeResult(msg.CmdId) n.broadcastNode() case common.CMD_PING: n.Write(common.CMD_PONG, msg.CmdId, msg.CmdData) case common.CMD_NONE: case common.CMD_PONG: pingTime := int64(msg.CmdData[0]) | int64(msg.CmdData[1])<<8 | int64(msg.CmdData[2])<<16 | int64(msg.CmdData[3])<<24 | int64(msg.CmdData[4])<<32 | int64(msg.CmdData[5])<<40 | int64(msg.CmdData[6])<<48 | int64(msg.CmdData[7])<<56 if pingTime != n.pingTime { return } n.pongTime = time.Now().Unix() if v, ok := n.loadQuery(msg.CmdId); ok { select { case v <- struct{}{}: default: } } case common.CMD_CONN_UDP_MSG: _, ok := n.connMap.Load(msg.CmdId) if ok { var conn common.Conn id := uint32(msg.CmdData[0]) | uint32(msg.CmdData[1])<<8 | uint32(msg.CmdData[2])<<16 | uint32(msg.CmdData[3])<<24 if v2, ok := n.connMap.Load(id); ok { conn = v2.(common.Conn) } else { var ip string switch msg.CmdData[4] { case 1: ip = fmt.Sprintf("%d.%d.%d.%d:%d", msg.CmdData[5], msg.CmdData[6], msg.CmdData[7], msg.CmdData[8], int(msg.CmdData[9])<<8|int(msg.CmdData[10])) case 3: case 4: } udpconn := &serverConnect{} udpconn.conn, err = net.Dial("udp", ip) if err != nil { return } udpconn.node = n udpconn.id = id udpconn.write = make(chan *bytes.Buffer, 64) udpconn.close = 0 udpconn.windowsSize = 0 udpconn.wait = make(chan int) n.connMap.Store(udpconn.id, udpconn) go udpconn.handUdpReceive() conn = udpconn } switch msg.CmdData[4] { case 1: conn.Write(append([]byte{common.CMD_CONN_UDP_MSG}, msg.CmdData[11:]...)) } } case common.CMD_LISTEN: //fmt.Println("listen", string(data[common.Headlen+4:])) _l, err := net.Listen("tcp", string(msg.CmdData)) if err != nil { n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) return } else { n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, []byte{1}) } l := &serverListen{listen: _l, node: n, id: msg.CmdId} n.listenMap.Store(msg.CmdId, l) go l.Lisen() case common.CMD_REMOTE_SOCKS5: cfg, err := common.ParseAddr(string(msg.CmdData)) if err != nil { n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) return } l := &serverListen{node: n, id: msg.CmdId} l.listen, err = StartSocks5WithServer(cfg, n, l.id) if err != nil { n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, append([]byte{0}, err.Error()...)) return } else { n.Write(common.CMD_LISTEN_RESULT, msg.CmdId, []byte{1}) } n.listenMap.Store(l.id, l) case common.CMD_LISTEN_RESULT: if v, ok := currentNode.listenMap.Load(msg.CmdId); ok { if c, ok := v.(*clientListen); ok { if msg.CmdData[0] == 0 { select { case c.result <- errors.New(string(msg.CmdData[1:])): default: } } else { select { case c.result <- nil: default: } } } } case common.CMD_DELETE_LISTEN: if v, ok := n.listenMap.Load(msg.CmdId); ok { switch s := v.(type) { case *serverListen: s.Close(remoteClose) case *clientListen: s.Close(remoteClose) } } n.listenMap.Delete(msg.CmdId) case common.CMD_DELETE_LISTENCONN_BYID: deleteId := uint32(msg.CmdData[0]) | uint32(msg.CmdData[1])<<8 | uint32(msg.CmdData[2])<<16 | uint32(msg.CmdData[3])<<24 if v, ok := n.listenMap.Load(msg.CmdId); ok { if s, ok := v.(*serverListen); ok { conn, ok := s.connMap.Load(deleteId) if ok { conn.(*serverConnect).Close(remoteClose) s.connMap.Delete(deleteId) } } } case common.CMD_PWD: pwd, _ := os.Getwd() n.Write(common.CMD_PWD_RESULT, msg.CmdId, []byte(pwd)) case common.CMD_PWD_RESULT: if v, ok := n.loadQuery(msg.CmdId); ok { select { case v <- string(msg.CmdData): default: } } case common.CMD_GET_NODE: n.writeGetNodeResult(msg.CmdId) case common.CMD_GET_NODE_RESULT: l := clientLock.Lock() defer l.Unlock() var s []nodeMsg err = json.Unmarshal(msg.CmdData, &s) if err == nil { for _, _n := range s { if _n.UUID != currentNode.uuid { if v, ok := nodeMap[_n.UUID]; !ok { nodeMap[_n.UUID] = newNode(_n, n) } else { v.hostName = _n.HostName v.mainIp = _n.MainIp v.port = _n.Port if _n.Addr != "" { v.addr = _n.Addr } } } } } v, ok := n.loadQuery(msg.CmdId) if ok { //通知已更新列表 select { case v <- err: default: } } case common.CMD_GET_CURRENT_NODE: nmsg := nodeMsg{ UUID: currentNode.uuid, HostName: currentNode.hostName, Addr: currentNode.addr, MainIp: currentNode.mainIp, Port: currentNode.port, Goos: currentNode.goos, } b, _ := json.Marshal(nmsg) n.Write(common.CMD_GET_CURRENT_NODE_RESULT, msg.CmdId, b) case common.CMD_ADD_NODE: var nmsg nodeMsg err = json.Unmarshal(msg.CmdData, &nmsg) if err != nil { return } l := clientLock.Lock() defer l.Unlock() if v, ok := nodeMap[nmsg.UUID]; !ok { _n := newNode(nmsg, n) nodeMap[nmsg.UUID] = _n } else if nmsg.UUID != currentNode.uuid { v.port = nmsg.Port v.mainIp = nmsg.MainIp v.hostName = nmsg.HostName v.goos = nmsg.Goos if nmsg.Addr != "" { v.addr = nmsg.Addr } } case common.CMD_DIR: dirPth := string(msg.CmdData) dir, err := ioutil.ReadDir(dirPth) if err != nil { n.Write(common.CMD_DIR_RESULT, msg.CmdId, []byte("读取目录 "+dirPth+" 失败")) return } var s []string var maxlen int var hasdir string for _, fi := range dir { if len(fi.Name()) > maxlen { maxlen = len(fi.Name()) } if fi.IsDir() { hasdir = " " } } for _, fi := range dir { var p string name := bytes.Repeat([]byte(" "), maxlen) copy(name, fi.Name()) if fi.IsDir() { // 忽略目录 p = "