fix: telnet连接不一定支持调整窗口大小先移除

This commit is contained in:
TsMask
2024-09-12 19:45:33 +08:00
parent c58b987a23
commit cb6f8ea382
10 changed files with 13 additions and 23 deletions

View File

@@ -1,77 +0,0 @@
package telnet
import (
"fmt"
"strings"
)
// ConvertToStr 转换为string
func ConvertToStr(telnetClient *ConnTelnet, cmd string) (string, error) {
output, err := telnetClient.RunCMD(cmd)
if err != nil {
return "", err
}
str := strings.ToLower(output)
// 截断
index := strings.Index(str, "\n")
if index != -1 {
str = str[:index]
}
// 命令成功
if strings.Contains(str, "ok") || strings.Contains(str, "success") {
return str, nil
}
return "", fmt.Errorf(str)
}
// ConvertToMap 转换为map
func ConvertToMap(telnetClient *ConnTelnet, cmd string) (map[string]string, error) {
output, err := telnetClient.RunCMD(cmd)
if err != nil {
return nil, err
}
// 无数据
if strings.HasPrefix(output, "No ") {
// 截断
index := strings.Index(output, "\n")
if index != -1 {
output = output[:index]
}
return nil, fmt.Errorf(output)
}
// 初始化一个map用于存储拆分后的键值对
m := make(map[string]string)
var items []string
if strings.Contains(output, "\r\n") {
// 按照分隔符"\r\n"进行拆分
items = strings.Split(output, "\r\n")
} else if strings.Contains(output, "\n") {
// 按照分隔符"\n"进行拆分
items = strings.Split(output, "\n")
}
// 遍历拆分后的结果
for _, item := range items {
var pair []string
if strings.Contains(item, "=") {
// 按照分隔符"="进行拆分键值对
pair = strings.SplitN(item, "=", 2)
} else if strings.Contains(item, ":") {
// 按照分隔符":"进行拆分键值对
pair = strings.SplitN(item, ":", 2)
}
if len(pair) == 2 {
// 将键值对存入map中
m[pair[0]] = pair[1]
}
}
return m, err
}

View File

@@ -1,121 +0,0 @@
package telnet
import (
"bytes"
"fmt"
"net"
"strings"
"time"
)
// ConnTelnet 连接telnet对象
type ConnTelnet struct {
User string `json:"user"` // 主机用户名
Addr string `json:"addr"` // 主机地址
Port int64 `json:"port"` // telnet端口
Password string `json:"password"` // 认证密码
DialTimeOut time.Duration `json:"dialTimeOut"` // 连接超时断开
Client *net.Conn `json:"client"`
LastResult string `json:"lastResult"` // 记最后一次执行命令的结果
}
// NewClient 创建Telnet客户端
func (c *ConnTelnet) NewClient() (*ConnTelnet, error) {
// IPV6地址协议
proto := "tcp"
if strings.Contains(c.Addr, ":") {
proto = "tcp6"
c.Addr = fmt.Sprintf("[%s]", c.Addr)
}
addr := fmt.Sprintf("%s:%d", c.Addr, c.Port)
// 默认等待5s
if c.DialTimeOut == 0 {
c.DialTimeOut = 5 * time.Second
}
// 连接到 Telnet 服务器
client, err := net.DialTimeout(proto, addr, c.DialTimeOut)
if err != nil {
return nil, err
}
// 进行登录
time.Sleep(100 * time.Millisecond)
client.Write([]byte(c.User + "\r\n"))
time.Sleep(100 * time.Millisecond)
client.Write([]byte(c.Password + "\r\n"))
// fmt.Fprintln(client, c.User)
// fmt.Fprintln(client, c.Password)
// 调整窗口大小 (120 列 x 128 行)
// 需要确保接收方理解并正确处理发送窗口大小设置命令
client.Write([]byte{255, 251, 31})
client.Write([]byte{255, 250, 31, byte(120 >> 8), byte(120 & 0xFF), byte(128 >> 8), byte(128 & 0xFF), 255, 240})
c.Client = &client
// 排空连接登录的信息
c.RunCMD("")
return c, nil
}
// Close 关闭当前Telnet客户端
func (c *ConnTelnet) Close() {
if c.Client != nil {
(*c.Client).Close()
}
}
// RunCMD 执行单次命令
func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
if c.Client == nil {
return "", fmt.Errorf("telnet client not connected")
}
conn := *c.Client
// 写入命令
if cmd != "" {
if _, err := conn.Write([]byte(cmd)); err != nil {
return "", err
}
}
var buf bytes.Buffer
tmp := make([]byte, 1024)
for {
// 读取命令消息
n, err := conn.Read(tmp)
if n == 0 || err != nil {
tmp = nil
break
}
tmpStr := string(tmp[:n])
buf.WriteString(tmpStr)
// 是否有终止符
if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") {
tmp = nil
break
}
}
defer buf.Reset()
c.LastResult = buf.String()
return c.LastResult, nil
}
// NewClient 创建Telnet客户端会话对象
func (c *ConnTelnet) NewClientSession(cols, rows int) (*TelnetClientSession, error) {
if c.Client == nil {
return nil, fmt.Errorf("telnet client not connected")
}
s := &TelnetClientSession{
Client: *c.Client,
}
s.WindowChange(cols, rows)
return s, nil
}

View File

@@ -1,85 +0,0 @@
package telnet
import (
"bytes"
"fmt"
"net"
"time"
)
// TelnetClientSession Telnet客户端会话对象
type TelnetClientSession struct {
Client net.Conn
}
// Close 关闭会话
func (s *TelnetClientSession) Close() {
if s.Client != nil {
s.Client.Close()
}
}
// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns.
func (s *TelnetClientSession) WindowChange(h, w int) error {
if s.Client == nil {
return fmt.Errorf("client is nil to content write failed")
}
// 需要确保接收方理解并正确处理发送窗口大小设置命令
s.Client.Write([]byte{255, 251, 31})
s.Client.Write([]byte{255, 250, 31, byte(w >> 8), byte(w & 0xFF), byte(h >> 8), byte(h & 0xFF), 255, 240})
return nil
}
// Write 写入命令 不带回车(\n)也会执行根据客户端情况
func (s *TelnetClientSession) Write(cmd string) (int, error) {
if s.Client == nil {
return 0, fmt.Errorf("client is nil to content write failed")
}
return s.Client.Write([]byte(cmd))
}
// Read 读取结果 等待一会才有结果
func (s *TelnetClientSession) Read() []byte {
if s.Client == nil {
return []byte{}
}
buf := make([]byte, 1024)
// 设置读取超时时间为100毫秒
s.Client.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
_, err := s.Client.Read(buf)
if err != nil {
return []byte{}
}
return buf
}
// CombinedOutput 发送命令带结果返回
func (s *TelnetClientSession) CombinedOutput(cmd string) (string, error) {
n, err := s.Write(cmd)
if n == 0 || err != nil {
return "", err
}
var buf bytes.Buffer
tmp := make([]byte, 1024)
for {
// 设置读取超时时间为1000毫秒
s.Client.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
n, err := s.Client.Read(tmp)
if err != nil {
// 判断是否是超时错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
break
}
break
}
if n == 0 {
break
}
buf.Write(tmp[:n])
}
defer buf.Reset()
return buf.String(), nil
}