From 73043ccdb435ca96c2c36c3fd81364ae53c0f4d2 Mon Sep 17 00:00:00 2001 From: simonzhangsz Date: Fri, 13 Sep 2024 20:47:24 +0800 Subject: [PATCH 1/5] fix: telnet serve enhancement --- sshsvc/sshsvc.go | 114 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 20 deletions(-) diff --git a/sshsvc/sshsvc.go b/sshsvc/sshsvc.go index 6952f893..bb7c5130 100644 --- a/sshsvc/sshsvc.go +++ b/sshsvc/sshsvc.go @@ -19,6 +19,7 @@ import ( "be.ems/sshsvc/config" "be.ems/sshsvc/logmml" "be.ems/sshsvc/snmp" + telnetOMC "be.ems/sshsvc/telnet" //"github.com/gliderlabs/ssh" "golang.org/x/crypto/ssh" @@ -110,22 +111,34 @@ func main() { log.Fatal("Failed to Listen: ", err) os.Exit(4) } - fmt.Printf("MML SSH server startup, listen port:%d\n", conf.Sshd.ListenPort) + //fmt.Printf("MML SSH server startup, listen port:%d\n", conf.Sshd.ListenPort) // 启动telnet服务器 - telnetUri := fmt.Sprintf("%s:%d", conf.TelnetServer.ListenAddr, conf.TelnetServer.ListenPort) + //telnetUri := fmt.Sprintf("%s:%d", conf.TelnetServer.ListenAddr, conf.TelnetServer.ListenPort) // telnetListener, err := net.Listen("tcp", telnetUri) // if err != nil { // log.Fatal("Failed to Listen: ", err) // os.Exit(4) // } - fmt.Printf("MML Telnet server startup, listen port:%d\n", conf.TelnetServer.ListenPort) + //fmt.Printf("MML Telnet server startup, listen port:%d\n", conf.TelnetServer.ListenPort) // telnetconn, err := telnetListener.Accept() // if err != nil { // log.Fatal("Failed to accept telnet connection: ", err) // os.Exit(6) // } - go startTelnetServer(telnetUri) + telnetSvc := telnetOMC.TelnetHandler{ + // ListenAddr: conf.TelnetServer.ListenAddr, + // ListenPort: conf.TelnetServer.ListenPort, + // UserName: conf.TelnetServer.UserName, + // Password: conf.TelnetServer.Password, + // AuthType: conf.TelnetServer.AuthType, + // MaxConnNum: conf.TelnetServer.MaxConnNum, + // TagNE: conf.TelnetServer.TagNE, + ListenHost: conf.TelnetServer.ListenAddr + ":" + strconv.Itoa(int(conf.TelnetServer.ListenPort)), + } + // go telnetSvc.StartTelnetServer() + go StartTelnetServer(telnetSvc.ListenHost) + snmpSvc := snmp.SNMPService{ ListenAddr: conf.SNMPServer.ListenAddr, ListenPort: conf.SNMPServer.ListenPort, @@ -183,7 +196,7 @@ func handleAuth(authType, userName, password string) bool { return false } -func startTelnetServer(addr string) { +func StartTelnetServer(addr string) { listener, err := net.Listen("tcp", addr) if err != nil { fmt.Println("Error starting Telnet server:", err) @@ -202,7 +215,7 @@ func startTelnetServer(addr string) { telnetMu.Lock() if telnetCC >= int(conf.TelnetServer.MaxConnNum) { telnetMu.Unlock() - io.WriteString(conn, "Connection limit reached. Try again later.\n") + io.WriteString(conn, "Connection limit reached. Try again later.\r\n") conn.Close() continue } @@ -225,7 +238,7 @@ func handleTelnetConnection(conn net.Conn) { writer := bufio.NewWriter(conn) // 发送欢迎信息 - writer.WriteString("Welcome to the Telnet server!\n") + writer.WriteString("Welcome to the Telnet server!\r\n") writer.Flush() // 请求用户名 @@ -266,41 +279,102 @@ func handleTelnetConnection(conn net.Conn) { writer.Flush() if handleAuth(conf.TelnetServer.AuthType, user, pass) { - writer.WriteString("\nAuthentication successful!\n") + writer.WriteString("\r\nAuthentication successful!\r\n") writer.Flush() - handleCommands(user, conf.TelnetServer.TagNE, reader, writer) + HandleCommands(user, conf.TelnetServer.TagNE, reader, writer) } else { - writer.WriteString("\nAuthentication failed!\n") + writer.WriteString("\r\nAuthentication failed!\r\n") + writer.Flush() + } +} + +// 处理命令输 +func 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\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() + } + writer.WriteString(clearLine + header) writer.Flush() } } // 处理命令输入 -func handleCommands(user, tag string, reader *bufio.Reader, writer *bufio.Writer) { +func HandleCommandsNew(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() + command, err := reader.ReadString('\n') if err != nil { return } command = strings.TrimSpace(command) - // 处理其他命令 + + // Handle other commands switch command { case "hello": - writer.WriteString("Hello, world!\n") + writer.WriteString("\r\nHello, world!\r\n") case "time": - writer.WriteString(fmt.Sprintf("Current time: %s\n", time.Now().Format(time.RFC1123))) + writer.WriteString(fmt.Sprintf("\r\nCurrent time: %s\r\n", time.Now().Format(time.RFC1123))) case "exit", "quit": - writer.WriteString("Goodbye!\n") + writer.WriteString("\r\nGoodbye!\r\n") writer.Flush() return - case "": - case "\n": - case "\xff\xfe\x01": default: - writer.WriteString("Unknown command\n") + writer.WriteString("\r\nUnknown command\r\n") } - writer.WriteString(header) + writer.Flush() } } From 8a0f4d848aa87737c5e68aa4513bda2b77fd1980 Mon Sep 17 00:00:00 2001 From: simonzhangsz Date: Fri, 13 Sep 2024 20:50:17 +0800 Subject: [PATCH 2/5] fix: telnet server enhancement... --- sshsvc/telnet/telnet.go | 308 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 sshsvc/telnet/telnet.go 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) +} From a0ad5fbd531e1c04f3787e04106660cbb92dc2be Mon Sep 17 00:00:00 2001 From: simonzhangsz Date: Sat, 14 Sep 2024 14:43:29 +0800 Subject: [PATCH 3/5] fix: remove agrandtech string --- config/etc/default/restconf.yaml | 4 ++-- restagent/etc/restconf.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/etc/default/restconf.yaml b/config/etc/default/restconf.yaml index 24032cac..378d0dbb 100644 --- a/config/etc/default/restconf.yaml +++ b/config/etc/default/restconf.yaml @@ -133,9 +133,9 @@ alarm: alarmEmailForward: enable: true emailList: - smtp: mail.agrandtech.com + smtp: mail.smtp.com port: 25 - user: smtpext@agrandtech.com + user: smtpext@smtp.com password: "1000smtp@omc!" tlsSkipVerify: true alarmSMSForward: diff --git a/restagent/etc/restconf.yaml b/restagent/etc/restconf.yaml index ddc13e5f..11d78526 100644 --- a/restagent/etc/restconf.yaml +++ b/restagent/etc/restconf.yaml @@ -130,9 +130,9 @@ alarm: alarmEmailForward: enable: true emailList: - smtp: mail.agrandtech.com + smtp: mail.smtp.com port: 25 - user: smtpext@agrandtech.com + user: smtpext@smtp.com password: "1000smtp@omc!" tlsSkipVerify: true alarmSMSForward: From 9e71a35cd75ebc82f2c2df388d015091faca82b8 Mon Sep 17 00:00:00 2001 From: simonzhangsz Date: Sat, 14 Sep 2024 14:44:02 +0800 Subject: [PATCH 4/5] fix: telnet server update --- sshsvc/sshsvc.go | 57 ++-------- sshsvc/telnet/telnet.go | 235 +++++++++++----------------------------- 2 files changed, 72 insertions(+), 220 deletions(-) diff --git a/sshsvc/sshsvc.go b/sshsvc/sshsvc.go index bb7c5130..5964e062 100644 --- a/sshsvc/sshsvc.go +++ b/sshsvc/sshsvc.go @@ -19,7 +19,7 @@ import ( "be.ems/sshsvc/config" "be.ems/sshsvc/logmml" "be.ems/sshsvc/snmp" - telnetOMC "be.ems/sshsvc/telnet" + omctelnet "be.ems/sshsvc/telnet" //"github.com/gliderlabs/ssh" "golang.org/x/crypto/ssh" @@ -126,18 +126,18 @@ func main() { // os.Exit(6) // } - telnetSvc := telnetOMC.TelnetHandler{ - // ListenAddr: conf.TelnetServer.ListenAddr, - // ListenPort: conf.TelnetServer.ListenPort, - // UserName: conf.TelnetServer.UserName, - // Password: conf.TelnetServer.Password, - // AuthType: conf.TelnetServer.AuthType, - // MaxConnNum: conf.TelnetServer.MaxConnNum, - // TagNE: conf.TelnetServer.TagNE, + telnetSvc := omctelnet.TelnetHandler{ + ListenAddr: conf.TelnetServer.ListenAddr, + ListenPort: conf.TelnetServer.ListenPort, + UserName: conf.TelnetServer.UserName, + Password: conf.TelnetServer.Password, + AuthType: conf.TelnetServer.AuthType, + MaxConnNum: conf.TelnetServer.MaxConnNum, + TagNE: conf.TelnetServer.TagNE, ListenHost: conf.TelnetServer.ListenAddr + ":" + strconv.Itoa(int(conf.TelnetServer.ListenPort)), } - // go telnetSvc.StartTelnetServer() - go StartTelnetServer(telnetSvc.ListenHost) + go telnetSvc.StartTelnetServer() + // go StartTelnetServer(telnetSvc.ListenHost) snmpSvc := snmp.SNMPService{ ListenAddr: conf.SNMPServer.ListenAddr, @@ -335,9 +335,6 @@ func HandleCommands(user, tag string, reader *bufio.Reader, writer *bufio.Writer writer.Flush() return case "": - // case "\n": - // case "\r\n": - case "\xff\xfe\x01": default: writer.WriteString("\r\nUnknown command\r\n") writer.Flush() @@ -347,38 +344,6 @@ func HandleCommands(user, tag string, reader *bufio.Reader, writer *bufio.Writer } } -// 处理命令输入 -func HandleCommandsNew(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() - - command, err := reader.ReadString('\n') - if err != nil { - return - } - command = strings.TrimSpace(command) - - // Handle other commands - 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 - default: - writer.WriteString("\r\nUnknown command\r\n") - } - - writer.Flush() - } -} - func handleSSHConnection(conn net.Conn, serverConfig *ssh.ServerConfig) { // SSH握手 sshConn, chans, reqs, err := ssh.NewServerConn(conn, serverConfig) diff --git a/sshsvc/telnet/telnet.go b/sshsvc/telnet/telnet.go index fbc4f6bb..28622b44 100644 --- a/sshsvc/telnet/telnet.go +++ b/sshsvc/telnet/telnet.go @@ -1,14 +1,15 @@ -package telnetOMC +package omctelnet import ( "bufio" "fmt" + "io" + "net" "strings" "sync" "time" "be.ems/lib/dborm" - "github.com/reiver/go-telnet" ) type TelnetHandler struct { @@ -25,24 +26,66 @@ type TelnetHandler struct { 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")) +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 } - t.connCount++ - t.mu.Unlock() + 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() + io.WriteString(conn, "Connection limit reached. Try again later.\r\n") + 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(r) - writer := bufio.NewWriter(w) + reader := bufio.NewReader(conn) + writer := bufio.NewWriter(conn) // 发送欢迎信息 writer.WriteString("Welcome to the Telnet server!\r\n") @@ -85,7 +128,7 @@ func (t *TelnetHandler) HandleTelnetConnection(w telnet.Writer, r telnet.Reader) writer.Write([]byte{255, 252, 1}) // IAC WONT ECHO writer.Flush() - if t.HandleAuth(t.AuthType, user, pass) { + if t.handleTelnetAuth(t.AuthType, user, pass) { writer.WriteString("\r\nAuthentication successful!\r\n") writer.Flush() t.HandleCommands(user, t.TagNE, reader, writer) @@ -95,14 +138,11 @@ func (t *TelnetHandler) HandleTelnetConnection(w telnet.Writer, r telnet.Reader) } } -// 处理命令输入 +// 处理命令输 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() @@ -112,6 +152,9 @@ func (t *TelnetHandler) HandleCommands(user, tag string, reader *bufio.Reader, w if b == '\n' || b == '\r' { break } + if b == '\xff' || b == '\xfe' || b == '\x01' { + continue + } if b == 127 { // 处理退格键 if commandBuilder.Len() > 0 { // 手动截断字符串 @@ -131,12 +174,6 @@ func (t *TelnetHandler) HandleCommands(user, tag string, reader *bufio.Reader, w } command := strings.TrimSpace(commandBuilder.String()) - // command, err := reader.ReadString('\n') - // if err != nil { - // return - // } - // command = strings.TrimSpace(command) - // 处理其他命令 switch command { case "hello": @@ -148,161 +185,11 @@ func (t *TelnetHandler) HandleCommands(user, tag string, reader *bufio.Reader, w writer.Flush() return case "": - // case "\n": - // case "\r\n": - case "\xff\xfe\x01": default: writer.WriteString("\r\nUnknown command\r\n") + writer.Flush() } - + writer.WriteString(clearLine + header) 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) -} From e9e5822d6ceab1c8b58bd837a793b89c2d6b5e1a Mon Sep 17 00:00:00 2001 From: simonzhangsz Date: Fri, 20 Sep 2024 11:03:43 +0800 Subject: [PATCH 5/5] fix: add parameter dataCoding and serverNumber to alarm SMS forward --- config/etc/default/restconf.yaml | 3 + config/param/omc_param_config.yaml | 14 +++ features/fm/smsforward.go | 119 +++++++----------- restagent/config/config.go | 38 ++++-- restagent/etc/restconf.yaml | 3 + src/modules/network_element/ne_config_test.go | 2 +- 6 files changed, 98 insertions(+), 81 deletions(-) diff --git a/config/etc/default/restconf.yaml b/config/etc/default/restconf.yaml index 378d0dbb..8790ea85 100644 --- a/config/etc/default/restconf.yaml +++ b/config/etc/default/restconf.yaml @@ -129,6 +129,7 @@ omc: # TLS Skip verify: true/false # email/sms # smProxy: sms(Short Message Service)/smsc(SMS Centre) +# dataCoding: 0:UCS2, 1:ASCII, 2:LATIN1 alarm: alarmEmailForward: enable: true @@ -145,6 +146,8 @@ alarm: systemID: "omc" password: "omc123" systemType: "UTRAN" + dataCoding: 0 + serviceNumber: "OMC" sms: apiURL: http://smsc.xxx.com/ accessKeyID: xxxx diff --git a/config/param/omc_param_config.yaml b/config/param/omc_param_config.yaml index 7b3ad248..b2c96186 100644 --- a/config/param/omc_param_config.yaml +++ b/config/param/omc_param_config.yaml @@ -98,3 +98,17 @@ omc: filter: "" display: "System Type" comment: "" + - name: "dataCoding" + type: "enum" + value: "ASCII" + access: "rw" + filter: '{"0":"UCS2","1":"ASCII","2":"LATIN1"}' + display: "Data Coding" + comment: "Short message coding type" + - name: "serviceNumber" + type: "string" + value: "OMC" + access: "rw" + filter: "3~20" + display: "Service Number" + comment: "It is the source address and length is between 3 and 20" \ No newline at end of file diff --git a/features/fm/smsforward.go b/features/fm/smsforward.go index e5d25bde..01f85d33 100644 --- a/features/fm/smsforward.go +++ b/features/fm/smsforward.go @@ -90,37 +90,24 @@ func AlarmForwardBySMS(alarmData *Alarm) (string, error) { case http.StatusOK, http.StatusAccepted, http.StatusNoContent, http.StatusCreated: return userList, nil default: - err := fmt.Errorf("Failed to send SMS: %s(Code=%d)", resp.Status, resp.StatusCode) - log.Error(err) + log.Error(fmt.Errorf("failed to send SMS: %s(Code=%d)", resp.Status, resp.StatusCode)) return userList, err } } +var smsForward = &(config.GetYamlConfig().Alarm.SMSCForward) + func AlarmForwardBySMPP(alarmData *Alarm) (string, error) { log.Info("AlarmForwardBySMPP processing... ") - // toUsers, err := dborm.XormGetAlarmForward("SMS") - // if err != nil { - // log.Error("Failed to XormGetAlarmForward:", err) - // return "", err - // } else if toUsers == nil { - // err := errors.New("not found forward phone number") - // log.Error(err) - // return "", err - // } - // userList := strings.Join(*toUsers, ",") - - userList := config.GetYamlConfig().Alarm.SMSCForward.MobileList + userList := smsForward.MobileList auth := gosmpp.Auth{ - SMSC: config.GetYamlConfig().Alarm.SMSCForward.SMSCAddr, - SystemID: config.GetYamlConfig().Alarm.SMSCForward.SystemID, - Password: config.GetYamlConfig().Alarm.SMSCForward.Password, - SystemType: config.GetYamlConfig().Alarm.SMSCForward.SystemType, + SMSC: smsForward.SMSCAddr, + SystemID: smsForward.SystemID, + Password: smsForward.Password, + SystemType: smsForward.SystemType, } - // conn, err := gosmpp.NonTLSDialer(auth.SMSC) - // connection := gosmpp.NewConnection(conn) - trans, err := gosmpp.NewSession( gosmpp.TXConnector(gosmpp.NonTLSDialer, auth), gosmpp.Settings{ @@ -150,17 +137,22 @@ func AlarmForwardBySMPP(alarmData *Alarm) (string, error) { _ = trans.Close() }() - // sending SMS(s) - // var results []string - // for _, toUser := range *toUsers { - message := "Alarm Notification: " + alarmData.AlarmTitle + " from " + alarmData.NeType + " " + alarmData.NeId + " at " + alarmData.EventTime - if err = trans.Transceiver().Submit(newSubmitSM(userList, message)); err != nil { - // result := fmt.Sprintf("Failed to submit %s hort message:%s", toUser, err.Error()) - // results = append(results, result) - log.Error("Failed to submit hort message:", err) - return userList, err + message := "Alarm Notification: " + alarmData.AlarmTitle + " from " + alarmData.NeType + "_" + alarmData.NeId + " at " + alarmData.EventTime + for _, user := range strings.Split(userList, ",") { + sm, err := newSubmitSM(user, message) + if err != nil { + log.Errorf("Failed to newSubmitSM %s short message: %v", user, err) + writeLog(alarmData, user, "SMS", err) + continue + } + if err = trans.Transceiver().Submit(sm); err != nil { + log.Errorf("Failed to Submit %s short message: %v", user, err) + writeLog(alarmData, user, "SMS", err) + continue + } + writeLog(alarmData, user, "SMS", nil) } - // } + return userList, nil } @@ -191,61 +183,42 @@ func writeLog(alarmData *Alarm, toUser, forwardBy string, err error) error { return nil } -func handlePDU() func(pdu.PDU) (pdu.PDU, bool) { - return func(p pdu.PDU) (pdu.PDU, bool) { - switch pd := p.(type) { - case *pdu.Unbind: - log.Trace("Unbind Received") - return pd.GetResponse(), true - - case *pdu.UnbindResp: - log.Trace("UnbindResp Received") - - case *pdu.SubmitSMResp: - log.Trace("SubmitSMResp Received") - - case *pdu.GenericNack: - log.Trace("GenericNack Received") - - case *pdu.EnquireLinkResp: - fmt.Println("EnquireLinkResp Received") - - case *pdu.EnquireLink: - log.Trace("EnquireLink Received") - return pd.GetResponse(), false - - case *pdu.DataSM: - log.Trace("DataSM receiver") - return pd.GetResponse(), false - - case *pdu.DeliverSM: - log.Trace("DeliverSM receiver") - return pd.GetResponse(), false - } - return nil, false - } -} - -func newSubmitSM(phoneNumber string, message string) *pdu.SubmitSM { +func newSubmitSM(phoneNumber string, message string) (*pdu.SubmitSM, error) { // build up submitSM srcAddr := pdu.NewAddress() srcAddr.SetTon(5) srcAddr.SetNpi(0) - _ = srcAddr.SetAddress("alarm notification:") - + err := srcAddr.SetAddress(smsForward.ServiceNumber) + if err != nil { + return nil, err + } destAddr := pdu.NewAddress() destAddr.SetTon(1) destAddr.SetNpi(1) - _ = destAddr.SetAddress(phoneNumber) - + err = destAddr.SetAddress(phoneNumber) + if err != nil { + return nil, err + } submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM) submitSM.SourceAddr = srcAddr submitSM.DestAddr = destAddr - _ = submitSM.Message.SetMessageWithEncoding(message, data.UCS2) + dataCoding := data.UCS2 + switch smsForward.DataCoding { + case config.CODING_UCS2: + dataCoding = data.UCS2 + case config.CODING_ASCII: + dataCoding = data.ASCII + case config.CODING_LATIN1: + dataCoding = data.LATIN1 + } + err = submitSM.Message.SetMessageWithEncoding(message, dataCoding) + if err != nil { + return nil, err + } submitSM.ProtocolID = 0 submitSM.RegisteredDelivery = 1 submitSM.ReplaceIfPresentFlag = 0 submitSM.EsmClass = 0 - return submitSM + return submitSM, nil } diff --git a/restagent/config/config.go b/restagent/config/config.go index 682e99b5..aad08afd 100644 --- a/restagent/config/config.go +++ b/restagent/config/config.go @@ -150,6 +150,16 @@ type DbConfig struct { Backup string `yaml:"backup"` } +//type codingType int + +const ( + // Short message data coding type + CODING_UCS2 int = iota + CODING_ASCII + CODING_LATIN1 + CODING_NODEF +) + type AlarmConfig struct { SplitEventAlarm bool `yaml:"splitEventAlarm"` //ForwardAlarm bool `yaml:"forwardAlarm"` @@ -164,12 +174,14 @@ type AlarmConfig struct { TLSSkipVerify bool `yaml:"tlsSkipVerify" json:"tlsSkipVerify"` } `yaml:"alarmEmailForward"` SMSCForward struct { - Enable bool `yaml:"enable" json:"enable"` - MobileList string `yaml:"mobileList" json:"mobileList"` - SMSCAddr string `yaml:"smscAddr" json:"smscAddr"` - SystemID string `yaml:"systemID" json:"systemID"` - Password string `yaml:"password" json:"password"` - SystemType string `yaml:"systemType" json:"systemType"` + Enable bool `yaml:"enable" json:"enable"` + MobileList string `yaml:"mobileList" json:"mobileList"` + SMSCAddr string `yaml:"smscAddr" json:"smscAddr"` + SystemID string `yaml:"systemID" json:"systemID"` + Password string `yaml:"password" json:"password"` + SystemType string `yaml:"systemType" json:"systemType"` + DataCoding int `yaml:"dataCoding" json:"dataCoding"` + ServiceNumber string `yaml:"serviceNumber" json:"serviceNumber"` } `yaml:"alarmSMSForward"` SMS struct { ApiURL string `yaml:"apiURL"` @@ -304,7 +316,19 @@ func WriteOrignalConfig(configFile string, paramName string, paramData map[strin for j := i + 1; j < len(lines); j++ { if strings.Contains(lines[j], k+":") { index := strings.Index(lines[j], k) - lines[j] = lines[j][:index] + fmt.Sprintf("%s: %v", k, v) + // Determine the type of v + switch v := v.(type) { + case string: + lines[j] = lines[j][:index] + fmt.Sprintf("%s: \"%s\"", k, v) + // case int: + // lines[j] = lines[j][:index] + fmt.Sprintf("%s: %d", k, v) + // case float64: + // lines[j] = lines[j][:index] + fmt.Sprintf("%s: %f", k, v) + case bool: + lines[j] = lines[j][:index] + fmt.Sprintf("%s: %t", k, v) + default: + lines[j] = lines[j][:index] + fmt.Sprintf("%s: %v", k, v) + } break } } diff --git a/restagent/etc/restconf.yaml b/restagent/etc/restconf.yaml index 11d78526..bd6e7b88 100644 --- a/restagent/etc/restconf.yaml +++ b/restagent/etc/restconf.yaml @@ -126,6 +126,7 @@ omc: # TLS Skip verify: true/false # email/sms # smProxy: sms(Short Message Service)/smsc(SMS Centre) +# dataCoding: 0:UCS2, 1:ASCII, 2:LATIN1 alarm: alarmEmailForward: enable: true @@ -142,6 +143,8 @@ alarm: systemID: "omc" password: "omc123" systemType: "UTRAN" + dataCoding: 0 + serviceNumber: "OMC" sms: apiURL: http://smsc.xxx.com/ accessKeyID: xxxx diff --git a/src/modules/network_element/ne_config_test.go b/src/modules/network_element/ne_config_test.go index 33ad2a9d..92636a6c 100644 --- a/src/modules/network_element/ne_config_test.go +++ b/src/modules/network_element/ne_config_test.go @@ -29,7 +29,7 @@ const ( // 配置文件路径 configParamDir = "../../../config/param" // configParamFile = "*" // 目录下全部更新 - configParamFile = "smsc_param_config.yaml" // 单文件更新 + configParamFile = "omc_param_config.yaml" // 单文件更新 ) func TestConfig(t *testing.T) {