186 lines
6.1 KiB
Go
186 lines
6.1 KiB
Go
package service
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"ems.agt/src/framework/config"
|
||
"ems.agt/src/framework/logger"
|
||
"ems.agt/src/framework/utils/cmd"
|
||
"ems.agt/src/framework/utils/date"
|
||
neService "ems.agt/src/modules/network_element/service"
|
||
)
|
||
|
||
// 实例化服务层 TcpdumpImpl 结构体
|
||
var NewTcpdumpImpl = &TcpdumpImpl{
|
||
neInfoService: neService.NewNeInfoImpl,
|
||
tcpdumpPIDMap: map[string]string{},
|
||
}
|
||
|
||
// 信令抓包 服务层处理
|
||
type TcpdumpImpl struct {
|
||
// 网元信息服务
|
||
neInfoService neService.INeInfo
|
||
// 抓包进程PID
|
||
tcpdumpPIDMap map[string]string
|
||
}
|
||
|
||
// DumpStart 触发tcpdump开始抓包 filePcapName, err
|
||
func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) {
|
||
// 检查网元信息
|
||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||
if neInfo.NeId != neId {
|
||
return "", fmt.Errorf("noData")
|
||
}
|
||
|
||
// SSH命令
|
||
usernameNe := config.Get("ne.user").(string) // 网元统一用户
|
||
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP)
|
||
|
||
// 是否拥有sudo权限并拼接
|
||
withSudo := ""
|
||
if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil {
|
||
withSudo = "sudo "
|
||
}
|
||
|
||
if msg, err := cmd.ExecWithCheck("ssh", sshHost, fmt.Sprintf("%s tcpdump --version", withSudo)); err != nil {
|
||
// stderr: bash: tcpdump:未找到命令 => exit status 127
|
||
msg = strings.TrimSpace(msg)
|
||
logger.Warnf("DumpStart err: %s => %s", msg, err.Error())
|
||
return "", fmt.Errorf(msg)
|
||
}
|
||
|
||
// 拼装命令
|
||
neTypeID := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId)
|
||
timeStr := date.ParseDateToStr(time.Now(), date.YYYYMMDDHHMMSS)
|
||
fileName := fmt.Sprintf("%s_%s", timeStr, neTypeID)
|
||
sendCmd := fmt.Sprintf("cd /tmp \n %s nohup timeout 30m tcpdump -i any %s -s0 -w %s.pcap > %s.log 2>&1 & \necho $!", withSudo, cmdStr, fileName, fileName)
|
||
// cd /tmp
|
||
// sudo nohup timeout 60m tcpdump -i any -n -s 0 -v -w -s0 -w 20240115140822_UDM_001.pcap > 20240115140822_UDM_001.log 2>&1 & echo $!
|
||
msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd)
|
||
msg = strings.TrimSpace(msg)
|
||
if err != nil || strings.HasPrefix(msg, "stderr:") {
|
||
logger.Warnf("DumpStart err: %s => %s", msg, err.Error())
|
||
return "", err
|
||
}
|
||
|
||
// 检查进程 ps aux | grep tcpdump
|
||
// 强杀 sudo pkill tcpdump
|
||
s.tcpdumpPIDMap[neTypeID] = msg
|
||
return fileName, err
|
||
}
|
||
|
||
// DumpStop 停止已存在抓包句柄
|
||
func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) {
|
||
// 检查网元信息
|
||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||
if neInfo.NeId != neId {
|
||
return "", fmt.Errorf("noData")
|
||
}
|
||
|
||
// SSH命令
|
||
usernameNe := config.Get("ne.user").(string) // 网元统一用户
|
||
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP)
|
||
|
||
// 是否拥有sudo权限并拼接
|
||
withSudo := ""
|
||
if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil {
|
||
withSudo = "sudo "
|
||
}
|
||
|
||
// 是否存在进程
|
||
neTypeID := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId)
|
||
pid, ok := s.tcpdumpPIDMap[neTypeID]
|
||
if !ok || pid == "" {
|
||
return "", fmt.Errorf("tcpdump is not running")
|
||
}
|
||
|
||
// 查看日志
|
||
viewLogFile := ""
|
||
if fileName != "" && strings.Contains(fileName, neTypeID) {
|
||
viewLogFile = fmt.Sprintf("\n cat %s.log", fileName)
|
||
}
|
||
|
||
// 拼装命令
|
||
sendCmd := fmt.Sprintf("cd /tmp \n %s kill %s %s", withSudo, pid, viewLogFile)
|
||
msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd)
|
||
delete(s.tcpdumpPIDMap, neTypeID)
|
||
if err != nil || strings.HasPrefix(msg, "stderr:") {
|
||
logger.Warnf("DumpStop err: %s => %s", strings.TrimSpace(msg), err.Error())
|
||
return "", err
|
||
}
|
||
return msg, nil
|
||
}
|
||
|
||
// DumpUPF UPF标准版抓包
|
||
func (s *TcpdumpImpl) DumpUPF(neType, neId, cmdStr string) (string, string, error) {
|
||
// 检查网元信息
|
||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||
if neInfo.NeId != neId {
|
||
return "", "", fmt.Errorf("noData")
|
||
}
|
||
|
||
// SSH命令
|
||
usernameNe := config.Get("ne.user").(string) // 网元统一用户
|
||
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP)
|
||
|
||
// 是否拥有sudo权限并拼接
|
||
withSudo := ""
|
||
if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil {
|
||
withSudo = "sudo "
|
||
}
|
||
|
||
if msg, err := cmd.ExecWithCheck("ssh", sshHost, fmt.Sprintf("%s expect -version", withSudo)); err != nil {
|
||
// stderr: bash: expect:未找到命令 => exit status 127
|
||
msg = strings.TrimSpace(msg)
|
||
logger.Warnf("DumpUPF err: %s => %s", msg, err.Error())
|
||
return "", "", fmt.Errorf(msg)
|
||
}
|
||
|
||
// 拼装命令
|
||
neTypeID := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId)
|
||
timeStr := date.ParseDateToStr(time.Now(), date.YYYYMMDDHHMMSS)
|
||
fileName := fmt.Sprintf("%s_%s", timeStr, neTypeID)
|
||
// UPF标准版本telnet脚本
|
||
scriptStr := "set pcapCmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$pcapCmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\""
|
||
writePcapFile := fmt.Sprintf("echo '%s' > pcapUPF.sh\n %s chmod +x pcapUPF.sh", scriptStr, withSudo)
|
||
writeLogFile := fmt.Sprintf("> %s.log 2>&1 \ncat %s.log", fileName, fileName)
|
||
|
||
// 以off结尾是停止抓包,不需要写文件
|
||
pcapCmd := cmdStr
|
||
if !strings.HasSuffix(pcapCmd, "off") {
|
||
pcapCmd = fmt.Sprintf("%s file %s.pcap", cmdStr, fileName)
|
||
}
|
||
sendCmd := fmt.Sprintf("cd /tmp \n%s\n expect ./pcapUPF.sh '%s' %s", writePcapFile, pcapCmd, writeLogFile)
|
||
// cd /tmp
|
||
// echo '' >
|
||
// expect ./cap.sh > pcapUPF.sh
|
||
// sudo chmod +x pcapUPF.sh
|
||
// expect ./cap.sh 'pcap dispatch trace off' > 20240115165701_UDM_001.log 2>&1
|
||
// cat 20240115165701_UDM_001.log
|
||
msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd)
|
||
msg = strings.TrimSpace(msg)
|
||
if err != nil || strings.HasPrefix(msg, "stderr:") {
|
||
logger.Warnf("DumpUPF err: %s => %s", msg, err.Error())
|
||
return "", "", err
|
||
}
|
||
if strings.Contains(msg, "Unable to connect to remote host") {
|
||
return "", "", fmt.Errorf("connection refused")
|
||
}
|
||
// 以off结尾是停止抓包,不需要写文件
|
||
if strings.HasSuffix(pcapCmd, "off") {
|
||
if strings.Contains(msg, "Write ") {
|
||
lastTmpIndex := strings.LastIndex(msg, "/tmp/")
|
||
text := msg[lastTmpIndex+5:]
|
||
extensionIndex := strings.LastIndex(text, ".pcap")
|
||
if extensionIndex != -1 {
|
||
fileName = text[:extensionIndex]
|
||
}
|
||
} else {
|
||
fileName = ""
|
||
}
|
||
}
|
||
return fileName, msg, err
|
||
}
|