Commit 4c295cf4 authored by liming6's avatar liming6
Browse files

fix 修复文件名中有空格不能正常识别的bug

parent 1f27f718
......@@ -69,3 +69,12 @@ func TestPids(t *testing.T) {
tt := time.Since(start)
t.Logf("%d ms", tt.Milliseconds())
}
func TestParseSftpLog(t *testing.T) {
sla, err := ParseSftpLog(`Mar 17 16:38:23 anolis sftp-server[62785]: close "/tmp/Everything-1.4.1.1030.x64-Setup. exe.tabby-upload" bytes read 0 written 1987848`)
if err != nil {
t.Error(err)
}
op := sla.(*SftpLogClose)
t.Logf("%+v", op)
}
......@@ -23,6 +23,11 @@ var (
SftpLogMap = make(map[int32]*SftpLogSet) // 全局的,用于记录sftp信息的map,key为进程id,value为日志集
SftpLogLock = sync.RWMutex{} // 保护SftpLogMap的锁
RegOpenFile = regexp.MustCompile(`(?i)^open "(.*)" flags (.*) mode (.*)$`)
RegCloseFile = regexp.MustCompile(`(?i)^close "(.*)" bytes read (\d+) written (\d+)$`)
RegRenameFile = regexp.MustCompile(`(?i)^rename old "(.*)" new "(.*)"$`)
RegForceCloseFile = regexp.MustCompile(`(?i)^forced close "(.*)" bytes read (\d+) written (\d+)$`)
)
type GetSLA interface {
......@@ -44,131 +49,91 @@ const (
SLACloseSession SftpLogAction = "session closed"
)
func parseSLA(s string, t time.Time) GetSLA {
prev := ""
func parseSLA(s string, t time.Time) (GetSLA, error) {
rerr := errors.New("error sftp log format")
switch {
case strings.HasPrefix(s, string(SLAOpen)):
fields := strings.Fields(s)
fields := RegOpenFile.FindStringSubmatch(s)
if len(fields) != 4 {
return nil, rerr
}
result := SftpLogOpen{Time: t}
for i, v := range fields[1:] {
if i == 0 {
result.Path = strings.Trim(v, `"`)
continue
}
switch v {
case "flags", "mode":
prev = v
default:
switch prev {
case "flags":
result.Flags = strings.Split(v, ",")
case "mode":
p, err := strconv.ParseUint(v, 8, 32)
if err == nil {
result.Mode = mo.None[uint32]()
} else {
result.Mode = mo.Some(uint32(p))
}
}
}
result.Path = fields[1]
result.Flags = strings.Split(fields[2], ",")
p, err := strconv.ParseUint(fields[3], 8, 32)
if err == nil {
result.Mode = mo.None[uint32]()
} else {
result.Mode = mo.Some(uint32(p))
}
return &result
return &result, nil
case strings.HasPrefix(s, string(SLAClose)):
fields := strings.Fields(s)
fields := RegCloseFile.FindStringSubmatch(s)
if len(fields) != 4 {
return nil, rerr
}
result := SftpLogClose{Time: t}
for k, v := range fields[1:] {
if k == 0 {
result.Path = strings.Trim(v, `"`)
}
switch v {
case "bytes", "read", "written":
prev = v
default:
switch prev {
case "read":
read, err := strconv.ParseUint(v, 10, 64)
if err != nil {
result.Read = mo.None[uint64]()
} else {
result.Read = mo.Some(read)
}
case "written":
read, err := strconv.ParseUint(v, 10, 64)
if err != nil {
result.Write = mo.None[uint64]()
} else {
result.Write = mo.Some(read)
}
}
}
result.Path = fields[1]
read, err := strconv.ParseUint(fields[2], 10, 64)
if err != nil {
result.Read = mo.None[uint64]()
} else {
result.Read = mo.Some(read)
}
return &result
write, err := strconv.ParseUint(fields[3], 10, 64)
if err != nil {
result.Write = mo.None[uint64]()
} else {
result.Write = mo.Some(write)
}
return &result, nil
case strings.HasPrefix(s, string(SLARemove)):
fields := strings.Fields(s)
result := SftpLogRemove{Time: t}
result.Path = fields[2]
return &result
result.Path = strings.Trim(strings.Trim(s, string(SLARemove)), `"`)
return &result, nil
case strings.HasPrefix(s, string(SLARename)):
fields := strings.Fields(s)
result := SftpLogRename{Time: t}
for _, v := range fields[1:] {
switch v {
case "old", "new":
prev = v
default:
switch prev {
case "old":
result.Old = strings.Trim(v, `"`)
case "new":
result.New = strings.Trim(v, `"`)
}
}
fields := RegRenameFile.FindStringSubmatch(s)
if len(fields) != 3 {
return nil, rerr
}
return &result
result := SftpLogRename{Time: t}
result.Old = fields[1]
result.New = fields[2]
return &result, nil
case strings.HasPrefix(s, string(SLAForceClose)):
fields := strings.Fields(s)
fields := RegForceCloseFile.FindStringSubmatch(s)
if len(fields) != 4 {
return nil, rerr
}
result := SftpLogForceClose{Time: t}
for k, v := range fields[2:] {
if k == 0 {
result.Path = strings.Trim(v, `"`)
}
switch v {
case "bytes", "read", "written":
prev = v
default:
switch prev {
case "read":
read, err := strconv.ParseUint(v, 10, 64)
if err != nil {
result.Read = mo.None[uint64]()
} else {
result.Read = mo.Some(read)
}
case "written":
read, err := strconv.ParseUint(v, 10, 64)
if err != nil {
result.Write = mo.None[uint64]()
} else {
result.Write = mo.Some(read)
}
}
}
result.Path = fields[1]
read, err := strconv.ParseUint(fields[2], 10, 64)
if err != nil {
result.Read = mo.None[uint64]()
} else {
result.Read = mo.Some(read)
}
write, err := strconv.ParseUint(fields[3], 10, 64)
if err != nil {
result.Write = mo.None[uint64]()
} else {
result.Write = mo.Some(write)
}
return &result
return &result, nil
case strings.HasPrefix(s, string(SLAOpenSession)):
result := SftpLogOpenSession{Time: t}
items := RegParseSession.FindStringSubmatch(s)
result.User = items[2]
result.From = items[3]
return &result
return &result, nil
case strings.HasPrefix(s, string(SLACloseSession)):
result := SftpLogCloseSession{Time: t}
items := RegParseSession.FindStringSubmatch(s)
result.User = items[2]
result.From = items[3]
return &result
return &result, nil
default:
return nil
return nil, nil
}
}
......@@ -588,6 +553,7 @@ func InsertAction(action GetSLA) {
}
}
// todo 需要适应文件名有空格的情况
func ParseSftpLog(s string) (GetSLA, error) {
if !strings.Contains(s, "sftp-server") {
// 不是sftp日志
......@@ -617,7 +583,10 @@ func ParseSftpLog(s string) (GetSLA, error) {
if err != nil {
return nil, err
}
fta := parseSLA(fs[2], t)
fta, err := parseSLA(fs[2], t)
if err != nil {
return nil, err
}
if fta == nil {
return nil, nil
}
......@@ -645,6 +614,7 @@ 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)
......
......@@ -8,6 +8,7 @@ import (
"time"
"github.com/gofrs/flock"
"github.com/spf13/pflag"
)
// import (
......@@ -75,24 +76,20 @@ import (
// }
var (
logfile *os.File
logfile *os.File
flagDebug = pflag.Bool("debug", false, "debug mode, print log to stdout, not file")
flagHelp = pflag.BoolP("help", "h", false, "show usage")
)
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 main() {
pflag.Parse()
func shutdown() {
if logfile != nil {
logfile.Close()
if *flagHelp {
fmt.Println("Monitor sftp and scp file uploads. After a file is uploaded, use clamdscan to scan the file. If the file contains a virus, delete it")
pflag.Usage()
return
}
}
func main() {
fileLock := flock.New("/tmp/file-monitor.lock")
locked, err := fileLock.TryLock()
if err != nil || !locked {
......@@ -103,5 +100,15 @@ func main() {
if err != nil {
log.Fatal(err)
}
if !*flagDebug {
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)
defer logFile.Close()
}
}
logic.StartSftpMonitor()
}
......@@ -15,3 +15,9 @@ file-minitor是一个监控sftp和scp上传文件动作并对上传文件进行
同样大小下,`.zip`文件扫描比较慢,建议压缩包格式为 `.tar.gz`
## todo
添加白名单:
- 用户白名单:不扫描指定用户上传的文件
- 路径白名单:不扫描上传到指定路径的文件
\ No newline at end of file
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