package trace import ( "fmt" "net" "net/http" "strings" "time" "be.ems/lib/core/conf" "be.ems/lib/core/utils/ctx" "be.ems/lib/core/vo/result" "be.ems/lib/dborm" "be.ems/lib/log" "be.ems/restagent/config" "be.ems/src/framework/utils/cmd" "be.ems/src/framework/utils/ssh" ) var ( UriTcpdumpTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask" CustomUriTcpdumpTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask" // decode message api UriTcpdumpPcapDownload = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload" CustomUriTcpdumpPcapDownload = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload" // decode message api UriTcpdumpNeUPFTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask" CustomUriTcpdumpNeUPFTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask" // decode message api ) // NeInfo 网元信息 func NeInfo(neType, neId string) (*dborm.NeInfo, error) { neInfo, err := dborm.XormGetNeInfo(neType, neId) if err != nil { log.Error("dborm.XormGetNeInfo is failed:", err) return nil, err } if neInfo == nil || neInfo.Ip == "" { return nil, fmt.Errorf("not ne_info or not IP") } return neInfo, nil } // TcpdumpNeTask 网元发送执行 pcap func TcpdumpNeTask(w http.ResponseWriter, r *http.Request) { var body struct { NeType string `json:"neType"` // 网元类型 NeId string `json:"neId"` // 网元ID Timeout int `json:"timeout"` // 超时时间 Cmd string `json:"cmd"` // 命令 } err := ctx.ShouldBindJSON(r, &body) if err != nil || body.NeType == "" || body.NeId == "" || body.Timeout < 5 || body.Cmd == "" { ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } neInfo, err := NeInfo(body.NeType, body.NeId) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } filePcapName := fmt.Sprintf("tmp_%s_%s_%d.pcap", body.NeType, body.NeId, time.Now().UnixMilli()) fileLogName := fmt.Sprintf("tmp_%s_%s_%d.log", body.NeType, body.NeId, time.Now().UnixMilli()) writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 cmdStr := fmt.Sprintf("cd /tmp \nsudo timeout %d tcpdump -i any %s -s0 -w %s", body.Timeout, body.Cmd, filePcapName) usernameNe := conf.Get("ne.user").(string) // 网元统一用户 sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr+writeLog) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "msg": msg, "fileName": filePcapName, })) } // TcpdumpPcapDownload 网元抓包pcap文件下载 func TcpdumpPcapDownload(w http.ResponseWriter, r *http.Request) { var body struct { NeType string `json:"neType"` // 网元类型 NeId string `json:"neId"` // 网元ID FileName string `json:"fileName"` // 文件名 } err := ctx.ShouldBindJSON(r, &body) if err != nil || body.NeType == "" || body.NeId == "" || body.FileName == "" { ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } neInfo, err := NeInfo(body.NeType, body.NeId) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } nePath := fmt.Sprintf("/tmp/%s", body.FileName) localPath := fmt.Sprintf("%s/tcpdump/pcap/%s", conf.Get("ne.omcdir"), body.FileName) err = ssh.FileSCPNeToLocal(neInfo.Ip, nePath, localPath) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } ctx.FileAttachment(w, r, localPath, body.FileName) } // TcpdumpNeUPFTask 网元UPF发送执行 pcap func TcpdumpNeUPFTask(w http.ResponseWriter, r *http.Request) { var body struct { NeType string `json:"neType"` // 网元类型 NeId string `json:"neId"` // 网元ID Cmd string `json:"cmd"` // 命令 RunType string `json:"runType"` // 执行开始start还是停止stop } err := ctx.ShouldBindJSON(r, &body) if err != nil || body.NeType != "UPF" || body.NeId == "" || body.Cmd == "" { ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } neInfo, err := NeInfo(body.NeType, body.NeId) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } // 开始telnet if body.RunType == "start_telnet" { // 创建TCP连接 conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002)) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } defer conn.Close() filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) cmdStr := fmt.Sprintf("pcap dispatch trace on max 100000 file %s", filePcapName) fmt.Fprintln(conn, cmdStr) // 读取内容 time.Sleep(time.Duration(200) * time.Millisecond) buf := make([]byte, 1024*8) n, err := conn.Read(buf) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) } else { str := string(buf[0:n]) s := strings.Index(str, "pcap dispatch trace:") if s != -1 { e := strings.Index(str, "\r\nupfd1#") str = str[s:e] } else { str = fmt.Sprintf("Executed, please stop before proceeding %d", n) } ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "msg": str, "fileName": filePcapName, })) } conn.Close() return } // 停止telnet if body.RunType == "stop_telnet" { // 创建TCP连接 conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002)) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } defer conn.Close() filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) cmdStr := "pcap dispatch trace off" fmt.Fprintln(conn, cmdStr) // 读取内容 time.Sleep(time.Duration(200) * time.Millisecond) buf := make([]byte, 1024*8) n, err := conn.Read(buf) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) } else { str := string(buf[0:n]) s := strings.Index(str, "pcap dispatch trace:") if s == -1 { s = strings.Index(str, "Write ") } if s != -1 { e := strings.Index(str, "\r\nupfd1#") str = str[s:e] } else { str = "No stoppable found" } ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "msg": str, "fileName": filePcapName, })) } conn.Close() return } // 开始 -脚本 if body.RunType == "start2" { fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) // 复制文件到网元上 err := ssh.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\restagent\\backup\\upf_pcap", "/tmp") if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace on max 100000 file %s' %s ", fileLogName, writeLog) usernameNe := conf.Get("ne.user").(string) // 网元统一用户 sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) } else { ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "msg": msg, "fileName": filePcapName, })) } return } // 停止 -脚本 if body.RunType == "stop2" { fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) // cmdStr := "cd /tmp \nexpect /tmp/cat.sh " err := ssh.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\restagent\\backup\\upf_pcap", "/tmp") if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) return } writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace off' %s ", writeLog) usernameNe := conf.Get("ne.user").(string) // 网元统一用户 sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) } else { ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": cmdStr, "msg": msg, "fileName": filePcapName, })) } return } // 开始-脚本字符串 if body.RunType == "start_str" { fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出,避免弹出code 127 capCmdStr := fmt.Sprintf("%s file %s", body.Cmd, filePcapName) cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog) usernameNe := conf.Get("ne.user").(string) // 网元统一用户 sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) } else { s := strings.Index(msg, "pcap dispatch trace:") if s != -1 { e := strings.Index(msg, "\r\nupfd1#") msg = msg[s:e] } else { msg = "Executed, please stop before proceeding" } ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": capCmdStr, "msg": msg, "fileName": filePcapName, })) } return } // 停止-脚本字符串 if body.RunType == "stop_str" { fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出,避免弹出code 127 capCmdStr := body.Cmd cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog) usernameNe := conf.Get("ne.user").(string) // 网元统一用户 sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) if err != nil { ctx.JSON(w, 200, result.ErrMsg(err.Error())) } else { s := strings.Index(msg, "pcap dispatch trace:") if s == -1 { s = strings.Index(msg, "Write ") } if s != -1 { e := strings.Index(msg, "\r\nupfd1#") msg = msg[s:e] } else { msg = "No stoppable found" } ctx.JSON(w, 200, result.OkData(map[string]any{ "cmd": capCmdStr, "msg": msg, "fileName": filePcapName, })) } return } ctx.JSON(w, 200, result.ErrMsg("runType is start or stop")) }