Commit 1f27f718 authored by liming6's avatar liming6
Browse files

feature sftp监控功能基本完善

parent 8a2d69fb
......@@ -29,30 +29,3 @@ sshd-tool监听这个unix socket,过滤出需要的信息
## auditd日志分析
tabby上传文件成功:
```
open(at) pid: 35286, ppid: 35262, open /tmp/navicat17_premium_lite_cs_x64.exe.tabby-upload, fd: 4
-----
close pid: 35286, ppid: 35262, fd: 4
-----
link(at): paths: [map[cap_fe:0 cap_fi:0 cap_fp:0 cap_frootid:0 cap_fver:0 dev:fc:00 inode:8126469 item:0 mode:0100644 name:/tmp/navicat17_premium_lite_cs_x64.exe.tabby-upload nametype:NORMAL ogid:0 ouid:0 rdev:00:00] map[cap_fe:0 cap_fi:0 cap_fp:0 cap_frootid:0 cap_fver:0 dev:fc:00 inode:8126465 item:1 mode:041777 name:/tmp/ nametype:PARENT ogid:0 ouid:0 rdev:00:00] map[cap_fe:0 cap_fi:0 cap_fp:0 cap_frootid:0 cap_fver:0 dev:fc:00 inode:8126469 item:2 mode:0100644 name:/tmp/navicat17_premium_lite_cs_x64.exe nametype:CREATE ogid:0 ouid:0 rdev:00:00]]
-----
unlink(at): paths: [map[cap_fe:0 cap_fi:0 cap_fp:0 cap_frootid:0 cap_fver:0 dev:fc:00 inode:8126465 item:0 mode:041777 name:/tmp/ nametype:PARENT ogid:0 ouid:0 rdev:00:00] map[cap_fe:0 cap_fi:0 cap_fp:0 cap_frootid:0 cap_fver:0 dev:fc:00 inode:8126469 item:1 mode:0100644 name:/tmp/navicat17_premium_lite_cs_x64.exe.tabby-upload nametype:DELETE ogid:0 ouid:0 rdev:00:00]]
-----
close pid: 35286, ppid: 35262, fd: 4
```
tabby创建文件后中断
```
open(at) pid: 35286, ppid: 35262, open /tmp/Rocky-8.10-x86_64-dvd1.iso.tabby-upload, fd: 4
-----
unlink(at): paths: [map[cap_fe:0 cap_fi:0 cap_fp:0 cap_frootid:0 cap_fver:0 dev:fc:00 inode:8126465 item:0 mode:041777 name:/tmp/ nametype:PARENT ogid:0 ouid:0 rdev:00:00] map[cap_fe:0 cap_fi:0 cap_fp:0 cap_frootid:0 cap_fver:0 dev:fc:00 inode:8126470 item:1 mode:0100644 name:/tmp/Rocky-8.10-x86_64-dvd1.iso.tabby-upload nametype:DELETE ogid:0 ouid:0 rdev:00:00]]
```
```
open(at) pid: 35286, ppid: 35262, open /tmp/AnolisOS-8.6-x86_64-dvd.iso.tabby-upload, fd: 5
-----
unlink(at): paths: [map[cap_fe:0 cap_fi:0 cap_fp:0 cap_frootid:0 cap_fver:0 dev:fc:00 inode:8126465 item:0 mode:041777 name:/tmp/ nametype:PARENT ogid:0 ouid:0 rdev:00:00] map[cap_fe:0 cap_fi:0 cap_fp:0 cap_frootid:0 cap_fver:0 dev:fc:00 inode:8126471 item:1 mode:0100644 name:/tmp/AnolisOS-8.6-x86_64-dvd.iso.tabby-upload nametype:DELETE ogid:0 ouid:0 rdev:00:00]]
```
\ No newline at end of file
......@@ -14,10 +14,14 @@ import (
var (
// 需要的二进制文件
NeedExec = []string{"clamscan", "clamdscan"}
ReInfectedFile = regexp.MustCompile(`(?i)^infected\s+files:\s+([0-9]+)\s*$`)
ErrNoLineMatch = errors.New("no line match")
HasGzip = false
HasBzip2 = false
HasXZ = false
HasZStd = false
CMExec = []string{"gzip", "bzip2", "xz", "zstd"}
)
func CheckExec() error {
......@@ -27,6 +31,20 @@ func CheckExec() error {
return fmt.Errorf("%s not found", v)
}
}
for k, v := range CMExec {
if utils.FindCmd(v) != nil {
switch k {
case 0:
HasGzip = true
case 1:
HasBzip2 = true
case 2:
HasXZ = true
case 3:
HasZStd = true
}
}
}
return nil
}
......@@ -47,7 +65,29 @@ func ScanFile(f string) (bool, error) {
if err != nil {
return false, err
}
// // 优化归档文件
// cm, istar, err := utils.DetectArchive(sf)
// if err == nil {
// if cm == utils.CMNone || cm == utils.CMUnknown {
// // 不能采用优化方法
// } else {
// // 是压缩后的tar包
// switch cm {
// case utils.CMGZip:
// if istar {
// exec.Command()
// } else {
// }
// case utils.CMBZip2:
// case utils.CMXZ:
// case utils.CMZStd:
// }
// }
// }
cmd := exec.Command("clamdscan", "-i", sf)
output, err := cmd.CombinedOutput()
if err != nil {
......
......@@ -7,6 +7,7 @@ import (
"net"
"os"
"regexp"
"slices"
"strconv"
"strings"
"sync"
......@@ -45,7 +46,8 @@ const (
func parseSLA(s string, t time.Time) GetSLA {
prev := ""
if strings.HasPrefix(s, string(SLAOpen)) {
switch {
case strings.HasPrefix(s, string(SLAOpen)):
fields := strings.Fields(s)
result := SftpLogOpen{Time: t}
for i, v := range fields[1:] {
......@@ -71,8 +73,7 @@ func parseSLA(s string, t time.Time) GetSLA {
}
}
return &result
}
if strings.HasPrefix(s, string(SLAClose)) {
case strings.HasPrefix(s, string(SLAClose)):
fields := strings.Fields(s)
result := SftpLogClose{Time: t}
for k, v := range fields[1:] {
......@@ -102,14 +103,12 @@ func parseSLA(s string, t time.Time) GetSLA {
}
}
return &result
}
if strings.HasPrefix(s, string(SLARemove)) {
case strings.HasPrefix(s, string(SLARemove)):
fields := strings.Fields(s)
result := SftpLogRemove{Time: t}
result.Path = fields[2]
return &result
}
if strings.HasPrefix(s, string(SLARename)) {
case strings.HasPrefix(s, string(SLARename)):
fields := strings.Fields(s)
result := SftpLogRename{Time: t}
for _, v := range fields[1:] {
......@@ -126,8 +125,7 @@ func parseSLA(s string, t time.Time) GetSLA {
}
}
return &result
}
if strings.HasPrefix(s, string(SLAForceClose)) {
case strings.HasPrefix(s, string(SLAForceClose)):
fields := strings.Fields(s)
result := SftpLogForceClose{Time: t}
for k, v := range fields[2:] {
......@@ -157,22 +155,21 @@ func parseSLA(s string, t time.Time) GetSLA {
}
}
return &result
}
if strings.HasPrefix(s, string(SLAOpenSession)) {
case strings.HasPrefix(s, string(SLAOpenSession)):
result := SftpLogOpenSession{Time: t}
items := RegParseSession.FindStringSubmatch(s)
result.User = items[2]
result.From = items[3]
return &result
}
if strings.HasPrefix(s, string(SLACloseSession)) {
case strings.HasPrefix(s, string(SLACloseSession)):
result := SftpLogCloseSession{Time: t}
items := RegParseSession.FindStringSubmatch(s)
result.User = items[2]
result.From = items[3]
return &result
}
default:
return nil
}
}
type SftpLogOpen struct {
......@@ -339,6 +336,11 @@ func NewSftpLogSet(pid int32, user *string, startTime *time.Time) *SftpLogSet {
user, err := p.Username()
if err == nil {
result.User = user
} else {
uids, err := p.Uids()
if err == nil && len(uids) > 0 {
result.User = fmt.Sprintf("UID: %d", uids[0])
}
}
}
}
......@@ -370,59 +372,76 @@ func (sls *SftpLogSet) CheckAlive() (bool, error) {
}
type FileInfo struct {
Path string
NameSet map[string]bool // 可用名称
Path string // 文件路径,对于tabby等中途会修改的sftp客户端,这里记录有后缀的名称
Log []GetSLA // 文件操作日志
LogSet *SftpLogSet
LogLock sync.RWMutex // 保护Log的读写
LogSet *SftpLogSet // 这个文件信息所属的日志集,用于获取用户名和pid
}
func NewFileInfo(path string, ls *SftpLogSet) *FileInfo {
return &FileInfo{
Path: path,
NameSet: make(map[string]bool),
Log: make([]GetSLA, 0, 4),
LogSet: ls,
LogLock: sync.RWMutex{},
}
}
// CheckNeedScan 检查是否需要扫描文件
func (fi *FileInfo) CheckNeedScan() {
// 检查最后一个日志的种类
rl := fi.LogLock.RLocker()
rl.Lock()
l := len(fi.Log)
if l == 0 {
return
}
last := fi.Log[l-1]
userName := fi.LogSet.User
rl.Unlock()
switch act := last.(type) {
case *SftpLogClose:
if strings.HasSuffix(act.Path, "tabby-upload") {
if strings.HasSuffix(act.Path, ".tabby-upload") {
return
}
log.Println("scan file: ", act.Path)
fi.LogSet.Lock.Lock()
delete(fi.LogSet.OpenedFile, act.Path)
fi.LogSet.Lock.Unlock()
log.Printf("user %s upload file: %s, scanning...\n", userName, act.Path)
have, _ := ScanFile(act.Path)
if have {
log.Println(act.Path, "有病毒")
log.Printf("user %s upload file %s containing viruses\n", userName, act.Path)
} else {
log.Println(act.Path, "没病毒")
log.Printf("user %s upload file %s not find virus\n", userName, act.Path)
}
return
case *SftpLogRename:
if strings.HasSuffix(act.Old, "tabby-upload") {
log.Println("scan file: ", act.New)
if strings.HasSuffix(act.Old, ".tabby-upload") {
log.Printf("user %s upload file: %s, scanning...\n", userName, act.New)
have, _ := ScanFile(act.New)
if have {
log.Println(act.New, "有病毒")
log.Printf("user %s upload file %s containing viruses\n", userName, act.New)
} else {
log.Println(act.New, "没病毒")
log.Printf("user %s upload file %s not find virus\n", userName, act.New)
}
fi.LogSet.Lock.Lock()
delete(fi.LogSet.OpenedFile, act.Old)
delete(fi.LogSet.OpenedFile, act.New)
fi.LogSet.Lock.Unlock()
}
return
case *SftpLogForceClose:
log.Println("scan file: ", act.Path)
log.Printf("user %s upload file: %s, scanning...\n", userName, act.Path)
have, _ := ScanFile(act.Path)
if have {
log.Println(act.Path, "有病毒")
log.Printf("user %s upload file %s containing viruses\n", userName, act.Path)
} else {
log.Println(act.Path, "没病毒")
log.Printf("user %s upload file %s not find virus\n", userName, act.Path)
}
fi.LogSet.Lock.Lock()
delete(fi.LogSet.OpenedFile, act.Path)
fi.LogSet.Lock.Unlock()
return
}
}
......@@ -431,24 +450,32 @@ func InsertAction(action GetSLA) {
return
}
pid := action.GetPid()
SftpLogLock.Lock()
defer SftpLogLock.Unlock()
switch act := action.(type) {
case *SftpLogOpenSession:
// 新建
SftpLogLock.Lock()
sls := NewSftpLogSet(pid, &act.User, &act.Time)
sls.From = act.From
SftpLogMap[pid] = sls
SftpLogLock.Unlock()
return
case *SftpLogCloseSession:
SftpLogLock.Lock()
delete(SftpLogMap, pid)
SftpLogLock.Unlock()
return
case *SftpLogOpen:
if slices.Contains(act.Flags, "READ") {
// 是读文件,不理会
return
}
SftpLogLock.Lock()
ls, have := SftpLogMap[pid]
if !have {
ls = NewSftpLogSet(pid, nil, &act.Time)
SftpLogMap[pid] = ls
}
SftpLogLock.Unlock()
istabby := strings.HasSuffix(act.Path, ".tabby-upload")
ls.IsTabby = mo.Some(istabby)
ls.Lock.Lock()
......@@ -456,62 +483,70 @@ func InsertAction(action GetSLA) {
if !have {
finfo = NewFileInfo(act.Path, ls)
ls.OpenedFile[act.Path] = finfo
ls.Lock.Unlock()
finfo.LogLock.Lock()
finfo.Log = append(finfo.Log, act)
finfo.LogLock.Unlock()
} else {
// 发生重复了???
}
ls.Lock.Unlock()
}
return
case *SftpLogClose:
// 关闭文件
if num, have := act.Write.Get(); have && num == 0 {
// 没有写入数据,不处理
return
}
SftpLogLock.Lock()
ls, have := SftpLogMap[pid]
if !have {
ls = NewSftpLogSet(pid, nil, &act.Time)
SftpLogMap[pid] = ls
}
SftpLogLock.Unlock()
ls.Lock.Lock()
if strings.HasSuffix(act.Path, ".tabby-upload") {
ls.IsTabby = mo.Some(true)
}
finfo, have := ls.OpenedFile[act.Path]
if !have {
finfo = NewFileInfo(act.Path, ls)
ls.OpenedFile[act.Path] = finfo
}
finfo.Log = append(finfo.Log, act)
ls.Lock.Unlock()
finfo.CheckNeedScan()
finfo.LogLock.Lock()
finfo.Log = append(finfo.Log, act)
finfo.LogLock.Unlock()
go finfo.CheckNeedScan()
return
case *SftpLogRemove:
// 查看是否为tabby,如果是tabby,需要检查是否为上传的文件
// 如果没有,不创建日志
SftpLogLock.Lock()
ls, have := SftpLogMap[pid]
if !have {
ls = NewSftpLogSet(pid, nil, &act.Time)
SftpLogMap[pid] = ls
}
SftpLogLock.Unlock()
a, b := ls.IsTabby.Get()
if a && b {
// 是tabby上传的文件,需要记录日志
ls.Lock.Lock()
finfo, have := ls.OpenedFile[act.Path]
if !have {
finfo = NewFileInfo(act.Path, ls)
ls.OpenedFile[act.Path] = finfo
}
finfo.Log = append(finfo.Log, act)
ls.Lock.Unlock()
} else {
delete(ls.OpenedFile, act.Path)
}
return
case *SftpLogRename:
// 查看是否为tabby,如果是tabby,需要检查是否为上传的文件
istabby := strings.HasSuffix(act.Old, ".tabby-upload")
if istabby {
SftpLogLock.Lock()
ls, have := SftpLogMap[pid]
if !have {
ls = NewSftpLogSet(pid, nil, &act.Time)
SftpLogMap[pid] = ls
}
istabby := strings.HasSuffix(act.Old, ".tabby-upload")
SftpLogLock.Unlock()
ls.IsTabby = mo.Some(istabby)
if istabby {
// 是tabby上传的文件,需要记录日志
ls.Lock.Lock()
finfo, have := ls.OpenedFile[act.Old]
......@@ -519,27 +554,36 @@ func InsertAction(action GetSLA) {
finfo = NewFileInfo(act.Old, ls)
ls.OpenedFile[act.Old] = finfo
}
finfo.Log = append(finfo.Log, act)
ls.Lock.Unlock()
finfo.CheckNeedScan()
finfo.LogLock.Lock()
finfo.Log = append(finfo.Log, act)
finfo.LogLock.Unlock()
go finfo.CheckNeedScan()
}
return
case *SftpLogForceClose:
if num, have := act.Write.Get(); have && num == 0 {
return
}
SftpLogLock.Lock()
// 是强制中断,需要检查是否为上传的文件
ls, have := SftpLogMap[pid]
if !have {
ls = NewSftpLogSet(pid, nil, &act.Time)
SftpLogMap[pid] = ls
}
SftpLogLock.Unlock()
ls.Lock.Lock()
finfo, have := ls.OpenedFile[act.Path]
if !have {
finfo = NewFileInfo(act.Path, ls)
ls.OpenedFile[act.Path] = finfo
}
finfo.Log = append(finfo.Log, act)
ls.Lock.Unlock()
finfo.CheckNeedScan()
finfo.LogLock.Lock()
finfo.Log = append(finfo.Log, act)
finfo.LogLock.Unlock()
go finfo.CheckNeedScan()
return
}
}
......@@ -582,13 +626,13 @@ func ParseSftpLog(s string) (GetSLA, error) {
}
func StartSftpMonitor() {
regRemove := regexp.MustCompile(`^<\d+>(.*)$`)
os.Remove("/tmp/rsyslog.sock")
conn, err := net.ListenPacket("unixgram", "/tmp/rsyslog.sock")
if err != nil {
log.Fatal(err)
}
defer os.Remove("/tmp/rsyslog.sock")
buffer := make([]byte, 16384)
for {
n, _, err := conn.ReadFrom(buffer)
......@@ -601,14 +645,14 @@ func StartSftpMonitor() {
continue
}
if strings.Contains(items[1], "sftp-server") {
fmt.Println(items[1])
l, err := ParseSftpLog(items[1])
if err != nil {
log.Println(err)
} else {
if l != nil {
InsertAction(l)
}
}
}
os.Remove("/tmp/rsyslog.sock")
}
}
package main
import (
"fmt"
"log"
"os"
"sshd-tool/cmd/file-monitor/logic"
"time"
"github.com/gofrs/flock"
)
// import (
......@@ -69,12 +74,34 @@ import (
// close(logic.EventChan)
// }
var (
logfile *os.File
)
func init() {
logFile, err := os.Create(fmt.Sprintf("/var/log/file-monitor.%s.log", time.Now().Format("2006-01-02_15-04-05")))
if err == nil {
logfile = logFile
log.SetOutput(logFile)
}
}
func shutdown() {
if logfile != nil {
logfile.Close()
}
}
func main() {
err := logic.CheckExec()
fileLock := flock.New("/tmp/file-monitor.lock")
locked, err := fileLock.TryLock()
if err != nil || !locked {
log.Fatal("there is already a file-monitor instance running, stopping")
}
defer fileLock.Unlock()
err = logic.CheckExec()
if err != nil {
log.Fatal(err)
}
logic.StartSftpMonitor()
}
# readme
sftp:
file-minitor是一个监控sftp和scp上传文件动作并对上传文件进行病毒扫描的工具
通过解析sftp日志实现感知文件上传动作,自动扫描文件
## 工作方式
scp:
针对sftp,它解析实时sftp日志,识别上传文件行为并使用clamdscan扫描文件
针对scp,它利用auditd中的审计规则判识别写文件动作
一旦上传文件完成,file-monitor会立即修改文件名,添加 `.scanning` 后缀,若扫描到文件,删除文件,并在原地留下一个警示文件 `.virus`
如果没有病毒,会恢复文件名
扫描病毒文件的时间会根据文件类型、文件大小而变化,最长扫描时间为5分钟
同样大小下,`.zip`文件扫描比较慢,建议压缩包格式为 `.tar.gz`
使用系统调用监控
package main
import (
"fmt"
"log"
"net"
)
func main() {
conn, err := net.ListenPacket("unixgram", "/tmp/rsyslog.sock")
if err != nil {
log.Fatal(err)
}
buffer := make([]byte, 16384)
for {
n, _, err := conn.ReadFrom(buffer)
if err != nil {
break
}
fmt.Println(string(buffer[:n]))
}
}
......@@ -11,6 +11,7 @@ require (
require (
github.com/ebitengine/purego v0.10.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/klauspost/compress v1.18.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
......@@ -18,6 +19,7 @@ require (
github.com/samber/mo v1.16.0 // indirect
github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
......
......@@ -47,6 +47,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
......@@ -99,6 +101,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
......
package utils
import (
"bytes"
"compress/bzip2"
"compress/gzip"
"io"
"os"
"github.com/klauspost/compress/zstd"
"github.com/ulikunitz/xz"
)
// 压缩格式魔术数
var (
PrefixZSTD = []byte{0x28, 0xB5, 0x2F, 0xFD}
PrefixGZip = []byte{0x1F, 0x8B}
PrefixBzip2 = []byte{0x42, 0x5A, 0x68}
PrefixXZ = []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}
)
type CompressMethod uint8
const (
CMUnknown CompressMethod = iota
CMGZip
CMBZip2
CMXZ
CMZStd
CMNone // 表示没有压缩
)
// IsTar 判断是否为tar包
func IsTar(r io.Reader) (bool, error) {
buf := make([]byte, 512)
rn, err := r.Read(buf)
if err != nil {
return false, err
}
if rn < 262 {
return false, nil
}
if string(buf[257:262]) == "ustar" {
return true, nil
}
return false, nil
}
// DetectArchive 探测文件是否为压缩包类型
func DetectArchive(path string) (CompressMethod, bool, error) {
f, err := os.Open(path)
if err != nil {
return CMUnknown, false, err
}
defer f.Close()
// 先判断是否为tar包
istar, err := IsTar(f)
if err != nil {
return CMUnknown, false, err
}
if istar {
return CMNone, true, nil
}
// 先判断压缩格式
_, err = f.Seek(0, 0)
if err != nil {
return CMUnknown, false, err
}
buf := make([]byte, 6)
rn, err := f.Read(buf)
if err != nil {
return CMUnknown, false, err
}
if rn != 6 {
return CMNone, false, nil
}
switch {
case bytes.HasPrefix(buf, PrefixZSTD):
reader, err := zstd.NewReader(f)
if err != nil {
return CMZStd, false, err
}
defer reader.Close()
isTar, err := IsTar(reader)
return CMZStd, isTar, err
case bytes.HasPrefix(buf, PrefixGZip):
reader, err := gzip.NewReader(f)
if err != nil {
return CMGZip, false, err
}
defer reader.Close()
isTar, err := IsTar(reader)
return CMGZip, isTar, err
case bytes.HasPrefix(buf, PrefixBzip2):
reader := bzip2.NewReader(f)
isTar, err := IsTar(reader)
return CMBZip2, isTar, err
case bytes.HasPrefix(buf, PrefixXZ):
reader, err := xz.NewReader(f)
if err != nil {
return CMXZ, false, err
}
isTar, err := IsTar(reader)
return CMXZ, isTar, err
default:
return CMUnknown, false, nil
}
}
package utils
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"os/exec"
"testing"
"time"
)
......@@ -143,7 +145,7 @@ func TestGetPidChild(t *testing.T) {
t.Error(err)
}
t.Logf("%v", pids)
t.Logf("num: %d",len(pids))
t.Logf("num: %d", len(pids))
}
func TestGetPidChild2(t *testing.T) {
......@@ -155,5 +157,22 @@ func TestGetPidChild2(t *testing.T) {
t.Error(err)
}
t.Logf("%v", pids)
t.Logf("num: %d",len(pids))
t.Logf("num: %d", len(pids))
}
func TestRunCmd(t *testing.T) {
cmd1 := exec.Command("echo", "hello world")
cmd2 := exec.Command("grep", "-o", "h.*o")
so, err := cmd1.StdoutPipe()
if err != nil {
t.Fatal(err)
}
cmd2.Stdin = so
var out bytes.Buffer
cmd2.Stdout = &out
_ = cmd1.Start()
_ = cmd2.Start()
cmd1.Wait()
cmd2.Wait()
t.Logf("%s", out.String())
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment