unpoller_unpoller/core/unifi/ids.go

156 lines
5.0 KiB
Go

package unifi
import (
"encoding/json"
"fmt"
"sort"
"time"
)
// IDS holds an Intrusion Prevention System Event.
type IDS struct {
Archived FlexBool `json:"archived"`
DestPort int `json:"dest_port,omitempty"`
SrcPort int `json:"src_port,omitempty"`
FlowID int64 `json:"flow_id"`
InnerAlertRev int64 `json:"inner_alert_rev"`
InnerAlertSeverity int64 `json:"inner_alert_severity"`
InnerAlertGID int64 `json:"inner_alert_gid"`
InnerAlertSignatureID int64 `json:"inner_alert_signature_id"`
Time int64 `json:"time"`
Timestamp int64 `json:"timestamp"`
Datetime time.Time `json:"datetime"`
AppProto string `json:"app_proto,omitempty"`
Catname string `json:"catname"`
DestIP string `json:"dest_ip"`
DstMAC string `json:"dst_mac"`
DstIPASN string `json:"dstipASN"`
DstIPCountry string `json:"dstipCountry"`
EventType string `json:"event_type"`
Host string `json:"host"`
ID string `json:"_id"`
InIface string `json:"in_iface"`
InnerAlertAction string `json:"inner_alert_action"`
InnerAlertCategory string `json:"inner_alert_category"`
InnerAlertSignature string `json:"inner_alert_signature"`
Key string `json:"key"`
Msg string `json:"msg"`
Proto string `json:"proto"`
SiteID string `json:"site_id"`
SiteName string `json:"-"`
SourceName string `json:"-"`
SrcIP string `json:"src_ip"`
SrcIPASN string `json:"srcipASN"`
SrcIPCountry string `json:"srcipCountry"`
SrcMAC string `json:"src_mac"`
Subsystem string `json:"subsystem"`
UniqueAlertID string `json:"unique_alertid"`
USGIP string `json:"usgip"`
USGIPASN string `json:"usgipASN"`
USGIPCountry string `json:"usgipCountry"`
DestIPGeo IPGeo `json:"dstipGeo"`
SourceIPGeo IPGeo `json:"srcipGeo"`
USGIPGeo IPGeo `json:"usgipGeo"`
}
// GetIDS returns Intrusion Detection Systems events for a list of Sites.
// timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End.
// Events between start and end are returned. End defaults to time.Now().
func (u *Unifi) GetIDS(sites []*Site, timeRange ...time.Time) ([]*IDS, error) {
data := []*IDS{}
for _, site := range sites {
response, err := u.GetIDSSite(site, timeRange...)
if err != nil {
return data, err
}
data = append(data, response...)
}
return data, nil
}
// GetIDSSite retreives the Intrusion Detection System Data for a single Site.
// timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End.
// Events between start and end are returned. End defaults to time.Now().
func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) {
if site == nil || site.Name == "" {
return nil, ErrNoSiteProvided
}
u.DebugLog("Polling Controller for IDS Events, site %s", site.SiteName)
var (
path = fmt.Sprintf(APIEventPathIDS, site.Name)
ids struct {
Data idsList `json:"data"`
}
)
if params, err := makeEventParams(timeRange...); err != nil {
return ids.Data, err
} else if err = u.GetData(path, &ids, params); err != nil {
return ids.Data, err
}
for i := range ids.Data {
// Add special SourceName value.
ids.Data[i].SourceName = u.URL
// Add the special "Site Name" to each event. This becomes a Grafana filter somewhere.
ids.Data[i].SiteName = site.SiteName
}
sort.Sort(ids.Data)
return ids.Data, nil
}
func makeEventParams(timeRange ...time.Time) (string, error) {
type eventReq struct {
Start int64 `json:"start,omitempty"`
End int64 `json:"end,omitempty"`
Limit int `json:"_limit,omitempty"`
Sort string `json:"_sort"`
}
rp := eventReq{Limit: eventLimit, Sort: "-time"}
switch len(timeRange) {
case 0:
rp.End = time.Now().Unix() * int64(time.Microsecond)
case 1:
rp.Start = timeRange[0].Unix() * int64(time.Microsecond)
rp.End = time.Now().Unix() * int64(time.Microsecond)
case 2: // nolint: gomnd
rp.Start = timeRange[0].Unix() * int64(time.Microsecond)
rp.End = timeRange[1].Unix() * int64(time.Microsecond)
default:
return "", ErrInvalidTimeRange
}
params, err := json.Marshal(&rp)
if err != nil {
return "", fmt.Errorf("json marshal: %w", err)
}
return string(params), nil
}
type idsList []*IDS
// Len satisfies sort.Interface.
func (e idsList) Len() int {
return len(e)
}
// Swap satisfies sort.Interface.
func (e idsList) Swap(i, j int) {
e[i], e[j] = e[j], e[i]
}
// Less satisfies sort.Interface. Sort our list by Datetime.
func (e idsList) Less(i, j int) bool {
return e[i].Datetime.Before(e[j].Datetime)
}