package main import ( "database/sql" "encoding/json" "fmt" "sort" ) type NetworkMapPoint struct { Country string `json:"country"` Protocol string `json:"protocol"` Direction string `json:"direction"` Count int `json:"count"` } type NetworkMapView struct { At int64 `json:"at"` ReceivedAt int64 `json:"receivedAt"` TCP int `json:"tcp"` UDP int `json:"udp"` ICMP int `json:"icmp"` Unmapped int `json:"unmapped"` MonitoringHidden int `json:"monitoringHidden"` Limited bool `json:"limited"` Error string `json:"error,omitempty"` Points []NetworkMapPoint `json:"points"` } func (s *Store) ReadNetworkSnapshot(agent string, rules []MonitoringRule, hide bool) (NetworkSnapshot, error) { var raw, name string err := s.db.QueryRow(`SELECT n.snapshot,a.name FROM network_sources n JOIN agents a ON a.id=n.agent WHERE n.agent=?`, agent).Scan(&raw, &name) if err == sql.ErrNoRows { return NetworkSnapshot{Flows: []NetworkFlow{}, Error: "Ожидание агента v0.21.0 или новее"}, nil } if err != nil { return NetworkSnapshot{}, err } var snapshot NetworkSnapshot if err = json.Unmarshal([]byte(raw), &snapshot); err != nil { return snapshot, err } snapshot.AgentName = name flows := make([]NetworkFlow, 0, len(snapshot.Flows)) for _, f := range snapshot.Flows { f.Monitoring = isMonitoringFlow(f, rules) if hide && f.Monitoring { snapshot.MonitoringHidden++ continue } flows = append(flows, f) } snapshot.Flows = flows return snapshot, nil } func makeNetworkMap(snapshot NetworkSnapshot, external bool) NetworkMapView { v := NetworkMapView{At: snapshot.At, ReceivedAt: snapshot.ReceivedAt, Limited: snapshot.Limited, Error: snapshot.Error, MonitoringHidden: snapshot.MonitoringHidden, Points: []NetworkMapPoint{}} if snapshot.ParseErrors > 0 { v.Error += fmt.Sprintf(" Нераспознанных строк: %d", snapshot.ParseErrors) } points := map[string]*NetworkMapPoint{} for _, f := range snapshot.Flows { if external && !f.External { continue } protocol := f.Protocol if protocol == "icmpv6" { protocol = "icmp" } switch protocol { case "tcp": v.TCP++ case "udp": v.UDP++ case "icmp": v.ICMP++ } country, direction := f.Country, "in" if !networkExternalIP(f.Source) { if networkExternalIP(f.Destination) { country, direction = f.DestinationCountry, "out" } else { v.Unmapped++ continue } } if country == "" || country == "LAN" { v.Unmapped++ continue } key := country + "/" + protocol + "/" + direction if points[key] == nil { points[key] = &NetworkMapPoint{Country: country, Protocol: protocol, Direction: direction} } points[key].Count++ } for _, p := range points { v.Points = append(v.Points, *p) } sort.Slice(v.Points, func(i, j int) bool { a, b := v.Points[i], v.Points[j] if a.Count != b.Count { return a.Count > b.Count } return a.Country+a.Protocol+a.Direction < b.Country+b.Protocol+b.Direction }) return v }