refact pkg/database: clean up code and error messages (#3263)

* refact pkg/database: extract alertfilter.go
* refact pkg/database: extract function rollbackOnError(); dry error messages
This commit is contained in:
mmetc 2024-12-19 17:01:16 +01:00 committed by GitHub
parent ecf34c2fa1
commit 26c15a1267
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 279 additions and 294 deletions

View file

@ -242,7 +242,7 @@ func TestAlertListFilters(t *testing.T) {
w = lapi.RecordResponse(t, ctx, "GET", "/v1/alerts?ip=gruueq", emptyBody, "password")
assert.Equal(t, 500, w.Code)
assert.JSONEq(t, `{"message":"unable to convert 'gruueq' to int: invalid address: invalid ip address / range"}`, w.Body.String())
assert.JSONEq(t, `{"message":"invalid ip address 'gruueq'"}`, w.Body.String())
// test range (ok)
@ -261,7 +261,7 @@ func TestAlertListFilters(t *testing.T) {
w = lapi.RecordResponse(t, ctx, "GET", "/v1/alerts?range=ratata", emptyBody, "password")
assert.Equal(t, 500, w.Code)
assert.JSONEq(t, `{"message":"unable to convert 'ratata' to int: invalid address: invalid ip address / range"}`, w.Body.String())
assert.JSONEq(t, `{"message":"invalid ip address 'ratata'"}`, w.Body.String())
// test since (ok)

View file

@ -21,18 +21,6 @@ func (c *Controller) HandleDBErrors(gctx *gin.Context, err error) {
case errors.Is(err, database.HashError):
gctx.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
return
case errors.Is(err, database.InsertFail):
gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
case errors.Is(err, database.QueryFail):
gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
case errors.Is(err, database.ParseTimeFail):
gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
case errors.Is(err, database.ParseDurationFail):
gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return
default:
gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
return

258
pkg/database/alertfilter.go Normal file
View file

@ -0,0 +1,258 @@
package database
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/crowdsecurity/crowdsec/pkg/database/ent"
"github.com/crowdsecurity/crowdsec/pkg/database/ent/alert"
"github.com/crowdsecurity/crowdsec/pkg/database/ent/decision"
"github.com/crowdsecurity/crowdsec/pkg/database/ent/predicate"
"github.com/crowdsecurity/crowdsec/pkg/types"
)
func handleSimulatedFilter(filter map[string][]string, predicates *[]predicate.Alert) {
/* 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 && v[0] == "false" {
*predicates = append(*predicates, alert.SimulatedEQ(false))
}
}
func handleOriginFilter(filter map[string][]string, predicates *[]predicate.Alert) {
if _, ok := filter["origin"]; ok {
filter["include_capi"] = []string{"true"}
}
}
func handleScopeFilter(scope string, predicates *[]predicate.Alert) {
if strings.ToLower(scope) == "ip" {
scope = types.Ip
} else if strings.ToLower(scope) == "range" {
scope = types.Range
}
*predicates = append(*predicates, alert.SourceScopeEQ(scope))
}
func handleTimeFilters(param, value string, predicates *[]predicate.Alert) error {
duration, err := ParseDuration(value)
if err != nil {
return fmt.Errorf("while parsing duration: %w", err)
}
timePoint := time.Now().UTC().Add(-duration)
if timePoint.IsZero() {
return fmt.Errorf("empty time now() - %s", timePoint.String())
}
switch param {
case "since":
*predicates = append(*predicates, alert.StartedAtGTE(timePoint))
case "created_before":
*predicates = append(*predicates, alert.CreatedAtLTE(timePoint))
case "until":
*predicates = append(*predicates, alert.StartedAtLTE(timePoint))
}
return nil
}
func handleIPv4Predicates(ip_sz int, contains bool, start_ip, start_sfx, end_ip, end_sfx int64, predicates *[]predicate.Alert) {
if contains { // decision contains {start_ip,end_ip}
*predicates = append(*predicates, alert.And(
alert.HasDecisionsWith(decision.StartIPLTE(start_ip)),
alert.HasDecisionsWith(decision.EndIPGTE(end_ip)),
alert.HasDecisionsWith(decision.IPSizeEQ(int64(ip_sz))),
))
} else { // decision is contained within {start_ip,end_ip}
*predicates = append(*predicates, alert.And(
alert.HasDecisionsWith(decision.StartIPGTE(start_ip)),
alert.HasDecisionsWith(decision.EndIPLTE(end_ip)),
alert.HasDecisionsWith(decision.IPSizeEQ(int64(ip_sz))),
))
}
}
func handleIPv6Predicates(ip_sz int, contains bool, start_ip, start_sfx, end_ip, end_sfx int64, predicates *[]predicate.Alert) {
if contains { // decision contains {start_ip,end_ip}
*predicates = append(*predicates, alert.And(
// matching addr size
alert.HasDecisionsWith(decision.IPSizeEQ(int64(ip_sz))),
alert.Or(
// decision.start_ip < query.start_ip
alert.HasDecisionsWith(decision.StartIPLT(start_ip)),
alert.And(
// decision.start_ip == query.start_ip
alert.HasDecisionsWith(decision.StartIPEQ(start_ip)),
// decision.start_suffix <= query.start_suffix
alert.HasDecisionsWith(decision.StartSuffixLTE(start_sfx)),
),
),
alert.Or(
// decision.end_ip > query.end_ip
alert.HasDecisionsWith(decision.EndIPGT(end_ip)),
alert.And(
// decision.end_ip == query.end_ip
alert.HasDecisionsWith(decision.EndIPEQ(end_ip)),
// decision.end_suffix >= query.end_suffix
alert.HasDecisionsWith(decision.EndSuffixGTE(end_sfx)),
),
),
))
} else { // decision is contained within {start_ip,end_ip}
*predicates = append(*predicates, alert.And(
// matching addr size
alert.HasDecisionsWith(decision.IPSizeEQ(int64(ip_sz))),
alert.Or(
// decision.start_ip > query.start_ip
alert.HasDecisionsWith(decision.StartIPGT(start_ip)),
alert.And(
// decision.start_ip == query.start_ip
alert.HasDecisionsWith(decision.StartIPEQ(start_ip)),
// decision.start_suffix >= query.start_suffix
alert.HasDecisionsWith(decision.StartSuffixGTE(start_sfx)),
),
),
alert.Or(
// decision.end_ip < query.end_ip
alert.HasDecisionsWith(decision.EndIPLT(end_ip)),
alert.And(
// decision.end_ip == query.end_ip
alert.HasDecisionsWith(decision.EndIPEQ(end_ip)),
// decision.end_suffix <= query.end_suffix
alert.HasDecisionsWith(decision.EndSuffixLTE(end_sfx)),
),
),
))
}
}
func handleIPPredicates(ip_sz int, contains bool, start_ip, start_sfx, end_ip, end_sfx int64, predicates *[]predicate.Alert) error {
if ip_sz == 4 {
handleIPv4Predicates(ip_sz, contains, start_ip, start_sfx, end_ip, end_sfx, predicates)
} else if ip_sz == 16 {
handleIPv6Predicates(ip_sz, contains, start_ip, start_sfx, end_ip, end_sfx, predicates)
} else if ip_sz != 0 {
return errors.Wrapf(InvalidFilter, "Unknown ip size %d", ip_sz)
}
return nil
}
func handleIncludeCapiFilter(value string, predicates *[]predicate.Alert) error {
if value == "false" {
*predicates = append(*predicates, alert.And(
// do not show alerts with active decisions having origin CAPI or lists
alert.And(
alert.Not(alert.HasDecisionsWith(decision.OriginEQ(types.CAPIOrigin))),
alert.Not(alert.HasDecisionsWith(decision.OriginEQ(types.ListOrigin))),
),
alert.Not(
alert.And(
// do not show neither alerts with no decisions if the Source Scope is lists: or CAPI
alert.Not(alert.HasDecisions()),
alert.Or(
alert.SourceScopeHasPrefix(types.ListOrigin+":"),
alert.SourceScopeEQ(types.CommunityBlocklistPullSourceScope),
),
),
),
))
} else if value != "true" {
log.Errorf("invalid bool '%s' for include_capi", value)
}
return nil
}
func AlertPredicatesFromFilter(filter map[string][]string) ([]predicate.Alert, error) {
predicates := make([]predicate.Alert, 0)
var (
err error
start_ip, start_sfx, end_ip, end_sfx int64
hasActiveDecision bool
ip_sz int
)
contains := 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)*/
handleSimulatedFilter(filter, &predicates)
handleOriginFilter(filter, &predicates)
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":
handleScopeFilter(value[0], &predicates)
case "value":
predicates = append(predicates, alert.SourceValueEQ(value[0]))
case "scenario":
predicates = append(predicates, alert.HasDecisionsWith(decision.ScenarioEQ(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, err
}
case "since", "created_before", "until":
if err := handleTimeFilters(param, value[0], &predicates); err != nil {
return nil, err
}
case "decision_type":
predicates = append(predicates, alert.HasDecisionsWith(decision.TypeEQ(value[0])))
case "origin":
predicates = append(predicates, alert.HasDecisionsWith(decision.OriginEQ(value[0])))
case "include_capi": // allows to exclude one or more specific origins
if err = handleIncludeCapiFilter(value[0], &predicates); err != nil {
return nil, err
}
case "has_active_decision":
if hasActiveDecision, err = strconv.ParseBool(value[0]); err != nil {
return nil, errors.Wrapf(ParseType, "'%s' is not a boolean: %s", value[0], err)
}
if hasActiveDecision {
predicates = append(predicates, alert.HasDecisionsWith(decision.UntilGTE(time.Now().UTC())))
} else {
predicates = append(predicates, alert.Not(alert.HasDecisions()))
}
case "limit":
continue
case "sort":
continue
case "simulated":
continue
case "with_decisions":
continue
default:
return nil, errors.Wrapf(InvalidFilter, "Filter parameter '%s' is unknown (=%s)", param, value[0])
}
}
if err := handleIPPredicates(ip_sz, contains, start_ip, start_sfx, end_ip, end_sfx, &predicates); err != nil {
return nil, err
}
return predicates, nil
}
func BuildAlertRequestFromFilter(alerts *ent.AlertQuery, filter map[string][]string) (*ent.AlertQuery, error) {
preds, err := AlertPredicatesFromFilter(filter)
if err != nil {
return nil, err
}
return alerts.Where(preds...), nil
}

View file

@ -20,7 +20,6 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/database/ent/decision"
"github.com/crowdsecurity/crowdsec/pkg/database/ent/event"
"github.com/crowdsecurity/crowdsec/pkg/database/ent/meta"
"github.com/crowdsecurity/crowdsec/pkg/database/ent/predicate"
"github.com/crowdsecurity/crowdsec/pkg/models"
"github.com/crowdsecurity/crowdsec/pkg/types"
)
@ -32,6 +31,14 @@ const (
maxLockRetries = 10 // how many times to retry a bulk operation when sqlite3.ErrBusy is encountered
)
func rollbackOnError(tx *ent.Tx, err error, msg string) error {
if rbErr := tx.Rollback(); rbErr != nil {
log.Errorf("rollback error: %v", rbErr)
}
return fmt.Errorf("%s: %w", msg, err)
}
// CreateOrUpdateAlert is specific to PAPI : It checks if alert already exists, otherwise inserts it
// if alert already exists, it checks it associated decisions already exists
// if some associated decisions are missing (ie. previous insert ended up in error) it inserts them
@ -285,12 +292,7 @@ func (c *Client) UpdateCommunityBlocklist(ctx context.Context, alertItem *models
duration, err := time.ParseDuration(*decisionItem.Duration)
if err != nil {
rollbackErr := txClient.Rollback()
if rollbackErr != nil {
log.Errorf("rollback error: %s", rollbackErr)
}
return 0, 0, 0, errors.Wrapf(ParseDurationFail, "decision duration '%+v' : %s", *decisionItem.Duration, err)
return 0,0,0, rollbackOnError(txClient, err, "parsing decision duration")
}
if decisionItem.Scope == nil {
@ -302,12 +304,7 @@ func (c *Client) UpdateCommunityBlocklist(ctx context.Context, alertItem *models
if strings.ToLower(*decisionItem.Scope) == "ip" || strings.ToLower(*decisionItem.Scope) == "range" {
sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(*decisionItem.Value)
if err != nil {
rollbackErr := txClient.Rollback()
if rollbackErr != nil {
log.Errorf("rollback error: %s", rollbackErr)
}
return 0, 0, 0, errors.Wrapf(InvalidIPOrRange, "invalid addr/range %s : %s", *decisionItem.Value, err)
return 0, 0, 0, rollbackOnError(txClient, err, "invalid ip addr/range")
}
}
@ -349,12 +346,7 @@ func (c *Client) UpdateCommunityBlocklist(ctx context.Context, alertItem *models
decision.ValueIn(deleteChunk...),
)).Exec(ctx)
if err != nil {
rollbackErr := txClient.Rollback()
if rollbackErr != nil {
log.Errorf("rollback error: %s", rollbackErr)
}
return 0, 0, 0, fmt.Errorf("while deleting older community blocklist decisions: %w", err)
return 0, 0, 0, rollbackOnError(txClient, err, "deleting older community blocklist decisions")
}
deleted += deletedDecisions
@ -365,12 +357,7 @@ func (c *Client) UpdateCommunityBlocklist(ctx context.Context, alertItem *models
for _, builderChunk := range builderChunks {
insertedDecisions, err := txClient.Decision.CreateBulk(builderChunk...).Save(ctx)
if err != nil {
rollbackErr := txClient.Rollback()
if rollbackErr != nil {
log.Errorf("rollback error: %s", rollbackErr)
}
return 0, 0, 0, fmt.Errorf("while bulk creating decisions: %w", err)
return 0, 0, 0, rollbackOnError(txClient, err, "bulk creating decisions")
}
inserted += len(insertedDecisions)
@ -380,12 +367,7 @@ func (c *Client) UpdateCommunityBlocklist(ctx context.Context, alertItem *models
err = txClient.Commit()
if err != nil {
rollbackErr := txClient.Rollback()
if rollbackErr != nil {
log.Errorf("rollback error: %s", rollbackErr)
}
return 0, 0, 0, fmt.Errorf("error committing transaction: %w", err)
return 0, 0, 0, rollbackOnError(txClient, err, "error committing transaction")
}
return alertRef.ID, inserted, deleted, nil
@ -727,247 +709,6 @@ func (c *Client) CreateAlert(ctx context.Context, machineID string, alertList []
return alertIDs, nil
}
func handleSimulatedFilter(filter map[string][]string, predicates *[]predicate.Alert) {
/* 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 && v[0] == "false" {
*predicates = append(*predicates, alert.SimulatedEQ(false))
}
}
func handleOriginFilter(filter map[string][]string, predicates *[]predicate.Alert) {
if _, ok := filter["origin"]; ok {
filter["include_capi"] = []string{"true"}
}
}
func handleScopeFilter(scope string, predicates *[]predicate.Alert) {
if strings.ToLower(scope) == "ip" {
scope = types.Ip
} else if strings.ToLower(scope) == "range" {
scope = types.Range
}
*predicates = append(*predicates, alert.SourceScopeEQ(scope))
}
func handleTimeFilters(param, value string, predicates *[]predicate.Alert) error {
duration, err := ParseDuration(value)
if err != nil {
return fmt.Errorf("while parsing duration: %w", err)
}
timePoint := time.Now().UTC().Add(-duration)
if timePoint.IsZero() {
return fmt.Errorf("empty time now() - %s", timePoint.String())
}
switch param {
case "since":
*predicates = append(*predicates, alert.StartedAtGTE(timePoint))
case "created_before":
*predicates = append(*predicates, alert.CreatedAtLTE(timePoint))
case "until":
*predicates = append(*predicates, alert.StartedAtLTE(timePoint))
}
return nil
}
func handleIPv4Predicates(ip_sz int, contains bool, start_ip, start_sfx, end_ip, end_sfx int64, predicates *[]predicate.Alert) {
if contains { // decision contains {start_ip,end_ip}
*predicates = append(*predicates, alert.And(
alert.HasDecisionsWith(decision.StartIPLTE(start_ip)),
alert.HasDecisionsWith(decision.EndIPGTE(end_ip)),
alert.HasDecisionsWith(decision.IPSizeEQ(int64(ip_sz))),
))
} else { // decision is contained within {start_ip,end_ip}
*predicates = append(*predicates, alert.And(
alert.HasDecisionsWith(decision.StartIPGTE(start_ip)),
alert.HasDecisionsWith(decision.EndIPLTE(end_ip)),
alert.HasDecisionsWith(decision.IPSizeEQ(int64(ip_sz))),
))
}
}
func handleIPv6Predicates(ip_sz int, contains bool, start_ip, start_sfx, end_ip, end_sfx int64, predicates *[]predicate.Alert) {
if contains { // decision contains {start_ip,end_ip}
*predicates = append(*predicates, alert.And(
// matching addr size
alert.HasDecisionsWith(decision.IPSizeEQ(int64(ip_sz))),
alert.Or(
// decision.start_ip < query.start_ip
alert.HasDecisionsWith(decision.StartIPLT(start_ip)),
alert.And(
// decision.start_ip == query.start_ip
alert.HasDecisionsWith(decision.StartIPEQ(start_ip)),
// decision.start_suffix <= query.start_suffix
alert.HasDecisionsWith(decision.StartSuffixLTE(start_sfx)),
),
),
alert.Or(
// decision.end_ip > query.end_ip
alert.HasDecisionsWith(decision.EndIPGT(end_ip)),
alert.And(
// decision.end_ip == query.end_ip
alert.HasDecisionsWith(decision.EndIPEQ(end_ip)),
// decision.end_suffix >= query.end_suffix
alert.HasDecisionsWith(decision.EndSuffixGTE(end_sfx)),
),
),
))
} else { // decision is contained within {start_ip,end_ip}
*predicates = append(*predicates, alert.And(
// matching addr size
alert.HasDecisionsWith(decision.IPSizeEQ(int64(ip_sz))),
alert.Or(
// decision.start_ip > query.start_ip
alert.HasDecisionsWith(decision.StartIPGT(start_ip)),
alert.And(
// decision.start_ip == query.start_ip
alert.HasDecisionsWith(decision.StartIPEQ(start_ip)),
// decision.start_suffix >= query.start_suffix
alert.HasDecisionsWith(decision.StartSuffixGTE(start_sfx)),
),
),
alert.Or(
// decision.end_ip < query.end_ip
alert.HasDecisionsWith(decision.EndIPLT(end_ip)),
alert.And(
// decision.end_ip == query.end_ip
alert.HasDecisionsWith(decision.EndIPEQ(end_ip)),
// decision.end_suffix <= query.end_suffix
alert.HasDecisionsWith(decision.EndSuffixLTE(end_sfx)),
),
),
))
}
}
func handleIPPredicates(ip_sz int, contains bool, start_ip, start_sfx, end_ip, end_sfx int64, predicates *[]predicate.Alert) error {
if ip_sz == 4 {
handleIPv4Predicates(ip_sz, contains, start_ip, start_sfx, end_ip, end_sfx, predicates)
} else if ip_sz == 16 {
handleIPv6Predicates(ip_sz, contains, start_ip, start_sfx, end_ip, end_sfx, predicates)
} else if ip_sz != 0 {
return errors.Wrapf(InvalidFilter, "Unknown ip size %d", ip_sz)
}
return nil
}
func handleIncludeCapiFilter(value string, predicates *[]predicate.Alert) error {
if value == "false" {
*predicates = append(*predicates, alert.And(
// do not show alerts with active decisions having origin CAPI or lists
alert.And(
alert.Not(alert.HasDecisionsWith(decision.OriginEQ(types.CAPIOrigin))),
alert.Not(alert.HasDecisionsWith(decision.OriginEQ(types.ListOrigin))),
),
alert.Not(
alert.And(
// do not show neither alerts with no decisions if the Source Scope is lists: or CAPI
alert.Not(alert.HasDecisions()),
alert.Or(
alert.SourceScopeHasPrefix(types.ListOrigin+":"),
alert.SourceScopeEQ(types.CommunityBlocklistPullSourceScope),
),
),
),
))
} else if value != "true" {
log.Errorf("invalid bool '%s' for include_capi", value)
}
return nil
}
func AlertPredicatesFromFilter(filter map[string][]string) ([]predicate.Alert, error) {
predicates := make([]predicate.Alert, 0)
var (
err error
start_ip, start_sfx, end_ip, end_sfx int64
hasActiveDecision bool
ip_sz int
)
contains := 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)*/
handleSimulatedFilter(filter, &predicates)
handleOriginFilter(filter, &predicates)
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":
handleScopeFilter(value[0], &predicates)
case "value":
predicates = append(predicates, alert.SourceValueEQ(value[0]))
case "scenario":
predicates = append(predicates, alert.HasDecisionsWith(decision.ScenarioEQ(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)
}
case "since", "created_before", "until":
if err := handleTimeFilters(param, value[0], &predicates); err != nil {
return nil, err
}
case "decision_type":
predicates = append(predicates, alert.HasDecisionsWith(decision.TypeEQ(value[0])))
case "origin":
predicates = append(predicates, alert.HasDecisionsWith(decision.OriginEQ(value[0])))
case "include_capi": // allows to exclude one or more specific origins
if err = handleIncludeCapiFilter(value[0], &predicates); err != nil {
return nil, err
}
case "has_active_decision":
if hasActiveDecision, err = strconv.ParseBool(value[0]); err != nil {
return nil, errors.Wrapf(ParseType, "'%s' is not a boolean: %s", value[0], err)
}
if hasActiveDecision {
predicates = append(predicates, alert.HasDecisionsWith(decision.UntilGTE(time.Now().UTC())))
} else {
predicates = append(predicates, alert.Not(alert.HasDecisions()))
}
case "limit":
continue
case "sort":
continue
case "simulated":
continue
case "with_decisions":
continue
default:
return nil, errors.Wrapf(InvalidFilter, "Filter parameter '%s' is unknown (=%s)", param, value[0])
}
}
if err := handleIPPredicates(ip_sz, contains, start_ip, start_sfx, end_ip, end_sfx, &predicates); err != nil {
return nil, err
}
return predicates, nil
}
func BuildAlertRequestFromFilter(alerts *ent.AlertQuery, filter map[string][]string) (*ent.AlertQuery, error) {
preds, err := AlertPredicatesFromFilter(filter)
if err != nil {
return nil, err
}
return alerts.Where(preds...), nil
}
func (c *Client) AlertsCountPerScenario(ctx context.Context, filters map[string][]string) (map[string]int, error) {
var res []struct {
Scenario string

View file

@ -14,7 +14,6 @@ var (
ParseTimeFail = errors.New("unable to parse time")
ParseDurationFail = errors.New("unable to parse duration")
MarshalFail = errors.New("unable to serialize")
UnmarshalFail = errors.New("unable to parse")
BulkError = errors.New("unable to insert bulk")
ParseType = errors.New("unable to parse type")
InvalidIPOrRange = errors.New("invalid ip address / range")

View file

@ -2,7 +2,6 @@ package types
import (
"encoding/binary"
"errors"
"fmt"
"math"
"net"
@ -39,7 +38,7 @@ func Addr2Ints(anyIP string) (int, int64, int64, int64, int64, error) {
if strings.Contains(anyIP, "/") {
_, net, err := net.ParseCIDR(anyIP)
if err != nil {
return -1, 0, 0, 0, 0, fmt.Errorf("while parsing range %s: %w", anyIP, err)
return -1, 0, 0, 0, 0, fmt.Errorf("invalid ip range '%s': %w", anyIP, err)
}
return Range2Ints(*net)
@ -47,12 +46,12 @@ func Addr2Ints(anyIP string) (int, int64, int64, int64, int64, error) {
ip := net.ParseIP(anyIP)
if ip == nil {
return -1, 0, 0, 0, 0, errors.New("invalid address")
return -1, 0, 0, 0, 0, fmt.Errorf("invalid ip address '%s'", anyIP)
}
sz, start, end, err := IP2Ints(ip)
if err != nil {
return -1, 0, 0, 0, 0, fmt.Errorf("while parsing ip %s: %w", anyIP, err)
return -1, 0, 0, 0, 0, fmt.Errorf("invalid ip address '%s': %w", anyIP, err)
}
return sz, start, end, start, end, nil

View file

@ -180,7 +180,7 @@ func TestAdd2Int(t *testing.T) {
},
{
in_addr: "xxx2",
exp_error: "invalid address",
exp_error: "invalid ip address 'xxx2'",
},
}

View file

@ -165,7 +165,7 @@ teardown() {
EOT
assert_stderr --partial 'Parsing values'
assert_stderr --partial 'Imported 1 decisions'
assert_file_contains "$LOGFILE" "invalid addr/range 'whatever': invalid address"
assert_file_contains "$LOGFILE" "invalid addr/range 'whatever': invalid ip address 'whatever'"
rune -0 cscli decisions list -a -o json
assert_json '[]'
@ -182,7 +182,7 @@ teardown() {
EOT
assert_stderr --partial 'Parsing values'
assert_stderr --partial 'Imported 3 decisions'
assert_file_contains "$LOGFILE" "invalid addr/range 'bad-apple': invalid address"
assert_file_contains "$LOGFILE" "invalid addr/range 'bad-apple': invalid ip address 'bad-apple'"
rune -0 cscli decisions list -a -o json
rune -0 jq -r '.[0].decisions | length' <(output)