199 lines
4.3 KiB
Go
199 lines
4.3 KiB
Go
package omctelnet
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"be.ems/sshsvc/dborm"
|
|
)
|
|
|
|
type TelnetHandler struct {
|
|
ListenAddr string
|
|
ListenPort uint16
|
|
UserName string
|
|
Password string
|
|
AuthType string
|
|
MaxConnNum int
|
|
TagNE string
|
|
ListenHost string
|
|
|
|
connCount int
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func (t *TelnetHandler) handleTelnetAuth(authType, userName, password string) bool {
|
|
switch authType {
|
|
case "local":
|
|
if userName == t.UserName && password == t.Password {
|
|
return true
|
|
}
|
|
return false
|
|
case "radius", "omc":
|
|
exist, err := dborm.XEngDB().Table("OMC_PUB.sysUser").Where("userName=? AND password=md5(?)", userName, password).Exist()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return exist
|
|
|
|
default:
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (t *TelnetHandler) StartTelnetServer() {
|
|
listener, err := net.Listen("tcp", t.ListenHost)
|
|
if err != nil {
|
|
fmt.Println("Error starting Telnet server:", err)
|
|
return
|
|
}
|
|
defer listener.Close()
|
|
fmt.Println("Telnet server started on", t.ListenHost)
|
|
|
|
for {
|
|
conn, err := listener.Accept()
|
|
if err != nil {
|
|
fmt.Println("Error accepting Telnet connection:", err)
|
|
continue
|
|
}
|
|
|
|
t.mu.Lock()
|
|
if t.connCount >= int(t.MaxConnNum) {
|
|
t.mu.Unlock()
|
|
msg := fmt.Sprintf("Connection limit reached (limit=%d). Try again later.\r\n", t.MaxConnNum)
|
|
io.WriteString(conn, msg)
|
|
conn.Close()
|
|
continue
|
|
}
|
|
t.connCount++
|
|
t.mu.Unlock()
|
|
|
|
go t.handleTelnetConnection(conn)
|
|
}
|
|
}
|
|
|
|
func (t *TelnetHandler) handleTelnetConnection(conn net.Conn) {
|
|
defer func() {
|
|
t.mu.Lock()
|
|
t.connCount--
|
|
t.mu.Unlock()
|
|
}()
|
|
defer conn.Close()
|
|
|
|
reader := bufio.NewReader(conn)
|
|
writer := bufio.NewWriter(conn)
|
|
|
|
// 发送欢迎信息
|
|
|
|
writer.WriteString(fmt.Sprintf("\r\nWelcome to the %s server!\r\n", strings.ToUpper(t.TagNE)))
|
|
writer.Flush()
|
|
|
|
// 请求用户名
|
|
writer.WriteString("Username: ")
|
|
writer.Flush()
|
|
user, _ := reader.ReadString('\n')
|
|
user = strings.TrimSpace(user)
|
|
|
|
// 关闭回显模式
|
|
writer.Write([]byte{255, 251, 1}) // IAC WILL ECHO
|
|
writer.Flush()
|
|
|
|
// 请求密码
|
|
writer.WriteString("Password: ")
|
|
writer.Flush()
|
|
|
|
// 读取密码并清除控制序列
|
|
var passBuilder strings.Builder
|
|
for {
|
|
b, err := reader.ReadByte()
|
|
if err != nil {
|
|
return
|
|
}
|
|
if b == '\n' || b == '\r' {
|
|
break
|
|
}
|
|
if b == 255 { // IAC
|
|
reader.ReadByte() // 忽略下一个字节
|
|
reader.ReadByte() // 忽略下一个字节
|
|
} else {
|
|
passBuilder.WriteByte(b)
|
|
}
|
|
}
|
|
pass := passBuilder.String()
|
|
|
|
// 恢复回显模式
|
|
writer.Write([]byte{255, 252, 1}) // IAC WONT ECHO
|
|
writer.Flush()
|
|
|
|
if t.handleTelnetAuth(t.AuthType, user, pass) {
|
|
msg := fmt.Sprintf("\r\n\r\nLast login: %s from %s \r\n\r\n", time.Now().Format(time.RFC1123), conn.RemoteAddr())
|
|
writer.WriteString(msg)
|
|
writer.Flush()
|
|
t.HandleCommands(user, t.TagNE, reader, writer)
|
|
} else {
|
|
writer.WriteString("\r\nAuthentication failed!\r\n")
|
|
writer.Flush()
|
|
}
|
|
}
|
|
|
|
// 处理命令输
|
|
func (t *TelnetHandler) HandleCommands(user, tag string, reader *bufio.Reader, writer *bufio.Writer) {
|
|
header := fmt.Sprintf("[%s@%s]> ", user, tag)
|
|
clearLine := "\033[2K\r" // ANSI 转义序列,用于清除当前行
|
|
for {
|
|
var commandBuilder strings.Builder
|
|
for {
|
|
b, err := reader.ReadByte()
|
|
if err != nil {
|
|
return
|
|
}
|
|
if b == '\n' || b == '\r' {
|
|
break
|
|
}
|
|
if b == '\xff' || b == '\xfe' || b == '\x01' {
|
|
continue
|
|
}
|
|
if b == 127 { // 处理退格键
|
|
if commandBuilder.Len() > 0 {
|
|
// 手动截断字符串
|
|
command := commandBuilder.String()
|
|
command = command[:len(command)-1]
|
|
commandBuilder.Reset()
|
|
commandBuilder.WriteString(command)
|
|
writer.WriteString("\b \b") // 回显退格
|
|
writer.Flush()
|
|
}
|
|
} else {
|
|
// 回显用户输入的字符
|
|
writer.WriteByte(b)
|
|
writer.Flush()
|
|
commandBuilder.WriteByte(b)
|
|
}
|
|
}
|
|
command := strings.TrimSpace(commandBuilder.String())
|
|
|
|
// 处理其他命令
|
|
switch command {
|
|
case "hello":
|
|
writer.WriteString("\r\nHello, world!\r\n")
|
|
case "time":
|
|
writer.WriteString(fmt.Sprintf("\r\nCurrent time: %s\r\n", time.Now().Format(time.RFC1123)))
|
|
case "exit", "quit":
|
|
writer.WriteString("\r\n\r\nGoodbye!\r\n")
|
|
writer.Flush()
|
|
return
|
|
case "":
|
|
default:
|
|
writer.WriteString("\r\nUnknown command\r\n")
|
|
writer.Flush()
|
|
}
|
|
writer.WriteString(clearLine + header)
|
|
writer.Flush()
|
|
}
|
|
}
|