77 lines
2.3 KiB
Go
77 lines
2.3 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"net"
|
||
"strings"
|
||
)
|
||
|
||
// Domain/path restrictions describe HTTP probes only. An IP-only rule also
|
||
// matches conntrack initiators; a destination match never hides other clients.
|
||
type MonitoringRule struct {
|
||
IP string `json:"ip"`
|
||
Domain string `json:"domain,omitempty"`
|
||
PathPrefix string `json:"pathPrefix,omitempty"`
|
||
}
|
||
|
||
func validateMonitoringRules(rules []MonitoringRule) ([]MonitoringRule, error) {
|
||
if len(rules) > 32 {
|
||
return nil, fmt.Errorf("Не более 32 правил мониторинга")
|
||
}
|
||
result := make([]MonitoringRule, 0, len(rules))
|
||
for i, r := range rules {
|
||
ip := net.ParseIP(strings.TrimSpace(r.IP))
|
||
if ip == nil {
|
||
return nil, fmt.Errorf("Правило %d: нужен точный IPv4/IPv6-адрес", i+1)
|
||
}
|
||
r.IP = ip.String()
|
||
r.Domain = strings.ToLower(strings.TrimSpace(r.Domain))
|
||
r.PathPrefix = strings.TrimSpace(r.PathPrefix)
|
||
if len(r.Domain) > 253 || strings.ContainsAny(r.Domain, " /|\t\r\n") || len(r.PathPrefix) > 256 || strings.ContainsAny(r.PathPrefix, "|\r\n") || (r.PathPrefix != "" && !strings.HasPrefix(r.PathPrefix, "/")) {
|
||
return nil, fmt.Errorf("Правило %d: проверьте домен и префикс пути (начинается с /)", i+1)
|
||
}
|
||
result = append(result, r)
|
||
}
|
||
return result, nil
|
||
}
|
||
func isMonitoringRequest(e TrafficEvent, rules []MonitoringRule) bool {
|
||
if e.Kind != "request" {
|
||
return false
|
||
}
|
||
for _, r := range rules {
|
||
if e.IP == r.IP && (r.Domain == "" || strings.EqualFold(e.Domain, r.Domain)) && strings.HasPrefix(e.Path, r.PathPrefix) {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
func isMonitoringFlow(f NetworkFlow, rules []MonitoringRule) bool {
|
||
for _, r := range rules {
|
||
if net.ParseIP(f.Source).Equal(net.ParseIP(r.IP)) && r.Domain == "" && r.PathPrefix == "" {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
func monitoringSQL(rules []MonitoringRule) (string, []any) {
|
||
var parts []string
|
||
var args []any
|
||
for _, r := range rules {
|
||
p := "(ip=?"
|
||
args = append(args, r.IP)
|
||
if r.Domain != "" {
|
||
p += " AND lower(domain)=?"
|
||
args = append(args, r.Domain)
|
||
}
|
||
if r.PathPrefix != "" {
|
||
p += " AND substr(path,1,length(?))=?"
|
||
args = append(args, r.PathPrefix, r.PathPrefix)
|
||
}
|
||
parts = append(parts, p+")")
|
||
}
|
||
if len(parts) == 0 {
|
||
return "", nil
|
||
}
|
||
return " AND NOT (kind='request' AND (" + strings.Join(parts, " OR ") + "))", args
|
||
}
|