123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- package database
- import (
- "fmt"
- "strings"
- "time"
- "strconv"
- "github.com/crowdsecurity/crowdsec/pkg/database/ent"
- "github.com/crowdsecurity/crowdsec/pkg/database/ent/decision"
- "github.com/crowdsecurity/crowdsec/pkg/types"
- "github.com/pkg/errors"
- )
- func BuildDecisionRequestWithFilter(query *ent.DecisionQuery, filter map[string][]string) (*ent.DecisionQuery, error) {
- var err error
- var start_ip, start_sfx, end_ip, end_sfx int64
- var ip_sz int
- var contains bool = true
- /*if contains is true, return bans that *contains* the given value (value is the inner)
- else, return bans that are *contained* by the given value (value is the outer)*/
- /*the simulated filter is a bit different : if it's not present *or* set to false, specifically exclude records with simulated to true */
- if v, ok := filter["simulated"]; ok {
- if v[0] == "false" {
- query = query.Where(decision.SimulatedEQ(false))
- }
- delete(filter, "simulated")
- } else {
- query = query.Where(decision.SimulatedEQ(false))
- }
- for param, value := range filter {
- switch param {
- case "contains":
- contains, err = strconv.ParseBool(value[0])
- if err != nil {
- return nil, errors.Wrapf(InvalidFilter, "invalid contains value : %s", err)
- }
- case "scope":
- for i, scope := range value {
- switch strings.ToLower(scope) {
- case "ip":
- value[i] = types.Ip
- case "range":
- value[i] = types.Range
- case "country":
- value[i] = types.Country
- case "as":
- value[i] = types.AS
- }
- }
- query = query.Where(decision.ScopeIn(value...))
- case "value":
- query = query.Where(decision.ValueEQ(value[0]))
- case "type":
- query = query.Where(decision.TypeEQ(value[0]))
- case "ip", "range":
- ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(value[0])
- if err != nil {
- return nil, errors.Wrapf(InvalidIPOrRange, "unable to convert '%s' to int: %s", value[0], err)
- }
- default:
- return query, errors.Wrapf(InvalidFilter, "'%s' doesn't exist", param)
- }
- }
- if ip_sz == 4 {
- if contains { /*decision contains {start_ip,end_ip}*/
- query = query.Where(decision.And(
- decision.StartIPLTE(start_ip),
- decision.EndIPGTE(end_ip),
- decision.IPSizeEQ(int64(ip_sz)),
- ))
- } else { /*decision is contained within {start_ip,end_ip}*/
- query = query.Where(decision.And(
- decision.StartIPGTE(start_ip),
- decision.EndIPLTE(end_ip),
- decision.IPSizeEQ(int64(ip_sz)),
- ))
- }
- } else if ip_sz == 16 {
- if contains { /*decision contains {start_ip,end_ip}*/
- query = query.Where(decision.And(
- //matching addr size
- decision.IPSizeEQ(int64(ip_sz)),
- decision.Or(
- //decision.start_ip < query.start_ip
- decision.StartIPLT(start_ip),
- decision.And(
- //decision.start_ip == query.start_ip
- decision.StartIPEQ(start_ip),
- //decision.start_suffix <= query.start_suffix
- decision.StartSuffixLTE(start_sfx),
- )),
- decision.Or(
- //decision.end_ip > query.end_ip
- decision.EndIPGT(end_ip),
- decision.And(
- //decision.end_ip == query.end_ip
- decision.EndIPEQ(end_ip),
- //decision.end_suffix >= query.end_suffix
- decision.EndSuffixGTE(end_sfx),
- ),
- ),
- ))
- } else { /*decision is contained {start_ip,end_ip}*/
- query = query.Where(decision.And(
- //matching addr size
- decision.IPSizeEQ(int64(ip_sz)),
- decision.Or(
- //decision.start_ip > query.start_ip
- decision.StartIPGT(start_ip),
- decision.And(
- //decision.start_ip == query.start_ip
- decision.StartIPEQ(start_ip),
- //decision.start_suffix >= query.start_suffix
- decision.StartSuffixGTE(start_sfx),
- )),
- decision.Or(
- //decision.end_ip < query.end_ip
- decision.EndIPLT(end_ip),
- decision.And(
- //decision.end_ip == query.end_ip
- decision.EndIPEQ(end_ip),
- //decision.end_suffix <= query.end_suffix
- decision.EndSuffixLTE(end_sfx),
- ),
- ),
- ))
- }
- } else if ip_sz != 0 {
- return nil, errors.Wrapf(InvalidFilter, "Unknown ip size %d", ip_sz)
- }
- return query, nil
- }
- func (c *Client) QueryDecisionWithFilter(filter map[string][]string) ([]*ent.Decision, error) {
- var data []*ent.Decision
- var err error
- decisions := c.Ent.Decision.Query().
- Where(decision.UntilGTE(time.Now().UTC()))
- decisions, err = BuildDecisionRequestWithFilter(decisions, filter)
- if err != nil {
- return []*ent.Decision{}, err
- }
- err = decisions.Select(
- decision.FieldID,
- decision.FieldUntil,
- decision.FieldScenario,
- decision.FieldType,
- decision.FieldStartIP,
- decision.FieldEndIP,
- decision.FieldValue,
- decision.FieldScope,
- decision.FieldOrigin,
- ).Scan(c.CTX, &data)
- if err != nil {
- c.Log.Warningf("QueryDecisionWithFilter : %s", err)
- return []*ent.Decision{}, errors.Wrap(QueryFail, "query decision failed")
- }
- return data, nil
- }
- func (c *Client) QueryAllDecisionsWithFilters(filters map[string][]string) ([]*ent.Decision, error) {
- query := c.Ent.Decision.Query().Where(decision.UntilGT(time.Now().UTC()))
- query, err := BuildDecisionRequestWithFilter(query, filters)
- if err != nil {
- c.Log.Warningf("QueryAllDecisionsWithFilters : %s", err)
- return []*ent.Decision{}, errors.Wrap(QueryFail, "get all decisions with filters")
- }
- data, err := query.All(c.CTX)
- if err != nil {
- c.Log.Warningf("QueryAllDecisionsWithFilters : %s", err)
- return []*ent.Decision{}, errors.Wrap(QueryFail, "get all decisions with filters")
- }
- return data, nil
- }
- func (c *Client) QueryExpiredDecisionsWithFilters(filters map[string][]string) ([]*ent.Decision, error) {
- query := c.Ent.Decision.Query().Where(decision.UntilLT(time.Now().UTC()))
- query, err := BuildDecisionRequestWithFilter(query, filters)
- if err != nil {
- c.Log.Warningf("QueryExpiredDecisionsWithFilters : %s", err)
- return []*ent.Decision{}, errors.Wrap(QueryFail, "get expired decisions with filters")
- }
- data, err := query.All(c.CTX)
- if err != nil {
- c.Log.Warningf("QueryExpiredDecisionsWithFilters : %s", err)
- return []*ent.Decision{}, errors.Wrap(QueryFail, "expired decisions")
- }
- return data, nil
- }
- func (c *Client) QueryExpiredDecisionsSinceWithFilters(since time.Time, filters map[string][]string) ([]*ent.Decision, error) {
- query := c.Ent.Decision.Query().Where(decision.UntilLT(time.Now().UTC())).Where(decision.UntilGT(since))
- query, err := BuildDecisionRequestWithFilter(query, filters)
- if err != nil {
- c.Log.Warningf("QueryExpiredDecisionsSinceWithFilters : %s", err)
- return []*ent.Decision{}, errors.Wrap(QueryFail, "expired decisions with filters")
- }
- data, err := query.All(c.CTX)
- if err != nil {
- c.Log.Warningf("QueryExpiredDecisionsSinceWithFilters : %s", err)
- return []*ent.Decision{}, errors.Wrap(QueryFail, "expired decisions with filters")
- }
- return data, nil
- }
- func (c *Client) QueryNewDecisionsSinceWithFilters(since time.Time, filters map[string][]string) ([]*ent.Decision, error) {
- query := c.Ent.Decision.Query().Where(decision.CreatedAtGT(since)).Where(decision.UntilGT(time.Now().UTC()))
- query, err := BuildDecisionRequestWithFilter(query, filters)
- if err != nil {
- c.Log.Warningf("QueryNewDecisionsSinceWithFilters : %s", err)
- return []*ent.Decision{}, errors.Wrapf(QueryFail, "new decisions since '%s'", since.String())
- }
- data, err := query.All(c.CTX)
- if err != nil {
- c.Log.Warningf("QueryNewDecisionsSinceWithFilters : %s", err)
- return []*ent.Decision{}, errors.Wrapf(QueryFail, "new decisions since '%s'", since.String())
- }
- return data, nil
- }
- func (c *Client) DeleteDecisionById(decisionId int) error {
- err := c.Ent.Decision.DeleteOneID(decisionId).Exec(c.CTX)
- if err != nil {
- c.Log.Warningf("DeleteDecisionById : %s", err)
- return errors.Wrapf(DeleteFail, "decision with id '%d' doesn't exist", decisionId)
- }
- return nil
- }
- func (c *Client) DeleteDecisionsWithFilter(filter map[string][]string) (string, error) {
- var err error
- var start_ip, start_sfx, end_ip, end_sfx int64
- var ip_sz int
- var contains bool = true
- /*if contains is true, return bans that *contains* the given value (value is the inner)
- else, return bans that are *contained* by the given value (value is the outer) */
- decisions := c.Ent.Decision.Delete()
- for param, value := range filter {
- switch param {
- case "contains":
- contains, err = strconv.ParseBool(value[0])
- if err != nil {
- return "0", errors.Wrapf(InvalidFilter, "invalid contains value : %s", err)
- }
- case "scope":
- decisions = decisions.Where(decision.ScopeEQ(value[0]))
- case "value":
- decisions = decisions.Where(decision.ValueEQ(value[0]))
- case "type":
- decisions = decisions.Where(decision.TypeEQ(value[0]))
- case "ip", "range":
- ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(value[0])
- if err != nil {
- return "0", errors.Wrapf(InvalidIPOrRange, "unable to convert '%s' to int: %s", value[0], err)
- }
- default:
- return "0", errors.Wrap(InvalidFilter, fmt.Sprintf("'%s' doesn't exist", param))
- }
- }
- if ip_sz == 4 {
- if contains { /*decision contains {start_ip,end_ip}*/
- decisions = decisions.Where(decision.And(
- decision.StartIPLTE(start_ip),
- decision.EndIPGTE(end_ip),
- decision.IPSizeEQ(int64(ip_sz)),
- ))
- } else { /*decision is contained within {start_ip,end_ip}*/
- decisions = decisions.Where(decision.And(
- decision.StartIPGTE(start_ip),
- decision.EndIPLTE(end_ip),
- decision.IPSizeEQ(int64(ip_sz)),
- ))
- }
- } else if ip_sz == 16 {
- if contains { /*decision contains {start_ip,end_ip}*/
- decisions = decisions.Where(decision.And(
- //matching addr size
- decision.IPSizeEQ(int64(ip_sz)),
- decision.Or(
- //decision.start_ip < query.start_ip
- decision.StartIPLT(start_ip),
- decision.And(
- //decision.start_ip == query.start_ip
- decision.StartIPEQ(start_ip),
- //decision.start_suffix <= query.start_suffix
- decision.StartSuffixLTE(start_sfx),
- )),
- decision.Or(
- //decision.end_ip > query.end_ip
- decision.EndIPGT(end_ip),
- decision.And(
- //decision.end_ip == query.end_ip
- decision.EndIPEQ(end_ip),
- //decision.end_suffix >= query.end_suffix
- decision.EndSuffixGTE(end_sfx),
- ),
- ),
- ))
- } else {
- decisions = decisions.Where(decision.And(
- //matching addr size
- decision.IPSizeEQ(int64(ip_sz)),
- decision.Or(
- //decision.start_ip > query.start_ip
- decision.StartIPGT(start_ip),
- decision.And(
- //decision.start_ip == query.start_ip
- decision.StartIPEQ(start_ip),
- //decision.start_suffix >= query.start_suffix
- decision.StartSuffixGTE(start_sfx),
- )),
- decision.Or(
- //decision.end_ip < query.end_ip
- decision.EndIPLT(end_ip),
- decision.And(
- //decision.end_ip == query.end_ip
- decision.EndIPEQ(end_ip),
- //decision.end_suffix <= query.end_suffix
- decision.EndSuffixLTE(end_sfx),
- ),
- ),
- ))
- }
- } else if ip_sz != 0 {
- return "0", errors.Wrapf(InvalidFilter, "Unknown ip size %d", ip_sz)
- }
- nbDeleted, err := decisions.Exec(c.CTX)
- if err != nil {
- c.Log.Warningf("DeleteDecisionsWithFilter : %s", err)
- return "0", errors.Wrap(DeleteFail, "decisions with provided filter")
- }
- return strconv.Itoa(nbDeleted), nil
- }
- // SoftDeleteDecisionsWithFilter udpate the expiration time to now() for the decisions matching the filter
- func (c *Client) SoftDeleteDecisionsWithFilter(filter map[string][]string) (string, error) {
- var err error
- var start_ip, start_sfx, end_ip, end_sfx int64
- var ip_sz int
- var contains bool = true
- /*if contains is true, return bans that *contains* the given value (value is the inner)
- else, return bans that are *contained* by the given value (value is the outer)*/
- decisions := c.Ent.Decision.Update().Where(decision.UntilGT(time.Now().UTC()))
- for param, value := range filter {
- switch param {
- case "contains":
- contains, err = strconv.ParseBool(value[0])
- if err != nil {
- return "0", errors.Wrapf(InvalidFilter, "invalid contains value : %s", err)
- }
- case "scope":
- decisions = decisions.Where(decision.ScopeEQ(value[0]))
- case "value":
- decisions = decisions.Where(decision.ValueEQ(value[0]))
- case "type":
- decisions = decisions.Where(decision.TypeEQ(value[0]))
- case "ip", "range":
- ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(value[0])
- if err != nil {
- return "0", errors.Wrapf(InvalidIPOrRange, "unable to convert '%s' to int: %s", value[0], err)
- }
- default:
- return "0", errors.Wrapf(InvalidFilter, "'%s' doesn't exist", param)
- }
- }
- if ip_sz == 4 {
- if contains {
- /*Decision contains {start_ip,end_ip}*/
- decisions = decisions.Where(decision.And(
- decision.StartIPLTE(start_ip),
- decision.EndIPGTE(end_ip),
- decision.IPSizeEQ(int64(ip_sz)),
- ))
- } else {
- /*Decision is contained within {start_ip,end_ip}*/
- decisions = decisions.Where(decision.And(
- decision.StartIPGTE(start_ip),
- decision.EndIPLTE(end_ip),
- decision.IPSizeEQ(int64(ip_sz)),
- ))
- }
- } else if ip_sz == 16 {
- /*decision contains {start_ip,end_ip}*/
- if contains {
- decisions = decisions.Where(decision.And(
- //matching addr size
- decision.IPSizeEQ(int64(ip_sz)),
- decision.Or(
- //decision.start_ip < query.start_ip
- decision.StartIPLT(start_ip),
- decision.And(
- //decision.start_ip == query.start_ip
- decision.StartIPEQ(start_ip),
- //decision.start_suffix <= query.start_suffix
- decision.StartSuffixLTE(start_sfx),
- )),
- decision.Or(
- //decision.end_ip > query.end_ip
- decision.EndIPGT(end_ip),
- decision.And(
- //decision.end_ip == query.end_ip
- decision.EndIPEQ(end_ip),
- //decision.end_suffix >= query.end_suffix
- decision.EndSuffixGTE(end_sfx),
- ),
- ),
- ))
- } else {
- /*decision is contained within {start_ip,end_ip}*/
- decisions = decisions.Where(decision.And(
- //matching addr size
- decision.IPSizeEQ(int64(ip_sz)),
- decision.Or(
- //decision.start_ip > query.start_ip
- decision.StartIPGT(start_ip),
- decision.And(
- //decision.start_ip == query.start_ip
- decision.StartIPEQ(start_ip),
- //decision.start_suffix >= query.start_suffix
- decision.StartSuffixGTE(start_sfx),
- )),
- decision.Or(
- //decision.end_ip < query.end_ip
- decision.EndIPLT(end_ip),
- decision.And(
- //decision.end_ip == query.end_ip
- decision.EndIPEQ(end_ip),
- //decision.end_suffix <= query.end_suffix
- decision.EndSuffixLTE(end_sfx),
- ),
- ),
- ))
- }
- } else if ip_sz != 0 {
- return "0", errors.Wrapf(InvalidFilter, "Unknown ip size %d", ip_sz)
- }
- nbDeleted, err := decisions.SetUntil(time.Now().UTC()).Save(c.CTX)
- if err != nil {
- c.Log.Warningf("SoftDeleteDecisionsWithFilter : %s", err)
- return "0", errors.Wrap(DeleteFail, "soft delete decisions with provided filter")
- }
- return strconv.Itoa(nbDeleted), nil
- }
- //SoftDeleteDecisionByID set the expiration of a decision to now()
- func (c *Client) SoftDeleteDecisionByID(decisionID int) error {
- nbUpdated, err := c.Ent.Decision.Update().Where(decision.IDEQ(decisionID)).SetUntil(time.Now().UTC()).Save(c.CTX)
- if err != nil || nbUpdated == 0 {
- c.Log.Warningf("SoftDeleteDecisionByID : %v (nb soft deleted: %d)", err, nbUpdated)
- return errors.Wrapf(DeleteFail, "decision with id '%d' doesn't exist", decisionID)
- }
- if nbUpdated == 0 {
- return ItemNotFound
- }
- return nil
- }
|