diff --git a/sshsvc/telnet/telnet.go b/sshsvc/telnet/telnet.go new file mode 100644 index 00000000..fbc4f6bb --- /dev/null +++ b/sshsvc/telnet/telnet.go @@ -0,0 +1,308 @@ +package telnetOMC + +import ( + "bufio" + "fmt" + "strings" + "sync" + "time" + + "be.ems/lib/dborm" + "github.com/reiver/go-telnet" +) + +type TelnetHandler struct { + ListenAddr string + ListenPort uint16 + UserName string + Password string + AuthType string + MaxConnNum uint8 + TagNE string + ListenHost string + + connCount int + mu sync.Mutex +} + +func (t *TelnetHandler) HandleTelnetConnection(w telnet.Writer, r telnet.Reader) { + t.mu.Lock() + if t.connCount >= int(t.MaxConnNum) { + t.mu.Unlock() + w.Write([]byte("Connection limit reached. Try again later.\r\n")) + return + } + t.connCount++ + t.mu.Unlock() + + defer func() { + t.mu.Lock() + t.connCount-- + t.mu.Unlock() + }() + + reader := bufio.NewReader(r) + writer := bufio.NewWriter(w) + + // 发送欢迎信息 + writer.WriteString("Welcome to the Telnet server!\r\n") + 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.HandleAuth(t.AuthType, user, pass) { + writer.WriteString("\r\nAuthentication successful!\r\n") + 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 { + writer.WriteString(clearLine + header) + writer.Flush() + + var commandBuilder strings.Builder + for { + b, err := reader.ReadByte() + if err != nil { + return + } + if b == '\n' || b == '\r' { + break + } + 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()) + + // command, err := reader.ReadString('\n') + // if err != nil { + // return + // } + // command = strings.TrimSpace(command) + + // 处理其他命令 + 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\nGoodbye!\r\n") + writer.Flush() + return + case "": + // case "\n": + // case "\r\n": + case "\xff\xfe\x01": + default: + writer.WriteString("\r\nUnknown command\r\n") + } + + writer.Flush() + } +} + +func (t *TelnetHandler) ServeTELNET(ctx telnet.Context, w telnet.Writer, r telnet.Reader) { + t.mu.Lock() + if t.connCount >= int(t.MaxConnNum) { + t.mu.Unlock() + w.Write([]byte("Connection limit reached. Try again later.\r\n")) + return + } + t.connCount++ + t.mu.Unlock() + + defer func() { + t.mu.Lock() + t.connCount-- + t.mu.Unlock() + }() + + writer := bufio.NewWriter(w) + reader := bufio.NewReader(r) + // 发送欢迎信息 + writer.WriteString("Welcome to the Telnet server!\r\n") + 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() + + // w.Write([]byte("Welcome to the Telnet server!\r\n")) + // w.Write([]byte("Username: ")) + // writer := bufio.NewWriter(w) + // reader := bufio.NewReader(r) + // writer.Flush() + + // user, _ := reader.ReadString('\n') + // user = strings.TrimSpace(user) + + // w.Write([]byte("Password: ")) + // writer.Flush() + + // pass, _ := reader.ReadString('\n') + // pass = strings.TrimSpace(pass) + + if !t.HandleAuth(t.AuthType, user, pass) { + w.Write([]byte("\r\nAuthentication failed!\r\n")) + writer.Flush() + return + } + + w.Write([]byte("\r\nAuthentication successful!\r\n")) + writer.Flush() + + header := fmt.Sprintf("[%s@%s]> ", t.UserName, t.TagNE) + for { + w.Write([]byte(header)) + var command strings.Builder + for { + b := make([]byte, 1) + _, err := r.Read(b) + if err != nil { + return + } + if b[0] == '\r' || b[0] == '\n' { + break + } + command.WriteByte(b[0]) + } + cmd := strings.TrimSpace(command.String()) + switch cmd { + case "hello": + w.Write([]byte("Hello, world!\r\n")) + case "time": + w.Write([]byte(fmt.Sprintf("Current time: %s\r\n", time.Now().Format(time.RFC1123)))) + case "exit", "quit": + w.Write([]byte("Goodbye!\r\n")) + return + default: + w.Write([]byte("Unknown command\r\n")) + } + } +} + +func (t *TelnetHandler) HandleAuth(authType, userName, password string) bool { + switch authType { + case "local": + if userName == t.UserName && password == t.Password { + return true + } + return false + case "radius": + exist, err := dborm.XEngDB().Table("OMC_PUB.sysUser").Where("userName=? AND password=md5(?)", userName, password).Exist() + if err != nil { + return false + } + return exist + case "omc": + + default: + } + + return false +} + +func (t *TelnetHandler) StartTelnetServer() { + // //handle := TelnetHandler{} + // listener, err := net.Listen("tcp", t.ListenHost) + // if err != nil { + // fmt.Println("Error starting Telnet server:", err) + // return + // } + // defer listener.Close() + // fmt.Printf("Telnet server started on %s\n", t.ListenHost) + + // go telnet.Serve(listener, t) + go telnet.ListenAndServe(t.ListenHost, t) +}