goproxy/client/main.go

420 lines
8.6 KiB
Go
Raw Normal View History

2024-01-09 13:00:48 +00:00
package main
import (
"bufio"
2024-01-09 16:29:59 +00:00
"bytes"
2024-01-09 13:00:48 +00:00
"encoding/binary"
"fmt"
"io"
"net"
"os"
2024-01-09 16:29:59 +00:00
"os/exec"
2024-01-09 13:00:48 +00:00
"strings"
"time"
2024-01-09 16:29:59 +00:00
"github.com/creack/pty"
2024-01-09 13:00:48 +00:00
"github.com/rs/zerolog/log"
"github.com/urfave/cli/v2"
)
2024-01-09 16:29:59 +00:00
// 帧类型 1字节
// 帧长度 4字节
2024-01-22 01:52:50 +00:00
// 帧数据 帧长度大小的数据
2024-01-09 16:29:59 +00:00
2024-01-22 01:52:50 +00:00
// 心跳包 02 00 00 00 00
// 注册包 01 00 00 00 00 device_id 00 token 00 desc
// 创建SESSION 03 00 00 00
2024-01-09 13:00:48 +00:00
type Config struct {
2024-01-22 01:52:50 +00:00
DeviceId string
2024-09-23 16:08:53 +00:00
DeviceType string
DeviceDesc string
2024-01-09 13:00:48 +00:00
AddrServer string
}
const HEART_BEAT_INTERVAL = time.Second * 5 // 心跳超时时间
const (
MSG_TYPE_UNKOWNM = iota
MSG_TYPE_REGISTER
2024-01-22 01:52:50 +00:00
MSG_TYPE_HEARTBEAT
2024-01-09 13:00:48 +00:00
MSG_TYPE_SESSION_CREATE
MSG_TYPE_SESSION_DATA
MSG_TYPE_SESSION_DESTORY
MSG_TYPE_TUNNEL_CREATE
MSG_TYPE_MAX
)
2024-01-22 01:52:50 +00:00
type Session struct {
sessionId string
inBound *os.File
dev *Device
}
2024-01-09 13:00:48 +00:00
type Device struct {
id string
category string
desc string /* description of the device */
conn net.Conn
create_time int64 /* connection time */
active time.Time
registered bool
closed uint32
send chan []byte // Buffered channel of outbound messages.
2024-01-22 01:52:50 +00:00
sessions map[string]*Session
2024-01-09 13:00:48 +00:00
}
func main() {
app := &cli.App{
Name: "XZRobot Ops Server",
Usage: "The Server Side For xzrobot ops",
Version: "1.0.0",
Commands: []*cli.Command{
{
Name: "run",
Usage: "Run Server",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "log",
2024-09-23 16:08:53 +00:00
Value: "goproxy.log",
2024-01-09 13:00:48 +00:00
Usage: "log file path",
},
&cli.StringFlag{
Name: "conf",
Aliases: []string{"c"},
2024-09-23 16:08:53 +00:00
Value: "./goproxy.conf",
2024-01-09 13:00:48 +00:00
Usage: "config file to load",
},
&cli.StringFlag{
Name: "addr-dev",
Value: ":9011",
Usage: "address to listen device",
},
&cli.StringFlag{
Name: "addr-user",
Value: ":9012",
Usage: "address to listen user",
},
&cli.StringFlag{
Name: "db",
Value: "sqlite://database.db",
Usage: "database source",
},
},
Action: func(c *cli.Context) error {
runClient(c)
return nil
},
},
},
Action: func(c *cli.Context) error {
c.App.Command("run").Run(c)
return nil
},
}
err := app.Run(os.Args)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
2024-09-23 16:08:53 +00:00
func reConnect(dev *Device, cfg *Config) {
2024-01-09 13:00:48 +00:00
tcpConn, err := createTcpConn(cfg.AddrServer)
if err != nil {
fmt.Println("TCP Connect Error! " + err.Error())
return
}
fmt.Println(tcpConn.LocalAddr().String() + " : Client Connected")
2024-09-23 16:08:53 +00:00
dev.conn = tcpConn
dev.closed = 0
2024-01-09 16:29:59 +00:00
go dev.readLoop()
2024-01-22 01:52:50 +00:00
go dev.writeLoop()
2024-01-09 16:29:59 +00:00
//registe
s := make([][]byte, 3)
2024-01-22 01:52:50 +00:00
s[0] = []byte("jmq") //id
s[1] = []byte("desc") //desc
s[2] = []byte("token") //token
2024-01-09 16:29:59 +00:00
dev.WriteMsg(MSG_TYPE_REGISTER, bytes.Join(s, []byte{0}))
2024-09-23 16:08:53 +00:00
}
func runClient(c *cli.Context) {
cfg := &Config{
DeviceId: "jmq",
DeviceType: "device",
DeviceDesc: "jmq",
AddrServer: "dev.xzrobot.com:9011",
}
for {
dev := &Device{
id: cfg.DeviceId,
category: cfg.DeviceType,
desc: cfg.DeviceDesc,
create_time: time.Now().Unix(),
active: time.Now(),
registered: false,
closed: 1,
send: make(chan []byte, 1024),
sessions: make(map[string]*Session),
}
// tcpConn, err := createTcpConn(cfg.AddrServer)
// if err != nil {
// fmt.Println("TCP Connect Error! " + err.Error())
// return
// }
// fmt.Println(tcpConn.LocalAddr().String() + " : Client Connected")
// go dev.readLoop()
// go dev.writeLoop()
//registe
// s := make([][]byte, 3)
// s[0] = []byte("jmq") //id
// s[1] = []byte("desc") //desc
// s[2] = []byte("token") //token
// dev.WriteMsg(MSG_TYPE_REGISTER, bytes.Join(s, []byte{0}))
t := time.NewTicker(time.Second * 1)
for {
select {
case <-t.C:
if dev.closed == 1 {
reConnect(dev, cfg)
}
}
}
log.Info().Msgf("main loop exit")
}
2024-01-09 16:29:59 +00:00
}
func (dev *Device) WriteMsg(typ int, data []byte) {
b := []byte{byte(typ), 0, 0, 0, 0}
binary.BigEndian.PutUint32(b[1:], uint32(len(data)))
dev.send <- append(b, data...)
2024-01-09 13:00:48 +00:00
}
2024-01-09 16:29:59 +00:00
func (dev *Device) readLoop() {
defer dev.conn.Close()
2024-01-22 01:52:50 +00:00
defer log.Debug().Msgf("dev readLoop finished")
2024-01-09 13:00:48 +00:00
2024-01-09 16:29:59 +00:00
reader := bufio.NewReader(dev.conn)
2024-01-09 13:00:48 +00:00
for {
2024-01-22 01:52:50 +00:00
b, err := reader.Peek(3)
2024-01-09 13:00:48 +00:00
if err != nil {
if err != io.EOF && !strings.Contains(err.Error(), "use of closed network connection") {
log.Error().Msg(err.Error())
2024-09-23 16:08:53 +00:00
dev.closed = 1
2024-01-09 13:00:48 +00:00
}
return
}
2024-01-22 01:52:50 +00:00
reader.Discard(3)
2024-01-09 13:00:48 +00:00
msg_type := b[0]
if msg_type >= MSG_TYPE_MAX {
log.Error().Msgf("invalid msg type: %d", msg_type)
return
}
2024-01-22 01:52:50 +00:00
msg_length := binary.BigEndian.Uint16(b[1:])
2024-01-09 13:00:48 +00:00
data := make([]byte, msg_length)
_, err = io.ReadFull(reader, data)
if err != nil {
log.Error().Msg(err.Error())
return
}
2024-01-09 16:29:59 +00:00
dev.active = time.Now()
2024-01-09 13:00:48 +00:00
switch msg_type {
case MSG_TYPE_HEARTBEAT:
2024-01-22 01:52:50 +00:00
log.Info().Msgf("Receive Heartbeat Time: %d", time.Now().Unix())
2024-01-09 16:29:59 +00:00
case MSG_TYPE_REGISTER:
dev.registered = true
log.Info().Msgf("Device Registry Success")
2024-01-22 01:52:50 +00:00
case MSG_TYPE_SESSION_CREATE:
sessionId := string(data[:32])
cmd := exec.Command("bash")
ff, err := pty.Start(cmd)
if err != nil {
fmt.Println("Create Pty Error! " + err.Error())
return
}
s := &Session{
sessionId: sessionId,
inBound: nil,
dev: dev,
}
dev.sessions[sessionId] = s
go func(s *Session) {
defer ff.Close()
reader := bufio.NewReader(ff)
for {
buffer := []byte{}
len, err := reader.Read(buffer)
if err != nil {
log.Error().Msg(err.Error())
return
}
dev.WriteMsg(MSG_TYPE_SESSION_DATA, append([]byte(s.sessionId), buffer[:len]...))
}
}(s)
case MSG_TYPE_SESSION_DATA:
sessionId := string(data[:32])
if session, ok := dev.sessions[sessionId]; ok {
session.dev.WriteMsg(MSG_TYPE_SESSION_DATA, data)
// session.inBound.Write(data[32:])
return
}
2024-01-09 16:29:59 +00:00
case MSG_TYPE_TUNNEL_CREATE:
log.Info().Msgf("Receive Tunnel Create")
cmd := exec.Command("bash")
ff, err := pty.Start(cmd)
if err != nil {
fmt.Println("Create Pty Error! " + err.Error())
return
}
2024-01-09 13:00:48 +00:00
2024-01-10 01:27:19 +00:00
remoteConn, err := createTcpConn("192.168.21.146:10001")
2024-01-09 16:29:59 +00:00
if err != nil {
fmt.Println("Create remoteAddr Error! " + err.Error())
return
}
go func() {
defer ff.Close()
defer remoteConn.Close()
_, err := io.Copy(ff, remoteConn)
if err != nil {
fmt.Println("Copy error! " + err.Error())
return
}
}()
go func() {
defer ff.Close()
defer remoteConn.Close()
_, err := io.Copy(remoteConn, ff)
if err != nil {
fmt.Println("Copy error! " + err.Error())
return
}
}()
// createTunnel("localhost:10001", "localhost:20001")
2024-01-09 13:00:48 +00:00
default:
log.Error().Msgf("invalid msg type: %d", msg_type)
}
}
}
2024-01-09 16:29:59 +00:00
func (dev *Device) writeLoop() {
defer dev.conn.Close()
2024-09-23 16:08:53 +00:00
defer log.Debug().Msgf("dev writeLoop finished")
ticker := time.NewTicker(time.Second)
2024-01-09 13:00:48 +00:00
ninactive := 0
lastHeartbeat := time.Now()
for {
select {
case msg, ok := <-dev.send:
if !ok {
return
}
_, err := dev.conn.Write(msg)
if err != nil {
log.Error().Msg(err.Error())
2024-09-23 16:08:53 +00:00
dev.closed = 1
2024-01-09 13:00:48 +00:00
return
}
case <-ticker.C:
now := time.Now()
if now.Sub(dev.active) > HEART_BEAT_INTERVAL*3/2 {
if dev.id == "" {
return
}
log.Error().Msgf("Inactive device in long time: %s", dev.id)
if ninactive > 3 {
log.Error().Msgf("Inactive 3 times, now kill it: %s", dev.id)
2024-09-23 16:08:53 +00:00
dev.closed = 1
2024-01-09 13:00:48 +00:00
return
}
ninactive = ninactive + 1
}
if now.Sub(lastHeartbeat) > HEART_BEAT_INTERVAL-1 {
lastHeartbeat = now
if len(dev.send) < 1 {
2024-09-23 16:08:53 +00:00
log.Info().Msgf("Transmit Heartbeat Time: %d", time.Now().Unix())
2024-01-09 13:00:48 +00:00
dev.WriteMsg(MSG_TYPE_HEARTBEAT, []byte{})
}
}
}
}
}
func createTcpConn(addr string) (*net.TCPConn, error) {
tcpConn, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
return nil, err
}
conn, err := net.DialTCP("tcp", nil, tcpConn)
if err != nil {
return nil, err
}
return conn, nil
}
func createTunnel(localAddr string, remoteAddr string) {
localConn, err := createTcpConn(localAddr)
if err != nil {
fmt.Println("Create LocalConn Error! " + err.Error())
return
}
remoteConn, err := createTcpConn(remoteAddr)
if err != nil {
fmt.Println("Create remoteAddr Error! " + err.Error())
return
}
go func() {
2024-01-09 16:29:59 +00:00
defer localConn.Close()
defer remoteConn.Close()
2024-01-09 13:00:48 +00:00
_, err := io.Copy(localConn, remoteConn)
if err != nil {
fmt.Println("Copy error! " + err.Error())
return
}
}()
go func() {
2024-01-09 16:29:59 +00:00
defer localConn.Close()
defer remoteConn.Close()
2024-01-09 13:00:48 +00:00
_, err := io.Copy(remoteConn, localConn)
if err != nil {
fmt.Println("Copy error! " + err.Error())
return
}
}()
}