-
Notifications
You must be signed in to change notification settings - Fork 30
/
read.go
119 lines (106 loc) · 2.9 KB
/
read.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package waflog
import (
"bytes"
"io"
"os"
"regexp"
"github.com/fzipi/go-ftw/config"
"github.com/icza/backscanner"
"github.com/rs/zerolog/log"
)
// Contains looks in logfile for regex
func (ll *FTWLogLines) Contains(match string) bool {
// this should be a flag
lines := ll.getMarkedLines()
log.Trace().Msgf("ftw/waflog: got %d lines", len(lines))
result := false
for _, line := range lines {
log.Trace().Msgf("ftw/waflog: Matching %s in %s", match, line)
got, err := regexp.Match(match, line)
if err != nil {
log.Fatal().Msgf("ftw/waflog: bad regexp %s", err.Error())
}
if got {
log.Trace().Msgf("ftw/waflog: Found %s at %s", match, line)
result = true
break
}
}
return result
}
func (ll *FTWLogLines) getMarkedLines() [][]byte {
var found [][]byte
if err := ll.openLogFile(); err != nil {
log.Error().Caller().Msgf("cannot open log file: %s", err)
}
fi, err := ll.logFile.Stat()
if err != nil {
log.Error().Caller().Msgf("cannot read file's size")
return found
}
// Lines in modsec logging can be quite large
backscannerOptions := &backscanner.Options{
ChunkSize: 4096,
}
scanner := backscanner.NewOptions(ll.logFile, int(fi.Size()), backscannerOptions)
endFound := false
// end marker is the *first* marker when reading backwards,
// start marker is the *last* marker
for {
line, _, err := scanner.LineBytes()
if err != nil {
if err != io.EOF {
log.Trace().Err(err)
}
break
}
lineLower := bytes.ToLower(line)
if !endFound && bytes.Equal(lineLower, ll.EndMarker) {
endFound = true
continue
}
if endFound && bytes.Equal(lineLower, ll.StartMarker) {
break
}
saneCopy := make([]byte, len(line))
copy(saneCopy, line)
found = append(found, saneCopy)
}
return found
}
// CheckLogForMarker reads the log file and searches for a marker line.
// logFile is the file to search
// stageID is the ID of the current stage, which is part of the marker line
func (ll *FTWLogLines) CheckLogForMarker(stageID string) []byte {
if config.FTWConfig.RunMode == config.DefaultRunMode && ll.logFile == nil {
log.Fatal().Caller().Msg("No log file supplied")
}
offset, err := ll.logFile.Seek(0, os.SEEK_END)
if err != nil {
log.Error().Caller().Err(err).Msgf("failed to seek end of log file")
return nil
}
// Lines in modsec logging can be quite large
backscannerOptions := &backscanner.Options{
ChunkSize: 4096,
}
scanner := backscanner.NewOptions(ll.logFile, int(offset), backscannerOptions)
stageIDBytes := []byte(stageID)
crsHeaderBytes := bytes.ToLower([]byte(config.FTWConfig.LogMarkerHeaderName))
line := []byte{}
// find the last non-empty line
for err == nil && len(line) == 0 {
line, _, err = scanner.LineBytes()
}
if err != nil {
if err == io.EOF {
return nil
}
log.Trace().Err(err)
}
line = bytes.ToLower(line)
if bytes.Contains(line, crsHeaderBytes) && bytes.Contains(line, stageIDBytes) {
return line
}
return nil
}