unpoller_unpoller/pkg/influxunifi/events.go

186 lines
5.5 KiB
Go

package influxunifi
import (
"time"
"github.com/unpoller/unifi"
)
// These constants are used as names for printed/logged counters.
const (
eventT = item("Event")
idsT = item("IDS")
)
// batchIDS generates intrusion detection datapoints for InfluxDB.
func (u *InfluxUnifi) batchIDS(r report, i *unifi.IDS) { // nolint:dupl
if time.Since(i.Datetime) > u.Interval.Duration+time.Second {
return // The event is older than our interval, ignore it.
}
fields := map[string]any{
"dest_port": i.DestPort,
"src_port": i.SrcPort,
"dest_ip": i.DestIP,
"dst_mac": i.DstMAC,
"host": i.Host,
"msg": i.Msg,
"src_ip": i.SrcIP,
"src_mac": i.SrcMAC,
"dstip_asn": i.DestIPGeo.Asn,
"dstip_latitude": i.DestIPGeo.Latitude,
"dstip_longitude": i.DestIPGeo.Longitude,
"dstip_city": i.DestIPGeo.City,
"dstip_continent_code": i.DestIPGeo.ContinentCode,
"dstip_country_code": i.DestIPGeo.CountryCode,
"dstip_country_name": i.DestIPGeo.CountryName,
"dstip_organization": i.DestIPGeo.Organization,
"srcip_asn": i.SourceIPGeo.Asn,
"srcip_latitude": i.SourceIPGeo.Latitude,
"srcip_longitude": i.SourceIPGeo.Longitude,
"srcip_city": i.SourceIPGeo.City,
"srcip_continent_code": i.SourceIPGeo.ContinentCode,
"srcip_country_code": i.SourceIPGeo.CountryCode,
"srcip_country_name": i.SourceIPGeo.CountryName,
"srcip_organization": i.SourceIPGeo.Organization,
}
r.addCount(idsT)
r.send(&metric{
Table: "unifi_ids",
TS: i.Datetime,
Fields: cleanFields(fields),
Tags: cleanTags(map[string]string{
"site_name": i.SiteName,
"source": i.SourceName,
"in_iface": i.InIface,
"event_type": i.EventType,
"subsystem": i.Subsystem,
"archived": i.Archived.Txt,
"usgip": i.USGIP,
"proto": i.Proto,
"key": i.Key,
"catname": i.Catname,
"app_proto": i.AppProto,
"action": i.InnerAlertAction,
}),
})
}
// batchEvents generates events from UniFi for InfluxDB.
func (u *InfluxUnifi) batchEvent(r report, i *unifi.Event) { // nolint: funlen
if time.Since(i.Datetime) > u.Interval.Duration+time.Second {
return // The event is older than our interval, ignore it.
}
fields := map[string]any{
"msg": i.Msg, // contains user[] or guest[] or admin[]
"duration": i.Duration.Val, // probably microseconds?
"guest": i.Guest, // mac address
"user": i.User, // mac address
"host": i.Host, // usg device?
"hostname": i.Hostname, // client name
"dest_port": i.DestPort,
"src_port": i.SrcPort,
"bytes": i.Bytes.Val,
"dest_ip": i.DestIP,
"dst_mac": i.DstMAC,
"ip": i.IP,
"src_ip": i.SrcIP,
"src_mac": i.SrcMAC,
"dstip_asn": i.DestIPGeo.Asn,
"dstip_latitude": i.DestIPGeo.Latitude,
"dstip_longitude": i.DestIPGeo.Longitude,
"dstip_city": i.DestIPGeo.City,
"dstip_continent_code": i.DestIPGeo.ContinentCode,
"dstip_country_code": i.DestIPGeo.CountryCode,
"dstip_country_name": i.DestIPGeo.CountryName,
"dstip_organization": i.DestIPGeo.Organization,
"srcip_asn": i.SourceIPGeo.Asn,
"srcip_latitude": i.SourceIPGeo.Latitude,
"srcip_longitude": i.SourceIPGeo.Longitude,
"srcip_city": i.SourceIPGeo.City,
"srcip_continent_code": i.SourceIPGeo.ContinentCode,
"srcip_country_code": i.SourceIPGeo.CountryCode,
"srcip_country_name": i.SourceIPGeo.CountryName,
"srcip_organization": i.SourceIPGeo.Organization,
}
r.addCount(eventT)
r.send(&metric{
TS: i.Datetime,
Table: "unifi_events",
Fields: cleanFields(fields),
Tags: cleanTags(map[string]string{
"admin": i.Admin, // username
"site_name": i.SiteName,
"source": i.SourceName,
"ap_from": i.ApFrom,
"ap_to": i.ApTo,
"ap": i.Ap,
"ap_name": i.ApName,
"gw": i.Gw,
"gw_name": i.GwName,
"sw": i.Sw,
"sw_name": i.SwName,
"catname": i.Catname,
"radio": i.Radio,
"radio_from": i.RadioFrom,
"radio_to": i.RadioTo,
"key": i.Key,
"in_iface": i.InIface,
"event_type": i.EventType,
"subsystem": i.Subsystem,
"ssid": i.SSID,
"is_admin": i.IsAdmin.Txt,
"channel": i.Channel.Txt,
"channel_from": i.ChannelFrom.Txt,
"channel_to": i.ChannelTo.Txt,
"usgip": i.USGIP,
"network": i.Network,
"app_proto": i.AppProto,
"proto": i.Proto,
"action": i.InnerAlertAction,
}),
})
}
// cleanTags removes any tag that is empty.
func cleanTags(tags map[string]string) map[string]string {
for i := range tags {
if tags[i] == "" {
delete(tags, i)
}
}
return tags
}
// cleanFields removes any field with a default (or empty) value.
func cleanFields(fields map[string]any) map[string]any { //nolint:cyclop
for s := range fields {
switch v := fields[s].(type) {
case nil:
delete(fields, s)
case int, int64, float64:
if v == 0 {
delete(fields, s)
}
case unifi.FlexBool:
if v.Txt == "" {
delete(fields, s)
}
case unifi.FlexInt:
if v.Txt == "" {
delete(fields, s)
}
case string:
if v == "" {
delete(fields, s)
}
}
}
return fields
}