func SendLForwardCmd(peerNode *node.Node, sport uint16, lhost string, dport uint16) {
	lforwardPacketCmd := protocol.NetLForwardPacketCmd{
		Start:   1,
		DstPort: dport,
		SrcPort: sport,
		LHost:   utils.IpToUint32(net.ParseIP(lhost)),
	}
	packetHeader := protocol.PacketHeader{
		Separator: global.PROTOCOL_SEPARATOR,
		SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
		DstHashID: utils.UUIDToArray32(peerNode.HashID),
		CmdType:   protocol.LFORWARD,
	}
	peerNode.WritePacket(packetHeader, lforwardPacketCmd)
	LForwardTarget[crypto.Sha256(fmt.Sprintf("%s:%d", lhost, sport))] = true
}
SendLForwardCmd Forward a local sport to a remote dport lhost:sport => dport
package dispather
import (
	"fmt"
	"io"
	"net"
	"os"
	"github.com/Dliv3/Venom/crypto"
	"github.com/Dliv3/Venom/global"
	"github.com/Dliv3/Venom/netio"
	"github.com/Dliv3/Venom/node"
	"github.com/Dliv3/Venom/protocol"
	"github.com/Dliv3/Venom/utils"
	"github.com/cheggaaa/pb/v3"
)
func SendSyncCmd() {
	node.GNetworkTopology.InitNetworkMap()
	networkMap := node.GNetworkTopology.GenerateNetworkMapData()
	for i := range node.Nodes {
		if node.Nodes[i].DirectConnection {
			packetHeader := protocol.PacketHeader{
				Separator: global.PROTOCOL_SEPARATOR,
				SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
				DstHashID: utils.UUIDToArray32(node.Nodes[i].HashID),
				CmdType:   protocol.SYNC,
			}
			syncPacket := protocol.SyncPacket{
				NetworkMapLen: uint64(len(networkMap)),
				NetworkMap:    networkMap,
			}
			node.Nodes[i].WritePacket(packetHeader, syncPacket)
			node.CurrentNode.CommandBuffers[protocol.SYNC].ReadPacket(&packetHeader, &syncPacket)
			node.GNetworkTopology.ResolveNetworkMapData(syncPacket.NetworkMap)
		}
	}
	node.GNetworkTopology.UpdateRouteTable()
	node.GNodeInfo.UpdateNoteInfo()
	for key, value := range node.GNetworkTopology.RouteTable {
		if _, ok := node.Nodes[key]; !ok {
			node.Nodes[key] = node.NewNode(
				0,
				key,
				node.Nodes[value].Conn,
				false,
			)
		}
	}
}
func SendListenCmd(peerNode *node.Node, port uint16) {
	listenPacketCmd := protocol.ListenPacketCmd{
		Port: port,
	}
	packetHeader := protocol.PacketHeader{
		Separator: global.PROTOCOL_SEPARATOR,
		SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
		DstHashID: utils.UUIDToArray32(peerNode.HashID),
		CmdType:   protocol.LISTEN,
	}
	peerNode.WritePacket(packetHeader, listenPacketCmd)
	var listenPacketRet protocol.ListenPacketRet
	node.CurrentNode.CommandBuffers[protocol.LISTEN].ReadPacket(&packetHeader, &listenPacketRet)
	if listenPacketRet.Success == 1 {
		fmt.Println(fmt.Sprintf("the port %d is successfully listening on the remote node!", port))
	} else {
		fmt.Println(fmt.Sprintf("failed to open the port %d on the remote node!", port))
		fmt.Println(string(listenPacketRet.Msg))
	}
}
func SendConnectCmd(peerNode *node.Node, ip string, port uint16) {
	connectPacketCmd := protocol.ConnectPacketCmd{
		IP:   utils.IpToUint32(net.ParseIP(ip)),
		Port: port,
	}
	packetHeader := protocol.PacketHeader{
		Separator: global.PROTOCOL_SEPARATOR,
		SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
		DstHashID: utils.UUIDToArray32(peerNode.HashID),
		CmdType:   protocol.CONNECT,
	}
	peerNode.WritePacket(packetHeader, connectPacketCmd)
	var connectPacketRet protocol.ConnectPacketRet
	node.CurrentNode.CommandBuffers[protocol.CONNECT].ReadPacket(&packetHeader, &connectPacketRet)
	if connectPacketRet.Success == 1 {
		fmt.Println("successfully connect to the remote node!")
	} else {
		fmt.Println("failed to connect to the remote node!")
		fmt.Println(string(connectPacketRet.Msg))
	}
}
func SendDownloadCmd(peerNode *node.Node, remotePath string, localPath string) bool {
	if utils.FileExists(localPath) {
		fmt.Println("local file already exists")
		return false
	}
	localFile, err := os.OpenFile(localPath, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		fmt.Println(err)
		return false
	}
	defer localFile.Close()
	downloadPacketCmd := protocol.DownloadPacketCmd{
		PathLen: uint32(len(remotePath)),
		Path:    []byte(remotePath),
	}
	packetHeader := protocol.PacketHeader{
		Separator: global.PROTOCOL_SEPARATOR,
		SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
		DstHashID: utils.UUIDToArray32(peerNode.HashID),
		CmdType:   protocol.DOWNLOAD,
	}
	peerNode.WritePacket(packetHeader, downloadPacketCmd)
	var retPacketHeader protocol.PacketHeader
	var downloadPacketRet protocol.DownloadPacketRet
	err = node.CurrentNode.CommandBuffers[protocol.DOWNLOAD].ReadPacket(&retPacketHeader, &downloadPacketRet)
	if err != nil {
		fmt.Println(fmt.Sprintf("downloadpacket error: %s", err))
		return false
	}
	if downloadPacketRet.Success == 0 {
		fmt.Println("download file error: " + string(downloadPacketRet.Msg))
		if utils.FileExists(localPath) {
			os.Remove(localPath)
		}
		return false
	}
	if downloadPacketRet.FileLen > 1024*1024*100 {
		fmt.Printf("this file is too large (%s), do you still want to download it? (y/n) ",
			utils.GetFileSizeDescription(downloadPacketRet.FileLen))
		var choise string
		fmt.Scanf("%s", &choise)
		if choise != "y" {
			fmt.Println("stop download.")
			downloadPacketCmd.StillDownload = 0
			peerNode.WritePacket(packetHeader, downloadPacketCmd)
			if utils.FileExists(localPath) {
				os.Remove(localPath)
			}
			return false
		}
	}
	downloadPacketCmd.StillDownload = 1
	peerNode.WritePacket(packetHeader, downloadPacketCmd)
	err = node.CurrentNode.CommandBuffers[protocol.DOWNLOAD].ReadPacket(&packetHeader, &downloadPacketRet)
	if err != nil {
		fmt.Println(fmt.Sprintf("[-]downloadpacket error: %s", err))
		return false
	}
	var dataBlockSize = uint64(global.MAX_PACKET_SIZE - 4)
	loop := int64(downloadPacketRet.FileLen / dataBlockSize)
	remainder := downloadPacketRet.FileLen % dataBlockSize
	bar := pb.New64(int64(downloadPacketRet.FileLen))
	bar.SetTemplate(pb.Full)
	bar.Set(pb.Bytes, true)
	bar.Start()
	for ; loop >= 0; loop-- {
		if loop != 0 || (loop == 0 && remainder != 0) {
			var fileDataPacket protocol.FileDataPacket
			node.CurrentNode.CommandBuffers[protocol.DOWNLOAD].ReadPacket(&packetHeader, &fileDataPacket)
			_, err = localFile.Write(fileDataPacket.Data)
			if err != nil {
				fmt.Println(err)
			}
			bar.Add64(int64(fileDataPacket.DataLen))
		}
	}
	bar.Finish()
	fmt.Println("download file successfully!")
	return true
}
func SendUploadCmd(peerNode *node.Node, localPath string, remotePath string) bool {
	if !utils.FileExists(localPath) {
		fmt.Println("local file does not exists")
		return false
	}
	if utils.IsDir(localPath) {
		fmt.Println("local file cannot be a folder")
		return false
	}
	localFile, err := os.Open(localPath)
	if err != nil {
		fmt.Println(err)
		return false
	}
	defer localFile.Close()
	var fileSize = utils.GetFileSize(localPath)
	if fileSize > 1024*1024*100 {
		fmt.Printf("this file is too large (%s), do you still want to upload it? (y/n) ",
			utils.GetFileSizeDescription(uint64(fileSize)))
		var choise string
		fmt.Scanf("%s", &choise)
		if choise != "y" {
			fmt.Println("stop upload.")
			return false
		}
	}
	uploadPacketCmd := protocol.UploadPacketCmd{
		PathLen: uint32(len(remotePath)),
		Path:    []byte(remotePath),
		FileLen: uint64(fileSize),
	}
	packetHeader := protocol.PacketHeader{
		Separator: global.PROTOCOL_SEPARATOR,
		SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
		DstHashID: utils.UUIDToArray32(peerNode.HashID),
		CmdType:   protocol.UPLOAD,
	}
	peerNode.WritePacket(packetHeader, uploadPacketCmd)
	var packetHeaderRet protocol.PacketHeader
	var uploadPacketRet protocol.UploadPacketRet
	err = node.CurrentNode.CommandBuffers[protocol.UPLOAD].ReadPacket(&packetHeaderRet, &uploadPacketRet)
	if err != nil {
		fmt.Println(fmt.Sprintf("syncpacket error: %s", err))
		return false
	}
	if uploadPacketRet.Success == 0 {
		fmt.Println("upload file error: " + string(uploadPacketRet.Msg))
		return false
	}
	peerNode.WritePacket(packetHeader, uploadPacketCmd)
	var dataBlockSize = int64(global.MAX_PACKET_SIZE - 4)
	loop := fileSize / dataBlockSize
	remainder := fileSize % dataBlockSize
	bar := pb.New64(fileSize)
	bar.SetTemplate(pb.Full)
	bar.Set(pb.Bytes, true)
	bar.Start()
	var size int64
	for ; loop >= 0; loop-- {
		var buf []byte
		if loop > 0 {
			buf = make([]byte, dataBlockSize)
		} else {
			buf = make([]byte, remainder)
		}
		n, err := io.ReadFull(localFile, buf)
		if n > 0 {
			size += int64(n)
			dataPacket := protocol.FileDataPacket{
				DataLen: uint32(n),
				Data:    buf[0:n],
			}
			packetHeader := protocol.PacketHeader{
				Separator: global.PROTOCOL_SEPARATOR,
				SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
				DstHashID: utils.UUIDToArray32(peerNode.HashID),
				CmdType:   protocol.UPLOAD,
			}
			peerNode.WritePacket(packetHeader, dataPacket)
			bar.Add64(int64(n))
		}
		if err != nil {
			if err != io.EOF {
				fmt.Println("[-]read file error")
			}
			break
		}
	}
	bar.Finish()
	err = node.CurrentNode.CommandBuffers[protocol.UPLOAD].ReadPacket(&packetHeaderRet, &uploadPacketRet)
	if err != nil {
		fmt.Println(fmt.Sprintf("[-]syncpacket error: %s", err))
		return false
	}
	if uploadPacketRet.Success == 0 {
		fmt.Println("upload file error: " + string(uploadPacketRet.Msg))
		return false
	}
	fmt.Println("upload file successfully!")
	return true
}
func SendShellCmd(peerNode *node.Node) {
	shellPacketCmd := protocol.ShellPacketCmd{
		Start: 1,
	}
	packetHeader := protocol.PacketHeader{
		Separator: global.PROTOCOL_SEPARATOR,
		SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
		DstHashID: utils.UUIDToArray32(peerNode.HashID),
		CmdType:   protocol.SHELL,
	}
	peerNode.WritePacket(packetHeader, shellPacketCmd)
	var packetHeaderRet protocol.PacketHeader
	var shellPacketRet protocol.ShellPacketRet
	node.CurrentNode.CommandBuffers[protocol.SHELL].ReadPacket(&packetHeaderRet, &shellPacketRet)
	if shellPacketRet.Success == 1 {
		c := make(chan bool, 2)
		go CopyStdin2Node(os.Stdin, peerNode, c)
		go CopyNode2Stdout(peerNode, os.Stdout, c)
		<-c
		<-c
	} else {
		fmt.Println("something error.")
	}
}
func SendSocks5Cmd(peerNode *node.Node, port uint16) bool {
	err := netio.InitTCP("listen", fmt.Sprintf("0.0.0.0:%d", port), peerNode.HashID, localSocks5Server)
	if err != nil {
		fmt.Println("socks5 proxy startup error.")
		return false
	}
	fmt.Printf("a socks5 proxy of the target node has started up on the local port %d.\n", port)
	return true
}
func localSocks5Server(conn net.Conn, peerNodeID string, done chan bool, args ...interface{}) {
	peerNode := node.Nodes[peerNodeID]
	currentSessionID := node.Nodes[peerNodeID].DataBuffers[protocol.SOCKSDATA].GetSessionID()
	socks5ControlCmd := protocol.Socks5ControlPacketCmd{
		SessionID: currentSessionID,
		Start:     1,
	}
	packetHeader := protocol.PacketHeader{
		Separator: global.PROTOCOL_SEPARATOR,
		SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
		DstHashID: utils.UUIDToArray32(peerNodeID),
		CmdType:   protocol.SOCKS,
	}
	node.Nodes[peerNodeID].WritePacket(packetHeader, socks5ControlCmd)
	var packetHeaderRet protocol.PacketHeader
	var socks5ControlRet protocol.Socks5ControlPacketRet
	node.CurrentNode.CommandBuffers[protocol.SOCKS].ReadPacket(&packetHeaderRet, &socks5ControlRet)
	if socks5ControlRet.Success == 0 {
		fmt.Println("socks5 start error on agent")
		return
	}
	defer func() {
		socks5CloseData := protocol.NetDataPacket{
			SessionID: currentSessionID,
			Close:     1,
		}
		packetHeader := protocol.PacketHeader{
			Separator: global.PROTOCOL_SEPARATOR,
			CmdType:   protocol.SOCKSDATA,
			SrcHashID: utils.UUIDToArray32(node.CurrentNode.HashID),
			DstHashID: utils.UUIDToArray32(peerNode.HashID),
		}
		peerNode.WritePacket(packetHeader, socks5CloseData)
	}()
	node.Nodes[peerNodeID].DataBuffers[protocol.SOCKSDATA].NewDataBuffer(currentSessionID)
	c := make(chan bool, 2)
	go node.CopyNode2Net(peerNode, conn, currentSessionID, protocol.SOCKSDATA, c)
	if err := AdminHandShake(conn, peerNode, currentSessionID); err != nil {
		return
	}
	_, err := AdminParseTarget(conn, peerNode, currentSessionID)
	if err != nil {
		return
	}
	go node.CopyNet2Node(conn, peerNode, currentSessionID, protocol.SOCKSDATA, c)
	<-c
	<-done
}