64 lines
1.4 KiB
Go
64 lines
1.4 KiB
Go
package parser
|
|
|
|
import (
|
|
"regexp"
|
|
|
|
"github.com/d3m0k1d/BanForge/internal/logger"
|
|
"github.com/d3m0k1d/BanForge/internal/metrics"
|
|
"github.com/d3m0k1d/BanForge/internal/storage"
|
|
)
|
|
|
|
type ApacheParser struct {
|
|
pattern *regexp.Regexp
|
|
logger *logger.Logger
|
|
}
|
|
|
|
func NewApacheParser() *ApacheParser {
|
|
pattern := regexp.MustCompile(
|
|
`^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+-\s+-\s+\[(.*?)\]\s+"(\w+)\s+(.*?)\s+HTTP/[\d.]+"\s+(\d+)\s+(\d+|-)\s+"(.*?)"\s+"(.*?)"`,
|
|
)
|
|
// Groups:
|
|
// 1: IP
|
|
// 2: Timestamp
|
|
// 3: Method (GET, POST, etc.)
|
|
// 4: Path
|
|
// 5: Status Code (200, 404, 403...)
|
|
// 6: Response Size
|
|
// 7: Referer
|
|
// 8: User-Agent
|
|
|
|
return &ApacheParser{
|
|
pattern: pattern,
|
|
logger: logger.New(false),
|
|
}
|
|
}
|
|
|
|
func (p *ApacheParser) Parse(eventCh <-chan Event, resultCh chan<- *storage.LogEntry) {
|
|
// Group 1: IP, Group 2: Timestamp, Group 3: Method, Group 4: Path, Group 5: Status
|
|
for event := range eventCh {
|
|
matches := p.pattern.FindStringSubmatch(event.Data)
|
|
if matches == nil {
|
|
continue
|
|
}
|
|
path := matches[4]
|
|
status := matches[5]
|
|
method := matches[3]
|
|
|
|
resultCh <- &storage.LogEntry{
|
|
Service: "apache",
|
|
IP: matches[1],
|
|
Path: path,
|
|
Status: status,
|
|
Method: method,
|
|
}
|
|
metrics.IncParserEvent("apache")
|
|
p.logger.Info(
|
|
"Parsed apache log entry",
|
|
"ip", matches[1],
|
|
"path", path,
|
|
"status", status,
|
|
"method", method,
|
|
)
|
|
}
|
|
}
|