Files
ProxmoxDash/traffic_network_map.go

108 lines
3.1 KiB
Go

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
}